From f306a1b9c449c6a0bd37d13cb4c176d8d96239f8 Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Thu, 31 Oct 2024 13:47:01 -0700 Subject: [PATCH 1/2] Strip hygiene code in favor of UUIDs --- Cargo.lock | 28 ++++++---- Cargo.toml | 8 +++ src/lib.rs | 127 ++++++++++++-------------------------------- src/test_helpers.rs | 7 ++- 4 files changed, 63 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 571c733..929ca30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -283,6 +283,7 @@ dependencies = [ "difference", "js-sys", "lazy_static", + "regex", "serde", "serde-wasm-bindgen", "serde_json", @@ -297,6 +298,7 @@ dependencies = [ "swc_ecma_utils", "swc_ecma_visit", "swc_error_reporters", + "uuid", "wasm-bindgen", ] @@ -1207,14 +1209,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.9", - "regex-syntax 0.7.5", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -1228,13 +1230,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.5", ] [[package]] @@ -1245,9 +1247,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" @@ -2585,9 +2587,13 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +dependencies = [ + "getrandom", + "rand", +] [[package]] name = "valuable" diff --git a/Cargo.toml b/Cargo.toml index b0f838a..2f329cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,8 +40,16 @@ serde-wasm-bindgen = "0.4" wasm-bindgen = "0.2.95" js-sys = "0.3.64" +[dependencies.uuid] +version = "1.11.0" +features = [ + "v4", # Lets you generate random UUIDs + "fast-rng" # Use a faster (but still sufficiently random) RNG +] + [dev-dependencies] difference = "2" +regex = "1.11.1" diff --git a/src/lib.rs b/src/lib.rs index 295b09e..96701a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,10 +15,10 @@ use swc_ecma_ast::{ }; use swc_ecma_codegen::Emitter; use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax, TsConfig}; -use swc_ecma_transforms::hygiene::hygiene_with_config; use swc_ecma_transforms::resolver; use swc_ecma_utils::private_ident; use swc_ecma_visit::{as_folder, VisitMutWith, VisitWith}; +use uuid::Uuid; mod bindings; mod snippets; @@ -116,16 +116,14 @@ impl Preprocessor { GLOBALS.set(&Default::default(), || { let mut parsed_module = parser.parse_module()?; - let found_id = find_existing_import(&parsed_module, target_module, target_specifier); - let had_id_already = found_id.is_some(); - let id = found_id.unwrap_or_else(|| private_ident!(target_specifier)); + let id = private_ident!(format!("{}_{}", target_specifier, Uuid::new_v4().to_string().replace("-", ""))); let mut needs_import = false; parsed_module.visit_mut_with(&mut as_folder(transform::TransformVisitor::new( &id, Some(&mut needs_import), ))); - if !had_id_already && needs_import { + if needs_import { insert_import(&mut parsed_module, target_module, target_specifier, &id) } @@ -134,16 +132,6 @@ impl Preprocessor { parsed_module.visit_mut_with(&mut resolver(unresolved_mark, top_level_mark, false)); - let mut h = hygiene_with_config(swc_ecma_transforms::hygiene::Config { - keep_class_names: true, - top_level_mark, - safari_10: false, - ignore_eval: false, - }); - parsed_module.visit_mut_with(&mut h); - - simplify_imports(&mut parsed_module); - Ok(self.print(&parsed_module, options.inline_source_map)) }) } @@ -192,38 +180,6 @@ impl Preprocessor { } } -fn find_existing_import( - parsed_module: &Module, - target_module: &str, - target_specifier: &str, -) -> Option { - for item in parsed_module.body.iter() { - match item { - ModuleItem::ModuleDecl(ModuleDecl::Import(import_declaration)) => { - if import_declaration.src.value.to_string() == target_module { - for specifier in import_declaration.specifiers.iter() { - match specifier { - ImportSpecifier::Named(s) => { - let imported = match &s.imported { - Some(ModuleExportName::Ident(i)) => i.sym.to_string(), - Some(ModuleExportName::Str(s)) => s.value.to_string(), - None => s.local.sym.to_string(), - }; - if imported == target_specifier { - return Some(s.local.clone()); - } - } - _ => {} - } - } - } - } - _ => {} - } - } - None -} - fn insert_import( parsed_module: &mut Module, target_module: &str, @@ -250,39 +206,6 @@ fn insert_import( ); } -// It's not until after the hygiene pass that we know what local name is being -// used for our import. If it turns out to equal the imported name, we can -// implify from "import { template as template } from..." down to "import { -// template } from ...". -fn simplify_imports(parsed_module: &mut Module) { - for item in parsed_module.body.iter_mut() { - match item { - ModuleItem::ModuleDecl(ModuleDecl::Import(import_declaration)) => { - for specifier in import_declaration.specifiers.iter_mut() { - match specifier { - ImportSpecifier::Named(specifier) => { - if let ImportNamedSpecifier { - imported: Some(ModuleExportName::Ident(imported)), - local, - .. - } = specifier - { - if local.sym == imported.sym { - specifier.imported = None; - } - } - } - _ => {} - } - } - } - _ => {} - } - } -} - - - #[cfg(test)] mod test_helpers; @@ -299,24 +222,26 @@ macro_rules! testcase { testcase! { no_preexisting_import, r#"let x = "#, - r#"import { template } from "@ember/template-compiler"; - let x = template(`hello`, { eval() { return eval(arguments[0])} });"# + r#"import { template as template_UUID } from "@ember/template-compiler"; + let x = template_UUID(`hello`, { eval() { return eval(arguments[0])} });"# } testcase! { - uses_preexisting_import, + preexisting_import, r#"import { template } from "@ember/template-compiler"; let x = "#, - r#"import { template } from "@ember/template-compiler"; - let x = template(`hello`, { eval() { return eval(arguments[0])} });"# + r#"import { template as template_UUID } from "@ember/template-compiler"; + import { template } from "@ember/template-compiler"; + let x = template_UUID(`hello`, { eval() { return eval(arguments[0])} });"# } testcase! { - uses_preexisting_renamed_import, + preexisting_renamed_import, r#"import { template as t } from "@ember/template-compiler"; let x = "#, - r#"import { template as t } from "@ember/template-compiler"; - let x = t(`hello`, { eval() { return eval(arguments[0])} })"# + r#"import { template as template_UUID } from "@ember/template-compiler"; + import { template as t } from "@ember/template-compiler"; + let x = template_UUID(`hello`, { eval() { return eval(arguments[0])} })"# } testcase! { @@ -330,10 +255,10 @@ testcase! { r#"function template() {}; console.log(template()); export default "#, - r#"import { template as template1 } from "@ember/template-compiler"; + r#"import { template as template_UUID } from "@ember/template-compiler"; function template() {}; console.log(template()); - export default template1(`Hi`, { eval() { return eval(arguments[0])} });"# + export default template_UUID(`Hi`, { eval() { return eval(arguments[0])} });"# } testcase! { @@ -342,10 +267,10 @@ testcase! { console.log(template); return ; };"#, - r#"import { template as template1 } from "@ember/template-compiler"; + r#"import { template as template_UUID } from "@ember/template-compiler"; export default function(template) { console.log(template); - return template1(`X`, { eval() { return eval(arguments[0])} }); + return template_UUID(`X`, { eval() { return eval(arguments[0])} }); };"# } @@ -355,9 +280,23 @@ testcase! { console.log(message); return }"#, - r#"import { template } from "@ember/template-compiler"; + r#"import { template as template_UUID } from "@ember/template-compiler"; function makeComponent(message: string) { console.log(message); - return template(`hello`, { eval() { return eval(arguments[0]) } }); + return template_UUID(`hello`, { eval() { return eval(arguments[0]) } }); + }"# +} + +testcase! { + handles_typescript_this, + r#"function f(this: Context, ...args: unknown[]) { + function t(this: Context, ...args: unknown[]) {}; + return + }"#, + r#"import { template as template_UUID } from "@ember/template-compiler"; + function f(this: Context, ...args: unknown[]) { + function t(this: Context, ...args: unknown[]) {} + ; + return template_UUID(``, { eval() { return eval(arguments[0]) } }); }"# } diff --git a/src/test_helpers.rs b/src/test_helpers.rs index 0798bca..0c85c97 100644 --- a/src/test_helpers.rs +++ b/src/test_helpers.rs @@ -1,4 +1,5 @@ use difference::Changeset; +use regex::Regex; use swc_common::comments::SingleThreadedComments; use swc_common::{self, sync::Lrc, FileName, SourceMap}; use swc_ecma_codegen::Emitter; @@ -7,13 +8,15 @@ use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax, TsConfig}; use crate::Preprocessor; pub fn testcase(input: &str, expected: &str) -> Result<(), swc_ecma_parser::error::Error> { + let re = Regex::new(r"template_[0-9a-f]{32}").unwrap(); let p = Preprocessor::new(); let actual = p.process(input, Default::default())?; + let actual_santized = re.replace_all(&actual, "template_UUID"); let normalized_expected = normalize(expected); - if actual != normalized_expected { + if actual_santized != normalized_expected { panic!( "code differs from expected:\n{}", - format!("{}", Changeset::new(&actual, &normalized_expected, "\n")) + format!("{}", Changeset::new(&actual_santized, &normalized_expected, "\n")) ); } Ok(()) From 8d8cb16e0f26d16ab1dd5939530fa188290d26c3 Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Thu, 31 Oct 2024 14:09:36 -0700 Subject: [PATCH 2/2] Fix node tests --- test/process.test.js | 20 ++++++++++++-------- test/require.test.cjs | 10 +++++++--- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/test/process.test.js b/test/process.test.js index e1d70de..76df479 100644 --- a/test/process.test.js +++ b/test/process.test.js @@ -8,13 +8,17 @@ const { expect } = chai; const p = new Preprocessor(); +function normalizeOutput(output) { + return output.replace(/template_[0-9a-f]{32}/g, "template_UUID"); +} + describe(`process`, function () { it("works for a basic example", function () { let output = p.process(""); - expect(output).to - .equalCode(`import { template } from "@ember/template-compiler"; - export default template(\`Hi\`, { + expect(normalizeOutput(output)).to + .equalCode(`import { template as template_UUID } from "@ember/template-compiler"; + export default template_UUID(\`Hi\`, { eval () { return eval(arguments[0]); } @@ -32,12 +36,12 @@ describe(`process`, function () { let output = p.process(input); - expect(output).to.equalCode( - `import { template } from "@ember/template-compiler"; - let Foo = class Foo extends Component { + expect(normalizeOutput(output)).to.equalCode( + `import { template as template_UUID } from "@ember/template-compiler"; + class Foo extends Component { greeting = 'Hello'; static{ - template(\`{{this.greeting}}, \\\`lifeform\\\`!\`, { + template_UUID(\`{{this.greeting}}, \\\`lifeform\\\`!\`, { component: this, eval () { return eval(arguments[0]); @@ -94,7 +98,7 @@ describe(`process`, function () { let output = p.process(``, { inline_source_map: true }); expect(output).to.match( - /sourceMappingURL=data:application\/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyI8dGVtcGxhdGU-SGk8L3RlbXBsYXRlPiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsZUFBQSxTQUFVLENBQUEsRUFBRSxDQUFBLEVBQUE7SUFBQTtRQUFBLE9BQUEsS0FBQSxTQUFBLENBQUEsRUFBVztJQUFEO0FBQUEsR0FBQyJ9/ + /sourceMappingURL=data:application\/json;base64,/ ); }); }); diff --git a/test/require.test.cjs b/test/require.test.cjs index efdf9ba..50de3e7 100644 --- a/test/require.test.cjs +++ b/test/require.test.cjs @@ -9,13 +9,17 @@ const { Preprocessor } = require("content-tag"); const p = new Preprocessor(); +function normalizeOutput(output) { + return output.replace(/template_[0-9a-f]{32}/g, "template_UUID"); +} + describe("cjs/require", function () { it("can call process", function () { let output = p.process(""); - expect(output).to - .equalCode(`import { template } from "@ember/template-compiler"; - export default template(\`Hi\`, { + expect(normalizeOutput(output)).to + .equalCode(`import { template as template_UUID } from "@ember/template-compiler"; + export default template_UUID(\`Hi\`, { eval () { return eval(arguments[0]); }