diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..001f1993 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +fixture \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index d1aaa61e..e0e2046f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,13 +63,25 @@ checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" [[package]] name = "ast_node" -version = "0.9.9" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4d23a6d1d5f18bdbc06d9aa908880e5f49205156ba804751af731c51f5cf81a" +dependencies = [ + "proc-macro2", + "quote", + "swc_macros_common 0.3.13", + "syn 2.0.77", +] + +[[package]] +name = "ast_node" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9184f2b369b3e8625712493c89b785881f27eedc6cde480a81883cef78868b2" +checksum = "94741d66bdda032fcbf33e621b4e3a888d7d11bd3ac4446d82c5593a136936ff" dependencies = [ "proc-macro2", "quote", - "swc_macros_common", + "swc_macros_common 1.0.0", "syn 2.0.77", ] @@ -96,9 +108,18 @@ dependencies = [ [[package]] name = "better_scoped_tls" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794edcc9b3fb07bb4aecaa11f093fd45663b4feadb782d68303a2268bc2701de" +checksum = "297b153aa5e573b5863108a6ddc9d5c968bd0b20e75cc614ee9821d2f45679c7" +dependencies = [ + "scoped-tls", +] + +[[package]] +name = "better_scoped_tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50fd297a11c709be8348aec039c8b91de16075d2b2bdaee1bd562c0875993664" dependencies = [ "scoped-tls", ] @@ -382,12 +403,23 @@ dependencies = [ [[package]] name = "from_variant" -version = "0.1.9" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32016f1242eb82af5474752d00fd8ebcd9004bd69b462b1c91de833972d08ed4" +checksum = "e8d8947525c49c73130b5a7187b55b027b6b78fe60268d9f4c283ed690698cb1" dependencies = [ "proc-macro2", - "swc_macros_common", + "swc_macros_common 0.3.13", + "syn 2.0.77", +] + +[[package]] +name = "from_variant" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d7ccf961415e7aa17ef93dcb6c2441faaa8e768abe09e659b908089546f74c5" +dependencies = [ + "proc-macro2", + "swc_macros_common 1.0.0", "syn 2.0.77", ] @@ -962,9 +994,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", @@ -980,9 +1012,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ "proc-macro2", "quote", @@ -1234,13 +1266,13 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "string_enum" -version = "0.4.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e383308aebc257e7d7920224fa055c632478d92744eca77f99be8fa1545b90" +checksum = "c9fe66b8ee349846ce2f9557a26b8f1e74843c4a13fb381f9a3d73617a5f956a" dependencies = [ "proc-macro2", "quote", - "swc_macros_common", + "swc_macros_common 1.0.0", "syn 2.0.77", ] @@ -1251,19 +1283,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "swc-plugin-gem" -version = "0.1.0" +name = "swc_allocator" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76aa0eb65c0f39f9b6d82a7e5192c30f7ac9a78f084a21f270de1d8c600ca388" dependencies = [ - "serde", - "swc_core", - "swc_ecma_parser", + "bumpalo", + "hashbrown 0.14.5", + "ptr_meta", + "rustc-hash", + "triomphe", ] [[package]] name = "swc_allocator" -version = "0.1.8" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc8bd3075d1c6964010333fae9ddcd91ad422a4f8eb8b3206a9b2b6afb4209e" +checksum = "52cacc28f0ada8e4e31a720dd849ff06864b10e6ab0a1aaa99c06456cfe046af" dependencies = [ "bumpalo", "hashbrown 0.14.5", @@ -1274,9 +1310,21 @@ dependencies = [ [[package]] name = "swc_atoms" -version = "0.6.7" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b25ff0f3fd48ab1a95d86fd0505fdd1ac904f84d0350dc8222bbc824e9d4fdf6" +dependencies = [ + "hstr", + "once_cell", + "rustc-hash", + "serde", +] + +[[package]] +name = "swc_atoms" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6567e4e67485b3e7662b486f1565bdae54bd5b9d6b16b2ba1a9babb1e42125" +checksum = "5d7211e5c57ea972f32b8a104d7006c4a68d094ec30c6a73bcd20d4d6c473c7c" dependencies = [ "bytecheck", "hstr", @@ -1288,17 +1336,45 @@ dependencies = [ [[package]] name = "swc_common" -version = "0.37.5" +version = "0.40.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12d0a8eaaf1606c9207077d75828008cb2dfb51b095a766bd2b72ef893576e31" +checksum = "ca32839a37f3b12213b18623b1bd58d37641cab750c50c3c287876cb98b12ab4" +dependencies = [ + "ast_node 1.0.0", + "better_scoped_tls 0.1.2", + "cfg-if", + "either", + "from_variant 1.0.0", + "new_debug_unreachable", + "num-bigint", + "once_cell", + "parking_lot", + "rustc-hash", + "serde", + "siphasher", + "swc_allocator 0.1.10", + "swc_atoms 1.0.2", + "swc_eq_ignore_macros 0.1.4", + "swc_visit 0.6.2", + "termcolor", + "tracing", + "unicode-width", + "url", +] + +[[package]] +name = "swc_common" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f87a21612a324493fd065e9c6fea960b4031088a213db782e2ca71d2fabb3ec" dependencies = [ "anyhow", - "ast_node", - "better_scoped_tls", + "ast_node 2.0.0", + "better_scoped_tls 1.0.0", "bytecheck", "cfg-if", "either", - "from_variant", + "from_variant 2.0.0", "new_debug_unreachable", "num-bigint", "once_cell", @@ -1308,10 +1384,10 @@ dependencies = [ "serde", "siphasher", "sourcemap", - "swc_allocator", - "swc_atoms", - "swc_eq_ignore_macros", - "swc_visit", + "swc_allocator 1.0.0", + "swc_atoms 2.0.0", + "swc_eq_ignore_macros 1.0.0", + "swc_visit 2.0.0", "termcolor", "tracing", "unicode-width", @@ -1320,14 +1396,14 @@ dependencies = [ [[package]] name = "swc_core" -version = "0.103.2" +version = "5.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1297a233d0681b82e8706df416c697331c37e777d3c873d9554243525c3407f1" +checksum = "92086975747587872715a20f78fc51e7047bac58f3a6a17d4ed5a9643f3fd0a2" dependencies = [ "once_cell", - "swc_allocator", - "swc_atoms", - "swc_common", + "swc_allocator 1.0.0", + "swc_atoms 2.0.0", + "swc_common 4.0.1", "swc_ecma_ast", "swc_ecma_transforms_base", "swc_ecma_transforms_testing", @@ -1340,9 +1416,9 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "0.118.2" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f866d12e4d519052b92a0a86d1ac7ff17570da1272ca0c89b3d6f802cd79df" +checksum = "1bdab7759509c1b37ec77bd9fc231f525b888d9609c2963ce71995da1b27357c" dependencies = [ "bitflags", "bytecheck", @@ -1352,25 +1428,27 @@ dependencies = [ "rkyv", "scoped-tls", "string_enum", - "swc_atoms", - "swc_common", + "swc_atoms 2.0.0", + "swc_common 4.0.1", + "swc_visit 2.0.0", "unicode-id-start", ] [[package]] name = "swc_ecma_codegen" -version = "0.155.1" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7641608ef117cfbef9581a99d02059b522fcca75e5244fa0cbbd8606689c6f" +checksum = "e474f6c2671524dbb179b44a36425cb1a58928f0f7211c45043f0951a1842c5d" dependencies = [ "memchr", "num-bigint", "once_cell", + "regex", "serde", "sourcemap", - "swc_allocator", - "swc_atoms", - "swc_common", + "swc_allocator 1.0.0", + "swc_atoms 2.0.0", + "swc_common 4.0.1", "swc_ecma_ast", "swc_ecma_codegen_macros", "tracing", @@ -1378,21 +1456,21 @@ dependencies = [ [[package]] name = "swc_ecma_codegen_macros" -version = "0.7.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859fabde36db38634f3fad548dd5e3410c1aebba1b67a3c63e67018fa57a0bca" +checksum = "5f9a42f479a6475647e248fa9750982c87cd985e19d1016a1fc18a70682305d1" dependencies = [ "proc-macro2", "quote", - "swc_macros_common", + "swc_macros_common 1.0.0", "syn 2.0.77", ] [[package]] name = "swc_ecma_parser" -version = "0.149.1" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683dada14722714588b56481399c699378b35b2ba4deb5c4db2fb627a97fb54b" +checksum = "54c5ab8bd4cc4a4956514699c84d1a25cdb5a33f5ec760ec64ce712e973019c9" dependencies = [ "either", "new_debug_unreachable", @@ -1403,8 +1481,8 @@ dependencies = [ "smallvec", "smartstring", "stacker", - "swc_atoms", - "swc_common", + "swc_atoms 2.0.0", + "swc_common 4.0.1", "swc_ecma_ast", "tracing", "typed-arena", @@ -1412,24 +1490,24 @@ dependencies = [ [[package]] name = "swc_ecma_testing" -version = "0.26.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945faa325af9833b2541d3b0b4e614812677480c2b763c6c6e8c2a42a133b906" +checksum = "9d0397cdbbdcfec2048da1291f44e2d433471fab9bfb430f8f879a831242d636" dependencies = [ "anyhow", "hex", "sha2", - "testing", + "testing 4.0.0", "tracing", ] [[package]] name = "swc_ecma_transforms_base" -version = "0.146.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b5a7c0a6c4cc7d0ba65549e7db52443bc0eb104563aeaae727ad87c176a1bbe" +checksum = "0eb4000822f02b54af0be4f668649fa1e5555f1e3392479d17a277eb81a841f0" dependencies = [ - "better_scoped_tls", + "better_scoped_tls 1.0.0", "bitflags", "indexmap", "once_cell", @@ -1437,8 +1515,8 @@ dependencies = [ "rustc-hash", "serde", "smallvec", - "swc_atoms", - "swc_common", + "swc_atoms 2.0.0", + "swc_common 4.0.1", "swc_ecma_ast", "swc_ecma_parser", "swc_ecma_utils", @@ -1448,9 +1526,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_testing" -version = "0.149.0" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea574b501787bb705d7ebf9e003c235375196449fe91360b799e289ffab7861" +checksum = "21721599724e9f9c40467ff9cdd20f045f134c26e5fe794b1ee6708798c724ed" dependencies = [ "ansi_term", "anyhow", @@ -1460,7 +1538,7 @@ dependencies = [ "serde_json", "sha2", "sourcemap", - "swc_common", + "swc_common 4.0.1", "swc_ecma_ast", "swc_ecma_codegen", "swc_ecma_parser", @@ -1469,22 +1547,22 @@ dependencies = [ "swc_ecma_utils", "swc_ecma_visit", "tempfile", - "testing", + "testing 4.0.0", ] [[package]] name = "swc_ecma_utils" -version = "0.134.3" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f4e07d0d4987f8f27933549498acce5f89451ebe09b7d65f4d4ed4fc731200" +checksum = "024a9ee9a19f448b31af002b90c43b9dfdb4e1fad23c76c21fe26a7c6e0f78a7" dependencies = [ "indexmap", "num_cpus", "once_cell", "rustc-hash", "ryu-js", - "swc_atoms", - "swc_common", + "swc_atoms 2.0.0", + "swc_common 4.0.1", "swc_ecma_ast", "swc_ecma_visit", "tracing", @@ -1493,16 +1571,16 @@ dependencies = [ [[package]] name = "swc_ecma_visit" -version = "0.104.8" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1c6802e68e51f336e8bc9644e9ff9da75d7da9c1a6247d532f2e908aa33e81" +checksum = "642c58202491c273ea984e0d7e923319afe0f94195d2985b3e7f71f7d8232e06" dependencies = [ "new_debug_unreachable", "num-bigint", - "swc_atoms", - "swc_common", + "swc_atoms 2.0.0", + "swc_common 4.0.1", "swc_ecma_ast", - "swc_visit", + "swc_visit 2.0.0", "tracing", ] @@ -1517,17 +1595,41 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "swc_eq_ignore_macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96e15288bf385ab85eb83cff7f9e2d834348da58d0a31b33bdb572e66ee413e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "swc_error_reporters" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83f9286183c9be40aafcbbe8c397403fb32af812a3dffe93eee9067aee4fbedb" +dependencies = [ + "anyhow", + "miette", + "once_cell", + "parking_lot", + "swc_common 0.40.2", +] + [[package]] name = "swc_error_reporters" -version = "0.21.0" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d049e9256abf29d9fc66d3db3ea44b6815a64ad565ce31e117a74ee96478bb3" +checksum = "fb4a3c124af5d297d98e6c18776ba04024087cde14602621017e8e9c6cd1c2d1" dependencies = [ "anyhow", "miette", "once_cell", "parking_lot", - "swc_common", + "swc_common 4.0.1", ] [[package]] @@ -1541,20 +1643,48 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "swc_macros_common" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a509f56fca05b39ba6c15f3e58636c3924c78347d63853632ed2ffcb6f5a0ac7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "swc_plugin" -version = "0.90.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd2ab83a683ee8cdd8be4ce3f363d760a9977d4539aeaee5dbed179ec49fcc7" +checksum = "6b45099a38ed45528bef939d0eac1a0c1347749d0c67d3dd744d545316c5fd05" dependencies = [ "once_cell", ] +[[package]] +name = "swc_plugin_gem" +version = "0.1.0" +dependencies = [ + "once_cell", + "regex", + "serde", + "serde_json", + "swc_common 4.0.1", + "swc_core", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_visit", + "testing 0.42.1", + "tracing", +] + [[package]] name = "swc_plugin_macro" -version = "0.9.16" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3232db481484070637b20a155c064096c0ea1ba04fa2247b89b618661b3574f4" +checksum = "0917ccfdcd3fa6cf41bdacef2388702a3b274f9ea708d930e1e8db37c7c3e1c6" dependencies = [ "proc-macro2", "quote", @@ -1563,13 +1693,13 @@ dependencies = [ [[package]] name = "swc_plugin_proxy" -version = "0.47.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07548e19126fbc58b16237e2c8b0075f037774dfdd691fe4c558ba898cfe784b" +checksum = "6749c4027aad79cf648ffce6633100ea01a7b0d6cf17299cfa68ce141897c26c" dependencies = [ - "better_scoped_tls", + "better_scoped_tls 1.0.0", "rkyv", - "swc_common", + "swc_common 4.0.1", "swc_ecma_ast", "swc_trace_macro", "tracing", @@ -1577,9 +1707,9 @@ dependencies = [ [[package]] name = "swc_trace_macro" -version = "0.1.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff9719b6085dd2824fd61938a881937be14b08f95e2d27c64c825a9f65e052ba" +checksum = "4c78717a841565df57f811376a3d19c9156091c55175e12d378f3a522de70cef" dependencies = [ "proc-macro2", "quote", @@ -1596,6 +1726,16 @@ dependencies = [ "new_debug_unreachable", ] +[[package]] +name = "swc_visit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9138b6a36bbe76dd6753c4c0794f7e26480ea757bee499738bedbbb3ae3ec5f3" +dependencies = [ + "either", + "new_debug_unreachable", +] + [[package]] name = "syn" version = "1.0.109" @@ -1648,9 +1788,9 @@ dependencies = [ [[package]] name = "testing" -version = "0.39.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3105e9569b7f674d1107d19494c993aafd19ea51f7a558b96b267b49c9b5f2bf" +checksum = "9217860da21fabe9c65981ba42f6dad2bd8f463b670448afe79aa9d50f0bc137" dependencies = [ "ansi_term", "cargo_metadata", @@ -1660,9 +1800,30 @@ dependencies = [ "regex", "serde", "serde_json", - "swc_common", - "swc_error_reporters", - "testing_macros", + "swc_common 0.40.2", + "swc_error_reporters 1.0.0", + "testing_macros 0.2.14", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "testing" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c6b200c27382caadd583563c79cdf870d854e14c4c078731d447ecbfe27c35f" +dependencies = [ + "ansi_term", + "cargo_metadata", + "difference", + "once_cell", + "pretty_assertions", + "regex", + "serde", + "serde_json", + "swc_common 4.0.1", + "swc_error_reporters 5.0.0", + "testing_macros 1.0.0", "tracing", "tracing-subscriber", ] @@ -1683,6 +1844,22 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "testing_macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d27bf245b90a80d5aa231133418ae7db98f032855ce5292e12071ab29c4b26" +dependencies = [ + "anyhow", + "glob", + "once_cell", + "proc-macro2", + "quote", + "regex", + "relative-path", + "syn 2.0.77", +] + [[package]] name = "textwrap" version = "0.16.1" diff --git a/Cargo.toml b/Cargo.toml index afa756e2..cdb8adad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,5 +14,12 @@ repository = "https://github.com/mantou132/gem.git" [workspace.dependencies] regex = { version = "1.10.4", default-features = false } serde = "1.0.203" -swc_core = "0.103.2" -swc_ecma_parser = "0.149.1" +serde_json = "1.0.117" +swc_core = "5.0.0" +swc_ecma_parser = "5.0.0" +swc_ecma_visit = "4.0.0" +swc_ecma_ast = "4.0.0" +swc_common = "4.0.0" +testing = "0.42.0" +once_cell = "1.19.0" +tracing = "0.1.40" diff --git a/biome.json b/biome.json index 21cacd93..9b7d02ff 100644 --- a/biome.json +++ b/biome.json @@ -28,7 +28,6 @@ "attributePosition": "auto" } }, - "overrides": [{ "include": ["*.md"], "formatter": { "lineWidth": 100 } }], "linter": { "enabled": true, "rules": { @@ -56,5 +55,9 @@ "noUnsafeDeclarationMerging": "error" } } - } + }, + "overrides": [ + { "include": ["*.md"], "formatter": { "lineWidth": 100 } }, + { "include": ["fixture/**"], "linter": { "enabled": false } } + ] } diff --git a/crates/swc-plugin-gem/Cargo.toml b/crates/swc-plugin-gem/Cargo.toml index 97e22e62..d6071c18 100644 --- a/crates/swc-plugin-gem/Cargo.toml +++ b/crates/swc-plugin-gem/Cargo.toml @@ -1,23 +1,27 @@ [package] -name = "swc-plugin-gem" +name = "swc_plugin_gem" version = "0.1.0" edition = { workspace = true } rust-version = { workspace = true } publish = false [lib] -crate-type = ["cdylib"] +crate-type = ["cdylib", "rlib"] [profile.release] lto = true [dependencies] -serde = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } swc_core = { workspace = true, features = ["ecma_plugin_transform"] } - -# .cargo/config defines few alias to build plugin. -# cargo build-wasi generates wasm-wasi32 binary -# cargo build-wasm32 generates wasm32-unknown-unknown binary. +swc_ecma_visit = { workspace = true } +swc_common = { workspace = true, features = ["concurrent"] } +swc_ecma_ast = { workspace = true } +once_cell = { workspace = true } +tracing = { workspace = true } +regex = { workspace = true } [dev-dependencies] swc_ecma_parser = { workspace = true } +testing = { workspace = true } diff --git a/crates/swc-plugin-gem/package.json b/crates/swc-plugin-gem/package.json index a76f0da1..87e59f94 100644 --- a/crates/swc-plugin-gem/package.json +++ b/crates/swc-plugin-gem/package.json @@ -11,7 +11,7 @@ "files": [], "scripts": { "prepublishOnly": "cross-env CARGO_TARGET_DIR=target cargo build-wasi --release && cp target/wasm32-wasip1/release/swc_plugin_gem.wasm .", - "test": "cargo watch -x test" + "test": "cross-env RUST_LOG=info cargo watch -x test" }, "preferUnplugged": true, "author": "mantou132", diff --git a/crates/swc-plugin-gem/src/lib.rs b/crates/swc-plugin-gem/src/lib.rs index 8e477c53..7e1bcd33 100644 --- a/crates/swc-plugin-gem/src/lib.rs +++ b/crates/swc-plugin-gem/src/lib.rs @@ -1,59 +1,68 @@ +use serde::Deserialize; +use swc_common::pass::Optional; +use swc_core::ecma::visit::VisitMutWith; use swc_core::plugin::{plugin_transform, proxies::TransformPluginProgramMetadata}; -use swc_core::{ - common::Spanned, - ecma::{ - ast::{op, BinExpr, Ident, Program}, - transforms::testing::test_inline, - visit::{as_folder, FoldWith, VisitMut, VisitMutWith}, - }, -}; +use swc_ecma_ast::Program; +pub use visitors::import::import_transform; +pub use visitors::memo::memo_transform; +pub use visitors::minify::minify_transform; -pub struct TransformVisitor; +mod visitors; -impl VisitMut for TransformVisitor { - // Implement necessary visit_mut_* methods for actual custom transform. - // A comprehensive list of possible visitor methods can be found here: - // https://rustdoc.swc.rs/swc_ecma_visit/trait.VisitMut.html - - fn visit_mut_bin_expr(&mut self, e: &mut BinExpr) { - e.visit_mut_children_with(self); - - if e.op == op!("===") { - e.left = Box::new(Ident::new_no_ctxt("kdy1".into(), e.left.span()).into()); - } - } +#[derive(Deserialize, Debug, Clone, PartialEq, Default)] +#[serde(rename_all = "camelCase")] +struct PluginConfig { + #[serde(default)] + pub auto_import: bool, + #[serde(default)] + pub auto_import_dts: bool, + #[serde(default)] + pub resolve_path: bool, + #[serde(default)] + pub style_minify: bool, + #[serde(default)] + pub esm_provider: String, } -/// An example plugin function with macro support. -/// `plugin_transform` macro interop pointers into deserialized structs, as well -/// as returning ptr back to host. -/// -/// It is possible to opt out from macro by writing transform fn manually -/// if plugin need to handle low-level ptr directly via -/// `__transform_plugin_process_impl( -/// ast_ptr: *const u8, ast_ptr_len: i32, -/// unresolved_mark: u32, should_enable_comments_proxy: i32) -> -/// i32 /* 0 for success, fail otherwise. -/// Note this is only for internal pointer interop result, -/// not actual transform result */` -/// -/// This requires manual handling of serialization / deserialization from ptrs. -/// Refer swc_plugin_macro to see how does it work internally. #[plugin_transform] -pub fn process_transform(program: Program, _metadata: TransformPluginProgramMetadata) -> Program { - program.fold_with(&mut as_folder(TransformVisitor)) +pub fn process_transform(mut program: Program, data: TransformPluginProgramMetadata) -> Program { + let plugin_config = &data + .get_transform_plugin_config() + .expect("failed to get plugin config for gem plugin"); + let config = + serde_json::from_str::(plugin_config).expect("invalid config for gem plugin"); + + program.visit_mut_with(&mut ( + Optional { + enabled: true, + visitor: memo_transform(), + }, + Optional { + enabled: config.auto_import, + visitor: import_transform(), + }, + Optional { + enabled: config.style_minify, + visitor: minify_transform(), + }, + )); + + program } -// An example to test plugin transform. -// Recommended strategy to test plugin's transform is verify -// the Visitor's behavior, instead of trying to run `process_transform` with mocks -// unless explicitly required to do so. -test_inline!( - Default::default(), - |_| as_folder(TransformVisitor), - boo, - // Input codes - r#"foo === bar"#, - // Output codes after transformed with plugin - r#"kdy1 === bar"# -); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_return_default_config() { + let config = serde_json::from_str::(r#"{"autoImport": true}"#).unwrap(); + assert_eq!( + config, + PluginConfig { + auto_import: true, + ..Default::default() + } + ) + } +} diff --git a/crates/swc-plugin-gem/src/visitors/import.rs b/crates/swc-plugin-gem/src/visitors/import.rs new file mode 100644 index 00000000..46f65761 --- /dev/null +++ b/crates/swc-plugin-gem/src/visitors/import.rs @@ -0,0 +1,210 @@ +use once_cell::sync::Lazy; +use regex::Regex; +use serde::Deserialize; +use std::collections::{BTreeMap, HashMap, HashSet}; +use swc_common::DUMMY_SP; +use swc_core::ecma::visit::{noop_visit_mut_type, VisitMut, VisitMutWith}; +use swc_ecma_ast::{ + Callee, Class, ClassDecl, ClassExpr, Decorator, Ident, ImportDecl, ImportNamedSpecifier, + ImportSpecifier, ModuleDecl, ModuleItem, Str, TaggedTpl, +}; + +static CUSTOM_ELEMENT_REGEX: Lazy = + Lazy::new(|| Regex::new(r"(?s)<(?\w+(-\w+)+)(\s|>)").unwrap()); + +#[derive(Deserialize, Debug, Clone, PartialEq)] +#[serde(untagged)] +enum MemberOrMemberAs { + Member(String), + MemberAs([String; 2]), +} + +#[derive(Deserialize, Debug, Clone, PartialEq, Default)] +#[serde(rename_all = "camelCase")] +struct AutoImportContent { + members: HashMap>, + elements: HashMap>, +} + +struct AutoImportConfig { + /// member -> package name + member_map: HashMap, + /// tag reg, path reg + tag_config: Vec<(Regex, String)>, +} + +static GEM_AUTO_IMPORT_CONFIG: Lazy = Lazy::new(|| { + let content: &str = include_str!("../auto-import.json"); + let content = serde_json::from_str::(content).expect("invalid json"); + + let mut member_map = HashMap::new(); + + for (package, import_vec) in content.members.iter() { + for member in import_vec { + // TODO: support `MemberAs` + if let MemberOrMemberAs::Member(name) = member { + member_map.insert(name.into(), package.into()); + } + } + } + + let mut tag_config = Vec::new(); + + for (package, import_map) in content.elements { + for (tag, path) in import_map { + if let Ok(reg) = Regex::new(&tag.replace("*", "(.*)")) { + tag_config.push((reg, format!("{}{}", package, path.replace("*", "$1")))); + } + } + } + + AutoImportConfig { + member_map, + tag_config, + } +}); + +trait IdentString { + fn to_name(&self) -> String; +} + +impl IdentString for Ident { + fn to_name(&self) -> String { + self.sym.as_str().into() + } +} + +#[derive(Default)] +pub struct TransformVisitor { + used_members: Vec, + defined_members: HashSet, + used_elements: Vec, +} + +impl TransformVisitor { + fn visit_mut_class(&mut self, node: &Box) { + if let Some(expr) = &node.super_class { + if let Some(ident) = expr.as_ident() { + self.used_members.push(ident.to_name()); + } + } + } +} + +impl VisitMut for TransformVisitor { + noop_visit_mut_type!(); + + fn visit_mut_import_specifier(&mut self, node: &mut ImportSpecifier) { + self.defined_members.insert(node.local().to_name()); + } + + fn visit_mut_callee(&mut self, node: &mut Callee) { + if let Callee::Expr(expr) = &node { + if let Some(ident) = expr.as_ident() { + self.used_members.push(ident.to_name()); + } + } + } + + fn visit_mut_decorator(&mut self, node: &mut Decorator) { + node.visit_mut_children_with(self); + + if let Some(ident) = node.expr.as_ident() { + self.used_members.push(ident.to_name()); + } + } + + fn visit_mut_tagged_tpl(&mut self, node: &mut TaggedTpl) { + node.visit_mut_children_with(self); + + if let Some(ident) = node.tag.as_ident() { + self.used_members.push(ident.to_name()); + } + + for ele in node.tpl.quasis.iter() { + for cap in CUSTOM_ELEMENT_REGEX.captures_iter(ele.raw.as_str()) { + self.used_elements.push(cap["tag"].to_string()); + } + } + } + + fn visit_mut_class_decl(&mut self, node: &mut ClassDecl) { + node.visit_mut_children_with(self); + + self.visit_mut_class(&node.class); + } + + fn visit_mut_class_expr(&mut self, node: &mut ClassExpr) { + node.visit_mut_children_with(self); + + self.visit_mut_class(&node.class); + } + + // https://swc.rs/docs/plugin/ecmascript/cheatsheet#inserting-new-nodes + // 只处理模块 + fn visit_mut_module_items(&mut self, node: &mut Vec) { + // TODO: 收集顶层声明, 防止重复声明 + node.visit_mut_children_with(self); + + let mut out: Vec = vec![]; + let mut available_import: HashMap> = HashMap::new(); + + for used_member in self.used_members.iter() { + if !self.defined_members.contains(used_member) { + let pkg = GEM_AUTO_IMPORT_CONFIG.member_map.get(used_member); + if let Some(pkg) = pkg { + let set = available_import + .entry(pkg.into()) + .or_insert(Default::default()); + set.insert(used_member.into(), used_member.into()); + } + } + } + + for (pkg, set) in available_import { + let mut specifiers: Vec = vec![]; + for (member, _) in set { + specifiers.push(ImportSpecifier::Named(ImportNamedSpecifier { + local: member.into(), + span: DUMMY_SP, + imported: None, + is_type_only: false, + })); + } + out.push(ImportDecl { + specifiers, + src: Box::new(Str::from(pkg)), + span: DUMMY_SP, + type_only: false, + with: None, + phase: Default::default(), + }); + } + + for tag in self.used_elements.iter() { + for (reg, path) in GEM_AUTO_IMPORT_CONFIG.tag_config.iter() { + if reg.is_match(tag) { + out.push(ImportDecl { + specifiers: vec![], + src: Box::new(Str::from(reg.replace(tag, path))), + span: DUMMY_SP, + type_only: false, + with: None, + phase: Default::default(), + }); + } + } + } + + node.splice( + 0..0, + out.into_iter() + .map(ModuleDecl::Import) + .map(ModuleItem::ModuleDecl), + ); + } +} + +pub fn import_transform() -> impl VisitMut { + TransformVisitor::default() +} diff --git a/crates/swc-plugin-gem/src/visitors/memo.rs b/crates/swc-plugin-gem/src/visitors/memo.rs new file mode 100644 index 00000000..4e3f23f7 --- /dev/null +++ b/crates/swc-plugin-gem/src/visitors/memo.rs @@ -0,0 +1,101 @@ +use swc_common::DUMMY_SP; +use swc_core::{ + atoms::Atom, + ecma::visit::{noop_visit_mut_type, VisitMut, VisitMutWith}, +}; +use swc_ecma_ast::{ + AssignExpr, AssignOp, AssignTarget, Callee, Class, ClassDecl, ClassExpr, ClassMember, Expr, + MemberExpr, MemberProp, MethodKind, PrivateMethod, PrivateName, PrivateProp, ReturnStmt, + SimpleAssignTarget, ThisExpr, +}; + +#[derive(Default)] +struct TransformVisitor { + private_props: Vec, + current_index: usize, +} + +impl TransformVisitor { + fn current_method(&self) -> &Atom { + self.private_props.get(self.current_index).unwrap() + } + + fn visit_mut_class(&mut self, node: &mut Box) { + for prop in self.private_props.iter() { + node.body.push(ClassMember::PrivateProp(PrivateProp { + key: PrivateName { + span: DUMMY_SP, + name: prop.as_str().into(), + }, + ..Default::default() + })); + } + } +} + +fn is_memo_getter(node: &mut PrivateMethod) -> bool { + if node.kind != MethodKind::Getter { + return false; + } + + node.function.decorators.iter().any(|x| { + if let Expr::Call(ref call_expr) = *x.expr { + if let Callee::Expr(ref b) = call_expr.callee { + if let Expr::Ident(ref ident) = **b { + return ident.sym.as_str() == "memo"; + } + } + } + false + }) +} + +impl VisitMut for TransformVisitor { + noop_visit_mut_type!(); + + fn visit_mut_class_decl(&mut self, node: &mut ClassDecl) { + node.visit_mut_children_with(self); + + self.visit_mut_class(&mut node.class); + } + + fn visit_mut_class_expr(&mut self, node: &mut ClassExpr) { + node.visit_mut_children_with(self); + + self.visit_mut_class(&mut node.class); + } + + fn visit_mut_private_method(&mut self, node: &mut PrivateMethod) { + if is_memo_getter(node) { + self.current_index = self.private_props.len(); + self.private_props.push(node.key.name.clone()); + + node.visit_mut_children_with(self); + + node.key = PrivateName { + span: DUMMY_SP, + name: format!("_{}", node.key.name).into(), + } + } + } + + fn visit_mut_return_stmt(&mut self, node: &mut ReturnStmt) { + node.arg = Some(Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: AssignOp::Assign, + left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { + span: DUMMY_SP, + obj: ThisExpr { span: DUMMY_SP }.into(), + prop: MemberProp::PrivateName(PrivateName { + span: DUMMY_SP, + name: self.current_method().clone(), + }), + })), + right: node.arg.clone().unwrap_or(Expr::undefined(DUMMY_SP)), + }))); + } +} + +pub fn memo_transform() -> impl VisitMut { + TransformVisitor::default() +} diff --git a/crates/swc-plugin-gem/src/visitors/minify.rs b/crates/swc-plugin-gem/src/visitors/minify.rs new file mode 100644 index 00000000..e59928c8 --- /dev/null +++ b/crates/swc-plugin-gem/src/visitors/minify.rs @@ -0,0 +1,21 @@ +use swc_core::ecma::visit::{noop_visit_mut_type, VisitMut, VisitMutWith}; +use swc_ecma_ast::TaggedTpl; + +#[derive(Default)] +struct TransformVisitor {} + +impl VisitMut for TransformVisitor { + noop_visit_mut_type!(); + + fn visit_mut_tagged_tpl(&mut self, node: &mut TaggedTpl) { + node.visit_mut_children_with(self); + + for _ele in node.tpl.quasis.iter() { + // TODO: implement + } + } +} + +pub fn minify_transform() -> impl VisitMut { + TransformVisitor::default() +} diff --git a/crates/swc-plugin-gem/src/visitors/mod.rs b/crates/swc-plugin-gem/src/visitors/mod.rs new file mode 100644 index 00000000..ccc72c28 --- /dev/null +++ b/crates/swc-plugin-gem/src/visitors/mod.rs @@ -0,0 +1,3 @@ +pub mod import; +pub mod memo; +pub mod minify; diff --git a/crates/swc-plugin-gem/tests/fixture.rs b/crates/swc-plugin-gem/tests/fixture.rs new file mode 100644 index 00000000..515696b9 --- /dev/null +++ b/crates/swc-plugin-gem/tests/fixture.rs @@ -0,0 +1,40 @@ +use std::path::PathBuf; + +use swc_core::ecma::transforms::testing::test_fixture; +use swc_ecma_parser::{Syntax, TsSyntax}; +use swc_ecma_visit::visit_mut_pass; +use swc_plugin_gem::{import_transform, memo_transform}; +use testing::fixture; + +fn get_syntax() -> Syntax { + Syntax::Typescript(TsSyntax { + decorators: true, + ..TsSyntax::default() + }) +} + +#[fixture("tests/fixture/auto-import/**/input.ts")] +fn fixture_auto_import(input: PathBuf) { + let output = input.parent().unwrap().join("output.ts"); + + test_fixture( + get_syntax(), + &|_| visit_mut_pass(import_transform()), + &input, + &output, + Default::default(), + ); +} + +#[fixture("tests/fixture/memo/input.ts")] +fn fixture_memo(input: PathBuf) { + let output = input.parent().unwrap().join("output.ts"); + + test_fixture( + get_syntax(), + &|_| visit_mut_pass(memo_transform()), + &input, + &output, + Default::default(), + ); +} diff --git a/crates/swc-plugin-gem/tests/fixture/auto-import/elements/input.ts b/crates/swc-plugin-gem/tests/fixture/auto-import/elements/input.ts new file mode 100644 index 00000000..034dd1ec --- /dev/null +++ b/crates/swc-plugin-gem/tests/fixture/auto-import/elements/input.ts @@ -0,0 +1,10 @@ +// @ts-nocheck + +export class MyElement extends GemElement { + render() { + return html` + + ${html``} + `; + } +} diff --git a/crates/swc-plugin-gem/tests/fixture/auto-import/elements/output.ts b/crates/swc-plugin-gem/tests/fixture/auto-import/elements/output.ts new file mode 100644 index 00000000..e1b8b7e4 --- /dev/null +++ b/crates/swc-plugin-gem/tests/fixture/auto-import/elements/output.ts @@ -0,0 +1,12 @@ +// @ts-nocheck +import { GemElement, html } from "@mantou/gem"; +import "@mantou/gem/elements/link" +import "duoyun-ui/elements/use" +export class MyElement extends GemElement { + render() { + return html` + + ${html``} + `; + } +} \ No newline at end of file diff --git a/crates/swc-plugin-gem/tests/fixture/auto-import/members/input.ts b/crates/swc-plugin-gem/tests/fixture/auto-import/members/input.ts new file mode 100644 index 00000000..5f639369 --- /dev/null +++ b/crates/swc-plugin-gem/tests/fixture/auto-import/members/input.ts @@ -0,0 +1,15 @@ +// @ts-nocheck +import { render, Emitter, GemElement } from '@mantou/gem'; + +const style = css``; +@adoptedStyle(style) +@customElement('my-element') +class MyElement extends GemElement { + @attribute name: string; + @emitter open: Emitter; + + @template() + render() { + return html`
`; + } +} diff --git a/crates/swc-plugin-gem/tests/fixture/auto-import/members/output.ts b/crates/swc-plugin-gem/tests/fixture/auto-import/members/output.ts new file mode 100644 index 00000000..daf2a41c --- /dev/null +++ b/crates/swc-plugin-gem/tests/fixture/auto-import/members/output.ts @@ -0,0 +1,16 @@ +// @ts-nocheck +import { adoptedStyle, attribute, css, customElement, emitter, html, styleMap, template } from "@mantou/gem"; +import { render, Emitter, GemElement } from '@mantou/gem'; +const style = css``; +@adoptedStyle(style) +@customElement('my-element') +class MyElement extends GemElement { + @attribute + name: string; + @emitter + open: Emitter; + @template() + render() { + return html`
`; + } +} \ No newline at end of file diff --git a/crates/swc-plugin-gem/tests/fixture/memo/input.ts b/crates/swc-plugin-gem/tests/fixture/memo/input.ts new file mode 100644 index 00000000..8f2e47fd --- /dev/null +++ b/crates/swc-plugin-gem/tests/fixture/memo/input.ts @@ -0,0 +1,8 @@ +// @ts-nocheck + +class MyElement { + @memo(['src']) + get #src() { + return '#src'; + } +} diff --git a/crates/swc-plugin-gem/tests/fixture/memo/output.ts b/crates/swc-plugin-gem/tests/fixture/memo/output.ts new file mode 100644 index 00000000..5d54fe6e --- /dev/null +++ b/crates/swc-plugin-gem/tests/fixture/memo/output.ts @@ -0,0 +1,9 @@ +// @ts-nocheck +class MyElement { + @memo(['src']) + get #_src() { + return this.#src = '#src'; + } + #src; + } + \ No newline at end of file diff --git a/crates/swc-plugin-gem/tests/fixture/minify/input.ts b/crates/swc-plugin-gem/tests/fixture/minify/input.ts new file mode 100644 index 00000000..3ef36b32 --- /dev/null +++ b/crates/swc-plugin-gem/tests/fixture/minify/input.ts @@ -0,0 +1,6 @@ +// @ts-nocheck +const style = css` + :host { + color: red; + } +` diff --git a/crates/swc-plugin-gem/tests/fixture/minify/output.ts b/crates/swc-plugin-gem/tests/fixture/minify/output.ts new file mode 100644 index 00000000..1c464d00 --- /dev/null +++ b/crates/swc-plugin-gem/tests/fixture/minify/output.ts @@ -0,0 +1,2 @@ +// @ts-nocheck +const style = css`:host {color: red;}` diff --git a/packages/gem-book/src/plugins/sandpack.ts b/packages/gem-book/src/plugins/sandpack.ts index a334a3d3..de857816 100644 --- a/packages/gem-book/src/plugins/sandpack.ts +++ b/packages/gem-book/src/plugins/sandpack.ts @@ -451,7 +451,6 @@ class _GbpSandpackElement extends GemBookPluginElement { try { this.#importConfig = trans(JSON.parse(await (await fetch(AUTO_IMPORT)).text())); } catch { - // TODO: remove content; this.#importConfig = trans({ members: {}, elements: {} }); } }; @@ -472,6 +471,8 @@ class _GbpSandpackElement extends GemBookPluginElement { }); new Set([...code.matchAll(/<(?\w+(-\w+)+)(\s|>)/gs)].map((match) => match.groups!.tag)).forEach((tag) => { for (const [reg, replace] of tagMap) { + // 用来排除 + if (!replace) continue; const importPath = tag.replace(reg, replace); if (importPath !== tag) { importLines.add(`import '${importPath}'`);