diff --git a/deps/swc/Cargo.lock b/deps/swc/Cargo.lock index 799963b7c..66ba52cb0 100644 --- a/deps/swc/Cargo.lock +++ b/deps/swc/Cargo.lock @@ -168,9 +168,9 @@ checksum = "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e" [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "approx" @@ -240,7 +240,7 @@ dependencies = [ [[package]] name = "ast_node" -version = "5.0.0" +version = "6.1.0" dependencies = [ "quote", "swc_macros_common", @@ -395,7 +395,7 @@ dependencies = [ [[package]] name = "binding_core_wasm" -version = "1.15.43" +version = "1.15.47" dependencies = [ "anyhow", "getrandom 0.3.4", @@ -408,7 +408,7 @@ dependencies = [ [[package]] name = "binding_es_ast_viewer" -version = "1.15.43" +version = "1.15.47" dependencies = [ "anyhow", "swc_core", @@ -444,7 +444,7 @@ dependencies = [ [[package]] name = "binding_html_wasm" -version = "1.15.43" +version = "1.15.47" dependencies = [ "anyhow", "getrandom 0.3.4", @@ -470,7 +470,7 @@ dependencies = [ [[package]] name = "binding_macros" -version = "69.0.0" +version = "73.0.0" dependencies = [ "anyhow", "console_error_panic_hook", @@ -509,7 +509,7 @@ dependencies = [ [[package]] name = "binding_minifier_wasm" -version = "1.15.43" +version = "1.15.47" dependencies = [ "getrandom 0.3.4", "serde", @@ -518,6 +518,29 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "binding_nodejs_support_wasm" +version = "1.15.47" +dependencies = [ + "anyhow", + "js-sys", + "miette", + "owo-colors", + "serde", + "serde-wasm-bindgen", + "serde_json", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_visit", + "swc_error_reporters", + "swc_ts_fast_strip", + "tracing", + "unicode-width 0.2.2", + "wasm-bindgen", + "wasm-bindgen-futures", +] + [[package]] name = "binding_react_compiler_node" version = "0.2.0" @@ -527,6 +550,7 @@ dependencies = [ "napi-build", "napi-derive", "serde", + "serde_json", "swc_core", "swc_ecma_react_compiler", "swc_malloc", @@ -535,7 +559,7 @@ dependencies = [ [[package]] name = "binding_typescript_wasm" -version = "1.15.43" +version = "1.15.47" dependencies = [ "anyhow", "js-sys", @@ -738,7 +762,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c02af038c863b51d496dd4a2eabdf781f8f7ab68025e13b984b7f2c525560454" dependencies = [ "bytes", - "rkyv 0.8.16", "serde", ] @@ -1573,9 +1596,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] @@ -1703,7 +1726,6 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.11.1", "syn 2.0.110", ] @@ -1773,7 +1795,7 @@ dependencies = [ [[package]] name = "dbg-swc" -version = "57.0.0" +version = "60.0.0" dependencies = [ "anyhow", "clap 3.2.25", @@ -1835,16 +1857,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" dependencies = [ - "derive_builder_macro 0.12.0", -] - -[[package]] -name = "derive_builder" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" -dependencies = [ - "derive_builder_macro 0.20.0", + "derive_builder_macro", ] [[package]] @@ -1859,38 +1872,16 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_builder_core" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" -dependencies = [ - "darling 0.20.10", - "proc-macro2", - "quote", - "syn 2.0.110", -] - [[package]] name = "derive_builder_macro" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" dependencies = [ - "derive_builder_core 0.12.0", + "derive_builder_core", "syn 1.0.109", ] -[[package]] -name = "derive_builder_macro" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" -dependencies = [ - "derive_builder_core 0.20.0", - "syn 2.0.110", -] - [[package]] name = "derive_more" version = "0.99.18" @@ -2579,18 +2570,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "getset" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "gimli" version = "0.28.1" @@ -2721,8 +2700,6 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "allocator-api2", - "equivalent", "foldhash 0.1.5", "serde", ] @@ -2804,7 +2781,7 @@ checksum = "ec9d92d097f4749b64e8cc33d924d9f40a2d4eb91402b458014b781f5733d60f" [[package]] name = "hstr" -version = "3.0.6" +version = "4.0.0" dependencies = [ "compact_str", "criterion", @@ -2815,11 +2792,9 @@ dependencies = [ "once_cell", "par-iter", "rand 0.8.6", - "rkyv 0.8.16", "rustc-hash 2.1.1", "serde", "serde_json", - "smartstring", "smol_str", "string_cache", "swc_malloc", @@ -3353,7 +3328,7 @@ dependencies = [ [[package]] name = "jsdoc" -version = "23.0.0" +version = "24.0.0" dependencies = [ "cbor4ii", "dashmap 6.1.0", @@ -4146,15 +4121,6 @@ dependencies = [ "syn 2.0.110", ] -[[package]] -name = "num_threads" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" -dependencies = [ - "libc", -] - [[package]] name = "object" version = "0.32.2" @@ -5016,11 +4982,11 @@ dependencies = [ [[package]] name = "regress" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ef7fa9ed0256d64a688a3747d0fef7a88851c18a5e1d57f115f38ec2e09366" +checksum = "158a764437582235e3501f683b93a0a6f8d825d04a789dbe5ed30b8799b8908a" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.16.0", "memchr", ] @@ -5669,17 +5635,6 @@ dependencies = [ "serde", ] -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - [[package]] name = "smol_str" version = "0.2.2" @@ -5814,7 +5769,7 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "swc" -version = "69.0.0" +version = "73.0.0" dependencies = [ "ansi_term", "anyhow", @@ -5904,7 +5859,7 @@ dependencies = [ [[package]] name = "swc_allocator" -version = "4.0.1" +version = "5.0.0" dependencies = [ "allocator-api2", "bumpalo", @@ -5926,22 +5881,19 @@ dependencies = [ [[package]] name = "swc_atoms" -version = "9.0.3" +version = "10.0.0" dependencies = [ "arbitrary", - "bytecheck 0.8.1", "cbor4ii", "hstr", "once_cell", - "rancor", - "rkyv 0.8.16", "serde", "shrink-to-fit", ] [[package]] name = "swc_bundler" -version = "51.0.1" +version = "54.0.0" dependencies = [ "anyhow", "crc", @@ -5983,7 +5935,7 @@ dependencies = [ [[package]] name = "swc_cli" -version = "0.116.3" +version = "0.120.2" dependencies = [ "anyhow", "par-core", @@ -5992,7 +5944,7 @@ dependencies = [ [[package]] name = "swc_cli_impl" -version = "71.0.0" +version = "75.0.0" dependencies = [ "anyhow", "assert_cmd", @@ -6012,13 +5964,12 @@ dependencies = [ [[package]] name = "swc_common" -version = "23.0.2" +version = "24.0.0" dependencies = [ "anyhow", "arbitrary", "ast_node", "better_scoped_tls", - "bytecheck 0.8.1", "bytes-str", "cbor4ii", "either", @@ -6027,8 +5978,6 @@ dependencies = [ "once_cell", "par-iter", "parking_lot", - "rancor", - "rkyv 0.8.16", "rustc-hash 2.1.1", "serde", "serde_json", @@ -6046,7 +5995,7 @@ dependencies = [ [[package]] name = "swc_compiler_base" -version = "59.0.0" +version = "62.0.0" dependencies = [ "anyhow", "base64 0.22.1", @@ -6071,7 +6020,7 @@ dependencies = [ [[package]] name = "swc_config" -version = "5.0.0" +version = "6.0.0" dependencies = [ "anyhow", "bytes-str", @@ -6100,7 +6049,7 @@ dependencies = [ [[package]] name = "swc_core" -version = "71.0.3" +version = "75.0.0" dependencies = [ "anyhow", "binding_macros", @@ -6149,12 +6098,11 @@ dependencies = [ "swc_transform_common", "swc_typescript", "testing", - "vergen", ] [[package]] name = "swc_css" -version = "28.0.0" +version = "29.0.0" dependencies = [ "swc_css_ast", "swc_css_codegen", @@ -6169,12 +6117,10 @@ dependencies = [ [[package]] name = "swc_css_ast" -version = "23.0.0" +version = "24.0.0" dependencies = [ - "bytecheck 0.8.1", "cbor4ii", "is-macro", - "rkyv 0.8.16", "serde", "string_enum", "swc_atoms", @@ -6183,7 +6129,7 @@ dependencies = [ [[package]] name = "swc_css_codegen" -version = "23.0.0" +version = "24.0.0" dependencies = [ "auto_impl", "bitflags 2.10.0", @@ -6209,7 +6155,7 @@ dependencies = [ [[package]] name = "swc_css_compat" -version = "23.0.0" +version = "24.0.0" dependencies = [ "bitflags 2.10.0", "serde", @@ -6225,7 +6171,7 @@ dependencies = [ [[package]] name = "swc_css_lints" -version = "25.0.0" +version = "27.0.0" dependencies = [ "anyhow", "auto_impl", @@ -6246,7 +6192,7 @@ dependencies = [ [[package]] name = "swc_css_minifier" -version = "23.0.0" +version = "24.0.0" dependencies = [ "rustc-hash 2.1.1", "serde", @@ -6262,7 +6208,7 @@ dependencies = [ [[package]] name = "swc_css_modules" -version = "23.0.0" +version = "24.0.0" dependencies = [ "indexmap 2.12.0", "rustc-hash 2.1.1", @@ -6279,7 +6225,7 @@ dependencies = [ [[package]] name = "swc_css_parser" -version = "23.0.0" +version = "24.0.0" dependencies = [ "codspeed-criterion-compat", "lexical", @@ -6295,7 +6241,7 @@ dependencies = [ [[package]] name = "swc_css_prefixer" -version = "28.0.0" +version = "29.0.0" dependencies = [ "once_cell", "preset_env_base", @@ -6314,7 +6260,7 @@ dependencies = [ [[package]] name = "swc_css_utils" -version = "23.0.0" +version = "24.0.0" dependencies = [ "once_cell", "rustc-hash 2.1.1", @@ -6327,7 +6273,7 @@ dependencies = [ [[package]] name = "swc_css_visit" -version = "23.0.0" +version = "24.0.0" dependencies = [ "serde", "swc_atoms", @@ -6338,18 +6284,15 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "25.0.0" +version = "27.0.0" dependencies = [ "arbitrary", "bitflags 2.10.0", - "bytecheck 0.8.1", "cbor4ii", "is-macro", "num-bigint", "once_cell", "phf", - "rancor", - "rkyv 0.8.16", "rustc-hash 2.1.1", "serde", "serde_json", @@ -6363,7 +6306,7 @@ dependencies = [ [[package]] name = "swc_ecma_codegen" -version = "28.0.2" +version = "30.0.0" dependencies = [ "ascii", "base64 0.22.1", @@ -6384,6 +6327,7 @@ dependencies = [ "swc_ecma_codegen_macros", "swc_ecma_parser", "swc_ecma_testing", + "swc_ecma_utils", "swc_malloc", "swc_sourcemap", "testing", @@ -6401,7 +6345,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_bugfixes" -version = "51.0.0" +version = "54.0.0" dependencies = [ "rustc-hash 2.1.1", "swc_atoms", @@ -6418,7 +6362,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_common" -version = "40.0.1" +version = "43.0.0" dependencies = [ "swc_common", "swc_ecma_ast", @@ -6428,7 +6372,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_es2015" -version = "50.0.0" +version = "53.0.0" dependencies = [ "arrayvec", "indexmap 2.12.0", @@ -6455,7 +6399,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_es2016" -version = "45.0.0" +version = "48.0.0" dependencies = [ "swc_ecma_ast", "swc_ecma_parser", @@ -6468,7 +6412,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_es2017" -version = "45.0.0" +version = "48.0.0" dependencies = [ "serde", "swc_common", @@ -6481,7 +6425,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_es2018" -version = "46.0.0" +version = "49.0.0" dependencies = [ "serde", "swc_ecma_ast", @@ -6493,7 +6437,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_es2019" -version = "45.0.0" +version = "48.0.0" dependencies = [ "swc_common", "swc_ecma_ast", @@ -6507,7 +6451,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_es2020" -version = "48.0.0" +version = "51.0.0" dependencies = [ "serde", "swc_common", @@ -6522,7 +6466,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_es2021" -version = "45.0.0" +version = "48.0.0" dependencies = [ "swc_ecma_ast", "swc_ecma_transformer", @@ -6533,7 +6477,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_es2022" -version = "48.0.0" +version = "51.0.0" dependencies = [ "rustc-hash 2.1.1", "swc_atoms", @@ -6550,7 +6494,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_es3" -version = "36.0.0" +version = "39.0.0" dependencies = [ "swc_ecma_ast", "swc_ecma_parser", @@ -6560,7 +6504,7 @@ dependencies = [ [[package]] name = "swc_ecma_compat_regexp" -version = "6.0.0" +version = "7.0.0" dependencies = [ "icu_properties 2.1.2", "swc_ecma_regexp", @@ -6570,7 +6514,7 @@ dependencies = [ [[package]] name = "swc_ecma_ext_transforms" -version = "31.0.0" +version = "33.0.0" dependencies = [ "phf", "swc_common", @@ -6581,7 +6525,7 @@ dependencies = [ [[package]] name = "swc_ecma_hooks" -version = "0.9.0" +version = "0.11.0" dependencies = [ "swc_atoms", "swc_common", @@ -6591,16 +6535,16 @@ dependencies = [ [[package]] name = "swc_ecma_lexer" -version = "40.0.1" +version = "42.0.0" dependencies = [ "bitflags 2.10.0", + "compact_str", "either", "num-bigint", "rustc-hash 2.1.1", "seq-macro", "serde", "smallvec", - "smartstring", "stacker", "swc_atoms", "swc_common", @@ -6613,7 +6557,7 @@ dependencies = [ [[package]] name = "swc_ecma_lints" -version = "33.0.0" +version = "35.0.0" dependencies = [ "auto_impl", "codspeed-criterion-compat", @@ -6637,7 +6581,7 @@ dependencies = [ [[package]] name = "swc_ecma_loader" -version = "24.0.1" +version = "25.0.0" dependencies = [ "anyhow", "dashmap 6.1.0", @@ -6658,7 +6602,7 @@ dependencies = [ [[package]] name = "swc_ecma_minifier" -version = "56.0.1" +version = "59.0.0" dependencies = [ "ansi_term", "anyhow", @@ -6701,11 +6645,12 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "41.1.2" +version = "43.0.0" dependencies = [ "bitflags 2.10.0", "cbor4ii", "codspeed-criterion-compat", + "compact_str", "either", "num-bigint", "pathdiff", @@ -6715,7 +6660,6 @@ dependencies = [ "seq-macro", "serde", "serde_json", - "smartstring", "stacker", "swc_atoms", "swc_common", @@ -6729,7 +6673,7 @@ dependencies = [ [[package]] name = "swc_ecma_preset_env" -version = "57.0.0" +version = "61.0.0" dependencies = [ "anyhow", "codspeed-criterion-compat", @@ -6757,7 +6701,7 @@ dependencies = [ [[package]] name = "swc_ecma_quote" -version = "41.0.0" +version = "43.0.0" dependencies = [ "swc_common", "swc_ecma_ast", @@ -6766,7 +6710,7 @@ dependencies = [ [[package]] name = "swc_ecma_quote_macros" -version = "41.0.0" +version = "43.0.0" dependencies = [ "anyhow", "proc-macro2", @@ -6782,7 +6726,7 @@ dependencies = [ [[package]] name = "swc_ecma_react_compiler" -version = "20.0.2" +version = "22.0.0" dependencies = [ "forked_react_compiler", "forked_react_compiler_ast", @@ -6802,7 +6746,7 @@ dependencies = [ [[package]] name = "swc_ecma_regexp" -version = "0.12.0" +version = "0.13.0" dependencies = [ "phf", "rustc-hash 2.1.1", @@ -6817,7 +6761,7 @@ dependencies = [ [[package]] name = "swc_ecma_regexp_ast" -version = "0.12.0" +version = "1.0.0" dependencies = [ "bitflags 2.10.0", "cbor4ii", @@ -6834,7 +6778,7 @@ version = "0.0.1" [[package]] name = "swc_ecma_regexp_visit" -version = "0.12.0" +version = "0.13.0" dependencies = [ "serde", "swc_atoms", @@ -6845,7 +6789,7 @@ dependencies = [ [[package]] name = "swc_ecma_testing" -version = "24.0.1" +version = "25.0.0" dependencies = [ "anyhow", "hex", @@ -6856,7 +6800,7 @@ dependencies = [ [[package]] name = "swc_ecma_transformer" -version = "16.0.3" +version = "19.0.0" dependencies = [ "rustc-hash 2.1.1", "swc_atoms", @@ -6873,7 +6817,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms" -version = "56.0.0" +version = "60.0.0" dependencies = [ "par-core", "swc_common", @@ -6893,7 +6837,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_base" -version = "44.0.3" +version = "47.0.0" dependencies = [ "better_scoped_tls", "codspeed-criterion-compat", @@ -6919,7 +6863,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "44.0.0" +version = "47.0.0" dependencies = [ "swc_common", "swc_ecma_ast", @@ -6930,7 +6874,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_compat" -version = "52.0.1" +version = "55.0.0" dependencies = [ "indexmap 2.12.0", "par-core", @@ -6971,7 +6915,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_module" -version = "49.0.1" +version = "53.0.0" dependencies = [ "Inflector", "anyhow", @@ -7003,7 +6947,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_optimization" -version = "47.0.1" +version = "50.0.0" dependencies = [ "bytes-str", "dashmap 6.1.0", @@ -7012,6 +6956,7 @@ dependencies = [ "par-core", "petgraph", "rustc-hash 2.1.1", + "serde", "serde_json", "swc_atoms", "swc_common", @@ -7031,7 +6976,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "44.0.1" +version = "47.0.0" dependencies = [ "either", "rustc-hash 2.1.1", @@ -7053,7 +6998,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "50.0.0" +version = "53.0.0" dependencies = [ "base64 0.22.1", "bytes-str", @@ -7080,7 +7025,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_testing" -version = "48.0.0" +version = "51.0.0" dependencies = [ "ansi_term", "anyhow", @@ -7104,7 +7049,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "50.0.0" +version = "53.0.0" dependencies = [ "bytes-str", "codspeed-criterion-compat", @@ -7128,7 +7073,7 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "31.0.1" +version = "33.0.0" dependencies = [ "dragonbox_ecma", "indexmap 2.12.0", @@ -7147,7 +7092,7 @@ dependencies = [ [[package]] name = "swc_ecma_visit" -version = "25.0.0" +version = "27.0.0" dependencies = [ "new_debug_unreachable", "num-bigint", @@ -7161,7 +7106,7 @@ dependencies = [ [[package]] name = "swc_ecmascript" -version = "64.0.0" +version = "68.0.0" dependencies = [ "par-core", "swc_ecma_ast", @@ -7186,7 +7131,7 @@ dependencies = [ [[package]] name = "swc_error_reporters" -version = "25.0.0" +version = "26.0.0" dependencies = [ "anyhow", "miette", @@ -7197,7 +7142,7 @@ dependencies = [ [[package]] name = "swc_estree_ast" -version = "23.0.0" +version = "24.0.0" dependencies = [ "better_scoped_tls", "serde", @@ -7208,7 +7153,7 @@ dependencies = [ [[package]] name = "swc_estree_compat" -version = "44.0.0" +version = "46.0.0" dependencies = [ "anyhow", "codspeed-criterion-compat", @@ -7243,7 +7188,7 @@ dependencies = [ [[package]] name = "swc_html" -version = "35.0.0" +version = "36.0.0" dependencies = [ "swc_html_ast", "swc_html_codegen", @@ -7253,12 +7198,10 @@ dependencies = [ [[package]] name = "swc_html_ast" -version = "23.0.0" +version = "24.0.0" dependencies = [ - "bytecheck 0.8.1", "cbor4ii", "is-macro", - "rkyv 0.8.16", "serde", "string_enum", "swc_atoms", @@ -7267,7 +7210,7 @@ dependencies = [ [[package]] name = "swc_html_codegen" -version = "24.0.0" +version = "25.0.0" dependencies = [ "auto_impl", "bitflags 2.10.0", @@ -7292,7 +7235,7 @@ dependencies = [ [[package]] name = "swc_html_minifier" -version = "56.0.0" +version = "59.0.0" dependencies = [ "codspeed-criterion-compat", "once_cell", @@ -7323,7 +7266,7 @@ dependencies = [ [[package]] name = "swc_html_parser" -version = "23.0.0" +version = "24.0.0" dependencies = [ "codspeed-criterion-compat", "rustc-hash 2.1.1", @@ -7340,7 +7283,7 @@ dependencies = [ [[package]] name = "swc_html_utils" -version = "16.0.0" +version = "17.0.0" dependencies = [ "once_cell", "rustc-hash 2.1.1", @@ -7351,7 +7294,7 @@ dependencies = [ [[package]] name = "swc_html_visit" -version = "23.0.0" +version = "24.0.0" dependencies = [ "serde", "swc_atoms", @@ -7379,7 +7322,7 @@ dependencies = [ [[package]] name = "swc_node_bundler" -version = "70.0.0" +version = "74.0.0" dependencies = [ "anyhow", "rustc-hash 2.1.1", @@ -7403,7 +7346,7 @@ dependencies = [ [[package]] name = "swc_node_comments" -version = "24.0.0" +version = "25.0.0" dependencies = [ "dashmap 6.1.0", "rustc-hash 2.1.1", @@ -7455,7 +7398,7 @@ dependencies = [ [[package]] name = "swc_plugin_backend_wasmer" -version = "13.0.0" +version = "15.0.0" dependencies = [ "anyhow", "enumset", @@ -7469,7 +7412,7 @@ dependencies = [ [[package]] name = "swc_plugin_backend_wasmtime" -version = "12.0.0" +version = "14.0.0" dependencies = [ "anyhow", "swc_common", @@ -7489,7 +7432,7 @@ dependencies = [ [[package]] name = "swc_plugin_proxy" -version = "26.0.0" +version = "28.0.0" dependencies = [ "better_scoped_tls", "cbor4ii", @@ -7501,7 +7444,7 @@ dependencies = [ [[package]] name = "swc_plugin_runner" -version = "30.0.0" +version = "32.0.0" dependencies = [ "anyhow", "blake3", @@ -7515,7 +7458,6 @@ dependencies = [ "swc_plugin_proxy", "swc_transform_common", "tracing", - "vergen", ] [[package]] @@ -7540,7 +7482,7 @@ dependencies = [ [[package]] name = "swc_transform_common" -version = "17.0.0" +version = "18.0.0" dependencies = [ "better_scoped_tls", "rustc-hash 2.1.1", @@ -7550,7 +7492,7 @@ dependencies = [ [[package]] name = "swc_ts_fast_strip" -version = "53.0.0" +version = "56.0.0" dependencies = [ "anyhow", "bytes-str", @@ -7571,9 +7513,10 @@ dependencies = [ [[package]] name = "swc_ts_fast_strip_binding" -version = "0.18.0" +version = "0.21.0" dependencies = [ "anyhow", + "codspeed-criterion-compat", "miette", "owo-colors", "serde", @@ -7588,7 +7531,7 @@ dependencies = [ [[package]] name = "swc_typescript" -version = "30.0.1" +version = "32.0.0" dependencies = [ "bitflags 2.10.0", "petgraph", @@ -7614,7 +7557,7 @@ dependencies = [ [[package]] name = "swc_xml" -version = "23.0.0" +version = "24.0.0" dependencies = [ "swc_xml_ast", "swc_xml_codegen", @@ -7624,7 +7567,7 @@ dependencies = [ [[package]] name = "swc_xml_ast" -version = "23.0.0" +version = "24.0.0" dependencies = [ "cbor4ii", "is-macro", @@ -7636,7 +7579,7 @@ dependencies = [ [[package]] name = "swc_xml_codegen" -version = "23.0.0" +version = "24.0.0" dependencies = [ "auto_impl", "bitflags 2.10.0", @@ -7659,7 +7602,7 @@ dependencies = [ [[package]] name = "swc_xml_parser" -version = "23.0.0" +version = "24.0.0" dependencies = [ "rustc-hash 2.1.1", "serde", @@ -7673,7 +7616,7 @@ dependencies = [ [[package]] name = "swc_xml_visit" -version = "23.0.0" +version = "24.0.0" dependencies = [ "serde", "swc_atoms", @@ -7846,7 +7789,7 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "testing" -version = "24.0.1" +version = "25.0.0" dependencies = [ "cargo_metadata", "difference", @@ -7865,7 +7808,7 @@ dependencies = [ [[package]] name = "testing_macros" -version = "1.0.1" +version = "1.0.2" dependencies = [ "anyhow", "glob", @@ -7875,6 +7818,7 @@ dependencies = [ "regex", "relative-path", "syn 2.0.110", + "tempfile", ] [[package]] @@ -7966,9 +7910,7 @@ checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", - "libc", "num-conv", - "num_threads", "powerfmt", "serde_core", "time-core", @@ -8372,34 +8314,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vergen" -version = "9.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c32e7318e93a9ac53693b6caccfb05ff22e04a44c7cf8a279051f24c09da286f" -dependencies = [ - "anyhow", - "cargo_metadata", - "derive_builder 0.20.0", - "getset", - "regex", - "rustversion", - "time", - "vergen-lib", -] - -[[package]] -name = "vergen-lib" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06bee42361e43b60f363bad49d63798d0f42fb1768091812270eca00c784720" -dependencies = [ - "anyhow", - "derive_builder 0.20.0", - "getset", - "rustversion", -] - [[package]] name = "version_check" version = "0.9.5" @@ -8823,7 +8737,7 @@ dependencies = [ "anyhow", "bytesize", "ciborium", - "derive_builder 0.12.0", + "derive_builder", "hex", "indexmap 2.12.0", "saffron", diff --git a/deps/swc/Cargo.toml b/deps/swc/Cargo.toml index 50a6d51b3..4e16f0330 100644 --- a/deps/swc/Cargo.toml +++ b/deps/swc/Cargo.toml @@ -15,12 +15,6 @@ repository = "https://github.com/swc-project/swc.git" [workspace.dependencies] -# bytecheck version should be in sync with rkyv version. Do not bump individually. -bytecheck = "0.8.0" -rancor = "0.1.0" -rkyv = "0.8.16" - - Inflector = "0.11.4" allocator-api2 = "0.2.18" ansi_term = "0.12.1" @@ -97,7 +91,7 @@ radix_fmt = "1.0.0" rand = "0.8.5" rayon = "1.7.0" regex = "1.5.4" -regress = "0.10.3" +regress = "0.11.1" relative-path = "1.6.1" reqwest = "0.11.14" rustc-hash = "2" @@ -114,7 +108,6 @@ sha2 = "0.10.8" shrink-to-fit = "0.2.1" siphasher = "0.3.9" smallvec = "1.8.0" -smartstring = "1.0.1" smol_str = "0.2.0" st-map = "0.2.0" string_cache = "0.8.7" @@ -131,7 +124,6 @@ triomphe = "0.1.13" unicode-id-start = "1.2.0" unicode-width = "0.2.1" url = "2.5.4" -vergen = { version = "9.0.0", default-features = false } walkdir = "2.4.0" wasi-common = { version = "38", default-features = false } wasm-bindgen = "0.2.100" diff --git a/deps/swc/bindings/binding_core_wasm/Cargo.toml b/deps/swc/bindings/binding_core_wasm/Cargo.toml index b32d18c4d..827126359 100644 --- a/deps/swc/bindings/binding_core_wasm/Cargo.toml +++ b/deps/swc/bindings/binding_core_wasm/Cargo.toml @@ -6,7 +6,7 @@ license = { workspace = true } name = "binding_core_wasm" publish = false repository = { workspace = true } -version = "1.15.43" +version = "1.15.47" [lib] bench = false diff --git a/deps/swc/bindings/binding_es_ast_viewer/Cargo.toml b/deps/swc/bindings/binding_es_ast_viewer/Cargo.toml index d3463ac53..abca73abe 100644 --- a/deps/swc/bindings/binding_es_ast_viewer/Cargo.toml +++ b/deps/swc/bindings/binding_es_ast_viewer/Cargo.toml @@ -5,7 +5,7 @@ license = { workspace = true } name = "binding_es_ast_viewer" publish = false repository = { workspace = true } -version = "1.15.43" +version = "1.15.47" [dependencies] anyhow = { workspace = true } diff --git a/deps/swc/bindings/binding_html_wasm/Cargo.toml b/deps/swc/bindings/binding_html_wasm/Cargo.toml index 0a1a99798..ebd6233e6 100644 --- a/deps/swc/bindings/binding_html_wasm/Cargo.toml +++ b/deps/swc/bindings/binding_html_wasm/Cargo.toml @@ -6,7 +6,7 @@ license = { workspace = true } name = "binding_html_wasm" publish = false repository = { workspace = true } -version = "1.15.43" +version = "1.15.47" [lib] bench = false diff --git a/deps/swc/bindings/binding_minifier_wasm/Cargo.toml b/deps/swc/bindings/binding_minifier_wasm/Cargo.toml index 724f4f104..d449f6659 100644 --- a/deps/swc/bindings/binding_minifier_wasm/Cargo.toml +++ b/deps/swc/bindings/binding_minifier_wasm/Cargo.toml @@ -6,7 +6,7 @@ license = { workspace = true } name = "binding_minifier_wasm" publish = false repository = { workspace = true } -version = "1.15.43" +version = "1.15.47" [lib] bench = false diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/.cargo/config.toml b/deps/swc/bindings/binding_nodejs_support_wasm/.cargo/config.toml new file mode 100644 index 000000000..dee02885d --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/.cargo/config.toml @@ -0,0 +1,3 @@ +[target.wasm32-unknown-unknown] +# support more stack size due to issue: https://github.com/swc-project/swc/issues/10207 +rustflags = ["-C", "link-args=-z stack-size=2097152"] diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/Cargo.toml b/deps/swc/bindings/binding_nodejs_support_wasm/Cargo.toml new file mode 100644 index 000000000..55eeec894 --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/Cargo.toml @@ -0,0 +1,40 @@ +[package] +authors = ["강동윤 "] +description = "Node.js support helpers compiled to WebAssembly" +edition = { workspace = true } +license = { workspace = true } +name = "binding_nodejs_support_wasm" +publish = false +repository = { workspace = true } +version = "1.15.47" + +[lib] +bench = false +crate-type = ["cdylib"] + +[features] +nightly = ["swc_ts_fast_strip/nightly"] + +[dependencies] +anyhow = { workspace = true } +js-sys = { workspace = true } +miette = { workspace = true } +owo-colors = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-wasm-bindgen = { workspace = true } +serde_json = { workspace = true } +swc_common = { path = "../../crates/swc_common" } +swc_ecma_ast = { path = "../../crates/swc_ecma_ast" } +swc_ecma_parser = { path = "../../crates/swc_ecma_parser" } +swc_ecma_visit = { path = "../../crates/swc_ecma_visit" } +swc_error_reporters = { path = "../../crates/swc_error_reporters" } +swc_ts_fast_strip = { path = "../../crates/swc_ts_fast_strip", features = [ + "wasm-bindgen", +] } +tracing = { workspace = true, features = ["max_level_off"] } +unicode-width = { workspace = true } +wasm-bindgen = { workspace = true, features = ["enable-interning"] } +wasm-bindgen-futures = { workspace = true } + +[package.metadata.wasm-pack.profile.release] +wasm-opt = false diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/LICENSE b/deps/swc/bindings/binding_nodejs_support_wasm/LICENSE new file mode 100644 index 000000000..8f3eaa819 --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2024 SWC contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/README.md b/deps/swc/bindings/binding_nodejs_support_wasm/README.md new file mode 100644 index 000000000..abd29b9bb --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/README.md @@ -0,0 +1,26 @@ +# @swc/nodejs-support-wasm + +This package provides a standalone WebAssembly binding for Node.js +integrations. Its Rust crate, source, build, and test setup are independent from +`@swc/wasm-typescript`. + +It includes the TypeScript transform API from `@swc/wasm-typescript` and +additional helpers for module syntax transformation, assertion locations, and +syntax validation. + +## API + +- `transform` and `transformSync` +- `transformModuleSyntax` +- `getFirstExpression` +- `isValidSyntax` +- `isRecoverableError` + +## Contributing + +See [the main repository](https://github.com/swc-project/swc)'s contributing +guide. + +## License + +Apache 2.0 diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/package.json b/deps/swc/bindings/binding_nodejs_support_wasm/package.json new file mode 100644 index 000000000..728a4a614 --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "@rstest/core": "^0.7.8" + } +} diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/rstest.config.mjs b/deps/swc/bindings/binding_nodejs_support_wasm/rstest.config.mjs new file mode 100644 index 000000000..0e541bbdd --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/rstest.config.mjs @@ -0,0 +1,4 @@ +export default { + include: ["__tests__/**/*.{js,jsx,ts,tsx}"], + globals: true, +}; diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/scripts/build.sh b/deps/swc/bindings/binding_nodejs_support_wasm/scripts/build.sh new file mode 100755 index 000000000..c5aaa25ce --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/scripts/build.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -eux + +export CARGO_PROFILE_RELEASE_LTO="fat" +export CARGO_PROFILE_RELEASE_OPT_LEVEL="z" + +wasm-pack build \ + --out-name wasm \ + --release \ + --scope=swc \ + --target nodejs \ + "$@" +ls -al ./pkg + +node ./scripts/patch.mjs +cp ./README.md ./pkg/README.md diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/scripts/patch.mjs b/deps/swc/bindings/binding_nodejs_support_wasm/scripts/patch.mjs new file mode 100644 index 000000000..e9f96cdef --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/scripts/patch.mjs @@ -0,0 +1,31 @@ +import fs from "node:fs/promises"; + +const rawWasmPath = "pkg/wasm_bg.wasm"; +const wasmJsPath = "pkg/wasm.js"; +const packageJsonPath = "pkg/package.json"; +const rawWasmFile = await fs.readFile(rawWasmPath); +const origJsFile = await fs.readFile(wasmJsPath, "utf8"); + +const base64 = rawWasmFile.toString("base64"); +const patchedJsFile = origJsFile + .replace( + `const path = require('path').join(__dirname, 'wasm_bg.wasm');`, + "" + ) + .replace(", fatal: true", "") + .replace( + `const bytes = require('fs').readFileSync(path);`, + ` +const { Buffer } = require('node:buffer'); +const bytes = Buffer.from('${base64}', 'base64');` + ); + +await fs.writeFile(wasmJsPath, patchedJsFile); +await fs.unlink(rawWasmPath); + +const pkgJsonFile = await fs.readFile(packageJsonPath, "utf8"); +const pkgJson = JSON.parse(pkgJsonFile); +pkgJson.name = "@swc/nodejs-support-wasm"; +pkgJson.description = "SWC WebAssembly helpers for Node.js"; +pkgJson.files = pkgJson.files.filter((file) => file !== "wasm_bg.wasm"); +await fs.writeFile(packageJsonPath, JSON.stringify(pkgJson, null, 2)); diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/scripts/test.sh b/deps/swc/bindings/binding_nodejs_support_wasm/scripts/test.sh new file mode 100755 index 000000000..4c3174b05 --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/scripts/test.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -eu + +./scripts/build.sh +npx rstest "$@" + +./scripts/build.sh --features nightly +npx rstest "$@" diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/src/error_reporter.rs b/deps/swc/bindings/binding_nodejs_support_wasm/src/error_reporter.rs new file mode 100644 index 000000000..684ba3073 --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/src/error_reporter.rs @@ -0,0 +1,881 @@ +use std::fmt::{self}; + +use miette::{ + Diagnostic, GraphicalTheme, LabeledSpan, ReportHandler, SourceCode, SourceSpan, ThemeCharacters, +}; +use owo_colors::{OwoColorize, Style}; +use unicode_width::UnicodeWidthChar; + +/** +A [`ReportHandler`] that displays a given [`Report`](crate::Report) in a +quasi-graphical way, using terminal colors, unicode drawing characters, and +other such things. + +This is the default reporter bundled with `miette`. + +This printer can be customized by using [`new_themed()`](GraphicalReportHandler::new_themed) and handing it a +[`GraphicalTheme`] of your own creation (or using one of its own defaults!) + +See [`set_hook()`](crate::set_hook) for more details on customizing your global +printer. +*/ +#[derive(Debug, Clone)] +pub struct SwcReportHandler { + pub(crate) theme: GraphicalTheme, + pub(crate) context_lines: usize, + pub(crate) tab_width: usize, +} + +impl SwcReportHandler { + /// Create a new `GraphicalReportHandler` with the default + /// [`GraphicalTheme`]. This will use both unicode characters and colors. + pub fn new() -> Self { + Self { + theme: GraphicalTheme::default(), + context_lines: 1, + tab_width: 4, + } + } + + /// Set a theme for this handler. + pub fn with_theme(mut self, theme: GraphicalTheme) -> Self { + self.theme = theme; + self + } +} + +impl Default for SwcReportHandler { + fn default() -> Self { + Self::new() + } +} + +impl SwcReportHandler { + /// Render a [`Diagnostic`]. This function is mostly internal and meant to + /// be called by the toplevel [`ReportHandler`] handler, but is made public + /// to make it easier (possible) to test in isolation from global state. + pub fn render_report( + &self, + f: &mut impl fmt::Write, + diagnostic: &dyn Diagnostic, + ) -> fmt::Result { + self.render_report_inner(f, diagnostic, diagnostic.source_code()) + } + + fn render_report_inner( + &self, + f: &mut impl fmt::Write, + diagnostic: &dyn Diagnostic, + parent_src: Option<&dyn SourceCode>, + ) -> fmt::Result { + let src = diagnostic.source_code().or(parent_src); + self.render_snippets(f, diagnostic, src)?; + + Ok(()) + } + + fn render_snippets( + &self, + f: &mut impl fmt::Write, + diagnostic: &dyn Diagnostic, + opt_source: Option<&dyn SourceCode>, + ) -> fmt::Result { + let source = match opt_source { + Some(source) => source, + None => return Ok(()), + }; + let labels = match diagnostic.labels() { + Some(labels) => labels, + None => return Ok(()), + }; + + let mut labels = labels.collect::>(); + labels.sort_unstable_by_key(|l| l.inner().offset()); + + let mut contexts = Vec::with_capacity(labels.len()); + for right in labels.iter().cloned() { + let right_conts = + match source.read_span(right.inner(), self.context_lines, self.context_lines) { + Ok(cont) => cont, + Err(err) => { + writeln!( + f, + " [{} `{}` (offset: {}, length: {}): {:?}]", + "Failed to read contents for label".style(self.theme.styles.error), + right + .label() + .unwrap_or("") + .style(self.theme.styles.link), + right.offset().style(self.theme.styles.link), + right.len().style(self.theme.styles.link), + err.style(self.theme.styles.warning) + )?; + return Ok(()); + } + }; + + if contexts.is_empty() { + contexts.push((right, right_conts)); + continue; + } + + let (left, left_conts) = contexts.last().unwrap(); + if left_conts.line() + left_conts.line_count() >= right_conts.line() { + // The snippets will overlap, so we create one Big Chunky Boi + let left_end = left.offset() + left.len(); + let right_end = right.offset() + right.len(); + let new_end = std::cmp::max(left_end, right_end); + + let new_span = LabeledSpan::new( + left.label().map(String::from), + left.offset(), + new_end - left.offset(), + ); + // Check that the two contexts can be combined + if let Ok(new_conts) = + source.read_span(new_span.inner(), self.context_lines, self.context_lines) + { + contexts.pop(); + // We'll throw the contents away later + contexts.push((new_span, new_conts)); + continue; + } + } + + contexts.push((right, right_conts)); + } + for (ctx, _) in contexts { + self.render_context(f, source, &ctx, &labels[..])?; + } + + Ok(()) + } + + fn render_context( + &self, + f: &mut impl fmt::Write, + source: &dyn SourceCode, + context: &LabeledSpan, + labels: &[LabeledSpan], + ) -> fmt::Result { + let lines = self.get_lines(source, context.inner())?; + + // sorting is your friend + let labels = labels + .iter() + .zip(self.theme.styles.highlights.iter().cloned().cycle()) + .map(|(label, st)| FancySpan::new(label.label().map(String::from), *label.inner(), st)) + .collect::>(); + + // The max number of gutter-lines that will be active at any given + // point. We need this to figure out indentation, so we do one loop + // over the lines to see what the damage is gonna be. + let mut max_gutter = 0usize; + for line in &lines { + let mut num_highlights = 0; + for hl in &labels { + if !line.span_line_only(hl) && line.span_applies_gutter(hl) { + num_highlights += 1; + } + } + max_gutter = std::cmp::max(max_gutter, num_highlights); + } + + // Now it's time for the fun part--actually rendering everything! + for line in &lines { + // Then, we need to print the gutter, along with any fly-bys We + // have separate gutters depending on whether we're on the actual + // line, or on one of the "highlight lines" below it. + self.render_line_gutter(f, max_gutter, line, &labels)?; + + // And _now_ we can print out the line text itself! + self.render_line_text(f, &line.text)?; + + // Next, we write all the highlights that apply to this particular line. + let (single_line, multi_line): (Vec<_>, Vec<_>) = labels + .iter() + .filter(|hl| line.span_applies(hl)) + .partition(|hl| line.span_line_only(hl)); + if !single_line.is_empty() { + // gutter _again_ + self.render_highlight_gutter( + f, + max_gutter, + line, + &labels, + LabelRenderMode::SingleLine, + )?; + self.render_single_line_highlights(f, line, max_gutter, &single_line, &labels)?; + } + for hl in multi_line { + if hl.label().is_some() && line.span_ends(hl) && !line.span_starts(hl) { + self.render_multi_line_end(f, &labels, max_gutter, line, hl)?; + } + } + } + + Ok(()) + } + + fn render_multi_line_end( + &self, + f: &mut impl fmt::Write, + labels: &[FancySpan], + max_gutter: usize, + line: &Line, + label: &FancySpan, + ) -> fmt::Result { + if let Some(label_parts) = label.label_parts() { + // if it has a label, how long is it? + let (first, rest) = label_parts.split_first().expect( + "cannot crash because rest would have been None, see docs on the `label` field of \ + FancySpan", + ); + + if rest.is_empty() { + // gutter _again_ + self.render_highlight_gutter( + f, + max_gutter, + line, + labels, + LabelRenderMode::SingleLine, + )?; + + self.render_multi_line_end_single( + f, + first, + label.style, + LabelRenderMode::SingleLine, + )?; + } else { + // gutter _again_ + self.render_highlight_gutter( + f, + max_gutter, + line, + labels, + LabelRenderMode::MultiLineFirst, + )?; + + self.render_multi_line_end_single( + f, + first, + label.style, + LabelRenderMode::MultiLineFirst, + )?; + for label_line in rest { + // gutter _again_ + self.render_highlight_gutter( + f, + max_gutter, + line, + labels, + LabelRenderMode::MultiLineRest, + )?; + self.render_multi_line_end_single( + f, + label_line, + label.style, + LabelRenderMode::MultiLineRest, + )?; + } + } + } else { + // gutter _again_ + self.render_highlight_gutter(f, max_gutter, line, labels, LabelRenderMode::SingleLine)?; + // has no label + writeln!(f, "{}", self.theme.characters.hbar.style(label.style))?; + } + + Ok(()) + } + + fn render_line_gutter( + &self, + f: &mut impl fmt::Write, + max_gutter: usize, + line: &Line, + highlights: &[FancySpan], + ) -> fmt::Result { + if max_gutter == 0 { + return Ok(()); + } + let chars = &self.theme.characters; + let mut gutter = String::new(); + let applicable = highlights.iter().filter(|hl| line.span_applies_gutter(hl)); + let mut arrow = false; + for (i, hl) in applicable.enumerate() { + if line.span_starts(hl) { + gutter.push_str(&chars.ltop.style(hl.style).to_string()); + gutter.push_str( + &chars + .hbar + .to_string() + .repeat(max_gutter.saturating_sub(i)) + .style(hl.style) + .to_string(), + ); + gutter.push_str(&chars.rarrow.style(hl.style).to_string()); + arrow = true; + break; + } else if line.span_ends(hl) { + if hl.label().is_some() { + gutter.push_str(&chars.lcross.style(hl.style).to_string()); + } else { + gutter.push_str(&chars.lbot.style(hl.style).to_string()); + } + gutter.push_str( + &chars + .hbar + .to_string() + .repeat(max_gutter.saturating_sub(i)) + .style(hl.style) + .to_string(), + ); + gutter.push_str(&chars.rarrow.style(hl.style).to_string()); + arrow = true; + break; + } else if line.span_flyby(hl) { + gutter.push_str(&chars.vbar.style(hl.style).to_string()); + } else { + gutter.push(' '); + } + } + write!( + f, + "{}{}", + gutter, + " ".repeat( + if arrow { 1 } else { 3 } + max_gutter.saturating_sub(gutter.chars().count()) + ) + )?; + Ok(()) + } + + fn render_highlight_gutter( + &self, + f: &mut impl fmt::Write, + max_gutter: usize, + line: &Line, + highlights: &[FancySpan], + render_mode: LabelRenderMode, + ) -> fmt::Result { + if max_gutter == 0 { + return Ok(()); + } + + // keeps track of how many columns wide the gutter is + // important for ansi since simply measuring the size of the final string + // gives the wrong result when the string contains ansi codes. + let mut gutter_cols = 0; + + let chars = &self.theme.characters; + let mut gutter = String::new(); + let applicable = highlights.iter().filter(|hl| line.span_applies_gutter(hl)); + for (i, hl) in applicable.enumerate() { + if !line.span_line_only(hl) && line.span_ends(hl) { + if render_mode == LabelRenderMode::MultiLineRest { + // this is to make multiline labels work. We want to make the right amount + // of horizontal space for them, but not actually draw the lines + let horizontal_space = max_gutter.saturating_sub(i) + 2; + for _ in 0..horizontal_space { + gutter.push(' '); + } + // account for one more horizontal space, since in multiline mode + // we also add in the vertical line before the label like this: + // 2 │ ╭─▶ text + // 3 │ ├─▶ here + // · ╰──┤ these two lines + // · │ are the problem + // ^this + gutter_cols += horizontal_space + 1; + } else { + let num_repeat = max_gutter.saturating_sub(i) + 2; + + gutter.push_str(&chars.lbot.style(hl.style).to_string()); + + gutter.push_str( + &chars + .hbar + .to_string() + .repeat( + num_repeat + // if we are rendering a multiline label, then leave a bit of space for the + // rcross character + - if render_mode == LabelRenderMode::MultiLineFirst { + 1 + } else { + 0 + }, + ) + .style(hl.style) + .to_string(), + ); + + // we count 1 for the lbot char, and then a few more, the same number + // as we just repeated for. For each repeat we only add 1, even though + // due to ansi escape codes the number of bytes in the string could grow + // a lot each time. + gutter_cols += num_repeat + 1; + } + break; + } else { + gutter.push_str(&chars.vbar.style(hl.style).to_string()); + + // we may push many bytes for the ansi escape codes style adds, + // but we still only add a single character-width to the string in a terminal + gutter_cols += 1; + } + } + + // now calculate how many spaces to add based on how many columns we just + // created. it's the max width of the gutter, minus how many + // character-widths we just generated capped at 0 (though this should + // never go below in reality), and then we add 3 to account for + // arrowheads when a gutter line ends + let num_spaces = (max_gutter + 3).saturating_sub(gutter_cols); + // we then write the gutter and as many spaces as we need + write!(f, "{}{:width$}", gutter, "", width = num_spaces)?; + Ok(()) + } + + /// Returns an iterator over the visual width of each character in a line. + fn line_visual_char_width<'a>(&self, text: &'a str) -> impl Iterator + 'a { + let mut column = 0; + let mut escaped = false; + let tab_width = self.tab_width; + text.chars().map(move |c| { + let width = match (escaped, c) { + // Round up to the next multiple of tab_width + (false, '\t') => tab_width - column % tab_width, + // start of ANSI escape + (false, '\x1b') => { + escaped = true; + 0 + } + // use Unicode width for all other characters + (false, c) => c.width().unwrap_or(0), + // end of ANSI escape + (true, 'm') => { + escaped = false; + 0 + } + // characters are zero width within escape sequence + (true, _) => 0, + }; + column += width; + width + }) + } + + /// Returns the visual column position of a byte offset on a specific line. + /// + /// If the offset occurs in the middle of a character, the returned column + /// corresponds to that character's first column in `start` is true, or its + /// last column if `start` is false. + fn visual_offset(&self, line: &Line, offset: usize, start: bool) -> usize { + let line_range = line.offset..=(line.offset + line.length); + assert!(line_range.contains(&offset)); + + let mut text_index = offset - line.offset; + while text_index <= line.text.len() && !line.text.is_char_boundary(text_index) { + if start { + text_index -= 1; + } else { + text_index += 1; + } + } + let text = &line.text[..text_index.min(line.text.len())]; + let text_width = self.line_visual_char_width(text).sum(); + if text_index > line.text.len() { + // Spans extending past the end of the line are always rendered as + // one column past the end of the visible line. + // + // This doesn't necessarily correspond to a specific byte-offset, + // since a span extending past the end of the line could contain: + // - an actual \n character (1 byte) + // - a CRLF (2 bytes) + // - EOF (0 bytes) + text_width + 1 + } else { + text_width + } + } + + /// Renders a line to the output formatter, replacing tabs with spaces. + fn render_line_text(&self, f: &mut impl fmt::Write, text: &str) -> fmt::Result { + for (c, width) in text.chars().zip(self.line_visual_char_width(text)) { + if c == '\t' { + for _ in 0..width { + f.write_char(' ')?; + } + } else { + f.write_char(c)?; + } + } + f.write_char('\n')?; + Ok(()) + } + + fn render_single_line_highlights( + &self, + f: &mut impl fmt::Write, + line: &Line, + max_gutter: usize, + single_liners: &[&FancySpan], + all_highlights: &[FancySpan], + ) -> fmt::Result { + let mut underlines = String::new(); + let mut highest = 0; + + let chars = &self.theme.characters; + let vbar_offsets: Vec<_> = single_liners + .iter() + .map(|hl| { + let byte_start = hl.offset(); + let byte_end = hl.offset() + hl.len(); + let start = self.visual_offset(line, byte_start, true).max(highest); + let end = if hl.len() == 0 { + start + 1 + } else { + self.visual_offset(line, byte_end, false).max(start + 1) + }; + + let vbar_offset = (start + end) / 2; + let num_left = vbar_offset - start; + let num_right = end - vbar_offset - 1; + underlines.push_str( + &format!( + "{:width$}{}{}{}", + "", + chars.underline.to_string().repeat(num_left), + if hl.len() == 0 { + chars.uarrow + } else if hl.label().is_some() { + chars.underbar + } else { + chars.underline + }, + chars.underline.to_string().repeat(num_right), + width = start.saturating_sub(highest), + ) + .style(hl.style) + .to_string(), + ); + highest = std::cmp::max(highest, end); + + (hl, vbar_offset) + }) + .collect(); + writeln!(f, "{underlines}")?; + + for hl in single_liners.iter().rev() { + if let Some(label) = hl.label_parts() { + if label.len() == 1 { + self.write_label_text( + f, + line, + max_gutter, + all_highlights, + chars, + &vbar_offsets, + hl, + &label[0], + LabelRenderMode::SingleLine, + )?; + } else { + let mut first = true; + for label_line in &label { + self.write_label_text( + f, + line, + max_gutter, + all_highlights, + chars, + &vbar_offsets, + hl, + label_line, + if first { + LabelRenderMode::MultiLineFirst + } else { + LabelRenderMode::MultiLineRest + }, + )?; + first = false; + } + } + } + } + Ok(()) + } + + // I know it's not good practice, but making this a function makes a lot of + // sense and making a struct for this does not... + #[allow(clippy::too_many_arguments)] + fn write_label_text( + &self, + f: &mut impl fmt::Write, + line: &Line, + max_gutter: usize, + all_highlights: &[FancySpan], + chars: &ThemeCharacters, + vbar_offsets: &[(&&FancySpan, usize)], + hl: &&FancySpan, + label: &str, + render_mode: LabelRenderMode, + ) -> fmt::Result { + self.render_highlight_gutter( + f, + max_gutter, + line, + all_highlights, + LabelRenderMode::SingleLine, + )?; + let mut curr_offset = 1usize; + for (offset_hl, vbar_offset) in vbar_offsets { + while curr_offset < *vbar_offset + 1 { + write!(f, " ")?; + curr_offset += 1; + } + if *offset_hl != hl { + write!(f, "{}", chars.vbar.to_string().style(offset_hl.style))?; + curr_offset += 1; + } else { + let lines = match render_mode { + LabelRenderMode::SingleLine => format!( + "{}{} {}", + chars.lbot, + chars.hbar.to_string().repeat(2), + label, + ), + LabelRenderMode::MultiLineFirst => { + format!("{}{}{} {}", chars.lbot, chars.hbar, chars.rcross, label,) + } + LabelRenderMode::MultiLineRest => { + format!(" {} {}", chars.vbar, label,) + } + }; + writeln!(f, "{}", lines.style(hl.style))?; + break; + } + } + Ok(()) + } + + fn render_multi_line_end_single( + &self, + f: &mut impl fmt::Write, + label: &str, + style: Style, + render_mode: LabelRenderMode, + ) -> fmt::Result { + match render_mode { + LabelRenderMode::SingleLine => { + writeln!(f, "{} {}", self.theme.characters.hbar.style(style), label)?; + } + LabelRenderMode::MultiLineFirst => { + writeln!(f, "{} {}", self.theme.characters.rcross.style(style), label)?; + } + LabelRenderMode::MultiLineRest => { + writeln!(f, "{} {}", self.theme.characters.vbar.style(style), label)?; + } + } + + Ok(()) + } + + fn get_lines<'a>( + &'a self, + source: &'a dyn SourceCode, + context_span: &'a SourceSpan, + ) -> Result, fmt::Error> { + let context_data = source + .read_span(context_span, self.context_lines, self.context_lines) + .map_err(|_| fmt::Error)?; + let context = String::from_utf8_lossy(context_data.data()); + let mut column = context_data.column(); + let mut offset = context_data.span().offset(); + let mut line_offset = offset; + let mut line_str = String::with_capacity(context.len()); + let mut lines = Vec::with_capacity(1); + let mut iter = context.chars().peekable(); + while let Some(ch) = iter.next() { + offset += ch.len_utf8(); + match ch { + '\r' if iter.next_if_eq(&'\n').is_some() => { + offset += 1; + column = 0; + } + '\r' => { + line_str.push(ch); + column += 1; + } + '\n' => { + column = 0; + } + _ => { + line_str.push(ch); + column += 1; + } + } + + if column == 0 || iter.peek().is_none() { + lines.push(Line { + offset: line_offset, + length: offset - line_offset, + text: line_str.clone(), + }); + line_str.clear(); + line_offset = offset; + } + } + Ok(lines) + } +} + +impl ReportHandler for SwcReportHandler { + fn debug(&self, diagnostic: &dyn Diagnostic, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.alternate() { + return fmt::Debug::fmt(diagnostic, f); + } + + self.render_report(f, diagnostic) + } +} + +/* +Support types +*/ + +#[derive(PartialEq, Debug)] +enum LabelRenderMode { + /// we're rendering a single line label (or not rendering in any special + /// way) + SingleLine, + /// we're rendering a multiline label + MultiLineFirst, + /// we're rendering the rest of a multiline label + MultiLineRest, +} + +#[derive(Debug)] +struct Line { + offset: usize, + length: usize, + text: String, +} + +impl Line { + fn span_line_only(&self, span: &FancySpan) -> bool { + span.offset() >= self.offset && span.offset() + span.len() <= self.offset + self.length + } + + /// Returns whether `span` should be visible on this line, either in the + /// gutter or under the text on this line + fn span_applies(&self, span: &FancySpan) -> bool { + let spanlen = if span.len() == 0 { 1 } else { span.len() }; + // Span starts in this line + + (span.offset() >= self.offset && span.offset() < self.offset + self.length) + // Span passes through this line + || (span.offset() < self.offset && span.offset() + spanlen > self.offset + self.length) //todo + // Span ends on this line + || (span.offset() + spanlen > self.offset && span.offset() + spanlen <= self.offset + self.length) + } + + /// Returns whether `span` should be visible on this line in the gutter (so + /// this excludes spans that are only visible on this line and do not + /// span multiple lines) + fn span_applies_gutter(&self, span: &FancySpan) -> bool { + let spanlen = if span.len() == 0 { 1 } else { span.len() }; + // Span starts in this line + self.span_applies(span) + && !( + // as long as it doesn't start *and* end on this line + (span.offset() >= self.offset && span.offset() < self.offset + self.length) + && (span.offset() + spanlen > self.offset + && span.offset() + spanlen <= self.offset + self.length) + ) + } + + // A 'flyby' is a multi-line span that technically covers this line, but + // does not begin or end within the line itself. This method is used to + // calculate gutters. + fn span_flyby(&self, span: &FancySpan) -> bool { + // The span itself starts before this line's starting offset (so, in a + // prev line). + span.offset() < self.offset + // ...and it stops after this line's end. + && span.offset() + span.len() > self.offset + self.length + } + + // Does this line contain the *beginning* of this multiline span? + // This assumes self.span_applies() is true already. + fn span_starts(&self, span: &FancySpan) -> bool { + span.offset() >= self.offset + } + + // Does this line contain the *end* of this multiline span? + // This assumes self.span_applies() is true already. + fn span_ends(&self, span: &FancySpan) -> bool { + span.offset() + span.len() >= self.offset + && span.offset() + span.len() <= self.offset + self.length + } +} + +#[derive(Debug, Clone)] +struct FancySpan { + /// this is deliberately an option of a vec because I wanted to be very + /// explicit that there can also be *no* label. If there is a label, it + /// can have multiple lines which is what the vec is for. + label: Option>, + span: SourceSpan, + style: Style, +} + +impl PartialEq for FancySpan { + fn eq(&self, other: &Self) -> bool { + self.label == other.label && self.span == other.span + } +} + +fn split_label(v: String) -> Vec { + v.split('\n').map(|i| i.to_string()).collect() +} + +impl FancySpan { + fn new(label: Option, span: SourceSpan, style: Style) -> Self { + FancySpan { + label: label.map(split_label), + span, + style, + } + } + + fn style(&self) -> Style { + self.style + } + + fn label(&self) -> Option { + self.label + .as_ref() + .map(|l| l.join("\n").style(self.style()).to_string()) + } + + fn label_parts(&self) -> Option> { + self.label.as_ref().map(|l| { + l.iter() + .map(|i| i.style(self.style()).to_string()) + .collect() + }) + } + + fn offset(&self) -> usize { + self.span.offset() + } + + fn len(&self) -> usize { + self.span.len() + } +} diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/src/lib.rs b/deps/swc/bindings/binding_nodejs_support_wasm/src/lib.rs new file mode 100644 index 000000000..e971058ac --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/src/lib.rs @@ -0,0 +1,308 @@ +use std::{ + iter::once, + mem::take, + sync::{Arc, Mutex}, +}; + +use anyhow::Error; +use error_reporter::SwcReportHandler; +use js_sys::Uint8Array; +use miette::{GraphicalTheme, LabeledSpan, ThemeCharacters, ThemeStyles}; +use serde::Serialize; +use swc_common::{ + errors::{DiagnosticBuilder, DiagnosticId, Emitter, Handler, HANDLER}, + sync::Lrc, + SourceMap, Span, GLOBALS, +}; +use swc_error_reporters::{convert_span, to_pretty_source_code}; +use swc_ts_fast_strip::{Options, TransformOutput}; +use wasm_bindgen::prelude::*; +use wasm_bindgen_futures::{future_to_promise, js_sys::Promise}; + +mod error_reporter; +mod nodejs; + +/// Custom interface definitions for `@swc/nodejs-support-wasm`. +#[wasm_bindgen(typescript_custom_section)] +const INTERFACE_DEFINITIONS: &'static str = r#" +export declare function transform(src: string | Uint8Array, opts?: Options): Promise; +export declare function transformSync(src: string | Uint8Array, opts?: Options): TransformOutput; +export declare function transformModuleSyntax(src: string | Uint8Array): ModuleSyntaxTransformOutput; +export declare function getFirstExpression(src: string | Uint8Array, startColumn: number): string; +export declare function isValidSyntax(src: string | Uint8Array): boolean; +export declare function isRecoverableError(src: string | Uint8Array): boolean; +export type { Options, TransformOutput }; + +export interface ModuleSyntaxTransformOutput { + code: string; + hadModuleSyntax: boolean; +} +"#; + +#[wasm_bindgen(skip_typescript)] +pub fn transform(input: JsValue, options: JsValue) -> Promise { + future_to_promise(async move { transform_sync(input, options) }) +} + +#[wasm_bindgen(js_name = "transformSync", skip_typescript)] +pub fn transform_sync(input: JsValue, options: JsValue) -> Result { + let options: Options = if options.is_falsy() { + Default::default() + } else { + serde_wasm_bindgen::from_value(options)? + }; + + let input = coerce_input(input)?; + + let result = GLOBALS.set(&Default::default(), || operate(input, options)); + + match result { + Ok(v) => Ok(serde_wasm_bindgen::to_value(&v)?), + Err(errors) => Err(serde_wasm_bindgen::to_value(&errors[0])?), + } +} + +#[wasm_bindgen(js_name = "transformModuleSyntax", skip_typescript)] +pub fn transform_module_syntax(input: JsValue) -> Result { + let input = coerce_input(input)?; + let output = nodejs::transform_module_syntax(input); + + Ok(serde_wasm_bindgen::to_value(&output)?) +} + +#[wasm_bindgen(js_name = "getFirstExpression", skip_typescript)] +pub fn get_first_expression(input: JsValue, start_column: u32) -> Result { + let input = coerce_input(input)?; + + Ok(nodejs::get_first_expression(input, start_column)) +} + +#[wasm_bindgen(js_name = "isValidSyntax", skip_typescript)] +pub fn is_valid_syntax(input: JsValue) -> Result { + let input = coerce_input(input)?; + + Ok(nodejs::is_valid_syntax(input)) +} + +#[wasm_bindgen(js_name = "isRecoverableError", skip_typescript)] +pub fn is_recoverable_error(input: JsValue) -> Result { + let input = coerce_input(input)?; + + Ok(nodejs::is_recoverable_error(input)) +} + +fn coerce_input(input: JsValue) -> Result { + match input.as_string() { + Some(input) => Ok(input), + None => { + if input.is_instance_of::() { + let input = input.unchecked_into::(); + + String::from_utf8(input.to_vec()) + .map_err(|_| JsValue::from_str("Input Uint8Array is not valid utf-8")) + } else { + Err(JsValue::from_str("Input is not a string or Uint8Array")) + } + } + } +} + +fn operate(input: String, options: Options) -> Result> { + let cm = Lrc::new(SourceMap::default()); + + try_with_json_handler(cm.clone(), |handler| { + swc_ts_fast_strip::operate(&cm, handler, input, options).map_err(anyhow::Error::new) + }) +} + +#[derive(Clone)] +struct JsonErrorWriter { + errors: Arc>>, + /// Successful transforms never need the graphical diagnostic reporter. + reporter: Option, + cm: Lrc, +} + +fn try_with_json_handler(cm: Lrc, op: F) -> Result> +where + F: FnOnce(&Handler) -> Result, +{ + let wr = JsonErrorWriter { + errors: Default::default(), + reporter: None, + cm, + }; + let emitter: Box = Box::new(wr.clone()); + + let handler = Handler::with_emitter(true, false, emitter); + + let ret = HANDLER.set(&handler, || op(&handler)); + + if handler.has_errors() { + let mut lock = wr.errors.lock().unwrap(); + let error = take(&mut *lock); + + Err(error) + } else { + Ok(ret.expect("it should not fail without emitting errors to handler")) + } +} + +impl Emitter for JsonErrorWriter { + fn emit(&mut self, db: &mut DiagnosticBuilder) { + let d = &**db; + + let snippet = d.span.primary_span().and_then(|span| { + let mut snippet = String::new(); + let reporter = self.reporter.get_or_insert_with(json_reporter); + match reporter.render_report( + &mut snippet, + &Snippet { + source_code: &to_pretty_source_code(&self.cm, true), + span, + }, + ) { + Ok(()) => Some(snippet), + Err(_) => None, + } + }); + + let children = d + .children + .iter() + .map(|d| todo!("json subdiagnostic: {d:?}")) + .collect::>(); + + let error_code = match &d.code { + Some(DiagnosticId::Error(s)) => Some(&**s), + Some(DiagnosticId::Lint(s)) => Some(&**s), + None => None, + }; + + let start = d + .span + .primary_span() + .and_then(|span| self.cm.try_lookup_char_pos(span.lo()).ok()); + + let end = d + .span + .primary_span() + .and_then(|span| self.cm.try_lookup_char_pos(span.hi()).ok()); + + let filename = start.as_ref().map(|loc| loc.file.name.to_string()); + + let error = JsonDiagnostic { + code: error_code.map(|s| s.to_string()), + message: d.message[0].0.to_string(), + snippet, + filename, + start_line: start.as_ref().map(|loc| loc.line), + start_column: start.as_ref().map(|loc| loc.col_display), + end_line: end.as_ref().map(|loc| loc.line), + end_column: end.as_ref().map(|loc| loc.col_display), + children, + }; + + self.errors.lock().unwrap().push(error); + } + + fn take_diagnostics(&mut self) -> Vec { + Default::default() + } +} + +fn json_reporter() -> SwcReportHandler { + SwcReportHandler::default().with_theme(GraphicalTheme { + characters: ThemeCharacters { + hbar: ' ', + vbar: ' ', + xbar: ' ', + vbar_break: ' ', + ltop: ' ', + rtop: ' ', + mtop: ' ', + lbot: ' ', + rbot: ' ', + mbot: ' ', + error: "".into(), + warning: "".into(), + advice: "".into(), + ..ThemeCharacters::ascii() + }, + styles: ThemeStyles::none(), + }) +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct JsonDiagnostic { + /// Error code + #[serde(skip_serializing_if = "Option::is_none")] + code: Option, + message: String, + + #[serde(skip_serializing_if = "Option::is_none")] + snippet: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + filename: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + start_line: Option, + #[serde(skip_serializing_if = "Option::is_none")] + start_column: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + end_line: Option, + #[serde(skip_serializing_if = "Option::is_none")] + end_column: Option, + + #[serde(skip_serializing_if = "Vec::is_empty")] + children: Vec, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct JsonSubdiagnostic { + message: String, + #[serde(skip_serializing_if = "Option::is_none")] + snippet: Option, + filename: String, + line: usize, +} + +struct Snippet<'a> { + source_code: &'a dyn miette::SourceCode, + span: Span, +} + +impl miette::Diagnostic for Snippet<'_> { + fn source_code(&self) -> Option<&dyn miette::SourceCode> { + if self.span.lo().is_dummy() || self.span.hi().is_dummy() { + return None; + } + + Some(self.source_code) + } + + fn labels(&self) -> Option + '_>> { + Some(Box::new(once(LabeledSpan::new_with_span( + None, + convert_span(self.span), + )))) + } +} + +impl std::error::Error for Snippet<'_> {} + +impl std::fmt::Display for Snippet<'_> { + fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Ok(()) + } +} + +impl std::fmt::Debug for Snippet<'_> { + fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Ok(()) + } +} diff --git a/deps/swc/bindings/binding_nodejs_support_wasm/src/nodejs.rs b/deps/swc/bindings/binding_nodejs_support_wasm/src/nodejs.rs new file mode 100644 index 000000000..cef6bf21e --- /dev/null +++ b/deps/swc/bindings/binding_nodejs_support_wasm/src/nodejs.rs @@ -0,0 +1,1749 @@ +//! Node.js-specific helpers for `@swc/nodejs-support-wasm`. +//! +//! These functions intentionally expose only the compact operations Node needs +//! from Rust and avoid serializing SWC ASTs into JavaScript. + +use serde::Serialize; +use swc_common::{comments::SingleThreadedComments, sync::Lrc, FileName, SourceMap, Span, Spanned}; +use swc_ecma_ast::{ + ArrowExpr, AssignExpr, AssignTarget, AssignTargetPat, BindingIdent, BlockStmt, BlockStmtOrExpr, + CallExpr, Callee, CatchClause, Class, ClassDecl, Decl, DefaultDecl, EsVersion, ExportSpecifier, + Expr, FnDecl, Function, ImportDecl, ImportSpecifier, MetaPropExpr, MetaPropKind, Module, + ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectLit, ObjectPatProp, Pat, Prop, + SimpleAssignTarget, Stmt, UpdateExpr, VarDecl, VarDeclKind, +}; +use swc_ecma_parser::{ + error::{Error as ParseError, SyntaxError}, + lexer::Lexer, + unstable::{Token, TokenAndSpan}, + EsSyntax, Parser, StringInput, Syntax, TsSyntax, +}; +use swc_ecma_visit::{Visit, VisitWith}; + +const DYNAMIC_IMPORT_NAME: &str = "__nodeREPLDynamicImport"; + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ModuleSyntaxTransformOutput { + pub code: String, + pub had_module_syntax: bool, +} + +/// Rewrites Node REPL module syntax into script syntax. +/// +/// The transform follows Node's edit-list approach: static imports become +/// awaited dynamic imports, dynamic `import(...)` is routed through Node's REPL +/// helper, and exports are unwrapped or dropped depending on whether they have +/// runtime declarations. +pub fn transform_module_syntax(code: String) -> ModuleSyntaxTransformOutput { + if !code.contains("import") && !code.contains("export") { + return ModuleSyntaxTransformOutput { + code, + had_module_syntax: false, + }; + } + + let Some(module) = parse_module(&code) else { + return ModuleSyntaxTransformOutput { + code, + had_module_syntax: false, + }; + }; + + let (edits, hoisted) = { + let mut transform = ModuleSyntaxTransform::new(&code); + + for item in &module.body { + transform.collect_module_item_edit(item); + } + + let replaced_ranges = transform + .edits + .iter() + .map(|edit| (edit.start, edit.end)) + .collect::>(); + module.visit_with(&mut ModuleFeatureCollector { + code: &code, + edits: &mut transform.edits, + replaced_ranges: &replaced_ranges, + }); + module.visit_with(&mut ImportBindingReferenceCollector { + code: &code, + edits: &mut transform.edits, + replaced_ranges: &replaced_ranges, + bindings: &transform.import_bindings, + scopes: vec![Vec::new()], + }); + + if transform.edits.is_empty() && transform.hoisted.is_empty() { + return ModuleSyntaxTransformOutput { + code, + had_module_syntax: false, + }; + } + + (transform.edits, transform.hoisted) + }; + + ModuleSyntaxTransformOutput { + code: prepend_hoisted_imports(apply_edits(code, edits), hoisted), + had_module_syntax: true, + } +} + +/// Extracts the first source expression associated with a V8 error column. +/// +/// `start_column` is interpreted as a JavaScript UTF-16 code-unit column to +/// match Node/V8 source locations. The implementation uses only lexer tokens +/// because the source line can be incomplete JavaScript. +pub fn get_first_expression(code: String, start_column: u32) -> String { + let start_byte = utf16_column_to_byte_pos(&code, start_column); + let mut last_token = None; + let mut potential_expression_start_token = None; + let mut first_member_access_name_token = None; + let mut pending_optional_chain_name_token = None; + let mut terminating_byte = None; + let mut paren_level = 0u32; + let mut member_bracket_depth = 0u32; + + for token in tokenize(&code) { + if token.token == Token::Eof { + break; + } + + let Some((token_start, token_end)) = span_range(token.span) else { + continue; + }; + if token_start < start_byte { + if token.token == Token::Semi { + potential_expression_start_token = None; + first_member_access_name_token = None; + pending_optional_chain_name_token = None; + member_bracket_depth = 0; + last_token = None; + continue; + } + + if member_bracket_depth > 0 { + match token.token { + Token::LBracket => member_bracket_depth += 1, + Token::RBracket => { + member_bracket_depth = member_bracket_depth.saturating_sub(1); + } + _ => {} + } + last_token = Some(token); + continue; + } + + if is_member_identifier_token(&code, &token) + && first_member_access_name_token.is_none() + && potential_expression_start_token.is_none() + { + potential_expression_start_token = Some(token); + } + + if token.token == Token::QuestionMark + && last_token + .as_ref() + .is_some_and(|last: &TokenAndSpan| is_member_identifier_token(&code, last)) + { + pending_optional_chain_name_token = last_token; + last_token = Some(token); + continue; + } + + if token.token == Token::Dot + && last_token + .as_ref() + .is_some_and(|last: &TokenAndSpan| last.token == Token::QuestionMark) + { + if let Some(name_token) = pending_optional_chain_name_token.take() { + first_member_access_name_token.get_or_insert(name_token); + last_token = Some(token); + continue; + } + } else if pending_optional_chain_name_token.take().is_some() { + first_member_access_name_token = None; + } + + if token.token == Token::LBracket + && last_token + .as_ref() + .is_some_and(|last: &TokenAndSpan| is_member_identifier_token(&code, last)) + { + first_member_access_name_token + .get_or_insert(potential_expression_start_token.unwrap_or(last_token.unwrap())); + member_bracket_depth = 1; + last_token = Some(token); + continue; + } + + if is_member_access_token(token.token) { + if last_token + .as_ref() + .is_some_and(|last: &TokenAndSpan| is_member_identifier_token(&code, last)) + { + first_member_access_name_token.get_or_insert( + potential_expression_start_token.unwrap_or(last_token.unwrap()), + ); + last_token = Some(token); + continue; + } + } else if token.token != Token::LParen && !is_member_name_token(&code, &token) { + potential_expression_start_token = None; + first_member_access_name_token = None; + } + + if token.token == Token::LParen && first_member_access_name_token.is_some() { + paren_level += 1; + last_token = Some(token); + continue; + } + + if token.token == Token::LParen + && last_token + .as_ref() + .is_some_and(|last: &TokenAndSpan| is_member_identifier_token(&code, last)) + { + first_member_access_name_token + .get_or_insert(potential_expression_start_token.unwrap_or(last_token.unwrap())); + paren_level += 1; + last_token = Some(token); + continue; + } + + last_token = Some(token); + continue; + } + + if token.token == Token::LParen + && last_token + .as_ref() + .is_some_and(|last: &TokenAndSpan| is_member_identifier_token(&code, last)) + { + first_member_access_name_token + .get_or_insert(potential_expression_start_token.unwrap_or(last_token.unwrap())); + } + + match token.token { + Token::LParen => { + paren_level += 1; + } + Token::RParen => { + paren_level = paren_level.saturating_sub(1); + if paren_level == 0 { + terminating_byte = Some(token_end); + break; + } + } + Token::Semi => { + terminating_byte = Some(token_start); + break; + } + _ => {} + } + } + + let start = first_member_access_name_token + .and_then(|token| span_range(token.span).map(|(start, _)| start)) + .unwrap_or(start_byte); + let end = terminating_byte.unwrap_or(code.len()); + + if start >= code.len() + || start > end + || !code.is_char_boundary(start) + || !code.is_char_boundary(end) + { + return String::new(); + } + + code[start..end].to_string() +} + +/// Returns true when the source parses as a program or expression. +pub fn is_valid_syntax(code: String) -> bool { + parses_as_program(&code) || parses_as_program(&format!("_={code}")) +} + +/// Returns true for parser errors that should keep a Node REPL input open. +pub fn is_recoverable_error(code: String) -> bool { + match parse_program_result(&code) { + ParseOutcome::Valid => false, + ParseOutcome::Invalid(errors) => { + if errors + .iter() + .any(|error| is_recoverable_parse_error(&code, error)) + { + return true; + } + + code.trim_start().starts_with('{') && is_recoverable_error(format!("({code}")) + } + } +} + +struct ModuleSyntaxTransform<'a> { + code: &'a str, + edits: Vec, + hoisted: Vec, + import_bindings: Vec, + import_namespace_count: u32, +} + +impl<'a> ModuleSyntaxTransform<'a> { + fn new(code: &'a str) -> Self { + Self { + code, + edits: Vec::new(), + hoisted: Vec::new(), + import_bindings: Vec::new(), + import_namespace_count: 0, + } + } + + fn collect_module_item_edit(&mut self, item: &ModuleItem) { + let ModuleItem::ModuleDecl(decl) = item else { + return; + }; + + match decl { + ModuleDecl::Import(import) => { + self.delete_span(import.span); + if !import.type_only { + if let Some(script) = self.import_decl_to_script(import) { + self.hoisted.push(script); + } + } + } + ModuleDecl::ExportDecl(export) => { + if is_type_only_decl(&export.decl) { + self.delete_span(export.span); + } else if let (Some((start, _)), Some((decl_start, _))) = + (span_range(export.span), span_range(export.decl.span())) + { + push_range_edit(&mut self.edits, self.code, start, decl_start, String::new()); + } + } + ModuleDecl::ExportNamed(export) => { + self.delete_span(export.span); + if let Some(src) = &export.src { + if let Some(required_exports) = named_export_source_imports(export) { + self.hoist_validated_import( + &src.value.to_string_lossy(), + export.with.as_deref(), + &required_exports, + ); + } + } + } + ModuleDecl::ExportDefaultDecl(export) => { + self.unwrap_default_declaration(export.span, export.decl.span(), &export.decl); + } + ModuleDecl::ExportDefaultExpr(export) => { + self.unwrap_default_expression( + export.span, + export.expr.span(), + matches!(&*export.expr, Expr::Object(..)), + ); + } + ModuleDecl::ExportAll(export) => { + self.delete_span(export.span); + if !export.type_only { + self.hoist_import(&export.src.value.to_string_lossy(), export.with.as_deref()); + } + } + ModuleDecl::TsImportEquals(import) => { + if import.is_type_only { + self.delete_span(import.span); + } + } + ModuleDecl::TsNamespaceExport(export) => { + self.delete_span(export.span); + } + ModuleDecl::TsExportAssignment(..) => {} + } + } + + fn delete_span(&mut self, span: Span) { + let replacement = if needs_statement_separator(self.code, span) { + ";" + } else { + "" + }; + self.replace_span(span, replacement.to_string()); + } + + fn replace_span(&mut self, span: Span, text: String) { + push_span_edit(&mut self.edits, self.code, span, text); + } + + fn hoist_import(&mut self, specifier: &str, with: Option<&ObjectLit>) { + self.hoisted.push(format!( + "await {};", + await_import(self.code, specifier, with, &[]) + )); + } + + fn hoist_validated_import( + &mut self, + specifier: &str, + with: Option<&ObjectLit>, + required_exports: &[String], + ) { + self.hoisted.push(format!( + "await {};", + await_import(self.code, specifier, with, required_exports) + )); + } + + fn import_decl_to_script(&mut self, node: &ImportDecl) -> Option { + let specifier = node.src.value.to_string_lossy(); + let with = node.with.as_deref(); + + if node.specifiers.is_empty() { + return Some(format!( + "await {};", + await_import(self.code, &specifier, with, &[]) + )); + } + + let mut namespace_name = None; + let mut default_name = None; + let mut named = Vec::new(); + let mut required_exports = Vec::new(); + + for specifier in &node.specifiers { + match specifier { + ImportSpecifier::Namespace(specifier) => { + namespace_name = Some(specifier.local.sym.to_string()); + } + ImportSpecifier::Default(specifier) => { + default_name = Some(specifier.local.sym.to_string()); + push_required_export(&mut required_exports, "default".to_string()); + } + ImportSpecifier::Named(specifier) => { + if specifier.is_type_only { + continue; + } + + let local = specifier.local.sym.to_string(); + let imported = specifier + .imported + .as_ref() + .map(module_export_name) + .unwrap_or_else(|| local.clone()); + push_required_export(&mut required_exports, imported.clone()); + named.push((local, imported)); + } + } + } + + if namespace_name.is_none() && default_name.is_none() && named.is_empty() { + return None; + } + + let namespace_name = namespace_name.unwrap_or_else(|| self.fresh_import_namespace_name()); + let out = format!( + "const {namespace_name} = await {};", + await_import(self.code, &specifier, with, &required_exports) + ); + + if let Some(default_name) = default_name { + self.import_bindings.push(ImportBinding { + local: default_name, + namespace: namespace_name.clone(), + export_name: "default".to_string(), + }); + } + + for (local, export_name) in named { + self.import_bindings.push(ImportBinding { + local, + namespace: namespace_name.clone(), + export_name, + }); + } + + Some(out) + } + + fn fresh_import_namespace_name(&mut self) -> String { + loop { + let candidate = format!("__nodeREPLImport{}", self.import_namespace_count); + self.import_namespace_count += 1; + + if !self.code.contains(&candidate) { + return candidate; + } + } + } + + fn unwrap_default_declaration( + &mut self, + export_span: Span, + decl_span: Span, + decl: &DefaultDecl, + ) { + if matches!(decl, DefaultDecl::TsInterfaceDecl(..)) { + self.delete_span(export_span); + return; + } + + let (Some((export_start, _)), Some((decl_start, decl_end))) = + (span_range(export_span), span_range(decl_span)) + else { + return; + }; + + push_range_edit( + &mut self.edits, + self.code, + export_start, + decl_start, + String::new(), + ); + + if default_declaration_needs_parentheses(decl) { + push_range_edit( + &mut self.edits, + self.code, + decl_start, + decl_start, + "(".to_string(), + ); + push_range_edit( + &mut self.edits, + self.code, + decl_end, + decl_end, + ");".to_string(), + ); + } + } + + fn unwrap_default_expression( + &mut self, + export_span: Span, + expr_span: Span, + needs_parentheses: bool, + ) { + let (Some((export_start, export_end)), Some((expr_start, expr_end))) = + (span_range(export_span), span_range(expr_span)) + else { + return; + }; + + push_range_edit( + &mut self.edits, + self.code, + export_start, + expr_start, + String::new(), + ); + + if needs_parentheses { + push_range_edit( + &mut self.edits, + self.code, + expr_start, + expr_start, + "(".to_string(), + ); + } + + let has_separator = self + .code + .get(expr_end..export_end) + .is_some_and(|tail| tail.contains(';')); + if needs_parentheses || !has_separator { + let mut suffix = String::new(); + if needs_parentheses { + suffix.push(')'); + } + if !has_separator { + suffix.push(';'); + } + push_range_edit(&mut self.edits, self.code, expr_end, expr_end, suffix); + } + } +} + +fn await_import( + code: &str, + specifier: &str, + with: Option<&ObjectLit>, + required_exports: &[String], +) -> String { + let mut out = format!("{DYNAMIC_IMPORT_NAME}({}", json_string(specifier)); + if let Some(options) = import_options_to_dynamic_options(code, with) { + out.push_str(", "); + out.push_str(&options); + } + out.push(')'); + if !required_exports.is_empty() { + out.push_str(".then((m) => { "); + for export_name in required_exports { + out.push_str("if (!("); + out.push_str(&json_string(export_name)); + out.push_str(" in m)) throw new SyntaxError("); + out.push_str(&json_string(&format!( + "The requested module '{specifier}' does not provide an export named \ + '{export_name}'" + ))); + out.push_str("); "); + } + out.push_str("return m; })"); + } + out +} + +fn import_options_to_dynamic_options(code: &str, with: Option<&ObjectLit>) -> Option { + let attributes = slice_span(code, with?.span)?; + Some(format!("{{ with: {attributes} }}")) +} + +fn default_declaration_needs_parentheses(decl: &DefaultDecl) -> bool { + matches!(decl, DefaultDecl::Class(class) if class.ident.is_none()) + || matches!(decl, DefaultDecl::Fn(function) if function.ident.is_none()) +} + +fn is_type_only_decl(decl: &Decl) -> bool { + matches!(decl, Decl::TsInterface(..) | Decl::TsTypeAlias(..)) +} + +fn named_export_source_imports(export: &NamedExport) -> Option> { + if export.type_only { + return None; + } + + let mut loads_source = export.specifiers.is_empty(); + let mut required_exports = Vec::new(); + + for specifier in &export.specifiers { + match specifier { + ExportSpecifier::Named(named) => { + if named.is_type_only { + continue; + } + + loads_source = true; + push_required_export(&mut required_exports, module_export_name(&named.orig)); + } + ExportSpecifier::Default(..) => { + loads_source = true; + push_required_export(&mut required_exports, "default".to_string()); + } + ExportSpecifier::Namespace(..) => { + loads_source = true; + } + } + } + + loads_source.then_some(required_exports) +} + +fn push_required_export(required_exports: &mut Vec, export_name: String) { + if !required_exports + .iter() + .any(|required| required == &export_name) + { + required_exports.push(export_name); + } +} + +fn module_export_name(name: &ModuleExportName) -> String { + match name { + ModuleExportName::Ident(ident) => ident.sym.to_string(), + ModuleExportName::Str(string) => string.value.to_string_lossy().into_owned(), + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +struct Edit { + start: usize, + end: usize, + text: String, +} + +#[derive(Debug)] +struct ImportBinding { + local: String, + namespace: String, + export_name: String, +} + +fn push_span_edit(edits: &mut Vec, code: &str, span: Span, text: String) { + if let Some((start, end)) = span_range(span) { + push_range_edit(edits, code, start, end, text); + } +} + +fn push_range_edit(edits: &mut Vec, code: &str, start: usize, end: usize, text: String) { + if start <= end && end <= code.len() { + edits.push(Edit { start, end, text }); + } +} + +fn apply_edits(mut code: String, mut edits: Vec) -> String { + edits.sort_by(|a, b| b.start.cmp(&a.start).then_with(|| b.end.cmp(&a.end))); + + for edit in edits { + if edit.start <= edit.end + && edit.end <= code.len() + && code.is_char_boundary(edit.start) + && code.is_char_boundary(edit.end) + { + code.replace_range(edit.start..edit.end, &edit.text); + } + } + + code +} + +fn needs_statement_separator(code: &str, span: Span) -> bool { + let Some((start, end)) = span_range(span) else { + return false; + }; + + code[..start].chars().any(|ch| !ch.is_whitespace()) + && code[end..].chars().any(|ch| !ch.is_whitespace()) +} + +fn prepend_hoisted_imports(code: String, hoisted: Vec) -> String { + if hoisted.is_empty() { + return code; + } + + let imports = hoisted.join("\n"); + if code.starts_with("#!") { + if let Some(line_end) = code.find('\n') { + let insert_at = line_end + 1; + let (hashbang, rest) = code.split_at(insert_at); + if rest.is_empty() || rest.starts_with('\n') { + format!("{hashbang}{imports}{rest}") + } else { + format!("{hashbang}{imports}\n{rest}") + } + } else { + format!("{code}\n{imports}") + } + } else if code.is_empty() { + imports + } else if code.starts_with('\n') || code.starts_with("\r\n") { + format!("{imports}{code}") + } else { + format!("{imports}\n{code}") + } +} + +struct ModuleFeatureCollector<'a, 'b> { + code: &'a str, + edits: &'b mut Vec, + replaced_ranges: &'b [(usize, usize)], +} + +impl Visit for ModuleFeatureCollector<'_, '_> { + fn visit_call_expr(&mut self, node: &CallExpr) { + if matches!(node.callee, Callee::Import(..)) { + if let Some((start, end)) = span_range(node.span) { + if !range_is_replaced(self.replaced_ranges, start, end) { + let original = &self.code[start..end]; + if original.starts_with("import") { + self.edits.push(Edit { + start, + end: start + "import".len(), + text: DYNAMIC_IMPORT_NAME.to_string(), + }); + } + } + } + } + + node.visit_children_with(self); + } + + fn visit_meta_prop_expr(&mut self, node: &MetaPropExpr) { + if node.kind == MetaPropKind::ImportMeta { + if let Some((start, end)) = span_range(node.span) { + if !range_is_replaced(self.replaced_ranges, start, end) { + self.edits.push(Edit { + start, + end, + text: import_meta_error_expression(), + }); + } + } + } + } +} + +struct ImportBindingReferenceCollector<'a, 'b> { + code: &'a str, + edits: &'b mut Vec, + replaced_ranges: &'b [(usize, usize)], + bindings: &'b [ImportBinding], + scopes: Vec>, +} + +impl Visit for ImportBindingReferenceCollector<'_, '_> { + fn visit_assign_expr(&mut self, node: &AssignExpr) { + if self.import_binding_for_assign_target(&node.left).is_some() { + self.replace_expression_with_import_assignment_error(node.span); + return; + } + + node.visit_children_with(self); + } + + fn visit_update_expr(&mut self, node: &UpdateExpr) { + if let Expr::Ident(ident) = &*node.arg { + if self.binding_for_unshadowed(ident.sym.as_ref()).is_some() { + self.replace_expression_with_import_assignment_error(node.span); + return; + } + } + + node.visit_children_with(self); + } + + fn visit_function(&mut self, node: &Function) { + let shadowed = function_scope_shadowed_bindings(node, self.bindings); + self.with_scope(shadowed, |this| node.visit_children_with(this)); + } + + fn visit_arrow_expr(&mut self, node: &ArrowExpr) { + let shadowed = arrow_scope_shadowed_bindings(node, self.bindings); + self.with_scope(shadowed, |this| node.visit_children_with(this)); + } + + fn visit_block_stmt(&mut self, node: &BlockStmt) { + let shadowed = direct_block_shadowed_bindings(node, self.bindings); + self.with_scope(shadowed, |this| node.visit_children_with(this)); + } + + fn visit_catch_clause(&mut self, node: &CatchClause) { + let mut shadowed = Vec::new(); + if let Some(param) = &node.param { + collect_shadowed_pat_bindings(&mut shadowed, param, self.bindings); + } + + self.with_scope(shadowed, |this| node.visit_children_with(this)); + } + + fn visit_expr(&mut self, node: &Expr) { + if let Expr::Ident(ident) = node { + self.replace_identifier(ident.span, ident.sym.as_ref()); + return; + } + + node.visit_children_with(self); + } + + fn visit_prop(&mut self, node: &Prop) { + if let Prop::Shorthand(ident) = node { + if let Some(binding) = self.binding_for_unshadowed(ident.sym.as_ref()) { + if let Some((start, end)) = span_range(ident.span) { + if !range_is_replaced(self.replaced_ranges, start, end) { + let access = import_binding_access(binding); + self.edits.push(Edit { + start, + end, + text: format!("{}: {access}", ident.sym), + }); + } + } + } + return; + } + + node.visit_children_with(self); + } +} + +impl ImportBindingReferenceCollector<'_, '_> { + fn replace_identifier(&mut self, span: Span, local: &str) { + let Some(binding) = self.binding_for_unshadowed(local) else { + return; + }; + + let Some((start, end)) = span_range(span) else { + return; + }; + + if range_is_replaced(self.replaced_ranges, start, end) { + return; + } + + if !self.code.get(start..end).is_some_and(|text| text == local) { + return; + } + + self.edits.push(Edit { + start, + end, + text: import_binding_access(binding), + }); + } + + fn binding_for(&self, local: &str) -> Option<&ImportBinding> { + self.bindings.iter().find(|binding| binding.local == local) + } + + fn binding_for_unshadowed(&self, local: &str) -> Option<&ImportBinding> { + if self.is_shadowed(local) { + return None; + } + + self.binding_for(local) + } + + fn import_binding_for_assign_target(&self, target: &AssignTarget) -> Option<&ImportBinding> { + match target { + AssignTarget::Simple(SimpleAssignTarget::Ident(ident)) => { + self.binding_for_unshadowed(ident.id.sym.as_ref()) + } + AssignTarget::Pat(pat) => self.import_binding_for_assign_target_pat(pat), + _ => None, + } + } + + fn import_binding_for_assign_target_pat( + &self, + target: &AssignTargetPat, + ) -> Option<&ImportBinding> { + match target { + AssignTargetPat::Array(array) => array + .elems + .iter() + .flatten() + .find_map(|pat| self.import_binding_for_pat(pat)), + AssignTargetPat::Object(object) => object.props.iter().find_map(|prop| match prop { + ObjectPatProp::KeyValue(prop) => self.import_binding_for_pat(&prop.value), + ObjectPatProp::Assign(prop) => { + self.binding_for_unshadowed(prop.key.id.sym.as_ref()) + } + ObjectPatProp::Rest(prop) => self.import_binding_for_pat(&prop.arg), + }), + AssignTargetPat::Invalid(..) => None, + } + } + + fn import_binding_for_pat(&self, pat: &Pat) -> Option<&ImportBinding> { + match pat { + Pat::Ident(ident) => self.binding_for_unshadowed(ident.id.sym.as_ref()), + Pat::Array(array) => array + .elems + .iter() + .flatten() + .find_map(|pat| self.import_binding_for_pat(pat)), + Pat::Rest(rest) => self.import_binding_for_pat(&rest.arg), + Pat::Object(object) => object.props.iter().find_map(|prop| match prop { + ObjectPatProp::KeyValue(prop) => self.import_binding_for_pat(&prop.value), + ObjectPatProp::Assign(prop) => { + self.binding_for_unshadowed(prop.key.id.sym.as_ref()) + } + ObjectPatProp::Rest(prop) => self.import_binding_for_pat(&prop.arg), + }), + Pat::Assign(assign) => self.import_binding_for_pat(&assign.left), + Pat::Invalid(..) | Pat::Expr(..) => None, + } + } + + fn replace_expression_with_import_assignment_error(&mut self, span: Span) { + let Some((start, end)) = span_range(span) else { + return; + }; + + if range_is_replaced(self.replaced_ranges, start, end) { + return; + } + + self.edits.push(Edit { + start, + end, + text: import_assignment_error_expression(), + }); + } + + fn with_scope(&mut self, shadowed: Vec, op: impl FnOnce(&mut Self)) { + self.scopes.push(shadowed); + op(self); + self.scopes.pop(); + } + + fn is_shadowed(&self, local: &str) -> bool { + self.scopes + .iter() + .rev() + .any(|scope| scope.iter().any(|name| name == local)) + } +} + +fn function_scope_shadowed_bindings(node: &Function, bindings: &[ImportBinding]) -> Vec { + let mut shadowed = Vec::new(); + for param in &node.params { + collect_shadowed_pat_bindings(&mut shadowed, ¶m.pat, bindings); + } + if let Some(body) = &node.body { + collect_function_var_shadowed_bindings(&mut shadowed, body, bindings); + } + shadowed +} + +fn arrow_scope_shadowed_bindings(node: &ArrowExpr, bindings: &[ImportBinding]) -> Vec { + let mut shadowed = Vec::new(); + for param in &node.params { + collect_shadowed_pat_bindings(&mut shadowed, param, bindings); + } + if let BlockStmtOrExpr::BlockStmt(body) = &*node.body { + collect_function_var_shadowed_bindings(&mut shadowed, body, bindings); + } + shadowed +} + +fn collect_function_var_shadowed_bindings( + out: &mut Vec, + body: &BlockStmt, + bindings: &[ImportBinding], +) { + let mut collector = FunctionScopedVarCollector { + bindings, + shadowed: out, + }; + body.visit_with(&mut collector); +} + +struct FunctionScopedVarCollector<'a, 'b> { + bindings: &'a [ImportBinding], + shadowed: &'b mut Vec, +} + +impl Visit for FunctionScopedVarCollector<'_, '_> { + fn visit_var_decl(&mut self, node: &VarDecl) { + if node.kind == VarDeclKind::Var { + collect_shadowed_var_decl_bindings(self.shadowed, node, self.bindings); + } + } + + fn visit_function(&mut self, _: &Function) {} + + fn visit_arrow_expr(&mut self, _: &ArrowExpr) {} + + fn visit_class(&mut self, _: &Class) {} +} + +fn direct_block_shadowed_bindings(node: &BlockStmt, bindings: &[ImportBinding]) -> Vec { + let mut shadowed = Vec::new(); + + for stmt in &node.stmts { + if let Stmt::Decl(decl) = stmt { + collect_shadowed_decl_bindings(&mut shadowed, decl, bindings); + } + } + + shadowed +} + +fn collect_shadowed_decl_bindings(out: &mut Vec, decl: &Decl, bindings: &[ImportBinding]) { + match decl { + Decl::Class(ClassDecl { ident, .. }) | Decl::Fn(FnDecl { ident, .. }) => { + push_shadowed_ident_binding(out, ident.sym.as_ref(), bindings); + } + Decl::Var(var) => { + collect_shadowed_var_decl_bindings(out, var, bindings); + } + Decl::Using(using) => { + for declarator in &using.decls { + collect_shadowed_pat_bindings(out, &declarator.name, bindings); + } + } + Decl::TsInterface(..) | Decl::TsTypeAlias(..) | Decl::TsEnum(..) | Decl::TsModule(..) => {} + } +} + +fn collect_shadowed_var_decl_bindings( + out: &mut Vec, + decl: &VarDecl, + bindings: &[ImportBinding], +) { + for declarator in &decl.decls { + collect_shadowed_pat_bindings(out, &declarator.name, bindings); + } +} + +fn collect_shadowed_pat_bindings(out: &mut Vec, pat: &Pat, bindings: &[ImportBinding]) { + match pat { + Pat::Ident(ident) => push_shadowed_binding_ident(out, ident, bindings), + Pat::Array(array) => { + for elem in array.elems.iter().flatten() { + collect_shadowed_pat_bindings(out, elem, bindings); + } + } + Pat::Rest(rest) => collect_shadowed_pat_bindings(out, &rest.arg, bindings), + Pat::Object(object) => { + for prop in &object.props { + match prop { + ObjectPatProp::KeyValue(prop) => { + collect_shadowed_pat_bindings(out, &prop.value, bindings); + } + ObjectPatProp::Assign(prop) => { + push_shadowed_binding_ident(out, &prop.key, bindings); + } + ObjectPatProp::Rest(prop) => { + collect_shadowed_pat_bindings(out, &prop.arg, bindings); + } + } + } + } + Pat::Assign(assign) => collect_shadowed_pat_bindings(out, &assign.left, bindings), + Pat::Invalid(..) | Pat::Expr(..) => {} + } +} + +fn push_shadowed_binding_ident( + out: &mut Vec, + ident: &BindingIdent, + bindings: &[ImportBinding], +) { + push_shadowed_ident_binding(out, ident.id.sym.as_ref(), bindings); +} + +fn push_shadowed_ident_binding(out: &mut Vec, local: &str, bindings: &[ImportBinding]) { + if bindings.iter().any(|binding| binding.local == local) + && !out.iter().any(|name| name == local) + { + out.push(local.to_string()); + } +} + +fn range_is_replaced(replaced_ranges: &[(usize, usize)], start: usize, end: usize) -> bool { + replaced_ranges + .iter() + .any(|(replace_start, replace_end)| start >= *replace_start && end <= *replace_end) +} + +fn import_binding_access(binding: &ImportBinding) -> String { + format!( + "{}{}", + binding.namespace, + export_property_access(&binding.export_name) + ) +} + +fn export_property_access(export_name: &str) -> String { + if is_identifier_name(export_name) { + format!(".{export_name}") + } else { + format!("[{}]", json_string(export_name)) + } +} + +fn import_meta_error_expression() -> String { + "(() => { throw new SyntaxError(\"Cannot use import.meta outside a module\"); })()".to_string() +} + +fn import_assignment_error_expression() -> String { + "(() => { throw new TypeError(\"Assignment to constant variable.\"); })()".to_string() +} + +fn is_identifier_name(value: &str) -> bool { + let mut chars = value.chars(); + let Some(first) = chars.next() else { + return false; + }; + + if !(first == '_' || first == '$' || first.is_ascii_alphabetic()) { + return false; + } + + chars.all(|ch| ch == '_' || ch == '$' || ch.is_ascii_alphanumeric()) +} + +enum ParseOutcome { + Valid, + Invalid(Vec), +} + +fn parse_program_result(code: &str) -> ParseOutcome { + let es = parse_program_result_with_syntax(code, Syntax::Es(es_syntax())); + if matches!(es, ParseOutcome::Valid) { + return es; + } + + parse_program_result_with_syntax(code, Syntax::Typescript(ts_syntax())) +} + +fn parse_program_result_with_syntax(code: &str, syntax: Syntax) -> ParseOutcome { + let cm = Lrc::new(SourceMap::default()); + let fm = cm.new_source_file(FileName::Anon.into(), code.to_string()); + let comments = SingleThreadedComments::default(); + let lexer = Lexer::new( + syntax, + EsVersion::latest(), + StringInput::from(&*fm), + Some(&comments), + ); + let mut parser = Parser::new_from(lexer); + + match parser.parse_program() { + Ok(..) => { + let errors = parser.take_errors(); + if errors.is_empty() { + ParseOutcome::Valid + } else { + ParseOutcome::Invalid(errors) + } + } + Err(error) => { + let mut errors = vec![error]; + errors.extend(parser.take_errors()); + ParseOutcome::Invalid(errors) + } + } +} + +fn parse_module(code: &str) -> Option { + parse_module_with_syntax(code, Syntax::Es(es_syntax())) + .or_else(|| parse_module_with_syntax(code, Syntax::Typescript(ts_syntax()))) +} + +fn parse_module_with_syntax(code: &str, syntax: Syntax) -> Option { + let cm = Lrc::new(SourceMap::default()); + let fm = cm.new_source_file(FileName::Anon.into(), code.to_string()); + let comments = SingleThreadedComments::default(); + let lexer = Lexer::new( + syntax, + EsVersion::latest(), + StringInput::from(&*fm), + Some(&comments), + ); + let mut parser = Parser::new_from(lexer); + let module = parser.parse_module().ok()?; + + if parser.take_errors().is_empty() { + Some(module) + } else { + None + } +} + +fn parses_as_program(code: &str) -> bool { + matches!(parse_program_result(code), ParseOutcome::Valid) +} + +fn tokenize(code: &str) -> Vec { + let cm = Lrc::new(SourceMap::default()); + let fm = cm.new_source_file(FileName::Anon.into(), code.to_string()); + let comments = SingleThreadedComments::default(); + Lexer::new( + Syntax::Es(es_syntax()), + EsVersion::latest(), + StringInput::from(&*fm), + Some(&comments), + ) + .collect() +} + +fn es_syntax() -> EsSyntax { + EsSyntax { + auto_accessors: true, + explicit_resource_management: true, + import_attributes: true, + ..Default::default() + } +} + +fn ts_syntax() -> TsSyntax { + TsSyntax { + decorators: true, + ..Default::default() + } +} + +fn is_recoverable_parse_error(code: &str, error: &ParseError) -> bool { + match error.kind() { + SyntaxError::Eof | SyntaxError::UnterminatedTpl | SyntaxError::UnterminatedBlockComment => { + true + } + SyntaxError::UnterminatedStrLit => has_trailing_line_continuation(code), + SyntaxError::Expected(_, got) => got == "", + _ => false, + } +} + +fn has_trailing_line_continuation(code: &str) -> bool { + code.ends_with("\\\n") + || code.ends_with("\\\r") + || code.ends_with("\\\r\n") + || code.ends_with("\\\u{2028}") + || code.ends_with("\\\u{2029}") +} + +fn is_member_access_token(token: Token) -> bool { + matches!( + token, + Token::Dot | Token::OptionalChain | Token::LBracket | Token::RBracket + ) +} + +fn is_member_name_token(code: &str, token: &TokenAndSpan) -> bool { + matches!(token.token, Token::Ident | Token::Str | Token::Num) + || token.token.is_known_ident() + || token_text_is_identifier(code, token) +} + +fn is_member_identifier_token(code: &str, token: &TokenAndSpan) -> bool { + token.token == Token::Ident + || token.token.is_known_ident() + || token_text_is_identifier(code, token) +} + +fn token_text_is_identifier(code: &str, token: &TokenAndSpan) -> bool { + slice_span(code, token.span).is_some_and(is_identifier_name) +} + +fn slice_span(code: &str, span: Span) -> Option<&str> { + let (start, end) = span_range(span)?; + code.get(start..end) +} + +fn span_range(span: Span) -> Option<(usize, usize)> { + if span.lo.is_dummy() || span.hi.is_dummy() { + return None; + } + + let start = span.lo.0.checked_sub(1)? as usize; + let end = span.hi.0.checked_sub(1)? as usize; + Some((start, end)) +} + +fn utf16_column_to_byte_pos(code: &str, column: u32) -> usize { + let mut utf16_pos = 0u32; + + for (byte_pos, ch) in code.char_indices() { + if utf16_pos >= column { + return byte_pos; + } + + utf16_pos += ch.len_utf16() as u32; + if utf16_pos > column { + return byte_pos; + } + } + + code.len() +} + +fn json_string(value: &str) -> String { + serde_json::to_string(value).expect("serializing a string should not fail") +} + +#[cfg(test)] +mod tests { + use super::*; + + fn validated_import(specifier: &str, required_exports: &[&str]) -> String { + validated_import_with_options(specifier, None, required_exports) + } + + fn validated_import_with_options( + specifier: &str, + options: Option<&str>, + required_exports: &[&str], + ) -> String { + let mut out = format!("{DYNAMIC_IMPORT_NAME}({}", json_string(specifier)); + if let Some(options) = options { + out.push_str(", "); + out.push_str(options); + } + out.push(')'); + + if !required_exports.is_empty() { + out.push_str(".then((m) => { "); + for export_name in required_exports { + out.push_str("if (!("); + out.push_str(&json_string(export_name)); + out.push_str(" in m)) throw new SyntaxError("); + out.push_str(&json_string(&format!( + "The requested module '{specifier}' does not provide an export named \ + '{export_name}'" + ))); + out.push_str("); "); + } + out.push_str("return m; })"); + } + + out + } + + #[test] + fn transform_import_forms() { + assert_eq!( + transform_module_syntax("import \"node:fs\";".into()).code, + "await __nodeREPLDynamicImport(\"node:fs\");" + ); + assert_eq!( + transform_module_syntax("import fs from \"node:fs\";".into()).code, + format!( + "const __nodeREPLImport0 = await {};", + validated_import("node:fs", &["default"]) + ) + ); + assert_eq!( + transform_module_syntax("import { readFile as rf } from \"node:fs\";".into()).code, + format!( + "const __nodeREPLImport0 = await {};", + validated_import("node:fs", &["readFile"]) + ) + ); + assert_eq!( + transform_module_syntax("import { readFile as rf } from \"node:fs\";\nrf();".into()) + .code, + format!( + "const __nodeREPLImport0 = await {};\n__nodeREPLImport0.readFile();", + validated_import("node:fs", &["readFile"]) + ) + ); + assert_eq!( + transform_module_syntax("import def, * as ns from \"mod\";".into()).code, + format!( + "const ns = await {};", + validated_import("mod", &["default"]) + ) + ); + assert_eq!( + transform_module_syntax("import def, * as ns from \"mod\";\ndef; ns;".into()).code, + format!( + "const ns = await {};\nns.default; ns;", + validated_import("mod", &["default"]) + ) + ); + assert_eq!( + transform_module_syntax("import { \"a-b\" as c } from \"mod\";".into()).code, + format!( + "const __nodeREPLImport0 = await {};", + validated_import("mod", &["a-b"]) + ) + ); + assert_eq!( + transform_module_syntax("import { \"a-b\" as c } from \"mod\";\nc;".into()).code, + format!( + "const __nodeREPLImport0 = await {};\n__nodeREPLImport0[\"a-b\"];", + validated_import("mod", &["a-b"]) + ) + ); + assert_eq!( + transform_module_syntax( + "import data from \"./data.json\" with { type: \"json\" };".into() + ) + .code, + format!( + "const __nodeREPLImport0 = await {};", + validated_import_with_options( + "./data.json", + Some("{ with: { type: \"json\" } }"), + &["default"] + ) + ) + ); + assert_eq!( + transform_module_syntax("console.log(typeof fs);\nimport fs from \"node:fs\";".into()) + .code, + format!( + "const __nodeREPLImport0 = await {};\nconsole.log(typeof \ + __nodeREPLImport0.default);\n", + validated_import("node:fs", &["default"]) + ) + ); + } + + #[test] + fn transform_export_forms() { + assert_eq!( + transform_module_syntax("export const x = 1;".into()).code, + "const x = 1;" + ); + assert_eq!( + transform_module_syntax("export default value;".into()).code, + "value;" + ); + assert_eq!( + transform_module_syntax("export default foo; doSomething();".into()).code, + "foo; doSomething();" + ); + assert_eq!( + transform_module_syntax("export default { ...config };".into()).code, + "({ ...config });" + ); + assert_eq!( + transform_module_syntax("export default function () {}".into()).code, + "(function () {});" + ); + assert_eq!( + transform_module_syntax( + "export default function f() { return import(\"node:fs\"); }".into() + ) + .code, + "function f() { return __nodeREPLDynamicImport(\"node:fs\"); }" + ); + assert_eq!( + transform_module_syntax( + "export default function () { return import(\"node:fs\"); }".into() + ) + .code, + "(function () { return __nodeREPLDynamicImport(\"node:fs\"); });" + ); + assert_eq!( + transform_module_syntax("export default class {}".into()).code, + "(class {});" + ); + assert_eq!(transform_module_syntax("export { x };".into()).code, ""); + assert_eq!( + transform_module_syntax("export * from \"mod\";".into()).code, + "await __nodeREPLDynamicImport(\"mod\");" + ); + assert_eq!( + transform_module_syntax("console.log(1);\nexport { value } from \"mod\";".into()).code, + format!( + "await {};\nconsole.log(1);\n", + validated_import("mod", &["value"]) + ) + ); + } + + #[test] + fn transform_preserves_missing_export_failures() { + let missing_default = transform_module_syntax("import missing from \"mod\";".into()); + assert!(missing_default.code.contains("\"default\" in m")); + assert!(missing_default.code.contains("export named 'default'")); + + let missing_named = transform_module_syntax("import { missing, ok } from \"mod\";".into()); + assert!(missing_named.code.contains("\"missing\" in m")); + assert!(missing_named.code.contains("\"ok\" in m")); + + let re_export = transform_module_syntax("export { missing } from \"mod\";".into()); + assert!(re_export.code.contains("\"missing\" in m")); + } + + #[test] + fn transform_preserves_import_binding_semantics() { + assert_eq!( + transform_module_syntax("import { spec } from \"m\";\nimport(spec);".into()).code, + format!( + "const __nodeREPLImport0 = await \ + {};\n__nodeREPLDynamicImport(__nodeREPLImport0.spec);", + validated_import("m", &["spec"]) + ) + ); + + assert_eq!( + transform_module_syntax( + "import { x } from \"m\";\nfunction f(x) { return x; }\nx;".into() + ) + .code, + format!( + "const __nodeREPLImport0 = await {};\nfunction f(x) {{ return x; \ + }}\n__nodeREPLImport0.x;", + validated_import("m", &["x"]) + ) + ); + + assert_eq!( + transform_module_syntax("import { x } from \"m\";\n{ const x = 1; x; }\nx;".into()) + .code, + format!( + "const __nodeREPLImport0 = await {};\n{{ const x = 1; x; }}\n__nodeREPLImport0.x;", + validated_import("m", &["x"]) + ) + ); + + assert_eq!( + transform_module_syntax("import { x } from \"m\";\ntry {} catch (x) { x; }\nx;".into()) + .code, + format!( + "const __nodeREPLImport0 = await {};\ntry {{}} catch (x) {{ x; \ + }}\n__nodeREPLImport0.x;", + validated_import("m", &["x"]) + ) + ); + + assert_eq!( + transform_module_syntax( + "import { x } from \"m\";\nfunction f(){ if (ok) { var x = 1; } return x; }\nx;" + .into() + ) + .code, + format!( + "const __nodeREPLImport0 = await {};\nfunction f(){{ if (ok) {{ var x = 1; }} \ + return x; }}\n__nodeREPLImport0.x;", + validated_import("m", &["x"]) + ) + ); + + assert_eq!( + transform_module_syntax("import { readFile } from \"node:fs\";\nreadFile = 1;".into()) + .code, + format!( + "const __nodeREPLImport0 = await {};\n(() => {{ throw new TypeError(\"Assignment \ + to constant variable.\"); }})();", + validated_import("node:fs", &["readFile"]) + ) + ); + + assert_eq!( + transform_module_syntax( + "import { readFile } from \"node:fs\";\n({ readFile } = obj);".into() + ) + .code, + format!( + "const __nodeREPLImport0 = await {};\n((() => {{ throw new TypeError(\"Assignment \ + to constant variable.\"); }})());", + validated_import("node:fs", &["readFile"]) + ) + ); + + assert_eq!( + transform_module_syntax("import { readFile } from \"node:fs\";\nreadFile++;".into()) + .code, + format!( + "const __nodeREPLImport0 = await {};\n(() => {{ throw new TypeError(\"Assignment \ + to constant variable.\"); }})();", + validated_import("node:fs", &["readFile"]) + ) + ); + } + + #[test] + fn transform_dynamic_import_and_noops() { + assert_eq!( + transform_module_syntax("const mod = import(\"node:fs\");".into()).code, + "const mod = __nodeREPLDynamicImport(\"node:fs\");" + ); + + let no_module_syntax = transform_module_syntax("const importName = \"import\";".into()); + assert!(!no_module_syntax.had_module_syntax); + assert_eq!(no_module_syntax.code, "const importName = \"import\";"); + + let incomplete = transform_module_syntax("import {".into()); + assert!(!incomplete.had_module_syntax); + assert_eq!(incomplete.code, "import {"); + + let import_meta = transform_module_syntax("console.log(import.meta.url);".into()); + assert!(import_meta.had_module_syntax); + assert!(import_meta + .code + .contains("Cannot use import.meta outside a module")); + } + + #[test] + fn transform_preserves_statement_boundaries() { + let hashbang = transform_module_syntax( + "#!/usr/bin/env node\nimport fs from \"node:fs\";\nfs.readFile;".into(), + ) + .code; + assert!(hashbang.starts_with("#!/usr/bin/env node\nconst __nodeREPLImport0 = await ")); + assert!(hashbang.contains("\n__nodeREPLImport0.default.readFile;")); + + assert_eq!( + transform_module_syntax("foo()\nimport \"x\";\n[1].forEach(bar)".into()).code, + "await __nodeREPLDynamicImport(\"x\");\nfoo()\n;\n[1].forEach(bar)" + ); + } + + #[test] + fn transform_typescript_module_syntax() { + assert_eq!( + transform_module_syntax("import fs from \"node:fs\";\nconst x: number = 1;".into()) + .code, + format!( + "const __nodeREPLImport0 = await {};\nconst x: number = 1;", + validated_import("node:fs", &["default"]) + ) + ); + + let type_only = transform_module_syntax( + "import type { Foo } from \"types\";\nexport type { Foo };\nconst x: number = 1;" + .into(), + ); + assert!(type_only.had_module_syntax); + assert!(!type_only.code.contains("__nodeREPLDynamicImport")); + assert!(!type_only.code.contains("import type")); + assert!(!type_only.code.contains("export type")); + + let re_export_type = + transform_module_syntax("export { type Foo } from \"types\";\nconst x = 1;".into()); + assert!(!re_export_type.code.contains("__nodeREPLDynamicImport")); + assert_eq!(re_export_type.code, "\nconst x = 1;"); + + let import_equals = + transform_module_syntax("import type Foo = require(\"foo\");\nconst x = 1;".into()); + assert!(import_equals.had_module_syntax); + assert_eq!(import_equals.code, "\nconst x = 1;"); + + let namespace_export = + transform_module_syntax("export as namespace Foo;\nconst x = 1;".into()); + assert!(namespace_export.had_module_syntax); + assert_eq!(namespace_export.code, "\nconst x = 1;"); + } + + #[test] + fn first_expression_from_error_column() { + assert_eq!( + get_first_expression("assert(value)".into(), 6), + "assert(value)" + ); + assert_eq!(get_first_expression("ok(value)".into(), 3), "ok(value)"); + assert_eq!( + get_first_expression("assert.ok(value)".into(), 9), + "assert.ok(value)" + ); + assert_eq!( + get_first_expression("assert['ok'](value)".into(), 12), + "assert['ok'](value)" + ); + assert_eq!( + get_first_expression("assert[method + suffix](value)".into(), 23), + "assert[method + suffix](value)" + ); + assert_eq!( + get_first_expression("assert.deepEqual(foo(), 1)".into(), 17), + "assert.deepEqual(foo(), 1)" + ); + assert_eq!( + get_first_expression("assert?.ok(value)".into(), 10), + "assert?.ok(value)" + ); + assert_eq!( + get_first_expression("a(); assert.ok(value); b()".into(), 13), + "assert.ok(value)" + ); + assert_eq!( + get_first_expression("const 🍣 = 1; assert.ok(🍣)".into(), 23), + "assert.ok(🍣)" + ); + } + + #[test] + fn valid_syntax_checks() { + assert!(is_valid_syntax("await foo".into())); + assert!(is_valid_syntax("{ value: 1 }".into())); + assert!(is_valid_syntax("foo + bar".into())); + assert!(is_valid_syntax("const x: number = 1".into())); + assert!(!is_valid_syntax("function foo(".into())); + } + + #[test] + fn recoverable_syntax_checks() { + assert!(is_recoverable_error("function foo() {".into())); + assert!(is_recoverable_error("{".into())); + assert!(is_recoverable_error("`template".into())); + assert!(is_recoverable_error("/* comment".into())); + assert!(is_recoverable_error("\"continued\\\n".into())); + assert!(!is_recoverable_error("const x: number = 1".into())); + assert!(!is_recoverable_error("{ value: 1 }".into())); + assert!(!is_recoverable_error("{}".into())); + assert!(!is_recoverable_error("2e".into())); + assert!(!is_recoverable_error("\"unterminated".into())); + } +} diff --git a/deps/swc/bindings/binding_react_compiler_node/Cargo.toml b/deps/swc/bindings/binding_react_compiler_node/Cargo.toml index 64f37cf09..552b0fa61 100644 --- a/deps/swc/bindings/binding_react_compiler_node/Cargo.toml +++ b/deps/swc/bindings/binding_react_compiler_node/Cargo.toml @@ -20,6 +20,7 @@ backtrace = { workspace = true } napi = { workspace = true, features = ["napi3", "serde-json"] } napi-derive = { workspace = true, features = ["type-def"] } serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } tracing = { workspace = true, features = ["release_max_level_info"] } diff --git a/deps/swc/bindings/binding_react_compiler_node/src/diagnostics.rs b/deps/swc/bindings/binding_react_compiler_node/src/diagnostics.rs new file mode 100644 index 000000000..7cc1a3c18 --- /dev/null +++ b/deps/swc/bindings/binding_react_compiler_node/src/diagnostics.rs @@ -0,0 +1,281 @@ +use swc_ecma_react_compiler::diagnostics::{ + DiagnosticDetail as CoreDiagnosticDetail, DiagnosticLocation as CoreDiagnosticLocation, + DiagnosticMessage, DiagnosticPosition as CoreDiagnosticPosition, Severity, +}; + +// `#[napi]` resolves via the crate-wide `#[macro_use] extern crate +// napi_derive;` in `lib.rs` — matches the convention already used in +// `support.rs`. +#[napi(object)] +#[derive(Debug, Clone)] +pub struct Diagnostic { + pub severity: String, + pub message: String, + #[napi(js_name = "ruleId")] + pub rule_id: Option, + pub category: Option, + pub reason: Option, + pub description: Option, + pub loc: Option, + pub details: Vec, +} + +#[napi(object)] +#[derive(Debug, Clone)] +pub struct DiagnosticLocation { + pub start: DiagnosticPosition, + pub end: DiagnosticPosition, + pub filename: Option, + #[napi(js_name = "identifierName")] + pub identifier_name: Option, +} + +#[napi(object)] +#[derive(Debug, Clone)] +pub struct DiagnosticPosition { + pub line: u32, + pub column: u32, + pub index: Option, +} + +#[napi(object)] +#[derive(Debug, Clone)] +pub struct DiagnosticDetail { + pub kind: String, + pub loc: Option, + pub message: Option, +} + +/// Converts a lint result's diagnostics into their napi-facing shape. +/// +/// `source_text` is the same source that was linted — needed to convert +/// `CoreDiagnosticPosition`'s byte-based `column`/`index` into the UTF-16 +/// code-unit-based positions JS/ESLint consumers expect. See +/// [`diagnostic_position_from`] for why this conversion can't happen +/// upstream in `swc_ecma_react_compiler` itself. +pub fn diagnostic_from_message(source_text: &str, value: &DiagnosticMessage) -> Diagnostic { + Diagnostic { + severity: match value.severity { + Severity::Error => "error".to_string(), + Severity::Warning => "warning".to_string(), + }, + message: value.message.clone(), + rule_id: value.rule_id.clone(), + category: value.category.clone(), + reason: value.reason.clone(), + description: value.description.clone(), + loc: value + .loc + .as_ref() + .map(|loc| diagnostic_location_from(source_text, loc)), + details: value + .details + .iter() + .map(|detail| diagnostic_detail_from(source_text, detail)) + .collect(), + } +} + +fn diagnostic_location_from( + source_text: &str, + value: &CoreDiagnosticLocation, +) -> DiagnosticLocation { + DiagnosticLocation { + start: diagnostic_position_from(source_text, &value.start), + end: diagnostic_position_from(source_text, &value.end), + filename: value.filename.clone(), + identifier_name: value.identifier_name.clone(), + } +} + +/// Converts a byte-offset-based position into a UTF-16 code-unit-based one. +/// +/// `swc_ecma_react_compiler`'s `DiagnosticPosition` (and the upstream +/// `Position` it's built from) is deliberately byte-based: it also feeds +/// `DiagnosticMessage.span`, which `@swc/core`'s existing react-compiler +/// transform-error path turns into a real `swc_common::Span`/`BytePos` for +/// terminal error rendering — that consumer genuinely needs byte offsets. +/// This napi package's `lint`/`lintSync` are a different consumer exposing +/// positions to JS/ESLint, whose string indexing is UTF-16-based. Rather +/// than changing the shared byte-based representation (and breaking the +/// unrelated transform-error consumer for any non-ASCII source), the +/// conversion happens here, at this package's own boundary. +/// +/// For ASCII-only source text this is a no-op (byte count == UTF-16 code +/// unit count for ASCII); they diverge for any non-ASCII character +/// appearing before the position being converted. +fn diagnostic_position_from( + source_text: &str, + value: &CoreDiagnosticPosition, +) -> DiagnosticPosition { + let line_text = source_text + .split('\n') + .nth(value.line.saturating_sub(1) as usize) + .unwrap_or_default(); + let byte_column = value.column as usize; + let column = line_text + .get(..byte_column) + .unwrap_or(line_text) + .encode_utf16() + .count() as u32; + + let index = value.index.map(|byte_index| { + source_text + .get(..byte_index as usize) + .unwrap_or(source_text) + .encode_utf16() + .count() as u32 + }); + + DiagnosticPosition { + line: value.line, + column, + index, + } +} + +fn diagnostic_detail_from(source_text: &str, value: &CoreDiagnosticDetail) -> DiagnosticDetail { + DiagnosticDetail { + kind: value.kind.clone(), + loc: value + .loc + .as_ref() + .map(|loc| diagnostic_location_from(source_text, loc)), + message: value.message.clone(), + } +} + +#[cfg(test)] +mod tests { + use swc_ecma_react_compiler::diagnostics::{ + DiagnosticDetail as CoreDiagnosticDetail, DiagnosticLocation as CoreDiagnosticLocation, + DiagnosticMessage, DiagnosticPosition as CoreDiagnosticPosition, Severity, + }; + + use super::diagnostic_from_message; + + // Line 3 (1-indexed) is `👋 const value = 1;` — a 4-byte emoji followed + // by a space, so byte offsets and UTF-16 offsets diverge from column 0 + // onward on this line, and `index` (absolute, from file start) diverges + // for every position after it. + const SOURCE: &str = "line one\nline two\n👋 const value = 1;\n"; + + fn sample_message() -> DiagnosticMessage { + DiagnosticMessage { + severity: Severity::Error, + message: "[ReactCompiler] Refs: invalid ref access".into(), + span: Some((1, 2)), + rule_id: Some("refs".into()), + category: Some("Refs".into()), + reason: Some("invalid ref access".into()), + description: Some("description".into()), + // All of these are the BYTE-based values `swc_ecma_react_compiler` + // would actually produce (what `diagnostic_from_message` takes as + // input) — `value` on line 3 starts after "👋 const ", which is + // 4 (the emoji, a 4-byte UTF-8 sequence) + 1 (space) + 6 + // ("const ") = 11 bytes. Lines 1-2 ("line one"/"line two") plus + // their newlines are 8 + 1 + 8 + 1 = 18 bytes, so `value`'s + // absolute byte index is 18 + 11 = 29. + loc: Some(CoreDiagnosticLocation { + start: CoreDiagnosticPosition { + line: 3, + column: 11, + index: Some(29), + }, + end: CoreDiagnosticPosition { + line: 3, + column: 16, // 11 + "value".len() + index: Some(34), + }, + filename: Some("input.tsx".into()), + identifier_name: Some("value".into()), + }), + details: vec![CoreDiagnosticDetail { + kind: "error".into(), + loc: None, + message: Some("detail".into()), + }], + } + } + + #[test] + fn converts_diagnostic_message_to_napi_shape() { + let diagnostic = diagnostic_from_message(SOURCE, &sample_message()); + + assert_eq!(diagnostic.severity, "error"); + assert_eq!( + diagnostic.message, + "[ReactCompiler] Refs: invalid ref access" + ); + assert_eq!(diagnostic.rule_id.as_deref(), Some("refs")); + assert_eq!(diagnostic.category.as_deref(), Some("Refs")); + + let loc = diagnostic.loc.expect("expected loc"); + assert_eq!(loc.start.line, 3); + assert_eq!(loc.identifier_name.as_deref(), Some("value")); + + assert_eq!(diagnostic.details.len(), 1); + assert_eq!(diagnostic.details[0].kind, "error"); + } + + #[test] + fn converts_warning_severity() { + let mut message = sample_message(); + message.severity = Severity::Warning; + + let diagnostic = diagnostic_from_message(SOURCE, &message); + + assert_eq!(diagnostic.severity, "warning"); + } + + #[test] + fn converts_byte_offsets_to_utf16_code_units_across_non_ascii_text() { + let diagnostic = diagnostic_from_message(SOURCE, &sample_message()); + let loc = diagnostic.loc.expect("expected loc"); + + // Byte column (11) counts the 4-byte emoji as 4 bytes; UTF-16 column + // counts it as 2 code units ('👋' is outside the BMP, so it's a + // surrogate pair): "👋"(2) + " "(1) + "const "(6) = 9. + assert_eq!(loc.start.column, 9); + assert_eq!(loc.end.column, 9 + 5); // + "value".len() + + // Same divergence propagated into the absolute `index`. Lines 1-2 + // and their newlines are ASCII, so their UTF-16 length equals their + // byte length (18); only line 3's emoji prefix diverges (9 UTF-16 + // units vs. 11 bytes), giving 18 + 9 = 27 instead of the byte-based + // 29. + assert_eq!(loc.start.index, Some(18 + 9)); + assert_eq!(loc.end.index, Some(18 + 9 + 5)); + } + + #[test] + fn ascii_only_source_leaves_positions_unchanged() { + let source = "line one\nfunction App() {\n const value = 1;\n}\n"; + let message = DiagnosticMessage { + loc: Some(CoreDiagnosticLocation { + start: CoreDiagnosticPosition { + line: 3, + column: 10, + index: Some(9 + 17 + 10), + }, + end: CoreDiagnosticPosition { + line: 3, + column: 15, + index: Some(9 + 17 + 15), + }, + filename: None, + identifier_name: None, + }), + ..sample_message() + }; + + let diagnostic = diagnostic_from_message(source, &message); + let loc = diagnostic.loc.expect("expected loc"); + + // For ASCII-only source, byte offsets and UTF-16 offsets coincide. + assert_eq!(loc.start.column, 10); + assert_eq!(loc.start.index, Some(9 + 17 + 10)); + assert_eq!(loc.end.column, 15); + assert_eq!(loc.end.index, Some(9 + 17 + 15)); + } +} diff --git a/deps/swc/bindings/binding_react_compiler_node/src/lib.rs b/deps/swc/bindings/binding_react_compiler_node/src/lib.rs index 12ae4f151..11460014d 100644 --- a/deps/swc/bindings/binding_react_compiler_node/src/lib.rs +++ b/deps/swc/bindings/binding_react_compiler_node/src/lib.rs @@ -10,6 +10,8 @@ use std::{env, panic::set_hook}; use backtrace::Backtrace; +mod diagnostics; +mod lint; mod support; #[napi_derive::module_init] diff --git a/deps/swc/bindings/binding_react_compiler_node/src/lint.rs b/deps/swc/bindings/binding_react_compiler_node/src/lint.rs new file mode 100644 index 000000000..c91c4d310 --- /dev/null +++ b/deps/swc/bindings/binding_react_compiler_node/src/lint.rs @@ -0,0 +1,257 @@ +use napi::bindgen_prelude::*; +use swc_core::ecma::parser::Syntax; + +use crate::diagnostics::{diagnostic_from_message, Diagnostic}; + +/// Matches `swc_ecma_parser::Syntax`'s own `Default` impl +/// (`Es(EsSyntax::default())` — plain ECMAScript, no JSX/TSX/decorators) rather +/// than any particular consumer's build settings. This package is +/// general-purpose; it must not silently assume one caller's parser +/// configuration for everyone else. +fn default_syntax() -> Syntax { + Syntax::default() +} + +/// Pure JSON decode, no napi types involved — this is the only part of +/// syntax parsing that unit tests may call directly. A `napi::Error` has a +/// non-trivial `Drop`/`ToNapiValue` impl that references live N-API C +/// functions (`napi_throw`, `napi_create_error`, ...), which only exist once +/// this cdylib is `dlopen`'d by a running Node process. If ANY function that +/// tests call constructs a `napi::Error` anywhere in its body — even in a +/// branch that specific test never executes — the whole function's compiled +/// object code references those unresolved symbols, and a standalone +/// `cargo test` binary (never loaded by Node) fails to link. Keep this +/// function's signature free of `napi::Error`/`napi::Result` so tests can +/// call it safely. +fn decode_syntax(bytes: &[u8]) -> std::result::Result { + serde_json::from_slice(bytes) +} + +/// Thin napi-facing wrapper — not unit tested (see `decode_syntax`'s doc +/// comment), matching this crate's existing convention of only testing the +/// pure logic behind a `#[napi]` function, never the function itself (see +/// `support.rs`'s `is_react_compiler_required(_sync)`, which have no tests +/// at all). +fn parse_syntax_option(syntax: Option) -> napi::Result { + match syntax { + Some(buf) => decode_syntax(buf.as_ref()).map_err(|err| { + napi::Error::new(napi::Status::InvalidArg, format!("invalid `syntax`: {err}")) + }), + None => Ok(default_syntax()), + } +} + +fn lint_inner(code: &str, syntax: Syntax) -> Vec { + let result = swc_ecma_react_compiler::lint_source( + code, + syntax, + swc_ecma_react_compiler::default_plugin_options(), + ); + + result + .diagnostics + .iter() + .map(|d| diagnostic_from_message(code, d)) + .collect() +} + +struct LintTask { + code: String, + syntax: Syntax, +} + +#[napi] +impl Task for LintTask { + type JsValue = Vec; + type Output = Vec; + + fn compute(&mut self) -> napi::Result { + Ok(lint_inner(&self.code, self.syntax)) + } + + fn resolve(&mut self, _env: napi::Env, output: Self::Output) -> napi::Result { + Ok(output) + } +} + +#[napi] +fn lint( + code: String, + syntax: Option, + signal: Option, +) -> napi::Result> { + let syntax = parse_syntax_option(syntax)?; + + Ok(AsyncTask::with_optional_signal( + LintTask { code, syntax }, + signal, + )) +} + +#[napi] +pub fn lint_sync(code: String, syntax: Option) -> napi::Result> { + let syntax = parse_syntax_option(syntax)?; + + Ok(lint_inner(&code, syntax)) +} + +#[cfg(test)] +mod tests { + use swc_core::ecma::parser::{EsSyntax, Syntax, TsSyntax}; + + use super::{decode_syntax, default_syntax, lint_inner}; + + /// Several documented React Compiler lint rules + /// (https://react.dev/reference/eslint-plugin-react-hooks) only surface + /// on JSX-bearing source, which `default_syntax()` (plain ECMAScript, no + /// JSX) can't parse. Tests exercising those rules use this instead. + fn tsx_syntax() -> Syntax { + Syntax::Typescript(TsSyntax { + tsx: true, + decorators: true, + ..Default::default() + }) + } + + #[test] + fn reports_ref_access_error_with_default_syntax() { + let source = r#" + import { useRef } from 'react'; + + function App() { + const ref = useRef(1); + return ref.current; + } + "#; + + let diagnostics = lint_inner(source, default_syntax()); + + assert_eq!(diagnostics.len(), 1); + assert_eq!(diagnostics[0].severity, "error"); + assert_eq!(diagnostics[0].rule_id.as_deref(), Some("refs")); + assert_eq!(diagnostics[0].category.as_deref(), Some("Refs")); + } + + #[test] + fn returns_empty_for_non_react_code() { + let diagnostics = lint_inner("const x = 1;", default_syntax()); + + assert!(diagnostics.is_empty()); + } + + /// One test per documented React Compiler lint rule + /// (https://react.dev/reference/eslint-plugin-react-hooks) that a + /// hand-written source snippet can reliably trigger. Every trigger + /// condition here was verified empirically against the actual compiled + /// binary before being written as a test — not guessed. Rules not + /// covered below either require configuration this crate deliberately + /// doesn't expose (`config`, `gating`: need explicit gating directives; + /// `purity`: `validate_no_impure_functions_in_render` defaults to + /// `false` upstream) or need more investigation to find a reliable + /// trigger (`error-boundaries`, `static-components`, + /// `set-state-in-effect`, `incompatible-library`). + mod documented_rule_coverage { + use super::{lint_inner, tsx_syntax}; + + fn assert_fires(source: &str, expected_rule_id: &str) { + let diagnostics = lint_inner(source, tsx_syntax()); + + assert!( + diagnostics + .iter() + .any(|d| d.rule_id.as_deref() == Some(expected_rule_id)), + "expected a `{expected_rule_id}` diagnostic, got: {diagnostics:#?}" + ); + } + + #[test] + fn globals() { + assert_fires( + r#" + let count = 0; + function App() { + const [x] = useState(0); + count = count + 1; + return
{count}{x}
; + } + "#, + "globals", + ); + } + + #[test] + fn immutability() { + assert_fires( + r#" + function App(props) { + const [x, setX] = useState(0); + props.value = 1; + return
setX(x + 1)}>{x}
; + } + "#, + "immutability", + ); + } + + #[test] + fn use_memo() { + assert_fires( + r#" + function App() { + const value = useMemo((extra) => extra, [1]); + return
{value}
; + } + "#, + "use-memo", + ); + } + + #[test] + fn set_state_in_render() { + assert_fires( + r#" + function App() { + const [state, setState] = useState(0); + setState(state + 1); + return
{state}
; + } + "#, + "set-state-in-render", + ); + } + + #[test] + fn unsupported_syntax() { + assert_fires( + r#" + function App() { + eval('1'); + return
; + } + "#, + "unsupported-syntax", + ); + } + } + + #[test] + fn decode_syntax_decodes_ecmascript_json() { + let syntax = decode_syntax(br#"{"syntax":"ecmascript","jsx":true}"#) + .expect("valid ecmascript syntax JSON should decode"); + + assert_eq!( + syntax, + Syntax::Es(EsSyntax { + jsx: true, + ..Default::default() + }) + ); + } + + #[test] + fn decode_syntax_rejects_invalid_json() { + let result = decode_syntax(b"not json"); + + assert!(result.is_err()); + } +} diff --git a/deps/swc/bindings/binding_typescript_wasm/Cargo.toml b/deps/swc/bindings/binding_typescript_wasm/Cargo.toml index 922980b92..b5c052525 100644 --- a/deps/swc/bindings/binding_typescript_wasm/Cargo.toml +++ b/deps/swc/bindings/binding_typescript_wasm/Cargo.toml @@ -6,7 +6,7 @@ license = { workspace = true } name = "binding_typescript_wasm" publish = false repository = { workspace = true } -version = "1.15.43" +version = "1.15.47" [lib] bench = false diff --git a/deps/swc/bindings/binding_typescript_wasm/src/lib.rs b/deps/swc/bindings/binding_typescript_wasm/src/lib.rs index ffc93e641..8d0ab76c8 100644 --- a/deps/swc/bindings/binding_typescript_wasm/src/lib.rs +++ b/deps/swc/bindings/binding_typescript_wasm/src/lib.rs @@ -77,7 +77,8 @@ fn operate(input: String, options: Options) -> Result>>, - reporter: SwcReportHandler, + /// Successful transforms never need the graphical diagnostic reporter. + reporter: Option, cm: Lrc, } @@ -87,25 +88,7 @@ where { let wr = JsonErrorWriter { errors: Default::default(), - reporter: SwcReportHandler::default().with_theme(GraphicalTheme { - characters: ThemeCharacters { - hbar: ' ', - vbar: ' ', - xbar: ' ', - vbar_break: ' ', - ltop: ' ', - rtop: ' ', - mtop: ' ', - lbot: ' ', - rbot: ' ', - mbot: ' ', - error: "".into(), - warning: "".into(), - advice: "".into(), - ..ThemeCharacters::ascii() - }, - styles: ThemeStyles::none(), - }), + reporter: None, cm, }; let emitter: Box = Box::new(wr.clone()); @@ -130,7 +113,8 @@ impl Emitter for JsonErrorWriter { let snippet = d.span.primary_span().and_then(|span| { let mut snippet = String::new(); - match self.reporter.render_report( + let reporter = self.reporter.get_or_insert_with(json_reporter); + match reporter.render_report( &mut snippet, &Snippet { source_code: &to_pretty_source_code(&self.cm, true), @@ -186,6 +170,28 @@ impl Emitter for JsonErrorWriter { } } +fn json_reporter() -> SwcReportHandler { + SwcReportHandler::default().with_theme(GraphicalTheme { + characters: ThemeCharacters { + hbar: ' ', + vbar: ' ', + xbar: ' ', + vbar_break: ' ', + ltop: ' ', + rtop: ' ', + mtop: ' ', + lbot: ' ', + rbot: ' ', + mbot: ' ', + error: "".into(), + warning: "".into(), + advice: "".into(), + ..ThemeCharacters::ascii() + }, + styles: ThemeStyles::none(), + }) +} + #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct JsonDiagnostic { diff --git a/deps/swc/bindings/swc_cli/Cargo.toml b/deps/swc/bindings/swc_cli/Cargo.toml index 0447ac4eb..92b5c895a 100644 --- a/deps/swc/bindings/swc_cli/Cargo.toml +++ b/deps/swc/bindings/swc_cli/Cargo.toml @@ -6,7 +6,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_cli" repository = { workspace = true } -version = "0.116.3" +version = "0.120.2" [[bin]] bench = false @@ -20,4 +20,4 @@ plugin = ["swc_cli_impl/plugin"] [dependencies] anyhow = { workspace = true } par-core = { workspace = true, features = ["chili"] } -swc_cli_impl = { version = "71.0.0", path = "../../crates/swc_cli_impl" } +swc_cli_impl = { version = "75.0.0", path = "../../crates/swc_cli_impl" } diff --git a/deps/swc/crates/ast_node/Cargo.toml b/deps/swc/crates/ast_node/Cargo.toml index bb4d94aba..650acbe90 100644 --- a/deps/swc/crates/ast_node/Cargo.toml +++ b/deps/swc/crates/ast_node/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "ast_node" repository = { workspace = true } -version = "5.0.0" +version = "6.1.0" [lib] bench = false diff --git a/deps/swc/crates/ast_node/src/ast_node_macro.rs b/deps/swc/crates/ast_node/src/ast_node_macro.rs index 1b76b3dfa..faabde72d 100644 --- a/deps/swc/crates/ast_node/src/ast_node_macro.rs +++ b/deps/swc/crates/ast_node/src/ast_node_macro.rs @@ -7,11 +7,29 @@ use syn::{ #[derive(Clone)] pub struct Args { pub ty: Literal, + pub no_partial_eq: bool, } impl Parse for Args { fn parse(i: ParseStream<'_>) -> syn::Result { - Ok(Args { ty: i.parse()? }) + let ty = i.parse()?; + let mut no_partial_eq = false; + + if i.parse::>()?.is_some() { + let option: Ident = i.parse()?; + + if option == "no_partial_eq" { + no_partial_eq = true; + } else { + return Err(Error::new(option.span(), "unknown ast_node option")); + } + } + + if !i.is_empty() { + return Err(i.error("unexpected ast_node arguments")); + } + + Ok(Args { ty, no_partial_eq }) } } diff --git a/deps/swc/crates/ast_node/src/lib.rs b/deps/swc/crates/ast_node/src/lib.rs index 351afe17e..f2177dba0 100644 --- a/deps/swc/crates/ast_node/src/lib.rs +++ b/deps/swc/crates/ast_node/src/lib.rs @@ -5,7 +5,7 @@ extern crate proc_macro; use quote::quote; use swc_macros_common::prelude::*; -use syn::{visit_mut::VisitMut, *}; +use syn::*; mod ast_node_macro; mod encoding; @@ -151,19 +151,11 @@ pub fn ast_serde( print("ast_serde", item) } -struct AddAttr; - -impl VisitMut for AddAttr { - fn visit_field_mut(&mut self, f: &mut Field) { - f.attrs - .push(parse_quote!(#[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))])); - } -} - -/// Alias for -/// `#[derive(Spanned, Fold, Clone, Debug, PartialEq)]` for a struct and -/// `#[derive(Spanned, Fold, Clone, Debug, PartialEq, FromVariant)]` for an -/// enum. +/// Adds the standard AST node derives and serialization metadata. +/// +/// Structs derive `PartialEq` by default. Pass `no_partial_eq` after the node +/// tag when the type provides a manual implementation: +/// `#[ast_node("CustomNode", no_partial_eq)]`. #[proc_macro_attribute] pub fn ast_node( args: proc_macro::TokenStream, @@ -171,8 +163,6 @@ pub fn ast_node( ) -> proc_macro::TokenStream { let mut input: DeriveInput = parse(input).expect("failed to parse input as a DeriveInput"); - AddAttr.visit_data_mut(&mut input.data); - // we should use call_site let mut item = TokenStream::new(); match &input.data { @@ -252,27 +242,6 @@ pub fn ast_node( )] #clone #non_exhaustive - #[cfg_attr( - feature = "rkyv-impl", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) - )] - #[cfg_attr( - feature = "rkyv-impl", - rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source)) - )] - #[cfg_attr(feature = "rkyv-impl", repr(u32))] - #[cfg_attr( - feature = "rkyv-impl", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) - )] - #[cfg_attr( - feature = "rkyv-impl", - rkyv(bytecheck(bounds( - __C: rkyv::validation::ArchiveContext, - __C::Error: rkyv::rancor::Source - ))) - )] #[cfg_attr( feature = "serde-impl", serde(untagged) @@ -321,34 +290,18 @@ pub fn ast_node( .as_ref() .map(|args| ast_node_macro::expand_struct(args.clone(), input.clone())); + let partial_eq = match &args { + Some(args) if args.no_partial_eq => None, + _ => Some(quote!(PartialEq,)), + }; + item.extend(quote!( #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(::swc_common::Spanned, Clone, Debug, PartialEq)] + #[derive(::swc_common::Spanned, Clone, Debug, #partial_eq)] #[cfg_attr( feature = "serde-impl", derive(::serde::Serialize, ::serde::Deserialize) )] - #[cfg_attr( - feature = "rkyv-impl", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) - )] - #[cfg_attr( - feature = "rkyv-impl", - rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source)) - )] - #[cfg_attr( - feature = "rkyv-impl", - rkyv(bytecheck(bounds( - __C: rkyv::validation::ArchiveContext, - __C::Error: rkyv::rancor::Source - ))) - )] - #[cfg_attr(feature = "rkyv-impl", repr(C))] - #[cfg_attr( - feature = "rkyv-impl", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) - )] #serde_tag #[cfg_attr( feature = "serde-impl", diff --git a/deps/swc/crates/binding_macros/Cargo.toml b/deps/swc/crates/binding_macros/Cargo.toml index bae521da1..4ef93de75 100644 --- a/deps/swc/crates/binding_macros/Cargo.toml +++ b/deps/swc/crates/binding_macros/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "binding_macros" repository = { workspace = true } -version = "69.0.0" +version = "73.0.0" [lib] bench = false @@ -33,11 +33,11 @@ binding_wasm = [ [dependencies] # Common deps for the SWC imports -swc = { optional = true, version = "69.0.0", path = "../swc", default-features = false } -swc_common = { optional = true, version = "23.0.2", path = "../swc_common", default-features = false } -swc_ecma_ast = { optional = true, version = "25.0.0", path = "../swc_ecma_ast", default-features = false } -swc_ecma_transforms = { optional = true, version = "56.0.0", path = "../swc_ecma_transforms", default-features = false } -swc_ecma_visit = { optional = true, version = "25.0.0", path = "../swc_ecma_visit", default-features = false } +swc = { optional = true, version = "73.0.0", path = "../swc", default-features = false } +swc_common = { optional = true, version = "24.0.0", path = "../swc_common", default-features = false } +swc_ecma_ast = { optional = true, version = "27.0.0", path = "../swc_ecma_ast", default-features = false } +swc_ecma_transforms = { optional = true, version = "60.0.0", path = "../swc_ecma_transforms", default-features = false } +swc_ecma_visit = { optional = true, version = "27.0.0", path = "../swc_ecma_visit", default-features = false } # Optional deps for the wasm binding macro anyhow = { workspace = true, optional = true } diff --git a/deps/swc/crates/dbg-swc/Cargo.toml b/deps/swc/crates/dbg-swc/Cargo.toml index 98ed5e53e..8277e412c 100644 --- a/deps/swc/crates/dbg-swc/Cargo.toml +++ b/deps/swc/crates/dbg-swc/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "dbg-swc" repository = { workspace = true } -version = "57.0.0" +version = "60.0.0" [[bin]] bench = false @@ -22,22 +22,22 @@ rayon = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } sha1 = { workspace = true } -swc_common = { version = "23.0.2", features = [ +swc_common = { version = "24.0.0", features = [ "concurrent", "tty-emitter", ], path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_minifier = { version = "56.0.1", path = "../swc_ecma_minifier", features = [ +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_minifier = { version = "59.0.0", path = "../swc_ecma_minifier", features = [ "concurrent", ] } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", features = [ +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", features = [ "flow", ] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_typescript = { version = "50.0.0", path = "../swc_ecma_transforms_typescript" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } -swc_error_reporters = { version = "25.0.0", path = "../swc_error_reporters" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_typescript = { version = "53.0.0", path = "../swc_ecma_transforms_typescript" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } +swc_error_reporters = { version = "26.0.0", path = "../swc_error_reporters" } tempfile = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true, features = ["fmt", "env-filter"] } diff --git a/deps/swc/crates/hstr/Cargo.toml b/deps/swc/crates/hstr/Cargo.toml index ef9b3e381..681105de3 100644 --- a/deps/swc/crates/hstr/Cargo.toml +++ b/deps/swc/crates/hstr/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "hstr" repository = { workspace = true } -version = "3.0.6" +version = "4.0.0" [lib] bench = false @@ -14,14 +14,12 @@ bench = false [features] atom_size_128 = [] atom_size_64 = [] -rkyv = ["dep:rkyv"] serde = ["dep:serde"] [dependencies] hashbrown = { workspace = true } new_debug_unreachable = { workspace = true } once_cell = { workspace = true } -rkyv = { workspace = true, optional = true } rustc-hash = { workspace = true } serde = { workspace = true, optional = true } triomphe = { workspace = true } @@ -35,7 +33,6 @@ num_cpus = { workspace = true } par-iter = { workspace = true } rand = { workspace = true } serde_json = { workspace = true } -smartstring = { workspace = true } smol_str = { workspace = true } string_cache = { workspace = true } diff --git a/deps/swc/crates/hstr/benches/libs.rs b/deps/swc/crates/hstr/benches/libs.rs index f5ca6621c..2d781e3de 100644 --- a/deps/swc/crates/hstr/benches/libs.rs +++ b/deps/swc/crates/hstr/benches/libs.rs @@ -11,7 +11,6 @@ use criterion::{black_box, BatchSize, BenchmarkId, Criterion}; use par_iter::prelude::*; use rand::distributions::{Alphanumeric, DistString}; use rustc_hash::FxHashSet; -use smartstring::{LazyCompact, SmartString}; macro_rules! string_creation { ($group:expr, $len:expr, $setup:expr) => {{ @@ -62,16 +61,6 @@ macro_rules! string_creation { ); }); - group.bench_with_input(BenchmarkId::new("smartstring", len), &len, |b, _| { - b.iter_batched( - $setup(len), - |text| { - black_box(SmartString::::from(text)); - }, - BatchSize::SmallInput, - ); - }); - group.bench_with_input(BenchmarkId::new("smol_str", len), &len, |b, _| { b.iter_batched( $setup(len), @@ -214,17 +203,6 @@ fn bench_hash_operation(c: &mut Criterion) { BatchSize::SmallInput, ); }); - group.bench_with_input(BenchmarkId::new("smartstring", len), &len, |b, _| { - b.iter_batched( - || prepare(len, &mut SmartString::::from), - |(map, keys)| { - for key in keys { - black_box(map.contains(&key)); - } - }, - BatchSize::SmallInput, - ); - }); group.bench_with_input(BenchmarkId::new("smol_str", len), &len, |b, _| { b.iter_batched( || prepare(len, &mut smol_str::SmolStr::from), diff --git a/deps/swc/crates/hstr/src/lib.rs b/deps/swc/crates/hstr/src/lib.rs index c643dd181..1c4472729 100644 --- a/deps/swc/crates/hstr/src/lib.rs +++ b/deps/swc/crates/hstr/src/lib.rs @@ -408,39 +408,6 @@ impl Borrow for Atom { } } -/// NOT A PUBLIC API -#[cfg(feature = "rkyv")] -impl rkyv::Archive for Atom { - type Archived = rkyv::string::ArchivedString; - type Resolver = rkyv::string::StringResolver; - - #[allow(clippy::unit_arg)] - unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - rkyv::string::ArchivedString::resolve_from_str(self, pos, resolver, out) - } -} - -/// NOT A PUBLIC API -#[cfg(feature = "rkyv")] -impl rkyv::Serialize for Atom { - fn serialize(&self, serializer: &mut S) -> Result { - String::serialize(&self.to_string(), serializer) - } -} - -/// NOT A PUBLIC API -#[cfg(feature = "rkyv")] -impl rkyv::Deserialize for rkyv::string::ArchivedString -where - D: ?Sized + rkyv::Fallible, -{ - fn deserialize(&self, deserializer: &mut D) -> Result::Error> { - let s: String = self.deserialize(deserializer)?; - - Ok(Atom::new(s)) - } -} - impl Atom { /// Converts a WTF-8 encoded [Wtf8Atom] to a regular UTF-8 [Atom] without /// validation. diff --git a/deps/swc/crates/jsdoc/Cargo.toml b/deps/swc/crates/jsdoc/Cargo.toml index 6020feb31..6d6bfe0ad 100644 --- a/deps/swc/crates/jsdoc/Cargo.toml +++ b/deps/swc/crates/jsdoc/Cargo.toml @@ -7,19 +7,17 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "jsdoc" repository = { workspace = true } -version = "23.0.0" +version = "24.0.0" [lib] bench = false [features] -__rkyv = [] encoding-impl = [ "cbor4ii", "swc_atoms/encoding-impl", "swc_common/encoding-impl", ] -rkyv-impl = [] serde-impl = ["serde"] [lints.rust] @@ -30,10 +28,10 @@ cbor4ii = { workspace = true, features = ["use_std"], optional = true } nom = { workspace = true } serde = { workspace = true, features = ["derive"], optional = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } [dev-dependencies] dashmap = { workspace = true } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -testing = { version = "24.0.1", path = "../testing" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc-ast-explorer/Cargo.toml b/deps/swc/crates/swc-ast-explorer/Cargo.toml index 35ca42b8c..5de77bef9 100644 --- a/deps/swc/crates/swc-ast-explorer/Cargo.toml +++ b/deps/swc/crates/swc-ast-explorer/Cargo.toml @@ -18,10 +18,10 @@ anyhow = { workspace = true } clap = { version = "3", features = ["derive"] } owo-colors = { workspace = true } regex = { workspace = true } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_error_reporters = { version = "25.0.0", path = "../swc_error_reporters" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_error_reporters = { version = "26.0.0", path = "../swc_error_reporters" } [dev-dependencies] assert_cmd = { workspace = true } diff --git a/deps/swc/crates/swc/Cargo.toml b/deps/swc/crates/swc/Cargo.toml index d3517a76a..9a98b218f 100644 --- a/deps/swc/crates/swc/Cargo.toml +++ b/deps/swc/crates/swc/Cargo.toml @@ -9,7 +9,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc" repository = { workspace = true } -version = "69.0.0" +version = "73.0.0" [lib] bench = false @@ -87,50 +87,50 @@ tracing = { workspace = true } url = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "sourcemap", "parking_lot", ] } -swc_compiler_base = { version = "59.0.0", path = "../swc_compiler_base" } -swc_config = { version = "5.0.0", path = "../swc_config" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_ext_transforms = { version = "31.0.0", path = "../swc_ecma_ext_transforms" } -swc_ecma_lints = { version = "33.0.0", path = "../swc_ecma_lints", optional = true } -swc_ecma_loader = { version = "24.0.1", path = "../swc_ecma_loader", features = [ +swc_compiler_base = { version = "62.0.0", path = "../swc_compiler_base" } +swc_config = { version = "6.0.0", path = "../swc_config" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_ext_transforms = { version = "33.0.0", path = "../swc_ecma_ext_transforms" } +swc_ecma_lints = { version = "35.0.0", path = "../swc_ecma_lints", optional = true } +swc_ecma_loader = { version = "25.0.0", path = "../swc_ecma_loader", features = [ "cache", "node", "tsc", ] } -swc_ecma_minifier = { version = "56.0.1", path = "../swc_ecma_minifier" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_ecma_minifier = { version = "59.0.0", path = "../swc_ecma_minifier" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_preset_env = { version = "57.0.0", path = "../swc_ecma_preset_env", default-features = false, features = [ +swc_ecma_preset_env = { version = "61.0.0", path = "../swc_ecma_preset_env", default-features = false, features = [ "serde-impl", ] } -swc_ecma_react_compiler = { version = "20.0.2", path = "../swc_ecma_react_compiler", optional = true } -swc_ecma_transforms = { version = "56.0.0", path = "../swc_ecma_transforms", features = [ +swc_ecma_react_compiler = { version = "22.0.0", path = "../swc_ecma_react_compiler", optional = true } +swc_ecma_transforms = { version = "60.0.0", path = "../swc_ecma_transforms", features = [ "compat", "optimization", "proposal", "react", "typescript", ] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_compat = { version = "52.0.1", path = "../swc_ecma_transforms_compat", default-features = false } -swc_ecma_transforms_module = { version = "49.0.1", path = "../swc_ecma_transforms_module", optional = true } -swc_ecma_transforms_optimization = { version = "47.0.1", path = "../swc_ecma_transforms_optimization" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } -swc_error_reporters = { version = "25.0.0", path = "../swc_error_reporters" } -swc_node_comments = { version = "24.0.0", path = "../swc_node_comments" } -swc_plugin_backend_wasmer = { version = "13.0.0", path = "../swc_plugin_backend_wasmer", optional = true, default-features = false } -swc_plugin_proxy = { version = "26.0.0", path = "../swc_plugin_proxy", optional = true } -swc_plugin_runner = { version = "30.0.0", path = "../swc_plugin_runner", optional = true, default-features = false } -swc_transform_common = { version = "17.0.0", path = "../swc_transform_common" } -swc_typescript = { version = "30.0.1", path = "../swc_typescript", optional = true } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_compat = { version = "55.0.0", path = "../swc_ecma_transforms_compat", default-features = false } +swc_ecma_transforms_module = { version = "53.0.0", path = "../swc_ecma_transforms_module", optional = true } +swc_ecma_transforms_optimization = { version = "50.0.0", path = "../swc_ecma_transforms_optimization" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } +swc_error_reporters = { version = "26.0.0", path = "../swc_error_reporters" } +swc_node_comments = { version = "25.0.0", path = "../swc_node_comments" } +swc_plugin_backend_wasmer = { version = "15.0.0", path = "../swc_plugin_backend_wasmer", optional = true, default-features = false } +swc_plugin_proxy = { version = "28.0.0", path = "../swc_plugin_proxy", optional = true } +swc_plugin_runner = { version = "32.0.0", path = "../swc_plugin_runner", optional = true, default-features = false } +swc_transform_common = { version = "18.0.0", path = "../swc_transform_common" } +swc_typescript = { version = "32.0.0", path = "../swc_typescript", optional = true } swc_visit = { version = "2.0.1", path = "../swc_visit" } [dependencies.tokio] @@ -156,24 +156,24 @@ par-core = { workspace = true, features = ["chili"] } tempfile = { workspace = true } walkdir = { workspace = true } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast", features = [ +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast", features = [ "serde-impl", ] } -swc_ecma_lints = { version = "33.0.0", path = "../swc_ecma_lints", features = [ +swc_ecma_lints = { version = "35.0.0", path = "../swc_ecma_lints", features = [ "non_critical_lints", ] } -swc_ecma_preset_env = { version = "57.0.0", path = "../swc_ecma_preset_env", features = [ +swc_ecma_preset_env = { version = "61.0.0", path = "../swc_ecma_preset_env", features = [ "es3", ] } -swc_ecma_testing = { version = "24.0.1", path = "../swc_ecma_testing" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base", features = [ +swc_ecma_testing = { version = "25.0.0", path = "../swc_ecma_testing" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base", features = [ "inline-helpers", ] } -swc_ecma_transforms_compat = { version = "52.0.1", path = "../swc_ecma_transforms_compat", features = [ +swc_ecma_transforms_compat = { version = "55.0.0", path = "../swc_ecma_transforms_compat", features = [ "es3", ] } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } [[example]] name = "transform" diff --git a/deps/swc/crates/swc/src/builder.rs b/deps/swc/crates/swc/src/builder.rs index 0cd9866db..653661239 100644 --- a/deps/swc/crates/swc/src/builder.rs +++ b/deps/swc/crates/swc/src/builder.rs @@ -55,7 +55,7 @@ impl Pass for MinifierPass<'_> { n.visit_mut_with(&mut hygiene_with_config( swc_ecma_transforms_base::hygiene::Config { top_level_mark: self.top_level_mark, - ..Default::default() + ..swc_ecma_transforms_base::hygiene::Config::hygiene_default() }, )); diff --git a/deps/swc/crates/swc/src/config/mod.rs b/deps/swc/crates/swc/src/config/mod.rs index 7ad7a71ac..3a0a6d616 100644 --- a/deps/swc/crates/swc/src/config/mod.rs +++ b/deps/swc/crates/swc/src/config/mod.rs @@ -603,9 +603,9 @@ impl Options { Some(ModuleConfig::Es6(..)) => TsImportExportAssignConfig::EsNext, Some(ModuleConfig::CommonJs(..)) | Some(ModuleConfig::Amd(..)) - | Some(ModuleConfig::Umd(..)) => TsImportExportAssignConfig::Preserve, + | Some(ModuleConfig::Umd(..)) + | Some(ModuleConfig::SystemJs(..)) => TsImportExportAssignConfig::Preserve, Some(ModuleConfig::NodeNext(..)) => TsImportExportAssignConfig::NodeNext, - // TODO: should Preserve for SystemJS _ => TsImportExportAssignConfig::Classic, }; @@ -652,7 +652,7 @@ impl Options { } else { Some(hygiene::Config { keep_class_names, - ..Default::default() + ..hygiene::Config::hygiene_default() }) }; let env = cfg.env.map(Into::into); @@ -702,6 +702,8 @@ impl Options { .map(|v| v.mangle.is_obj() || v.mangle.is_true()) .unwrap_or(false); + let jsx_preserve = transform.react.runtime == Some(react::Runtime::Preserve); + #[cfg(feature = "module")] let rewrite_import_pass: Box = { let swc_import_rewriter: Box = match resolver.clone() { @@ -715,7 +717,7 @@ impl Options { }; let typescript_import_rewriter = Optional::new( - modules::rewriter::typescript_import_rewriter(), + modules::rewriter::typescript_import_rewriter(jsx_preserve), rewrite_relative_import_extensions.into_bool(), ); @@ -791,7 +793,9 @@ impl Options { Optional::new( hygiene_with_config(swc_ecma_transforms_base::hygiene::Config { top_level_mark, - ..hygiene_config.clone().unwrap_or_default() + ..hygiene_config + .clone() + .unwrap_or_else(hygiene::Config::hygiene_default) }), hygiene_config.is_some() && !is_mangler_enabled, ), @@ -878,8 +882,7 @@ impl Options { { plugin_transforms.unwrap() } else { - let jsx_enabled = - syntax.jsx() && transform.react.runtime != Some(react::Runtime::Preserve); + let jsx_enabled = syntax.jsx() && !jsx_preserve; let decorator_pass: Box = match transform.decorator_version.unwrap_or_default() { @@ -1727,8 +1730,8 @@ impl ModuleConfig { Some(ModuleConfig::SystemJs(config)) => build_resolver( base_url, paths, - config.config.resolve_fully, - &config.config.out_file_extension, + config.resolve_fully, + &config.out_file_extension, preserve_symlinks, ), }; @@ -1813,8 +1816,8 @@ pub struct TransformConfig { /// Public `.swcrc` configuration for React Compiler. /// /// This intentionally mirrors only a curated subset of upstream -/// `PluginOptions`; the deep `environment` configuration is kept internal for -/// the first SWC integration. +/// `PluginOptions`. The nested `environment` object likewise exposes only a +/// curated subset of the compiler's environment configuration. #[derive(Debug, Default, Clone, Serialize, Deserialize, Merge)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct ReactCompilerConfig { @@ -1856,6 +1859,9 @@ pub struct ReactCompilerConfig { #[serde(default)] pub dynamic_gating: Option, + + #[serde(default)] + pub environment: Option, } #[cfg(feature = "react-compiler")] @@ -1907,6 +1913,9 @@ impl ReactCompilerConfig { if let Some(dynamic_gating) = self.dynamic_gating { options.dynamic_gating = Some(dynamic_gating.into()); } + if let Some(environment) = self.environment { + environment.apply_to(&mut options); + } options } @@ -2031,6 +2040,38 @@ impl From for swc_ecma_react_compiler::Dynamic } } +/// Curated subset of the React Compiler `environment` options exposed through +/// the SWC config, mirroring Babel's `reactCompiler.environment` object. +/// +/// Only fields wired end-to-end into the compiler are exposed here. A field +/// left unset (`None`) leaves the compiler default untouched, so a partial +/// object such as `{ "enableFunctionOutlining": false }` overrides only that +/// setting. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct ReactCompilerEnvironmentConfig { + /// Extract anonymous functions that do not close over local variables into + /// top-level helper functions. Maps to the compiler's + /// `environment.enable_function_outlining` (default `true`). + #[serde(default)] + pub enable_function_outlining: Option, +} + +#[cfg(feature = "react-compiler")] +impl ReactCompilerEnvironmentConfig { + /// Apply the set (`Some`) overrides onto the compiler options' environment, + /// leaving unset fields at their existing (default) values. + /// + /// This mutates the public `environment` field in place rather than naming + /// the upstream `EnvironmentConfig` type, so the config layer does not + /// require that type to be re-exported. + fn apply_to(self, options: &mut swc_ecma_react_compiler::PluginOptions) { + if let Some(enable_function_outlining) = self.enable_function_outlining { + options.environment.enable_function_outlining = enable_function_outlining; + } + } +} + #[cfg(feature = "react-compiler")] fn react_compiler_options( config: BoolOrDataConfig, diff --git a/deps/swc/crates/swc_allocator/Cargo.toml b/deps/swc/crates/swc_allocator/Cargo.toml index dfed6c906..55ea3b94c 100644 --- a/deps/swc/crates/swc_allocator/Cargo.toml +++ b/deps/swc/crates/swc_allocator/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_allocator" repository = { workspace = true } -version = "4.0.1" +version = "5.0.0" [package.metadata.docs.rs] all-features = true @@ -21,8 +21,7 @@ nightly = [ # The latest pinned nightly rejects the bumpalo/hashbrown/allocator-api2 # nightly-only allocator paths. Stable allocator-api2 support is sufficient # for our usage here. -# This two features are actually useless -rkyv = [] +# This feature is actually useless. serde = [] # This feature is used to suppress warnings about slowness caused by stable rustc. # It's recommended to use nightly rustc until the allocator APIs are stabilized. diff --git a/deps/swc/crates/swc_atoms/Cargo.toml b/deps/swc/crates/swc_atoms/Cargo.toml index 254a714bd..49c08ad65 100644 --- a/deps/swc/crates/swc_atoms/Cargo.toml +++ b/deps/swc/crates/swc_atoms/Cargo.toml @@ -6,26 +6,20 @@ edition = { workspace = true } license = { workspace = true } name = "swc_atoms" repository = { workspace = true } -version = "9.0.3" +version = "10.0.0" [lib] bench = false [features] -__rkyv = [] encoding-impl = ["cbor4ii"] -rkyv-impl = ["__rkyv", "rkyv", "bytecheck", "rancor"] shrink-to-fit = ["dep:shrink-to-fit"] [dependencies] -# bytecheck version should be in sync with rkyv version. Do not bump individually. arbitrary = { workspace = true, optional = true } -bytecheck = { workspace = true, optional = true } cbor4ii = { workspace = true, features = ["use_std"], optional = true } once_cell = { workspace = true } -rancor = { workspace = true, optional = true } -rkyv = { workspace = true, optional = true } serde = { workspace = true } shrink-to-fit = { workspace = true, optional = true } -hstr = { version = "3.0.6", path = "../hstr", features = ["serde"] } +hstr = { version = "4.0.0", path = "../hstr", features = ["serde"] } diff --git a/deps/swc/crates/swc_atoms/src/lib.rs b/deps/swc/crates/swc_atoms/src/lib.rs index 4d2391352..fa8f36caf 100644 --- a/deps/swc/crates/swc_atoms/src/lib.rs +++ b/deps/swc/crates/swc_atoms/src/lib.rs @@ -34,7 +34,6 @@ mod wtf8_atom; /// /// See [tendril] for more details. #[derive(Clone, Default)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] #[repr(transparent)] pub struct Atom(hstr::Atom); @@ -284,40 +283,6 @@ impl PartialEq for str { } } -/// NOT A PUBLIC API -#[cfg(feature = "rkyv-impl")] -impl rkyv::Archive for Atom { - type Archived = rkyv::string::ArchivedString; - type Resolver = rkyv::string::StringResolver; - - #[allow(clippy::unit_arg)] - fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place) { - rkyv::string::ArchivedString::resolve_from_str(self, resolver, out) - } -} - -/// NOT A PUBLIC API -#[cfg(feature = "rkyv-impl")] -impl rkyv::Serialize for Atom -where - ::Error: rancor::Source, -{ - fn serialize(&self, serializer: &mut S) -> Result { - rkyv::string::ArchivedString::serialize_from_str(self.as_str(), serializer) - } -} - -/// NOT A PUBLIC API -#[cfg(feature = "rkyv-impl")] -impl rkyv::Deserialize for rkyv::string::ArchivedString -where - D: ?Sized + rancor::Fallible, -{ - fn deserialize(&self, _: &mut D) -> Result::Error> { - Ok(Atom::new(self.as_str())) - } -} - #[doc(hidden)] pub type CahcedAtom = Lazy; diff --git a/deps/swc/crates/swc_atoms/src/wtf8_atom.rs b/deps/swc/crates/swc_atoms/src/wtf8_atom.rs index 47898822b..ddd08f2e4 100644 --- a/deps/swc/crates/swc_atoms/src/wtf8_atom.rs +++ b/deps/swc/crates/swc_atoms/src/wtf8_atom.rs @@ -14,7 +14,6 @@ use crate::Atom; /// /// See [tendril] for more details. #[derive(Clone, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] #[repr(transparent)] pub struct Wtf8Atom(pub(super) hstr::Wtf8Atom); @@ -192,46 +191,6 @@ impl<'de> serde::de::Deserialize<'de> for Wtf8Atom { } } -/// NOT A PUBLIC API -#[cfg(feature = "rkyv-impl")] -impl rkyv::Archive for Wtf8Atom { - type Archived = rkyv::vec::ArchivedVec; - type Resolver = rkyv::vec::VecResolver; - - #[allow(clippy::unit_arg)] - fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place) { - rkyv::vec::ArchivedVec::::resolve_from_slice(self.as_bytes(), resolver, out) - } -} - -/// NOT A PUBLIC API -#[cfg(feature = "rkyv-impl")] -impl rkyv::Serialize - for Wtf8Atom -where - ::Error: rancor::Source, -{ - fn serialize(&self, serializer: &mut S) -> Result { - rkyv::vec::ArchivedVec::::serialize_from_slice(self.as_bytes(), serializer) - } -} - -/// NOT A PUBLIC API -#[cfg(feature = "rkyv-impl")] -impl rkyv::Deserialize for rkyv::vec::ArchivedVec -where - D: ?Sized + rancor::Fallible, - ::Error: rancor::Source, -{ - fn deserialize(&self, _: &mut D) -> Result::Error> { - Ok(Wtf8Atom::new( - // SAFETY: `ArchivedVec` is guaranteed to be serialized with `Wtf8Atom` byte - // sequence. `Wtf8Atom` byte sequence is identical to `Wtf8` byte sequence. - unsafe { Wtf8::from_bytes_unchecked(self.as_slice()) }, - )) - } -} - /// noop #[cfg(feature = "shrink-to-fit")] impl shrink_to_fit::ShrinkToFit for Wtf8Atom { diff --git a/deps/swc/crates/swc_bundler/Cargo.toml b/deps/swc/crates/swc_bundler/Cargo.toml index 41be17431..f47ee000b 100644 --- a/deps/swc/crates/swc_bundler/Cargo.toml +++ b/deps/swc/crates/swc_bundler/Cargo.toml @@ -9,7 +9,7 @@ include = ["Cargo.toml", "build.rs", "src/**/*.rs", "src/**/*.js"] license = { workspace = true } name = "swc_bundler" repository = { workspace = true } -version = "51.0.1" +version = "54.0.0" [package.metadata.docs.rs] all-features = true @@ -40,18 +40,18 @@ relative-path = { workspace = true } rustc-hash = { workspace = true } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_loader = { version = "24.0.1", path = "../swc_ecma_loader" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_loader = { version = "25.0.0", path = "../swc_ecma_loader" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_optimization = { version = "47.0.1", path = "../swc_ecma_transforms_optimization" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_optimization = { version = "50.0.0", path = "../swc_ecma_transforms_optimization" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } swc_graph_analyzer = { version = "14.0.2", path = "../swc_graph_analyzer/" } [dev-dependencies] @@ -63,18 +63,18 @@ reqwest = { workspace = true, features = ["blocking"] } sha1 = { workspace = true } tempfile = { workspace = true } -swc_ecma_loader = { version = "24.0.1", path = "../swc_ecma_loader", features = [ +swc_ecma_loader = { version = "25.0.0", path = "../swc_ecma_loader", features = [ "node", "cache", ] } -swc_ecma_minifier = { version = "56.0.1", path = "../swc_ecma_minifier", features = [ +swc_ecma_minifier = { version = "59.0.0", path = "../swc_ecma_minifier", features = [ "concurrent", ] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base", features = [ +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base", features = [ "inline-helpers", ] } -swc_ecma_transforms_proposal = { version = "44.0.1", path = "../swc_ecma_transforms_proposal" } -swc_ecma_transforms_react = { version = "50.0.0", path = "../swc_ecma_transforms_react" } -swc_ecma_transforms_typescript = { version = "50.0.0", path = "../swc_ecma_transforms_typescript" } +swc_ecma_transforms_proposal = { version = "47.0.0", path = "../swc_ecma_transforms_proposal" } +swc_ecma_transforms_react = { version = "53.0.0", path = "../swc_ecma_transforms_react" } +swc_ecma_transforms_typescript = { version = "53.0.0", path = "../swc_ecma_transforms_typescript" } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_cli_impl/Cargo.toml b/deps/swc/crates/swc_cli_impl/Cargo.toml index 944554b72..b59be9e87 100644 --- a/deps/swc/crates/swc_cli_impl/Cargo.toml +++ b/deps/swc/crates/swc_cli_impl/Cargo.toml @@ -6,7 +6,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_cli_impl" repository = { workspace = true } -version = "71.0.0" +version = "75.0.0" [[bin]] name = "swc" @@ -37,7 +37,7 @@ serde_json = { workspace = true, features = ["unbounded_depth"] } tracing = { workspace = true } walkdir = { workspace = true } -swc_core = { version = "71.0.3", features = [ +swc_core = { version = "75.0.0", features = [ "common_concurrent", "base_concurrent", "base_flow", diff --git a/deps/swc/crates/swc_common/Cargo.toml b/deps/swc/crates/swc_common/Cargo.toml index 467031a6c..fee6b1a5b 100644 --- a/deps/swc/crates/swc_common/Cargo.toml +++ b/deps/swc/crates/swc_common/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_common" repository = { workspace = true } -version = "23.0.2" +version = "24.0.0" [package.metadata.docs.rs] all-features = true @@ -26,7 +26,7 @@ concurrent = ["parking_lot"] debug = [] default = [] diagnostic-serde = [] -plugin-base = ["__plugin", "rkyv-impl", "diagnostic-serde"] +plugin-base = ["__plugin", "diagnostic-serde"] plugin-mode = ["__plugin_mode", "plugin-base"] plugin-rt = ["__plugin_rt", "plugin-base"] sourcemap = ["dep:swc_sourcemap"] @@ -36,16 +36,7 @@ plugin_transform_schema_vtest = [] tty-emitter = ["termcolor"] -__rkyv = [] encoding-impl = ["cbor4ii", "swc_atoms/encoding-impl"] -rkyv-impl = [ - "__rkyv", - "rkyv", - "swc_atoms/rkyv-impl", - "bytes-str/rkyv", - "bytecheck", - "rancor", -] shrink-to-fit = ["dep:shrink-to-fit", "swc_atoms/shrink-to-fit"] @@ -53,15 +44,12 @@ shrink-to-fit = ["dep:shrink-to-fit", "swc_atoms/shrink-to-fit"] [dependencies] anyhow = { workspace = true } arbitrary = { workspace = true, features = ["derive"], optional = true } -bytecheck = { workspace = true, optional = true } bytes-str = { workspace = true, features = ["serde"] } cbor4ii = { workspace = true, features = ["use_std"], optional = true } either = { workspace = true } num-bigint = { workspace = true } once_cell = { workspace = true } parking_lot = { workspace = true, optional = true } -rancor = { workspace = true, optional = true } -rkyv = { workspace = true, optional = true } rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } shrink-to-fit = { workspace = true, optional = true } @@ -72,10 +60,10 @@ tracing = { workspace = true } unicode-width = { workspace = true } url = { workspace = true } -ast_node = { version = "5.0.0", path = "../ast_node" } +ast_node = { version = "6.1.0", path = "../ast_node" } better_scoped_tls = { version = "1.0.1", path = "../better_scoped_tls" } from_variant = { version = "3.0.0", path = "../from_variant" } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } swc_eq_ignore_macros = { version = "1.0.1", path = "../swc_eq_ignore_macros" } swc_visit = { version = "2.0.1", path = "../swc_visit" } diff --git a/deps/swc/crates/swc_common/src/cache.rs b/deps/swc/crates/swc_common/src/cache.rs index d943cb347..b2221f445 100644 --- a/deps/swc/crates/swc_common/src/cache.rs +++ b/deps/swc/crates/swc_common/src/cache.rs @@ -2,7 +2,7 @@ use std::ops::Deref; use once_cell::sync::OnceCell; -/// Wrapper for [OnceCell] with support for [rkyv]. +/// Wrapper for [OnceCell]. #[derive(Clone, Debug)] pub struct CacheCell(OnceCell); @@ -31,86 +31,3 @@ impl Default for CacheCell { Self::new() } } - -#[cfg(feature = "rkyv-impl")] -mod rkyv_impl { - use std::hint::unreachable_unchecked; - - use rancor::Fallible; - use rkyv::{ - munge::munge, option::ArchivedOption, traits::NoUndef, Archive, Deserialize, Place, - Serialize, - }; - - use super::*; - - #[allow(dead_code)] - #[repr(u8)] - enum ArchivedOptionTag { - None, - Some, - } - - // SAFETY: `ArchivedOptionTag` is `repr(u8)` and so always consists of a single - // well-defined byte. - unsafe impl NoUndef for ArchivedOptionTag {} - - #[repr(C)] - struct ArchivedOptionVariantNone(ArchivedOptionTag); - - #[repr(C)] - struct ArchivedOptionVariantSome(ArchivedOptionTag, T); - - impl Archive for CacheCell { - type Archived = ArchivedOption; - type Resolver = Option; - - fn resolve(&self, resolver: Self::Resolver, out: Place) { - match resolver { - None => { - let out = unsafe { out.cast_unchecked::() }; - munge!(let ArchivedOptionVariantNone(tag) = out); - tag.write(ArchivedOptionTag::None); - } - Some(resolver) => { - let out = - unsafe { out.cast_unchecked::>() }; - munge!(let ArchivedOptionVariantSome(tag, out_value) = out); - tag.write(ArchivedOptionTag::Some); - - let value = if let Some(value) = self.get() { - value - } else { - unsafe { - unreachable_unchecked(); - } - }; - - value.resolve(resolver, out_value); - } - } - } - } - - impl, S: Fallible + ?Sized> Serialize for CacheCell { - fn serialize(&self, serializer: &mut S) -> Result { - self.get() - .map(|value| value.serialize(serializer)) - .transpose() - } - } - - impl Deserialize, D> for ArchivedOption - where - T: Archive, - T::Archived: Deserialize, - D: Fallible + ?Sized, - { - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(match self { - ArchivedOption::Some(value) => CacheCell::from(value.deserialize(deserializer)?), - ArchivedOption::None => CacheCell::new(), - }) - } - } -} diff --git a/deps/swc/crates/swc_common/src/comments.rs b/deps/swc/crates/swc_common/src/comments.rs index df39f7fa0..69e3d57ad 100644 --- a/deps/swc/crates/swc_common/src/comments.rs +++ b/deps/swc/crates/swc_common/src/comments.rs @@ -630,12 +630,6 @@ impl SingleThreadedComments { } #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr(feature = "encoding-impl", derive(crate::Encode, crate::Decode))] pub struct Comment { pub kind: CommentKind, @@ -651,12 +645,6 @@ impl Spanned for Comment { } #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr(feature = "encoding-impl", derive(crate::Encode, crate::Decode))] pub enum CommentKind { Line = 0, diff --git a/deps/swc/crates/swc_common/src/errors/diagnostic.rs b/deps/swc/crates/swc_common/src/errors/diagnostic.rs index f96c749ba..5f84b0d65 100644 --- a/deps/swc/crates/swc_common/src/errors/diagnostic.rs +++ b/deps/swc/crates/swc_common/src/errors/diagnostic.rs @@ -18,12 +18,6 @@ use crate::syntax_pos::{MultiSpan, Span}; feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -36,12 +30,6 @@ pub struct Message(pub String, pub Style); feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -73,12 +61,6 @@ pub struct Diagnostic { feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -94,12 +76,6 @@ pub enum DiagnosticId { feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) diff --git a/deps/swc/crates/swc_common/src/errors/mod.rs b/deps/swc/crates/swc_common/src/errors/mod.rs index bd9a7d50c..ecfffb0b1 100644 --- a/deps/swc/crates/swc_common/src/errors/mod.rs +++ b/deps/swc/crates/swc_common/src/errors/mod.rs @@ -48,12 +48,6 @@ mod styled_buffer; feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -70,12 +64,6 @@ pub enum Applicability { feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -127,12 +115,6 @@ pub struct CodeSuggestion { feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -146,12 +128,6 @@ pub struct Substitution { feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -919,12 +895,6 @@ impl Handler { feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) diff --git a/deps/swc/crates/swc_common/src/errors/snippet.rs b/deps/swc/crates/swc_common/src/errors/snippet.rs index e72539912..a8c3a6ce4 100644 --- a/deps/swc/crates/swc_common/src/errors/snippet.rs +++ b/deps/swc/crates/swc_common/src/errors/snippet.rs @@ -176,12 +176,6 @@ pub struct StyledString { feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) diff --git a/deps/swc/crates/swc_common/src/lib.rs b/deps/swc/crates/swc_common/src/lib.rs index 6dadc449c..500e9197d 100644 --- a/deps/swc/crates/swc_common/src/lib.rs +++ b/deps/swc/crates/swc_common/src/lib.rs @@ -76,18 +76,6 @@ pub mod util; #[cfg(all(not(debug_assertions), feature = "plugin-rt", feature = "plugin-mode"))] compile_error!("You can't enable `plugin-rt` and `plugin-mode` at the same time"); -/// Warning: The particular implementation of serialization and deserialization -/// of the ast nodes may change in the future, and so these types would be -/// removed. It's safe to say they will be serializable in some form or another, -/// but not necessarily with these specific types underlying the implementation. -/// As such, *use these types at your own risk*. -#[cfg(feature = "rkyv-impl")] -#[doc(hidden)] -pub use self::syntax_pos::{ - ArchivedBytePos, ArchivedCharPos, ArchivedFileName, ArchivedMultiSpan, ArchivedSourceFile, - ArchivedSourceFileAndBytePos, ArchivedSpan, ArchivedSpanLinesError, ArchivedSpanSnippetError, -}; - #[cfg(swc_ast_unknown)] #[track_caller] pub fn unknown_impl() -> std::convert::Infallible { diff --git a/deps/swc/crates/swc_common/src/plugin/diagnostics.rs b/deps/swc/crates/swc_common/src/plugin/diagnostics.rs index 985ff3db2..0eab07447 100644 --- a/deps/swc/crates/swc_common/src/plugin/diagnostics.rs +++ b/deps/swc/crates/swc_common/src/plugin/diagnostics.rs @@ -1,14 +1,8 @@ /// A serializable, wrapped struct for the diagnostics information /// included in plugin binaries. -/// TODO: Must implement bytecheck with forward-compatible schema changes to +/// TODO: Must implement forward-compatible validation for schema changes to /// prevent handshake failure. #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) diff --git a/deps/swc/crates/swc_common/src/plugin/serialized.rs b/deps/swc/crates/swc_common/src/plugin/serialized.rs index dac996dea..b139994be 100644 --- a/deps/swc/crates/swc_common/src/plugin/serialized.rs +++ b/deps/swc/crates/swc_common/src/plugin/serialized.rs @@ -4,11 +4,6 @@ use anyhow::Error; #[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] -#[cfg_attr( - feature = "__plugin", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "__plugin", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "__plugin", repr(u32))] /// Enum for possible errors while running transform via plugin. /// @@ -58,25 +53,6 @@ impl PluginSerializedBytes { * This is sort of mimic TryFrom behavior, since we can't use generic * to implement TryFrom trait */ - /* - #[cfg_attr(debug_assertions, tracing::instrument(level = "info", skip_all))] - pub fn try_serialize(t: &VersionedSerializable) -> Result - where - W: rkyv::Serialize>, - { - rkyv::to_bytes::<_, 512>(t) - .map(|field| PluginSerializedBytes { field }) - .map_err(|err| match err { - rkyv::ser::serializers::CompositeSerializerError::SerializerError(e) => e.into(), - rkyv::ser::serializers::CompositeSerializerError::ScratchSpaceError(_e) => { - Error::msg("AllocScratchError") - } - rkyv::ser::serializers::CompositeSerializerError::SharedError(_e) => { - Error::msg("SharedSerializeMapError") - } - }) - } - */ #[cfg_attr(debug_assertions, tracing::instrument(level = "info", skip_all))] pub fn try_serialize(t: &VersionedSerializable) -> Result @@ -125,26 +101,6 @@ impl PluginSerializedBytes { .with_context(|| format!("failed to deserialize `{}`", type_name::()))?; Ok(VersionedSerializable(deserialized)) } - - /* - #[cfg_attr(debug_assertions, tracing::instrument(level = "info", skip_all))] - pub fn deserialize(&self) -> Result, Error> - where - W: rkyv::Archive, - W::Archived: rkyv::Deserialize - + for<'a> rkyv::CheckBytes>, - { - use anyhow::Context; - - let archived = rkyv::check_archived_root::>(&self.field[..]) - .map_err(|err| { - anyhow::format_err!("wasm plugin bytecheck failed {:?}", err.to_string()) - })?; - - archived - .deserialize(&mut rkyv::de::deserializers::SharedDeserializeMap::new()) - .with_context(|| format!("failed to deserialize `{}`", type_name::())) - } */ } /// A wrapper type for the structures to be passed into plugins @@ -154,18 +110,9 @@ impl PluginSerializedBytes { /// First field indicate version of struct type (schema). Any consumers like /// swc_plugin_macro can use this to validate compatiblility before attempt to /// serialize. -#[cfg_attr( - feature = "__plugin", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] #[repr(transparent)] -#[cfg_attr(feature = "__plugin", derive(bytecheck::CheckBytes))] #[derive(Debug)] -pub struct VersionedSerializable( - // [NOTE]: https://github.com/rkyv/rkyv/issues/373#issuecomment-1546360897 - //#[cfg_attr(feature = "__plugin", with(rkyv::with::AsBox))] - pub T, -); +pub struct VersionedSerializable(pub T); impl VersionedSerializable { pub fn new(value: T) -> Self { diff --git a/deps/swc/crates/swc_common/src/syntax_pos.rs b/deps/swc/crates/swc_common/src/syntax_pos.rs index 51bca32b6..d46f15b40 100644 --- a/deps/swc/crates/swc_common/src/syntax_pos.rs +++ b/deps/swc/crates/swc_common/src/syntax_pos.rs @@ -29,12 +29,6 @@ pub mod hygiene; /// assume that the length of the `span = hi - lo`; there may be space in the /// `BytePos` range between files. #[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -42,10 +36,8 @@ pub mod hygiene; #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] pub struct Span { #[serde(rename = "start")] - #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub lo: BytePos, #[serde(rename = "end")] - #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub hi: BytePos, } @@ -167,21 +159,9 @@ better_scoped_tls::scoped_tls!( pub static GLOBALS: Globals ); -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)] pub enum FileName { - Real( - #[cfg_attr( - any(feature = "rkyv-impl"), - rkyv(with = crate::source_map::EncodePathBuf) - )] - PathBuf, - ), + Real(PathBuf), /// A macro. This includes the full name of the macro, so that there are no /// clashes. Macros(String), @@ -192,7 +172,7 @@ pub enum FileName { /// Hack in src/libsyntax/parse.rs MacroExpansion, ProcMacroSourceCode, - Url(#[cfg_attr(any(feature = "rkyv-impl"), rkyv(with = crate::source_map::EncodeUrl))] Url), + Url(Url), Internal(String), /// Custom sources for explicit parser calls from plugins and drivers Custom(String), @@ -296,103 +276,6 @@ impl<'de> cbor4ii::core::dec::Decode<'de> for FileName { } } -/// A wrapper that attempts to convert a type to and from UTF-8. -/// -/// Types like `OsString` and `PathBuf` aren't guaranteed to be encoded as -/// UTF-8, but they usually are anyway. Using this wrapper will archive them as -/// if they were regular `String`s. -/// -/// There is built-in `AsString` supports PathBuf but it requires custom -/// serializer wrapper to handle conversion errors. This wrapper is simplified -/// version accepts errors -#[cfg(feature = "rkyv-impl")] -#[derive(Debug, Clone, Copy)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] -pub struct EncodePathBuf; - -#[cfg(feature = "rkyv-impl")] -impl rkyv::with::ArchiveWith for EncodePathBuf { - type Archived = rkyv::string::ArchivedString; - type Resolver = rkyv::string::StringResolver; - - #[inline] - fn resolve_with(field: &PathBuf, resolver: Self::Resolver, out: rkyv::Place) { - // It's safe to unwrap here because if the OsString wasn't valid UTF-8 it would - // have failed to serialize - rkyv::string::ArchivedString::resolve_from_str(field.to_str().unwrap(), resolver, out); - } -} - -#[cfg(feature = "rkyv-impl")] -impl rkyv::with::SerializeWith for EncodePathBuf -where - S: ?Sized + rancor::Fallible + rkyv::ser::Writer, - S::Error: rancor::Source, -{ - #[inline] - fn serialize_with(field: &PathBuf, serializer: &mut S) -> Result { - let s = field.to_str().unwrap_or_default(); - rkyv::string::ArchivedString::serialize_from_str(s, serializer) - } -} - -#[cfg(feature = "rkyv-impl")] -impl rkyv::with::DeserializeWith for EncodePathBuf -where - D: ?Sized + rancor::Fallible, -{ - #[inline] - fn deserialize_with( - field: &rkyv::string::ArchivedString, - _: &mut D, - ) -> Result { - Ok(::from_str(field.as_str()).unwrap()) - } -} - -/// A wrapper that attempts to convert a Url to and from String. -#[cfg(feature = "rkyv-impl")] -#[derive(Debug, Clone, Copy)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] -pub struct EncodeUrl; - -#[cfg(feature = "rkyv-impl")] -impl rkyv::with::ArchiveWith for EncodeUrl { - type Archived = rkyv::string::ArchivedString; - type Resolver = rkyv::string::StringResolver; - - #[inline] - fn resolve_with(field: &Url, resolver: Self::Resolver, out: rkyv::Place) { - rkyv::string::ArchivedString::resolve_from_str(field.as_str(), resolver, out); - } -} - -#[cfg(feature = "rkyv-impl")] -impl rkyv::with::SerializeWith for EncodeUrl -where - S: ?Sized + rancor::Fallible + rkyv::ser::Writer, - S::Error: rancor::Source, -{ - #[inline] - fn serialize_with(field: &Url, serializer: &mut S) -> Result { - let field = field.as_str(); - rkyv::string::ArchivedString::serialize_from_str(field, serializer) - } -} - -#[cfg(feature = "rkyv-impl")] -impl rkyv::with::DeserializeWith, Url, D> for EncodeUrl -where - D: ?Sized + rancor::Fallible, -{ - #[inline] - fn deserialize_with(field: &rkyv::string::ArchivedString, _: &mut D) -> Result { - Ok(Url::parse(field.as_str()).unwrap()) - } -} - impl std::fmt::Display for FileName { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match *self { @@ -459,12 +342,6 @@ impl FileName { feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -482,12 +359,6 @@ pub struct PrimarySpanLabel(pub Span, pub String); feature = "diagnostic-serde", derive(serde::Serialize, serde::Deserialize) )] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -795,12 +666,6 @@ impl From> for MultiSpan { pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty(); /// Identifies an offset of a multi-byte character in a SourceFile -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub struct MultiByteChar { /// The absolute offset of the character in the SourceMap @@ -825,12 +690,6 @@ impl MultiByteChar { } /// Identifies an offset of a non-narrow character in a SourceFile -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum NonNarrowChar { /// Represents a zero-width character @@ -893,12 +752,6 @@ impl Sub for NonNarrowChar { } /// A single source in the SourceMap. -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[derive(Clone)] pub struct SourceFile { /// The name of the file that the source came from. Source that doesn't @@ -923,12 +776,6 @@ pub struct SourceFile { lazy: CacheCell, } -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[derive(Clone)] pub struct SourceFileAnalysis { /// Stable hash of the source code. @@ -1203,14 +1050,8 @@ pub trait SmallPos { )] #[serde(transparent)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -pub struct BytePos(#[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub u32); +pub struct BytePos(pub u32); #[cfg(feature = "encoding-impl")] impl cbor4ii::core::enc::Encode for BytePos { @@ -1273,12 +1114,6 @@ impl BytePos { /// A character offset. Because of multibyte utf8 characters, a byte offset /// is not equivalent to a character offset. The SourceMap will convert BytePos /// values to CharPos values as necessary. -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr(feature = "encoding-impl", derive(crate::Encode, crate::Decode))] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] pub struct CharPos( @@ -1374,7 +1209,7 @@ impl Sub for CharPos { /// A source code location used for error reporting. /// -/// Note: This struct intentionally does not implement rkyv's archieve +/// Note: This struct intentionally does not implement an archive format /// to avoid redundant data copy (https://github.com/swc-project/swc/issues/5471) /// source_map_proxy constructs plugin-side Loc instead with shared SourceFile /// instance. @@ -1392,12 +1227,6 @@ pub struct Loc { /// A struct to exchange `Loc` with omitting SourceFile as needed. /// This is internal struct between plugins to the host, not a public interface. -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Debug, Clone) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr(feature = "encoding-impl", derive(crate::Encode, crate::Decode))] pub struct PartialLoc { #[cfg_attr( @@ -1431,12 +1260,6 @@ pub struct SourceFileAndLine { pub line: usize, } -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -1452,12 +1275,6 @@ pub struct SourceFileAndBytePos { } #[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr(feature = "encoding-impl", derive(crate::Encode, crate::Decode))] pub struct LineInfo { /// Index of line, starting from 0. @@ -1483,7 +1300,7 @@ pub struct LineCol { /// A struct to represent lines of a source file. /// -/// Note: This struct intentionally does not implement rkyv's archieve +/// Note: This struct intentionally does not implement an archive format /// to avoid redundant data copy (https://github.com/swc-project/swc/issues/5471) /// source_map_proxy constructs plugin-side Loc instead with shared SourceFile /// instance. @@ -1494,12 +1311,6 @@ pub struct FileLines { /// A struct to exchange `FileLines` with omitting SourceFile as needed. /// This is internal struct between plugins to the host, not a public interface. -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Debug, Clone) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -1523,12 +1334,6 @@ pub type FileLinesResult = Result>; pub type PartialFileLinesResult = Result>; #[derive(Clone, PartialEq, Eq, Debug)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -1539,12 +1344,6 @@ pub enum SpanLinesError { } #[derive(Clone, PartialEq, Eq, Debug)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] pub enum SpanSnippetError { DummyBytePos, IllFormedSpan(Span), @@ -1612,12 +1411,6 @@ impl<'de> cbor4ii::core::dec::Decode<'de> for SpanSnippetError { /// /// This type is small. #[derive(Clone, PartialEq, Eq, Debug)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -1627,12 +1420,6 @@ pub enum SourceMapLookupError { } #[derive(Clone, PartialEq, Eq, Debug)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -1647,12 +1434,6 @@ pub struct FilePos( ); #[derive(Clone, PartialEq, Eq, Debug)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) @@ -1663,12 +1444,6 @@ pub struct DistinctSources { } #[derive(Clone, PartialEq, Eq, Debug)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) diff --git a/deps/swc/crates/swc_common/src/syntax_pos/hygiene.rs b/deps/swc/crates/swc_common/src/syntax_pos/hygiene.rs index 448166db5..a4337cb38 100644 --- a/deps/swc/crates/swc_common/src/syntax_pos/hygiene.rs +++ b/deps/swc/crates/swc_common/src/syntax_pos/hygiene.rs @@ -31,14 +31,8 @@ use crate::EqIgnoreSpan; /// marks). #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[serde(transparent)] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -pub struct SyntaxContext(#[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] u32); +pub struct SyntaxContext(u32); #[cfg(feature = "encoding-impl")] impl cbor4ii::core::enc::Encode for SyntaxContext { @@ -104,12 +98,6 @@ pub(crate) struct MarkData { pub(crate) parent: Mark, } -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::ast_node::Encode, ::ast_node::Decode) diff --git a/deps/swc/crates/swc_common/src/unknown.rs b/deps/swc/crates/swc_common/src/unknown.rs index 3a4166439..92452bde1 100644 --- a/deps/swc/crates/swc_common/src/unknown.rs +++ b/deps/swc/crates/swc_common/src/unknown.rs @@ -37,57 +37,6 @@ impl std::hash::Hash for Unknown { } } -#[cfg(feature = "rkyv-impl")] -#[derive(Debug)] -struct UnknownError; - -#[cfg(feature = "rkyv-impl")] -impl std::error::Error for UnknownError {} - -#[cfg(feature = "rkyv-impl")] -impl std::fmt::Display for UnknownError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "cannot access unknown type") - } -} - -#[cfg(feature = "rkyv-impl")] -impl rkyv::Archive for Unknown { - type Archived = std::marker::PhantomData; - type Resolver = (); - - fn resolve(&self, _resolver: Self::Resolver, _out: rkyv::Place) { - // - } -} - -/// NOT A PUBLIC API -#[cfg(feature = "rkyv-impl")] -impl rkyv::Serialize for Unknown -where - S: rancor::Fallible + rkyv::ser::Writer + ?Sized, - S::Error: rancor::Source, -{ - fn serialize(&self, _serializer: &mut S) -> Result { - Err(::new(UnknownError)) - } -} - -/// NOT A PUBLIC API -#[cfg(feature = "rkyv-impl")] -impl rkyv::Deserialize for std::marker::PhantomData -where - D: ?Sized + rancor::Fallible, - D::Error: rancor::Source, -{ - fn deserialize( - &self, - _deserializer: &mut D, - ) -> Result::Error> { - Err(::new(UnknownError)) - } -} - impl std::fmt::Debug for Unknown { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Unknown") diff --git a/deps/swc/crates/swc_compiler_base/Cargo.toml b/deps/swc/crates/swc_compiler_base/Cargo.toml index e68be15ad..05c91e8ba 100644 --- a/deps/swc/crates/swc_compiler_base/Cargo.toml +++ b/deps/swc/crates/swc_compiler_base/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_compiler_base" repository = { workspace = true } -version = "59.0.0" +version = "62.0.0" [features] node = ["napi", "napi-derive"] @@ -23,18 +23,18 @@ serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } swc_sourcemap = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "sourcemap", ] } -swc_config = { version = "5.0.0", path = "../swc_config" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_minifier = { version = "56.0.1", path = "../swc_ecma_minifier" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_config = { version = "6.0.0", path = "../swc_config" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_minifier = { version = "59.0.0", path = "../swc_ecma_minifier" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dependencies.napi-derive] default-features = false diff --git a/deps/swc/crates/swc_config/Cargo.toml b/deps/swc/crates/swc_config/Cargo.toml index dbeb0fc11..ad4d24161 100644 --- a/deps/swc/crates/swc_config/Cargo.toml +++ b/deps/swc/crates/swc_config/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_config" repository = { workspace = true } -version = "5.0.0" +version = "6.0.0" [package.metadata.docs.rs] diff --git a/deps/swc/crates/swc_core/Cargo.toml b/deps/swc/crates/swc_core/Cargo.toml index 522e119c2..60424e51e 100644 --- a/deps/swc/crates/swc_core/Cargo.toml +++ b/deps/swc/crates/swc_core/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_core" repository = { workspace = true } -version = "71.0.3" +version = "75.0.0" [package.metadata.docs.rs] features = [ "allocator_node", @@ -332,55 +332,52 @@ __visit = ["__ecma", "swc_ecma_visit"] par-core = { workspace = true, optional = true } # swc_* dependencies -binding_macros = { optional = true, version = "69.0.0", path = "../binding_macros" } -swc = { optional = true, version = "69.0.0", path = "../swc", default-features = false } -swc_allocator = { version = "4.0.1", path = "../swc_allocator", default-features = false } -swc_atoms = { optional = true, version = "9.0.3", path = "../swc_atoms" } -swc_bundler = { optional = true, version = "51.0.1", path = "../swc_bundler" } -swc_common = { optional = true, version = "23.0.2", path = "../swc_common" } -swc_config = { optional = true, version = "5.0.0", path = "../swc_config" } -swc_css_ast = { optional = true, version = "23.0.0", path = "../swc_css_ast" } -swc_css_codegen = { optional = true, version = "23.0.0", path = "../swc_css_codegen" } -swc_css_compat = { optional = true, version = "23.0.0", path = "../swc_css_compat" } -swc_css_minifier = { optional = true, version = "23.0.0", path = "../swc_css_minifier" } -swc_css_modules = { optional = true, version = "23.0.0", path = "../swc_css_modules" } -swc_css_parser = { optional = true, version = "23.0.0", path = "../swc_css_parser" } -swc_css_prefixer = { optional = true, version = "28.0.0", path = "../swc_css_prefixer" } -swc_css_utils = { optional = true, version = "23.0.0", path = "../swc_css_utils/" } -swc_css_visit = { optional = true, version = "23.0.0", path = "../swc_css_visit" } -swc_ecma_ast = { optional = true, version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { optional = true, version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_lints = { optional = true, version = "33.0.0", path = "../swc_ecma_lints" } -swc_ecma_loader = { optional = true, version = "24.0.1", path = "../swc_ecma_loader" } -swc_ecma_minifier = { optional = true, version = "56.0.1", path = "../swc_ecma_minifier" } -swc_ecma_parser = { optional = true, version = "41.1.2", path = "../swc_ecma_parser", default-features = false } -swc_ecma_preset_env = { optional = true, version = "57.0.0", path = "../swc_ecma_preset_env" } -swc_ecma_quote_macros = { optional = true, version = "41.0.0", path = "../swc_ecma_quote_macros" } -swc_ecma_react_compiler = { optional = true, version = "20.0.2", path = "../swc_ecma_react_compiler" } -swc_ecma_transforms_base = { optional = true, version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_compat = { optional = true, version = "52.0.1", path = "../swc_ecma_transforms_compat" } -swc_ecma_transforms_module = { optional = true, version = "49.0.1", path = "../swc_ecma_transforms_module" } -swc_ecma_transforms_optimization = { optional = true, version = "47.0.1", path = "../swc_ecma_transforms_optimization" } -swc_ecma_transforms_proposal = { optional = true, version = "44.0.1", path = "../swc_ecma_transforms_proposal" } -swc_ecma_transforms_react = { optional = true, version = "50.0.0", path = "../swc_ecma_transforms_react" } -swc_ecma_transforms_testing = { optional = true, version = "48.0.0", path = "../swc_ecma_transforms_testing" } -swc_ecma_transforms_typescript = { optional = true, version = "50.0.0", path = "../swc_ecma_transforms_typescript" } -swc_ecma_utils = { optional = true, version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { optional = true, version = "25.0.0", path = "../swc_ecma_visit" } +binding_macros = { optional = true, version = "73.0.0", path = "../binding_macros" } +swc = { optional = true, version = "73.0.0", path = "../swc", default-features = false } +swc_allocator = { version = "5.0.0", path = "../swc_allocator", default-features = false } +swc_atoms = { optional = true, version = "10.0.0", path = "../swc_atoms" } +swc_bundler = { optional = true, version = "54.0.0", path = "../swc_bundler" } +swc_common = { optional = true, version = "24.0.0", path = "../swc_common" } +swc_config = { optional = true, version = "6.0.0", path = "../swc_config" } +swc_css_ast = { optional = true, version = "24.0.0", path = "../swc_css_ast" } +swc_css_codegen = { optional = true, version = "24.0.0", path = "../swc_css_codegen" } +swc_css_compat = { optional = true, version = "24.0.0", path = "../swc_css_compat" } +swc_css_minifier = { optional = true, version = "24.0.0", path = "../swc_css_minifier" } +swc_css_modules = { optional = true, version = "24.0.0", path = "../swc_css_modules" } +swc_css_parser = { optional = true, version = "24.0.0", path = "../swc_css_parser" } +swc_css_prefixer = { optional = true, version = "29.0.0", path = "../swc_css_prefixer" } +swc_css_utils = { optional = true, version = "24.0.0", path = "../swc_css_utils/" } +swc_css_visit = { optional = true, version = "24.0.0", path = "../swc_css_visit" } +swc_ecma_ast = { optional = true, version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { optional = true, version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_lints = { optional = true, version = "35.0.0", path = "../swc_ecma_lints" } +swc_ecma_loader = { optional = true, version = "25.0.0", path = "../swc_ecma_loader" } +swc_ecma_minifier = { optional = true, version = "59.0.0", path = "../swc_ecma_minifier" } +swc_ecma_parser = { optional = true, version = "43.0.0", path = "../swc_ecma_parser", default-features = false } +swc_ecma_preset_env = { optional = true, version = "61.0.0", path = "../swc_ecma_preset_env" } +swc_ecma_quote_macros = { optional = true, version = "43.0.0", path = "../swc_ecma_quote_macros" } +swc_ecma_react_compiler = { optional = true, version = "22.0.0", path = "../swc_ecma_react_compiler" } +swc_ecma_transforms_base = { optional = true, version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_compat = { optional = true, version = "55.0.0", path = "../swc_ecma_transforms_compat" } +swc_ecma_transforms_module = { optional = true, version = "53.0.0", path = "../swc_ecma_transforms_module" } +swc_ecma_transforms_optimization = { optional = true, version = "50.0.0", path = "../swc_ecma_transforms_optimization" } +swc_ecma_transforms_proposal = { optional = true, version = "47.0.0", path = "../swc_ecma_transforms_proposal" } +swc_ecma_transforms_react = { optional = true, version = "53.0.0", path = "../swc_ecma_transforms_react" } +swc_ecma_transforms_testing = { optional = true, version = "51.0.0", path = "../swc_ecma_transforms_testing" } +swc_ecma_transforms_typescript = { optional = true, version = "53.0.0", path = "../swc_ecma_transforms_typescript" } +swc_ecma_utils = { optional = true, version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { optional = true, version = "27.0.0", path = "../swc_ecma_visit" } swc_malloc = { optional = true, version = "1.2.5", path = "../swc_malloc" } -swc_node_bundler = { optional = true, version = "70.0.0", path = "../swc_node_bundler" } +swc_node_bundler = { optional = true, version = "74.0.0", path = "../swc_node_bundler" } swc_nodejs_common = { optional = true, version = "1.0.3", path = "../swc_nodejs_common" } swc_plugin = { optional = true, version = "1.0.1", path = "../swc_plugin" } swc_plugin_macro = { optional = true, version = "1.1.1", path = "../swc_plugin_macro" } -swc_plugin_proxy = { optional = true, version = "26.0.0", path = "../swc_plugin_proxy" } -swc_plugin_runner = { optional = true, version = "30.0.0", path = "../swc_plugin_runner", default-features = false } -swc_transform_common = { optional = true, version = "17.0.0", path = "../swc_transform_common" } -swc_typescript = { optional = true, version = "30.0.1", path = "../swc_typescript" } -testing = { optional = true, version = "24.0.1", path = "../testing" } - -[build-dependencies] -vergen = { workspace = true, features = ["cargo"] } +swc_plugin_proxy = { optional = true, version = "28.0.0", path = "../swc_plugin_proxy" } +swc_plugin_runner = { optional = true, version = "32.0.0", path = "../swc_plugin_runner", default-features = false } +swc_transform_common = { optional = true, version = "18.0.0", path = "../swc_transform_common" } +swc_typescript = { optional = true, version = "32.0.0", path = "../swc_typescript" } +testing = { optional = true, version = "25.0.0", path = "../testing" } [dev-dependencies] anyhow = { workspace = true } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_core/build.rs b/deps/swc/crates/swc_core/build.rs index f3a1c9a5f..1da24415e 100644 --- a/deps/swc/crates/swc_core/build.rs +++ b/deps/swc/crates/swc_core/build.rs @@ -1,11 +1,4 @@ -use std::{ - env, - fs::File, - io::{BufWriter, Write}, - path::Path, -}; - -use vergen::{CargoBuilder, Emitter}; +use std::{env, fs, path::Path}; // Validate conflict between host / plugin features #[cfg(all( @@ -22,23 +15,25 @@ compile_error!( ); fn main() { - let cargo = CargoBuilder::all_cargo().unwrap(); - - // Creates a static compile time constants for the version of swc_core. + // Keep these generated files deterministic so sccache can reuse builds. let pkg_version = env::var("CARGO_PKG_VERSION").unwrap(); let out_dir = env::var("OUT_DIR").expect("Outdir should exist"); - let dest_path = Path::new(&out_dir).join("core_pkg_version.txt"); - let mut f = BufWriter::new( - File::create(dest_path).expect("Failed to create swc_core version constant"), - ); - write!(f, "{pkg_version}").expect("Failed to write swc_core version constant"); + let out_dir = Path::new(&out_dir); + + fs::write(out_dir.join("core_pkg_version.txt"), pkg_version) + .expect("Failed to write swc_core version constant"); + fs::write(out_dir.join("cargo_features.txt"), cargo_features()) + .expect("Failed to write swc_core feature list"); +} - // Attempt to collect some build time env values but will skip if there are any - // errors. +fn cargo_features() -> String { + let mut features = env::vars() + .filter_map(|(key, _)| { + key.strip_prefix("CARGO_FEATURE_") + .map(|feature| feature.to_ascii_lowercase()) + }) + .collect::>(); - Emitter::default() - .add_instructions(&cargo) - .unwrap() - .emit() - .unwrap(); + features.sort_unstable(); + features.join(",") } diff --git a/deps/swc/crates/swc_core/src/lib.rs b/deps/swc/crates/swc_core/src/lib.rs index c16fcd63f..8bfed50ea 100644 --- a/deps/swc/crates/swc_core/src/lib.rs +++ b/deps/swc/crates/swc_core/src/lib.rs @@ -307,12 +307,9 @@ pub mod diagnostics { /// Returns metadata about the swc_core engine that was built against. pub fn get_core_engine_diagnostics() -> CoreEngineDiagnostics { CoreEngineDiagnostics { - package_semver: option_env!("VERGEN_BUILD_SEMVER") - .unwrap_or_else(|| PKG_SEMVER_FALLBACK) - .to_string(), + package_semver: PKG_SEMVER_FALLBACK.to_string(), git_sha: GIT_SHA.to_string(), - cargo_features: option_env!("VERGEN_CARGO_FEATURES") - .unwrap_or_else(|| "Unavailable to query") + cargo_features: include_str!(concat!(env!("OUT_DIR"), "/cargo_features.txt")) .to_string(), } } diff --git a/deps/swc/crates/swc_css/Cargo.toml b/deps/swc/crates/swc_css/Cargo.toml index 216a0c4b9..5c1b0b1c6 100644 --- a/deps/swc/crates/swc_css/Cargo.toml +++ b/deps/swc/crates/swc_css/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_css" repository = { workspace = true } -version = "28.0.0" +version = "29.0.0" [package.metadata.docs.rs] all-features = true @@ -22,12 +22,12 @@ modules = ["swc_css_modules"] prefixer = ["swc_css_prefixer"] [dependencies] -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast" } -swc_css_codegen = { version = "23.0.0", path = "../swc_css_codegen" } -swc_css_compat = { version = "23.0.0", path = "../swc_css_compat", optional = true } -swc_css_minifier = { version = "23.0.0", path = "../swc_css_minifier", optional = true } -swc_css_modules = { version = "23.0.0", path = "../swc_css_modules", optional = true } -swc_css_parser = { version = "23.0.0", path = "../swc_css_parser" } -swc_css_prefixer = { version = "28.0.0", path = "../swc_css_prefixer", optional = true } -swc_css_utils = { version = "23.0.0", path = "../swc_css_utils/" } -swc_css_visit = { version = "23.0.0", path = "../swc_css_visit" } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast" } +swc_css_codegen = { version = "24.0.0", path = "../swc_css_codegen" } +swc_css_compat = { version = "24.0.0", path = "../swc_css_compat", optional = true } +swc_css_minifier = { version = "24.0.0", path = "../swc_css_minifier", optional = true } +swc_css_modules = { version = "24.0.0", path = "../swc_css_modules", optional = true } +swc_css_parser = { version = "24.0.0", path = "../swc_css_parser" } +swc_css_prefixer = { version = "29.0.0", path = "../swc_css_prefixer", optional = true } +swc_css_utils = { version = "24.0.0", path = "../swc_css_utils/" } +swc_css_visit = { version = "24.0.0", path = "../swc_css_visit" } diff --git a/deps/swc/crates/swc_css_ast/Cargo.toml b/deps/swc/crates/swc_css_ast/Cargo.toml index 805857230..a8d6e305c 100644 --- a/deps/swc/crates/swc_css_ast/Cargo.toml +++ b/deps/swc/crates/swc_css_ast/Cargo.toml @@ -6,36 +6,26 @@ edition = { workspace = true } license = { workspace = true } name = "swc_css_ast" repository = { workspace = true } -version = "23.0.0" +version = "24.0.0" [lib] bench = false [features] -__rkyv = [] default = [] encoding-impl = [ "cbor4ii", "swc_atoms/encoding-impl", "swc_common/encoding-impl", ] -rkyv-impl = [ - "__rkyv", - "rkyv", - "swc_atoms/rkyv-impl", - "swc_common/rkyv-impl", - "bytecheck", -] serde-impl = ["serde"] [dependencies] -bytecheck = { workspace = true, optional = true } is-macro = { workspace = true } serde = { workspace = true, features = ["derive"], optional = true } string_enum = { version = "1.0.2", path = "../string_enum/" } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } cbor4ii = { workspace = true, features = ["use_std"], optional = true } -rkyv = { workspace = true, optional = true } diff --git a/deps/swc/crates/swc_css_ast/src/at_rule.rs b/deps/swc/crates/swc_css_ast/src/at_rule.rs index b986304de..b764f6afe 100644 --- a/deps/swc/crates/swc_css_ast/src/at_rule.rs +++ b/deps/swc/crates/swc_css_ast/src/at_rule.rs @@ -509,21 +509,10 @@ pub struct MediaFeatureBoolean { } #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Is, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) )] -//#[cfg_attr( -// feature = "rkyv", -// archive(bound(serialize = "__S: rkyv::ser::ScratchSpace + -// rkyv::ser::Serializer")) -//)] pub enum MediaFeatureRangeComparison { /// `<` Lt, @@ -876,17 +865,6 @@ pub struct SizeFeatureBoolean { } #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Is, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(u32))] -//#[cfg_attr( -// feature = "rkyv", -// archive(bound(serialize = "__S: rkyv::ser::ScratchSpace + -// rkyv::ser::Serializer")) -//)] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) diff --git a/deps/swc/crates/swc_css_ast/src/selector.rs b/deps/swc/crates/swc_css_ast/src/selector.rs index aa2a56f67..4225b9ed6 100644 --- a/deps/swc/crates/swc_css_ast/src/selector.rs +++ b/deps/swc/crates/swc_css_ast/src/selector.rs @@ -131,17 +131,6 @@ pub struct Combinator { } #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Is, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) @@ -299,17 +288,6 @@ pub struct AttributeSelector { } #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Is, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(u32))] -//#[cfg_attr( -// feature = "rkyv", -// archive(bound(serialize = "__S: rkyv::ser::ScratchSpace + -// rkyv::ser::Serializer")) -//)] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) diff --git a/deps/swc/crates/swc_css_ast/src/token.rs b/deps/swc/crates/swc_css_ast/src/token.rs index a741ecf39..021a87b42 100644 --- a/deps/swc/crates/swc_css_ast/src/token.rs +++ b/deps/swc/crates/swc_css_ast/src/token.rs @@ -24,12 +24,6 @@ impl Take for TokenAndSpan { #[derive(Debug, Clone, PartialEq, EqIgnoreSpan, Hash)] #[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) @@ -37,17 +31,6 @@ impl Take for TokenAndSpan { pub struct UrlKeyValue(pub Atom, pub Atom); #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Is, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(u32))] -#[cfg_attr( - feature = "rkyv", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) -)] #[cfg_attr(feature = "serde-impl", derive(Serialize, Deserialize))] #[cfg_attr( feature = "encoding-impl", @@ -61,12 +44,6 @@ pub enum NumberType { } #[derive(Debug, Clone, PartialEq, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(C))] #[cfg_attr(feature = "serde-impl", derive(Serialize, Deserialize))] #[cfg_attr( feature = "encoding-impl", @@ -84,17 +61,6 @@ pub struct DimensionToken { } #[derive(Debug, Clone, PartialEq, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(u32))] -#[cfg_attr( - feature = "rkyv", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) -)] #[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( feature = "encoding-impl", diff --git a/deps/swc/crates/swc_css_ast/src/value.rs b/deps/swc/crates/swc_css_ast/src/value.rs index 5a0bfce39..4e19dfcac 100644 --- a/deps/swc/crates/swc_css_ast/src/value.rs +++ b/deps/swc/crates/swc_css_ast/src/value.rs @@ -132,17 +132,6 @@ impl EqIgnoreSpan for Str { } #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Is, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) @@ -429,17 +418,6 @@ pub struct Ratio { } #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Is, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) @@ -560,17 +538,6 @@ pub struct CalcOperator { } #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Is, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) diff --git a/deps/swc/crates/swc_css_codegen/Cargo.toml b/deps/swc/crates/swc_css_codegen/Cargo.toml index d6816218c..1a2d90de4 100644 --- a/deps/swc/crates/swc_css_codegen/Cargo.toml +++ b/deps/swc/crates/swc_css_codegen/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_css_codegen" repository = { workspace = true } -version = "23.0.0" +version = "24.0.0" [lib] bench = false @@ -18,16 +18,16 @@ bitflags = { workspace = true } rustc-hash = { workspace = true } serde = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast" } swc_css_codegen_macros = { version = "1.0.2", path = "../swc_css_codegen_macros" } -swc_css_utils = { version = "23.0.0", path = "../swc_css_utils" } +swc_css_utils = { version = "24.0.0", path = "../swc_css_utils" } [dev-dependencies] -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "sourcemap", ] } -swc_css_parser = { version = "23.0.0", path = "../swc_css_parser" } -swc_css_visit = { version = "23.0.0", path = "../swc_css_visit" } -testing = { version = "24.0.1", path = "../testing" } +swc_css_parser = { version = "24.0.0", path = "../swc_css_parser" } +swc_css_visit = { version = "24.0.0", path = "../swc_css_visit" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_css_compat/Cargo.toml b/deps/swc/crates/swc_css_compat/Cargo.toml index 9202ed4c3..734df5c2d 100644 --- a/deps/swc/crates/swc_css_compat/Cargo.toml +++ b/deps/swc/crates/swc_css_compat/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/**/*.json", "data/**/*.json"] license = { workspace = true } name = "swc_css_compat" repository = { workspace = true } -version = "23.0.0" +version = "24.0.0" [lib] bench = false @@ -16,13 +16,13 @@ bench = false bitflags = { workspace = true } serde = { workspace = true, features = ["derive"] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast" } -swc_css_utils = { version = "23.0.0", path = "../swc_css_utils/" } -swc_css_visit = { version = "23.0.0", path = "../swc_css_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast" } +swc_css_utils = { version = "24.0.0", path = "../swc_css_utils/" } +swc_css_visit = { version = "24.0.0", path = "../swc_css_visit" } [dev-dependencies] -swc_css_codegen = { version = "23.0.0", path = "../swc_css_codegen" } -swc_css_parser = { version = "23.0.0", path = "../swc_css_parser" } -testing = { version = "24.0.1", path = "../testing" } +swc_css_codegen = { version = "24.0.0", path = "../swc_css_codegen" } +swc_css_parser = { version = "24.0.0", path = "../swc_css_parser" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_css_lints/Cargo.toml b/deps/swc/crates/swc_css_lints/Cargo.toml index f1c10eb6c..d7835c644 100644 --- a/deps/swc/crates/swc_css_lints/Cargo.toml +++ b/deps/swc/crates/swc_css_lints/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_css_lints" repository = { workspace = true } -version = "25.0.0" +version = "27.0.0" [lib] bench = false @@ -21,14 +21,14 @@ rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } thiserror = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_config = { version = "5.0.0", path = "../swc_config", features = ["regex"] } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast" } -swc_css_visit = { version = "23.0.0", path = "../swc_css_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_config = { version = "6.0.0", path = "../swc_config", features = ["regex"] } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast" } +swc_css_visit = { version = "24.0.0", path = "../swc_css_visit" } [dev-dependencies] serde_json = { workspace = true } -swc_css_parser = { version = "23.0.0", path = "../swc_css_parser" } -testing = { version = "24.0.1", path = "../testing" } +swc_css_parser = { version = "24.0.0", path = "../swc_css_parser" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_css_minifier/Cargo.toml b/deps/swc/crates/swc_css_minifier/Cargo.toml index c9c969450..022cb8ad2 100644 --- a/deps/swc/crates/swc_css_minifier/Cargo.toml +++ b/deps/swc/crates/swc_css_minifier/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_css_minifier" repository = { workspace = true } -version = "23.0.0" +version = "24.0.0" [lib] bench = false @@ -16,14 +16,14 @@ bench = false rustc-hash = { workspace = true } serde = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast" } -swc_css_utils = { version = "23.0.0", path = "../swc_css_utils/" } -swc_css_visit = { version = "23.0.0", path = "../swc_css_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast" } +swc_css_utils = { version = "24.0.0", path = "../swc_css_utils/" } +swc_css_visit = { version = "24.0.0", path = "../swc_css_visit" } [dev-dependencies] -swc_css_codegen = { version = "23.0.0", path = "../swc_css_codegen" } -swc_css_parser = { version = "23.0.0", path = "../swc_css_parser" } -testing = { version = "24.0.1", path = "../testing" } +swc_css_codegen = { version = "24.0.0", path = "../swc_css_codegen" } +swc_css_parser = { version = "24.0.0", path = "../swc_css_parser" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_css_modules/Cargo.toml b/deps/swc/crates/swc_css_modules/Cargo.toml index d41f853ad..04ce4e65c 100644 --- a/deps/swc/crates/swc_css_modules/Cargo.toml +++ b/deps/swc/crates/swc_css_modules/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_css_modules" repository = { workspace = true } -version = "23.0.0" +version = "24.0.0" [lib] bench = false @@ -18,15 +18,15 @@ bench = false rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast" } -swc_css_codegen = { version = "23.0.0", path = "../swc_css_codegen" } -swc_css_parser = { version = "23.0.0", path = "../swc_css_parser" } -swc_css_visit = { version = "23.0.0", path = "../swc_css_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast" } +swc_css_codegen = { version = "24.0.0", path = "../swc_css_codegen" } +swc_css_parser = { version = "24.0.0", path = "../swc_css_parser" } +swc_css_visit = { version = "24.0.0", path = "../swc_css_visit" } [dev-dependencies] indexmap = { workspace = true, features = ["serde"] } -swc_css_compat = { version = "23.0.0", path = "../swc_css_compat" } -testing = { version = "24.0.1", path = "../testing" } +swc_css_compat = { version = "24.0.0", path = "../swc_css_compat" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_css_parser/Cargo.toml b/deps/swc/crates/swc_css_parser/Cargo.toml index 118705309..38baf4b98 100644 --- a/deps/swc/crates/swc_css_parser/Cargo.toml +++ b/deps/swc/crates/swc_css_parser/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_css_parser" repository = { workspace = true } -version = "23.0.0" +version = "24.0.0" [lib] bench = false @@ -19,20 +19,20 @@ debug = [] lexical = { workspace = true } serde = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast" } [dev-dependencies] codspeed-criterion-compat = { workspace = true } serde_json = { workspace = true } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast", features = [ +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast", features = [ "serde-impl", ] } -swc_css_visit = { version = "23.0.0", path = "../swc_css_visit" } +swc_css_visit = { version = "24.0.0", path = "../swc_css_visit" } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } [[bench]] harness = false diff --git a/deps/swc/crates/swc_css_prefixer/Cargo.toml b/deps/swc/crates/swc_css_prefixer/Cargo.toml index f0c704557..2d8efb239 100644 --- a/deps/swc/crates/swc_css_prefixer/Cargo.toml +++ b/deps/swc/crates/swc_css_prefixer/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/**/*.json", "data/**/*.json"] license = { workspace = true } name = "swc_css_prefixer" repository = { workspace = true } -version = "28.0.0" +version = "29.0.0" [lib] bench = false @@ -19,13 +19,13 @@ serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } preset_env_base = { version = "8.0.1", path = "../preset_env_base" } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast" } -swc_css_utils = { version = "23.0.0", path = "../swc_css_utils/" } -swc_css_visit = { version = "23.0.0", path = "../swc_css_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast" } +swc_css_utils = { version = "24.0.0", path = "../swc_css_utils/" } +swc_css_visit = { version = "24.0.0", path = "../swc_css_visit" } [dev-dependencies] -swc_css_codegen = { version = "23.0.0", path = "../swc_css_codegen" } -swc_css_parser = { version = "23.0.0", path = "../swc_css_parser" } -testing = { version = "24.0.1", path = "../testing" } +swc_css_codegen = { version = "24.0.0", path = "../swc_css_codegen" } +swc_css_parser = { version = "24.0.0", path = "../swc_css_parser" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_css_utils/Cargo.toml b/deps/swc/crates/swc_css_utils/Cargo.toml index 1fc26037e..e401ed1fb 100644 --- a/deps/swc/crates/swc_css_utils/Cargo.toml +++ b/deps/swc/crates/swc_css_utils/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/**/*.json"] license = { workspace = true } name = "swc_css_utils" repository = { workspace = true } -version = "23.0.0" +version = "24.0.0" [lib] bench = false @@ -18,6 +18,6 @@ rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast" } -swc_css_visit = { version = "23.0.0", path = "../swc_css_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast" } +swc_css_visit = { version = "24.0.0", path = "../swc_css_visit" } diff --git a/deps/swc/crates/swc_css_visit/Cargo.toml b/deps/swc/crates/swc_css_visit/Cargo.toml index 3e61eba9f..eaf9fdf62 100644 --- a/deps/swc/crates/swc_css_visit/Cargo.toml +++ b/deps/swc/crates/swc_css_visit/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_css_visit" repository = { workspace = true } -version = "23.0.0" +version = "24.0.0" [package.metadata.docs.rs] all-features = true @@ -23,7 +23,7 @@ serde-impl = ["serde"] [dependencies] serde = { workspace = true, optional = true, features = ["derive"] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast" } swc_visit = { version = "2.0.1", path = "../swc_visit" } diff --git a/deps/swc/crates/swc_ecma_ast/Cargo.toml b/deps/swc/crates/swc_ecma_ast/Cargo.toml index 1815d32e8..9c2727be4 100644 --- a/deps/swc/crates/swc_ecma_ast/Cargo.toml +++ b/deps/swc/crates/swc_ecma_ast/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_ast" repository = { workspace = true } -version = "25.0.0" +version = "27.0.0" [package.metadata.docs.rs] all-features = true @@ -19,7 +19,6 @@ bench = false unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [features] -__rkyv = [] default = [] encoding-impl = [ "cbor4ii", @@ -27,14 +26,6 @@ encoding-impl = [ "swc_common/encoding-impl", ] fuzzing = ["arbitrary", "swc_atoms/arbitrary", "swc_common/arbitrary"] -rkyv-impl = [ - "__rkyv", - "rkyv", - "bytecheck", - "rancor", - "swc_atoms/rkyv-impl", - "swc_common/rkyv-impl", -] serde-impl = ["serde"] shrink-to-fit = [ "dep:shrink-to-fit", @@ -45,21 +36,18 @@ shrink-to-fit = [ [dependencies] arbitrary = { workspace = true, features = ["derive"], optional = true } bitflags = { workspace = true } -bytecheck = { workspace = true, optional = true } is-macro = { workspace = true } num-bigint = { workspace = true, features = ["serde"] } once_cell = { workspace = true } phf = { workspace = true, features = ["macros"] } -rancor = { workspace = true, optional = true } -rkyv = { workspace = true, optional = true } rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"], optional = true } shrink-to-fit = { workspace = true, optional = true } unicode-id-start = { workspace = true } string_enum = { version = "1.0.2", path = "../string_enum" } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } swc_visit = { version = "2.0.1", path = "../swc_visit" } cbor4ii = { workspace = true, features = ["use_std"], optional = true } diff --git a/deps/swc/crates/swc_ecma_ast/src/class.rs b/deps/swc/crates/swc_ecma_ast/src/class.rs index b3591a11e..dff1ca115 100644 --- a/deps/swc/crates/swc_ecma_ast/src/class.rs +++ b/deps/swc/crates/swc_ecma_ast/src/class.rs @@ -315,12 +315,6 @@ pub struct Decorator { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EqIgnoreSpan, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] #[cfg_attr( diff --git a/deps/swc/crates/swc_ecma_ast/src/decl.rs b/deps/swc/crates/swc_ecma_ast/src/decl.rs index 8e8ecfd40..0b8a9e10f 100644 --- a/deps/swc/crates/swc_ecma_ast/src/decl.rs +++ b/deps/swc/crates/swc_ecma_ast/src/decl.rs @@ -172,12 +172,6 @@ impl Take for VarDecl { #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, EqIgnoreSpan, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] #[cfg_attr( feature = "encoding-impl", diff --git a/deps/swc/crates/swc_ecma_ast/src/expr.rs b/deps/swc/crates/swc_ecma_ast/src/expr.rs index 56ff932ef..1c8fb6284 100644 --- a/deps/swc/crates/swc_ecma_ast/src/expr.rs +++ b/deps/swc/crates/swc_ecma_ast/src/expr.rs @@ -1154,12 +1154,6 @@ pub struct MetaPropExpr { #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, EqIgnoreSpan)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] #[cfg_attr( feature = "encoding-impl", @@ -1369,27 +1363,6 @@ impl Take for Import { #[derive(Clone, Debug, PartialEq, Eq, Hash, EqIgnoreSpan)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) -)] -#[cfg_attr( - feature = "rkyv-impl", - rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source)) -)] -#[cfg_attr( - feature = "rkyv-impl", - rkyv(bytecheck(bounds( - __C: rkyv::validation::ArchiveContext, - __C::Error: rkyv::rancor::Source - ))) - )] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( feature = "encoding-impl", @@ -1397,7 +1370,6 @@ impl Take for Import { )] pub struct ExprOrSpread { #[cfg_attr(feature = "serde-impl", serde(default))] - #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] #[cfg_attr( feature = "encoding-impl", encoding(with = "cbor4ii::core::types::Maybe") @@ -1405,7 +1377,6 @@ pub struct ExprOrSpread { pub spread: Option, #[cfg_attr(feature = "serde-impl", serde(rename = "expression"))] - #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub expr: Box, } diff --git a/deps/swc/crates/swc_ecma_ast/src/ident.rs b/deps/swc/crates/swc_ecma_ast/src/ident.rs index 38a68175f..afe9f25ae 100644 --- a/deps/swc/crates/swc_ecma_ast/src/ident.rs +++ b/deps/swc/crates/swc_ecma_ast/src/ident.rs @@ -17,27 +17,6 @@ use crate::{typescript::TsTypeAnn, Expr}; /// Identifier used as a pattern. #[derive(Clone, Debug, PartialEq, Eq, Hash, EqIgnoreSpan, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-impl", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) -)] -#[cfg_attr( - feature = "rkyv-impl", - rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source)) -)] -#[cfg_attr( - feature = "rkyv-impl", - rkyv(bytecheck(bounds( - __C: rkyv::validation::ArchiveContext, - __C::Error: rkyv::rancor::Source - ))) -)] -#[cfg_attr(feature = "rkyv-impl", repr(C))] #[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] #[cfg_attr( @@ -46,11 +25,9 @@ use crate::{typescript::TsTypeAnn, Expr}; )] pub struct BindingIdent { #[cfg_attr(feature = "serde-impl", serde(flatten))] - #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub id: Ident, #[cfg_attr(feature = "serde-impl", serde(default, rename = "typeAnnotation"))] - #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] #[cfg_attr( feature = "encoding-impl", encoding(with = "cbor4ii::core::types::Maybe") @@ -181,10 +158,8 @@ bridge_from!(BindingIdent, Ident, Id); #[derive(Eq, Hash, Default)] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] pub struct Ident { - #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub span: Span, - #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub ctxt: SyntaxContext, #[cfg_attr(feature = "serde-impl", serde(rename = "value"))] @@ -420,7 +395,6 @@ impl Ident { #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] pub struct IdentName { - #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub span: Span, #[cfg_attr(feature = "serde-impl", serde(rename = "value"))] diff --git a/deps/swc/crates/swc_ecma_ast/src/lib.rs b/deps/swc/crates/swc_ecma_ast/src/lib.rs index faed62d44..2003e91d6 100644 --- a/deps/swc/crates/swc_ecma_ast/src/lib.rs +++ b/deps/swc/crates/swc_ecma_ast/src/lib.rs @@ -400,367 +400,3 @@ impl EsVersion { EsVersion::EsNext } } - -/// Warning: The particular implementation of serialization and deserialization -/// of the ast nodes may change in the future, and so these types would be -/// removed. It's safe to say they will be serializable in some form or another, -/// but not necessarily with these specific types underlying the implementation. -/// As such, *use these types at your own risk*. -#[cfg(feature = "rkyv-impl")] -#[doc(hidden)] -pub use self::{ - class::{ - ArchivedAutoAccessor, ArchivedClass, ArchivedClassMember, ArchivedClassMethod, - ArchivedClassProp, ArchivedConstructor, ArchivedDecorator, ArchivedKey, ArchivedMethodKind, - ArchivedPrivateMethod, ArchivedPrivateProp, ArchivedStaticBlock, - }, - decl::{ - ArchivedClassDecl, ArchivedDecl, ArchivedFnDecl, ArchivedUsingDecl, ArchivedVarDecl, - ArchivedVarDeclKind, ArchivedVarDeclarator, - }, - expr::{ - ArchivedArrayLit, ArchivedArrowExpr, ArchivedAssignExpr, ArchivedAssignTarget, - ArchivedAwaitExpr, ArchivedBinExpr, ArchivedBlockStmtOrExpr, ArchivedCallExpr, - ArchivedCallee, ArchivedClassExpr, ArchivedCondExpr, ArchivedExpr, ArchivedExprOrSpread, - ArchivedFnExpr, ArchivedImport, ArchivedMemberExpr, ArchivedMemberProp, - ArchivedMetaPropExpr, ArchivedMetaPropKind, ArchivedNewExpr, ArchivedObjectLit, - ArchivedOptCall, ArchivedOptChainBase, ArchivedOptChainExpr, ArchivedParenExpr, - ArchivedPropOrSpread, ArchivedSeqExpr, ArchivedSpreadElement, ArchivedSuper, - ArchivedSuperProp, ArchivedSuperPropExpr, ArchivedTaggedTpl, ArchivedThisExpr, ArchivedTpl, - ArchivedTplElement, ArchivedUnaryExpr, ArchivedUpdateExpr, ArchivedYieldExpr, - }, - function::{ArchivedFunction, ArchivedParam, ArchivedParamOrTsParamProp}, - ident::{ArchivedBindingIdent, ArchivedIdent, ArchivedIdentName, ArchivedPrivateName}, - jsx::{ - ArchivedJSXAttr, ArchivedJSXAttrName, ArchivedJSXAttrOrSpread, ArchivedJSXAttrValue, - ArchivedJSXClosingElement, ArchivedJSXClosingFragment, ArchivedJSXElement, - ArchivedJSXElementChild, ArchivedJSXElementName, ArchivedJSXEmptyExpr, ArchivedJSXExpr, - ArchivedJSXExprContainer, ArchivedJSXFragment, ArchivedJSXMemberExpr, - ArchivedJSXNamespacedName, ArchivedJSXObject, ArchivedJSXOpeningElement, - ArchivedJSXOpeningFragment, ArchivedJSXSpreadChild, ArchivedJSXText, - }, - lit::{ - ArchivedBigInt, ArchivedBool, ArchivedLit, ArchivedNull, ArchivedNumber, ArchivedRegex, - ArchivedStr, - }, - module::{ArchivedModule, ArchivedModuleItem, ArchivedProgram, ArchivedScript}, - module_decl::{ - ArchivedDefaultDecl, ArchivedExportAll, ArchivedExportDecl, ArchivedExportDefaultDecl, - ArchivedExportDefaultExpr, ArchivedExportDefaultSpecifier, ArchivedExportNamedSpecifier, - ArchivedExportNamespaceSpecifier, ArchivedExportSpecifier, ArchivedImportDecl, - ArchivedImportDefaultSpecifier, ArchivedImportNamedSpecifier, ArchivedImportSpecifier, - ArchivedImportStarAsSpecifier, ArchivedModuleDecl, ArchivedModuleExportName, - ArchivedNamedExport, - }, - operators::{ArchivedAssignOp, ArchivedBinaryOp, ArchivedUnaryOp, ArchivedUpdateOp}, - pat::{ - ArchivedArrayPat, ArchivedAssignPat, ArchivedAssignPatProp, ArchivedKeyValuePatProp, - ArchivedObjectPat, ArchivedObjectPatProp, ArchivedPat, ArchivedRestPat, - }, - prop::{ - ArchivedAssignProp, ArchivedComputedPropName, ArchivedGetterProp, ArchivedKeyValueProp, - ArchivedMethodProp, ArchivedProp, ArchivedPropName, ArchivedSetterProp, - }, - stmt::{ - ArchivedBlockStmt, ArchivedBreakStmt, ArchivedCatchClause, ArchivedContinueStmt, - ArchivedDebuggerStmt, ArchivedDoWhileStmt, ArchivedEmptyStmt, ArchivedExprStmt, - ArchivedForHead, ArchivedForInStmt, ArchivedForOfStmt, ArchivedForStmt, ArchivedIfStmt, - ArchivedLabeledStmt, ArchivedReturnStmt, ArchivedStmt, ArchivedSwitchCase, - ArchivedSwitchStmt, ArchivedThrowStmt, ArchivedTryStmt, ArchivedVarDeclOrExpr, - ArchivedWhileStmt, ArchivedWithStmt, - }, - typescript::{ - ArchivedAccessibility, ArchivedTruePlusMinus, ArchivedTsArrayType, ArchivedTsAsExpr, - ArchivedTsCallSignatureDecl, ArchivedTsConditionalType, ArchivedTsConstAssertion, - ArchivedTsConstructSignatureDecl, ArchivedTsConstructorType, ArchivedTsEntityName, - ArchivedTsEnumDecl, ArchivedTsEnumMember, ArchivedTsEnumMemberId, - ArchivedTsExportAssignment, ArchivedTsExprWithTypeArgs, ArchivedTsExternalModuleRef, - ArchivedTsFnOrConstructorType, ArchivedTsFnParam, ArchivedTsFnType, - ArchivedTsGetterSignature, ArchivedTsImportEqualsDecl, ArchivedTsImportType, - ArchivedTsIndexSignature, ArchivedTsIndexedAccessType, ArchivedTsInferType, - ArchivedTsInstantiation, ArchivedTsInterfaceBody, ArchivedTsInterfaceDecl, - ArchivedTsIntersectionType, ArchivedTsKeywordType, ArchivedTsKeywordTypeKind, - ArchivedTsLit, ArchivedTsLitType, ArchivedTsMappedType, ArchivedTsMethodSignature, - ArchivedTsModuleBlock, ArchivedTsModuleDecl, ArchivedTsModuleName, ArchivedTsModuleRef, - ArchivedTsNamespaceBody, ArchivedTsNamespaceDecl, ArchivedTsNamespaceExportDecl, - ArchivedTsNonNullExpr, ArchivedTsOptionalType, ArchivedTsParamProp, - ArchivedTsParamPropParam, ArchivedTsParenthesizedType, ArchivedTsPropertySignature, - ArchivedTsQualifiedName, ArchivedTsRestType, ArchivedTsSatisfiesExpr, - ArchivedTsSetterSignature, ArchivedTsThisType, ArchivedTsThisTypeOrIdent, - ArchivedTsTplLitType, ArchivedTsTupleElement, ArchivedTsTupleType, ArchivedTsType, - ArchivedTsTypeAliasDecl, ArchivedTsTypeAnn, ArchivedTsTypeAssertion, ArchivedTsTypeElement, - ArchivedTsTypeLit, ArchivedTsTypeOperator, ArchivedTsTypeOperatorOp, ArchivedTsTypeParam, - ArchivedTsTypeParamDecl, ArchivedTsTypeParamInstantiation, ArchivedTsTypePredicate, - ArchivedTsTypeQuery, ArchivedTsTypeQueryExpr, ArchivedTsTypeRef, - ArchivedTsUnionOrIntersectionType, ArchivedTsUnionType, - }, -}; - -#[cfg(feature = "rkyv-impl")] -mod rkyv_layout_assert { - use crate::*; - - macro_rules! assert_size { - ($T:ty, $size:expr) => { - const _: fn() = || { - let _ = std::mem::transmute::<$T, [u8; $size]>; - }; - }; - } - - assert_size!(ArchivedProgram, 32); - assert_size!(ArchivedModule, 28); - assert_size!(ArchivedScript, 28); - assert_size!(ArchivedModuleItem, 52); - - // Class types - assert_size!(ArchivedAutoAccessor, 96); - assert_size!(ArchivedClass, 64); - assert_size!(ArchivedClassMember, 104); - assert_size!(ArchivedClassMethod, 64); - assert_size!(ArchivedClassProp, 88); - assert_size!(ArchivedConstructor, 96); - assert_size!(ArchivedDecorator, 12); - assert_size!(ArchivedKey, 48); - assert_size!(ArchivedMethodKind, 1); - assert_size!(ArchivedPrivateMethod, 36); - assert_size!(ArchivedPrivateProp, 64); - assert_size!(ArchivedStaticBlock, 28); - - // Declaration types - assert_size!(ArchivedClassDecl, 32); - assert_size!(ArchivedDecl, 36); - assert_size!(ArchivedFnDecl, 32); - assert_size!(ArchivedUsingDecl, 20); - assert_size!(ArchivedVarDecl, 24); - assert_size!(ArchivedVarDeclKind, 1); - assert_size!(ArchivedVarDeclarator, 56); - - // Expression types - assert_size!(ArchivedArrayLit, 16); - assert_size!(ArchivedArrowExpr, 44); - assert_size!(ArchivedAssignExpr, 60); - assert_size!(ArchivedAssignTarget, 44); - assert_size!(ArchivedAwaitExpr, 12); - assert_size!(ArchivedBinExpr, 20); - assert_size!(ArchivedBlockStmtOrExpr, 24); - assert_size!(ArchivedCallExpr, 44); - assert_size!(ArchivedCallee, 16); - assert_size!(ArchivedClassExpr, 32); - assert_size!(ArchivedCondExpr, 20); - assert_size!(ArchivedExpr, 64); - assert_size!(ArchivedExprOrSpread, 16); - assert_size!(ArchivedFnExpr, 32); - assert_size!(ArchivedImport, 12); - assert_size!(ArchivedMemberExpr, 32); - assert_size!(ArchivedMemberProp, 20); - assert_size!(ArchivedMetaPropExpr, 12); - assert_size!(ArchivedMetaPropKind, 1); - assert_size!(ArchivedNewExpr, 36); - assert_size!(ArchivedObjectLit, 16); - assert_size!(ArchivedOptCall, 32); - assert_size!(ArchivedOptChainBase, 36); - assert_size!(ArchivedOptChainExpr, 16); - assert_size!(ArchivedParenExpr, 12); - assert_size!(ArchivedPropOrSpread, 16); - assert_size!(ArchivedSeqExpr, 16); - assert_size!(ArchivedSpreadElement, 12); - assert_size!(ArchivedSuper, 8); - assert_size!(ArchivedSuperProp, 20); - assert_size!(ArchivedSuperPropExpr, 36); - assert_size!(ArchivedTaggedTpl, 28); - assert_size!(ArchivedThisExpr, 8); - assert_size!(ArchivedTpl, 24); - assert_size!(ArchivedTplElement, 32); - assert_size!(ArchivedUnaryExpr, 16); - assert_size!(ArchivedUpdateExpr, 16); - assert_size!(ArchivedYieldExpr, 20); - - // Function types - assert_size!(ArchivedFunction, 72); - assert_size!(ArchivedParam, 52); - assert_size!(ArchivedParamOrTsParamProp, 60); - - // Identifier types - assert_size!(ArchivedBindingIdent, 32); - assert_size!(ArchivedIdent, 24); - assert_size!(ArchivedIdentName, 16); - assert_size!(ArchivedPrivateName, 16); - - // JSX types - assert_size!(ArchivedJSXAttr, 92); - assert_size!(ArchivedJSXAttrName, 44); - assert_size!(ArchivedJSXAttrOrSpread, 96); - assert_size!(ArchivedJSXAttrValue, 36); - assert_size!(ArchivedJSXClosingElement, 64); - assert_size!(ArchivedJSXClosingFragment, 8); - assert_size!(ArchivedJSXElement, 168); - assert_size!(ArchivedJSXElementChild, 36); - assert_size!(ArchivedJSXElementName, 56); - assert_size!(ArchivedJSXEmptyExpr, 8); - assert_size!(ArchivedJSXExpr, 12); - assert_size!(ArchivedJSXExprContainer, 20); - assert_size!(ArchivedJSXFragment, 32); - assert_size!(ArchivedJSXMemberExpr, 52); - assert_size!(ArchivedJSXNamespacedName, 40); - assert_size!(ArchivedJSXObject, 28); - assert_size!(ArchivedJSXOpeningElement, 84); - assert_size!(ArchivedJSXOpeningFragment, 8); - assert_size!(ArchivedJSXSpreadChild, 12); - assert_size!(ArchivedJSXText, 24); - - // Literal types - assert_size!(ArchivedBigInt, 28); - assert_size!(ArchivedBool, 12); - assert_size!(ArchivedLit, 40); - assert_size!(ArchivedNull, 8); - assert_size!(ArchivedNumber, 32); - assert_size!(ArchivedRegex, 24); - assert_size!(ArchivedStr, 28); - - // Module declaration types - assert_size!(ArchivedDefaultDecl, 36); - assert_size!(ArchivedExportAll, 24); - assert_size!(ArchivedExportDecl, 44); - assert_size!(ArchivedExportDefaultDecl, 44); - assert_size!(ArchivedExportDefaultExpr, 12); - assert_size!(ArchivedExportDefaultSpecifier, 24); - assert_size!(ArchivedExportNamedSpecifier, 80); - assert_size!(ArchivedExportNamespaceSpecifier, 40); - assert_size!(ArchivedExportSpecifier, 84); - assert_size!(ArchivedImportDecl, 36); - assert_size!(ArchivedImportDefaultSpecifier, 32); - assert_size!(ArchivedImportNamedSpecifier, 72); - assert_size!(ArchivedImportSpecifier, 76); - assert_size!(ArchivedImportStarAsSpecifier, 32); - assert_size!(ArchivedModuleDecl, 48); - assert_size!(ArchivedModuleExportName, 32); - assert_size!(ArchivedNamedExport, 36); - - // Operator types - assert_size!(ArchivedAssignOp, 1); - assert_size!(ArchivedBinaryOp, 1); - assert_size!(ArchivedUnaryOp, 1); - assert_size!(ArchivedUpdateOp, 1); - - // Pattern types - assert_size!(ArchivedArrayPat, 28); - assert_size!(ArchivedAssignPat, 16); - assert_size!(ArchivedAssignPatProp, 48); - assert_size!(ArchivedKeyValuePatProp, 48); - assert_size!(ArchivedObjectPat, 28); - assert_size!(ArchivedObjectPatProp, 56); - assert_size!(ArchivedPat, 36); - assert_size!(ArchivedRestPat, 28); - - // Property types - assert_size!(ArchivedAssignProp, 36); - assert_size!(ArchivedComputedPropName, 12); - assert_size!(ArchivedGetterProp, 80); - assert_size!(ArchivedKeyValueProp, 48); - assert_size!(ArchivedMethodProp, 48); - assert_size!(ArchivedProp, 128); - assert_size!(ArchivedPropName, 40); - assert_size!(ArchivedSetterProp, 120); - - // Statement types - assert_size!(ArchivedBlockStmt, 20); - assert_size!(ArchivedBreakStmt, 36); - assert_size!(ArchivedCatchClause, 68); - assert_size!(ArchivedContinueStmt, 36); - assert_size!(ArchivedDebuggerStmt, 8); - assert_size!(ArchivedDoWhileStmt, 16); - assert_size!(ArchivedEmptyStmt, 8); - assert_size!(ArchivedExprStmt, 12); - assert_size!(ArchivedForHead, 8); - assert_size!(ArchivedForInStmt, 24); - assert_size!(ArchivedForOfStmt, 28); - assert_size!(ArchivedForStmt, 40); - assert_size!(ArchivedIfStmt, 24); - assert_size!(ArchivedLabeledStmt, 36); - assert_size!(ArchivedReturnStmt, 16); - assert_size!(ArchivedStmt, 44); - assert_size!(ArchivedSwitchCase, 24); - assert_size!(ArchivedSwitchStmt, 20); - assert_size!(ArchivedThrowStmt, 12); - assert_size!(ArchivedTryStmt, 124); - assert_size!(ArchivedVarDeclOrExpr, 8); - assert_size!(ArchivedWhileStmt, 16); - assert_size!(ArchivedWithStmt, 16); - - // TypeScript types - assert_size!(ArchivedAccessibility, 1); - assert_size!(ArchivedTruePlusMinus, 1); - assert_size!(ArchivedTsArrayType, 12); - assert_size!(ArchivedTsAsExpr, 16); - assert_size!(ArchivedTsCallSignatureDecl, 32); - assert_size!(ArchivedTsConditionalType, 24); - assert_size!(ArchivedTsConstAssertion, 12); - assert_size!(ArchivedTsConstructSignatureDecl, 32); - assert_size!(ArchivedTsConstructorType, 32); - assert_size!(ArchivedTsEntityName, 28); - assert_size!(ArchivedTsEnumDecl, 44); - assert_size!(ArchivedTsEnumMember, 48); - assert_size!(ArchivedTsEnumMemberId, 32); - assert_size!(ArchivedTsExportAssignment, 12); - assert_size!(ArchivedTsExprWithTypeArgs, 20); - assert_size!(ArchivedTsExternalModuleRef, 36); - assert_size!(ArchivedTsFnOrConstructorType, 36); - assert_size!(ArchivedTsFnParam, 36); - assert_size!(ArchivedTsFnType, 28); - assert_size!(ArchivedTsGetterSignature, 24); - assert_size!(ArchivedTsImportEqualsDecl, 76); - assert_size!(ArchivedTsImportType, 92); - assert_size!(ArchivedTsIndexSignature, 28); - assert_size!(ArchivedTsIndexedAccessType, 20); - assert_size!(ArchivedTsInferType, 60); - assert_size!(ArchivedTsInstantiation, 16); - assert_size!(ArchivedTsInterfaceBody, 16); - assert_size!(ArchivedTsInterfaceDecl, 68); - assert_size!(ArchivedTsIntersectionType, 16); - assert_size!(ArchivedTsKeywordType, 12); - assert_size!(ArchivedTsKeywordTypeKind, 1); - assert_size!(ArchivedTsLit, 40); - assert_size!(ArchivedTsLitType, 48); - assert_size!(ArchivedTsMappedType, 84); - assert_size!(ArchivedTsMethodSignature, 40); - assert_size!(ArchivedTsModuleBlock, 16); - assert_size!(ArchivedTsModuleDecl, 92); - assert_size!(ArchivedTsModuleName, 32); - assert_size!(ArchivedTsModuleRef, 40); - assert_size!(ArchivedTsNamespaceBody, 44); - assert_size!(ArchivedTsNamespaceDecl, 40); - assert_size!(ArchivedTsNamespaceExportDecl, 32); - assert_size!(ArchivedTsNonNullExpr, 12); - assert_size!(ArchivedTsOptionalType, 12); - assert_size!(ArchivedTsParamProp, 56); - assert_size!(ArchivedTsParamPropParam, 36); - assert_size!(ArchivedTsParenthesizedType, 12); - assert_size!(ArchivedTsPropertySignature, 28); - assert_size!(ArchivedTsQualifiedName, 52); - assert_size!(ArchivedTsRestType, 12); - assert_size!(ArchivedTsSatisfiesExpr, 16); - assert_size!(ArchivedTsSetterSignature, 52); - assert_size!(ArchivedTsThisType, 8); - assert_size!(ArchivedTsThisTypeOrIdent, 28); - assert_size!(ArchivedTsTplLitType, 24); - assert_size!(ArchivedTsTupleElement, 52); - assert_size!(ArchivedTsTupleType, 16); - assert_size!(ArchivedTsType, 120); - assert_size!(ArchivedTsTypeAliasDecl, 48); - assert_size!(ArchivedTsTypeAnn, 12); - assert_size!(ArchivedTsTypeAssertion, 16); - assert_size!(ArchivedTsTypeElement, 56); - assert_size!(ArchivedTsTypeLit, 16); - assert_size!(ArchivedTsTypeOperator, 16); - assert_size!(ArchivedTsTypeOperatorOp, 1); - assert_size!(ArchivedTsTypeParam, 52); - assert_size!(ArchivedTsTypeParamDecl, 16); - assert_size!(ArchivedTsTypeParamInstantiation, 16); - assert_size!(ArchivedTsTypePredicate, 48); - assert_size!(ArchivedTsTypeQuery, 112); - assert_size!(ArchivedTsTypeQueryExpr, 96); - assert_size!(ArchivedTsTypeRef, 44); - assert_size!(ArchivedTsUnionOrIntersectionType, 20); - assert_size!(ArchivedTsUnionType, 16); -} diff --git a/deps/swc/crates/swc_ecma_ast/src/lit.rs b/deps/swc/crates/swc_ecma_ast/src/lit.rs index 904430f22..307198057 100644 --- a/deps/swc/crates/swc_ecma_ast/src/lit.rs +++ b/deps/swc/crates/swc_ecma_ast/src/lit.rs @@ -86,7 +86,6 @@ impl Lit { #[derive(Eq, Hash)] pub struct BigInt { pub span: Span, - #[cfg_attr(any(feature = "rkyv-impl"), rkyv(with = EncodeBigInt))] #[cfg_attr(feature = "encoding-impl", encoding(with = "EncodeBigInt2"))] pub value: Box, @@ -138,61 +137,6 @@ impl<'de> cbor4ii::core::dec::Decode<'de> for EncodeBigInt2> { } } -#[cfg(feature = "rkyv-impl")] -#[derive(Debug, Clone, Copy)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(C))] -pub struct EncodeBigInt; - -#[cfg(feature = "rkyv-impl")] -impl rkyv::with::ArchiveWith> for EncodeBigInt { - type Archived = rkyv::Archived; - type Resolver = rkyv::Resolver; - - fn resolve_with( - field: &Box, - resolver: Self::Resolver, - out: rkyv::Place, - ) { - use rkyv::Archive; - - let s = field.to_string(); - s.resolve(resolver, out); - } -} - -#[cfg(feature = "rkyv-impl")] -impl rkyv::with::SerializeWith, S> for EncodeBigInt -where - S: ?Sized + rancor::Fallible + rkyv::ser::Writer, - S::Error: rancor::Source, -{ - fn serialize_with( - field: &Box, - serializer: &mut S, - ) -> Result { - let field = field.to_string(); - rkyv::string::ArchivedString::serialize_from_str(&field, serializer) - } -} - -#[cfg(feature = "rkyv-impl")] -impl rkyv::with::DeserializeWith, Box, D> for EncodeBigInt -where - D: ?Sized + rancor::Fallible, -{ - fn deserialize_with( - field: &rkyv::Archived, - deserializer: &mut D, - ) -> Result, D::Error> { - use rkyv::Deserialize; - - let s: String = field.deserialize(deserializer)?; - - Ok(Box::new(s.parse().unwrap())) - } -} - #[cfg(feature = "arbitrary")] #[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))] impl<'a> arbitrary::Arbitrary<'a> for BigInt { @@ -578,13 +522,14 @@ impl<'a> arbitrary::Arbitrary<'a> for Regex { /// All of `Box`, `Expr`, `Lit`, `Number` implements `From<64>` and /// `From`. -#[ast_node("NumericLiteral")] +#[ast_node("NumericLiteral", no_partial_eq)] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] pub struct Number { pub span: Span, - /// **Note**: This should not be `NaN`. Use [crate::Ident] to represent NaN. + /// The numeric value, including `NaN` and positive or negative infinity. /// - /// If you store `NaN` in this field, a hash map will behave strangely. + /// Equality treats all `NaN` representations as equal and distinguishes + /// positive and negative zero. pub value: f64, /// Use `None` value only for transformations to avoid recalculate @@ -596,38 +541,52 @@ pub struct Number { pub raw: Option, } +impl PartialEq for Number { + fn eq(&self, other: &Self) -> bool { + self.span == other.span && number_value_eq(self.value, other.value) && self.raw == other.raw + } +} + impl Eq for Number {} impl EqIgnoreSpan for Number { fn eq_ignore_span(&self, other: &Self) -> bool { - self.value == other.value && self.value.is_sign_positive() == other.value.is_sign_positive() + number_value_eq(self.value, other.value) } } -#[allow(clippy::derived_hash_with_manual_eq)] -#[allow(unnecessary_transmutes)] impl Hash for Number { fn hash(&self, state: &mut H) { - fn integer_decode(val: f64) -> (u64, i16, i8) { - let bits: u64 = val.to_bits(); - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - - exponent -= 1023 + 52; - (mantissa, exponent, sign) - } - self.span.hash(state); - integer_decode(self.value).hash(state); + canonical_number_bits(self.value).hash(state); self.raw.hash(state); } } +/// Compares numeric values using the equality semantics required by `Number`. +/// +/// NaN payloads are not observable in ECMAScript, while the sign of zero is. +#[inline] +fn number_value_eq(left: f64, right: f64) -> bool { + // Compare bits so positive and negative zero remain distinct. + left.to_bits() == right.to_bits() || (left.is_nan() && right.is_nan()) +} + +/// Returns bits consistent with [`number_value_eq`]. +/// +/// This follows the NaN canonicalization used by `ordered-float`, but retains +/// the sign bit of zero. +#[inline] +fn canonical_number_bits(value: f64) -> u64 { + const CANONICAL_NAN_BITS: u64 = 0x7ff8_0000_0000_0000; + + if value.is_nan() { + CANONICAL_NAN_BITS + } else { + value.to_bits() + } +} + impl Display for Number { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { if self.value.is_infinite() { diff --git a/deps/swc/crates/swc_ecma_ast/src/module_decl.rs b/deps/swc/crates/swc_ecma_ast/src/module_decl.rs index 6e0fe1477..1cd9d8fe1 100644 --- a/deps/swc/crates/swc_ecma_ast/src/module_decl.rs +++ b/deps/swc/crates/swc_ecma_ast/src/module_decl.rs @@ -145,12 +145,6 @@ pub struct ImportDecl { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, EqIgnoreSpan)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( feature = "encoding-impl", diff --git a/deps/swc/crates/swc_ecma_ast/src/operators.rs b/deps/swc/crates/swc_ecma_ast/src/operators.rs index 27c4b0b43..eb37349d2 100644 --- a/deps/swc/crates/swc_ecma_ast/src/operators.rs +++ b/deps/swc/crates/swc_ecma_ast/src/operators.rs @@ -4,12 +4,6 @@ use swc_common::EqIgnoreSpan; #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, EqIgnoreSpan, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) @@ -122,12 +116,6 @@ impl BinaryOp { #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, EqIgnoreSpan, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) @@ -204,12 +192,6 @@ impl AssignOp { #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, EqIgnoreSpan, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) @@ -226,12 +208,6 @@ pub enum UpdateOp { #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, EqIgnoreSpan, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) diff --git a/deps/swc/crates/swc_ecma_ast/src/typescript.rs b/deps/swc/crates/swc_ecma_ast/src/typescript.rs index c3d9b3333..e7d244a65 100644 --- a/deps/swc/crates/swc_ecma_ast/src/typescript.rs +++ b/deps/swc/crates/swc_ecma_ast/src/typescript.rs @@ -452,12 +452,6 @@ pub struct TsKeywordType { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, EqIgnoreSpan)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( feature = "encoding-impl", @@ -813,12 +807,6 @@ pub struct TsTypeOperator { #[derive(StringEnum, Clone, Copy, PartialEq, Eq, Hash, EqIgnoreSpan)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) @@ -848,12 +836,6 @@ pub struct TsIndexedAccessType { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EqIgnoreSpan)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) @@ -1281,12 +1263,6 @@ pub struct TsSatisfiesExpr { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EqIgnoreSpan)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[cfg_attr( - any(feature = "rkyv-impl"), - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv-impl", repr(u32))] #[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))] #[cfg_attr( diff --git a/deps/swc/crates/swc_ecma_codegen/Cargo.toml b/deps/swc/crates/swc_ecma_codegen/Cargo.toml index b8f9e87f7..6878e0466 100644 --- a/deps/swc/crates/swc_ecma_codegen/Cargo.toml +++ b/deps/swc/crates/swc_ecma_codegen/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_codegen" repository = { workspace = true } -version = "28.0.2" +version = "30.0.0" [features] # This does not enable serde for ast nodes. @@ -20,39 +20,40 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } bench = false [dependencies] -ascii = { workspace = true } -compact_str = { workspace = true } -dragonbox_ecma = { workspace = true } -memchr = { workspace = true } -num-bigint = { workspace = true, features = ["serde"] } -once_cell = { workspace = true } -regex = { workspace = true } -rustc-hash = { workspace = true } -serde = { workspace = true } -tracing = { workspace = true } - -swc_allocator = { version = "4.0.1", path = "../swc_allocator", default-features = false, features = [ +ascii = { workspace = true } +compact_str = { workspace = true } +dragonbox_ecma = { workspace = true } +memchr = { workspace = true } +num-bigint = { workspace = true, features = ["serde"] } +once_cell = { workspace = true } +regex = { workspace = true } +rustc-hash = { workspace = true } +serde = { workspace = true } +tracing = { workspace = true } + +swc_allocator = { version = "5.0.0", path = "../swc_allocator", default-features = false, features = [ "hashbrown", ] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } swc_ecma_codegen_macros = { version = "2.0.2", path = "../swc_ecma_codegen_macros" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } [dev-dependencies] base64 = { workspace = true } codspeed-criterion-compat = { workspace = true } serde_json = { workspace = true } -swc_allocator = { version = "4.0.1", path = "../swc_allocator" } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_allocator = { version = "5.0.0", path = "../swc_allocator" } +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "sourcemap", ] } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_testing = { version = "24.0.1", path = "../swc_ecma_testing" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_testing = { version = "25.0.0", path = "../swc_ecma_testing" } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } swc_sourcemap = { workspace = true } +testing = { version = "25.0.0", path = "../testing" } [[bench]] harness = false diff --git a/deps/swc/crates/swc_ecma_codegen/src/class.rs b/deps/swc/crates/swc_ecma_codegen/src/class.rs index 1936da0b2..10385ebc4 100644 --- a/deps/swc/crates/swc_ecma_codegen/src/class.rs +++ b/deps/swc/crates/swc_ecma_codegen/src/class.rs @@ -8,7 +8,7 @@ use crate::{ scope_helpers::{for_each_constructor_param_binding, for_each_param_binding}, text_writer::{BindingStorage, ScopeKind, WriteJs}, util::StartsWithAlphaNum, - Emitter, ListFormat, Result, SourceMapperExt, + Emitter, ExprPrecedence, ListFormat, Result, SourceMapperExt, }; impl Emitter<'_, W, S> @@ -21,13 +21,13 @@ where space!(self); keyword!(self, "extends"); - if super_class.starts_with_alpha_num() { + if self.expr_starts_with_alpha_num_after_codegen(super_class, ExprPrecedence::POSTFIX) { space!(self); } else { formatting_space!(self) } - emit!(self, node.super_class); + self.emit_expr_with_precedence(super_class, ExprPrecedence::POSTFIX)?; emit!(self, node.super_type_params); } @@ -94,13 +94,15 @@ impl MacroNode for Class { space!(emitter); keyword!(emitter, "extends"); - if super_class.starts_with_alpha_num() { + if emitter + .expr_starts_with_alpha_num_after_codegen(super_class, ExprPrecedence::POSTFIX) + { space!(emitter); } else { formatting_space!(emitter) } - emit!(self.super_class); + emitter.emit_expr_with_precedence(super_class, ExprPrecedence::POSTFIX)?; emit!(self.super_type_params); } diff --git a/deps/swc/crates/swc_ecma_codegen/src/lib.rs b/deps/swc/crates/swc_ecma_codegen/src/lib.rs index db788f1de..6dc436833 100644 --- a/deps/swc/crates/swc_ecma_codegen/src/lib.rs +++ b/deps/swc/crates/swc_ecma_codegen/src/lib.rs @@ -119,6 +119,41 @@ where pub wr: W, } +/// The minimum precedence required by an expression's parent. +/// +/// Most expressions are already parenthesized by the fixer, but non-finite +/// numeric literals can expand into division expressions while being emitted. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct ExprPrecedence(u8); + +impl ExprPrecedence { + const EXPONENTIATION: Self = Self(11); + const LOWEST: Self = Self(0); + const MULTIPLICATIVE: Self = Self(10); + const POSTFIX: Self = Self(13); + const PREFIX: Self = Self(12); + + #[inline] + fn for_binary_left(op: BinaryOp) -> Self { + if op == op!("**") { + // Exponentiation cannot have an unparenthesized unary expression on + // the left-hand side. + Self::PREFIX + } else { + Self(op.precedence() - 1) + } + } + + #[inline] + fn for_binary_right(op: BinaryOp) -> Self { + if op == op!("**") { + Self::MULTIPLICATIVE + } else { + Self(op.precedence()) + } + } +} + enum CowStr<'a> { Borrowed(&'a str), Owned(CompactString), @@ -154,6 +189,43 @@ where node.emit_with(self) } + /// Emits an expression with the precedence required by its parent. + /// + /// This only changes non-finite numeric literals. All other expressions + /// continue through their existing emitters. + #[inline] + fn emit_expr_with_precedence(&mut self, expr: &Expr, precedence: ExprPrecedence) -> Result { + if let Expr::Lit(Lit::Num(num)) = expr { + if !num.value.is_finite() { + self.emit_num_lit_expr(num, precedence, false)?; + + if self.comments.is_some() { + self.emit_trailing_comments_of_pos(expr.span().hi, true, true)?; + } + + return Ok(()); + } + } + + expr.emit_with(self) + } + + /// Returns whether an expression starts with an alphanumeric token after + /// applying code-generation-only rewrites. + #[inline] + fn expr_starts_with_alpha_num_after_codegen( + &self, + expr: &Expr, + precedence: ExprPrecedence, + ) -> bool { + match expr { + Expr::Lit(Lit::Num(num)) if !num.value.is_finite() => { + self.non_finite_expr_starts_with_alpha_num(num, precedence) + } + _ => expr.starts_with_alpha_num(), + } + } + #[inline(always)] fn scope_tracking_enabled(&self) -> bool { self.wr.has_scope_tracking() @@ -208,14 +280,15 @@ where keyword!(self, "new"); - let starts_with_alpha_num = node.callee.starts_with_alpha_num(); + let starts_with_alpha_num = + self.expr_starts_with_alpha_num_after_codegen(&node.callee, ExprPrecedence::POSTFIX); if starts_with_alpha_num { space!(self); } else { formatting_space!(self); } - emit!(self, node.callee); + self.emit_expr_with_precedence(&node.callee, ExprPrecedence::POSTFIX)?; if let Some(type_args) = &node.type_args { emit!(self, type_args); @@ -320,7 +393,7 @@ where span.is_pure() || self .comments - .is_some_and(|comments| comments.has_leading(node.right.span().lo)) + .is_some_and(|comments| comments.has_leading(span.lo)) } else { require_space_before_rhs(&node.right, &node.op) } @@ -336,7 +409,7 @@ where } else { formatting_space!(self); } - emit!(self, node.right); + self.emit_expr_with_precedence(&node.right, ExprPrecedence::for_binary_right(node.op))?; Ok(()) } @@ -1574,7 +1647,7 @@ impl MacroNode for Callee { if let Expr::New(new) = &**e { emitter.emit_new(new, false)?; } else { - emit!(e); + emitter.emit_expr_with_precedence(e, ExprPrecedence::POSTFIX)?; } } Callee::Super(n) => emit!(n), @@ -1684,7 +1757,7 @@ impl MacroNode for OptChainExpr { if let Expr::New(new) = &*e.obj { emitter.emit_new(new, false)?; } else { - emit!(e.obj); + emitter.emit_expr_with_precedence(&e.obj, ExprPrecedence::POSTFIX)?; } if self.optional { punct!(emitter, "?."); @@ -1702,7 +1775,7 @@ impl MacroNode for OptChainExpr { } OptChainBase::Call(e) => { debug_assert!(!e.callee.is_new()); - emit!(e.callee); + emitter.emit_expr_with_precedence(&e.callee, ExprPrecedence::POSTFIX)?; if self.optional { punct!(emitter, "?."); @@ -1787,7 +1860,8 @@ impl MacroNode for MemberExpr { emitter.emit_new(new, false)?; } Expr::Lit(Lit::Num(num)) => { - needs_2dots_for_property_access = emitter.emit_num_lit_internal(num, true)?; + needs_2dots_for_property_access = + emitter.emit_num_lit_expr(num, ExprPrecedence::POSTFIX, true)?; } _ => { emit!(self.obj); @@ -2012,7 +2086,10 @@ impl MacroNode for BinExpr { for (i, left) in lefts.into_iter().rev().enumerate() { if i == 0 { - emit!(left.left); + emitter.emit_expr_with_precedence( + &left.left, + ExprPrecedence::for_binary_left(left.op), + )?; } // Check if it's last if i + 1 != len { @@ -2228,7 +2305,7 @@ impl MacroNode for TaggedTpl { if let Expr::New(new) = &*self.tag { emitter.emit_new(new, false)?; } else { - emit!(self.tag); + emitter.emit_expr_with_precedence(&self.tag, ExprPrecedence::POSTFIX)?; } emit!(self.type_params); @@ -2267,7 +2344,7 @@ impl MacroNode for UnaryExpr { formatting_space!(emitter); } - emit!(self.arg); + emitter.emit_expr_with_precedence(&self.arg, ExprPrecedence::EXPONENTIATION)?; Ok(()) } @@ -2354,7 +2431,7 @@ impl MacroNode for AwaitExpr { keyword!(emitter, "await"); space!(emitter); - emit!(self.arg); + emitter.emit_expr_with_precedence(&self.arg, ExprPrecedence::EXPONENTIATION)?; Ok(()) } diff --git a/deps/swc/crates/swc_ecma_codegen/src/lit.rs b/deps/swc/crates/swc_ecma_codegen/src/lit.rs index fa4f81336..a932f44d1 100644 --- a/deps/swc/crates/swc_ecma_codegen/src/lit.rs +++ b/deps/swc/crates/swc_ecma_codegen/src/lit.rs @@ -6,10 +6,45 @@ use swc_atoms::wtf8::{CodePoint, Wtf8}; use swc_common::{Spanned, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_codegen_macros::node_impl; +use swc_ecma_utils::number::minify_number; #[cfg(swc_ast_unknown)] use crate::unknown_error; -use crate::{text_writer::WriteJs, CowStr, Emitter, SourceMapperExt}; +use crate::{text_writer::WriteJs, CowStr, Emitter, ExprPrecedence, SourceMapperExt}; + +#[derive(Clone, Copy)] +enum NonFiniteNumber { + NaN, + PositiveInfinity, + NegativeInfinity, +} + +impl NonFiniteNumber { + #[inline] + fn from_value(value: f64) -> Self { + debug_assert!(!value.is_finite()); + + if value.is_nan() { + Self::NaN + } else if value.is_sign_positive() { + Self::PositiveInfinity + } else { + Self::NegativeInfinity + } + } + + #[inline] + fn division_text(self, minify: bool) -> &'static str { + match (self, minify) { + (Self::NaN, false) => "0 / 0", + (Self::PositiveInfinity, false) => "1 / 0", + (Self::NegativeInfinity, false) => "-1 / 0", + (Self::NaN, true) => "0/0", + (Self::PositiveInfinity, true) => "1/0", + (Self::NegativeInfinity, true) => "-1/0", + } + } +} #[node_impl] impl MacroNode for Lit { @@ -29,7 +64,9 @@ impl MacroNode for Lit { Lit::Null(Null { .. }) => keyword!(emitter, "null"), Lit::Str(ref s) => emit!(s), Lit::BigInt(ref s) => emit!(s), - Lit::Num(ref n) => emit!(n), + Lit::Num(ref n) => { + emitter.emit_num_lit_expr(n, ExprPrecedence::LOWEST, false)?; + } Lit::Regex(ref n) => { punct!(emitter, "/"); // Encode non-ASCII characters in regex pattern when ascii_only is enabled @@ -218,6 +255,77 @@ where W: WriteJs, S: SourceMapperExt, { + /// Emits a numeric literal in expression position. + /// + /// Readable output preserves a non-finite value's raw text when present. + /// Otherwise, non-finite values use division expressions, with spaces + /// omitted in minified output. Positive infinity uses an overflow literal + /// when division would require parentheses, avoiding an opening + /// parenthesis that could interact with automatic semicolon insertion. + /// Other generated expressions are parenthesized here because the fixer + /// cannot see code-generation-only expressions. + pub(crate) fn emit_num_lit_expr( + &mut self, + num: &Number, + precedence: ExprPrecedence, + detect_dot: bool, + ) -> std::result::Result { + if num.value.is_finite() { + return self.emit_num_lit_internal(num, detect_dot); + } + + if !self.cfg.minify && num.raw.is_some() { + return self.emit_num_lit_internal(num, detect_dot); + } + + self.wr.commit_pending_semi()?; + self.emit_leading_comments_of_span(num.span(), false)?; + + srcmap!(self, num, true); + + let kind = NonFiniteNumber::from_value(num.value); + let requires_parentheses = precedence >= ExprPrecedence::MULTIPLICATIVE; + let (text, wrap) = + if requires_parentheses && matches!(kind, NonFiniteNumber::PositiveInfinity) { + ("2e308", false) + } else { + (kind.division_text(self.cfg.minify), requires_parentheses) + }; + + if wrap { + punct!(self, "("); + } + self.wr.write_str_lit(num.span, text)?; + if wrap { + punct!(self, ")"); + } + + Ok(false) + } + + pub(crate) fn non_finite_expr_starts_with_alpha_num( + &self, + num: &Number, + precedence: ExprPrecedence, + ) -> bool { + debug_assert!(!num.value.is_finite()); + + if !self.cfg.minify { + if let Some(raw) = &num.raw { + return raw + .as_bytes() + .first() + .is_some_and(u8::is_ascii_alphanumeric); + } + } + + if precedence >= ExprPrecedence::MULTIPLICATIVE { + return num.value == f64::INFINITY; + } + + !num.value.is_sign_negative() || num.value.is_nan() + } + /// `1.toString` is an invalid property access, /// should emit a dot after the literal if return true pub fn emit_num_lit_internal( @@ -559,78 +667,6 @@ pub fn get_quoted_utf16(v: &Wtf8, ascii_only: bool, target: EsVersion) -> (Ascii (quote_char, CowStr::Owned(buf)) } -pub fn minify_number(num: f64, detect_dot: &mut bool) -> String { - // ddddd -> 0xhhhh - // len(0xhhhh) == len(ddddd) - // 10000000 <= num <= 0xffffff - 'hex: { - if num.fract() == 0.0 && num.abs() <= u64::MAX as f64 { - let int = num.abs() as u64; - - if int < 10000000 { - break 'hex; - } - - // use scientific notation - if int % 1000 == 0 { - break 'hex; - } - - *detect_dot = false; - return format!( - "{}{:#x}", - if num.is_sign_negative() { "-" } else { "" }, - int - ); - } - } - - let mut num = num.to_string(); - - if num.contains(".") { - *detect_dot = false; - } - - if let Some(num) = num.strip_prefix("0.") { - let cnt = clz(num); - if cnt > 2 { - return format!("{}e-{}", &num[cnt..], num.len()); - } - return format!(".{num}"); - } - - if let Some(num) = num.strip_prefix("-0.") { - let cnt = clz(num); - if cnt > 2 { - return format!("-{}e-{}", &num[cnt..], num.len()); - } - return format!("-.{num}"); - } - - if num.ends_with("000") { - *detect_dot = false; - - let cnt = num - .as_bytes() - .iter() - .rev() - .skip(3) - .take_while(|&&c| c == b'0') - .count() - + 3; - - num.truncate(num.len() - cnt); - num.push('e'); - num.push_str(&cnt.to_string()); - } - - num -} - -fn clz(s: &str) -> usize { - s.as_bytes().iter().take_while(|&&c| c == b'0').count() -} - pub trait Print { fn print(&self) -> String; } diff --git a/deps/swc/crates/swc_ecma_codegen/src/typescript.rs b/deps/swc/crates/swc_ecma_codegen/src/typescript.rs index b51d0b470..53c16f032 100644 --- a/deps/swc/crates/swc_ecma_codegen/src/typescript.rs +++ b/deps/swc/crates/swc_ecma_codegen/src/typescript.rs @@ -4,6 +4,7 @@ use swc_ecma_codegen_macros::node_impl; #[cfg(swc_ast_unknown)] use crate::unknown_error; +use crate::ExprPrecedence; #[node_impl] impl MacroNode for ParamOrTsParamProp { @@ -819,7 +820,7 @@ impl MacroNode for TsNonNullExpr { fn emit(&mut self, emitter: &mut Macro) -> Result { emitter.emit_leading_comments_of_span(self.span(), false)?; - emit!(self.expr); + emitter.emit_expr_with_precedence(&self.expr, ExprPrecedence::POSTFIX)?; punct!(emitter, "!"); Ok(()) } @@ -1135,7 +1136,7 @@ impl MacroNode for TsTypeAssertion { punct!(emitter, "<"); emit!(self.type_ann); punct!(emitter, ">"); - emit!(self.expr); + emitter.emit_expr_with_precedence(&self.expr, ExprPrecedence::EXPONENTIATION)?; Ok(()) } } @@ -1422,7 +1423,7 @@ impl MacroNode for TsInstantiation { fn emit(&mut self, emitter: &mut Macro) -> Result { emitter.emit_leading_comments_of_span(self.span(), false)?; - emit!(self.expr); + emitter.emit_expr_with_precedence(&self.expr, ExprPrecedence::POSTFIX)?; emit!(self.type_args); Ok(()) diff --git a/deps/swc/crates/swc_ecma_compat_bugfixes/Cargo.toml b/deps/swc/crates/swc_ecma_compat_bugfixes/Cargo.toml index f5491ebff..e5c1628f0 100644 --- a/deps/swc/crates/swc_ecma_compat_bugfixes/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_bugfixes/Cargo.toml @@ -7,21 +7,21 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_bugfixes" repository = { workspace = true } -version = "51.0.0" +version = "54.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] rustc-hash = { workspace = true } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_compat_es2015 = { version = "50.0.0", path = "../swc_ecma_compat_es2015" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_compat_es2015 = { version = "53.0.0", path = "../swc_ecma_compat_es2015" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } diff --git a/deps/swc/crates/swc_ecma_compat_common/Cargo.toml b/deps/swc/crates/swc_ecma_compat_common/Cargo.toml index e4b675a86..d4b836ee3 100644 --- a/deps/swc/crates/swc_ecma_compat_common/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_common/Cargo.toml @@ -7,12 +7,12 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_common" repository = { workspace = true } -version = "40.0.1" +version = "43.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } diff --git a/deps/swc/crates/swc_ecma_compat_es2015/Cargo.toml b/deps/swc/crates/swc_ecma_compat_es2015/Cargo.toml index 19bde72f0..7e784a2e6 100644 --- a/deps/swc/crates/swc_ecma_compat_es2015/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_es2015/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_es2015" repository = { workspace = true } -version = "50.0.0" +version = "53.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -23,21 +23,21 @@ rustc-hash = { workspace = true } serde = { workspace = true } serde_derive = { workspace = true } smallvec = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_config = { version = "5.0.0", path = "../swc_config" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_compat_common = { version = "40.0.1", path = "../swc_ecma_compat_common" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_classes = { version = "44.0.0", path = "../swc_ecma_transforms_classes" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_config = { version = "6.0.0", path = "../swc_config" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_compat_common = { version = "43.0.0", path = "../swc_ecma_compat_common" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_classes = { version = "47.0.0", path = "../swc_ecma_transforms_classes" } swc_ecma_transforms_macros = { version = "1.0.1", path = "../swc_ecma_transforms_macros" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } tracing = { workspace = true } [dev-dependencies] -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } diff --git a/deps/swc/crates/swc_ecma_compat_es2015/src/classes/prop_name.rs b/deps/swc/crates/swc_ecma_compat_es2015/src/classes/prop_name.rs index 6044c7f0a..d79ee5f9e 100644 --- a/deps/swc/crates/swc_ecma_compat_es2015/src/classes/prop_name.rs +++ b/deps/swc/crates/swc_ecma_compat_es2015/src/classes/prop_name.rs @@ -1,6 +1,7 @@ use swc_atoms::Wtf8Atom; use swc_common::{Span, Spanned}; use swc_ecma_ast::*; +use swc_ecma_utils::number::ToJsString; #[derive(Debug, PartialEq, Eq, Hash)] pub enum HashKey { @@ -14,7 +15,7 @@ impl From<&PropName> for HashKey { match p { PropName::Ident(IdentName { sym: value, .. }) => HashKey::Str(value.clone().into()), PropName::Str(Str { value, .. }) => HashKey::Str(value.clone()), - PropName::Num(Number { value, .. }) => HashKey::Str(value.to_string().into()), + PropName::Num(Number { value, .. }) => HashKey::Str(value.to_js_string().into()), PropName::BigInt(BigInt { value, .. }) => HashKey::Str(value.to_string().into()), PropName::Computed(expr) => HashKey::Computed(expr.span()), #[cfg(swc_ast_unknown)] diff --git a/deps/swc/crates/swc_ecma_compat_es2016/Cargo.toml b/deps/swc/crates/swc_ecma_compat_es2016/Cargo.toml index 9a95a58df..801f3b578 100644 --- a/deps/swc/crates/swc_ecma_compat_es2016/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_es2016/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_es2016" repository = { workspace = true } -version = "45.0.0" +version = "48.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -16,12 +16,12 @@ version = "45.0.0" unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [dependencies] -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } tracing = { workspace = true } [dev-dependencies] -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } diff --git a/deps/swc/crates/swc_ecma_compat_es2017/Cargo.toml b/deps/swc/crates/swc_ecma_compat_es2017/Cargo.toml index 45074f4f8..eddad7d45 100644 --- a/deps/swc/crates/swc_ecma_compat_es2017/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_es2017/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_es2017" repository = { workspace = true } -version = "45.0.0" +version = "48.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -17,11 +17,11 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [dependencies] serde = { workspace = true, features = ["derive"] } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } tracing = { workspace = true } [dev-dependencies] diff --git a/deps/swc/crates/swc_ecma_compat_es2018/Cargo.toml b/deps/swc/crates/swc_ecma_compat_es2018/Cargo.toml index 2c1dacde0..4bdfb6750 100644 --- a/deps/swc/crates/swc_ecma_compat_es2018/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_es2018/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_es2018" repository = { workspace = true } -version = "46.0.0" +version = "49.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -17,10 +17,10 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [dependencies] serde = { workspace = true, features = ["derive"] } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } tracing = { workspace = true } [dev-dependencies] diff --git a/deps/swc/crates/swc_ecma_compat_es2019/Cargo.toml b/deps/swc/crates/swc_ecma_compat_es2019/Cargo.toml index 2d5621420..0ee15085b 100644 --- a/deps/swc/crates/swc_ecma_compat_es2019/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_es2019/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_es2019" repository = { workspace = true } -version = "45.0.0" +version = "48.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -16,13 +16,13 @@ version = "45.0.0" unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [dependencies] -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } tracing = { workspace = true } [dev-dependencies] -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } diff --git a/deps/swc/crates/swc_ecma_compat_es2020/Cargo.toml b/deps/swc/crates/swc_ecma_compat_es2020/Cargo.toml index 60f6fe6f1..14ab08eca 100644 --- a/deps/swc/crates/swc_ecma_compat_es2020/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_es2020/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_es2020" repository = { workspace = true } -version = "48.0.0" +version = "51.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -19,12 +19,12 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } serde = { workspace = true, features = ["derive"] } tracing = { workspace = true } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_compat_es2022 = { version = "48.0.0", path = "../swc_ecma_compat_es2022" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_compat_es2022 = { version = "51.0.0", path = "../swc_ecma_compat_es2022" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] diff --git a/deps/swc/crates/swc_ecma_compat_es2021/Cargo.toml b/deps/swc/crates/swc_ecma_compat_es2021/Cargo.toml index b94ac88c3..08d5c2f95 100644 --- a/deps/swc/crates/swc_ecma_compat_es2021/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_es2021/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_es2021" repository = { workspace = true } -version = "45.0.0" +version = "48.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -18,7 +18,7 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [dependencies] tracing = { workspace = true } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } diff --git a/deps/swc/crates/swc_ecma_compat_es2022/Cargo.toml b/deps/swc/crates/swc_ecma_compat_es2022/Cargo.toml index e70c3e4da..f6ab99f90 100644 --- a/deps/swc/crates/swc_ecma_compat_es2022/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_es2022/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_es2022" repository = { workspace = true } -version = "48.0.0" +version = "51.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -20,12 +20,12 @@ rustc-hash = { workspace = true } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_classes = { version = "44.0.0", path = "../swc_ecma_transforms_classes" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_classes = { version = "47.0.0", path = "../swc_ecma_transforms_classes" } swc_ecma_transforms_macros = { version = "1.0.1", path = "../swc_ecma_transforms_macros" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } diff --git a/deps/swc/crates/swc_ecma_compat_es3/Cargo.toml b/deps/swc/crates/swc_ecma_compat_es3/Cargo.toml index 9eccaa29c..607feeea9 100644 --- a/deps/swc/crates/swc_ecma_compat_es3/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_es3/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_es3" repository = { workspace = true } -version = "36.0.0" +version = "39.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -16,11 +16,11 @@ version = "36.0.0" unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [dependencies] -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer", features = [ +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer", features = [ "es3", ] } [dev-dependencies] -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } diff --git a/deps/swc/crates/swc_ecma_compat_regexp/Cargo.toml b/deps/swc/crates/swc_ecma_compat_regexp/Cargo.toml index 919862831..c51317a9c 100644 --- a/deps/swc/crates/swc_ecma_compat_regexp/Cargo.toml +++ b/deps/swc/crates/swc_ecma_compat_regexp/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_compat_regexp" repository = "https://github.com/swc-project/swc.git" -version = "6.0.0" +version = "7.0.0" [lib] bench = false @@ -15,8 +15,8 @@ bench = false [dependencies] icu_properties = { version = "2.0.0", default-features = false, features = ["compiled_data", "alloc"] } -swc_ecma_regexp_ast = { version = "0.12.0", path = "../swc_ecma_regexp_ast" } -swc_ecma_regexp_visit = { version = "0.12.0", path = "../swc_ecma_regexp_visit" } +swc_ecma_regexp_ast = { version = "1.0.0", path = "../swc_ecma_regexp_ast" } +swc_ecma_regexp_visit = { version = "0.13.0", path = "../swc_ecma_regexp_visit" } [dev-dependencies] -swc_ecma_regexp = { version = "0.12.0", path = "../swc_ecma_regexp" } +swc_ecma_regexp = { version = "0.13.0", path = "../swc_ecma_regexp" } diff --git a/deps/swc/crates/swc_ecma_ext_transforms/Cargo.toml b/deps/swc/crates/swc_ecma_ext_transforms/Cargo.toml index e0e3fc9cd..d61630de1 100644 --- a/deps/swc/crates/swc_ecma_ext_transforms/Cargo.toml +++ b/deps/swc/crates/swc_ecma_ext_transforms/Cargo.toml @@ -6,14 +6,14 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_ext_transforms" repository = { workspace = true } -version = "31.0.0" +version = "33.0.0" [lib] bench = false [dependencies] phf = { workspace = true, features = ["macros"] } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } diff --git a/deps/swc/crates/swc_ecma_hooks/Cargo.toml b/deps/swc/crates/swc_ecma_hooks/Cargo.toml index 95d29467f..6b435aa31 100644 --- a/deps/swc/crates/swc_ecma_hooks/Cargo.toml +++ b/deps/swc/crates/swc_ecma_hooks/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_hooks" repository = { workspace = true } -version = "0.9.0" +version = "0.11.0" [package.metadata.docs.rs] all-features = true @@ -16,7 +16,7 @@ rustdoc-args = ["--cfg", "docsrs"] bench = false [dependencies] -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } diff --git a/deps/swc/crates/swc_ecma_lexer/Cargo.toml b/deps/swc/crates/swc_ecma_lexer/Cargo.toml index ae9b624f7..1531fbb07 100644 --- a/deps/swc/crates/swc_ecma_lexer/Cargo.toml +++ b/deps/swc/crates/swc_ecma_lexer/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "examples/**/*.rs"] license = { workspace = true } name = "swc_ecma_lexer" repository = { workspace = true } -version = "40.0.1" +version = "42.0.0" [package.metadata.docs.rs] all-features = true @@ -29,31 +29,31 @@ verify = ["swc_ecma_visit"] [dependencies] bitflags = { workspace = true } +compact_str = { workspace = true } either = { workspace = true } num-bigint = { workspace = true } rustc-hash = { workspace = true } seq-macro = { workspace = true } serde = { workspace = true, features = ["derive"] } smallvec = { workspace = true } -smartstring = { workspace = true } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit", optional = true } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit", optional = true } [target.'cfg(not(any(target_arch = "wasm32", target_arch = "arm")))'.dependencies] stacker = { version = "0.1.15", optional = true } [dev-dependencies] -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast", features = [ +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast", features = [ "serde-impl", ] } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } -testing = { version = "24.0.1", path = "../testing" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } +testing = { version = "25.0.0", path = "../testing" } [[example]] name = "lexer" diff --git a/deps/swc/crates/swc_ecma_lexer/src/common/lexer/mod.rs b/deps/swc/crates/swc_ecma_lexer/src/common/lexer/mod.rs index 306598781..1a2670ecd 100644 --- a/deps/swc/crates/swc_ecma_lexer/src/common/lexer/mod.rs +++ b/deps/swc/crates/swc_ecma_lexer/src/common/lexer/mod.rs @@ -1,9 +1,9 @@ use std::borrow::Cow; use char::CharExt; +use compact_str::CompactString; use either::Either::{self, Left, Right}; use num_bigint::BigInt as BigIntValue; -use smartstring::{LazyCompact, SmartString}; use state::State; use swc_atoms::{ wtf8::{CodePoint, Wtf8, Wtf8Buf}, @@ -1008,7 +1008,7 @@ pub trait Lexer<'a, TokenAndSpan>: Tokens + Sized { s.chars().all(|c| c.is_ascii_digit()) } - let mut s = SmartString::::default(); + let mut s = CompactString::default(); debug_assert!(self.input().cur().is_some_and(|c| c == b'&')); self.bump(); diff --git a/deps/swc/crates/swc_ecma_lints/Cargo.toml b/deps/swc/crates/swc_ecma_lints/Cargo.toml index 2a1bedc7a..9549dc043 100644 --- a/deps/swc/crates/swc_ecma_lints/Cargo.toml +++ b/deps/swc/crates/swc_ecma_lints/Cargo.toml @@ -6,7 +6,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_lints" repository = { workspace = true } -version = "33.0.0" +version = "35.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] @@ -24,23 +24,23 @@ regex = { workspace = true } rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "concurrent", ] } -swc_config = { version = "5.0.0", path = "../swc_config" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast", features = [ +swc_config = { version = "6.0.0", path = "../swc_config" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast", features = [ "serde", ] } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] codspeed-criterion-compat = { workspace = true } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } [features] non_critical_lints = [] diff --git a/deps/swc/crates/swc_ecma_loader/Cargo.toml b/deps/swc/crates/swc_ecma_loader/Cargo.toml index ed1f9050c..08153e6e3 100644 --- a/deps/swc/crates/swc_ecma_loader/Cargo.toml +++ b/deps/swc/crates/swc_ecma_loader/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_loader" repository = { workspace = true } -version = "24.0.1" +version = "25.0.0" [package.metadata.docs.rs] all-features = true @@ -37,8 +37,8 @@ serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, optional = true } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } [dev-dependencies] lazy_static = { workspace = true } diff --git a/deps/swc/crates/swc_ecma_minifier/AGENTS.md b/deps/swc/crates/swc_ecma_minifier/AGENTS.md index 1e39e76d0..a49776bd7 100644 --- a/deps/swc/crates/swc_ecma_minifier/AGENTS.md +++ b/deps/swc/crates/swc_ecma_minifier/AGENTS.md @@ -5,6 +5,36 @@ - Always run execution tests after making changes. - You can run fixture tests by doing ./scripts/test.sh, and you can do UPDATE=1 ./scripts/test.sh to update fixtures. +### Minifier Semantic Assumptions + +The ECMAScript minifier may rely on the documented assumptions from the SWC +minification guide: + +- Calls to primitive coercion helpers such as `toString` and `valueOf` are + side-effect free, and built-in object implementations have not been + overridden. +- `undefined`, `NaN`, and `Infinity` have not been externally redefined. +- `arguments.callee`, `arguments.caller`, and `Function.prototype.caller` are + not used. +- Code does not depend on the exact contents of `Function.prototype.toString()` + or `Error.prototype.stack`. +- Getting or setting properties on a plain object does not trigger side effects + through `watch`, `Proxy`, or similar mechanisms. +- Object properties can be added, removed, and modified unless the change is + intentionally handling frozen, sealed, non-extensible, or descriptor-locked + objects. +- `document.all` is treated as not `null`. +- Assigning properties to classes is assumed to be side-effect free and + non-throwing. +- Accessing declared top-level identifiers is assumed to be side-effect free. +- TDZ violations are not preserved. +- Arithmetic expressions are treated as side-effect free, including runtime + exceptions such as mixing `bigint` and `number`. + +If a minifier change relies on an assumption beyond this list, update the +public minification documentation or leave an explicit code comment describing +the narrower local invariant. + ### Fixture Test Addition Guide - Preferred fixture roots in this crate: tests/fixture, tests/mangle, tests/pass-1, tests/pass-default, tests/full, tests/projects, benches/full. diff --git a/deps/swc/crates/swc_ecma_minifier/Cargo.toml b/deps/swc/crates/swc_ecma_minifier/Cargo.toml index c17a58c5c..7165b071b 100644 --- a/deps/swc/crates/swc_ecma_minifier/Cargo.toml +++ b/deps/swc/crates/swc_ecma_minifier/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/lists/*.json"] license = { workspace = true } name = "swc_ecma_minifier" repository = { workspace = true } -version = "56.0.1" +version = "59.0.0" [package.metadata.docs.rs] all-features = true @@ -51,25 +51,25 @@ rustc-hash = { workspace = true } ryu-js = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_config = { version = "5.0.0", path = "../swc_config", features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_config = { version = "6.0.0", path = "../swc_config", features = [ "sourcemap", "file_pattern", "regex_js", ] } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast", features = [ +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast", features = [ "serde", ] } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_hooks = { version = "0.9.0", path = "../swc_ecma_hooks" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_hooks = { version = "0.11.0", path = "../swc_ecma_hooks" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_optimization = { version = "47.0.1", path = "../swc_ecma_transforms_optimization" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_optimization = { version = "50.0.0", path = "../swc_ecma_transforms_optimization" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } tracing = { workspace = true } [dev-dependencies] @@ -80,9 +80,9 @@ flate2 = { workspace = true } humansize = { workspace = true } par-core = { workspace = true, features = ["chili"] } pretty_assertions = { workspace = true } -swc_ecma_testing = { version = "24.0.1", path = "../swc_ecma_testing" } +swc_ecma_testing = { version = "25.0.0", path = "../swc_ecma_testing" } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } walkdir = { workspace = true } [[bench]] diff --git a/deps/swc/crates/swc_ecma_minifier/fuzz/Cargo.lock b/deps/swc/crates/swc_ecma_minifier/fuzz/Cargo.lock index 44d612616..49fb4d9b0 100644 --- a/deps/swc/crates/swc_ecma_minifier/fuzz/Cargo.lock +++ b/deps/swc/crates/swc_ecma_minifier/fuzz/Cargo.lock @@ -1170,17 +1170,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -1236,7 +1225,7 @@ dependencies = [ [[package]] name = "swc_common" -version = "23.0.1" +version = "23.0.2" dependencies = [ "anyhow", "arbitrary", @@ -1310,7 +1299,7 @@ dependencies = [ [[package]] name = "swc_ecma_codegen" -version = "28.0.1" +version = "28.0.2" dependencies = [ "ascii", "compact_str", @@ -1350,7 +1339,7 @@ dependencies = [ [[package]] name = "swc_ecma_minifier" -version = "55.0.2" +version = "57.0.1" dependencies = [ "arrayvec", "bitflags", @@ -1399,16 +1388,16 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "41.1.0" +version = "41.1.2" dependencies = [ "bitflags", + "compact_str", "either", "num-bigint", "phf", "rustc-hash", "seq-macro", "serde", - "smartstring", "stacker", "swc_atoms", "swc_common", @@ -1418,7 +1407,7 @@ dependencies = [ [[package]] name = "swc_ecma_testing" -version = "24.0.0" +version = "24.0.1" dependencies = [ "anyhow", "hex", @@ -1429,7 +1418,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_base" -version = "44.0.2" +version = "45.0.0" dependencies = [ "better_scoped_tls", "indexmap", @@ -1449,7 +1438,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_optimization" -version = "47.0.0" +version = "48.0.0" dependencies = [ "bytes-str", "dashmap", @@ -1471,7 +1460,7 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "31.0.0" +version = "31.0.2" dependencies = [ "dragonbox_ecma", "indexmap", @@ -1592,7 +1581,7 @@ dependencies = [ [[package]] name = "testing" -version = "24.0.0" +version = "24.0.1" dependencies = [ "cargo_metadata", "difference", diff --git a/deps/swc/crates/swc_ecma_minifier/src/cli/bin.rs b/deps/swc/crates/swc_ecma_minifier/src/cli/bin.rs index c983a0dbc..1afa7705d 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/cli/bin.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/cli/bin.rs @@ -1,4 +1,5 @@ use std::{env::args, io, path::Path}; + use swc_common::{input::SourceFileInput, sync::Lrc, FilePathMapping, Mark, SourceMap}; use swc_ecma_ast::Module; use swc_ecma_codegen::text_writer::JsWriter; @@ -60,9 +61,7 @@ fn run_cli(filename: String) -> Result<(), ParseError> { &ExtraOptions { top_level_mark }, ); - let output = output - .fold_with(&mut hygiene_with_config(Default::default())) - .fold_with(&mut fixer(None)); + let output = output.fold_with(&mut hygiene()).fold_with(&mut fixer(None)); print_js(cm.clone(), &output); diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/arguments.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/arguments.rs index 1d48b0615..1dd9d954e 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/arguments.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/arguments.rs @@ -2,7 +2,11 @@ use std::iter::repeat_with; use swc_common::{util::take::Take, DUMMY_SP}; use swc_ecma_ast::*; -use swc_ecma_utils::{find_pat_ids, is_valid_prop_ident, private_ident}; +use swc_ecma_utils::{ + find_pat_ids, is_valid_prop_ident, + number::{parse_canonical_index, ToJsString}, + private_ident, +}; use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith}; use super::Optimizer; @@ -179,64 +183,17 @@ impl VisitMut for ArgReplacer<'_> { n.visit_mut_children_with(self); - if let Expr::Member(MemberExpr { - obj, - prop: MemberProp::Computed(c), - .. - }) = n - { - match &**obj { - Expr::Ident(Ident { sym, .. }) if &**sym == "arguments" => { - match &*c.expr { - Expr::Lit(Lit::Str(Str { value, .. })) => { - let Some(value) = value.as_str() else { - return; - }; - let idx = value.parse::(); - let idx = match idx { - Ok(v) => v, - _ => return, - }; - - self.inject_params_if_required(idx); - - if let Some(param) = self.params.get(idx) { - if let Pat::Ident(i) = ¶m.pat { - self.changed = true; - report_change!( - "arguments: Replacing access to arguments to normal \ - reference" - ); - *n = i.id.clone().into(); - } - } - } - Expr::Lit(Lit::Num(Number { value, .. })) => { - if value.fract() != 0.0 { - // We ignores non-integer values. - return; - } - - let idx = value.round() as i64 as usize; - - self.inject_params_if_required(idx); - - // - if let Some(param) = self.params.get(idx) { - if let Pat::Ident(i) = ¶m.pat { - report_change!( - "arguments: Replacing access to arguments to normal \ - reference" - ); - self.changed = true; - *n = i.id.clone().into(); - } - } - } - _ => {} - } - } - _ => (), + let Some(idx) = argument_access_index(n) else { + return; + }; + + self.inject_params_if_required(idx); + + if let Some(param) = self.params.get(idx) { + if let Pat::Ident(i) = ¶m.pat { + self.changed = true; + report_change!("arguments: Replacing access to arguments to normal reference"); + *n = i.id.clone().into(); } } } @@ -266,3 +223,29 @@ impl VisitMut for ArgReplacer<'_> { } } } + +/// Returns an `arguments` index only when the property key is already in its +/// canonical non-negative integer spelling. +fn argument_access_index(expr: &Expr) -> Option { + let Expr::Member(MemberExpr { + obj, + prop: MemberProp::Computed(computed), + .. + }) = expr + else { + return None; + }; + let Expr::Ident(Ident { sym, .. }) = &**obj else { + return None; + }; + + if &**sym != "arguments" { + return None; + } + + match &*computed.expr { + Expr::Lit(Lit::Str(Str { value, .. })) => parse_canonical_index(value.as_str()?), + Expr::Lit(Lit::Num(Number { value, .. })) => parse_canonical_index(&value.to_js_string()), + _ => None, + } +} diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs index 09d1f5c0f..01b7ead97 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs @@ -1,13 +1,12 @@ -use std::num::FpCategory; - use swc_atoms::atom; -use swc_common::{util::take::Take, Spanned, SyntaxContext, DUMMY_SP}; +use swc_common::{util::take::Take, Spanned}; use swc_ecma_ast::*; -use swc_ecma_utils::{ExprExt, Value::Known}; +use swc_ecma_utils::{number::JsNumber, ExprExt, Value::Known}; use super::{BitCtx, Optimizer}; use crate::{ - compress::util::eval_as_number, program_data::VarUsageInfoFlags, DISABLE_BUGGY_PASSES, + compress::util::eval_as_number, program_data::VarUsageInfoFlags, util::make_number, + DISABLE_BUGGY_PASSES, }; /// Methods related to the option `evaluate`. @@ -111,7 +110,7 @@ impl Optimizer<'_> { enum IdentGlobal { Undefined, - Infinity, + Number(f64), } let ident_global = match e { @@ -119,8 +118,11 @@ impl Optimizer<'_> { Expr::Ident(i) if &*i.sym == "undefined" && !self.is_declared_ident(i) => { Some((i.span, IdentGlobal::Undefined)) } + Expr::Ident(i) if &*i.sym == "NaN" && !self.is_declared_ident(i) => { + Some((i.span, IdentGlobal::Number(f64::NAN))) + } Expr::Ident(i) if &*i.sym == "Infinity" && !self.is_declared_ident(i) => { - Some((i.span, IdentGlobal::Infinity)) + Some((i.span, IdentGlobal::Number(f64::INFINITY))) } _ => None, }; @@ -132,26 +134,10 @@ impl Optimizer<'_> { self.changed = true; *e = *Expr::undefined(span); } - IdentGlobal::Infinity => { - report_change!("evaluate: `Infinity` -> `1 / 0`"); + IdentGlobal::Number(value) => { + report_change!("evaluate: Global numeric constant -> numeric literal"); self.changed = true; - *e = BinExpr { - span, - op: op!("/"), - left: Lit::Num(Number { - span: DUMMY_SP, - value: 1.0, - raw: None, - }) - .into(), - right: Lit::Num(Number { - span: DUMMY_SP, - value: 0.0, - raw: None, - }) - .into(), - } - .into(); + *e = make_number(span, value); } } return; @@ -182,39 +168,19 @@ impl Optimizer<'_> { .into(); } "NaN" => { - report_change!("evaluate: `Number.NaN` -> `NaN`"); + report_change!("evaluate: `Number.NaN` -> numeric literal"); self.changed = true; - *e = Ident::new( - atom!("NaN"), - *span, - SyntaxContext::empty().apply_mark(self.marks.unresolved_mark), - ) - .into(); + *e = make_number(*span, f64::NAN); } "POSITIVE_INFINITY" => { - report_change!("evaluate: `Number.POSITIVE_INFINITY` -> `Infinity`"); + report_change!("evaluate: `Number.POSITIVE_INFINITY` -> numeric literal"); self.changed = true; - *e = Ident::new( - atom!("Infinity"), - *span, - SyntaxContext::empty().apply_mark(self.marks.unresolved_mark), - ) - .into(); + *e = make_number(*span, f64::INFINITY); } "NEGATIVE_INFINITY" => { - report_change!("evaluate: `Number.NEGATIVE_INFINITY` -> `-Infinity`"); + report_change!("evaluate: `Number.NEGATIVE_INFINITY` -> numeric literal"); self.changed = true; - *e = UnaryExpr { - span: *span, - op: op!(unary, "-"), - arg: Ident::new( - atom!("Infinity"), - *span, - SyntaxContext::empty().apply_mark(self.marks.unresolved_mark), - ) - .into(), - } - .into(); + *e = make_number(*span, f64::NEG_INFINITY); } _ => {} } @@ -334,7 +300,7 @@ impl Optimizer<'_> { } if let Known(char_code) = args[0].expr.as_pure_number(self.ctx.expr_ctx) { - let v = char_code.floor() as u32; + let v = u32::from(JsNumber::from(char_code).to_uint16()); if let Some(v) = char::from_u32(v) { if !v.is_ascii() { @@ -342,7 +308,7 @@ impl Optimizer<'_> { } self.changed = true; report_change!( - "evaluate: Evaluated `String.charCodeAt({})` as `{}`", + "evaluate: Evaluated `String.fromCharCode({})` as `{}`", char_code, v ); @@ -450,23 +416,7 @@ impl Optimizer<'_> { if let Some(value) = eval_as_number(self.ctx.expr_ctx, e) { self.changed = true; report_change!("evaluate: Evaluated an expression as `{}`", value); - - if value.is_nan() { - *e = Ident::new( - atom!("NaN"), - e.span(), - SyntaxContext::empty().apply_mark(self.marks.unresolved_mark), - ) - .into(); - return; - } - - *e = Lit::Num(Number { - span: e.span(), - value, - raw: None, - }) - .into(); + *e = make_number(e.span(), value); return; } } @@ -482,19 +432,9 @@ impl Optimizer<'_> { report_change!("evaluate: Evaluated `{:?} ** {:?}`", l, r); if l.is_nan() || r.is_nan() { - *e = Ident::new( - atom!("NaN"), - bin.span, - SyntaxContext::empty().apply_mark(self.marks.unresolved_mark), - ) - .into(); + *e = make_number(bin.span, f64::NAN); } else { - *e = Lit::Num(Number { - span: bin.span, - value: l.powf(r), - raw: None, - }) - .into(); + *e = make_number(bin.span, l.powf(r)); }; } } @@ -505,31 +445,11 @@ impl Optimizer<'_> { let rn = bin.right.as_pure_number(self.ctx.expr_ctx); if let (Known(ln), Known(rn)) = (ln, rn) { - // Prefer `0/0` over NaN. - if ln == 0.0 && rn == 0.0 { - return; - } - // Prefer `1/0` over Infinity. - if ln == 1.0 && rn == 0.0 { - return; - } - - // It's NaN - if let (FpCategory::Normal, FpCategory::Zero) = (ln.classify(), rn.classify()) { + let value = ln / rn; + if !value.is_finite() { self.changed = true; - report_change!("evaluate: `{} / 0` => `Infinity`", ln); - - // Sign does not matter for NaN - *e = if ln.is_sign_positive() == rn.is_sign_positive() { - Ident::new_no_ctxt(atom!("Infinity"), bin.span).into() - } else { - UnaryExpr { - span: bin.span, - op: op!(unary, "-"), - arg: Ident::new_no_ctxt(atom!("Infinity"), bin.span).into(), - } - .into() - }; + report_change!("evaluate: Evaluated `{} / {}`", ln, rn); + *e = make_number(bin.span, value); } } } diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/iife.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/iife.rs index cdc56c181..1b59280f8 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/iife.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/iife.rs @@ -565,6 +565,12 @@ impl Optimizer<'_> { return false; } + if let Some(scope) = self.data.get_scope(f.ctxt) { + if scope.intersects(ScopeData::HAS_EVAL_CALL) { + return false; + } + } + if f.params.iter().any(|param| !param.is_ident()) { return false; } @@ -608,7 +614,13 @@ impl Optimizer<'_> { let body = f.function.body.as_ref().unwrap(); - if contains_this_expr(body) || self.data.used_arguments(f.function.ctxt) { + if let Some(scope) = self.data.get_scope(f.function.ctxt) { + if scope.intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::USED_ARGUMENTS)) { + return false; + } + } + + if contains_this_expr(body) { return false; } } @@ -861,8 +873,24 @@ impl Optimizer<'_> { param_ids: impl ExactSizeIterator + Clone, args: &[ExprOrSpread], ) -> bool { - // Don't create top-level variables. + if param_ids.len() == 0 { + return true; + } + if !self.may_add_ident() { + // cannot add new ident, but sometimes inline or unused pass could remove those + // new vars + // but not when there's eval + + if self + .data + .get_scope(self.ctx.scope) + .unwrap() + .contains(ScopeData::HAS_EVAL_CALL) + { + return false; + } + for (idx, pid) in param_ids.clone().enumerate() { if let Some(usage) = self.data.vars.get(&pid.to_id()) { let arg = args.get(idx).map(|a| &*a.expr); @@ -986,17 +1014,6 @@ impl Optimizer<'_> { return false; } - // Abort on eval. - // See https://github.com/swc-project/swc/pull/6478 - // - // We completely abort on eval, because we cannot know whether a variable in - // upper scope will be afftected by eval. - // https://github.com/swc-project/swc/issues/6628 - if self.data.top.contains(ScopeData::HAS_EVAL_CALL) { - log_abort!("iife: [x] Aborting because of eval"); - return false; - } - if !self.may_add_ident() { let has_decl = if for_stmt { // we check it later diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/inline.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/inline.rs index da9229c7a..e29117904 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/inline.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/inline.rs @@ -41,8 +41,10 @@ impl Optimizer<'_> { self.may_remove_ident(ident) ); - if self.data.top.contains(ScopeData::HAS_EVAL_CALL) { - return; + if let Some(scope) = self.data.get_scope(self.ctx.var_scope) { + if scope.intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT)) { + return; + } } // We will inline if possible. @@ -65,13 +67,20 @@ impl Optimizer<'_> { return; } - if self.data.top.contains(ScopeData::USED_ARGUMENTS) + let used_arguments = self + .data + .get_scope(self.ctx.var_scope) + .unwrap() + .contains(ScopeData::USED_ARGUMENTS); + + if used_arguments && usage .flags .contains(VarUsageInfoFlags::DECLARED_AS_FN_PARAM) { return; } + if usage .flags .contains(VarUsageInfoFlags::DECLARED_AS_CATCH_PARAM) @@ -437,39 +446,7 @@ impl Optimizer<'_> { return; } - Expr::Fn(f) => { - let excluded: Vec = find_pat_ids(&f.function.params); - - for id in idents_used_by(&f.function.params) { - if excluded.contains(&id) { - continue; - } - if let Some(v_usage) = self.data.vars.get(&id) { - if v_usage.flags.contains(VarUsageInfoFlags::REASSIGNED) { - return; - } - } else { - return; - } - } - } - - Expr::Arrow(f) => { - let excluded: Vec = find_pat_ids(&f.params); - - for id in idents_used_by(&f.params) { - if excluded.contains(&id) { - continue; - } - if let Some(v_usage) = self.data.vars.get(&id) { - if v_usage.flags.contains(VarUsageInfoFlags::REASSIGNED) { - return; - } - } else { - return; - } - } - } + Expr::Fn(_) | Expr::Arrow(_) => {} Expr::Object(..) if self.options.pristine_globals => { for id in idents_used_by_ignoring_nested(init) { @@ -696,16 +673,14 @@ impl Optimizer<'_> { return; } - if self - .data - .top - .intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT)) - { - return; - } - let id = i.to_id(); + if let Some(scope) = self.data.get_scope(self.ctx.var_scope) { + if scope.intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT)) { + return; + } + } + if let Some(usage) = self.data.vars.get(&id) { if usage .flags @@ -798,13 +773,13 @@ impl Optimizer<'_> { id.1 ); - for i in collect_infects_from( + for (i, _) in collect_infects_from( &f.function, AliasConfig::default() .marks(Some(self.marks)) .need_all(true), ) { - if let Some(usage) = self.data.vars.get_mut(&i.0) { + if let Some(usage) = self.data.vars.get_mut(&i) { usage.ref_count += 1; } } diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/mod.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/mod.rs index ac2c94345..a65af9d81 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/mod.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/mod.rs @@ -79,7 +79,8 @@ pub(super) fn optimizer<'a>( in_strict: options.module, remaining_depth: 6, }, - scope: SyntaxContext::default(), + scope: marks.top_level_ctxt, + var_scope: marks.top_level_ctxt, bit_ctx: BitCtx::default(), }; @@ -111,6 +112,9 @@ struct Ctx { /// Current scope. scope: SyntaxContext, + /// fn or top level scope + var_scope: SyntaxContext, + bit_ctx: BitCtx, } @@ -373,10 +377,6 @@ impl Optimizer<'_> { } fn may_add_ident(&self) -> bool { - if self.ctx.in_top_level() && self.data.top.contains(ScopeData::HAS_EVAL_CALL) { - return false; - } - // in class field if self.ctx.bit_ctx.contains(BitCtx::InClass) && !self @@ -393,7 +393,7 @@ impl Optimizer<'_> { if self .data - .get_scope(self.ctx.scope) + .get_scope(self.ctx.var_scope) .unwrap() .contains(ScopeData::HAS_EVAL_CALL) { @@ -1518,6 +1518,7 @@ impl VisitMut for Optimizer<'_> { .with(BitCtx::InFnLike, true) .with(BitCtx::TopLevel, false), scope: n.ctxt, + var_scope: n.ctxt, ..self.ctx.clone() }; n.body.visit_mut_with(&mut *self.with_ctx(ctx)); @@ -1809,6 +1810,21 @@ impl VisitMut for Optimizer<'_> { private_method.visit_mut_with(&mut *self.with_ctx(ctx)); } + ClassMember::StaticBlock(s) => { + let ctx = Ctx { + bit_ctx: self + .ctx + .bit_ctx + .with(BitCtx::TopLevel, false) + .with(BitCtx::InBlock, true) + .with(BitCtx::InParam, false), + scope: s.body.ctxt, + var_scope: s.body.ctxt, + ..self.ctx.clone() + }; + n.visit_mut_children_with(&mut *self.with_ctx(ctx)); + } + _ => { n.visit_mut_children_with(&mut *self.with_ctx(ctx)); } @@ -2336,6 +2352,7 @@ impl VisitMut for Optimizer<'_> { .with(BitCtx::InFnLike, true) .with(BitCtx::TopLevel, false), scope: n.ctxt, + var_scope: n.ctxt, ..self.ctx.clone() }; let optimizer = &mut *self.with_ctx(ctx); @@ -2540,6 +2557,8 @@ impl VisitMut for Optimizer<'_> { n.args.visit_mut_with(&mut *self.with_ctx(ctx)); } + self.ignore_unused_args_of_new(n); + // Try to replace global object with alias (after other transformations) if self .static_alias_state diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs index dbca08ea5..5bb9c153d 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs @@ -20,10 +20,7 @@ use crate::{ }, option::CompressOptions, program_data::{ScopeData, VarUsageInfoFlags}, - usage_analyzer::{ - alias::{try_collect_infects_from, AccessKind, AliasConfig}, - util::is_global_var_with_pure_property_access, - }, + usage_analyzer::util::is_global_var_with_pure_property_access, util::{ idents_used_by, idents_used_by_ignoring_nested, ExprOptExt, IdentUsageCollector, ModuleItemExt, @@ -1102,56 +1099,7 @@ impl Optimizer<'_> { Mergable::Drop => return false, } - let e_id = e.to_id(); - let ids_used_by_a_init = match a { - Mergable::Var(a) => a.init.as_ref().map(|init| { - try_collect_infects_from( - init, - AliasConfig::default() - .marks(Some(self.marks)) - .ignore_nested(true) - .need_all(true), - 8, - ) - }), - Mergable::Expr(a) => match a { - Expr::Assign(a) if a.is_simple_assign() => Some(try_collect_infects_from( - &a.right, - AliasConfig::default() - .marks(Some(self.marks)) - .ignore_nested(true) - .need_all(true), - 8, - )), - - _ => None, - }, - - Mergable::FnDecl(a) => Some(try_collect_infects_from( - &a.function, - AliasConfig::default() - .marks(Some(self.marks)) - .ignore_nested(true) - .need_all(true), - 8, - )), - - Mergable::Drop => return false, - }; - - if let Some(deps) = ids_used_by_a_init { - let Ok(deps) = deps else { - return false; - }; - - if deps.iter().any(|(id, kind)| { - id == &e_id && matches!(kind, AccessKind::Reference | AccessKind::Call) - }) { - return false; - } - } - - if !self.assignee_skippable_for_seq(a, &e_id) { + if !self.assignee_skippable_for_seq(a, &e.to_id()) { return false; } } @@ -2442,10 +2390,9 @@ impl Optimizer<'_> { Mergable::Var(a) => { if self.options.unused { if let Some(usage) = self.data.vars.get(&left_id.to_id()) { - // We are eliminating one usage, so we use 1 instead of - // 0 + // We are eliminating one usage, so we use 1 instead of 0 if !force_drop - && usage.usage_count == 1 + && usage.ref_count == 1 && !usage.flags.contains(VarUsageInfoFlags::REASSIGNED) { report_change!("sequences: Dropping inlined variable"); diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/strings.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/strings.rs index eb46fbe97..01d796f09 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/strings.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/strings.rs @@ -1,9 +1,10 @@ -use swc_atoms::{atom, Atom, Wtf8Atom}; -use swc_common::{util::take::Take, Spanned, SyntaxContext}; +use swc_atoms::{Atom, Wtf8Atom}; +use swc_common::{util::take::Take, Spanned}; use swc_ecma_ast::*; use swc_ecma_utils::{ExprExt, Value::Known}; use super::Optimizer; +use crate::util::make_number; impl Optimizer<'_> { pub(super) fn optimize_expr_in_str_ctx_unsafely(&mut self, e: &mut Expr) { @@ -123,12 +124,7 @@ impl Optimizer<'_> { }) => { if let (Expr::Lit(Lit::Num(l)), Expr::Lit(Lit::Num(r))) = (&**left, &**right) { if l.value == 0.0 && r.value == 0.0 { - *n = Ident::new( - atom!("NaN"), - *span, - SyntaxContext::empty().apply_mark(self.marks.unresolved_mark), - ) - .into(); + *n = make_number(*span, f64::NAN); self.changed = true; report_change!("strings: Evaluated 0 / 0 => NaN in string context"); } diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/unused.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/unused.rs index d610fbdc8..0326b81f0 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/unused.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/optimize/unused.rs @@ -707,7 +707,8 @@ impl Optimizer<'_> { if self .data - .top + .get_scope(self.ctx.var_scope) + .unwrap() .intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT)) { return; @@ -753,7 +754,8 @@ impl Optimizer<'_> { if self .data - .top + .get_scope(self.ctx.var_scope) + .unwrap() .intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT)) { return; @@ -1160,6 +1162,10 @@ impl Optimizer<'_> { return; } + if self.ctx.bit_ctx.intersects(BitCtx::InWithStmt) { + return; + } + if e.args.iter().any(|a| a.spread.is_some()) { return; } @@ -1243,6 +1249,120 @@ impl Optimizer<'_> { } } } + + pub(crate) fn ignore_unused_args_of_new(&mut self, e: &mut NewExpr) { + if !self.options.unused && !self.options.reduce_vars { + return; + } + + if self.ctx.bit_ctx.intersects(BitCtx::InWithStmt) { + return; + } + + let args = if let Some(args) = &mut e.args { + args + } else { + return; + }; + + if args.iter().any(|a| a.spread.is_some()) { + return; + } + + let callee = &mut *e.callee; + + match callee { + Expr::Fn(FnExpr { function, .. }) => { + if let Some(scope) = self.data.get_scope(function.ctxt) { + if scope.intersects(ScopeData::USED_ARGUMENTS.union(ScopeData::HAS_EVAL_CALL)) { + return; + } + } + } + Expr::Class(c) => { + for m in &c.class.body { + if let Some(scope) = + m.as_constructor().and_then(|c| self.data.get_scope(c.ctxt)) + { + if scope + .intersects(ScopeData::USED_ARGUMENTS.union(ScopeData::HAS_EVAL_CALL)) + { + return; + } + } + } + } + _ => (), + } + + let params_len = match callee { + Expr::Fn(FnExpr { function, .. }) => { + let params = &function.params; + + if !params.iter().any(|p| p.pat.is_rest()) { + params.len() + } else { + return; + } + } + Expr::Class(ClassExpr { class, .. }) => { + let c = class + .body + .iter() + .filter_map(|c| c.as_constructor()) + .find(|c| c.body.is_some()); + + if let Some(c) = c { + if !c + .params + .iter() + .any(|p| p.as_param().and_then(|p| p.pat.as_rest()).is_some()) + { + c.params.len() + } else { + return; + } + } else { + return; + } + } + Expr::Ident(i) => { + if let Some(scope) = self.data.get_scope(i.ctxt) { + if scope.intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT)) { + return; + } + } + + if let Some(data) = self.data.get_var_data(i.to_id()) { + if let (true, Some(Value::Known(count))) = ( + data.flags.intersects(VarUsageInfoFlags::DECLARED), + data.param_count, + ) { + count as usize + } else { + return; + } + } else { + return; + } + } + _ => return, + }; + + if args.len() > params_len { + for i in (params_len..args.len()).rev() { + if let Some(arg) = args.get_mut(i) { + let new = self.ignore_return_value(&mut arg.expr); + + if let Some(new) = new { + *arg.expr = new; + } else { + args.remove(i); + } + } + } + } + } } fn can_remove_property(sym: &swc_atoms::Wtf8Atom) -> bool { diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/pure/bools.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/pure/bools.rs index edafd4f98..b56597288 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/pure/bools.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/pure/bools.rs @@ -7,7 +7,7 @@ use swc_ecma_utils::{ExprCtx, ExprExt, Type, Value}; use super::Pure; use crate::{ compress::util::{can_absorb_negate, is_eq, is_pure_undefined, negate, negate_cost}, - util::make_bool, + util::{is_falsy_number, make_bool}, }; #[inline(always)] @@ -529,7 +529,7 @@ impl Pure<'_> { self.changed = true; *n = Lit::Num(Number { span: *span, - value: if *value == 0.0 { 1.0 } else { 0.0 }, + value: if is_falsy_number(*value) { 1.0 } else { 0.0 }, raw: None, }) .into() @@ -601,7 +601,7 @@ impl Pure<'_> { self.changed = true; *n = Lit::Num(Number { span: num.span, - value: if num.value == 0.0 { 0.0 } else { 1.0 }, + value: if is_falsy_number(num.value) { 0.0 } else { 1.0 }, raw: None, }) .into(); diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/pure/conds.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/pure/conds.rs index 0fc6203de..587922cc7 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/pure/conds.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/pure/conds.rs @@ -223,16 +223,21 @@ impl Pure<'_> { return; } + fn can_rewrite_as_arithmetic(non_zero: &Number, zero: &Number) -> bool { + non_zero.value.is_finite() + && non_zero.value > 0.0 + && zero.value == 0.0 + && zero.value.is_sign_positive() + } + let Expr::Cond(cond) = e else { return }; let span = cond.span; match (&mut *cond.cons, &mut *cond.alt) { - ( - Expr::Lit(Lit::Num(Number { value, .. })), - Expr::Lit(Lit::Num(Number { value: 0.0, .. })), - ) if *value > 0.0 - && (!cond.test.is_bin() - || cond.test.get_type(self.expr_ctx) == Value::Known(Type::Bool)) => + (Expr::Lit(Lit::Num(non_zero)), Expr::Lit(Lit::Num(zero))) + if can_rewrite_as_arithmetic(non_zero, zero) + && (!cond.test.is_bin() + || cond.test.get_type(self.expr_ctx) == Value::Known(Type::Bool)) => { report_change!("conditionals: `foo ? num : 0` => `num * !!foo`"); self.changed = true; @@ -248,11 +253,9 @@ impl Pure<'_> { right, }) } - ( - Expr::Lit(Lit::Num(Number { value: 0.0, .. })), - Expr::Lit(Lit::Num(Number { value, .. })), - ) if *value > 0.0 - && (!cond.test.is_bin() || can_absorb_negate(&cond.test, self.expr_ctx)) => + (Expr::Lit(Lit::Num(zero)), Expr::Lit(Lit::Num(non_zero))) + if can_rewrite_as_arithmetic(non_zero, zero) + && (!cond.test.is_bin() || can_absorb_negate(&cond.test, self.expr_ctx)) => { report_change!("conditionals: `foo ? 0 : num` => `num * !foo`"); self.changed = true; diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs index e5d9dd086..602fa4a3a 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs @@ -1,9 +1,11 @@ +use std::{num::FpCategory, ops::RangeInclusive}; + use radix_fmt::Radix; use swc_atoms::atom; -use swc_common::{util::take::Take, Spanned, SyntaxContext}; +use swc_common::{util::take::Take, Spanned}; use swc_ecma_ast::*; use swc_ecma_utils::{ - number::ToJsString, + number::{parse_canonical_index, ToJsString}, unicode::{is_high_surrogate, is_low_surrogate}, ExprExt, IsEmpty, Type, Value, }; @@ -16,9 +18,62 @@ use crate::{ pure::Ctx, util::{eval_as_number, is_pure_undefined_or_null}, }, - util::ValueExt, + util::{make_number, ValueExt}, }; +/// Formats an integer with `radix_fmt` only where its exact integer output is +/// also a valid ECMAScript `Number::toString` result. +fn format_integer_in_radix(value: f64, radix: u8) -> Option { + const MAX_SAFE_INTEGER: f64 = 9_007_199_254_740_991_f64; + + let magnitude = value.abs(); + let is_safe_integer = magnitude <= MAX_SAFE_INTEGER; + let is_supported_binary_radix = radix.is_power_of_two() && magnitude < u128::MAX as f64; + + if !is_safe_integer && !is_supported_binary_radix { + return None; + } + + let digits = Radix::new(magnitude as u128, radix).to_string(); + if value >= 0_f64 { + return Some(digits); + } + + let mut output = String::with_capacity(digits.len() + 1); + output.push('-'); + output.push_str(&digits); + Some(output) +} + +/// Applies ECMAScript's `ToIntegerOrInfinity` operation to a known number. +/// +/// https://tc39.es/ecma262/multipage/abstract-operations.html#sec-tointegerorinfinity +fn to_integer_or_infinity(value: f64) -> f64 { + // Step 1 (`ToNumber`) is already satisfied by the `f64` input. + // 2. If number is one of NaN, +0𝔽, or -0𝔽, return 0. + // 3. If number is +∞𝔽, return +∞. + // 4. If number is -∞𝔽, return -∞. + // 5. Return truncate(ℝ(number)). + match value.classify() { + FpCategory::Nan | FpCategory::Zero => 0.0, + FpCategory::Infinite => value, + _ => value.trunc(), + } +} + +/// Converts a `ToIntegerOrInfinity` result to `u8` if it is within `range`. +fn to_u8_if_in_range(value: f64, range: RangeInclusive) -> Option { + let start = f64::from(*range.start()); + let end = f64::from(*range.end()); + let valid_range = start..=end; + + if !valid_range.contains(&value) { + return None; + } + + Some(value as u8) +} + impl Pure<'_> { /// /// - `1 == 1` => `true` @@ -412,7 +467,9 @@ impl Pure<'_> { MemberProp::Computed(p) => { if let Expr::Lit(Lit::Str(s)) = &*p.expr { if let Some(value) = s.value.as_str() { - if let Ok(value) = value.parse::() { + if let Some(value) = + parse_canonical_index(value).and_then(|value| u32::try_from(value).ok()) + { p.expr = Lit::Num(Number { span: s.span, value: value as f64, @@ -530,16 +587,16 @@ impl Pure<'_> { // 2. Let f be ? ToIntegerOrInfinity(fractionDigits). // 3. Assert: If fractionDigits is undefined, then f is 0. let precision = first_arg.unwrap_or(0f64); - let f = precision.trunc() as u8; // 4. If f is not finite, throw a RangeError exception. // 5. If f < 0 or f > 100, throw a RangeError exception. - + let f = to_integer_or_infinity(precision); // Note: ES2018 increased the maximum number of fraction digits from 20 to 100. - // It relies on runtime behavior. - if !(0..=20).contains(&f) { + // Preserve the optimizer's existing conservative folding range. Wider valid + // values are left to runtime. + let Some(f) = to_u8_if_in_range(f, 0..=20) else { return; - } + }; let mut buffer = ryu_js::Buffer::new(); let value = buffer.format_to_fixed(num.value, f); @@ -583,13 +640,23 @@ impl Pure<'_> { .into(); return; } else if let Some(precision) = first_arg { - let p = precision.trunc() as usize; - // 5. If p < 1 or p > 100, throw a RangeError exception. - if !(1..=21).contains(&p) { - return; - } + // 3. Let p be ? ToIntegerOrInfinity(precision). + let p = to_integer_or_infinity(precision); + + let value = if num.value.is_finite() { + // 5. If p < 1 or p > 100, throw a RangeError exception. + // Preserve the optimizer's existing conservative folding range. Wider valid + // values are left to runtime. + let Some(p) = to_u8_if_in_range(p, 1..=21) else { + return; + }; + + f64_to_precision(num.value, usize::from(p)) + } else { + // 4. If x is not finite, return Number::toString(x, 10). + num.value.to_js_string() + }; - let value = f64_to_precision(num.value, p); self.changed = true; report_change!( "evaluate: Evaluating `{}.toPrecision()` as `{}`", @@ -625,13 +692,22 @@ impl Pure<'_> { .into(); return; } else if let Some(precision) = first_arg { - let p = precision.trunc() as usize; - // 5. If p < 1 or p > 100, throw a RangeError exception. - if !(0..=20).contains(&p) { - return; - } + // 3. Let f be ? ToIntegerOrInfinity(fractionDigits). + let p = to_integer_or_infinity(precision); + + let value = if num.value.is_finite() { + // 5. If f < 0 or f > 100, throw a RangeError exception. + // Preserve the optimizer's existing conservative folding range. Wider valid + // values are left to runtime. + let Some(p) = to_u8_if_in_range(p, 0..=20) else { + return; + }; - let value = f64_to_exponential_with_precision(num.value, p).into(); + f64_to_exponential_with_precision(num.value, usize::from(p)).into() + } else { + // 4. If x is not finite, return Number::toString(x, 10). + num.value.to_js_string().into() + }; self.changed = true; report_change!( @@ -666,26 +742,17 @@ impl Pure<'_> { if num.value.fract() == 0.0 && (2.0..=36.0).contains(&base) && base.fract() == 0.0 { let base = base.floor() as u8; - - self.changed = true; - - let value = { - let x = num.value; - if x < 0. { - // I don't know if u128 is really needed, but it works. - format!("-{}", Radix::new(-x as u128, base)) - } else { - Radix::new(x as u128, base).to_string() - } - } - .into(); + let Some(value) = format_integer_in_radix(num.value, base) else { + return; + }; *e = Lit::Str(Str { span: e.span(), raw: None, - value, + value: value.into(), }) - .into() + .into(); + self.changed = true; } } } @@ -867,7 +934,7 @@ impl Pure<'_> { report_change!( "evaluate: Evaluated `charCodeAt` of a string literal as `NaN`", ); - *e = Ident::new(atom!("NaN"), e.span(), SyntaxContext::empty()).into() + *e = make_number(e.span(), f64::NAN) } } } @@ -932,12 +999,7 @@ impl Pure<'_> { report_change!( "evaluate: Evaluated `codePointAt` of a string literal as `NaN`", ); - *e = Ident::new( - atom!("NaN"), - e.span(), - SyntaxContext::empty().apply_mark(self.marks.unresolved_mark), - ) - .into() + *e = make_number(e.span(), f64::NAN) } } } @@ -960,6 +1022,10 @@ impl Pure<'_> { // Code from boa // https://github.com/boa-dev/boa/blob/f8b682085d7fe0bbfcd0333038e93cf2f5aee710/boa_engine/src/builtins/number/mod.rs#L408 fn f64_to_precision(value: f64, precision: usize) -> String { + if !value.is_finite() { + return value.to_js_string(); + } + let mut x = value; let p_i32 = precision as i32; @@ -1114,6 +1180,10 @@ fn round_to_precision(digits: &mut String, precision: usize) -> bool { /// Helper function that formats a float as a ES6-style exponential number /// string. fn f64_to_exponential(n: f64) -> String { + if !n.is_finite() { + return n.to_js_string(); + } + match n.abs() { x if x >= 1.0 || x == 0.0 => format!("{n:e}").replace('e', "e+"), _ => format!("{n:e}"), @@ -1127,6 +1197,10 @@ fn f64_to_exponential(n: f64) -> String { // Instead we get the index of 'e', and if the next character is not '-' // we insert the plus sign fn f64_to_exponential_with_precision(n: f64, prec: usize) -> String { + if !n.is_finite() { + return n.to_js_string(); + } + let mut res = format!("{n:.prec$e}"); let idx = res.find('e').expect("'e' not found in exponential string"); if res.as_bytes()[idx + 1] != b'-' { diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/pure/member_expr.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/pure/member_expr.rs index 85fe377e6..caea93c0d 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/pure/member_expr.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/pure/member_expr.rs @@ -5,7 +5,10 @@ use swc_ecma_ast::{ ArrayLit, Expr, ExprOrSpread, IdentName, Lit, MemberExpr, MemberProp, ObjectLit, Prop, PropOrSpread, SeqExpr, Str, }; -use swc_ecma_utils::{prop_name_eq, ExprExt, Known}; +use swc_ecma_utils::{ + number::{parse_canonical_index, ToJsString}, + prop_name_eq, ExprExt, Known, +}; use super::Pure; use crate::compress::pure::Ctx; @@ -150,6 +153,31 @@ fn is_string_symbol(sym: &str) -> bool { STRING_SYMBOLS.contains(sym) || is_object_symbol(sym) } +/// A statically known property key with optional metadata for literal indexing. +/// +/// `property_key` is always the exact ECMAScript property key. `index` is only +/// populated for canonical non-negative decimal keys that can index a literal +/// array or string without reinterpreting the property key. +struct KnownMemberKey { + property_key: Atom, + index: Option, +} + +impl KnownMemberKey { + fn from_number(value: f64) -> Self { + Self::from_property_key(Atom::from(value.to_js_string())) + } + + fn from_property_key(property_key: Atom) -> Self { + let index = parse_canonical_index(property_key.as_str()); + + Self { + property_key, + index, + } + } +} + /// Checks if the given key exists in the given properties, taking the /// `__proto__` property and order of keys into account (the order of keys /// matters for nested `__proto__` properties). @@ -258,29 +286,13 @@ impl Pure<'_> { return None; } - /// Taken from `simplify::expr`. - /// - /// `x.length` is handled as `IndexStr`, since `x.length` calls for - /// String and Array are handled in `simplify::expr` (the `length` - /// prototype for both of these types cannot be changed). - #[derive(Clone, PartialEq)] - enum KnownOp { - // [a, b][2] - // - // ({})[1] - Index(f64), - - /// ({}).foo - /// - /// ({}).length - IndexStr(Atom), - } - let op = match prop { - MemberProp::Ident(IdentName { sym, .. }) => KnownOp::IndexStr(sym.clone()), + MemberProp::Ident(IdentName { sym, .. }) => { + KnownMemberKey::from_property_key(sym.clone()) + } MemberProp::Computed(c) => match &*c.expr { - Expr::Lit(Lit::Num(n)) => KnownOp::Index(n.value), + Expr::Lit(Lit::Num(n)) => KnownMemberKey::from_number(n.value), Expr::Ident(..) => { return None; @@ -291,11 +303,7 @@ impl Pure<'_> { return None; }; - if let Ok(n) = s.parse::() { - KnownOp::Index(n) - } else { - KnownOp::IndexStr(Atom::from(s)) - } + KnownMemberKey::from_property_key(Atom::from(s)) } }, @@ -328,9 +336,14 @@ impl Pure<'_> { } Expr::Lit(Lit::Str(Str { value, span, .. })) => { - match op { - KnownOp::Index(idx) => { - if idx.fract() != 0.0 || idx < 0.0 || idx as usize >= value.len() { + match op.index { + Some(index) => { + // JavaScript indexes strings by UTF-16 code unit, not by WTF-8 byte. + // WTF-8 byte length remains a safe upper bound for a fast rejection. + let is_out_of_bounds = index >= value.len() + || value.to_ill_formed_utf16().nth(index).is_none(); + + if is_out_of_bounds { Some(*Expr::undefined(*span)) } else { // idx is in bounds, this is handled in simplify @@ -338,7 +351,9 @@ impl Pure<'_> { } } - KnownOp::IndexStr(key) => { + None => { + let key = op.property_key; + if key == "length" { // handled in simplify::expr return None; @@ -365,9 +380,9 @@ impl Pure<'_> { return None; } - match op { - KnownOp::Index(idx) => { - if idx >= 0.0 && (idx as usize) < elems.len() && idx.fract() == 0.0 { + match op.index { + Some(index) => { + if index < elems.len() { // idx is in bounds, handled in simplify return None; } @@ -400,7 +415,9 @@ impl Pure<'_> { }) } - KnownOp::IndexStr(key) if key != "length" /* handled in simplify */ => { + None if op.property_key != "length" /* handled in simplify */ => { + let key = op.property_key; + // If the property is a known symbol, e.g. [].push let is_known_symbol = is_array_symbol(&key); @@ -490,13 +507,10 @@ impl Pure<'_> { } // Get key as Atom - let key = match op { - KnownOp::Index(i) => Atom::from(i.to_string()), - KnownOp::IndexStr(key) if key != *"yield" => key, - _ => { - return None; - } - }; + let key = op.property_key; + if key == "yield" { + return None; + } // Check if key exists let exists = does_key_exist(&key, props); diff --git a/deps/swc/crates/swc_ecma_minifier/src/compress/pure/misc.rs b/deps/swc/crates/swc_ecma_minifier/src/compress/pure/misc.rs index 665782bdb..f96125c7f 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/compress/pure/misc.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/compress/pure/misc.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, fmt::Write, num::FpCategory}; +use std::{borrow::Cow, num::FpCategory}; use rustc_hash::FxHashSet; use swc_atoms::{ @@ -9,7 +9,9 @@ use swc_atoms::{ use swc_common::{iter::IdentifyLast, util::take::Take, Span, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_transforms_optimization::debug_assert_valid; -use swc_ecma_utils::{ExprCtx, ExprExt, ExprFactory, IdentUsageFinder, Type, Value}; +use swc_ecma_utils::{ + number::ToJsString, ExprCtx, ExprExt, ExprFactory, IdentUsageFinder, Type, Value, +}; use super::Pure; use crate::{ @@ -292,13 +294,32 @@ impl Pure<'_> { } } + // Spreading a primitive of these types copies zero own enumerable + // properties (`ToObject` on them yields a wrapper whose properties are + // all non-enumerable), so `{ ...x }` where `x` is one of them + // contributes nothing. + // + // Strings are intentionally EXCLUDED: they expose indexed own + // enumerable properties (`{ ..."ab" }` === `{ 0: "a", 1: "b" }`). + // Objects, arrays, functions, etc. are also excluded as they carry + // real properties. + fn spreads_no_props(expr: &Expr, expr_ctx: ExprCtx) -> bool { + matches!( + expr.get_type(expr_ctx), + Value::Known(Type::Undefined | Type::Null | Type::Bool | Type::Num | Type::Symbol) + ) + } + fn can_flatten_spread_expr(expr: &Expr, expr_ctx: ExprCtx) -> bool { match expr { Expr::Object(ObjectLit { props, .. }) => { props.iter().all(|p| can_flatten_spread_prop(p, expr_ctx)) } - Expr::Lit(Lit::Null(_)) => true, - _ => false, + // Spreading a side-effect-free expression that has no own + // enumerable properties contributes nothing. We require purity + // so that we never discard observable side effects + // (e.g. `{ ...void foo() }`). + _ => spreads_no_props(expr, expr_ctx) && !expr.may_have_side_effects(expr_ctx), } } @@ -374,16 +395,12 @@ impl Pure<'_> { PropOrSpread::Spread(SpreadElement { expr, .. }) if can_flatten_spread_expr(&expr, self.expr_ctx) => { - match *expr { - Expr::Object(ObjectLit { props, .. }) => { - for p in props { - new_props.push(p); - } - } - - Expr::Lit(Lit::Null(_)) => {} - - _ => {} + // A plain object literal is flattened into the target; any + // other flattenable spread is a no-property primitive + // (including `null`) that contributes nothing, so it is + // simply dropped. + if let Expr::Object(ObjectLit { props, .. }) = *expr { + new_props.extend(props); } } @@ -709,7 +726,7 @@ impl Pure<'_> { res.push_wtf8(&s.value); } Expr::Lit(Lit::Num(n)) => { - write!(res, "{}", n.value).unwrap(); + res.push_str(&n.value.to_js_string()); } e if is_pure_undefined(self.expr_ctx, e) => {} Expr::Lit(Lit::Null(..)) => {} @@ -901,7 +918,7 @@ impl Pure<'_> { for literal in literals.iter() { match &*literal.expr { Expr::Lit(Lit::Str(s)) => joined.push_wtf8(&s.value), - Expr::Lit(Lit::Num(n)) => write!(joined, "{}", n.value).unwrap(), + Expr::Lit(Lit::Num(n)) => joined.push_str(&n.value.to_js_string()), Expr::Lit(Lit::Null(..)) => { // For string concatenation, null becomes // empty string @@ -957,7 +974,7 @@ impl Pure<'_> { match &*literal.expr { Expr::Lit(Lit::Str(s)) => joined.push_wtf8(&s.value), - Expr::Lit(Lit::Num(n)) => write!(joined, "{}", n.value).unwrap(), + Expr::Lit(Lit::Num(n)) => joined.push_str(&n.value.to_js_string()), Expr::Lit(Lit::Null(..)) => { // null becomes empty string } @@ -1137,17 +1154,19 @@ impl Pure<'_> { if let ExprOrSpread { spread: None, expr } = &args[0] { match &**expr { Expr::Lit(Lit::Num(num)) => { - if num.value <= 5_f64 && num.value >= 0_f64 { - Some( - ArrayLit { - span: *span, - elems: vec![None; num.value as usize], - } - .into(), - ) - } else { - None + let length = num.value; + + if !(0_f64..=5_f64).contains(&length) || length.fract() != 0_f64 { + return None; } + + Some( + ArrayLit { + span: *span, + elems: vec![None; length as usize], + } + .into(), + ) } Expr::Lit(_) => Some( ArrayLit { diff --git a/deps/swc/crates/swc_ecma_minifier/src/eval.rs b/deps/swc/crates/swc_ecma_minifier/src/eval.rs index ecae2b90e..facceeb41 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/eval.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/eval.rs @@ -12,6 +12,7 @@ use crate::{ mode::Mode, option::{CompressOptions, TopLevelOptions}, usage_analyzer::marks::Marks, + util::is_falsy_number, }; pub struct Evaluator { @@ -313,7 +314,7 @@ fn is_truthy(lit: &EvalResult) -> Option { Lit::Str(v) => Some(!v.value.is_empty()), Lit::Bool(v) => Some(v.value), Lit::Null(_) => Some(false), - Lit::Num(v) => Some(v.value != 0.0 && v.value != -0.0), + Lit::Num(v) => Some(!is_falsy_number(v.value)), _ => None, }, EvalResult::Undefined => Some(false), diff --git a/deps/swc/crates/swc_ecma_minifier/src/program_data.rs b/deps/swc/crates/swc_ecma_minifier/src/program_data.rs index 9cf6051c2..eef6b3d61 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/program_data.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/program_data.rs @@ -42,8 +42,6 @@ pub(crate) struct ProgramData { initialized_vars: IndexSet, - pub(crate) top: ScopeData, - scopes: Vec, pub(crate) property_atoms: Option>, @@ -214,10 +212,6 @@ impl Storage for ProgramData { &self.scopes } - fn top_scope(&mut self) -> &mut Self::ScopeData { - &mut self.top - } - fn var_or_default(&mut self, id: Id) -> &mut Self::VarData { self.vars.entry(id).or_default() } diff --git a/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/alias/mod.rs b/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/alias/mod.rs index a2f2224b8..1ef2eadb1 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/alias/mod.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/alias/mod.rs @@ -295,7 +295,7 @@ impl Visit for InfectionCollector { match e { Expr::Ident(i) => { - if self.ctx.contains(Ctx::TrackExprIdent) { + if self.ctx.contains(Ctx::TrackExprIdent) || self.config.need_all { self.add_usage(i.to_id()); } } @@ -340,14 +340,12 @@ impl Visit for InfectionCollector { fn visit_member_expr(&mut self, n: &MemberExpr) { { - let mut ctx = self.ctx; - ctx.set(Ctx::TrackExprIdent, self.config.need_all); + let ctx = self.ctx - Ctx::TrackExprIdent; n.obj.visit_with(&mut *self.with_ctx(ctx)); } { - let mut ctx = self.ctx; - ctx.set(Ctx::TrackExprIdent, self.config.need_all); + let ctx = self.ctx - Ctx::TrackExprIdent; n.prop.visit_with(&mut *self.with_ctx(ctx)); } } diff --git a/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/analyzer/mod.rs b/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/analyzer/mod.rs index 00fc30bd3..7fbdcfefa 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/analyzer/mod.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/analyzer/mod.rs @@ -44,8 +44,13 @@ where top_scope.merge(scope.clone(), true); } - v.data.top_scope().merge(top_scope.clone(), false); - v.data.scope(SyntaxContext::empty()).merge(top_scope, false); + v.data + .scope( + marks + .map(|m| m.top_level_ctxt) + .unwrap_or(SyntaxContext::empty()), + ) + .merge(top_scope, false); v.data } @@ -225,6 +230,68 @@ where }); } } + + fn store_function_arity(&mut self, id: Id, function: &Function) { + let scope = self.data.scope(function.ctxt); + + let known = !scope.used_arguments() + && !scope.used_eval() + && !function.params.iter().any(|p| p.pat.is_rest()); + + let arity = if known { + Self::param_count_to_value(function.params.len()) + } else { + Value::Unknown + }; + + self.data.var_or_default(id).store_param_count(arity); + } + + fn store_arrow_arity(&mut self, id: Id, arrow: &ArrowExpr) { + let scope = self.data.scope(arrow.ctxt); + let known = !scope.used_eval() && !arrow.params.iter().any(|p| p.is_rest()); + + let arity = if known { + Self::param_count_to_value(arrow.params.len()) + } else { + Value::Unknown + }; + + self.data.var_or_default(id).store_param_count(arity); + } + + fn store_class_arity(&mut self, id: Id, class: &Class) { + let constructor = class + .body + .iter() + .filter_map(|s| s.as_constructor()) + .find(|c| c.body.is_some()); + + let arity = if let Some(c) = constructor { + let scope = self.data.scope(c.ctxt); + let known = !scope.used_arguments() + && !scope.used_eval() + && !c + .params + .iter() + .filter_map(|p| p.as_param()) + .any(|p| p.pat.is_rest()); + + if known { + Self::param_count_to_value(c.params.len()) + } else { + Value::Unknown + } + } else { + if class.super_class.is_some() { + Value::Unknown + } else { + Value::Known(0) + } + }; + + self.data.var_or_default(id).store_param_count(arity); + } } impl Visit for UsageAnalyzer @@ -337,28 +404,13 @@ where if let (Some(id), op!("=")) = (&n.left.as_ident(), n.op) { match &*n.right { Expr::Fn(n) => { - let scope = self.data.scope(n.function.ctxt); - let known = !scope.used_arguments() - && !scope.used_eval() - && !n.function.params.iter().any(|p| p.pat.is_rest()); - let data = self.data.var_or_default(id.id.to_id()); - - if known { - data.store_param_count(Self::param_count_to_value(n.function.params.len())); - } else { - data.store_param_count(Value::Unknown); - } + self.store_function_arity(id.id.to_id(), &n.function); } Expr::Arrow(n) => { - let scope = self.data.scope(n.ctxt); - let known = !scope.used_eval() && !n.params.iter().any(|p| p.is_rest()); - let data = self.data.var_or_default(id.id.to_id()); - - if known { - data.store_param_count(Self::param_count_to_value(n.params.len())); - } else { - data.store_param_count(Value::Unknown) - } + self.store_arrow_arity(id.id.to_id(), n); + } + Expr::Class(c) => { + self.store_class_arity(id.id.to_id(), &c.class); } _ => self .data @@ -609,6 +661,8 @@ where .insert(id.clone(), RecursiveUsage::FnOrClass); n.visit_children_with(self); + self.store_class_arity(n.ident.to_id(), &n.class); + self.used_recursively.remove(&id); } @@ -875,18 +929,7 @@ where } } - let scope = self.data.scope(n.function.ctxt); - let known = !scope.used_arguments() - && !scope.used_eval() - && !n.function.params.iter().any(|p| p.pat.is_rest()); - - let data = self.data.var_or_default(n.ident.to_id()); - - if known { - data.store_param_count(Self::param_count_to_value(n.function.params.len())); - } else { - data.store_param_count(Value::Unknown); - } + self.store_function_arity(id, &n.function); } #[cfg_attr( @@ -1498,30 +1541,13 @@ where match init { Expr::Fn(n) => { - let scope = self.data.scope(n.function.ctxt); - let known = !scope.used_arguments() - && !scope.used_eval() - && !n.function.params.iter().any(|p| p.pat.is_rest()); - let data = self.data.var_or_default(var.id.to_id()); - - if known { - data.store_param_count(Self::param_count_to_value( - n.function.params.len(), - )); - } else { - data.store_param_count(Value::Unknown); - } + self.store_function_arity(var.id.to_id(), &n.function); } Expr::Arrow(n) => { - let scope = self.data.scope(n.ctxt); - let known = !scope.used_eval() && !n.params.iter().any(|p| p.is_rest()); - let data = self.data.var_or_default(var.id.to_id()); - - if known { - data.store_param_count(Self::param_count_to_value(n.params.len())); - } else { - data.store_param_count(Value::Unknown) - } + self.store_arrow_arity(var.id.to_id(), n); + } + Expr::Class(c) => { + self.store_class_arity(var.id.to_id(), &c.class); } _ => self .data diff --git a/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/analyzer/storage.rs b/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/analyzer/storage.rs index 24d03d7fe..61210081e 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/analyzer/storage.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/usage_analyzer/analyzer/storage.rs @@ -18,8 +18,6 @@ pub trait Storage: Sized { fn scopes(&self) -> &[Self::ScopeData]; - fn top_scope(&mut self) -> &mut Self::ScopeData; - fn var_or_default(&mut self, id: Id) -> &mut Self::VarData; fn merge(&mut self, kind: ScopeKind, child: Self); diff --git a/deps/swc/crates/swc_ecma_minifier/src/util/mod.rs b/deps/swc/crates/swc_ecma_minifier/src/util/mod.rs index 5692d8682..cdc8b1775 100644 --- a/deps/swc/crates/swc_ecma_minifier/src/util/mod.rs +++ b/deps/swc/crates/swc_ecma_minifier/src/util/mod.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use std::time::Instant; +use std::{num::FpCategory, time::Instant}; use rustc_hash::FxHashSet; use swc_atoms::Atom; @@ -14,6 +14,12 @@ pub(crate) mod base54; pub(crate) mod size; pub(crate) mod sort; +/// Returns whether a number is falsy according to ECMAScript semantics. +#[inline] +pub(crate) fn is_falsy_number(value: f64) -> bool { + matches!(value.classify(), FpCategory::Zero | FpCategory::Nan) +} + pub(crate) fn make_number(span: Span, value: f64) -> Expr { trace_op!("Creating a numeric literal"); Lit::Num(Number { diff --git a/deps/swc/crates/swc_ecma_parser/Cargo.toml b/deps/swc/crates/swc_ecma_parser/Cargo.toml index f500368c3..d987ca859 100644 --- a/deps/swc/crates/swc_ecma_parser/Cargo.toml +++ b/deps/swc/crates/swc_ecma_parser/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "examples/**/*.rs"] license = { workspace = true } name = "swc_ecma_parser" repository = { workspace = true } -version = "41.1.2" +version = "43.0.0" [package.metadata.docs.rs] all-features = true @@ -31,17 +31,17 @@ verify = ["swc_ecma_visit"] [dependencies] bitflags = { workspace = true } +compact_str = { workspace = true } either = { workspace = true } num-bigint = { workspace = true } phf = { workspace = true, features = ["macros"] } rustc-hash = { workspace = true } seq-macro = { workspace = true } serde = { workspace = true, features = ["derive"] } -smartstring = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit", optional = true } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit", optional = true } tracing = { workspace = true } [target.'cfg(not(any(target_arch = "wasm32", target_arch = "arm")))'.dependencies] @@ -55,13 +55,13 @@ walkdir = { workspace = true } cbor4ii = { workspace = true, features = ["use_std"] } codspeed-criterion-compat = { workspace = true } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast", features = [ +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast", features = [ "serde-impl", "encoding-impl", ] } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } [[example]] name = "typescript" diff --git a/deps/swc/crates/swc_ecma_parser/src/lexer/mod.rs b/deps/swc/crates/swc_ecma_parser/src/lexer/mod.rs index 4d89c450e..35d55a102 100644 --- a/deps/swc/crates/swc_ecma_parser/src/lexer/mod.rs +++ b/deps/swc/crates/swc_ecma_parser/src/lexer/mod.rs @@ -2,9 +2,9 @@ use std::{borrow::Cow, char, rc::Rc}; +use compact_str::CompactString; use either::Either::{self, Left, Right}; use rustc_hash::FxHashMap; -use smartstring::{LazyCompact, SmartString}; use swc_atoms::{ wtf8::{CodePoint, Wtf8, Wtf8Buf}, Atom, AtomStoreCell, @@ -1385,7 +1385,7 @@ impl<'a> Lexer<'a> { s.chars().all(|c| c.is_ascii_digit()) } - let mut s = SmartString::::default(); + let mut s = CompactString::default(); debug_assert!(self.input().cur().is_some_and(|c| c == b'&')); self.bump(1); // `&` diff --git a/deps/swc/crates/swc_ecma_preset_env/Cargo.toml b/deps/swc/crates/swc_ecma_preset_env/Cargo.toml index 4afaf7677..077c8901f 100644 --- a/deps/swc/crates/swc_ecma_preset_env/Cargo.toml +++ b/deps/swc/crates/swc_ecma_preset_env/Cargo.toml @@ -13,7 +13,7 @@ include = [ license = { workspace = true } name = "swc_ecma_preset_env" repository = { workspace = true } -version = "57.0.0" +version = "61.0.0" [lib] bench = false @@ -36,16 +36,16 @@ precomputed-map = { workspace = true } rustc-hash = { workspace = true } string_enum = { version = "1.0.2", path = "../string_enum" } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transformer = { version = "16.0.3", path = "../swc_ecma_transformer" } -swc_ecma_transforms = { version = "56.0.0", path = "../swc_ecma_transforms", features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transformer = { version = "19.0.0", path = "../swc_ecma_transformer" } +swc_ecma_transforms = { version = "60.0.0", path = "../swc_ecma_transforms", features = [ "compat", "proposal", ] } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [build-dependencies] anyhow = { workspace = true } @@ -59,9 +59,9 @@ serde_json = { workspace = true } codspeed-criterion-compat = { workspace = true } pretty_assertions = { workspace = true } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -testing = { version = "24.0.1", path = "../testing" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +testing = { version = "25.0.0", path = "../testing" } [[bench]] harness = false diff --git a/deps/swc/crates/swc_ecma_quote/Cargo.toml b/deps/swc/crates/swc_ecma_quote/Cargo.toml index 84787da48..b5d37fadb 100644 --- a/deps/swc/crates/swc_ecma_quote/Cargo.toml +++ b/deps/swc/crates/swc_ecma_quote/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_quote" repository = { workspace = true } -version = "41.0.0" +version = "43.0.0" [lib] bench = false @@ -15,8 +15,8 @@ bench = false unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [dependencies] -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_quote_macros = { version = "41.0.0", path = "../swc_ecma_quote_macros" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_quote_macros = { version = "43.0.0", path = "../swc_ecma_quote_macros" } [dev-dependencies] diff --git a/deps/swc/crates/swc_ecma_quote_macros/Cargo.toml b/deps/swc/crates/swc_ecma_quote_macros/Cargo.toml index ee4f1ca1d..622f79fea 100644 --- a/deps/swc/crates/swc_ecma_quote_macros/Cargo.toml +++ b/deps/swc/crates/swc_ecma_quote_macros/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_quote_macros" repository = { workspace = true } -version = "41.0.0" +version = "43.0.0" [lib] bench = false @@ -22,10 +22,10 @@ quote = { workspace = true } rustc-hash = { workspace = true } syn = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } swc_macros_common = { version = "1.0.1", path = "../swc_macros_common" } diff --git a/deps/swc/crates/swc_ecma_react_compiler/Cargo.toml b/deps/swc/crates/swc_ecma_react_compiler/Cargo.toml index 88ac30640..c187e133a 100644 --- a/deps/swc/crates/swc_ecma_react_compiler/Cargo.toml +++ b/deps/swc/crates/swc_ecma_react_compiler/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_react_compiler" repository = { workspace = true } -version = "20.0.2" +version = "22.0.0" [package.metadata.docs.rs] @@ -20,18 +20,18 @@ react_compiler_hir = { version = "=0.2.0", package = "forked_react_compiler_hir" rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_ecma_react_compiler/src/convert_scope.rs b/deps/swc/crates/swc_ecma_react_compiler/src/convert_scope.rs index 45752ffca..368952c3f 100644 --- a/deps/swc/crates/swc_ecma_react_compiler/src/convert_scope.rs +++ b/deps/swc/crates/swc_ecma_react_compiler/src/convert_scope.rs @@ -48,6 +48,7 @@ impl ScopeFlags { pub const ClassStaticBlock: Self = Self { bits: 1 << 2 }; pub const For: Self = Self { bits: 1 << 3 }; pub const Function: Self = Self { bits: 1 << 4 }; + pub const Parameter: Self = Self { bits: 1 << 9 }; pub const StrictMode: Self = Self { bits: 1 << 5 }; pub const Switch: Self = Self { bits: 1 << 6 }; pub const Top: Self = Self { bits: 1 << 7 }; @@ -100,6 +101,11 @@ impl ScopeFlags { pub fn is_catch_clause(self) -> bool { self.contains(Self::CatchClause) } + + #[inline] + pub fn is_parameter(self) -> bool { + self.contains(Self::Parameter) + } } impl std::ops::BitOr for ScopeFlags { @@ -140,6 +146,12 @@ impl SymbolFlags { pub const FunctionScopedVariable: Self = Self { bits: 1 << 7 }; pub const Import: Self = Self { bits: 1 << 8 }; pub const Param: Self = Self { bits: 1 << 9 }; + pub const Value: Self = Self { + bits: Self::Variable.bits | Self::Class.bits | Self::Function.bits | Self::Enum.bits, + }; + pub const Variable: Self = Self { + bits: Self::FunctionScopedVariable.bits | Self::BlockScopedVariable.bits, + }; #[inline] pub const fn contains(self, other: Self) -> bool { @@ -153,16 +165,7 @@ impl SymbolFlags { #[inline] pub fn is_value(self) -> bool { - self.intersects( - Self::FunctionScopedVariable - | Self::BlockScopedVariable - | Self::Function - | Self::FunctionExpression - | Self::Class - | Self::Enum - | Self::Import - | Self::Param, - ) + self.intersects(Self::Value | Self::Import) } #[inline] @@ -188,6 +191,7 @@ pub struct Symbol { pub name: String, pub span: swc_common::Span, pub flags: SymbolFlags, + pub scope_id: ScopeId, } /// A reference to a symbol. @@ -249,6 +253,10 @@ impl Scoping { self.symbols[symbol_id.0 as usize].span } + pub fn symbol_scope_id(&self, symbol_id: SymbolId) -> ScopeId { + self.symbols[symbol_id.0 as usize].scope_id + } + pub fn scope_flags(&self, scope_id: ScopeId) -> ScopeFlags { self.scopes[scope_id.0 as usize].flags } @@ -265,10 +273,26 @@ impl Scoping { self.scopes[scope_id.0 as usize].bindings.values().copied() } + pub fn iter_binding_entries_in( + &self, + scope_id: ScopeId, + ) -> impl Iterator + '_ { + self.scopes[scope_id.0 as usize] + .bindings + .iter() + .map(|(name, &symbol_id)| (name.as_str(), symbol_id)) + } + pub fn get_binding(&self, scope_id: ScopeId, name: &str) -> Option { self.scopes[scope_id.0 as usize].bindings.get(name).copied() } + pub fn bind_symbol_on_scope(&mut self, scope_id: ScopeId, name: String, symbol_id: SymbolId) { + if let Some(scope) = self.scopes.get_mut(scope_id.0 as usize) { + scope.bindings.insert(name, symbol_id); + } + } + pub fn root_scope_id(&self) -> ScopeId { ScopeId(0) } @@ -298,6 +322,7 @@ impl Scoping { name: name.clone(), span, flags, + scope_id, }); if let Some(scope) = self.scopes.get_mut(scope_id.0 as usize) { scope.bindings.insert(name, id); @@ -348,7 +373,7 @@ pub struct SemanticBuilder { declaration_starts: std::collections::HashSet, /// Re-declaration sites that should resolve to an existing binding. redeclaration_bindings: HashMap, - /// Flat list of unresolved references: (name, reference_id). + /// Flat list of unresolved references: (name, `reference_id`). unresolved_references: Vec<(String, ReferenceId)>, /// Track function body spans so they don't create extra block scopes. function_body_spans: std::collections::HashSet, @@ -464,8 +489,14 @@ impl SemanticBuilder { ) -> SymbolId { if flags.contains(SymbolFlags::FunctionScopedVariable) { if let Some(symbol_id) = self.scoping.get_binding(scope_id, &name) { - self.record_redeclaration_binding(span, symbol_id); - return symbol_id; + if !self + .scoping + .symbol_flags(symbol_id) + .contains(SymbolFlags::FunctionExpression) + { + self.record_redeclaration_binding(span, symbol_id); + return symbol_id; + } } } @@ -474,6 +505,35 @@ impl SemanticBuilder { symbol_id } + fn declare_symbol_on_scope_with_alias( + &mut self, + span: swc_common::Span, + name: String, + flags: SymbolFlags, + scope_id: ScopeId, + alias_scope_id: Option, + ) -> SymbolId { + let symbol_id = self.declare_symbol_on_scope(span, name.clone(), flags, scope_id); + if let Some(alias_scope_id) = alias_scope_id { + self.scoping + .bind_symbol_on_scope(alias_scope_id, name, symbol_id); + } + symbol_id + } + + fn alias_bindings_to_scope(&mut self, from_scope_id: ScopeId, to_scope_id: ScopeId) { + let bindings: Vec<(String, SymbolId)> = self + .scoping + .iter_binding_entries_in(from_scope_id) + .map(|(name, symbol_id)| (name.to_string(), symbol_id)) + .collect(); + + for (name, symbol_id) in bindings { + self.scoping + .bind_symbol_on_scope(to_scope_id, name, symbol_id); + } + } + fn record_redeclaration_binding(&mut self, span: swc_common::Span, symbol_id: SymbolId) { let start = self.start(span); self.declaration_starts.insert(start); @@ -509,11 +569,39 @@ impl SemanticBuilder { return true; } } - scope_id = self.scoping.scope_parent_id(sid); + scope_id = self.resolution_parent_id(sid); } false } + fn resolution_parent_id(&self, scope_id: ScopeId) -> Option { + let parent_id = self.scoping.scope_parent_id(scope_id)?; + if self.scoping.scope_flags(scope_id).is_parameter() { + // Parameter initializers run before the function body environment is + // visible. Check parameter aliases first, then continue at the + // outer scope instead of the function scope that will hold body + // bindings in the React Compiler-compatible output model. + return self.scoping.scope_parent_id(parent_id); + } + + Some(parent_id) + } + + /// Resolve references emitted while visiting function or catch parameters + /// before body bindings are added to the same scope. + fn resolve_references_from_checkpoint(&mut self, checkpoint: usize) { + if checkpoint >= self.unresolved_references.len() { + return; + } + + let references = self.unresolved_references.split_off(checkpoint); + for (name, reference_id) in references { + if !self.walk_up_resolve_reference(&name, reference_id) { + self.unresolved_references.push((name, reference_id)); + } + } + } + fn try_resolve_reference(&mut self, reference_id: ReferenceId, symbol_id: SymbolId) -> bool { let symbol_flags = self.scoping.symbol_flags(symbol_id); @@ -539,7 +627,36 @@ impl SemanticBuilder { .unwrap_or(ScopeId(0)) } + #[inline] + fn param_flags() -> SymbolFlags { + SymbolFlags::FunctionScopedVariable | SymbolFlags::Param + } + fn collect_pat_bindings(&mut self, pat: &Pat, flags: SymbolFlags) { + self.collect_pat_bindings_in_scope(pat, flags, self.current_scope(), None); + } + + fn collect_parameter_pat_bindings( + &mut self, + pat: &Pat, + function_scope_id: ScopeId, + parameter_scope_id: ScopeId, + ) { + self.collect_pat_bindings_in_scope( + pat, + Self::param_flags(), + function_scope_id, + Some(parameter_scope_id), + ); + } + + fn collect_pat_bindings_in_scope( + &mut self, + pat: &Pat, + flags: SymbolFlags, + scope_id: ScopeId, + alias_scope_id: Option, + ) { match pat { Pat::Ident(binding_ident) => { // TypeScript `this` pseudo-parameters are type annotations only. @@ -547,15 +664,17 @@ impl SemanticBuilder { if binding_ident.id.sym.as_str() == "this" { return; } - self.declare_symbol( + self.declare_symbol_on_scope_with_alias( binding_ident.id.span, binding_ident.id.sym.to_string(), flags, + scope_id, + alias_scope_id, ); } Pat::Array(arr) => { for p in arr.elems.iter().flatten() { - self.collect_pat_bindings(p, flags); + self.collect_pat_bindings_in_scope(p, flags, scope_id, alias_scope_id); } } Pat::Object(obj) => { @@ -565,35 +684,207 @@ impl SemanticBuilder { if let PropName::Computed(computed) = &kv.key { computed.visit_with(self); } - self.collect_pat_bindings(&kv.value, flags); + self.collect_pat_bindings_in_scope( + &kv.value, + flags, + scope_id, + alias_scope_id, + ); } ObjectPatProp::Assign(assign) => { - self.declare_symbol( + self.declare_symbol_on_scope_with_alias( assign.key.id.span, assign.key.id.sym.to_string(), flags, + scope_id, + alias_scope_id, ); if let Some(value) = &assign.value { value.visit_with(self); } } ObjectPatProp::Rest(rest) => { - self.collect_pat_bindings(&rest.arg, flags); + self.collect_pat_bindings_in_scope( + &rest.arg, + flags, + scope_id, + alias_scope_id, + ); } } } } Pat::Rest(rest) => { - self.collect_pat_bindings(&rest.arg, flags); + self.collect_pat_bindings_in_scope(&rest.arg, flags, scope_id, alias_scope_id); } Pat::Assign(assign) => { - self.collect_pat_bindings(&assign.left, flags); + self.collect_pat_bindings_in_scope(&assign.left, flags, scope_id, alias_scope_id); assign.right.visit_with(self); } Pat::Expr(_) | Pat::Invalid(_) => {} } } + fn visit_function_params( + &mut self, + function_scope_id: ScopeId, + scope_span: swc_common::Span, + params: &[Param], + ) { + if params + .iter() + .any(|param| Self::pat_needs_parameter_scope(¶m.pat)) + { + self.with_parameter_scope(function_scope_id, scope_span, |this, parameter_scope_id| { + for param in params { + this.collect_parameter_pat_bindings( + ¶m.pat, + function_scope_id, + parameter_scope_id, + ); + } + }); + } else { + for param in params { + self.collect_pat_bindings_in_scope( + ¶m.pat, + Self::param_flags(), + function_scope_id, + None, + ); + } + } + } + + fn visit_arrow_params( + &mut self, + function_scope_id: ScopeId, + scope_span: swc_common::Span, + params: &[Pat], + ) { + if params.iter().any(Self::pat_needs_parameter_scope) { + self.with_parameter_scope(function_scope_id, scope_span, |this, parameter_scope_id| { + for param in params { + this.collect_parameter_pat_bindings( + param, + function_scope_id, + parameter_scope_id, + ); + } + }); + } else { + for param in params { + self.collect_pat_bindings_in_scope( + param, + Self::param_flags(), + function_scope_id, + None, + ); + } + } + } + + fn visit_constructor_params( + &mut self, + function_scope_id: ScopeId, + scope_span: swc_common::Span, + params: &[ParamOrTsParamProp], + ) { + if params + .iter() + .any(Self::constructor_param_needs_parameter_scope) + { + self.with_parameter_scope(function_scope_id, scope_span, |this, parameter_scope_id| { + for param in params { + this.collect_constructor_param_bindings( + param, + function_scope_id, + Some(parameter_scope_id), + ); + } + }); + } else { + for param in params { + self.collect_constructor_param_bindings(param, function_scope_id, None); + } + } + } + + fn visit_accessor_param( + &mut self, + function_scope_id: ScopeId, + scope_span: swc_common::Span, + param: &Pat, + ) { + if Self::pat_needs_parameter_scope(param) { + self.with_parameter_scope(function_scope_id, scope_span, |this, parameter_scope_id| { + this.collect_parameter_pat_bindings(param, function_scope_id, parameter_scope_id); + }); + } else { + self.collect_pat_bindings_in_scope(param, Self::param_flags(), function_scope_id, None); + } + } + + fn with_parameter_scope( + &mut self, + function_scope_id: ScopeId, + scope_span: swc_common::Span, + visit_params: F, + ) where + F: FnOnce(&mut Self, ScopeId), + { + let checkpoint = self.unresolved_references.len(); + let parameter_scope_id = self.push_scope(ScopeFlags::Parameter, scope_span); + // Named function expression bindings are visible in parameter defaults, + // but body bindings are not. Parameters are declared in the function + // scope for output compatibility and aliased here for resolution. + self.alias_bindings_to_scope(function_scope_id, parameter_scope_id); + visit_params(self, parameter_scope_id); + self.pop_scope(); + self.resolve_references_from_checkpoint(checkpoint); + } + + fn pat_needs_parameter_scope(pat: &Pat) -> bool { + match pat { + Pat::Ident(_) | Pat::Invalid(_) => false, + Pat::Array(arr) => arr + .elems + .iter() + .flatten() + .any(Self::pat_needs_parameter_scope), + Pat::Object(obj) => obj.props.iter().any(|prop| match prop { + ObjectPatProp::KeyValue(kv) => { + matches!(kv.key, PropName::Computed(_)) + || Self::pat_needs_parameter_scope(&kv.value) + } + ObjectPatProp::Assign(assign) => assign.value.is_some(), + ObjectPatProp::Rest(rest) => Self::pat_needs_parameter_scope(&rest.arg), + }), + Pat::Rest(rest) => Self::pat_needs_parameter_scope(&rest.arg), + Pat::Assign(_) | Pat::Expr(_) => true, + } + } + + fn constructor_param_needs_parameter_scope(param: &ParamOrTsParamProp) -> bool { + match param { + ParamOrTsParamProp::Param(param) => Self::pat_needs_parameter_scope(¶m.pat), + ParamOrTsParamProp::TsParamProp(param_prop) => { + matches!(param_prop.param, TsParamPropParam::Assign(_)) + } + } + } + + /// A simple catch parameter is function-scoped for `var` redeclaration + /// compatibility, while destructuring is block-scoped. + fn collect_catch_pat_bindings(&mut self, pat: &Pat) { + let flags = if matches!(pat, Pat::Ident(_)) { + SymbolFlags::FunctionScopedVariable | SymbolFlags::CatchVariable + } else { + SymbolFlags::BlockScopedVariable | SymbolFlags::CatchVariable + }; + self.collect_pat_bindings(pat, flags); + } + fn visit_function_inner(&mut self, function: &Function, flags: ScopeFlags) { self.visit_function_inner_with_span(function.span, function, flags); } @@ -604,14 +895,12 @@ impl SemanticBuilder { function: &Function, flags: ScopeFlags, ) { - let _scope_id = self.push_scope( + let scope_id = self.push_scope( self.body_scope_flags(flags, function.body.as_ref()), scope_span, ); - for param in &function.params { - self.collect_pat_bindings(¶m.pat, SymbolFlags::Param); - } + self.visit_function_params(scope_id, scope_span, &function.params); if let Some(body) = &function.body { self.function_body_spans.insert(self.start(body.span)); @@ -622,14 +911,12 @@ impl SemanticBuilder { } fn visit_constructor_inner(&mut self, constructor: &Constructor) { - let _scope_id = self.push_scope( + let scope_id = self.push_scope( self.body_scope_flags(ScopeFlags::Function, constructor.body.as_ref()), constructor.span, ); - for param in &constructor.params { - self.collect_constructor_param_bindings(param); - } + self.visit_constructor_params(scope_id, constructor.span, &constructor.params); if let Some(body) = &constructor.body { self.function_body_spans.insert(self.start(body.span)); @@ -639,21 +926,38 @@ impl SemanticBuilder { self.pop_scope(); } - fn collect_constructor_param_bindings(&mut self, param: &ParamOrTsParamProp) { + fn collect_constructor_param_bindings( + &mut self, + param: &ParamOrTsParamProp, + function_scope_id: ScopeId, + alias_scope_id: Option, + ) { match param { ParamOrTsParamProp::Param(param) => { - self.collect_pat_bindings(¶m.pat, SymbolFlags::Param); + self.collect_pat_bindings_in_scope( + ¶m.pat, + Self::param_flags(), + function_scope_id, + alias_scope_id, + ); } ParamOrTsParamProp::TsParamProp(param_prop) => match ¶m_prop.param { TsParamPropParam::Ident(binding_ident) => { - self.declare_symbol( + self.declare_symbol_on_scope_with_alias( binding_ident.id.span, binding_ident.id.sym.to_string(), - SymbolFlags::Param, + Self::param_flags(), + function_scope_id, + alias_scope_id, ); } TsParamPropParam::Assign(assign) => { - self.collect_pat_bindings(&assign.left, SymbolFlags::Param); + self.collect_pat_bindings_in_scope( + &assign.left, + Self::param_flags(), + function_scope_id, + alias_scope_id, + ); assign.right.visit_with(self); } }, @@ -666,10 +970,10 @@ impl SemanticBuilder { param: Option<&Pat>, body: Option<&BlockStmt>, ) { - let _scope_id = self.push_scope(self.body_scope_flags(ScopeFlags::Function, body), span); + let scope_id = self.push_scope(self.body_scope_flags(ScopeFlags::Function, body), span); if let Some(param) = param { - self.collect_pat_bindings(param, SymbolFlags::Param); + self.visit_accessor_param(scope_id, span, param); } if let Some(body) = body { @@ -780,19 +1084,17 @@ impl Visit for SemanticBuilder { fn visit_fn_expr(&mut self, fn_expr: &FnExpr) { let flags = self.body_scope_flags(ScopeFlags::Function, fn_expr.function.body.as_ref()); - self.push_scope(flags, fn_expr.function.span); + let scope_id = self.push_scope(flags, fn_expr.function.span); if let Some(ident) = &fn_expr.ident { self.declare_symbol( ident.span, ident.sym.to_string(), - SymbolFlags::FunctionExpression, + SymbolFlags::Function | SymbolFlags::FunctionExpression, ); } - for param in &fn_expr.function.params { - self.collect_pat_bindings(¶m.pat, SymbolFlags::Param); - } + self.visit_function_params(scope_id, fn_expr.function.span, &fn_expr.function.params); if let Some(body) = &fn_expr.function.body { self.function_body_spans.insert(self.start(body.span)); @@ -809,11 +1111,9 @@ impl Visit for SemanticBuilder { } BlockStmtOrExpr::Expr(_) => ScopeFlags::Function, }; - self.push_scope(flags, arrow.span); + let scope_id = self.push_scope(flags, arrow.span); - for param in &arrow.params { - self.collect_pat_bindings(param, SymbolFlags::Param); - } + self.visit_arrow_params(scope_id, arrow.span, &arrow.params); match &*arrow.body { BlockStmtOrExpr::BlockStmt(block) => { @@ -873,10 +1173,11 @@ impl Visit for SemanticBuilder { self.push_scope(ScopeFlags::CatchClause, catch.span); if let Some(param) = &catch.param { - self.collect_pat_bindings(param, SymbolFlags::CatchVariable); + let checkpoint = self.unresolved_references.len(); + self.collect_catch_pat_bindings(param); + self.resolve_references_from_checkpoint(checkpoint); } - self.function_body_spans.insert(self.start(catch.body.span)); catch.body.visit_with(self); self.pop_scope(); @@ -1105,55 +1406,7 @@ impl Visit for SemanticBuilder { impl SemanticBuilder { fn collect_pat_bindings_with_scope(&mut self, pat: &Pat, flags: SymbolFlags, scope: ScopeId) { - match pat { - Pat::Ident(binding_ident) => { - let _symbol_id = self.declare_symbol_on_scope( - binding_ident.id.span, - binding_ident.id.sym.to_string(), - flags, - scope, - ); - } - Pat::Array(arr) => { - for p in arr.elems.iter().flatten() { - self.collect_pat_bindings_with_scope(p, flags, scope); - } - } - Pat::Object(obj) => { - for prop in &obj.props { - match prop { - ObjectPatProp::KeyValue(kv) => { - if let PropName::Computed(computed) = &kv.key { - computed.visit_with(self); - } - self.collect_pat_bindings_with_scope(&kv.value, flags, scope); - } - ObjectPatProp::Assign(assign) => { - let _symbol_id = self.declare_symbol_on_scope( - assign.key.id.span, - assign.key.id.sym.to_string(), - flags, - scope, - ); - if let Some(value) = &assign.value { - value.visit_with(self); - } - } - ObjectPatProp::Rest(rest) => { - self.collect_pat_bindings_with_scope(&rest.arg, flags, scope); - } - } - } - } - Pat::Rest(rest) => { - self.collect_pat_bindings_with_scope(&rest.arg, flags, scope); - } - Pat::Assign(assign) => { - self.collect_pat_bindings_with_scope(&assign.left, flags, scope); - assign.right.visit_with(self); - } - Pat::Expr(_) | Pat::Invalid(_) => {} - } + self.collect_pat_bindings_in_scope(pat, flags, scope, None); } /// Consume the builder and produce a React Compiler [`ScopeInfo`]. @@ -1205,12 +1458,39 @@ impl SemanticBuilder { }); } + // Parameter scopes are internal resolution environments. They must not + // overwrite BindingData.scope or appear as scope-creating AST nodes in + // the React Compiler ScopeInfo. + let mut scope_to_out_scope: HashMap = HashMap::new(); + for scope_id in self.scoping.scope_descendants_from_root() { + if self.scoping.scope_flags(scope_id).is_parameter() { + continue; + } + let out_scope_id = OutScopeId(scope_to_out_scope.len() as u32); + scope_to_out_scope.insert(scope_id, out_scope_id); + } + + for symbol_id in self.scoping.symbol_ids() { + if let Some(&binding_id) = symbol_to_binding.get(&symbol_id) { + let symbol_scope_id = self.scoping.symbol_scope_id(symbol_id); + let out_scope_id = output_scope_for_internal_scope( + &self.scoping, + &scope_to_out_scope, + symbol_scope_id, + ); + bindings[binding_id.0 as usize].scope = out_scope_id; + } + } + // Second pass: Create all scopes and update binding scope references for scope_id in self.scoping.scope_descendants_from_root() { let scope_flags = self.scoping.scope_flags(scope_id); - let parent = self.scoping.scope_parent_id(scope_id); + if scope_flags.is_parameter() { + continue; + } - let out_scope_id = OutScopeId(scope_id.0); + let out_scope_id = scope_to_out_scope[&scope_id]; + let parent = output_parent_scope(&self.scoping, &scope_to_out_scope, scope_id); let kind = get_scope_kind(scope_flags); @@ -1219,7 +1499,6 @@ impl SemanticBuilder { if let Some(&binding_id) = symbol_to_binding.get(&symbol_id) { let name = bindings[binding_id.0 as usize].name.clone(); scope_bindings.insert(name, binding_id); - bindings[binding_id.0 as usize].scope = out_scope_id; } } @@ -1237,7 +1516,7 @@ impl SemanticBuilder { scopes.push(ScopeData { id: out_scope_id, - parent: parent.map(|p| OutScopeId(p.0)), + parent, kind, bindings: scope_bindings, }); @@ -1292,7 +1571,7 @@ impl SemanticBuilder { } } - let program_scope = OutScopeId(self.scoping.root_scope_id().0); + let program_scope = scope_to_out_scope[&self.scoping.root_scope_id()]; ScopeInfo { scopes, @@ -1307,6 +1586,37 @@ impl SemanticBuilder { } } +fn output_parent_scope( + scoping: &Scoping, + scope_to_out_scope: &HashMap, + scope_id: ScopeId, +) -> Option { + let mut parent_id = scoping.scope_parent_id(scope_id); + while let Some(parent) = parent_id { + if let Some(&out_parent) = scope_to_out_scope.get(&parent) { + return Some(out_parent); + } + parent_id = scoping.scope_parent_id(parent); + } + None +} + +fn output_scope_for_internal_scope( + scoping: &Scoping, + scope_to_out_scope: &HashMap, + mut scope_id: ScopeId, +) -> react_compiler_ast::scope::ScopeId { + loop { + if let Some(&out_scope_id) = scope_to_out_scope.get(&scope_id) { + return out_scope_id; + } + + scope_id = scoping + .scope_parent_id(scope_id) + .expect("internal scope should have an output ancestor"); + } +} + /// Build a map from import specifier span start to its import data. fn build_import_map( program: &Program, @@ -1365,7 +1675,7 @@ fn build_import_map( map } -/// Map our ScopeFlags to react_compiler_ast ScopeKind. +/// Map our `ScopeFlags` to `react_compiler_ast` `ScopeKind`. fn get_scope_kind(flags: ScopeFlags) -> react_compiler_ast::scope::ScopeKind { use react_compiler_ast::scope::ScopeKind; @@ -1396,7 +1706,7 @@ fn get_scope_kind(flags: ScopeFlags) -> react_compiler_ast::scope::ScopeKind { ScopeKind::Block } -/// Map our SymbolFlags to react_compiler_ast BindingKind. +/// Map our `SymbolFlags` to `react_compiler_ast` `BindingKind`. fn get_binding_kind(flags: SymbolFlags) -> react_compiler_ast::scope::BindingKind { use react_compiler_ast::scope::BindingKind; @@ -1419,9 +1729,8 @@ fn get_binding_kind(flags: SymbolFlags) -> react_compiler_ast::scope::BindingKin if flags.contains(SymbolFlags::BlockScopedVariable) { if flags.contains(SymbolFlags::ConstVariable) { return BindingKind::Const; - } else { - return BindingKind::Let; } + return BindingKind::Let; } if flags.contains(SymbolFlags::FunctionExpression) { diff --git a/deps/swc/crates/swc_ecma_react_compiler/src/diagnostics.rs b/deps/swc/crates/swc_ecma_react_compiler/src/diagnostics.rs index cb45f8ff0..c768b45a7 100644 --- a/deps/swc/crates/swc_ecma_react_compiler/src/diagnostics.rs +++ b/deps/swc/crates/swc_ecma_react_compiler/src/diagnostics.rs @@ -4,20 +4,73 @@ // LICENSE file in the root directory of this source tree. use react_compiler::entrypoint::compile_result::{ - CompileResult, CompilerErrorDetailInfo, CompilerErrorInfo, LoggerEvent, + CompileResult, CompilerErrorDetailInfo, CompilerErrorInfo, CompilerErrorItemInfo, LoggerEvent, + LoggerPosition, LoggerSourceLocation, }; +use serde::Serialize; #[derive(Debug, Clone)] pub enum Severity { Error, Warning, } +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum DiagnosticSeverity { + Error, + Warning, +} + +impl From<&Severity> for DiagnosticSeverity { + fn from(value: &Severity) -> Self { + match value { + Severity::Error => Self::Error, + Severity::Warning => Self::Warning, + } + } +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticPosition { + pub line: u32, + pub column: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub index: Option, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticLocation { + pub start: DiagnosticPosition, + pub end: DiagnosticPosition, + #[serde(skip_serializing_if = "Option::is_none")] + pub filename: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub identifier_name: Option, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticDetail { + pub kind: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub loc: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, +} #[derive(Debug, Clone)] pub struct DiagnosticMessage { pub severity: Severity, pub message: String, pub span: Option<(u32, u32)>, + pub rule_id: Option, + pub category: Option, + pub reason: Option, + pub description: Option, + pub loc: Option, + pub details: Vec, } /// Convert a [`CompileResult`] into SWC-facing diagnostics. @@ -63,11 +116,18 @@ fn error_info_to_diagnostic(error: &CompilerErrorInfo) -> DiagnosticMessage { severity: Severity::Error, message, span: None, + rule_id: None, + category: None, + reason: Some(error.reason.clone()), + description: error.description.clone(), + loc: None, + details: Vec::new(), } } fn error_detail_to_diagnostic( detail: &CompilerErrorDetailInfo, + fn_loc: Option<&LoggerSourceLocation>, suppress_error_diagnostics: bool, ) -> Option { let message = if let Some(description) = &detail.description { @@ -92,7 +152,20 @@ fn error_detail_to_diagnostic( Some(DiagnosticMessage { severity, message, - span: None, + span: primary_location(detail, fn_loc) + .and_then(|loc| Some((loc.start.index?, loc.end.index?))), + rule_id: rule_id_for_category(&detail.category).map(str::to_string), + category: Some(detail.category.clone()), + reason: Some(detail.reason.clone()), + description: detail.description.clone(), + loc: primary_location(detail, fn_loc).map(Into::into), + details: detail + .details + .as_deref() + .unwrap_or_default() + .iter() + .map(Into::into) + .collect(), }) } @@ -102,9 +175,11 @@ fn event_to_diagnostic( ) -> Option { match event { LoggerEvent::CompileSuccess { .. } | LoggerEvent::CompileSkip { .. } => None, - LoggerEvent::CompileError { detail, .. } - | LoggerEvent::CompileErrorWithLoc { detail, .. } => { - error_detail_to_diagnostic(detail, suppress_error_diagnostics) + LoggerEvent::CompileError { detail, fn_loc } => { + error_detail_to_diagnostic(detail, fn_loc.as_ref(), suppress_error_diagnostics) + } + LoggerEvent::CompileErrorWithLoc { detail, fn_loc } => { + error_detail_to_diagnostic(detail, Some(fn_loc), suppress_error_diagnostics) } LoggerEvent::CompileUnexpectedThrow { .. } | LoggerEvent::PipelineError { .. } if suppress_error_diagnostics => @@ -115,11 +190,404 @@ fn event_to_diagnostic( severity: Severity::Error, message: format!("[ReactCompiler] Unexpected error: {data}"), span: None, + rule_id: None, + category: None, + reason: Some("Unexpected error".into()), + description: Some(data.clone()), + loc: None, + details: Vec::new(), }), LoggerEvent::PipelineError { data, .. } => Some(DiagnosticMessage { severity: Severity::Error, message: format!("[ReactCompiler] Pipeline error: {data}"), span: None, + rule_id: None, + category: None, + reason: Some("Pipeline error".into()), + description: Some(data.clone()), + loc: None, + details: Vec::new(), }), } } + +fn primary_location<'a>( + detail: &'a CompilerErrorDetailInfo, + fn_loc: Option<&'a LoggerSourceLocation>, +) -> Option<&'a LoggerSourceLocation> { + detail + .details + .as_deref() + .and_then(|details| { + details + .iter() + .find(|detail| detail.kind == "error") + .and_then(|detail| detail.loc.as_ref()) + }) + .or(detail.loc.as_ref()) + .or(fn_loc) +} + +fn rule_id_for_category(category: &str) -> Option<&'static str> { + Some(match category { + "CapitalizedCalls" => "capitalized-calls", + "Config" => "config", + "EffectDependencies" => "memoized-effect-dependencies", + "EffectExhaustiveDependencies" => "exhaustive-effect-dependencies", + "EffectDerivationsOfState" => "no-deriving-state-in-effects", + "EffectSetState" => "set-state-in-effect", + "ErrorBoundaries" => "error-boundaries", + "FBT" => "fbt", + "Gating" => "gating", + "Globals" => "globals", + "Hooks" => "hooks", + "Immutability" => "immutability", + "Invariant" => "invariant", + "PreserveManualMemo" => "preserve-manual-memoization", + "Purity" => "purity", + "Refs" => "refs", + "RenderSetState" => "set-state-in-render", + "StaticComponents" => "static-components", + "Suppression" => "rule-suppression", + "Syntax" => "syntax", + "Todo" => "todo", + "UnsupportedSyntax" => "unsupported-syntax", + "UseMemo" => "use-memo", + "VoidUseMemo" => "void-use-memo", + "MemoDependencies" => "memo-dependencies", + "IncompatibleLibrary" => "incompatible-library", + _ => return None, + }) +} + +impl From<&LoggerPosition> for DiagnosticPosition { + fn from(value: &LoggerPosition) -> Self { + Self { + line: value.line, + column: value.column, + index: value.index, + } + } +} + +impl From<&LoggerSourceLocation> for DiagnosticLocation { + fn from(value: &LoggerSourceLocation) -> Self { + Self { + start: (&value.start).into(), + end: (&value.end).into(), + filename: value.filename.clone(), + identifier_name: value.identifier_name.clone(), + } + } +} + +impl From<&CompilerErrorItemInfo> for DiagnosticDetail { + fn from(value: &CompilerErrorItemInfo) -> Self { + Self { + kind: value.kind.clone(), + loc: value.loc.as_ref().map(Into::into), + message: value.message.clone(), + } + } +} + +#[cfg(test)] +mod tests { + use react_compiler::entrypoint::compile_result::{ + CompileResult, CompilerErrorDetailInfo, LoggerEvent, LoggerPosition, LoggerSourceLocation, + }; + + use super::{compile_result_to_diagnostics, Severity}; + + fn loc() -> LoggerSourceLocation { + LoggerSourceLocation { + start: LoggerPosition { + line: 3, + column: 10, + index: Some(42), + }, + end: LoggerPosition { + line: 3, + column: 21, + index: Some(53), + }, + filename: Some("input.tsx".into()), + identifier_name: Some("value".into()), + } + } + + fn detail(category: &str, severity: &str) -> CompilerErrorDetailInfo { + CompilerErrorDetailInfo { + category: category.into(), + reason: format!("{category} reason"), + description: Some(format!("{category} description")), + severity: severity.into(), + suggestions: None, + details: None, + loc: Some(loc()), + } + } + + fn diagnostic_for(category: &str, severity: &str) -> super::DiagnosticMessage { + let result = CompileResult::Success { + ast: None, + events: vec![LoggerEvent::CompileErrorWithLoc { + fn_loc: loc(), + detail: detail(category, severity), + }], + ordered_log: Vec::new(), + renames: Vec::new(), + timing: Vec::new(), + }; + + compile_result_to_diagnostics(&result, true) + .into_iter() + .next() + .unwrap() + } + + #[test] + fn maps_documented_react_compiler_rule_ids() { + let cases = [ + ("Config", "config"), + ("ErrorBoundaries", "error-boundaries"), + ("Gating", "gating"), + ("Globals", "globals"), + ("Immutability", "immutability"), + ("IncompatibleLibrary", "incompatible-library"), + ("PreserveManualMemo", "preserve-manual-memoization"), + ("Purity", "purity"), + ("Refs", "refs"), + ("EffectSetState", "set-state-in-effect"), + ("RenderSetState", "set-state-in-render"), + ("StaticComponents", "static-components"), + ("UnsupportedSyntax", "unsupported-syntax"), + ("UseMemo", "use-memo"), + ]; + + for (category, rule_id) in cases { + let diagnostic = diagnostic_for(category, "Error"); + assert_eq!(diagnostic.category.as_deref(), Some(category)); + assert_eq!(diagnostic.rule_id.as_deref(), Some(rule_id)); + } + } + + fn assert_category_maps_to_rule_id(category: &str, rule_id: &str) { + let diagnostic = diagnostic_for(category, "Error"); + assert_eq!(diagnostic.category.as_deref(), Some(category)); + assert_eq!(diagnostic.rule_id.as_deref(), Some(rule_id)); + } + + #[test] + fn react_docs_rule_id_config() { + assert_category_maps_to_rule_id("Config", "config"); + } + + #[test] + fn react_docs_rule_id_error_boundaries() { + assert_category_maps_to_rule_id("ErrorBoundaries", "error-boundaries"); + } + + #[test] + fn react_docs_rule_id_gating() { + assert_category_maps_to_rule_id("Gating", "gating"); + } + + #[test] + fn react_docs_rule_id_globals() { + assert_category_maps_to_rule_id("Globals", "globals"); + } + + #[test] + fn react_docs_rule_id_immutability() { + assert_category_maps_to_rule_id("Immutability", "immutability"); + } + + #[test] + fn react_docs_rule_id_incompatible_library() { + assert_category_maps_to_rule_id("IncompatibleLibrary", "incompatible-library"); + } + + #[test] + fn react_docs_rule_id_preserve_manual_memoization() { + assert_category_maps_to_rule_id("PreserveManualMemo", "preserve-manual-memoization"); + } + + #[test] + fn react_docs_rule_id_purity() { + assert_category_maps_to_rule_id("Purity", "purity"); + } + + #[test] + fn react_docs_rule_id_refs() { + assert_category_maps_to_rule_id("Refs", "refs"); + } + + #[test] + fn react_docs_rule_id_set_state_in_effect() { + assert_category_maps_to_rule_id("EffectSetState", "set-state-in-effect"); + } + + #[test] + fn react_docs_rule_id_set_state_in_render() { + assert_category_maps_to_rule_id("RenderSetState", "set-state-in-render"); + } + + #[test] + fn react_docs_rule_id_static_components() { + assert_category_maps_to_rule_id("StaticComponents", "static-components"); + } + + #[test] + fn react_docs_rule_id_unsupported_syntax() { + assert_category_maps_to_rule_id("UnsupportedSyntax", "unsupported-syntax"); + } + + #[test] + fn react_docs_rule_id_use_memo() { + assert_category_maps_to_rule_id("UseMemo", "use-memo"); + } + + #[test] + fn react_docs_rule_id_exhaustive_deps_is_not_react_compiler_backed() { + assert!(![ + "Config", + "ErrorBoundaries", + "Gating", + "Globals", + "Immutability", + "IncompatibleLibrary", + "PreserveManualMemo", + "Purity", + "Refs", + "EffectSetState", + "RenderSetState", + "StaticComponents", + "UnsupportedSyntax", + "UseMemo", + ] + .into_iter() + .any(|category| { + diagnostic_for(category, "Error").rule_id.as_deref() == Some("exhaustive-deps") + })); + } + + #[test] + fn react_docs_rule_id_rules_of_hooks_is_not_the_compiler_hooks_id() { + let diagnostic = diagnostic_for("Hooks", "Error"); + assert_eq!(diagnostic.rule_id.as_deref(), Some("hooks")); + assert_ne!(diagnostic.rule_id.as_deref(), Some("rules-of-hooks")); + } + + #[test] + fn react_docs_rule_id_component_hook_factories_is_deprecated_not_compiler_backed() { + assert!(![ + "Config", + "ErrorBoundaries", + "Gating", + "Globals", + "Immutability", + "IncompatibleLibrary", + "PreserveManualMemo", + "Purity", + "Refs", + "EffectSetState", + "RenderSetState", + "StaticComponents", + "UnsupportedSyntax", + "UseMemo", + ] + .into_iter() + .any(|category| { + diagnostic_for(category, "Error").rule_id.as_deref() == Some("component-hook-factories") + })); + } + + #[test] + fn preserves_structured_diagnostic_location() { + let diagnostic = diagnostic_for("Refs", "Error"); + let loc = diagnostic.loc.expect("expected loc"); + + assert_eq!(loc.start.line, 3); + assert_eq!(loc.start.column, 10); + assert_eq!(loc.start.index, Some(42)); + assert_eq!(loc.end.line, 3); + assert_eq!(loc.end.column, 21); + assert_eq!(loc.end.index, Some(53)); + assert_eq!(loc.filename.as_deref(), Some("input.tsx")); + assert_eq!(loc.identifier_name.as_deref(), Some("value")); + } + + #[test] + fn maps_warning_severity_without_suppressing_lint_output() { + let diagnostic = diagnostic_for("UnsupportedSyntax", "Warning"); + + assert!(matches!(diagnostic.severity, Severity::Warning)); + assert_eq!(diagnostic.rule_id.as_deref(), Some("unsupported-syntax")); + } + + #[test] + fn maps_compiler_hooks_category_to_hooks_not_rules_of_hooks() { + let diagnostic = diagnostic_for("Hooks", "Error"); + + assert_eq!(diagnostic.category.as_deref(), Some("Hooks")); + assert_eq!(diagnostic.rule_id.as_deref(), Some("hooks")); + } + + #[test] + fn documents_all_react_docs_recommended_rule_ids() { + let compiler_backed = [ + "config", + "error-boundaries", + "gating", + "globals", + "immutability", + "incompatible-library", + "preserve-manual-memoization", + "purity", + "refs", + "set-state-in-effect", + "set-state-in-render", + "static-components", + "unsupported-syntax", + "use-memo", + ]; + let non_compiler_backed_in_this_path = [ + // Standalone eslint-plugin-react-hooks rules. + "exhaustive-deps", + "rules-of-hooks", + // Deprecated wrapper rule in the local React plugin index, not a + // React Compiler diagnostic category. + "component-hook-factories", + ]; + + let mut documented_recommended = compiler_backed + .into_iter() + .chain(non_compiler_backed_in_this_path) + .collect::>(); + documented_recommended.sort_unstable(); + + assert_eq!( + documented_recommended, + vec![ + "component-hook-factories", + "config", + "error-boundaries", + "exhaustive-deps", + "gating", + "globals", + "immutability", + "incompatible-library", + "preserve-manual-memoization", + "purity", + "refs", + "rules-of-hooks", + "set-state-in-effect", + "set-state-in-render", + "static-components", + "unsupported-syntax", + "use-memo", + ] + ); + } +} diff --git a/deps/swc/crates/swc_ecma_react_compiler/src/lib.rs b/deps/swc/crates/swc_ecma_react_compiler/src/lib.rs index b804bb4db..d1cfaf6e4 100644 --- a/deps/swc/crates/swc_ecma_react_compiler/src/lib.rs +++ b/deps/swc/crates/swc_ecma_react_compiler/src/lib.rs @@ -20,7 +20,7 @@ use apply_renames::{apply_renames, build_rename_plan}; use convert_ast::convert_program; use convert_ast_reverse::convert_program_to_swc; use diagnostics::{compile_result_to_diagnostics, DiagnosticMessage}; -use prefilter::{has_react_like_functions, has_resource_management_declarations}; +use prefilter::has_resource_management_declarations; use react_compiler::entrypoint::compile_result::LoggerEvent; // Re-exported so integrations needn't depend on the upstream `react_compiler` crate. pub use react_compiler::entrypoint::plugin_options::{ @@ -28,7 +28,7 @@ pub use react_compiler::entrypoint::plugin_options::{ }; use react_compiler_hir::environment_config::EnvironmentConfig; pub use source_type::SourceType; -use swc_common::comments::SingleThreadedComments; +use swc_common::{comments::SingleThreadedComments, sync::Lrc, FileName}; use swc_ecma_ast::Program; use crate::{convert_ast::ConvertResult, convert_scope::SemanticBuilder}; @@ -84,16 +84,6 @@ pub fn transform( comments: Option<&SingleThreadedComments>, options: PluginOptions, ) -> TransformResult { - if !matches!(options.compilation_mode.as_str(), "all" | "annotation") - && !has_react_like_functions(program) - { - return TransformResult { - program: None, - diagnostics: vec![], - events: vec![], - }; - } - if has_resource_management_declarations(program) { return TransformResult { program: None, @@ -146,13 +136,13 @@ pub(crate) fn transform_source( syntax: swc_ecma_parser::Syntax, options: PluginOptions, ) -> TransformResult { - match parse_source_for_tests(source_text, syntax) { + match parse_source(source_text, syntax) { Ok((program, comments, source_type)) => { transform(&program, source_type, source_text, Some(&comments), options) } Err(diagnostic) => TransformResult { program: None, - diagnostics: vec![diagnostic], + diagnostics: vec![*diagnostic], events: vec![], }, } @@ -179,33 +169,30 @@ pub fn lint( } } -/// Convenience wrapper: parses source text, then lints. -#[cfg(test)] -pub(crate) fn lint_source( +/// Parses source text, then lints it. This is the entry point for callers +/// (e.g. the `@swc/react-compiler` napi binding) that have not already +/// parsed their source into a [`Program`]. +pub fn lint_source( source_text: &str, syntax: swc_ecma_parser::Syntax, options: PluginOptions, ) -> LintResult { - match parse_source_for_tests(source_text, syntax) { + match parse_source(source_text, syntax) { Ok((program, comments, source_type)) => { lint(&program, source_type, source_text, Some(&comments), options) } Err(diagnostic) => LintResult { - diagnostics: vec![diagnostic], + diagnostics: vec![*diagnostic], }, } } -#[cfg(test)] -fn parse_source_for_tests( +fn parse_source( source_text: &str, syntax: swc_ecma_parser::Syntax, -) -> Result<(Program, SingleThreadedComments, SourceType), DiagnosticMessage> { - let cm = std::sync::Arc::new(swc_common::SourceMap::default()); - let fm = cm.new_source_file( - std::sync::Arc::new(swc_common::FileName::Anon), - source_text.to_string(), - ); +) -> Result<(Program, SingleThreadedComments, SourceType), Box> { + let cm = Lrc::new(swc_common::SourceMap::default()); + let fm = cm.new_source_file(Lrc::new(FileName::Anon), source_text.to_string()); let comments = SingleThreadedComments::default(); let mut errors = Vec::new(); let is_typescript = syntax.typescript(); @@ -220,10 +207,16 @@ fn parse_source_for_tests( let source_type = SourceType::from_program(&program).with_typescript(is_typescript); Ok((program, comments, source_type)) } - Err(error) => Err(DiagnosticMessage { + Err(error) => Err(Box::new(DiagnosticMessage { severity: diagnostics::Severity::Error, message: format!("[ReactCompiler] Parse error: {error:?}"), span: None, - }), + rule_id: None, + category: None, + reason: Some("Parse error".into()), + description: None, + loc: None, + details: Vec::new(), + })), } } diff --git a/deps/swc/crates/swc_ecma_react_compiler/src/prefilter.rs b/deps/swc/crates/swc_ecma_react_compiler/src/prefilter.rs index 01a2df4a9..895a18a7c 100644 --- a/deps/swc/crates/swc_ecma_react_compiler/src/prefilter.rs +++ b/deps/swc/crates/swc_ecma_react_compiler/src/prefilter.rs @@ -3,20 +3,9 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. -use react_compiler_hir::environment::is_react_like_name; use swc_ecma_ast as swc; use swc_ecma_visit::{Visit, VisitWith}; -/// Whether the program contains a component or hook candidate. -pub fn has_react_like_functions(program: &swc::Program) -> bool { - let mut visitor = ReactLikeVisitor { - found: false, - current_name: None, - }; - program.visit_with(&mut visitor); - visitor.found -} - /// Whether the program contains `using` or `await using` declarations. pub fn has_resource_management_declarations(program: &swc::Program) -> bool { let mut visitor = ResourceManagementVisitor { found: false }; @@ -24,28 +13,6 @@ pub fn has_resource_management_declarations(program: &swc::Program) -> bool { visitor.found } -/// `memo`/`forwardRef` wrappers mark callback functions as component-like even -/// when the callback itself is anonymous. -fn is_component_wrapper(callee: &swc::Callee) -> bool { - let is_wrapper = |name: &str| matches!(name, "memo" | "forwardRef"); - match callee { - swc::Callee::Expr(expr) => match &**expr { - swc::Expr::Ident(id) => is_wrapper(&id.sym), - swc::Expr::Member(member) => match &member.prop { - swc::MemberProp::Ident(prop) => is_wrapper(&prop.sym), - _ => false, - }, - _ => false, - }, - _ => false, - } -} - -struct ReactLikeVisitor { - found: bool, - current_name: Option, -} - struct ResourceManagementVisitor { found: bool, } @@ -66,119 +33,3 @@ impl Visit for ResourceManagementVisitor { let _ = decl; } } - -impl Visit for ReactLikeVisitor { - fn visit_var_declarator(&mut self, decl: &swc::VarDeclarator) { - if self.found { - return; - } - - let name = match &decl.name { - swc::Pat::Ident(ident) => Some(ident.id.sym.to_string()), - _ => None, - }; - - let prev_name = self.current_name.take(); - self.current_name = name; - - if let Some(init) = &decl.init { - init.visit_with(self); - } - - self.current_name = prev_name; - } - - fn visit_assign_expr(&mut self, expr: &swc::AssignExpr) { - if self.found { - return; - } - - let name = match &expr.left { - swc::AssignTarget::Simple(swc::SimpleAssignTarget::Ident(ident)) => { - Some(ident.id.sym.to_string()) - } - _ => None, - }; - - let prev_name = self.current_name.take(); - self.current_name = name; - - expr.right.visit_with(self); - - self.current_name = prev_name; - } - - fn visit_fn_decl(&mut self, decl: &swc::FnDecl) { - if self.found { - return; - } - - if is_react_like_name(&decl.ident.sym) { - self.found = true; - } - - // Do not traverse into function bodies. - } - - fn visit_fn_expr(&mut self, expr: &swc::FnExpr) { - if self.found { - return; - } - - if let Some(id) = &expr.ident { - if is_react_like_name(&id.sym) { - self.found = true; - return; - } - } - - if expr.ident.is_none() { - if let Some(name) = &self.current_name { - if is_react_like_name(name) { - self.found = true; - } - } - } - - // Do not traverse into function bodies. - } - - fn visit_arrow_expr(&mut self, expr: &swc::ArrowExpr) { - if self.found { - return; - } - - if let Some(name) = &self.current_name { - if is_react_like_name(name) { - self.found = true; - return; - } - } - - // Do not traverse into function bodies. - let _ = expr; - } - - fn visit_call_expr(&mut self, call: &swc::CallExpr) { - if self.found { - return; - } - - if is_component_wrapper(&call.callee) - && call - .args - .iter() - .any(|arg| matches!(&*arg.expr, swc::Expr::Fn(_) | swc::Expr::Arrow(_))) - { - self.found = true; - return; - } - - call.visit_children_with(self); - } - - fn visit_class(&mut self, class: &swc::Class) { - // Skip class bodies entirely. - let _ = class; - } -} diff --git a/deps/swc/crates/swc_ecma_regexp/Cargo.toml b/deps/swc/crates/swc_ecma_regexp/Cargo.toml index 347264859..1750340dc 100644 --- a/deps/swc/crates/swc_ecma_regexp/Cargo.toml +++ b/deps/swc/crates/swc_ecma_regexp/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/**/*.json"] license = { workspace = true } name = "swc_ecma_regexp" repository = "https://github.com/swc-project/swc.git" -version = "0.12.0" +version = "0.13.0" [lib] bench = false @@ -20,11 +20,11 @@ phf = { workspace = true, features = ["macros"] } rustc-hash = { workspace = true } unicode-id-start = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_regexp_ast = { version = "0.12.0", path = "../swc_ecma_regexp_ast" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_regexp_ast = { version = "1.0.0", path = "../swc_ecma_regexp_ast" } swc_ecma_regexp_common = { version = "0.0.1", path = "../swc_ecma_regexp_common" } -swc_ecma_regexp_visit = { version = "0.12.0", path = "../swc_ecma_regexp_visit" } +swc_ecma_regexp_visit = { version = "0.13.0", path = "../swc_ecma_regexp_visit" } [dev-dependencies] diff --git a/deps/swc/crates/swc_ecma_regexp_ast/Cargo.toml b/deps/swc/crates/swc_ecma_regexp_ast/Cargo.toml index 919fd7f13..6d99c4001 100644 --- a/deps/swc/crates/swc_ecma_regexp_ast/Cargo.toml +++ b/deps/swc/crates/swc_ecma_regexp_ast/Cargo.toml @@ -6,20 +6,18 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_regexp_ast" repository = { workspace = true } -version = "0.12.0" +version = "1.0.0" [lib] bench = false [features] -__rkyv = [] default = [] encoding-impl = [ "cbor4ii", "swc_atoms/encoding-impl", "swc_common/encoding-impl", ] -rkyv-impl = [] serde-impl = ["serde"] [dependencies] @@ -28,6 +26,6 @@ cbor4ii = { workspace = true, features = ["use_std"], optional = true } is-macro = { workspace = true } serde = { workspace = true, features = ["derive"], optional = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } swc_ecma_regexp_common = { version = "0.0.1", path = "../swc_ecma_regexp_common" } diff --git a/deps/swc/crates/swc_ecma_regexp_visit/Cargo.toml b/deps/swc/crates/swc_ecma_regexp_visit/Cargo.toml index a0b4738cc..6c95f0f55 100644 --- a/deps/swc/crates/swc_ecma_regexp_visit/Cargo.toml +++ b/deps/swc/crates/swc_ecma_regexp_visit/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_regexp_visit" repository = { workspace = true } -version = "0.12.0" +version = "0.13.0" [lib] bench = false @@ -19,7 +19,7 @@ serde-impl = ["serde"] [dependencies] serde = { workspace = true, optional = true, features = ["derive"] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_regexp_ast = { version = "0.12.0", path = "../swc_ecma_regexp_ast" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_regexp_ast = { version = "1.0.0", path = "../swc_ecma_regexp_ast" } swc_visit = { version = "2.0.1", path = "../swc_visit" } diff --git a/deps/swc/crates/swc_ecma_testing/Cargo.toml b/deps/swc/crates/swc_ecma_testing/Cargo.toml index cde59fc36..d72e4042c 100644 --- a/deps/swc/crates/swc_ecma_testing/Cargo.toml +++ b/deps/swc/crates/swc_ecma_testing/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_testing" repository = { workspace = true } -version = "24.0.1" +version = "25.0.0" [lib] bench = false @@ -17,4 +17,4 @@ hex = { workspace = true } sha2 = { workspace = true } tracing = { workspace = true } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_ecma_transformer/Cargo.toml b/deps/swc/crates/swc_ecma_transformer/Cargo.toml index 5ac346deb..d9522636c 100644 --- a/deps/swc/crates/swc_ecma_transformer/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transformer/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_transformer" repository = { workspace = true } -version = "16.0.3" +version = "19.0.0" [features] default = [] @@ -18,15 +18,15 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [dependencies] rustc-hash = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_compat_regexp = { version = "6.0.0", path = "../swc_ecma_compat_regexp" } -swc_ecma_hooks = { version = "0.9.0", path = "../swc_ecma_hooks" } -swc_ecma_regexp = { version = "0.12.0", path = "../swc_ecma_regexp" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit", features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_compat_regexp = { version = "7.0.0", path = "../swc_ecma_compat_regexp" } +swc_ecma_hooks = { version = "0.11.0", path = "../swc_ecma_hooks" } +swc_ecma_regexp = { version = "0.13.0", path = "../swc_ecma_regexp" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit", features = [ "path", ] } tracing = { workspace = true } diff --git a/deps/swc/crates/swc_ecma_transformer/src/es2018/object_rest_spread.rs b/deps/swc/crates/swc_ecma_transformer/src/es2018/object_rest_spread.rs index efd93637f..c8d142ad1 100644 --- a/deps/swc/crates/swc_ecma_transformer/src/es2018/object_rest_spread.rs +++ b/deps/swc/crates/swc_ecma_transformer/src/es2018/object_rest_spread.rs @@ -5,7 +5,9 @@ use swc_common::{util::take::Take, Spanned, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_hooks::VisitMutHook; use swc_ecma_transforms_base::{assumptions::Assumptions, helper, helper_expr}; -use swc_ecma_utils::{alias_if_required, private_ident, quote_ident, ExprFactory}; +use swc_ecma_utils::{ + alias_if_required, number::ToJsString, private_ident, quote_ident, ExprFactory, +}; use crate::TraverseCtx; @@ -1053,7 +1055,7 @@ fn make_rest_call(config: Config, source: Ident, excluded: Vec) -> Exp PropName::Str(s) => Expr::Lit(Lit::Str(s)), PropName::Num(n) => Expr::Lit(Lit::Str(Str { span: n.span, - value: n.value.to_string().into(), + value: n.value.to_js_string().into(), raw: None, })), PropName::Computed(c) if impure_count == 1 && !is_lit_str(&c.expr) => CallExpr { diff --git a/deps/swc/crates/swc_ecma_transforms/Cargo.toml b/deps/swc/crates/swc_ecma_transforms/Cargo.toml index 6bb412450..758a0ca65 100644 --- a/deps/swc/crates/swc_ecma_transforms/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transforms/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_transforms" repository = { workspace = true } -version = "56.0.0" +version = "60.0.0" [package.metadata.docs.rs] all-features = true @@ -38,23 +38,23 @@ typescript = ["swc_ecma_transforms_typescript"] [dependencies] par-core = { workspace = true } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_compat = { version = "52.0.1", path = "../swc_ecma_transforms_compat", optional = true, default-features = false } -swc_ecma_transforms_module = { version = "49.0.1", path = "../swc_ecma_transforms_module", optional = true } -swc_ecma_transforms_optimization = { version = "47.0.1", path = "../swc_ecma_transforms_optimization", optional = true } -swc_ecma_transforms_proposal = { version = "44.0.1", path = "../swc_ecma_transforms_proposal", optional = true } -swc_ecma_transforms_react = { version = "50.0.0", path = "../swc_ecma_transforms_react", optional = true } -swc_ecma_transforms_typescript = { version = "50.0.0", path = "../swc_ecma_transforms_typescript", optional = true } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_compat = { version = "55.0.0", path = "../swc_ecma_transforms_compat", optional = true, default-features = false } +swc_ecma_transforms_module = { version = "53.0.0", path = "../swc_ecma_transforms_module", optional = true } +swc_ecma_transforms_optimization = { version = "50.0.0", path = "../swc_ecma_transforms_optimization", optional = true } +swc_ecma_transforms_proposal = { version = "47.0.0", path = "../swc_ecma_transforms_proposal", optional = true } +swc_ecma_transforms_react = { version = "53.0.0", path = "../swc_ecma_transforms_react", optional = true } +swc_ecma_transforms_typescript = { version = "53.0.0", path = "../swc_ecma_transforms_typescript", optional = true } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } [dev-dependencies] par-core = { workspace = true, features = ["chili"] } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base", features = [ +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base", features = [ "inline-helpers", ] } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } -testing = { version = "24.0.1", path = "../testing" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_ecma_transforms_base/Cargo.toml b/deps/swc/crates/swc_ecma_transforms_base/Cargo.toml index 90b84c9af..c37013b52 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transforms_base/Cargo.toml @@ -3,11 +3,11 @@ authors = ["강동윤 "] description = "rust port of babel and closure compiler." documentation = "https://rustdoc.swc.rs/swc_ecma_transforms_base/" edition = { workspace = true } -include = ["Cargo.toml", "src/**/*.rs", "src/**/*.js"] +include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_transforms_base" repository = { workspace = true } -version = "44.0.3" +version = "47.0.0" [lib] bench = false @@ -32,23 +32,23 @@ rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] codspeed-criterion-compat = { workspace = true } par-core = { workspace = true, features = ["chili"] } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } swc_ecma_transforms_macros = { version = "1.0.1", path = "../swc_ecma_transforms_macros" } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } [[bench]] harness = false diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/fixer.rs b/deps/swc/crates/swc_ecma_transforms_base/src/fixer.rs index 94682e66d..70a606ab8 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/fixer.rs +++ b/deps/swc/crates/swc_ecma_transforms_base/src/fixer.rs @@ -71,6 +71,28 @@ enum Context { } impl Fixer<'_> { + /// `Pat::Expr` is needed for parenthesized for-head expressions, but a + /// bare identifier should use the same pattern shape as `for (x of y)`. + fn normalize_for_head_pat(n: &mut ForHead) { + let ForHead::Pat(pat) = n else { + return; + }; + + if pat.as_expr().and_then(|expr| expr.as_ident()).is_none() { + return; + } + + let Pat::Expr(expr) = *pat.take() else { + unreachable!() + }; + + let Expr::Ident(ident) = *expr else { + unreachable!() + }; + + **pat = ident.into(); + } + fn should_wrap_tagged_tpl_new_callee(tag: &Expr) -> bool { match tag { Expr::Call(..) | Expr::New(..) => true, @@ -390,6 +412,25 @@ impl VisitMut for Fixer<'_> { if let Callee::Expr(e) = &mut node.callee { match &**e { Expr::OptChain(_) if !self.in_opt_chain => self.wrap(e), + // Preserve parentheses around callees that carry a leading + // annotation like `/* @__PURE__ */` so downstream tools do not + // interpret the annotation as applying to the outer chained + // call expression. See issue #12019. + Expr::New(..) | Expr::Call(..) | Expr::TaggedTpl(..) if !self.remove_only => { + let span = e.span(); + let has_annotation = !span.is_dummy() + && self.comments.is_some_and(|c| { + c.has_flag(span.lo, "PURE") || c.has_flag(span.lo, "NO_SIDE_EFFECTS") + }); + if has_annotation { + let expr = e.take(); + *e = ParenExpr { + expr, + span: DUMMY_SP, + } + .into(); + } + } _ => self.wrap_callee(e), } } @@ -507,30 +548,30 @@ impl VisitMut for Fixer<'_> { let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, true); n.visit_mut_children_with(self); self.in_for_stmt_head = in_for_stmt_head; + + Self::normalize_for_head_pat(n); } fn visit_mut_for_of_stmt(&mut self, s: &mut ForOfStmt) { s.visit_mut_children_with(self); - if !s.is_await { - match &s.left { - ForHead::Pat(p) - if match &**p { - Pat::Ident(BindingIdent { - id: Ident { sym, .. }, - .. - }) => &**sym == "async", - _ => false, - } => - { - let expr: Pat = p.clone().expect_ident().into(); - s.left = ForHead::Pat(expr.into()); + if !self.remove_only && !s.is_await { + if let ForHead::Pat(p) = &mut s.left { + if matches!( + &**p, + Pat::Ident(BindingIdent { + id: Ident { sym, .. }, + .. + }) if &**sym == "async" + ) { + let Pat::Ident(ident) = *p.take() else { + unreachable!() + }; + + **p = Pat::Expr(ident.into()); } - _ => (), - } - if let ForHead::Pat(e) = &mut s.left { - if let Pat::Expr(expr) = &mut **e { + if let Pat::Expr(expr) = &mut **p { if expr.is_ident_ref_to("async") { self.wrap(&mut *expr); } @@ -609,6 +650,25 @@ impl VisitMut for Fixer<'_> { Expr::OptChain(..) if !self.in_opt_chain => { self.wrap(&mut n.obj); } + // Preserve parentheses around expressions that carry a leading + // annotation like `/* @__PURE__ */` so downstream tools do not + // interpret the annotation as applying to the full chained + // expression. See issue #12019. + Expr::New(..) | Expr::Call(..) | Expr::TaggedTpl(..) if !self.remove_only => { + let span = n.obj.span(); + let has_annotation = !span.is_dummy() + && self.comments.is_some_and(|c| { + c.has_flag(span.lo, "PURE") || c.has_flag(span.lo, "NO_SIDE_EFFECTS") + }); + if has_annotation { + let expr = n.obj.take(); + n.obj = ParenExpr { + expr, + span: DUMMY_SP, + } + .into(); + } + } _ => {} } } @@ -1224,7 +1284,10 @@ fn will_eat_else_token(s: &Stmt) -> bool { #[cfg(test)] mod tests { - use swc_ecma_ast::noop_pass; + use swc_ecma_ast::{noop_pass, ForHead, ModuleItem, Pat, Program, Stmt}; + use swc_ecma_parser::Syntax; + + use super::paren_remover; fn run_test(from: &str, to: &str) { crate::tests::test_transform( @@ -1253,6 +1316,46 @@ mod tests { }; } + fn assert_for_head_ident(left: &ForHead, expected: &str) { + let ForHead::Pat(pat) = left else { + panic!("expected for head pattern"); + }; + + let Pat::Ident(ident) = &**pat else { + panic!("expected identifier pattern"); + }; + + assert_eq!(&*ident.sym, expected); + } + + #[test] + fn paren_remover_normalizes_ident_for_head_pat_exprs() { + crate::tests::Tester::run(|tester| { + let program = tester.apply_transform( + paren_remover(None), + "input.js", + Syntax::default(), + "for ((((x))) of y) {}\nfor ((((x))) in y) {}\nfor ((((async))) of y) {}", + )?; + + let Program::Module(module) = program else { + panic!("expected module"); + }; + + let [ModuleItem::Stmt(Stmt::ForOf(for_of)), ModuleItem::Stmt(Stmt::ForIn(for_in)), ModuleItem::Stmt(Stmt::ForOf(for_of_async))] = + &module.body[..] + else { + panic!("expected for-of, for-in, and async for-of"); + }; + + assert_for_head_ident(&for_of.left, "x"); + assert_for_head_ident(&for_in.left, "x"); + assert_for_head_ident(&for_of_async.left, "async"); + + Ok(()) + }); + } + identical!(fn_expr_position, r#"foo(function(){}())"#); identical!(fn_decl, r#"function foo(){}"#); @@ -1346,6 +1449,12 @@ const _ref = {}, { c =( _tmp = {}, d = _extends({}, _tmp), _tmp) } = _ref;" test_fixer!(fixer_04, "for ((a, b), c;;) ;", "for(a, b, c;;);"); + test_fixer!( + for_of_async_head, + "var async; for (async of [1, 2]);", + "var async; for ((async) of [1, 2]);" + ); + test_fixer!( fixer_05, "var a, b, c = (1), d, e, f = (2); diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_array_like_to_array.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_array_like_to_array.js deleted file mode 100644 index 89ef96932..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_array_like_to_array.js +++ /dev/null @@ -1,5 +0,0 @@ -function _array_like_to_array(arr, len) { - if (len == null || len > arr.length) len = arr.length; - for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; - return arr2; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_array_with_holes.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_array_with_holes.js deleted file mode 100644 index 2078741c0..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_array_with_holes.js +++ /dev/null @@ -1,3 +0,0 @@ -function _array_with_holes(arr) { - if (Array.isArray(arr)) return arr; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_array_without_holes.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_array_without_holes.js deleted file mode 100644 index 146ae6fa7..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_array_without_holes.js +++ /dev/null @@ -1,3 +0,0 @@ -function _array_without_holes(arr) { - if (Array.isArray(arr)) return _array_like_to_array(arr); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_assert_this_initialized.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_assert_this_initialized.js deleted file mode 100644 index ae7cb5f9e..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_assert_this_initialized.js +++ /dev/null @@ -1,6 +0,0 @@ -function _assert_this_initialized(self) { - if (self === void 0) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - return self; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_to_generator.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_to_generator.js deleted file mode 100644 index 0d39cafa9..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_to_generator.js +++ /dev/null @@ -1,29 +0,0 @@ -function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error) { - reject(error); - return; - } - if (info.done) { - resolve(value); - } else { - Promise.resolve(value).then(_next, _throw); - } -} -function _async_to_generator(fn) { - return function() { - var self = this, args = arguments; - return new Promise(function(resolve, reject) { - var gen = fn.apply(self, args); - function _next(value) { - asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); - } - _next(undefined); - }); - }; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_await_async_generator.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_await_async_generator.js deleted file mode 100644 index e85565425..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_await_async_generator.js +++ /dev/null @@ -1,3 +0,0 @@ -function _await_async_generator(value) { - return new _overload_yield(value, /* kind: await */ 0); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_await_value.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_await_value.js deleted file mode 100644 index 1673e3a7f..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_await_value.js +++ /dev/null @@ -1,3 +0,0 @@ -function _await_value(value) { - this.wrapped = value; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_call_super.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_call_super.js deleted file mode 100644 index 9ff48ed01..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_call_super.js +++ /dev/null @@ -1,11 +0,0 @@ -function _call_super(_this, derived, args) { - // Super - derived = _get_prototype_of(derived); - return _possible_constructor_return( - _this, - _is_native_reflect_construct() - // NOTE: This doesn't work if this.__proto__.constructor has been modified. - ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) - : derived.apply(_this, args) - ); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_check_private_redeclaration.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_check_private_redeclaration.js deleted file mode 100644 index f4bb5162d..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_check_private_redeclaration.js +++ /dev/null @@ -1,5 +0,0 @@ -function _check_private_redeclaration(obj, privateCollection) { - if (privateCollection.has(obj)) { - throw new TypeError("Cannot initialize the same private elements twice on an object"); - } -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_destructure.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_destructure.js deleted file mode 100644 index 2e3fd3d63..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_destructure.js +++ /dev/null @@ -1,20 +0,0 @@ -function _class_apply_descriptor_destructure(receiver, descriptor) { - if (descriptor.set) { - if (!("__destrObj" in descriptor)) { - descriptor.__destrObj = { - set value(v) { - descriptor.set.call(receiver, v); - } - }; - } - return descriptor.__destrObj; - } else { - if (!descriptor.writable) { - // This should only throw in strict mode, but class bodies are - // always strict and private fields can only be used inside - // class bodies. - throw new TypeError("attempted to set read only private field"); - } - return descriptor; - } -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_get.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_get.js deleted file mode 100644 index 8d9e823e2..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_get.js +++ /dev/null @@ -1,6 +0,0 @@ -function _class_apply_descriptor_get(receiver, descriptor) { - if (descriptor.get) { - return descriptor.get.call(receiver); - } - return descriptor.value; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_set.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_set.js deleted file mode 100644 index dc1730d12..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_set.js +++ /dev/null @@ -1,13 +0,0 @@ -function _class_apply_descriptor_set(receiver, descriptor, value) { - if (descriptor.set) { - descriptor.set.call(receiver, value); - } else { - if (!descriptor.writable) { - // This should only throw in strict mode, but class bodies are - // always strict and private fields can only be used inside - // class bodies. - throw new TypeError("attempted to set read only private field"); - } - descriptor.value = value; - } -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_update.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_update.js deleted file mode 100644 index 79dd0f80d..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_apply_descriptor_update.js +++ /dev/null @@ -1,26 +0,0 @@ -function _class_apply_descriptor_update(receiver, descriptor) { - if (descriptor.set) { - if (!descriptor.get) { - throw new TypeError("attempted to read set only private field"); - } - if (!("__destrWrapper" in descriptor)) { - descriptor.__destrWrapper = { - set value(v) { - descriptor.set.call(receiver, v); - }, - get value() { - return descriptor.get.call(receiver); - } - }; - } - return descriptor.__destrWrapper; - } else { - if (!descriptor.writable) { - // This should only throw in strict mode, but class bodies are - // always strict and private fields can only be used inside - // class bodies. - throw new TypeError("attempted to set read only private field"); - } - return descriptor; - } -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_call_check.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_call_check.js deleted file mode 100644 index fc3d8cd30..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_call_check.js +++ /dev/null @@ -1,5 +0,0 @@ -function _class_call_check(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_check_private_static_access.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_check_private_static_access.js deleted file mode 100644 index 9f111acac..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_check_private_static_access.js +++ /dev/null @@ -1,5 +0,0 @@ -function _class_check_private_static_access(receiver, classConstructor) { - if (receiver !== classConstructor) { - throw new TypeError("Private static access of wrong provenance"); - } -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_check_private_static_field_descriptor.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_check_private_static_field_descriptor.js deleted file mode 100644 index 0c713ac4d..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_check_private_static_field_descriptor.js +++ /dev/null @@ -1,5 +0,0 @@ -function _class_check_private_static_field_descriptor(descriptor, action) { - if (descriptor === undefined) { - throw new TypeError("attempted to " + action + " private static field before its declaration"); - } -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_extract_field_descriptor.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_extract_field_descriptor.js deleted file mode 100644 index 3bb24f479..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_extract_field_descriptor.js +++ /dev/null @@ -1,6 +0,0 @@ -function _class_extract_field_descriptor(receiver, privateMap, action) { - if (!privateMap.has(receiver)) { - throw new TypeError("attempted to " + action + " private field on non-instance"); - } - return privateMap.get(receiver); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_name_tdz_error.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_name_tdz_error.js deleted file mode 100644 index 441bcb97f..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_name_tdz_error.js +++ /dev/null @@ -1,3 +0,0 @@ -function _class_name_tdz_error(name) { - throw new ReferenceError("Class \"" + name + "\" cannot be referenced in computed property keys."); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_destructure.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_destructure.js deleted file mode 100644 index 9ce317bdd..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_destructure.js +++ /dev/null @@ -1,4 +0,0 @@ -function _class_private_field_destructure(receiver, privateMap) { - var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set"); - return _class_apply_descriptor_destructure(receiver, descriptor); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_get.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_get.js deleted file mode 100644 index 583c164d2..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_get.js +++ /dev/null @@ -1,4 +0,0 @@ -function _class_private_field_get(receiver, privateMap) { - var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get"); - return _class_apply_descriptor_get(receiver, descriptor); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_init.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_init.js deleted file mode 100644 index b2c9c03bc..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_init.js +++ /dev/null @@ -1,4 +0,0 @@ -function _class_private_field_init(obj, privateMap, value) { - _check_private_redeclaration(obj, privateMap); - privateMap.set(obj, value); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_base.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_base.js deleted file mode 100644 index 4a6752e70..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_base.js +++ /dev/null @@ -1,6 +0,0 @@ -function _class_private_field_loose_base(receiver, privateKey) { - if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { - throw new TypeError("attempted to use private field on non-instance"); - } - return receiver; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_key.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_key.js deleted file mode 100644 index a04419c1f..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_key.js +++ /dev/null @@ -1,4 +0,0 @@ -var id = 0; -function _class_private_field_loose_key(name) { - return "__private_" + id++ + "_" + name; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_set.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_set.js deleted file mode 100644 index 71c9defdf..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_set.js +++ /dev/null @@ -1,5 +0,0 @@ -function _class_private_field_set(receiver, privateMap, value) { - var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set"); - _class_apply_descriptor_set(receiver, descriptor, value); - return value; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_update.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_update.js deleted file mode 100644 index 2bae86cff..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_update.js +++ /dev/null @@ -1,4 +0,0 @@ -function _class_private_field_update(receiver, privateMap) { - var descriptor = _class_extract_field_descriptor(receiver, privateMap, "update"); - return _class_apply_descriptor_update(receiver, descriptor); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_method_get.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_method_get.js deleted file mode 100644 index 4fb72d8ea..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_method_get.js +++ /dev/null @@ -1,6 +0,0 @@ -function _class_private_method_get(receiver, privateSet, fn) { - if (!privateSet.has(receiver)) { - throw new TypeError("attempted to get private field on non-instance"); - } - return fn; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_method_init.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_method_init.js deleted file mode 100644 index a2085b74d..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_method_init.js +++ /dev/null @@ -1,4 +0,0 @@ -function _class_private_method_init(obj, privateSet) { - _check_private_redeclaration(obj, privateSet); - privateSet.add(obj); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_method_set.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_method_set.js deleted file mode 100644 index 79fd1f375..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_private_method_set.js +++ /dev/null @@ -1,3 +0,0 @@ -function _class_private_method_set() { - throw new TypeError("attempted to reassign private method"); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_destructure.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_destructure.js deleted file mode 100644 index 9c41b7088..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_destructure.js +++ /dev/null @@ -1,5 +0,0 @@ -function _class_static_private_field_destructure(receiver, classConstructor, descriptor) { - _class_check_private_static_access(receiver, classConstructor); - _class_check_private_static_field_descriptor(descriptor, "set"); - return _class_apply_descriptor_destructure(receiver, descriptor); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_spec_get.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_spec_get.js deleted file mode 100644 index 65fddaf01..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_spec_get.js +++ /dev/null @@ -1,5 +0,0 @@ -function _class_static_private_field_spec_get(receiver, classConstructor, descriptor) { - _class_check_private_static_access(receiver, classConstructor); - _class_check_private_static_field_descriptor(descriptor, "get"); - return _class_apply_descriptor_get(receiver, descriptor); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_spec_set.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_spec_set.js deleted file mode 100644 index df6f3c8ca..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_spec_set.js +++ /dev/null @@ -1,6 +0,0 @@ -function _class_static_private_field_spec_set(receiver, classConstructor, descriptor, value) { - _class_check_private_static_access(receiver, classConstructor); - _class_check_private_static_field_descriptor(descriptor, "set"); - _class_apply_descriptor_set(receiver, descriptor, value); - return value; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_update.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_update.js deleted file mode 100644 index 2c1778e5b..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_field_update.js +++ /dev/null @@ -1,5 +0,0 @@ -function _class_static_private_field_update(receiver, classConstructor, descriptor) { - _class_check_private_static_access(receiver, classConstructor); - _class_check_private_static_field_descriptor(descriptor, "update"); - return _class_apply_descriptor_update(receiver, descriptor); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_method_get.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_method_get.js deleted file mode 100644 index e1b0ba546..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_class_static_private_method_get.js +++ /dev/null @@ -1,4 +0,0 @@ -function _class_static_private_method_get(receiver, classConstructor, method) { - _class_check_private_static_access(receiver, classConstructor); - return method; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_construct.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_construct.js deleted file mode 100644 index 31f863015..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_construct.js +++ /dev/null @@ -1,15 +0,0 @@ -function _construct(Parent, args, Class) { - if (_is_native_reflect_construct()) { - _construct = Reflect.construct; - } else { - _construct = function construct(Parent, args, Class) { - var a = [null]; - a.push.apply(a, args); - var Constructor = Function.bind.apply(Parent, a); - var instance = new Constructor(); - if (Class) _set_prototype_of(instance, Class.prototype); - return instance; - }; - } - return _construct.apply(null, arguments); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_create_class.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_create_class.js deleted file mode 100644 index 7b7e1a1fc..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_create_class.js +++ /dev/null @@ -1,14 +0,0 @@ -function _defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } -} -function _create_class(Constructor, protoProps, staticProps) { - if (protoProps) _defineProperties(Constructor.prototype, protoProps); - if (staticProps) _defineProperties(Constructor, staticProps); - return Constructor; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_create_for_of_iterator_helper_loose.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_create_for_of_iterator_helper_loose.js deleted file mode 100644 index 02f06b754..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_create_for_of_iterator_helper_loose.js +++ /dev/null @@ -1,18 +0,0 @@ -function _create_for_of_iterator_helper_loose(o, allowArrayLike) { - var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; - if (it) return (it = it.call(o)).next.bind(it); - // Fallback for engines without symbol support - if (Array.isArray(o) || (it = _unsupported_iterable_to_array(o)) || allowArrayLike && o && typeof o.length === "number") { - if (it) o = it; - var i = 0; - return function() { - if (i >= o.length) { - return { done: true }; - } - return { done: false, value: o[i++] }; - }; - } - throw new TypeError( - "Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method." - ); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_create_super.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_create_super.js deleted file mode 100644 index db281bc57..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_create_super.js +++ /dev/null @@ -1,13 +0,0 @@ -function _create_super(Derived) { - var hasNativeReflectConstruct = _is_native_reflect_construct(); - return function _createSuperInternal() { - var Super = _get_prototype_of(Derived), result; - if (hasNativeReflectConstruct) { - var NewTarget = _get_prototype_of(this).constructor; - result = Reflect.construct(Super, arguments, NewTarget); - } else { - result = Super.apply(this, arguments); - } - return _possible_constructor_return(this, result); - }; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_defaults.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_defaults.js deleted file mode 100644 index 2ba392ed6..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_defaults.js +++ /dev/null @@ -1,11 +0,0 @@ -function _defaults(obj, defaults) { - var keys = Object.getOwnPropertyNames(defaults); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - var value = Object.getOwnPropertyDescriptor(defaults, key); - if (value && value.configurable && obj[key] === undefined) { - Object.defineProperty(obj, key, value); - } - } - return obj; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_define_enumerable_properties.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_define_enumerable_properties.js deleted file mode 100644 index f935fce01..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_define_enumerable_properties.js +++ /dev/null @@ -1,19 +0,0 @@ -function _define_enumerable_properties(obj, descs) { - for (var key in descs) { - var desc = descs[key]; - desc.configurable = desc.enumerable = true; - if ("value" in desc) desc.writable = true; - Object.defineProperty(obj, key, desc); - } - if (Object.getOwnPropertySymbols) { - var objectSymbols = Object.getOwnPropertySymbols(descs); - for (var i = 0; i < objectSymbols.length; i++) { - var sym = objectSymbols[i]; - var desc = descs[sym]; - desc.configurable = desc.enumerable = true; - if ("value" in desc) desc.writable = true; - Object.defineProperty(obj, sym, desc); - } - } - return obj; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_define_property.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_define_property.js deleted file mode 100644 index e766329cb..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_define_property.js +++ /dev/null @@ -1,8 +0,0 @@ -function _define_property(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); - } else { - obj[key] = value; - } - return obj; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_export_star.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_export_star.js deleted file mode 100644 index 65e1cc949..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_export_star.js +++ /dev/null @@ -1,13 +0,0 @@ -function _export_star(from, to) { - Object.keys(from).forEach(function(k) { - if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { - Object.defineProperty(to, k, { - enumerable: true, - get: function() { - return from[k]; - } - }); - } - }); - return from; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_extends.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_extends.js deleted file mode 100644 index acef0a282..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_extends.js +++ /dev/null @@ -1,14 +0,0 @@ -function _extends() { - _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - return target; - }; - return _extends.apply(this, arguments); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_get.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_get.js deleted file mode 100644 index f222cf82b..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_get.js +++ /dev/null @@ -1,16 +0,0 @@ -function _get(target, property, receiver) { - if (typeof Reflect !== "undefined" && Reflect.get) { - _get = Reflect.get; - } else { - _get = function get(target, property, receiver) { - var base = _super_prop_base(target, property); - if (!base) return; - var desc = Object.getOwnPropertyDescriptor(base, property); - if (desc.get) { - return desc.get.call(receiver || target); - } - return desc.value; - }; - } - return _get(target, property, receiver || target); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_get_prototype_of.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_get_prototype_of.js deleted file mode 100644 index 458439f51..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_get_prototype_of.js +++ /dev/null @@ -1,6 +0,0 @@ -function _get_prototype_of(o) { - _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) { - return o.__proto__ || Object.getPrototypeOf(o); - }; - return _get_prototype_of(o); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_identity.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_identity.js deleted file mode 100644 index 2eed63eb2..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_identity.js +++ /dev/null @@ -1 +0,0 @@ -function _identity(x) { return x; } diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_inherits.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_inherits.js deleted file mode 100644 index d16557677..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_inherits.js +++ /dev/null @@ -1,9 +0,0 @@ -function _inherits(subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function"); - } - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { value: subClass, writable: true, configurable: true } - }); - if (superClass) _set_prototype_of(subClass, superClass); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_inherits_loose.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_inherits_loose.js deleted file mode 100644 index c045a102d..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_inherits_loose.js +++ /dev/null @@ -1,5 +0,0 @@ -function _inherits_loose(subClass, superClass) { - subClass.prototype = Object.create(superClass.prototype); - subClass.prototype.constructor = subClass; - subClass.__proto__ = superClass; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_initializer_define_property.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_initializer_define_property.js deleted file mode 100644 index 042dcb0bf..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_initializer_define_property.js +++ /dev/null @@ -1,9 +0,0 @@ -function _initializer_define_property(target, property, descriptor, context) { - if (!descriptor) return; - Object.defineProperty(target, property, { - enumerable: descriptor.enumerable, - configurable: descriptor.configurable, - writable: descriptor.writable, - value: descriptor.initializer ? descriptor.initializer.call(context) : void 0 - }); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_initializer_warning_helper.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_initializer_warning_helper.js deleted file mode 100644 index f05909123..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_initializer_warning_helper.js +++ /dev/null @@ -1,7 +0,0 @@ -function _initializer_warning_helper(descriptor, context) { - throw new Error( - "Decorating class property failed. Please ensure that " + "proposal-class-properties is enabled and set to use loose mode. " - + "To use proposal-class-properties in spec mode with decorators, wait for " - + "the next major version of decorators in stage 2." - ); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_instanceof.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_instanceof.js deleted file mode 100644 index 5e83a5dcc..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_instanceof.js +++ /dev/null @@ -1,9 +0,0 @@ -function _instanceof(left, right) { - "@swc/helpers - instanceof"; - - if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { - return !!right[Symbol.hasInstance](left); - } else { - return left instanceof right; - } -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_interop_require_default.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_interop_require_default.js deleted file mode 100644 index 42b216fbe..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_interop_require_default.js +++ /dev/null @@ -1,3 +0,0 @@ -function _interop_require_default(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_interop_require_wildcard.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_interop_require_wildcard.js deleted file mode 100644 index 22aab86e4..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_interop_require_wildcard.js +++ /dev/null @@ -1,37 +0,0 @@ -function _getRequireWildcardCache(nodeInterop) { - if (typeof WeakMap !== "function") return null; - var cacheBabelInterop = new WeakMap(); - var cacheNodeInterop = new WeakMap(); - return (_getRequireWildcardCache = function(nodeInterop) { - return nodeInterop ? cacheNodeInterop : cacheBabelInterop; - })(nodeInterop); -} -function _interop_require_wildcard(obj, nodeInterop) { - if (!nodeInterop && obj && obj.__esModule) { - return obj; - } - if (obj === null || typeof obj !== "object" && typeof obj !== "function") { - return { default: obj }; - } - var cache = _getRequireWildcardCache(nodeInterop); - if (cache && cache.has(obj)) { - return cache.get(obj); - } - var newObj = { __proto__: null }; - var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; - for (var key in obj) { - if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { - var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; - if (desc && (desc.get || desc.set)) { - Object.defineProperty(newObj, key, desc); - } else { - newObj[key] = obj[key]; - } - } - } - newObj.default = obj; - if (cache) { - cache.set(obj, newObj); - } - return newObj; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_is_native_function.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_is_native_function.js deleted file mode 100644 index 2148fba01..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_is_native_function.js +++ /dev/null @@ -1,3 +0,0 @@ -function _is_native_function(fn) { - return Function.toString.call(fn).indexOf("[native code]") !== -1; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_is_native_reflect_construct.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_is_native_reflect_construct.js deleted file mode 100644 index 74d2cdc0d..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_is_native_reflect_construct.js +++ /dev/null @@ -1,14 +0,0 @@ -function _is_native_reflect_construct() { - // Since Reflect.construct can't be properly polyfilled, some - // implementations (e.g. core-js@2) don't set the correct internal slots. - // Those polyfills don't allow us to subclass built-ins, so we need to - // use our fallback implementation. - try { - // If the internal slots aren't set, this throws an error similar to - // TypeError: this is not a Boolean object. - var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {})); - } catch (_) {} - return (_is_native_reflect_construct = function() { - return !!result; - })(); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_iterable_to_array.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_iterable_to_array.js deleted file mode 100644 index e21d1637d..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_iterable_to_array.js +++ /dev/null @@ -1,3 +0,0 @@ -function _iterable_to_array(iter) { - if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_iterable_to_array_limit.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_iterable_to_array_limit.js deleted file mode 100644 index 9ab87e786..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_iterable_to_array_limit.js +++ /dev/null @@ -1,24 +0,0 @@ -function _iterable_to_array_limit(arr, i) { - var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; - if (_i == null) return; - var _arr = []; - var _n = true; - var _d = false; - var _s, _e; - try { - for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } - } - return _arr; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_iterable_to_array_limit_loose.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_iterable_to_array_limit_loose.js deleted file mode 100644 index 24b507417..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_iterable_to_array_limit_loose.js +++ /dev/null @@ -1,10 +0,0 @@ -function _iterable_to_array_limit_loose(arr, i) { - var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]); - if (_i == null) return; - var _arr = []; - for (_i = _i.call(arr), _step; !(_step = _i.next()).done;) { - _arr.push(_step.value); - if (i && _arr.length === i) break; - } - return _arr; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_jsx.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_jsx.js deleted file mode 100644 index 0e155e403..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_jsx.js +++ /dev/null @@ -1,30 +0,0 @@ -var REACT_ELEMENT_TYPE; -function _jsx(type, props, key, children) { - if (!REACT_ELEMENT_TYPE) { - REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol.for && Symbol.for("react.element") || 0xeac7; - } - var defaultProps = type && type.defaultProps; - var childrenLength = arguments.length - 3; - if (!props && childrenLength !== 0) { - props = { children: void 0 }; - } - if (props && defaultProps) { - for (var propName in defaultProps) { - if (props[propName] === void 0) { - props[propName] = defaultProps[propName]; - } - } - } else if (!props) { - props = defaultProps || {}; - } - if (childrenLength === 1) { - props.children = children; - } else if (childrenLength > 1) { - var childArray = new Array(childrenLength); - for (var i = 0; i < childrenLength; i++) { - childArray[i] = arguments[i + 3]; - } - props.children = childArray; - } - return { $$typeof: REACT_ELEMENT_TYPE, type: type, key: key === undefined ? null : "" + key, ref: null, props: props, _owner: null }; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_new_arrow_check.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_new_arrow_check.js deleted file mode 100644 index 11ce97952..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_new_arrow_check.js +++ /dev/null @@ -1,5 +0,0 @@ -function _new_arrow_check(innerThis, boundThis) { - if (innerThis !== boundThis) { - throw new TypeError("Cannot instantiate an arrow function"); - } -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_non_iterable_rest.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_non_iterable_rest.js deleted file mode 100644 index 649c15433..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_non_iterable_rest.js +++ /dev/null @@ -1,5 +0,0 @@ -function _non_iterable_rest() { - throw new TypeError( - "Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method." - ); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_non_iterable_spread.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_non_iterable_spread.js deleted file mode 100644 index d450671a1..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_non_iterable_spread.js +++ /dev/null @@ -1,5 +0,0 @@ -function _non_iterable_spread() { - throw new TypeError( - "Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method." - ); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_destructuring_empty.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_destructuring_empty.js deleted file mode 100644 index 6be6fae5b..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_destructuring_empty.js +++ /dev/null @@ -1,4 +0,0 @@ -function _object_destructuring_empty(o) { - if (o === null || o === void 0) throw new TypeError("Cannot destructure " + o); - return o; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_spread.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_spread.js deleted file mode 100644 index 6528e5b40..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_spread.js +++ /dev/null @@ -1,17 +0,0 @@ -function _object_spread(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i] != null ? arguments[i] : {}; - var ownKeys = Object.keys(source); - if (typeof Object.getOwnPropertySymbols === "function") { - ownKeys = ownKeys.concat( - Object.getOwnPropertySymbols(source).filter(function(sym) { - return Object.getOwnPropertyDescriptor(source, sym).enumerable; - }) - ); - } - ownKeys.forEach(function(key) { - _define_property(target, key, source[key]); - }); - } - return target; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_spread_props.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_spread_props.js deleted file mode 100644 index f569e4082..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_spread_props.js +++ /dev/null @@ -1,24 +0,0 @@ -function ownKeys(object, enumerableOnly) { - var keys = Object.keys(object); - if (Object.getOwnPropertySymbols) { - var symbols = Object.getOwnPropertySymbols(object); - if (enumerableOnly) { - symbols = symbols.filter(function(sym) { - return Object.getOwnPropertyDescriptor(object, sym).enumerable; - }); - } - keys.push.apply(keys, symbols); - } - return keys; -} -function _object_spread_props(target, source) { - source = source != null ? source : {}; - if (Object.getOwnPropertyDescriptors) { - Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); - } else { - ownKeys(Object(source)).forEach(function(key) { - Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); - }); - } - return target; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_without_properties_loose.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_without_properties_loose.js deleted file mode 100644 index b38cbe5af..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_without_properties_loose.js +++ /dev/null @@ -1,13 +0,0 @@ -function _object_without_properties_loose(source, excluded) { - if (source == null) return {}; - - var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i; - for (i = 0; i < sourceKeys.length; i++) { - key = sourceKeys[i]; - if (excluded.indexOf(key) >= 0) continue; - if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; - target[key] = source[key]; - } - - return target; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_overload_yield.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_overload_yield.js deleted file mode 100644 index bb2897917..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_overload_yield.js +++ /dev/null @@ -1,4 +0,0 @@ -function _overload_yield(value, /** 0: await 1: delegate */ kind) { - this.v = value; - this.k = kind; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_possible_constructor_return.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_possible_constructor_return.js deleted file mode 100644 index ab98d13a4..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_possible_constructor_return.js +++ /dev/null @@ -1,6 +0,0 @@ -function _possible_constructor_return(self, call) { - if (call && (_type_of(call) === "object" || typeof call === "function")) { - return call; - } - return _assert_this_initialized(self); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_read_only_error.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_read_only_error.js deleted file mode 100644 index e953a3a92..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_read_only_error.js +++ /dev/null @@ -1,3 +0,0 @@ -function _read_only_error(name) { - throw new TypeError("\"" + name + "\" is read-only"); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_set_prototype_of.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_set_prototype_of.js deleted file mode 100644 index 4edc6a97e..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_set_prototype_of.js +++ /dev/null @@ -1,7 +0,0 @@ -function _set_prototype_of(o, p) { - _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) { - o.__proto__ = p; - return o; - }; - return _set_prototype_of(o, p); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_skip_first_generator_next.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_skip_first_generator_next.js deleted file mode 100644 index 900e68661..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_skip_first_generator_next.js +++ /dev/null @@ -1,7 +0,0 @@ -function _skip_first_generator_next(fn) { - return function() { - var it = fn.apply(this, arguments); - it.next(); - return it; - }; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_sliced_to_array.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_sliced_to_array.js deleted file mode 100644 index ee2a8ee4f..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_sliced_to_array.js +++ /dev/null @@ -1,3 +0,0 @@ -function _sliced_to_array(arr, i) { - return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest(); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_sliced_to_array_loose.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_sliced_to_array_loose.js deleted file mode 100644 index dcbe68f93..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_sliced_to_array_loose.js +++ /dev/null @@ -1,4 +0,0 @@ -function _sliced_to_array_loose(arr, i) { - return _array_with_holes(arr) || _iterable_to_array_limit_loose(arr, i) || _unsupported_iterable_to_array(arr, i) - || _non_iterable_rest(); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_super_prop_base.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_super_prop_base.js deleted file mode 100644 index 87bc9bc8f..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_super_prop_base.js +++ /dev/null @@ -1,7 +0,0 @@ -function _super_prop_base(object, property) { - while (!Object.prototype.hasOwnProperty.call(object, property)) { - object = _get_prototype_of(object); - if (object === null) break; - } - return object; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_tagged_template_literal.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_tagged_template_literal.js deleted file mode 100644 index 0b558f527..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_tagged_template_literal.js +++ /dev/null @@ -1,6 +0,0 @@ -function _tagged_template_literal(strings, raw) { - if (!raw) { - raw = strings.slice(0); - } - return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_tagged_template_literal_loose.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_tagged_template_literal_loose.js deleted file mode 100644 index f9c525878..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_tagged_template_literal_loose.js +++ /dev/null @@ -1,7 +0,0 @@ -function _tagged_template_literal_loose(strings, raw) { - if (!raw) { - raw = strings.slice(0); - } - strings.raw = raw; - return strings; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_throw.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_throw.js deleted file mode 100644 index 1ce873108..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_throw.js +++ /dev/null @@ -1,3 +0,0 @@ -function _throw(e) { - throw e; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_array.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_array.js deleted file mode 100644 index 8126c7edd..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_array.js +++ /dev/null @@ -1,3 +0,0 @@ -function _to_array(arr) { - return _array_with_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_rest(); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_consumable_array.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_consumable_array.js deleted file mode 100644 index d9bbf962b..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_consumable_array.js +++ /dev/null @@ -1,3 +0,0 @@ -function _to_consumable_array(arr) { - return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread(); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_primitive.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_primitive.js deleted file mode 100644 index 239f50f33..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_primitive.js +++ /dev/null @@ -1,10 +0,0 @@ -function _to_primitive(input, hint) { - if (_type_of(input) !== "object" || input === null) return input; - var prim = input[Symbol.toPrimitive]; - if (prim !== undefined) { - var res = prim.call(input, hint || "default"); - if (_type_of(res) !== "object") return res; - throw new TypeError("@@toPrimitive must return a primitive value."); - } - return (hint === "string" ? String : Number)(input); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_property_key.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_property_key.js deleted file mode 100644 index 383beec99..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_to_property_key.js +++ /dev/null @@ -1,4 +0,0 @@ -function _to_property_key(arg) { - var key = _to_primitive(arg, "string"); - return _type_of(key) === "symbol" ? key : String(key); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_add_disposable_resource.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_add_disposable_resource.js deleted file mode 100644 index 2ecbaaa88..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_add_disposable_resource.js +++ /dev/null @@ -1,22 +0,0 @@ -function _ts_add_disposable_resource(env, value, async) { - if (value !== null && value !== void 0) { - if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); - var dispose, inner; - if (async) { - if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); - dispose = value[Symbol.asyncDispose]; - } - if (dispose === void 0) { - if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); - dispose = value[Symbol.dispose]; - if (async) inner = dispose; - } - if (typeof dispose !== "function") throw new TypeError("Object not disposable."); - if (inner) dispose = function () { try { inner.call(this); } catch (e) { return Promise.reject(e); } }; - env.stack.push({ value: value, dispose: dispose, async: async }); - } - else if (async) { - env.stack.push({ async: true }); - } - return value; -} \ No newline at end of file diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_decorate.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_decorate.js deleted file mode 100644 index 986e404fd..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_decorate.js +++ /dev/null @@ -1,6 +0,0 @@ -function _ts_decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -} \ No newline at end of file diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_dispose_resources.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_dispose_resources.js deleted file mode 100644 index 8865a070c..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_dispose_resources.js +++ /dev/null @@ -1,33 +0,0 @@ -function _ts_dispose_resources(env) { - var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { - var e = new Error(message); - return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; - }; - - - return (_ts_dispose_resources = function _ts_dispose_resources(env) { - function fail(e) { - env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; - env.hasError = true; - } - var r, s = 0; - function next() { - while (r = env.stack.pop()) { - try { - if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); - if (r.dispose) { - var result = r.dispose.call(r.value); - if (r.async) return s |= 2, Promise.resolve(result).then(next, function (e) { fail(e); return next(); }); - } - else s |= 1; - } - catch (e) { - fail(e); - } - } - if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); - if (env.hasError) throw env.error; - } - return next(); - })(env); -} \ No newline at end of file diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_metadata.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_metadata.js deleted file mode 100644 index 4d28dd307..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_metadata.js +++ /dev/null @@ -1,3 +0,0 @@ -function _ts_metadata(k, v) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); -} \ No newline at end of file diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_param.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_param.js deleted file mode 100644 index a52ed9e6f..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_param.js +++ /dev/null @@ -1,3 +0,0 @@ -function _ts_param(paramIndex, decorator) { - return function (target, key) { decorator(target, key, paramIndex); } -} \ No newline at end of file diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_rewrite_relative_import_extension.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_rewrite_relative_import_extension.js deleted file mode 100644 index adb3e6f3f..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_rewrite_relative_import_extension.js +++ /dev/null @@ -1,8 +0,0 @@ -function _ts_rewrite_relative_import_extension(path, preserveJsx) { - if (typeof path === "string" && /^\.\.?\//.test(path)) { - return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) { - return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js"); - }); - } - return path; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_values.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_values.js deleted file mode 100644 index cdfde621a..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_values.js +++ /dev/null @@ -1,11 +0,0 @@ -function _ts_values(o) { - var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; - if (m) return m.call(o); - if (o && typeof o.length === "number") return { - next: function () { - if (o && i >= o.length) o = void 0; - return { value: o && o[i++], done: !o }; - } - }; - throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); -} \ No newline at end of file diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_type_of.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_type_of.js deleted file mode 100644 index 6ac66d204..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_type_of.js +++ /dev/null @@ -1,4 +0,0 @@ -function _type_of(obj) { - "@swc/helpers - typeof"; - return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_unsupported_iterable_to_array.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_unsupported_iterable_to_array.js deleted file mode 100644 index 048124613..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_unsupported_iterable_to_array.js +++ /dev/null @@ -1,8 +0,0 @@ -function _unsupported_iterable_to_array(o, minLen) { - if (!o) return; - if (typeof o === "string") return _array_like_to_array(o, minLen); - var n = Object.prototype.toString.call(o).slice(8, -1); - if (n === "Object" && o.constructor) n = o.constructor.name; - if (n === "Map" || n === "Set") return Array.from(n); - if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_update.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_update.js deleted file mode 100644 index 0fd806042..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_update.js +++ /dev/null @@ -1,10 +0,0 @@ -function _update(target, property, receiver, isStrict) { - return { - get _() { - return _get(target, property, receiver); - }, - set _(value) { - _set(target, property, value, receiver, isStrict); - } - }; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_using.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_using.js deleted file mode 100644 index 9e837f488..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_using.js +++ /dev/null @@ -1,19 +0,0 @@ -function _using(stack, value, isAwait) { - if (value === null || value === void 0) return value; - if (Object(value) !== value) { - throw new TypeError("using declarations can only be used with objects, functions, null, or undefined."); - } - // core-js-pure uses Symbol.for for polyfilling well-known symbols - if (isAwait) { - var dispose = - value[Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose")]; - } - if (dispose === null || dispose === void 0) { - dispose = value[Symbol.dispose || Symbol.for("Symbol.dispose")]; - } - if (typeof dispose !== "function") { - throw new TypeError(`Property [Symbol.dispose] is not a function.`); - } - stack.push({ v: value, d: dispose, a: isAwait }); - return value; -} \ No newline at end of file diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_wrap_async_generator.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_wrap_async_generator.js deleted file mode 100644 index 1381a8583..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_wrap_async_generator.js +++ /dev/null @@ -1,5 +0,0 @@ -function _wrap_async_generator(fn) { - return function() { - return new _async_generator(fn.apply(this, arguments)); - }; -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_wrap_native_super.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_wrap_native_super.js deleted file mode 100644 index 31c53f4be..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_wrap_native_super.js +++ /dev/null @@ -1,21 +0,0 @@ -function _wrap_native_super(Class) { - var _cache = typeof Map === "function" ? new Map() : undefined; - _wrap_native_super = function wrapNativeSuper(Class) { - if (Class === null || !_is_native_function(Class)) return Class; - if (typeof Class !== "function") { - throw new TypeError("Super expression must either be null or a function"); - } - if (typeof _cache !== "undefined") { - if (_cache.has(Class)) return _cache.get(Class); - _cache.set(Class, Wrapper); - } - function Wrapper() { - return _construct(Class, arguments, _get_prototype_of(this).constructor); - } - Wrapper.prototype = Object.create(Class.prototype, { - constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } - }); - return _set_prototype_of(Wrapper, Class); - }; - return _wrap_native_super(Class); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_write_only_error.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_write_only_error.js deleted file mode 100644 index 48589660a..000000000 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_write_only_error.js +++ /dev/null @@ -1,3 +0,0 @@ -function _write_only_error(name) { - throw new TypeError("\"" + name + "\" is write-only"); -} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_apply_decorated_descriptor.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_apply_decorated_descriptor.rs similarity index 51% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_apply_decorated_descriptor.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_apply_decorated_descriptor.rs index de19a79c8..b63fcc302 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_apply_decorated_descriptor.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_apply_decorated_descriptor.rs @@ -1,17 +1,28 @@ -function _apply_decorated_descriptor(target, property, decorators, descriptor, context) { +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::apply_decorated_descriptor, + local: "_apply_decorated_descriptor", + import_path: "@swc/helpers/_/_apply_decorated_descriptor", + #[cfg(feature = "inline-helpers")] + source: r#"function _apply_decorated_descriptor(target, property, decorators, descriptor, context) { var desc = {}; + Object["ke" + "ys"](descriptor).forEach(function(key) { desc[key] = descriptor[key]; }); desc.enumerable = !!desc.enumerable; desc.configurable = !!desc.configurable; - if ("value" in desc || desc.initializer) { - desc.writable = true; - } + + if ("value" in desc || desc.initializer) desc.writable = true; desc = decorators.slice().reverse().reduce(function(desc, decorator) { return decorator ? decorator(target, property, desc) || desc : desc; }, desc); + var hasAccessor = Object.prototype.hasOwnProperty.call(desc, "get") || Object.prototype.hasOwnProperty.call(desc, "set"); + if (context && desc.initializer !== void 0 && !hasAccessor) { desc.value = desc.initializer ? desc.initializer.call(context) : void 0; desc.initializer = undefined; @@ -25,5 +36,17 @@ function _apply_decorated_descriptor(target, property, decorators, descriptor, c Object["define" + "Property"](target, property, desc); desc = null; } + return desc; } +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000000001), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_apply_decs_2203_r.rs similarity index 71% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_apply_decs_2203_r.rs index 6e898d16a..b5453f0e4 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_apply_decs_2203_r.rs @@ -1,4 +1,13 @@ -/* @minVersion 7.20.0 */ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::apply_decs_2203_r, + local: "_apply_decs_2203_r", + import_path: "@swc/helpers/_/_apply_decs_2203_r", + #[cfg(feature = "inline-helpers")] + source: r##"/* @minVersion 7.20.0 */ /** Enums are used in this file, but not assigned to vars to avoid non-hoistable values @@ -18,7 +27,7 @@ CLASS = 10; // only used in assertValidReturnValue */ -function applyDecs2203RFactory() { +function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) { function createAddInitializerMethod(initializers, decoratorFinishedRef) { return function addInitializer(initializer) { assertNotFinished(decoratorFinishedRef, "addInitializer"); @@ -27,17 +36,7 @@ function applyDecs2203RFactory() { }; } - function memberDec( - dec, - name, - desc, - initializers, - kind, - isStatic, - isPrivate, - metadata, - value - ) { + function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) { var kindStr; switch (kind) { @@ -57,20 +56,11 @@ function applyDecs2203RFactory() { kindStr = "field"; } - var ctx = { - kind: kindStr, - name: isPrivate ? "#" + name : name, - static: isStatic, - private: isPrivate, - metadata: metadata, - }; + var ctx = { kind: kindStr, name: isPrivate ? "#" + name : name, static: isStatic, private: isPrivate, metadata: metadata }; var decoratorFinishedRef = { v: false }; - ctx.addInitializer = createAddInitializerMethod( - initializers, - decoratorFinishedRef - ); + ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef); var get, set; if (kind === 0 /* FIELD */) { @@ -78,27 +68,27 @@ function applyDecs2203RFactory() { get = desc.get; set = desc.set; } else { - get = function () { + get = function() { return this[name]; }; - set = function (v) { + set = function(v) { this[name] = v; }; } } else if (kind === 2 /* METHOD */) { - get = function () { + get = function() { return desc.value; }; } else { // replace with values that will go through the final getter and setter if (kind === 1 /* ACCESSOR */ || kind === 3 /* GETTER */) { - get = function () { + get = function() { return desc.get.call(this); }; } if (kind === 1 /* ACCESSOR */ || kind === 4 /* SETTER */) { - set = function (v) { + set = function(v) { desc.set.call(this, v); }; } @@ -106,7 +96,7 @@ function applyDecs2203RFactory() { if (get) { var originalGet = get; - get = function (target) { + get = function(target) { if (arguments.length === 0) { target = this; } @@ -116,7 +106,7 @@ function applyDecs2203RFactory() { if (set) { var originalSet = set; - set = function (target, value) { + set = function(target, value) { if (arguments.length === 1) { value = target; target = this; @@ -126,18 +116,12 @@ function applyDecs2203RFactory() { } if (isPrivate) { - ctx.access = - get && set ? { get: get, set: set } : get ? { get: get } : { set: set }; + ctx.access = get && set ? { get: get, set: set } : get ? { get: get } : { set: set }; } else { - var has = function (target) { + var has = function(target) { return name in target; }; - ctx.access = - get && set - ? { has: has, get: get, set: set } - : get - ? { has: has, get: get } - : { has: has, set: set }; + ctx.access = get && set ? { has: has, get: get, set: set } : get ? { has: has, get: get } : { has: has, set: set }; } var newValue = dec(value, ctx); @@ -147,9 +131,7 @@ function applyDecs2203RFactory() { function assertNotFinished(decoratorFinishedRef, fnName) { if (decoratorFinishedRef.v) { - throw new Error( - "attempted to call " + fnName + " after decoration was finished" - ); + throw new Error("attempted to call " + fnName + " after decoration was finished"); } } @@ -164,9 +146,7 @@ function applyDecs2203RFactory() { if (kind === 1 /* ACCESSOR */) { if (type !== "object" || value === null) { - throw new TypeError( - "accessor decorators must return an object with get, set, or init properties or void 0" - ); + throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0"); } if (value.get !== undefined) { assertCallable(value.get, "accessor.get"); @@ -186,55 +166,31 @@ function applyDecs2203RFactory() { } else { hint = "method"; } - throw new TypeError( - hint + " decorators must return a function or void 0" - ); + throw new TypeError(hint + " decorators must return a function or void 0"); } } - function applyMemberDec( - ret, - base, - decInfo, - name, - kind, - isStatic, - isPrivate, - initializers, - metadata - ) { + function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) { var decs = decInfo[0]; var desc, init, value; if (isPrivate) { if (kind === 0 /* FIELD */ || kind === 1 /* ACCESSOR */) { - desc = { - get: decInfo[3], - set: decInfo[4], - }; + desc = { get: decInfo[3], set: decInfo[4] }; } else if (kind === 3 /* GETTER */) { - desc = { - get: decInfo[3], - }; + desc = { get: decInfo[3] }; } else if (kind === 4 /* SETTER */) { - desc = { - set: decInfo[3], - }; + desc = { set: decInfo[3] }; } else { - desc = { - value: decInfo[3], - }; + desc = { value: decInfo[3] }; } } else if (kind !== 0 /* FIELD */) { desc = Object.getOwnPropertyDescriptor(base, name); } if (kind === 1 /* ACCESSOR */) { - value = { - get: desc.get, - set: desc.set, - }; + value = { get: desc.get, set: desc.set }; } else if (kind === 2 /* METHOD */) { value = desc.value; } else if (kind === 3 /* GETTER */) { @@ -246,17 +202,7 @@ function applyDecs2203RFactory() { var newValue, get, set; if (typeof decs === "function") { - newValue = memberDec( - decs, - name, - desc, - initializers, - kind, - isStatic, - isPrivate, - metadata, - value - ); + newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value); if (newValue !== void 0) { assertValidReturnValue(kind, newValue); @@ -277,17 +223,7 @@ function applyDecs2203RFactory() { for (var i = decs.length - 1; i >= 0; i--) { var dec = decs[i]; - newValue = memberDec( - dec, - name, - desc, - initializers, - kind, - isStatic, - isPrivate, - metadata, - value - ); + newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value); if (newValue !== void 0) { assertValidReturnValue(kind, newValue); @@ -321,25 +257,23 @@ function applyDecs2203RFactory() { if (kind === 0 /* FIELD */ || kind === 1 /* ACCESSOR */) { if (init === void 0) { // If the initializer was void 0, sub in a dummy initializer - init = function (instance, init) { + init = function(instance, init) { return init; }; } else if (typeof init !== "function") { var ownInitializers = init; - init = function (instance, init) { + init = function(instance, init) { var value = init; - for (var i = 0; i < ownInitializers.length; i++) { - value = ownInitializers[i].call(instance, value); - } + for (var i = 0; i < ownInitializers.length; i++) value = ownInitializers[i].call(instance, value); return value; }; } else { var originalInitializer = init; - init = function (instance, init) { + init = function(instance, init) { return originalInitializer.call(instance, init); }; } @@ -361,16 +295,16 @@ function applyDecs2203RFactory() { if (isPrivate) { if (kind === 1 /* ACCESSOR */) { - ret.push(function (instance, args) { + ret.push(function(instance, args) { return value.get.call(instance, args); }); - ret.push(function (instance, args) { + ret.push(function(instance, args) { return value.set.call(instance, args); }); } else if (kind === 2 /* METHOD */) { ret.push(value); } else { - ret.push(function (instance, args) { + ret.push(function(instance, args) { return value.call(instance, args); }); } @@ -416,20 +350,14 @@ function applyDecs2203RFactory() { } if (kind !== 0 /* FIELD */ && !isPrivate) { - var existingNonFields = isStatic - ? existingStaticNonFields - : existingProtoNonFields; + var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields; var existingKind = existingNonFields.get(name) || 0; - if ( - existingKind === true || - (existingKind === 3 /* GETTER */ && kind !== 4) /* SETTER */ || - (existingKind === 4 /* SETTER */ && kind !== 3) /* GETTER */ - ) { + if (existingKind === true || (existingKind === 3 /* GETTER */ && kind !== 4) /* SETTER */ || (existingKind === 4 /* SETTER */ && kind !== 3) /* GETTER */) { throw new Error( - "Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + - name + "Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + + name ); } else if (!existingKind && kind > 2 /* METHOD */) { existingNonFields.set(name, kind); @@ -438,17 +366,7 @@ function applyDecs2203RFactory() { } } - applyMemberDec( - ret, - base, - decInfo, - name, - kind, - isStatic, - isPrivate, - initializers, - metadata - ); + applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata); } pushInitializers(ret, protoInitializers); @@ -458,10 +376,8 @@ function applyDecs2203RFactory() { function pushInitializers(ret, initializers) { if (initializers) { - ret.push(function (instance) { - for (var i = 0; i < initializers.length; i++) { - initializers[i].call(instance); - } + ret.push(function(instance) { + for (var i = 0; i < initializers.length; i++) initializers[i].call(instance); return instance; }); } @@ -476,47 +392,30 @@ function applyDecs2203RFactory() { for (var i = classDecs.length - 1; i >= 0; i--) { var decoratorFinishedRef = { v: false }; - var nextNewClass = classDecs[i](newClass, { - kind: "class", - name: name, - addInitializer: createAddInitializerMethod( - initializers, - decoratorFinishedRef - ), - metadata, - }); + var nextNewClass = classDecs[i](newClass, { kind: "class", name: name, addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef), metadata }); decoratorFinishedRef.v = true; if (nextNewClass !== undefined) { - assertValidReturnValue(10 /* CLASS */, nextNewClass); + assertValidReturnValue(10, /* CLASS */ nextNewClass); newClass = nextNewClass; } } - return [ - defineMetadata(newClass, metadata), - function () { - for (var i = 0; i < initializers.length; i++) { - initializers[i].call(newClass); - } - }, - ]; + return [defineMetadata(newClass, metadata), function() { + for (var i = 0; i < initializers.length; i++) initializers[i].call(newClass); + }]; } // The transformer will not emit assignment when there are no class decorators, // so we don't have to return an empty array here. } function defineMetadata(Class, metadata) { - return Object.defineProperty( - Class, - Symbol.metadata || Symbol.for("Symbol.metadata"), - { configurable: true, enumerable: true, value: metadata } - ); + return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), { configurable: true, enumerable: true, value: metadata }); } /** Basic usage: - + applyDecs( Class, [ @@ -534,59 +433,59 @@ function applyDecs2203RFactory() { ] ) ``` - + Fully transpiled example: - + ```js @dec class Class { @dec a = 123; - + @dec #a = 123; - + @dec @dec2 accessor b = 123; - + @dec accessor #b = 123; - + @dec c() { console.log('c'); } - + @dec #c() { console.log('privC'); } - + @dec get d() { console.log('d'); } - + @dec get #d() { console.log('privD'); } - + @dec set e(v) { console.log('e'); } - + @dec set #e(v) { console.log('privE'); } } - - + + // becomes let initializeInstance; let initializeClass; - + let initA; let initPrivA; - + let initB; let initPrivB, getPrivB, setPrivB; - + let privC; let privD; let privE; - + let Class; class _Class { static { @@ -608,66 +507,63 @@ function applyDecs2203RFactory() { dec ] ) - + initA = ret[0]; - + initPrivA = ret[1]; - + initB = ret[2]; - + initPrivB = ret[3]; getPrivB = ret[4]; setPrivB = ret[5]; - + privC = ret[6]; - + privD = ret[7]; - + privE = ret[8]; - + initializeInstance = ret[9]; - + Class = ret[10] - + initializeClass = ret[11]; } - + a = (initializeInstance(this), initA(this, 123)); - + #a = initPrivA(this, 123); - + #bData = initB(this, 123); get b() { return this.#bData } set b(v) { this.#bData = v } - + #privBData = initPrivB(this, 123); get #b() { return getPrivB(this); } set #b(v) { setPrivB(this, v); } - + c() { console.log('c'); } - + #c(...args) { return privC(this, ...args) } - + get d() { console.log('d'); } - + get #d() { return privD(this); } - + set e(v) { console.log('e'); } - + set #e(v) { privE(this, v); } } - + initializeClass(Class); */ - return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) { + _apply_decs_2203_r = function(targetClass, memberDecs, classDecs, parentClass) { if (parentClass !== void 0) { - var parentMetadata = - parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")]; + var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")]; } - var metadata = Object.create( - parentMetadata === void 0 ? null : parentMetadata - ); + var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata); var e = applyMemberDecs(targetClass, memberDecs, metadata); if (!classDecs.length) defineMetadata(targetClass, metadata); return { @@ -675,16 +571,20 @@ function applyDecs2203RFactory() { // Lazily apply class decorations so that member init locals can be properly bound. get c() { return applyClassDecs(targetClass, classDecs, metadata); - }, + } }; }; -} -function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) { - return (_apply_decs_2203_r = applyDecs2203RFactory())( - targetClass, - memberDecs, - classDecs, - parentClass - ); + return _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass); +} +"##, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000000002), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS } diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2311.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_apply_decs_2311.rs similarity index 61% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2311.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_apply_decs_2311.rs index fe647d209..e1b9995d8 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2311.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_apply_decs_2311.rs @@ -1,4 +1,13 @@ -/* @minVersion 7.24.0 */ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::apply_decs_2311, + local: "_apply_decs_2311", + import_path: "@swc/helpers/_/_apply_decs_2311", + #[cfg(feature = "inline-helpers")] + source: r##"/* @minVersion 7.24.0 */ function toPrimitive(input, hint) { if (typeof input !== "object" || input === null) { @@ -24,10 +33,7 @@ function toPropertyKey(arg) { function checkInRHS(value) { if (Object(value) !== value) { - throw TypeError( - "right-hand side of 'in' should be an object, got " + - (value !== null ? typeof value : "null") - ); + throw TypeError("right-hand side of 'in' should be an object, got " + (value !== null ? typeof value : "null")); } return value; @@ -40,10 +46,7 @@ function setFunctionName(fn, name, prefix) { } try { - Object.defineProperty(fn, "name", { - configurable: true, - value: prefix ? prefix + " " + name : name, - }); + Object.defineProperty(fn, "name", { configurable: true, value: prefix ? prefix + " " + name : name }); } catch (_) {} return fn; @@ -62,14 +65,7 @@ function setFunctionName(fn, name, prefix) { STATIC = 8 DECORATORS_HAVE_THIS = 16 */ -function _apply_decs_2311( - targetClass, - classDecs, - memberDecs, - classDecsHaveThis, - instanceBrand, - parentClass -) { +function _apply_decs_2311(targetClass, classDecs, memberDecs, classDecsHaveThis, instanceBrand, parentClass) { var symbolMetadata = Symbol.metadata || Symbol.for("Symbol.metadata"); var defineProperty = Object.defineProperty; var create = Object.create; @@ -79,15 +75,13 @@ function _apply_decs_2311( var _; function createRunInitializers(initializers, useStaticThis, hasValue) { - return function (thisArg, value) { + return function(thisArg, value) { if (useStaticThis) { value = thisArg; thisArg = targetClass; } - for (var i = 0; i < initializers.length; i++) { - value = initializers[i].apply(thisArg, hasValue ? [value] : []); - } + for (var i = 0; i < initializers.length; i++) value = initializers[i].apply(thisArg, hasValue ? [value] : []); return hasValue ? value : thisArg; }; @@ -96,37 +90,17 @@ function _apply_decs_2311( function assertCallable(fn, hint1, hint2, throwUndefined) { if (typeof fn !== "function") { if (throwUndefined || fn !== void 0) { - throw new TypeError( - hint1 + - " must " + - (hint2 || "be") + - " a function" + - (throwUndefined ? "" : " or undefined") - ); + throw new TypeError(hint1 + " must " + (hint2 || "be") + " a function" + (throwUndefined ? "" : " or undefined")); } } return fn; } - function applyDec( - Class, - decInfo, - decoratorsHaveThis, - name, - kind, - initializers, - ret, - isStatic, - isPrivate, - isField, - hasPrivateBrand - ) { + function applyDec(Class, decInfo, decoratorsHaveThis, name, kind, initializers, ret, isStatic, isPrivate, isField, hasPrivateBrand) { function assertInstanceIfPrivate(target) { if (!hasPrivateBrand(target)) { - throw new TypeError( - "Attempted to access private element on non-instance" - ); + throw new TypeError("Attempted to access private element on non-instance"); } } @@ -140,7 +114,7 @@ function _apply_decs_2311( var isMethod = kind === 2; function bindPropCall(name, useStaticThis, before) { - return function (_this, value) { + return function(_this, value) { if (useStaticThis) { value = _this; _this = Class; @@ -163,15 +137,15 @@ function _apply_decs_2311( if (isField || isAccessor) { desc = { get: setFunctionName( - function () { + function() { return decVal(this); }, name, "get" ), - set: function (value) { + set: function(value) { decInfo[4](this, value); - }, + } }; } else { desc[key] = decVal; @@ -187,11 +161,7 @@ function _apply_decs_2311( if (!isField && !isPrivate) { _ = existingNonFields[+isStatic][name]; if (_ && (_ ^ kind) !== 7) { - throw new Error( - "Decorating two elements with the same name (" + - desc[key].name + - ") is not supported yet" - ); + throw new Error("Decorating two elements with the same name (" + desc[key].name + ") is not supported yet"); } existingNonFields[+isStatic][name] = kind < 3 ? 1 : kind; @@ -209,15 +179,14 @@ function _apply_decs_2311( kind: ["field", "accessor", "method", "getter", "setter", "class"][kind], name: name, metadata: metadata, - addInitializer: function (decoratorFinishedRef, initializer) { + addInitializer: function(decoratorFinishedRef, initializer) { if (decoratorFinishedRef.v) { - throw new TypeError( - "attempted to call addInitializer after decoration was finished" - ); + throw new TypeError("attempted to call addInitializer after decoration was finished"); } assertCallable(initializer, "An initializer", "be", true); initializers.push(initializer); - }.bind(null, decoratorFinishedRef), + } + .bind(null, decoratorFinishedRef) }; if (isClass) { @@ -233,44 +202,31 @@ function _apply_decs_2311( ctx.static = isStatic; ctx.private = isPrivate; _ = ctx.access = { - has: isPrivate - ? hasPrivateBrand.bind() - : function (target) { - return name in target; - }, + has: isPrivate ? hasPrivateBrand.bind() : function(target) { + return name in target; + } }; if (!isSetter) { _.get = isPrivate ? isMethod - ? function (_this) { - assertInstanceIfPrivate(_this); - return desc.value; - } + ? function(_this) { + assertInstanceIfPrivate(_this); + return desc.value; + } : bindPropCall("get", 0, assertInstanceIfPrivate) - : function (target) { - return target[name]; - }; + : function(target) { + return target[name]; + }; } if (!isMethod && !isGetter) { - _.set = isPrivate - ? bindPropCall("set", 0, assertInstanceIfPrivate) - : function (target, value) { - target[name] = value; - }; + _.set = isPrivate ? bindPropCall("set", 0, assertInstanceIfPrivate) : function(target, value) { + target[name] = value; + }; } - newValue = dec.call( - decThis, - isAccessor - ? { - get: desc.get, - set: desc.set, - } - : desc[key], - ctx - ); + newValue = dec.call(decThis, isAccessor ? { get: desc.get, set: desc.set } : desc[key], ctx); decoratorFinishedRef.v = 1; @@ -286,17 +242,9 @@ function _apply_decs_2311( init.unshift(_); } } else if (newValue !== void 0) { - throw new TypeError( - "accessor decorators must return an object with get, set, or init properties or undefined" - ); + throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } - } else if ( - assertCallable( - newValue, - (isField ? "field" : "method") + " decorators", - "return" - ) - ) { + } else if (assertCallable(newValue, (isField ? "field" : "method") + " decorators", "return")) { if (isField) { init.unshift(newValue); } else { @@ -306,21 +254,13 @@ function _apply_decs_2311( } if (kind < 2) { - ret.push( - createRunInitializers(init, isStatic, 1), - createRunInitializers(initializers, isStatic, 0) - ); + ret.push(createRunInitializers(init, isStatic, 1), createRunInitializers(initializers, isStatic, 0)); } if (!isField && !isClass) { if (isPrivate) { if (isAccessor) { - ret.splice( - -1, - 0, - bindPropCall("get", isStatic), - bindPropCall("set", isStatic) - ); + ret.splice(-1, 0, bindPropCall("get", isStatic), bindPropCall("set", isStatic)); } else { ret.push(isMethod ? desc[key] : assertCallable.call.bind(desc[key])); } @@ -337,13 +277,13 @@ function _apply_decs_2311( var protoInitializers; var staticInitializers; - var pushInitializers = function (initializers) { + var pushInitializers = function(initializers) { if (initializers) { ret.push(createRunInitializers(initializers)); } }; - var applyMemberDecsOfKind = function (isStatic, isField) { + var applyMemberDecsOfKind = function(isStatic, isField) { for (var i = 0; i < memberDecs.length; i++) { var decInfo = memberDecs[i]; var kind = decInfo[1]; @@ -360,19 +300,15 @@ function _apply_decs_2311( decoratorsHaveThis, isPrivate ? "#" + name : toPropertyKey(name), kindOnly, - kindOnly < 2 - ? [] - : isStatic - ? (staticInitializers = staticInitializers || []) - : (protoInitializers = protoInitializers || []), + kindOnly < 2 ? [] : isStatic ? (staticInitializers = staticInitializers || []) : (protoInitializers = protoInitializers || []), ret, !!isStatic, isPrivate, isField, isStatic && isPrivate - ? function (_) { - return checkInRHS(_) === targetClass; - } + ? function(_) { + return checkInRHS(_) === targetClass; + } : instanceBrand ); } @@ -391,11 +327,7 @@ function _apply_decs_2311( } function defineMetadata(Class) { - return defineProperty(Class, symbolMetadata, { - configurable: true, - enumerable: true, - value: metadata, - }); + return defineProperty(Class, symbolMetadata, { configurable: true, enumerable: true, value: metadata }); } if (parentClass !== undefined) { @@ -413,21 +345,18 @@ function _apply_decs_2311( e: _, get c() { var initializers = []; - return ( - hasClassDecs && [ - defineMetadata( - (targetClass = applyDec( - targetClass, - [classDecs], - classDecsHaveThis, - targetClass.name, - 5, - initializers - )) - ), - createRunInitializers(initializers, 1), - ] - ); - }, + return (hasClassDecs && [defineMetadata(targetClass = applyDec(targetClass, [classDecs], classDecsHaveThis, targetClass.name, 5, initializers)), createRunInitializers(initializers, 1)]); + } }; } +"##, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000000004), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_array_like_to_array.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_array_like_to_array.rs new file mode 100644 index 000000000..2d9b49658 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_array_like_to_array.rs @@ -0,0 +1,27 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::array_like_to_array, + local: "_array_like_to_array", + import_path: "@swc/helpers/_/_array_like_to_array", + #[cfg(feature = "inline-helpers")] + source: r#"function _array_like_to_array(arr, len) { + if (len == null || len > arr.length) len = arr.length; + + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + + return arr2; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000000008), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_array_with_holes.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_array_with_holes.rs new file mode 100644 index 000000000..41be758d0 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_array_with_holes.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::array_with_holes, + local: "_array_with_holes", + import_path: "@swc/helpers/_/_array_with_holes", + #[cfg(feature = "inline-helpers")] + source: r#"function _array_with_holes(arr) { + if (Array.isArray(arr)) return arr; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000000010), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_array_without_holes.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_array_without_holes.rs new file mode 100644 index 000000000..b16a9bf13 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_array_without_holes.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::array_without_holes, + local: "_array_without_holes", + import_path: "@swc/helpers/_/_array_without_holes", + #[cfg(feature = "inline-helpers")] + source: r#"function _array_without_holes(arr) { + if (Array.isArray(arr)) return _array_like_to_array(arr); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000000028), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_assert_this_initialized.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_assert_this_initialized.rs new file mode 100644 index 000000000..5fc9b0ece --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_assert_this_initialized.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::assert_this_initialized, + local: "_assert_this_initialized", + import_path: "@swc/helpers/_/_assert_this_initialized", + #[cfg(feature = "inline-helpers")] + source: r#"function _assert_this_initialized(self) { + if (self === void 0) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + + return self; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000000040), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_generator.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_generator.rs similarity index 74% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_generator.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_generator.rs index 69d23f2db..b2b775077 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_generator.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_generator.rs @@ -1,5 +1,15 @@ -function _async_generator(gen) { +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::async_generator, + local: "_async_generator", + import_path: "@swc/helpers/_/_async_generator", + #[cfg(feature = "inline-helpers")] + source: r#"function _async_generator(gen) { var front, back; + function send(key, arg) { return new Promise(function(resolve, reject) { var request = { key: key, arg: arg, resolve: resolve, reject: reject, next: null }; @@ -10,6 +20,7 @@ function _async_generator(gen) { } }); } + function resume(key, arg) { try { var result = gen[key](arg); @@ -29,6 +40,7 @@ function _async_generator(gen) { settle("throw", err); } } + function settle(type, value) { switch (type) { case "return": @@ -47,17 +59,33 @@ function _async_generator(gen) { } this._invoke = send; + if (typeof gen.return !== "function") this.return = undefined; } + _async_generator.prototype[(typeof Symbol === "function" && Symbol.asyncIterator) || "@@asyncIterator"] = function() { return this; }; + _async_generator.prototype.next = function(arg) { return this._invoke("next", arg); }; + _async_generator.prototype.throw = function(arg) { return this._invoke("throw", arg); }; + _async_generator.prototype.return = function(arg) { return this._invoke("return", arg); }; +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000002000000000000000080), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_generator_delegate.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_generator_delegate.rs similarity index 58% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_generator_delegate.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_generator_delegate.rs index b05d51506..ac7d80cac 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_generator_delegate.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_generator_delegate.rs @@ -1,28 +1,45 @@ -function _async_generator_delegate(inner) { +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::async_generator_delegate, + local: "_async_generator_delegate", + import_path: "@swc/helpers/_/_async_generator_delegate", + #[cfg(feature = "inline-helpers")] + source: r#"function _async_generator_delegate(inner) { var iter = {}, waiting = false; + function pump(key, value) { waiting = true; value = new Promise(function(resolve) { resolve(inner[key](value)); }); + return { done: false, value: new _overload_yield(value, /* kind: delegate */ 1) }; } + iter[(typeof Symbol !== "undefined" && Symbol.iterator) || "@@iterator"] = function() { return this; }; + iter.next = function(value) { if (waiting) { waiting = false; + return value; } + return pump("next", value); }; + if (typeof inner.throw === "function") { iter.throw = function(value) { if (waiting) { waiting = false; throw value; } + return pump("throw", value); }; } @@ -35,5 +52,17 @@ function _async_generator_delegate(inner) { return pump("return", value); }; } + return iter; } +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000002000000000000000100), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_iterator.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_iterator.rs similarity index 63% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_iterator.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_iterator.rs index afc18a37e..1be99010d 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_async_iterator.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_iterator.rs @@ -1,4 +1,13 @@ -function _async_iterator(iterable) { +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::async_iterator, + local: "_async_iterator", + import_path: "@swc/helpers/_/_async_iterator", + #[cfg(feature = "inline-helpers")] + source: r#"function _async_iterator(iterable) { var method, async, sync, retry = 2; for ("undefined" != typeof Symbol && (async = Symbol.asyncIterator, sync = Symbol.iterator); retry--;) { if (async && null != (method = iterable[async])) return method.call(iterable); @@ -10,30 +19,45 @@ function _async_iterator(iterable) { function AsyncFromSyncIterator(s) { function AsyncFromSyncIteratorContinuation(r) { if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object.")); + var done = r.done; + return Promise.resolve(r.value).then(function(value) { return { value: value, done: done }; }); } + return AsyncFromSyncIterator = function(s) { this.s = s, this.n = s.next; }, AsyncFromSyncIterator.prototype = { s: null, n: null, + next: function() { return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments)); }, return: function(value) { var ret = this.s.return; - return void 0 === ret - ? Promise.resolve({ value: value, done: !0 }) - : AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments)); + + return void 0 === ret ? Promise.resolve({ value: value, done: !0 }) : AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments)); }, throw: function(value) { var thr = this.s.return; + return void 0 === thr ? Promise.reject(value) : AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments)); } }, new AsyncFromSyncIterator(s); } +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000000200), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_to_generator.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_to_generator.rs new file mode 100644 index 000000000..a44d29d4a --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_async_to_generator.rs @@ -0,0 +1,50 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::async_to_generator, + local: "_async_to_generator", + import_path: "@swc/helpers/_/_async_to_generator", + #[cfg(feature = "inline-helpers")] + source: r#"function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + if (info.done) resolve(value); + else Promise.resolve(value).then(_next, _throw); +} +function _async_to_generator(fn) { + return function() { + var self = this, args = arguments; + + return new Promise(function(resolve, reject) { + var gen = fn.apply(self, args); + + function _next(value) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); + } + + function _throw(err) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); + } + + _next(undefined); + }); + }; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000000400), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_await_async_generator.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_await_async_generator.rs new file mode 100644 index 000000000..d8ca6e880 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_await_async_generator.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::await_async_generator, + local: "_await_async_generator", + import_path: "@swc/helpers/_/_await_async_generator", + #[cfg(feature = "inline-helpers")] + source: r#"function _await_async_generator(value) { + return new _overload_yield(value, /* kind: await */ 0); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000002000000000000000800), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_await_value.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_await_value.rs new file mode 100644 index 000000000..6db475d65 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_await_value.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::await_value, + local: "_await_value", + import_path: "@swc/helpers/_/_await_value", + #[cfg(feature = "inline-helpers")] + source: r#"function _await_value(value) { + this.wrapped = value; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000001000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_call_super.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_call_super.rs new file mode 100644 index 000000000..e65c97bc7 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_call_super.rs @@ -0,0 +1,31 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::call_super, + local: "_call_super", + import_path: "@swc/helpers/_/_call_super", + #[cfg(feature = "inline-helpers")] + source: r#"function _call_super(_this, derived, args) { + // Super + derived = _get_prototype_of(derived); + return _possible_constructor_return( + _this, + _is_native_reflect_construct() + // NOTE: This doesn't work if this.__proto__.constructor has been modified. + ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) + : derived.apply(_this, args) + ); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000002000004002008000000002040), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_check_private_redeclaration.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_check_private_redeclaration.rs new file mode 100644 index 000000000..533df06a4 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_check_private_redeclaration.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::check_private_redeclaration, + local: "_check_private_redeclaration", + import_path: "@swc/helpers/_/_check_private_redeclaration", + #[cfg(feature = "inline-helpers")] + source: r#"function _check_private_redeclaration(obj, privateCollection) { + if (privateCollection.has(obj)) { + throw new TypeError("Cannot initialize the same private elements twice on an object"); + } +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000004000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_destructure.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_destructure.rs new file mode 100644 index 000000000..40a56ef44 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_destructure.rs @@ -0,0 +1,42 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_apply_descriptor_destructure, + local: "_class_apply_descriptor_destructure", + import_path: "@swc/helpers/_/_class_apply_descriptor_destructure", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_apply_descriptor_destructure(receiver, descriptor) { + if (descriptor.set) { + if (!("__destrObj" in descriptor)) { + descriptor.__destrObj = { + set value(v) { + descriptor.set.call(receiver, v); + } + }; + } + + return descriptor.__destrObj; + } else { + if (!descriptor.writable) { + // This should only throw in strict mode, but class bodies are + // always strict and private fields can only be used inside + // class bodies. + throw new TypeError("attempted to set read only private field"); + } + + return descriptor; + } +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000008000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_get.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_get.rs new file mode 100644 index 000000000..8d27d904f --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_get.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_apply_descriptor_get, + local: "_class_apply_descriptor_get", + import_path: "@swc/helpers/_/_class_apply_descriptor_get", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_apply_descriptor_get(receiver, descriptor) { + if (descriptor.get) return descriptor.get.call(receiver); + + return descriptor.value; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000010000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_set.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_set.rs new file mode 100644 index 000000000..e05d1e9d0 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_set.rs @@ -0,0 +1,32 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_apply_descriptor_set, + local: "_class_apply_descriptor_set", + import_path: "@swc/helpers/_/_class_apply_descriptor_set", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_apply_descriptor_set(receiver, descriptor, value) { + if (descriptor.set) descriptor.set.call(receiver, value); + else { + if (!descriptor.writable) { + // This should only throw in strict mode, but class bodies are + // always strict and private fields can only be used inside + // class bodies. + throw new TypeError("attempted to set read only private field"); + } + descriptor.value = value; + } +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000020000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_update.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_update.rs new file mode 100644 index 000000000..f343c8b1c --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_apply_descriptor_update.rs @@ -0,0 +1,47 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_apply_descriptor_update, + local: "_class_apply_descriptor_update", + import_path: "@swc/helpers/_/_class_apply_descriptor_update", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_apply_descriptor_update(receiver, descriptor) { + if (descriptor.set) { + if (!descriptor.get) throw new TypeError("attempted to read set only private field"); + + if (!("__destrWrapper" in descriptor)) { + descriptor.__destrWrapper = { + set value(v) { + descriptor.set.call(receiver, v); + }, + get value() { + return descriptor.get.call(receiver); + } + }; + } + + return descriptor.__destrWrapper; + } else { + if (!descriptor.writable) { + // This should only throw in strict mode, but class bodies are + // always strict and private fields can only be used inside + // class bodies. + throw new TypeError("attempted to set read only private field"); + } + + return descriptor; + } +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000040000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_call_check.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_call_check.rs new file mode 100644 index 000000000..635c99335 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_call_check.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_call_check, + local: "_class_call_check", + import_path: "@swc/helpers/_/_class_call_check", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_call_check(instance, Constructor) { + if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000080000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_check_private_static_access.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_check_private_static_access.rs new file mode 100644 index 000000000..e9821f569 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_check_private_static_access.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_check_private_static_access, + local: "_class_check_private_static_access", + import_path: "@swc/helpers/_/_class_check_private_static_access", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_check_private_static_access(receiver, classConstructor) { + if (receiver !== classConstructor) throw new TypeError("Private static access of wrong provenance"); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000100000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_check_private_static_field_descriptor.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_check_private_static_field_descriptor.rs new file mode 100644 index 000000000..429c45682 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_check_private_static_field_descriptor.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_check_private_static_field_descriptor, + local: "_class_check_private_static_field_descriptor", + import_path: "@swc/helpers/_/_class_check_private_static_field_descriptor", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_check_private_static_field_descriptor(descriptor, action) { + if (descriptor === undefined) { + throw new TypeError("attempted to " + action + " private static field before its declaration"); + } +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000200000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_extract_field_descriptor.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_extract_field_descriptor.rs new file mode 100644 index 000000000..3f1d71657 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_extract_field_descriptor.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_extract_field_descriptor, + local: "_class_extract_field_descriptor", + import_path: "@swc/helpers/_/_class_extract_field_descriptor", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_extract_field_descriptor(receiver, privateMap, action) { + if (!privateMap.has(receiver)) throw new TypeError("attempted to " + action + " private field on non-instance"); + + return privateMap.get(receiver); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000400000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_name_tdz_error.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_name_tdz_error.rs new file mode 100644 index 000000000..b3aa4f304 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_name_tdz_error.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_name_tdz_error, + local: "_class_name_tdz_error", + import_path: "@swc/helpers/_/_class_name_tdz_error", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_name_tdz_error(name) { + throw new ReferenceError("Class \"" + name + "\" cannot be referenced in computed property keys."); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000000800000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_destructure.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_destructure.rs new file mode 100644 index 000000000..92c7cd2c6 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_destructure.rs @@ -0,0 +1,24 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_private_field_destructure, + local: "_class_private_field_destructure", + import_path: "@swc/helpers/_/_class_private_field_destructure", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_private_field_destructure(receiver, privateMap) { + var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set"); + return _class_apply_descriptor_destructure(receiver, descriptor); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000001408000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_get.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_get.rs new file mode 100644 index 000000000..71f2e7fed --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_get.rs @@ -0,0 +1,24 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_private_field_get, + local: "_class_private_field_get", + import_path: "@swc/helpers/_/_class_private_field_get", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_private_field_get(receiver, privateMap) { + var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get"); + return _class_apply_descriptor_get(receiver, descriptor); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000002410000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_init.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_init.rs new file mode 100644 index 000000000..efa57ec1a --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_init.rs @@ -0,0 +1,24 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_private_field_init, + local: "_class_private_field_init", + import_path: "@swc/helpers/_/_class_private_field_init", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_private_field_init(obj, privateMap, value) { + _check_private_redeclaration(obj, privateMap); + privateMap.set(obj, value); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000004004000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_loose_base.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_loose_base.rs new file mode 100644 index 000000000..bef81e7de --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_loose_base.rs @@ -0,0 +1,27 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_private_field_loose_base, + local: "_class_private_field_loose_base", + import_path: "@swc/helpers/_/_class_private_field_loose_base", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_private_field_loose_base(receiver, privateKey) { + if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { + throw new TypeError("attempted to use private field on non-instance"); + } + + return receiver; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000008000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_loose_key.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_loose_key.rs new file mode 100644 index 000000000..468b10d8c --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_loose_key.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_private_field_loose_key, + local: "_class_private_field_loose_key", + import_path: "@swc/helpers/_/_class_private_field_loose_key", + #[cfg(feature = "inline-helpers")] + source: r#"var id = 0; + +function _class_private_field_loose_key(name) { + return "__private_" + id++ + "_" + name; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000010000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_set.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_set.rs new file mode 100644 index 000000000..0c6ab27bf --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_set.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_private_field_set, + local: "_class_private_field_set", + import_path: "@swc/helpers/_/_class_private_field_set", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_private_field_set(receiver, privateMap, value) { + var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set"); + _class_apply_descriptor_set(receiver, descriptor, value); + return value; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000020420000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_update.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_update.rs new file mode 100644 index 000000000..f9b4f2103 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_field_update.rs @@ -0,0 +1,24 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_private_field_update, + local: "_class_private_field_update", + import_path: "@swc/helpers/_/_class_private_field_update", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_private_field_update(receiver, privateMap) { + var descriptor = _class_extract_field_descriptor(receiver, privateMap, "update"); + return _class_apply_descriptor_update(receiver, descriptor); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000040440000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_method_get.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_method_get.rs new file mode 100644 index 000000000..7d4552e5a --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_method_get.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_private_method_get, + local: "_class_private_method_get", + import_path: "@swc/helpers/_/_class_private_method_get", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_private_method_get(receiver, privateSet, fn) { + if (!privateSet.has(receiver)) throw new TypeError("attempted to get private field on non-instance"); + + return fn; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000080000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_method_init.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_method_init.rs new file mode 100644 index 000000000..52440ca9a --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_method_init.rs @@ -0,0 +1,24 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_private_method_init, + local: "_class_private_method_init", + import_path: "@swc/helpers/_/_class_private_method_init", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_private_method_init(obj, privateSet) { + _check_private_redeclaration(obj, privateSet); + privateSet.add(obj); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000100004000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_method_set.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_method_set.rs new file mode 100644 index 000000000..d260aa836 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_private_method_set.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_private_method_set, + local: "_class_private_method_set", + import_path: "@swc/helpers/_/_class_private_method_set", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_private_method_set() { + throw new TypeError("attempted to reassign private method"); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000200000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_static_private_field_destructure.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_static_private_field_destructure.rs new file mode 100644 index 000000000..8e0cdfd2d --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_static_private_field_destructure.rs @@ -0,0 +1,26 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_static_private_field_destructure, + local: "_class_static_private_field_destructure", + import_path: "@swc/helpers/_/_class_static_private_field_destructure", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_static_private_field_destructure(receiver, classConstructor, descriptor) { + _class_check_private_static_access(receiver, classConstructor); + _class_check_private_static_field_descriptor(descriptor, "set"); + + return _class_apply_descriptor_destructure(receiver, descriptor); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000000400308000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_static_private_field_update.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_static_private_field_update.rs new file mode 100644 index 000000000..be4522715 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_static_private_field_update.rs @@ -0,0 +1,26 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_static_private_field_update, + local: "_class_static_private_field_update", + import_path: "@swc/helpers/_/_class_static_private_field_update", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_static_private_field_update(receiver, classConstructor, descriptor) { + _class_check_private_static_access(receiver, classConstructor); + _class_check_private_static_field_descriptor(descriptor, "update"); + + return _class_apply_descriptor_update(receiver, descriptor); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000002000340000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_static_private_method_get.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_static_private_method_get.rs new file mode 100644 index 000000000..0e8b1852b --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_class_static_private_method_get.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::class_static_private_method_get, + local: "_class_static_private_method_get", + import_path: "@swc/helpers/_/_class_static_private_method_get", + #[cfg(feature = "inline-helpers")] + source: r#"function _class_static_private_method_get(receiver, classConstructor, method) { + _class_check_private_static_access(receiver, classConstructor); + + return method; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000004000100000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_construct.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_construct.rs new file mode 100644 index 000000000..e13784300 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_construct.rs @@ -0,0 +1,37 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::construct, + local: "_construct", + import_path: "@swc/helpers/_/_construct", + #[cfg(feature = "inline-helpers")] + source: r#"function _construct(Parent, args, Class) { + if (_is_native_reflect_construct()) _construct = Reflect.construct; + else { + _construct = function construct(Parent, args, Class) { + var a = [null]; + a.push.apply(a, args); + var Constructor = Function.bind.apply(Parent, a); + var instance = new Constructor(); + + if (Class) _set_prototype_of(instance, Class.prototype); + + return instance; + }; + } + + return _construct.apply(null, arguments); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000020002000008000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_create_class.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_create_class.rs new file mode 100644 index 000000000..035323145 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_create_class.rs @@ -0,0 +1,37 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::create_class, + local: "_create_class", + import_path: "@swc/helpers/_/_create_class", + #[cfg(feature = "inline-helpers")] + source: r#"function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + + if ("value" in descriptor) descriptor.writable = true; + + Object.defineProperty(target, descriptor.key, descriptor); + } +} +function _create_class(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + + return Constructor; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000010000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_create_for_of_iterator_helper_loose.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_create_for_of_iterator_helper_loose.rs new file mode 100644 index 000000000..543fb223e --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_create_for_of_iterator_helper_loose.rs @@ -0,0 +1,39 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::create_for_of_iterator_helper_loose, + local: "_create_for_of_iterator_helper_loose", + import_path: "@swc/helpers/_/_create_for_of_iterator_helper_loose", + #[cfg(feature = "inline-helpers")] + source: r#"function _create_for_of_iterator_helper_loose(o, allowArrayLike) { + var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; + + if (it) return (it = it.call(o)).next.bind(it); + // Fallback for engines without symbol support + if (Array.isArray(o) || (it = _unsupported_iterable_to_array(o)) || allowArrayLike && o && typeof o.length === "number") { + if (it) o = it; + + var i = 0; + + return function() { + if (i >= o.length) return { done: true }; + + return { done: false, value: o[i++] }; + }; + } + + throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000004000000000000020000000008), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_create_super.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_create_super.rs new file mode 100644 index 000000000..ad0745c64 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_create_super.rs @@ -0,0 +1,36 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::create_super, + local: "_create_super", + import_path: "@swc/helpers/_/_create_super", + #[cfg(feature = "inline-helpers")] + source: r#"function _create_super(Derived) { + var hasNativeReflectConstruct = _is_native_reflect_construct(); + + return function _createSuperInternal() { + var Super = _get_prototype_of(Derived), result; + + if (hasNativeReflectConstruct) { + var NewTarget = _get_prototype_of(this).constructor; + result = Reflect.construct(Super, arguments, NewTarget); + } else { + result = Super.apply(this, arguments); + } + + return _possible_constructor_return(this, result); + }; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000002000004002008040000000040), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_decorate.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_decorate.rs similarity index 75% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_decorate.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_decorate.rs index 16e0a58a9..a5811125d 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_decorate.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_decorate.rs @@ -1,50 +1,55 @@ -function _decorate(decorators, factory, superClass) { +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::decorate, + local: "_decorate", + import_path: "@swc/helpers/_/_decorate", + #[cfg(feature = "inline-helpers")] + source: r#"function _decorate(decorators, factory, superClass) { var r = factory(function initialize(O) { _initializeInstanceElements(O, decorated.elements); }, superClass); var decorated = _decorateClass(_coalesceClassElements(r.d.map(_createElementDescriptor)), decorators); _initializeClassElements(r.F, decorated.elements); + return _runClassFinishers(r.F, decorated.finishers); } function _createElementDescriptor(def) { var key = _to_property_key(def.key); var descriptor; + if (def.kind === "method") { descriptor = { value: def.value, writable: true, configurable: true, enumerable: false }; Object.defineProperty(def.value, "name", { value: _type_of(key) === "symbol" ? "" : key, configurable: true }); - } else if (def.kind === "get") { - descriptor = { get: def.value, configurable: true, enumerable: false }; - } else if (def.kind === "set") { - descriptor = { set: def.value, configurable: true, enumerable: false }; - } else if (def.kind === "field") { - descriptor = { configurable: true, writable: true, enumerable: true }; - } - var element = { - kind: def.kind === "field" ? "field" : "method", - key: key, - placement: def.static ? "static" : def.kind === "field" ? "own" : "prototype", - descriptor: descriptor - }; + } else if (def.kind === "get") descriptor = { get: def.value, configurable: true, enumerable: false }; + else if (def.kind === "set") descriptor = { set: def.value, configurable: true, enumerable: false }; + else if (def.kind === "field") descriptor = { configurable: true, writable: true, enumerable: true }; + + var element = { kind: def.kind === "field" ? "field" : "method", key: key, placement: def.static ? "static" : def.kind === "field" ? "own" : "prototype", descriptor: descriptor }; + if (def.decorators) element.decorators = def.decorators; + if (def.kind === "field") element.initializer = def.value; + return element; } function _coalesceGetterSetter(element, other) { - if (element.descriptor.get !== undefined) { - other.descriptor.get = element.descriptor.get; - } else { - other.descriptor.set = element.descriptor.set; - } + if (element.descriptor.get !== undefined) other.descriptor.get = element.descriptor.get; + else other.descriptor.set = element.descriptor.set; } function _coalesceClassElements(elements) { var newElements = []; var isSameElement = function isSameElement(other) { return other.kind === "method" && other.key === element.key && other.placement === element.placement; }; + for (var i = 0; i < elements.length; i++) { var element = elements[i]; var other; + if (element.kind === "method" && (other = newElements.find(isSameElement))) { if (_isDataDescriptor(element.descriptor) || _isDataDescriptor(other.descriptor)) { if (_hasDecorators(element) || _hasDecorators(other)) { @@ -54,9 +59,7 @@ function _coalesceClassElements(elements) { } else { if (_hasDecorators(element)) { if (_hasDecorators(other)) { - throw new ReferenceError( - "Decorators can't be placed on different accessors with for " + "the same property (" + element.key + ")." - ); + throw new ReferenceError("Decorators can't be placed on different accessors with for " + "the same property (" + element.key + ")."); } other.decorators = element.decorators; } @@ -66,6 +69,7 @@ function _coalesceClassElements(elements) { newElements.push(element); } } + return newElements; } function _hasDecorators(element) { @@ -89,9 +93,7 @@ function _initializeClassElements(F, elements) { function _initializeInstanceElements(O, elements) { ["method", "field"].forEach(function(kind) { elements.forEach(function(element) { - if (element.kind === kind && element.placement === "own") { - _defineClassElement(O, element); - } + if (element.kind === kind && element.placement === "own") _defineClassElement(O, element); }); }); } @@ -99,12 +101,7 @@ function _defineClassElement(receiver, element) { var descriptor = element.descriptor; if (element.kind === "field") { var initializer = element.initializer; - descriptor = { - enumerable: descriptor.enumerable, - writable: descriptor.writable, - configurable: descriptor.configurable, - value: initializer === void 0 ? void 0 : initializer.call(receiver) - }; + descriptor = { enumerable: descriptor.enumerable, writable: descriptor.writable, configurable: descriptor.configurable, value: initializer === void 0 ? void 0 : initializer.call(receiver) }; } Object.defineProperty(receiver, element.key, descriptor); } @@ -122,19 +119,16 @@ function _decorateClass(elements, decorators) { newElements.push.apply(newElements, elementFinishersExtras.extras); finishers.push.apply(finishers, elementFinishersExtras.finishers); }); - if (!decorators) { - return { elements: newElements, finishers: finishers }; - } + if (!decorators) return { elements: newElements, finishers: finishers }; var result = _decorateConstructor(newElements, decorators); finishers.push.apply(finishers, result.finishers); result.finishers = finishers; + return result; } function _addElementPlacement(element, placements, silent) { var keys = placements[element.placement]; - if (!silent && keys.indexOf(element.key) !== -1) { - throw new TypeError("Duplicated element (" + element.key + ")"); - } + if (!silent && keys.indexOf(element.key) !== -1) throw new TypeError("Duplicated element (" + element.key + ")"); keys.push(element.key); } function _decorateElement(element, placements) { @@ -147,17 +141,14 @@ function _decorateElement(element, placements) { var elementFinisherExtras = _toElementFinisherExtras((0, decorators[i])(elementObject) || elementObject); element = elementFinisherExtras.element; _addElementPlacement(element, placements); - if (elementFinisherExtras.finisher) { - finishers.push(elementFinisherExtras.finisher); - } + if (elementFinisherExtras.finisher) finishers.push(elementFinisherExtras.finisher); var newExtras = elementFinisherExtras.extras; if (newExtras) { - for (var j = 0; j < newExtras.length; j++) { - _addElementPlacement(newExtras[j], placements); - } + for (var j = 0; j < newExtras.length; j++) _addElementPlacement(newExtras[j], placements); extras.push.apply(extras, newExtras); } } + return { element: element, finishers: finishers, extras: extras }; } function _decorateConstructor(elements, decorators) { @@ -165,9 +156,7 @@ function _decorateConstructor(elements, decorators) { for (var i = decorators.length - 1; i >= 0; i--) { var obj = _fromClassDescriptor(elements); var elementsAndFinisher = _toClassDescriptor((0, decorators[i])(obj) || obj); - if (elementsAndFinisher.finisher !== undefined) { - finishers.push(elementsAndFinisher.finisher); - } + if (elementsAndFinisher.finisher !== undefined) finishers.push(elementsAndFinisher.finisher); if (elementsAndFinisher.elements !== undefined) { elements = elementsAndFinisher.elements; for (var j = 0; j < elements.length - 1; j++) { @@ -179,6 +168,7 @@ function _decorateConstructor(elements, decorators) { } } } + return { elements: elements, finishers: finishers }; } function _fromElementDescriptor(element) { @@ -186,65 +176,67 @@ function _fromElementDescriptor(element) { var desc = { value: "Descriptor", configurable: true }; Object.defineProperty(obj, Symbol.toStringTag, desc); if (element.kind === "field") obj.initializer = element.initializer; + return obj; } function _toElementDescriptors(elementObjects) { if (elementObjects === undefined) return; + return _to_array(elementObjects).map(function(elementObject) { var element = _toElementDescriptor(elementObject); _disallowProperty(elementObject, "finisher", "An element descriptor"); _disallowProperty(elementObject, "extras", "An element descriptor"); + return element; }); } function _toElementDescriptor(elementObject) { var kind = String(elementObject.kind); if (kind !== "method" && kind !== "field") { - throw new TypeError( - "An element descriptor's .kind property must be either \"method\" or" - + " \"field\", but a decorator created an element descriptor with" + " .kind \"" + kind + "\"" - ); + throw new TypeError("An element descriptor's .kind property must be either \"method\" or" + " \"field\", but a decorator created an element descriptor with" + " .kind \"" + kind + "\""); } var key = _to_property_key(elementObject.key); var placement = String(elementObject.placement); if (placement !== "static" && placement !== "prototype" && placement !== "own") { throw new TypeError( "An element descriptor's .placement property must be one of \"static\"," - + " \"prototype\" or \"own\", but a decorator created an element descriptor" + " with .placement \"" + placement + "\"" + + " \"prototype\" or \"own\", but a decorator created an element descriptor" + + " with .placement \"" + + placement + + "\"" ); } var descriptor = elementObject.descriptor; _disallowProperty(elementObject, "elements", "An element descriptor"); var element = { kind: kind, key: key, placement: placement, descriptor: Object.assign({}, descriptor) }; - if (kind !== "field") { - _disallowProperty(elementObject, "initializer", "A method descriptor"); - } else { + if (kind !== "field") _disallowProperty(elementObject, "initializer", "A method descriptor"); + else { _disallowProperty(descriptor, "get", "The property descriptor of a field descriptor"); _disallowProperty(descriptor, "set", "The property descriptor of a field descriptor"); _disallowProperty(descriptor, "value", "The property descriptor of a field descriptor"); element.initializer = elementObject.initializer; } + return element; } function _toElementFinisherExtras(elementObject) { var element = _toElementDescriptor(elementObject); var finisher = _optionalCallableProperty(elementObject, "finisher"); var extras = _toElementDescriptors(elementObject.extras); + return { element: element, finisher: finisher, extras: extras }; } function _fromClassDescriptor(elements) { var obj = { kind: "class", elements: elements.map(_fromElementDescriptor) }; var desc = { value: "Descriptor", configurable: true }; Object.defineProperty(obj, Symbol.toStringTag, desc); + return obj; } function _toClassDescriptor(obj) { var kind = String(obj.kind); if (kind !== "class") { - throw new TypeError( - "A class descriptor's .kind property must be \"class\", but a decorator" + " created a class descriptor with .kind \"" + kind - + "\"" - ); + throw new TypeError("A class descriptor's .kind property must be \"class\", but a decorator" + " created a class descriptor with .kind \"" + kind + "\""); } _disallowProperty(obj, "key", "A class descriptor"); _disallowProperty(obj, "placement", "A class descriptor"); @@ -253,29 +245,39 @@ function _toClassDescriptor(obj) { _disallowProperty(obj, "extras", "A class descriptor"); var finisher = _optionalCallableProperty(obj, "finisher"); var elements = _toElementDescriptors(obj.elements); + return { elements: elements, finisher: finisher }; } function _disallowProperty(obj, name, objectType) { - if (obj[name] !== undefined) { - throw new TypeError(objectType + " can't have a ." + name + " property."); - } + if (obj[name] !== undefined) throw new TypeError(objectType + " can't have a ." + name + " property."); } function _optionalCallableProperty(obj, name) { var value = obj[name]; if (value !== undefined && typeof value !== "function") { throw new TypeError("Expected '" + name + "' to be a function"); } + return value; } function _runClassFinishers(constructor, finishers) { for (var i = 0; i < finishers.length; i++) { var newConstructor = (0, finishers[i])(constructor); if (newConstructor !== undefined) { - if (typeof newConstructor !== "function") { - throw new TypeError("Finishers must return a constructor."); - } + if (typeof newConstructor !== "function") throw new TypeError("Finishers must return a constructor."); constructor = newConstructor; } } + return constructor; } +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x0000000601a000044000080000000018), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_defaults.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_defaults.rs new file mode 100644 index 000000000..0501a57b2 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_defaults.rs @@ -0,0 +1,32 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::defaults, + local: "_defaults", + import_path: "@swc/helpers/_/_defaults", + #[cfg(feature = "inline-helpers")] + source: r#"function _defaults(obj, defaults) { + var keys = Object.getOwnPropertyNames(defaults); + + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var value = Object.getOwnPropertyDescriptor(defaults, key); + + if (value && value.configurable && obj[key] === undefined) Object.defineProperty(obj, key, value); + } + + return obj; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000100000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_define_enumerable_properties.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_define_enumerable_properties.rs new file mode 100644 index 000000000..df2c111eb --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_define_enumerable_properties.rs @@ -0,0 +1,43 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::define_enumerable_properties, + local: "_define_enumerable_properties", + import_path: "@swc/helpers/_/_define_enumerable_properties", + #[cfg(feature = "inline-helpers")] + source: r#"function _define_enumerable_properties(obj, descs) { + for (var key in descs) { + var desc = descs[key]; + desc.configurable = desc.enumerable = true; + + if ("value" in desc) desc.writable = true; + + Object.defineProperty(obj, key, desc); + } + + if (Object.getOwnPropertySymbols) { + var objectSymbols = Object.getOwnPropertySymbols(descs); + for (var i = 0; i < objectSymbols.length; i++) { + var sym = objectSymbols[i]; + var desc = descs[sym]; + desc.configurable = desc.enumerable = true; + if ("value" in desc) desc.writable = true; + Object.defineProperty(obj, sym, desc); + } + } + + return obj; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000200000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_define_property.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_define_property.rs new file mode 100644 index 000000000..b04235e8a --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_define_property.rs @@ -0,0 +1,27 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::define_property, + local: "_define_property", + import_path: "@swc/helpers/_/_define_property", + #[cfg(feature = "inline-helpers")] + source: r#"function _define_property(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); + } else obj[key] = value; + + return obj; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000400000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_dispose.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_dispose.rs similarity index 57% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_dispose.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_dispose.rs index 8d1b848fa..bfce08426 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_dispose.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_dispose.rs @@ -1,4 +1,13 @@ -/* @minVersion 7.22.0 */ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::dispose, + local: "_dispose", + import_path: "@swc/helpers/_/_dispose", + #[cfg(feature = "inline-helpers")] + source: r#"/* @minVersion 7.22.0 */ function dispose_SuppressedError(error, suppressed) { if (typeof SuppressedError !== "undefined") { // eslint-disable-next-line no-undef @@ -9,13 +18,7 @@ function dispose_SuppressedError(error, suppressed) { this.error = error; this.stack = new Error().stack; }; - dispose_SuppressedError.prototype = Object.create(Error.prototype, { - constructor: { - value: dispose_SuppressedError, - writable: true, - configurable: true, - }, - }); + dispose_SuppressedError.prototype = Object.create(Error.prototype, { constructor: { value: dispose_SuppressedError, writable: true, configurable: true } }); } return new dispose_SuppressedError(error, suppressed); } @@ -42,4 +45,15 @@ function _dispose(stack, error, hasError) { } return next(); -} \ No newline at end of file +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000000800000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_export_star.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_export_star.rs new file mode 100644 index 000000000..acf55f5f7 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_export_star.rs @@ -0,0 +1,34 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::export_star, + local: "_export_star", + import_path: "@swc/helpers/_/_export_star", + #[cfg(feature = "inline-helpers")] + source: r#"function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + + return from; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000001000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_extends.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_extends.rs new file mode 100644 index 000000000..585beb764 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_extends.rs @@ -0,0 +1,32 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::extends, + local: "_extends", + import_path: "@swc/helpers/_/_extends", + #[cfg(feature = "inline-helpers")] + source: r#"function _extends() { + _extends = Object.assign || function assign(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + + return target; + }; + + return _extends.apply(this, arguments); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000002000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_get.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_get.rs new file mode 100644 index 000000000..b38dc318a --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_get.rs @@ -0,0 +1,38 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::get, + local: "_get", + import_path: "@swc/helpers/_/_get", + #[cfg(feature = "inline-helpers")] + source: r#"function _get(target, property, receiver) { + if (typeof Reflect !== "undefined" && Reflect.get) _get = Reflect.get; + else { + _get = function get(target, property, receiver) { + var base = _super_prop_base(target, property); + + if (!base) return; + + var desc = Object.getOwnPropertyDescriptor(base, property); + + if (desc.get) return desc.get.call(receiver || target); + + return desc.value; + }; + } + + return _get(target, property, receiver || target); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x0000000000020000000c000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_get_prototype_of.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_get_prototype_of.rs new file mode 100644 index 000000000..2f3503595 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_get_prototype_of.rs @@ -0,0 +1,27 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::get_prototype_of, + local: "_get_prototype_of", + import_path: "@swc/helpers/_/_get_prototype_of", + #[cfg(feature = "inline-helpers")] + source: r#"function _get_prototype_of(o) { + _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) { + return o.__proto__ || Object.getPrototypeOf(o); + }; + + return _get_prototype_of(o); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000008000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_identity.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_identity.rs new file mode 100644 index 000000000..3843a12f2 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_identity.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::identity, + local: "_identity", + import_path: "@swc/helpers/_/_identity", + #[cfg(feature = "inline-helpers")] + source: r#"function _identity(x) { + return x; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000010000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_inherits.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_inherits.rs new file mode 100644 index 000000000..211708ddd --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_inherits.rs @@ -0,0 +1,29 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::inherits, + local: "_inherits", + import_path: "@swc/helpers/_/_inherits", + #[cfg(feature = "inline-helpers")] + source: r#"function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function"); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); + + if (superClass) _set_prototype_of(subClass, superClass); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000020000020000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_inherits_loose.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_inherits_loose.rs new file mode 100644 index 000000000..00d24a5b2 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_inherits_loose.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::inherits_loose, + local: "_inherits_loose", + import_path: "@swc/helpers/_/_inherits_loose", + #[cfg(feature = "inline-helpers")] + source: r#"function _inherits_loose(subClass, superClass) { + subClass.prototype = Object.create(superClass.prototype); + subClass.prototype.constructor = subClass; + subClass.__proto__ = superClass; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000040000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_initializer_define_property.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_initializer_define_property.rs new file mode 100644 index 000000000..ad7a5e0d8 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_initializer_define_property.rs @@ -0,0 +1,30 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::initializer_define_property, + local: "_initializer_define_property", + import_path: "@swc/helpers/_/_initializer_define_property", + #[cfg(feature = "inline-helpers")] + source: r#"function _initializer_define_property(target, property, descriptor, context) { + if (!descriptor) return; + + Object.defineProperty(target, property, { + enumerable: descriptor.enumerable, + configurable: descriptor.configurable, + writable: descriptor.writable, + value: descriptor.initializer ? descriptor.initializer.call(context) : void 0 + }); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000080000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_initializer_warning_helper.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_initializer_warning_helper.rs new file mode 100644 index 000000000..ae59aa6a0 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_initializer_warning_helper.rs @@ -0,0 +1,28 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::initializer_warning_helper, + local: "_initializer_warning_helper", + import_path: "@swc/helpers/_/_initializer_warning_helper", + #[cfg(feature = "inline-helpers")] + source: r#"function _initializer_warning_helper(descriptor, context) { + throw new Error( + "Decorating class property failed. Please ensure that " + + "proposal-class-properties is enabled and set to use loose mode. " + + "To use proposal-class-properties in spec mode with decorators, wait for " + + "the next major version of decorators in stage 2." + ); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000100000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_instanceof.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_instanceof.rs new file mode 100644 index 000000000..da9bf00f2 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_instanceof.rs @@ -0,0 +1,27 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::instanceof, + local: "_instanceof", + import_path: "@swc/helpers/_/_instanceof", + #[cfg(feature = "inline-helpers")] + source: r#"function _instanceof(left, right) { + "@swc/helpers - instanceof"; + + if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { + return !!right[Symbol.hasInstance](left); + } else return left instanceof right; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000200000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_interop_require_default.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_interop_require_default.rs new file mode 100644 index 000000000..c615754d8 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_interop_require_default.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::interop_require_default, + local: "_interop_require_default", + import_path: "@swc/helpers/_/_interop_require_default", + #[cfg(feature = "inline-helpers")] + source: r#"function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000400000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_interop_require_wildcard.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_interop_require_wildcard.rs new file mode 100644 index 000000000..dfb73204c --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_interop_require_wildcard.rs @@ -0,0 +1,55 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::interop_require_wildcard, + local: "_interop_require_wildcard", + import_path: "@swc/helpers/_/_interop_require_wildcard", + #[cfg(feature = "inline-helpers")] + source: r#"function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +} +function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { default: obj }; + + var cache = _getRequireWildcardCache(nodeInterop); + + if (cache && cache.has(obj)) return cache.get(obj); + + var newObj = { __proto__: null }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + + for (var key in obj) { + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + + newObj.default = obj; + + if (cache) cache.set(obj, newObj); + + return newObj; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000000800000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_is_native_function.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_is_native_function.rs new file mode 100644 index 000000000..5138ac0ab --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_is_native_function.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::is_native_function, + local: "_is_native_function", + import_path: "@swc/helpers/_/_is_native_function", + #[cfg(feature = "inline-helpers")] + source: r#"function _is_native_function(fn) { + return Function.toString.call(fn).indexOf("[native code]") !== -1; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000001000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_is_native_reflect_construct.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_is_native_reflect_construct.rs new file mode 100644 index 000000000..c8b010af3 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_is_native_reflect_construct.rs @@ -0,0 +1,34 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::is_native_reflect_construct, + local: "_is_native_reflect_construct", + import_path: "@swc/helpers/_/_is_native_reflect_construct", + #[cfg(feature = "inline-helpers")] + source: r#"function _is_native_reflect_construct() { + // Since Reflect.construct can't be properly polyfilled, some + // implementations (e.g. core-js@2) don't set the correct internal slots. + // Those polyfills don't allow us to subclass built-ins, so we need to + // use our fallback implementation. + try { + // If the internal slots aren't set, this throws an error similar to + // TypeError: this is not a Boolean object. + var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {})); + } catch (_) {} + return (_is_native_reflect_construct = function() { + return !!result; + })(); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000002000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_iterable_to_array.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_iterable_to_array.rs new file mode 100644 index 000000000..789083f54 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_iterable_to_array.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::iterable_to_array, + local: "_iterable_to_array", + import_path: "@swc/helpers/_/_iterable_to_array", + #[cfg(feature = "inline-helpers")] + source: r#"function _iterable_to_array(iter) { + if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) { + return Array.from(iter); + } +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000004000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_iterable_to_array_limit.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_iterable_to_array_limit.rs new file mode 100644 index 000000000..cde95ee04 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_iterable_to_array_limit.rs @@ -0,0 +1,48 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::iterable_to_array_limit, + local: "_iterable_to_array_limit", + import_path: "@swc/helpers/_/_iterable_to_array_limit", + #[cfg(feature = "inline-helpers")] + source: r#"function _iterable_to_array_limit(arr, i) { + var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; + + if (_i == null) return; + + var _arr = []; + var _n = true; + var _d = false; + var _s, _e; + + try { + for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; + } + } + + return _arr; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000008000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_iterable_to_array_limit_loose.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_iterable_to_array_limit_loose.rs new file mode 100644 index 000000000..c1580e975 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_iterable_to_array_limit_loose.rs @@ -0,0 +1,34 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::iterable_to_array_limit_loose, + local: "_iterable_to_array_limit_loose", + import_path: "@swc/helpers/_/_iterable_to_array_limit_loose", + #[cfg(feature = "inline-helpers")] + source: r#"function _iterable_to_array_limit_loose(arr, i) { + var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]); + + if (_i == null) return; + + var _arr = []; + + for (_i = _i.call(arr), _step; !(_step = _i.next()).done;) { + _arr.push(_step.value); + if (i && _arr.length === i) break; + } + + return _arr; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000010000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_new_arrow_check.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_new_arrow_check.rs new file mode 100644 index 000000000..5ae814b12 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_new_arrow_check.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::new_arrow_check, + local: "_new_arrow_check", + import_path: "@swc/helpers/_/_new_arrow_check", + #[cfg(feature = "inline-helpers")] + source: r#"function _new_arrow_check(innerThis, boundThis) { + if (innerThis !== boundThis) throw new TypeError("Cannot instantiate an arrow function"); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000020000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_non_iterable_rest.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_non_iterable_rest.rs new file mode 100644 index 000000000..3d9bc0db9 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_non_iterable_rest.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::non_iterable_rest, + local: "_non_iterable_rest", + import_path: "@swc/helpers/_/_non_iterable_rest", + #[cfg(feature = "inline-helpers")] + source: r#"function _non_iterable_rest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000040000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_non_iterable_spread.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_non_iterable_spread.rs new file mode 100644 index 000000000..2ea177969 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_non_iterable_spread.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::non_iterable_spread, + local: "_non_iterable_spread", + import_path: "@swc/helpers/_/_non_iterable_spread", + #[cfg(feature = "inline-helpers")] + source: r#"function _non_iterable_spread() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000080000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_destructuring_empty.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_destructuring_empty.rs new file mode 100644 index 000000000..4bf56e6bd --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_destructuring_empty.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::object_destructuring_empty, + local: "_object_destructuring_empty", + import_path: "@swc/helpers/_/_object_destructuring_empty", + #[cfg(feature = "inline-helpers")] + source: r#"function _object_destructuring_empty(o) { + if (o === null || o === void 0) throw new TypeError("Cannot destructure " + o); + + return o; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000100000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_spread.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_spread.rs new file mode 100644 index 000000000..00a401d0a --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_spread.rs @@ -0,0 +1,40 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::object_spread, + local: "_object_spread", + import_path: "@swc/helpers/_/_object_spread", + #[cfg(feature = "inline-helpers")] + source: r#"function _object_spread(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + var ownKeys = Object.keys(source); + + if (typeof Object.getOwnPropertySymbols === "function") { + ownKeys = ownKeys.concat( + Object.getOwnPropertySymbols(source).filter(function(sym) { + return Object.getOwnPropertyDescriptor(source, sym).enumerable; + }) + ); + } + + ownKeys.forEach(function(key) { + _define_property(target, key, source[key]); + }); + } + + return target; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000200000400000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_spread_props.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_spread_props.rs new file mode 100644 index 000000000..0d1c52498 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_spread_props.rs @@ -0,0 +1,47 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::object_spread_props, + local: "_object_spread_props", + import_path: "@swc/helpers/_/_object_spread_props", + #[cfg(feature = "inline-helpers")] + source: r#"function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + if (enumerableOnly) { + symbols = symbols.filter(function(sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + }); + } + keys.push.apply(keys, symbols); + } + + return keys; +} +function _object_spread_props(target, source) { + source = source != null ? source : {}; + + if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); + else { + ownKeys(Object(source)).forEach(function(key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + + return target; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000000400000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_without_properties.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_without_properties.rs similarity index 54% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_without_properties.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_without_properties.rs index 518a15ade..57ea35a20 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_object_without_properties.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_without_properties.rs @@ -1,4 +1,13 @@ -function _object_without_properties(source, excluded) { +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::object_without_properties, + local: "_object_without_properties", + import_path: "@swc/helpers/_/_object_without_properties", + #[cfg(feature = "inline-helpers")] + source: r#"function _object_without_properties(source, excluded) { if (source == null) return {}; var target = {}, sourceKeys, key, i; @@ -27,3 +36,14 @@ function _object_without_properties(source, excluded) { return target; } +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000001800000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_without_properties_loose.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_without_properties_loose.rs new file mode 100644 index 000000000..a5d172bdd --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_object_without_properties_loose.rs @@ -0,0 +1,33 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::object_without_properties_loose, + local: "_object_without_properties_loose", + import_path: "@swc/helpers/_/_object_without_properties_loose", + #[cfg(feature = "inline-helpers")] + source: r#"function _object_without_properties_loose(source, excluded) { + if (source == null) return {}; + + var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i; + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; + target[key] = source[key]; + } + + return target; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000001000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_overload_yield.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_overload_yield.rs new file mode 100644 index 000000000..e89fe0434 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_overload_yield.rs @@ -0,0 +1,24 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::overload_yield, + local: "_overload_yield", + import_path: "@swc/helpers/_/_overload_yield", + #[cfg(feature = "inline-helpers")] + source: r#"function _overload_yield(value, /** 0: await 1: delegate */ kind) { + this.v = value; + this.k = kind; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000002000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_possible_constructor_return.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_possible_constructor_return.rs new file mode 100644 index 000000000..3b254e480 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_possible_constructor_return.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::possible_constructor_return, + local: "_possible_constructor_return", + import_path: "@swc/helpers/_/_possible_constructor_return", + #[cfg(feature = "inline-helpers")] + source: r#"function _possible_constructor_return(self, call) { + if (call && (_type_of(call) === "object" || typeof call === "function")) return call; + + return _assert_this_initialized(self); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000002000004000000000000000040), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_read_only_error.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_read_only_error.rs new file mode 100644 index 000000000..d703cc78e --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_read_only_error.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::read_only_error, + local: "_read_only_error", + import_path: "@swc/helpers/_/_read_only_error", + #[cfg(feature = "inline-helpers")] + source: r#"function _read_only_error(name) { + throw new TypeError("\"" + name + "\" is read-only"); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000008000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_set.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_set.rs similarity index 52% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_set.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_set.rs index cd527d856..9a447bd01 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_set.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_set.rs @@ -1,7 +1,15 @@ -function set(target, property, value, receiver) { - if (typeof Reflect !== "undefined" && Reflect.set) { - set = Reflect.set; - } else { +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::set, + local: "_set", + import_path: "@swc/helpers/_/_set", + #[cfg(feature = "inline-helpers")] + source: r#"function set(target, property, value, receiver) { + if (typeof Reflect !== "undefined" && Reflect.set) set = Reflect.set; + else { set = function set(target, property, value, receiver) { var base = _super_prop_base(target, property); var desc; @@ -9,6 +17,7 @@ function set(target, property, value, receiver) { desc = Object.getOwnPropertyDescriptor(base, property); if (desc.set) { desc.set.call(receiver, value); + return true; } else if (!desc.writable) { return false; @@ -16,23 +25,34 @@ function set(target, property, value, receiver) { } desc = Object.getOwnPropertyDescriptor(receiver, property); if (desc) { - if (!desc.writable) { - return false; - } + if (!desc.writable) return false; desc.value = value; Object.defineProperty(receiver, property, desc); } else { _define_property(receiver, property, value); } + return true; }; } + return set(target, property, value, receiver); } + function _set(target, property, value, receiver, isStrict) { var s = set(target, property, value, receiver || target); - if (!s && isStrict) { - throw new Error("failed to set property"); - } + if (!s && isStrict) throw new Error("failed to set property"); + return value; } +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000210000008400000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_set_prototype_of.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_set_prototype_of.rs new file mode 100644 index 000000000..fea0cec11 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_set_prototype_of.rs @@ -0,0 +1,29 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::set_prototype_of, + local: "_set_prototype_of", + import_path: "@swc/helpers/_/_set_prototype_of", + #[cfg(feature = "inline-helpers")] + source: r#"function _set_prototype_of(o, p) { + _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) { + o.__proto__ = p; + + return o; + }; + + return _set_prototype_of(o, p); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000020000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_skip_first_generator_next.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_skip_first_generator_next.rs new file mode 100644 index 000000000..85056a61a --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_skip_first_generator_next.rs @@ -0,0 +1,28 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::skip_first_generator_next, + local: "_skip_first_generator_next", + import_path: "@swc/helpers/_/_skip_first_generator_next", + #[cfg(feature = "inline-helpers")] + source: r#"function _skip_first_generator_next(fn) { + return function() { + var it = fn.apply(this, arguments); + it.next(); + + return it; + }; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000040000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_sliced_to_array.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_sliced_to_array.rs new file mode 100644 index 000000000..55f96bcb4 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_sliced_to_array.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::sliced_to_array, + local: "_sliced_to_array", + import_path: "@swc/helpers/_/_sliced_to_array", + #[cfg(feature = "inline-helpers")] + source: r#"function _sliced_to_array(arr, i) { + return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest(); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000004000080048000000000000018), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_sliced_to_array_loose.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_sliced_to_array_loose.rs new file mode 100644 index 000000000..8fda428fd --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_sliced_to_array_loose.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::sliced_to_array_loose, + local: "_sliced_to_array_loose", + import_path: "@swc/helpers/_/_sliced_to_array_loose", + #[cfg(feature = "inline-helpers")] + source: r#"function _sliced_to_array_loose(arr, i) { + return _array_with_holes(arr) || _iterable_to_array_limit_loose(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest(); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000004000100050000000000000018), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_super_prop_base.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_super_prop_base.rs new file mode 100644 index 000000000..e7371b277 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_super_prop_base.rs @@ -0,0 +1,28 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::super_prop_base, + local: "_super_prop_base", + import_path: "@swc/helpers/_/_super_prop_base", + #[cfg(feature = "inline-helpers")] + source: r#"function _super_prop_base(object, property) { + while (!Object.prototype.hasOwnProperty.call(object, property)) { + object = _get_prototype_of(object); + if (object === null) break; + } + + return object; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000200000008000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_tagged_template_literal.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_tagged_template_literal.rs new file mode 100644 index 000000000..11c2c5e38 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_tagged_template_literal.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::tagged_template_literal, + local: "_tagged_template_literal", + import_path: "@swc/helpers/_/_tagged_template_literal", + #[cfg(feature = "inline-helpers")] + source: r#"function _tagged_template_literal(strings, raw) { + if (!raw) raw = strings.slice(0); + + return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000400000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_tagged_template_literal_loose.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_tagged_template_literal_loose.rs new file mode 100644 index 000000000..e68c2d995 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_tagged_template_literal_loose.rs @@ -0,0 +1,27 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::tagged_template_literal_loose, + local: "_tagged_template_literal_loose", + import_path: "@swc/helpers/_/_tagged_template_literal_loose", + #[cfg(feature = "inline-helpers")] + source: r#"function _tagged_template_literal_loose(strings, raw) { + if (!raw) raw = strings.slice(0); + + strings.raw = raw; + + return strings; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000000800000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_throw.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_throw.rs new file mode 100644 index 000000000..a17fbbec4 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_throw.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::throw, + local: "_throw", + import_path: "@swc/helpers/_/_throw", + #[cfg(feature = "inline-helpers")] + source: r#"function _throw(e) { + throw e; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000001000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_array.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_array.rs new file mode 100644 index 000000000..eb2a2b6b3 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_array.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::to_array, + local: "_to_array", + import_path: "@swc/helpers/_/_to_array", + #[cfg(feature = "inline-helpers")] + source: r#"function _to_array(arr) { + return _array_with_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_rest(); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000004002000044000000000000018), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_consumable_array.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_consumable_array.rs new file mode 100644 index 000000000..5fe422a6f --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_consumable_array.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::to_consumable_array, + local: "_to_consumable_array", + import_path: "@swc/helpers/_/_to_consumable_array", + #[cfg(feature = "inline-helpers")] + source: r#"function _to_consumable_array(arr) { + return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread(); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000004004000084000000000000028), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_primitive.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_primitive.rs new file mode 100644 index 000000000..42c7a2de7 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_primitive.rs @@ -0,0 +1,33 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::to_primitive, + local: "_to_primitive", + import_path: "@swc/helpers/_/_to_primitive", + #[cfg(feature = "inline-helpers")] + source: r#"function _to_primitive(input, hint) { + if (_type_of(input) !== "object" || input === null) return input; + + var prim = input[Symbol.toPrimitive]; + + if (prim !== undefined) { + var res = prim.call(input, hint || "default"); + if (_type_of(res) !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + + return (hint === "string" ? String : Number)(input); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000002008000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_property_key.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_property_key.rs new file mode 100644 index 000000000..3a1035bfb --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_to_property_key.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::to_property_key, + local: "_to_property_key", + import_path: "@swc/helpers/_/_to_property_key", + #[cfg(feature = "inline-helpers")] + source: r#"function _to_property_key(arg) { + var key = _to_primitive(arg, "string"); + + return _type_of(key) === "symbol" ? key : String(key); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000002018000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_add_disposable_resource.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_add_disposable_resource.rs new file mode 100644 index 000000000..67c10dab0 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_add_disposable_resource.rs @@ -0,0 +1,59 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::ts_add_disposable_resource, + local: "_ts_add_disposable_resource", + import_path: "@swc/helpers/_/_ts_add_disposable_resource", + #[cfg(feature = "inline-helpers")] + source: r#"function _ts_add_disposable_resource(env, value, async) { + if (value !== null && value !== void 0) { + if (typeof value !== "object" && typeof value !== "function") { + throw new TypeError("Object expected."); + } + var dispose, inner; + if (async) { + if (!Symbol.asyncDispose) { + throw new TypeError("Symbol.asyncDispose is not defined."); + } + dispose = value[Symbol.asyncDispose]; + } + if (dispose === void 0) { + if (!Symbol.dispose) { + throw new TypeError("Symbol.dispose is not defined."); + } + dispose = value[Symbol.dispose]; + if (async) { + inner = dispose; + } + } + if (typeof dispose !== "function") { + throw new TypeError("Object not disposable."); + } + if (inner) { + dispose = function() { + try { + inner.call(this); + } catch (e) { + return Promise.reject(e); + } + }; + } + env.stack.push({ value: value, dispose: dispose, async: async }); + } else if (async) { + env.stack.push({ async: true }); + } + return value; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000020000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_decorate.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_decorate.rs new file mode 100644 index 000000000..a49103e1b --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_decorate.rs @@ -0,0 +1,33 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::ts_decorate, + local: "_ts_decorate", + import_path: "@swc/helpers/_/_ts_decorate", + #[cfg(feature = "inline-helpers")] + source: r#"function _ts_decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") { + r = Reflect.decorate(decorators, target, key, desc); + } else { + for (var i = decorators.length - 1; i >= 0; i--) { + if (d = decorators[i]) { + r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + } + } + } + return c > 3 && r && Object.defineProperty(target, key, r), r; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000040000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_dispose_resources.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_dispose_resources.rs new file mode 100644 index 000000000..4644cdf1c --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_dispose_resources.rs @@ -0,0 +1,62 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::ts_dispose_resources, + local: "_ts_dispose_resources", + import_path: "@swc/helpers/_/_ts_dispose_resources", + #[cfg(feature = "inline-helpers")] + source: r#"var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}; + +function _ts_dispose_resources(env) { + function fail(e) { + env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; + env.hasError = true; + } + var r, s = 0; + function next() { + while (r = env.stack.pop()) { + try { + if (!r.async && s === 1) { + return s = 0, env.stack.push(r), Promise.resolve().then(next); + } + if (r.dispose) { + var result = r.dispose.call(r.value); + if (r.async) { + return s |= 2, + Promise.resolve(result).then(next, function(e) { + fail(e); + return next(); + }); + } + } else { + s |= 1; + } + } catch (e) { + fail(e); + } + } + if (s === 1) { + return env.hasError ? Promise.reject(env.error) : Promise.resolve(); + } + if (env.hasError) { + throw env.error; + } + } + return next(); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000080000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_generator.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_generator.rs similarity index 72% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_generator.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_generator.rs index 4fde75b49..f0ae7ba07 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_ts_generator.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_generator.rs @@ -1,4 +1,13 @@ -function _ts_generator(thisArg, body) { +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::ts_generator, + local: "_ts_generator", + import_path: "@swc/helpers/_/_ts_generator", + #[cfg(feature = "inline-helpers")] + source: r#"function _ts_generator(thisArg, body) { var f, y, t, _ = { label: 0, sent: function () { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty; return d(g, "next", { value: verb(0) }), d(g, "throw", { value: verb(1) }), d(g, "return", { value: verb(2) }), typeof Symbol === "function" && d(g, Symbol.iterator, { value: function () { return this; } }), g; function verb(n) { return function (v) { return step([n, v]); }; } @@ -24,4 +33,15 @@ function _ts_generator(thisArg, body) { } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } -} \ No newline at end of file +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000100000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_metadata.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_metadata.rs new file mode 100644 index 000000000..41d1afa34 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_metadata.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::ts_metadata, + local: "_ts_metadata", + import_path: "@swc/helpers/_/_ts_metadata", + #[cfg(feature = "inline-helpers")] + source: r#"function _ts_metadata(metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") { + return Reflect.metadata(metadataKey, metadataValue); + } +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000200000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_param.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_param.rs new file mode 100644 index 000000000..a698aee98 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_param.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::ts_param, + local: "_ts_param", + import_path: "@swc/helpers/_/_ts_param", + #[cfg(feature = "inline-helpers")] + source: r#"function _ts_param(paramIndex, decorator) { + return function(target, key) { + decorator(target, key, paramIndex); + }; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000400000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_rewrite_relative_import_extension.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_rewrite_relative_import_extension.rs new file mode 100644 index 000000000..3269d0643 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_rewrite_relative_import_extension.rs @@ -0,0 +1,28 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::ts_rewrite_relative_import_extension, + local: "_ts_rewrite_relative_import_extension", + import_path: "@swc/helpers/_/_ts_rewrite_relative_import_extension", + #[cfg(feature = "inline-helpers")] + source: r#"function _ts_rewrite_relative_import_extension(path, preserveJsx) { + if (typeof path === "string" && /^\.\.?\//.test(path)) { + return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) { + return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js"; + }); + } + return path; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000000800000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_values.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_values.rs new file mode 100644 index 000000000..975ac44f4 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_ts_values.rs @@ -0,0 +1,37 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::ts_values, + local: "_ts_values", + import_path: "@swc/helpers/_/_ts_values", + #[cfg(feature = "inline-helpers")] + source: r#"function _ts_values(o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) { + return m.call(o); + } + if (o && typeof o.length === "number") { + return { + next: function() { + if (o && i >= o.length) { + o = void 0; + } + return { value: o && o[i++], done: !o }; + } + }; + } + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000001000000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_type_of.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_type_of.rs new file mode 100644 index 000000000..f760ae32a --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_type_of.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::type_of, + local: "_type_of", + import_path: "@swc/helpers/_/_type_of", + #[cfg(feature = "inline-helpers")] + source: r#"function _type_of(obj) { + "@swc/helpers - typeof"; + + return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000002000000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_unsupported_iterable_to_array.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_unsupported_iterable_to_array.rs new file mode 100644 index 000000000..c473ff218 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_unsupported_iterable_to_array.rs @@ -0,0 +1,30 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::unsupported_iterable_to_array, + local: "_unsupported_iterable_to_array", + import_path: "@swc/helpers/_/_unsupported_iterable_to_array", + #[cfg(feature = "inline-helpers")] + source: r#"function _unsupported_iterable_to_array(o, minLen) { + if (!o) return; + if (typeof o === "string") return _array_like_to_array(o, minLen); + + var n = Object.prototype.toString.call(o).slice(8, -1); + + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(n); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000004000000000000000000000008), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_update.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_update.rs new file mode 100644 index 000000000..9eb359ba9 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_update.rs @@ -0,0 +1,30 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::update, + local: "_update", + import_path: "@swc/helpers/_/_update", + #[cfg(feature = "inline-helpers")] + source: r#"function _update(target, property, receiver, isStrict) { + return { + get _() { + return _get(target, property, receiver); + }, + set _(value) { + _set(target, property, value, receiver, isStrict); + } + }; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x0000000800021000000c400000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_using.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_using.rs new file mode 100644 index 000000000..1a9b8f167 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_using.rs @@ -0,0 +1,40 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::using, + local: "_using", + import_path: "@swc/helpers/_/_using", + #[cfg(feature = "inline-helpers")] + source: r#"/* @minVersion 7.22.0 */ + +function _using(stack, value, isAwait) { + if (value === null || value === void 0) return value; + if (Object(value) !== value) { + throw new TypeError("using declarations can only be used with objects, functions, null, or undefined."); + } + // core-js-pure uses Symbol.for for polyfilling well-known symbols + if (isAwait) { + var dispose = value[Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose")]; + } + if (dispose === null || dispose === void 0) { + dispose = value[Symbol.dispose || Symbol.for("Symbol.dispose")]; + } + if (typeof dispose !== "function") { + throw new TypeError(`Property [Symbol.dispose] is not a function.`); + } + stack.push({ v: value, d: dispose, a: isAwait }); + return value; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000010000000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_using_ctx.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_using_ctx.rs similarity index 60% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_using_ctx.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_using_ctx.rs index 29c3422f4..3ad85b2c6 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_using_ctx.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_using_ctx.rs @@ -1,9 +1,17 @@ -function _using_ctx() { - var _disposeSuppressedError = - typeof SuppressedError === "function" - ? // eslint-disable-next-line no-undef - SuppressedError - : (function (error, suppressed) { +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::using_ctx, + local: "_using_ctx", + import_path: "@swc/helpers/_/_using_ctx", + #[cfg(feature = "inline-helpers")] + source: r#"function _using_ctx() { + var _disposeSuppressedError = typeof SuppressedError === "function" + // eslint-disable-next-line no-undef + ? SuppressedError + : (function(error, suppressed) { var err = new Error(); err.name = "SuppressedError"; err.suppressed = suppressed; @@ -15,14 +23,11 @@ function _using_ctx() { function using(isAwait, value) { if (value != null) { if (Object(value) !== value) { - throw new TypeError( - "using declarations can only be used with objects, functions, null, or undefined.", - ); + throw new TypeError("using declarations can only be used with objects, functions, null, or undefined."); } // core-js-pure uses Symbol.for for polyfilling well-known symbols if (isAwait) { - var dispose = - value[Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose")]; + var dispose = value[Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose")]; } if (dispose == null) { dispose = value[Symbol.dispose || Symbol.for("Symbol.dispose")]; @@ -45,15 +50,14 @@ function _using_ctx() { // await using a: using.bind(null, true), // dispose - d: function () { + d: function() { var error = this.e; function next() { // eslint-disable-next-line @typescript-eslint/no-use-before-define while ((resource = stack.pop())) { try { - var resource, - disposalResult = resource.d && resource.d.call(resource.v); + var resource, disposalResult = resource.d && resource.d.call(resource.v); if (resource.a) { return Promise.resolve(disposalResult).then(next, err); } @@ -71,6 +75,17 @@ function _using_ctx() { } return next(); - }, + } }; -} \ No newline at end of file +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000020000000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_wrap_async_generator.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_wrap_async_generator.rs new file mode 100644 index 000000000..702776b93 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_wrap_async_generator.rs @@ -0,0 +1,25 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::wrap_async_generator, + local: "_wrap_async_generator", + import_path: "@swc/helpers/_/_wrap_async_generator", + #[cfg(feature = "inline-helpers")] + source: r#"function _wrap_async_generator(fn) { + return function() { + return new _async_generator(fn.apply(this, arguments)); + }; +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000040000002000000000000000080), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_wrap_native_super.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_wrap_native_super.rs new file mode 100644 index 000000000..1f16d5d62 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_wrap_native_super.rs @@ -0,0 +1,40 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::wrap_native_super, + local: "_wrap_native_super", + import_path: "@swc/helpers/_/_wrap_native_super", + #[cfg(feature = "inline-helpers")] + source: r#"function _wrap_native_super(Class) { + var _cache = typeof Map === "function" ? new Map() : undefined; + _wrap_native_super = function(Class) { + if (Class === null || !_is_native_function(Class)) return Class; + if (typeof Class !== "function") throw new TypeError("Super expression must either be null or a function"); + if (typeof _cache !== "undefined") { + if (_cache.has(Class)) return _cache.get(Class); + _cache.set(Class, Wrapper); + } + + function Wrapper() { + return _construct(Class, arguments, _get_prototype_of(this).constructor); + } + Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); + + return _set_prototype_of(Wrapper, Class); + }; + + return _wrap_native_super(Class); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000080000020003008008000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_wrap_reg_exp.js b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_wrap_reg_exp.rs similarity index 80% rename from deps/swc/crates/swc_ecma_transforms_base/src/helpers/_wrap_reg_exp.js rename to deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_wrap_reg_exp.rs index e26d6c77a..29326a5d2 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/_wrap_reg_exp.js +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_wrap_reg_exp.rs @@ -1,4 +1,13 @@ -function _wrap_reg_exp(re, groups, source) { +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::wrap_reg_exp, + local: "_wrap_reg_exp", + import_path: "@swc/helpers/_/_wrap_reg_exp", + #[cfg(feature = "inline-helpers")] + source: r#"function _wrap_reg_exp(re, groups, source) { _wrap_reg_exp = function(re, groups, source) { return new WrappedRegExp(re, undefined, groups, source); }; @@ -76,3 +85,14 @@ function _wrap_reg_exp(re, groups, source) { } return _wrap_reg_exp.apply(this, arguments); } +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000100000020000020000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_write_only_error.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_write_only_error.rs new file mode 100644 index 000000000..88c86a2ff --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/_write_only_error.rs @@ -0,0 +1,23 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. + +use super::{HelperDef, HelperName}; + +pub const DEF: HelperDef = HelperDef { + name: HelperName::write_only_error, + local: "_write_only_error", + import_path: "@swc/helpers/_/_write_only_error", + #[cfg(feature = "inline-helpers")] + source: r#"function _write_only_error(name) { + throw new TypeError("\"" + name + "\" is write-only"); +} +"#, + #[cfg(feature = "inline-helpers")] + deps: super::HelperBitmap::from_bits(0x00000200000000000000000000000000), +}; + +#[cfg(feature = "inline-helpers")] +pub fn stmts() -> &'static [swc_ecma_ast::Stmt] { + static STMTS: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path)); + &STMTS +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/mod.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/mod.rs new file mode 100644 index 000000000..67177c4a7 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/generated/mod.rs @@ -0,0 +1,1070 @@ +// This file is generated by `cargo codegen helpers`. DO NOT MODIFY. +#![allow(clippy::all)] + +mod _apply_decorated_descriptor; +mod _apply_decs_2203_r; +mod _apply_decs_2311; +mod _array_like_to_array; +mod _array_with_holes; +mod _array_without_holes; +mod _assert_this_initialized; +mod _async_generator; +mod _async_generator_delegate; +mod _async_iterator; +mod _async_to_generator; +mod _await_async_generator; +mod _await_value; +mod _call_super; +mod _check_private_redeclaration; +mod _class_apply_descriptor_destructure; +mod _class_apply_descriptor_get; +mod _class_apply_descriptor_set; +mod _class_apply_descriptor_update; +mod _class_call_check; +mod _class_check_private_static_access; +mod _class_check_private_static_field_descriptor; +mod _class_extract_field_descriptor; +mod _class_name_tdz_error; +mod _class_private_field_destructure; +mod _class_private_field_get; +mod _class_private_field_init; +mod _class_private_field_loose_base; +mod _class_private_field_loose_key; +mod _class_private_field_set; +mod _class_private_field_update; +mod _class_private_method_get; +mod _class_private_method_init; +mod _class_private_method_set; +mod _class_static_private_field_destructure; +mod _class_static_private_field_spec_get; +mod _class_static_private_field_spec_set; +mod _class_static_private_field_update; +mod _class_static_private_method_get; +mod _construct; +mod _create_class; +mod _create_for_of_iterator_helper_loose; +mod _create_super; +mod _decorate; +mod _defaults; +mod _define_enumerable_properties; +mod _define_property; +mod _dispose; +mod _export_star; +mod _extends; +mod _get; +mod _get_prototype_of; +mod _identity; +mod _inherits; +mod _inherits_loose; +mod _initializer_define_property; +mod _initializer_warning_helper; +mod _instanceof; +mod _interop_require_default; +mod _interop_require_wildcard; +mod _is_native_function; +mod _is_native_reflect_construct; +mod _iterable_to_array; +mod _iterable_to_array_limit; +mod _iterable_to_array_limit_loose; +mod _new_arrow_check; +mod _non_iterable_rest; +mod _non_iterable_spread; +mod _object_destructuring_empty; +mod _object_spread; +mod _object_spread_props; +mod _object_without_properties; +mod _object_without_properties_loose; +mod _overload_yield; +mod _possible_constructor_return; +mod _read_only_error; +mod _set; +mod _set_prototype_of; +mod _skip_first_generator_next; +mod _sliced_to_array; +mod _sliced_to_array_loose; +mod _super_prop_base; +mod _tagged_template_literal; +mod _tagged_template_literal_loose; +mod _throw; +mod _to_array; +mod _to_consumable_array; +mod _to_primitive; +mod _to_property_key; +mod _ts_add_disposable_resource; +mod _ts_decorate; +mod _ts_dispose_resources; +mod _ts_generator; +mod _ts_metadata; +mod _ts_param; +mod _ts_rewrite_relative_import_extension; +mod _ts_values; +mod _type_of; +mod _unsupported_iterable_to_array; +mod _update; +mod _using; +mod _using_ctx; +mod _wrap_async_generator; +mod _wrap_native_super; +mod _wrap_reg_exp; +mod _write_only_error; + +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(usize)] +pub enum HelperName { + apply_decorated_descriptor, + apply_decs_2203_r, + apply_decs_2311, + array_like_to_array, + array_with_holes, + array_without_holes, + assert_this_initialized, + async_generator, + async_generator_delegate, + async_iterator, + async_to_generator, + await_async_generator, + await_value, + call_super, + check_private_redeclaration, + class_apply_descriptor_destructure, + class_apply_descriptor_get, + class_apply_descriptor_set, + class_apply_descriptor_update, + class_call_check, + class_check_private_static_access, + class_check_private_static_field_descriptor, + class_extract_field_descriptor, + class_name_tdz_error, + class_private_field_destructure, + class_private_field_get, + class_private_field_init, + class_private_field_loose_base, + class_private_field_loose_key, + class_private_field_set, + class_private_field_update, + class_private_method_get, + class_private_method_init, + class_private_method_set, + class_static_private_field_destructure, + class_static_private_field_spec_get, + class_static_private_field_spec_set, + class_static_private_field_update, + class_static_private_method_get, + construct, + create_class, + create_for_of_iterator_helper_loose, + create_super, + decorate, + defaults, + define_enumerable_properties, + define_property, + dispose, + export_star, + extends, + get, + get_prototype_of, + identity, + inherits, + inherits_loose, + initializer_define_property, + initializer_warning_helper, + instanceof, + interop_require_default, + interop_require_wildcard, + is_native_function, + is_native_reflect_construct, + iterable_to_array, + iterable_to_array_limit, + iterable_to_array_limit_loose, + new_arrow_check, + non_iterable_rest, + non_iterable_spread, + object_destructuring_empty, + object_spread, + object_spread_props, + object_without_properties, + object_without_properties_loose, + overload_yield, + possible_constructor_return, + read_only_error, + set, + set_prototype_of, + skip_first_generator_next, + sliced_to_array, + sliced_to_array_loose, + super_prop_base, + tagged_template_literal, + tagged_template_literal_loose, + throw, + to_array, + to_consumable_array, + to_primitive, + to_property_key, + ts_add_disposable_resource, + ts_decorate, + ts_dispose_resources, + ts_generator, + ts_metadata, + ts_param, + ts_rewrite_relative_import_extension, + ts_values, + type_of, + unsupported_iterable_to_array, + update, + using, + using_ctx, + wrap_async_generator, + wrap_native_super, + wrap_reg_exp, + write_only_error, +} + +pub const HELPER_COUNT: usize = 106; + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub struct HelperBitmap(u128); + +impl HelperBitmap { + pub const EMPTY: Self = Self(0); + + pub const fn single(name: HelperName) -> Self { + Self(1u128 << (name as usize)) + } + + pub const fn from_bits(bits: u128) -> Self { + Self(bits) + } + + pub fn contains(self, name: HelperName) -> bool { + self.0 & Self::single(name).0 != 0 + } + + pub fn insert(&mut self, name: HelperName) { + self.0 |= Self::single(name).0; + } + + pub fn is_empty(self) -> bool { + self.0 == 0 + } +} + +impl core::ops::BitOr for HelperBitmap { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self { + Self(self.0 | rhs.0) + } +} + +impl core::ops::BitOrAssign for HelperBitmap { + fn bitor_assign(&mut self, rhs: Self) { + self.0 |= rhs.0; + } +} + +#[derive(Clone, Copy, Debug)] +pub struct HelperDef { + pub name: HelperName, + pub local: &'static str, + pub import_path: &'static str, + #[cfg(feature = "inline-helpers")] + pub source: &'static str, + #[cfg(feature = "inline-helpers")] + pub deps: HelperBitmap, +} + +pub const ALL: &[HelperDef; HELPER_COUNT] = &[ + _apply_decorated_descriptor::DEF, + _apply_decs_2203_r::DEF, + _apply_decs_2311::DEF, + _array_like_to_array::DEF, + _array_with_holes::DEF, + _array_without_holes::DEF, + _assert_this_initialized::DEF, + _async_generator::DEF, + _async_generator_delegate::DEF, + _async_iterator::DEF, + _async_to_generator::DEF, + _await_async_generator::DEF, + _await_value::DEF, + _call_super::DEF, + _check_private_redeclaration::DEF, + _class_apply_descriptor_destructure::DEF, + _class_apply_descriptor_get::DEF, + _class_apply_descriptor_set::DEF, + _class_apply_descriptor_update::DEF, + _class_call_check::DEF, + _class_check_private_static_access::DEF, + _class_check_private_static_field_descriptor::DEF, + _class_extract_field_descriptor::DEF, + _class_name_tdz_error::DEF, + _class_private_field_destructure::DEF, + _class_private_field_get::DEF, + _class_private_field_init::DEF, + _class_private_field_loose_base::DEF, + _class_private_field_loose_key::DEF, + _class_private_field_set::DEF, + _class_private_field_update::DEF, + _class_private_method_get::DEF, + _class_private_method_init::DEF, + _class_private_method_set::DEF, + _class_static_private_field_destructure::DEF, + _class_static_private_field_spec_get::DEF, + _class_static_private_field_spec_set::DEF, + _class_static_private_field_update::DEF, + _class_static_private_method_get::DEF, + _construct::DEF, + _create_class::DEF, + _create_for_of_iterator_helper_loose::DEF, + _create_super::DEF, + _decorate::DEF, + _defaults::DEF, + _define_enumerable_properties::DEF, + _define_property::DEF, + _dispose::DEF, + _export_star::DEF, + _extends::DEF, + _get::DEF, + _get_prototype_of::DEF, + _identity::DEF, + _inherits::DEF, + _inherits_loose::DEF, + _initializer_define_property::DEF, + _initializer_warning_helper::DEF, + _instanceof::DEF, + _interop_require_default::DEF, + _interop_require_wildcard::DEF, + _is_native_function::DEF, + _is_native_reflect_construct::DEF, + _iterable_to_array::DEF, + _iterable_to_array_limit::DEF, + _iterable_to_array_limit_loose::DEF, + _new_arrow_check::DEF, + _non_iterable_rest::DEF, + _non_iterable_spread::DEF, + _object_destructuring_empty::DEF, + _object_spread::DEF, + _object_spread_props::DEF, + _object_without_properties::DEF, + _object_without_properties_loose::DEF, + _overload_yield::DEF, + _possible_constructor_return::DEF, + _read_only_error::DEF, + _set::DEF, + _set_prototype_of::DEF, + _skip_first_generator_next::DEF, + _sliced_to_array::DEF, + _sliced_to_array_loose::DEF, + _super_prop_base::DEF, + _tagged_template_literal::DEF, + _tagged_template_literal_loose::DEF, + _throw::DEF, + _to_array::DEF, + _to_consumable_array::DEF, + _to_primitive::DEF, + _to_property_key::DEF, + _ts_add_disposable_resource::DEF, + _ts_decorate::DEF, + _ts_dispose_resources::DEF, + _ts_generator::DEF, + _ts_metadata::DEF, + _ts_param::DEF, + _ts_rewrite_relative_import_extension::DEF, + _ts_values::DEF, + _type_of::DEF, + _unsupported_iterable_to_array::DEF, + _update::DEF, + _using::DEF, + _using_ctx::DEF, + _wrap_async_generator::DEF, + _wrap_native_super::DEF, + _wrap_reg_exp::DEF, + _write_only_error::DEF, +]; + +pub fn helper(name: HelperName) -> &'static HelperDef { + &ALL[name as usize] +} + +pub fn helper_name(name: &str) -> Option { + match name { + "apply_decorated_descriptor" => Some(HelperName::apply_decorated_descriptor), + "apply_decs_2203_r" => Some(HelperName::apply_decs_2203_r), + "apply_decs_2311" => Some(HelperName::apply_decs_2311), + "array_like_to_array" => Some(HelperName::array_like_to_array), + "array_with_holes" => Some(HelperName::array_with_holes), + "array_without_holes" => Some(HelperName::array_without_holes), + "assert_this_initialized" => Some(HelperName::assert_this_initialized), + "async_generator" => Some(HelperName::async_generator), + "async_generator_delegate" => Some(HelperName::async_generator_delegate), + "async_iterator" => Some(HelperName::async_iterator), + "async_to_generator" => Some(HelperName::async_to_generator), + "await_async_generator" => Some(HelperName::await_async_generator), + "await_value" => Some(HelperName::await_value), + "call_super" => Some(HelperName::call_super), + "check_private_redeclaration" => Some(HelperName::check_private_redeclaration), + "class_apply_descriptor_destructure" => { + Some(HelperName::class_apply_descriptor_destructure) + } + "class_apply_descriptor_get" => Some(HelperName::class_apply_descriptor_get), + "class_apply_descriptor_set" => Some(HelperName::class_apply_descriptor_set), + "class_apply_descriptor_update" => Some(HelperName::class_apply_descriptor_update), + "class_call_check" => Some(HelperName::class_call_check), + "class_check_private_static_access" => Some(HelperName::class_check_private_static_access), + "class_check_private_static_field_descriptor" => { + Some(HelperName::class_check_private_static_field_descriptor) + } + "class_extract_field_descriptor" => Some(HelperName::class_extract_field_descriptor), + "class_name_tdz_error" => Some(HelperName::class_name_tdz_error), + "class_private_field_destructure" => Some(HelperName::class_private_field_destructure), + "class_private_field_get" => Some(HelperName::class_private_field_get), + "class_private_field_init" => Some(HelperName::class_private_field_init), + "class_private_field_loose_base" => Some(HelperName::class_private_field_loose_base), + "class_private_field_loose_key" => Some(HelperName::class_private_field_loose_key), + "class_private_field_set" => Some(HelperName::class_private_field_set), + "class_private_field_update" => Some(HelperName::class_private_field_update), + "class_private_method_get" => Some(HelperName::class_private_method_get), + "class_private_method_init" => Some(HelperName::class_private_method_init), + "class_private_method_set" => Some(HelperName::class_private_method_set), + "class_static_private_field_destructure" => { + Some(HelperName::class_static_private_field_destructure) + } + "class_static_private_field_spec_get" => { + Some(HelperName::class_static_private_field_spec_get) + } + "class_static_private_field_spec_set" => { + Some(HelperName::class_static_private_field_spec_set) + } + "class_static_private_field_update" => Some(HelperName::class_static_private_field_update), + "class_static_private_method_get" => Some(HelperName::class_static_private_method_get), + "construct" => Some(HelperName::construct), + "create_class" => Some(HelperName::create_class), + "create_for_of_iterator_helper_loose" => { + Some(HelperName::create_for_of_iterator_helper_loose) + } + "create_super" => Some(HelperName::create_super), + "decorate" => Some(HelperName::decorate), + "defaults" => Some(HelperName::defaults), + "define_enumerable_properties" => Some(HelperName::define_enumerable_properties), + "define_property" => Some(HelperName::define_property), + "dispose" => Some(HelperName::dispose), + "export_star" => Some(HelperName::export_star), + "extends" => Some(HelperName::extends), + "get" => Some(HelperName::get), + "get_prototype_of" => Some(HelperName::get_prototype_of), + "identity" => Some(HelperName::identity), + "inherits" => Some(HelperName::inherits), + "inherits_loose" => Some(HelperName::inherits_loose), + "initializer_define_property" => Some(HelperName::initializer_define_property), + "initializer_warning_helper" => Some(HelperName::initializer_warning_helper), + "instanceof" => Some(HelperName::instanceof), + "interop_require_default" => Some(HelperName::interop_require_default), + "interop_require_wildcard" => Some(HelperName::interop_require_wildcard), + "is_native_function" => Some(HelperName::is_native_function), + "is_native_reflect_construct" => Some(HelperName::is_native_reflect_construct), + "iterable_to_array" => Some(HelperName::iterable_to_array), + "iterable_to_array_limit" => Some(HelperName::iterable_to_array_limit), + "iterable_to_array_limit_loose" => Some(HelperName::iterable_to_array_limit_loose), + "new_arrow_check" => Some(HelperName::new_arrow_check), + "non_iterable_rest" => Some(HelperName::non_iterable_rest), + "non_iterable_spread" => Some(HelperName::non_iterable_spread), + "object_destructuring_empty" => Some(HelperName::object_destructuring_empty), + "object_spread" => Some(HelperName::object_spread), + "object_spread_props" => Some(HelperName::object_spread_props), + "object_without_properties" => Some(HelperName::object_without_properties), + "object_without_properties_loose" => Some(HelperName::object_without_properties_loose), + "overload_yield" => Some(HelperName::overload_yield), + "possible_constructor_return" => Some(HelperName::possible_constructor_return), + "read_only_error" => Some(HelperName::read_only_error), + "set" => Some(HelperName::set), + "set_prototype_of" => Some(HelperName::set_prototype_of), + "skip_first_generator_next" => Some(HelperName::skip_first_generator_next), + "sliced_to_array" => Some(HelperName::sliced_to_array), + "sliced_to_array_loose" => Some(HelperName::sliced_to_array_loose), + "super_prop_base" => Some(HelperName::super_prop_base), + "tagged_template_literal" => Some(HelperName::tagged_template_literal), + "tagged_template_literal_loose" => Some(HelperName::tagged_template_literal_loose), + "throw" => Some(HelperName::throw), + "to_array" => Some(HelperName::to_array), + "to_consumable_array" => Some(HelperName::to_consumable_array), + "to_primitive" => Some(HelperName::to_primitive), + "to_property_key" => Some(HelperName::to_property_key), + "ts_add_disposable_resource" => Some(HelperName::ts_add_disposable_resource), + "ts_decorate" => Some(HelperName::ts_decorate), + "ts_dispose_resources" => Some(HelperName::ts_dispose_resources), + "ts_generator" => Some(HelperName::ts_generator), + "ts_metadata" => Some(HelperName::ts_metadata), + "ts_param" => Some(HelperName::ts_param), + "ts_rewrite_relative_import_extension" => { + Some(HelperName::ts_rewrite_relative_import_extension) + } + "ts_values" => Some(HelperName::ts_values), + "type_of" => Some(HelperName::type_of), + "unsupported_iterable_to_array" => Some(HelperName::unsupported_iterable_to_array), + "update" => Some(HelperName::update), + "using" => Some(HelperName::using), + "using_ctx" => Some(HelperName::using_ctx), + "wrap_async_generator" => Some(HelperName::wrap_async_generator), + "wrap_native_super" => Some(HelperName::wrap_native_super), + "wrap_reg_exp" => Some(HelperName::wrap_reg_exp), + "write_only_error" => Some(HelperName::write_only_error), + _ => None, + } +} + +impl super::Helpers { + pub fn apply_decorated_descriptor(&self) { + self.enable(HelperName::apply_decorated_descriptor); + } + + pub fn apply_decs_2203_r(&self) { + self.enable(HelperName::apply_decs_2203_r); + } + + pub fn apply_decs_2311(&self) { + self.enable(HelperName::apply_decs_2311); + } + + pub fn array_like_to_array(&self) { + self.enable(HelperName::array_like_to_array); + } + + pub fn array_with_holes(&self) { + self.enable(HelperName::array_with_holes); + } + + pub fn array_without_holes(&self) { + self.enable(HelperName::array_without_holes); + } + + pub fn assert_this_initialized(&self) { + self.enable(HelperName::assert_this_initialized); + } + + pub fn async_generator(&self) { + self.enable(HelperName::async_generator); + } + + pub fn async_generator_delegate(&self) { + self.enable(HelperName::async_generator_delegate); + } + + pub fn async_iterator(&self) { + self.enable(HelperName::async_iterator); + } + + pub fn async_to_generator(&self) { + self.enable(HelperName::async_to_generator); + } + + pub fn await_async_generator(&self) { + self.enable(HelperName::await_async_generator); + } + + pub fn await_value(&self) { + self.enable(HelperName::await_value); + } + + pub fn call_super(&self) { + self.enable(HelperName::call_super); + } + + pub fn check_private_redeclaration(&self) { + self.enable(HelperName::check_private_redeclaration); + } + + pub fn class_apply_descriptor_destructure(&self) { + self.enable(HelperName::class_apply_descriptor_destructure); + } + + pub fn class_apply_descriptor_get(&self) { + self.enable(HelperName::class_apply_descriptor_get); + } + + pub fn class_apply_descriptor_set(&self) { + self.enable(HelperName::class_apply_descriptor_set); + } + + pub fn class_apply_descriptor_update(&self) { + self.enable(HelperName::class_apply_descriptor_update); + } + + pub fn class_call_check(&self) { + self.enable(HelperName::class_call_check); + } + + pub fn class_check_private_static_access(&self) { + self.enable(HelperName::class_check_private_static_access); + } + + pub fn class_check_private_static_field_descriptor(&self) { + self.enable(HelperName::class_check_private_static_field_descriptor); + } + + pub fn class_extract_field_descriptor(&self) { + self.enable(HelperName::class_extract_field_descriptor); + } + + pub fn class_name_tdz_error(&self) { + self.enable(HelperName::class_name_tdz_error); + } + + pub fn class_private_field_destructure(&self) { + self.enable(HelperName::class_private_field_destructure); + } + + pub fn class_private_field_get(&self) { + self.enable(HelperName::class_private_field_get); + } + + pub fn class_private_field_init(&self) { + self.enable(HelperName::class_private_field_init); + } + + pub fn class_private_field_loose_base(&self) { + self.enable(HelperName::class_private_field_loose_base); + } + + pub fn class_private_field_loose_key(&self) { + self.enable(HelperName::class_private_field_loose_key); + } + + pub fn class_private_field_set(&self) { + self.enable(HelperName::class_private_field_set); + } + + pub fn class_private_field_update(&self) { + self.enable(HelperName::class_private_field_update); + } + + pub fn class_private_method_get(&self) { + self.enable(HelperName::class_private_method_get); + } + + pub fn class_private_method_init(&self) { + self.enable(HelperName::class_private_method_init); + } + + pub fn class_private_method_set(&self) { + self.enable(HelperName::class_private_method_set); + } + + pub fn class_static_private_field_destructure(&self) { + self.enable(HelperName::class_static_private_field_destructure); + } + + pub fn class_static_private_field_spec_get(&self) { + self.enable(HelperName::class_static_private_field_spec_get); + } + + pub fn class_static_private_field_spec_set(&self) { + self.enable(HelperName::class_static_private_field_spec_set); + } + + pub fn class_static_private_field_update(&self) { + self.enable(HelperName::class_static_private_field_update); + } + + pub fn class_static_private_method_get(&self) { + self.enable(HelperName::class_static_private_method_get); + } + + pub fn construct(&self) { + self.enable(HelperName::construct); + } + + pub fn create_class(&self) { + self.enable(HelperName::create_class); + } + + pub fn create_for_of_iterator_helper_loose(&self) { + self.enable(HelperName::create_for_of_iterator_helper_loose); + } + + pub fn create_super(&self) { + self.enable(HelperName::create_super); + } + + pub fn decorate(&self) { + self.enable(HelperName::decorate); + } + + pub fn defaults(&self) { + self.enable(HelperName::defaults); + } + + pub fn define_enumerable_properties(&self) { + self.enable(HelperName::define_enumerable_properties); + } + + pub fn define_property(&self) { + self.enable(HelperName::define_property); + } + + pub fn dispose(&self) { + self.enable(HelperName::dispose); + } + + pub fn export_star(&self) { + self.enable(HelperName::export_star); + } + + pub fn extends(&self) { + self.enable(HelperName::extends); + } + + pub fn get(&self) { + self.enable(HelperName::get); + } + + pub fn get_prototype_of(&self) { + self.enable(HelperName::get_prototype_of); + } + + pub fn identity(&self) { + self.enable(HelperName::identity); + } + + pub fn inherits(&self) { + self.enable(HelperName::inherits); + } + + pub fn inherits_loose(&self) { + self.enable(HelperName::inherits_loose); + } + + pub fn initializer_define_property(&self) { + self.enable(HelperName::initializer_define_property); + } + + pub fn initializer_warning_helper(&self) { + self.enable(HelperName::initializer_warning_helper); + } + + pub fn instanceof(&self) { + self.enable(HelperName::instanceof); + } + + pub fn interop_require_default(&self) { + self.enable(HelperName::interop_require_default); + } + + pub fn interop_require_wildcard(&self) { + self.enable(HelperName::interop_require_wildcard); + } + + pub fn is_native_function(&self) { + self.enable(HelperName::is_native_function); + } + + pub fn is_native_reflect_construct(&self) { + self.enable(HelperName::is_native_reflect_construct); + } + + pub fn iterable_to_array(&self) { + self.enable(HelperName::iterable_to_array); + } + + pub fn iterable_to_array_limit(&self) { + self.enable(HelperName::iterable_to_array_limit); + } + + pub fn iterable_to_array_limit_loose(&self) { + self.enable(HelperName::iterable_to_array_limit_loose); + } + + pub fn new_arrow_check(&self) { + self.enable(HelperName::new_arrow_check); + } + + pub fn non_iterable_rest(&self) { + self.enable(HelperName::non_iterable_rest); + } + + pub fn non_iterable_spread(&self) { + self.enable(HelperName::non_iterable_spread); + } + + pub fn object_destructuring_empty(&self) { + self.enable(HelperName::object_destructuring_empty); + } + + pub fn object_spread(&self) { + self.enable(HelperName::object_spread); + } + + pub fn object_spread_props(&self) { + self.enable(HelperName::object_spread_props); + } + + pub fn object_without_properties(&self) { + self.enable(HelperName::object_without_properties); + } + + pub fn object_without_properties_loose(&self) { + self.enable(HelperName::object_without_properties_loose); + } + + pub fn overload_yield(&self) { + self.enable(HelperName::overload_yield); + } + + pub fn possible_constructor_return(&self) { + self.enable(HelperName::possible_constructor_return); + } + + pub fn read_only_error(&self) { + self.enable(HelperName::read_only_error); + } + + pub fn set(&self) { + self.enable(HelperName::set); + } + + pub fn set_prototype_of(&self) { + self.enable(HelperName::set_prototype_of); + } + + pub fn skip_first_generator_next(&self) { + self.enable(HelperName::skip_first_generator_next); + } + + pub fn sliced_to_array(&self) { + self.enable(HelperName::sliced_to_array); + } + + pub fn sliced_to_array_loose(&self) { + self.enable(HelperName::sliced_to_array_loose); + } + + pub fn super_prop_base(&self) { + self.enable(HelperName::super_prop_base); + } + + pub fn tagged_template_literal(&self) { + self.enable(HelperName::tagged_template_literal); + } + + pub fn tagged_template_literal_loose(&self) { + self.enable(HelperName::tagged_template_literal_loose); + } + + pub fn throw(&self) { + self.enable(HelperName::throw); + } + + pub fn to_array(&self) { + self.enable(HelperName::to_array); + } + + pub fn to_consumable_array(&self) { + self.enable(HelperName::to_consumable_array); + } + + pub fn to_primitive(&self) { + self.enable(HelperName::to_primitive); + } + + pub fn to_property_key(&self) { + self.enable(HelperName::to_property_key); + } + + pub fn ts_add_disposable_resource(&self) { + self.enable(HelperName::ts_add_disposable_resource); + } + + pub fn ts_decorate(&self) { + self.enable(HelperName::ts_decorate); + } + + pub fn ts_dispose_resources(&self) { + self.enable(HelperName::ts_dispose_resources); + } + + pub fn ts_generator(&self) { + self.enable(HelperName::ts_generator); + } + + pub fn ts_metadata(&self) { + self.enable(HelperName::ts_metadata); + } + + pub fn ts_param(&self) { + self.enable(HelperName::ts_param); + } + + pub fn ts_rewrite_relative_import_extension(&self) { + self.enable(HelperName::ts_rewrite_relative_import_extension); + } + + pub fn ts_values(&self) { + self.enable(HelperName::ts_values); + } + + pub fn type_of(&self) { + self.enable(HelperName::type_of); + } + + pub fn unsupported_iterable_to_array(&self) { + self.enable(HelperName::unsupported_iterable_to_array); + } + + pub fn update(&self) { + self.enable(HelperName::update); + } + + pub fn using(&self) { + self.enable(HelperName::using); + } + + pub fn using_ctx(&self) { + self.enable(HelperName::using_ctx); + } + + pub fn wrap_async_generator(&self) { + self.enable(HelperName::wrap_async_generator); + } + + pub fn wrap_native_super(&self) { + self.enable(HelperName::wrap_native_super); + } + + pub fn wrap_reg_exp(&self) { + self.enable(HelperName::wrap_reg_exp); + } + + pub fn write_only_error(&self) { + self.enable(HelperName::write_only_error); + } +} + +#[cfg(feature = "inline-helpers")] +pub fn stmts(name: HelperName) -> &'static [swc_ecma_ast::Stmt] { + match name { + HelperName::apply_decorated_descriptor => _apply_decorated_descriptor::stmts(), + HelperName::apply_decs_2203_r => _apply_decs_2203_r::stmts(), + HelperName::apply_decs_2311 => _apply_decs_2311::stmts(), + HelperName::array_like_to_array => _array_like_to_array::stmts(), + HelperName::array_with_holes => _array_with_holes::stmts(), + HelperName::array_without_holes => _array_without_holes::stmts(), + HelperName::assert_this_initialized => _assert_this_initialized::stmts(), + HelperName::async_generator => _async_generator::stmts(), + HelperName::async_generator_delegate => _async_generator_delegate::stmts(), + HelperName::async_iterator => _async_iterator::stmts(), + HelperName::async_to_generator => _async_to_generator::stmts(), + HelperName::await_async_generator => _await_async_generator::stmts(), + HelperName::await_value => _await_value::stmts(), + HelperName::call_super => _call_super::stmts(), + HelperName::check_private_redeclaration => _check_private_redeclaration::stmts(), + HelperName::class_apply_descriptor_destructure => { + _class_apply_descriptor_destructure::stmts() + } + HelperName::class_apply_descriptor_get => _class_apply_descriptor_get::stmts(), + HelperName::class_apply_descriptor_set => _class_apply_descriptor_set::stmts(), + HelperName::class_apply_descriptor_update => _class_apply_descriptor_update::stmts(), + HelperName::class_call_check => _class_call_check::stmts(), + HelperName::class_check_private_static_access => { + _class_check_private_static_access::stmts() + } + HelperName::class_check_private_static_field_descriptor => { + _class_check_private_static_field_descriptor::stmts() + } + HelperName::class_extract_field_descriptor => _class_extract_field_descriptor::stmts(), + HelperName::class_name_tdz_error => _class_name_tdz_error::stmts(), + HelperName::class_private_field_destructure => _class_private_field_destructure::stmts(), + HelperName::class_private_field_get => _class_private_field_get::stmts(), + HelperName::class_private_field_init => _class_private_field_init::stmts(), + HelperName::class_private_field_loose_base => _class_private_field_loose_base::stmts(), + HelperName::class_private_field_loose_key => _class_private_field_loose_key::stmts(), + HelperName::class_private_field_set => _class_private_field_set::stmts(), + HelperName::class_private_field_update => _class_private_field_update::stmts(), + HelperName::class_private_method_get => _class_private_method_get::stmts(), + HelperName::class_private_method_init => _class_private_method_init::stmts(), + HelperName::class_private_method_set => _class_private_method_set::stmts(), + HelperName::class_static_private_field_destructure => { + _class_static_private_field_destructure::stmts() + } + HelperName::class_static_private_field_spec_get => { + _class_static_private_field_spec_get::stmts() + } + HelperName::class_static_private_field_spec_set => { + _class_static_private_field_spec_set::stmts() + } + HelperName::class_static_private_field_update => { + _class_static_private_field_update::stmts() + } + HelperName::class_static_private_method_get => _class_static_private_method_get::stmts(), + HelperName::construct => _construct::stmts(), + HelperName::create_class => _create_class::stmts(), + HelperName::create_for_of_iterator_helper_loose => { + _create_for_of_iterator_helper_loose::stmts() + } + HelperName::create_super => _create_super::stmts(), + HelperName::decorate => _decorate::stmts(), + HelperName::defaults => _defaults::stmts(), + HelperName::define_enumerable_properties => _define_enumerable_properties::stmts(), + HelperName::define_property => _define_property::stmts(), + HelperName::dispose => _dispose::stmts(), + HelperName::export_star => _export_star::stmts(), + HelperName::extends => _extends::stmts(), + HelperName::get => _get::stmts(), + HelperName::get_prototype_of => _get_prototype_of::stmts(), + HelperName::identity => _identity::stmts(), + HelperName::inherits => _inherits::stmts(), + HelperName::inherits_loose => _inherits_loose::stmts(), + HelperName::initializer_define_property => _initializer_define_property::stmts(), + HelperName::initializer_warning_helper => _initializer_warning_helper::stmts(), + HelperName::instanceof => _instanceof::stmts(), + HelperName::interop_require_default => _interop_require_default::stmts(), + HelperName::interop_require_wildcard => _interop_require_wildcard::stmts(), + HelperName::is_native_function => _is_native_function::stmts(), + HelperName::is_native_reflect_construct => _is_native_reflect_construct::stmts(), + HelperName::iterable_to_array => _iterable_to_array::stmts(), + HelperName::iterable_to_array_limit => _iterable_to_array_limit::stmts(), + HelperName::iterable_to_array_limit_loose => _iterable_to_array_limit_loose::stmts(), + HelperName::new_arrow_check => _new_arrow_check::stmts(), + HelperName::non_iterable_rest => _non_iterable_rest::stmts(), + HelperName::non_iterable_spread => _non_iterable_spread::stmts(), + HelperName::object_destructuring_empty => _object_destructuring_empty::stmts(), + HelperName::object_spread => _object_spread::stmts(), + HelperName::object_spread_props => _object_spread_props::stmts(), + HelperName::object_without_properties => _object_without_properties::stmts(), + HelperName::object_without_properties_loose => _object_without_properties_loose::stmts(), + HelperName::overload_yield => _overload_yield::stmts(), + HelperName::possible_constructor_return => _possible_constructor_return::stmts(), + HelperName::read_only_error => _read_only_error::stmts(), + HelperName::set => _set::stmts(), + HelperName::set_prototype_of => _set_prototype_of::stmts(), + HelperName::skip_first_generator_next => _skip_first_generator_next::stmts(), + HelperName::sliced_to_array => _sliced_to_array::stmts(), + HelperName::sliced_to_array_loose => _sliced_to_array_loose::stmts(), + HelperName::super_prop_base => _super_prop_base::stmts(), + HelperName::tagged_template_literal => _tagged_template_literal::stmts(), + HelperName::tagged_template_literal_loose => _tagged_template_literal_loose::stmts(), + HelperName::throw => _throw::stmts(), + HelperName::to_array => _to_array::stmts(), + HelperName::to_consumable_array => _to_consumable_array::stmts(), + HelperName::to_primitive => _to_primitive::stmts(), + HelperName::to_property_key => _to_property_key::stmts(), + HelperName::ts_add_disposable_resource => _ts_add_disposable_resource::stmts(), + HelperName::ts_decorate => _ts_decorate::stmts(), + HelperName::ts_dispose_resources => _ts_dispose_resources::stmts(), + HelperName::ts_generator => _ts_generator::stmts(), + HelperName::ts_metadata => _ts_metadata::stmts(), + HelperName::ts_param => _ts_param::stmts(), + HelperName::ts_rewrite_relative_import_extension => { + _ts_rewrite_relative_import_extension::stmts() + } + HelperName::ts_values => _ts_values::stmts(), + HelperName::type_of => _type_of::stmts(), + HelperName::unsupported_iterable_to_array => _unsupported_iterable_to_array::stmts(), + HelperName::update => _update::stmts(), + HelperName::using => _using::stmts(), + HelperName::using_ctx => _using_ctx::stmts(), + HelperName::wrap_async_generator => _wrap_async_generator::stmts(), + HelperName::wrap_native_super => _wrap_native_super::stmts(), + HelperName::wrap_reg_exp => _wrap_reg_exp::stmts(), + HelperName::write_only_error => _write_only_error::stmts(), + } +} diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/mod.rs b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/mod.rs index e8d4120a6..855212885 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/helpers/mod.rs +++ b/deps/swc/crates/swc_ecma_transforms_base/src/helpers/mod.rs @@ -6,22 +6,28 @@ use swc_ecma_ast::*; use swc_ecma_utils::{prepend_stmts, quote_ident, DropSpan, ExprFactory}; use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith}; +#[doc(hidden)] +pub mod generated; + +use generated::{HelperBitmap, HelperName}; + #[macro_export] macro_rules! enable_helper { ($i:ident) => {{ $crate::helpers::HELPERS.with(|helpers| { - helpers.$i(); + let helper = $crate::helpers::generated::HelperName::$i; + helpers.enable(helper); helpers.mark() }) }}; } #[cfg(feature = "inline-helpers")] -fn parse(code: &str) -> Vec { +fn parse(code: &str, path: &str) -> Vec { let cm = swc_common::SourceMap::default(); let fm = cm.new_source_file( - swc_common::FileName::Custom(stringify!($name).into()).into(), + swc_common::FileName::Custom(path.into()).into(), code.to_string(), ); swc_ecma_parser::parse_file_as_script( @@ -41,55 +47,6 @@ fn parse(code: &str) -> Vec { .unwrap() } -#[cfg(feature = "inline-helpers")] -macro_rules! add_to { - ($buf:expr, $name:ident, $b:expr, $mark:expr) => {{ - static STMTS: once_cell::sync::Lazy> = once_cell::sync::Lazy::new(|| { - let code = include_str!(concat!("./_", stringify!($name), ".js")); - parse(&code) - }); - - let enable = $b; - if enable { - $buf.extend(STMTS.iter().cloned().map(|mut stmt| { - stmt.visit_mut_with(&mut Marker { - base: SyntaxContext::empty().apply_mark($mark), - decls: Default::default(), - - decl_ctxt: SyntaxContext::empty().apply_mark(Mark::new()), - }); - stmt - })) - } - }}; -} - -macro_rules! add_import_to { - ($buf:expr, $name:ident, $b:expr, $mark:expr) => {{ - let enable = $b; - if enable { - let ctxt = SyntaxContext::empty().apply_mark($mark); - let s = ImportSpecifier::Named(ImportNamedSpecifier { - span: DUMMY_SP, - local: Ident::new(concat!("_", stringify!($name)).into(), DUMMY_SP, ctxt), - imported: Some(quote_ident!("_").into()), - is_type_only: false, - }); - - let src: Str = concat!("@swc/helpers/_/_", stringify!($name)).into(); - - $buf.push(ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { - span: DUMMY_SP, - specifiers: vec![s], - src: Box::new(src), - with: Default::default(), - type_only: Default::default(), - phase: Default::default(), - }))) - } - }}; -} - better_scoped_tls::scoped_tls!( /// This variable is used to manage helper scripts like `_inherits` from babel. /// @@ -154,274 +111,43 @@ impl Default for HelperMark { } } -macro_rules! define_helpers { - ( - Helpers { - $( $name:ident : ( $( $dep:ident ),* ), )* - } - ) => { - #[derive(Debug,Default, Clone, Copy)] - struct Inner { - $( $name: bool, )* - } - - impl Helpers { - $( - pub fn $name(&self) { - self.inner.borrow_mut().$name = true; - - if !self.external { - $( - self.$dep(); - )* - } - } - )* - } - - - impl Helpers { - pub fn extend_from(&self, other: &Self) { - let other = other.inner.borrow(); - let mut me = self.inner.borrow_mut(); - $( - if other.$name { - me.$name = true; - } - )* - } - } - - impl InjectHelpers { - fn is_helper_used(&self) -> bool{ - - HELPERS.with(|helpers|{ - let inner = helpers.inner.borrow(); - false $( - || inner.$name - )* - }) - } +#[derive(Debug, Clone, Copy, Default)] +struct Inner { + used: HelperBitmap, +} - #[cfg(feature = "inline-helpers")] - fn build_helpers(&self) -> Vec { - let mut buf = Vec::new(); +impl Inner { + fn enable(&mut self, name: HelperName) { + self.used.insert(name); + } - HELPERS.with(|helpers|{ - let inner = helpers.inner.borrow(); - $( - add_to!(buf, $name, inner.$name, helpers.mark.0); - )* - }); + fn extend_from(&mut self, other: &Self) { + self.used |= other.used; + } - buf - } + fn is_enabled(&self, name: HelperName) -> bool { + self.used.contains(name) + } - fn build_imports(&self) -> Vec { - let mut buf = Vec::new(); + fn any(&self) -> bool { + !self.used.is_empty() + } +} - HELPERS.with(|helpers|{ - let inner = helpers.inner.borrow(); - $( - add_import_to!(buf, $name, inner.$name, helpers.mark.0); - )* - }); +impl Helpers { + #[doc(hidden)] + pub fn enable(&self, name: HelperName) { + self.inner.borrow_mut().enable(name); + } - buf - } + pub fn extend_from(&self, other: &Self) { + let other = other.inner.borrow(); + let mut me = self.inner.borrow_mut(); - fn build_requires(&self) -> Vec{ - let mut buf = Vec::new(); - HELPERS.with(|helpers|{ - let inner = helpers.inner.borrow(); - $( - let enable = inner.$name; - if enable { - buf.push(self.build_reqire(stringify!($name), helpers.mark.0)) - } - // add_require_to!(buf, $name, helpers.inner.$name, helpers.mark.0, self.global_mark); - )* - }); - buf - } - } - }; + me.extend_from(&other); + } } -define_helpers!(Helpers { - apply_decorated_descriptor: (), - array_like_to_array: (), - array_with_holes: (), - array_without_holes: (array_like_to_array), - assert_this_initialized: (), - async_generator: (overload_yield), - async_generator_delegate: (overload_yield), - async_iterator: (), - async_to_generator: (), - await_async_generator: (overload_yield), - await_value: (), - call_super: ( - get_prototype_of, - is_native_reflect_construct, - possible_constructor_return - ), - check_private_redeclaration: (), - class_apply_descriptor_destructure: (), - class_apply_descriptor_get: (), - class_apply_descriptor_set: (), - class_apply_descriptor_update: (), - class_call_check: (), - class_check_private_static_field_descriptor: (), - class_extract_field_descriptor: (), - class_name_tdz_error: (), - class_private_field_get: (class_extract_field_descriptor, class_apply_descriptor_get), - class_private_field_init: (check_private_redeclaration), - class_private_field_loose_base: (), - class_private_field_loose_key: (), - class_private_field_set: (class_extract_field_descriptor, class_apply_descriptor_set), - class_private_field_update: ( - class_extract_field_descriptor, - class_apply_descriptor_update - ), - class_private_method_get: (), - class_private_method_init: (check_private_redeclaration), - class_private_method_set: (), - class_static_private_field_spec_get: ( - class_check_private_static_access, - class_check_private_static_field_descriptor, - class_apply_descriptor_get - ), - class_static_private_field_spec_set: ( - class_check_private_static_access, - class_check_private_static_field_descriptor, - class_apply_descriptor_set - ), - class_static_private_field_update: ( - class_check_private_static_access, - class_check_private_static_field_descriptor, - class_apply_descriptor_update - ), - construct: (is_native_reflect_construct, set_prototype_of), - create_class: (), - decorate: (to_array, to_property_key), - defaults: (), - define_enumerable_properties: (), - define_property: (), - export_star: (), - extends: (), - get: (super_prop_base), - get_prototype_of: (), - inherits: (set_prototype_of), - inherits_loose: (), - initializer_define_property: (), - initializer_warning_helper: (), - instanceof: (), - interop_require_default: (), - interop_require_wildcard: (), - is_native_function: (), - iterable_to_array: (), - iterable_to_array_limit: (), - iterable_to_array_limit_loose: (), - jsx: (), - new_arrow_check: (), - non_iterable_rest: (), - non_iterable_spread: (), - object_destructuring_empty: (), - object_spread: (define_property), - object_spread_props: (), - object_without_properties: (object_without_properties_loose), - object_without_properties_loose: (), - overload_yield: (), - possible_constructor_return: (type_of, assert_this_initialized), - read_only_error: (), - set: (super_prop_base, define_property), - set_prototype_of: (), - skip_first_generator_next: (), - sliced_to_array: ( - array_with_holes, - iterable_to_array_limit, - unsupported_iterable_to_array, - non_iterable_rest - ), - sliced_to_array_loose: ( - array_with_holes, - iterable_to_array_limit_loose, - unsupported_iterable_to_array, - non_iterable_rest - ), - super_prop_base: (get_prototype_of), - tagged_template_literal: (), - tagged_template_literal_loose: (), - // temporal_ref: (temporal_undefined), - // temporal_undefined: (), - throw: (), - to_array: ( - array_with_holes, - iterable_to_array, - unsupported_iterable_to_array, - non_iterable_rest - ), - to_consumable_array: ( - array_without_holes, - iterable_to_array, - unsupported_iterable_to_array, - non_iterable_spread - ), - to_primitive: (type_of), - to_property_key: (type_of, to_primitive), - update: (get, set), - type_of: (), - unsupported_iterable_to_array: (array_like_to_array), - wrap_async_generator: (async_generator), - wrap_native_super: ( - construct, - get_prototype_of, - set_prototype_of, - is_native_function - ), - wrap_reg_exp: (inherits, set_prototype_of), - write_only_error: (), - - class_private_field_destructure: ( - class_extract_field_descriptor, - class_apply_descriptor_destructure - ), - class_static_private_field_destructure: ( - class_check_private_static_access, - class_extract_field_descriptor, - class_apply_descriptor_destructure - ), - - class_static_private_method_get: (class_check_private_static_access), - class_check_private_static_access: (), - - is_native_reflect_construct: (), - - create_super: ( - get_prototype_of, - is_native_reflect_construct, - possible_constructor_return - ), - - create_for_of_iterator_helper_loose: (unsupported_iterable_to_array), - - ts_decorate: (), - ts_generator: (), - ts_metadata: (), - ts_param: (), - ts_values: (), - ts_add_disposable_resource: (), - ts_dispose_resources: (), - ts_rewrite_relative_import_extension: (), - - apply_decs_2203_r: (), - apply_decs_2311: (), - identity: (), - dispose: (), - using: (), - using_ctx: (), -}); - pub fn inject_helpers(global_mark: Mark) -> impl Pass + VisitMut { visit_mut_pass(InjectHelpers { global_mark, @@ -435,6 +161,96 @@ struct InjectHelpers { } impl InjectHelpers { + fn is_helper_used(&self) -> bool { + HELPERS.with(|helpers| helpers.inner.borrow().any()) + } + + #[cfg(feature = "inline-helpers")] + fn build_helpers(&self) -> Vec { + let (required, mark) = HELPERS.with(|helpers| { + let inner = helpers.inner.borrow(); + let mut required = HelperBitmap::EMPTY; + + for helper in generated::ALL { + if inner.is_enabled(helper.name) { + required |= helper.deps; + } + } + + (required, helpers.mark.0) + }); + + let base = SyntaxContext::empty().apply_mark(mark); + let mut buf = Vec::new(); + + for helper in generated::ALL { + if required.contains(helper.name) { + buf.extend( + generated::stmts(helper.name) + .iter() + .cloned() + .map(|mut stmt| { + stmt.visit_mut_with(&mut Marker { + base, + decls: Default::default(), + decl_ctxt: SyntaxContext::empty().apply_mark(Mark::new()), + }); + stmt + }), + ); + } + } + + buf + } + + fn build_imports(&self) -> Vec { + let mut buf = Vec::new(); + + HELPERS.with(|helpers| { + let inner = helpers.inner.borrow(); + let ctxt = SyntaxContext::empty().apply_mark(helpers.mark.0); + + for helper in generated::ALL { + if inner.is_enabled(helper.name) { + let specifier = ImportSpecifier::Named(ImportNamedSpecifier { + span: DUMMY_SP, + local: Ident::new(helper.local.into(), DUMMY_SP, ctxt), + imported: Some(quote_ident!("_").into()), + is_type_only: false, + }); + + buf.push(ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { + span: DUMMY_SP, + specifiers: vec![specifier], + src: Box::new(Str::from(helper.import_path)), + with: Default::default(), + type_only: Default::default(), + phase: Default::default(), + }))); + } + } + }); + + buf + } + + fn build_requires(&self) -> Vec { + let mut buf = Vec::new(); + + HELPERS.with(|helpers| { + let inner = helpers.inner.borrow(); + + for helper in generated::ALL { + if inner.is_enabled(helper.name) { + buf.push(self.build_reqire(helper, helpers.mark.0)); + } + } + }); + + buf + } + #[allow(unused_variables)] fn make_helpers_for_module(&mut self) -> Vec { let (helper_mark, external) = HELPERS.with(|helper| (helper.mark(), helper.external())); @@ -473,7 +289,7 @@ impl InjectHelpers { } } - fn build_reqire(&self, name: &str, mark: Mark) -> Stmt { + fn build_reqire(&self, helper: &generated::HelperDef, mark: Mark) -> Stmt { let c = CallExpr { span: DUMMY_SP, callee: Expr::from(Ident { @@ -485,7 +301,7 @@ impl InjectHelpers { .as_callee(), args: vec![Str { span: DUMMY_SP, - value: format!("@swc/helpers/_/_{name}").into(), + value: helper.import_path.into(), raw: None, } .as_arg()], @@ -496,7 +312,7 @@ impl InjectHelpers { kind: VarDeclKind::Var, decls: vec![VarDeclarator { span: DUMMY_SP, - name: Pat::Ident(Ident::new(format!("_{name}").into(), DUMMY_SP, ctxt).into()), + name: Pat::Ident(Ident::new(helper.local.into(), DUMMY_SP, ctxt).into()), init: Some(c.into()), definite: false, }], @@ -728,6 +544,45 @@ let _throw1 = null; ) } + #[test] + #[cfg(feature = "inline-helpers")] + fn inline_helper_dependencies() { + let input = "_to_consumable_array(foo);"; + crate::tests::Tester::run(|tester| { + HELPERS.set(&Helpers::new(false), || { + enable_helper!(to_consumable_array); + + let tr = inject_helpers(Mark::new()); + let actual = tester + .apply_transform(tr, "input.js", Default::default(), input)? + .apply(crate::hygiene::hygiene()) + .apply(crate::fixer::fixer(None)); + let actual_src = tester.print(&actual); + + for helper in [ + "_array_like_to_array", + "_array_without_holes", + "_iterable_to_array", + "_non_iterable_spread", + "_to_consumable_array", + "_unsupported_iterable_to_array", + ] { + assert!( + actual_src.contains(&format!("function {helper}(")), + "expected inline helper `{helper}` in output:\n{actual_src}" + ); + } + + assert!( + !actual_src.contains("@swc/helpers"), + "inline helpers should not emit external imports:\n{actual_src}" + ); + + Ok(()) + }) + }); + } + #[test] fn use_strict_abort() { crate::tests::test_transform( @@ -810,7 +665,7 @@ let x = 4;", if (error !== empty) throw error; } function err(e) { - error = error !== empty ? new _disposeSuppressedError(error, e) : e; + error = error !== empty ? new _disposeSuppressedError(e, error) : e; return next(); } return next(); diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/hygiene/mod.rs b/deps/swc/crates/swc_ecma_transforms_base/src/hygiene/mod.rs index 3224ddc6e..b69ace488 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/hygiene/mod.rs +++ b/deps/swc/crates/swc_ecma_transforms_base/src/hygiene/mod.rs @@ -23,10 +23,20 @@ pub struct Config { pub ignore_eval: bool, } +// https://github.com/swc-project/swc/issues/9791 +impl Config { + pub fn hygiene_default() -> Self { + Self { + ignore_eval: true, + ..Default::default() + } + } +} + /// See [hygiene_with_config] for doc. Creates a `hygiene` pass with default /// value of [Config]. pub fn hygiene() -> impl Pass + VisitMut { - hygiene_with_config(Default::default()) + hygiene_with_config(Config::hygiene_default()) } /// The pass actually modifies the identifiers in the way that different diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/rename/analyzer/mod.rs b/deps/swc/crates/swc_ecma_transforms_base/src/rename/analyzer/mod.rs index 3271c2be6..adc9bd4d1 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/rename/analyzer/mod.rs +++ b/deps/swc/crates/swc_ecma_transforms_base/src/rename/analyzer/mod.rs @@ -1,3 +1,4 @@ +use swc_atoms::atom; use swc_common::Mark; use swc_ecma_ast::*; @@ -180,8 +181,16 @@ impl Analyzer { } pub(super) fn handle_expr(&mut self, e: &Expr) { - if let Expr::Ident(i) = e { - self.add_usage(i.to_id()); + match e { + Expr::Ident(i) => self.add_usage(i.to_id()), + Expr::Lit(Lit::Num(num)) if !num.value.is_finite() => match num.raw.as_deref() { + Some("NaN") => self.scope.reserve_output_symbol(atom!("NaN")), + Some("Infinity") => { + self.scope.reserve_output_symbol(atom!("Infinity")); + } + _ => {} + }, + _ => {} } } diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/rename/analyzer/scope.rs b/deps/swc/crates/swc_ecma_transforms_base/src/rename/analyzer/scope.rs index 4e1f92dee..da62953dd 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/rename/analyzer/scope.rs +++ b/deps/swc/crates/swc_ecma_transforms_base/src/rename/analyzer/scope.rs @@ -42,6 +42,10 @@ pub(super) struct ScopeData { all: FxHashSet, queue: FxIndexSet, + + /// Names emitted by non-identifier expressions in this scope or its + /// descendants. Renamed bindings must not capture these names. + reserved_output_symbols: FxHashSet, } impl Scope { @@ -75,6 +79,10 @@ impl Scope { self.data.all.insert(id); } + pub(super) fn reserve_output_symbol(&mut self, symbol: Atom) { + self.data.reserved_output_symbols.insert(symbol); + } + pub(crate) fn reserve_usage(&mut self, len: usize) { self.data.all.reserve(len); } @@ -85,6 +93,9 @@ impl Scope { child.prepare_renaming(); self.data.all.extend(child.data.all.iter().cloned()); + self.data + .reserved_output_symbols + .extend(child.data.reserved_output_symbols.iter().cloned()); }); } @@ -159,7 +170,9 @@ impl Scope { loop { let sym = renamer.new_name_for(&id, &mut n); - if preserved_symbols.contains(&sym) { + if preserved_symbols.contains(&sym) + || self.data.reserved_output_symbols.contains(&sym) + { continue; } @@ -305,7 +318,9 @@ impl Scope { let sym = renamer.new_name_for(&id, &mut n); // TODO: Use base54::decode - if preserved_symbols.contains(&sym) { + if preserved_symbols.contains(&sym) + || self.data.reserved_output_symbols.contains(&sym) + { continue; } diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/rename/mod.rs b/deps/swc/crates/swc_ecma_transforms_base/src/rename/mod.rs index bca6a153e..c0efba0c1 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/rename/mod.rs +++ b/deps/swc/crates/swc_ecma_transforms_base/src/rename/mod.rs @@ -311,6 +311,24 @@ where } } + // Drop identity mappings before apply. Operator already no-ops when + // `sym == ident.sym`, so they only inflate the apply walk. + // + // Identities must still be inserted into `map` *during* analysis so + // later scopes can skip via `to.get(id)`. Without that (e.g. hygiene + // alone, no resolver), the same Id is reprocessed in every scope and + // the reverse map blows up. + // + // Keep identities when `keep_class_names` is set: Operator uses that + // flag to rewrite `class Foo` into `let Foo = class Foo`, and on the + // old path those identity entries were what kept the map non-empty so + // Operator ran. Minifier `keep_classnames` preserves class Ids instead + // (they never enter the map), so this does not reintroduce apply work + // for those fixtures. + if !self.config.keep_class_names { + map.retain(|id, v| v.atom() != &id.0); + } + map } diff --git a/deps/swc/crates/swc_ecma_transforms_base/src/resolver/mod.rs b/deps/swc/crates/swc_ecma_transforms_base/src/resolver/mod.rs index c07694088..f23df821f 100644 --- a/deps/swc/crates/swc_ecma_transforms_base/src/resolver/mod.rs +++ b/deps/swc/crates/swc_ecma_transforms_base/src/resolver/mod.rs @@ -528,6 +528,7 @@ impl VisitMut for Resolver<'_> { fn visit_mut_arrow_expr(&mut self, e: &mut ArrowExpr) { self.with_child(ScopeKind::Fn, |child| { + child.mark_block(&mut e.ctxt); e.type_params.visit_mut_with(child); let old = child.ident_type; @@ -719,6 +720,7 @@ impl VisitMut for Resolver<'_> { } self.with_child(ScopeKind::Fn, |child| { + child.mark_block(&mut c.ctxt); let old = child.ident_type; child.ident_type = IdentType::Binding; { diff --git a/deps/swc/crates/swc_ecma_transforms_classes/Cargo.toml b/deps/swc/crates/swc_ecma_transforms_classes/Cargo.toml index 905357278..88a5b25d0 100644 --- a/deps/swc/crates/swc_ecma_transforms_classes/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transforms_classes/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_transforms_classes" repository = { workspace = true } -version = "44.0.0" +version = "47.0.0" [lib] bench = false @@ -15,8 +15,8 @@ bench = false unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [dependencies] -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } diff --git a/deps/swc/crates/swc_ecma_transforms_compat/Cargo.toml b/deps/swc/crates/swc_ecma_transforms_compat/Cargo.toml index cfbfc5d3c..7dfe28d11 100644 --- a/deps/swc/crates/swc_ecma_transforms_compat/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transforms_compat/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_transforms_compat" repository = { workspace = true } -version = "52.0.1" +version = "55.0.0" [lib] bench = false @@ -29,31 +29,31 @@ par-core = { workspace = true } serde = { workspace = true, features = ["derive"] } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_compat_bugfixes = { version = "51.0.0", path = "../swc_ecma_compat_bugfixes" } -swc_ecma_compat_common = { version = "40.0.1", path = "../swc_ecma_compat_common" } -swc_ecma_compat_es2015 = { version = "50.0.0", path = "../swc_ecma_compat_es2015" } -swc_ecma_compat_es2016 = { version = "45.0.0", path = "../swc_ecma_compat_es2016" } -swc_ecma_compat_es2017 = { version = "45.0.0", path = "../swc_ecma_compat_es2017" } -swc_ecma_compat_es2018 = { version = "46.0.0", path = "../swc_ecma_compat_es2018" } -swc_ecma_compat_es2019 = { version = "45.0.0", path = "../swc_ecma_compat_es2019" } -swc_ecma_compat_es2020 = { version = "48.0.0", path = "../swc_ecma_compat_es2020" } -swc_ecma_compat_es2021 = { version = "45.0.0", path = "../swc_ecma_compat_es2021" } -swc_ecma_compat_es2022 = { version = "48.0.0", path = "../swc_ecma_compat_es2022" } -swc_ecma_compat_es3 = { version = "36.0.0", path = "../swc_ecma_compat_es3", optional = true } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_compat_bugfixes = { version = "54.0.0", path = "../swc_ecma_compat_bugfixes" } +swc_ecma_compat_common = { version = "43.0.0", path = "../swc_ecma_compat_common" } +swc_ecma_compat_es2015 = { version = "53.0.0", path = "../swc_ecma_compat_es2015" } +swc_ecma_compat_es2016 = { version = "48.0.0", path = "../swc_ecma_compat_es2016" } +swc_ecma_compat_es2017 = { version = "48.0.0", path = "../swc_ecma_compat_es2017" } +swc_ecma_compat_es2018 = { version = "49.0.0", path = "../swc_ecma_compat_es2018" } +swc_ecma_compat_es2019 = { version = "48.0.0", path = "../swc_ecma_compat_es2019" } +swc_ecma_compat_es2020 = { version = "51.0.0", path = "../swc_ecma_compat_es2020" } +swc_ecma_compat_es2021 = { version = "48.0.0", path = "../swc_ecma_compat_es2021" } +swc_ecma_compat_es2022 = { version = "51.0.0", path = "../swc_ecma_compat_es2022" } +swc_ecma_compat_es3 = { version = "39.0.0", path = "../swc_ecma_compat_es3", optional = true } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] par-core = { workspace = true, features = ["chili"] } serde_json = { workspace = true } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base", features = [ +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base", features = [ "inline-helpers", ] } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } -testing = { version = "24.0.1", path = "../testing" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_ecma_transforms_module/Cargo.toml b/deps/swc/crates/swc_ecma_transforms_module/Cargo.toml index 8b3208eb0..857ff9fdf 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transforms_module/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_transforms_module" repository = { workspace = true } -version = "49.0.1" +version = "53.0.0" [lib] bench = false @@ -28,31 +28,31 @@ rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_config = { version = "5.0.0", path = "../swc_config", features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_config = { version = "6.0.0", path = "../swc_config", features = [ "file_pattern", ] } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_loader = { version = "24.0.1", path = "../swc_ecma_loader", features = [ +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_loader = { version = "25.0.0", path = "../swc_ecma_loader", features = [ ] } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] indexmap = { workspace = true, features = ["serde"] } serde_json = { workspace = true } tempfile = { workspace = true } -swc_ecma_loader = { version = "24.0.1", path = "../swc_ecma_loader", features = [ +swc_ecma_loader = { version = "25.0.0", path = "../swc_ecma_loader", features = [ "node", "tsc", ] } -swc_ecma_transforms_compat = { version = "52.0.1", path = "../swc_ecma_transforms_compat" } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } -swc_ecma_transforms_typescript = { version = "50.0.0", path = "../swc_ecma_transforms_typescript" } -testing = { version = "24.0.1", path = "../testing/" } +swc_ecma_transforms_compat = { version = "55.0.0", path = "../swc_ecma_transforms_compat" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } +swc_ecma_transforms_typescript = { version = "53.0.0", path = "../swc_ecma_transforms_typescript" } +testing = { version = "25.0.0", path = "../testing/" } diff --git a/deps/swc/crates/swc_ecma_transforms_module/README.md b/deps/swc/crates/swc_ecma_transforms_module/README.md new file mode 100644 index 000000000..a53d99795 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/README.md @@ -0,0 +1,390 @@ +# Module Transforms + +This crate lowers ECMAScript module syntax into several legacy module formats. +The CommonJS, AMD, and UMD passes share one source-module collection and +reduction model, then diverge at the format-specific import/export emit +boundary. The SystemJS pass also reuses source-module collection, but it lowers +the collected records into a SystemJS-specific IR instead of using the shared +CommonJS-like reducer. + +```mermaid +flowchart TD + Input["Input ECMAScript module AST"] + TopLevelThis["Top-level this rewrite"] + Source["SourceModule::collect"] + Strip["syntax_strip::lower"] + Reducer["ModuleRecordEntryReducer"] + Rewrite["ImportMap and export getter list"] + Cjs["CommonJS emitter"] + Amd["AMD emitter"] + Umd["UMD emitter"] + SysLower["SystemJS lower"] + SysRewrite["SystemJS rewrite"] + SysEmit["SystemJS emitter"] + CjsOut["require calls, export getters, and module.exports"] + AmdOut["define dependency array and factory body"] + UmdOut["adapter IIFE and shared factory body"] + SysOut["System.register call"] + + Input --> TopLevelThis --> Source + Source --> Strip --> Reducer --> Rewrite + Rewrite --> Cjs --> CjsOut + Rewrite --> Amd --> AmdOut + Rewrite --> Umd --> UmdOut + Source --> SysLower --> SysRewrite --> SysEmit --> SysOut +``` + +SystemJS is documented separately below because its live-binding and execution +model is organized around `System.register`, dependency setters, and an +`execute` function. + +## Shared Terminology + +The shared collector in `src/module_record.rs` intentionally uses names close +to the ECMAScript module record vocabulary: + +- `SourceModule::collect` walks source module declarations, records their + module linkage information, and keeps ordered executable source items. +- `SourceModuleItem` keeps declarations that target lowerers still need to + lower, including exported declarations, default exports, and external + TypeScript `import = require(...)`. +- `RequestedModules` is grouped by `ModuleRequestRecord` and preserves source + order with `IndexMap`. +- `ModuleRequestRecord` stores the module specifier and normalized import + attributes for that request. +- `RequestedModule` stores the first useful source span, the collected + `ModuleRecordEntry` set, and `ModuleRequestUsage`. +- `LocalExportEntries` stores local exports keyed by exported name. +- `ModuleRecordEntry` represents import entries, indirect export entries, and + star exports. +- `syntax_strip::lower` converts `SourceModule` into `SyntaxStrippedModule` for + the CommonJS, AMD, and UMD passes. +- `ModuleRecordEntryReducer` converts collected entries into emitter-facing + structures: an `ImportMap` for rewritten local references and an + `ExportObjectProperties` list for generated export getters. + +`SourceModule` is a target-neutral collection model, not a full ECMAScript +linker. `ModuleRecordEntryReducer` converts its syntactic linkage facts for +CommonJS-like emitters and keeps unresolved binding access lazy through generated +property reads. + +SystemJS preserves import attributes in its dependency metadata. CommonJS, AMD, +and UMD do not process import attributes because their output formats cannot +express them; those lowering paths assume attributed requests are not provided. + +## Shared Front-End Flow + +The CommonJS, AMD, and UMD transforms follow the same broad pipeline: + +1. Replace top-level `this` with `undefined` unless + `Config::allow_top_level_this` is enabled. +2. Run `SourceModule::collect`. +3. Run `syntax_strip::lower` to remove module syntax from the executable body. +4. Move initial directive statements into the output body. +5. Insert `"use strict"` when `Config::strict_mode` requires it and the module + does not already contain one. +6. Emit an `__esModule` marker when the input had module syntax, import interop + is enabled, and the module is not a TypeScript `export =` module. +7. Convert collected module entries into format-specific import statements, + dependency parameters, export getters, and import-reference rewrites. +8. Append the stripped executable body. +9. Apply format-specific handling for `export =`, dynamic `import()`, and + `import.meta` where supported by that transform. +10. Rewrite local import binding references using the generated `ImportMap`. + +The strip step removes module declarations while preserving executable +declarations: + +- `import ... from "mod"` is removed after its import entries are collected. +- `export const foo = 1` becomes `const foo = 1`, and `foo` is registered in + `LocalExportEntries`. +- `export { foo as bar }` is removed and recorded as a local export entry. +- `export { foo as bar } from "mod"` is removed and recorded as an indirect + export entry under the requested module. +- `export * from "mod"` is removed and recorded as `StarExport`. +- `export default function foo() {}` keeps the declaration and records + `"default" -> foo`. +- `export default expr` becomes a generated `_default` binding and records + `"default" -> _default`. +- A non-exported external TypeScript `import x = require("mod")` is kept as an + ordered source item for the target lowerer. It models the CTS form of ES + `import.sync`, so it does not participate in ES module linking or mark the + source as an ES module. +- The exported form also registers `x` in `LocalExportEntries` and therefore + participates in module linking. +- Type-only imports and exports do not create runtime module entries. + +## Module Request Usage + +`ModuleRequestUsage` summarizes which runtime shape a requested module needs: + +- `NAMED` means generated code reads named properties from the module object. +- `DEFAULT` means generated code may need default interop. +- `NAMESPACE` is the combined named/default shape needed for namespace imports + and namespace re-exports. +- `STAR_EXPORT` means generated code calls the `_export_star` helper. + +When `importInterop` is `none`, namespace usage is removed before emit because +the transform must not inject interop helpers. + +## Entry Reduction + +`ModuleRecordEntryReducer` is the shared bridge from module-record-like entries +to CommonJS-like emit structures: + +- Named imports add `local -> module.importName` entries to `ImportMap`. +- Default imports add `local -> module.default`, except Node default interop can + map default-only imports directly to the module object. +- Namespace imports add `local -> module`. +- Indirect named/default exports add synthetic imported bindings to `ImportMap` + and then add export getter entries. +- Indirect namespace exports add an export getter that returns the module object. +- Star exports are emitted by the caller with `_export_star(...)`. + +Export getters are sorted by exported name before emit. A single export uses a +direct `Object.defineProperty` call, while multiple exports use the shared +`_export(exports, { ... })` helper shape. + +## CommonJS Binding Flow + +The CommonJS-like binding path can be summarized as: + +```mermaid +flowchart LR + Ast["ES module AST"] --> Collect["SourceModule::collect"] + Collect --> Strip["syntax_strip::lower"] + Strip --> Reduce["Entry reduction
ImportMap + export bindings"] + Strip --> Body["Stripped body"] + Reduce --> Emit["Emit require/export statements"] + Emit --> Assemble["Assemble statements"] + Body --> Assemble + Reduce --> Rewrite["rewrite_import_bindings"] + Assemble --> Rewrite --> Output["CommonJS module"] +``` + +## CommonJS Flow + +The CommonJS pass lives in `src/common_js.rs` and produces direct `require(...)` +calls. + +CommonJS lowers external TypeScript `import x = require("mod")` after +`syntax_strip::lower` keeps it in the executable body: + +- Non-exported `import x = require("mod")` becomes + `const x = require("mod")` or `var x = require("mod")`. +- Exported `export import x = require("mod")` becomes + `exports.x = require("mod")` and adds `x -> exports.x` to the import map. + +For each requested module, CommonJS: + +1. Creates a stable private module identifier from the request string. +2. Reduces module entries into `ImportMap` and export bindings. +3. Builds `require("mod")` through the configured path resolver. +4. Wraps the require call in `_export_star(require("mod"), exports)` for star + re-exports. +5. Applies interop helpers: + - SWC default interop uses `_interop_require_default(...)`. + - SWC namespace/default combined usage uses + `_interop_require_wildcard(...)`. + - Node namespace usage uses `_interop_require_wildcard(..., true)`. +6. Emits either a declaration for the module temporary, a lazy require wrapper, + or a side-effect-only statement. + +Before module request statements, CommonJS emits local and indirect export +getters unless the module uses `export =`. For `export = expr`, the pass appends +`module.exports = expr`. + +When `exportInteropAnnotation` is enabled, CommonJS also emits +`cjs-module-lexer`-friendly dead-code annotations such as +`0 && (exports.foo = 0)` and star re-export annotations. + +Dynamic `import()` is lowered to a `Promise.resolve(...).then(...)` shape that +calls `require(...)`. Literal dynamic import paths are resolved before emit. +`import.meta` is lowered to CommonJS equivalents such as `__filename`, +`__dirname`, `require.resolve`, or `require.main == module` unless +`preserveImportMeta` is enabled. + +## AMD Flow + +The AMD pass lives in `src/amd.rs` and emits one `define(...)` call. + +Before wrapping, AMD builds a factory body using the shared front-end flow. Each +requested module contributes: + +1. A dependency entry in `dep_list`. +2. A factory parameter identifier. +3. Import-map and export-binding entries through `ModuleRecordEntryReducer`. +4. Optional post-parameter interop assignment inside the factory body. + +External TypeScript `import x = require("mod")` also contributes a dependency +entry and factory parameter. Exported forms assign that parameter to +`exports.x`. + +The final wrapper dependency array always starts with `"require"` and a matching +`require` factory parameter. The pass adds `"exports"` only when generated code +needs the exports object, and `"module"` only when generated `import.meta` +lowering needs it. Requested modules are appended after those special AMD +dependencies. + +The call shape is: + +```javascript +define([deps...], function (params...) { + // generated body +}); +``` + +If `Config::module_id` is present, it is emitted as the first `define` argument. +If it is absent, the pass can read a TypeScript-style +`/// ` leading line comment and use that name. + +For `export = expr`, AMD appends `return expr` from the factory body instead of +using an exports object. + +Dynamic `import()` is lowered to: + +```javascript +new Promise(function (resolve, reject) { + require([arg], function (m) { + resolve(interopedModule); + }, reject); +}); +``` + +`import.meta` is lowered with AMD primitives where possible, for example +`module.uri`, `require.toUrl(...)`, and `module.id == "main"`. + +## UMD Flow + +The UMD pass lives in `src/umd.rs` and emits an adapter IIFE plus a factory. +The factory body is produced with the same collection and reduction flow as AMD. +Requested modules are stored in `dep_list` and become factory parameters. + +External TypeScript `import x = require("mod")` also becomes a factory +parameter. Exported forms assign that parameter to `exports.x`. + +The wrapper chooses among CommonJS, AMD, and global execution: + +```javascript +(function (global, factory) { + if (typeof module === "object" && typeof module.exports === "object") { + factory(exports, require("mod")); + } else if (typeof define === "function" && define.amd) { + define(["exports", "mod"], factory); + } else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) { + factory((global.lib = {}), global.mod); + } +})(this, function (exports, mod) { + // generated body +}); +``` + +When `SourceModule` records a TypeScript `export =` assignment, UMD does not +create an exports object parameter. The generated factory returns the assigned +expression, and the CommonJS branch assigns that factory result to +`module.exports`. The browser fallback assigns the same result to the inferred +global export name: + +```javascript +module.exports = factory(require("mod")); +define(["mod"], factory); +global.lib = factory(global.mod); +``` + +Some TypeScript/CommonJS syntax paths are already represented as executable +`module.exports = ...` statements in the factory body by the time the UMD wrapper +is emitted; those paths keep the normal wrapper call shape. + +UMD determines the global export name from the configured `globals` and module +name settings. It resolves dependency request strings before emitting the CJS +`require(...)`, AMD dependency string, and browser global property access. + +Unlike the CommonJS and AMD passes, the current UMD pass does not rewrite +dynamic `import()` or `import.meta` itself in this module-transform stage. + +## SystemJS Flow + +The SystemJS pass lives in `src/system_js.rs` with private implementation +modules in `src/system_js/`. Its public entry point is +`system_js(resolver, unresolved_mark, config)`, and its public `Config` type is +the shared `util::Config`. + +```mermaid +flowchart LR + Ast["Module AST"] --> Source["SourceModule::collect"] + Source --> Lower["Lower to IR"] + Lower --> Rewrite["Scoped rewrites"] + Rewrite --> Emit["Emit System.register"] +``` + +SystemJS shares only the collection stage with the CommonJS-like passes. It +lowers `RequestedModules`, `LocalExportEntries`, ordered source items, and +TypeScript `export =` assignments into a private SystemJS IR. It does not use +`syntax_strip::lower`, `ModuleRecordEntryReducer`, `ImportMap`, export getter +emission, or helper injection. + +`src/system_js.rs` owns the public pass, directive handling, strict mode, +top-level `this` rewrite, and top-level-await detection. The private +`src/system_js/` modules then own the format-specific stages: + +- `lower.rs` builds `SystemModule`: dependency slots, wrapper-scope bindings, + export announcements, and execute-time statements. +- `rewrite.rs` is the scoped visitor boundary for `import.meta`, dynamic + `import()`, `__moduleName`, and live-binding updates. +- `emit.rs` is the only layer that creates the final `System.register(...)` + call. + +Lowering keeps SystemJS timing explicit. ECMAScript module requests are merged +by `ModuleRequestRecord` in first-observed order, and each dependency slot owns +the setter operations needed for imports and re-exports. Dependency requests +from external TypeScript `import = require(...)` stay outside `RequestedModules` +and lower to independent dependency slots. Top-level function declarations stay +in wrapper scope, while variable and class initializers run from `execute`. +Import attributes stay attached to dependency slots and become the optional +metadata argument to `System.register`. + +Local exports are announced before the returned `{ setters, execute }` object: +function exports, including anonymous default functions, use their function +values, and other exports start as `void 0`. Later writes to exported locals +call `_export`; exported destructuring and loop heads use setter patterns so +local bindings and exported values stay in sync. + +After ordered source items are lowered, TypeScript `export = expr` is appended +to `execute` as a batch export update: + +```javascript +_export(expr); +``` + +## Helper Injection + +`src/import_analysis.rs` runs before module lowering to enable only the helpers +required by the module syntax in the source: + +- `_export_star` is enabled when any module request has `STAR_EXPORT`. +- `_interop_require_default` is enabled for SWC default-only interop. +- `_interop_require_wildcard` is enabled for namespace usage and, when dynamic + import is not ignored, for possible dynamic-import interop. + +The emitters assume these helpers are available when they generate the +corresponding helper calls. + +## Important Boundaries + +- `module_record.rs` owns target-neutral source module collection and the + CommonJS-like `ModuleRecordEntryReducer`. +- `syntax_strip.rs` owns the CommonJS-like module syntax stripping step. +- `common_js.rs`, `amd.rs`, and `umd.rs` own target lowering, dependency + construction, interop application, and special runtime rewrites for their + format. +- `amd/emit.rs` and `umd/emit.rs` own wrapper construction for those formats. +- `system_js.rs` owns the SystemJS facade, while `src/system_js/` owns its + private IR, lowering, rewrite traversal, and `System.register` emission. +- `module_ref_rewriter.rs` owns replacing imported local binding references with + the generated property access. +- `util.rs` owns shared helper-building code such as `define_es_module`, + `_export(...)` emission, export sorting, and property-name construction. + +Keeping these boundaries intact makes it easier to adjust interop behavior or +add module-record fields without coupling the collector to a specific output +format. diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/amd.rs b/deps/swc/crates/swc_ecma_transforms_module/src/amd.rs index 6cf649482..2f7036d66 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/amd.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/amd.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; -use anyhow::Context; use regex::Regex; +use rustc_hash::FxHashSet; use serde::{Deserialize, Serialize}; use swc_atoms::{atom, Atom}; use swc_common::{ @@ -12,24 +12,29 @@ use swc_common::{ }; use swc_ecma_ast::*; use swc_ecma_transforms_base::helper_expr; -use swc_ecma_utils::{ - member_expr, private_ident, quote_ident, quote_str, ExprFactory, FunctionFactory, IsDirective, -}; +use swc_ecma_utils::{member_expr, private_ident, quote_ident, quote_str, ExprFactory}; use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith}; pub use super::util::Config as InnerConfig; use crate::{ - module_decl_strip::{Export, Link, LinkFlag, LinkItem, LinkSpecifierReducer, ModuleDeclStrip}, + module_record::{ + exported_external_ts_import_equals_name, external_ts_import_equals_source, + LocalExportEntries, ModuleRecordEntryReducer, ModuleRequestUsage, RequestedModule, + RequestedModules, SourceModule, + }, module_ref_rewriter::{rewrite_import_bindings, ImportMap}, path::Resolver, + syntax_strip::{self, SyntaxStrippedModule}, top_level_this::top_level_this, util::{ - define_es_module, emit_export_stmts, local_name_for_src, sort_export_obj_prop_list, - use_strict, ImportInterop, VecStmtLike, + define_es_module, emit_export_stmts, local_name_for_src, sort_export_bindings, use_strict, + ImportInterop, }, SpanCtx, }; +mod emit; + #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct Config { @@ -113,54 +118,55 @@ where self.module_id = self.get_amd_module_id_from_comments(n.span); } - let mut stmts: Vec = Vec::with_capacity(n.body.len() + 4); + if !self.config.allow_top_level_this { + top_level_this(&mut n.body, *Expr::undefined(DUMMY_SP)); + } - // Collect directives - stmts.extend( - &mut n - .body - .iter_mut() - .take_while(|i| i.directive_continue()) - .map(|i| i.take()) - .map(ModuleItem::expect_stmt), - ); + let SyntaxStrippedModule { + directives, + has_use_strict, + requested_modules, + local_export_entries, + export_assign, + body, + has_module_syntax, + } = syntax_strip::lower(SourceModule::collect(n.body.take()), self.const_var_kind); + + let mut stmts: Vec = Vec::with_capacity(body.len() + 4); + stmts.extend(directives); // "use strict"; - if self.config.strict_mode && !stmts.has_use_strict() { + if self.config.strict_mode && !has_use_strict { stmts.push(use_strict()); } - if !self.config.allow_top_level_this { - top_level_this(&mut n.body, *Expr::undefined(DUMMY_SP)); - } - let import_interop = self.config.import_interop(); - let mut strip = ModuleDeclStrip::new(self.const_var_kind); - n.body.visit_mut_with(&mut strip); - - let ModuleDeclStrip { - link, - export, - export_assign, - has_module_decl, - .. - } = strip; - let is_export_assign = export_assign.is_some(); - if has_module_decl && !import_interop.is_none() && !is_export_assign { - stmts.push(define_es_module(self.exports())) + if has_module_syntax && !import_interop.is_none() && !is_export_assign { + stmts.push(define_es_module(self.exports())); } let mut import_map = Default::default(); + let ts_import_equals_exports: FxHashSet = body + .iter() + .filter_map(exported_external_ts_import_equals_name) + .cloned() + .collect(); + + stmts.extend(self.handle_import_export( + &mut import_map, + requested_modules, + local_export_entries, + &ts_import_equals_exports, + is_export_assign, + )); - stmts.extend(self.handle_import_export(&mut import_map, link, export, is_export_assign)); - - stmts.extend(n.body.take().into_iter().filter_map(|item| match item { - ModuleItem::Stmt(stmt) if !stmt.is_empty() => Some(stmt), - _ => None, - })); + stmts.extend( + body.into_iter() + .filter_map(|item| self.lower_body_item(&mut import_map, item)), + ); if let Some(export_assign) = export_assign { let return_stmt = ReturnStmt { @@ -168,7 +174,7 @@ where arg: Some(export_assign), }; - stmts.push(return_stmt.into()) + stmts.push(return_stmt.into()); } if !self.config.ignore_dynamic || !self.config.preserve_import_meta { @@ -177,75 +183,18 @@ where rewrite_import_bindings(&mut stmts, import_map, Default::default()); - // ==================== - // Emit - // ==================== - - let mut elems = vec![Some(quote_str!("require").as_arg())]; - let mut params = vec![self.require.clone().into()]; - - if let Some(exports) = self.exports.take() { - elems.push(Some(quote_str!("exports").as_arg())); - params.push(exports.into()) - } - - if let Some(module) = self.module.clone() { - elems.push(Some(quote_str!("module").as_arg())); - params.push(module.into()) - } - - self.dep_list - .take() - .into_iter() - .for_each(|(ident, src_path, src_span)| { - let src_path = match &self.resolver { - Resolver::Real { resolver, base } => resolver - .resolve_import(base, &src_path) - .with_context(|| format!("failed to resolve `{src_path}`")) - .unwrap(), - Resolver::Default => src_path, - }; - - elems.push(Some(quote_str!(src_span.0, src_path).as_arg())); - params.push(ident.into()); - }); - - let mut amd_call_args = Vec::with_capacity(3); - if let Some(module_id) = self.module_id.clone() { - amd_call_args.push(quote_str!(module_id).as_arg()); - } - amd_call_args.push( - ArrayLit { - span: DUMMY_SP, - elems, - } - .as_arg(), - ); - - amd_call_args.push( - Function { - params, - decorators: Default::default(), - span: DUMMY_SP, - body: Some(BlockStmt { - stmts, - ..Default::default() - }), - is_generator: false, - is_async: false, - ..Default::default() - } - .into_fn_expr(None) - .as_arg(), + n.body = emit::emit( + stmts, + emit::EmitModule { + module_id: self.module_id.clone(), + require: self.require.clone(), + exports: self.exports.take(), + module: self.module.clone(), + deps: self.dep_list.take(), + }, + self.unresolved_mark, + &self.resolver, ); - - n.body = vec![quote_ident!( - SyntaxContext::empty().apply_mark(self.unresolved_mark), - "define" - ) - .as_call(DUMMY_SP, amd_call_args) - .into_stmt() - .into()]; } fn visit_mut_script(&mut self, _: &mut Script) { @@ -281,6 +230,9 @@ where let mut require = self.require.clone(); require.span = *import_span; + // `import()` is specified as an ImportCall. AMD lowers it to a + // promise around async `require([arg], ...)`. + // Spec: https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-import-calls *n = amd_dynamic_import( *span, args.take(), @@ -293,9 +245,13 @@ where if !self.config.preserve_import_meta && obj .as_meta_prop() - .map(|p| p.kind == MetaPropKind::ImportMeta) - .unwrap_or_default() => + .is_some_and(|p| p.kind == MetaPropKind::ImportMeta) => { + // `import.meta` is host-populated in the spec. AMD lowers + // supported host fields to loader-specific values. + // Spec: + // - https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-hostgetimportmetaproperties + // - https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-hostfinalizeimportmeta let p = match prop { MemberProp::Ident(IdentName { sym, .. }) => Cow::Borrowed(&**sym), MemberProp::Computed(ComputedPropName { expr, .. }) => match &**expr { @@ -386,7 +342,7 @@ where n.visit_mut_with(self); return; } - }; + } n.visit_mut_children_with(self); } @@ -402,42 +358,45 @@ where fn handle_import_export( &mut self, import_map: &mut ImportMap, - link: Link, - export: Export, + requested_modules: RequestedModules, + local_export_entries: LocalExportEntries, + ts_import_equals_exports: &FxHashSet, is_export_assign: bool, ) -> impl Iterator { let import_interop = self.config.import_interop(); - let mut stmts = Vec::with_capacity(link.len()); + let mut stmts = Vec::with_capacity(requested_modules.len()); - let mut export_obj_prop_list = export.into_iter().collect(); + let mut export_bindings = local_export_entries.into_iter().collect(); - link.into_iter().for_each( - |(src, LinkItem(src_span, link_specifier_set, mut link_flag))| { - let is_node_default = !link_flag.has_named() && import_interop.is_node(); + requested_modules.into_iter().for_each( + |( + module_request, + RequestedModule { + span: src_span, + entries: module_entries, + usage: mut module_usage, + .. + }, + )| { + let src = module_request.src().clone(); + let is_node_default = !module_usage.has_named() && import_interop.is_node(); if import_interop.is_none() { - link_flag -= LinkFlag::NAMESPACE; + module_usage -= ModuleRequestUsage::NAMESPACE; } - let need_re_export = link_flag.export_star(); - let need_interop = link_flag.interop(); - let need_new_var = link_flag.need_raw_import(); + let need_re_export = module_usage.has_star_export(); + let need_interop = module_usage.needs_interop(); let mod_ident = private_ident!(local_name_for_src(&src)); - let new_var_ident = if need_new_var { - private_ident!(local_name_for_src(&src)) - } else { - mod_ident.clone() - }; self.dep_list.push((mod_ident.clone(), src, src_span)); - link_specifier_set.reduce( + module_entries.reduce( import_map, - &mut export_obj_prop_list, - &new_var_ident, - &Some(mod_ident.clone()), + &mut export_bindings, + &mod_ident, &mut false, is_node_default, ); @@ -455,52 +414,107 @@ where // _introp(mod); if need_interop { import_expr = match import_interop { - ImportInterop::Swc if link_flag.interop() => if link_flag.namespace() { - helper_expr!(interop_require_wildcard) - } else { - helper_expr!(interop_require_default) + ImportInterop::Swc if module_usage.needs_interop() => { + if module_usage.needs_namespace_object() { + helper_expr!(interop_require_wildcard) + } else { + helper_expr!(interop_require_default) + } + .as_call(PURE_SP, vec![import_expr.as_arg()]) } - .as_call(PURE_SP, vec![import_expr.as_arg()]), - ImportInterop::Node if link_flag.namespace() => { + ImportInterop::Node if module_usage.needs_namespace_object() => { helper_expr!(interop_require_wildcard) .as_call(PURE_SP, vec![import_expr.as_arg(), true.as_arg()]) } _ => import_expr, } - }; + } // mod = _introp(mod); - // var mod1 = _introp(mod); - if need_new_var { - let stmt: Stmt = import_expr - .into_var_decl(self.const_var_kind, new_var_ident.into()) - .into(); - - stmts.push(stmt) - } else if need_interop { + if need_interop { let stmt = import_expr .make_assign_to(op!("="), mod_ident.into()) .into_stmt(); stmts.push(stmt); } else if need_re_export { stmts.push(import_expr.into_stmt()); - }; + } }, ); let mut export_stmts = Default::default(); - if !export_obj_prop_list.is_empty() && !is_export_assign { - sort_export_obj_prop_list(&mut export_obj_prop_list); + export_bindings.retain(|(export_name, _)| !ts_import_equals_exports.contains(export_name)); + + if !export_bindings.is_empty() && !is_export_assign { + sort_export_bindings(&mut export_bindings); let exports = self.exports(); - export_stmts = emit_export_stmts(exports, export_obj_prop_list); + export_stmts = emit_export_stmts(exports, export_bindings); } export_stmts.into_iter().chain(stmts) } + fn lower_body_item(&mut self, import_map: &mut ImportMap, item: ModuleItem) -> Option { + match item { + ModuleItem::Stmt(stmt) if !stmt.is_empty() => Some(stmt), + ModuleItem::ModuleDecl(ModuleDecl::TsImportEquals(import)) => { + self.lower_ts_import_equals(import_map, *import) + } + _ => None, + } + } + + fn lower_ts_import_equals( + &mut self, + import_map: &mut ImportMap, + import: TsImportEqualsDecl, + ) -> Option { + let src = external_ts_import_equals_source(&import)?; + let src_span = src.span; + let request = src.value.to_atom_lossy().into_owned(); + let TsImportEqualsDecl { + id: local, + is_export, + .. + } = import; + let param = if is_export { + local.clone().into_private() + } else { + local.clone() + }; + + self.dep_list + .push((param.clone(), request, (src_span, Default::default()))); + + if !is_export { + return None; + } + + Some(self.emit_ts_import_equals(import_map, local, is_export, param.into())) + } + + fn emit_ts_import_equals( + &mut self, + import_map: &mut ImportMap, + local: Ident, + is_export: bool, + value: Expr, + ) -> Stmt { + if is_export { + import_map.insert(local.to_id(), (self.exports(), Some(local.sym.clone()))); + return value + .make_assign_to(op!("="), self.exports().make_member(local.into()).into()) + .into_stmt(); + } + + value + .into_var_decl(self.const_var_kind, local.into()) + .into() + } + fn module(&mut self) -> Ident { self.module .get_or_insert_with(|| private_ident!("module")) diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/amd/emit.rs b/deps/swc/crates/swc_ecma_transforms_module/src/amd/emit.rs new file mode 100644 index 000000000..fbb267234 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/src/amd/emit.rs @@ -0,0 +1,87 @@ +use anyhow::Context; +use swc_atoms::Atom; +use swc_common::{Mark, SyntaxContext, DUMMY_SP}; +use swc_ecma_ast::*; +use swc_ecma_utils::{quote_ident, quote_str, ExprFactory, FunctionFactory}; + +use crate::{path::Resolver, SpanCtx}; + +pub(super) struct EmitModule { + pub module_id: Option, + pub require: Ident, + pub exports: Option, + pub module: Option, + pub deps: Vec<(Ident, Atom, SpanCtx)>, +} + +pub(super) fn emit( + stmts: Vec, + mut module: EmitModule, + unresolved_mark: Mark, + resolver: &Resolver, +) -> Vec { + let mut elems = vec![Some(quote_str!("require").as_arg())]; + let mut params = vec![module.require.into()]; + + if let Some(exports) = module.exports { + elems.push(Some(quote_str!("exports").as_arg())); + params.push(exports.into()); + } + + if let Some(module) = module.module { + elems.push(Some(quote_str!("module").as_arg())); + params.push(module.into()); + } + + module + .deps + .into_iter() + .for_each(|(ident, src_path, src_span)| { + let src_path = match resolver { + Resolver::Real { resolver, base } => resolver + .resolve_import(base, &src_path) + .with_context(|| format!("failed to resolve `{src_path}`")) + .unwrap(), + Resolver::Default => src_path, + }; + + elems.push(Some(quote_str!(src_span.0, src_path).as_arg())); + params.push(ident.into()); + }); + + let mut amd_call_args = Vec::with_capacity(3); + if let Some(module_id) = module.module_id.take() { + amd_call_args.push(quote_str!(module_id).as_arg()); + } + amd_call_args.push( + ArrayLit { + span: DUMMY_SP, + elems, + } + .as_arg(), + ); + + amd_call_args.push( + Function { + params, + decorators: Default::default(), + span: DUMMY_SP, + body: Some(BlockStmt { + stmts, + ..Default::default() + }), + is_generator: false, + is_async: false, + ..Default::default() + } + .into_fn_expr(None) + .as_arg(), + ); + + vec![ + quote_ident!(SyntaxContext::empty().apply_mark(unresolved_mark), "define") + .as_call(DUMMY_SP, amd_call_args) + .into_stmt() + .into(), + ] +} diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/common_js.rs b/deps/swc/crates/swc_ecma_transforms_module/src/common_js.rs index d6e8c4843..6cfad131d 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/common_js.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/common_js.rs @@ -1,27 +1,31 @@ use std::borrow::Cow; use rustc_hash::FxHashSet; +use swc_atoms::Atom; use swc_common::{ source_map::PURE_SP, util::take::Take, Mark, Span, Spanned, SyntaxContext, DUMMY_SP, }; use swc_ecma_ast::*; use swc_ecma_transforms_base::helper_expr; use swc_ecma_utils::{ - member_expr, private_ident, quote_expr, quote_ident, ExprFactory, FunctionFactory, IsDirective, + member_expr, private_ident, quote_expr, quote_ident, ExprFactory, FunctionFactory, }; use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith}; pub use super::util::Config; use crate::{ - module_decl_strip::{ - Export, ExportKV, Link, LinkFlag, LinkItem, LinkSpecifierReducer, ModuleDeclStrip, + module_record::{ + exported_external_ts_import_equals_name, external_ts_import_equals_source, ExportBinding, + LocalExportEntries, ModuleRecordEntryReducer, ModuleRequestUsage, RequestedModule, + RequestedModules, SourceModule, }, module_ref_rewriter::{rewrite_import_bindings, ImportMap}, path::Resolver, + syntax_strip::{self, SyntaxStrippedModule}, top_level_this::top_level_this, util::{ - define_es_module, emit_export_stmts, local_name_for_src, prop_name, - sort_export_obj_prop_list, use_strict, ImportInterop, VecStmtLike, + define_es_module, emit_export_stmts, local_name_for_src, prop_name, sort_export_bindings, + use_strict, ImportInterop, }, }; @@ -31,6 +35,7 @@ pub struct FeatureFlag { pub support_arrow: bool, } +#[must_use] pub fn common_js( resolver: Resolver, unresolved_mark: Mark, @@ -62,22 +67,6 @@ impl VisitMut for Cjs { noop_visit_mut_type!(fail); fn visit_mut_module(&mut self, n: &mut Module) { - let mut stmts: Vec = Vec::with_capacity(n.body.len() + 6); - - // Collect directives - stmts.extend( - &mut n - .body - .iter_mut() - .take_while(|i| i.directive_continue()) - .map(|i| i.take()), - ); - - // "use strict"; - if self.config.strict_mode && !stmts.has_use_strict() { - stmts.push(use_strict().into()); - } - if !self.config.allow_top_level_this { top_level_this(&mut n.body, *Expr::undefined(DUMMY_SP)); } @@ -86,39 +75,36 @@ impl VisitMut for Cjs { let mut module_map = Default::default(); - let mut has_ts_import_equals = false; - - // handle `import foo = require("mod")` - n.body.iter_mut().for_each(|item| { - if let ModuleItem::ModuleDecl(module_decl) = item { - *item = self.handle_ts_import_equals( - module_decl.take(), - &mut module_map, - &mut has_ts_import_equals, - ); - } - }); - - let mut strip = ModuleDeclStrip::new(self.const_var_kind); - n.body.visit_mut_with(&mut strip); - - let ModuleDeclStrip { - link, - export, + let SyntaxStrippedModule { + directives, + has_use_strict, + requested_modules, + local_export_entries, export_assign, - has_module_decl, - .. - } = strip; + body, + has_module_syntax, + } = syntax_strip::lower(SourceModule::collect(n.body.take()), self.const_var_kind); + + let mut stmts: Vec = Vec::with_capacity(body.len() + 6); + stmts.extend(directives.into_iter().map(ModuleItem::from)); - let has_module_decl = has_module_decl || has_ts_import_equals; + // "use strict"; + if self.config.strict_mode && !has_use_strict { + stmts.push(use_strict().into()); + } let is_export_assign = export_assign.is_some(); - if has_module_decl && !import_interop.is_none() && !is_export_assign { - stmts.push(define_es_module(self.exports()).into()) + if has_module_syntax && !import_interop.is_none() && !is_export_assign { + stmts.push(define_es_module(self.exports()).into()); } let mut lazy_record = Default::default(); + let ts_import_equals_exports: FxHashSet = body + .iter() + .filter_map(exported_external_ts_import_equals_name) + .cloned() + .collect(); // `import` -> `require` // `export` -> `_export(exports, {});` @@ -126,17 +112,18 @@ impl VisitMut for Cjs { self.handle_import_export( &mut module_map, &mut lazy_record, - link, - export, + requested_modules, + local_export_entries, + &ts_import_equals_exports, is_export_assign, ) .map(From::from), ); - stmts.extend(n.body.take().into_iter().filter(|item| match item { - ModuleItem::Stmt(stmt) => !stmt.is_empty(), - _ => false, - })); + stmts.extend( + body.into_iter() + .filter_map(|item| self.lower_body_item(&mut module_map, item)), + ); // `export = expr;` -> `module.exports = expr;` if let Some(export_assign) = export_assign { @@ -153,7 +140,7 @@ impl VisitMut for Cjs { ) .into_stmt() .into(), - ) + ); } if !self.config.ignore_dynamic || !self.config.preserve_import_meta { @@ -201,6 +188,9 @@ impl VisitMut for Cjs { let unresolved_ctxt = SyntaxContext::empty().apply_mark(self.unresolved_mark); + // `import()` is specified as an ImportCall. CommonJS lowers it + // to a promise chain that evaluates `require(...)`. + // Spec: https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-import-calls *n = cjs_dynamic_import( *span, args.take(), @@ -214,9 +204,13 @@ impl VisitMut for Cjs { if !self.config.preserve_import_meta && obj .as_meta_prop() - .map(|p| p.kind == MetaPropKind::ImportMeta) - .unwrap_or_default() => + .is_some_and(|p| p.kind == MetaPropKind::ImportMeta) => { + // `import.meta` is host-populated in the spec. CommonJS + // lowers supported host fields to Node-like runtime values. + // Spec: + // - https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-hostgetimportmetaproperties + // - https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-hostfinalizeimportmeta let p = match prop { MemberProp::Ident(IdentName { sym, .. }) => Cow::Borrowed(&**sym), MemberProp::Computed(ComputedPropName { expr, .. }) => match &**expr { @@ -289,7 +283,7 @@ impl VisitMut for Cjs { n.visit_mut_with(self); return; } - }; + } n.visit_mut_children_with(self); } @@ -303,47 +297,57 @@ impl Cjs { &mut self, import_map: &mut ImportMap, lazy_record: &mut FxHashSet, - link: Link, - export: Export, + requested_modules: RequestedModules, + local_export_entries: LocalExportEntries, + ts_import_equals_exports: &FxHashSet, is_export_assign: bool, ) -> impl Iterator { let import_interop = self.config.import_interop(); let export_interop_annotation = self.config.export_interop_annotation(); let is_node = import_interop.is_node(); - let mut stmts = Vec::with_capacity(link.len()); + let mut stmts = Vec::with_capacity(requested_modules.len()); - let mut export_obj_prop_list = export.into_iter().collect(); + let mut export_bindings: Vec = local_export_entries.into_iter().collect(); let lexer_reexport = if export_interop_annotation { - self.emit_lexer_reexport(&link) + self.emit_lexer_reexport(&requested_modules) } else { None }; - link.into_iter().for_each( - |(src, LinkItem(src_span, link_specifier_set, mut link_flag))| { - let is_node_default = !link_flag.has_named() && is_node; + requested_modules.into_iter().for_each( + |( + module_request, + RequestedModule { + span: src_span, + entries: module_entries, + usage: mut module_usage, + .. + }, + )| { + let src = module_request.src().clone(); if import_interop.is_none() { - link_flag -= LinkFlag::NAMESPACE; + module_usage -= ModuleRequestUsage::NAMESPACE; } + let is_node_default = !module_usage.has_named() && is_node; let mod_ident = private_ident!(local_name_for_src(&src)); let mut decl_mod_ident = false; - link_specifier_set.reduce( + module_entries.reduce( import_map, - &mut export_obj_prop_list, + &mut export_bindings, &mod_ident, - &None, &mut decl_mod_ident, is_node_default, ); - let is_lazy = - decl_mod_ident && !link_flag.export_star() && self.config.lazy.is_lazy(&src); + let is_lazy = decl_mod_ident + && !module_usage.has_star_export() + && self.config.lazy.is_lazy(&src); if is_lazy { lazy_record.insert(mod_ident.to_id()); @@ -352,10 +356,10 @@ impl Cjs { // require("mod"); let import_expr = self.resolver - .make_require_call(self.unresolved_mark, src, src_span.0); + .make_require_call(self.unresolved_mark, src.clone(), src_span.0); // _export_star(require("mod"), exports); - let import_expr = if link_flag.export_star() { + let import_expr = if module_usage.has_star_export() { helper_expr!(export_star).as_call( DUMMY_SP, vec![import_expr.as_arg(), self.exports().as_arg()], @@ -367,13 +371,15 @@ impl Cjs { // _introp(require("mod")); let import_expr = { match import_interop { - ImportInterop::Swc if link_flag.interop() => if link_flag.namespace() { - helper_expr!(interop_require_wildcard) - } else { - helper_expr!(interop_require_default) + ImportInterop::Swc if module_usage.needs_interop() => { + if module_usage.needs_namespace_object() { + helper_expr!(interop_require_wildcard) + } else { + helper_expr!(interop_require_default) + } + .as_call(PURE_SP, vec![import_expr.as_arg()]) } - .as_call(PURE_SP, vec![import_expr.as_arg()]), - ImportInterop::Node if link_flag.namespace() => { + ImportInterop::Node if module_usage.needs_namespace_object() => { helper_expr!(interop_require_wildcard) .as_call(PURE_SP, vec![import_expr.as_arg(), true.as_arg()]) } @@ -399,16 +405,18 @@ impl Cjs { let mut export_stmts: Vec = Default::default(); - if !export_obj_prop_list.is_empty() && !is_export_assign { - sort_export_obj_prop_list(&mut export_obj_prop_list); + export_bindings.retain(|(export_name, _)| !ts_import_equals_exports.contains(export_name)); + + if !export_bindings.is_empty() && !is_export_assign { + sort_export_bindings(&mut export_bindings); let exports = self.exports(); - if export_interop_annotation && export_obj_prop_list.len() > 1 { - export_stmts.extend(self.emit_lexer_exports_init(&export_obj_prop_list)); + if export_interop_annotation && export_bindings.len() > 1 { + export_stmts.extend(self.emit_lexer_exports_init(&export_bindings)); } - export_stmts.extend(emit_export_stmts(exports, export_obj_prop_list)); + export_stmts.extend(emit_export_stmts(exports, export_bindings)); } export_stmts.extend(lexer_reexport); @@ -416,67 +424,48 @@ impl Cjs { export_stmts.into_iter().chain(stmts) } - fn handle_ts_import_equals( - &self, - module_decl: ModuleDecl, - module_map: &mut ImportMap, - has_ts_import_equals: &mut bool, - ) -> ModuleItem { - match module_decl { - ModuleDecl::TsImportEquals(v) - if matches!( - &*v, - TsImportEqualsDecl { - is_type_only: false, - module_ref: TsModuleRef::TsExternalModuleRef(TsExternalModuleRef { .. }), - .. - } - ) => - { - let TsImportEqualsDecl { - span, - is_export, - id, - module_ref, - .. - } = *v; - let Str { - span: src_span, - value: src, - .. - } = module_ref.expect_ts_external_module_ref().expr; - - *has_ts_import_equals = true; - - let require = self.resolver.make_require_call( - self.unresolved_mark, - src.to_atom_lossy().into_owned(), - src_span, - ); - - if is_export { - // exports.foo = require("mod") - module_map.insert(id.to_id(), (self.exports(), Some(id.sym.clone()))); + fn lower_body_item(&self, import_map: &mut ImportMap, item: ModuleItem) -> Option { + match item { + ModuleItem::Stmt(stmt) if !stmt.is_empty() => Some(stmt.into()), + ModuleItem::ModuleDecl(ModuleDecl::TsImportEquals(import)) => self + .lower_ts_import_equals(import_map, *import) + .map(From::from), + _ => None, + } + } - let assign_expr = AssignExpr { - span, - op: op!("="), - left: self.exports().make_member(id.into()).into(), - right: Box::new(require), - }; + fn lower_ts_import_equals( + &self, + import_map: &mut ImportMap, + import: TsImportEqualsDecl, + ) -> Option { + let src = external_ts_import_equals_source(&import)?; + let value = self.resolver.make_require_call( + self.unresolved_mark, + src.value.to_atom_lossy().into_owned(), + src.span, + ); - assign_expr.into_stmt() - } else { - // const foo = require("mod") - let mut var_decl = require.into_var_decl(self.const_var_kind, id.into()); - var_decl.span = span; + Some(self.emit_ts_import_equals(import_map, import.id, import.is_export, value)) + } - var_decl.into() - } - .into() - } - _ => module_decl.into(), + fn emit_ts_import_equals( + &self, + import_map: &mut ImportMap, + local: Ident, + is_export: bool, + value: Expr, + ) -> Stmt { + if is_export { + import_map.insert(local.to_id(), (self.exports(), Some(local.sym.clone()))); + return value + .make_assign_to(op!("="), self.exports().make_member(local.into()).into()) + .into_stmt(); } + + value + .into_var_decl(self.const_var_kind, local.into()) + .into() } fn exports(&self) -> Ident { @@ -491,7 +480,7 @@ impl Cjs { /// 0 && (exports.foo = 0); /// 0 && (module.exports = { foo: _, bar: _ }); /// ``` - fn emit_lexer_exports_init(&mut self, export_id_list: &[ExportKV]) -> Option { + fn emit_lexer_exports_init(&mut self, export_id_list: &[ExportBinding]) -> Option { match export_id_list.len() { 0 => None, 1 => { @@ -559,13 +548,16 @@ impl Cjs { /// ```javascript /// 0 && __export(require("foo")) && __export(require("bar")); /// ``` - fn emit_lexer_reexport(&self, link: &Link) -> Option { - link.iter() - .filter(|(.., LinkItem(.., link_flag))| link_flag.export_star()) - .map(|(src, ..)| { - let import_expr = - self.resolver - .make_require_call(self.unresolved_mark, src.clone(), DUMMY_SP); + fn emit_lexer_reexport(&self, requested_modules: &RequestedModules) -> Option { + requested_modules + .iter() + .filter(|(.., RequestedModule { usage, .. })| usage.has_star_export()) + .map(|(module_request, ..)| { + let import_expr = self.resolver.make_require_call( + self.unresolved_mark, + module_request.src().clone(), + DUMMY_SP, + ); quote_ident!("__export").as_call(DUMMY_SP, vec![import_expr.as_arg()]) }) @@ -637,7 +629,7 @@ pub(crate) fn cjs_dynamic_import( ) } -/// require('url').pathToFileURL(__filename).toString() +/// require('url').pathToFileURL(__`filename).toString()` fn cjs_import_meta_url(span: Span, require: Ident, unresolved_mark: Mark) -> Expr { require .as_call(DUMMY_SP, vec!["url".as_arg()]) @@ -663,6 +655,7 @@ fn cjs_import_meta_url(span: Span, require: Ident, unresolved_mark: Mark) -> Exp /// return data; /// } /// ``` +#[must_use] pub fn lazy_require(expr: Expr, mod_ident: Ident, var_kind: VarDeclKind) -> FnDecl { let data = private_ident!("data"); let data_decl = expr.into_var_decl(var_kind, data.clone().into()); diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/import_analysis.rs b/deps/swc/crates/swc_ecma_transforms_module/src/import_analysis.rs index 994beeaa9..1cbaaa678 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/import_analysis.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/import_analysis.rs @@ -6,8 +6,9 @@ use swc_ecma_visit::{ noop_visit_mut_type, noop_visit_type, visit_mut_pass, Visit, VisitMut, VisitWith, }; -use crate::{module_decl_strip::LinkFlag, util::ImportInterop, wtf8::str_to_atom}; +use crate::{module_record::ModuleRequestUsage, util::ImportInterop, wtf8::str_to_atom}; +#[must_use] pub fn import_analyzer(import_interop: ImportInterop, ignore_dynamic: bool) -> impl Pass { visit_mut_pass(ImportAnalyzer { import_interop, @@ -21,7 +22,7 @@ pub struct ImportAnalyzer { import_interop: ImportInterop, ignore_dynamic: bool, - flag_record: FxHashMap, + flag_record: FxHashMap, dynamic_import_found: bool, } @@ -38,7 +39,7 @@ impl Visit for ImportAnalyzer { noop_visit_type!(fail); fn visit_module_items(&mut self, n: &[ModuleItem]) { - for item in n.iter() { + for item in n { if item.is_module_decl() { item.visit_with(self); } @@ -46,7 +47,10 @@ impl Visit for ImportAnalyzer { let flag_record = &self.flag_record; - if flag_record.values().any(|flag| flag.export_star()) { + if flag_record + .values() + .any(super::module_record::ModuleRequestUsage::has_star_export) + { enable_helper!(export_star); } @@ -57,17 +61,20 @@ impl Visit for ImportAnalyzer { if self.import_interop.is_swc() && flag_record .values() - .any(|flag| flag.interop() && !flag.has_named()) + .any(|flag| flag.needs_interop() && !flag.has_named()) { enable_helper!(interop_require_default); } - if flag_record.values().any(|flag| flag.namespace()) { + if flag_record + .values() + .any(super::module_record::ModuleRequestUsage::needs_namespace_object) + { enable_helper!(interop_require_wildcard); } else if !self.ignore_dynamic { // `import/export * as foo from "foo"` not found // but it may be used with dynamic import - for item in n.iter() { + for item in n { if item.is_stmt() { item.visit_with(self); } @@ -99,7 +106,7 @@ impl Visit for ImportAnalyzer { fn visit_export_all(&mut self, n: &ExportAll) { let src = str_to_atom(&n.src); - *self.flag_record.entry(src).or_default() |= LinkFlag::EXPORT_STAR; + *self.flag_record.entry(src).or_default() |= ModuleRequestUsage::STAR_EXPORT; } fn visit_import(&mut self, _: &Import) { diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/lib.rs b/deps/swc/crates/swc_ecma_transforms_module/src/lib.rs index 045f8f4c7..2531554ed 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/lib.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/lib.rs @@ -14,10 +14,11 @@ pub mod util; pub mod amd; pub mod common_js; pub mod import_analysis; -pub(crate) mod module_decl_strip; +pub(crate) mod module_record; pub(crate) mod module_ref_rewriter; pub mod path; pub mod rewriter; +pub(crate) mod syntax_strip; pub mod system_js; mod top_level_this; pub mod umd; diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/module_decl_strip.rs b/deps/swc/crates/swc_ecma_transforms_module/src/module_decl_strip.rs deleted file mode 100644 index 10552d646..000000000 --- a/deps/swc/crates/swc_ecma_transforms_module/src/module_decl_strip.rs +++ /dev/null @@ -1,812 +0,0 @@ -use indexmap::IndexMap; -use rustc_hash::{FxHashMap, FxHashSet}; -use swc_atoms::{atom, Atom}; -use swc_common::{util::take::Take, Mark, Span, SyntaxContext}; -use swc_ecma_ast::*; -use swc_ecma_utils::{find_pat_ids, private_ident, quote_ident, ExprFactory}; -use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith}; - -use crate::{module_ref_rewriter::ImportMap, SpanCtx}; - -/// key: module path -pub type Link = IndexMap; -/// key: export binding name -pub type Export = FxHashMap; - -#[derive(Debug)] -pub struct ModuleDeclStrip { - /// all imports/exports collected by path in source text order - pub link: Link, - - /// local exported binding - /// - /// `export { foo as "1", bar }` - /// -> Map("1" => foo, bar => bar) - pub export: Export, - - /// `export = ` detected - pub export_assign: Option>, - - pub has_module_decl: bool, - - /// `export default expr` - export_default: Option, - - const_var_kind: VarDeclKind, -} - -impl ModuleDeclStrip { - pub fn new(const_var_kind: VarDeclKind) -> Self { - Self { - link: Default::default(), - export: Default::default(), - export_assign: Default::default(), - has_module_decl: Default::default(), - export_default: Default::default(), - const_var_kind, - } - } -} - -impl VisitMut for ModuleDeclStrip { - noop_visit_mut_type!(fail); - - fn visit_mut_module_items(&mut self, n: &mut Vec) { - let mut list = Vec::with_capacity(n.len()); - - for item in n.drain(..) { - match item { - ModuleItem::Stmt(stmt) => list.push(stmt.into()), - - ModuleItem::ModuleDecl(mut module_decl) => { - // collect link meta - module_decl.visit_mut_with(self); - self.has_module_decl = true; - - // emit stmt - match module_decl { - ModuleDecl::Import(..) => continue, - ModuleDecl::ExportDecl(ExportDecl { decl, .. }) => { - list.push(decl.into()); - } - ModuleDecl::ExportNamed(..) => continue, - ModuleDecl::ExportDefaultDecl(ExportDefaultDecl { decl, .. }) => match decl - { - DefaultDecl::Class(class_expr) => { - list.extend(class_expr.as_class_decl().map(From::from)) - } - DefaultDecl::Fn(fn_expr) => { - list.extend(fn_expr.as_fn_decl().map(From::from)) - } - DefaultDecl::TsInterfaceDecl(_) => continue, - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - }, - ModuleDecl::ExportDefaultExpr(..) => { - list.extend(self.export_default.take().map(From::from)) - } - ModuleDecl::ExportAll(..) => continue, - ModuleDecl::TsImportEquals(..) => continue, - ModuleDecl::TsExportAssignment(..) => continue, - ModuleDecl::TsNamespaceExport(..) => continue, - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - }; - } - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - }; - } - - *n = list; - } - - // collect all static import - fn visit_mut_import_decl(&mut self, n: &mut ImportDecl) { - if n.type_only { - return; - } - - let ImportDecl { - specifiers, src, .. - } = n.take(); - - self.link - .entry(src.value.to_atom_lossy().into_owned()) - .or_default() - .mut_dummy_span(src.span) - .extend(specifiers.into_iter().map(From::from)); - } - - /// ```javascript - /// export const foo = 1, bar = 2, { baz } = { baz: 3 }; - /// export let a = 1, [b] = [2]; - /// export function x() {} - /// export class y {} - /// ``` - /// -> - /// ```javascript - /// const foo = 1, bar = 2, { baz } = { baz: 3 }; - /// let a = 1, [b] = [2]; - /// function x() {} - /// class y {} - /// ``` - fn visit_mut_export_decl(&mut self, n: &mut ExportDecl) { - match &n.decl { - Decl::Class(ClassDecl { ident, .. }) | Decl::Fn(FnDecl { ident, .. }) => { - self.export.insert( - ident.sym.clone(), - ExportItem::new((ident.span, ident.ctxt), ident.clone()), - ); - } - - Decl::Var(v) => { - self.export.extend( - find_pat_ids::<_, Ident>(&v.decls) - .into_iter() - .map(|id| (id.sym.clone(), ExportItem::new((id.span, id.ctxt), id))), - ); - } - _ => {} - }; - } - - /// ```javascript - /// export { foo, foo as bar, foo as "baz" }; - /// export { "foo", foo as bar, "foo" as "baz" } from "mod"; - /// export * as foo from "mod"; - /// export * as "bar" from "mod"; - /// ``` - fn visit_mut_named_export(&mut self, n: &mut NamedExport) { - if n.type_only { - return; - } - - let NamedExport { - specifiers, src, .. - } = n.take(); - - if let Some(src) = src { - self.link - .entry(src.value.to_atom_lossy().into_owned()) - .or_default() - .mut_dummy_span(src.span) - .extend(specifiers.into_iter().map(From::from)); - } else { - self.export.extend(specifiers.into_iter().map(|e| match e { - ExportSpecifier::Namespace(..) => { - unreachable!("`export *` without src is invalid") - } - ExportSpecifier::Default(..) => { - unreachable!("`export foo` without src is invalid") - } - ExportSpecifier::Named(ExportNamedSpecifier { orig, exported, .. }) => { - let orig = match orig { - ModuleExportName::Ident(id) => id, - ModuleExportName::Str(_) => { - unreachable!(r#"`export {{ "foo" }}` without src is invalid"#) - } - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - }; - - if let Some(exported) = exported { - let (export_name, export_name_span) = match exported { - ModuleExportName::Ident(Ident { - ctxt, span, sym, .. - }) => (sym, (span, ctxt)), - ModuleExportName::Str(Str { span, value, .. }) => ( - value.to_atom_lossy().into_owned(), - (span, Default::default()), - ), - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - }; - - (export_name, ExportItem::new(export_name_span, orig)) - } else { - ( - orig.sym.clone(), - ExportItem::new((orig.span, orig.ctxt), orig), - ) - } - } - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - })) - } - } - - /// ```javascript - /// export default class foo {}; - /// export default class {}; - /// export default function bar () {}; - /// export default function () {}; - /// ``` - /// -> - /// ```javascript - /// class foo {}; - /// class _default {}; - /// function bar () {}; - /// function _default () {}; - /// ``` - fn visit_mut_export_default_decl(&mut self, n: &mut ExportDefaultDecl) { - match &mut n.decl { - DefaultDecl::Class(class_expr) => { - let ident = class_expr - .ident - .get_or_insert_with(|| private_ident!(n.span, "_default")) - .clone(); - - self.export.insert( - atom!("default"), - ExportItem::new((n.span, Default::default()), ident), - ); - } - DefaultDecl::Fn(fn_expr) => { - let ident = fn_expr - .ident - .get_or_insert_with(|| private_ident!(n.span, "_default")) - .clone(); - - self.export.insert( - atom!("default"), - ExportItem::new((n.span, Default::default()), ident), - ); - } - DefaultDecl::TsInterfaceDecl(_) => {} - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - } - } - - /// ```javascript - /// export default foo; - /// export default 1 - /// ``` - /// -> - /// ```javascript - /// var _default = foo; - /// var _default = 1; - /// ``` - fn visit_mut_export_default_expr(&mut self, n: &mut ExportDefaultExpr) { - let ident = private_ident!(n.span, "_default"); - - self.export.insert( - atom!("default"), - ExportItem::new((n.span, Default::default()), ident.clone()), - ); - - self.export_default = Some( - n.expr - .take() - .into_var_decl(self.const_var_kind, ident.into()) - .into(), - ); - } - - /// ```javascript - /// export * from "mod"; - /// ``` - fn visit_mut_export_all(&mut self, n: &mut ExportAll) { - let Str { - value: src_key, - span: src_span, - .. - } = *n.take().src; - - self.link - .entry(src_key.to_atom_lossy().into_owned()) - .or_default() - .mut_dummy_span(src_span) - .insert(LinkSpecifier::ExportStar); - } - - /// ```javascript - /// import foo = require("mod"); - /// export import foo = require("mod"); - /// ``` - fn visit_mut_ts_import_equals_decl(&mut self, n: &mut TsImportEqualsDecl) { - if n.is_type_only { - return; - } - - let TsImportEqualsDecl { - id, - module_ref, - is_export, - .. - } = n; - - if let TsModuleRef::TsExternalModuleRef(TsExternalModuleRef { - expr: - Str { - span, - value: src_key, - .. - }, - .. - }) = module_ref - { - if *is_export { - self.export.insert( - id.sym.clone(), - ExportItem::new((id.span, id.ctxt), id.clone()), - ); - } - - self.link - .entry(src_key.to_atom_lossy().into_owned()) - .or_default() - .mut_dummy_span(*span) - .insert(LinkSpecifier::ImportEqual(id.to_id())); - } - } - - /// ```javascript - /// export = expr; - /// ``` - fn visit_mut_ts_export_assignment(&mut self, n: &mut TsExportAssignment) { - self.export_assign.get_or_insert(n.expr.take()); - } -} - -#[derive(Debug, PartialEq, Eq, Hash)] -pub enum LinkSpecifier { - ///```javascript - /// import "mod"; - /// import {} from "mod", - /// import { type foo } from "mod"; - /// export {} from "mod"; - /// export { type foo } from "mod"; - /// ``` - Empty, - - /// ```javascript - /// import { imported as local, local } from "mod"; - /// import { "imported" as local } from "mod"; - /// ``` - /// Note: imported will never be `default` - ImportNamed { imported: Option, local: Id }, - - /// ```javascript - /// import foo from "mod"; - /// ``` - ImportDefault(Id), - - /// ```javascript - /// import * as foo from "mod"; - /// ``` - ImportStarAs(Id), - - /// ```javascript - /// export { orig, orig as exported } from "mod"; - /// export { "orig", "orig" as "exported" } from "mod"; - /// ``` - /// Note: orig will never be `default` - ExportNamed { - orig: (Atom, SpanCtx), - exported: Option<(Atom, SpanCtx)>, - }, - - /// ```javascript - /// export { default } from "foo"; - /// export { "default" } from "foo"; - /// export { default as foo } from "mod"; - /// ``` - /// (default_span, local_sym, local_span) - ExportDefaultAs(SpanCtx, Atom, SpanCtx), - - /// ```javascript - /// export * as foo from "mod"; - /// export * as "bar" from "mod"; - /// ``` - ExportStarAs(Atom, SpanCtx), - - /// ```javascript - /// export * from "mod"; - /// ``` - ExportStar, - - /// ```javascript - /// import foo = require("foo"); - /// ``` - ImportEqual(Id), -} - -impl From for LinkSpecifier { - fn from(i: ImportSpecifier) -> Self { - match i { - ImportSpecifier::Namespace(ImportStarAsSpecifier { local, .. }) => { - Self::ImportStarAs(local.to_id()) - } - - ImportSpecifier::Default(ImportDefaultSpecifier { local, .. }) => { - Self::ImportDefault(local.to_id()) - } - ImportSpecifier::Named(ImportNamedSpecifier { - is_type_only: false, - local, - imported: Some(ModuleExportName::Ident(Ident { sym: s, .. })), - .. - }) if &*s == "default" => Self::ImportDefault(local.to_id()), - - ImportSpecifier::Named(ImportNamedSpecifier { - is_type_only: false, - local, - imported: Some(ModuleExportName::Str(Str { value: s, .. })), - .. - }) if &s == "default" => Self::ImportDefault(local.to_id()), - - ImportSpecifier::Named(ImportNamedSpecifier { - is_type_only: false, - local, - imported, - .. - }) => { - let imported = imported.and_then(|e| match e { - ModuleExportName::Ident(Ident { sym, .. }) => Some(sym), - ModuleExportName::Str(Str { value, .. }) => value.as_atom().cloned(), - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - }); - - Self::ImportNamed { - local: local.to_id(), - imported, - } - } - _ => Self::Empty, - } - } -} - -impl From for LinkSpecifier { - fn from(e: ExportSpecifier) -> Self { - match e { - ExportSpecifier::Namespace(ExportNamespaceSpecifier { - name: - ModuleExportName::Str(Str { - span, value: sym, .. - }), - .. - }) => Self::ExportStarAs( - sym.to_atom_lossy().into_owned(), - (span, SyntaxContext::empty()), - ), - ExportSpecifier::Namespace(ExportNamespaceSpecifier { - name: ModuleExportName::Ident(Ident { span, sym, .. }), - .. - }) => Self::ExportStarAs(sym, (span, SyntaxContext::empty())), - - ExportSpecifier::Default(ExportDefaultSpecifier { exported }) => { - // https://github.com/tc39/proposal-export-default-from - Self::ExportDefaultAs( - (exported.span, exported.ctxt), - exported.sym, - (exported.span, exported.ctxt), - ) - } - - ExportSpecifier::Named(ExportNamedSpecifier { - is_type_only: false, - orig, - exported, - .. - }) => { - let orig = match orig { - ModuleExportName::Ident(Ident { span, sym, .. }) => { - (sym, (span, SyntaxContext::empty().apply_mark(Mark::new()))) - } - ModuleExportName::Str(Str { - span, value: sym, .. - }) => ( - sym.to_atom_lossy().into_owned(), - (span, SyntaxContext::empty().apply_mark(Mark::new())), - ), - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - }; - - let exported = exported.map(|exported| match exported { - ModuleExportName::Ident(Ident { span, sym, .. }) => { - (sym, (span, SyntaxContext::empty().apply_mark(Mark::new()))) - } - ModuleExportName::Str(Str { - span, value: sym, .. - }) => ( - sym.to_atom_lossy().into_owned(), - (span, SyntaxContext::empty().apply_mark(Mark::new())), - ), - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - }); - - match (&*orig.0, orig.1) { - ("default", default_span) => { - let (sym, span) = exported.unwrap_or(orig); - - Self::ExportDefaultAs(default_span, sym, span) - } - _ => Self::ExportNamed { orig, exported }, - } - } - _ => Self::Empty, - } - } -} - -#[derive(Debug, Default)] -pub struct LinkItem(pub SpanCtx, pub FxHashSet, pub LinkFlag); - -use bitflags::bitflags; - -bitflags! { - #[derive(Default, Debug)] - pub struct LinkFlag: u8 { - const NAMED = 1 << 0; - const DEFAULT = 1 << 1; - const NAMESPACE = Self::NAMED.bits() | Self::DEFAULT.bits(); - const EXPORT_STAR = 1 << 2; - const IMPORT_EQUAL = 1 << 3; - } -} - -impl LinkFlag { - pub fn interop(&self) -> bool { - self.intersects(Self::DEFAULT) - } - - pub fn has_named(&self) -> bool { - self.intersects(Self::NAMED) - } - - pub fn namespace(&self) -> bool { - self.contains(Self::NAMESPACE) - } - - pub fn need_raw_import(&self) -> bool { - self.interop() && self.intersects(Self::IMPORT_EQUAL) - } - - pub fn export_star(&self) -> bool { - self.intersects(Self::EXPORT_STAR) - } -} - -impl From<&LinkSpecifier> for LinkFlag { - fn from(s: &LinkSpecifier) -> Self { - match s { - LinkSpecifier::Empty => Self::empty(), - LinkSpecifier::ImportStarAs(..) => Self::NAMESPACE, - LinkSpecifier::ImportDefault(..) => Self::DEFAULT, - LinkSpecifier::ImportNamed { .. } => Self::NAMED, - - LinkSpecifier::ExportStarAs(..) => Self::NAMESPACE, - LinkSpecifier::ExportDefaultAs(..) => Self::DEFAULT, - LinkSpecifier::ExportNamed { .. } => Self::NAMED, - - LinkSpecifier::ImportEqual(..) => Self::IMPORT_EQUAL, - LinkSpecifier::ExportStar => Self::EXPORT_STAR, - } - } -} - -impl From<&ImportSpecifier> for LinkFlag { - fn from(i: &ImportSpecifier) -> Self { - match i { - ImportSpecifier::Namespace(..) => Self::NAMESPACE, - - ImportSpecifier::Default(ImportDefaultSpecifier { .. }) => Self::DEFAULT, - - ImportSpecifier::Named(ImportNamedSpecifier { - is_type_only: false, - imported: Some(ModuleExportName::Ident(Ident { sym: default, .. })), - .. - }) if &**default == "default" => Self::DEFAULT, - - ImportSpecifier::Named(ImportNamedSpecifier { - is_type_only: false, - imported: Some(ModuleExportName::Str(Str { value: default, .. })), - .. - }) if default == "default" => Self::DEFAULT, - - ImportSpecifier::Named(ImportNamedSpecifier { - is_type_only: false, - .. - }) => Self::NAMED, - - _ => Self::empty(), - } - } -} - -impl From<&ExportSpecifier> for LinkFlag { - fn from(e: &ExportSpecifier) -> Self { - match e { - ExportSpecifier::Namespace(..) => Self::NAMESPACE, - - // https://github.com/tc39/proposal-export-default-from - ExportSpecifier::Default(..) => Self::DEFAULT, - - ExportSpecifier::Named(ExportNamedSpecifier { - is_type_only: false, - orig: ModuleExportName::Str(Str { value: s, .. }), - .. - }) if s == "default" => Self::DEFAULT, - - ExportSpecifier::Named(ExportNamedSpecifier { - is_type_only: false, - orig: ModuleExportName::Ident(Ident { sym: s, .. }), - .. - }) if &**s == "default" => Self::DEFAULT, - - ExportSpecifier::Named(ExportNamedSpecifier { - is_type_only: false, - .. - }) => Self::NAMED, - - _ => Self::empty(), - } - } -} - -impl Extend for LinkItem { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each(|link| { - self.insert(link); - }); - } -} - -impl LinkItem { - fn mut_dummy_span(&mut self, span: Span) -> &mut Self { - if self.0 .0.is_dummy() { - self.0 .0 = span; - } - - self - } - - fn insert(&mut self, link: LinkSpecifier) -> bool { - self.2 |= (&link).into(); - self.1.insert(link) - } -} - -pub(crate) type ExportObjPropList = Vec; - -/// Reduce self to generate ImportMap and ExportObjPropList -pub(crate) trait LinkSpecifierReducer { - fn reduce( - self, - import_map: &mut ImportMap, - export_obj_prop_list: &mut ExportObjPropList, - mod_ident: &Ident, - raw_mod_ident: &Option, - ref_to_mod_ident: &mut bool, - // do not emit `mod.default`, emit `mod` instead - default_nowrap: bool, - ); -} - -impl LinkSpecifierReducer for FxHashSet { - fn reduce( - self, - import_map: &mut ImportMap, - export_obj_prop_list: &mut ExportObjPropList, - mod_ident: &Ident, - raw_mod_ident: &Option, - ref_to_mod_ident: &mut bool, - default_nowrap: bool, - ) { - self.into_iter().for_each(|s| match s { - LinkSpecifier::ImportNamed { imported, local } => { - *ref_to_mod_ident = true; - - import_map.insert( - local.clone(), - (mod_ident.clone(), imported.or(Some(local.0))), - ); - } - LinkSpecifier::ImportDefault(id) => { - *ref_to_mod_ident = true; - - import_map.insert( - id, - ( - mod_ident.clone(), - (!default_nowrap).then(|| atom!("default")), - ), - ); - } - LinkSpecifier::ImportStarAs(id) => { - *ref_to_mod_ident = true; - - import_map.insert(id, (mod_ident.clone(), None)); - } - LinkSpecifier::ExportNamed { orig, exported } => { - *ref_to_mod_ident = true; - - // ```javascript - // export { foo as bar } from "mod"; - // - // import { foo } from "mod"; - // export { foo as bar }; - // ``` - - // foo -> mod.foo - import_map.insert( - (orig.0.clone(), orig.1 .1), - (mod_ident.clone(), Some(orig.0.clone())), - ); - - let (export_name, export_name_span) = exported.unwrap_or_else(|| orig.clone()); - - // bar -> foo - export_obj_prop_list.push(( - export_name, - ExportItem::new(export_name_span, quote_ident!(orig.1 .1, orig.1 .0, orig.0)), - )) - } - LinkSpecifier::ExportDefaultAs(_, key, span) => { - *ref_to_mod_ident = true; - - // ```javascript - // export { default as foo } from "mod"; - // - // import { default as foo } from "mod"; - // export { foo }; - // ``` - - // foo -> mod.default - import_map.insert( - (key.clone(), span.1), - (mod_ident.clone(), Some(atom!("default"))), - ); - - export_obj_prop_list.push(( - key.clone(), - ExportItem::new(span, quote_ident!(span.1, span.0, key)), - )); - } - LinkSpecifier::ExportStarAs(key, span) => { - *ref_to_mod_ident = true; - - export_obj_prop_list.push((key, ExportItem::new(span, mod_ident.clone()))); - } - LinkSpecifier::ExportStar => {} - LinkSpecifier::ImportEqual(id) => { - *ref_to_mod_ident = true; - - import_map.insert( - id, - ( - raw_mod_ident.clone().unwrap_or_else(|| mod_ident.clone()), - None, - ), - ); - } - LinkSpecifier::Empty => {} - }) - } -} - -#[derive(Debug)] -pub struct ExportItem(SpanCtx, Ident); - -impl ExportItem { - pub fn new(export_name_span: SpanCtx, local_ident: Ident) -> Self { - Self(export_name_span, local_ident) - } - - pub fn export_name_span(&self) -> SpanCtx { - self.0 - } - - pub fn into_local_ident(self) -> Ident { - self.1 - } -} - -pub type ExportKV = (Atom, ExportItem); diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/module_record.rs b/deps/swc/crates/swc_ecma_transforms_module/src/module_record.rs new file mode 100644 index 000000000..5849dc6a8 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/src/module_record.rs @@ -0,0 +1,974 @@ +use std::cmp::Ordering; + +use indexmap::IndexMap; +use rustc_hash::{FxHashMap, FxHashSet}; +use swc_atoms::{atom, Atom, Wtf8Atom}; +use swc_common::{Mark, Span, SyntaxContext}; +use swc_ecma_ast::*; +use swc_ecma_utils::{find_pat_ids, quote_ident, IsDirective}; + +use crate::{module_ref_rewriter::ImportMap, SpanCtx}; + +/// `Source Text Module Record.[[RequestedModules]]`, kept in source order for +/// deterministic emit. +/// +/// Entries are grouped by `ModuleRequest` Record so import attributes stay +/// paired with the matching dependency slot. +/// +/// Spec: +/// - +/// - +/// - +pub(crate) type RequestedModules = IndexMap; +/// `Source Text Module Record.[[LocalExportEntries]]`, keyed by export name. +/// +/// Spec: +pub(crate) type LocalExportEntries = FxHashMap; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub(crate) struct ModuleRequestRecord { + /// `ModuleRequest` Record [[Specifier]]. + specifier: Atom, + /// `ModuleRequest` Record [[Attributes]]. + attributes: Vec, +} + +impl ModuleRequestRecord { + pub fn src(&self) -> &Atom { + &self.specifier + } + + pub fn attributes(&self) -> &[ImportAttributeRecord] { + &self.attributes + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub(crate) struct ImportAttributeRecord { + /// `ImportAttribute` Record [[Key]]. + key: Atom, + /// `ImportAttribute` Record [[Value]]. + value: Wtf8Atom, +} + +impl ImportAttributeRecord { + pub fn key(&self) -> &Atom { + &self.key + } + + pub fn value(&self) -> &Wtf8Atom { + &self.value + } +} + +fn import_attributes(with: Option>) -> Vec { + let Some(with) = with else { + return Vec::new(); + }; + + let Some(mut attributes) = with + .props + .into_iter() + .map(|prop| import_attribute_record(&prop)) + .collect::>>() + else { + return Vec::new(); + }; + + attributes.sort_unstable_by(|a, b| { + cmp_utf16(a.key.as_str(), b.key.as_str()).then_with(|| a.value.cmp(&b.value)) + }); + + attributes +} + +fn import_attribute_record(prop: &PropOrSpread) -> Option { + let PropOrSpread::Prop(prop) = prop else { + return None; + }; + + let Prop::KeyValue(key_value) = &**prop else { + return None; + }; + + let key = match &key_value.key { + PropName::Ident(key) => key.sym.clone(), + PropName::Str(key) => key.value.as_str()?.into(), + _ => return None, + }; + + let Expr::Lit(Lit::Str(value)) = &*key_value.value else { + return None; + }; + + Some(ImportAttributeRecord { + key, + value: value.value.clone(), + }) +} + +fn cmp_utf16(a: &str, b: &str) -> Ordering { + a.encode_utf16().cmp(b.encode_utf16()) +} + +/// Source-level module syntax split into reusable module-record data and +/// ordered body items. +/// +/// This keeps extraction separate from target-specific stripping. Lowerers are +/// responsible for deciding how an exported declaration or expression becomes +/// executable code in their output format. +#[derive(Debug)] +pub(crate) struct SourceModule { + /// Directive prologue statements, preserved before generated wrapper code. + pub directives: Vec, + /// Whether the original directive prologue contained `"use strict"`. + pub has_use_strict: bool, + pub requested_modules: RequestedModules, + pub local_export_entries: LocalExportEntries, + /// TypeScript `export = expr` syntax is a source-level module record fact. + /// CJS-like lowerers consume it as an output-specific assignment. + pub ts_export_assignment: Option>, + pub body: Vec, + /// Whether the original source contained any module declaration. + /// This preserves the legacy extractor signal used for interop decisions. + pub has_module_syntax: bool, +} + +impl SourceModule { + pub fn collect(body: Vec) -> Self { + SourceModuleCollector::default().collect(body) + } +} + +/// Ordered executable source items after top-level module declarations are +/// recorded, but before any target-specific lowering removes export syntax. +#[derive(Debug)] +pub(crate) enum SourceModuleItem { + Stmt(Stmt), + ExportDecl(ExportDecl), + ExportDefaultDecl(ExportDefaultDecl), + ExportDefaultExpr(ExportDefaultExpr), + TsImportEquals(Box), +} + +pub(crate) fn external_ts_import_equals_source(import: &TsImportEqualsDecl) -> Option<&Str> { + if import.is_type_only { + return None; + } + + match &import.module_ref { + TsModuleRef::TsExternalModuleRef(TsExternalModuleRef { expr, .. }) => Some(expr), + _ => None, + } +} + +pub(crate) fn exported_external_ts_import_equals_name(item: &ModuleItem) -> Option<&Atom> { + let ModuleItem::ModuleDecl(ModuleDecl::TsImportEquals(import)) = item else { + return None; + }; + + if !import.is_export || external_ts_import_equals_source(import).is_none() { + return None; + } + + Some(&import.id.sym) +} + +#[derive(Default)] +struct SourceModuleCollector { + requested_modules: RequestedModules, + local_export_entries: LocalExportEntries, + ts_export_assignment: Option>, + has_module_syntax: bool, +} + +impl SourceModuleCollector { + fn collect(mut self, body: Vec) -> SourceModule { + let mut directives = Vec::new(); + let mut has_use_strict = false; + let mut source_items = Vec::with_capacity(body.len()); + let mut in_directive_prologue = true; + + for item in body { + if in_directive_prologue && item.directive_continue() { + let stmt = item.expect_stmt(); + if !has_use_strict { + has_use_strict = stmt.is_use_strict(); + } + directives.push(stmt); + continue; + } + + in_directive_prologue = false; + + match item { + ModuleItem::Stmt(stmt) => source_items.push(SourceModuleItem::Stmt(stmt)), + ModuleItem::ModuleDecl(module_decl) => { + if match &module_decl { + ModuleDecl::TsImportEquals(import) => { + import.is_export && external_ts_import_equals_source(import).is_some() + } + _ => true, + } { + self.has_module_syntax = true; + } + + if let Some(item) = self.collect_module_decl(module_decl) { + source_items.push(item); + } + } + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + } + } + + SourceModule { + directives, + has_use_strict, + requested_modules: self.requested_modules, + local_export_entries: self.local_export_entries, + ts_export_assignment: self.ts_export_assignment, + body: source_items, + has_module_syntax: self.has_module_syntax, + } + } + + fn collect_module_decl(&mut self, module_decl: ModuleDecl) -> Option { + match module_decl { + ModuleDecl::Import(import) => { + self.collect_import_decl(import); + None + } + ModuleDecl::ExportDecl(export) => { + self.collect_export_decl(&export); + Some(SourceModuleItem::ExportDecl(export)) + } + ModuleDecl::ExportNamed(export) => { + self.collect_named_export(export); + None + } + ModuleDecl::ExportDefaultDecl(export) => { + self.collect_export_default_decl(&export); + Some(SourceModuleItem::ExportDefaultDecl(export)) + } + ModuleDecl::ExportDefaultExpr(export) => { + Some(SourceModuleItem::ExportDefaultExpr(export)) + } + ModuleDecl::ExportAll(export) => { + self.collect_export_all(export); + None + } + ModuleDecl::TsImportEquals(import) => self.collect_ts_import_equals(import), + ModuleDecl::TsExportAssignment(export) => { + self.ts_export_assignment.get_or_insert(export.expr); + None + } + ModuleDecl::TsNamespaceExport(_) => None, + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + } + } + + fn module_request( + specifier: Atom, + attributes: &[ImportAttributeRecord], + ) -> ModuleRequestRecord { + ModuleRequestRecord { + specifier, + attributes: attributes.to_vec(), + } + } + + fn collect_import_decl(&mut self, import: ImportDecl) { + if import.type_only { + return; + } + + let ImportDecl { + specifiers, + src, + with, + .. + } = import; + + let src_key = src.value.to_atom_lossy().into_owned(); + let attributes = import_attributes(with); + let module_request = Self::module_request(src_key, &attributes); + + self.requested_modules + .entry(module_request) + .or_default() + .mut_dummy_span(src.span) + .extend(specifiers.into_iter().map(From::from)); + } + + fn collect_export_decl(&mut self, export: &ExportDecl) { + match &export.decl { + Decl::Class(ClassDecl { ident, .. }) | Decl::Fn(FnDecl { ident, .. }) => { + self.local_export_entries.insert( + ident.sym.clone(), + LocalExportEntry::new((ident.span, ident.ctxt), ident.clone()), + ); + } + + Decl::Var(v) => { + self.local_export_entries.extend( + find_pat_ids::<_, Ident>(&v.decls).into_iter().map(|id| { + ( + id.sym.clone(), + LocalExportEntry::new((id.span, id.ctxt), id), + ) + }), + ); + } + _ => {} + } + } + + fn collect_named_export(&mut self, export: NamedExport) { + if export.type_only { + return; + } + + let NamedExport { + specifiers, + src, + with, + .. + } = export; + + if let Some(src) = src { + let src_key = src.value.to_atom_lossy().into_owned(); + let attributes = import_attributes(with); + let module_request = Self::module_request(src_key, &attributes); + + self.requested_modules + .entry(module_request) + .or_default() + .mut_dummy_span(src.span) + .extend(specifiers.into_iter().map(From::from)); + } else { + self.local_export_entries + .extend(specifiers.into_iter().map(Self::local_export_entry)); + } + } + + fn local_export_entry(specifier: ExportSpecifier) -> ExportBinding { + match specifier { + ExportSpecifier::Namespace(..) => unreachable!("`export *` without src is invalid"), + ExportSpecifier::Default(..) => unreachable!("`export foo` without src is invalid"), + ExportSpecifier::Named(ExportNamedSpecifier { orig, exported, .. }) => { + let orig = match orig { + ModuleExportName::Ident(id) => id, + ModuleExportName::Str(_) => { + unreachable!(r#"`export {{ "foo" }}` without src is invalid"#) + } + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + }; + + if let Some(exported) = exported { + let (export_name, export_name_span) = match exported { + ModuleExportName::Ident(Ident { + ctxt, span, sym, .. + }) => (sym, (span, ctxt)), + ModuleExportName::Str(Str { span, value, .. }) => ( + value.to_atom_lossy().into_owned(), + (span, Default::default()), + ), + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + }; + + (export_name, LocalExportEntry::new(export_name_span, orig)) + } else { + ( + orig.sym.clone(), + LocalExportEntry::new((orig.span, orig.ctxt), orig), + ) + } + } + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + } + } + + fn collect_export_default_decl(&mut self, export: &ExportDefaultDecl) { + match &export.decl { + DefaultDecl::Class(class_expr) => { + if let Some(ident) = &class_expr.ident { + self.local_export_entries.insert( + atom!("default"), + LocalExportEntry::new((export.span, Default::default()), ident.clone()), + ); + } + } + DefaultDecl::Fn(fn_expr) => { + if let Some(ident) = &fn_expr.ident { + self.local_export_entries.insert( + atom!("default"), + LocalExportEntry::new((export.span, Default::default()), ident.clone()), + ); + } + } + DefaultDecl::TsInterfaceDecl(_) => {} + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + } + } + + fn collect_export_all(&mut self, export: ExportAll) { + let ExportAll { src, with, .. } = export; + let Str { + value: src_key, + span: src_span, + .. + } = *src; + + let attributes = import_attributes(with); + let module_request = + Self::module_request(src_key.to_atom_lossy().into_owned(), &attributes); + + self.requested_modules + .entry(module_request) + .or_default() + .mut_dummy_span(src_span) + .insert(ModuleRecordEntry::StarExport); + } + + fn collect_ts_import_equals( + &mut self, + import: Box, + ) -> Option { + external_ts_import_equals_source(&import)?; + + if import.is_export { + self.local_export_entries.insert( + import.id.sym.clone(), + LocalExportEntry::new((import.id.span, import.id.ctxt), import.id.clone()), + ); + } + + Some(SourceModuleItem::TsImportEquals(import)) + } +} + +/// `ImportEntry` and `ExportEntry` record fields used by this transform. +/// +/// Spec: +/// - +/// - +/// - +/// - +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum ModuleRecordEntry { + ///```javascript + /// import "mod"; + /// import {} from "mod", + /// import { type foo } from "mod"; + /// export {} from "mod"; + /// export { type foo } from "mod"; + /// ``` + Empty, + + /// ```javascript + /// import { imported as local, local } from "mod"; + /// import { "imported" as local } from "mod"; + /// ``` + /// Note: `import_name` will never be `default`. + ImportNamed { + import_name: Option, + local_name: Id, + }, + + /// ```javascript + /// import foo from "mod"; + /// ``` + ImportDefault { local_name: Id }, + + /// ```javascript + /// import * as foo from "mod"; + /// ``` + /// The spec resolves this to a Module Namespace Exotic Object. This legacy + /// module transform emits an interop object instead. + /// Spec: + /// - + /// - + ImportNamespace { local_name: Id }, + + /// ```javascript + /// export { orig, orig as exported } from "mod"; + /// export { "orig", "orig" as "exported" } from "mod"; + /// ``` + /// Note: `import_name` will never be `default`. + IndirectExportNamed { + import_name: (Atom, SpanCtx), + export_name: Option<(Atom, SpanCtx)>, + }, + + /// ```javascript + /// export { default } from "foo"; + /// export { "default" } from "foo"; + /// export { default as foo } from "mod"; + /// ``` + IndirectExportDefault { + export_name: Atom, + export_name_span: SpanCtx, + }, + + /// ```javascript + /// export * as foo from "mod"; + /// export * as "bar" from "mod"; + /// ``` + /// The spec resolves this to a namespace export binding. This transform + /// emits a legacy interop object getter instead. + /// Spec: + /// - + /// - + IndirectExportNamespace { + export_name: Atom, + export_name_span: SpanCtx, + }, + + /// ```javascript + /// export * from "mod"; + /// ``` + /// Related spec operation: `GetExportedNames` walks + /// `[[StarExportEntries]]` and omits `default` from star-exported names. + /// + StarExport, +} + +impl From for ModuleRecordEntry { + fn from(i: ImportSpecifier) -> Self { + match i { + ImportSpecifier::Namespace(ImportStarAsSpecifier { local, .. }) => { + Self::ImportNamespace { + local_name: local.to_id(), + } + } + + ImportSpecifier::Default(ImportDefaultSpecifier { local, .. }) => Self::ImportDefault { + local_name: local.to_id(), + }, + ImportSpecifier::Named(ImportNamedSpecifier { + is_type_only: false, + local, + imported: Some(ModuleExportName::Ident(Ident { sym: s, .. })), + .. + }) if &*s == "default" => Self::ImportDefault { + local_name: local.to_id(), + }, + + ImportSpecifier::Named(ImportNamedSpecifier { + is_type_only: false, + local, + imported: Some(ModuleExportName::Str(Str { value: s, .. })), + .. + }) if &s == "default" => Self::ImportDefault { + local_name: local.to_id(), + }, + + ImportSpecifier::Named(ImportNamedSpecifier { + is_type_only: false, + local, + imported, + .. + }) => { + let import_name = imported.and_then(|e| match e { + ModuleExportName::Ident(Ident { sym, .. }) => Some(sym), + ModuleExportName::Str(Str { value, .. }) => value.as_atom().cloned(), + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + }); + + Self::ImportNamed { + local_name: local.to_id(), + import_name, + } + } + _ => Self::Empty, + } + } +} + +impl From for ModuleRecordEntry { + fn from(e: ExportSpecifier) -> Self { + match e { + ExportSpecifier::Namespace(ExportNamespaceSpecifier { + name: + ModuleExportName::Str(Str { + span, value: sym, .. + }), + .. + }) => Self::IndirectExportNamespace { + export_name: sym.to_atom_lossy().into_owned(), + export_name_span: (span, SyntaxContext::empty()), + }, + ExportSpecifier::Namespace(ExportNamespaceSpecifier { + name: ModuleExportName::Ident(Ident { span, sym, .. }), + .. + }) => Self::IndirectExportNamespace { + export_name: sym, + export_name_span: (span, SyntaxContext::empty()), + }, + + ExportSpecifier::Default(ExportDefaultSpecifier { exported }) => { + // https://github.com/tc39/proposal-export-default-from + Self::IndirectExportDefault { + export_name: exported.sym, + export_name_span: (exported.span, exported.ctxt), + } + } + + ExportSpecifier::Named(ExportNamedSpecifier { + is_type_only: false, + orig, + exported, + .. + }) => { + let orig = match orig { + ModuleExportName::Ident(Ident { span, sym, .. }) => { + (sym, (span, SyntaxContext::empty().apply_mark(Mark::new()))) + } + ModuleExportName::Str(Str { + span, value: sym, .. + }) => ( + sym.to_atom_lossy().into_owned(), + (span, SyntaxContext::empty().apply_mark(Mark::new())), + ), + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + }; + + let exported = exported.map(|exported| match exported { + ModuleExportName::Ident(Ident { span, sym, .. }) => { + (sym, (span, SyntaxContext::empty().apply_mark(Mark::new()))) + } + ModuleExportName::Str(Str { + span, value: sym, .. + }) => ( + sym.to_atom_lossy().into_owned(), + (span, SyntaxContext::empty().apply_mark(Mark::new())), + ), + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + }); + + match (&*orig.0, orig.1) { + ("default", _) => { + let (sym, span) = exported.unwrap_or(orig); + + Self::IndirectExportDefault { + export_name: sym, + export_name_span: span, + } + } + _ => Self::IndirectExportNamed { + import_name: orig, + export_name: exported, + }, + } + } + _ => Self::Empty, + } + } +} + +#[derive(Debug, Default)] +pub struct RequestedModule { + /// First useful source span for the module request. The spec tracks this as + /// a `ModuleRequest` Record; emitters keep the span for generated literals + /// and diagnostics. + /// + /// Spec: + pub span: SpanCtx, + /// `ImportEntry` and `ExportEntry` records associated with this module + /// request. + pub entries: FxHashSet, + /// Emitter-only summary of which runtime module shape is needed. + pub usage: ModuleRequestUsage, +} + +use bitflags::bitflags; + +bitflags! { + #[derive(Default, Debug)] + pub struct ModuleRequestUsage: u8 { + const NAMED = 1 << 0; + const DEFAULT = 1 << 1; + const NAMESPACE = Self::NAMED.bits() | Self::DEFAULT.bits(); + const STAR_EXPORT = 1 << 2; + } +} + +impl ModuleRequestUsage { + pub fn needs_interop(&self) -> bool { + self.intersects(Self::DEFAULT) + } + + pub fn has_named(&self) -> bool { + self.intersects(Self::NAMED) + } + + pub fn needs_namespace_object(&self) -> bool { + self.contains(Self::NAMESPACE) + } + + pub fn has_star_export(&self) -> bool { + self.intersects(Self::STAR_EXPORT) + } +} + +impl From<&ModuleRecordEntry> for ModuleRequestUsage { + fn from(s: &ModuleRecordEntry) -> Self { + match s { + ModuleRecordEntry::Empty => Self::empty(), + ModuleRecordEntry::ImportNamespace { .. } => Self::NAMESPACE, + ModuleRecordEntry::ImportDefault { .. } => Self::DEFAULT, + ModuleRecordEntry::ImportNamed { .. } => Self::NAMED, + + ModuleRecordEntry::IndirectExportNamespace { .. } => Self::NAMESPACE, + ModuleRecordEntry::IndirectExportDefault { .. } => Self::DEFAULT, + ModuleRecordEntry::IndirectExportNamed { .. } => Self::NAMED, + + ModuleRecordEntry::StarExport => Self::STAR_EXPORT, + } + } +} + +impl From<&ImportSpecifier> for ModuleRequestUsage { + fn from(i: &ImportSpecifier) -> Self { + match i { + ImportSpecifier::Namespace(..) => Self::NAMESPACE, + + ImportSpecifier::Default(ImportDefaultSpecifier { .. }) => Self::DEFAULT, + + ImportSpecifier::Named(ImportNamedSpecifier { + is_type_only: false, + imported: Some(ModuleExportName::Ident(Ident { sym: default, .. })), + .. + }) if &**default == "default" => Self::DEFAULT, + + ImportSpecifier::Named(ImportNamedSpecifier { + is_type_only: false, + imported: Some(ModuleExportName::Str(Str { value: default, .. })), + .. + }) if default == "default" => Self::DEFAULT, + + ImportSpecifier::Named(ImportNamedSpecifier { + is_type_only: false, + .. + }) => Self::NAMED, + + _ => Self::empty(), + } + } +} + +impl From<&ExportSpecifier> for ModuleRequestUsage { + fn from(e: &ExportSpecifier) -> Self { + match e { + ExportSpecifier::Namespace(..) => Self::NAMESPACE, + + // https://github.com/tc39/proposal-export-default-from + ExportSpecifier::Default(..) => Self::DEFAULT, + + ExportSpecifier::Named(ExportNamedSpecifier { + is_type_only: false, + orig: ModuleExportName::Str(Str { value: s, .. }), + .. + }) if s == "default" => Self::DEFAULT, + + ExportSpecifier::Named(ExportNamedSpecifier { + is_type_only: false, + orig: ModuleExportName::Ident(Ident { sym: s, .. }), + .. + }) if &**s == "default" => Self::DEFAULT, + + ExportSpecifier::Named(ExportNamedSpecifier { + is_type_only: false, + .. + }) => Self::NAMED, + + _ => Self::empty(), + } + } +} + +impl Extend for RequestedModule { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|link| { + self.insert(link); + }); + } +} + +impl RequestedModule { + fn mut_dummy_span(&mut self, span: Span) -> &mut Self { + if self.span.0.is_dummy() { + self.span.0 = span; + } + + self + } + + fn insert(&mut self, entry: ModuleRecordEntry) -> bool { + self.usage |= (&entry).into(); + self.entries.insert(entry) + } +} + +pub(crate) type ExportObjectProperties = Vec; + +/// Reduce module record entries into the import map and export object +/// properties required by CommonJS-like emitters. +/// +/// This is not a full ECMAScript module linker. It only lowers collected +/// syntactic entries to emitter-local data structures; the corresponding spec +/// operations for linked modules are `GetExportedNames` and `ResolveExport`. +/// - +/// - +pub(crate) trait ModuleRecordEntryReducer { + fn reduce( + self, + import_map: &mut ImportMap, + export_bindings: &mut ExportObjectProperties, + mod_ident: &Ident, + ref_to_mod_ident: &mut bool, + // do not emit `mod.default`, emit `mod` instead + default_nowrap: bool, + ); +} + +impl ModuleRecordEntryReducer for FxHashSet { + fn reduce( + self, + import_map: &mut ImportMap, + export_bindings: &mut ExportObjectProperties, + mod_ident: &Ident, + ref_to_mod_ident: &mut bool, + default_nowrap: bool, + ) { + self.into_iter().for_each(|s| match s { + ModuleRecordEntry::ImportNamed { + import_name, + local_name, + } => { + *ref_to_mod_ident = true; + + import_map.insert( + local_name.clone(), + (mod_ident.clone(), import_name.or(Some(local_name.0))), + ); + } + ModuleRecordEntry::ImportDefault { local_name } => { + *ref_to_mod_ident = true; + + import_map.insert( + local_name, + ( + mod_ident.clone(), + (!default_nowrap).then(|| atom!("default")), + ), + ); + } + ModuleRecordEntry::ImportNamespace { local_name } => { + *ref_to_mod_ident = true; + + import_map.insert(local_name, (mod_ident.clone(), None)); + } + ModuleRecordEntry::IndirectExportNamed { + import_name, + export_name, + } => { + *ref_to_mod_ident = true; + + // ```javascript + // export { foo as bar } from "mod"; + // + // import { foo } from "mod"; + // export { foo as bar }; + // ``` + + // foo -> mod.foo + import_map.insert( + (import_name.0.clone(), import_name.1 .1), + (mod_ident.clone(), Some(import_name.0.clone())), + ); + + let (export_name, export_name_span) = + export_name.unwrap_or_else(|| import_name.clone()); + + // bar -> foo + export_bindings.push(( + export_name, + LocalExportEntry::new( + export_name_span, + quote_ident!(import_name.1 .1, import_name.1 .0, import_name.0), + ), + )); + } + ModuleRecordEntry::IndirectExportDefault { + export_name, + export_name_span, + .. + } => { + *ref_to_mod_ident = true; + + // ```javascript + // export { default as foo } from "mod"; + // + // import { default as foo } from "mod"; + // export { foo }; + // ``` + + // foo -> mod.default + import_map.insert( + (export_name.clone(), export_name_span.1), + (mod_ident.clone(), Some(atom!("default"))), + ); + + export_bindings.push(( + export_name.clone(), + LocalExportEntry::new( + export_name_span, + quote_ident!(export_name_span.1, export_name_span.0, export_name), + ), + )); + } + ModuleRecordEntry::IndirectExportNamespace { + export_name, + export_name_span, + } => { + *ref_to_mod_ident = true; + + export_bindings.push(( + export_name, + LocalExportEntry::new(export_name_span, mod_ident.clone()), + )); + } + ModuleRecordEntry::StarExport => {} + ModuleRecordEntry::Empty => {} + }); + } +} + +#[derive(Debug)] +pub struct LocalExportEntry(SpanCtx, Ident); + +impl LocalExportEntry { + pub fn new(export_name_span: SpanCtx, local_ident: Ident) -> Self { + Self(export_name_span, local_ident) + } + + pub fn export_name_span(&self) -> SpanCtx { + self.0 + } + + pub fn into_local_ident(self) -> Ident { + self.1 + } +} + +pub type ExportBinding = (Atom, LocalExportEntry); diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs b/deps/swc/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs index b7da9ee1e..fe1a8041b 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs @@ -81,8 +81,7 @@ impl QueryRef for ImportQuery { self.import_map .get(&ident.to_id()) - .map(|(_, prop)| prop.is_some()) - .unwrap_or_default() + .is_some_and(|(_, prop)| prop.is_some()) } } @@ -100,7 +99,7 @@ pub(crate) fn rewrite_import_bindings( helper_ctxt: { HELPERS .is_set() - .then(|| HELPERS.with(|helper| helper.mark())) + .then(|| HELPERS.with(swc_ecma_transforms_base::helpers::Helpers::mark)) .map(|mark| SyntaxContext::empty().apply_mark(mark)) }, }, diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/path.rs b/deps/swc/crates/swc_ecma_transforms_module/src/path.rs index 08285710b..89c73f02c 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/path.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/path.rs @@ -73,7 +73,7 @@ pub trait ImportResolver { fn resolve_import(&self, base: &FileName, module_specifier: &str) -> Result; } -/// [ImportResolver] implementation which just uses original source. +/// [`ImportResolver`] implementation which just uses original source. #[derive(Debug, Clone, Copy, Default)] pub struct NoopImportResolver; @@ -83,11 +83,11 @@ impl ImportResolver for NoopImportResolver { } } -/// [ImportResolver] implementation for node.js +/// [`ImportResolver`] implementation for node.js /// -/// Supports [FileName::Real] and [FileName::Anon] for `base`, [FileName::Real] -/// and [FileName::Custom] for `target`. ([FileName::Custom] is used for core -/// modules) +/// Supports [`FileName::Real`] and [`FileName::Anon`] for `base`, +/// [`FileName::Real`] and [`FileName::Custom`] for `target`. +/// ([`FileName::Custom`] is used for core modules) #[derive(Debug, Clone, Default)] pub struct NodeImportResolver where @@ -335,8 +335,26 @@ where }; if base.is_absolute() != target.is_absolute() { - base = Cow::Owned(absolute_path(self.config.base_dir.as_deref(), &base)?); - target = absolute_path(self.config.base_dir.as_deref(), &target)?; + if base.is_absolute() { + base = Cow::Owned(base.to_path_buf().clean()); + } else { + base = Cow::Owned(absolute_base_path(self.config.base_dir.as_deref(), &base)?); + } + + if target.is_absolute() { + target = target.clean(); + } else { + target = absolute_path(self.config.base_dir.as_deref(), &target)?; + } + } + + #[cfg(windows)] + { + (base, target) = normalize_extended_length_path_prefixes( + self.config.base_dir.as_deref(), + base, + target, + ); } #[cfg(debug_assertions)] @@ -444,3 +462,188 @@ fn absolute_path(base_dir: Option<&Path>, path: &Path) -> io::Result { Ok(absolute_path) } + +fn absolute_base_path(base_dir: Option<&Path>, path: &Path) -> io::Result { + if path.is_absolute() { + return Ok(path.to_path_buf().clean()); + } + + let Some(base_dir) = base_dir else { + return absolute_path(None, path); + }; + + let base_dir_path = base_dir.join(path).clean(); + let cwd = match current_dir() { + Ok(path) => normalize_path_prefix_like(base_dir, path.clean()), + Err(_) => return Ok(base_dir_path), + }; + + Ok(absolute_base_path_with_cwd( + base_dir, + path, + &cwd, + base_dir_path, + )) +} + +fn absolute_base_path_with_cwd( + base_dir: &Path, + path: &Path, + cwd: &Path, + base_dir_path: PathBuf, +) -> PathBuf { + let cwd_path = cwd.join(path).clean(); + + // Relative CLI filenames are rooted at the current process directory. Other + // API callers commonly pass filenames relative to `jsc.baseUrl`, so keep + // that legacy behavior unless the cwd-rooted path visibly enters baseUrl + // from outside it. If cwd is already inside baseUrl, every relative path is + // under baseUrl and the interpretation is ambiguous. + if cwd_path.starts_with(base_dir) && !cwd.starts_with(base_dir) { + cwd_path + } else { + base_dir_path + } +} + +#[cfg(windows)] +fn normalize_path_prefix_like(reference: &Path, path: PathBuf) -> PathBuf { + let reference = reference.as_os_str().to_string_lossy(); + let path_str = path.as_os_str().to_string_lossy(); + + normalize_extended_length_path_prefix(&reference, &path_str) + .map(PathBuf::from) + .unwrap_or(path) +} + +#[cfg(not(windows))] +fn normalize_path_prefix_like(_: &Path, path: PathBuf) -> PathBuf { + path +} + +#[cfg(windows)] +fn normalize_extended_length_path_prefixes<'a>( + base_dir: Option<&Path>, + base: Cow<'a, Path>, + target: PathBuf, +) -> (Cow<'a, Path>, PathBuf) { + if !base.is_absolute() || !target.is_absolute() { + return (base, target); + } + + let reference = match base_dir { + Some(base_dir) if has_extended_length_path_prefix(base_dir) => Some(base_dir.to_path_buf()), + _ if has_extended_length_path_prefix(base.as_ref()) => Some(base.to_path_buf()), + _ if has_extended_length_path_prefix(&target) => Some(target.clone()), + _ => None, + }; + + let Some(reference) = reference else { + return (base, target); + }; + + // Windows canonicalization often returns extended-length paths (`\\?\...`). + // `pathdiff` treats those as a different prefix from ordinary absolute + // paths, so align both sides before calculating a relative import. + ( + Cow::Owned(normalize_path_prefix_like(&reference, base.into_owned())), + normalize_path_prefix_like(&reference, target), + ) +} + +#[cfg(windows)] +fn has_extended_length_path_prefix(path: &Path) -> bool { + path.as_os_str().to_string_lossy().starts_with(r"\\?\") +} + +#[cfg(any(test, windows))] +fn normalize_extended_length_path_prefix(reference: &str, path: &str) -> Option { + if !reference.starts_with(r"\\?\") || path.starts_with(r"\\?\") { + return None; + } + + if !is_windows_absolute_path(path) { + return None; + } + + if let Some(path) = path.strip_prefix(r"\\") { + if path.starts_with(r".\") { + return None; + } + + return Some(format!(r"\\?\UNC\{path}")); + } + + Some(format!(r"\\?\{path}")) +} + +#[cfg(any(test, windows))] +fn is_windows_absolute_path(path: &str) -> bool { + path.starts_with(r"\\") || has_windows_drive_prefix(path) +} + +#[cfg(any(test, windows))] +fn has_windows_drive_prefix(path: &str) -> bool { + let bytes = path.as_bytes(); + + bytes.len() >= 3 + && bytes[0].is_ascii_alphabetic() + && bytes[1] == b':' + && matches!(bytes[2], b'/' | b'\\') +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn absolute_base_path_keeps_base_dir_when_cwd_is_inside_base_dir() { + let base_dir = Path::new("/repo"); + let cwd = Path::new("/repo/packages/app"); + let path = Path::new("src"); + + assert_eq!( + absolute_base_path_with_cwd(base_dir, path, cwd, base_dir.join(path).clean()), + PathBuf::from("/repo/src") + ); + } + + #[test] + fn absolute_base_path_uses_cwd_when_relative_path_enters_base_dir() { + let base_dir = Path::new("/repo/bazel-out/foo-app"); + let cwd = Path::new("/repo"); + let path = Path::new("bazel-out/foo-app/src"); + + assert_eq!( + absolute_base_path_with_cwd(base_dir, path, cwd, base_dir.join(path).clean()), + PathBuf::from("/repo/bazel-out/foo-app/src") + ); + } + + #[test] + fn extended_unc_prefix_uses_canonical_unc_form() { + assert_eq!( + normalize_extended_length_path_prefix( + r"\\?\UNC\server\share\repo", + r"\\server\share\repo\src" + ), + Some(r"\\?\UNC\server\share\repo\src".into()) + ); + } + + #[test] + fn extended_drive_prefix_preserves_drive_form() { + assert_eq!( + normalize_extended_length_path_prefix(r"\\?\C:\repo", r"C:\repo\src"), + Some(r"\\?\C:\repo\src".into()) + ); + } + + #[test] + fn extended_drive_prefix_skips_relative_path() { + assert_eq!( + normalize_extended_length_path_prefix(r"\\?\C:\repo", r"repo\src"), + None + ); + } +} diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/rewriter/import_rewriter_typescript.rs b/deps/swc/crates/swc_ecma_transforms_module/src/rewriter/import_rewriter_typescript.rs index 5ce9d0c1b..5cae7a6bb 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/rewriter/import_rewriter_typescript.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/rewriter/import_rewriter_typescript.rs @@ -7,11 +7,17 @@ use swc_ecma_transforms_base::helper; use swc_ecma_visit::{visit_mut_pass, VisitMut, VisitMutWith}; /// This is the implementation of rewriteRelativeImportExtensions in TypeScript -pub fn typescript_import_rewriter() -> impl Pass { - visit_mut_pass(Rewriter) +/// +/// `jsx_preserve` corresponds to TypeScript's `jsx: "preserve"`: when set, +/// `.tsx` specifiers are rewritten to `.jsx` instead of `.js`. +#[must_use] +pub fn typescript_import_rewriter(jsx_preserve: bool) -> impl Pass { + visit_mut_pass(Rewriter { jsx_preserve }) } -struct Rewriter; +struct Rewriter { + jsx_preserve: bool, +} impl VisitMut for Rewriter { fn visit_mut_call_expr(&mut self, e: &mut CallExpr) { @@ -32,19 +38,26 @@ impl VisitMut for Rewriter { if let Some(ExprOrSpread { spread: None, expr }) = &mut e.args.get_mut(0) { if let Expr::Lit(Lit::Str(s)) = &mut **expr { - if let Some(src) = get_output_extension_wtf8(&s.value) { + if let Some(src) = get_output_extension_wtf8(&s.value, self.jsx_preserve) { s.raw = None; s.value = src; } } else { let importee = expr.take(); + let mut args = vec![ExprOrSpread { + spread: None, + expr: importee, + }]; + if self.jsx_preserve { + args.push(ExprOrSpread { + spread: None, + expr: true.into(), + }); + } **expr = Expr::Call(CallExpr { span: DUMMY_SP, callee: helper!(ts_rewrite_relative_import_extension), - args: vec![ExprOrSpread { - spread: None, - expr: importee, - }], + args, ..Default::default() }); } @@ -52,7 +65,7 @@ impl VisitMut for Rewriter { } fn visit_mut_import_decl(&mut self, i: &mut ImportDecl) { - if let Some(src) = get_output_extension_wtf8(&i.src.value) { + if let Some(src) = get_output_extension_wtf8(&i.src.value, self.jsx_preserve) { i.src.value = src; i.src.raw = None; } @@ -60,7 +73,7 @@ impl VisitMut for Rewriter { fn visit_mut_named_export(&mut self, e: &mut NamedExport) { if let Some(src) = &mut e.src { - if let Some(new_src) = get_output_extension_wtf8(&src.value) { + if let Some(new_src) = get_output_extension_wtf8(&src.value, self.jsx_preserve) { src.value = new_src; src.raw = None; } @@ -68,14 +81,14 @@ impl VisitMut for Rewriter { } fn visit_mut_export_all(&mut self, n: &mut ExportAll) { - if let Some(new_src) = get_output_extension_wtf8(&n.src.value) { + if let Some(new_src) = get_output_extension_wtf8(&n.src.value, self.jsx_preserve) { n.src.value = new_src; n.src.raw = None; } } } -fn get_output_extension(specifier: &Atom) -> Option { +fn get_output_extension(specifier: &Atom, jsx_preserve: bool) -> Option { // https://github.com/microsoft/TypeScript/blob/3eb7b6a1794a6d2cde7948a3016c57e628b104b9/src/compiler/utilities.ts#L4331 let path = Path::new(specifier.as_str()); if !(path.starts_with("./") @@ -96,7 +109,15 @@ fn get_output_extension(specifier: &Atom) -> Option { let ext = match ext { "js" | "ts" => "js", "json" => "json", - "jsx" | "tsx" => "jsx", + // `.jsx` is not rewritten: TypeScript only rewrites specifiers with a + // TS extension (`shouldRewriteModuleSpecifier` in utilities.ts). + "tsx" => { + if jsx_preserve { + "jsx" + } else { + "js" + } + } "mjs" | "mts" => "mjs", "cjs" | "cts" => "cjs", _ => return None, @@ -105,7 +126,7 @@ fn get_output_extension(specifier: &Atom) -> Option { Some(Atom::new(path.with_extension(ext).to_str()?)) } -fn get_output_extension_wtf8(specifier: &Wtf8Atom) -> Option { +fn get_output_extension_wtf8(specifier: &Wtf8Atom, jsx_preserve: bool) -> Option { let normalized = specifier.to_atom_lossy(); - get_output_extension(normalized.as_ref()).map(Into::into) + get_output_extension(normalized.as_ref(), jsx_preserve).map(Into::into) } diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/syntax_strip.rs b/deps/swc/crates/swc_ecma_transforms_module/src/syntax_strip.rs new file mode 100644 index 000000000..fc456fca0 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/src/syntax_strip.rs @@ -0,0 +1,119 @@ +use swc_atoms::atom; +use swc_ecma_ast::*; +use swc_ecma_utils::{private_ident, ExprFactory}; + +use crate::module_record::{ + LocalExportEntries, LocalExportEntry, RequestedModules, SourceModule, SourceModuleItem, +}; + +/// Source module after module syntax is stripped from the executable body. +#[derive(Debug)] +pub(crate) struct SyntaxStrippedModule { + pub directives: Vec, + pub has_use_strict: bool, + pub requested_modules: RequestedModules, + pub local_export_entries: LocalExportEntries, + pub export_assign: Option>, + pub body: Vec, + pub has_module_syntax: bool, +} + +pub(crate) fn lower(source: SourceModule, const_var_kind: VarDeclKind) -> SyntaxStrippedModule { + let SourceModule { + directives, + has_use_strict, + requested_modules, + mut local_export_entries, + ts_export_assignment, + body, + has_module_syntax, + } = source; + let mut lowered_body = Vec::with_capacity(body.len()); + + for item in body { + match item { + SourceModuleItem::Stmt(stmt) => lowered_body.push(stmt.into()), + SourceModuleItem::ExportDecl(export) => lowered_body.push(export.decl.into()), + SourceModuleItem::ExportDefaultDecl(export) => { + lowered_body.extend(lower_export_default_decl(export, &mut local_export_entries)); + } + SourceModuleItem::ExportDefaultExpr(export) => { + lowered_body.push(lower_export_default_expr( + export, + &mut local_export_entries, + const_var_kind, + )); + } + SourceModuleItem::TsImportEquals(import) => { + lowered_body.push(ModuleDecl::TsImportEquals(import).into()); + } + } + } + + SyntaxStrippedModule { + directives, + has_use_strict, + requested_modules, + local_export_entries, + export_assign: ts_export_assignment, + body: lowered_body, + has_module_syntax, + } +} + +fn lower_export_default_decl( + export: ExportDefaultDecl, + local_export_entries: &mut LocalExportEntries, +) -> Option { + match export.decl { + DefaultDecl::Class(mut class_expr) => { + let ident = class_expr + .ident + .get_or_insert_with(|| private_ident!(export.span, "_default")) + .clone(); + + local_export_entries.insert( + atom!("default"), + LocalExportEntry::new((export.span, Default::default()), ident), + ); + + class_expr.as_class_decl().map(From::from) + } + DefaultDecl::Fn(mut fn_expr) => { + let ident = fn_expr + .ident + .get_or_insert_with(|| private_ident!(export.span, "_default")) + .clone(); + + local_export_entries.insert( + atom!("default"), + LocalExportEntry::new((export.span, Default::default()), ident), + ); + + fn_expr.as_fn_decl().map(From::from) + } + DefaultDecl::TsInterfaceDecl(_) => None, + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + } +} + +fn lower_export_default_expr( + export: ExportDefaultExpr, + local_export_entries: &mut LocalExportEntries, + const_var_kind: VarDeclKind, +) -> ModuleItem { + let ident = private_ident!(export.span, "_default"); + + local_export_entries.insert( + atom!("default"), + LocalExportEntry::new((export.span, Default::default()), ident.clone()), + ); + + let stmt: Stmt = export + .expr + .into_var_decl(const_var_kind, ident.into()) + .into(); + + stmt.into() +} diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/system_js.rs b/deps/swc/crates/swc_ecma_transforms_module/src/system_js.rs index 03b682cac..394e9b546 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/system_js.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/system_js.rs @@ -1,1181 +1,95 @@ -use anyhow::Context; -use rustc_hash::FxHashMap; -use serde::{Deserialize, Serialize}; -use swc_atoms::Atom; -use swc_common::{Mark, Span, SyntaxContext, DUMMY_SP}; +use swc_common::{util::take::Take, Mark, SyntaxContext, DUMMY_SP}; use swc_ecma_ast::*; -use swc_ecma_utils::{ - member_expr, private_ident, quote_ident, quote_str, var::VarCollector, ExprFactory, -}; -use swc_ecma_visit::{fold_pass, standard_only_fold, Fold, FoldWith, VisitWith}; +use swc_ecma_utils::{contains_top_level_await, private_ident, quote_ident, ExprFactory}; +use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut}; -pub use super::util::Config as InnerConfig; +pub use super::util::Config; use crate::{ - path::Resolver, - top_level_this::top_level_this, - util::{local_name_for_src, use_strict}, - wtf8::{normalize_wtf8_atom, wtf8_to_cow_str}, + module_record::SourceModule, path::Resolver, top_level_this::top_level_this, util::use_strict, }; -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(deny_unknown_fields, rename_all = "camelCase")] -pub struct Config { - #[serde(default)] - pub allow_top_level_this: bool, - - #[serde(flatten, default)] - pub config: InnerConfig, -} -struct SystemJs { - unresolved_mark: Mark, - resolver: Resolver, - config: Config, - - declare_var_idents: Vec, - export_map: FxHashMap>, - export_names: Vec, - export_values: Vec>, - tla: bool, - enter_async_fn: u32, - root_fn_decl_idents: Vec, - module_item_meta_list: Vec, - import_idents: Vec, - export_ident: Ident, - context_ident: Ident, -} +mod emit; +mod ir; +mod lower; +mod pattern; +mod rewrite; +mod util; +#[must_use] pub fn system_js(resolver: Resolver, unresolved_mark: Mark, config: Config) -> impl Pass { - fold_pass(SystemJs { - unresolved_mark, + visit_mut_pass(SystemJs { resolver, + unresolved_mark, config, - declare_var_idents: Vec::new(), - export_map: Default::default(), - export_names: Vec::new(), - export_values: Vec::new(), - tla: false, - enter_async_fn: 0, - root_fn_decl_idents: Vec::new(), - module_item_meta_list: Vec::new(), - import_idents: Vec::new(), - export_ident: private_ident!("_export"), - context_ident: private_ident!("_context"), }) } -struct ModuleItemMeta { - export_names: Vec, - export_values: Vec>, - has_export_all: bool, - src: Atom, - setter_fn_stmts: Vec, -} - -impl SystemJs { - fn export_call(&self, name: Atom, span: Span, expr: Expr) -> CallExpr { - CallExpr { - span, - callee: self.export_ident.clone().as_callee(), - args: vec![quote_str!(name).as_arg(), expr.as_arg()], - ..Default::default() - } - } - - fn fold_module_name_ident(&mut self, ident: Ident) -> Expr { - if &*ident.sym == "__moduleName" && ident.ctxt.outer() == self.unresolved_mark { - return self - .context_ident - .clone() - .make_member(quote_ident!("id")) - .into(); - } - ident.into() - } - - fn replace_assign_expr(&mut self, assign_expr: AssignExpr) -> Expr { - match &assign_expr.left { - AssignTarget::Simple(pat_or_expr) => match pat_or_expr { - SimpleAssignTarget::Ident(ident) => { - for (k, v) in self.export_map.iter() { - if ident.ctxt == k.1 && ident.sym == k.0 { - let mut expr = assign_expr.into(); - for value in v.iter() { - expr = self.export_call(value.clone(), DUMMY_SP, expr).into(); - } - return expr; - } - } - assign_expr.into() - } - _ => assign_expr.into(), - }, - AssignTarget::Pat(pat) => { - let mut to: Vec = Vec::new(); - pat.visit_with(&mut VarCollector { to: &mut to }); - - match pat { - AssignTargetPat::Object(..) | AssignTargetPat::Array(..) => { - let mut exprs = vec![Box::new(Expr::Assign(assign_expr))]; - - for to in to { - for (k, v) in self.export_map.iter() { - if to == *k { - for _ in v.iter() { - exprs.push( - self.export_call( - to.0.clone(), - DUMMY_SP, - Ident::new(to.0.clone(), DUMMY_SP, to.1).into(), - ) - .into(), - ); - } - break; - } - } - } - SeqExpr { - span: DUMMY_SP, - exprs, - } - .into() - } - _ => assign_expr.into(), - } - } - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - } - } - - fn replace_update_expr(&mut self, update_expr: UpdateExpr) -> Expr { - if !update_expr.prefix { - match &*update_expr.arg { - Expr::Ident(ident) => { - for (k, v) in self.export_map.iter() { - if ident.ctxt == k.1 && ident.sym == k.0 { - let mut expr = BinExpr { - span: DUMMY_SP, - op: op!(bin, "+"), - left: UnaryExpr { - span: DUMMY_SP, - op: op!(unary, "+"), - arg: Box::new(Expr::Ident(ident.clone())), - } - .into(), - right: 1.0.into(), - } - .into(); - for value in v.iter() { - expr = self.export_call(value.clone(), DUMMY_SP, expr).into(); - } - return SeqExpr { - span: DUMMY_SP, - exprs: vec![Box::new(expr), Box::new(Expr::Update(update_expr))], - } - .into(); - } - } - update_expr.into() - } - _ => update_expr.into(), - } - } else { - update_expr.into() - } - } - - fn add_export_name(&mut self, key: Id, value: Atom) { - let mut find = false; - for (k, v) in self.export_map.iter_mut() { - if key == *k { - v.push(value.clone()); - find = true; - break; - } - } - if !find { - self.export_map.insert(key, vec![value]); - } - } - - fn add_declare_var_idents(&mut self, ident: &Ident) { - self.declare_var_idents.push(ident.clone()); - } - - fn build_export_call( - &mut self, - export_names: &mut Vec, - export_values: &mut Vec>, - ) -> Vec { - match export_names.len() { - 0 => Vec::new(), - 1 => vec![self - .export_call(export_names.remove(0), DUMMY_SP, *export_values.remove(0)) - .into_stmt()], - _ => { - let mut props = Vec::new(); - for (sym, value) in export_names.drain(..).zip(export_values.drain(..)) { - props.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { - key: match Ident::verify_symbol(&sym) { - Ok(..) => PropName::Ident(quote_ident!(sym)), - Err(..) => PropName::Str(quote_str!(sym)), - }, - value, - })))); - } - vec![CallExpr { - span: DUMMY_SP, - callee: self.export_ident.clone().as_callee(), - args: vec![ObjectLit { - span: DUMMY_SP, - props, - } - .as_arg()], - ..Default::default() - } - .into_stmt()] - } - } - } - - fn build_module_item_export_all(&mut self, mut meta: ModuleItemMeta) -> Vec { - if !meta.has_export_all { - meta.setter_fn_stmts.append( - &mut self.build_export_call(&mut meta.export_names, &mut meta.export_values), - ); - } else { - let export_obj = quote_ident!("exportObj"); - let key_ident = quote_ident!("key"); - let target = quote_ident!(local_name_for_src(&meta.src)); - meta.setter_fn_stmts.push( - VarDecl { - kind: VarDeclKind::Var, - decls: vec![VarDeclarator { - span: DUMMY_SP, - name: export_obj.clone().into(), - init: Some(Box::new(Expr::Object(ObjectLit { - span: DUMMY_SP, - props: Vec::new(), - }))), - definite: false, - }], - ..Default::default() - } - .into(), - ); - meta.setter_fn_stmts.push( - ForInStmt { - span: DUMMY_SP, - left: VarDecl { - kind: VarDeclKind::Var, - decls: vec![VarDeclarator { - span: DUMMY_SP, - name: key_ident.clone().into(), - init: None, - definite: false, - }], - ..Default::default() - } - .into(), - right: target.clone().into(), - - body: Box::new(Stmt::Block(BlockStmt { - span: DUMMY_SP, - stmts: vec![Stmt::If(IfStmt { - span: DUMMY_SP, - test: Box::new(Expr::Bin(BinExpr { - span: DUMMY_SP, - op: op!("&&"), - left: Box::new( - key_ident - .clone() - .make_bin(op!("!=="), quote_str!("default")), - ), - right: Box::new( - key_ident - .clone() - .make_bin(op!("!=="), quote_str!("__esModule")), - ), - })), - cons: Box::new(Stmt::Block(BlockStmt { - stmts: vec![AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: export_obj - .clone() - .computed_member(key_ident.clone()) - .into(), - right: target.computed_member(key_ident).into(), - } - .into_stmt()], - ..Default::default() - })), - alt: None, - })], - - ..Default::default() - })), - } - .into(), - ); - for (sym, value) in meta - .export_names - .drain(..) - .zip(meta.export_values.drain(..)) - { - meta.setter_fn_stmts.push( - AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: export_obj.clone().make_member(quote_ident!(sym)).into(), - right: value, - } - .into_stmt(), - ); - } - meta.setter_fn_stmts.push( - CallExpr { - span: DUMMY_SP, - callee: self.export_ident.clone().as_callee(), - args: vec![export_obj.as_arg()], - ..Default::default() - } - .into_stmt(), - ); - } - - meta.setter_fn_stmts - } - - fn add_module_item_meta(&mut self, mut m: ModuleItemMeta) { - match self - .module_item_meta_list - .iter() - .position(|i| m.src.eq(&i.src)) - { - Some(index) => { - let mut meta = self.module_item_meta_list.remove(index); - meta.setter_fn_stmts.append(&mut m.setter_fn_stmts); - meta.export_names.append(&mut m.export_names); - meta.export_values.append(&mut m.export_values); - if m.has_export_all { - meta.has_export_all = m.has_export_all; - } - self.module_item_meta_list.insert(index, meta); - } - None => { - self.module_item_meta_list.push(m); - } - } - } - - #[allow(clippy::boxed_local)] - fn hoist_var_decl(&mut self, var_decl: Box) -> Option { - let mut exprs = Vec::new(); - for var_declarator in var_decl.decls { - let mut tos: Vec = Vec::new(); - var_declarator.visit_with(&mut VarCollector { to: &mut tos }); - - for (sym, ctxt) in tos { - if var_declarator.init.is_none() { - for (k, v) in self.export_map.iter_mut() { - if (sym.clone(), ctxt) == *k { - for value in v.iter() { - self.export_names.push(value.clone()); - self.export_values.push(Expr::undefined(DUMMY_SP)); - } - break; - } - } - } - self.declare_var_idents - .push(Ident::new(sym, DUMMY_SP, ctxt)); - } - - if let Some(init) = var_declarator.init { - exprs.push( - AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: var_declarator.name.try_into().unwrap(), - right: init, - } - .into(), - ); - } - } - match exprs.len() { - 0 => None, - _ => Some( - SeqExpr { - span: DUMMY_SP, - exprs, - } - .into(), - ), - } - } - - fn hoist_for_var_decl(&mut self, var_decl_or_pat: ForHead) -> ForHead { - if let ForHead::VarDecl(mut var_decl) = var_decl_or_pat { - if var_decl.kind == VarDeclKind::Var { - let var_declarator = var_decl.decls.remove(0); - let mut tos: Vec = Vec::new(); - var_declarator.visit_with(&mut VarCollector { to: &mut tos }); - - for to in tos { - if var_declarator.init.is_none() { - for (k, v) in self.export_map.iter_mut() { - if to == *k { - for value in v.iter() { - self.export_names.push(value.clone()); - self.export_values.push(Expr::undefined(DUMMY_SP)); - } - break; - } - } - } - self.declare_var_idents - .push(Ident::new(to.0, DUMMY_SP, to.1)); - } - - ForHead::Pat(var_declarator.name.into()) - } else { - ForHead::VarDecl(var_decl) - } - } else { - var_decl_or_pat - } - } - - fn hoist_variables(&mut self, stmt: Stmt) -> Stmt { - match stmt { - Stmt::Decl(decl) => { - if let Decl::Var(var_decl) = decl { - // if var_decl.kind == VarDeclKind::Var { - if let Some(expr) = self.hoist_var_decl(var_decl) { - expr.into_stmt() - } else { - EmptyStmt { span: DUMMY_SP }.into() - } - // } else { - // return Stmt::Decl(Decl::Var(var_decl)); - // } - } else { - decl.into() - } - } - Stmt::For(for_stmt) => { - if let Some(init) = for_stmt.init { - if let VarDeclOrExpr::VarDecl(var_decl) = init { - if var_decl.kind == VarDeclKind::Var { - ForStmt { - init: self - .hoist_var_decl(var_decl) - .map(|expr| VarDeclOrExpr::Expr(Box::new(expr))), - ..for_stmt - } - .into() - } else { - ForStmt { - init: Some(VarDeclOrExpr::VarDecl(var_decl)), - ..for_stmt - } - .into() - } - } else { - ForStmt { - init: Some(init), - ..for_stmt - } - .into() - } - } else { - for_stmt.into() - } - } - Stmt::ForIn(for_in_stmt) => ForInStmt { - left: self.hoist_for_var_decl(for_in_stmt.left), - ..for_in_stmt - } - .into(), - Stmt::ForOf(for_of_stmt) => ForOfStmt { - left: self.hoist_for_var_decl(for_of_stmt.left), - ..for_of_stmt - } - .into(), - _ => stmt, - } - } +struct SystemJs { + resolver: Resolver, + unresolved_mark: Mark, + config: Config, } -impl Fold for SystemJs { - standard_only_fold!(); - - fn fold_call_expr(&mut self, expr: CallExpr) -> CallExpr { - let expr = expr.fold_children_with(self); - - match expr.callee { - Callee::Import(_) => CallExpr { - callee: self - .context_ident - .clone() - .make_member(quote_ident!("import")) - .as_callee(), - ..expr - }, - _ => expr, - } - } - - fn fold_expr(&mut self, expr: Expr) -> Expr { - let expr = expr.fold_children_with(self); - - match expr { - Expr::Ident(ident) => self.fold_module_name_ident(ident), - Expr::Assign(assign) => { - let assign_expr = AssignExpr { - right: match *assign.right { - Expr::Ident(ident) => Box::new(self.fold_module_name_ident(ident)), - Expr::Assign(AssignExpr { - op: AssignOp::Assign, - .. - }) => { - return self.replace_assign_expr(AssignExpr { - right: assign.right, - ..assign - }); - } - _ => assign.right, - }, - ..assign - } - .fold_with(self); - self.replace_assign_expr(assign_expr) - } - Expr::Update(update) => self.replace_update_expr(update), - Expr::Call(call) => match call.callee { - Callee::Import(_) => CallExpr { - args: call.args.fold_with(self), - callee: self - .context_ident - .clone() - .make_member(quote_ident!("import")) - .as_callee(), - ..call - } - .into(), - _ => call.into(), - }, - Expr::MetaProp(meta_prop_expr) => match meta_prop_expr.kind { - MetaPropKind::ImportMeta => self - .context_ident - .clone() - .make_member(quote_ident!("meta")) - .into(), - _ => meta_prop_expr.into(), - }, - Expr::Await(await_expr) => { - if self.enter_async_fn == 0 { - self.tla = true; - } - - await_expr.into() - } - _ => expr, - } - } - - fn fold_fn_decl(&mut self, fn_decl: FnDecl) -> FnDecl { - let is_async = fn_decl.function.is_async; - if is_async { - self.enter_async_fn += 1; - } - let fold_fn_expr = fn_decl.fold_children_with(self); - if is_async { - self.enter_async_fn -= 1; - } - fold_fn_expr - } - - fn fold_prop(&mut self, prop: Prop) -> Prop { - let prop = prop.fold_children_with(self); - - match prop { - Prop::Shorthand(shorthand) => Prop::KeyValue(KeyValueProp { - key: PropName::Ident(shorthand.clone().into()), - value: Box::new(self.fold_module_name_ident(shorthand)), - }), - Prop::KeyValue(key_value_prop) => Prop::KeyValue(KeyValueProp { - key: key_value_prop.key, - value: match *key_value_prop.value { - Expr::Ident(ident) => Box::new(self.fold_module_name_ident(ident)), - _ => key_value_prop.value, - }, - }), - _ => prop, - } - } - - fn fold_module(&mut self, module: Module) -> Module { - let module = { - let mut module = module; - if !self.config.allow_top_level_this { - top_level_this(&mut module, *Expr::undefined(DUMMY_SP)); - } - module - }; - let mut before_body_stmts: Vec = Vec::new(); - let mut execute_stmts = Vec::new(); +impl VisitMut for SystemJs { + noop_visit_mut_type!(fail); - // collect top level fn decl - for item in &module.body { - if let ModuleItem::Stmt(Stmt::Decl(Decl::Fn(fn_decl))) = item { - self.root_fn_decl_idents.push(fn_decl.ident.clone()); - } + fn visit_mut_module(&mut self, n: &mut Module) { + if !self.config.allow_top_level_this { + top_level_this(&mut n.body, *Expr::undefined(DUMMY_SP)); } - for item in module.body { - match item { - ModuleItem::ModuleDecl(decl) => match decl { - ModuleDecl::Import(import) => { - let src = match &self.resolver { - Resolver::Real { resolver, base } => { - let spec = wtf8_to_cow_str(&import.src.value); - resolver - .resolve_import(base, &spec) - .with_context(|| { - format!( - "failed to resolve import `{}`", - import.src.value.to_string_lossy() - ) - }) - .unwrap() - } - Resolver::Default => normalize_wtf8_atom(&import.src.value), - }; - - let source_alias = local_name_for_src(&src); - - let mut setter_fn_stmts = Vec::new(); - - for specifier in import.specifiers { - match specifier { - ImportSpecifier::Default(specifier) => { - self.import_idents.push(specifier.local.to_id()); - self.add_declare_var_idents(&specifier.local); - setter_fn_stmts.push( - AssignExpr { - span: specifier.span, - op: op!("="), - left: specifier.local.into(), - right: quote_ident!(source_alias.clone()) - .make_member(quote_ident!("default")) - .into(), - } - .into_stmt(), - ); - } - ImportSpecifier::Named(specifier) => { - self.add_declare_var_idents(&specifier.local); - setter_fn_stmts.push( - AssignExpr { - span: specifier.span, - op: op!("="), - left: specifier.local.clone().into(), - right: MemberExpr { - span: DUMMY_SP, - obj: Box::new( - quote_ident!(source_alias.clone()).into(), - ), - prop: match specifier.imported { - Some(m) => get_module_export_member_prop(&m), - None => { - MemberProp::Ident(specifier.local.into()) - } - }, - } - .into(), - } - .into_stmt(), - ); - } - ImportSpecifier::Namespace(specifier) => { - self.import_idents.push(specifier.local.to_id()); - self.add_declare_var_idents(&specifier.local); - setter_fn_stmts.push( - AssignExpr { - span: specifier.span, - op: op!("="), - left: specifier.local.into(), - right: quote_ident!(source_alias.clone()).into(), - } - .into_stmt(), - ); - } - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - } - } - - self.add_module_item_meta(ModuleItemMeta { - export_names: Vec::new(), - export_values: Vec::new(), - has_export_all: false, - src: src.clone(), - setter_fn_stmts, - }); - } - ModuleDecl::ExportNamed(decl) => match decl.src { - Some(s) => { - let src = match &self.resolver { - Resolver::Real { resolver, base } => { - let spec = wtf8_to_cow_str(&s.value); - resolver - .resolve_import(base, &spec) - .with_context(|| { - format!( - "failed to resolve import `{}`", - s.value.to_string_lossy() - ) - }) - .unwrap() - } - Resolver::Default => normalize_wtf8_atom(&s.value), - }; - for specifier in decl.specifiers { - let source_alias = local_name_for_src(&src); - let mut export_names = Vec::new(); - let mut export_values = Vec::new(); - - match specifier { - ExportSpecifier::Named(specifier) => { - export_names.push(match &specifier.exported { - Some(m) => get_module_export_name(m).0, - None => get_module_export_name(&specifier.orig).0, - }); - export_values.push( - MemberExpr { - span: DUMMY_SP, - obj: Box::new( - quote_ident!(source_alias.clone()).into(), - ), - prop: get_module_export_member_prop( - &specifier.orig, - ), - } - .into(), - ); - } - ExportSpecifier::Default(specifier) => { - export_names.push(specifier.exported.sym.clone()); - export_values.push( - quote_ident!(source_alias.clone()) - .make_member(quote_ident!("default")) - .into(), - ); - } - ExportSpecifier::Namespace(specifier) => { - export_names - .push(get_module_export_name(&specifier.name).0); - export_values - .push(quote_ident!(source_alias.clone()).into()); - } - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - } + let mut source = SourceModule::collect(n.body.take()); + let has_use_strict = source.has_use_strict; + let mut wrapper_stmts = std::mem::take(&mut source.directives); + wrapper_stmts.reserve(8); - self.add_module_item_meta(ModuleItemMeta { - export_names, - export_values, - has_export_all: false, - src: src.clone(), - setter_fn_stmts: Vec::new(), - }); - } - } - None => { - for specifier in decl.specifiers { - if let ExportSpecifier::Named(specifier) = specifier { - let id = get_module_export_name(&specifier.orig); - - if self.root_fn_decl_idents.iter().any(|i| i.sym == id.0) { - // hoisted function export - self.export_names.push(match &specifier.exported { - Some(m) => get_module_export_name(m).0, - None => id.0.clone(), - }); - self.export_values.push(Box::new(get_module_export_expr( - &specifier.orig, - ))); - } - if self.import_idents.contains(&id) { - execute_stmts.push( - self.export_call( - id.0.clone(), - DUMMY_SP, - match &specifier.exported { - Some(m) => get_module_export_expr(m), - None => get_module_export_expr(&specifier.orig), - }, - ) - .into_stmt(), - ); - } - self.add_export_name( - id, - match specifier.exported { - Some(m) => get_module_export_name(&m).0, - None => get_module_export_name(&specifier.orig).0, - }, - ); - } - } - } - }, - ModuleDecl::ExportDecl(decl) => { - match decl.decl { - Decl::Class(class_decl) => { - let ident = class_decl.ident; - self.export_names.push(ident.sym.clone()); - self.export_values.push(Expr::undefined(DUMMY_SP)); - self.add_declare_var_idents(&ident); - self.add_export_name(ident.to_id(), ident.sym.clone()); - execute_stmts.push( - AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: ident.clone().into(), - right: ClassExpr { - ident: Some(ident.clone()), - class: class_decl.class, - } - .into(), - } - .into_stmt(), - ); - } - Decl::Fn(fn_decl) => { - self.export_names.push(fn_decl.ident.sym.clone()); - self.export_values.push(fn_decl.ident.clone().into()); - self.add_export_name( - fn_decl.ident.to_id(), - fn_decl.ident.sym.clone(), - ); - before_body_stmts.push(fn_decl.into()); - } - Decl::Var(var_decl) => { - let mut decl = VarDecl { - decls: Vec::new(), - ..*var_decl - }; - for var_declarator in var_decl.decls { - let mut tos: Vec = Vec::new(); - var_declarator.visit_with(&mut VarCollector { to: &mut tos }); - for to in tos { - let ident = Ident::new(to.0.clone(), DUMMY_SP, to.1); - self.add_export_name(to, ident.sym.clone()); - } - decl.decls.push(var_declarator); - } - execute_stmts.push(decl.into()); - } - _ => {} - }; - } - ModuleDecl::ExportDefaultDecl(decl) => { - match decl.decl { - DefaultDecl::Class(class_expr) => { - if let Some(ident) = &class_expr.ident { - self.export_names.push("default".into()); - self.export_values.push(Expr::undefined(DUMMY_SP)); - self.add_declare_var_idents(ident); - self.add_export_name(ident.to_id(), "default".into()); - execute_stmts.push( - AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: ident.clone().into(), - right: class_expr.into(), - } - .into_stmt(), - ); - } else { - self.export_names.push("default".into()); - self.export_values.push(class_expr.into()); - } - } - DefaultDecl::Fn(fn_expr) => { - if let Some(ident) = &fn_expr.ident { - self.export_names.push("default".into()); - self.export_values.push(ident.clone().into()); - self.add_export_name(ident.to_id(), "default".into()); - before_body_stmts.push( - FnDecl { - ident: ident.clone(), - declare: false, - function: fn_expr.function, - } - .into(), - ); - } else { - self.export_names.push("default".into()); - self.export_values.push(fn_expr.into()); - } - } - _ => {} - }; - } - ModuleDecl::ExportDefaultExpr(expr) => { - execute_stmts.push( - self.export_call("default".into(), expr.span, *expr.expr) - .into_stmt(), - ); - } - ModuleDecl::ExportAll(decl) => { - self.add_module_item_meta(ModuleItemMeta { - export_names: Vec::new(), - export_values: Vec::new(), - has_export_all: true, - src: normalize_wtf8_atom(&decl.src.value), - setter_fn_stmts: Vec::new(), - }); - } - _ => {} - }, - ModuleItem::Stmt(stmt) => match stmt { - Stmt::Decl(decl) => match decl { - Decl::Class(class_decl) => { - self.add_declare_var_idents(&class_decl.ident); - execute_stmts.push( - AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: class_decl.ident.clone().into(), - right: ClassExpr { - ident: Some(class_decl.ident.clone()), - class: class_decl.class, - } - .into(), - } - .into_stmt(), - ); - } - Decl::Fn(fn_decl) => { - before_body_stmts.push(fn_decl.into()); - } - _ => execute_stmts.push(decl.into()), - }, - _ => execute_stmts.push(stmt), - }, - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - } + if self.config.strict_mode && !has_use_strict { + wrapper_stmts.push(use_strict()); } - // ==================== - // fold_with function, here export_map is collected finished. - // ==================== - - before_body_stmts = before_body_stmts - .into_iter() - .map(|s| s.fold_with(self)) - .collect(); - - execute_stmts = execute_stmts - .into_iter() - .map(|s| self.hoist_variables(s).fold_with(self)) - .filter(|s| !matches!(s, Stmt::Empty(_))) - .collect(); + let export_ident = private_ident!("_export"); + let context_ident = private_ident!("_context"); + let unresolved_ctxt = SyntaxContext::empty().apply_mark(self.unresolved_mark); - // ==================== - // generate export call, here export_names is collected finished. - // ==================== - if !self.export_names.is_empty() { - let mut export_names = self.export_names.drain(..).collect(); - let mut export_values = self.export_values.drain(..).collect(); - before_body_stmts - .append(&mut self.build_export_call(&mut export_names, &mut export_values)); - } - - let mut setters = ArrayLit { - span: DUMMY_SP, - elems: Vec::new(), - }; + let mut module = lower::lower(source); - let mut dep_module_names = ArrayLit { - span: DUMMY_SP, - elems: Vec::new(), - }; + rewrite::rewrite_special_refs( + &mut module, + context_ident.clone(), + unresolved_ctxt, + &self.resolver, + self.config.ignore_dynamic, + self.config.preserve_import_meta, + ); - let module_item_meta_list: Vec = - self.module_item_meta_list.drain(..).collect(); - for meta in module_item_meta_list { - dep_module_names - .elems - .push(Some(quote_str!(meta.src.clone()).as_arg())); - setters.elems.push(Some( - Function { - params: vec![Param { - span: DUMMY_SP, - decorators: Default::default(), - pat: quote_ident!(local_name_for_src(&meta.src)).into(), - }], - span: DUMMY_SP, - body: Some(BlockStmt { - span: DUMMY_SP, - stmts: self.build_module_item_export_all(meta), - ..Default::default() - }), - is_generator: false, - is_async: false, - ..Default::default() - } - .as_arg(), - )); + let mut export_rewriter = rewrite::ExportBindingRewriter::new( + module.exports.local_exports.clone(), + export_ident.clone(), + module.export_setters.clone(), + ); + rewrite::rewrite_export_bindings(&mut module, &mut export_rewriter); + if export_rewriter.needs_old_temp() { + module.wrapper_vars.push(export_rewriter.old_temp()); } - - let execute = Box::new(Function { - params: Vec::new(), - decorators: Default::default(), - span: DUMMY_SP, - body: Some(BlockStmt { - stmts: execute_stmts, - ..Default::default() - }), - is_generator: false, - is_async: self.tla, - ..Default::default() - }); - - let return_stmt = ReturnStmt { - span: DUMMY_SP, - arg: Some( - ObjectLit { - span: DUMMY_SP, - props: vec![ - PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { - key: quote_ident!("setters").into(), - value: Box::new(Expr::Array(setters)), - }))), - PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { - key: quote_ident!("execute").into(), - value: Box::new(Expr::Fn(FnExpr { - ident: None, - function: execute, - })), - }))), - ], - } - .into(), - ), - }; - - let mut function_stmts = vec![use_strict()]; - - if !self.declare_var_idents.is_empty() { - function_stmts.push( - VarDecl { - span: DUMMY_SP, - kind: VarDeclKind::Var, - declare: false, - decls: self - .declare_var_idents - .iter() - .map(|i| VarDeclarator { - span: i.span, - name: i.clone().into(), - init: None, - definite: false, - }) - .collect(), - ..Default::default() - } - .into(), - ); + if export_rewriter.needs_export_setters() { + module.needs_export_setters = true; } - function_stmts.append(&mut before_body_stmts); - function_stmts.push(return_stmt.into()); - let function = Box::new(Function { - params: vec![ - Param { - span: DUMMY_SP, - decorators: Default::default(), - pat: self.export_ident.clone().into(), - }, - Param { - span: DUMMY_SP, - decorators: Default::default(), - pat: self.context_ident.clone().into(), - }, - ], - decorators: Default::default(), - span: DUMMY_SP, - body: Some(BlockStmt { - span: DUMMY_SP, - stmts: function_stmts, - ..Default::default() - }), - is_generator: false, - is_async: false, - ..Default::default() - }); + module.async_execute = module.execute_stmts.iter().any(contains_top_level_await); + let register_args = emit::emit( + wrapper_stmts, + module, + export_ident, + context_ident, + &self.resolver, + ); - Module { - body: vec![CallExpr { - span: DUMMY_SP, - callee: member_expr!(Default::default(), Default::default(), System.register) - .as_callee(), - args: vec![ - dep_module_names.as_arg(), - FnExpr { - ident: None, - function, - } - .as_arg(), - ], - ..Default::default() - } + n.body = vec![quote_ident!(unresolved_ctxt, "System") + .make_member(quote_ident!("register")) + .as_call(DUMMY_SP, register_args) .into_stmt() - .into()], - ..module - } + .into()]; } -} -#[inline] -fn get_module_export_name(module_export_name: &ModuleExportName) -> Id { - match &module_export_name { - ModuleExportName::Ident(ident) => ident.to_id(), - ModuleExportName::Str(s) => (s.value.to_atom_lossy().into_owned(), SyntaxContext::empty()), - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - } -} - -#[inline] -fn get_module_export_expr(module_export_name: &ModuleExportName) -> Expr { - match &module_export_name { - ModuleExportName::Ident(ident) => ident.clone().into(), - ModuleExportName::Str(s) => { - Lit::Str(quote_str!(s.value.to_atom_lossy().into_owned())).into() - } - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - } -} - -#[inline] -fn get_module_export_member_prop(module_export_name: &ModuleExportName) -> MemberProp { - match &module_export_name { - ModuleExportName::Ident(ident) => MemberProp::Ident(ident.clone().into()), - ModuleExportName::Str(s) => MemberProp::Computed(ComputedPropName { - span: s.span, - expr: Lit::Str(quote_str!(s.value.to_atom_lossy().into_owned())).into(), - }), - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - } + fn visit_mut_script(&mut self, _: &mut Script) {} } diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/system_js/emit.rs b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/emit.rs new file mode 100644 index 000000000..70bda2222 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/emit.rs @@ -0,0 +1,516 @@ +use indexmap::{IndexMap, IndexSet}; +use swc_atoms::Atom; +use swc_common::{util::take::Take, Spanned, DUMMY_SP}; +use swc_ecma_ast::*; +use swc_ecma_utils::{ + private_ident, prop_name_from_str, quote_ident, quote_str, ExprFactory, FunctionFactory, +}; + +use super::{ + ir::{DependencySlot, ExecuteStmt, ExportInit, ExportName, SetterOp, SystemModule}, + lower::{export_call, export_names_call}, + util::{export_object_init, member_expr_for, member_for_export, object_lit_prop_name}, +}; +use crate::{module_record::ImportAttributeRecord, path::Resolver, util::prop_name}; + +enum DirectReExport { + Named(Atom), + Namespace, +} + +impl DirectReExport { + fn into_value(self, namespace: Ident) -> Expr { + match self { + Self::Named(imported) => member_for_export(namespace, &imported), + Self::Namespace => namespace.into(), + } + } +} + +pub(super) fn emit( + mut stmts: Vec, + mut module: SystemModule, + export_ident: Ident, + context_ident: Ident, + resolver: &Resolver, +) -> Vec { + let deps = emit_dependency_array(&module.dependencies, resolver); + let setters = emit_setters(&module.dependencies, &module, &export_ident); + let metadata = emit_metadata_array(&module.dependencies); + let initialized_exports = module.export_inits.take(); + let export_inits = emit_export_inits(&module, initialized_exports, &export_ident); + + emit_var_decl(&mut stmts, module.wrapper_vars.take()); + emit_export_setters(&mut stmts, &module, &export_ident); + stmts.extend( + module + .wrapper_fns + .take() + .into_iter() + .map(|f| Stmt::Decl(Decl::Fn(f))), + ); + stmts.extend(module.wrapper_stmts.take()); + stmts.extend(export_inits); + + let execute: Expr = Function { + body: Some(BlockStmt { + stmts: module + .execute_stmts + .into_iter() + .map(|execute_stmt| emit_execute_stmt(execute_stmt, &export_ident)) + .collect(), + ..Default::default() + }), + is_async: module.async_execute, + ..Default::default() + } + .into_fn_expr(None) + .into(); + + let register_body = ObjectLit { + span: DUMMY_SP, + props: vec![ + Prop::KeyValue(KeyValueProp { + key: quote_ident!("setters").into(), + value: setters.into(), + }) + .into(), + Prop::KeyValue(KeyValueProp { + key: quote_ident!("execute").into(), + value: execute.into(), + }) + .into(), + ], + }; + + stmts.push( + ReturnStmt { + span: DUMMY_SP, + arg: Some(register_body.into()), + } + .into(), + ); + + let register = Function { + params: vec![export_ident.into(), context_ident.into()], + body: Some(BlockStmt { + stmts, + ..Default::default() + }), + ..Default::default() + } + .into_fn_expr(None); + + let mut args = vec![deps.as_arg(), register.as_arg()]; + if let Some(metadata) = metadata { + args.push(metadata.as_arg()); + } + + args +} + +fn emit_execute_stmt(stmt: ExecuteStmt, export_ident: &Ident) -> Stmt { + match stmt { + ExecuteStmt::Source(stmt) => stmt, + ExecuteStmt::Assign { left, right } => AssignExpr { + span: right.span(), + op: op!("="), + left, + right, + } + .into_stmt(), + ExecuteStmt::ExportAssign { + exports, + local, + right, + } => { + let assign: Expr = AssignExpr { + span: right.span(), + op: op!("="), + left: local.into(), + right, + } + .into(); + export_call(export_ident, &exports, assign).into_stmt() + } + ExecuteStmt::ExportValue { export, value } => { + export_call(export_ident, &[export], *value).into_stmt() + } + ExecuteStmt::ExportBatch { value } => export_ident + .clone() + .as_call(value.span(), vec![value.as_arg()]) + .into_stmt(), + ExecuteStmt::ExportNames { exports, value } => { + export_names_call(export_ident, &exports, value).into_stmt() + } + } +} + +fn emit_dependency_array(deps: &[DependencySlot], resolver: &Resolver) -> Expr { + ArrayLit { + elems: deps + .iter() + .map(|dep| { + let request = resolver.resolve(dep.request.clone()); + Some( + Str { + span: dep.span.0, + value: request.into(), + raw: None, + } + .as_arg(), + ) + }) + .collect(), + ..Default::default() + } + .into() +} + +fn emit_metadata_array(deps: &[DependencySlot]) -> Option { + if !deps.iter().any(|dep| !dep.attributes.is_empty()) { + return None; + } + + let array = ArrayLit { + elems: deps.iter().map(emit_metadata_element).collect(), + ..Default::default() + }; + + Some(array.into()) +} + +fn emit_metadata_element(dep: &DependencySlot) -> Option { + let metadata = ObjectLit { + props: emit_metadata_props(&dep.attributes), + ..Default::default() + }; + + Some(metadata.as_arg()) +} + +fn emit_metadata_props(attributes: &[ImportAttributeRecord]) -> Vec { + if attributes.is_empty() { + return Vec::new(); + } + + let assert_prop = Prop::KeyValue(KeyValueProp { + key: quote_ident!("assert").into(), + value: emit_import_attributes(attributes).into(), + }); + + vec![assert_prop.into()] +} + +fn emit_import_attributes(attributes: &[ImportAttributeRecord]) -> ObjectLit { + ObjectLit { + props: attributes + .iter() + .map(|attribute| { + Prop::KeyValue(KeyValueProp { + key: prop_name_from_str(DUMMY_SP, attribute.key()), + value: attribute.value().clone().into(), + }) + .into() + }) + .collect(), + ..Default::default() + } +} + +fn emit_setters(deps: &[DependencySlot], module: &SystemModule, export_ident: &Ident) -> Expr { + ArrayLit { + elems: deps + .iter() + .map(|dep| Some(emit_setter(dep, module, export_ident).as_arg())) + .collect(), + ..Default::default() + } + .into() +} + +fn emit_setter(dep: &DependencySlot, module: &SystemModule, export_ident: &Ident) -> Expr { + let needs_namespace = !dep.setter_ops.is_empty(); + let mut stmts = Vec::new(); + let mut direct_reexports = Vec::new(); + let mut has_star = false; + + for op in &dep.setter_ops { + match op { + SetterOp::Import { local, imported } => { + let value = imported.as_ref().map_or_else( + || dep.namespace.clone().into(), + |name| member_for_export(dep.namespace.clone(), name), + ); + stmts.push( + value + .make_assign_to(op!("="), local.clone().into()) + .into_stmt(), + ); + if let Some(exports) = module.exports.exports_for(&local.to_id()) { + stmts.push(export_names_call(export_ident, exports, local.clone()).into_stmt()); + } + } + SetterOp::ReExport { export, imported } => { + direct_reexports.push((export.clone(), DirectReExport::Named(imported.clone()))); + } + SetterOp::ReExportNamespace { export } => { + direct_reexports.push((export.clone(), DirectReExport::Namespace)); + } + SetterOp::StarExport => { + has_star = true; + } + } + } + + if has_star { + let export_obj = private_ident!("exportObj"); + stmts.push( + export_object_init() + .into_var_decl(VarDeclKind::Var, export_obj.clone().into()) + .into(), + ); + stmts.push(emit_star_loop(export_obj.clone(), dep.namespace.clone())); + for (export, imported) in direct_reexports { + stmts.push( + imported + .into_value(dep.namespace.clone()) + .make_assign_to( + op!("="), + member_expr_for(export_obj.clone(), &export.name, export.span).into(), + ) + .into_stmt(), + ); + } + stmts.push( + export_ident + .clone() + .as_call(DUMMY_SP, vec![export_obj.as_arg()]) + .into_stmt(), + ); + } else if !direct_reexports.is_empty() { + let exports = direct_reexports + .into_iter() + .map(|(export, imported)| (export, imported.into_value(dep.namespace.clone()))) + .collect::>(); + stmts.push(export_values_call(export_ident, exports).into_stmt()); + } + + Function { + params: if needs_namespace { + vec![dep.namespace.clone().into()] + } else { + Default::default() + }, + body: Some(BlockStmt { + stmts, + ..Default::default() + }), + ..Default::default() + } + .into_fn_expr(None) + .into() +} + +fn emit_star_loop(export_obj: Ident, namespace: Ident) -> Stmt { + let key = quote_ident!("key"); + let test = key + .clone() + .make_bin(op!("!=="), quote_str!("default")) + .make_bin( + op!("&&"), + key.clone().make_bin(op!("!=="), quote_str!("__esModule")), + ); + let assign = namespace + .clone() + .computed_member(key.clone()) + .make_assign_to(op!("="), export_obj.computed_member(key.clone()).into()) + .into_stmt(); + + ForInStmt { + span: DUMMY_SP, + left: VarDecl { + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: key.clone().into(), + init: None, + definite: false, + }], + ..Default::default() + } + .into(), + right: namespace.into(), + body: IfStmt { + span: DUMMY_SP, + test: test.into(), + cons: assign.into(), + alt: None, + } + .into(), + } + .into() +} + +fn emit_var_decl(stmts: &mut Vec, mut vars: Vec) { + vars.sort_unstable_by(|a, b| a.sym.cmp(&b.sym)); + let mut seen: IndexSet = IndexSet::default(); + let decls = vars + .into_iter() + .filter(|ident| seen.insert(ident.to_id())) + .map(|ident| VarDeclarator { + span: ident.span, + name: ident.into(), + init: None, + definite: false, + }) + .collect::>(); + + if !decls.is_empty() { + stmts.push( + VarDecl { + kind: VarDeclKind::Var, + decls, + ..Default::default() + } + .into(), + ); + } +} + +fn emit_export_setters(stmts: &mut Vec, module: &SystemModule, export_ident: &Ident) { + if !module.needs_export_setters { + return; + } + + let setters = module + .exports + .local_exports + .iter() + .filter(|(_, exports)| !exports.is_empty()) + .map(|((sym, ctxt), exports)| { + let local = Ident::new(sym.clone(), DUMMY_SP, *ctxt); + let value = private_ident!("_value"); + Prop::Setter(SetterProp { + key: prop_name(sym, Default::default()).into(), + this_param: None, + param: Pat::Ident(BindingIdent { + id: value.clone(), + type_ann: None, + }) + .into(), + body: Some(BlockStmt { + stmts: vec![ + value + .make_assign_to(op!("="), local.clone().into()) + .into_stmt(), + export_names_call(export_ident, exports, local).into_stmt(), + ], + ..Default::default() + }), + span: DUMMY_SP, + }) + .into() + }) + .collect::>(); + + if setters.is_empty() { + return; + } + + stmts.push( + ObjectLit { + props: setters, + ..Default::default() + } + .into_var_decl(VarDeclKind::Var, module.export_setters.clone().into()) + .into(), + ); +} + +fn emit_export_inits( + module: &SystemModule, + initialized_exports: Vec, + export_ident: &Ident, +) -> Vec { + let mut announced = Vec::new(); + let mut seen: IndexSet = IndexSet::default(); + for export in &module.exports.announced { + if seen.insert(export.name.clone()) { + announced.push(export.clone()); + } + } + + if announced.is_empty() { + return Default::default(); + } + + let mut initial_values = module + .wrapper_fns + .iter() + .filter_map(|fn_decl| { + module + .exports + .exports_for(&fn_decl.ident.to_id()) + .map(|exports| (fn_decl.ident.clone(), exports)) + }) + .flat_map(|(ident, exports)| { + exports + .iter() + .map(move |export| (export.name.clone(), ident.clone())) + }) + .map(|(export, ident)| (export, Expr::from(ident))) + .collect::>(); + for ExportInit { export, value } in initialized_exports { + initial_values.insert(export.name, *value); + } + + let props = announced + .into_iter() + .map(|export| { + let value = initial_values + .shift_remove(&export.name) + .unwrap_or_else(|| *Expr::undefined(DUMMY_SP)); + (export, value) + }) + .collect::>(); + + vec![export_values_call(export_ident, props).into_stmt()] +} + +fn export_values_call(export_ident: &Ident, exports: Vec<(ExportName, Expr)>) -> Expr { + if exports.len() == 1 { + let (export, value) = exports.into_iter().next().unwrap(); + return export_ident.clone().as_call( + value.span(), + vec![ + Str { + span: export.span.0, + value: export.name.into(), + raw: None, + } + .as_arg(), + value.as_arg(), + ], + ); + } + + let props = exports + .into_iter() + .map(|(export, value)| { + Prop::KeyValue(KeyValueProp { + key: object_lit_prop_name(&export.name, export.span), + value: value.into(), + }) + .into() + }) + .collect(); + + export_ident.clone().as_call( + DUMMY_SP, + vec![ObjectLit { + props, + ..Default::default() + } + .as_arg()], + ) +} diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/system_js/ir.rs b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/ir.rs new file mode 100644 index 000000000..d02c84829 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/ir.rs @@ -0,0 +1,231 @@ +use indexmap::IndexMap; +use swc_atoms::Atom; +use swc_ecma_ast::*; +use swc_ecma_utils::private_ident; +use swc_ecma_visit::{Visit, VisitMut, VisitMutWith, VisitWith}; + +use crate::{module_record::ImportAttributeRecord, SpanCtx}; + +#[derive(Clone, Debug)] +pub(super) struct ExportName { + pub name: Atom, + pub span: SpanCtx, +} + +#[derive(Clone, Debug, Default)] +pub(super) struct ExportTable { + pub announced: Vec, + pub local_exports: IndexMap>, +} + +impl ExportTable { + pub fn add_local(&mut self, local: Id, export: ExportName) { + self.announced.push(export.clone()); + self.local_exports.entry(local).or_default().push(export); + } + + pub fn add_indirect(&mut self, export: ExportName) { + self.announced.push(export); + } + + pub fn exports_for(&self, id: &Id) -> Option<&[ExportName]> { + self.local_exports.get(id).map(Vec::as_slice) + } +} + +/// Export value initialized in the `System.register` declaration callback. +#[derive(Debug)] +pub(super) struct ExportInit { + pub export: ExportName, + pub value: Box, +} + +impl ExportInit { + pub fn new(export: ExportName, value: Box) -> Self { + Self { export, value } + } +} + +#[derive(Debug)] +pub(super) enum SetterOp { + Import { + local: Ident, + imported: Option, + }, + ReExport { + export: ExportName, + imported: Atom, + }, + ReExportNamespace { + export: ExportName, + }, + StarExport, +} + +#[derive(Debug)] +pub(super) struct DependencySlot { + pub request: Atom, + pub span: SpanCtx, + pub attributes: Vec, + pub namespace: Ident, + pub setter_ops: Vec, +} + +#[derive(Debug)] +pub(super) enum ExecuteStmt { + Source(Stmt), + Assign { + left: AssignTarget, + right: Box, + }, + ExportAssign { + exports: Vec, + local: Ident, + right: Box, + }, + ExportValue { + export: ExportName, + value: Box, + }, + /// SystemJS batch export update: `_export(value)`. + ExportBatch { + value: Box, + }, + ExportNames { + exports: Vec, + value: Ident, + }, +} + +impl ExecuteStmt { + pub fn source(stmt: Stmt) -> Self { + Self::Source(stmt) + } + + pub fn assign(left: AssignTarget, right: Box) -> Self { + Self::Assign { left, right } + } + + pub fn export_assign(exports: &[ExportName], local: Ident, right: Box) -> Self { + Self::ExportAssign { + exports: exports.to_vec(), + local, + right, + } + } + + pub fn export_value(export: ExportName, value: Box) -> Self { + Self::ExportValue { export, value } + } + + pub fn export_batch(value: Box) -> Self { + Self::ExportBatch { value } + } + + pub fn export_names(exports: &[ExportName], value: Ident) -> Self { + Self::ExportNames { + exports: exports.to_vec(), + value, + } + } +} + +impl VisitMutWith for ExecuteStmt +where + V: ?Sized + VisitMut, +{ + fn visit_mut_with(&mut self, visitor: &mut V) { + self.visit_mut_children_with(visitor); + } + + fn visit_mut_children_with(&mut self, visitor: &mut V) { + // ExecuteStmt traversal intentionally exposes only user-authored + // expressions/statements. SystemJS scaffold such as export names and + // synthetic assignment targets is emitted later. + match self { + ExecuteStmt::Source(stmt) => { + stmt.visit_mut_with(visitor); + } + ExecuteStmt::Assign { left, right } => { + left.visit_mut_with(visitor); + right.visit_mut_with(visitor); + } + ExecuteStmt::ExportAssign { right, .. } => { + right.visit_mut_with(visitor); + } + ExecuteStmt::ExportValue { value, .. } => { + value.visit_mut_with(visitor); + } + ExecuteStmt::ExportBatch { value } => { + value.visit_mut_with(visitor); + } + ExecuteStmt::ExportNames { .. } => {} + } + } +} + +impl VisitWith for ExecuteStmt +where + V: ?Sized + Visit, +{ + fn visit_with(&self, visitor: &mut V) { + self.visit_children_with(visitor); + } + + fn visit_children_with(&self, visitor: &mut V) { + match self { + ExecuteStmt::Source(stmt) => { + stmt.visit_with(visitor); + } + ExecuteStmt::Assign { left, right } => { + left.visit_with(visitor); + right.visit_with(visitor); + } + ExecuteStmt::ExportAssign { right, .. } => { + right.visit_with(visitor); + } + ExecuteStmt::ExportValue { value, .. } => { + value.visit_with(visitor); + } + ExecuteStmt::ExportBatch { value } => { + value.visit_with(visitor); + } + ExecuteStmt::ExportNames { .. } => {} + } + } +} + +#[derive(Debug)] +pub(super) struct SystemModule { + pub dependencies: Vec, + pub exports: ExportTable, + pub export_inits: Vec, + pub wrapper_vars: Vec, + pub wrapper_fns: Vec, + pub wrapper_stmts: Vec, + pub execute_stmts: Vec, + pub export_setters: Ident, + pub needs_export_setters: bool, + pub async_execute: bool, +} + +impl SystemModule { + pub fn new(exports: ExportTable) -> Self { + Self { + dependencies: Default::default(), + exports, + export_inits: Default::default(), + wrapper_vars: Default::default(), + wrapper_fns: Default::default(), + wrapper_stmts: Default::default(), + execute_stmts: Default::default(), + export_setters: private_ident!("_export_setters"), + needs_export_setters: false, + async_execute: false, + } + } +} + +pub(super) fn export_name(name: Atom, span: SpanCtx) -> ExportName { + ExportName { name, span } +} diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/system_js/lower.rs b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/lower.rs new file mode 100644 index 000000000..0042125d7 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/lower.rs @@ -0,0 +1,596 @@ +use swc_atoms::{atom, Atom}; +use swc_common::{util::take::Take, Spanned, DUMMY_SP}; +use swc_ecma_ast::*; +use swc_ecma_utils::{find_pat_ids, private_ident, ExprFactory}; + +use super::{ + ir::{ + export_name as make_export_name, DependencySlot, ExecuteStmt, ExportInit, ExportName, + ExportTable, SetterOp, SystemModule, + }, + pattern::replace_exported_pat, + util::object_lit_prop_name, +}; +use crate::{ + module_record::{ + external_ts_import_equals_source, LocalExportEntries, ModuleRecordEntry, RequestedModule, + RequestedModules, SourceModule, SourceModuleItem, + }, + util::local_name_for_src, +}; + +pub(super) fn lower(source: SourceModule) -> SystemModule { + let SourceModule { + directives: _directives, + has_use_strict: _has_use_strict, + requested_modules, + local_export_entries, + ts_export_assignment, + body, + has_module_syntax: _has_module_syntax, + } = source; + let default_value_exports = collect_default_value_exports(&body); + let mut exports = collect_local_exports(local_export_entries); + exports.announced.extend(default_value_exports); + exports + .announced + .sort_unstable_by(|a, b| a.name.cmp(&b.name)); + let mut module = SystemModule::new(exports.clone()); + + lower_dependencies(&mut module, &mut exports, requested_modules); + module.exports = exports; + + for item in body { + lower_source_item(&mut module, item); + } + if let Some(export_assignment) = ts_export_assignment { + module + .execute_stmts + .push(ExecuteStmt::export_batch(export_assignment)); + } + + module +} + +fn collect_default_value_exports(body: &[SourceModuleItem]) -> Vec { + let mut exports = Vec::new(); + for item in body { + match item { + SourceModuleItem::ExportDefaultExpr(export) => { + exports.push(default_export_name(export.span)); + } + SourceModuleItem::ExportDefaultDecl(export) => match &export.decl { + DefaultDecl::Class(class_expr) if class_expr.ident.is_none() => { + exports.push(default_export_name(export.span)); + } + DefaultDecl::Fn(fn_expr) if fn_expr.ident.is_none() => { + exports.push(default_export_name(export.span)); + } + _ => {} + }, + _ => {} + } + } + + exports +} + +fn collect_local_exports(local_export_entries: LocalExportEntries) -> ExportTable { + let mut entries: Vec<_> = local_export_entries.into_iter().collect(); + entries.sort_unstable_by(|a, b| a.0.cmp(&b.0)); + + let mut exports = ExportTable::default(); + for (name, entry) in entries { + let span = entry.export_name_span(); + let local = entry.into_local_ident(); + exports.add_local(local.to_id(), make_export_name(name, span)); + } + + exports +} + +fn lower_dependencies( + module: &mut SystemModule, + exports: &mut ExportTable, + requested_modules: RequestedModules, +) { + for (module_request, RequestedModule { span, entries, .. }) in requested_modules { + let request = module_request.src().clone(); + let attributes = module_request.attributes().to_vec(); + let namespace = namespace_ident_for(&request); + let mut setter_ops = Vec::with_capacity(entries.len()); + let mut entries: Vec<_> = entries.into_iter().collect(); + entries.sort_unstable_by(compare_module_entries); + + for entry in entries { + match entry { + ModuleRecordEntry::Empty => {} + ModuleRecordEntry::ImportDefault { local_name } => { + let local = ident_from_id(local_name, span.0); + module.wrapper_vars.push(local.clone()); + setter_ops.push(SetterOp::Import { + local, + imported: Some(atom!("default")), + }); + } + ModuleRecordEntry::ImportNamed { + import_name, + local_name, + } => { + let local = ident_from_id(local_name.clone(), span.0); + module.wrapper_vars.push(local.clone()); + setter_ops.push(SetterOp::Import { + local, + imported: Some(import_name.unwrap_or(local_name.0)), + }); + } + ModuleRecordEntry::ImportNamespace { local_name } => { + let local = ident_from_id(local_name, span.0); + module.wrapper_vars.push(local.clone()); + setter_ops.push(SetterOp::Import { + local, + imported: None, + }); + } + ModuleRecordEntry::IndirectExportNamed { + import_name, + export_name, + } => { + let (export_name, export_span) = + export_name.unwrap_or_else(|| import_name.clone()); + let export = make_export_name(export_name, export_span); + exports.add_indirect(export.clone()); + setter_ops.push(SetterOp::ReExport { + export, + imported: import_name.0, + }); + } + ModuleRecordEntry::IndirectExportDefault { + export_name, + export_name_span, + } => { + let export = make_export_name(export_name, export_name_span); + exports.add_indirect(export.clone()); + setter_ops.push(SetterOp::ReExport { + export, + imported: atom!("default"), + }); + } + ModuleRecordEntry::IndirectExportNamespace { + export_name, + export_name_span, + } => { + let export = make_export_name(export_name, export_name_span); + exports.add_indirect(export.clone()); + setter_ops.push(SetterOp::ReExportNamespace { export }); + } + ModuleRecordEntry::StarExport => { + setter_ops.push(SetterOp::StarExport); + } + } + } + + module.dependencies.push(DependencySlot { + request, + span, + attributes, + namespace, + setter_ops, + }); + } +} + +fn lower_source_item(module: &mut SystemModule, item: SourceModuleItem) { + match item { + SourceModuleItem::Stmt(stmt) => lower_stmt(module, stmt), + SourceModuleItem::ExportDecl(export) => lower_decl(module, export.decl), + SourceModuleItem::ExportDefaultDecl(export) => lower_default_decl(module, export), + SourceModuleItem::ExportDefaultExpr(export) => { + module.execute_stmts.push(ExecuteStmt::export_value( + default_export_name(export.span), + export.expr, + )); + } + SourceModuleItem::TsImportEquals(import) => lower_ts_import_equals(module, *import), + } +} + +fn default_export_name(span: swc_common::Span) -> ExportName { + make_export_name(atom!("default"), (span, Default::default())) +} + +fn lower_ts_import_equals(module: &mut SystemModule, import: TsImportEqualsDecl) { + let Some(src) = external_ts_import_equals_source(&import) else { + return; + }; + + let request = src.value.to_atom_lossy().into_owned(); + let span = (src.span, Default::default()); + let namespace = namespace_ident_for(&request); + let local = import.id; + + module.wrapper_vars.push(local.clone()); + module.dependencies.push(DependencySlot { + request, + span, + attributes: Vec::new(), + namespace, + setter_ops: vec![SetterOp::Import { + local, + imported: None, + }], + }); +} + +fn lower_stmt(module: &mut SystemModule, stmt: Stmt) { + if let Stmt::Decl(decl) = stmt { + lower_decl(module, decl); + } else { + let mut stmt = stmt; + lower_var_scoped_decls(module, &mut stmt); + module.execute_stmts.push(ExecuteStmt::source(stmt)); + } +} + +fn lower_decl(module: &mut SystemModule, decl: Decl) { + match decl { + Decl::Fn(fn_decl) => { + module.wrapper_fns.push(fn_decl); + } + Decl::Class(class_decl) => { + let ClassDecl { + ident, + declare: _, + class, + } = class_decl; + + module.wrapper_vars.push(ident.clone()); + module.execute_stmts.push(assign_or_export( + module, + ident.clone(), + ClassExpr { + ident: Some(ident), + class, + } + .into(), + )); + } + Decl::Var(var_decl) => { + lower_var_decl(module, *var_decl); + } + _ => module + .execute_stmts + .push(ExecuteStmt::source(Stmt::Decl(decl))), + } +} + +fn lower_default_decl(module: &mut SystemModule, export: ExportDefaultDecl) { + let export_span = export.span; + + match export.decl { + DefaultDecl::Class(class_expr) => { + let Some(ident) = class_expr.ident else { + module.execute_stmts.push(ExecuteStmt::export_value( + default_export_name(export_span), + ClassExpr { + ident: None, + class: class_expr.class, + } + .into(), + )); + return; + }; + + module.wrapper_vars.push(ident.clone()); + module.execute_stmts.push(assign_or_export( + module, + ident.clone(), + ClassExpr { + ident: Some(ident), + class: class_expr.class, + } + .into(), + )); + } + DefaultDecl::Fn(fn_expr) => { + let Some(ident) = fn_expr.ident.clone() else { + module.export_inits.push(ExportInit::new( + default_export_name(export_span), + fn_expr.into(), + )); + return; + }; + + module.wrapper_fns.push(FnDecl { + ident, + declare: false, + function: fn_expr.function, + }); + } + DefaultDecl::TsInterfaceDecl(_) => {} + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + } +} + +fn lower_var_decl(module: &mut SystemModule, var_decl: VarDecl) { + for declarator in var_decl.decls { + if let Pat::Ident(binding) = declarator.name { + let ident = binding.id; + let Some(init) = declarator.init else { + module.wrapper_vars.push(ident); + continue; + }; + + module.wrapper_vars.push(ident.clone()); + module + .execute_stmts + .push(assign_or_export(module, ident, init)); + continue; + } + + let ids = find_pat_ids::<_, Ident>(&declarator.name); + module.wrapper_vars.extend(ids.iter().cloned()); + + let Some(init) = declarator.init else { + continue; + }; + + let mut pattern = declarator.name; + let uses_export_setters = replace_exported_pat( + &mut pattern, + &module.exports.local_exports, + &module.export_setters, + ); + if uses_export_setters { + module.needs_export_setters = true; + } + + if let Ok(left) = AssignTarget::try_from(pattern) { + module.execute_stmts.push(ExecuteStmt::assign(left, init)); + if !uses_export_setters { + for ident in ids { + if let Some(exports) = module.exports.exports_for(&ident.to_id()) { + module + .execute_stmts + .push(ExecuteStmt::export_names(exports, ident)); + } + } + } + } + } +} + +fn assign_or_export(module: &SystemModule, ident: Ident, value: Box) -> ExecuteStmt { + if let Some(exports) = module.exports.exports_for(&ident.to_id()) { + ExecuteStmt::export_assign(exports, ident, value) + } else { + ExecuteStmt::assign(ident.into(), value) + } +} + +fn lower_var_scoped_decls(module: &mut SystemModule, stmt: &mut Stmt) { + // Function declarations are emitted in wrapper scope, so `var` bindings + // from the module's execution scope must live there too. Lexical + // declarations inside nested blocks keep their original scope. + match stmt { + Stmt::Block(block) => lower_var_scoped_decls_in_stmts(module, &mut block.stmts), + Stmt::With(with) => lower_var_scoped_decls(module, &mut with.body), + Stmt::Labeled(labeled) => lower_var_scoped_decls(module, &mut labeled.body), + Stmt::If(if_stmt) => { + lower_var_scoped_decls(module, &mut if_stmt.cons); + if let Some(alt) = &mut if_stmt.alt { + lower_var_scoped_decls(module, alt); + } + } + Stmt::Switch(switch) => { + for case in &mut switch.cases { + lower_var_scoped_decls_in_stmts(module, &mut case.cons); + } + } + Stmt::Try(try_stmt) => { + lower_var_scoped_decls_in_stmts(module, &mut try_stmt.block.stmts); + if let Some(handler) = &mut try_stmt.handler { + lower_var_scoped_decls_in_stmts(module, &mut handler.body.stmts); + } + if let Some(finalizer) = &mut try_stmt.finalizer { + lower_var_scoped_decls_in_stmts(module, &mut finalizer.stmts); + } + } + Stmt::While(while_stmt) => lower_var_scoped_decls(module, &mut while_stmt.body), + Stmt::DoWhile(do_while) => lower_var_scoped_decls(module, &mut do_while.body), + Stmt::For(for_stmt) => { + lower_for_init(module, &mut for_stmt.init); + lower_var_scoped_decls(module, &mut for_stmt.body); + } + Stmt::ForIn(for_in) => { + lower_for_head(module, &mut for_in.left); + lower_var_scoped_decls(module, &mut for_in.body); + } + Stmt::ForOf(for_of) => { + lower_for_head(module, &mut for_of.left); + lower_var_scoped_decls(module, &mut for_of.body); + } + Stmt::Decl(Decl::Var(var_decl)) if var_decl.kind == VarDeclKind::Var => { + *stmt = lower_var_decl_stmt(module, *var_decl.take()); + } + _ => {} + } +} + +fn lower_var_scoped_decls_in_stmts(module: &mut SystemModule, stmts: &mut [Stmt]) { + for stmt in stmts { + lower_var_scoped_decls(module, stmt); + } +} + +fn lower_for_init(module: &mut SystemModule, init: &mut Option) { + let Some(VarDeclOrExpr::VarDecl(var_decl)) = init else { + return; + }; + if var_decl.kind != VarDeclKind::Var { + return; + } + + *init = var_decl_to_assignments(module, *var_decl.take()).map(VarDeclOrExpr::Expr); +} + +fn lower_for_head(module: &mut SystemModule, head: &mut ForHead) { + let ForHead::VarDecl(var_decl) = head else { + return; + }; + if var_decl.kind != VarDeclKind::Var { + return; + } + + for declarator in &var_decl.decls { + module + .wrapper_vars + .extend(find_pat_ids::<_, Ident>(&declarator.name)); + } + + if var_decl.decls.len() == 1 { + let mut var_decl = var_decl.take(); + let declarator = var_decl.decls.pop().unwrap(); + *head = declarator.name.into(); + } +} + +fn lower_var_decl_stmt(module: &mut SystemModule, var_decl: VarDecl) -> Stmt { + var_decl_to_assignments(module, var_decl).map_or_else( + || EmptyStmt { span: DUMMY_SP }.into(), + ExprFactory::into_stmt, + ) +} + +fn var_decl_to_assignments(module: &mut SystemModule, var_decl: VarDecl) -> Option> { + let mut exprs = Vec::new(); + for declarator in var_decl.decls { + module + .wrapper_vars + .extend(find_pat_ids::<_, Ident>(&declarator.name)); + + let Some(init) = declarator.init else { + continue; + }; + let Ok(left) = AssignTarget::try_from(declarator.name) else { + continue; + }; + + exprs.push( + AssignExpr { + span: declarator.span, + op: op!("="), + left, + right: init, + } + .into(), + ); + } + + match exprs.len() { + 0 => None, + 1 => exprs.pop(), + _ => Some( + SeqExpr { + span: var_decl.span, + exprs, + } + .into(), + ), + } +} + +pub(super) fn export_call(export_ident: &Ident, exports: &[ExportName], value: Expr) -> Expr { + exports.iter().fold(value, |value, export| { + export_ident.clone().as_call( + value.span(), + vec![ + Str { + span: export.span.0, + value: export.name.clone().into(), + raw: None, + } + .as_arg(), + value.as_arg(), + ], + ) + }) +} + +pub(super) fn export_names_call( + export_ident: &Ident, + exports: &[ExportName], + value_ident: Ident, +) -> Expr { + if exports.len() == 1 { + export_call(export_ident, exports, value_ident.into()) + } else { + let props = exports + .iter() + .map(|export| { + Prop::KeyValue(KeyValueProp { + key: object_lit_prop_name(&export.name, export.span), + value: value_ident.clone().into(), + }) + .into() + }) + .collect(); + + export_ident.clone().as_call( + DUMMY_SP, + vec![ObjectLit { + span: DUMMY_SP, + props, + } + .as_arg()], + ) + } +} + +fn namespace_ident_for(src: &Atom) -> Ident { + let base = local_name_for_src(src); + private_ident!(format!("{base}_ns")) +} + +fn ident_from_id((sym, ctxt): Id, span: swc_common::Span) -> Ident { + Ident::new(sym, span, ctxt) +} + +fn compare_module_entries(a: &ModuleRecordEntry, b: &ModuleRecordEntry) -> std::cmp::Ordering { + module_entry_rank(a) + .cmp(&module_entry_rank(b)) + .then_with(|| module_entry_sort_name(a).cmp(&module_entry_sort_name(b))) +} + +fn module_entry_rank(entry: &ModuleRecordEntry) -> u8 { + match entry { + ModuleRecordEntry::Empty => 0, + ModuleRecordEntry::ImportDefault { .. } => 1, + ModuleRecordEntry::ImportNamespace { .. } => 2, + ModuleRecordEntry::ImportNamed { .. } => 3, + ModuleRecordEntry::IndirectExportDefault { .. } => 4, + ModuleRecordEntry::IndirectExportNamed { .. } => 5, + ModuleRecordEntry::IndirectExportNamespace { .. } => 6, + ModuleRecordEntry::StarExport => 7, + } +} + +fn module_entry_sort_name(entry: &ModuleRecordEntry) -> Option<&Atom> { + match entry { + ModuleRecordEntry::ImportDefault { local_name } + | ModuleRecordEntry::ImportNamespace { local_name } + | ModuleRecordEntry::ImportNamed { local_name, .. } => Some(&local_name.0), + ModuleRecordEntry::IndirectExportDefault { export_name, .. } + | ModuleRecordEntry::IndirectExportNamespace { export_name, .. } => Some(export_name), + ModuleRecordEntry::IndirectExportNamed { + export_name, + import_name, + } => Some( + export_name + .as_ref() + .map_or(&import_name.0, |export_name| &export_name.0), + ), + ModuleRecordEntry::Empty | ModuleRecordEntry::StarExport => None, + } +} diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/system_js/pattern.rs b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/pattern.rs new file mode 100644 index 000000000..da104d0b0 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/pattern.rs @@ -0,0 +1,74 @@ +use indexmap::IndexMap; +use swc_ecma_ast::*; + +use super::{ir::ExportName, util::export_setter_member}; + +/// Rewrites assignment patterns so writes to exported locals flow through +/// setter properties. The setter body updates the local binding and calls +/// `_export`, which keeps destructuring evaluation order compatible with live +/// bindings. +pub(super) fn replace_exported_pat( + pat: &mut Pat, + exports: &IndexMap>, + export_setters: &Ident, +) -> bool { + match pat { + Pat::Ident(binding) => { + if exports.contains_key(&binding.id.to_id()) { + *pat = export_setter_member(export_setters, &binding.id); + true + } else { + false + } + } + Pat::Array(array) => { + let mut changed = false; + for pat in array.elems.iter_mut().flatten() { + changed |= replace_exported_pat(pat, exports, export_setters); + } + changed + } + Pat::Rest(rest) => replace_exported_pat(&mut rest.arg, exports, export_setters), + Pat::Object(object) => { + let mut changed = false; + for prop in &mut object.props { + changed |= match prop { + ObjectPatProp::KeyValue(key_value) => { + replace_exported_pat(&mut key_value.value, exports, export_setters) + } + ObjectPatProp::Assign(assign) => { + if exports.contains_key(&assign.key.id.to_id()) { + let member = export_setter_member(export_setters, &assign.key.id); + let value = if let Some(default) = assign.value.take() { + Pat::Assign(AssignPat { + span: assign.span, + left: member.into(), + right: default, + }) + } else { + member + }; + *prop = ObjectPatProp::KeyValue(KeyValuePatProp { + key: PropName::Ident(assign.key.id.clone().into()), + value: value.into(), + }); + true + } else { + false + } + } + ObjectPatProp::Rest(rest) => { + replace_exported_pat(&mut rest.arg, exports, export_setters) + } + #[cfg(swc_ast_unknown)] + _ => false, + }; + } + changed + } + Pat::Assign(assign) => replace_exported_pat(&mut assign.left, exports, export_setters), + Pat::Invalid(_) | Pat::Expr(_) => false, + #[cfg(swc_ast_unknown)] + _ => false, + } +} diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/system_js/rewrite.rs b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/rewrite.rs new file mode 100644 index 000000000..95e215ded --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/rewrite.rs @@ -0,0 +1,308 @@ +use indexmap::IndexMap; +use swc_common::{util::take::Take, Spanned, SyntaxContext}; +use swc_ecma_ast::*; +use swc_ecma_utils::{private_ident, quote_ident, ExprFactory}; +use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith}; + +use super::{ + ir::{ExportName, SystemModule}, + lower::export_names_call, + pattern::replace_exported_pat, + util::{context_member, context_meta}, +}; +use crate::path::Resolver; + +pub(super) fn rewrite_special_refs( + module: &mut SystemModule, + context_ident: Ident, + unresolved_ctxt: SyntaxContext, + resolver: &Resolver, + ignore_dynamic: bool, + preserve_import_meta: bool, +) { + let mut rewriter = SpecialRefRewriter { + context_ident, + unresolved_ctxt, + resolver, + ignore_dynamic, + preserve_import_meta, + }; + for wrapper_fn in &mut module.wrapper_fns { + wrapper_fn.visit_mut_with(&mut rewriter); + } + for export_init in &mut module.export_inits { + export_init.value.visit_mut_with(&mut rewriter); + } + for stmt in &mut module.execute_stmts { + stmt.visit_mut_with(&mut rewriter); + } +} + +pub(super) fn rewrite_export_bindings( + module: &mut SystemModule, + rewriter: &mut ExportBindingRewriter, +) { + for wrapper_fn in &mut module.wrapper_fns { + wrapper_fn.visit_mut_with(rewriter); + } + for export_init in &mut module.export_inits { + export_init.value.visit_mut_with(rewriter); + } + for stmt in &mut module.execute_stmts { + stmt.visit_mut_with(rewriter); + } +} + +struct SpecialRefRewriter<'a> { + context_ident: Ident, + unresolved_ctxt: SyntaxContext, + resolver: &'a Resolver, + ignore_dynamic: bool, + preserve_import_meta: bool, +} + +impl VisitMut for SpecialRefRewriter<'_> { + noop_visit_mut_type!(fail); + + fn visit_mut_expr(&mut self, n: &mut Expr) { + match n { + Expr::Ident(ident) if self.is_unresolved_module_name(ident) => { + *n = self.module_name_expr(ident); + } + Expr::MetaProp(MetaPropExpr { + kind: MetaPropKind::ImportMeta, + .. + }) if !self.preserve_import_meta => { + *n = context_meta(&self.context_ident).into(); + } + Expr::Call(CallExpr { + callee: + Callee::Import(Import { + phase: ImportPhase::Evaluation, + .. + }), + args, + .. + }) if !self.ignore_dynamic => { + args.visit_mut_with(self); + if let Some(ExprOrSpread { spread: None, expr }) = args.get_mut(0) { + if let Expr::Lit(Lit::Str(Str { value, raw, .. })) = &mut **expr { + let original = value.to_atom_lossy().into_owned(); + let resolved = self.resolver.resolve(original.clone()); + if resolved != original { + *value = resolved.into(); + *raw = None; + } + } + } + + let args = std::mem::take(args); + *n = context_member(&self.context_ident, quote_ident!("import")) + .as_call(n.span(), args); + } + _ => n.visit_mut_children_with(self), + } + } + + fn visit_mut_prop(&mut self, n: &mut Prop) { + match n { + Prop::Shorthand(ident) if self.is_unresolved_module_name(ident) => { + let key = PropName::Ident(IdentName::new(ident.sym.clone(), ident.span)); + let value = self.module_name_expr(ident); + *n = KeyValueProp { + key, + value: value.into(), + } + .into(); + } + _ => n.visit_mut_children_with(self), + } + } +} + +impl SpecialRefRewriter<'_> { + fn is_unresolved_module_name(&self, ident: &Ident) -> bool { + ident.sym == *"__moduleName" && ident.ctxt == self.unresolved_ctxt + } + + fn module_name_expr(&self, ident: &Ident) -> Expr { + CondExpr { + span: ident.span, + test: context_meta(&self.context_ident).into(), + cons: context_meta(&self.context_ident) + .make_member(quote_ident!("url")) + .into(), + alt: context_member(&self.context_ident, quote_ident!("id")).into(), + } + .into() + } +} + +pub(super) struct ExportBindingRewriter { + exports: IndexMap>, + export_ident: Ident, + export_setters: Ident, + old_temp: Ident, + needs_old_temp: bool, + needs_export_setters: bool, +} + +impl ExportBindingRewriter { + pub fn new( + exports: IndexMap>, + export_ident: Ident, + export_setters: Ident, + ) -> Self { + Self { + exports, + export_ident, + export_setters, + old_temp: private_ident!("_old"), + needs_old_temp: false, + needs_export_setters: false, + } + } + + pub fn needs_old_temp(&self) -> bool { + self.needs_old_temp + } + + pub fn old_temp(&self) -> Ident { + self.old_temp.clone() + } + + pub fn needs_export_setters(&self) -> bool { + self.needs_export_setters + } +} + +impl VisitMut for ExportBindingRewriter { + noop_visit_mut_type!(fail); + + fn visit_mut_expr(&mut self, n: &mut Expr) { + match n { + Expr::Call(CallExpr { + callee: Callee::Expr(callee), + .. + }) if callee + .as_ident() + .is_some_and(|ident| ident.to_id() == self.export_ident.to_id()) => {} + Expr::Assign(assign) => { + assign.right.visit_mut_with(self); + + match &mut assign.left { + AssignTarget::Simple(SimpleAssignTarget::Ident(binding)) => { + if let Some(exports) = self.exports.get(&binding.id.to_id()) { + let ident = binding.id.clone(); + let assign_expr: Expr = AssignExpr { + span: assign.span, + op: assign.op, + left: ident.clone().into(), + right: assign.right.take(), + } + .into(); + let export = + export_names_call(&self.export_ident, exports, ident.clone()); + *n = SeqExpr { + span: assign.span, + exprs: vec![assign_expr.into(), export.into(), ident.into()], + } + .into(); + } + } + AssignTarget::Pat(pat) => { + let mut new_pat: Pat = pat.take().into(); + if replace_exported_pat(&mut new_pat, &self.exports, &self.export_setters) { + self.needs_export_setters = true; + if let Ok(new_left) = AssignTarget::try_from(new_pat) { + assign.left = new_left; + assign.left.visit_mut_with(self); + } + } else { + assign.left.visit_mut_with(self); + } + } + _ => assign.left.visit_mut_with(self), + } + } + Expr::Update(update) => { + let Expr::Ident(ident) = &*update.arg else { + update.arg.visit_mut_with(self); + return; + }; + let Some(exports) = self.exports.get(&ident.to_id()) else { + return; + }; + + let ident = ident.clone(); + let update_expr: Expr = UpdateExpr { + span: update.span, + op: update.op, + prefix: update.prefix, + arg: ident.clone().into(), + } + .into(); + let export = export_names_call(&self.export_ident, exports, ident.clone()); + + let exprs = if update.prefix { + vec![update_expr.into(), export.into(), ident.into()] + } else { + self.needs_old_temp = true; + vec![ + update_expr + .make_assign_to(op!("="), self.old_temp.clone().into()) + .into(), + export.into(), + self.old_temp.clone().into(), + ] + }; + + *n = SeqExpr { + span: update.span, + exprs, + } + .into(); + } + _ => n.visit_mut_children_with(self), + } + } + + fn visit_mut_for_in_stmt(&mut self, n: &mut ForInStmt) { + n.right.visit_mut_with(self); + self.rewrite_for_head(&mut n.left); + n.body.visit_mut_with(self); + } + + fn visit_mut_for_of_stmt(&mut self, n: &mut ForOfStmt) { + n.right.visit_mut_with(self); + self.rewrite_for_head(&mut n.left); + n.body.visit_mut_with(self); + } +} + +impl ExportBindingRewriter { + fn rewrite_for_head(&mut self, head: &mut ForHead) { + match head { + ForHead::Pat(pat) => { + if replace_exported_pat(pat, &self.exports, &self.export_setters) { + self.needs_export_setters = true; + } + pat.visit_mut_with(self); + } + ForHead::VarDecl(var_decl) => { + for decl in &mut var_decl.decls { + if replace_exported_pat(&mut decl.name, &self.exports, &self.export_setters) { + self.needs_export_setters = true; + } + decl.name.visit_mut_with(self); + if let Some(init) = &mut decl.init { + init.visit_mut_with(self); + } + } + } + ForHead::UsingDecl(_) => {} + #[cfg(swc_ast_unknown)] + _ => {} + } + } +} diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/system_js/util.rs b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/util.rs new file mode 100644 index 000000000..9a08d852c --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/src/system_js/util.rs @@ -0,0 +1,51 @@ +use swc_atoms::Atom; +use swc_common::DUMMY_SP; +use swc_ecma_ast::*; +use swc_ecma_utils::{prop_name_from_str, quote_ident, ExprFactory}; + +use crate::{util::prop_name, SpanCtx}; + +pub(super) fn context_meta(context_ident: &Ident) -> MemberExpr { + context_member(context_ident, quote_ident!("meta")) +} + +pub(super) fn context_member(context_ident: &Ident, prop: IdentName) -> MemberExpr { + context_ident.clone().make_member(prop) +} + +pub(super) fn export_object_init() -> Expr { + ObjectLit { + span: DUMMY_SP, + props: vec![Prop::KeyValue(KeyValueProp { + key: quote_ident!("__proto__").into(), + value: Lit::Null(Null { span: DUMMY_SP }).into(), + }) + .into()], + } + .into() +} + +pub(super) fn export_setter_member(export_setters: &Ident, ident: &Ident) -> Pat { + Pat::Expr( + export_setters + .clone() + .make_member(quote_ident!(ident.sym.clone())) + .into(), + ) +} + +pub(super) fn member_for_export(namespace: Ident, imported: &Atom) -> Expr { + member_expr_for(namespace, imported, Default::default()).into() +} + +pub(super) fn member_expr_for(obj: Ident, prop: &Atom, span: SpanCtx) -> MemberExpr { + MemberExpr { + span: span.0, + obj: obj.into(), + prop: prop_name(prop, span).into(), + } +} + +pub(super) fn object_lit_prop_name(prop: &Atom, (span, _): SpanCtx) -> PropName { + prop_name_from_str(span, prop) +} diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/umd.rs b/deps/swc/crates/swc_ecma_transforms_module/src/umd.rs index d1d910c62..ee96ad1f4 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/umd.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/umd.rs @@ -1,31 +1,32 @@ -use anyhow::Context; +use rustc_hash::FxHashSet; use swc_atoms::Atom; -use swc_common::{ - source_map::PURE_SP, sync::Lrc, util::take::Take, Mark, SourceMap, Span, SyntaxContext, - DUMMY_SP, -}; +use swc_common::{source_map::PURE_SP, sync::Lrc, util::take::Take, Mark, SourceMap, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_transforms_base::helper_expr; -use swc_ecma_utils::{ - is_valid_prop_ident, private_ident, quote_ident, quote_str, ExprFactory, IsDirective, -}; -use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith}; +use swc_ecma_utils::{private_ident, ExprFactory}; +use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut}; use self::config::BuiltConfig; pub use self::config::Config; use crate::{ - module_decl_strip::{Export, Link, LinkFlag, LinkItem, LinkSpecifierReducer, ModuleDeclStrip}, + module_record::{ + exported_external_ts_import_equals_name, external_ts_import_equals_source, + LocalExportEntries, ModuleRecordEntryReducer, ModuleRequestUsage, RequestedModule, + RequestedModules, SourceModule, + }, module_ref_rewriter::{rewrite_import_bindings, ImportMap}, path::Resolver, + syntax_strip::{self, SyntaxStrippedModule}, top_level_this::top_level_this, util::{ - define_es_module, emit_export_stmts, local_name_for_src, sort_export_obj_prop_list, - use_strict, ImportInterop, VecStmtLike, + define_es_module, emit_export_stmts, local_name_for_src, sort_export_bindings, use_strict, + ImportInterop, }, SpanCtx, }; mod config; +mod emit; #[derive(Default)] pub struct FeatureFlag { @@ -76,53 +77,58 @@ impl VisitMut for Umd { fn visit_mut_module(&mut self, module: &mut Module) { let module_items = &mut module.body; - let mut stmts: Vec = Vec::with_capacity(module_items.len() + 4); + if !self.config.config.allow_top_level_this { + top_level_this(module_items, *Expr::undefined(DUMMY_SP)); + } - // Collect directives - stmts.extend( - module_items - .iter_mut() - .take_while(|i| i.directive_continue()) - .map(|i| i.take()) - .map(ModuleItem::expect_stmt), + let SyntaxStrippedModule { + directives, + has_use_strict, + requested_modules, + local_export_entries, + export_assign, + body, + has_module_syntax, + } = syntax_strip::lower( + SourceModule::collect(module_items.take()), + self.const_var_kind, ); + let mut stmts: Vec = Vec::with_capacity(body.len() + 4); + stmts.extend(directives); + // "use strict"; - if self.config.config.strict_mode && !stmts.has_use_strict() { + if self.config.config.strict_mode && !has_use_strict { stmts.push(use_strict()); } - if !self.config.config.allow_top_level_this { - top_level_this(module_items, *Expr::undefined(DUMMY_SP)); - } - let import_interop = self.config.config.import_interop(); - let mut strip = ModuleDeclStrip::new(self.const_var_kind); - module_items.visit_mut_with(&mut strip); - - let ModuleDeclStrip { - link, - export, - export_assign, - has_module_decl, - .. - } = strip; - let is_export_assign = export_assign.is_some(); - if has_module_decl && !import_interop.is_none() && !is_export_assign { - stmts.push(define_es_module(self.exports())) + if has_module_syntax && !import_interop.is_none() && !is_export_assign { + stmts.push(define_es_module(self.exports())); } let mut import_map = Default::default(); + let ts_import_equals_exports: FxHashSet = body + .iter() + .filter_map(exported_external_ts_import_equals_name) + .cloned() + .collect(); + + stmts.extend(self.handle_import_export( + &mut import_map, + requested_modules, + local_export_entries, + &ts_import_equals_exports, + is_export_assign, + )); - stmts.extend(self.handle_import_export(&mut import_map, link, export, is_export_assign)); - - stmts.extend(module_items.take().into_iter().filter_map(|i| match i { - ModuleItem::Stmt(stmt) if !stmt.is_empty() => Some(stmt), - _ => None, - })); + stmts.extend( + body.into_iter() + .filter_map(|item| self.lower_body_item(&mut import_map, item)), + ); if let Some(export_assign) = export_assign { let return_stmt = ReturnStmt { @@ -130,41 +136,24 @@ impl VisitMut for Umd { arg: Some(export_assign), }; - stmts.push(return_stmt.into()) + stmts.push(return_stmt.into()); } rewrite_import_bindings(&mut stmts, import_map, Default::default()); - // ==================== - // Emit - // ==================== - - let (adapter_fn_expr, factory_params) = self.adapter(module.span, is_export_assign); - - let factory_fn_expr: Expr = Function { - params: factory_params, - decorators: Default::default(), - span: DUMMY_SP, - body: Some(BlockStmt { - stmts, - ..Default::default() - }), - is_generator: false, - is_async: false, - ..Default::default() - } - .into(); - - *module_items = vec![adapter_fn_expr - .as_call( - DUMMY_SP, - vec![ - ThisExpr { span: DUMMY_SP }.as_arg(), - factory_fn_expr.as_arg(), - ], - ) - .into_stmt() - .into()] + *module_items = emit::emit( + stmts, + emit::EmitModule { + span: module.span, + is_export_assign, + exports: self.exports.clone(), + deps: self.dep_list.take(), + }, + &self.cm, + &self.config, + self.unresolved_mark, + &self.resolver, + ); } } @@ -172,42 +161,45 @@ impl Umd { fn handle_import_export( &mut self, import_map: &mut ImportMap, - link: Link, - export: Export, + requested_modules: RequestedModules, + local_export_entries: LocalExportEntries, + ts_import_equals_exports: &FxHashSet, is_export_assign: bool, ) -> impl Iterator { let import_interop = self.config.config.import_interop(); - let mut stmts = Vec::with_capacity(link.len()); + let mut stmts = Vec::with_capacity(requested_modules.len()); - let mut export_obj_prop_list = export.into_iter().collect(); + let mut export_bindings = local_export_entries.into_iter().collect(); - link.into_iter().for_each( - |(src, LinkItem(src_span, link_specifier_set, mut link_flag))| { - let is_node_default = !link_flag.has_named() && import_interop.is_node(); + requested_modules.into_iter().for_each( + |( + module_request, + RequestedModule { + span: src_span, + entries: module_entries, + usage: mut module_usage, + .. + }, + )| { + let src = module_request.src().clone(); + let is_node_default = !module_usage.has_named() && import_interop.is_node(); if import_interop.is_none() { - link_flag -= LinkFlag::NAMESPACE; + module_usage -= ModuleRequestUsage::NAMESPACE; } - let need_re_export = link_flag.export_star(); - let need_interop = link_flag.interop(); - let need_new_var = link_flag.need_raw_import(); + let need_re_export = module_usage.has_star_export(); + let need_interop = module_usage.needs_interop(); let mod_ident = private_ident!(local_name_for_src(&src)); - let new_var_ident = if need_new_var { - private_ident!(local_name_for_src(&src)) - } else { - mod_ident.clone() - }; self.dep_list.push((mod_ident.clone(), src, src_span)); - link_specifier_set.reduce( + module_entries.reduce( import_map, - &mut export_obj_prop_list, - &new_var_ident, - &Some(mod_ident.clone()), + &mut export_bindings, + &mod_ident, &mut false, is_node_default, ); @@ -225,29 +217,24 @@ impl Umd { // _introp(mod); if need_interop { import_expr = match import_interop { - ImportInterop::Swc if link_flag.interop() => if link_flag.namespace() { - helper_expr!(interop_require_wildcard) - } else { - helper_expr!(interop_require_default) + ImportInterop::Swc if module_usage.needs_interop() => { + if module_usage.needs_namespace_object() { + helper_expr!(interop_require_wildcard) + } else { + helper_expr!(interop_require_default) + } + .as_call(PURE_SP, vec![import_expr.as_arg()]) } - .as_call(PURE_SP, vec![import_expr.as_arg()]), - ImportInterop::Node if link_flag.namespace() => { + ImportInterop::Node if module_usage.needs_namespace_object() => { helper_expr!(interop_require_wildcard) .as_call(PURE_SP, vec![import_expr.as_arg(), true.as_arg()]) } _ => import_expr, } - }; + } // mod = _introp(mod); - // var mod1 = _introp(mod); - if need_new_var { - let stmt: Stmt = import_expr - .into_var_decl(self.const_var_kind, new_var_ident.into()) - .into(); - - stmts.push(stmt) - } else if need_interop { + if need_interop { let stmt = import_expr .make_assign_to(op!("="), mod_ident.into()) .into_stmt(); @@ -260,234 +247,80 @@ impl Umd { let mut export_stmts = Default::default(); - if !export_obj_prop_list.is_empty() && !is_export_assign { - sort_export_obj_prop_list(&mut export_obj_prop_list); + export_bindings.retain(|(export_name, _)| !ts_import_equals_exports.contains(export_name)); + + if !export_bindings.is_empty() && !is_export_assign { + sort_export_bindings(&mut export_bindings); let exports = self.exports(); - export_stmts = emit_export_stmts(exports, export_obj_prop_list); + export_stmts = emit_export_stmts(exports, export_bindings); } export_stmts.into_iter().chain(stmts) } - fn exports(&mut self) -> Ident { - self.exports - .get_or_insert_with(|| private_ident!("exports")) - .clone() - } - - /// - Without `export =` - /// ```javascript - /// (function (global, factory) { - /// if (typeof module === "object" && typeof module.exports === "object") { - /// factory(exports, require("mod")); - /// } else if (typeof define === "function" && define.amd) { - /// define(["exports", "mod"], factory); - /// } else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) { - /// factory((global.lib = {}), global.mod); - /// } - /// })(this, function (exports, mod) { - /// ... - /// }); - /// ``` - /// - With `export =` - /// ```javascript - /// (function (global, factory) { - /// if (typeof module === "object" && typeof module.exports === "object") { - /// module.exports = factory(require("mod")); - /// } else if (typeof define === "function" && define.amd) { - /// define(["mod"], factory); - /// } else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) { - /// global.lib = factory(global.mod); - /// } - /// })(this, function (mod) { - /// ... - /// }); - /// ``` - /// Return: adapter expr and factory params - fn adapter(&mut self, module_span: Span, is_export_assign: bool) -> (FnExpr, Vec) { - macro_rules! js_typeof { - ($test:expr =>! $type:expr) => { - Expr::Unary(UnaryExpr { - span: DUMMY_SP, - op: op!("typeof"), - arg: Box::new(Expr::from($test)), - }) - .make_bin(op!("!=="), quote_str!($type)) - }; - - ($test:expr => $type:expr) => { - Expr::Unary(UnaryExpr { - span: DUMMY_SP, - op: op!("typeof"), - arg: Box::new(Expr::from($test)), - }) - .make_bin(op!("==="), quote_str!($type)) - }; + fn lower_body_item(&mut self, import_map: &mut ImportMap, item: ModuleItem) -> Option { + match item { + ModuleItem::Stmt(stmt) if !stmt.is_empty() => Some(stmt), + ModuleItem::ModuleDecl(ModuleDecl::TsImportEquals(import)) => { + self.lower_ts_import_equals(import_map, *import) + } + _ => None, } + } - // define unresolved ref - let module = quote_ident!( - SyntaxContext::empty().apply_mark(self.unresolved_mark), - "module" - ); - - let require = quote_ident!( - SyntaxContext::empty().apply_mark(self.unresolved_mark), - "require" - ); - let define = quote_ident!( - SyntaxContext::empty().apply_mark(self.unresolved_mark), - "define" - ); - let global_this = quote_ident!( - SyntaxContext::empty().apply_mark(self.unresolved_mark), - "globalThis" - ); - let js_self = quote_ident!( - SyntaxContext::empty().apply_mark(self.unresolved_mark), - "self" - ); - - // adapter arguments - let global = private_ident!("global"); - let factory = private_ident!("factory"); - - let module_exports = module.clone().make_member(quote_ident!("exports")); - let define_amd = define.clone().make_member(quote_ident!("amd")); - - let mut cjs_args = Vec::new(); - let mut amd_dep_list = Vec::new(); - let mut browser_args = Vec::new(); - - let mut factory_params = Vec::new(); - - if !is_export_assign && self.exports.is_some() { - let filename = self.cm.span_to_filename(module_span); - let exported_name = self.config.determine_export_name(filename); - let global_lib = global.clone().make_member(exported_name.into()); - - cjs_args.push(quote_ident!("exports").as_arg()); - amd_dep_list.push(Some(quote_str!("exports").as_arg())); - browser_args.push( - ObjectLit { - span: DUMMY_SP, - props: Default::default(), - } - .make_assign_to(op!("="), global_lib.into()) - .as_arg(), - ); - factory_params.push(self.exports().into()); - } + fn lower_ts_import_equals( + &mut self, + import_map: &mut ImportMap, + import: TsImportEqualsDecl, + ) -> Option { + let src = external_ts_import_equals_source(&import)?; + let src_span = src.span; + let request = src.value.to_atom_lossy().into_owned(); + let TsImportEqualsDecl { + id: local, + is_export, + .. + } = import; + let param = if is_export { + local.clone().into_private() + } else { + local.clone() + }; self.dep_list - .take() - .into_iter() - .for_each(|(ident, src_path, src_span)| { - let src_path = match &self.resolver { - Resolver::Real { resolver, base } => resolver - .resolve_import(base, &src_path) - .with_context(|| format!("failed to resolve `{src_path}`")) - .unwrap(), - Resolver::Default => src_path, - }; + .push((param.clone(), request, (src_span, Default::default()))); - cjs_args.push( - require - .clone() - .as_call( - DUMMY_SP, - vec![quote_str!(src_span.0, src_path.clone()).as_arg()], - ) - .as_arg(), - ); - amd_dep_list.push(Some(quote_str!(src_span.0, src_path.clone()).as_arg())); - - let global_dep = { - let dep_name = self.config.global_name(&src_path); - let global = global.clone(); - if is_valid_prop_ident(&dep_name) { - global.make_member(quote_ident!(dep_name)) - } else { - global.computed_member(quote_str!(dep_name)) - } - }; - browser_args.push(global_dep.as_arg()); - factory_params.push(ident.into()); - }); - - let cjs_if_test = js_typeof!(module => "object") - .make_bin(op!("&&"), js_typeof!(module_exports.clone() => "object")); - let mut cjs_if_body = factory.clone().as_call(DUMMY_SP, cjs_args); - if is_export_assign { - cjs_if_body = cjs_if_body.make_assign_to(op!("="), module_exports.clone().into()); + if !is_export { + return None; } - let amd_if_test = js_typeof!(define.clone() => "function").make_bin(op!("&&"), define_amd); - let amd_if_body = define.as_call( - DUMMY_SP, - vec![ - ArrayLit { - span: DUMMY_SP, - elems: amd_dep_list, - } - .as_arg(), - factory.clone().as_arg(), - ], - ); - - let browser_if_test = CondExpr { - span: DUMMY_SP, - test: Box::new(js_typeof!(global_this.clone() =>! "undefined")), - cons: Box::new(global_this.into()), - alt: Box::new(global.clone().make_bin(op!("||"), js_self)), - } - .make_assign_to(op!("="), global.clone().into()); + Some(self.emit_ts_import_equals(import_map, local, is_export, param.into())) + } - let mut browser_if_body = factory.clone().as_call(DUMMY_SP, browser_args); - if is_export_assign { - browser_if_body = browser_if_body.make_assign_to(op!("="), module_exports.into()); + fn emit_ts_import_equals( + &mut self, + import_map: &mut ImportMap, + local: Ident, + is_export: bool, + value: Expr, + ) -> Stmt { + if is_export { + import_map.insert(local.to_id(), (self.exports(), Some(local.sym.clone()))); + return value + .make_assign_to(op!("="), self.exports().make_member(local.into()).into()) + .into_stmt(); } - let adapter_body = BlockStmt { - span: DUMMY_SP, - stmts: vec![IfStmt { - span: DUMMY_SP, - test: Box::new(cjs_if_test), - cons: Box::new(cjs_if_body.into_stmt()), - alt: Some(Box::new( - IfStmt { - span: DUMMY_SP, - test: Box::new(amd_if_test), - cons: Box::new(amd_if_body.into_stmt()), - alt: Some(Box::new( - IfStmt { - span: DUMMY_SP, - test: Box::new(browser_if_test), - cons: Box::new(browser_if_body.into_stmt()), - alt: None, - } - .into(), - )), - } - .into(), - )), - } - .into()], - ..Default::default() - }; - - let adapter_fn_expr = Function { - params: vec![global.into(), factory.into()], - span: DUMMY_SP, - body: Some(adapter_body), - is_generator: false, - is_async: false, - ..Default::default() - } - .into(); + value + .into_var_decl(self.const_var_kind, local.into()) + .into() + } - (adapter_fn_expr, factory_params) + fn exports(&mut self) -> Ident { + self.exports + .get_or_insert_with(|| private_ident!("exports")) + .clone() } } diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/umd/config.rs b/deps/swc/crates/swc_ecma_transforms_module/src/umd/config.rs index 49fa166e9..344834b44 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/umd/config.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/umd/config.rs @@ -43,7 +43,7 @@ impl Config { ) .map_err(|e| { if HANDLER.is_set() { - HANDLER.with(|h| e.into_diagnostic(h).emit()) + HANDLER.with(|h| e.into_diagnostic(h).emit()); } }) .unwrap() diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/umd/emit.rs b/deps/swc/crates/swc_ecma_transforms_module/src/umd/emit.rs new file mode 100644 index 000000000..1f0f17968 --- /dev/null +++ b/deps/swc/crates/swc_ecma_transforms_module/src/umd/emit.rs @@ -0,0 +1,261 @@ +use anyhow::Context; +use swc_atoms::Atom; +use swc_common::{sync::Lrc, Mark, SourceMap, Span, SyntaxContext, DUMMY_SP}; +use swc_ecma_ast::*; +use swc_ecma_utils::{is_valid_prop_ident, private_ident, quote_ident, quote_str, ExprFactory}; + +use super::config::BuiltConfig; +use crate::{path::Resolver, SpanCtx}; + +pub(super) struct EmitModule { + pub span: Span, + pub is_export_assign: bool, + pub exports: Option, + pub deps: Vec<(Ident, Atom, SpanCtx)>, +} + +pub(super) fn emit( + stmts: Vec, + module: EmitModule, + cm: &Lrc, + config: &BuiltConfig, + unresolved_mark: Mark, + resolver: &Resolver, +) -> Vec { + let (adapter_fn_expr, factory_params) = + emit_adapter(&module, cm, config, unresolved_mark, resolver); + + let factory_fn_expr: Expr = Function { + params: factory_params, + decorators: Default::default(), + span: DUMMY_SP, + body: Some(BlockStmt { + stmts, + ..Default::default() + }), + is_generator: false, + is_async: false, + ..Default::default() + } + .into(); + + vec![adapter_fn_expr + .as_call( + DUMMY_SP, + vec![ + ThisExpr { span: DUMMY_SP }.as_arg(), + factory_fn_expr.as_arg(), + ], + ) + .into_stmt() + .into()] +} + +/// Builds the UMD adapter function and returns it with the factory params. +/// +/// The adapter always emits `CommonJS`, AMD, and global-fallback branches: +/// ```javascript +/// if (typeof module === "object" && typeof module.exports === "object") { ... } +/// else if (typeof define === "function" && define.amd) { ... } +/// else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) { ... } +/// ``` +/// +/// For regular ES exports, `exports` is added as the first CommonJS/AMD +/// dependency and factory param. The global fallback creates the configured +/// export object and passes it as the first factory argument: +/// ```javascript +/// factory(exports, require("mod")); +/// define(["exports", "mod"], factory); +/// factory((global.lib = {}), global.mod); +/// function (exports, mod) { ... } +/// ``` +/// +/// For `export =`, there is no `exports` param. The factory returns the module +/// value, `CommonJS` assigns that return value to `module.exports`, AMD only +/// registers the dependency list, and the fallback branch assigns the factory +/// result to the inferred global export name: +/// ```javascript +/// module.exports = factory(require("mod")); +/// define(["mod"], factory); +/// global.lib = factory(global.mod); +/// function (mod) { ... } +/// ``` +fn emit_adapter( + module: &EmitModule, + cm: &Lrc, + config: &BuiltConfig, + unresolved_mark: Mark, + resolver: &Resolver, +) -> (FnExpr, Vec) { + macro_rules! js_typeof { + ($test:expr =>! $type:expr) => { + Expr::Unary(UnaryExpr { + span: DUMMY_SP, + op: op!("typeof"), + arg: Box::new(Expr::from($test)), + }) + .make_bin(op!("!=="), quote_str!($type)) + }; + + ($test:expr => $type:expr) => { + Expr::Unary(UnaryExpr { + span: DUMMY_SP, + op: op!("typeof"), + arg: Box::new(Expr::from($test)), + }) + .make_bin(op!("==="), quote_str!($type)) + }; + } + + let module_ident = quote_ident!(SyntaxContext::empty().apply_mark(unresolved_mark), "module"); + let require = quote_ident!( + SyntaxContext::empty().apply_mark(unresolved_mark), + "require" + ); + let define = quote_ident!(SyntaxContext::empty().apply_mark(unresolved_mark), "define"); + let global_this = quote_ident!( + SyntaxContext::empty().apply_mark(unresolved_mark), + "globalThis" + ); + let js_self = quote_ident!(SyntaxContext::empty().apply_mark(unresolved_mark), "self"); + + let global = private_ident!("global"); + let factory = private_ident!("factory"); + + let module_exports = module_ident.clone().make_member(quote_ident!("exports")); + let define_amd = define.clone().make_member(quote_ident!("amd")); + + let mut cjs_args = Vec::new(); + let mut amd_dep_list = Vec::new(); + let mut browser_args = Vec::new(); + + let mut factory_params = Vec::new(); + + if !module.is_export_assign { + if let Some(exports) = &module.exports { + cjs_args.push(quote_ident!("exports").as_arg()); + amd_dep_list.push(Some(quote_str!("exports").as_arg())); + browser_args.push( + ObjectLit::default() + .make_assign_to( + op!("="), + module_global_export_member(module.span, cm, config, &global).into(), + ) + .as_arg(), + ); + factory_params.push(exports.clone().into()); + } + } + + module.deps.iter().for_each(|(ident, src_path, src_span)| { + let src_path = match resolver { + Resolver::Real { resolver, base } => resolver + .resolve_import(base, src_path) + .with_context(|| format!("failed to resolve `{src_path}`")) + .unwrap(), + Resolver::Default => src_path.clone(), + }; + + cjs_args.push( + require + .clone() + .as_call( + DUMMY_SP, + vec![quote_str!(src_span.0, src_path.clone()).as_arg()], + ) + .as_arg(), + ); + amd_dep_list.push(Some(quote_str!(src_span.0, src_path.clone()).as_arg())); + + let global_dep = { + let dep_name = config.global_name(&src_path); + let global = global.clone(); + if is_valid_prop_ident(&dep_name) { + global.make_member(quote_ident!(dep_name)) + } else { + global.computed_member(quote_str!(dep_name)) + } + }; + browser_args.push(global_dep.as_arg()); + factory_params.push(ident.clone().into()); + }); + + let cjs_if_test = js_typeof!(module_ident.clone() => "object") + .make_bin(op!("&&"), js_typeof!(module_exports.clone() => "object")); + let mut cjs_if_body = factory.clone().as_call(DUMMY_SP, cjs_args); + if module.is_export_assign { + cjs_if_body = cjs_if_body.make_assign_to(op!("="), module_exports.clone().into()); + } + + let amd_if_test = js_typeof!(define.clone() => "function").make_bin(op!("&&"), define_amd); + let amd_if_body = define.as_call( + DUMMY_SP, + vec![ + ArrayLit { + span: DUMMY_SP, + elems: amd_dep_list, + } + .as_arg(), + factory.clone().as_arg(), + ], + ); + + let browser_if_test = CondExpr { + span: DUMMY_SP, + test: Box::new(js_typeof!(global_this.clone() =>! "undefined")), + cons: Box::new(global_this.into()), + alt: Box::new(global.clone().make_bin(op!("||"), js_self)), + } + .make_assign_to(op!("="), global.clone().into()); + + let mut browser_if_body = factory.clone().as_call(DUMMY_SP, browser_args); + if module.is_export_assign { + browser_if_body = browser_if_body.make_assign_to( + op!("="), + module_global_export_member(module.span, cm, config, &global).into(), + ); + } + + let browser_if = if_stmt(browser_if_test, browser_if_body, None); + let amd_if = if_stmt(amd_if_test, amd_if_body, Some(browser_if)); + let adapter_body = BlockStmt { + span: DUMMY_SP, + stmts: vec![if_stmt(cjs_if_test, cjs_if_body, Some(amd_if))], + ..Default::default() + }; + + let adapter_fn_expr = Function { + params: vec![global.into(), factory.into()], + span: DUMMY_SP, + body: Some(adapter_body), + is_generator: false, + is_async: false, + ..Default::default() + } + .into(); + + (adapter_fn_expr, factory_params) +} + +fn if_stmt(test: Expr, body: Expr, alt: Option) -> Stmt { + IfStmt { + span: DUMMY_SP, + test: Box::new(test), + cons: Box::new(body.into_stmt()), + alt: alt.map(Box::new), + } + .into() +} + +/// Returns the browser fallback global member for the current module. +fn module_global_export_member( + module_span: Span, + cm: &Lrc, + config: &BuiltConfig, + global: &Ident, +) -> MemberExpr { + let filename = cm.span_to_filename(module_span); + let exported_name = config.determine_export_name(filename); + + global.clone().make_member(exported_name.into()) +} diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/util.rs b/deps/swc/crates/swc_ecma_transforms_module/src/util.rs index 970af03a5..05a8cec9b 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/util.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/util.rs @@ -6,11 +6,11 @@ use swc_config::file_pattern::FilePattern; use swc_ecma_ast::*; use swc_ecma_utils::{ is_valid_prop_ident, member_expr, private_ident, quote_ident, quote_str, ExprFactory, - FunctionFactory, IsDirective, + FunctionFactory, }; use crate::{ - module_decl_strip::{ExportItem, ExportKV}, + module_record::{ExportBinding, LocalExportEntry}, SpanCtx, }; @@ -33,7 +33,7 @@ pub struct Config { /// swc will emit `cjs-module-lexer` detectable annotation with this option /// enabled. /// - /// Defaults to `true` if import_interop is Node, else `false` + /// Defaults to `true` if `import_interop` is Node, else `false` #[serde(default)] pub export_interop_annotation: Option, #[serde(default)] @@ -52,6 +52,7 @@ pub struct Config { } impl Config { + #[must_use] pub fn default_js_ext() -> String { "js".to_string() } @@ -100,12 +101,14 @@ impl From for ImportInterop { impl Config { #[inline(always)] + #[must_use] pub fn import_interop(&self) -> ImportInterop { self.import_interop .unwrap_or_else(|| self.no_interop.into()) } #[inline(always)] + #[must_use] pub fn export_interop_annotation(&self) -> bool { self.export_interop_annotation .unwrap_or_else(|| self.import_interop == Some(ImportInterop::Node)) @@ -119,6 +122,7 @@ pub struct LazyObjectConfig { } impl LazyObjectConfig { + #[must_use] pub fn is_lazy(&self, src: &Atom) -> bool { self.patterns.iter().any(|pat| pat.is_match(src)) } @@ -133,6 +137,7 @@ pub enum Lazy { } impl Lazy { + #[must_use] pub fn is_lazy(&self, src: &Atom) -> bool { match *self { Lazy::Bool(false) => false, @@ -157,14 +162,14 @@ pub(super) fn local_name_for_src(src: &Atom) -> Atom { .unwrap_or(src); let id = match Ident::verify_symbol(src) { - Ok(_) => src.into(), + Ok(()) => src.into(), Err(err) => err, }; - if !id.starts_with('_') { - format!("_{id}").into() - } else { + if id.starts_with('_') { id.into() + } else { + format!("_{id}").into() } } @@ -209,35 +214,6 @@ pub(super) fn define_es_module(exports: Ident) -> Stmt { .into_stmt() } -pub(super) trait VecStmtLike { - type StmtLike: IsDirective; - - fn as_ref(&self) -> &[Self::StmtLike]; - - fn has_use_strict(&self) -> bool { - self.as_ref() - .iter() - .take_while(|s| s.directive_continue()) - .any(IsDirective::is_use_strict) - } -} - -impl VecStmtLike for [ModuleItem] { - type StmtLike = ModuleItem; - - fn as_ref(&self) -> &[Self::StmtLike] { - self - } -} - -impl VecStmtLike for [Stmt] { - type StmtLike = Stmt; - - fn as_ref(&self) -> &[Self::StmtLike] { - self - } -} - pub(super) fn use_strict() -> Stmt { Lit::Str(quote_str!("use strict")).into_stmt() } @@ -335,11 +311,11 @@ pub(crate) fn esm_export() -> Function { /// Sort export properties by key without allocating cached keys or cloning /// `Atom`s for each entry. #[inline] -pub(crate) fn sort_export_obj_prop_list(prop_list: &mut [ExportKV]) { +pub(crate) fn sort_export_bindings(prop_list: &mut [ExportBinding]) { prop_list.sort_unstable_by(|a, b| a.0.cmp(&b.0)); } -pub(crate) fn emit_export_stmts(exports: Ident, mut prop_list: Vec) -> Vec { +pub(crate) fn emit_export_stmts(exports: Ident, mut prop_list: Vec) -> Vec { match prop_list.len() { 0 | 1 => prop_list .pop() @@ -349,7 +325,7 @@ pub(crate) fn emit_export_stmts(exports: Ident, mut prop_list: Vec) -> quote_str!(export_item.export_name_span().0, export_name).as_arg(), prop_function(( "get".into(), - ExportItem::new(Default::default(), export_item.into_local_ident()), + LocalExportEntry::new(Default::default(), export_item.into_local_ident()), )) .into(), ) @@ -423,7 +399,7 @@ impl From for MemberProp { /// }, /// } /// ``` -pub(crate) fn prop_function((key, export_item): ExportKV) -> Prop { +pub(crate) fn prop_function((key, export_item): ExportBinding) -> Prop { let key = prop_name(&key, export_item.export_name_span()).into(); KeyValueProp { @@ -447,7 +423,7 @@ pub(crate) fn prop_function((key, export_item): ExportKV) -> Prop { /// } /// ``` /// Compatibility: getter is supported in Node.js v0.10+ -fn getter_function((key, export_item): ExportKV) -> Prop { +fn getter_function((key, export_item): ExportBinding) -> Prop { let key = prop_name(&key, export_item.export_name_span()).into(); GetterProp { diff --git a/deps/swc/crates/swc_ecma_transforms_module/src/wtf8.rs b/deps/swc/crates/swc_ecma_transforms_module/src/wtf8.rs index e282d57fd..d01698131 100644 --- a/deps/swc/crates/swc_ecma_transforms_module/src/wtf8.rs +++ b/deps/swc/crates/swc_ecma_transforms_module/src/wtf8.rs @@ -10,8 +10,7 @@ use swc_ecma_ast::Str; pub(crate) fn normalize_wtf8_atom(value: &Wtf8Atom) -> Atom { value .as_str() - .map(Atom::from) - .unwrap_or_else(|| Atom::from(value.to_string_lossy())) + .map_or_else(|| Atom::from(value.to_string_lossy()), Atom::from) } /// Convert a [`Str`] literal into a UTF-8 [`Atom`], preserving valid UTF-8 @@ -22,8 +21,8 @@ pub(crate) fn str_to_atom(value: &Str) -> Atom { } pub(crate) fn wtf8_to_cow_str(value: &Wtf8Atom) -> Cow<'_, str> { - value - .as_str() - .map(Cow::Borrowed) - .unwrap_or_else(|| Cow::Owned(value.to_string_lossy().into_owned())) + value.as_str().map_or_else( + || Cow::Owned(value.to_string_lossy().into_owned()), + Cow::Borrowed, + ) } diff --git a/deps/swc/crates/swc_ecma_transforms_optimization/Cargo.toml b/deps/swc/crates/swc_ecma_transforms_optimization/Cargo.toml index 8956b3c34..c61922701 100644 --- a/deps/swc/crates/swc_ecma_transforms_optimization/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transforms_optimization/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_transforms_optimization" repository = { workspace = true } -version = "47.0.1" +version = "50.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] @@ -29,30 +29,31 @@ once_cell = { workspace = true } par-core = { workspace = true } petgraph = { workspace = true } rustc-hash = { workspace = true } -serde_json = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true, features = ["raw_value"] } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] par-core = { workspace = true, features = ["chili"] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base", features = [ +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base", features = [ "inline-helpers", ] } -swc_ecma_transforms_compat = { version = "52.0.1", path = "../swc_ecma_transforms_compat" } -swc_ecma_transforms_module = { version = "49.0.1", path = "../swc_ecma_transforms_module" } -swc_ecma_transforms_proposal = { version = "44.0.1", path = "../swc_ecma_transforms_proposal" } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } -swc_ecma_transforms_typescript = { version = "50.0.0", path = "../swc_ecma_transforms_typescript" } -testing = { version = "24.0.1", path = "../testing" } +swc_ecma_transforms_compat = { version = "55.0.0", path = "../swc_ecma_transforms_compat" } +swc_ecma_transforms_module = { version = "53.0.0", path = "../swc_ecma_transforms_module" } +swc_ecma_transforms_proposal = { version = "47.0.0", path = "../swc_ecma_transforms_proposal" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } +swc_ecma_transforms_typescript = { version = "53.0.0", path = "../swc_ecma_transforms_typescript" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_ecma_transforms_optimization/src/debug.rs b/deps/swc/crates/swc_ecma_transforms_optimization/src/debug.rs index 490aaab03..dab5b47ab 100644 --- a/deps/swc/crates/swc_ecma_transforms_optimization/src/debug.rs +++ b/deps/swc/crates/swc_ecma_transforms_optimization/src/debug.rs @@ -42,11 +42,6 @@ impl Visit for AssertValid { panic!("Invalid node found"); } - #[cfg(debug_assertions)] - fn visit_number(&mut self, n: &Number) { - assert!(!n.value.is_nan(), "NaN should be an identifier"); - } - #[cfg(debug_assertions)] fn visit_setter_prop(&mut self, p: &SetterProp) { p.body.visit_with(self); diff --git a/deps/swc/crates/swc_ecma_transforms_optimization/src/json_parse.rs b/deps/swc/crates/swc_ecma_transforms_optimization/src/json_parse.rs index 7996cd320..353b9d581 100644 --- a/deps/swc/crates/swc_ecma_transforms_optimization/src/json_parse.rs +++ b/deps/swc/crates/swc_ecma_transforms_optimization/src/json_parse.rs @@ -1,9 +1,15 @@ -use serde_json::Value; +use std::{collections::BTreeMap, fmt::Write}; + +use serde::{ + ser::{SerializeMap, SerializeSeq}, + Serialize, Serializer, +}; +use serde_json::value::RawValue; use swc_atoms::Wtf8Atom; -use swc_common::{util::take::Take, Spanned, DUMMY_SP}; +use swc_common::{Spanned, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_transforms_base::perf::Parallel; -use swc_ecma_utils::{calc_literal_cost, member_expr, ExprFactory}; +use swc_ecma_utils::{calc_literal_cost, member_expr, number::ToJsString, ExprFactory}; use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith}; /// Transform to optimize performance of literals. @@ -65,13 +71,11 @@ impl VisitMut for JsonParse { Expr::Array(..) | Expr::Object(..) => { let (is_lit, cost) = calc_literal_cost(&*expr, false); if is_lit && cost >= self.min_cost { - let value = - serde_json::to_string(&jsonify(expr.take())).unwrap_or_else(|err| { - unreachable!("failed to serialize serde_json::Value as json: {}", err) - }); + let span = expr.span(); + let value = jsonify(expr); *expr = CallExpr { - span: expr.span(), + span, callee: member_expr!(Default::default(), DUMMY_SP, JSON.parse).as_callee(), args: vec![Lit::Str(Str { span: DUMMY_SP, @@ -109,61 +113,105 @@ fn wtf8_to_json_string(value: &Wtf8Atom) -> String { result.push(ch); } else { // Lone surrogate - escape as \uXXXX - use std::fmt::Write; write!(&mut result, "\\u{:04X}", cp.to_u32()).unwrap(); } } result } -fn jsonify(e: Expr) -> Value { - match e { - Expr::Object(obj) => Value::Object( - obj.props - .into_iter() - .map(|v| match v { - PropOrSpread::Prop(p) if p.is_key_value() => p.key_value().unwrap(), - _ => unreachable!(), - }) - .map(|p: KeyValueProp| { - let value = jsonify(*p.value); - let key = match p.key { - PropName::Str(s) => wtf8_to_json_string(&s.value), - PropName::Ident(id) => id.sym.to_string(), - PropName::Num(n) => format!("{}", n.value), - _ => unreachable!(), +/// Converts a finite ECMAScript number without using a saturating integer cast. +fn json_number(value: f64) -> serde_json::Number { + let is_i64 = value.fract() == 0.0 && value >= i64::MIN as f64 && value < i64::MAX as f64; + let preserves_zero_sign = value != 0.0 || value.is_sign_positive(); + + if is_i64 && preserves_zero_sign { + return (value as i64).into(); + } + + serde_json::Number::from_f64(value) + .unwrap_or_else(|| unreachable!("non-finite numbers require raw JSON serialization")) +} + +/// Converts a property name to the string key created by an object literal. +fn json_key(key: &PropName) -> String { + match key { + PropName::Str(s) => wtf8_to_json_string(&s.value), + PropName::Ident(id) => id.sym.to_string(), + PropName::Num(n) => n.value.to_js_string(), + _ => unreachable!(), + } +} + +/// Serializes a literal expression to JSON text while preserving ECMAScript +/// numeric values that are not representable by `serde_json::Value`. +fn jsonify(e: &Expr) -> String { + serde_json::to_string(&JsonLiteral(e)) + .unwrap_or_else(|err| unreachable!("failed to serialize literal as JSON: {err}")) +} + +/// Adapts an ECMAScript literal expression to Serde's data model. +struct JsonLiteral<'a>(&'a Expr); + +impl Serialize for JsonLiteral<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.0 { + Expr::Object(obj) => { + let mut values = BTreeMap::new(); + for prop in &obj.props { + let PropOrSpread::Prop(prop) = prop else { + unreachable!() + }; + let Prop::KeyValue(prop) = &**prop else { + unreachable!() }; - (key, value) - }) - .collect(), - ), - Expr::Array(arr) => Value::Array( - arr.elems - .into_iter() - .map(|v| jsonify(*v.unwrap().expr)) - .collect(), - ), - Expr::Lit(Lit::Str(Str { value, .. })) => Value::String(wtf8_to_json_string(&value)), - Expr::Lit(Lit::Num(Number { value, .. })) => { - if value.fract() == 0.0 { - Value::Number((value as i64).into()) - } else { - match serde_json::Number::from_f64(value) { - Some(n) => Value::Number(n), - None => Value::Number((value as i64).into()), + values.insert(json_key(&prop.key), &*prop.value); } + + let mut map = serializer.serialize_map(Some(values.len()))?; + for (key, value) in values { + map.serialize_entry(&key, &JsonLiteral(value))?; + } + map.end() + } + Expr::Array(arr) => { + let mut seq = serializer.serialize_seq(Some(arr.elems.len()))?; + for value in &arr.elems { + let value = value.as_ref().unwrap(); + seq.serialize_element(&JsonLiteral(value.expr.as_ref()))?; + } + seq.end() + } + Expr::Lit(Lit::Str(Str { value, .. })) => { + wtf8_to_json_string(value).serialize(serializer) + } + Expr::Lit(Lit::Num(Number { value, .. })) if value.is_infinite() => { + let value = if value.is_sign_positive() { + "2e308" + } else { + "-2e308" + }; + RawValue::from_string(value.into()) + .unwrap() + .serialize(serializer) + } + Expr::Lit(Lit::Num(Number { value, .. })) => json_number(*value).serialize(serializer), + Expr::Lit(Lit::Null(..)) => serializer.serialize_none(), + Expr::Lit(Lit::Bool(v)) => serializer.serialize_bool(v.value), + Expr::Tpl(Tpl { quasis, .. }) => { + let value = match quasis.first() { + Some(TplElement { + cooked: Some(value), + .. + }) => wtf8_to_json_string(value), + _ => String::new(), + }; + value.serialize(serializer) } + _ => unreachable!("jsonify: Expr {:?} cannot be converted to json", self.0), } - Expr::Lit(Lit::Null(..)) => Value::Null, - Expr::Lit(Lit::Bool(v)) => Value::Bool(v.value), - Expr::Tpl(Tpl { quasis, .. }) => Value::String(match quasis.first() { - Some(TplElement { - cooked: Some(value), - .. - }) => wtf8_to_json_string(value), - _ => String::new(), - }), - _ => unreachable!("jsonify: Expr {:?} cannot be converted to json", e), } } diff --git a/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/branch/mod.rs b/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/branch/mod.rs index 9f68b57dd..5af7b4265 100644 --- a/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/branch/mod.rs +++ b/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/branch/mod.rs @@ -736,7 +736,7 @@ impl VisitMut for Remover { ( &Expr::Lit(Lit::Num(Number { value: test, .. })), &Expr::Lit(Lit::Num(Number { value: d, .. })), - ) => (test - d).abs() < 1e-10, + ) => test == d || (test - d).abs() < 1e-10, ( &Expr::Lit(Lit::Bool(Bool { value: test, .. })), &Expr::Lit(Lit::Bool(Bool { value: d, .. })), diff --git a/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index a07086b06..f2242b63e 100644 --- a/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -310,11 +310,27 @@ struct VarInfo { struct Analyzer<'a> { #[allow(dead_code)] config: &'a Config, + expr_ctx: ExprCtx, in_var_decl: bool, scope: Scope<'a>, data: &'a mut Data, cur_class_id: Option, cur_fn_id: Option, + /// Lexical class bindings already declared earlier in the current scope. + /// Used to tell a backward (TDZ-safe) superclass reference, which may + /// participate in a removable declaration cycle, from a forward one, which + /// must be preserved. + initialized_classes: FxHashSet, + /// Subset of the above whose declaration carries decorators. A decorated + /// class is kept observable by its decorator independently of the cycle, so + /// a subclass extending it must not collapse the cycle. + /// Lexical class bindings, among those already initialized, whose + /// declaration is NOT definition-time trivial (see `class_def_is_trivial`): + /// it evaluates decorators, computed keys, or static initializers when + /// defined. A subclass must not collapse its `extends` cycle with such a + /// superclass, since the superclass's eager evaluation may depend on the + /// cycle being intact. + nontrivial_classes: FxHashSet, } #[derive(Debug, Default)] @@ -370,6 +386,9 @@ impl Analyzer<'_> { data: self.data, cur_fn_id: self.cur_fn_id.clone(), cur_class_id: self.cur_class_id.clone(), + // A new scope starts a fresh lexical-initialization context. + initialized_classes: Default::default(), + nontrivial_classes: Default::default(), ..*self }; @@ -448,6 +467,84 @@ impl Analyzer<'_> { } } +/// A class declaration is "definition-time trivial" when evaluating it (running +/// its declaration) does nothing observable beyond resolving its `extends` +/// clause and any computed member keys (whose identifier references are pinned +/// separately by the analyzer). The eager evaluations this guards against are +/// decorators (on the class or any member) and `static` member initializers +/// (`static x = …`, `static #x = …`, and `static {}` blocks). Method and +/// constructor bodies and instance-field initializers run later (at +/// call/instantiation time), so they are not definition-time evaluations. +/// +/// Any eager evaluation may read another class still in its temporal dead zone +/// and throw. Restricting the backward-reference optimization to trivial +/// classes (on both sides of the `extends` edge) means a removable cycle can +/// only be collapsed when neither class evaluates anything at definition time +/// except the heritage reference itself — which the caller separately checks is +/// a safe backward reference. This closes the whole family of definition-time +/// TDZ hazards structurally instead of enumerating each one. The `extends` +/// expression is intentionally not inspected here; it is handled by the caller. +fn class_def_is_trivial(class: &Class) -> bool { + if !class.decorators.is_empty() { + return false; + } + class.body.iter().all(|member| match member { + ClassMember::Constructor(_) | ClassMember::TsIndexSignature(_) | ClassMember::Empty(_) => { + true + } + ClassMember::Method(m) => m.function.decorators.is_empty(), + ClassMember::PrivateMethod(m) => m.function.decorators.is_empty(), + ClassMember::ClassProp(p) => p.decorators.is_empty() && !(p.is_static && p.value.is_some()), + ClassMember::PrivateProp(p) => { + p.decorators.is_empty() && !(p.is_static && p.value.is_some()) + } + ClassMember::AutoAccessor(a) => { + a.decorators.is_empty() && !(a.is_static && a.value.is_some()) + } + ClassMember::StaticBlock(_) => false, + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + }) +} + +/// Returns true when the class definition has no observable side effects, i.e. +/// it is safe to drop when unused. Kept in sync with the `Decl::Class` arm of +/// `visit_mut_decl`'s drop predicate, which calls this. +fn class_def_is_side_effect_free(class: &Class, expr_ctx: ExprCtx) -> bool { + class + .super_class + .as_deref() + .map_or(true, |e| !e.may_have_side_effects(expr_ctx)) + && class.body.iter().all(|m| match m { + ClassMember::Method(m) => !matches!(m.key, PropName::Computed(..)), + ClassMember::ClassProp(m) => { + !matches!(m.key, PropName::Computed(..)) + && !m + .value + .as_deref() + .is_some_and(|e| e.may_have_side_effects(expr_ctx)) + } + ClassMember::AutoAccessor(m) => { + !matches!(m.key, Key::Public(PropName::Computed(..))) + && !m + .value + .as_deref() + .is_some_and(|e| e.may_have_side_effects(expr_ctx)) + } + ClassMember::PrivateProp(m) => !m + .value + .as_deref() + .is_some_and(|e| e.may_have_side_effects(expr_ctx)), + ClassMember::StaticBlock(_) => false, + ClassMember::TsIndexSignature(_) + | ClassMember::Empty(_) + | ClassMember::Constructor(_) + | ClassMember::PrivateMethod(_) => true, + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + }) +} + impl Visit for Analyzer<'_> { noop_visit_type!(); @@ -468,12 +565,53 @@ impl Visit for Analyzer<'_> { } fn visit_class_decl(&mut self, n: &ClassDecl) { - if let Some(super_class) = &n.class.super_class { - super_class.visit_with(self); + // A superclass that is a backward reference to an already-initialized + // class can be attributed as a normal dependency edge, letting an + // unreachable `extends` cycle collapse. A forward reference, a + // non-identifier expression, or anything else is treated as a top-level + // reference (the original behavior): it pins the referent as an entry + // and preserves any cycle it belongs to. This keeps TDZ-observable + // cycles such as `class A extends B {} class B extends A {}` (which + // throws at runtime) from being eliminated. + // The backward-reference optimization (attributing the `extends` edge to + // the subclass so an unreachable cycle can collapse) is only applied when + // it is provably safe. It requires the superclass to be an identifier + // already initialized earlier in this scope, AND: + // - the subclass carries no decorators, and the superclass is not decorated + // either — a decorator runs at definition time and keeps a class observable + // independently of the cycle, so collapsing it could drop a sibling the + // decorator still needs; + // - neither class is in `top_retain`, which keeps it externally reachable. + // Anything else falls back to the original behavior (the heritage + // reference pins the referent as an entry, preserving the cycle). + // Preserving an unused cycle is always safe; dropping a live one is the bug. + let super_id = n.class.super_class.as_deref().and_then(|sc| match sc { + Expr::Ident(i) => Some(i.to_id()), + _ => None, + }); + let super_is_initialized_class_ref = class_def_is_trivial(&n.class) + && !self.config.top_retain.contains(&n.ident.sym) + && super_id.as_ref().is_some_and(|id| { + self.initialized_classes.contains(id) + && !self.nontrivial_classes.contains(id) + && !self.config.top_retain.contains(&id.0) + }); + + if !super_is_initialized_class_ref { + if let Some(super_class) = &n.class.super_class { + super_class.visit_with(self); + } } self.with_ast_path(vec![n.ident.to_id()], |v| { let old = v.cur_class_id.take(); + + if super_is_initialized_class_ref { + if let Some(super_class) = &n.class.super_class { + super_class.visit_with(v); + } + } + v.cur_class_id = Some(n.ident.to_id()); n.ident.visit_with(v); n.class.decorators.visit_with(v); @@ -483,7 +621,25 @@ impl Visit for Analyzer<'_> { if !n.class.decorators.is_empty() { v.add(n.ident.to_id(), false); } - }) + }); + + // A class that is not definition-time trivial evaluates something when + // defined (decorators, computed keys, or static initializers) that may + // read another class still in its TDZ. It is recorded so a later + // subclass extending it will not collapse their cycle, and is itself + // pinned as an entry so any cycle it participates in is kept alive. + // Independently, a class whose definition has observable side effects + // cannot be dropped either. + let is_trivial = class_def_is_trivial(&n.class); + if !is_trivial { + self.nontrivial_classes.insert(n.ident.to_id()); + } + if !is_trivial || !class_def_is_side_effect_free(&n.class, self.expr_ctx) { + let idx = self.data.node(&n.ident.to_id()); + self.data.entries.insert(idx); + } + + self.initialized_classes.insert(n.ident.to_id()); } fn visit_class_expr(&mut self, n: &ClassExpr) { @@ -777,6 +933,48 @@ impl TreeShaker { } } +/// Top-level declared identifiers, without descending into function bodies. +fn push_decl_binding_ids(decl: &Decl, out: &mut Vec) { + match decl { + Decl::Class(c) => out.push(c.ident.to_id()), + Decl::Fn(f) => out.push(f.ident.to_id()), + Decl::Var(v) => { + for d in &v.decls { + out.extend(find_pat_ids::<_, Id>(&d.name)); + } + } + _ => {} + } +} + +/// Collects `var` bindings that hoist to the enclosing top-level (module or +/// script) scope: `var`s anywhere except inside a nested function scope. Used +/// alongside the immediate top-level declarations so a `var` hoisted out of a +/// top-level block (e.g. `if (c) { var x }`) stays visible to a root `eval`. +#[derive(Default)] +struct RootHoistedVars { + ids: Vec, +} + +impl Visit for RootHoistedVars { + noop_visit_type!(); + + // Nested function scopes don't hoist their `var`s to the root. + fn visit_function(&mut self, _: &Function) {} + + fn visit_arrow_expr(&mut self, _: &ArrowExpr) {} + + fn visit_constructor(&mut self, _: &Constructor) {} + + fn visit_var_decl(&mut self, n: &VarDecl) { + if n.kind == VarDeclKind::Var { + for d in &n.decls { + self.ids.extend(find_pat_ids::<_, Id>(&d.name)); + } + } + } +} + impl VisitMut for TreeShaker { noop_visit_mut_type!(); @@ -831,41 +1029,7 @@ impl VisitMut for TreeShaker { } Decl::Class(c) if self.can_drop_binding(c.ident.to_id(), false) - && c.class - .super_class - .as_deref() - .map_or(true, |e| !e.may_have_side_effects(self.expr_ctx)) - && c.class.body.iter().all(|m| match m { - ClassMember::Method(m) => !matches!(m.key, PropName::Computed(..)), - ClassMember::ClassProp(m) => { - !matches!(m.key, PropName::Computed(..)) - && !m - .value - .as_deref() - .is_some_and(|e| e.may_have_side_effects(self.expr_ctx)) - } - ClassMember::AutoAccessor(m) => { - !matches!(m.key, Key::Public(PropName::Computed(..))) - && !m - .value - .as_deref() - .is_some_and(|e| e.may_have_side_effects(self.expr_ctx)) - } - - ClassMember::PrivateProp(m) => !m - .value - .as_deref() - .is_some_and(|e| e.may_have_side_effects(self.expr_ctx)), - - ClassMember::StaticBlock(_) => false, - - ClassMember::TsIndexSignature(_) - | ClassMember::Empty(_) - | ClassMember::Constructor(_) - | ClassMember::PrivateMethod(_) => true, - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - }) => + && class_def_is_side_effect_free(&c.class, self.expr_ctx) => { #[cfg(debug_assertions)] debug!("Dropping class `{}` as it's not used", c.ident); @@ -1032,13 +1196,62 @@ impl VisitMut for TreeShaker { { let mut analyzer = Analyzer { config: &self.config, + expr_ctx: self.expr_ctx, in_var_decl: false, scope: Default::default(), data: &mut data, cur_class_id: Default::default(), cur_fn_id: Default::default(), + initialized_classes: Default::default(), + nontrivial_classes: Default::default(), }; m.visit_with(&mut analyzer); + + if analyzer.scope.found_direct_eval { + // A direct `eval` reaching the root can resolve any + // top-level binding by name. Pin the module's top-level + // declarations as graph entries so DCE can't drop them. + // Unlike `collect_decls`, we do NOT descend into function + // bodies: a top-level `eval` cannot observe bindings nested + // inside another scope. + let mut ids = Vec::new(); + for item in &m.body { + match item { + ModuleItem::Stmt(Stmt::Decl(d)) => push_decl_binding_ids(d, &mut ids), + ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(e)) => { + push_decl_binding_ids(&e.decl, &mut ids) + } + ModuleItem::ModuleDecl(ModuleDecl::Import(i)) => { + for spec in &i.specifiers { + ids.push(match spec { + ImportSpecifier::Named(s) => s.local.to_id(), + ImportSpecifier::Default(s) => s.local.to_id(), + ImportSpecifier::Namespace(s) => s.local.to_id(), + #[cfg(swc_ast_unknown)] + _ => continue, + }); + } + } + _ => {} + } + } + + // Also pin `var`s hoisted out of nested top-level statements + // (e.g. `if (c) { var x }`), visible to a root `eval`. + let mut hoisted = RootHoistedVars::default(); + m.visit_with(&mut hoisted); + ids.extend(hoisted.ids); + + for id in ids { + // Pin as a graph entry so `subtract_cycles` never + // subtracts it (survives Repeat passes), and bump usage + // so a lone binding — which has no in-graph references — + // isn't dropped by `can_drop_binding`. + let ix = analyzer.data.node(&id); + analyzer.data.entries.insert(ix); + analyzer.data.used_names.entry(id).or_default().usage += 1; + } + } } data.subtract_cycles(); self.data = data; @@ -1098,13 +1311,47 @@ impl VisitMut for TreeShaker { { let mut analyzer = Analyzer { config: &self.config, + expr_ctx: self.expr_ctx, in_var_decl: false, scope: Default::default(), data: &mut data, cur_class_id: Default::default(), cur_fn_id: Default::default(), + initialized_classes: Default::default(), + nontrivial_classes: Default::default(), }; m.visit_with(&mut analyzer); + + // A direct `eval` can reference any binding in its enclosing + // lexical scope chain, up to the top level. `found_direct_eval` + // is propagated to the root scope, but unlike function scopes + // (see `with_scope`), the root never consumed it, so top-level + // declarations reachable by a direct `eval` were dropped. + // Preserve them here. + if analyzer.scope.found_direct_eval { + let mut ids = Vec::new(); + for stmt in &m.body { + if let Stmt::Decl(d) = stmt { + push_decl_binding_ids(d, &mut ids); + } + } + + // Also pin `var`s hoisted out of nested top-level statements + // (e.g. `if (c) { var x }`), visible to a root `eval`. + let mut hoisted = RootHoistedVars::default(); + m.visit_with(&mut hoisted); + ids.extend(hoisted.ids); + + for id in ids { + // Pin as a graph entry so `subtract_cycles` never + // subtracts it (survives Repeat passes), and bump usage + // so a lone binding — which has no in-graph references — + // isn't dropped by `can_drop_binding`. + let ix = analyzer.data.node(&id); + analyzer.data.entries.insert(ix); + analyzer.data.used_names.entry(id).or_default().usage += 1; + } + } } data.subtract_cycles(); self.data = data; diff --git a/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs b/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs index e6f648f97..ca470d62a 100644 --- a/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs +++ b/deps/swc/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs @@ -1,7 +1,6 @@ use std::{borrow::Cow, iter, iter::once}; use swc_atoms::{ - atom, wtf8::{CodePoint, Wtf8, Wtf8Buf}, Atom, }; @@ -16,8 +15,10 @@ use swc_ecma_transforms_base::{ perf::{cpu_count, Parallel, ParallelExt}, }; use swc_ecma_utils::{ - is_literal, number::JsNumber, prop_name_eq, to_int32, BoolType, ExprCtx, ExprExt, NullType, - NumberType, ObjectType, StringType, SymbolType, UndefinedType, Value, + is_literal, + number::{minify_number, parse_canonical_index, JsNumber, ToJsString}, + prop_name_eq, to_int32, BoolType, ExprCtx, ExprExt, NullType, NumberType, ObjectType, + StringType, SymbolType, UndefinedType, Value, }; use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith}; use Value::{Known, Unknown}; @@ -589,21 +590,45 @@ where } /// Gets the `idx`-th UTF-16 code unit from the given [Wtf8]. -/// Surrogate pairs are splitted into high and low surrogates and counted +/// Surrogate pairs are split into high and low surrogates and counted /// separately. -fn nth_char(s: &Wtf8, idx: usize) -> CodePoint { - match s.to_ill_formed_utf16().nth(idx) { - Some(c) => - // SAFETY: `IllFormedUtf16CodeUnits` always returns code units in the range of UTF-16. - unsafe { CodePoint::from_u32_unchecked(c as u32) }, - None => unreachable!("string is too short"), - } +fn nth_char(s: &Wtf8, idx: usize) -> Option { + s.to_ill_formed_utf16().nth(idx).map(|c| { + // SAFETY: `IllFormedUtf16CodeUnits` always returns code units in the range of + // UTF-16. + unsafe { CodePoint::from_u32_unchecked(c as u32) } + }) } fn need_zero_for_this(e: &Expr) -> bool { e.directness_matters() || e.is_seq() } +/// A statically known property key with optional metadata for literal indexing. +/// +/// `property_key` is always the exact ECMAScript property key. `index` is only +/// populated for canonical non-negative decimal keys that can index a literal +/// array or string without reinterpreting the property key. +struct KnownMemberKey { + property_key: Atom, + index: Option, +} + +impl KnownMemberKey { + fn from_number(value: f64) -> Self { + Self::from_property_key(Atom::from(value.to_js_string())) + } + + fn from_property_key(property_key: Atom) -> Self { + let index = parse_canonical_index(property_key.as_str()); + + Self { + property_key, + index, + } + } +} + /// Gets the value of the given key from the given object properties, if the key /// exists. If the key does exist, `Some` is returned and the property is /// removed from the given properties. @@ -685,24 +710,17 @@ pub fn optimize_member_expr( _ => return, }; - #[derive(Clone, PartialEq, Debug)] enum KnownOp { /// [a, b].length Len, - /// [a, b][0] - /// - /// {0.5: "bar"}[0.5] - /// Note: callers need to check `v.fract() == 0.0` in some cases. - /// ie non-integer indexes for arrays result in `undefined` - /// but not for objects (because indexing an object - /// returns the value of the key, ie `0.5` will not - /// return `undefined` if a key `0.5` exists - /// and its value is not `undefined`). - Index(f64), - - /// ({}).foo - IndexStr(Atom), + /// A known ECMAScript property key. + Key { + key: KnownMemberKey, + // Numeric keys preserve the existing object-folding eligibility; + // other keys still require a fully literal object. + requires_literal_object: bool, + }, } let op = match prop { MemberProp::Ident(IdentName { sym, .. }) if &**sym == "length" && !obj.is_object() => { @@ -713,7 +731,10 @@ pub fn optimize_member_expr( return; } - KnownOp::IndexStr(sym.clone()) + KnownOp::Key { + key: KnownMemberKey::from_property_key(sym.clone()), + requires_literal_object: true, + } } MemberProp::Computed(ComputedPropName { expr, .. }) => { if is_callee { @@ -722,17 +743,19 @@ pub fn optimize_member_expr( if let Expr::Lit(Lit::Num(Number { value, .. })) = &**expr { // x[5] - KnownOp::Index(*value) + KnownOp::Key { + key: KnownMemberKey::from_number(*value), + requires_literal_object: false, + } } else if let Known(s) = expr.as_pure_string(expr_ctx) { if s == "length" && !obj.is_object() { // Length of non-object type KnownOp::Len - } else if let Ok(n) = s.parse::() { - // x['0'] is treated as x[0] - KnownOp::Index(n) } else { - // x[''] or x[...] where ... is an expression like [], ie x[[]] - KnownOp::IndexStr(s.into()) + KnownOp::Key { + key: KnownMemberKey::from_property_key(s.into()), + requires_literal_object: true, + } } } else { return; @@ -769,14 +792,22 @@ pub fn optimize_member_expr( } // 'foo'[1] - KnownOp::Index(idx) => { - if idx.fract() != 0.0 || idx < 0.0 || idx as usize >= value.len() { - // Prototype changes affect indexing if the index is out of bounds, so we - // don't replace out-of-bound indexes. + KnownOp::Key { key, .. } => { + let Some(index) = key.index else { + return; + }; + + // WTF-8 byte length is an upper bound for UTF-16 code-unit length. + if index >= value.len() { return; } - let c = nth_char(value, idx as _); + // Prototype changes affect indexing if the index is out of bounds, so we + // don't replace out-of-bound indexes. This lookup must use UTF-16 code units, + // which are JavaScript's string indexing units, rather than WTF-8 bytes. + let Some(c) = nth_char(value, index) else { + return; + }; *changed = true; // `nth_char` always returns a code point within the UTF-16 range. @@ -790,11 +821,6 @@ pub fn optimize_member_expr( }) .into() } - - // 'foo'[''] - // - // Handled in compress - KnownOp::IndexStr(..) => {} }, // [1, 2, 3].length @@ -835,22 +861,23 @@ pub fn optimize_member_expr( .into(); } - KnownOp::Index(idx) => { - // If the fraction part is non-zero, or if the index is out of bounds, - // then we handle this in compress as Array's prototype may be modified. - if idx.fract() != 0.0 || idx < 0.0 || idx as usize >= elems.len() { + KnownOp::Key { key, .. } => { + let Some(index) = key.index else { + return; + }; + + // Out-of-bound indexes are handled in compress because Array's + // prototype may be modified. + if index >= elems.len() { return; } // Don't change if after has side effects. let after_has_side_effect = - elems - .iter() - .skip((idx as usize + 1) as _) - .any(|elem| match elem { - Some(elem) => elem.expr.may_have_side_effects(expr_ctx), - None => false, - }); + elems.iter().skip(index + 1).any(|elem| match elem { + Some(elem) => elem.expr.may_have_side_effects(expr_ctx), + None => false, + }); if after_has_side_effect { return; @@ -859,7 +886,7 @@ pub fn optimize_member_expr( *changed = true; // elements before target element - let before: Vec> = elems.drain(..(idx as usize)).collect(); + let before: Vec> = elems.drain(..index).collect(); let mut iter = elems.take().into_iter(); // element at idx let e = iter.next().flatten(); @@ -901,9 +928,6 @@ pub fn optimize_member_expr( exprs.push(val); *expr = *Expr::from_exprs(exprs); } - - // Handled in compress - KnownOp::IndexStr(..) => {} } } @@ -913,8 +937,14 @@ pub fn optimize_member_expr( Expr::Object(ObjectLit { props, span }) => { // get key let key = match op { - KnownOp::Index(i) => Atom::from(i.to_string()), - KnownOp::IndexStr(key) if key != *"yield" && is_literal(props) => key, + KnownOp::Key { + key, + requires_literal_object, + } if key.property_key != *"yield" + && (!requires_literal_object || is_literal(props)) => + { + key.property_key + } _ => return, }; @@ -976,15 +1006,11 @@ pub fn optimize_bin_expr(expr_ctx: ExprCtx, expr: &mut Expr, changed: &mut bool) Known(v) => { *changed = true; - let value_expr = if !v.is_nan() { - Expr::Lit(Lit::Num(Number { - value: v, - span: *span, - raw: None, - })) - } else { - Expr::Ident(Ident::new(atom!("NaN"), *span, expr_ctx.unresolved_ctxt)) - }; + let value_expr = Expr::Lit(Lit::Num(Number { + value: v, + span: *span, + raw: None, + })); *expr = *expr_ctx.preserve_effects(*span, value_expr.into(), { iter::once(left.take()).chain(iter::once(right.take())) @@ -1057,16 +1083,12 @@ pub fn optimize_bin_expr(expr_ctx: ExprCtx, expr: &mut Expr, changed: &mut bool) *changed = true; let span = *span; - let value_expr = if !v.is_nan() { - Lit::Num(Number { - value: v, - span, - raw: None, - }) - .into() - } else { - Ident::new(atom!("NaN"), span, expr_ctx.unresolved_ctxt).into() - }; + let value_expr = Lit::Num(Number { + value: v, + span, + raw: None, + }) + .into(); *expr = *expr_ctx.preserve_effects( span, @@ -1230,16 +1252,12 @@ pub fn optimize_bin_expr(expr_ctx: ExprCtx, expr: &mut Expr, changed: &mut bool) { if *left_op == op { if let Known(value) = perform_arithmetic_op(expr_ctx, op, left_rhs, right) { - let value_expr = if !value.is_nan() { - Lit::Num(Number { - value, - span: *span, - raw: None, - }) - .into() - } else { - Ident::new(atom!("NaN"), *span, expr_ctx.unresolved_ctxt).into() - }; + let value_expr = Lit::Num(Number { + value, + span: *span, + raw: None, + }) + .into(); *changed = true; *left = left_lhs.take(); @@ -1309,15 +1327,6 @@ pub fn optimize_unary_expr(expr_ctx: ExprCtx, expr: &mut Expr, changed: &mut boo if let Known(v) = arg.as_pure_number(expr_ctx) { *changed = true; - if v.is_nan() { - *expr = *expr_ctx.preserve_effects( - *span, - Ident::new(atom!("NaN"), *span, expr_ctx.unresolved_ctxt).into(), - iter::once(arg.take()), - ); - return; - } - *expr = *expr_ctx.preserve_effects( *span, Lit::Num(Number { @@ -1373,11 +1382,7 @@ pub fn optimize_unary_expr(expr_ctx: ExprCtx, expr: &mut Expr, changed: &mut boo *changed = true; *expr = Lit::Num(Number { span: *span, - value: if value < 0.0 { - !(value as i32 as u32) as i32 as f64 - } else { - !(value as u32) as i32 as f64 - }, + value: (!JsNumber::from(value)).into(), raw: None, }) .into(); @@ -1435,29 +1440,39 @@ fn try_fold_typeof(_expr_ctx: ExprCtx, expr: &mut Expr, changed: &mut bool) { /// Try to fold arithmetic binary operators fn perform_arithmetic_op(expr_ctx: ExprCtx, op: BinaryOp, left: &Expr, right: &Expr) -> Value { /// Replace only if it becomes shorter - macro_rules! try_replace { - ($value:expr) => {{ - let (ls, rs) = (left.span(), right.span()); - if ls.is_dummy() || rs.is_dummy() { - Known($value) - } else { - let new_len = format!("{}", $value).len(); - if right.span().hi() > left.span().lo() { - let orig_len = - right.span().hi() - right.span().lo() + left.span().hi() - left.span().lo(); - if new_len <= orig_len.0 as usize + 1 { - Known($value) - } else { - Unknown - } - } else { - Known($value) - } - } - }}; - (i32, $value:expr) => { - try_replace!($value as f64) - }; + fn try_replace(lv: f64, rv: f64, value: f64) -> Value { + if !value.is_finite() { + return Known(value); + } + + let new_len = minify_number(value, &mut false).len(); + + let orig_len = + minify_number(lv, &mut false).len() + 1 + minify_number(rv, &mut false).len(); + + if new_len <= orig_len { + Known(value) + } else { + Unknown + } + } + + fn try_replace_i32(lv: f64, rv: f64, value: i32) -> Value { + let new_len = value.to_string().len(); + + let orig_len = minify_number(lv, &mut false) + .len() + .min(to_int32(lv).to_string().len()) + + 1 + + minify_number(rv, &mut false) + .len() + .min(to_int32(rv).to_string().len()); + + if new_len <= orig_len { + Known(value as f64) + } else { + Unknown + } } let (lv, rv) = ( @@ -1476,7 +1491,7 @@ fn perform_arithmetic_op(expr_ctx: ExprCtx, op: BinaryOp, left: &Expr, right: &E match op { op!(bin, "+") => { if let (Known(lv), Known(rv)) = (lv, rv) { - return try_replace!(lv + rv); + return try_replace(lv, rv, lv + rv); } if lv == Known(0.0) { @@ -1489,7 +1504,7 @@ fn perform_arithmetic_op(expr_ctx: ExprCtx, op: BinaryOp, left: &Expr, right: &E } op!(bin, "-") => { if let (Known(lv), Known(rv)) = (lv, rv) { - return try_replace!(lv - rv); + return try_replace(lv, rv, lv - rv); } // 0 - x => -x @@ -1506,7 +1521,7 @@ fn perform_arithmetic_op(expr_ctx: ExprCtx, op: BinaryOp, left: &Expr, right: &E } op!("*") => { if let (Known(lv), Known(rv)) = (lv, rv) { - return try_replace!(lv * rv); + return try_replace(lv, rv, lv * rv); } // NOTE: 0*x != 0 for all x, if x==0, then it is NaN. So we can't take // advantage of that without some kind of non-NaN proof. So the special cases @@ -1523,10 +1538,7 @@ fn perform_arithmetic_op(expr_ctx: ExprCtx, op: BinaryOp, left: &Expr, right: &E op!("/") => { if let (Known(lv), Known(rv)) = (lv, rv) { - if rv == 0.0 { - return Unknown; - } - return try_replace!(lv / rv); + return try_replace(lv, rv, lv / rv); } // NOTE: 0/x != 0 for all x, if x==0, then it is NaN @@ -1545,10 +1557,10 @@ fn perform_arithmetic_op(expr_ctx: ExprCtx, op: BinaryOp, left: &Expr, right: &E } if let (Known(lv), Known(rv)) = (lv, rv) { - let lv: JsNumber = lv.into(); - let rv: JsNumber = rv.into(); - let result: f64 = lv.pow(rv).into(); - return try_replace!(result); + let js_lv: JsNumber = lv.into(); + let js_rv: JsNumber = rv.into(); + let result: f64 = js_lv.pow(js_rv).into(); + return try_replace(lv, rv, result); } return Unknown; @@ -1561,15 +1573,10 @@ fn perform_arithmetic_op(expr_ctx: ExprCtx, op: BinaryOp, left: &Expr, right: &E }; match op { - op!("&") => try_replace!(i32, to_int32(lv) & to_int32(rv)), - op!("|") => try_replace!(i32, to_int32(lv) | to_int32(rv)), - op!("^") => try_replace!(i32, to_int32(lv) ^ to_int32(rv)), - op!("%") => { - if rv == 0.0 { - return Unknown; - } - try_replace!(lv % rv) - } + op!("&") => try_replace_i32(lv, rv, to_int32(lv) & to_int32(rv)), + op!("|") => try_replace_i32(lv, rv, to_int32(lv) | to_int32(rv)), + op!("^") => try_replace_i32(lv, rv, to_int32(lv) ^ to_int32(rv)), + op!("%") => try_replace(lv, rv, lv % rv), _ => unreachable!("unknown binary operator: {:?}", op), } } diff --git a/deps/swc/crates/swc_ecma_transforms_proposal/Cargo.toml b/deps/swc/crates/swc_ecma_transforms_proposal/Cargo.toml index 37a8c418c..3c5c5a73b 100644 --- a/deps/swc/crates/swc_ecma_transforms_proposal/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transforms_proposal/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_transforms_proposal" repository = { workspace = true } -version = "44.0.1" +version = "47.0.0" [lib] bench = false @@ -24,18 +24,18 @@ either = { workspace = true } rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_classes = { version = "44.0.0", path = "../swc_ecma_transforms_classes" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_classes = { version = "47.0.0", path = "../swc_ecma_transforms_classes" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] serde_json = { workspace = true } -swc_ecma_compat_es2022 = { version = "48.0.0", path = "../swc_ecma_compat_es2022" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms_compat = { version = "52.0.1", path = "../swc_ecma_transforms_compat" } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } -testing = { version = "24.0.1", path = "../testing" } +swc_ecma_compat_es2022 = { version = "51.0.0", path = "../swc_ecma_compat_es2022" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms_compat = { version = "55.0.0", path = "../swc_ecma_transforms_compat" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_ecma_transforms_proposal/src/decorator_impl.rs b/deps/swc/crates/swc_ecma_transforms_proposal/src/decorator_impl.rs index 04fd95f65..240462639 100644 --- a/deps/swc/crates/swc_ecma_transforms_proposal/src/decorator_impl.rs +++ b/deps/swc/crates/swc_ecma_transforms_proposal/src/decorator_impl.rs @@ -3385,6 +3385,19 @@ impl VisitMut for DecoratorPass { return; } + + let mut old_state = take(&mut self.state); + let private_id_index = old_state.private_id_index; + self.state = ClassState { + private_id_index, + ..Default::default() + }; + maybe_grow_default(|| c.visit_mut_with(self)); + let nested_state = take(&mut self.state); + old_state.private_id_index = nested_state.private_id_index; + self.state = old_state; + + return; } maybe_grow_default(|| e.visit_mut_children_with(self)); diff --git a/deps/swc/crates/swc_ecma_transforms_react/Cargo.toml b/deps/swc/crates/swc_ecma_transforms_react/Cargo.toml index 0f059a715..6a2deb809 100644 --- a/deps/swc/crates/swc_ecma_transforms_react/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transforms_react/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ecma_transforms_react" repository = { workspace = true } -version = "50.0.0" +version = "53.0.0" [lib] bench = false @@ -31,21 +31,21 @@ serde = { workspace = true, features = ["derive"], optional = true } sha1 = { workspace = true } string_enum = { version = "1.0.2", path = "../string_enum" } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_config = { version = "5.0.0", path = "../swc_config" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_hooks = { version = "0.9.0", path = "../swc_ecma_hooks" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_config = { version = "6.0.0", path = "../swc_config" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_hooks = { version = "0.11.0", path = "../swc_ecma_hooks" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_compat = { version = "52.0.1", path = "../swc_ecma_transforms_compat/", optional = true } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_compat = { version = "55.0.0", path = "../swc_ecma_transforms_compat/", optional = true } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen/" } -swc_ecma_transforms_compat = { version = "52.0.1", path = "../swc_ecma_transforms_compat/" } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } -testing = { version = "24.0.1", path = "../testing" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen/" } +swc_ecma_transforms_compat = { version = "55.0.0", path = "../swc_ecma_transforms_compat/" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_ecma_transforms_react/src/jsx/mod.rs b/deps/swc/crates/swc_ecma_transforms_react/src/jsx/mod.rs index bbc7b3dc9..a8f70e36a 100644 --- a/deps/swc/crates/swc_ecma_transforms_react/src/jsx/mod.rs +++ b/deps/swc/crates/swc_ecma_transforms_react/src/jsx/mod.rs @@ -30,7 +30,10 @@ use swc_ecma_utils::{ use swc_ecma_visit::VisitMut; use self::static_check::should_use_create_element; -use crate::refresh::options::{deserialize_refresh, RefreshOptions}; +use crate::{ + jsx_self::JsxSelfCtx, + refresh::options::{deserialize_refresh, RefreshOptions}, +}; mod static_check; #[cfg(test)] @@ -245,6 +248,7 @@ where .throw_if_namespace .unwrap_or_else(default_throw_if_namespace), top_level_node: true, + self_ctx: JsxSelfCtx::new(), } } @@ -295,6 +299,7 @@ where pragma_frag: Lrc>, development: bool, throw_if_namespace: bool, + self_ctx: JsxSelfCtx, } #[derive(Debug, Default, Clone, PartialEq, Eq)] @@ -489,6 +494,47 @@ impl Jsx where C: Comments, { + /// Build the JSXDEV source argument for fragments, which cannot carry + /// synthetic attributes. + fn jsx_dev_source_arg(&self, span: Span) -> ExprOrSpread { + if span == DUMMY_SP { + return Expr::undefined(DUMMY_SP).as_arg(); + } + + let loc = self.cm.lookup_char_pos(span.lo); + + ObjectLit { + span: DUMMY_SP, + props: vec![ + PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(quote_ident!("fileName")), + value: Box::new(Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + raw: None, + value: loc.file.name.to_string().into(), + }))), + }))), + PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(quote_ident!("lineNumber")), + value: loc.line.into(), + }))), + PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(quote_ident!("columnNumber")), + value: (loc.col.0 + 1).into(), + }))), + ], + } + .as_arg() + } + + fn jsx_dev_self_arg(&self) -> ExprOrSpread { + if self.self_ctx.can_add_self() { + ThisExpr { span: DUMMY_SP }.as_arg() + } else { + Expr::undefined(DUMMY_SP).as_arg() + } + } + /// Process JSX attribute value, handling JSXElements and JSXFragments fn process_attr_value(&mut self, value: Option) -> Box { match value { @@ -636,6 +682,8 @@ where props_obj.as_arg(), Expr::undefined(DUMMY_SP).as_arg(), use_jsxs.as_arg(), + self.jsx_dev_source_arg(el.opening.span), + self.jsx_dev_self_arg(), ] } else { vec![fragment.as_arg(), props_obj.as_arg()] @@ -1160,6 +1208,86 @@ impl VisitMutHook<()> for Jsx where C: Comments, { + fn enter_class(&mut self, n: &mut Class, _ctx: &mut ()) { + self.self_ctx.enter_class(n); + } + + fn exit_class(&mut self, _n: &mut Class, _ctx: &mut ()) { + self.self_ctx.pop(); + } + + fn enter_fn_decl(&mut self, _n: &mut FnDecl, _ctx: &mut ()) { + self.self_ctx.enter_non_constructor_scope(); + } + + fn exit_fn_decl(&mut self, _n: &mut FnDecl, _ctx: &mut ()) { + self.self_ctx.pop(); + } + + fn enter_fn_expr(&mut self, _n: &mut FnExpr, _ctx: &mut ()) { + self.self_ctx.enter_non_constructor_scope(); + } + + fn exit_fn_expr(&mut self, _n: &mut FnExpr, _ctx: &mut ()) { + self.self_ctx.pop(); + } + + fn enter_getter_prop(&mut self, _n: &mut GetterProp, _ctx: &mut ()) { + self.self_ctx.enter_non_constructor_scope(); + } + + fn exit_getter_prop(&mut self, _n: &mut GetterProp, _ctx: &mut ()) { + self.self_ctx.pop(); + } + + fn enter_setter_prop(&mut self, _n: &mut SetterProp, _ctx: &mut ()) { + self.self_ctx.enter_non_constructor_scope(); + } + + fn exit_setter_prop(&mut self, _n: &mut SetterProp, _ctx: &mut ()) { + self.self_ctx.pop(); + } + + fn enter_method_prop(&mut self, _n: &mut MethodProp, _ctx: &mut ()) { + self.self_ctx.enter_non_constructor_scope(); + } + + fn exit_method_prop(&mut self, _n: &mut MethodProp, _ctx: &mut ()) { + self.self_ctx.pop(); + } + + fn enter_constructor(&mut self, _n: &mut Constructor, _ctx: &mut ()) { + self.self_ctx.enter_constructor(); + } + + fn exit_constructor(&mut self, _n: &mut Constructor, _ctx: &mut ()) { + self.self_ctx.pop(); + } + + fn enter_class_method(&mut self, _n: &mut ClassMethod, _ctx: &mut ()) { + self.self_ctx.enter_non_constructor_scope(); + } + + fn exit_class_method(&mut self, _n: &mut ClassMethod, _ctx: &mut ()) { + self.self_ctx.pop(); + } + + fn enter_private_method(&mut self, _n: &mut PrivateMethod, _ctx: &mut ()) { + self.self_ctx.enter_non_constructor_scope(); + } + + fn exit_private_method(&mut self, _n: &mut PrivateMethod, _ctx: &mut ()) { + self.self_ctx.pop(); + } + + fn enter_static_block(&mut self, _n: &mut StaticBlock, _ctx: &mut ()) { + self.self_ctx.enter_non_constructor_scope(); + } + + fn exit_static_block(&mut self, _n: &mut StaticBlock, _ctx: &mut ()) { + self.self_ctx.pop(); + } + /// Called after visiting children of an expression. /// /// This is where we transform JSX syntax to JavaScript function calls. diff --git a/deps/swc/crates/swc_ecma_transforms_react/src/jsx_self/mod.rs b/deps/swc/crates/swc_ecma_transforms_react/src/jsx_self/mod.rs index 42a97cad0..f210268a3 100644 --- a/deps/swc/crates/swc_ecma_transforms_react/src/jsx_self/mod.rs +++ b/deps/swc/crates/swc_ecma_transforms_react/src/jsx_self/mod.rs @@ -12,7 +12,7 @@ mod tests; pub fn hook(dev: bool) -> impl VisitMutHook<()> { JsxSelf { dev, - ctx_stack: vec![Context::default()], + ctx: JsxSelfCtx::new(), } } @@ -23,28 +23,76 @@ struct Context { in_derived_class: bool, } -struct JsxSelf { - dev: bool, +/// Tracks when JSXDEV can safely use `this` for the self argument. +/// +/// This mirrors Babel's `transform-react-jsx-self` constructor guard. Arrow +/// functions keep the surrounding `this`, so they intentionally do not enter a +/// new context. +pub(crate) struct JsxSelfCtx { ctx_stack: Vec, } -impl JsxSelf { - fn current_ctx(&self) -> Context { +impl JsxSelfCtx { + pub(crate) fn new() -> Self { + Self { + ctx_stack: vec![Context::default()], + } + } + + fn current(&self) -> Context { *self .ctx_stack .last() .expect("context stack should never be empty") } - fn push_ctx(&mut self, ctx: Context) { + fn push(&mut self, ctx: Context) { self.ctx_stack.push(ctx); } - fn pop_ctx(&mut self) { + pub(crate) fn pop(&mut self) { if self.ctx_stack.len() > 1 { self.ctx_stack.pop(); } } + + pub(crate) fn enter_class(&mut self, class: &Class) { + let mut new_ctx = self.current(); + new_ctx.in_derived_class = class.super_class.is_some(); + self.push(new_ctx); + } + + pub(crate) fn enter_constructor(&mut self) { + let mut new_ctx = self.current(); + new_ctx.in_constructor = true; + self.push(new_ctx); + } + + /// Enter a function-like scope where `this` is no longer the current + /// constructor's uninitialized `this`. + pub(crate) fn enter_non_constructor_scope(&mut self) { + let mut new_ctx = self.current(); + new_ctx.in_constructor = false; + self.push(new_ctx); + } + + /// Return whether a JSXDEV call can safely use `this` for the self + /// argument. + pub(crate) fn can_add_self(&self) -> bool { + let ctx = self.current(); + !(ctx.in_constructor && ctx.in_derived_class) + } +} + +impl Default for JsxSelfCtx { + fn default() -> Self { + Self::new() + } +} + +struct JsxSelf { + dev: bool, + ctx: JsxSelfCtx, } // For tests @@ -61,103 +109,83 @@ fn jsx_self(dev: bool) -> impl Pass { impl VisitMutHook<()> for JsxSelf { fn enter_class(&mut self, n: &mut Class, _ctx: &mut ()) { - let mut new_ctx = self.current_ctx(); - new_ctx.in_derived_class = n.super_class.is_some(); - self.push_ctx(new_ctx); + self.ctx.enter_class(n); } fn exit_class(&mut self, _n: &mut Class, _ctx: &mut ()) { - self.pop_ctx(); + self.ctx.pop(); } fn enter_fn_decl(&mut self, _n: &mut FnDecl, _ctx: &mut ()) { - let mut new_ctx = self.current_ctx(); - new_ctx.in_constructor = false; - self.push_ctx(new_ctx); + self.ctx.enter_non_constructor_scope(); } fn exit_fn_decl(&mut self, _n: &mut FnDecl, _ctx: &mut ()) { - self.pop_ctx(); + self.ctx.pop(); } fn enter_fn_expr(&mut self, _n: &mut FnExpr, _ctx: &mut ()) { - let mut new_ctx = self.current_ctx(); - new_ctx.in_constructor = false; - self.push_ctx(new_ctx); + self.ctx.enter_non_constructor_scope(); } fn exit_fn_expr(&mut self, _n: &mut FnExpr, _ctx: &mut ()) { - self.pop_ctx(); + self.ctx.pop(); } fn enter_getter_prop(&mut self, _n: &mut GetterProp, _ctx: &mut ()) { - let mut new_ctx = self.current_ctx(); - new_ctx.in_constructor = false; - self.push_ctx(new_ctx); + self.ctx.enter_non_constructor_scope(); } fn exit_getter_prop(&mut self, _n: &mut GetterProp, _ctx: &mut ()) { - self.pop_ctx(); + self.ctx.pop(); } fn enter_setter_prop(&mut self, _n: &mut SetterProp, _ctx: &mut ()) { - let mut new_ctx = self.current_ctx(); - new_ctx.in_constructor = false; - self.push_ctx(new_ctx); + self.ctx.enter_non_constructor_scope(); } fn exit_setter_prop(&mut self, _n: &mut SetterProp, _ctx: &mut ()) { - self.pop_ctx(); + self.ctx.pop(); } fn enter_method_prop(&mut self, _n: &mut MethodProp, _ctx: &mut ()) { - let mut new_ctx = self.current_ctx(); - new_ctx.in_constructor = false; - self.push_ctx(new_ctx); + self.ctx.enter_non_constructor_scope(); } fn exit_method_prop(&mut self, _n: &mut MethodProp, _ctx: &mut ()) { - self.pop_ctx(); + self.ctx.pop(); } fn enter_constructor(&mut self, _n: &mut Constructor, _ctx: &mut ()) { - let mut new_ctx = self.current_ctx(); - new_ctx.in_constructor = true; - self.push_ctx(new_ctx); + self.ctx.enter_constructor(); } fn exit_constructor(&mut self, _n: &mut Constructor, _ctx: &mut ()) { - self.pop_ctx(); + self.ctx.pop(); } fn enter_class_method(&mut self, _n: &mut ClassMethod, _ctx: &mut ()) { - let mut new_ctx = self.current_ctx(); - new_ctx.in_constructor = false; - self.push_ctx(new_ctx); + self.ctx.enter_non_constructor_scope(); } fn exit_class_method(&mut self, _n: &mut ClassMethod, _ctx: &mut ()) { - self.pop_ctx(); + self.ctx.pop(); } fn enter_private_method(&mut self, _n: &mut PrivateMethod, _ctx: &mut ()) { - let mut new_ctx = self.current_ctx(); - new_ctx.in_constructor = false; - self.push_ctx(new_ctx); + self.ctx.enter_non_constructor_scope(); } fn exit_private_method(&mut self, _n: &mut PrivateMethod, _ctx: &mut ()) { - self.pop_ctx(); + self.ctx.pop(); } fn enter_static_block(&mut self, _n: &mut StaticBlock, _ctx: &mut ()) { - let mut new_ctx = self.current_ctx(); - new_ctx.in_constructor = false; - self.push_ctx(new_ctx); + self.ctx.enter_non_constructor_scope(); } fn exit_static_block(&mut self, _n: &mut StaticBlock, _ctx: &mut ()) { - self.pop_ctx(); + self.ctx.pop(); } fn enter_jsx_opening_element(&mut self, n: &mut JSXOpeningElement, _ctx: &mut ()) { @@ -165,10 +193,8 @@ impl VisitMutHook<()> for JsxSelf { return; } - let ctx = self.current_ctx(); - // https://github.com/babel/babel/blob/1bdb1a4175ed1fc40751fb84dc4ad1900260f28f/packages/babel-plugin-transform-react-jsx-self/src/index.ts#L50 - if ctx.in_constructor && ctx.in_derived_class { + if !self.ctx.can_add_self() { return; } diff --git a/deps/swc/crates/swc_ecma_transforms_testing/Cargo.toml b/deps/swc/crates/swc_ecma_transforms_testing/Cargo.toml index 0c69c3bd7..7d5a44d42 100644 --- a/deps/swc/crates/swc_ecma_transforms_testing/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transforms_testing/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_transforms_testing" repository = { workspace = true } -version = "48.0.0" +version = "51.0.0" [lib] bench = false @@ -19,16 +19,16 @@ hex = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } sha2 = { workspace = true } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "sourcemap", ] } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_testing = { version = "24.0.1", path = "../swc_ecma_testing" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_testing = { version = "25.0.0", path = "../swc_ecma_testing" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } swc_sourcemap = { workspace = true } tempfile = { workspace = true } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_ecma_transforms_typescript/Cargo.toml b/deps/swc/crates/swc_ecma_transforms_typescript/Cargo.toml index 502fec69c..2c33ea1fe 100644 --- a/deps/swc/crates/swc_ecma_transforms_typescript/Cargo.toml +++ b/deps/swc/crates/swc_ecma_transforms_typescript/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "examples/**/*.rs"] license = { workspace = true } name = "swc_ecma_transforms_typescript" repository = { workspace = true } -version = "50.0.0" +version = "53.0.0" [lib] bench = false @@ -24,24 +24,24 @@ bytes-str = { workspace = true } rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_react = { version = "50.0.0", path = "../swc_ecma_transforms_react" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_react = { version = "53.0.0", path = "../swc_ecma_transforms_react" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] codspeed-criterion-compat = { workspace = true } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } serde_json = { workspace = true } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", features = ["flow"] } -swc_ecma_transforms_compat = { version = "52.0.1", path = "../swc_ecma_transforms_compat" } -swc_ecma_transforms_proposal = { version = "44.0.1", path = "../swc_ecma_transforms_proposal" } -swc_ecma_transforms_testing = { version = "48.0.0", path = "../swc_ecma_transforms_testing" } -testing = { version = "24.0.1", path = "../testing" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", features = ["flow"] } +swc_ecma_transforms_compat = { version = "55.0.0", path = "../swc_ecma_transforms_compat" } +swc_ecma_transforms_proposal = { version = "47.0.0", path = "../swc_ecma_transforms_proposal" } +swc_ecma_transforms_testing = { version = "51.0.0", path = "../swc_ecma_transforms_testing" } +testing = { version = "25.0.0", path = "../testing" } [[bench]] harness = false diff --git a/deps/swc/crates/swc_ecma_transforms_typescript/src/semantic.rs b/deps/swc/crates/swc_ecma_transforms_typescript/src/semantic.rs index 20c105e43..8d0e138c7 100644 --- a/deps/swc/crates/swc_ecma_transforms_typescript/src/semantic.rs +++ b/deps/swc/crates/swc_ecma_transforms_typescript/src/semantic.rs @@ -6,7 +6,7 @@ use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; use crate::{ retain::{should_retain_decl, IsConcrete}, - shared::{enum_member_id_atom, get_module_ident}, + shared::{enum_member_name, get_module_ident}, ts_enum::{EnumValueComputer, TsEnumRecord, TsEnumRecordKey, TsEnumRecordValue}, }; @@ -277,7 +277,7 @@ impl SemanticAnalyzer { // name as the runtime string value. The AST does not retain // the explicit `of string` kind, so `Void` acts as the // sentinel for Flow's default string mode here. - TsEnumRecordValue::String(enum_member_id_atom(&member.id)) + TsEnumRecordValue::String(enum_member_name(&member.id)) } else { default_init.clone() } @@ -572,7 +572,7 @@ impl Visit for SemanticAnalyzer { default_init = value.inc(); - let member_name = enum_member_id_atom(&member.id); + let member_name = enum_member_name(&member.id); let key = TsEnumRecordKey { enum_id: id.to_id(), member_name, @@ -670,7 +670,7 @@ mod tests { let value = SemanticAnalyzer::transform_ts_enum_member( enum_member("A"), &id("E"), - &TsEnumRecordValue::Number(2.0.into()), + &TsEnumRecordValue::from(2.0), &Default::default(), SyntaxContext::empty(), false, @@ -679,6 +679,6 @@ mod tests { let TsEnumRecordValue::Number(value) = value else { panic!("expected defaulted TypeScript enum member to stay numeric"); }; - assert_eq!(*value, 2.0); + assert_eq!(value.value, 2.0); } } diff --git a/deps/swc/crates/swc_ecma_transforms_typescript/src/shared.rs b/deps/swc/crates/swc_ecma_transforms_typescript/src/shared.rs index eee9ddab1..2079b1621 100644 --- a/deps/swc/crates/swc_ecma_transforms_typescript/src/shared.rs +++ b/deps/swc/crates/swc_ecma_transforms_typescript/src/shared.rs @@ -1,12 +1,12 @@ -use swc_atoms::Atom; +use swc_atoms::Wtf8Atom; use swc_ecma_ast::{Ident, TsEntityName, TsEnumMemberId}; -/// Returns enum member key as an atom for record lookup. +/// Returns an enum member name without discarding lone surrogates. #[inline] -pub(crate) fn enum_member_id_atom(id: &TsEnumMemberId) -> Atom { +pub(crate) fn enum_member_name(id: &TsEnumMemberId) -> Wtf8Atom { match id { - TsEnumMemberId::Ident(ident) => ident.sym.clone(), - TsEnumMemberId::Str(str_lit) => str_lit.value.to_atom_lossy().into_owned(), + TsEnumMemberId::Ident(ident) => ident.sym.clone().into(), + TsEnumMemberId::Str(str_lit) => str_lit.value.clone(), #[cfg(swc_ast_unknown)] _ => panic!("unable to access unknown nodes"), } diff --git a/deps/swc/crates/swc_ecma_transforms_typescript/src/transform.rs b/deps/swc/crates/swc_ecma_transforms_typescript/src/transform.rs index 570c46d8d..0f530f21b 100644 --- a/deps/swc/crates/swc_ecma_transforms_typescript/src/transform.rs +++ b/deps/swc/crates/swc_ecma_transforms_typescript/src/transform.rs @@ -1,7 +1,7 @@ -use std::{iter, mem}; +use std::{borrow::Borrow, iter, mem}; use rustc_hash::{FxHashMap, FxHashSet}; -use swc_atoms::Atom; +use swc_atoms::{Atom, Wtf8Atom}; use swc_common::{ errors::HANDLER, source_map::PURE_SP, util::take::Take, Mark, Span, Spanned, SyntaxContext, DUMMY_SP, @@ -21,8 +21,8 @@ use crate::{ config::TsImportExportAssignConfig, retain::{should_retain_module_item, should_retain_stmt}, semantic::SemanticInfo, - shared::enum_member_id_atom, - ts_enum::{EnumValueComputer, TsEnumRecordKey, TsEnumRecordValue}, + shared::enum_member_name, + ts_enum::{static_enum_member_name, EnumValueComputer, TsEnumRecordKey, TsEnumRecordValue}, utils::{assign_value_to_this_private_prop, assign_value_to_this_prop, Factory}, }; @@ -1118,7 +1118,7 @@ impl Transform { .into_iter() .map(|m| { let span = m.span; - let name = enum_member_id_atom(&m.id); + let name = enum_member_name(&m.id); let key = TsEnumRecordKey { enum_id: id.to_id(), @@ -1643,7 +1643,7 @@ impl Transform { return; } - let Some(member_name) = get_member_key(prop) else { + let Some(member_name) = static_enum_member_name(prop) else { return; }; @@ -1901,13 +1901,13 @@ impl QueryRef for ExportQuery { struct EnumMemberRefQuery<'a> { enum_id: &'a Id, - member_names: &'a FxHashSet, + member_names: &'a FxHashSet, unresolved_ctxt: SyntaxContext, } impl QueryRef for EnumMemberRefQuery<'_> { fn query_ref(&self, ident: &Ident) -> Option> { - if ident.ctxt == self.unresolved_ctxt && self.member_names.contains(&ident.sym) { + if ident.ctxt == self.unresolved_ctxt && self.member_names.contains(ident.sym.borrow()) { Some( self.enum_id .clone() @@ -1924,7 +1924,7 @@ impl QueryRef for EnumMemberRefQuery<'_> { } fn query_jsx(&self, ident: &Ident) -> Option { - if ident.ctxt == self.unresolved_ctxt && self.member_names.contains(&ident.sym) { + if ident.ctxt == self.unresolved_ctxt && self.member_names.contains(ident.sym.borrow()) { Some( JSXMemberExpr { span: DUMMY_SP, @@ -1941,7 +1941,7 @@ impl QueryRef for EnumMemberRefQuery<'_> { struct EnumMemberItem { span: Span, - name: Atom, + name: Wtf8Atom, value: TsEnumRecordValue, } @@ -1953,20 +1953,19 @@ impl EnumMemberItem { fn build_assign(self, enum_id: &Id) -> Stmt { let is_string = self.value.is_string(); let value: Expr = self.value.into(); + let name: Expr = Str::from(self.name).into(); let inner_assign = value.make_assign_to( op!("="), Ident::from(enum_id.clone()) - .computed_member(self.name.clone()) + .computed_member(name.clone()) .into(), ); let outer_assign = if is_string { inner_assign } else { - let value: Expr = self.name.clone().into(); - - value.make_assign_to( + name.make_assign_to( op!("="), Ident::from(enum_id.clone()) .computed_member(inner_assign) @@ -2010,24 +2009,3 @@ fn get_enum_id(e: &Expr) -> Option { None } } - -fn get_member_key(prop: &MemberProp) -> Option { - match prop { - MemberProp::Ident(ident) => Some(ident.sym.clone()), - MemberProp::Computed(ComputedPropName { expr, .. }) => match &**expr { - Expr::Lit(Lit::Str(Str { value, .. })) => Some(value.to_atom_lossy().into_owned()), - Expr::Tpl(Tpl { exprs, quasis, .. }) => match (exprs.len(), quasis.len()) { - (0, 1) => quasis[0] - .cooked - .as_ref() - .map(|cooked| cooked.to_atom_lossy().into_owned()) - .or_else(|| Some(quasis[0].raw.clone())), - _ => None, - }, - _ => None, - }, - MemberProp::PrivateName(_) => None, - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - } -} diff --git a/deps/swc/crates/swc_ecma_transforms_typescript/src/ts_enum.rs b/deps/swc/crates/swc_ecma_transforms_typescript/src/ts_enum.rs index 6da0c929d..a05ef5139 100644 --- a/deps/swc/crates/swc_ecma_transforms_typescript/src/ts_enum.rs +++ b/deps/swc/crates/swc_ecma_transforms_typescript/src/ts_enum.rs @@ -1,5 +1,5 @@ use rustc_hash::FxHashMap; -use swc_atoms::{atom, Atom, Wtf8Atom}; +use swc_atoms::{wtf8::Wtf8Buf, Atom, Wtf8Atom}; use swc_common::{SyntaxContext, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_utils::{ @@ -7,34 +7,45 @@ use swc_ecma_utils::{ ExprFactory, }; -#[inline] -fn atom_from_wtf8_atom(value: &Wtf8Atom) -> Atom { - value - .as_str() - .map(Atom::from) - .unwrap_or_else(|| Atom::from(value.to_string_lossy())) -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct TsEnumRecordKey { pub enum_id: Id, - pub member_name: Atom, + pub member_name: Wtf8Atom, } pub(crate) type TsEnumRecord = FxHashMap; #[derive(Debug, Clone)] pub(crate) enum TsEnumRecordValue { - String(Atom), - Number(JsNumber), + String(Wtf8Atom), + Number(Number), Opaque(Box), Void, } impl TsEnumRecordValue { + /// Creates a computed number. Computations intentionally discard source + /// spelling so code generation can choose the canonical representation. + fn number(value: impl Into) -> Self { + Self::Number(Number { + span: DUMMY_SP, + value: value.into(), + raw: None, + }) + } + + /// Creates a number converted directly from an AST value. + fn converted_number(value: impl Into, raw: Option) -> Self { + Self::Number(Number { + span: DUMMY_SP, + value: value.into(), + raw, + }) + } + pub fn inc(&self) -> Self { match self { - Self::Number(num) => Self::Number((**num + 1.0).into()), + Self::Number(num) => Self::number(num.value + 1.0), _ => Self::Void, } } @@ -53,43 +64,23 @@ impl TsEnumRecordValue { pub fn has_value(&self) -> bool { !matches!(self, TsEnumRecordValue::Void) } + + fn push_to_string(&self, output: &mut Wtf8Buf) -> bool { + match self { + Self::String(value) => output.push_wtf8(value), + Self::Number(value) => output.push_str(&value.value.to_js_string()), + Self::Opaque(_) | Self::Void => return false, + } + + true + } } impl From for Expr { fn from(value: TsEnumRecordValue) -> Self { match value { TsEnumRecordValue::String(string) => Lit::Str(string.into()).into(), - TsEnumRecordValue::Number(num) if num.is_nan() => Ident { - span: DUMMY_SP, - sym: atom!("NaN"), - ..Default::default() - } - .into(), - TsEnumRecordValue::Number(num) if num.is_infinite() => { - let value: Expr = Ident { - span: DUMMY_SP, - sym: atom!("Infinity"), - ..Default::default() - } - .into(); - - if num.is_sign_negative() { - UnaryExpr { - span: DUMMY_SP, - op: op!(unary, "-"), - arg: value.into(), - } - .into() - } else { - value - } - } - TsEnumRecordValue::Number(num) => Lit::Num(Number { - span: DUMMY_SP, - value: *num, - raw: None, - }) - .into(), + TsEnumRecordValue::Number(num) => Lit::Num(num).into(), TsEnumRecordValue::Void => *Expr::undefined(DUMMY_SP), TsEnumRecordValue::Opaque(expr) => *expr, } @@ -98,7 +89,7 @@ impl From for Expr { impl From for TsEnumRecordValue { fn from(value: f64) -> Self { - Self::Number(value.into()) + Self::number(value) } } @@ -108,6 +99,24 @@ pub(crate) struct EnumValueComputer<'a> { pub record: &'a TsEnumRecord, } +/// Returns a statically known enum member key without discarding lone +/// surrogates. +pub(crate) fn static_enum_member_name(property: &MemberProp) -> Option { + match property { + MemberProp::Ident(ident) => Some(ident.sym.clone().into()), + MemberProp::Computed(ComputedPropName { expr, .. }) => match &**expr { + Expr::Lit(Lit::Str(string)) => Some(string.value.clone()), + Expr::Tpl(template) if template.exprs.is_empty() && template.quasis.len() == 1 => { + template.quasis[0].cooked.clone() + } + _ => None, + }, + MemberProp::PrivateName(_) => None, + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), + } +} + /// https://github.com/microsoft/TypeScript/pull/50528 impl EnumValueComputer<'_> { pub fn compute(&self, expr: Box) -> TsEnumRecordValue { @@ -116,12 +125,12 @@ impl EnumValueComputer<'_> { fn compute_rec(&self, expr: Box) -> TsEnumRecordValue { match *expr { - Expr::Lit(Lit::Str(s)) => TsEnumRecordValue::String(atom_from_wtf8_atom(&s.value)), - Expr::Lit(Lit::Num(n)) => TsEnumRecordValue::Number(n.value.into()), + Expr::Lit(Lit::Str(s)) => TsEnumRecordValue::String(s.value), + Expr::Lit(Lit::Num(n)) => TsEnumRecordValue::Number(n), Expr::Ident(ref ident) if ident.ctxt == self.unresolved_ctxt => { if let Some(value) = self.record.get(&TsEnumRecordKey { enum_id: self.enum_id.clone(), - member_name: ident.sym.clone(), + member_name: ident.sym.clone().into(), }) { if value.is_const() { value.clone() @@ -135,8 +144,13 @@ impl EnumValueComputer<'_> { } } else { match ident.sym.as_ref() { - "Infinity" => TsEnumRecordValue::Number(f64::INFINITY.into()), - "NaN" => TsEnumRecordValue::Number(f64::NAN.into()), + "Infinity" => TsEnumRecordValue::converted_number( + f64::INFINITY, + Some(ident.sym.clone()), + ), + "NaN" => { + TsEnumRecordValue::converted_number(f64::NAN, Some(ident.sym.clone())) + } _ => TsEnumRecordValue::Opaque(expr), } } @@ -177,9 +191,9 @@ impl EnumValueComputer<'_> { }; match expr.op { - op!(unary, "+") => TsEnumRecordValue::Number(num), - op!(unary, "-") => TsEnumRecordValue::Number(-num), - op!("~") => TsEnumRecordValue::Number(!num), + op!(unary, "+") => TsEnumRecordValue::number(num.value), + op!(unary, "-") => TsEnumRecordValue::number(-num.value), + op!("~") => TsEnumRecordValue::number(!JsNumber::from(num.value)), _ => unreachable!(), } } @@ -207,8 +221,18 @@ impl EnumValueComputer<'_> { let left = self.compute_rec(expr.left); let right = self.compute_rec(expr.right); + if expr.op == BinaryOp::Add && (left.is_string() || right.is_string()) { + let mut value = Wtf8Buf::new(); + + if left.push_to_string(&mut value) && right.push_to_string(&mut value) { + return TsEnumRecordValue::String(Wtf8Atom::from(&*value)); + } + } + match (left, right, expr.op) { (TsEnumRecordValue::Number(left), TsEnumRecordValue::Number(right), op) => { + let left = JsNumber::from(left.value); + let right = JsNumber::from(right.value); let value = match op { op!(bin, "+") => left + right, op!(bin, "-") => left - right, @@ -225,20 +249,7 @@ impl EnumValueComputer<'_> { _ => unreachable!(), }; - TsEnumRecordValue::Number(value) - } - (TsEnumRecordValue::String(left), TsEnumRecordValue::String(right), op!(bin, "+")) => { - TsEnumRecordValue::String(format!("{left}{right}").into()) - } - (TsEnumRecordValue::Number(left), TsEnumRecordValue::String(right), op!(bin, "+")) => { - let left = left.to_js_string(); - - TsEnumRecordValue::String(format!("{left}{right}").into()) - } - (TsEnumRecordValue::String(left), TsEnumRecordValue::Number(right), op!(bin, "+")) => { - let right = right.to_js_string(); - - TsEnumRecordValue::String(format!("{left}{right}").into()) + TsEnumRecordValue::number(value) } (left, right, _) => { let mut origin_expr = origin_expr; @@ -257,22 +268,10 @@ impl EnumValueComputer<'_> { } fn compute_member(&self, expr: MemberExpr) -> TsEnumRecordValue { - if matches!(expr.prop, MemberProp::PrivateName(..)) { - return TsEnumRecordValue::Opaque(expr.into()); - } - let opaque_expr = TsEnumRecordValue::Opaque(expr.clone().into()); - let member_name = match expr.prop { - MemberProp::Ident(ident) => ident.sym, - MemberProp::Computed(ComputedPropName { expr, .. }) => { - let Expr::Lit(Lit::Str(s)) = *expr else { - return opaque_expr; - }; - - atom_from_wtf8_atom(&s.value) - } - _ => return opaque_expr, + let Some(member_name) = static_enum_member_name(&expr.prop) else { + return opaque_expr; }; let Expr::Ident(ident) = *expr.obj else { @@ -296,23 +295,27 @@ impl EnumValueComputer<'_> { let mut quasis_iter = quasis.into_iter(); - let Some(mut string) = quasis_iter.next().map(|q| q.raw.to_string()) else { + let Some(first_quasi) = quasis_iter.next() else { return opaque_expr; }; + let Some(first_cooked) = first_quasi.cooked.as_ref() else { + return opaque_expr; + }; + let mut string = Wtf8Buf::from(first_cooked); for (q, expr) in quasis_iter.zip(exprs) { let expr = self.compute_rec(expr); - let expr = match expr { - TsEnumRecordValue::String(s) => s.to_string(), - TsEnumRecordValue::Number(n) => n.to_js_string(), - _ => return opaque_expr, + if !expr.push_to_string(&mut string) { + return opaque_expr; + } + let Some(cooked) = q.cooked.as_ref() else { + return opaque_expr; }; - string.push_str(&expr); - string.push_str(&q.raw); + string.push_wtf8(cooked); } - TsEnumRecordValue::String(string.into()) + TsEnumRecordValue::String(Wtf8Atom::from(&*string)) } } diff --git a/deps/swc/crates/swc_ecma_utils/Cargo.toml b/deps/swc/crates/swc_ecma_utils/Cargo.toml index b28c2f777..e41bedecd 100644 --- a/deps/swc/crates/swc_ecma_utils/Cargo.toml +++ b/deps/swc/crates/swc_ecma_utils/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_utils" repository = { workspace = true } -version = "31.0.1" +version = "33.0.0" [package.metadata.docs.rs] all-features = true @@ -31,14 +31,14 @@ par-core = { workspace = true } rustc-hash = { workspace = true } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [target.'cfg(not(any(target_arch = "wasm32", target_arch = "arm")))'.dependencies] stacker = { version = "0.1.15", optional = true } [dev-dependencies] par-core = { workspace = true, features = ["chili"] } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } diff --git a/deps/swc/crates/swc_ecma_utils/src/lib.rs b/deps/swc/crates/swc_ecma_utils/src/lib.rs index 4c3b6f703..98da04c95 100644 --- a/deps/swc/crates/swc_ecma_utils/src/lib.rs +++ b/deps/swc/crates/swc_ecma_utils/src/lib.rs @@ -499,6 +499,7 @@ pub trait StmtExt { allow_break: bool, allow_throw: bool, ) -> Result { + // println!("2222 {in_switch} {allow_break} {:#?}", stmt); Ok(match stmt { Stmt::Break(_) => { if in_switch { @@ -542,7 +543,16 @@ pub trait StmtExt { let mut has_default = false; let mut has_non_empty_terminates = false; - for case in &s.cases { + // last case empty or no case at all + if s.cases + .last() + .map(|case| case.cons.is_empty()) + .unwrap_or(true) + { + return Ok(false); + } + + for case in s.cases.iter().rev() { if case.test.is_none() { has_default = true } @@ -1172,7 +1182,9 @@ impl Visit for LiteralVisitor { } fn visit_number(&mut self, node: &Number) { - if !self.allow_non_json_value && node.value.is_infinite() { + // JSON number syntax can express infinities as overflowed values such + // as `2e308`, but it has no representation that parses to `NaN`. + if !self.allow_non_json_value && node.value.is_nan() { self.is_lit = false; } } @@ -2051,7 +2063,7 @@ pub fn prop_name_eq(p: &PropName, key: &str) -> bool { match p { PropName::Ident(i) => i.sym == *key, PropName::Str(s) => s.value == *key, - PropName::Num(n) => n.value.to_string() == *key, + PropName::Num(n) => n.value.to_js_string() == *key, PropName::BigInt(_) => false, PropName::Computed(e) => match &*e.expr { Expr::Lit(Lit::Str(Str { value, .. })) => *value == *key, @@ -2298,6 +2310,10 @@ impl Visit for TopLevelAwait { key: PropName::Computed(computed), .. }) => computed.visit_children_with(self), + ClassMember::AutoAccessor(AutoAccessor { + key: Key::Public(PropName::Computed(computed)), + .. + }) => computed.visit_children_with(self), _ => (), }; } @@ -2306,9 +2322,16 @@ impl Visit for TopLevelAwait { match prop { Prop::KeyValue(KeyValueProp { key: PropName::Computed(computed), + value, .. - }) - | Prop::Getter(GetterProp { + }) => { + computed.visit_children_with(self); + value.visit_with(self); + } + Prop::KeyValue(KeyValueProp { value, .. }) | Prop::Assign(AssignProp { value, .. }) => { + value.visit_with(self); + } + Prop::Getter(GetterProp { key: PropName::Computed(computed), .. }) @@ -2740,8 +2763,10 @@ fn is_array_lit(expr: &Expr) -> bool { } fn is_nan(expr: &Expr) -> bool { - // NaN is special - expr.is_ident_ref_to("NaN") + match expr { + Expr::Lit(Lit::Num(number)) => number.value.is_nan(), + _ => expr.is_ident_ref_to("NaN"), + } } fn is_undefined(expr: &Expr, ctx: ExprCtx) -> bool { @@ -2779,20 +2804,26 @@ fn as_pure_bool(expr: &Expr, ctx: ExprCtx) -> BoolValue { } } +/// Returns whether a number is truthy according to ECMAScript semantics. +#[inline] +fn is_truthy_number(value: f64) -> bool { + !matches!(value.classify(), FpCategory::Nan | FpCategory::Zero) +} + fn cast_to_bool(expr: &Expr, ctx: ExprCtx) -> (Purity, BoolValue) { let Some(ctx) = ctx.consume_depth() else { return (MayBeImpure, Unknown); }; if let Expr::Ident(i) = expr { - if &*i.sym == "NaN" { - return (Pure, Known(false)); - } - if i.ctxt != ctx.unresolved_ctxt { return (Pure, Unknown); } + if &*i.sym == "NaN" { + return (Pure, Known(false)); + } + if &*i.sym == "undefined" { return (Pure, Known(false)); } @@ -2848,7 +2879,7 @@ fn cast_to_bool(expr: &Expr, ctx: ExprCtx) -> (Purity, BoolValue) { }) => { let v = arg.as_pure_number(ctx); match v { - Known(n) => Known(!matches!(n.classify(), FpCategory::Nan | FpCategory::Zero)), + Known(n) => Known(is_truthy_number(-n)), Unknown => return (MayBeImpure, Unknown), } } @@ -2875,13 +2906,7 @@ fn cast_to_bool(expr: &Expr, ctx: ExprCtx) -> (Purity, BoolValue) { return ( lp + rp, match (ln, rn) { - (Known(ln), Known(rn)) => { - if ln == rn { - Known(false) - } else { - Known(true) - } - } + (Known(ln), Known(rn)) => Known(is_truthy_number(ln - rn)), _ => Unknown, }, ); @@ -2898,17 +2923,7 @@ fn cast_to_bool(expr: &Expr, ctx: ExprCtx) -> (Purity, BoolValue) { match (lv, rv) { (Known(lv), Known(rv)) => { - // NaN is false - if lv == 0.0 && rv == 0.0 { - return (Pure, Known(false)); - } - // Infinity is true. - if rv == 0.0 { - return (Pure, Known(true)); - } - let v = lv / rv; - - return (Pure, Known(v != 0.0)); + return (Pure, Known(is_truthy_number(lv / rv))); } _ => Unknown, } @@ -3017,9 +3032,7 @@ fn cast_to_bool(expr: &Expr, ctx: ExprCtx) -> (Purity, BoolValue) { return ( Pure, Known(match *lit { - Lit::Num(Number { value: n, .. }) => { - !matches!(n.classify(), FpCategory::Nan | FpCategory::Zero) - } + Lit::Num(Number { value: n, .. }) => is_truthy_number(n), Lit::BigInt(ref v) => v .value .to_string() @@ -3818,13 +3831,44 @@ pub fn prop_name_from_ident(ident: Ident) -> PropName { } } +pub fn prop_name_from_str(span: Span, s: &str) -> PropName { + if s == "__proto__" { + PropName::Computed(ComputedPropName { + span: DUMMY_SP, + expr: Box::new(Expr::Lit(Lit::Str(Str { + span, + value: s.into(), + raw: None, + }))), + }) + } else if is_valid_prop_ident(s) { + PropName::Ident(IdentName { + span, + sym: s.into(), + }) + } else { + PropName::Str(quote_str!(span, s)) + } +} + #[cfg(test)] mod tests { - use swc_common::{input::StringInput, BytePos}; + use swc_common::{input::StringInput, BytePos, DUMMY_SP}; use swc_ecma_parser::{Parser, Syntax}; use super::*; + #[test] + fn number_literal_nan_is_recognized() { + let expr = Expr::Lit(Lit::Num(Number { + span: DUMMY_SP, + value: f64::NAN, + raw: None, + })); + + assert!(expr.is_nan()); + } + #[test] fn test_collect_decls() { run_collect_decls( @@ -3890,11 +3934,83 @@ mod tests { assert!(has_top_level_await("for await (let iter of []){}")) } + #[test] + fn top_level_await_object_property() { + assert!(has_top_level_await("const obj = { value: await test };")); + assert!(has_top_level_await("const obj = { [await key]: value };")); + assert!(!has_top_level_await( + "const obj = { async method() { await test; } };" + )); + } + + #[test] + fn top_level_await_class() { + assert!(has_top_level_await("class C extends (await base) {}")); + assert!(has_top_level_await("class C { [await key]() {} }")); + assert!(!has_top_level_await( + "class C { async method() { await test; } }" + )); + } + + #[test] + fn nested_await_is_not_top_level_await() { + assert!(!has_top_level_await("const f = async () => await test;")); + } + #[test] fn top_level_export_await() { assert!(has_top_level_await("export const foo = await 1;")); assert!(has_top_level_await("export default await 1;")); } + + #[test] + fn switch_default_before_empty_case_does_not_terminate() { + assert!(!stmt_in_function_terminates( + r#" +switch (foo) { + default: + return 1; + case "0": +} +"# + )); + } + + #[test] + fn switch_empty_case_before_default_terminates() { + assert!(stmt_in_function_terminates( + r#" +switch (foo) { + case "0": + default: + return 1; +} +"# + )); + } + + #[test] + fn switch_non_terminating_case_falls_through_to_terminating_case() { + assert!(!stmt_in_function_terminates( + r#" +switch (foo) { + case "0": + foo(); + default: + return 1; +} +"# + )); + } + + fn stmt_in_function_terminates(text: &str) -> bool { + let module = parse_module(&format!("function f() {{ {text} }}")); + let ModuleItem::Stmt(Stmt::Decl(Decl::Fn(f))) = &module.body[0] else { + unreachable!("expected a function declaration") + }; + let body = f.function.body.as_ref().unwrap(); + body.stmts[0].terminates() + } } #[cfg(test)] diff --git a/deps/swc/crates/swc_ecma_utils/src/number.rs b/deps/swc/crates/swc_ecma_utils/src/number.rs index d3c47b8a9..ca604d315 100644 --- a/deps/swc/crates/swc_ecma_utils/src/number.rs +++ b/deps/swc/crates/swc_ecma_utils/src/number.rs @@ -10,6 +10,25 @@ impl ToJsString for f64 { } } +/// Parses the canonical non-negative decimal representation of a `usize`. +/// +/// This does not apply numeric coercion, so distinct ECMAScript property keys +/// such as `"01"`, `"1.0"`, and `"+1"` are not reinterpreted as the index `1`. +pub fn parse_canonical_index(property_key: &str) -> Option { + let bytes = property_key.as_bytes(); + let is_canonical = match bytes { + [b'0'] => true, + [b'1'..=b'9', rest @ ..] => rest.iter().all(u8::is_ascii_digit), + _ => false, + }; + + if !is_canonical { + return None; + } + + property_key.parse().ok() +} + #[derive(Debug, Clone, Copy, PartialEq)] pub struct JsNumber(f64); @@ -34,6 +53,13 @@ impl std::ops::Deref for JsNumber { } impl JsNumber { + /// Applies ECMAScript `ToUint16` conversion. + /// + /// + pub fn to_uint16(self) -> u16 { + self.as_uint32() as u16 + } + // https://tc39.es/ecma262/#sec-toint32 fn as_int32(&self) -> i32 { self.as_uint32() as i32 @@ -188,10 +214,93 @@ impl std::ops::Not for JsNumber { } } +fn clz(s: &str) -> usize { + s.as_bytes().iter().take_while(|&&c| c == b'0').count() +} + +pub fn minify_number(num: f64, detect_dot: &mut bool) -> String { + // ddddd -> 0xhhhh + // len(0xhhhh) == len(ddddd) + // 10000000 <= num <= 0xffffff + 'hex: { + if num.fract() == 0.0 && num.abs() <= u64::MAX as f64 { + let int = num.abs() as u64; + + if int < 10000000 { + break 'hex; + } + + // use scientific notation + if int % 1000 == 0 { + break 'hex; + } + + *detect_dot = false; + return format!( + "{}{:#x}", + if num.is_sign_negative() { "-" } else { "" }, + int + ); + } + } + + let mut num = num.to_string(); + + if num.contains(".") { + *detect_dot = false; + } + + if let Some(num) = num.strip_prefix("0.") { + let cnt = clz(num); + if cnt > 2 { + return format!("{}e-{}", &num[cnt..], num.len()); + } + return format!(".{num}"); + } + + if let Some(num) = num.strip_prefix("-0.") { + let cnt = clz(num); + if cnt > 2 { + return format!("-{}e-{}", &num[cnt..], num.len()); + } + return format!("-.{num}"); + } + + if num.ends_with("000") { + *detect_dot = false; + + let cnt = num + .as_bytes() + .iter() + .rev() + .skip(3) + .take_while(|&&c| c == b'0') + .count() + + 3; + + num.truncate(num.len() - cnt); + num.push('e'); + num.push_str(&cnt.to_string()); + } + + num +} + #[cfg(test)] mod test_js_number { use super::*; + #[test] + fn test_parse_canonical_index() { + assert_eq!(parse_canonical_index("0"), Some(0)); + assert_eq!(parse_canonical_index("42"), Some(42)); + assert_eq!(parse_canonical_index(""), None); + assert_eq!(parse_canonical_index("01"), None); + assert_eq!(parse_canonical_index("1.0"), None); + assert_eq!(parse_canonical_index("+1"), None); + assert_eq!(parse_canonical_index("-0"), None); + } + #[test] fn test_as_int32() { assert_eq!(JsNumber(f64::NAN).as_int32(), 0); @@ -211,6 +320,20 @@ mod test_js_number { assert_eq!(JsNumber(-8.0).as_uint32(), 4294967288); } + #[test] + fn test_to_uint16() { + assert_eq!(JsNumber(65.9).to_uint16(), 65); + assert_eq!(JsNumber(-1.0).to_uint16(), 65535); + assert_eq!(JsNumber(-65535.9).to_uint16(), 1); + assert_eq!(JsNumber(65536.0).to_uint16(), 0); + assert_eq!(JsNumber(65537.0).to_uint16(), 1); + assert_eq!(JsNumber(f64::NAN).to_uint16(), 0); + assert_eq!(JsNumber(f64::INFINITY).to_uint16(), 0); + assert_eq!(JsNumber(f64::NEG_INFINITY).to_uint16(), 0); + assert_eq!(JsNumber(4294967361.0).to_uint16(), 65); + assert_eq!(JsNumber(-4294967231.0).to_uint16(), 65); + } + #[test] fn test_add() { assert_eq!(JsNumber(1.0) + JsNumber(2.0), JsNumber(3.0)); diff --git a/deps/swc/crates/swc_ecma_visit/Cargo.toml b/deps/swc/crates/swc_ecma_visit/Cargo.toml index 0e7eb802e..f211def2c 100644 --- a/deps/swc/crates/swc_ecma_visit/Cargo.toml +++ b/deps/swc/crates/swc_ecma_visit/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecma_visit" repository = { workspace = true } -version = "25.0.0" +version = "27.0.0" [package.metadata.docs.rs] all-features = true @@ -30,7 +30,7 @@ num-bigint = { workspace = true, features = ["serde"] } serde = { workspace = true, optional = true, features = ["derive"] } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } swc_visit = { version = "2.0.1", path = "../swc_visit" } diff --git a/deps/swc/crates/swc_ecmascript/Cargo.toml b/deps/swc/crates/swc_ecmascript/Cargo.toml index 7268a1ad7..fcd92e6fe 100644 --- a/deps/swc/crates/swc_ecmascript/Cargo.toml +++ b/deps/swc/crates/swc_ecmascript/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ecmascript" repository = { workspace = true } -version = "64.0.0" +version = "68.0.0" [package.metadata.docs.rs] all-features = true @@ -26,7 +26,6 @@ minifier = ["swc_ecma_minifier"] parser = ["swc_ecma_parser"] preset_env = ["swc_ecma_preset_env"] quote = ["swc_ecma_quote"] -rkyv-impl = ["swc_ecma_ast/rkyv-impl"] transforms = ["swc_ecma_transforms"] utils = ["swc_ecma_utils"] visit = ["swc_ecma_visit"] @@ -41,15 +40,15 @@ react = ["swc_ecma_transforms/react"] typescript = ["typescript-parser", "swc_ecma_transforms/typescript"] [dependencies] -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen", optional = true } -swc_ecma_minifier = { version = "56.0.1", path = "../swc_ecma_minifier", optional = true } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", optional = true, default-features = false } -swc_ecma_preset_env = { version = "57.0.0", path = "../swc_ecma_preset_env", optional = true } -swc_ecma_quote = { version = "41.0.0", path = "../swc_ecma_quote", optional = true } -swc_ecma_transforms = { version = "56.0.0", path = "../swc_ecma_transforms", optional = true } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils", optional = true } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit", optional = true } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen", optional = true } +swc_ecma_minifier = { version = "59.0.0", path = "../swc_ecma_minifier", optional = true } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", optional = true, default-features = false } +swc_ecma_preset_env = { version = "61.0.0", path = "../swc_ecma_preset_env", optional = true } +swc_ecma_quote = { version = "43.0.0", path = "../swc_ecma_quote", optional = true } +swc_ecma_transforms = { version = "60.0.0", path = "../swc_ecma_transforms", optional = true } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils", optional = true } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit", optional = true } [dev-dependencies] par-core = { workspace = true, features = ["chili"] } diff --git a/deps/swc/crates/swc_error_reporters/Cargo.toml b/deps/swc/crates/swc_error_reporters/Cargo.toml index be462d8bb..eec554e60 100644 --- a/deps/swc/crates/swc_error_reporters/Cargo.toml +++ b/deps/swc/crates/swc_error_reporters/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_error_reporters" repository = { workspace = true } -version = "25.0.0" +version = "26.0.0" [lib] bench = false @@ -17,6 +17,6 @@ miette = { workspace = true, features = ["fancy-no-syscall"] } once_cell = { workspace = true } serde = { workspace = true } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "concurrent", ] } diff --git a/deps/swc/crates/swc_estree_ast/Cargo.toml b/deps/swc/crates/swc_estree_ast/Cargo.toml index a33ebe46f..0e8ce65e5 100644 --- a/deps/swc/crates/swc_estree_ast/Cargo.toml +++ b/deps/swc/crates/swc_estree_ast/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" license = { workspace = true } name = "swc_estree_ast" repository = "https://github.com/swc-project/swc.git" -version = "23.0.0" +version = "24.0.0" [package.metadata.docs.rs] all-features = true @@ -26,5 +26,5 @@ serde = { workspace = true, features = ["derive"], optional = true } serde_json = { workspace = true } better_scoped_tls = { version = "1.0.1", path = "../better_scoped_tls" } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } diff --git a/deps/swc/crates/swc_estree_compat/Cargo.toml b/deps/swc/crates/swc_estree_compat/Cargo.toml index 52438a4e6..0badfbd54 100644 --- a/deps/swc/crates/swc_estree_compat/Cargo.toml +++ b/deps/swc/crates/swc_estree_compat/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_estree_compat" repository = { workspace = true } -version = "44.0.0" +version = "46.0.0" [package.metadata.docs.rs] all-features = true @@ -26,29 +26,29 @@ copyless = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "sourcemap", "tty-emitter", ] } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } -swc_estree_ast = { version = "23.0.0", path = "../swc_estree_ast" } -swc_node_comments = { version = "24.0.0", path = "../swc_node_comments/" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } +swc_estree_ast = { version = "24.0.0", path = "../swc_estree_ast" } +swc_node_comments = { version = "25.0.0", path = "../swc_node_comments/" } [dev-dependencies] codspeed-criterion-compat = { workspace = true } pretty_assertions = { workspace = true } -swc = { version = "69.0.0", path = "../swc", default-features = false } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms = { version = "56.0.0", path = "../swc_ecma_transforms/" } -testing = { version = "24.0.1", path = "../testing" } +swc = { version = "73.0.0", path = "../swc", default-features = false } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms = { version = "60.0.0", path = "../swc_ecma_transforms/" } +testing = { version = "25.0.0", path = "../testing" } walkdir = { workspace = true } [[bench]] diff --git a/deps/swc/crates/swc_graph_analyzer/Cargo.toml b/deps/swc/crates/swc_graph_analyzer/Cargo.toml index 76aa935db..6a2af5581 100644 --- a/deps/swc/crates/swc_graph_analyzer/Cargo.toml +++ b/deps/swc/crates/swc_graph_analyzer/Cargo.toml @@ -18,4 +18,4 @@ rustc-hash = { workspace = true } tracing = { workspace = true } [dev-dependencies] -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_html/Cargo.toml b/deps/swc/crates/swc_html/Cargo.toml index 569f81a6f..5848d0f27 100644 --- a/deps/swc/crates/swc_html/Cargo.toml +++ b/deps/swc/crates/swc_html/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" license = { workspace = true } name = "swc_html" repository = "https://github.com/swc-project/swc.git" -version = "35.0.0" +version = "36.0.0" [package.metadata.docs.rs] all-features = true @@ -22,7 +22,7 @@ bench = false minifier = [] [dependencies] -swc_html_ast = { version = "23.0.0", path = "../swc_html_ast" } -swc_html_codegen = { version = "24.0.0", path = "../swc_html_codegen" } -swc_html_parser = { version = "23.0.0", path = "../swc_html_parser" } -swc_html_visit = { version = "23.0.0", path = "../swc_html_visit" } +swc_html_ast = { version = "24.0.0", path = "../swc_html_ast" } +swc_html_codegen = { version = "25.0.0", path = "../swc_html_codegen" } +swc_html_parser = { version = "24.0.0", path = "../swc_html_parser" } +swc_html_visit = { version = "24.0.0", path = "../swc_html_visit" } diff --git a/deps/swc/crates/swc_html_ast/Cargo.toml b/deps/swc/crates/swc_html_ast/Cargo.toml index 1aa5bdded..b2c7482a4 100644 --- a/deps/swc/crates/swc_html_ast/Cargo.toml +++ b/deps/swc/crates/swc_html_ast/Cargo.toml @@ -9,34 +9,24 @@ edition = "2021" license = { workspace = true } name = "swc_html_ast" repository = "https://github.com/swc-project/swc.git" -version = "23.0.0" +version = "24.0.0" [lib] bench = false [features] -__rkyv = [] encoding-impl = [ "cbor4ii", "swc_atoms/encoding-impl", "swc_common/encoding-impl", ] -rkyv-impl = [ - "__rkyv", - "rkyv", - "swc_atoms/rkyv-impl", - "swc_common/rkyv-impl", - "bytecheck", -] serde-impl = ["serde"] [dependencies] -bytecheck = { workspace = true, optional = true } cbor4ii = { workspace = true, features = ["use_std"], optional = true } is-macro = { workspace = true } -rkyv = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"], optional = true } string_enum = { version = "1.0.2", path = "../string_enum/" } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } diff --git a/deps/swc/crates/swc_html_ast/src/base.rs b/deps/swc/crates/swc_html_ast/src/base.rs index ae218a4e1..d96283799 100644 --- a/deps/swc/crates/swc_html_ast/src/base.rs +++ b/deps/swc/crates/swc_html_ast/src/base.rs @@ -19,17 +19,6 @@ pub struct DocumentFragment { } #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -//#[cfg_attr( -// feature = "rkyv", -// archive(bound(serialize = "__S: rkyv::ser::ScratchSpace + -// rkyv::ser::Serializer")) -//)] -#[cfg_attr(feature = "rkyv", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) @@ -94,17 +83,6 @@ impl EqIgnoreSpan for DocumentType { } #[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -//#[cfg_attr( -// feature = "rkyv", -// archive(bound(serialize = "__S: rkyv::ser::ScratchSpace + -// rkyv::ser::Serializer")) -//)] -#[cfg_attr(feature = "rkyv", repr(u32))] #[cfg_attr( feature = "encoding-impl", derive(::swc_common::Encode, ::swc_common::Decode) diff --git a/deps/swc/crates/swc_html_ast/src/token.rs b/deps/swc/crates/swc_html_ast/src/token.rs index 56861c4a0..b22e261dc 100644 --- a/deps/swc/crates/swc_html_ast/src/token.rs +++ b/deps/swc/crates/swc_html_ast/src/token.rs @@ -33,17 +33,6 @@ pub struct AttributeToken { } #[derive(Debug, Clone, PartialEq, Eq, Hash, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(u32))] #[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( feature = "encoding-impl", @@ -55,17 +44,6 @@ pub enum Raw { } #[derive(Debug, Clone, PartialEq, Eq, Hash, EqIgnoreSpan)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv", - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, - __S::Error: rkyv::rancor::Source)) -)] -#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))] -#[cfg_attr(feature = "rkyv", repr(u32))] #[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( feature = "encoding-impl", diff --git a/deps/swc/crates/swc_html_codegen/Cargo.toml b/deps/swc/crates/swc_html_codegen/Cargo.toml index 9617fc71d..c545c413b 100644 --- a/deps/swc/crates/swc_html_codegen/Cargo.toml +++ b/deps/swc/crates/swc_html_codegen/Cargo.toml @@ -10,7 +10,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_html_codegen" repository = "https://github.com/swc-project/swc.git" -version = "24.0.0" +version = "25.0.0" [lib] bench = false @@ -20,16 +20,16 @@ auto_impl = { workspace = true } bitflags = { workspace = true } rustc-hash = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_html_ast = { version = "23.0.0", path = "../swc_html_ast" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_html_ast = { version = "24.0.0", path = "../swc_html_ast" } swc_html_codegen_macros = { version = "1.0.1", path = "../swc_html_codegen_macros" } -swc_html_utils = { version = "16.0.0", path = "../swc_html_utils" } +swc_html_utils = { version = "17.0.0", path = "../swc_html_utils" } [dev-dependencies] -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "sourcemap", ] } -swc_html_parser = { version = "23.0.0", path = "../swc_html_parser" } -swc_html_visit = { version = "23.0.0", path = "../swc_html_visit" } -testing = { version = "24.0.1", path = "../testing" } +swc_html_parser = { version = "24.0.0", path = "../swc_html_parser" } +swc_html_visit = { version = "24.0.0", path = "../swc_html_visit" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_html_minifier/Cargo.toml b/deps/swc/crates/swc_html_minifier/Cargo.toml index 6c7b3d842..cdc5be9f2 100644 --- a/deps/swc/crates/swc_html_minifier/Cargo.toml +++ b/deps/swc/crates/swc_html_minifier/Cargo.toml @@ -10,7 +10,7 @@ include = ["Cargo.toml", "src/**/*.rs", "data/**/*.json"] license = { workspace = true } name = "swc_html_minifier" repository = "https://github.com/swc-project/swc.git" -version = "56.0.0" +version = "59.0.0" [lib] bench = false @@ -34,36 +34,36 @@ rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_config = { version = "5.0.0", path = "../swc_config", features = ["regex"] } -swc_css_ast = { version = "23.0.0", path = "../swc_css_ast", optional = true } -swc_css_codegen = { version = "23.0.0", path = "../swc_css_codegen", optional = true } -swc_css_minifier = { version = "23.0.0", path = "../swc_css_minifier", optional = true } -swc_css_parser = { version = "23.0.0", path = "../swc_css_parser", optional = true } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen", features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_config = { version = "6.0.0", path = "../swc_config", features = ["regex"] } +swc_css_ast = { version = "24.0.0", path = "../swc_css_ast", optional = true } +swc_css_codegen = { version = "24.0.0", path = "../swc_css_codegen", optional = true } +swc_css_minifier = { version = "24.0.0", path = "../swc_css_minifier", optional = true } +swc_css_parser = { version = "24.0.0", path = "../swc_css_parser", optional = true } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen", features = [ "serde-impl", ] } -swc_ecma_minifier = { version = "56.0.1", path = "../swc_ecma_minifier", features = [ +swc_ecma_minifier = { version = "59.0.0", path = "../swc_ecma_minifier", features = [ "extra-serde", ] } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } -swc_html_ast = { version = "23.0.0", path = "../swc_html_ast" } -swc_html_codegen = { version = "24.0.0", path = "../swc_html_codegen" } -swc_html_parser = { version = "23.0.0", path = "../swc_html_parser" } -swc_html_utils = { version = "16.0.0", path = "../swc_html_utils" } -swc_html_visit = { version = "23.0.0", path = "../swc_html_visit" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } +swc_html_ast = { version = "24.0.0", path = "../swc_html_ast" } +swc_html_codegen = { version = "25.0.0", path = "../swc_html_codegen" } +swc_html_parser = { version = "24.0.0", path = "../swc_html_parser" } +swc_html_utils = { version = "17.0.0", path = "../swc_html_utils" } +swc_html_visit = { version = "24.0.0", path = "../swc_html_visit" } [dev-dependencies] codspeed-criterion-compat = { workspace = true } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } [[bench]] harness = false diff --git a/deps/swc/crates/swc_html_minifier/src/lib.rs b/deps/swc/crates/swc_html_minifier/src/lib.rs index d952d23d3..4f3ff1e03 100644 --- a/deps/swc/crates/swc_html_minifier/src/lib.rs +++ b/deps/swc/crates/swc_html_minifier/src/lib.rs @@ -1789,6 +1789,20 @@ impl Minifier<'_, C> { result.ok() } + /// Escapes serialized JSON so it cannot terminate its containing HTML + /// `script` element. + /// + /// HTML tokenization recognizes ` String { + if json.contains('<') { + json.replace('<', "\\u003C") + } else { + json + } + } + fn need_minify_js(&self) -> bool { match self.options.minify_js { MinifyJsOption::Bool(value) => value, @@ -2742,7 +2756,7 @@ impl VisitMut for Minifier<'_, C> { None => return, }; - n.data = minified.into(); + n.data = Self::escape_json_for_html_script(minified).into(); } Some(MinifierType::Css) => { let minified = diff --git a/deps/swc/crates/swc_html_parser/Cargo.toml b/deps/swc/crates/swc_html_parser/Cargo.toml index b84211772..a35452861 100644 --- a/deps/swc/crates/swc_html_parser/Cargo.toml +++ b/deps/swc/crates/swc_html_parser/Cargo.toml @@ -10,7 +10,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/**/*.json"] license = { workspace = true } name = "swc_html_parser" repository = "https://github.com/swc-project/swc.git" -version = "23.0.0" +version = "24.0.0" [lib] bench = false @@ -21,22 +21,22 @@ debug = [] [dependencies] rustc-hash = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_html_ast = { version = "23.0.0", path = "../swc_html_ast" } -swc_html_utils = { version = "16.0.0", path = "../swc_html_utils" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_html_ast = { version = "24.0.0", path = "../swc_html_ast" } +swc_html_utils = { version = "17.0.0", path = "../swc_html_utils" } [dev-dependencies] codspeed-criterion-compat = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -swc_html_ast = { version = "23.0.0", path = "../swc_html_ast", features = [ +swc_html_ast = { version = "24.0.0", path = "../swc_html_ast", features = [ "serde-impl", ] } -swc_html_visit = { version = "23.0.0", path = "../swc_html_visit" } +swc_html_visit = { version = "24.0.0", path = "../swc_html_visit" } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } [[bench]] harness = false diff --git a/deps/swc/crates/swc_html_utils/Cargo.toml b/deps/swc/crates/swc_html_utils/Cargo.toml index 3bf37d099..b1989297e 100644 --- a/deps/swc/crates/swc_html_utils/Cargo.toml +++ b/deps/swc/crates/swc_html_utils/Cargo.toml @@ -10,7 +10,7 @@ include = ["Cargo.toml", "src/**/*.rs", "data/**/*.json"] license = { workspace = true } name = "swc_html_utils" repository = "https://github.com/swc-project/swc.git" -version = "16.0.0" +version = "17.0.0" [lib] bench = false @@ -21,4 +21,4 @@ rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } diff --git a/deps/swc/crates/swc_html_visit/Cargo.toml b/deps/swc/crates/swc_html_visit/Cargo.toml index f715c0c72..ada88b65a 100644 --- a/deps/swc/crates/swc_html_visit/Cargo.toml +++ b/deps/swc/crates/swc_html_visit/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" license = { workspace = true } name = "swc_html_visit" repository = "https://github.com/swc-project/swc.git" -version = "23.0.0" +version = "24.0.0" [package.metadata.docs.rs] all-features = true @@ -26,7 +26,7 @@ serde-impl = ["serde"] [dependencies] serde = { workspace = true, optional = true, features = ["derive"] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_html_ast = { version = "23.0.0", path = "../swc_html_ast" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_html_ast = { version = "24.0.0", path = "../swc_html_ast" } swc_visit = { version = "2.0.1", path = "../swc_visit" } diff --git a/deps/swc/crates/swc_node_bundler/Cargo.toml b/deps/swc/crates/swc_node_bundler/Cargo.toml index 0f108a8fe..0c59f060c 100644 --- a/deps/swc/crates/swc_node_bundler/Cargo.toml +++ b/deps/swc/crates/swc_node_bundler/Cargo.toml @@ -7,7 +7,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_node_bundler" repository = { workspace = true } -version = "70.0.0" +version = "74.0.0" [lib] bench = false @@ -25,27 +25,27 @@ serde = { workspace = true, features = ["derive"], optional = true } tracing = { workspace = true } string_enum = { version = "1.0.2", path = "../string_enum" } -swc = { version = "69.0.0", path = "../swc" } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_bundler = { version = "51.0.1", path = "../swc_bundler", features = [ +swc = { version = "73.0.0", path = "../swc" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_bundler = { version = "54.0.0", path = "../swc_bundler", features = [ "concurrent", ] } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "concurrent", ] } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_loader = { version = "24.0.1", path = "../swc_ecma_loader" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_loader = { version = "25.0.0", path = "../swc_ecma_loader" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", ] } -swc_ecma_transforms = { version = "56.0.0", path = "../swc_ecma_transforms" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } +swc_ecma_transforms = { version = "60.0.0", path = "../swc_ecma_transforms" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } [dev-dependencies] -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base", features = [ +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base", features = [ "inline-helpers", ] } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_node_comments/Cargo.toml b/deps/swc/crates/swc_node_comments/Cargo.toml index 83073905c..c6ad365be 100644 --- a/deps/swc/crates/swc_node_comments/Cargo.toml +++ b/deps/swc/crates/swc_node_comments/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" license = { workspace = true } name = "swc_node_comments" repository = "https://github.com/swc-project/swc.git" -version = "24.0.0" +version = "25.0.0" [lib] bench = false @@ -18,5 +18,5 @@ bench = false dashmap = { workspace = true } rustc-hash = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } diff --git a/deps/swc/crates/swc_plugin_backend_tests/Cargo.toml b/deps/swc/crates/swc_plugin_backend_tests/Cargo.toml index 0f3df6d7c..ce24e70de 100644 --- a/deps/swc/crates/swc_plugin_backend_tests/Cargo.toml +++ b/deps/swc/crates/swc_plugin_backend_tests/Cargo.toml @@ -13,10 +13,7 @@ bench = false doctest = false [features] -# for ast_node macro default = ["encoding-impl"] -__rkyv = [] -rkyv-impl = [] serde-impl = [] encoding-impl = [] @@ -33,21 +30,21 @@ tokio = { workspace = true, features = ["rt"] } tracing = { workspace = true } cbor4ii = { workspace = true, features = [ "use_std" ] } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "concurrent", ] } -swc_plugin_runner = { version = "30.0.0", path = "../swc_plugin_runner", features = ["encoding-impl", "plugin_transform_schema_v1"] } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast", features = [ +swc_plugin_runner = { version = "32.0.0", path = "../swc_plugin_runner", features = ["encoding-impl", "plugin_transform_schema_v1"] } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast", features = [ "encoding-impl", ] } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } -swc_transform_common = { version = "17.0.0", path = "../swc_transform_common" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } +swc_transform_common = { version = "18.0.0", path = "../swc_transform_common" } swc_malloc = { version = "1.2.5", path = "../swc_malloc" } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } -swc_plugin_backend_wasmer = { version = "13.0", path = "../swc_plugin_backend_wasmer" } -swc_plugin_backend_wasmtime = { version = "12.0", path = "../swc_plugin_backend_wasmtime" } +swc_plugin_backend_wasmer = { version = "15.0", path = "../swc_plugin_backend_wasmer" } +swc_plugin_backend_wasmtime = { version = "14.0", path = "../swc_plugin_backend_wasmtime" } [[bench]] harness = false diff --git a/deps/swc/crates/swc_plugin_backend_wasmer/Cargo.toml b/deps/swc/crates/swc_plugin_backend_wasmer/Cargo.toml index 6151617aa..b4010f2f8 100644 --- a/deps/swc/crates/swc_plugin_backend_wasmer/Cargo.toml +++ b/deps/swc/crates/swc_plugin_backend_wasmer/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_plugin_backend_wasmer" repository = { workspace = true } -version = "13.0.0" +version = "15.0.0" [lib] bench = false @@ -33,10 +33,10 @@ parking_lot = { workspace = true } wasmer = { workspace = true } wasmer-wasix = { workspace = true } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "concurrent", ] } -swc_plugin_runner = { version = "30.0.0", path = "../swc_plugin_runner" } +swc_plugin_runner = { version = "32.0.0", path = "../swc_plugin_runner" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] wasmer-compiler-cranelift = { version = "6.1.0-rc.3", default-features = false } diff --git a/deps/swc/crates/swc_plugin_backend_wasmtime/Cargo.toml b/deps/swc/crates/swc_plugin_backend_wasmtime/Cargo.toml index 36a4e41ce..8d010e5f8 100644 --- a/deps/swc/crates/swc_plugin_backend_wasmtime/Cargo.toml +++ b/deps/swc/crates/swc_plugin_backend_wasmtime/Cargo.toml @@ -5,14 +5,14 @@ edition = { workspace = true } license = { workspace = true } name = "swc_plugin_backend_wasmtime" repository = { workspace = true } -version = "12.0.0" +version = "14.0.0" [dependencies] anyhow = { workspace = true } wasi-common = { workspace = true, features = ["sync", "wasmtime"] } wasmtime = { workspace = true, features = ["runtime", "cranelift", "threads"] } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "concurrent", ] } -swc_plugin_runner = { version = "30.0.0", path = "../swc_plugin_runner" } +swc_plugin_runner = { version = "32.0.0", path = "../swc_plugin_runner" } diff --git a/deps/swc/crates/swc_plugin_proxy/Cargo.toml b/deps/swc/crates/swc_plugin_proxy/Cargo.toml index 613df997e..630bf4413 100644 --- a/deps/swc/crates/swc_plugin_proxy/Cargo.toml +++ b/deps/swc/crates/swc_plugin_proxy/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_plugin_proxy" repository = { workspace = true } -version = "26.0.0" +version = "28.0.0" [lib] bench = false @@ -25,5 +25,5 @@ tracing = { workspace = true } cbor4ii = { workspace = true, features = [ "use_std" ], optional = true } better_scoped_tls = { version = "1.0.1", path = "../better_scoped_tls" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } diff --git a/deps/swc/crates/swc_plugin_runner/Cargo.toml b/deps/swc/crates/swc_plugin_runner/Cargo.toml index e8b88fc68..8707f491d 100644 --- a/deps/swc/crates/swc_plugin_runner/Cargo.toml +++ b/deps/swc/crates/swc_plugin_runner/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_plugin_runner" repository = { workspace = true } -version = "30.0.0" +version = "32.0.0" [lib] bench = false @@ -26,10 +26,6 @@ ecma = ["swc_ecma_ast/encoding-impl"] encoding-impl = ["swc_common/plugin-rt", "swc_plugin_proxy/plugin-rt"] -[build-dependencies] -vergen = { workspace = true, features = ["build", "cargo"] } - - [dependencies] anyhow = { workspace = true } parking_lot = { workspace = true } @@ -38,13 +34,13 @@ serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } tracing = { workspace = true } -swc_atoms = { version = "9.0.3", path = '../swc_atoms' } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_atoms = { version = "10.0.0", path = '../swc_atoms' } +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "concurrent", ] } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast", optional = true } -swc_plugin_proxy = { version = "26.0.0", path = "../swc_plugin_proxy" } -swc_transform_common = { version = "17.0.0", path = "../swc_transform_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast", optional = true } +swc_plugin_proxy = { version = "28.0.0", path = "../swc_plugin_proxy" } +swc_transform_common = { version = "18.0.0", path = "../swc_transform_common" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] blake3 = { workspace = true, optional = true } diff --git a/deps/swc/crates/swc_plugin_runner/build.rs b/deps/swc/crates/swc_plugin_runner/build.rs deleted file mode 100644 index bb189fc6f..000000000 --- a/deps/swc/crates/swc_plugin_runner/build.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::error::Error; - -use vergen::{BuildBuilder, CargoBuilder, Emitter}; - -fn main() -> Result<(), Box> { - let build = BuildBuilder::all_build()?; - let cargo = CargoBuilder::default() - .dependencies(true) - .name_filter("*_ast") - .build()?; - - Emitter::default() - .add_instructions(&build)? - .add_instructions(&cargo)? - .emit()?; - - Ok(()) -} diff --git a/deps/swc/crates/swc_plugin_runner/src/transform_executor.rs b/deps/swc/crates/swc_plugin_runner/src/transform_executor.rs index 7364b7e3c..3ea3e06a6 100644 --- a/deps/swc/crates/swc_plugin_runner/src/transform_executor.rs +++ b/deps/swc/crates/swc_plugin_runner/src/transform_executor.rs @@ -274,20 +274,12 @@ impl TransformExecutor { See https://plugins.swc.rs/versions/from-plugin-runner/{PKG_VERSION} for the list of the compatible versions. - Build info: - Date: {BUILD_DATE} - Timestamp: {BUILD_TIMESTAMP} - Version info: swc_plugin_runner: {PKG_VERSION} - Dependencies: {PKG_DEPS} " ) }) } } -const BUILD_DATE: &str = env!("VERGEN_BUILD_DATE"); -const BUILD_TIMESTAMP: &str = env!("VERGEN_BUILD_TIMESTAMP"); const PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); -const PKG_DEPS: &str = env!("VERGEN_CARGO_DEPENDENCIES"); diff --git a/deps/swc/crates/swc_transform_common/Cargo.toml b/deps/swc/crates/swc_transform_common/Cargo.toml index b8ed235b7..66b44ff27 100644 --- a/deps/swc/crates/swc_transform_common/Cargo.toml +++ b/deps/swc/crates/swc_transform_common/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_transform_common" repository = { workspace = true } -version = "17.0.0" +version = "18.0.0" [package.metadata.docs.rs] all-features = true @@ -20,4 +20,4 @@ rustc-hash = { workspace = true } serde = { workspace = true } better_scoped_tls = { version = "1.0.1", path = "../better_scoped_tls" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_common = { version = "24.0.0", path = "../swc_common" } diff --git a/deps/swc/crates/swc_ts_fast_strip/Cargo.toml b/deps/swc/crates/swc_ts_fast_strip/Cargo.toml index b69b0a970..9987bb8eb 100644 --- a/deps/swc/crates/swc_ts_fast_strip/Cargo.toml +++ b/deps/swc/crates/swc_ts_fast_strip/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_ts_fast_strip" repository = { workspace = true } -version = "53.0.0" +version = "56.0.0" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } @@ -20,25 +20,25 @@ nightly = [] anyhow = { workspace = true } bytes-str = { workspace = true } serde = { workspace = true, features = ["derive"] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "sourcemap", ] } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser", default-features = false, features = [ +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser", default-features = false, features = [ "typescript", "unstable", ] } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -swc_ecma_transforms_react = { version = "50.0.0", path = "../swc_ecma_transforms_react" } -swc_ecma_transforms_typescript = { version = "50.0.0", path = "../swc_ecma_transforms_typescript" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +swc_ecma_transforms_react = { version = "53.0.0", path = "../swc_ecma_transforms_react" } +swc_ecma_transforms_typescript = { version = "53.0.0", path = "../swc_ecma_transforms_typescript" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } wasm-bindgen = { workspace = true, optional = true } [dev-dependencies] codspeed-criterion-compat = { workspace = true } -testing = { version = "24.0.1", path = "../testing" } +testing = { version = "25.0.0", path = "../testing" } [[bench]] harness = false diff --git a/deps/swc/crates/swc_ts_fast_strip/benches/assets.rs b/deps/swc/crates/swc_ts_fast_strip/benches/assets.rs index 5d102a946..e0c1b5ef2 100644 --- a/deps/swc/crates/swc_ts_fast_strip/benches/assets.rs +++ b/deps/swc/crates/swc_ts_fast_strip/benches/assets.rs @@ -1,22 +1,50 @@ use codspeed_criterion_compat::{black_box, criterion_group, criterion_main, Bencher, Criterion}; use swc_ts_fast_strip::{operate, Options}; -static SOURCE: &str = include_str!("assets/test.ts"); +const CASES: &[(&str, &str)] = &[ + ("typescript/fast-strip", include_str!("assets/test.ts")), + ( + "typescript/fast-strip/docusaurus-config", + include_str!("assets/docusaurus.config.ts"), + ), + ( + "typescript/fast-strip/ant-design-config", + include_str!("assets/ant-design.vitest.config.ts"), + ), + ( + "typescript/fast-strip/typescript-eslint-generate-configs", + include_str!("assets/typescript-eslint.generate-configs.mts"), + ), + ( + "typescript/fast-strip/graphile-config", + include_str!("assets/graphile.config.ts"), + ), + ( + "typescript/fast-strip/hono-types-test", + include_str!("assets/hono.types.test.ts"), + ), +]; fn fast_ts(c: &mut Criterion) { - c.bench_function("typescript/fast-strip", fast_typescript); + for &(name, source) in CASES { + c.bench_function(name, |b| fast_typescript(b, source)); + } } -fn fast_typescript(b: &mut Bencher) { + +fn fast_typescript(b: &mut Bencher, source: &str) { b.iter(|| { ::testing::run_test(false, |cm, handler| { - let _result = black_box(operate( + let result = operate( &cm, handler, - black_box(SOURCE.to_string()), + black_box(source.to_string()), Options { ..Default::default() }, - )); + ) + .expect("benchmark source should be valid erasable TypeScript"); + + black_box(result); Ok(()) }) diff --git a/deps/swc/crates/swc_ts_fast_strip/benches/assets/README.md b/deps/swc/crates/swc_ts_fast_strip/benches/assets/README.md new file mode 100644 index 000000000..83cc11d4e --- /dev/null +++ b/deps/swc/crates/swc_ts_fast_strip/benches/assets/README.md @@ -0,0 +1,12 @@ +# Real-world benchmark sources + +These files are copied unchanged from pinned upstream revisions. They are used +only as inputs for the `swc_ts_fast_strip` benchmarks. + +| Local file | Upstream source | License | +| --- | --- | --- | +| `docusaurus.config.ts` | [facebook/docusaurus@a0bc322](https://github.com/facebook/docusaurus/blob/a0bc32214436d52a5ac9de9be1a515d872987366/website/docusaurus.config.ts) | [MIT](https://github.com/facebook/docusaurus/blob/a0bc32214436d52a5ac9de9be1a515d872987366/LICENSE) | +| `ant-design.vitest.config.ts` | [ant-design/ant-design@afe2c19](https://github.com/ant-design/ant-design/blob/afe2c19fc03442ded9675a1260126bbda1108ca8/vitest.config.ts) | [MIT](https://github.com/ant-design/ant-design/blob/afe2c19fc03442ded9675a1260126bbda1108ca8/LICENSE) | +| `typescript-eslint.generate-configs.mts` | [typescript-eslint/typescript-eslint@c8cafa4](https://github.com/typescript-eslint/typescript-eslint/blob/c8cafa4ae9a0b57a64ba23659eba25a01301684a/tools/scripts/generate-configs.mts) | [MIT](https://github.com/typescript-eslint/typescript-eslint/blob/c8cafa4ae9a0b57a64ba23659eba25a01301684a/LICENSE) | +| `graphile.config.ts` | [graphile/crystal@33f239b](https://github.com/graphile/crystal/blob/33f239b494f43df2d11ee7264832ea8c732311f1/postgraphile/postgraphile/graphile.config.ts) | [MIT](https://github.com/graphile/crystal/blob/33f239b494f43df2d11ee7264832ea8c732311f1/LICENSE.md) | +| `hono.types.test.ts` | [honojs/hono@971106d](https://github.com/honojs/hono/blob/971106d132ec8a989be12ec5c8e63cfaf597cd4f/src/types.test.ts) | [MIT](https://github.com/honojs/hono/blob/971106d132ec8a989be12ec5c8e63cfaf597cd4f/LICENSE) | diff --git a/deps/swc/crates/swc_ts_fast_strip/benches/assets/ant-design.vitest.config.ts b/deps/swc/crates/swc_ts_fast_strip/benches/assets/ant-design.vitest.config.ts new file mode 100644 index 000000000..e624080cd --- /dev/null +++ b/deps/swc/crates/swc_ts_fast_strip/benches/assets/ant-design.vitest.config.ts @@ -0,0 +1,195 @@ +import { resolve } from 'node:path'; +import { defineConfig } from 'vitest/config'; + +// POC: 对标 .jest.js 的 moduleNameMapper / LIB_DIR 机制。 +// LIB_DIR=es|lib 时让 antd 指向对应产物目录,否则指向源码 components。 +// 注:dist/dist-min(UMD 产物 dist/antd.js、dist/antd.min.js)的映射与源码不同, +// 本 POC 未验证,故不纳入;仅支持 es/lib 与默认 components。 +const LIB_DIR = process.env.LIB_DIR || 'components'; +const baseDir = ['es', 'lib'].includes(LIB_DIR) ? LIB_DIR : 'components'; + +const r = (p: string) => resolve(__dirname, p); + +export default defineConfig({ + // JSX 走 automatic runtime(方案 A:丢弃 babel)。Vitest 4 默认转换器为 oxc, + // 其 jsx.runtime 默认即 'automatic',无需再像 esbuild 时代那样显式声明。 + resolve: { + alias: [ + // 对标 jest moduleNameMapper,并接入 LIB_DIR 切换 + { find: /^antd$/, replacement: r(`${baseDir}/index`) }, + { find: /^antd\/es\/(.*)$/, replacement: r(`${baseDir}/$1`) }, + { find: /^antd\/lib\/(.*)$/, replacement: r(`${baseDir}/$1`) }, + { find: /^antd\/locale\/(.*)$/, replacement: r(`${baseDir}/locale/$1`) }, + // 部分 antd 生态包默认解析到 CJS lib/(内部 require('antd') 绕过 alias); + // 强制走各自 ESM es/,其 import 'antd' 可命中上面的 antd alias。 + { find: /^antd-style$/, replacement: r('node_modules/antd-style/es/index.js') }, + { + find: /^@ant-design\/happy-work-theme$/, + replacement: r('node_modules/@ant-design/happy-work-theme/es/index.js'), + }, + // css/less → identity-obj-proxy(CSS-in-JS,测试不需要真实样式) + { find: /\.(css|less)$/, replacement: 'identity-obj-proxy' }, + ], + }, + test: { + globals: true, + environment: 'jsdom', + setupFiles: [r('vitest.setup.ts')], + // POC:Vitest 的 snapshot key 格式与 Jest 不同(`A > B` vs `A B`)。将 Vitest 基线放在 + // 测试同目录的 __snapshots__/vitest/ 子目录,与组件就近存放;Jest 通过 + // modulePathIgnorePatterns 忽略该子目录,避免在 --ci 下把它判为 obsolete 而报错。 + resolveSnapshotPath: (testPath, snapExtension) => { + const normalized = testPath.replace(/\\/g, '/'); + const dir = normalized.slice(0, normalized.lastIndexOf('/')); + const file = normalized.slice(normalized.lastIndexOf('/') + 1); + return `${dir}/__snapshots__/vitest/${file}${snapExtension}`; + }, + // include 覆盖全组件;exclude 是当前 Vitest 迁移进度的显式 manifest。 + // 维护规则: + // - 每次从 exclude 移除文件,都要先单跑该文件,再跑 npm run test:vitest。 + // - 只提交当前 collected test files 对应的 __snapshots__/vitest/*.snap。 + // - CI 的覆盖统计使用 vitest list --filesOnly;不要用普通 vitest list 统计文件数。 + // + // exclude 分四类: + // (A) 非 jsdom 环境 / 需独立配置的测试类型 + // (B) demo 测试——依赖 jest.requireActual 同步 shim,且 antd-style 的 style-class.tsx + // demo 在 Vitest 中因模块状态冲突无法加载(57 个组件受影响) + // (C) jest.mock() 提升问题——通过垫片间接调用不会被 Vitest 提升 + // (D) 其他兼容性问题(Tooltip popup 时序、requireActual 相对路径等) + include: ['components/**/__tests__/**/*.test.{ts,tsx}'], + exclude: [ + '**/node_modules/**', + // (A) 非 jsdom 环境测试 + '**/image.test.*', + '**/node.test.*', + '**/demo-semantic.test.*', + '**/a11y.test.*', + '**/type.test.*', + // (B) demo 测试(jest.requireActual shim + antd-style 模块冲突) + '**/demo.test.*', + '**/demo-extend.test.*', + // (C) jest.mock() 提升 / requireActual 相对路径 / ResizeObserver 兼容性等 + 'components/affix/__tests__/Affix.test.tsx', + 'components/__tests__/index.test.ts', + 'components/__tests__/17.test.ts', + 'components/__tests__/node.test.tsx', + 'components/_util/__tests__/useZIndex.test.tsx', + 'components/_util/__tests__/wave.test.tsx', + 'components/_util/__tests__/wave-util.test.tsx', + 'components/anchor/__tests__/Anchor.test.tsx', + 'components/auto-complete/__tests__/index.test.tsx', + 'components/auto-complete/__tests__/semantic.test.tsx', + 'components/avatar/__tests__/Avatar.test.tsx', + 'components/breadcrumb/__tests__/Breadcrumb.test.tsx', + 'components/button/__tests__/delay-timer.test.tsx', + 'components/button/__tests__/index.test.tsx', + 'components/button/__tests__/wave.test.tsx', + 'components/calendar/__tests__/index.test.tsx', + 'components/cascader/__tests__/index.test.tsx', + 'components/cascader/__tests__/semantic.test.tsx', + 'components/collapse/__tests__/index.test.tsx', + 'components/color-picker/__tests__/gradient.test.tsx', + 'components/color-picker/__tests__/index.test.tsx', + 'components/color-picker/__tests__/semantic.test.tsx', + 'components/config-provider/__tests__/components.test.tsx', + 'components/config-provider/__tests__/cssinjs.test.tsx', + 'components/config-provider/__tests__/form.test.tsx', + 'components/config-provider/__tests__/index.test.tsx', + 'components/config-provider/__tests__/locale.test.tsx', + 'components/config-provider/__tests__/motion.test.tsx', + 'components/config-provider/__tests__/nonce.test.tsx', + 'components/config-provider/__tests__/popup.test.tsx', + 'components/config-provider/__tests__/style.test.tsx', + 'components/config-provider/__tests__/wave.test.tsx', + 'components/date-picker/__tests__/DatePicker.test.tsx', + 'components/date-picker/__tests__/RangePicker.test.tsx', + 'components/descriptions/__tests__/index.test.tsx', + 'components/dropdown/__tests__/dropdown-button.test.tsx', + 'components/dropdown/__tests__/index.test.tsx', + 'components/dropdown/__tests__/semantic.test.tsx', + 'components/flex/__tests__/index.test.tsx', + 'components/float-button/__tests__/index.test.tsx', + 'components/form/__tests__/index.test.tsx', + 'components/grid/__tests__/gap.test.tsx', + 'components/grid/__tests__/index.test.tsx', + 'components/grid/__tests__/server.test.tsx', + 'components/input/__tests__/textarea.test.tsx', + 'components/layout/__tests__/index.test.tsx', + 'components/locale/__tests__/config.test.tsx', + 'components/masonry/__tests__/index.test.tsx', + 'components/mentions/__tests__/index.test.tsx', + 'components/menu/__tests__/index.test.tsx', + 'components/message/__tests__/config.test.tsx', + 'components/message/__tests__/hooks.test.tsx', + 'components/message/__tests__/immediately.test.tsx', + 'components/message/__tests__/index.test.tsx', + 'components/message/__tests__/semantic.test.tsx', + 'components/message/__tests__/static-warning.test.tsx', + 'components/message/__tests__/type.test.tsx', + 'components/modal/__tests__/confirm.test.tsx', + 'components/modal/__tests__/hook.test.tsx', + 'components/modal/__tests__/Modal.test.tsx', + 'components/modal/__tests__/static-warning.test.tsx', + 'components/notification/__tests__/config.test.tsx', + 'components/notification/__tests__/index.test.tsx', + 'components/notification/__tests__/placement.test.tsx', + 'components/notification/__tests__/semantic.test.tsx', + 'components/notification/__tests__/static-warning.test.tsx', + 'components/popconfirm/__tests__/index.test.tsx', + 'components/popconfirm/__tests__/semantic.test.tsx', + 'components/popover/__tests__/index.test.tsx', + 'components/popover/__tests__/semantic.test.tsx', + 'components/progress/__tests__/index.test.tsx', + 'components/progress/__tests__/placement.test.tsx', + 'components/segmented/__tests__/index.test.tsx', + 'components/select/__tests__/index.test.tsx', + 'components/select/__tests__/semantic.test.tsx', + 'components/slider/__tests__/index.test.tsx', + 'components/slider/__tests__/SliderTooltip.test.tsx', + 'components/slider/__tests__/tooltip.test.tsx', + 'components/space/__tests__/gap.test.tsx', + 'components/spin/__tests__/delay.test.tsx', + 'components/splitter/__tests__/index.test.tsx', + 'components/splitter/__tests__/lazy.test.tsx', + 'components/switch/__tests__/index.test.tsx', + 'components/switch/__tests__/semantic.test.tsx', + 'components/table/__tests__/semantic.test.tsx', + 'components/table/__tests__/Table.filter.test.tsx', + 'components/table/__tests__/Table.IE.test.tsx', + 'components/table/__tests__/Table.pagination.test.tsx', + 'components/table/__tests__/Table.rowSelection.test.tsx', + 'components/table/__tests__/Table.sorter.test.tsx', + 'components/table/__tests__/Table.test.tsx', + 'components/tabs/__tests__/index.test.tsx', + 'components/tag/__tests__/index.test.tsx', + 'components/time-picker/__tests__/index.test.tsx', + 'components/time-picker/__tests__/semantic.test.tsx', + 'components/tooltip/__tests__/semantic.test.tsx', + 'components/tooltip/__tests__/tooltip.test.tsx', + 'components/tour/__tests__/index.test.tsx', + 'components/transfer/__tests__/dropdown.test.tsx', + 'components/transfer/__tests__/index.test.tsx', + 'components/tree/__tests__/directory.test.tsx', + 'components/tree-select/__tests__/index.test.tsx', + 'components/typography/__tests__/copy.test.tsx', + 'components/typography/__tests__/editable.test.tsx', + 'components/typography/__tests__/ellipsis.test.tsx', + 'components/typography/__tests__/index.test.tsx', + 'components/upload/__tests__/upload.test.tsx', + 'components/upload/__tests__/uploadlist.test.tsx', + 'components/watermark/__tests__/index.test.tsx', + ], + environmentOptions: { + jsdom: { url: 'http://localhost' }, + }, + // 与 jest maxWorkers:'50%' 对齐,保证性能对比公平 + pool: 'threads', + server: { + deps: { + // 这些依赖内部 import 'antd',需经 Vite 处理才能命中 alias; + // 同时强制内联 ESM 依赖(对标 jest transformIgnorePatterns)。 + inline: [/@rc-component/, /rc-/, /@ant-design/, /antd-style/, /@emotion/], + }, + }, + }, +}); diff --git a/deps/swc/crates/swc_ts_fast_strip/benches/assets/docusaurus.config.ts b/deps/swc/crates/swc_ts_fast_strip/benches/assets/docusaurus.config.ts new file mode 100644 index 000000000..8c00701ef --- /dev/null +++ b/deps/swc/crates/swc_ts_fast_strip/benches/assets/docusaurus.config.ts @@ -0,0 +1,908 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import path from 'path'; +// eslint-disable-next-line import/default +import npm2yarn from '@docusaurus/remark-plugin-npm2yarn'; +import remarkMath from 'remark-math'; +import rehypeKatex from 'rehype-katex'; +import configTabs from './src/remark/configTabs'; + +import versions from './versions.json'; +import VersionsArchived from './versionsArchived.json'; +import { + dogfoodingPluginInstances, + dogfoodingThemeInstances, + dogfoodingRedirects, + dogfoodingTransformFrontMatter, + isArgosBuild, +} from './_dogfooding/dogfooding.config'; + +import ConfigLocalized from './docusaurus.config.localized.json'; + +import PrismLight from './src/utils/prismLight'; +import PrismDark from './src/utils/prismDark'; + +import type {Config, DocusaurusConfig, VcsPreset} from '@docusaurus/types'; + +import type * as Preset from '@docusaurus/preset-classic'; +import type {Options as DocsOptions} from '@docusaurus/plugin-content-docs'; +import type {Options as BlogOptions} from '@docusaurus/plugin-content-blog'; +import type {Options as PageOptions} from '@docusaurus/plugin-content-pages'; +import type {Options as IdealImageOptions} from '@docusaurus/plugin-ideal-image'; +import type {Options as ClientRedirectsOptions} from '@docusaurus/plugin-client-redirects'; +import type {ThemeConfig as LiveCodeBlockThemeConfig} from '@docusaurus/theme-live-codeblock'; + +type ThemeConfig = Preset.ThemeConfig & LiveCodeBlockThemeConfig; + +const ArchivedVersionsDropdownItems = Object.entries(VersionsArchived).splice( + 0, + 5, +); + +function isPrerelease(version: string) { + return ( + version.includes('-') || + version.includes('alpha') || + version.includes('beta') || + version.includes('rc') + ); +} + +function getLastStableVersion() { + const lastStableVersion = versions.find((version) => !isPrerelease(version)); + if (!lastStableVersion) { + throw new Error('unexpected, no stable Docusaurus version?'); + } + return lastStableVersion; +} +const announcedVersion = getAnnouncedVersion(); + +function getLastStableVersionTuple(): [string, string, string] { + const lastStableVersion = getLastStableVersion(); + const parts = lastStableVersion.split('.'); + if (parts.length !== 3) { + throw new Error(`Unexpected stable version name: ${lastStableVersion}`); + } + return [parts[0]!, parts[1]!, parts[2]!]; +} + +// The version announced on the homepage hero and announcement banner +// 3.3.2 => 3.3 +// 3.0.5 => 3.0 +function getAnnouncedVersion() { + const [major, minor] = getLastStableVersionTuple(); + return `${major}.${minor}`; +} + +// This probably only makes sense for the alpha/beta/rc phase, temporary +function getNextVersionName() { + return 'Canary'; + /* + const expectedPrefix = '2.0.0-rc.'; + + const lastReleasedVersion = versions[0]; + if (!lastReleasedVersion || !lastReleasedVersion.includes(expectedPrefix)) { + throw new Error( + 'this code is only meant to be used during the 2.0 alpha/beta/rc phase.', + ); + } + const version = parseInt(lastReleasedVersion.replace(expectedPrefix, ''), 10); + return `${expectedPrefix}${version + 1}`; + + */ +} + +// Artificial way to crash the SSR rendering and test errors +// See website/_dogfooding/_pages tests/crashTest.tsx +// Test with: DOCUSAURUS_CRASH_TEST=true pnpm build:website:fast +const crashTest = process.env.DOCUSAURUS_CRASH_TEST === 'true'; + +// By default, we use Docusaurus Faster +// DOCUSAURUS_SLOWER=true is useful for benchmarking faster against slower +// hyperfine --prepare 'pnpm clear:website' --runs 3 'DOCUSAURUS_SLOWER=true pnpm build:website:fast' 'pnpm build:website:fast' +const isSlower = process.env.DOCUSAURUS_SLOWER === 'true'; +if (isSlower) { + console.log('🐢 Using slower Docusaurus build'); +} + +const router = process.env + .DOCUSAURUS_ROUTER as DocusaurusConfig['future']['experimental_router']; + +const vcs = process.env.DOCUSAURUS_SITE_VCS as VcsPreset; + +const isDev = process.env.NODE_ENV === 'development'; + +// See https://docs.netlify.com/configure-builds/environment-variables/ +const isProductionDeployment = + !!process.env.NETLIFY && process.env.CONTEXT === 'production'; + +const isDeployPreview = + !!process.env.NETLIFY && process.env.CONTEXT === 'deploy-preview'; + +// Netlify branch deploy like "docusaurus-v2" +const isBranchDeploy = + !!process.env.NETLIFY && process.env.CONTEXT === 'branch-deploy'; + +// Used to debug production build issues faster +const isBuildFast = !!process.env.BUILD_FAST; + +const baseUrl = process.env.BASE_URL ?? '/'; + +// Special deployment for staging locales until they get enough translations +// https://app.netlify.com/sites/docusaurus-i18n-staging +// https://docusaurus-i18n-staging.netlify.app/ +const isI18nStaging = process.env.I18N_STAGING === 'true'; + +const isVersioningDisabled = !!process.env.DISABLE_VERSIONING || isI18nStaging; + +const isRsdoctor = process.env.RSDOCTOR === 'true'; + +/* +const TwitterSvg = + ''; +*/ + +const defaultLocale = 'en'; + +function getLocalizedConfigValue(key: keyof typeof ConfigLocalized) { + const currentLocale = process.env.DOCUSAURUS_CURRENT_LOCALE ?? defaultLocale; + const values = ConfigLocalized[key]; + if (!values) { + throw new Error(`Localized config key=${key} not found`); + } + const value = values[currentLocale] ?? values[defaultLocale]; + if (!value) { + throw new Error( + `Localized value for config key=${key} not found for both currentLocale=${currentLocale} or defaultLocale=${defaultLocale}`, + ); + } + return value; +} + +// By default, we don't want to run "git log" commands on i18n sites +// This makes localized sites build much slower on Netlify +// See also https://github.com/facebook/docusaurus/issues/11208 +// const showLastUpdate = process.env.DOCUSAURUS_CURRENT_LOCALE === defaultLocale; +const showLastUpdate = true; + +export default async function createConfigAsync() { + return { + title: 'Docusaurus', + tagline: getLocalizedConfigValue('tagline'), + organizationName: 'facebook', + projectName: 'docusaurus', + baseUrl, + baseUrlIssueBanner: true, + url: 'https://docusaurus.io', + future: { + v4: !isSlower, // Not accurate, but good enough + faster: isSlower + ? false + : { + // Verbose object: easier to independently test single attributes + swcJsLoader: true, + swcJsMinimizer: true, + swcHtmlMinimizer: true, + lightningCssMinimizer: true, + mdxCrossCompilerCache: true, + rspackBundler: true, + rspackPersistentCache: true, + ssgWorkerThreads: true, + gitEagerVcs: true, + }, + experimental_vcs: vcs, + experimental_router: router, + }, + // Dogfood both settings: + // - force trailing slashes for deploy previews + // - avoid trailing slashes in prod + trailingSlash: isDeployPreview, + stylesheets: [ + { + href: '/katex/katex.min.css', + type: 'text/css', + }, + ], + i18n: { + defaultLocale, + + localeConfigs: { + [defaultLocale]: { + // Forces the translation process to run for default locale + // Permits to dogfood translation key conflicts detection + translate: true, + }, + }, + + locales: + isDeployPreview || isBranchDeploy + ? // Deploy preview and branch deploys: keep them fast! + [defaultLocale] + : isI18nStaging + ? // Staging locales: https://docusaurus-i18n-staging.netlify.app/ + [defaultLocale, 'ja'] + : // Production locales + [defaultLocale, 'fr', 'pt-BR', 'ko', 'zh-CN'], + }, + markdown: { + format: 'detect', + mermaid: true, + hooks: { + onBrokenMarkdownLinks: 'warn', + }, + mdx1Compat: { + // Needed for us until Crowdin improves support + // See https://github.com/facebook/docusaurus/pull/11847#issuecomment-4183213345 + admonitions: true, + }, + remarkRehypeOptions: { + footnoteLabel: getLocalizedConfigValue('remarkRehypeOptions_footnotes'), + }, + parseFrontMatter: async (params) => { + const result = await params.defaultParseFrontMatter(params); + return { + ...result, + frontMatter: dogfoodingTransformFrontMatter(result.frontMatter), + }; + }, + preprocessor: ({filePath, fileContent}) => { + let result = fileContent; + + // This fixes Crowdin bug altering MDX comments on i18n sites... + // https://github.com/facebook/docusaurus/pull/9220 + result = result.replaceAll('{/_', '{/*'); + result = result.replaceAll('_/}', '*/}'); + + const showDevLink = false; + + if (isDev && showDevLink) { + const isPartial = path.basename(filePath).startsWith('_'); + if (!isPartial) { + // "vscode://file/${projectPath}${filePath}:${line}:${column}", + // "webstorm://open?file=${projectPath}${filePath}&line=${line}&column=${column}", + const vscodeLink = `vscode://file/${filePath}`; + const webstormLink = `webstorm://open?file=${filePath}`; + const intellijLink = `idea://open?file=${filePath}`; + result = `${result}\n\n---\n\n**DEV**: open this file in [VSCode](<${vscodeLink}>) | [WebStorm](<${webstormLink}>) | [IntelliJ](<${intellijLink}>)\n`; + } + } + + return result; + }, + }, + onBrokenLinks: + isVersioningDisabled || + process.env.DOCUSAURUS_CURRENT_LOCALE !== defaultLocale + ? 'warn' + : 'throw', + onBrokenAnchors: + isVersioningDisabled || + process.env.DOCUSAURUS_CURRENT_LOCALE !== defaultLocale + ? 'warn' + : 'throw', + favicon: 'img/docusaurus.ico', + customFields: { + crashTest, + isDeployPreview, + description: + 'An optimized site generator in React. Docusaurus helps you to move fast and write content. Build documentation websites, blogs, marketing pages, and more.', + announcedVersion, + }, + staticDirectories: [ + 'static', + path.join(__dirname, '_dogfooding/_asset-tests'), + // Adding a non-existent static directory. If user deleted `static` + // without specifying `staticDirectories: []`, build should still work + path.join(__dirname, '_dogfooding/non-existent'), + ], + themes: ['live-codeblock', ...dogfoodingThemeInstances], + plugins: [ + function disableExpensiveBundlerOptimizationPlugin() { + return { + name: 'disable-expensive-bundler-optimizations', + configureWebpack(_config, isServer) { + // This optimization is expensive and only reduces by 3% the JS + // Let's skip it for local and deploy preview builds + // See also https://github.com/facebook/docusaurus/discussions/11199 + return { + optimization: { + concatenateModules: isProductionDeployment ? !isServer : false, + }, + }; + }, + }; + }, + isRsdoctor && [ + 'rsdoctor', + { + rsdoctorOptions: { + disableTOSUpload: true, + supports: { + // https://rsdoctor.dev/config/options/options#generatetilegraph + generateTileGraph: true, + }, + linter: { + // See https://rsdoctor.dev/guide/usage/rule-config + rules: { + 'ecma-version-check': 'off', + 'duplicate-package': 'off', + }, + }, + }, + }, + ], + [ + './src/plugins/changelog/index.ts', + { + blogTitle: 'Docusaurus changelog', + // Not useful, but permits to run git commands earlier + // Otherwise the sitemap plugin will run them in postBuild() + showLastUpdateAuthor: showLastUpdate, + showLastUpdateTime: showLastUpdate, + blogDescription: + 'Keep yourself up-to-date about new features in every release', + blogSidebarCount: 'ALL', + blogSidebarTitle: 'Changelog', + routeBasePath: '/changelog', + showReadingTime: false, + postsPerPage: 20, + archiveBasePath: null, + authorsMapPath: 'authors.json', + feedOptions: { + type: 'all', + title: 'Docusaurus changelog', + description: + 'Keep yourself up-to-date about new features in every release', + copyright: `Copyright © ${new Date().getFullYear()} Facebook, Inc.`, + language: defaultLocale, + }, + onInlineAuthors: 'warn', + }, + ], + [ + 'content-docs', + { + id: 'community', + path: 'community', + routeBasePath: 'community', + editUrl: ({locale, versionDocsDirPath, docPath}) => { + if (locale !== defaultLocale) { + return `https://crowdin.com/project/docusaurus-v2/${locale}`; + } + return `https://github.com/facebook/docusaurus/edit/main/website/${versionDocsDirPath}/${docPath}`; + }, + remarkPlugins: [npm2yarn], + editCurrentVersion: true, + sidebarPath: './sidebarsCommunity.js', + showLastUpdateAuthor: showLastUpdate, + showLastUpdateTime: showLastUpdate, + } satisfies DocsOptions, + ], + !process.env.DOCUSAURUS_SKIP_BUNDLING && [ + 'client-redirects', + { + fromExtensions: ['html'], + createRedirects(routePath) { + // Redirect to /docs from /docs/introduction (now docs root doc) + if (routePath === '/docs' || routePath === '/docs/') { + return [`${routePath}/introduction`]; + } + return []; + }, + redirects: [ + { + from: ['/docs/support', '/docs/next/support'], + to: '/community/support', + }, + { + from: ['/docs/team', '/docs/next/team'], + to: '/community/team', + }, + { + from: ['/docs/resources', '/docs/next/resources'], + to: '/community/resources', + }, + { + from: '/docs/api/misc/docusaurus-init', + to: '/docs/api/misc/create-docusaurus', + }, + ...dogfoodingRedirects, + ], + } satisfies ClientRedirectsOptions, + ], + [ + 'ideal-image', + { + quality: 70, + max: 1030, + min: 640, + steps: 2, + // Use false to debug, but it incurs huge perf costs + disableInDev: true, + } satisfies IdealImageOptions, + ], + [ + 'pwa', + { + // debug: isDeployPreview, + offlineModeActivationStrategies: [ + 'appInstalled', + 'standalone', + 'queryString', + ], + // swRegister: false, + swCustom: require.resolve('./src/sw.js'), // TODO make it possible to use relative path + pwaHead: [ + { + tagName: 'link', + rel: 'icon', + href: 'img/docusaurus.png', + }, + { + tagName: 'link', + rel: 'manifest', + href: 'manifest.json', + }, + { + tagName: 'meta', + name: 'theme-color', + content: 'rgb(37, 194, 160)', + }, + { + tagName: 'meta', + name: 'apple-mobile-web-app-capable', + content: 'yes', + }, + { + tagName: 'meta', + name: 'apple-mobile-web-app-status-bar-style', + content: '#000', + }, + { + tagName: 'link', + rel: 'apple-touch-icon', + href: 'img/docusaurus.png', + }, + { + tagName: 'link', + rel: 'mask-icon', + href: 'img/docusaurus.png', + color: 'rgb(62, 204, 94)', + }, + { + tagName: 'meta', + name: 'msapplication-TileImage', + content: 'img/docusaurus.png', + }, + { + tagName: 'meta', + name: 'msapplication-TileColor', + content: '#000', + }, + ], + }, + ], + '@docusaurus/theme-mermaid', + './src/plugins/featureRequests/FeatureRequestsPlugin.js', + ...dogfoodingPluginInstances, + ], + presets: [ + [ + 'classic', + { + debug: true, // force debug plugin usage + docs: { + // routeBasePath: '/', + path: 'docs', + sidebarPath: 'sidebars.ts', + // sidebarCollapsible: false, + // sidebarCollapsed: true, + editUrl: ({locale, docPath}) => { + if (locale !== defaultLocale) { + return `https://crowdin.com/project/docusaurus-v2/${locale}`; + } + // We want users to submit updates to the upstream/next version! + // Otherwise we risk losing the update on the next release. + const nextVersionDocsDirPath = 'docs'; + return `https://github.com/facebook/docusaurus/edit/main/website/${nextVersionDocsDirPath}/${docPath}`; + }, + admonitions: { + keywords: ['my-custom-admonition'], + }, + showLastUpdateAuthor: showLastUpdate, + showLastUpdateTime: showLastUpdate, + remarkPlugins: [[npm2yarn, {sync: true}], remarkMath, configTabs], + rehypePlugins: [rehypeKatex], + disableVersioning: isVersioningDisabled, + lastVersion: + isDev || + isVersioningDisabled || + isDeployPreview || + isBranchDeploy || + isBuildFast + ? 'current' + : getLastStableVersion(), + + onlyIncludeVersions: (() => { + if (isBuildFast) { + return ['current']; + } else if ( + !isVersioningDisabled && + (isDev || isDeployPreview || isBranchDeploy) + ) { + return ['current', ...versions.slice(0, 2)]; + } + return undefined; + })(), + versions: { + current: { + label: `${getNextVersionName()} 🚧`, + }, + }, + }, + blog: { + // routeBasePath: '/', + path: 'blog', + showLastUpdateAuthor: showLastUpdate, + showLastUpdateTime: showLastUpdate, + editUrl: ({locale, blogDirPath, blogPath}) => { + if (locale !== defaultLocale) { + return `https://crowdin.com/project/docusaurus-v2/${locale}`; + } + return `https://github.com/facebook/docusaurus/edit/main/website/${blogDirPath}/${blogPath}`; + }, + remarkPlugins: [npm2yarn], + postsPerPage: 5, + feedOptions: { + type: 'all', + description: + 'Keep up to date with upcoming Docusaurus releases and articles by following our feed!', + copyright: `Copyright © ${new Date().getFullYear()} Facebook, Inc.`, + xslt: true, + }, + blogTitle: 'Docusaurus blog', + blogDescription: 'Read blog posts about Docusaurus from the team', + blogSidebarCount: 'ALL', + blogSidebarTitle: 'All our posts', + onUntruncatedBlogPosts: + process.env.DOCUSAURUS_CURRENT_LOCALE !== defaultLocale + ? 'warn' + : 'throw', + onInlineTags: + process.env.DOCUSAURUS_CURRENT_LOCALE !== defaultLocale + ? 'warn' + : 'throw', + } satisfies BlogOptions, + pages: { + remarkPlugins: [npm2yarn], + editUrl: ({locale, pagesPath}) => { + if (locale !== defaultLocale) { + return `https://crowdin.com/project/docusaurus-v2/${locale}`; + } + return `https://github.com/facebook/docusaurus/edit/main/website/src/pages/${pagesPath}`; + }, + showLastUpdateAuthor: showLastUpdate, + showLastUpdateTime: showLastUpdate, + } satisfies PageOptions, + theme: { + customCss: [ + './src/css/custom.css', + // relative paths are relative to site dir + './_dogfooding/dogfooding.css', + ], + }, + gtag: !(isDeployPreview || isBranchDeploy) + ? { + trackingID: ['G-E5CR2Q1NRE'], + } + : undefined, + sitemap: { + ignorePatterns: isArgosBuild + ? undefined + : // Note: /tests/docs already has noIndex: true + ['/tests/{blog,pages}/**'], + lastmod: showLastUpdate ? 'date' : null, + priority: null, + changefreq: null, + }, + svgr: { + svgrConfig: { + svgoConfig: undefined, // Use .svgo.config.js + }, + }, + } satisfies Preset.Options, + ], + ], + + themeConfig: { + liveCodeBlock: { + playgroundPosition: 'bottom', + }, + docs: { + sidebar: { + hideable: true, + autoCollapseCategories: true, + }, + }, + colorMode: { + defaultMode: 'light', + disableSwitch: false, + respectPrefersColorScheme: true, + }, + announcementBar: { + id: `announcementBar-v${announcedVersion}`, + // content: `⭐️ If you like Docusaurus, give it a star on GitHub and follow us on X ${TwitterSvg}`, + content: `🎉️ Docusaurus v${announcedVersion} is out! 🥳️`, + }, + prism: { + additionalLanguages: [ + 'java', + 'latex', + 'haskell', + 'matlab', + 'PHp', + 'powershell', + 'bash', + 'diff', + 'json', + 'scss', + ], + magicComments: [ + { + className: 'theme-code-block-highlighted-line', + line: 'highlight-next-line', + block: {start: 'highlight-start', end: 'highlight-end'}, + }, + { + className: 'code-block-error-line', + line: 'This will error', + }, + ], + theme: PrismLight, + darkTheme: PrismDark, + }, + image: 'img/docusaurus-social-card.jpg', + // metadata: [{name: 'twitter:card', content: 'summary'}], + algolia: { + appId: 'X1Z85QJPUV', + apiKey: 'bf7211c161e8205da2f933a02534105a', + indexName: 'docusaurus-2', + + // TODO Docusaurus v4: remove after we drop DocSearch v3 + // temporary, for DocSearch v3/v4 conditional Ask AI integration + // see https://github.com/facebook/docusaurus/pull/11327 + ...(require('@docsearch/react').version.startsWith('4.') + ? { + askAi: { + // cSpell:ignore IMYF + assistantId: 'RgIMYFUmTfrN', + indexName: 'docusaurus-markdown', + suggestedQuestions: true, + }, + } + : {}), + + replaceSearchResultPathname: + isDev || isDeployPreview + ? { + from: /^\/docs\/next/g.source, + to: '/docs', + } + : undefined, + }, + navbar: { + hideOnScroll: true, + title: 'Docusaurus', + logo: { + alt: '', + src: 'img/docusaurus.svg', + srcDark: 'img/docusaurus_keytar.svg', + width: 32, + height: 32, + }, + items: [ + { + type: 'doc', + position: 'left', + docId: 'introduction', + label: 'Docs', + }, + { + type: 'docSidebar', + position: 'left', + sidebarId: 'api', + label: 'API', + }, + {to: 'blog', label: 'Blog', position: 'left'}, + {to: 'showcase', label: 'Showcase', position: 'left'}, + { + to: '/community/support', + label: 'Community', + position: 'left', + activeBaseRegex: `/community/`, + }, + // This item links to a draft doc: only displayed in dev + { + type: 'doc', + docId: 'index', + label: 'Tests', + docsPluginId: 'docs-tests', + }, + isDev && {to: '/__docusaurus/debug', label: 'Debug'}, + // Custom item for dogfooding: only displayed in /tests/ routes + { + type: 'custom-dogfood-navbar-item', + content: '😉', + }, + // Right + { + type: 'docsVersionDropdown', + position: 'right', + dropdownActiveClassDisabled: true, + dropdownItemsAfter: [ + { + type: 'html', + value: '', + }, + { + type: 'html', + className: 'dropdown-archived-versions', + value: 'Archived versions', + }, + ...ArchivedVersionsDropdownItems.map( + ([versionName, versionUrl]) => ({ + label: versionName, + href: versionUrl, + }), + ), + { + href: 'https://v1.docusaurus.io', + label: '1.x.x', + }, + { + type: 'html', + value: '', + }, + { + to: '/versions', + label: 'All versions', + }, + ], + }, + { + type: 'localeDropdown', + position: 'right', + dropdownItemsAfter: [ + { + type: 'html', + value: '
', + }, + { + href: 'https://github.com/facebook/docusaurus/issues/3526', + label: 'Help Us Translate', + }, + ], + }, + { + href: 'https://github.com/facebook/docusaurus', + position: 'right', + className: 'header-github-link', + 'aria-label': 'GitHub repository', + }, + ] + // TODO fix type + .filter(Boolean) as NonNullable< + Preset.ThemeConfig['navbar'] + >['items'], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Learn', + items: [ + { + label: 'Introduction', + to: 'docs', + }, + { + label: 'Installation', + to: 'docs/installation', + }, + { + label: 'Migration from v1 to v2', + to: 'docs/migration', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Stack Overflow', + href: 'https://stackoverflow.com/questions/tagged/docusaurus', + }, + { + label: 'Feature Requests', + to: '/feature-requests', + }, + { + label: 'Discord', + href: 'https://discordapp.com/invite/docusaurus', + }, + { + label: 'Help', + to: '/community/support', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Blog', + to: 'blog', + }, + { + label: 'Changelog', + to: '/changelog', + }, + { + label: 'GitHub', + href: 'https://github.com/facebook/docusaurus', + }, + { + label: 'X', + href: 'https://x.com/docusaurus', + }, + { + html: ` + + Deploys by Netlify + + `, + }, + { + html: ` + + Covered by Argos + + `, + }, + ], + }, + { + title: 'Legal', + className: 'footer-column-legal', + // Don't remove the privacy and terms, it's a legal requirement. + items: [ + { + label: 'Privacy', + className: 'footer-item-privacy', + href: 'https://opensource.facebook.com/legal/privacy/', + }, + { + label: 'Terms', + href: 'https://opensource.facebook.com/legal/terms/', + }, + { + label: 'Cookie Policy', + href: 'https://opensource.facebook.com/legal/cookie-policy/', + }, + ], + }, + ], + logo: { + alt: 'Meta Open Source Logo', + src: '/img/meta_opensource_logo_negative.svg', + href: 'https://opensource.fb.com', + }, + copyright: `Copyright © ${new Date().getFullYear()} Meta Platforms, Inc. Built with Docusaurus.`, + }, + } satisfies ThemeConfig, + } satisfies Config; +} diff --git a/deps/swc/crates/swc_ts_fast_strip/benches/assets/graphile.config.ts b/deps/swc/crates/swc_ts_fast_strip/benches/assets/graphile.config.ts new file mode 100644 index 000000000..1ec76f7d7 --- /dev/null +++ b/deps/swc/crates/swc_ts_fast_strip/benches/assets/graphile.config.ts @@ -0,0 +1,747 @@ +/* eslint-disable import/no-unresolved */ +import type { PgSelectSingleStep } from "@dataplan/pg"; +import PersistedPlugin from "@grafserv/persisted"; +import { EXPORTABLE, exportSchema } from "graphile-export"; +import { extendSchema, wrapPlans } from "graphile-utils"; +import * as jsonwebtoken from "jsonwebtoken"; +import type {} from "postgraphile"; +import { jsonParse } from "postgraphile/@dataplan/json"; +import { makePgService } from "postgraphile/adaptors/pg"; +import type { EdgeStep, ObjectStep } from "postgraphile/grafast"; +import { + connection, + constant, + context, + error, + isAsyncIterable, + lambda, + list, + listen, + object, + sideEffect, +} from "postgraphile/grafast"; +import { defaultMaskError } from "postgraphile/grafserv"; +import type {} from "postgraphile/grafserv/node"; +import { StreamDeferPlugin } from "postgraphile/graphile-build"; +import { PostGraphileAmberPreset } from "postgraphile/presets/amber"; +import { PgLazyJWTPreset } from "postgraphile/presets/lazy-jwt"; +import { PostGraphileRelayPreset } from "postgraphile/presets/relay"; +import { makeV4Preset } from "postgraphile/presets/v4"; + +// import { PgManyToManyPreset } from "../../contrib/pg-many-to-many/dist/index.js"; +// import { PostGraphileConnectionFilterPreset } from "../../contrib/postgraphile-plugin-connection-filter/dist/index.js"; + +// Every field plan is wrapped in a side effect; should this side effect log the results? +const LOG_RESULTS = false; + +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +declare global { + namespace Grafast { + interface Context { + mol?: number; + number?: number; + } + } +} + +/* +const PrimaryKeyMutationsOnlyPlugin: GraphileConfig.Plugin = { + name: "PrimaryKeyMutationsOnlyPlugin", + version: "0.0.0", + + gather: { + hooks: { + pgIntrospection_introspection(info, event) { + const { introspection } = event; + for (const pgConstraint of introspection.constraints) { + if (pgConstraint.contype === "u") { + const tags = pgConstraint.getTags(); + const newBehavior = ["-update", "-delete"]; + if (typeof tags.behavior === "string") { + newBehavior.push(tags.behavior); + } else if (Array.isArray(tags.behavior)) { + newBehavior.push(...tags.behavior); + } + tags.behavior = newBehavior; + console.log(pgConstraint.getClass().relname, newBehavior); + } + } + }, + }, + }, +}; +*/ + +const HTML_ESCAPES = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", +}; +function escapeHTML(rawText: string): string { + return rawText.replace( + /[&<>"']/g, + (l) => HTML_ESCAPES[l as keyof typeof HTML_ESCAPES], + ); +} + +function ruruTitle(title: string): GraphileConfig.Plugin { + return { + name: "RuruTitlePlugin", + version: "0.0.0", + + grafserv: { + middleware: { + ruruHTML(next, event) { + const { htmlParts, request } = event; + htmlParts.titleTag = `${escapeHTML( + title + " | " + request.getHeader("host"), + )}`; + return next(); + }, + }, + }, + }; +} + +const RuruQueryParamsPlugin: GraphileConfig.Plugin = { + name: "RuruQueryParamsPlugin", + version: "0.0.0", + + grafserv: { + middleware: { + ruruHTML(next, event) { + const { htmlParts } = event; + htmlParts.headerScripts += ` + +`; + return next(); + }, + }, + }, +}; + +/** + * Update the URL search params with the current query and variables + */ +const RuruQueryParamsUpdatePlugin: GraphileConfig.Plugin = { + name: "RuruQueryParamsUpdatePlugin", + version: "0.0.0", + + grafserv: { + middleware: { + ruruHTML(next, event) { + const { htmlParts } = event; + htmlParts.headerScripts += ` + +`; + return next(); + }, + }, + }, +}; + +const ExportSchemaPlugin: GraphileConfig.Plugin = { + name: "ExportSchemaPlugin", + version: "0.0.0", + + schema: { + hooks: { + finalize(schema) { + exportSchema(schema, `${__dirname}/exported-schema.mjs`, { + mode: "typeDefs", + modules: { + jsonwebtoken, + }, + }).catch((e) => { + console.error(e); + }); + return schema; + }, + }, + }, +}; + +const NonNullRelationsPlugin: GraphileConfig.Plugin = { + name: "NonNullRelationsPlugin", + description: + "Makes foreign key fields non-nullable if their columns are all `not null`", + version: "0.0.0", + + schema: { + hooks: { + // Hook a field that has already been defined + GraphQLObjectType_fields_field(field, build, context) { + const { + graphql: { GraphQLNonNull, getNullableType }, + input: { pgRegistry }, + } = build; + // Extract details about why this field was defined. + const { isPgSingleRelationField, pgRelationDetails } = context.scope; + // See if the field was defined for a singular relation + if (isPgSingleRelationField && pgRelationDetails) { + // If so, extract details about the relation + const { codec, relationName } = pgRelationDetails; + // Look up the relation in the registry + const relation = pgRegistry.pgRelations[codec.name][relationName]; + // Determine if every column is non-null + const everyColumnIsNonNull = relation.localAttributes.every( + (attrName) => codec.attributes[attrName].notNull, + ); + if (!relation.isReferencee && everyColumnIsNonNull) { + // If so, change the type of the field to be non-nullable + field.type = new GraphQLNonNull(getNullableType(field.type)); + } + } + return field; + }, + }, + }, +}; + +const LeftArmPlugin = extendSchema((build) => { + const { left_arm } = build.input.pgRegistry.pgResources; + return { + typeDefs: /* GraphQL */ ` + extend type Person { + allArms: PersonRelatedArmConnection + } + type PersonRelatedArmConnection { + edges: [PersonRelatedArmEdge] + } + type PersonRelatedArmEdge { + node: LeftArm + isTheirs: Boolean + } + `, + objects: { + Person: { + plans: { + allArms: EXPORTABLE( + (connection, left_arm, object) => ($person) => { + const $arms = left_arm.find(); + + return connection($arms, { + edgeDataPlan($arm) { + return object({ arm: $arm, person: $person }); + }, + }); + }, + [connection, left_arm, object], + ), + }, + }, + PersonRelatedArmEdge: { + plans: { + isTheirs: EXPORTABLE( + (aEqualsB, lambda) => + ( + $edge: EdgeStep< + any, + any, + ObjectStep<{ + arm: PgSelectSingleStep; + person: PgSelectSingleStep; + }> + >, + ) => { + const $obj = $edge.data(); + const $arm = $obj.get("arm"); + const $armPersonId = $arm.get("person_id"); + const $person = $obj.get("person"); + const $personId = $person.get("id"); + return lambda([$personId, $armPersonId], aEqualsB); + }, + [aEqualsB, lambda], + ), + }, + }, + }, + }; +}); + +const testResolver = EXPORTABLE( + (context, sideEffect) => + function () { + const $context = context(); + sideEffect($context, (context) => (context.number = 3)); + sideEffect($context, (context) => context.number!++); + sideEffect($context, (_context) => { + throw new Error("Side effect 3 failed"); + }); + sideEffect($context, (context) => context.number!++); + sideEffect($context, (context) => context.number!++); + return $context.get("number"); + }, + [context, sideEffect], +); + +const TestSideEffectCancellingPlugin = extendSchema({ + typeDefs: /* GraphQL */ ` + extend type Query { + testSideEffectCancelling: Int + } + extend type Mutation { + testSideEffectCancelling: Int + } + `, + objects: { + Mutation: { + plans: { + testSideEffectCancelling: testResolver, + }, + }, + Query: { + plans: { + testSideEffectCancelling: testResolver, + }, + }, + }, +}); + +const AddToResponseExtensionsPropertyPlugin: GraphileConfig.Plugin = { + name: "AddToResponseExtensionsPropertyPlugin", + + grafast: { + middleware: { + execute(next, event) { + return next.callback((error, result) => { + if (error) throw error; + const context = (event.args.contextValue ?? + Object.create(null)) as Grafast.Context; + if (!isAsyncIterable(result)) { + if (!result.extensions) result.extensions = Object.create(null); + result.extensions!.number = context.number; + } + return result; + }); + }, + }, + }, +}; + +const preset: GraphileConfig.Preset = { + plugins: [ + StreamDeferPlugin, + extendSchema((build) => { + const { + dataplanPg: { TYPES }, + } = build; + return { + typeDefs: /* GraphQL */ ` + extend type Person { + greet( + greeting: String! = "Hello" @deprecated(reason: "TESTING") + ): String + query: Query + } + extend type Query { + throw: Int + wrapMe: Int + } + `, + objects: { + Query: { + plans: { + wrapMe: EXPORTABLE((constant) => () => constant(42), [constant]), + throw: EXPORTABLE( + (error) => () => { + return error( + Object.assign( + new Error( + "You've requested the 'throw' field... which throws!", + ), + { + metadata: true, + mol: 42, + }, + ), + ); + }, + [error], + ), + }, + }, + Person: { + plans: { + greet: EXPORTABLE( + (TYPES) => + ($user: PgSelectSingleStep, { $greeting }) => { + const placeholderSql = $user.placeholder( + $greeting, + TYPES.text, + ); + return $user.select( + (sql) => sql`${placeholderSql} || ', ' || ${$user}.name`, + TYPES.text, + ); + }, + [TYPES], + ), + query: EXPORTABLE( + (constant) => () => { + return constant(true); + }, + [constant], + ), + }, + }, + }, + }; + }), + wrapPlans({ + Query: { + wrapMe(plan) { + return plan(); + }, + }, + Mutation: { + updatePost(plan) { + return plan(); + }, + }, + }), + extendSchema({ + typeDefs: /* GraphQL */ ` + extend type Query { + mol: Int + } + extend type Subscription { + sub(topic: String!): Int + gql(max: Int! = 10): Int + slow: String + } + `, + objects: { + Query: { + plans: { + mol: EXPORTABLE( + (context) => () => { + return context().get("mol"); + }, + [context], + ), + }, + }, + Subscription: { + plans: { + // Test via SQL: `NOTIFY test, '{"a":40}';` + sub: EXPORTABLE( + (context, jsonParse, listen, object) => (_$root, args) => { + const $topic = args.getRaw("topic"); + const $pgSubscriber = context().get("pgSubscriber"); + return listen($pgSubscriber, $topic, ($payload) => + object({ sub: jsonParse($payload).get("a" as never) }), + ); + }, + [context, jsonParse, listen, object], + ), + gql: { + resolve: EXPORTABLE( + () => + function resolve(e) { + return e; + }, + [], + ), + subscribe: EXPORTABLE( + (sleep) => + async function* subscribe(_, { max }) { + for (let i = 1; i <= max; i++) { + yield i; + await sleep(300); + } + }, + [sleep], + ), + }, + slow: { + resolve: EXPORTABLE( + () => + function resolve(e) { + return e; + }, + [], + ), + subscribe: EXPORTABLE( + (sleep) => + async function* subscribe() { + while (true) { + yield new Date().toISOString(); + // Wait two minutes between ticks + await sleep(120000); + } + }, + [sleep], + ), + }, + }, + }, + }, + }), + extendSchema({ + typeDefs: /* GraphQL */ ` + extend type Subscription { + error: Int + errorAfter(n: Int! = 3): Int + } + `, + objects: { + Subscription: { + plans: { + error: { + subscribePlan: EXPORTABLE( + (constant, lambda) => + function subscribePlan() { + return lambda(constant(3), () => { + throw new Error("Testing error"); + }); + }, + [constant, lambda], + ), + }, + errorAfter: { + subscribe: EXPORTABLE( + (sleep) => + async function* subscribe(_, { n }) { + for (let i = 0; i < n; i++) { + yield i; + await sleep(1000); + } + throw new Error(`Error after ${n}`); + }, + [sleep], + ), + resolve: EXPORTABLE( + () => + function resolve(i) { + return i; + }, + [], + ), + }, + }, + }, + }, + }), + // Testing errors + extendSchema({ + typeDefs: /* GraphQL */ ` + extend type Query { + errorTests: ErrorTests + } + extend type Subscription { + errorTests: ErrorTests + } + type ErrorTests { + nested: ErrorTests + nestedList: [ErrorTests] + index: Int + errorOnOddNumbers: Int! + fourtyTwo: Int! + nonNullableReturningNull: Int! + coercionFailure: Int + planningError: Int + } + `, + objects: { + Query: { + plans: { + errorTests: EXPORTABLE( + (constant) => () => constant({}), + [constant], + ), + }, + }, + Subscription: { + plans: { + errorTests: { + subscribePlan: EXPORTABLE( + (lambda, sleep) => () => { + return lambda(null, () => { + return (async function* () { + for (let index = 0; ; index++) { + yield { index }; + await sleep(1000); + } + })(); + }); + }, + [lambda, sleep], + ), + plan: EXPORTABLE( + () => + function plan($event) { + return $event; + }, + [], + ), + }, + }, + }, + ErrorTests: { + plans: { + planningError: EXPORTABLE( + () => () => { + throw new Error(`This error occurred during planning!`); + }, + [], + ), + nested: EXPORTABLE(() => ($test) => $test, []), + nestedList: EXPORTABLE((list) => ($test) => list([$test]), [list]), + errorOnOddNumbers: EXPORTABLE( + (lambda) => ($payload) => + lambda($payload, (p: any) => { + if (p.index % 2 === 1) { + throw new Error(`ODD! ${p.index}`); + } else { + return p.index; + } + }), + [lambda], + ), + fourtyTwo: EXPORTABLE((constant) => () => constant(42), [constant]), + nonNullableReturningNull: EXPORTABLE( + (constant) => () => constant(null), + [constant], + ), + coercionFailure: EXPORTABLE( + (constant) => () => constant("NOT A NUMBER"), + [constant], + ), + }, + }, + }, + }), + // PrimaryKeyMutationsOnlyPlugin, + PersistedPlugin, + ruruTitle(""), + ExportSchemaPlugin, + NonNullRelationsPlugin, + RuruQueryParamsPlugin, + RuruQueryParamsUpdatePlugin, + ...(Math.random() > 2 ? [LeftArmPlugin] : []), + TestSideEffectCancellingPlugin, + AddToResponseExtensionsPropertyPlugin, + wrapPlans( + () => true, + () => ({ + // autoApplyFieldArgs: false, + plan: EXPORTABLE( + (LOG_RESULTS, sideEffect) => (plan, _) => { + const $result = plan(); + sideEffect( + $result, + (r) => void (LOG_RESULTS ? console.dir(r) : null), + ); + return $result; + }, + [LOG_RESULTS, sideEffect], + ), + }), + ), + ], + extends: [ + PostGraphileAmberPreset, + makeV4Preset({ + simpleCollections: "both", + jwtPgTypeIdentifier: '"b"."jwt_token"', + dynamicJson: true, + graphiql: true, + graphiqlRoute: "/", + ignoreRBAC: false, + simpleSubscriptions: true, + }), + // PgManyToManyPreset, + // PostGraphileConnectionFilterPreset, + PostGraphileRelayPreset, + PgLazyJWTPreset, + ], + ruru: { + htmlParts: { + metaTags: (base) => base + "", + }, + }, + inflection: {}, + gather: { + pgJwtTypes: "b.jwt_token", + }, + schema: { + retryOnInitFail: true, + exportSchemaSDLPath: `${__dirname}/latestSchema.graphql`, + exportSchemaIntrospectionResultPath: `${__dirname}/latestSchema.json`, + sortExport: true, + pgJwtSecret: "FROGS", + }, + grafserv: { + port: 5678, + graphqlPath: "/graphql", + websockets: true, + graphqlOverGET: true, + persistedOperationsDirectory: `${process.cwd()}/.persisted_operations`, + allowUnpersistedOperation: true, + maskError(error) { + const masked = defaultMaskError(error); + const stack = error.originalError?.stack; + if (typeof stack === "string") { + masked.extensions.stack = stack.split(/\n/); + } + return masked; + }, + }, + grafast: { + context(requestContext, args) { + return { + number: -1, + pgSettings: { + // role: "postgres", + ...args.contextValue?.pgSettings, + }, + mol: 42, + }; + }, + explain: true, + }, + pgServices: [ + makePgService({ + // Database connection string: + connectionString: + process.env.DATABASE_URL ?? "postgres:///graphilecrystaltest", + // List of schemas to expose: + schemas: + process.env.DATABASE_SCHEMAS?.split(",") ?? + (process.env.DATABASE_URL ? ["public"] : ["a", "b", "c"]), + // Enable LISTEN/NOTIFY client + pubsub: true, + }), + ], +}; /* satisfies GraphileConfig.Preset */ + +function aEqualsB([a, b]: readonly [a: any, b: any]) { + return a === b; +} +export default preset; diff --git a/deps/swc/crates/swc_ts_fast_strip/benches/assets/hono.types.test.ts b/deps/swc/crates/swc_ts_fast_strip/benches/assets/hono.types.test.ts new file mode 100644 index 000000000..c8c3a44a9 --- /dev/null +++ b/deps/swc/crates/swc_ts_fast_strip/benches/assets/hono.types.test.ts @@ -0,0 +1,3294 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { expectTypeOf } from 'vitest' +import { hc } from './client' +import { Context } from './context' +import { createMiddleware } from './helper/factory' +import { Hono } from './hono' +import { poweredBy } from './middleware/powered-by' +import type { + AddParam, + Env, + ExtractSchema, + Handler, + InputToDataByTarget, + MergePath, + MergeSchemaPath, + MiddlewareHandler, + ParamKeyToRecord, + ParamKeys, + RemoveQuestion, + ResponseFormat, + ToSchema, + TypedResponse, +} from './types' +import type { ContentfulStatusCode, StatusCode } from './utils/http-status' +import type { Equal, Expect } from './utils/types' +import { validator } from './validator' + +describe('Env', () => { + test('Env', () => { + type E = { + Variables: { + foo: string + } + Bindings: { + FLAG: boolean + } + } + const app = new Hono() + app.use('*', poweredBy()) + app.get('/', (c) => { + const foo = c.get('foo') + expectTypeOf(foo).toEqualTypeOf() + const FLAG = c.env.FLAG + expectTypeOf(FLAG).toEqualTypeOf() + return c.text('foo') + }) + }) +}) + +describe('HandlerInterface', () => { + type Env = {} + + type Payload = { foo: string; bar: boolean } + + describe('no path pattern', () => { + const app = new Hono() + const middleware: MiddlewareHandler< + Env, + '/', + { + in: { json: Payload } + out: { json: Payload } + } + > = async (_c, next) => { + await next() + } + test('Context', () => { + const route = app.get(middleware, (c) => { + type Expected = Context< + Env, + '/', + { + in: { json: Payload } + out: { json: Payload } + } + > + expectTypeOf(c).toEqualTypeOf() + return c.json({ + message: 'Hello!', + }) + }) + app.get(middleware, (c) => { + const data = c.req.valid('json') + expectTypeOf(data).toEqualTypeOf() + return c.json({ + message: 'Hello!', + }) + }) + type Actual = ExtractSchema + type Expected = { + '/': { + $get: { + input: { + json: Payload + } + output: { + message: string + } + outputFormat: 'json' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + }) + + describe('path pattern', () => { + const app = new Hono() + const middleware: MiddlewareHandler< + Env, + '/foo', + { in: { json: Payload }; out: { json: Payload } }, + never + > = async (_c, next) => { + await next() + } + + test('Context and AppType', () => { + const route = app.get('/foo', middleware, (c) => { + type Expected = Context + expectTypeOf(c).toEqualTypeOf() + return c.json({ + message: 'Hello!', + }) + }) + type Actual = ExtractSchema + type Expected = { + '/foo': { + $get: { + input: { + json: { + foo: string + bar: boolean + } + } + output: { + message: string + } + outputFormat: 'json' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + }) + + describe('With path parameters', () => { + const app = new Hono() + const middleware: MiddlewareHandler = async (_c, next) => { + await next() + } + it('Should have the `param` type', () => { + const route = app.get('/post/:id', middleware, (c) => { + return c.text('foo') + }) + type Actual = ExtractSchema + type Expected = { + '/post/:id': { + $get: { + input: { + param: { + id: string + } + } + output: 'foo' + outputFormat: 'text' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + }) + + describe('Without path', () => { + const app = new Hono().basePath('/foo/:foo') + + it('With basePath and path params', () => { + const route = app.get(async (c) => { + const foo = c.req.param('foo') + expect(typeof foo).toBe('string') + return c.text(foo) + }) + type Actual = ExtractSchema + + type Expected = { + '/foo/:foo': { + $get: { + input: { + param: { + foo: string + } + } + output: string + outputFormat: 'text' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + + it('Chained', () => { + const route = app.post('/books/:id').get((c) => { + const id = c.req.param('id') + return c.text(id) + }) + type Actual = ExtractSchema + type Expected = { + '/foo/:foo/books/:id': { + $get: { + input: { + param: { + id: string + } & { + foo: string + } + } + output: string + outputFormat: 'text' + status: ContentfulStatusCode + } + } + } & { + '/foo/:foo/books/:id': { + $post: { + input: { + param: { + id: string + } & { + foo: string + } + } + output: {} + outputFormat: ResponseFormat + status: StatusCode + } + } + } + type verify = Expect> + }) + }) +}) + +describe('OnHandlerInterface', () => { + const app = new Hono() + test('Context', () => { + const middleware: MiddlewareHandler< + Env, + '/purge', + { in: { form: { id: string } }; out: { form: { id: number } } } + > = async (_c, next) => { + await next() + } + const route = app.on('PURGE', '/purge', middleware, (c) => { + const data = c.req.valid('form') + expectTypeOf(data).toEqualTypeOf<{ id: number }>() + return c.json({ + success: true, + }) + }) + type Actual = ExtractSchema + type Expected = { + '/purge': { + $purge: { + input: { + form: { + id: string + } + } + output: { + success: true + } + outputFormat: 'json' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + + test('app.on(method, path[], middleware, handler) should not throw a type error', () => { + const middleware: MiddlewareHandler<{ Variables: { foo: string } }> = async () => {} + app.on('GET', ['/a', '/b'], middleware, (c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + return c.json({}) + }) + }) +}) + +describe('TypedResponse', () => { + test('unknown', () => { + type Actual = TypedResponse + type Expected = { + _data: unknown + _status: StatusCode + _format: ResponseFormat + } + type verify = Expect> + }) + + test('text auto infer', () => { + type Actual = TypedResponse + type Expected = { + _data: string + _status: StatusCode + _format: 'text' + } + type verify = Expect> + }) + + test('json auto infer', () => { + type Actual = TypedResponse<{ ok: true }> + type Expected = { + _data: { ok: true } + _status: StatusCode + _format: 'json' + } + type verify = Expect> + }) +}) + +describe('Schema', () => { + test('Schema', () => { + type AppType = Hono< + Env, + ToSchema< + 'post', + '/api/posts/:id', + { + in: { + json: { + id: number + title: string + } + } + }, + TypedResponse< + { + message: string + success: boolean + }, + StatusCode, + 'json' + > + > + > + + type Actual = ExtractSchema + type Expected = { + '/api/posts/:id': { + $post: { + input: { + json: { + id: number + title: string + } + } & { + param: { + id: string + } + } + output: { + message: string + success: boolean + } + outputFormat: 'json' + status: StatusCode + } + } + } + type verify = Expect> + }) +}) + +describe('Support c.json(undefined)', () => { + it('Should return a correct type', () => { + const app = new Hono().get('/this/is/a/test', async (c) => { + return c.json(undefined) + }) + type Actual = ExtractSchema + type Expected = { + '/this/is/a/test': { + $get: { + input: {} + output: never + outputFormat: 'json' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) +}) + +describe('Test types of Handler', () => { + type E = { + Variables: { + foo: number + } + } + + const url = 'http://localhost/' + + test('Env', async () => { + const app = new Hono() + const handler: Handler = (c) => { + const foo = c.get('foo') + expectTypeOf(foo).toEqualTypeOf() + const id = c.req.param('id') + expectTypeOf(id).toEqualTypeOf() + return c.text('Hi') + } + app.get('/', handler) + const res = await app.request(url) + expect(res.status).toBe(200) + }) + + test('Env, Path', async () => { + const app = new Hono() + const handler: Handler = (c) => { + const foo = c.get('foo') + expectTypeOf(foo).toEqualTypeOf() + return c.text('Hi') + } + app.get('/', handler) + + const res = await app.request(url) + expect(res.status).toBe(200) + }) + + type User = { + name: string + age: number + } + + test('Env, Path, Type', async () => { + const app = new Hono() + const handler: Handler = (c) => { + const foo = c.get('foo') + expectTypeOf(foo).toEqualTypeOf() + const { name } = c.req.valid('json') + expectTypeOf(name).toEqualTypeOf() + return c.text('Hi') + } + }) +}) + +describe('`json()`', () => { + const app = new Hono<{ Variables: { foo: string } }>() + app.get('/post/:id', (c) => { + c.req.param('id') + const id = c.req.param('id') + return c.text('foo') + }) + + test('json', () => { + const route = app.get('/hello', (c) => { + return c.json({ + message: 'Hello!', + }) + }) + type Actual = ExtractSchema + type Expected = { + '/hello': { + $get: { + input: {} + output: { + message: string + } + outputFormat: 'json' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + + test('json with specific status code', () => { + const route = app.get('/hello', (c) => { + return c.json( + { + message: 'Hello!', + }, + 200 + ) + }) + type Actual = ExtractSchema + type Expected = { + '/hello': { + $get: { + input: {} + output: { + message: string + } + outputFormat: 'json' + status: 200 + } + } + } + type verify = Expect> + }) +}) + +describe('Path parameters', () => { + test('ParamKeys', () => { + type Actual = ParamKeys<'/posts/:postId/comment/:commentId'> + type Expected = 'postId' | 'commentId' + type verify = Expect> + }) + + describe('ParamKeyToRecord', () => { + test('With ?', () => { + type Actual = ParamKeyToRecord<'/animal/type?'> + type Expected = { [K in '/animal/type']: string | undefined } + type verify = Expect> + }) + test('Without ?', () => { + type Actual = ParamKeyToRecord<'/animal/type'> + type Expected = { [K in '/animal/type']: string } + type verify = Expect> + }) + }) + + describe('Path parameters in app', () => { + test('Optional parameters - /api/:a/:b?', () => { + const app = new Hono() + const routes = app.get('/api/:a/:b?', (c) => { + const a = c.req.param('a') + const b = c.req.param('b') + expectTypeOf(a).toEqualTypeOf() + expectTypeOf(b).toEqualTypeOf() + return c.json({ a, b }) + }) + type T = ExtractSchema + type Output = T['/api/:a/:b?']['$get']['output'] + type Expected = { + a: string + b: string | undefined + } + type verify = Expect> + }) + }) +}) + +describe('For HonoRequest', () => { + type Input = { + json: { + id: number + title: string + } + query: { + page: string + } + } + + test('InputToDataByType with value', () => { + type Actual = InputToDataByTarget + type Expected = { + id: number + title: string + } + type verify = Expect> + }) + + test('InputToDataByType without value', () => { + type Actual = InputToDataByTarget + type verify = Expect> + }) + + test('RemoveQuestion', () => { + type Actual = RemoveQuestion<'/animal/type?'> + type verify = Expect> + }) +}) + +describe('AddParam', () => { + it('Should add params to input correctly', () => { + type Actual = AddParam< + { + param: { + id: string + } + } & { + query: { + page: string + } + }, + '/:id' + > + type Expected = { + query: { + page: string + } + } & { + param: { + id: string + } + } + type verify = Expect> + }) +}) + +describe('ToSchema', () => { + it('Should convert parameters to schema correctly', () => { + type Actual = ToSchema< + 'get', + '/:id', + { in: { param: { id: string }; query: { page: string } } }, + TypedResponse<{}> + > + type Expected = { + '/:id': { + $get: { + input: { + param: { + id: string + } + query: { + page: string + } + } + output: {} + outputFormat: 'json' + status: StatusCode + } + } + } + type verify = Expect> + }) +}) + +describe('MergePath', () => { + it('Should merge paths correctly', () => { + type path1 = MergePath<'/api', '/book'> + type verify1 = Expect> + type path2 = MergePath<'/api/', '/book'> + type verify2 = Expect> + type path3 = MergePath<'/api/', '/'> + type verify3 = Expect> + type path4 = MergePath<'/api', '/'> + type verify4 = Expect> + type path5 = MergePath<'/', ''> + type verify5 = Expect> + type path6 = MergePath<'', '/'> + type verify6 = Expect> + type path7 = MergePath<'/', '/'> + type verify7 = Expect> + type path8 = MergePath<'', ''> + type verify8 = Expect> + }) +}) + +describe('MergeSchemaPath', () => { + it('Should merge schema and sub path correctly', () => { + type Sub = ToSchema< + 'post', + '/posts', + { + in: { + json: { + id: number + title: string + } + } + }, + TypedResponse<{ + message: string + }> + > & + ToSchema< + 'get', + '/posts', + {}, + TypedResponse<{ + ok: boolean + }> + > + + type Actual = MergeSchemaPath + + type Expected = { + '/api/posts': { + $post: { + input: { + json: { + id: number + title: string + } + } + output: { + message: string + } + outputFormat: 'json' + status: StatusCode + } + $get: { + input: {} + output: { + ok: boolean + } + outputFormat: 'json' + status: StatusCode + } + } + } + + type verify = Expect> + }) + + it('Should merge schema which has params and sub path does not have params', () => { + type Actual = MergeSchemaPath< + { + '/': { + $get: { + input: { + param: { + id: string + } + query: { + page: string + } + } + output: {} + outputFormat: 'json' + status: StatusCode + } + } + }, + '/something' + > + type Expected = { + '/something': { + $get: { + input: { + param: { + id: string + } + query: { + page: string + } + } + output: {} + outputFormat: 'json' + status: StatusCode + } + } + } + type verify = Expect> + }) + + type GetKey = T extends Record ? K : never + + it('Should remove a slash - `/` + `/`', () => { + type Sub = ToSchema<'get', '/', {}, TypedResponse<{}>> + type Actual = MergeSchemaPath + type verify = Expect>> + }) + + it('Should remove a slash - `/tags` + `/`', () => { + type Sub = ToSchema<'get', '/tags', {}, TypedResponse<{}>> + type Actual = MergeSchemaPath + type verify = Expect>> + }) + + it('Should remove a slash - `/` + `/tags`', () => { + type Sub = ToSchema<'get', '/', {}, TypedResponse<{}>> + type Actual = MergeSchemaPath + type verify = Expect>> + }) + + test('MergeSchemaPath - SubPath has path params', () => { + type Actual = MergeSchemaPath, '/a/:b'> + type Expected = { + '/a/:b': { + $get: { + input: { + param: { + b: string + } + } + output: {} + outputFormat: ResponseFormat + status: StatusCode + } + } + } + type verify = Expect> + }) + + test('MergeSchemaPath - Path and SubPath have path params', () => { + type Actual = MergeSchemaPath>, '/a/:b'> + type Expected = { + '/a/:b/c/:d': { + $get: { + input: { + param: { + d: string + } & { + b: string + } + } + output: {} + outputFormat: 'json' + status: StatusCode + } + } + } + type verify = Expect> + }) + + test('MergeSchemaPath - Path and SubPath have regexp path params', () => { + type Actual = MergeSchemaPath>, '/a/:b{.+}'> + type Expected = { + '/a/:b{.+}/c/:d{.+}': { + $get: { + input: { + param: { + d: string + } & { + b: string + } + } + output: {} + outputFormat: 'json' + status: StatusCode + } + } + } + type verify = Expect> + }) + + test('MergeSchemaPath - Method has Endpoints as Union', () => { + type Actual = MergeSchemaPath< + { + '/': { + $get: + | { + input: {} + output: { + error: string + } + outputFormat: 'json' + status: 404 + } + | { + input: {} + output: { + success: boolean + } + outputFormat: 'json' + status: 200 + } + } + }, + '/api/hello' + > + type Expected = { + '/api/hello': { + $get: + | { + input: {} + output: { + error: string + } + outputFormat: 'json' + status: 404 + } + | { + input: {} + output: { + success: boolean + } + outputFormat: 'json' + status: 200 + } + } + } + type verify = Expect> + }) +}) + +describe('Different types using json()', () => { + describe('no path pattern', () => { + const app = new Hono() + + test('Three different types', () => { + const route = app.get((c) => { + const flag = false + if (flag) { + return c.json({ + ng: true, + }) + } + if (!flag) { + return c.json({ + ok: true, + }) + } + return c.json({ + default: true, + }) + }) + type Actual = ExtractSchema + type Expected = { + '/': { + $get: + | { + input: {} + output: { + ng: true + } + outputFormat: 'json' + status: ContentfulStatusCode + } + | { + input: {} + output: { + ok: true + } + outputFormat: 'json' + status: ContentfulStatusCode + } + | { + input: {} + output: { + default: true + } + outputFormat: 'json' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + + test('Three different types and status codes', () => { + const route = app.get((c) => { + const flag = false + if (flag) { + return c.json( + { + ng: true, + }, + 400 + ) + } + if (!flag) { + return c.json( + { + ok: true, + }, + 200 + ) + } + return c.json({ + default: true, + }) + }) + type Actual = ExtractSchema + type Expected = { + '/': { + $get: + | { + input: {} + output: { + ng: true + } + outputFormat: 'json' + status: 400 + } + | { + input: {} + output: { + ok: true + } + outputFormat: 'json' + status: 200 + } + | { + input: {} + output: { + default: true + } + outputFormat: 'json' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + }) + + describe('path pattern', () => { + const app = new Hono() + + test('Three different types', () => { + const route = app.get('/foo', (c) => { + const flag = false + if (flag) { + return c.json({ + ng: true, + }) + } + if (!flag) { + return c.json({ + ok: true, + }) + } + return c.json({ + default: true, + }) + }) + type Actual = ExtractSchema + type Expected = { + '/foo': { + $get: + | { + input: {} + output: { + ng: true + } + outputFormat: 'json' + status: ContentfulStatusCode + } + | { + input: {} + output: { + ok: true + } + outputFormat: 'json' + status: ContentfulStatusCode + } + | { + input: {} + output: { + default: true + } + outputFormat: 'json' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + + test('Three different types and status codes', () => { + const route = app.get('/foo', (c) => { + const flag = false + if (flag) { + return c.json( + { + ng: true, + }, + 400 + ) + } + if (!flag) { + return c.json( + { + ok: true, + }, + 200 + ) + } + return c.json({ + default: true, + }) + }) + type Actual = ExtractSchema + type Expected = { + '/foo': { + $get: + | { + input: {} + output: { + ng: true + } + outputFormat: 'json' + status: 400 + } + | { + input: {} + output: { + ok: true + } + outputFormat: 'json' + status: 200 + } + | { + input: {} + output: { + default: true + } + outputFormat: 'json' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + }) +}) + +describe('json() in an async handler', () => { + const app = new Hono() + + test('json', () => { + const route = app.get(async (c) => { + return c.json({ + ok: true, + }) + }) + type Actual = ExtractSchema + type Expected = { + '/': { + $get: { + input: {} + output: { + ok: true + } + outputFormat: 'json' + status: ContentfulStatusCode + } + } + } + type verify = Expect> + }) + + test('json with specific status code', () => { + const route = app.get(async (c) => { + return c.json( + { + ok: true, + }, + 200 + ) + }) + type Actual = ExtractSchema + type Expected = { + '/': { + $get: { + input: {} + output: { + ok: true + } + outputFormat: 'json' + status: 200 + } + } + } + type verify = Expect> + }) +}) + +/** + * Other tests for `c.var` are written in `hono.test.ts`. + * This tests are only for types. + */ +describe('c.var with chaining - test only types', () => { + const mw1 = createMiddleware< + { Variables: { foo1: string } }, + string, + { out: { query: { bar1: number } } } + >(async () => {}) + const mw2 = createMiddleware< + { Variables: { foo2: string } }, + string, + { out: { query: { bar2: number } } } + >(async () => {}) + const mw3 = createMiddleware< + { Variables: { foo3: string } }, + string, + { out: { query: { bar3: number } } } + >(async () => {}) + const mw4 = createMiddleware< + { Variables: { foo4: string } }, + string, + { out: { query: { bar4: number } } } + >(async () => {}) + const mw5 = createMiddleware< + { Variables: { foo5: string } }, + string, + { out: { query: { bar5: number } } } + >(async () => {}) + const mw6 = createMiddleware< + { Variables: { foo6: string } }, + string, + { out: { query: { bar6: number } } } + >(async () => {}) + const mw7 = createMiddleware< + { Variables: { foo7: string } }, + string, + { out: { query: { bar7: number } } } + >(async () => {}) + const mw8 = createMiddleware< + { Variables: { foo8: string } }, + string, + { out: { query: { bar8: number } } } + >(async () => {}) + const mw9 = createMiddleware< + { Variables: { foo9: string } }, + string, + { out: { query: { bar9: number } } } + >(async () => {}) + const mw10 = createMiddleware< + { Variables: { foo10: string } }, + string, + { out: { query: { bar10: number } } } + >(async () => {}) + + it('Should not throw type errors', () => { + // app.get(handler...) + + new Hono().get(mw1).get('/', (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + return c.json(0) + }) + + new Hono().get(mw1, mw2).get('/', (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + return c.json(0) + }) + + new Hono().get(mw1, mw2, mw3).get('/', (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + return c.json(0) + }) + + new Hono().get(mw1, mw2, mw3, mw4).get('/', (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + return c.json(0) + }) + + new Hono().get(mw1, mw2, mw3, mw4, mw5).get('/', (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + return c.json(0) + }) + + new Hono().get(mw1, mw2, mw3, mw4, mw5, mw6).get('/', (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + return c.json(0) + }) + + new Hono().get(mw1, mw2, mw3, mw4, mw5, mw6, mw7).get('/', (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + expectTypeOf(c.var.foo7).toEqualTypeOf() + return c.json(0) + }) + + new Hono().get(mw1, mw2, mw3, mw4, mw5, mw6, mw7, mw8).get('/', (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + expectTypeOf(c.var.foo7).toEqualTypeOf() + expectTypeOf(c.var.foo8).toEqualTypeOf() + return c.json(0) + }) + + new Hono().get(mw1, mw2, mw3, mw4, mw5, mw6, mw7, mw8, mw9).get('/', (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + expectTypeOf(c.var.foo7).toEqualTypeOf() + expectTypeOf(c.var.foo8).toEqualTypeOf() + expectTypeOf(c.var.foo9).toEqualTypeOf() + return c.json(0) + }) + + new Hono().get(mw1, mw2, mw3, mw4, mw5, mw6, mw7, mw8, mw9, mw10).get('/', (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + expectTypeOf(c.var.foo7).toEqualTypeOf() + expectTypeOf(c.var.foo8).toEqualTypeOf() + expectTypeOf(c.var.foo9).toEqualTypeOf() + expectTypeOf(c.var.foo10).toEqualTypeOf() + return c.json(0) + }) + + new Hono().get( + mw1, + mw2, + mw3, + mw4, + mw5, + mw6, + mw7, + mw8, + async (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + expectTypeOf(c.var.foo7).toEqualTypeOf() + expectTypeOf(c.var.foo8).toEqualTypeOf() + }, + (c) => c.json(0) + ) + + new Hono().get(mw1, mw2, mw3, mw4, mw5, mw6, mw7, mw8, mw9, (c) => { + expectTypeOf(c.req.valid('query')).toMatchTypeOf<{ + bar1: number + bar2: number + bar3: number + bar4: number + bar5: number + bar6: number + bar7: number + bar8: number + bar9: number + }>() + + return c.json(0) + }) + + new Hono().get( + '/', + mw1, + mw2, + mw3, + mw4, + mw5, + mw6, + mw7, + mw8, + async (c) => { + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + expectTypeOf(c.var.foo7).toEqualTypeOf() + expectTypeOf(c.var.foo8).toEqualTypeOf() + }, + (c) => c.json(0) + ) + + new Hono().get('/', mw1, mw2, mw3, mw4, mw5, mw6, mw7, mw8, mw9, (c) => { + expectTypeOf(c.req.valid('query')).toMatchTypeOf<{ + bar1: number + bar2: number + bar3: number + bar4: number + bar5: number + bar6: number + bar7: number + bar8: number + bar9: number + }>() + + return c.json(0) + }) + + type Env = { + Variables: { + init: number + } + } + + new Hono() + .get('/', mw1, (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.var.foo1).toEqualTypeOf() + return c.json(0) + }) + .get('/', (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + // @ts-expect-error foo1 is not typed + c.get('foo1') + // @ts-expect-error foo1 is not typed + c.var.foo1 + return c.json(0) + }) + new Hono() + .get('/', mw1, mw2, (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.get('foo2')).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + return c.json(0) + }) + .get('/', (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + // @ts-expect-error foo1 is not typed + c.get('foo1') + // @ts-expect-error foo1 is not typed + c.var.foo1 + // @ts-expect-error foo2 is not typed + c.get('foo2') + // @ts-expect-error foo2 is not typed + c.var.foo2 + return c.json(0) + }) + new Hono() + .get('/', mw1, mw2, mw3, (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.get('foo2')).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.get('foo3')).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + return c.json(0) + }) + .get('/', (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + // @ts-expect-error foo1 is not typed + c.get('foo1') + // @ts-expect-error foo1 is not typed + c.var.foo1 + // @ts-expect-error foo2 is not typed + c.get('foo2') + // @ts-expect-error foo2 is not typed + c.var.foo2 + // @ts-expect-error foo3 is not typed + c.get('foo3') + // @ts-expect-error foo3 is not typed + c.var.foo3 + return c.json(0) + }) + new Hono() + .get('/', mw1, mw2, mw3, mw4, (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.get('foo2')).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.get('foo3')).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.get('foo4')).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + return c.json(0) + }) + .get('/', (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + // @ts-expect-error foo1 is not typed + c.get('foo1') + // @ts-expect-error foo1 is not typed + c.var.foo1 + // @ts-expect-error foo2 is not typed + c.get('foo2') + // @ts-expect-error foo2 is not typed + c.var.foo2 + // @ts-expect-error foo3 is not typed + c.get('foo3') + // @ts-expect-error foo3 is not typed + c.var.foo3 + // @ts-expect-error foo4 is not typed + c.get('foo4') + // @ts-expect-error foo4 is not typed + c.var.foo4 + return c.json(0) + }) + + new Hono() + .get('/', mw1, mw2, mw3, mw4, mw5, (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.get('foo2')).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.get('foo3')).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.get('foo4')).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.get('foo5')).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + return c.json(0) + }) + .get('/', (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + // @ts-expect-error foo1 is not typed + c.get('foo1') + // @ts-expect-error foo1 is not typed + c.var.foo1 + // @ts-expect-error foo2 is not typed + c.get('foo2') + // @ts-expect-error foo2 is not typed + c.var.foo2 + // @ts-expect-error foo3 is not typed + c.get('foo3') + // @ts-expect-error foo3 is not typed + c.var.foo3 + // @ts-expect-error foo4 is not typed + c.get('foo4') + // @ts-expect-error foo4 is not typed + c.var.foo4 + // @ts-expect-error foo5 is not typed + c.get('foo5') + // @ts-expect-error foo5 is not typed + c.var.foo5 + return c.json(0) + }) + new Hono() + .get('/', mw1, mw2, mw3, mw4, mw5, mw6, (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.get('foo2')).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.get('foo3')).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.get('foo4')).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.get('foo5')).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.get('foo6')).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + return c.json(0) + }) + .get('/', (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + // @ts-expect-error foo1 is not typed + c.get('foo1') + // @ts-expect-error foo1 is not typed + c.var.foo1 + // @ts-expect-error foo2 is not typed + c.get('foo2') + // @ts-expect-error foo2 is not typed + c.var.foo2 + // @ts-expect-error foo3 is not typed + c.get('foo3') + // @ts-expect-error foo3 is not typed + c.var.foo3 + // @ts-expect-error foo4 is not typed + c.get('foo4') + // @ts-expect-error foo4 is not typed + c.var.foo4 + // @ts-expect-error foo5 is not typed + c.get('foo5') + // @ts-expect-error foo5 is not typed + c.var.foo5 + // @ts-expect-error foo6 is not typed + c.get('foo6') + // @ts-expect-error foo6 is not typed + c.var.foo6 + return c.json(0) + }) + new Hono() + .get('/', mw1, mw2, mw3, mw4, mw5, mw6, mw7, (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.get('foo2')).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.get('foo3')).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.get('foo4')).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.get('foo5')).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.get('foo6')).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + expectTypeOf(c.get('foo7')).toEqualTypeOf() + expectTypeOf(c.var.foo7).toEqualTypeOf() + return c.json(0) + }) + .get('/', (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + // @ts-expect-error foo1 is not typed + c.get('foo1') + // @ts-expect-error foo1 is not typed + c.var.foo1 + // @ts-expect-error foo2 is not typed + c.get('foo2') + // @ts-expect-error foo2 is not typed + c.var.foo2 + // @ts-expect-error foo3 is not typed + c.get('foo3') + // @ts-expect-error foo3 is not typed + c.var.foo3 + // @ts-expect-error foo4 is not typed + c.get('foo4') + // @ts-expect-error foo4 is not typed + c.var.foo4 + // @ts-expect-error foo5 is not typed + c.get('foo5') + // @ts-expect-error foo5 is not typed + c.var.foo5 + // @ts-expect-error foo6 is not typed + c.get('foo6') + // @ts-expect-error foo6 is not typed + c.var.foo6 + // @ts-expect-error foo7 is not typed + c.get('foo7') + // @ts-expect-error foo7 is not typed + c.var.foo7 + return c.json(0) + }) + new Hono() + .get('/', mw1, mw2, mw3, mw4, mw5, mw6, mw7, mw8, (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.get('foo2')).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.get('foo3')).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.get('foo4')).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.get('foo5')).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.get('foo6')).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + expectTypeOf(c.get('foo7')).toEqualTypeOf() + expectTypeOf(c.var.foo7).toEqualTypeOf() + expectTypeOf(c.get('foo8')).toEqualTypeOf() + expectTypeOf(c.var.foo8).toEqualTypeOf() + return c.json(0) + }) + .get('/', (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + // @ts-expect-error foo1 is not typed + c.get('foo1') + // @ts-expect-error foo1 is not typed + c.var.foo1 + // @ts-expect-error foo2 is not typed + c.get('foo2') + // @ts-expect-error foo2 is not typed + c.var.foo2 + // @ts-expect-error foo3 is not typed + c.get('foo3') + // @ts-expect-error foo3 is not typed + c.var.foo3 + // @ts-expect-error foo4 is not typed + c.get('foo4') + // @ts-expect-error foo4 is not typed + c.var.foo4 + // @ts-expect-error foo5 is not typed + c.get('foo5') + // @ts-expect-error foo5 is not typed + c.var.foo5 + // @ts-expect-error foo6 is not typed + c.get('foo6') + // @ts-expect-error foo6 is not typed + c.var.foo6 + // @ts-expect-error foo7 is not typed + c.get('foo7') + // @ts-expect-error foo7 is not typed + c.var.foo7 + // @ts-expect-error foo8 is not typed + c.get('foo8') + // @ts-expect-error foo8 is not typed + c.var.foo8 + return c.json(0) + }) + + new Hono() + .get('/', mw1, mw2, mw3, mw4, mw5, mw6, mw7, mw8, mw9, (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.var.foo1).toEqualTypeOf() + expectTypeOf(c.get('foo2')).toEqualTypeOf() + expectTypeOf(c.var.foo2).toEqualTypeOf() + expectTypeOf(c.get('foo3')).toEqualTypeOf() + expectTypeOf(c.var.foo3).toEqualTypeOf() + expectTypeOf(c.get('foo4')).toEqualTypeOf() + expectTypeOf(c.var.foo4).toEqualTypeOf() + expectTypeOf(c.get('foo5')).toEqualTypeOf() + expectTypeOf(c.var.foo5).toEqualTypeOf() + expectTypeOf(c.get('foo6')).toEqualTypeOf() + expectTypeOf(c.var.foo6).toEqualTypeOf() + expectTypeOf(c.get('foo7')).toEqualTypeOf() + expectTypeOf(c.var.foo7).toEqualTypeOf() + expectTypeOf(c.get('foo8')).toEqualTypeOf() + expectTypeOf(c.var.foo8).toEqualTypeOf() + expectTypeOf(c.get('foo9')).toEqualTypeOf() + expectTypeOf(c.var.foo9).toEqualTypeOf() + return c.json(0) + }) + .get('/', (c) => { + expectTypeOf(c.get('init')).toEqualTypeOf() + expectTypeOf(c.var.init).toEqualTypeOf() + // @ts-expect-error foo1 is not typed + c.get('foo1') + // @ts-expect-error foo1 is not typed + c.var.foo1 + // @ts-expect-error foo2 is not typed + c.get('foo2') + // @ts-expect-error foo2 is not typed + c.var.foo2 + // @ts-expect-error foo3 is not typed + c.get('foo3') + // @ts-expect-error foo3 is not typed + c.var.foo3 + // @ts-expect-error foo4 is not typed + c.get('foo4') + // @ts-expect-error foo4 is not typed + c.var.foo4 + // @ts-expect-error foo5 is not typed + c.get('foo5') + // @ts-expect-error foo5 is not typed + c.var.foo5 + // @ts-expect-error foo6 is not typed + c.get('foo6') + // @ts-expect-error foo6 is not typed + c.var.foo6 + // @ts-expect-error foo7 is not typed + c.get('foo7') + // @ts-expect-error foo7 is not typed + c.var.foo7 + // @ts-expect-error foo8 is not typed + c.get('foo8') + // @ts-expect-error foo8 is not typed + c.var.foo8 + // @ts-expect-error foo9 is not typed + c.get('foo9') + // @ts-expect-error foo9 is not typed + c.var.foo9 + return c.json(0) + }) + }) +}) + +/** + * + * Declaring a ContextVariableMap for testing. + */ +declare module './context' { + interface ContextVariableMap { + payload: string + } +} + +describe('ContextVariableMap type tests', () => { + it('Should not throw type errors with c.var', () => { + new Hono().get((c) => { + expectTypeOf(c.get('payload')).toEqualTypeOf() + return c.json(0) + }) + new Hono().get((c) => { + expectTypeOf(c.var.payload).toEqualTypeOf() + return c.json(0) + }) + }) + + it('Should override ContextVariableMap with env variables', () => { + const middleware = createMiddleware<{ + Variables: { + payload: number + } + }>(async (c, next) => { + c.set('payload', 123) + await next() + }) + + new Hono().get(middleware, (c) => { + expectTypeOf(c.get('payload')).toEqualTypeOf() + return c.json(0) + }) + }) + + it('Should use ContextVariableMap when c is Context', () => { + const c = new Context(new Request('http://localhost')) + expectTypeOf(c.get('payload')).toEqualTypeOf() + expectTypeOf(c.var.payload).toEqualTypeOf() + // @ts-expect-error the value of payload should be string + expectTypeOf(c.set('payload', 123)) + }) +}) + +/** + * It's challenge to test all cases. This is a minimal pattern. + */ +describe('Env types with chained routes - test only types', () => { + const app = new Hono<{ Variables: { testVar: string } }>() + it('Should not throw a type error', () => { + app + .post( + '/', + validator('json', (v) => v), + async (c) => { + expectTypeOf(c.get('testVar')).toEqualTypeOf() + return c.json({ success: true }) + } + ) + .patch( + '/', + validator('json', (v) => v), + async (c) => { + expectTypeOf(c.get('testVar')).toEqualTypeOf() + return c.json({ success: true }) + } + ) + }) +}) + +/** + * Ref: https://github.com/honojs/hono/issues/3027 + */ +describe('Env types with validator as first middleware - test only types', () => { + const app = new Hono<{ Variables: { testVar: string } }>() + it('Should not throw a type error', () => { + const testApp = app.get( + validator('json', () => { + return { + cd: 'bar', + } + }), + async (c) => { + const foo = c.req.valid('json') // Error here + return c.json(1) + } + ) + + const dummyMiddleware1 = createMiddleware(async (c, next) => { + await next() + }) + // Multiple levels of middleware + const testApp2 = app.post( + validator('json', () => { + return { + cd: 'bar', + } + }), + dummyMiddleware1, + createMiddleware(async (c, next) => { + await next() + }), + async (c) => { + const foo = c.req.valid('json') // Error here also + return c.json(1) + } + ) + }) +}) + +describe('Env types with `use` middleware - test only types', () => { + const app = new Hono() + + const mw1 = createMiddleware<{ Variables: { foo1: string } }>(async () => {}) + const mw2 = createMiddleware<{ Variables: { foo2: string } }>(async () => {}) + + it('Should not throw a type error', () => { + app + .use(mw1) + .use(mw2) + .get('/', (c) => { + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.get('foo2')).toEqualTypeOf() + return c.json({ success: true }) + }) + app.use(mw1, mw2).get('/', (c) => { + expectTypeOf(c.get('foo1')).toEqualTypeOf() + expectTypeOf(c.get('foo2')).toEqualTypeOf() + return c.json({ success: true }) + }) + }) +}) + +describe('Env types and a path type with `app.use(path, handler...)` - test only types', () => { + it('Should not throw a type error', () => { + type Env = { + Variables: { + foo: string + } + } + + // app.use(path, handler) + new Hono() + .use('/:id', async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }) + .get((c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + return c.json(0) + }) + + // app.use(path, handler x2) + new Hono() + .use( + '/:id', + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + } + ) + .get((c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + return c.json(0) + }) + + // app.use(path, handler x3) + new Hono() + .use( + '/:id', + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + } + ) + .get((c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + return c.json(0) + }) + + // app.use(path, handler x4) + new Hono() + .use( + '/:id', + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + } + ) + .get((c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + return c.json(0) + }) + + // app.use(path, handler x5) + new Hono() + .use( + '/:id', + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + } + ) + .get((c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + return c.json(0) + }) + + // app.use(path, handler x6) + new Hono() + .use( + '/:id', + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + } + ) + .get((c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + return c.json(0) + }) + + // app.use(path, handler x7) + new Hono() + .use( + '/:id', + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + } + ) + .get((c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + return c.json(0) + }) + + // app.use(path, handler x8) + new Hono() + .use( + '/:id', + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + } + ) + .get((c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + return c.json(0) + }) + + // app.use(path, handler x9) + new Hono() + .use( + '/:id', + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + } + ) + .get((c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + return c.json(0) + }) + + // app.use(path, handler x10) + new Hono() + .use( + '/:id', + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + }, + async (c, next) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + await next() + } + ) + .get((c) => { + expectTypeOf(c.var.foo).toEqualTypeOf() + expectTypeOf(c.req.param('id')).toEqualTypeOf() + return c.json(0) + }) + }) +}) + +// https://github.com/honojs/hono/issues/3122 +describe('Returning type from `app.use(path, mw)`', () => { + const mw = createMiddleware(async (c, next) => { + await next() + }) + it('Should not mark `*` as never', () => { + const app = new Hono().use('*', mw) + type Actual = ExtractSchema + type Expected = { + '*': {} + } + type verify = Expect> + }) +}) + +describe('generic typed variables', () => { + const okHelper = (c: Context) => { + return (data: TData) => c.json({ data }) + } + type Variables = { + ok: ReturnType + } + const app = new Hono<{ Variables: Variables }>() + + it('Should set and get variables with correct types', async () => { + const route = app + .use('*', async (c, next) => { + c.set('ok', okHelper(c)) + await next() + }) + .get('/', (c) => { + const ok = c.get('ok') + return ok('Hello') + }) + type Actual = ExtractSchema['/']['$get']['output'] + type Expected = { data: string } + expectTypeOf().toEqualTypeOf() + }) +}) + +describe('status code', () => { + const app = new Hono() + + it('should only allow to return .json() with contentful status codes', async () => { + const route = app.get('/', async (c) => c.json({})) + type Actual = ExtractSchema['/']['$get']['status'] + expectTypeOf().toEqualTypeOf() + }) + + it('should only allow to return .body(null) with all status codes', async () => { + const route = app.get('/', async (c) => c.body(null)) + type Actual = ExtractSchema['/']['$get']['status'] + expectTypeOf().toEqualTypeOf() + }) + + it('should only allow to return .text() with contentful status codes', async () => { + const route = app.get('/', async (c) => c.text('whatever')) + type Actual = ExtractSchema['/']['$get']['status'] + expectTypeOf().toEqualTypeOf() + }) + + it('should throw type error when .json({}) is used with contentless status codes', async () => { + // @ts-expect-error 204 is not contentful status code + app.get('/', async (c) => c.json({}, 204)) + app.get('/', async (c) => + c.json( + {}, + // @ts-expect-error 204 is not contentful status code + { + status: 204, + } + ) + ) + }) + + it('should throw type error when .body(content) is used with contentless status codes', async () => { + // @ts-expect-error 204 is not contentful status code + app.get('/', async (c) => c.body('content', 204)) + // @ts-expect-error 204 is not contentful status code + app.get('/', async (c) => c.body('content', { status: 204 })) + }) + + it('should throw type error when .text(content) is used with contentless status codes', async () => { + // @ts-expect-error 204 is not contentful status code + app.get('/', async (c) => c.text('content', 204)) + // @ts-expect-error 204 is not contentful status code + app.get('/', async (c) => c.text('content', { status: 204 })) + }) + + it('should throw type error when .html(content) is used with contentless status codes', async () => { + // @ts-expect-error 204 is not contentful status code + app.get('/', async (c) => c.html('

title

', 204)) + // @ts-expect-error 204 is not contentful status code + app.get('/', async (c) => c.html('

title

', { status: 204 })) + }) + + it('.body() not override other responses in hono client', async () => { + const router = app.get('/', async (c) => { + if (c.req.header('Content-Type') === 'application/json') { + return c.text('Hello', 200) + } + + if (c.req.header('Content-Type') === 'application/x-www-form-urlencoded') { + return c.body('Hello', 201) + } + + return c.body(null, 204) + }) + + type Actual = ExtractSchema['/']['$get']['status'] + expectTypeOf().toEqualTypeOf<204 | 201 | 200>() + }) +}) + +describe('RPC supports Middleware responses', () => { + describe('Merge responses from multiple handlers, path pattern', () => { + test('merge responses from 1 middleware', async () => { + const middleware = createMiddleware(async (c) => c.json({ '400': true }, 400)) + + const app = new Hono().get('/test', middleware, (c) => c.json({ '200': true }, 200)) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.test.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + }) + + test('merge responses from 2 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + + const app = new Hono().get('/test', middleware1, middleware2, (c) => + c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.test.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + }) + + test('merge responses from 3 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + + const app = new Hono().get('/test', middleware1, middleware2, middleware3, (c) => + c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.test.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + }) + + test('merge responses from 4 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + + const app = new Hono().get('/test', middleware1, middleware2, middleware3, middleware4, (c) => + c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.test.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 404) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 404: true }>() + } + }) + + test('merge responses from 5 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + const middleware5 = createMiddleware(async (c) => c.json({ '300': true }, 300)) + + const app = new Hono().get( + '/test', + middleware1, + middleware2, + middleware3, + middleware4, + middleware5, + (c) => c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.test.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 300) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 300: true }>() + } + }) + + test('merge responses from 6 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + const middleware5 = createMiddleware(async (c) => c.json({ '300': true }, 300)) + const middleware6 = createMiddleware(async (c) => c.json({ '201': true }, 201)) + + const app = new Hono().get( + '/test', + middleware1, + middleware2, + middleware3, + middleware4, + middleware5, + middleware6, + (c) => c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.test.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 404) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 404: true }>() + } + if (res.status === 300) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 300: true }>() + } + if (res.status === 201) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 201: true }>() + } + }) + + test('merge responses from 7 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + const middleware5 = createMiddleware(async (c) => c.json({ '300': true }, 300)) + const middleware6 = createMiddleware(async (c) => c.json({ '201': true }, 201)) + const middleware7 = createMiddleware(async (c) => c.json({ '202': true }, 202)) + + const app = new Hono().get( + '/test', + middleware1, + middleware2, + middleware3, + middleware4, + middleware5, + middleware6, + middleware7, + (c) => c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.test.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 404) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 404: true }>() + } + if (res.status === 300) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 300: true }>() + } + if (res.status === 201) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 201: true }>() + } + if (res.status === 202) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 202: true }>() + } + }) + + test('merge responses from 8 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + const middleware5 = createMiddleware(async (c) => c.json({ '300': true }, 300)) + const middleware6 = createMiddleware(async (c) => c.json({ '201': true }, 201)) + const middleware7 = createMiddleware(async (c) => c.json({ '202': true }, 202)) + const middleware8 = createMiddleware(async (c) => c.json({ '203': true }, 203)) + + const app = new Hono().get( + '/test', + middleware1, + middleware2, + middleware3, + middleware4, + middleware5, + middleware6, + middleware7, + middleware8, + (c) => c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.test.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 404) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 404: true }>() + } + if (res.status === 300) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 300: true }>() + } + if (res.status === 201) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 201: true }>() + } + if (res.status === 202) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 202: true }>() + } + if (res.status === 203) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 203: true }>() + } + }) + + test('merge responses from 9 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + const middleware5 = createMiddleware(async (c) => c.json({ '300': true }, 300)) + const middleware6 = createMiddleware(async (c) => c.json({ '201': true }, 201)) + const middleware7 = createMiddleware(async (c) => c.json({ '202': true }, 202)) + const middleware8 = createMiddleware(async (c) => c.json({ '203': true }, 203)) + const middleware9 = createMiddleware(async (c) => c.json({ '301': true }, 301)) + + const app = new Hono().get( + '/test', + middleware1, + middleware2, + middleware3, + middleware4, + middleware5, + middleware6, + middleware7, + middleware8, + middleware9, + (c) => c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.test.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 404) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 404: true }>() + } + if (res.status === 300) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 300: true }>() + } + if (res.status === 201) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 201: true }>() + } + if (res.status === 202) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 202: true }>() + } + if (res.status === 203) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 203: true }>() + } + if (res.status === 301) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 301: true }>() + } + }) + }) + + describe('Merge responses from multiple handlers, no path pattern', () => { + test('merge responses from 1 middleware', async () => { + const middleware = createMiddleware(async (c) => c.json({ '400': true }, 400)) + + const app = new Hono().get(middleware, (c) => c.json({ '200': true }, 200)) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.index.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + }) + + test('merge responses from 2 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + + const app = new Hono().get(middleware1, middleware2, (c) => c.json({ '200': true }, 200)) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.index.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + }) + + test('merge responses from 3 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + + const app = new Hono().get(middleware1, middleware2, middleware3, (c) => + c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.index.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + }) + + test('merge responses from 4 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + + const app = new Hono().get(middleware1, middleware2, middleware3, middleware4, (c) => + c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.index.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 404) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 404: true }>() + } + }) + + test('merge responses from 5 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + const middleware5 = createMiddleware(async (c) => c.json({ '300': true }, 300)) + + const app = new Hono().get( + middleware1, + middleware2, + middleware3, + middleware4, + middleware5, + (c) => c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.index.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 300) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 300: true }>() + } + }) + + test('merge responses from 6 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + const middleware5 = createMiddleware(async (c) => c.json({ '300': true }, 300)) + const middleware6 = createMiddleware(async (c) => c.json({ '201': true }, 201)) + + const app = new Hono().get( + middleware1, + middleware2, + middleware3, + middleware4, + middleware5, + middleware6, + (c) => c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.index.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 404) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 404: true }>() + } + if (res.status === 300) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 300: true }>() + } + if (res.status === 201) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 201: true }>() + } + }) + + test('merge responses from 7 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + const middleware5 = createMiddleware(async (c) => c.json({ '300': true }, 300)) + const middleware6 = createMiddleware(async (c) => c.json({ '201': true }, 201)) + const middleware7 = createMiddleware(async (c) => c.json({ '202': true }, 202)) + + const app = new Hono().get( + middleware1, + middleware2, + middleware3, + middleware4, + middleware5, + middleware6, + middleware7, + (c) => c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.index.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 404) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 404: true }>() + } + if (res.status === 300) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 300: true }>() + } + if (res.status === 201) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 201: true }>() + } + if (res.status === 202) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 202: true }>() + } + }) + + test('merge responses from 8 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + const middleware5 = createMiddleware(async (c) => c.json({ '300': true }, 300)) + const middleware6 = createMiddleware(async (c) => c.json({ '201': true }, 201)) + const middleware7 = createMiddleware(async (c) => c.json({ '202': true }, 202)) + const middleware8 = createMiddleware(async (c) => c.json({ '203': true }, 203)) + + const app = new Hono().get( + middleware1, + middleware2, + middleware3, + middleware4, + middleware5, + middleware6, + middleware7, + middleware8, + (c) => c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.index.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 404) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 404: true }>() + } + if (res.status === 300) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 300: true }>() + } + if (res.status === 201) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 201: true }>() + } + if (res.status === 202) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 202: true }>() + } + if (res.status === 203) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 203: true }>() + } + }) + + test('merge responses from 9 middlewares', async () => { + const middleware1 = createMiddleware(async (c) => c.json({ '400': true }, 400)) + const middleware2 = createMiddleware(async (c) => c.json({ '401': true }, 401)) + const middleware3 = createMiddleware(async (c) => c.json({ '403': true }, 403)) + const middleware4 = createMiddleware(async (c) => c.json({ '404': true }, 404)) + const middleware5 = createMiddleware(async (c) => c.json({ '300': true }, 300)) + const middleware6 = createMiddleware(async (c) => c.json({ '201': true }, 201)) + const middleware7 = createMiddleware(async (c) => c.json({ '202': true }, 202)) + const middleware8 = createMiddleware(async (c) => c.json({ '203': true }, 203)) + const middleware9 = createMiddleware(async (c) => c.json({ '301': true }, 301)) + + const app = new Hono().get( + middleware1, + middleware2, + middleware3, + middleware4, + middleware5, + middleware6, + middleware7, + middleware8, + middleware9, + (c) => c.json({ '200': true }, 200) + ) + const client = hc('http://localhost', { fetch: app.request }) + const res = await client.index.$get() + + if (res.status === 200) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 200: true }>() + } + if (res.status === 400) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 400: true }>() + } + if (res.status === 401) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 401: true }>() + } + if (res.status === 403) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 403: true }>() + } + if (res.status === 404) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 404: true }>() + } + if (res.status === 300) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 300: true }>() + } + if (res.status === 201) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 201: true }>() + } + if (res.status === 202) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 202: true }>() + } + if (res.status === 203) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 203: true }>() + } + if (res.status === 301) { + expectTypeOf(await res.json()).toEqualTypeOf<{ 301: true }>() + } + }) + }) + + describe('Infers types with multiple middlewares but none returning response', () => { + const middleware = createMiddleware(async () => {}) + const handler = (c: Context) => c.json({ ok: true }, 200) + type Expected = { + '/': { + $get: { + input: {} + output: { + ok: true + } + outputFormat: 'json' + status: 200 + } + } + } + + test('infer the correct response type with 1 middleware and 1 handler', () => { + const routes = new Hono().get('/', middleware, handler) + type Actual = ExtractSchema + type verify = Expect> + }) + + test('infer the correct response type with 1 middleware and 2 handler', () => { + const routes = new Hono().get('/', middleware, handler, handler) + type Actual = ExtractSchema + type verify = Expect> + }) + + test('infer the correct response type with 2 middleware and 1 handler', () => { + const routes = new Hono().get('/', middleware, middleware, handler) + type Actual = ExtractSchema + type verify = Expect> + }) + + test('infer the correct response type with 3 middleware and 1 handler', () => { + const routes = new Hono().get('/', middleware, middleware, middleware, handler) + type Actual = ExtractSchema + type verify = Expect> + }) + + test('infer the correct response type with 4 middleware and 1 handler', () => { + const routes = new Hono().get('/', middleware, middleware, middleware, middleware, handler) + type Actual = ExtractSchema + type verify = Expect> + }) + + test('infer the correct response type with 5 middleware and 1 handler', () => { + const routes = new Hono().get( + '/', + middleware, + middleware, + middleware, + middleware, + middleware, + handler + ) + type Actual = ExtractSchema + type verify = Expect> + }) + + test('infer the correct response type with 6 middleware and 1 handler', () => { + const routes = new Hono().get( + '/', + middleware, + middleware, + middleware, + middleware, + middleware, + middleware, + handler + ) + type Actual = ExtractSchema + type verify = Expect> + }) + + test('infer the correct response type with 7 middleware and 1 handler', () => { + const routes = new Hono().get( + '/', + middleware, + middleware, + middleware, + middleware, + middleware, + middleware, + middleware, + handler + ) + type Actual = ExtractSchema + type verify = Expect> + }) + + test('infer the correct response type with 8 middleware and 1 handler', () => { + const routes = new Hono().get( + '/', + middleware, + middleware, + middleware, + middleware, + middleware, + middleware, + middleware, + middleware, + handler + ) + type Actual = ExtractSchema + type verify = Expect> + }) + + test('infer the correct response type with 9 middleware and 1 handler', () => { + const routes = new Hono().get( + '/', + middleware, + middleware, + middleware, + middleware, + middleware, + middleware, + middleware, + middleware, + middleware, + handler + ) + type Actual = ExtractSchema + type verify = Expect> + }) + }) + + describe('Infers types with multiple middlewares but only some returning response', () => { + const handler = (c: Context) => c.json({ ok: true }, 200) + + test('infer the correct response type with 2 middleware, only one returning response', () => { + const middleware1 = async (c: Context) => { + if (Math.random() > 0.5) { + return c.json( + { + q: true, + }, + 200 + ) + } + } + const middleware2 = async () => {} + + const routes = new Hono().get('/', middleware1, middleware2, handler) + type Actual = ExtractSchema + type Expected = { + '/': { + $get: + | { + input: {} + output: { + ok: true + } + outputFormat: 'json' + status: 200 + } + | { + input: {} + output: { + q: true + } + outputFormat: 'json' + status: 200 + } + } + } + type verify = Expect> + }) + + test('infer the correct response type with 3 middleware, 2 returning response', () => { + const middleware1 = async (c: Context) => { + if (Math.random() > 0.5) { + return c.json( + { + q1: true, + }, + 200 + ) + } + } + const middleware2 = async (c: Context) => { + if (Math.random() > 0.5) { + return c.json( + { + q2: true, + }, + 200 + ) + } + } + const middleware3 = async () => {} + + const routes = new Hono().get('/', middleware1, middleware2, middleware3, handler) + type Actual = ExtractSchema + type Expected = { + '/': { + $get: + | { + input: {} + output: { + ok: true + } + outputFormat: 'json' + status: 200 + } + | { + input: {} + output: { + q1: true + } + outputFormat: 'json' + status: 200 + } + | { + input: {} + output: { + q2: true + } + outputFormat: 'json' + status: 200 + } + } + } + type verify = Expect> + }) + }) +}) diff --git a/deps/swc/crates/swc_ts_fast_strip/benches/assets/typescript-eslint.generate-configs.mts b/deps/swc/crates/swc_ts_fast_strip/benches/assets/typescript-eslint.generate-configs.mts new file mode 100644 index 000000000..9bd318804 --- /dev/null +++ b/deps/swc/crates/swc_ts_fast_strip/benches/assets/typescript-eslint.generate-configs.mts @@ -0,0 +1,454 @@ +import type { ESLintPluginRuleModule } from '@typescript-eslint/eslint-plugin/use-at-your-own-risk/rules'; +import type { + ClassicConfig, + FlatConfig, + Linter, + RuleRecommendation, +} from '@typescript-eslint/utils/ts-eslint'; + +import eslintPlugin from '@typescript-eslint/eslint-plugin'; +import fs from 'node:fs'; +import path from 'node:path'; +import prettier from 'prettier'; + +import { PACKAGES_ESLINT_PLUGIN, PRETTIER_CONFIG_PATH } from './paths.mts'; + +// no need for us to bring in an entire dependency for a few simple terminal colors +const chalk = { + blueBright: (val: string): string => `\x1B[94m${val}\x1B[39m`, + dim: (val: string): string => `\x1B[2m${val}\x1B[22m`, + gray: (val: string): string => `\x1B[90m${val}\x1B[39m`, + green: (val: string): string => `\x1B[32m${val}\x1B[39m`, + red: (val: string): string => `\x1B[31m${val}\x1B[39m`, +}; + +const AUTO_GENERATED_COMMENT_LINES = [ + '// THIS CODE WAS AUTOMATICALLY GENERATED', + '// DO NOT EDIT THIS CODE BY HAND', + '// SEE https://typescript-eslint.io/users/configs', + '//', + '// For developers working in the typescript-eslint monorepo:', + '// You can regenerate it using `pnpm run generate-configs`', + '', +] as const; + +const EXTENDS_MODULES = [ + { + moduleRelativePath: './base', + name: 'baseConfig', + packageRelativePath: './configs/eslintrc/base', + }, + { + moduleRelativePath: './eslint-recommended', + name: 'eslintRecommendedConfig', + packageRelativePath: './configs/eslintrc/eslint-recommended', + }, +] as const; +const CLASSIC_EXTENDS: readonly string[] = EXTENDS_MODULES.map( + mod => mod.packageRelativePath, +); + +function addAutoGeneratedComment(code?: string): string { + return [...AUTO_GENERATED_COMMENT_LINES, code].join('\n'); +} + +const prettierConfig = await prettier.resolveConfig('file.ts', { + config: PRETTIER_CONFIG_PATH, +}); + +type LinterConfigRules = Record< + string, + [ClassicConfig.RuleLevel, ...unknown[]] | ClassicConfig.RuleLevel +>; + +interface LinterConfig extends ClassicConfig.Config { + extends?: string | string[]; + plugins?: string[]; +} + +const RULE_NAME_PREFIX = '@typescript-eslint/'; +const MAX_RULE_NAME_LENGTH = Math.max( + ...Object.keys(eslintPlugin.rules).map(name => name.length), +); +const BASE_RULES_TO_BE_OVERRIDDEN = new Map( + Object.entries(eslintPlugin.rules) + .filter(([, rule]) => rule.meta.docs.extendsBaseRule) + .map( + ([ruleName, rule]) => + [ + ruleName, + typeof rule.meta.docs.extendsBaseRule === 'string' + ? rule.meta.docs.extendsBaseRule + : ruleName, + ] as const, + ), +); + +// special case - return-await used to be an extension, but no longer is. +// See https://github.com/typescript-eslint/typescript-eslint/issues/9517 +BASE_RULES_TO_BE_OVERRIDDEN.set('return-await', 'no-return-await'); + +type RuleEntry = [string, ESLintPluginRuleModule]; + +const allRuleEntries: RuleEntry[] = Object.entries(eslintPlugin.rules).sort( + (a, b) => a[0].localeCompare(b[0]), +); + +type GetRuleOptions = ( + rule: ESLintPluginRuleModule, +) => readonly unknown[] | true | undefined; + +interface ConfigRuleSettings { + baseRuleForExtensionRule?: 'exclude'; + deprecated?: 'exclude'; + forcedRuleLevel?: Linter.RuleLevel; + getOptions?: GetRuleOptions | undefined; + typeChecked?: 'exclude' | 'include-only'; +} + +/** + * Helper function reduces records to key - value pairs. + */ +function reducer( + config: LinterConfigRules, + [key, value]: RuleEntry, + settings: ConfigRuleSettings = {}, +): LinterConfigRules { + if (value.meta.deprecated) { + if (value.meta.docs.recommended) { + throw new Error(`${key} is both deprecated and recommended.`); + } + if (settings.deprecated) { + return config; + } + } + + // Explicitly exclude rules requiring type-checking + if ( + settings.typeChecked === 'exclude' && + value.meta.docs.requiresTypeChecking === true + ) { + return config; + } + + if ( + settings.typeChecked === 'include-only' && + value.meta.docs.requiresTypeChecking !== true + ) { + return config; + } + + const ruleName = `${RULE_NAME_PREFIX}${key}`; + + if ( + settings.baseRuleForExtensionRule !== 'exclude' && + BASE_RULES_TO_BE_OVERRIDDEN.has(key) + ) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const baseRuleName = BASE_RULES_TO_BE_OVERRIDDEN.get(key)!; + console.log( + baseRuleName + .padStart(RULE_NAME_PREFIX.length + baseRuleName.length) + .padEnd(RULE_NAME_PREFIX.length + MAX_RULE_NAME_LENGTH), + '=', + chalk.green('off'), + ); + config[baseRuleName] = 'off'; + } + console.log( + `${chalk.dim(RULE_NAME_PREFIX)}${key.padEnd(MAX_RULE_NAME_LENGTH)}`, + '=', + chalk.red('error'), + ); + + const ruleLevel = settings.forcedRuleLevel ?? 'error'; + const ruleOptions = settings.getOptions?.(value); + + config[ruleName] = + ruleOptions && ruleOptions !== true + ? [ruleLevel, ...ruleOptions] + : ruleLevel; + + return config; +} + +interface WriteConfigSettings { + description: string; + getConfig: () => LinterConfig; + name: string; +} + +/** + * Helper function that writes configuration. + */ +async function writeConfig({ + description, + getConfig, + name, +}: WriteConfigSettings): Promise { + const hyphens = '-'.repeat(35 - Math.ceil(name.length / 2)); + console.log(chalk.blueBright(`\n${hyphens} ${name}.ts ${hyphens}`)); + + const config = getConfig(); + + // + // 1. Classic Config - written to eslint-plugin/src/configs/eslintrc + // These configs are just JSON blobs that we write as TS files + // + + // note: we use `export =` because ESLint will import these configs via a commonjs import + const classicCode = [ + "import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint';", + '', + `export = ${JSON.stringify(config)} satisfies ClassicConfig.Config;`, + ].join('\n'); + const classicConfigStr = await prettier.format( + addAutoGeneratedComment(classicCode), + { + parser: 'typescript', + ...prettierConfig, + }, + ); + fs.writeFileSync( + path.join( + PACKAGES_ESLINT_PLUGIN, + 'src', + 'configs', + 'eslintrc', + `${name}.ts`, + ), + classicConfigStr, + ); + + // + // 2. Flat Config - written to eslint-plugin/src/configs/flat + // These configs are actual TS modules that import other configs + // + const flatCode: string[] = [ + ...AUTO_GENERATED_COMMENT_LINES, + "import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint';", + '', + ]; + const flatExtends: string[] = []; + const flatConfig: FlatConfig.Config = { + name: `typescript-eslint/${name}`, + rules: config.rules, + }; + if (config.extends) { + for (const extendPath of config.extends) { + const config = EXTENDS_MODULES.find( + mod => mod.packageRelativePath === extendPath, + ); + if (config == null) { + throw new Error("Couldn't find config"); + } + flatCode.push( + `import ${config.name} from '${config.moduleRelativePath}';`, + ); + flatExtends.push(config.name); + } + flatCode.push(''); + } + if (config.parserOptions) { + flatConfig.languageOptions ??= {}; + flatConfig.languageOptions.parserOptions = config.parserOptions; + } + + const docComment = `/** + * ${description} + * @see {@link https://typescript-eslint.io/users/configs#${name}} + */`; + const flatConfigJson = JSON.stringify(flatConfig); + if (flatExtends.length > 0) { + flatCode.push( + docComment, + 'export default (plugin: FlatConfig.Plugin, parser: FlatConfig.Parser): FlatConfig.ConfigArray => [', + ...flatExtends.map(ext => `${ext}(plugin, parser),`), + flatConfigJson, + '];', + ); + } else { + flatCode.push( + docComment, + `export default (_plugin: FlatConfig.Plugin, _parser: FlatConfig.Parser): FlatConfig.Config => (${flatConfigJson});`, + ); + } + const flatConfigStr = await prettier.format(flatCode.join('\n'), { + parser: 'typescript', + ...prettierConfig, + }); + fs.writeFileSync( + path.join(PACKAGES_ESLINT_PLUGIN, 'src', 'configs', 'flat', `${name}.ts`), + flatConfigStr, + ); +} + +interface ExtendedConfigSettings { + description: string; + name: string; + ruleEntries: readonly RuleEntry[]; + settings?: ConfigRuleSettings; +} + +async function writeExtendedConfig({ + description, + name, + ruleEntries, + settings, +}: ExtendedConfigSettings): Promise { + await writeConfig({ + description, + getConfig: () => ({ + extends: [...CLASSIC_EXTENDS], + rules: ruleEntries.reduce( + (config, entry) => reducer(config, entry, settings), + {}, + ), + }), + name, + }); +} + +function filterRuleEntriesTo( + ...recommendations: (RuleRecommendation | undefined)[] +): RuleEntry[] { + return allRuleEntries.filter(([, rule]) => + typeof rule.meta.docs.recommended === 'object' + ? Object.keys(rule.meta.docs.recommended).some(level => + recommendations.includes(level as RuleRecommendation), + ) + : recommendations.includes(rule.meta.docs.recommended), + ); +} + +function createGetOptionsForLevel( + level: 'recommended' | 'strict', +): GetRuleOptions { + return rule => + typeof rule.meta.docs.recommended === 'object' + ? rule.meta.docs.recommended[level] + : undefined; +} + +await writeExtendedConfig({ + description: + 'Enables each the rules provided as a part of typescript-eslint. Note that many rules are not applicable in all codebases, or are meant to be configured.', + name: 'all', + ruleEntries: allRuleEntries, + settings: { + deprecated: 'exclude', + }, +}); + +await writeExtendedConfig({ + description: + 'Recommended rules for code correctness that you can drop in without additional configuration.', + name: 'recommended', + ruleEntries: filterRuleEntriesTo('recommended'), + settings: { + getOptions: createGetOptionsForLevel('recommended'), + typeChecked: 'exclude', + }, +}); + +await writeExtendedConfig({ + description: + 'Contains all of `recommended` along with additional recommended rules that require type information.', + name: 'recommended-type-checked', + ruleEntries: filterRuleEntriesTo('recommended'), + settings: { + getOptions: createGetOptionsForLevel('recommended'), + }, +}); + +await writeExtendedConfig({ + description: + 'A version of `recommended` that only contains type-checked rules and disables of any corresponding core ESLint rules.', + name: 'recommended-type-checked-only', + ruleEntries: filterRuleEntriesTo('recommended'), + settings: { + getOptions: createGetOptionsForLevel('recommended'), + typeChecked: 'include-only', + }, +}); + +await writeExtendedConfig({ + description: + 'Contains all of `recommended`, as well as additional strict rules that can also catch bugs. ', + name: 'strict', + ruleEntries: filterRuleEntriesTo('recommended', 'strict'), + settings: { + getOptions: createGetOptionsForLevel('strict'), + typeChecked: 'exclude', + }, +}); + +await writeExtendedConfig({ + description: + 'Contains all of `recommended`, `recommended-type-checked`, and `strict`, along with additional strict rules that require type information.', + name: 'strict-type-checked', + ruleEntries: filterRuleEntriesTo('recommended', 'strict'), + settings: { + getOptions: createGetOptionsForLevel('strict'), + }, +}); + +await writeExtendedConfig({ + description: + 'A version of `strict` that only contains type-checked rules and disables of any corresponding core ESLint rules.', + name: 'strict-type-checked-only', + ruleEntries: filterRuleEntriesTo('recommended', 'strict'), + settings: { + getOptions: createGetOptionsForLevel('strict'), + typeChecked: 'include-only', + }, +}); + +await writeExtendedConfig({ + description: + 'Rules considered to be best practice for modern TypeScript codebases, but that do not impact program logic.', + name: 'stylistic', + ruleEntries: filterRuleEntriesTo('stylistic'), + settings: { + typeChecked: 'exclude', + }, +}); + +await writeExtendedConfig({ + description: + 'Contains all of `stylistic`, along with additional stylistic rules that require type information.', + name: 'stylistic-type-checked', + ruleEntries: filterRuleEntriesTo('stylistic'), +}); + +await writeExtendedConfig({ + description: + 'A version of `stylistic` that only contains type-checked rules and disables of any corresponding core ESLint rules.', + name: 'stylistic-type-checked-only', + ruleEntries: filterRuleEntriesTo('stylistic'), + settings: { + typeChecked: 'include-only', + }, +}); + +await writeConfig({ + description: + 'A utility ruleset that will disable type-aware linting and all type-aware rules available in our project.', + getConfig: () => ({ + parserOptions: { + program: null, + project: false, + projectService: false, + }, + rules: allRuleEntries.reduce( + (config, entry) => + reducer(config, entry, { + baseRuleForExtensionRule: 'exclude', + forcedRuleLevel: 'off', + typeChecked: 'include-only', + }), + {}, + ), + }), + name: 'disable-type-checked', +}); diff --git a/deps/swc/crates/swc_ts_fast_strip/src/lib.rs b/deps/swc/crates/swc_ts_fast_strip/src/lib.rs index 9f9098ab8..b1046563d 100644 --- a/deps/swc/crates/swc_ts_fast_strip/src/lib.rs +++ b/deps/swc/crates/swc_ts_fast_strip/src/lib.rs @@ -4,7 +4,7 @@ use anyhow::Context; use bytes_str::BytesStr; use serde::{Deserialize, Serialize}; use swc_common::{ - comments::SingleThreadedComments, + comments::{Comments, SingleThreadedComments}, errors::{DiagnosticId, Handler, HANDLER}, source_map::DefaultSourceMapGenConfig, sync::Lrc, @@ -15,11 +15,11 @@ use swc_ecma_ast::{ ClassProp, Constructor, Decl, DefaultDecl, DoWhileStmt, EsVersion, ExportAll, ExportDecl, ExportDefaultDecl, ExportSpecifier, Expr, FnDecl, ForInStmt, ForOfStmt, ForStmt, GetterProp, IfStmt, ImportDecl, ImportSpecifier, ModuleDecl, ModuleItem, NamedExport, ObjectPat, Param, - Pat, PrivateMethod, PrivateProp, Program, ReturnStmt, SetterProp, Stmt, ThrowStmt, TsAsExpr, - TsConstAssertion, TsEnumDecl, TsExportAssignment, TsImportEqualsDecl, TsIndexSignature, - TsInstantiation, TsModuleDecl, TsModuleName, TsNamespaceBody, TsNonNullExpr, TsParamPropParam, - TsSatisfiesExpr, TsTypeAliasDecl, TsTypeAnn, TsTypeAssertion, TsTypeParamDecl, - TsTypeParamInstantiation, VarDeclarator, WhileStmt, YieldExpr, + Pat, PrivateMethod, PrivateProp, Program, SetterProp, Stmt, TsAsExpr, TsConstAssertion, + TsEnumDecl, TsExportAssignment, TsImportEqualsDecl, TsIndexSignature, TsInstantiation, + TsModuleDecl, TsModuleName, TsNamespaceBody, TsNonNullExpr, TsParamPropParam, TsSatisfiesExpr, + TsTypeAliasDecl, TsTypeAnn, TsTypeAssertion, TsTypeParamDecl, TsTypeParamInstantiation, + VarDeclarator, WhileStmt, }; use swc_ecma_parser::{ lexer::Lexer, @@ -37,6 +37,10 @@ use swc_ecma_visit::{Visit, VisitWith}; #[cfg(feature = "wasm-bindgen")] use wasm_bindgen::prelude::*; +use crate::strip::StripEditPlan; + +mod strip; + #[derive(Default, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Options { @@ -249,14 +253,15 @@ pub fn operate( let syntax = Syntax::Typescript(options.parser); let target = EsVersion::latest(); - let comments = SingleThreadedComments::default(); + let comments = matches!(&options.mode, Mode::Transform).then(SingleThreadedComments::default); + let lexer_comments = comments.as_ref().map(|comments| comments as &dyn Comments); - let (program, errors, mut tokens) = if should_capture_tokens { + let (program, errors, tokens) = if should_capture_tokens { let lexer = Capturing::new(Lexer::new( syntax, target, StringInput::from(&*fm), - Some(&comments), + lexer_comments, )); let mut parser = Parser::new_from(lexer); @@ -270,7 +275,7 @@ pub fn operate( (program, errors, tokens) } else { - let lexer = Lexer::new(syntax, target, StringInput::from(&*fm), Some(&comments)); + let lexer = Lexer::new(syntax, target, StringInput::from(&*fm), lexer_comments); let mut parser = Parser::new_from(lexer); let program = match options.module { @@ -282,6 +287,12 @@ pub fn operate( (program, errors, Vec::new()) }; + debug_assert!( + tokens + .windows(2) + .all(|tokens| tokens[0].span.lo < tokens[1].span.lo), + "captured tokens must be ordered by source position" + ); let mut program = match program { Ok(program) => program, @@ -318,11 +329,10 @@ pub fn operate( match options.mode { Mode::StripOnly => { - tokens.sort_by_key(|t| t.span); - if deprecated_ts_module_as_error { program.visit_with(&mut ErrorOnTsModule { src: &fm.src, + source_start: fm.start_pos, tokens: &tokens, }); if handler.has_errors() { @@ -334,7 +344,7 @@ pub fn operate( } // Strip typescript types - let mut ts_strip = TsStrip::new(fm.src.clone(), tokens); + let mut ts_strip = TsStrip::new(fm.src.clone(), fm.start_pos, tokens); program.visit_with(&mut ts_strip); if handler.has_errors() { @@ -344,83 +354,16 @@ pub fn operate( }); } - let replacements = ts_strip.replacements; - let overwrites = ts_strip.overwrites; + let edits = ts_strip.edits; - if replacements.is_empty() && overwrites.is_empty() { + if edits.is_empty() { return Ok(TransformOutput { code: fm.src.to_string(), map: Default::default(), }); } - let source = fm.src.clone(); - let mut code = fm.src.to_string().into_bytes(); - - for r in replacements { - let (start, end) = (r.0 .0 as usize - 1, r.1 .0 as usize - 1); - - for (i, c) in source[start..end].char_indices() { - let i = start + i; - match c { - // https://262.ecma-international.org/#sec-white-space - '\u{0009}' | '\u{0000B}' | '\u{000C}' | '\u{FEFF}' => continue, - // Space_Separator - '\u{0020}' | '\u{00A0}' | '\u{1680}' | '\u{2000}' | '\u{2001}' - | '\u{2002}' | '\u{2003}' | '\u{2004}' | '\u{2005}' | '\u{2006}' - | '\u{2007}' | '\u{2008}' | '\u{2009}' | '\u{200A}' | '\u{202F}' - | '\u{205F}' | '\u{3000}' => continue, - // https://262.ecma-international.org/#sec-line-terminators - '\u{000A}' | '\u{000D}' | '\u{2028}' | '\u{2029}' => continue, - _ => match c.len_utf8() { - 1 => { - // Space 0020 - code[i] = 0x20; - } - 2 => { - // No-Break Space 00A0 - code[i] = 0xc2; - code[i + 1] = 0xa0; - } - 3 => { - // En Space 2002 - code[i] = 0xe2; - code[i + 1] = 0x80; - code[i + 2] = 0x82; - } - 4 => { - // We do not have a 4-byte space character in the Unicode standard. - - // Space 0020 - code[i] = 0x20; - // ZWNBSP FEFF - code[i + 1] = 0xef; - code[i + 2] = 0xbb; - code[i + 3] = 0xbf; - } - _ => unreachable!(), - }, - } - } - } - - for (i, v) in overwrites { - code[i.0 as usize - 1] = v; - } - - #[cfg(debug_assertions)] - let code = { - String::from_utf8(code).map_err(|err| TsError { - message: format!("failed to convert to utf-8: {err}"), - code: ErrorCode::Unknown, - })? - }; - #[cfg(not(debug_assertions))] - let code = { - // SAFETY: We've already validated that the source is valid utf-8 - // and our operations are limited to character-level string replacements. - unsafe { String::from_utf8_unchecked(code) } - }; + let code = edits.render(fm.start_pos, &fm.src); Ok(TransformOutput { code, @@ -429,6 +372,7 @@ pub fn operate( } Mode::Transform => { + let comments = comments.expect("transform mode must collect comments"); let unresolved_mark = Mark::new(); let top_level_mark = Mark::new(); @@ -436,10 +380,9 @@ pub fn operate( program.mutate(&mut resolver(unresolved_mark, top_level_mark, true)); if deprecated_ts_module_as_error { - tokens.sort_by_key(|t| t.span); - program.visit_with(&mut ErrorOnTsModule { src: &fm.src, + source_start: fm.start_pos, tokens: &tokens, }); if handler.has_errors() { @@ -541,6 +484,7 @@ pub fn operate( struct ErrorOnTsModule<'a> { src: &'a str, + source_start: BytePos, tokens: &'a [TokenAndSpan], } @@ -591,8 +535,11 @@ impl Visit for ErrorOnTsModule<'_> { } pos = span.lo; - } else if self.src.as_bytes()[pos.0 as usize - 1] != b'm' { - return; + } else { + let offset = (pos.0 - self.source_start.0) as usize; + if self.src.as_bytes()[offset] != b'm' { + return; + } } if HANDLER.is_set() { @@ -611,22 +558,17 @@ impl Visit for ErrorOnTsModule<'_> { struct TsStrip { src: BytesStr, - - /// Replaced with whitespace - replacements: Vec<(BytePos, BytePos)>, - - // should be string, but we use u8 for only `)` usage. - overwrites: Vec<(BytePos, u8)>, - + source_start: BytePos, + edits: StripEditPlan, tokens: std::vec::Vec, } impl TsStrip { - fn new(src: BytesStr, tokens: std::vec::Vec) -> Self { + fn new(src: BytesStr, source_start: BytePos, tokens: std::vec::Vec) -> Self { TsStrip { src, - replacements: Default::default(), - overwrites: Default::default(), + source_start, + edits: Default::default(), tokens, } } @@ -634,15 +576,17 @@ impl TsStrip { impl TsStrip { fn add_replacement(&mut self, span: Span) { - self.replacements.push((span.lo, span.hi)); + self.edits.erase(span); } - fn add_overwrite(&mut self, pos: BytePos, value: u8) { - self.overwrites.push((pos, value)); + fn add_overwrite(&mut self, pos: BytePos, value: char) { + self.edits.overwrite(pos, value); } fn get_src_slice(&self, span: Span) -> &str { - &self.src[(span.lo.0 - 1) as usize..(span.hi.0 - 1) as usize] + let start = (span.lo.0 - self.source_start.0) as usize; + let end = (span.hi.0 - self.source_start.0) as usize; + &self.src[start..end] } fn get_next_token_index(&self, pos: BytePos) -> usize { @@ -708,15 +652,16 @@ impl TsStrip { Token::LParen | Token::LBracket | Token::NoSubstitutionTemplateLiteral + | Token::TemplateHead | Token::Plus | Token::Minus | Token::Regex => { if prev_token == &Token::Semi { - self.add_overwrite(prev_span.lo, b';'); + self.add_overwrite(prev_span.lo, ';'); return; } - self.add_overwrite(span.lo, b';'); + self.add_overwrite(span.lo, ';'); } _ => {} @@ -731,12 +676,16 @@ impl TsStrip { if let TokenAndSpan { // Only `(`, `[` and backtick affect ASI. - token: Token::LParen | Token::LBracket | Token::NoSubstitutionTemplateLiteral, + token: + Token::LParen + | Token::LBracket + | Token::NoSubstitutionTemplateLiteral + | Token::TemplateHead, had_line_break: true, .. } = &self.tokens[index + 1] { - self.add_overwrite(span.lo, b';'); + self.add_overwrite(span.lo, ';'); } } @@ -804,32 +753,51 @@ impl TsStrip { self.add_replacement(*span); } + // Stripping the type parameters can expose a line break that either makes + // JavaScript invalid (`async`, `throw`) or changes its parsing (`return`, + // `yield`): + // // ```TypeScript - // return/yield/throw - // (v: T) => v; + // const f = async + // (value: T) => value; + // + // return + // (value: T) => value; // ``` // - // ```TypeScript - // return/yield/throw ( - // v ) => v; + // Move the existing opening parenthesis into the type parameter slot so + // the output keeps the same byte length and line breaks: + // + // ```JavaScript + // const f = async( + // value ) => value; + // + // return ( + // value ) => value; // ``` - fn fix_asi_in_arrow_expr(&mut self, arrow_expr: &ArrowExpr) { - if let Some(tp) = &arrow_expr.type_params { - let l_paren = self.get_next_token(tp.span.hi); - debug_assert_eq!(l_paren.token, Token::LParen); - - let slice = self.get_src_slice(tp.span.with_hi(l_paren.span.lo)); - - if !slice.chars().any(is_new_line) { - return; - } + fn move_arrow_opening_paren(&mut self, arrow_expr: &ArrowExpr, type_params: Span) { + let type_params_index = self.get_next_token_index(type_params.lo); + let follows_restricted_keyword = type_params_index > 0 + && !self.tokens[type_params_index].had_line_break + && matches!( + self.tokens[type_params_index - 1].token, + Token::Return | Token::Yield | Token::Throw + ); + + if !arrow_expr.is_async && !follows_restricted_keyword { + return; + } - let l_paren_pos = l_paren.span.lo; - let l_lt_pos = tp.span.lo; + let l_paren = self.get_next_token(type_params.hi); + debug_assert_eq!(l_paren.token, Token::LParen); - self.add_overwrite(l_paren_pos, b' '); - self.add_overwrite(l_lt_pos, b'('); + let slice = self.get_src_slice(type_params.with_hi(l_paren.span.lo)); + if !slice.chars().any(is_new_line) { + return; } + + self.add_overwrite(l_paren.span.lo, ' '); + self.add_overwrite(type_params.lo, '('); } fn assertion_chain_would_change_binary_grouping( @@ -951,38 +919,9 @@ impl Visit for TsStrip { } fn visit_arrow_expr(&mut self, n: &ArrowExpr) { - 'type_params: { - // ```TypeScript - // let f = async < - // T - // >(v: T) => v; - // ``` - - // ```TypeScript - // let f = async ( - // - // v ) => v; - // ``` - if let Some(tp) = &n.type_params { - self.add_replacement(tp.span); - - if !n.is_async { - break 'type_params; - } - - let slice = self.get_src_slice(tp.span); - if !slice.chars().any(is_new_line) { - break 'type_params; - } - - let l_paren = self.get_next_token(tp.span.hi); - debug_assert_eq!(l_paren.token, Token::LParen); - let l_paren_pos = l_paren.span.lo; - let l_lt_pos = tp.span.lo; - - self.add_overwrite(l_paren_pos, b' '); - self.add_overwrite(l_lt_pos, b'('); - } + if let Some(type_params) = &n.type_params { + self.add_replacement(type_params.span); + self.move_arrow_opening_paren(n, type_params.span); } if let Some(ret) = &n.return_type { @@ -1015,12 +954,14 @@ impl Visit for TsStrip { // ``` let mut pos = ret.span.hi - BytePos(1); - while !self.src.as_bytes()[pos.0 as usize - 1].is_utf8_char_boundary() { - self.add_overwrite(pos, b' '); + while !self + .src + .is_char_boundary((pos.0 - self.source_start.0) as usize) + { pos = pos - BytePos(1); } - self.add_overwrite(pos, b')'); + self.add_overwrite(pos, ')'); } } @@ -1028,61 +969,6 @@ impl Visit for TsStrip { n.body.visit_with(self); } - fn visit_return_stmt(&mut self, n: &ReturnStmt) { - let Some(arg) = n.arg.as_deref() else { - return; - }; - - arg.visit_with(self); - - let Some(arrow_expr) = arg.as_arrow() else { - return; - }; - - if arrow_expr.is_async { - // We have already handled type parameters in `visit_arrow_expr`. - return; - } - - self.fix_asi_in_arrow_expr(arrow_expr); - } - - fn visit_yield_expr(&mut self, n: &YieldExpr) { - let Some(arg) = &n.arg else { - return; - }; - - arg.visit_with(self); - - let Some(arrow_expr) = arg.as_arrow() else { - return; - }; - - if arrow_expr.is_async { - // We have already handled type parameters in `visit_arrow_expr`. - return; - } - - self.fix_asi_in_arrow_expr(arrow_expr); - } - - fn visit_throw_stmt(&mut self, n: &ThrowStmt) { - let arg = &n.arg; - - arg.visit_with(self); - - let Some(arrow_expr) = arg.as_arrow() else { - return; - }; - - if arrow_expr.is_async { - // We have already handled type parameters in `visit_arrow_expr`. - return; - } - - self.fix_asi_in_arrow_expr(arrow_expr); - } - fn visit_binding_ident(&mut self, n: &BindingIdent) { n.visit_children_with(self); @@ -1180,7 +1066,7 @@ impl Visit for TsStrip { .filter(|k| matches!(k.sym.as_ref(), "in" | "instanceof")) .is_some()) { - self.add_overwrite(start_pos, b';'); + self.add_overwrite(start_pos, ';'); } n.visit_children_with(self); @@ -1215,7 +1101,7 @@ impl Visit for TsStrip { // `get: number` // `get; ` if let Some(type_ann) = &n.type_ann { - self.add_overwrite(type_ann.span.lo, b';'); + self.add_overwrite(type_ann.span.lo, ';'); } } } @@ -1235,7 +1121,7 @@ impl Visit for TsStrip { .filter(|k| matches!(k.sym.as_ref(), "in" | "instanceof")) .is_some()) { - self.add_overwrite(start_pos, b';'); + self.add_overwrite(start_pos, ';'); } n.visit_children_with(self); @@ -1633,12 +1519,12 @@ impl Visit for TsStrip { n.visit_children_with(self); if n.cons.is_ts_declare() { - self.add_overwrite(n.cons.span_lo(), b';'); + self.add_overwrite(n.cons.span_lo(), ';'); } if let Some(alt) = &n.alt { if alt.is_ts_declare() { - self.add_overwrite(alt.span_lo(), b';'); + self.add_overwrite(alt.span_lo(), ';'); } } } @@ -1647,7 +1533,7 @@ impl Visit for TsStrip { n.visit_children_with(self); if n.body.is_ts_declare() { - self.add_overwrite(n.body.span_lo(), b';'); + self.add_overwrite(n.body.span_lo(), ';'); } } @@ -1655,7 +1541,7 @@ impl Visit for TsStrip { n.visit_children_with(self); if n.body.is_ts_declare() { - self.add_overwrite(n.body.span_lo(), b';'); + self.add_overwrite(n.body.span_lo(), ';'); } } @@ -1663,7 +1549,7 @@ impl Visit for TsStrip { n.visit_children_with(self); if n.body.is_ts_declare() { - self.add_overwrite(n.body.span_lo(), b';'); + self.add_overwrite(n.body.span_lo(), ';'); } } @@ -1671,7 +1557,7 @@ impl Visit for TsStrip { n.visit_children_with(self); if n.body.is_ts_declare() { - self.add_overwrite(n.body.span_lo(), b';'); + self.add_overwrite(n.body.span_lo(), ';'); } } @@ -1679,7 +1565,7 @@ impl Visit for TsStrip { n.visit_children_with(self); if n.body.is_ts_declare() { - self.add_overwrite(n.body.span_lo(), b';'); + self.add_overwrite(n.body.span_lo(), ';'); } } @@ -1814,19 +1700,6 @@ impl IsUninstantiated for DefaultDecl { } } -trait U8Helper { - fn is_utf8_char_boundary(&self) -> bool; -} - -impl U8Helper for u8 { - // Copy from std::core::num::u8 - #[inline] - fn is_utf8_char_boundary(&self) -> bool { - // This is bit magic equivalent to: b < 128 || b >= 192 - (*self as i8) >= -0x40 - } -} - fn span(lo: BytePos, hi: BytePos) -> Span { Span::new(lo, hi) } diff --git a/deps/swc/crates/swc_ts_fast_strip/src/strip.rs b/deps/swc/crates/swc_ts_fast_strip/src/strip.rs new file mode 100644 index 000000000..4b6b834a0 --- /dev/null +++ b/deps/swc/crates/swc_ts_fast_strip/src/strip.rs @@ -0,0 +1,271 @@ +use std::ops::Range; + +use swc_common::{BytePos, Span}; + +/// Edits produced while visiting the TypeScript AST. +/// +/// Parser positions remain UTF-8 byte positions. The renderer is solely +/// responsible for translating them to the output coordinate system. +#[derive(Default)] +pub(crate) struct StripEditPlan { + erasures: Vec, + overwrites: Vec, +} + +#[derive(Clone, Copy)] +struct Overwrite { + pos: BytePos, + value: char, +} + +impl StripEditPlan { + pub(crate) fn erase(&mut self, span: Span) { + self.erasures.push(span); + } + + /// Replaces the source scalar at `pos` while preserving its UTF-16 width. + pub(crate) fn overwrite(&mut self, pos: BytePos, value: char) { + assert!(value.is_ascii(), "strip overwrites must be ASCII"); + self.overwrites.push(Overwrite { pos, value }); + } + + pub(crate) fn is_empty(&self) -> bool { + self.erasures.is_empty() && self.overwrites.is_empty() + } + + /// Applies all edits while preserving the source UTF-16 length. + pub(crate) fn render(self, source_start: BytePos, source: &str) -> String { + if self.is_empty() { + return source.to_owned(); + } + + let plan = LocalEditPlan::new(self, source_start, source); + if let Some(output) = plan.render_ascii_edits(source) { + return output; + } + + plan.render_unicode_edits(source) + } +} + +struct LocalEditPlan { + erasures: Vec>, + overwrites: Vec, +} + +#[derive(Clone, Copy)] +struct LocalOverwrite { + byte_offset: usize, + value: char, +} + +impl LocalEditPlan { + fn new(plan: StripEditPlan, source_start: BytePos, source: &str) -> Self { + let source_len = source.len(); + let mut erasures: Vec> = plan + .erasures + .into_iter() + .map(|span| { + let start = local_offset(span.lo, source_start, source_len); + let end = local_offset(span.hi, source_start, source_len); + assert!(start <= end, "invalid strip erasure range"); + start..end + }) + .collect(); + erasures.sort_unstable_by_key(|range| range.start); + let mut merged_erasures: Vec> = Vec::with_capacity(erasures.len()); + for range in erasures { + assert!( + source.is_char_boundary(range.start) && source.is_char_boundary(range.end), + "strip erasure is not on a UTF-8 character boundary" + ); + if let Some(previous) = merged_erasures.last_mut() { + if range.start <= previous.end { + previous.end = previous.end.max(range.end); + continue; + } + } + merged_erasures.push(range); + } + + let mut overwrites: Vec = plan + .overwrites + .into_iter() + .map(|overwrite| LocalOverwrite { + byte_offset: local_offset(overwrite.pos, source_start, source_len), + value: overwrite.value, + }) + .collect(); + // Stable sorting keeps the previous renderer's last-write-wins + // behavior if the planner emits the same position more than once. + overwrites.sort_by_key(|overwrite| overwrite.byte_offset); + let mut deduplicated_overwrites: Vec = Vec::with_capacity(overwrites.len()); + for overwrite in overwrites { + assert!( + overwrite.byte_offset < source_len + && source.is_char_boundary(overwrite.byte_offset), + "strip overwrite is not on a source character" + ); + if let Some(previous) = deduplicated_overwrites.last_mut() { + if previous.byte_offset == overwrite.byte_offset { + *previous = overwrite; + continue; + } + } + deduplicated_overwrites.push(overwrite); + } + + Self { + erasures: merged_erasures, + overwrites: deduplicated_overwrites, + } + } + + /// Uses byte offsets only when every edited source scalar is ASCII. + fn render_ascii_edits(&self, source: &str) -> Option { + let source = source.as_bytes(); + let mut output = source.to_vec(); + + for range in &self.erasures { + for (source, output) in source[range.clone()].iter().zip(&mut output[range.clone()]) { + if !source.is_ascii() { + return None; + } + if !is_preserved_ascii_whitespace(*source) { + *output = b' '; + } + } + } + + for overwrite in &self.overwrites { + if !source[overwrite.byte_offset].is_ascii() { + return None; + } + output[overwrite.byte_offset] = overwrite.value as u8; + } + + // SAFETY: `source` was valid UTF-8. Every modified source byte was + // checked to be ASCII and every replacement is ASCII, so the edits + // cannot change any multi-byte UTF-8 sequence. + Some(unsafe { String::from_utf8_unchecked(output) }) + } + + /// Renders Unicode edits directly to UTF-8 while preserving each source + /// scalar's UTF-16 width. + /// + /// Unedited segments are copied as whole UTF-8 slices. Only erased source + /// segments and overwritten scalars need Unicode decoding. + fn render_unicode_edits(&self, source: &str) -> String { + let mut output = String::with_capacity(source.len()); + let mut source_offset = 0; + let mut overwrite_index = 0; + + for erasure in &self.erasures { + while overwrite_index < self.overwrites.len() + && self.overwrites[overwrite_index].byte_offset < erasure.start + { + let overwrite = self.overwrites[overwrite_index]; + output.push_str(&source[source_offset..overwrite.byte_offset]); + source_offset = render_overwrite(&mut output, source, overwrite); + overwrite_index += 1; + } + + output.push_str(&source[source_offset..erasure.start]); + source_offset = erasure.start; + + while overwrite_index < self.overwrites.len() + && self.overwrites[overwrite_index].byte_offset < erasure.end + { + let overwrite = self.overwrites[overwrite_index]; + render_erasure(&mut output, &source[source_offset..overwrite.byte_offset]); + source_offset = render_overwrite(&mut output, source, overwrite); + overwrite_index += 1; + } + + render_erasure(&mut output, &source[source_offset..erasure.end]); + source_offset = erasure.end; + } + + for &overwrite in &self.overwrites[overwrite_index..] { + output.push_str(&source[source_offset..overwrite.byte_offset]); + source_offset = render_overwrite(&mut output, source, overwrite); + } + output.push_str(&source[source_offset..]); + + output + } +} + +fn local_offset(pos: BytePos, source_start: BytePos, source_len: usize) -> usize { + let offset = pos + .0 + .checked_sub(source_start.0) + .expect("strip edit precedes its source file") as usize; + assert!(offset <= source_len, "strip edit exceeds its source file"); + offset +} + +fn push_spaces(output: &mut String, count: usize) { + for _ in 0..count { + output.push(' '); + } +} + +fn render_erasure(output: &mut String, source: &str) { + for c in source.chars() { + if is_preserved_whitespace(c) { + output.push(c); + } else { + push_spaces(output, c.len_utf16()); + } + } +} + +fn render_overwrite(output: &mut String, source: &str, overwrite: LocalOverwrite) -> usize { + let original = source[overwrite.byte_offset..] + .chars() + .next() + .expect("strip overwrite points to the end of the source"); + + output.push(overwrite.value); + push_spaces(output, original.len_utf16() - 1); + + overwrite.byte_offset + original.len_utf8() +} + +fn is_preserved_whitespace(c: char) -> bool { + matches!( + c, + // ECMAScript whitespace. + '\u{0009}' + | '\u{000B}' + | '\u{000C}' + | '\u{FEFF}' + | '\u{0020}' + | '\u{00A0}' + | '\u{1680}' + | '\u{2000}' + | '\u{2001}' + | '\u{2002}' + | '\u{2003}' + | '\u{2004}' + | '\u{2005}' + | '\u{2006}' + | '\u{2007}' + | '\u{2008}' + | '\u{2009}' + | '\u{200A}' + | '\u{202F}' + | '\u{205F}' + | '\u{3000}' + // ECMAScript line terminators. + | '\u{000A}' + | '\u{000D}' + | '\u{2028}' + | '\u{2029}' + ) +} + +fn is_preserved_ascii_whitespace(byte: u8) -> bool { + matches!(byte, b'\t' | 0x0b | 0x0c | b' ' | b'\n' | b'\r') +} diff --git a/deps/swc/crates/swc_ts_fast_strip_binding/Cargo.toml b/deps/swc/crates/swc_ts_fast_strip_binding/Cargo.toml index 9ba3e78b0..6c67010be 100644 --- a/deps/swc/crates/swc_ts_fast_strip_binding/Cargo.toml +++ b/deps/swc/crates/swc_ts_fast_strip_binding/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_ts_fast_strip_binding" repository = { workspace = true } -version = "0.18.0" +version = "0.21.0" [lib] bench = false @@ -17,12 +17,17 @@ anyhow = { workspace = true } miette = { workspace = true } owo-colors = { workspace = true } serde = { workspace = true, features = ["derive"] } -swc_common = { version = "23.0.2", path = "../../crates/swc_common" } -swc_error_reporters = { version = "25.0.0", path = "../../crates/swc_error_reporters" } -swc_ts_fast_strip = { version = "53.0.0", path = "../../crates/swc_ts_fast_strip" } +swc_common = { version = "24.0.0", path = "../../crates/swc_common" } +swc_error_reporters = { version = "26.0.0", path = "../../crates/swc_error_reporters" } +swc_ts_fast_strip = { version = "56.0.0", path = "../../crates/swc_ts_fast_strip" } tracing = { workspace = true } unicode-width = { workspace = true } [dev-dependencies] +codspeed-criterion-compat.workspace = true serde_json.workspace = true -swc_ecma_parser = { version = "41.1.2", path = "../../crates/swc_ecma_parser" } +swc_ecma_parser = { version = "43.0.0", path = "../../crates/swc_ecma_parser" } + +[[bench]] +harness = false +name = "assets" diff --git a/deps/swc/crates/swc_ts_fast_strip_binding/benches/assets.rs b/deps/swc/crates/swc_ts_fast_strip_binding/benches/assets.rs new file mode 100644 index 000000000..bd8a16b9e --- /dev/null +++ b/deps/swc/crates/swc_ts_fast_strip_binding/benches/assets.rs @@ -0,0 +1,49 @@ +use codspeed_criterion_compat::{black_box, criterion_group, criterion_main, Bencher, Criterion}; +use swc_ts_fast_strip::Options; +use swc_ts_fast_strip_binding::transform; + +const CASES: &[(&str, &str)] = &[ + ( + "typescript/fast-strip-binding/synthetic", + include_str!("../../swc_ts_fast_strip/benches/assets/test.ts"), + ), + ( + "typescript/fast-strip-binding/docusaurus-config", + include_str!("../../swc_ts_fast_strip/benches/assets/docusaurus.config.ts"), + ), + ( + "typescript/fast-strip-binding/ant-design-config", + include_str!("../../swc_ts_fast_strip/benches/assets/ant-design.vitest.config.ts"), + ), + ( + "typescript/fast-strip-binding/typescript-eslint-generate-configs", + include_str!( + "../../swc_ts_fast_strip/benches/assets/typescript-eslint.generate-configs.mts" + ), + ), + ( + "typescript/fast-strip-binding/graphile-config", + include_str!("../../swc_ts_fast_strip/benches/assets/graphile.config.ts"), + ), + ( + "typescript/fast-strip-binding/hono-types-test", + include_str!("../../swc_ts_fast_strip/benches/assets/hono.types.test.ts"), + ), +]; + +fn assets(c: &mut Criterion) { + for &(name, source) in CASES { + c.bench_function(name, |b| transform_typescript(b, source)); + } +} + +fn transform_typescript(b: &mut Bencher, source: &str) { + b.iter(|| { + let result = transform(black_box(source.to_owned()), Options::default()) + .expect("benchmark source should be valid erasable TypeScript"); + black_box(result); + }); +} + +criterion_group!(benches, assets); +criterion_main!(benches); diff --git a/deps/swc/crates/swc_ts_fast_strip_binding/src/lib.rs b/deps/swc/crates/swc_ts_fast_strip_binding/src/lib.rs index 2d3679066..fe785c6a4 100644 --- a/deps/swc/crates/swc_ts_fast_strip_binding/src/lib.rs +++ b/deps/swc/crates/swc_ts_fast_strip_binding/src/lib.rs @@ -33,7 +33,8 @@ fn operate(input: String, options: Options) -> Result>>, - reporter: SwcReportHandler, + /// Successful transforms never need the graphical diagnostic reporter. + reporter: Option, cm: Lrc, } @@ -43,25 +44,7 @@ where { let wr = JsonErrorWriter { errors: Default::default(), - reporter: SwcReportHandler::default().with_theme(GraphicalTheme { - characters: ThemeCharacters { - hbar: ' ', - vbar: ' ', - xbar: ' ', - vbar_break: ' ', - ltop: ' ', - rtop: ' ', - mtop: ' ', - lbot: ' ', - rbot: ' ', - mbot: ' ', - error: "".into(), - warning: "".into(), - advice: "".into(), - ..ThemeCharacters::ascii() - }, - styles: ThemeStyles::none(), - }), + reporter: None, cm, }; let emitter: Box = Box::new(wr.clone()); @@ -86,7 +69,8 @@ impl Emitter for JsonErrorWriter { let snippet = d.span.primary_span().and_then(|span| { let mut snippet = String::new(); - match self.reporter.render_report( + let reporter = self.reporter.get_or_insert_with(json_reporter); + match reporter.render_report( &mut snippet, &Snippet { source_code: &to_pretty_source_code(&self.cm, true), @@ -142,6 +126,28 @@ impl Emitter for JsonErrorWriter { } } +fn json_reporter() -> SwcReportHandler { + SwcReportHandler::default().with_theme(GraphicalTheme { + characters: ThemeCharacters { + hbar: ' ', + vbar: ' ', + xbar: ' ', + vbar_break: ' ', + ltop: ' ', + rtop: ' ', + mtop: ' ', + lbot: ' ', + rbot: ' ', + mbot: ' ', + error: "".into(), + warning: "".into(), + advice: "".into(), + ..ThemeCharacters::ascii() + }, + styles: ThemeStyles::none(), + }) +} + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct JsonDiagnostic { diff --git a/deps/swc/crates/swc_typescript/Cargo.toml b/deps/swc/crates/swc_typescript/Cargo.toml index 2f5374e9e..722ce8358 100644 --- a/deps/swc/crates/swc_typescript/Cargo.toml +++ b/deps/swc/crates/swc_typescript/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "swc_typescript" repository = { workspace = true } -version = "30.0.1" +version = "32.0.0" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } @@ -16,15 +16,15 @@ bitflags = { workspace = true } petgraph = { workspace = true } rustc-hash = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_ecma_ast = { version = "25.0.0", path = "../swc_ecma_ast" } -swc_ecma_utils = { version = "31.0.1", path = "../swc_ecma_utils" } -swc_ecma_visit = { version = "25.0.0", path = "../swc_ecma_visit" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_ecma_ast = { version = "27.0.0", path = "../swc_ecma_ast" } +swc_ecma_utils = { version = "33.0.0", path = "../swc_ecma_utils" } +swc_ecma_visit = { version = "27.0.0", path = "../swc_ecma_visit" } [dev-dependencies] -swc_ecma_codegen = { version = "28.0.2", path = "../swc_ecma_codegen" } -swc_ecma_parser = { version = "41.1.2", path = "../swc_ecma_parser" } -swc_ecma_transforms_base = { version = "44.0.3", path = "../swc_ecma_transforms_base" } -testing = { version = "24.0.1", path = "../testing" } +swc_ecma_codegen = { version = "30.0.0", path = "../swc_ecma_codegen" } +swc_ecma_parser = { version = "43.0.0", path = "../swc_ecma_parser" } +swc_ecma_transforms_base = { version = "47.0.0", path = "../swc_ecma_transforms_base" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_typescript/src/fast_dts/enum.rs b/deps/swc/crates/swc_typescript/src/fast_dts/enum.rs index f43b385ac..30a2a3399 100644 --- a/deps/swc/crates/swc_typescript/src/fast_dts/enum.rs +++ b/deps/swc/crates/swc_typescript/src/fast_dts/enum.rs @@ -1,25 +1,53 @@ use core::f64; +use std::borrow::Borrow; use rustc_hash::FxHashMap; -use swc_atoms::{atom, Atom}; -use swc_common::{Spanned, SyntaxContext, DUMMY_SP}; +use swc_atoms::{wtf8::Wtf8Buf, Atom, Wtf8Atom}; +use swc_common::{Spanned, DUMMY_SP}; use swc_ecma_ast::{ - BinExpr, BinaryOp, Expr, Ident, Lit, Number, Str, TsEnumDecl, TsEnumMemberId, UnaryExpr, - UnaryOp, + BinExpr, BinaryOp, Expr, Lit, Number, Str, TsEnumDecl, TsEnumMemberId, UnaryExpr, UnaryOp, }; -use swc_ecma_utils::number::JsNumber; +use swc_ecma_utils::number::{JsNumber, ToJsString}; use super::{util::ast_ext::MemberPropExt, FastDts}; #[derive(Debug, Clone)] enum ConstantValue { - Number(f64), - String(String), + Number(Number), + String(Wtf8Atom), +} + +impl ConstantValue { + /// Creates a computed number. Computations intentionally discard source + /// spelling so code generation can choose the canonical representation. + fn number(value: f64) -> Self { + Self::Number(Number { + span: DUMMY_SP, + value, + raw: None, + }) + } + + /// Creates a number converted directly from an AST value. + fn converted_number(value: f64, raw: Option) -> Self { + Self::Number(Number { + span: DUMMY_SP, + value, + raw, + }) + } + + fn push_to(self, output: &mut Wtf8Buf) { + match self { + Self::Number(number) => output.push_str(&number.value.to_js_string()), + Self::String(string) => output.push_wtf8(&string), + } + } } impl FastDts { pub(crate) fn transform_enum(&mut self, decl: &mut TsEnumDecl) { - let mut prev_init_value = Some(ConstantValue::Number(-1.0)); + let mut prev_init_value = Some(ConstantValue::number(-1.0)); let mut prev_members = FxHashMap::default(); for member in &mut decl.members { let value = if let Some(init_expr) = &member.init { @@ -29,58 +57,22 @@ impl FastDts { } computed_value } else if let Some(ConstantValue::Number(v)) = prev_init_value { - Some(ConstantValue::Number(v + 1.0)) + Some(ConstantValue::number(v.value + 1.0)) } else { None }; prev_init_value = value.clone(); if let Some(value) = &value { - let member_name = match &member.id { - TsEnumMemberId::Ident(ident) => ident.sym.clone(), - TsEnumMemberId::Str(s) => s - .value - .clone() - .try_into_atom() - .unwrap_or_else(|wtf8| Atom::from(&*wtf8.to_string_lossy())), - #[cfg(swc_ast_unknown)] - _ => panic!("unable to access unknown nodes"), - }; - prev_members.insert(member_name.clone(), value.clone()); + prev_members.insert(enum_member_name(&member.id), value.clone()); } member.init = value.map(|value| { Box::new(match value { - ConstantValue::Number(v) => { - let is_neg = v < 0.0; - let expr = if v.is_infinite() { - Expr::Ident(Ident { - span: DUMMY_SP, - sym: atom!("Infinity"), - ctxt: SyntaxContext::empty(), - optional: false, - }) - } else { - Expr::Lit(Lit::Num(Number { - span: DUMMY_SP, - value: v, - raw: Some(v.to_string().into()), - })) - }; - - if is_neg { - Expr::Unary(UnaryExpr { - span: DUMMY_SP, - arg: Box::new(expr), - op: UnaryOp::Minus, - }) - } else { - expr - } - } - ConstantValue::String(s) => Expr::Lit(Lit::Str(Str { + ConstantValue::Number(number) => Expr::Lit(Lit::Num(number)), + ConstantValue::String(value) => Expr::Lit(Lit::Str(Str { span: DUMMY_SP, - value: s.clone().into(), + value, raw: None, })), }) @@ -92,24 +84,30 @@ impl FastDts { &self, expr: &Expr, enum_name: &Atom, - prev_members: &FxHashMap, + prev_members: &FxHashMap, ) -> Option { match expr { Expr::Lit(lit) => match lit { - Lit::Str(s) => Some(ConstantValue::String(s.value.to_string_lossy().to_string())), - Lit::Num(number) => Some(ConstantValue::Number(number.value)), + Lit::Str(string) => Some(ConstantValue::String(string.value.clone())), + Lit::Num(number) => Some(ConstantValue::Number(number.clone())), Lit::Null(_) | Lit::BigInt(_) | Lit::Bool(_) | Lit::Regex(_) | Lit::JSXText(_) => { None } #[cfg(swc_ast_unknown)] _ => panic!("unable to access unknown nodes"), }, - Expr::Tpl(tpl) => { - let mut value = String::new(); - for part in &tpl.quasis { - value.push_str(&part.raw); + Expr::Tpl(template) => { + let mut quasis = template.quasis.iter(); + let first = quasis.next()?.cooked.as_ref()?; + let mut value = Wtf8Buf::from(first); + + for (expr, quasi) in template.exprs.iter().zip(quasis) { + self.evaluate(expr, enum_name, prev_members)? + .push_to(&mut value); + value.push_wtf8(quasi.cooked.as_ref()?); } - Some(ConstantValue::String(value)) + + Some(ConstantValue::String(Wtf8Atom::from(&*value))) } Expr::Paren(expr) => self.evaluate(&expr.expr, enum_name, prev_members), Expr::Bin(bin_expr) => self.evaluate_binary_expr(bin_expr, enum_name, prev_members), @@ -118,11 +116,17 @@ impl FastDts { } Expr::Ident(ident) => { if ident.sym == "Infinity" { - Some(ConstantValue::Number(f64::INFINITY)) + Some(ConstantValue::converted_number( + f64::INFINITY, + Some(ident.sym.clone()), + )) } else if ident.sym == "NaN" { - Some(ConstantValue::Number(f64::NAN)) + Some(ConstantValue::converted_number( + f64::NAN, + Some(ident.sym.clone()), + )) } else { - prev_members.get(&ident.sym).cloned() + prev_members.get(ident.sym.borrow()).cloned() } } Expr::Member(member) => { @@ -152,16 +156,16 @@ impl FastDts { &self, expr: &UnaryExpr, enum_name: &Atom, - prev_members: &FxHashMap, + prev_members: &FxHashMap, ) -> Option { let value = self.evaluate(&expr.arg, enum_name, prev_members)?; let value = match value { - ConstantValue::Number(n) => n, + ConstantValue::Number(number) => number.value, ConstantValue::String(_) => { let value = if expr.op == UnaryOp::Minus { - ConstantValue::Number(f64::NAN) + ConstantValue::number(f64::NAN) } else if expr.op == UnaryOp::Tilde { - ConstantValue::Number(-1.0) + ConstantValue::number(-1.0) } else { value }; @@ -170,9 +174,9 @@ impl FastDts { }; match expr.op { - UnaryOp::Minus => Some(ConstantValue::Number(-value)), - UnaryOp::Plus => Some(ConstantValue::Number(value)), - UnaryOp::Tilde => Some(ConstantValue::Number((!JsNumber::from(value)).into())), + UnaryOp::Minus => Some(ConstantValue::number(-value)), + UnaryOp::Plus => Some(ConstantValue::number(value)), + UnaryOp::Tilde => Some(ConstantValue::number((!JsNumber::from(value)).into())), _ => None, } } @@ -181,7 +185,7 @@ impl FastDts { &self, expr: &BinExpr, enum_name: &Atom, - prev_members: &FxHashMap, + prev_members: &FxHashMap, ) -> Option { let left = self.evaluate(&expr.left, enum_name, prev_members)?; let right = self.evaluate(&expr.right, enum_name, prev_members)?; @@ -190,28 +194,19 @@ impl FastDts { && (matches!(left, ConstantValue::String(_)) || matches!(right, ConstantValue::String(_))) { - let left_string = match left { - ConstantValue::Number(number) => number.to_string(), - ConstantValue::String(s) => s, - }; - - let right_string = match right { - ConstantValue::Number(number) => number.to_string(), - ConstantValue::String(s) => s, - }; - - return Some(ConstantValue::String(format!( - "{left_string}{right_string}" - ))); + let mut value = Wtf8Buf::new(); + left.push_to(&mut value); + right.push_to(&mut value); + return Some(ConstantValue::String(Wtf8Atom::from(&*value))); } let left = JsNumber::from(match left { - ConstantValue::Number(n) => n, + ConstantValue::Number(number) => number.value, ConstantValue::String(_) => return None, }); let right = JsNumber::from(match right { - ConstantValue::Number(n) => n, + ConstantValue::Number(number) => number.value, ConstantValue::String(_) => return None, }); @@ -223,13 +218,22 @@ impl FastDts { BinaryOp::Sub => Some(left - right), BinaryOp::Mul => Some(left * right), BinaryOp::Div => Some(left / right), - BinaryOp::Mod => Some(left & right), + BinaryOp::Mod => Some(left % right), BinaryOp::BitOr => Some(left | right), BinaryOp::BitXor => Some(left ^ right), BinaryOp::BitAnd => Some(left & right), BinaryOp::Exp => Some(left.pow(right)), _ => None, } - .map(|number| ConstantValue::Number(number.into())) + .map(|number| ConstantValue::number(number.into())) + } +} + +fn enum_member_name(member: &TsEnumMemberId) -> Wtf8Atom { + match member { + TsEnumMemberId::Ident(ident) => ident.sym.clone().into(), + TsEnumMemberId::Str(string) => string.value.clone(), + #[cfg(swc_ast_unknown)] + _ => panic!("unable to access unknown nodes"), } } diff --git a/deps/swc/crates/swc_typescript/src/fast_dts/util/ast_ext.rs b/deps/swc/crates/swc_typescript/src/fast_dts/util/ast_ext.rs index c109f582e..6de072074 100644 --- a/deps/swc/crates/swc_typescript/src/fast_dts/util/ast_ext.rs +++ b/deps/swc/crates/swc_typescript/src/fast_dts/util/ast_ext.rs @@ -1,11 +1,12 @@ -use std::borrow::Cow; +use std::borrow::{Borrow, Cow}; -use swc_atoms::Atom; +use swc_atoms::{Atom, Wtf8Atom}; use swc_common::Mark; use swc_ecma_ast::{ BindingIdent, ComputedPropName, Expr, Ident, Lit, MemberProp, ObjectPatProp, Pat, Prop, PropName, TsTypeAnn, }; +use swc_ecma_utils::number::ToJsString; pub trait ExprExit { fn get_root_ident(&self) -> Option<&Ident>; @@ -144,7 +145,7 @@ impl PropNameExit for PropName { match self { PropName::Ident(ident_name) => Some(Cow::Borrowed(ident_name.sym.as_str())), PropName::Str(string) => Some(Cow::Borrowed(string.value.as_str()?)), - PropName::Num(number) => Some(Cow::Owned(number.value.to_string())), + PropName::Num(number) => Some(Cow::Owned(number.value.to_js_string())), PropName::BigInt(big_int) => Some(Cow::Owned(big_int.value.to_string())), PropName::Computed(computed_prop_name) => computed_prop_name.static_name(), #[cfg(swc_ast_unknown)] @@ -167,7 +168,7 @@ impl PropNameExit for ComputedPropName { Lit::Str(string) => Some(Cow::Borrowed(string.value.as_str()?)), Lit::Bool(b) => Some(Cow::Owned(b.value.to_string())), Lit::Null(_) => Some(Cow::Borrowed("null")), - Lit::Num(number) => Some(Cow::Owned(number.value.to_string())), + Lit::Num(number) => Some(Cow::Owned(number.value.to_js_string())), Lit::BigInt(big_int) => Some(Cow::Owned(big_int.value.to_string())), Lit::Regex(regex) => Some(Cow::Owned(regex.exp.to_string())), Lit::JSXText(_) => None, @@ -233,17 +234,17 @@ impl PropNameExit for Prop { } pub trait MemberPropExt { - fn static_name(&self) -> Option<&Atom>; + fn static_name(&self) -> Option<&Wtf8Atom>; } impl MemberPropExt for MemberProp { - fn static_name(&self) -> Option<&Atom> { + fn static_name(&self) -> Option<&Wtf8Atom> { match self { - MemberProp::Ident(ident_name) => Some(&ident_name.sym), + MemberProp::Ident(ident_name) => Some(ident_name.sym.borrow()), MemberProp::Computed(computed_prop_name) => match computed_prop_name.expr.as_ref() { - Expr::Lit(Lit::Str(s)) => s.value.as_atom(), + Expr::Lit(Lit::Str(s)) => Some(&s.value), Expr::Tpl(tpl) if tpl.quasis.len() == 1 && tpl.exprs.is_empty() => { - Some(&tpl.quasis[0].raw) + tpl.quasis[0].cooked.as_ref() } _ => None, }, diff --git a/deps/swc/crates/swc_xml/Cargo.toml b/deps/swc/crates/swc_xml/Cargo.toml index 433a42426..19390be1c 100644 --- a/deps/swc/crates/swc_xml/Cargo.toml +++ b/deps/swc/crates/swc_xml/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" license = { workspace = true } name = "swc_xml" repository = "https://github.com/swc-project/swc.git" -version = "23.0.0" +version = "24.0.0" [package.metadata.docs.rs] all-features = true @@ -19,7 +19,7 @@ rustdoc-args = ["--cfg", "docsrs"] bench = false [dependencies] -swc_xml_ast = { version = "23.0.0", path = "../swc_xml_ast" } -swc_xml_codegen = { version = "23.0.0", path = "../swc_xml_codegen" } -swc_xml_parser = { version = "23.0.0", path = "../swc_xml_parser" } -swc_xml_visit = { version = "23.0.0", path = "../swc_xml_visit" } +swc_xml_ast = { version = "24.0.0", path = "../swc_xml_ast" } +swc_xml_codegen = { version = "24.0.0", path = "../swc_xml_codegen" } +swc_xml_parser = { version = "24.0.0", path = "../swc_xml_parser" } +swc_xml_visit = { version = "24.0.0", path = "../swc_xml_visit" } diff --git a/deps/swc/crates/swc_xml_ast/Cargo.toml b/deps/swc/crates/swc_xml_ast/Cargo.toml index bc5a6ade8..f5fff5c4e 100644 --- a/deps/swc/crates/swc_xml_ast/Cargo.toml +++ b/deps/swc/crates/swc_xml_ast/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" license = { workspace = true } name = "swc_xml_ast" repository = "https://github.com/swc-project/swc.git" -version = "23.0.0" +version = "24.0.0" [lib] bench = false @@ -28,5 +28,5 @@ is-macro = { workspace = true } serde = { workspace = true, features = ["derive"], optional = true } string_enum = { version = "1.0.2", path = "../string_enum/" } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } diff --git a/deps/swc/crates/swc_xml_codegen/Cargo.toml b/deps/swc/crates/swc_xml_codegen/Cargo.toml index 675fcdd5a..0b223165f 100644 --- a/deps/swc/crates/swc_xml_codegen/Cargo.toml +++ b/deps/swc/crates/swc_xml_codegen/Cargo.toml @@ -10,7 +10,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_xml_codegen" repository = "https://github.com/swc-project/swc.git" -version = "23.0.0" +version = "24.0.0" [lib] bench = false @@ -19,14 +19,14 @@ bench = false auto_impl = { workspace = true } bitflags = { workspace = true } rustc-hash = { workspace = true } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_xml_ast = { version = "23.0.0", path = "../swc_xml_ast" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_xml_ast = { version = "24.0.0", path = "../swc_xml_ast" } swc_xml_codegen_macros = { version = "1.0.1", path = "../swc_xml_codegen_macros" } [dev-dependencies] -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "sourcemap", ] } -swc_xml_parser = { version = "23.0.0", path = "../swc_xml_parser" } -swc_xml_visit = { version = "23.0.0", path = "../swc_xml_visit" } -testing = { version = "24.0.1", path = "../testing" } +swc_xml_parser = { version = "24.0.0", path = "../swc_xml_parser" } +swc_xml_visit = { version = "24.0.0", path = "../swc_xml_visit" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_xml_parser/Cargo.toml b/deps/swc/crates/swc_xml_parser/Cargo.toml index 828d11249..4c779d5f4 100644 --- a/deps/swc/crates/swc_xml_parser/Cargo.toml +++ b/deps/swc/crates/swc_xml_parser/Cargo.toml @@ -10,7 +10,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/**/*.json"] license = { workspace = true } name = "swc_xml_parser" repository = "https://github.com/swc-project/swc.git" -version = "23.0.0" +version = "24.0.0" [lib] bench = false @@ -21,16 +21,16 @@ debug = [] [dependencies] rustc-hash = { workspace = true } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } -swc_xml_ast = { version = "23.0.0", path = "../swc_xml_ast" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } +swc_xml_ast = { version = "24.0.0", path = "../swc_xml_ast" } [dev-dependencies] serde = { workspace = true } serde_json = { workspace = true } -swc_xml_ast = { version = "23.0.0", path = "../swc_xml_ast", features = [ +swc_xml_ast = { version = "24.0.0", path = "../swc_xml_ast", features = [ "serde-impl", ] } -swc_xml_visit = { version = "23.0.0", path = "../swc_xml_visit" } -testing = { version = "24.0.1", path = "../testing" } +swc_xml_visit = { version = "24.0.0", path = "../swc_xml_visit" } +testing = { version = "25.0.0", path = "../testing" } diff --git a/deps/swc/crates/swc_xml_visit/Cargo.toml b/deps/swc/crates/swc_xml_visit/Cargo.toml index bde76ef35..41ff99b9f 100644 --- a/deps/swc/crates/swc_xml_visit/Cargo.toml +++ b/deps/swc/crates/swc_xml_visit/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" license = { workspace = true } name = "swc_xml_visit" repository = "https://github.com/swc-project/swc.git" -version = "23.0.0" +version = "24.0.0" [package.metadata.docs.rs] all-features = true @@ -26,7 +26,7 @@ serde-impl = ["serde"] [dependencies] serde = { workspace = true, optional = true, features = ["derive"] } -swc_atoms = { version = "9.0.3", path = "../swc_atoms" } -swc_common = { version = "23.0.2", path = "../swc_common" } +swc_atoms = { version = "10.0.0", path = "../swc_atoms" } +swc_common = { version = "24.0.0", path = "../swc_common" } swc_visit = { version = "2.0.1", path = "../swc_visit" } -swc_xml_ast = { version = "23.0.0", path = "../swc_xml_ast" } +swc_xml_ast = { version = "24.0.0", path = "../swc_xml_ast" } diff --git a/deps/swc/crates/testing/Cargo.toml b/deps/swc/crates/testing/Cargo.toml index 803f3f31d..cf87556f2 100644 --- a/deps/swc/crates/testing/Cargo.toml +++ b/deps/swc/crates/testing/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "testing" repository = { workspace = true } -version = "24.0.1" +version = "25.0.0" [lib] bench = false @@ -23,8 +23,8 @@ serde_json = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter"] } -swc_common = { version = "23.0.2", path = "../swc_common", features = [ +swc_common = { version = "24.0.0", path = "../swc_common", features = [ "tty-emitter", ] } -swc_error_reporters = { version = "25.0.0", path = "../swc_error_reporters" } -testing_macros = { version = "1.0.1", path = "../testing_macros" } +swc_error_reporters = { version = "26.0.0", path = "../swc_error_reporters" } +testing_macros = { version = "1.0.2", path = "../testing_macros" } diff --git a/deps/swc/crates/testing_macros/Cargo.toml b/deps/swc/crates/testing_macros/Cargo.toml index d241562e3..4198b842b 100644 --- a/deps/swc/crates/testing_macros/Cargo.toml +++ b/deps/swc/crates/testing_macros/Cargo.toml @@ -6,7 +6,7 @@ edition = { workspace = true } license = { workspace = true } name = "testing_macros" repository = { workspace = true } -version = "1.0.1" +version = "1.0.2" [features] # Skip generating fixtures so the editor becomes faster again @@ -28,3 +28,6 @@ relative-path = { workspace = true } [dependencies.syn] features = ["fold", "parsing", "full", "extra-traits"] workspace = true + +[dev-dependencies] +tempfile = { workspace = true } diff --git a/deps/swc/crates/testing_macros/src/fixture.rs b/deps/swc/crates/testing_macros/src/fixture.rs index 39c980174..81a5735e0 100644 --- a/deps/swc/crates/testing_macros/src/fixture.rs +++ b/deps/swc/crates/testing_macros/src/fixture.rs @@ -1,6 +1,6 @@ use std::{ env, - path::{Component, PathBuf}, + path::{Component, Path, PathBuf}, }; use anyhow::{Context, Error}; @@ -96,7 +96,12 @@ pub fn expand(callee: &Ident, attr: Config) -> Result, Error> { let base_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect( "#[fixture] requires CARGO_MANIFEST_DIR because it's relative to cargo manifest directory", )); - let resolved_path = RelativePath::new(&attr.pattern).to_path(&base_dir); + + expand_from(callee, attr, &base_dir) +} + +fn expand_from(callee: &Ident, attr: Config, base_dir: &Path) -> Result, Error> { + let resolved_path = RelativePath::new(&attr.pattern).to_path(base_dir); let pattern = resolved_path.to_string_lossy(); let paths = @@ -111,7 +116,7 @@ pub fn expand(callee: &Ident, attr: Config) -> Result, Error> { .canonicalize() .with_context(|| format!("failed to canonicalize {}", path.display()))?; - let path_for_name = path.strip_prefix(&base_dir).with_context(|| { + let path_for_name = path.strip_prefix(base_dir).with_context(|| { format!( "Failed to strip prefix `{}` from `{}`", base_dir.display(), @@ -130,10 +135,7 @@ pub fn expand(callee: &Ident, attr: Config) -> Result, Error> { } } - let ignored = path.components().any(|c| match c { - Component::Normal(s) => s.to_string_lossy().starts_with('.'), - _ => false, - }); + let ignored = is_ignored_fixture(path_for_name); let test_name = format!( "{}_{}", callee, @@ -174,6 +176,15 @@ pub fn expand(callee: &Ident, attr: Config) -> Result, Error> { Ok(test_fns) } +/// Returns whether a manifest-relative fixture path contains a hidden +/// component. +fn is_ignored_fixture(path: &Path) -> bool { + path.components().any(|component| match component { + Component::Normal(name) => name.to_string_lossy().starts_with('.'), + _ => false, + }) +} + struct InputParen { input: Punctuated, } @@ -185,3 +196,61 @@ impl Parse for InputParen { }) } } + +#[cfg(test)] +mod tests { + use std::fs::{create_dir_all, write}; + + use proc_macro2::Span; + use tempfile::tempdir; + + use super::*; + + #[test] + fn ignores_only_hidden_fixture_path_components() { + let temp_dir = tempdir().unwrap(); + let manifest_dir = temp_dir + .path() + .join(".codex") + .join("worktrees") + .join("swc") + .join("crates") + .join("testing_macros"); + let fixture_dir = manifest_dir.join("tests").join("fixture"); + let ignored_fixture_dir = fixture_dir.join(".ignored"); + + create_dir_all(&ignored_fixture_dir).unwrap(); + write(fixture_dir.join("normal.ts"), "").unwrap(); + write(ignored_fixture_dir.join("ignored.ts"), "").unwrap(); + + let cases = expand_from( + &Ident::new("fixture", Span::call_site()), + Config { + pattern: "tests/fixture/**/*.ts".into(), + exclude_patterns: Vec::new(), + }, + &manifest_dir, + ) + .unwrap(); + + let case_count = cases.len(); + let ignored_count = cases + .into_iter() + .map(|case| syn::parse2::(case).unwrap()) + .filter(|case| case.attrs.iter().any(|attr| attr.path().is_ident("ignore"))) + .count(); + + assert_eq!(case_count, 2); + assert_eq!(ignored_count, 1); + } + + #[test] + fn ignores_hidden_components_in_cross_crate_fixture_paths() { + assert!(!is_ignored_fixture(Path::new( + "../other-crate/tests/fixture/input.js" + ))); + assert!(is_ignored_fixture(Path::new( + "../other-crate/tests/fixture/.case/input.js" + ))); + } +} diff --git a/deps/swc/crates/testing_macros/src/lib.rs b/deps/swc/crates/testing_macros/src/lib.rs index 0e9c2a3bb..e6841642d 100644 --- a/deps/swc/crates/testing_macros/src/lib.rs +++ b/deps/swc/crates/testing_macros/src/lib.rs @@ -38,10 +38,11 @@ mod fixture; /// /// ## Ignoring a test /// -/// If the path to the file contains a component starts with `.` (dot), it will -/// be ignore. This convention is widely used in many projects (including other -/// languages), as a file or a directory starting with `.` means hidden file in -/// unix system. +/// If the fixture path relative to the crate's `Cargo.toml` contains a +/// component that starts with `.` (dot), it will be ignored. Ancestors of the +/// crate are not considered. This convention is widely used in many projects +/// (including other languages), as a file or a directory starting with `.` +/// means a hidden file in unix systems. /// /// Note that they are added as a test `#[ignore]`, so you can use /// `cargo test -- --ignored` or `cargo test -- --include-ignored` to run those diff --git a/deps/swc/tools/generate-code/Cargo.toml b/deps/swc/tools/generate-code/Cargo.toml index c1e0c7bf5..48b1b8d71 100644 --- a/deps/swc/tools/generate-code/Cargo.toml +++ b/deps/swc/tools/generate-code/Cargo.toml @@ -15,6 +15,6 @@ quote = { workspace = true } syn = { workspace = true, features = ["full", "visit-mut", "extra-traits"] } walkdir = { workspace = true } -swc_config = { version = "5.0.0", path = "../../crates/swc_config", features = [ +swc_config = { version = "6.0.0", path = "../../crates/swc_config", features = [ "regex", ] } diff --git a/deps/swc/tools/generate-code/src/generators/helpers.rs b/deps/swc/tools/generate-code/src/generators/helpers.rs new file mode 100644 index 000000000..97c0a022f --- /dev/null +++ b/deps/swc/tools/generate-code/src/generators/helpers.rs @@ -0,0 +1,571 @@ +use std::{ + collections::{BTreeMap, BTreeSet}, + fs, + path::{Path, PathBuf}, +}; + +use anyhow::{bail, Context, Result}; + +const GENERATED_HEADER: &str = + "// This file is generated by `cargo codegen helpers`. DO NOT MODIFY.\n"; +const HELPER_BITMAP_BITS: usize = 128; + +#[derive(Debug)] +pub struct Config { + pub input_dir: PathBuf, + pub output_dir: PathBuf, +} + +#[derive(Debug)] +struct Helper { + module_name: String, + ident: String, + source: String, + deps: Vec, +} + +pub fn generate(config: Config) -> Result> { + let input_dir = config + .input_dir + .canonicalize() + .context("failed to canonicalize helper input directory")?; + + let ordered_modules = read_index_order(&input_dir)?; + let available_modules = read_available_modules(&input_dir)?; + + let ordered_set = ordered_modules.iter().collect::>(); + for module_name in &available_modules { + if !ordered_set.contains(module_name) { + bail!( + "helper `{module_name}` exists in packages/helpers/esm but is missing from \ + index.js" + ); + } + } + + let mut helpers = Vec::with_capacity(ordered_modules.len()); + for module_name in &ordered_modules { + if !available_modules.contains(module_name) { + bail!("helper `{module_name}` is exported from index.js but the file is missing"); + } + + let path = input_dir.join(format!("{module_name}.js")); + helpers.push(parse_helper(module_name, &path)?); + } + + validate_deps(&helpers)?; + let inline_deps = compute_inline_deps(&helpers)?; + + fs::create_dir_all(&config.output_dir) + .with_context(|| format!("failed to create output directory: {:?}", config.output_dir))?; + + let expected_files = helpers + .iter() + .map(|helper| format!("{}.rs", helper.module_name)) + .chain(std::iter::once("mod.rs".into())) + .collect::>(); + + for entry in fs::read_dir(&config.output_dir) + .with_context(|| format!("failed to read output directory: {:?}", config.output_dir))? + { + let entry = entry?; + let path = entry.path(); + if path.extension().and_then(|ext| ext.to_str()) != Some("rs") { + continue; + } + + let file_name = path + .file_name() + .and_then(|file_name| file_name.to_str()) + .context("generated helper path is not utf-8")?; + + if !expected_files.contains(file_name) { + fs::remove_file(&path) + .with_context(|| format!("failed to remove stale generated helper: {path:?}"))?; + } + } + + let mut written = Vec::with_capacity(helpers.len() + 1); + let mod_rs = config.output_dir.join("mod.rs"); + fs::write(&mod_rs, generate_mod_rs(&helpers)) + .with_context(|| format!("failed to write generated helper module: {mod_rs:?}"))?; + written.push(mod_rs); + + for (helper, inline_deps) in helpers.iter().zip(inline_deps) { + let output = config.output_dir.join(format!("{}.rs", helper.module_name)); + fs::write(&output, generate_helper_rs(helper, inline_deps)) + .with_context(|| format!("failed to write generated helper file: {output:?}"))?; + written.push(output); + } + + Ok(written) +} + +fn read_index_order(input_dir: &Path) -> Result> { + let index_path = input_dir.join("index.js"); + let index = fs::read_to_string(&index_path) + .with_context(|| format!("failed to read helper index: {index_path:?}"))?; + let mut modules = Vec::new(); + + for line in index.lines() { + let line = line.trim(); + let Some(rest) = line.strip_prefix("export { _ as ") else { + continue; + }; + + let Some((exported, rest)) = rest.split_once(" } from \"./") else { + bail!("unsupported helper index export line: `{line}`"); + }; + let Some(source) = rest.strip_suffix(".js\";") else { + bail!("unsupported helper index export source: `{line}`"); + }; + + if exported != source { + bail!("helper index exports `{exported}` from `{source}`, but they must match"); + } + + modules.push(exported.to_string()); + } + + if modules.is_empty() { + bail!("helper index did not contain any helper exports"); + } + + Ok(modules) +} + +fn read_available_modules(input_dir: &Path) -> Result> { + let mut modules = BTreeSet::new(); + + for entry in fs::read_dir(input_dir) + .with_context(|| format!("failed to read helper input directory: {input_dir:?}"))? + { + let entry = entry?; + let path = entry.path(); + if path.extension().and_then(|ext| ext.to_str()) != Some("js") { + continue; + } + + let Some(stem) = path.file_stem().and_then(|stem| stem.to_str()) else { + bail!("helper path is not utf-8: {path:?}"); + }; + + if stem == "index" { + continue; + } + + if !stem.starts_with('_') { + bail!("helper file name must start with `_`: {path:?}"); + } + + modules.insert(stem.to_string()); + } + + Ok(modules) +} + +fn parse_helper(module_name: &str, path: &Path) -> Result { + let code = fs::read_to_string(path) + .with_context(|| format!("failed to read helper source: {path:?}"))?; + + let mut deps = Vec::new(); + let mut stripped = Vec::new(); + let mut export_count = 0usize; + + for line in code.lines() { + let trimmed = line.trim(); + + if trimmed.starts_with("import ") { + deps.push(parse_import(module_name, trimmed)?); + continue; + } + + if trimmed.starts_with("export ") { + let expected = format!("export {{ {module_name} as _ }};"); + if trimmed != expected { + bail!("helper `{module_name}` must export exactly `{expected}`, found `{trimmed}`"); + } + + export_count += 1; + continue; + } + + stripped.push(line); + } + + if export_count != 1 { + bail!("helper `{module_name}` must have exactly one export, found {export_count}"); + } + + let mut source = stripped.join("\n"); + source = source.trim_matches('\n').to_string(); + source.push('\n'); + + let function_head = format!("function {module_name}("); + if !source.contains(&function_head) { + bail!("helper `{module_name}` must define `{function_head}`"); + } + + if source.lines().any(|line| { + line.trim_start().starts_with("import ") || line.trim_start().starts_with("export ") + }) { + bail!("helper `{module_name}` still contains module syntax after stripping"); + } + + let first_function = source + .find("function ") + .context("helper source must contain a function declaration")?; + let prelude = &source[..first_function]; + for dep in &deps { + if prelude.contains(dep) { + bail!( + "helper `{module_name}` references dependency `{dep}` before the first function \ + declaration; helper order would become significant" + ); + } + } + + let ident = module_name + .strip_prefix('_') + .context("helper module name must start with `_`")? + .to_string(); + if !is_valid_helper_ident(&ident) { + bail!("invalid helper module name: {module_name}"); + } + + Ok(Helper { + module_name: module_name.to_string(), + ident, + source, + deps, + }) +} + +fn is_valid_helper_ident(ident: &str) -> bool { + if ident.is_empty() || ident.split('_').any(|part| part.is_empty()) || is_rust_keyword(ident) { + return false; + } + + ident + .bytes() + .all(|byte| byte == b'_' || byte.is_ascii_lowercase() || byte.is_ascii_digit()) +} + +fn is_rust_keyword(ident: &str) -> bool { + matches!( + ident, + "Self" + | "abstract" + | "as" + | "async" + | "await" + | "become" + | "box" + | "break" + | "const" + | "continue" + | "crate" + | "do" + | "dyn" + | "else" + | "enum" + | "extern" + | "false" + | "final" + | "fn" + | "for" + | "gen" + | "if" + | "impl" + | "in" + | "let" + | "loop" + | "macro" + | "match" + | "mod" + | "move" + | "mut" + | "override" + | "priv" + | "pub" + | "ref" + | "return" + | "self" + | "static" + | "struct" + | "super" + | "trait" + | "true" + | "try" + | "type" + | "typeof" + | "unsafe" + | "unsized" + | "use" + | "virtual" + | "where" + | "while" + | "yield" + ) +} + +fn parse_import(module_name: &str, line: &str) -> Result { + let Some(rest) = line.strip_prefix("import { _ as ") else { + bail!("unsupported import in helper `{module_name}`: `{line}`"); + }; + + let Some((binding, rest)) = rest.split_once(" } from \"./") else { + bail!("unsupported import in helper `{module_name}`: `{line}`"); + }; + + let Some(source) = rest.strip_suffix(".js\";") else { + bail!("unsupported import source in helper `{module_name}`: `{line}`"); + }; + + if binding != source { + bail!( + "helper `{module_name}` imports `{binding}` from `{source}`, but the binding must \ + match the source" + ); + } + + Ok(binding.to_string()) +} + +fn validate_deps(helpers: &[Helper]) -> Result<()> { + let helper_map = helpers + .iter() + .map(|helper| (helper.module_name.as_str(), helper)) + .collect::>(); + + for helper in helpers { + for dep in &helper.deps { + if !helper_map.contains_key(dep.as_str()) { + bail!( + "helper `{}` imports missing helper `{dep}`", + helper.module_name + ); + } + } + } + + Ok(()) +} + +fn compute_inline_deps(helpers: &[Helper]) -> Result> { + if helpers.len() > HELPER_BITMAP_BITS { + bail!( + "helper count {} exceeds {HELPER_BITMAP_BITS}; migrate helper dependency bitmaps to \ + multiple words", + helpers.len() + ); + } + + let helper_indices = helpers + .iter() + .enumerate() + .map(|(index, helper)| (helper.module_name.as_str(), index)) + .collect::>(); + + let mut inline_deps = Vec::with_capacity(helpers.len()); + for index in 0..helpers.len() { + let mut bits = 0u128; + collect_inline_deps(index, helpers, &helper_indices, &mut bits)?; + inline_deps.push(bits); + } + + Ok(inline_deps) +} + +fn collect_inline_deps( + index: usize, + helpers: &[Helper], + helper_indices: &BTreeMap<&str, usize>, + bits: &mut u128, +) -> Result<()> { + let bit = 1u128 << index; + if *bits & bit != 0 { + return Ok(()); + } + + *bits |= bit; + + for dep in &helpers[index].deps { + let dep_index = helper_indices + .get(dep.as_str()) + .copied() + .with_context(|| format!("missing helper `{dep}` during dependency flattening"))?; + collect_inline_deps(dep_index, helpers, helper_indices, bits)?; + } + + Ok(()) +} + +fn generate_mod_rs(helpers: &[Helper]) -> String { + let mut output = String::new(); + + output.push_str(GENERATED_HEADER); + output.push_str("#![allow(clippy::all)]\n\n"); + + for helper in helpers { + output.push_str("mod "); + output.push_str(&helper.module_name); + output.push_str(";\n"); + } + + output.push_str("\n#[allow(non_camel_case_types)]\n"); + output.push_str("#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]\n"); + output.push_str("#[repr(usize)]\n"); + output.push_str("pub enum HelperName {\n"); + for helper in helpers { + output.push_str(" "); + output.push_str(&helper.ident); + output.push_str(",\n"); + } + output.push_str("}\n\n"); + + output.push_str("pub const HELPER_COUNT: usize = "); + output.push_str(&helpers.len().to_string()); + output.push_str(";\n\n"); + + output.push_str("#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]\n"); + output.push_str("pub struct HelperBitmap(u128);\n\n"); + output.push_str("impl HelperBitmap {\n"); + output.push_str(" pub const EMPTY: Self = Self(0);\n\n"); + output.push_str(" pub const fn single(name: HelperName) -> Self {\n"); + output.push_str(" Self(1u128 << (name as usize))\n"); + output.push_str(" }\n\n"); + output.push_str(" pub const fn from_bits(bits: u128) -> Self {\n"); + output.push_str(" Self(bits)\n"); + output.push_str(" }\n\n"); + output.push_str(" pub fn contains(self, name: HelperName) -> bool {\n"); + output.push_str(" self.0 & Self::single(name).0 != 0\n"); + output.push_str(" }\n\n"); + output.push_str(" pub fn insert(&mut self, name: HelperName) {\n"); + output.push_str(" self.0 |= Self::single(name).0;\n"); + output.push_str(" }\n\n"); + output.push_str(" pub fn is_empty(self) -> bool {\n"); + output.push_str(" self.0 == 0\n"); + output.push_str(" }\n"); + output.push_str("}\n\n"); + output.push_str("impl core::ops::BitOr for HelperBitmap {\n"); + output.push_str(" type Output = Self;\n\n"); + output.push_str(" fn bitor(self, rhs: Self) -> Self {\n"); + output.push_str(" Self(self.0 | rhs.0)\n"); + output.push_str(" }\n"); + output.push_str("}\n\n"); + output.push_str("impl core::ops::BitOrAssign for HelperBitmap {\n"); + output.push_str(" fn bitor_assign(&mut self, rhs: Self) {\n"); + output.push_str(" self.0 |= rhs.0;\n"); + output.push_str(" }\n"); + output.push_str("}\n\n"); + + output.push_str("#[derive(Clone, Copy, Debug)]\n"); + output.push_str("pub struct HelperDef {\n"); + output.push_str(" pub name: HelperName,\n"); + output.push_str(" pub local: &'static str,\n"); + output.push_str(" pub import_path: &'static str,\n"); + output.push_str(" #[cfg(feature = \"inline-helpers\")]\n"); + output.push_str(" pub source: &'static str,\n"); + output.push_str(" #[cfg(feature = \"inline-helpers\")]\n"); + output.push_str(" pub deps: HelperBitmap,\n"); + output.push_str("}\n\n"); + + output.push_str("pub const ALL: &[HelperDef; HELPER_COUNT] = &[\n"); + for helper in helpers { + output.push_str(" "); + output.push_str(&helper.module_name); + output.push_str("::DEF,\n"); + } + output.push_str("];\n\n"); + + output.push_str("pub fn helper(name: HelperName) -> &'static HelperDef {\n"); + output.push_str(" &ALL[name as usize]\n"); + output.push_str("}\n\n"); + + output.push_str("pub fn helper_name(name: &str) -> Option {\n"); + output.push_str(" match name {\n"); + for helper in helpers { + output.push_str(" \""); + output.push_str(&helper.ident); + output.push_str("\" => Some(HelperName::"); + output.push_str(&helper.ident); + output.push_str("),\n"); + } + output.push_str(" _ => None,\n"); + output.push_str(" }\n"); + output.push_str("}\n\n"); + + output.push_str("impl super::Helpers {\n"); + for helper in helpers { + output.push_str(" pub fn "); + output.push_str(&helper.ident); + output.push_str("(&self) {\n"); + output.push_str(" self.enable(HelperName::"); + output.push_str(&helper.ident); + output.push_str(");\n"); + output.push_str(" }\n\n"); + } + output.push_str("}\n\n"); + + output.push_str("#[cfg(feature = \"inline-helpers\")]\n"); + output.push_str("pub fn stmts(name: HelperName) -> &'static [swc_ecma_ast::Stmt] {\n"); + output.push_str(" match name {\n"); + for helper in helpers { + output.push_str(" HelperName::"); + output.push_str(&helper.ident); + output.push_str(" => "); + output.push_str(&helper.module_name); + output.push_str("::stmts(),\n"); + } + output.push_str(" }\n"); + output.push_str("}\n"); + + output +} + +fn generate_helper_rs(helper: &Helper, inline_deps: u128) -> String { + let mut output = String::new(); + + output.push_str(GENERATED_HEADER); + output.push_str("\nuse super::{HelperDef, HelperName};\n\n"); + output.push_str("pub const DEF: HelperDef = HelperDef {\n"); + output.push_str(" name: HelperName::"); + output.push_str(&helper.ident); + output.push_str(",\n"); + output.push_str(" local: \""); + output.push_str(&helper.module_name); + output.push_str("\",\n"); + output.push_str(" import_path: \"@swc/helpers/_/"); + output.push_str(&helper.module_name); + output.push_str("\",\n"); + output.push_str(" #[cfg(feature = \"inline-helpers\")]\n"); + output.push_str(" source: "); + output.push_str(&raw_string_literal(&helper.source)); + output.push_str(",\n"); + output.push_str(" #[cfg(feature = \"inline-helpers\")]\n"); + output.push_str(" deps: super::HelperBitmap::from_bits("); + output.push_str(&format!("0x{inline_deps:032x}")); + output.push_str("),\n"); + output.push_str("};\n\n"); + output.push_str("#[cfg(feature = \"inline-helpers\")]\n"); + output.push_str("pub fn stmts() -> &'static [swc_ecma_ast::Stmt] {\n"); + output.push_str(" static STMTS: once_cell::sync::Lazy> =\n"); + output.push_str(" once_cell::sync::Lazy::new(|| "); + output.push_str("super::super::parse(DEF.source, DEF.import_path));\n"); + output.push_str(" &STMTS\n"); + output.push_str("}\n"); + + output +} + +fn raw_string_literal(value: &str) -> String { + for hashes in 1.. { + let delimiter = "#".repeat(hashes); + if !value.contains(&format!("\"{delimiter}")) { + return format!("r{delimiter}\"{value}\"{delimiter}"); + } + } + + unreachable!("raw string delimiter search should always terminate") +} diff --git a/deps/swc/tools/generate-code/src/generators/mod.rs b/deps/swc/tools/generate-code/src/generators/mod.rs index 1a49dced3..8e6e8a0b7 100644 --- a/deps/swc/tools/generate-code/src/generators/mod.rs +++ b/deps/swc/tools/generate-code/src/generators/mod.rs @@ -1 +1,2 @@ +pub mod helpers; pub mod visitor; diff --git a/deps/swc/tools/generate-code/src/main.rs b/deps/swc/tools/generate-code/src/main.rs index 3d2fa7bf6..64d7ce146 100644 --- a/deps/swc/tools/generate-code/src/main.rs +++ b/deps/swc/tools/generate-code/src/main.rs @@ -1,9 +1,14 @@ #![allow(clippy::only_used_in_recursion)] -use std::path::{Path, PathBuf}; - -use anyhow::{bail, Context, Result}; -use clap::Parser; +use std::{ + collections::BTreeMap, + fs, + path::{Path, PathBuf}, + time::{SystemTime, UNIX_EPOCH}, +}; + +use anyhow::{anyhow, bail, Context, Result}; +use clap::{Parser, Subcommand}; use swc_config::regex::CachedRegex; use syn::Item; @@ -14,27 +19,198 @@ mod types; #[derive(Debug, Parser)] struct CliArgs { + #[clap(subcommand)] + command: Option, + /// The directory containing the crate to generate the visitor for. #[clap(short = 'i', long)] - input_dir: PathBuf, + input_dir: Option, /// The file for the generated visitor code. #[clap(short = 'o', long)] - output: PathBuf, + output: Option, /// The list of types to exclude from the generated visitor. #[clap(long)] exclude: Vec, } +#[derive(Debug, Subcommand)] +enum Command { + /// Generate Rust artifacts for ECMAScript helpers. + Helpers { + /// Check that generated helper artifacts are up to date without + /// changing the workspace. + #[clap(long)] + check: bool, + }, +} + fn main() -> Result<()> { let CliArgs { + command, input_dir, output, exclude, } = CliArgs::parse(); - run_visitor_codegen(&input_dir, &output, &exclude)?; + match command { + Some(Command::Helpers { check }) => run_helpers_codegen(check)?, + None => { + let input_dir = input_dir.context("`--input-dir` is required for visitor codegen")?; + let output = output.context("`--output` is required for visitor codegen")?; + + run_visitor_codegen(&input_dir, &output, &exclude)?; + } + } + + Ok(()) +} + +fn run_helpers_codegen(check: bool) -> Result<()> { + let root = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .canonicalize() + .context("failed to canonicalize repository root")?; + + let input_dir = root.join("packages/helpers/esm"); + let output_dir = root.join("crates/swc_ecma_transforms_base/src/helpers/generated"); + + if check { + return check_helpers_codegen(&input_dir, &output_dir); + } + + let written = generators::helpers::generate(generators::helpers::Config { + input_dir, + output_dir, + })?; + + eprintln!("Generated {} helper artifact files", written.len()); + + run_cargo_fmt_many(&written)?; + + Ok(()) +} + +fn check_helpers_codegen(input_dir: &Path, output_dir: &Path) -> Result<()> { + let temp_dir = create_temp_dir("swc-helper-codegen-check")?; + let generated_dir = temp_dir.join("generated"); + + let result = (|| { + let written = generators::helpers::generate(generators::helpers::Config { + input_dir: input_dir.to_path_buf(), + output_dir: generated_dir.clone(), + })?; + + run_cargo_fmt_many(&written)?; + compare_generated_dirs(output_dir, &generated_dir) + })(); + + let cleanup_result = fs::remove_dir_all(&temp_dir) + .with_context(|| format!("failed to remove temporary directory: {temp_dir:?}")); + + result?; + cleanup_result?; + + eprintln!("Helper artifacts are up to date"); + + Ok(()) +} + +fn create_temp_dir(prefix: &str) -> Result { + let nanos = SystemTime::now() + .duration_since(UNIX_EPOCH) + .context("system clock is before unix epoch")? + .as_nanos(); + let path = std::env::temp_dir().join(format!("{prefix}-{}-{nanos}", std::process::id())); + + fs::create_dir_all(&path) + .with_context(|| format!("failed to create temporary directory: {path:?}"))?; + + Ok(path) +} + +fn compare_generated_dirs(committed_dir: &Path, generated_dir: &Path) -> Result<()> { + let committed_files = collect_files(committed_dir)?; + let generated_files = collect_files(generated_dir)?; + + for path in generated_files.keys() { + if !committed_files.contains_key(path) { + return Err(stale_helper_artifacts(format_args!( + "generated helper artifact `{}` is missing", + path.display() + ))); + } + } + + for path in committed_files.keys() { + if !generated_files.contains_key(path) { + return Err(stale_helper_artifacts(format_args!( + "generated helper artifact `{}` is stale", + path.display() + ))); + } + } + + for (path, generated_path) in generated_files { + let committed_path = &committed_files[&path]; + let committed = fs::read(committed_path) + .with_context(|| format!("failed to read generated artifact: {committed_path:?}"))?; + let generated = fs::read(&generated_path) + .with_context(|| format!("failed to read generated artifact: {generated_path:?}"))?; + + if committed != generated { + return Err(stale_helper_artifacts(format_args!( + "generated helper artifact `{}` is stale", + path.display() + ))); + } + } + + Ok(()) +} + +fn stale_helper_artifacts(message: std::fmt::Arguments<'_>) -> anyhow::Error { + anyhow!("{message}; run `cargo codegen helpers` and commit the generated helper artifacts") +} + +fn collect_files(root: &Path) -> Result> { + let mut files = BTreeMap::new(); + collect_files_inner(root, root, &mut files)?; + Ok(files) +} + +fn collect_files_inner( + root: &Path, + dir: &Path, + files: &mut BTreeMap, +) -> Result<()> { + for entry in fs::read_dir(dir) + .with_context(|| format!("failed to read generated artifact directory: {dir:?}"))? + { + let entry = entry?; + let path = entry.path(); + let file_type = entry.file_type().with_context(|| { + format!("failed to read file type for generated artifact: {path:?}") + })?; + + if file_type.is_dir() { + collect_files_inner(root, &path, files)?; + continue; + } + + if file_type.is_file() { + let relative = path + .strip_prefix(root) + .with_context(|| { + format!( + "generated artifact path is not under root: path={path:?}, root={root:?}" + ) + })? + .to_path_buf(); + files.insert(relative, path); + } + } Ok(()) } @@ -257,6 +433,12 @@ fn test_xml() { .unwrap(); } +#[test] +fn test_helpers() { + run_helpers_codegen(false).unwrap(); + run_helpers_codegen(true).unwrap(); +} + fn get_type_defs(file: &syn::File) -> Vec<&Item> { let mut type_defs = Vec::new(); for item in &file.items { @@ -301,3 +483,26 @@ fn run_cargo_fmt(file: &Path) -> Result<()> { Ok(()) } + +fn run_cargo_fmt_many(files: &[PathBuf]) -> Result<()> { + if files.is_empty() { + return Ok(()); + } + + let files = files + .iter() + .map(|file| file.canonicalize().context("failed to canonicalize file")) + .collect::>>()?; + + let mut cmd = std::process::Command::new("cargo"); + cmd.arg("fmt").arg("--").args(&files); + + eprintln!("Running cargo fmt for {} files", files.len()); + let status = cmd.status().context("failed to run cargo fmt")?; + + if !status.success() { + bail!("cargo fmt failed with status: {status:?}"); + } + + Ok(()) +}