From 134778eb8d74745fa77145e3ade636e5bf8a060c Mon Sep 17 00:00:00 2001 From: Jovi De Croock Date: Mon, 14 Jul 2025 09:36:44 +0200 Subject: [PATCH] Add SWC transform for signal --- .../.cargo/config.toml | 5 + .../signals-react-transform/.gitignore | 3 + .../signals-react-transform/Cargo.lock | 2473 +++++++++++++++++ .../signals-react-transform/Cargo.toml | 22 + .../signals-react-transform/package.json | 16 + .../signals-react-transform/src/lib.rs | 1446 ++++++++++ 6 files changed, 3965 insertions(+) create mode 100644 packages/react-transform/swc-plugin/signals-react-transform/.cargo/config.toml create mode 100644 packages/react-transform/swc-plugin/signals-react-transform/.gitignore create mode 100644 packages/react-transform/swc-plugin/signals-react-transform/Cargo.lock create mode 100644 packages/react-transform/swc-plugin/signals-react-transform/Cargo.toml create mode 100644 packages/react-transform/swc-plugin/signals-react-transform/package.json create mode 100644 packages/react-transform/swc-plugin/signals-react-transform/src/lib.rs diff --git a/packages/react-transform/swc-plugin/signals-react-transform/.cargo/config.toml b/packages/react-transform/swc-plugin/signals-react-transform/.cargo/config.toml new file mode 100644 index 000000000..5e9878a1b --- /dev/null +++ b/packages/react-transform/swc-plugin/signals-react-transform/.cargo/config.toml @@ -0,0 +1,5 @@ +# These command aliases are not final, may change +[alias] +# Alias to build actual plugin binary for the specified target. +build-wasip1 = "build --target wasm32-wasip1" +build-wasm32 = "build --target wasm32-unknown-unknown" diff --git a/packages/react-transform/swc-plugin/signals-react-transform/.gitignore b/packages/react-transform/swc-plugin/signals-react-transform/.gitignore new file mode 100644 index 000000000..6bdfa85b9 --- /dev/null +++ b/packages/react-transform/swc-plugin/signals-react-transform/.gitignore @@ -0,0 +1,3 @@ +/target +^target/ +target diff --git a/packages/react-transform/swc-plugin/signals-react-transform/Cargo.lock b/packages/react-transform/swc-plugin/signals-react-transform/Cargo.lock new file mode 100644 index 000000000..52eecebc3 --- /dev/null +++ b/packages/react-transform/swc-plugin/signals-react-transform/Cargo.lock @@ -0,0 +1,2473 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ascii" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" + +[[package]] +name = "ast_node" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e2cddd48eafd883890770673b1971faceaf80a185445671abc3ea0c00593ee" +dependencies = [ + "quote", + "swc_macros_common", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "better_scoped_tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd228125315b132eed175bf47619ac79b945b26e56b848ba203ae4ea8603609" +dependencies = [ + "scoped-tls", +] + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "bytecheck" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50690fb3370fb9fe3550372746084c46f2ac8c9685c583d2be10eefd89d3d1a3" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "rancor", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efb7846e0cb180355c2dec69e721edafa36919850f1a9f52ffba4ebc0393cb71" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "bytes-str" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c60b5ce37e0b883c37eb89f79a1e26fbe9c1081945d024eee93e8d91a7e18b3" +dependencies = [ + "bytes", + "rkyv", + "serde", +] + +[[package]] +name = "camino" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.12", +] + +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cc" +version = "1.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "compact_str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "ryu", + "static_assertions", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "serde", + "uuid", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "from_variant" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308530a56b099da144ebc5d8e179f343ad928fa2b3558d1eb3db9af18d6eff43" +dependencies = [ + "swc_macros_common", + "syn", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hstr" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b85186bc48d3c611ead052cc3f907748e40b63d73a99e4ed34d18063e2baaf1b" +dependencies = [ + "hashbrown 0.14.5", + "new_debug_unreachable", + "once_cell", + "rustc-hash", + "triomphe", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown 0.15.4", +] + +[[package]] +name = "is-macro" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57a3e447e24c22647738e4607f1df1e0ec6f72e16182c4cd199f647cdfb0e4" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "cfg-if", + "miette-derive", + "owo-colors", + "textwrap", + "unicode-width 0.1.14", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "munge" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cce144fab80fbb74ec5b89d1ca9d41ddf6b644ab7e986f7d3ed0aab31625cb1" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "574af9cd5b9971cbfdf535d6a8d533778481b241c447826d976101e0149392a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owo-colors" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e" + +[[package]] +name = "par-core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96cbd21255b7fb29a5d51ef38a779b517a91abd59e2756c039583f43ef4c90f" +dependencies = [ + "once_cell", +] + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.1", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" +dependencies = [ + "cc", +] + +[[package]] +name = "ptr_meta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rancor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" +dependencies = [ + "ptr_meta", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "redox_syscall" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "rend" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rkyv" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65" +dependencies = [ + "bytecheck", + "bytes", + "hashbrown 0.15.4", + "indexmap", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "ryu-js" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd29631678d6fb0903b69223673e122c32e9ae559d0960a38d574695ebc0ea15" + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +dependencies = [ + "serde", +] + +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signals-react-transform" +version = "0.1.0" +dependencies = [ + "once_cell", + "regex", + "serde", + "serde_json", + "swc_core", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "smallvec" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "stacker" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.59.0", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_enum" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae36a4951ca7bd1cfd991c241584a9824a70f6aff1e7d4f693fb3f2465e4030e" +dependencies = [ + "quote", + "swc_macros_common", + "syn", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "swc_allocator" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d7eefd2c8b228a8c73056482b2ae4b3a1071fbe07638e3b55ceca8570cc48bb" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.14.5", + "rustc-hash", +] + +[[package]] +name = "swc_atoms" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fda66fe4175cddc27a79643ded7ce297b6b2bf133f038ec5907fb4673e4b2ba" +dependencies = [ + "bytecheck", + "hstr", + "once_cell", + "rancor", + "rkyv", + "serde", +] + +[[package]] +name = "swc_common" +version = "13.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e103c3a47a343a175e9f65603122c5d3c8ec007776b00a4a4bc368a1347c4770" +dependencies = [ + "anyhow", + "ast_node", + "better_scoped_tls", + "bytecheck", + "bytes-str", + "either", + "from_variant", + "new_debug_unreachable", + "num-bigint", + "once_cell", + "parking_lot", + "rancor", + "rkyv", + "rustc-hash", + "serde", + "siphasher 0.3.11", + "swc_atoms", + "swc_eq_ignore_macros", + "swc_sourcemap", + "swc_visit", + "termcolor", + "tracing", + "unicode-width 0.1.14", + "url", +] + +[[package]] +name = "swc_core" +version = "31.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fe7787e59eccca32521b3a49a80c6957f8c44270f3967bdef23f9921482c4eb" +dependencies = [ + "swc_allocator", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_transforms_testing", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_plugin", + "swc_plugin_macro", + "swc_plugin_proxy", + "swc_transform_common", + "testing", + "vergen", +] + +[[package]] +name = "swc_ecma_ast" +version = "13.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3de29559723afd8436efd427648b22346fd408f741f93c0464aa0815857e69a4" +dependencies = [ + "bitflags", + "bytecheck", + "is-macro", + "num-bigint", + "once_cell", + "phf", + "rancor", + "rkyv", + "rustc-hash", + "string_enum", + "swc_atoms", + "swc_common", + "swc_visit", + "unicode-id-start", +] + +[[package]] +name = "swc_ecma_codegen" +version = "15.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a639a205901c8cc0af6f2d7ff4548eb86f0935b1e70662423a9298a304ead6c2" +dependencies = [ + "ascii", + "compact_str", + "memchr", + "num-bigint", + "once_cell", + "regex", + "rustc-hash", + "ryu-js", + "serde", + "swc_allocator", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_codegen_macros", + "swc_sourcemap", + "tracing", +] + +[[package]] +name = "swc_ecma_codegen_macros" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e276dc62c0a2625a560397827989c82a93fd545fcf6f7faec0935a82cc4ddbb8" +dependencies = [ + "proc-macro2", + "swc_macros_common", + "syn", +] + +[[package]] +name = "swc_ecma_lexer" +version = "19.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180810f860c9128eb74b970da8826e0d86fd8f99808c2fbe224cc5c714af2b70" +dependencies = [ + "arrayvec", + "bitflags", + "either", + "new_debug_unreachable", + "num-bigint", + "phf", + "rustc-hash", + "seq-macro", + "serde", + "smallvec", + "smartstring", + "stacker", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "tracing", +] + +[[package]] +name = "swc_ecma_parser" +version = "19.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98c059cc69b577ca26d5bc1efdb022c7ee3e186637b6b355bb2f6660491a6ed1" +dependencies = [ + "either", + "num-bigint", + "serde", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_lexer", + "tracing", +] + +[[package]] +name = "swc_ecma_testing" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bccfc5af9527cf3efe6d59749011769bcc69213dda8eadbfa0211da2c19c4812" +dependencies = [ + "anyhow", + "hex", + "sha2", + "testing", + "tracing", +] + +[[package]] +name = "swc_ecma_transforms_base" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2231c70c3cb3ce733e71224b287ce494a60d928b1b0f151129ff18d023cc7b0" +dependencies = [ + "better_scoped_tls", + "indexmap", + "once_cell", + "par-core", + "phf", + "rustc-hash", + "serde", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_utils", + "swc_ecma_visit", + "tracing", +] + +[[package]] +name = "swc_ecma_transforms_testing" +version = "23.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c51d2cc9bfd6cc68955debd7cc119c46a9984e973ce3043edd50ba048ef9387" +dependencies = [ + "ansi_term", + "anyhow", + "base64", + "hex", + "serde", + "serde_json", + "sha2", + "swc_common", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_parser", + "swc_ecma_testing", + "swc_ecma_transforms_base", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_sourcemap", + "tempfile", + "testing", +] + +[[package]] +name = "swc_ecma_utils" +version = "18.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21c9a1dda55bddf62dae2130640452813ad70df9014450852b94753b154885ec" +dependencies = [ + "indexmap", + "num_cpus", + "once_cell", + "par-core", + "rustc-hash", + "ryu-js", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_visit", + "tracing", +] + +[[package]] +name = "swc_ecma_visit" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ad28e3449b376bfe1f2bde28bfcf305961ba23c1e205bedb03a7c108a1d1ff6" +dependencies = [ + "new_debug_unreachable", + "num-bigint", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_visit", + "tracing", +] + +[[package]] +name = "swc_eq_ignore_macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c16ce73424a6316e95e09065ba6a207eba7765496fed113702278b7711d4b632" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "swc_error_reporters" +version = "15.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b8bad18498e57f0f904e846b270af576bbfb7b583f1ee00bdeebe46748eb01" +dependencies = [ + "anyhow", + "miette", + "once_cell", + "serde", + "swc_common", +] + +[[package]] +name = "swc_macros_common" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1efbaa74943dc5ad2a2fb16cbd78b77d7e4d63188f3c5b4df2b4dcd2faaae" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "swc_plugin" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92b27449420554de6ad8d49004ad3d36e6ac64ecb51d1b0fe1002afcd7a45d85" +dependencies = [ + "once_cell", +] + +[[package]] +name = "swc_plugin_macro" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace467dfafbbdf3aecff786b8605b35db57d945e92fd88800569aa2cba0cdf61" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "swc_plugin_proxy" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4592caaec04f5de44f5a507a8d14bedee21e9cd8ca366ccf48169347162ac250" +dependencies = [ + "better_scoped_tls", + "bytecheck", + "rancor", + "rkyv", + "rustc-hash", + "swc_common", + "swc_ecma_ast", + "swc_trace_macro", + "tracing", +] + +[[package]] +name = "swc_sourcemap" +version = "9.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9755c673c6a83c461e98fa018f681adb8394a3f44f89a06f27e80fd4fe4fa1e4" +dependencies = [ + "base64-simd", + "bitvec", + "bytes-str", + "data-encoding", + "debugid", + "if_chain", + "rustc-hash", + "serde", + "serde_json", + "unicode-id-start", + "url", +] + +[[package]] +name = "swc_trace_macro" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfd2b4b0adb82e36f2ac688d00a6a67132c7f4170c772617516793a701be89e8" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "swc_transform_common" +version = "7.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "364479c8afe381e0f0ae0c438f92f3018111004e6ec77960b4e58b2dc8038263" +dependencies = [ + "better_scoped_tls", + "rustc-hash", + "serde", + "swc_common", +] + +[[package]] +name = "swc_visit" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62fb71484b486c185e34d2172f0eabe7f4722742aad700f426a494bb2de232a2" +dependencies = [ + "either", + "new_debug_unreachable", +] + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "testing" +version = "14.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec446acef3673f1e8cc5674e70b5ed30f248495fe2cdb4aa556e4d3ab64da3e2" +dependencies = [ + "cargo_metadata 0.18.1", + "difference", + "once_cell", + "pretty_assertions", + "regex", + "rustc-hash", + "serde", + "serde_json", + "swc_common", + "swc_error_reporters", + "testing_macros", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "testing_macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7442bd3ca09f38d4788dc5ebafbc1967c3717726b4b074db011d470b353548b" +dependencies = [ + "anyhow", + "glob", + "once_cell", + "proc-macro2", + "quote", + "regex", + "relative-path", + "syn", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "unicode-linebreak", + "unicode-width 0.2.1", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "triomphe" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" +dependencies = [ + "serde", + "stable_deref_trait", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-id-start" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f322b60f6b9736017344fa0635d64be2f458fbc04eef65f6be22976dd1ffd5b" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vergen" +version = "9.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b2bf58be11fc9414104c6d3a2e464163db5ef74b12296bda593cac37b6e4777" +dependencies = [ + "anyhow", + "cargo_metadata 0.19.2", + "derive_builder", + "regex", + "rustversion", + "vergen-lib", +] + +[[package]] +name = "vergen-lib" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b07e6010c0f3e59fcb164e0163834597da68d1f864e2b8ca49f74de01e9c166" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/packages/react-transform/swc-plugin/signals-react-transform/Cargo.toml b/packages/react-transform/swc-plugin/signals-react-transform/Cargo.toml new file mode 100644 index 000000000..f575c35bb --- /dev/null +++ b/packages/react-transform/swc-plugin/signals-react-transform/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "signals-react-transform" +version = "0.1.0" +edition = "2021" + +[lib] +name = "signals_react_transform" +crate-type = ["cdylib"] + +[profile.release] +lto = true + +[dependencies] +serde = { version = "1", features = ["derive"] } +serde_json = "1" +swc_core = { version = "31.1.*", features = ["ecma_plugin_transform", "__utils", "testing", "__parser"] } +once_cell = "1.19" +regex = "1.10" + +# .cargo/config.toml defines few alias to build plugin. +# cargo build-wasip1 generates wasm32-wasip1 binary +# cargo build-wasm32 generates wasm32-unknown-unknown binary. diff --git a/packages/react-transform/swc-plugin/signals-react-transform/package.json b/packages/react-transform/swc-plugin/signals-react-transform/package.json new file mode 100644 index 000000000..33e36bdf8 --- /dev/null +++ b/packages/react-transform/swc-plugin/signals-react-transform/package.json @@ -0,0 +1,16 @@ +{ + "name": "signals-react-transform", + "version": "0.1.0", + "description": "", + "author": "", + "license": "MIT", + "keywords": [ + "swc-plugin" + ], + "main": "target/wasm32-wasip1/release/signals_react_transform.wasm", + "scripts": { + "prepublishOnly": "cargo build-wasip1 --release" + }, + "files": [], + "preferUnplugged": true +} diff --git a/packages/react-transform/swc-plugin/signals-react-transform/src/lib.rs b/packages/react-transform/swc-plugin/signals-react-transform/src/lib.rs new file mode 100644 index 000000000..cddcfb86d --- /dev/null +++ b/packages/react-transform/swc-plugin/signals-react-transform/src/lib.rs @@ -0,0 +1,1446 @@ +use once_cell::sync::Lazy; +use regex::Regex; +use serde::{Deserialize, Serialize}; +use std::collections::{HashMap, HashSet}; +use swc_core::{ + common::{comments::Comments, Span, SyntaxContext, DUMMY_SP}, + ecma::{ + ast::*, + utils::quote_ident, + visit::{Fold, FoldWith, VisitMut, VisitMutWith}, + }, + plugin::{plugin_transform, proxies::TransformPluginProgramMetadata}, +}; + +pub static OPT_OUT_COMMENT: Lazy = Lazy::new(|| Regex::new(r"(^|\s)@no(Use|Track)Signals(\s|$)").unwrap()); +pub static OPT_IN_COMMENT: Lazy = Lazy::new(|| Regex::new(r"(^|\s)@(use|track)Signals(\s|$)").unwrap()); + +const DEFAULT_IMPORT_SOURCE: &str = "@preact/signals-react/runtime"; +const IMPORT_NAME: &str = "useSignals"; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PluginOptions { + #[serde(default)] + pub mode: Option, + #[serde(default)] + pub import_source: Option, + #[serde(default)] + pub detect_transformed_jsx: Option, + #[serde(default)] + pub experimental: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ExperimentalOptions { + #[serde(default)] + pub no_try_finally: Option, +} + +impl Default for PluginOptions { + fn default() -> Self { + Self { + mode: Some("auto".to_string()), + import_source: None, + detect_transformed_jsx: Some(false), + experimental: None, + } + } +} + +#[derive(Debug, Clone)] +pub struct FunctionInfo { + pub name: Option, + pub is_component: bool, + pub is_hook: bool, + pub has_jsx: bool, + pub uses_signals: bool, + pub has_opt_in_comment: bool, + pub has_opt_out_comment: bool, +} + +pub struct TransformVisitor { + options: PluginOptions, + functions: HashMap, + jsx_identifiers: HashSet, + jsx_objects: HashMap>, + use_signals_ident: Option, + pub comments: Option>, +} + +impl TransformVisitor { + pub fn new(options: PluginOptions) -> Self { + let jsx_identifiers = HashSet::new(); + let jsx_objects = HashMap::new(); + + Self { + options, + functions: HashMap::new(), + jsx_identifiers, + jsx_objects, + use_signals_ident: None, + comments: None, + } + } + + pub fn with_comments(options: PluginOptions, comments: Box) -> Self { + let jsx_identifiers = HashSet::new(); + let jsx_objects = HashMap::new(); + + Self { + options, + functions: HashMap::new(), + jsx_identifiers, + jsx_objects, + use_signals_ident: None, + comments: Some(comments), + } + } + + + fn is_component_name(&self, name: &str) -> bool { + name.chars().next().map_or(false, |c| c.is_uppercase()) + } + + fn is_hook_name(&self, name: &str) -> bool { + name.starts_with("use") && name.len() > 3 && + name.chars().nth(3).map_or(false, |c| c.is_uppercase()) + } + + fn has_leading_comment(&self, span: Span, pattern: &Regex) -> bool { + if let Some(ref comments) = self.comments { + // Check leading comments for the span + if let Some(leading_comments) = comments.get_leading(span.lo) { + for comment in leading_comments { + if pattern.is_match(&comment.text) { + return true; + } + } + } + + // Also check trailing comments of the previous line + if let Some(trailing_comments) = comments.get_trailing(span.lo) { + for comment in trailing_comments { + if pattern.is_match(&comment.text) { + return true; + } + } + } + } + false + } + + fn detect_jsx_imports(&mut self, module: &Module) { + let jsx_packages = [ + ("react/jsx-runtime", vec!["jsx".to_string(), "jsxs".to_string()]), + ("react/jsx-dev-runtime", vec!["jsxDEV".to_string()]), + ("react", vec!["createElement".to_string()]), + ]; + + for item in &module.body { + match item { + ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)) => { + let src = import_decl.src.value.to_string(); + if let Some((_, methods)) = jsx_packages.iter().find(|(pkg, _)| *pkg == src) { + for spec in &import_decl.specifiers { + match spec { + ImportSpecifier::Named(named) => { + let imported_name = match &named.imported { + Some(ModuleExportName::Ident(ident)) => ident.sym.to_string(), + _ => named.local.sym.to_string(), + }; + if methods.iter().any(|m| m == &imported_name) { + self.jsx_identifiers.insert(named.local.sym.to_string()); + } + } + ImportSpecifier::Default(default) => { + self.jsx_objects.insert(default.local.sym.to_string(), methods.clone()); + } + _ => {} + } + } + } + } + _ => {} + } + } + } + + fn is_jsx_call(&self, call: &CallExpr) -> bool { + if !self.options.detect_transformed_jsx.unwrap_or(false) { + return false; + } + + match &call.callee { + Callee::Expr(expr) => match expr.as_ref() { + Expr::Ident(ident) => self.jsx_identifiers.contains(&ident.sym.to_string()), + Expr::Member(member) => { + if let (Expr::Ident(obj), MemberProp::Ident(prop)) = (member.obj.as_ref(), &member.prop) { + let obj_name = obj.sym.to_string(); + let prop_name = prop.sym.to_string(); + self.jsx_objects.get(&obj_name) + .map_or(false, |methods| methods.contains(&prop_name)) + } else { + false + } + } + _ => false, + } + _ => false, + } + } + + fn is_value_member_access(&self, expr: &MemberExpr) -> bool { + match &expr.prop { + MemberProp::Ident(ident) => ident.sym == "value", + MemberProp::Computed(computed) => { + if let Expr::Lit(Lit::Str(str_lit)) = computed.expr.as_ref() { + str_lit.value == "value" + } else { + false + } + } + _ => false, + } + } + + fn has_value_in_object_pattern(&self, pat: &ObjectPat) -> bool { + pat.props.iter().any(|prop| { + if let ObjectPatProp::KeyValue(kv) = prop { + match &kv.key { + PropName::Ident(ident) => ident.sym == "value", + PropName::Str(str_lit) => str_lit.value == "value", + _ => false, + } + } else { + false + } + }) + } + + pub fn should_transform(&self, info: &FunctionInfo) -> bool { + if info.has_opt_out_comment { + return false; + } + if info.has_opt_in_comment { + return true; + } + + let mode = self.options.mode.as_deref().unwrap_or("auto"); + match mode { + "all" => info.is_component, + "auto" => info.uses_signals && (info.is_component || info.is_hook), + _ => false, // "manual" or unknown modes + } + } + + fn wrap_function_body(&mut self, function: &mut Function, info: &FunctionInfo) { + let hook_usage = if info.is_hook { "2" } else { "1" }; + let use_try_finally = !self.options.experimental + .as_ref() + .and_then(|exp| exp.no_try_finally) + .unwrap_or(false); + + // Get or create the useSignals identifier + let use_signals_call = if let Some(ref ident) = self.use_signals_ident { + ident.clone() + } else { + let ident_name = quote_ident!("_useSignals"); + let ident = Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: ident_name.sym, + optional: false, + }; + self.use_signals_ident = Some(ident.clone()); + ident + }; + + let original_body = function.body.take(); + let mut new_stmts = Vec::new(); + + if use_try_finally { + // Create: var _effect = _useSignals(1); + let effect_ident_name = quote_ident!("_effect"); + let effect_ident = Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: effect_ident_name.sym, + optional: false, + }; + let hook_usage_expr = Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: hook_usage.into(), + raw: None, + })); + + let init_stmt = Stmt::Decl(Decl::Var(Box::new(VarDecl { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + kind: VarDeclKind::Var, + declare: false, + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: Pat::Ident(BindingIdent { + id: effect_ident.clone(), + type_ann: None, + }), + init: Some(Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + callee: Callee::Expr(Box::new(Expr::Ident(use_signals_call))), + args: vec![ExprOrSpread { + spread: None, + expr: Box::new(hook_usage_expr), + }], + type_args: None, + }))), + definite: false, + }], + }))); + + new_stmts.push(init_stmt); + + // Create try-finally block + let try_stmt = Stmt::Try(Box::new(TryStmt { + span: DUMMY_SP, + block: original_body.unwrap_or_else(|| BlockStmt { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + stmts: vec![], + }), + handler: None, + finalizer: Some(BlockStmt { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + stmts: vec![Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + callee: Callee::Expr(Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(effect_ident)), + prop: MemberProp::Ident(quote_ident!("f")), + }))), + args: vec![], + type_args: None, + })), + })], + }), + })); + + new_stmts.push(try_stmt); + } else { + // Just prepend useSignals() call + let call_stmt = Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + callee: Callee::Expr(Box::new(Expr::Ident(use_signals_call))), + args: vec![], + type_args: None, + })), + }); + + new_stmts.push(call_stmt); + + if let Some(original) = original_body { + new_stmts.extend(original.stmts); + } + } + + function.body = Some(BlockStmt { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + stmts: new_stmts, + }); + } + + fn add_import(&mut self, module: &mut Module) { + if self.use_signals_ident.is_none() { + return; + } + + let import_source = self.options.import_source.as_deref().unwrap_or(DEFAULT_IMPORT_SOURCE); + + // Check if import already exists + let has_existing_import = module.body.iter().any(|item| { + if let ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)) = item { + import_decl.src.value == import_source + } else { + false + } + }); + + if !has_existing_import { + let import_decl = ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { + span: DUMMY_SP, + specifiers: vec![ImportSpecifier::Named(ImportNamedSpecifier { + span: DUMMY_SP, + local: self.use_signals_ident.clone().unwrap(), + imported: Some(ModuleExportName::Ident(Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: IMPORT_NAME.into(), + optional: false, + })), + is_type_only: false, + })], + src: Box::new(Str { + span: DUMMY_SP, + value: import_source.into(), + raw: None, + }), + type_only: false, + with: None, + phase: Default::default(), + })); + + module.body.insert(0, import_decl); + } + } +} + +impl VisitMut for TransformVisitor { + fn visit_mut_module(&mut self, module: &mut Module) { + if self.options.detect_transformed_jsx.unwrap_or(false) { + self.detect_jsx_imports(module); + } + + // Single pass: visit children and transform as we go + module.visit_mut_children_with(self); + + // Add import at the end if we transformed anything + if self.use_signals_ident.is_some() { + self.add_import(module); + } + } + + fn visit_mut_function(&mut self, function: &mut Function) { + // For function expressions and other cases not handled by visit_mut_fn_decl + // We only store info, transformation happens in visit_mut_fn_decl + function.visit_mut_children_with(self); + } + + fn visit_mut_fn_decl(&mut self, fn_decl: &mut FnDecl) { + let span = fn_decl.function.span; + let name = Some(fn_decl.ident.sym.to_string()); + + let is_component = name.as_ref().map_or(false, |n| self.is_component_name(n)); + let is_hook = name.as_ref().map_or(false, |n| self.is_hook_name(n)); + + // Check for opt-in/opt-out comments + let has_opt_in_comment = self.has_leading_comment(span, &OPT_IN_COMMENT); + let has_opt_out_comment = self.has_leading_comment(span, &OPT_OUT_COMMENT); + + let info = FunctionInfo { + name: name.clone(), + is_component, + is_hook, + has_jsx: false, + uses_signals: false, + has_opt_in_comment, + has_opt_out_comment, + }; + + self.functions.insert(span, info); + + fn_decl.visit_mut_children_with(self); + + // Apply transformation if needed + let info_option = self.functions.get(&span); + let should_transform = info_option + .map(|info| self.should_transform(info)) + .unwrap_or(false); + + if should_transform { + let info_clone = self.functions.get(&span).unwrap().clone(); + self.wrap_function_body(&mut fn_decl.function, &info_clone); + } + } + + fn visit_mut_var_decl(&mut self, var_decl: &mut VarDecl) { + // Handle arrow functions in variable declarations like: const MyComponent = () => {} + for decl in &mut var_decl.decls { + if let Pat::Ident(binding_ident) = &decl.name { + if let Some(init) = &mut decl.init { + if let Expr::Arrow(arrow) = init.as_mut() { + let span = arrow.span; + let name = Some(binding_ident.id.sym.to_string()); + + let is_component = name.as_ref().map_or(false, |n| self.is_component_name(n)); + let is_hook = name.as_ref().map_or(false, |n| self.is_hook_name(n)); + + // Check for opt-in/opt-out comments + let has_opt_in_comment = self.has_leading_comment(span, &OPT_IN_COMMENT); + let has_opt_out_comment = self.has_leading_comment(span, &OPT_OUT_COMMENT); + + let info = FunctionInfo { + name: name.clone(), + is_component, + is_hook, + has_jsx: false, + uses_signals: false, + has_opt_in_comment, + has_opt_out_comment, + }; + + self.functions.insert(span, info); + + // Visit children first + arrow.visit_mut_children_with(self); + + // Apply transformation if needed + let info_option = self.functions.get(&span); + let should_transform = info_option + .map(|info| self.should_transform(info)) + .unwrap_or(false); + + if should_transform { + let info_clone = self.functions.get(&span).unwrap().clone(); + self.transform_arrow_function(arrow, &info_clone); + } + } + } + } + } + + // Note: We don't call visit_mut_children_with here because we handle arrow functions above + } + + fn visit_mut_arrow_expr(&mut self, arrow: &mut ArrowExpr) { + // For arrow functions not in variable declarations + arrow.visit_mut_children_with(self); + } + + fn visit_mut_jsx_element(&mut self, jsx: &mut JSXElement) { + // Mark current function as having JSX + if let Some((_, info)) = self.functions.iter_mut().last() { + info.has_jsx = true; + } + jsx.visit_mut_children_with(self); + } + + fn visit_mut_jsx_fragment(&mut self, jsx: &mut JSXFragment) { + // Mark current function as having JSX + if let Some((_, info)) = self.functions.iter_mut().last() { + info.has_jsx = true; + } + jsx.visit_mut_children_with(self); + } + + fn visit_mut_call_expr(&mut self, call: &mut CallExpr) { + if self.is_jsx_call(call) { + if let Some((_, info)) = self.functions.iter_mut().last() { + info.has_jsx = true; + } + } + call.visit_mut_children_with(self); + } + + fn visit_mut_member_expr(&mut self, member: &mut MemberExpr) { + if self.is_value_member_access(member) { + if let Some((_, info)) = self.functions.iter_mut().last() { + info.uses_signals = true; + } + } + member.visit_mut_children_with(self); + } + + fn visit_mut_object_pat(&mut self, pat: &mut ObjectPat) { + if self.has_value_in_object_pattern(pat) { + if let Some((_, info)) = self.functions.iter_mut().last() { + info.uses_signals = true; + } + } + pat.visit_mut_children_with(self); + } + +} + +impl TransformVisitor { + fn transform_arrow_function(&mut self, arrow: &mut ArrowExpr, info: &FunctionInfo) { + let hook_usage = if info.is_hook { "2" } else { "1" }; + let use_try_finally = !self.options.experimental + .as_ref() + .and_then(|exp| exp.no_try_finally) + .unwrap_or(false); + + // Get or create the useSignals identifier + let use_signals_call = if let Some(ref ident) = self.use_signals_ident { + ident.clone() + } else { + let ident_name = quote_ident!("_useSignals"); + let ident = Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: ident_name.sym, + optional: false, + }; + self.use_signals_ident = Some(ident.clone()); + ident + }; + + // Convert arrow function to block statement if it's an expression + let block_stmt = match arrow.body.as_ref() { + BlockStmtOrExpr::BlockStmt(block) => block.clone(), + BlockStmtOrExpr::Expr(expr) => { + // Convert expression to return statement + BlockStmt { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + stmts: vec![Stmt::Return(ReturnStmt { + span: DUMMY_SP, + arg: Some(expr.clone()), + })], + } + } + }; + + let mut new_stmts = Vec::new(); + + if use_try_finally { + // Create: var _effect = _useSignals(1); + let effect_ident_name = quote_ident!("_effect"); + let effect_ident = Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: effect_ident_name.sym, + optional: false, + }; + let hook_usage_expr = Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: hook_usage.into(), + raw: None, + })); + + let init_stmt = Stmt::Decl(Decl::Var(Box::new(VarDecl { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + kind: VarDeclKind::Var, + declare: false, + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: Pat::Ident(BindingIdent { + id: effect_ident.clone(), + type_ann: None, + }), + init: Some(Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + callee: Callee::Expr(Box::new(Expr::Ident(use_signals_call))), + args: vec![ExprOrSpread { + spread: None, + expr: Box::new(hook_usage_expr), + }], + type_args: None, + }))), + definite: false, + }], + }))); + + new_stmts.push(init_stmt); + + // Create try-finally block + let try_stmt = Stmt::Try(Box::new(TryStmt { + span: DUMMY_SP, + block: block_stmt, + handler: None, + finalizer: Some(BlockStmt { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + stmts: vec![Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + callee: Callee::Expr(Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(effect_ident)), + prop: MemberProp::Ident(quote_ident!("f")), + }))), + args: vec![], + type_args: None, + })), + })], + }), + })); + + new_stmts.push(try_stmt); + } else { + // Just prepend useSignals() call + let call_stmt = Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + callee: Callee::Expr(Box::new(Expr::Ident(use_signals_call))), + args: vec![], + type_args: None, + })), + }); + + new_stmts.push(call_stmt); + new_stmts.extend(block_stmt.stmts); + } + + arrow.body = Box::new(BlockStmtOrExpr::BlockStmt(BlockStmt { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + stmts: new_stmts, + })); + } +} + +impl Fold for TransformVisitor { + fn fold_program(&mut self, program: Program) -> Program { + program.fold_children_with(self) + } +} + +// Helper function for creating transformer +pub fn signals_transform(options: PluginOptions) -> TransformVisitor { + TransformVisitor::new(options) +} + +#[plugin_transform] +pub fn process_transform(program: Program, metadata: TransformPluginProgramMetadata) -> Program { + let config = metadata + .get_transform_plugin_config() + .and_then(|json_str| serde_json::from_str::(&json_str).ok()) + .unwrap_or_default(); + + program.fold_with(&mut TransformVisitor::new(config)) +} + +// Macro for inline testing similar to XantreDev's implementation +#[cfg(test)] +macro_rules! test_inline { + (ignore, $syntax:expr, $tr:expr, $test_name:ident, $input:expr, $output:expr) => { + #[test] + #[ignore] + fn $test_name() { + use swc_core::ecma::transforms::testing::test_inline_input_output; + test_inline_input_output($syntax, Some(true), $tr, $input, $output) + } + }; + + ($syntax:expr, $tr:expr, $test_name:ident, $input:expr, $output:expr) => { + #[test] + fn $test_name() { + use swc_core::ecma::transforms::testing::test_inline_input_output; + test_inline_input_output($syntax, Some(true), $tr, $input, $output) + } + }; +} + +#[cfg(test)] +fn get_syntax() -> swc_core::ecma::parser::Syntax { + use swc_core::ecma::parser::{EsSyntax, Syntax}; + + let mut es_syntax = EsSyntax::default(); + es_syntax.jsx = true; + Syntax::Es(es_syntax) +} + +// Test cases to verify the plugin works +test_inline!( + get_syntax(), + |_| { + use swc_core::ecma::visit::visit_mut_pass; + visit_mut_pass(TransformVisitor::new(PluginOptions::default())) + }, + signals_transform_basic, + r#" +function MyComponent() { + return
{signal.value}
; +} + "#, + r#" +import { useSignals as _useSignals } from "@preact/signals-react/runtime"; +function MyComponent() { + var _effect = _useSignals("1"); + try { + return
{signal.value}
; + } finally { + _effect.f(); + } +} + "# +); + +test_inline!( + get_syntax(), + |_| { + use swc_core::ecma::visit::visit_mut_pass; + visit_mut_pass(TransformVisitor::new(PluginOptions { + experimental: Some(ExperimentalOptions { + no_try_finally: Some(true) + }), + ..Default::default() + })) + }, + signals_transform_no_try_finally, + r#" +function MyComponent() { + return
{signal.value}
; +} + "#, + r#" +import { useSignals as _useSignals } from "@preact/signals-react/runtime"; +function MyComponent() { + _useSignals(); + return
{signal.value}
; +} + "# +); + +// Test arrow function components +test_inline!( + get_syntax(), + |_| { + use swc_core::ecma::visit::visit_mut_pass; + visit_mut_pass(TransformVisitor::new(PluginOptions::default())) + }, + signals_transform_arrow_function, + r#" +const MyComponent = () => { + return
{signal.value}
; +}; + "#, + r#" +import { useSignals as _useSignals } from "@preact/signals-react/runtime"; +const MyComponent = () => { + var _effect = _useSignals("1"); + try { + return
{signal.value}
; + } finally { + _effect.f(); + } +}; + "# +); + +// Test opt-out comment prevents transformation +// Note: Comments are not available in SWC test_inline! macro testing framework +// This test is ignored as comment detection requires access to Comments struct +test_inline!( + ignore, + get_syntax(), + |_| { + use swc_core::ecma::visit::visit_mut_pass; + visit_mut_pass(TransformVisitor::new(PluginOptions::default())) + }, + signals_transform_opt_out_comment, + r#" +/** @noUseSignals */ +function MyComponent() { + return
{signal.value}
; +} + "#, + r#" +/** @noUseSignals */ +function MyComponent() { + return
{signal.value}
; +} + "# +); + +// Test opt-in comment enables transformation +// Note: Comments are not available in SWC test_inline! macro testing framework +// This test is ignored as comment detection requires access to Comments struct +test_inline!( + ignore, + get_syntax(), + |_| { + use swc_core::ecma::visit::visit_mut_pass; + visit_mut_pass(TransformVisitor::new(PluginOptions { + mode: Some("manual".to_string()), + ..Default::default() + })) + }, + signals_transform_opt_in_comment, + r#" +/** @useSignals */ +function myFunction() { + return regularValue; +} + "#, + r#" +import { useSignals as _useSignals } from "@preact/signals-react/runtime"; +/** @useSignals */ +function myFunction() { + var _effect = _useSignals("1"); + try { + return regularValue; + } finally { + _effect.f(); + } +} + "# +); + +#[cfg(test)] +mod tests { + use super::*; + use swc_core::{ + common::SyntaxContext, + ecma::{ + ast::{ + BindingIdent, ComputedPropName, Expr, Ident, ImportDecl, ImportNamedSpecifier, + ImportSpecifier, KeyValuePatProp, Lit, MemberExpr, MemberProp, Module, + ModuleDecl, ModuleExportName, ModuleItem, ObjectPat, ObjectPatProp, Pat, + PropName, Str, + }, + utils::quote_ident, + }, + }; + + #[test] + fn test_plugin_creation() { + let options = PluginOptions::default(); + let _visitor = signals_transform(options); + // Basic test to ensure the plugin can be instantiated + assert!(true); + } + + #[test] + fn test_component_name_detection() { + let visitor = signals_transform(PluginOptions::default()); + assert!(visitor.is_component_name("MyComponent")); + assert!(visitor.is_component_name("App")); + assert!(visitor.is_component_name("Button")); + assert!(!visitor.is_component_name("myFunction")); + assert!(!visitor.is_component_name("helper")); + assert!(!visitor.is_component_name("")); + } + + #[test] + fn test_hook_name_detection() { + let visitor = signals_transform(PluginOptions::default()); + assert!(visitor.is_hook_name("useEffect")); + assert!(visitor.is_hook_name("useCustomHook")); + assert!(visitor.is_hook_name("useState")); + assert!(visitor.is_hook_name("useName")); + assert!(visitor.is_hook_name("useGreeting")); + assert!(!visitor.is_hook_name("use")); + assert!(!visitor.is_hook_name("useless")); + assert!(!visitor.is_hook_name("user")); + assert!(!visitor.is_hook_name("")); + } + + #[test] + fn test_value_member_access_detection() { + let visitor = signals_transform(PluginOptions::default()); + + // Test with ident property + let member_expr = MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: "signal".into(), + optional: false, + })), + prop: MemberProp::Ident(quote_ident!("value")), + }; + assert!(visitor.is_value_member_access(&member_expr)); + + // Test with non-value property + let member_expr_non_value = MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: "signal".into(), + optional: false, + })), + prop: MemberProp::Ident(quote_ident!("other")), + }; + assert!(!visitor.is_value_member_access(&member_expr_non_value)); + + // Test with computed property + let member_expr_computed = MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: "signal".into(), + optional: false, + })), + prop: MemberProp::Computed(ComputedPropName { + span: DUMMY_SP, + expr: Box::new(Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: "value".into(), + raw: None, + }))), + }), + }; + assert!(visitor.is_value_member_access(&member_expr_computed)); + } + + #[test] + fn test_value_in_object_pattern_detection() { + let visitor = signals_transform(PluginOptions::default()); + + // Test pattern with value property + let object_pat = ObjectPat { + span: DUMMY_SP, + props: vec![ObjectPatProp::KeyValue(KeyValuePatProp { + key: PropName::Ident(quote_ident!("value")), + value: Box::new(Pat::Ident(BindingIdent { + id: Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: "val".into(), + optional: false, + }, + type_ann: None, + })), + })], + optional: false, + type_ann: None, + }; + assert!(visitor.has_value_in_object_pattern(&object_pat)); + + // Test pattern without value property + let object_pat_no_value = ObjectPat { + span: DUMMY_SP, + props: vec![ObjectPatProp::KeyValue(KeyValuePatProp { + key: PropName::Ident(quote_ident!("other")), + value: Box::new(Pat::Ident(BindingIdent { + id: Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: "val".into(), + optional: false, + }, + type_ann: None, + })), + })], + optional: false, + type_ann: None, + }; + assert!(!visitor.has_value_in_object_pattern(&object_pat_no_value)); + } + + #[test] + fn test_should_transform_logic() { + let visitor = signals_transform(PluginOptions::default()); + + // Test auto mode (default) - component with signals + let info_component_with_signals = FunctionInfo { + name: Some("MyComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: true, + uses_signals: true, + has_opt_in_comment: false, + has_opt_out_comment: false, + }; + assert!(visitor.should_transform(&info_component_with_signals)); + + // Test auto mode - component without signals + let info_component_no_signals = FunctionInfo { + name: Some("MyComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: true, + uses_signals: false, + has_opt_in_comment: false, + has_opt_out_comment: false, + }; + assert!(!visitor.should_transform(&info_component_no_signals)); + + // Test auto mode - hook with signals + let info_hook_with_signals = FunctionInfo { + name: Some("useCustomHook".to_string()), + is_component: false, + is_hook: true, + has_jsx: false, + uses_signals: true, + has_opt_in_comment: false, + has_opt_out_comment: false, + }; + assert!(visitor.should_transform(&info_hook_with_signals)); + + // Test auto mode - hook without signals + let info_hook_no_signals = FunctionInfo { + name: Some("useCustomHook".to_string()), + is_component: false, + is_hook: true, + has_jsx: false, + uses_signals: false, + has_opt_in_comment: false, + has_opt_out_comment: false, + }; + assert!(!visitor.should_transform(&info_hook_no_signals)); + + // Test opt-out comment always prevents transformation + let info_with_opt_out = FunctionInfo { + name: Some("MyComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: true, + uses_signals: true, + has_opt_in_comment: false, + has_opt_out_comment: true, + }; + assert!(!visitor.should_transform(&info_with_opt_out)); + + // Test opt-in comment always enables transformation + let info_with_opt_in = FunctionInfo { + name: Some("myFunction".to_string()), + is_component: false, + is_hook: false, + has_jsx: false, + uses_signals: false, + has_opt_in_comment: true, + has_opt_out_comment: false, + }; + assert!(visitor.should_transform(&info_with_opt_in)); + } + + #[test] + fn test_mode_all() { + let visitor = signals_transform(PluginOptions { + mode: Some("all".to_string()), + ..Default::default() + }); + + // Test "all" mode transforms all components regardless of signal usage + let info_component_no_signals = FunctionInfo { + name: Some("MyComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: true, + uses_signals: false, + has_opt_in_comment: false, + has_opt_out_comment: false, + }; + assert!(visitor.should_transform(&info_component_no_signals)); + + // Test "all" mode doesn't transform non-components + let info_regular_function = FunctionInfo { + name: Some("myFunction".to_string()), + is_component: false, + is_hook: false, + has_jsx: false, + uses_signals: true, + has_opt_in_comment: false, + has_opt_out_comment: false, + }; + assert!(!visitor.should_transform(&info_regular_function)); + } + + #[test] + fn test_mode_manual() { + let visitor = signals_transform(PluginOptions { + mode: Some("manual".to_string()), + ..Default::default() + }); + + // Test "manual" mode only transforms with explicit opt-in + let info_component_with_signals = FunctionInfo { + name: Some("MyComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: true, + uses_signals: true, + has_opt_in_comment: false, + has_opt_out_comment: false, + }; + assert!(!visitor.should_transform(&info_component_with_signals)); + + // Test "manual" mode with opt-in comment + let info_with_opt_in = FunctionInfo { + name: Some("MyComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: true, + uses_signals: true, + has_opt_in_comment: true, + has_opt_out_comment: false, + }; + assert!(visitor.should_transform(&info_with_opt_in)); + } + + #[test] + fn test_jsx_identifiers_detection() { + let mut visitor = signals_transform(PluginOptions { + detect_transformed_jsx: Some(true), + ..Default::default() + }); + + // Test jsx runtime import detection + let module = Module { + span: DUMMY_SP, + body: vec![ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { + span: DUMMY_SP, + specifiers: vec![ImportSpecifier::Named(ImportNamedSpecifier { + span: DUMMY_SP, + local: Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: "jsx".into(), + optional: false, + }, + imported: Some(ModuleExportName::Ident(Ident { + span: DUMMY_SP, + ctxt: SyntaxContext::empty(), + sym: "jsx".into(), + optional: false, + })), + is_type_only: false, + })], + src: Box::new(Str { + span: DUMMY_SP, + value: "react/jsx-runtime".into(), + raw: None, + }), + type_only: false, + with: None, + phase: Default::default(), + }))], + shebang: None, + }; + + visitor.detect_jsx_imports(&module); + assert!(visitor.jsx_identifiers.contains("jsx")); + } + + #[test] + fn test_experimental_no_try_finally_option() { + let visitor = signals_transform(PluginOptions { + experimental: Some(ExperimentalOptions { + no_try_finally: Some(true), + }), + ..Default::default() + }); + + // Verify that experimental option is properly stored + assert_eq!( + visitor.options.experimental.as_ref().unwrap().no_try_finally, + Some(true) + ); + } + + #[test] + fn test_custom_import_source() { + let custom_source = "custom-signals-runtime"; + let visitor = signals_transform(PluginOptions { + import_source: Some(custom_source.to_string()), + ..Default::default() + }); + + assert_eq!(visitor.options.import_source.as_deref(), Some(custom_source)); + } + + #[test] + fn test_function_info_initialization() { + let info = FunctionInfo { + name: Some("TestComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: false, + uses_signals: false, + has_opt_in_comment: false, + has_opt_out_comment: false, + }; + + assert_eq!(info.name, Some("TestComponent".to_string())); + assert!(info.is_component); + assert!(!info.is_hook); + assert!(!info.has_jsx); + assert!(!info.uses_signals); + assert!(!info.has_opt_in_comment); + assert!(!info.has_opt_out_comment); + } + + #[test] + fn test_import_name_constant() { + assert_eq!(IMPORT_NAME, "useSignals"); + assert_eq!(DEFAULT_IMPORT_SOURCE, "@preact/signals-react/runtime"); + } + + #[test] + fn test_opt_out_comment_regex() { + let regex = &*OPT_OUT_COMMENT; + + // Test valid opt-out patterns + assert!(regex.is_match("@noUseSignals")); + assert!(regex.is_match("@noTrackSignals")); + assert!(regex.is_match(" @noUseSignals ")); + assert!(regex.is_match(" @noTrackSignals ")); + assert!(regex.is_match("some text @noUseSignals")); + assert!(regex.is_match("@noUseSignals and more text")); + + // Test invalid patterns + assert!(!regex.is_match("@noSignals")); + assert!(!regex.is_match("@noUse")); + assert!(!regex.is_match("noUseSignals")); + assert!(!regex.is_match("@useSignals")); + } + + #[test] + fn test_opt_in_comment_regex() { + let regex = &*OPT_IN_COMMENT; + + // Test valid opt-in patterns + assert!(regex.is_match("@useSignals")); + assert!(regex.is_match("@trackSignals")); + assert!(regex.is_match(" @useSignals ")); + assert!(regex.is_match(" @trackSignals ")); + assert!(regex.is_match("some text @useSignals")); + assert!(regex.is_match("@trackSignals and more text")); + + // Test invalid patterns + assert!(!regex.is_match("@signals")); + assert!(!regex.is_match("@use")); + assert!(!regex.is_match("useSignals")); + assert!(!regex.is_match("@noUseSignals")); + } + + #[test] + fn test_opt_out_comment_overrides_transform() { + let visitor = signals_transform(PluginOptions::default()); + + // Test that opt-out comment prevents transformation even for component with signals + let info_with_opt_out = FunctionInfo { + name: Some("MyComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: true, + uses_signals: true, + has_opt_in_comment: false, + has_opt_out_comment: true, + }; + assert!(!visitor.should_transform(&info_with_opt_out)); + + // Test that opt-out comment prevents transformation even in "all" mode + let visitor_all = signals_transform(PluginOptions { + mode: Some("all".to_string()), + ..Default::default() + }); + assert!(!visitor_all.should_transform(&info_with_opt_out)); + } + + #[test] + fn test_opt_in_comment_enables_transform() { + let visitor = signals_transform(PluginOptions::default()); + + // Test that opt-in comment enables transformation for non-component + let info_with_opt_in = FunctionInfo { + name: Some("myFunction".to_string()), + is_component: false, + is_hook: false, + has_jsx: false, + uses_signals: false, + has_opt_in_comment: true, + has_opt_out_comment: false, + }; + assert!(visitor.should_transform(&info_with_opt_in)); + + // Test that opt-in comment works in "manual" mode + let visitor_manual = signals_transform(PluginOptions { + mode: Some("manual".to_string()), + ..Default::default() + }); + assert!(visitor_manual.should_transform(&info_with_opt_in)); + } + + #[test] + fn test_opt_out_takes_precedence_over_opt_in() { + let visitor = signals_transform(PluginOptions::default()); + + // Test that opt-out comment takes precedence when both are present + let info_both_comments = FunctionInfo { + name: Some("MyComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: true, + uses_signals: true, + has_opt_in_comment: true, + has_opt_out_comment: true, + }; + assert!(!visitor.should_transform(&info_both_comments)); + } + + #[test] + fn test_comment_functionality_integration() { + // Test opt-out comment integration + let visitor = signals_transform(PluginOptions::default()); + + let info_with_opt_out = FunctionInfo { + name: Some("MyComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: true, + uses_signals: true, + has_opt_in_comment: false, + has_opt_out_comment: true, + }; + + assert!(!visitor.should_transform(&info_with_opt_out), "Opt-out comment should prevent transformation"); + + // Test opt-in comment integration + let visitor_manual = signals_transform(PluginOptions { + mode: Some("manual".to_string()), + ..Default::default() + }); + + let info_with_opt_in = FunctionInfo { + name: Some("myFunction".to_string()), + is_component: false, + is_hook: false, + has_jsx: false, + uses_signals: false, + has_opt_in_comment: true, + has_opt_out_comment: false, + }; + + assert!(visitor_manual.should_transform(&info_with_opt_in), "Opt-in comment should enable transformation"); + + // Test comment precedence integration + let info_both_comments = FunctionInfo { + name: Some("MyComponent".to_string()), + is_component: true, + is_hook: false, + has_jsx: true, + uses_signals: true, + has_opt_in_comment: true, + has_opt_out_comment: true, + }; + + assert!(!visitor.should_transform(&info_both_comments), "Opt-out should take precedence over opt-in"); + } + + #[test] + fn test_comment_regex_patterns_advanced() { + // Test opt-out patterns with various formats + assert!(OPT_OUT_COMMENT.is_match("@noUseSignals")); + assert!(OPT_OUT_COMMENT.is_match("@noTrackSignals")); + assert!(OPT_OUT_COMMENT.is_match(" @noUseSignals ")); + assert!(OPT_OUT_COMMENT.is_match("/** @noUseSignals */")); + assert!(OPT_OUT_COMMENT.is_match("// @noTrackSignals")); + assert!(OPT_OUT_COMMENT.is_match("some text @noUseSignals more text")); + assert!(!OPT_OUT_COMMENT.is_match("@useSignals")); + assert!(!OPT_OUT_COMMENT.is_match("@noSignals")); + assert!(!OPT_OUT_COMMENT.is_match("noUseSignals")); + + // Test opt-in patterns with various formats + assert!(OPT_IN_COMMENT.is_match("@useSignals")); + assert!(OPT_IN_COMMENT.is_match("@trackSignals")); + assert!(OPT_IN_COMMENT.is_match(" @useSignals ")); + assert!(OPT_IN_COMMENT.is_match("/** @useSignals */")); + assert!(OPT_IN_COMMENT.is_match("// @trackSignals")); + assert!(OPT_IN_COMMENT.is_match("some text @useSignals more text")); + assert!(!OPT_IN_COMMENT.is_match("@noUseSignals")); + assert!(!OPT_IN_COMMENT.is_match("@signals")); + assert!(!OPT_IN_COMMENT.is_match("useSignals")); + } +}