diff --git a/Cargo.lock b/Cargo.lock index f2ed4730e3b..fe07ed002da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2305,7 +2305,7 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "swc" -version = "0.63.1" +version = "0.64.0" dependencies = [ "ahash", "anyhow", @@ -2410,7 +2410,7 @@ dependencies = [ [[package]] name = "swc_bundler" -version = "0.65.0" +version = "0.66.0" dependencies = [ "ahash", "anyhow", @@ -2650,7 +2650,7 @@ dependencies = [ [[package]] name = "swc_ecma_minifier" -version = "0.34.2" +version = "0.35.0" dependencies = [ "ansi_term 0.12.1", "anyhow", @@ -2708,7 +2708,7 @@ dependencies = [ [[package]] name = "swc_ecma_preset_env" -version = "0.49.0" +version = "0.50.0" dependencies = [ "dashmap", "indexmap", @@ -2734,7 +2734,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms" -version = "0.78.0" +version = "0.79.0" dependencies = [ "pretty_assertions 0.6.1", "sourcemap", @@ -2851,7 +2851,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_optimization" -version = "0.48.0" +version = "0.49.0" dependencies = [ "dashmap", "indexmap", @@ -2903,7 +2903,7 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "0.45.0" +version = "0.46.0" dependencies = [ "base64 0.13.0", "dashmap", @@ -2995,7 +2995,7 @@ dependencies = [ [[package]] name = "swc_ecmascript" -version = "0.70.0" +version = "0.71.0" dependencies = [ "swc_ecma_ast", "swc_ecma_codegen", diff --git a/Cargo.toml b/Cargo.toml index 4642b018c23..6233b92fbd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ edition = "2018" license = "Apache-2.0/MIT" name = "swc" repository = "https://github.com/swc-project/swc.git" -version = "0.63.1" +version = "0.64.0" [lib] name = "swc" @@ -52,16 +52,16 @@ serde = {version = "1", features = ["derive"]} serde_json = "1" sourcemap = "6" swc_atoms = {version = "0.2", path = "./atoms"} -swc_bundler = {version = "0.65.0", path = "./bundler"} +swc_bundler = {version = "0.66.0", path = "./bundler"} swc_common = {version = "0.13.0", path = "./common", features = ["sourcemap", "concurrent"]} swc_ecma_ast = {version = "0.54.0", path = "./ecmascript/ast"} swc_ecma_codegen = {version = "0.74.0", path = "./ecmascript/codegen"} swc_ecma_ext_transforms = {version = "0.31.0", path = "./ecmascript/ext-transforms"} swc_ecma_loader = {version = "0.20.0", path = "./ecmascript/loader", features = ["lru", "node", "tsc"]} -swc_ecma_minifier = {version = "0.34.0", path = "./ecmascript/minifier"} +swc_ecma_minifier = {version = "0.35.0", path = "./ecmascript/minifier"} swc_ecma_parser = {version = "0.73.0", path = "./ecmascript/parser"} -swc_ecma_preset_env = {version = "0.49.0", path = "./ecmascript/preset-env"} -swc_ecma_transforms = {version = "0.78.0", path = "./ecmascript/transforms", features = [ +swc_ecma_preset_env = {version = "0.50.0", path = "./ecmascript/preset-env"} +swc_ecma_transforms = {version = "0.79.0", path = "./ecmascript/transforms", features = [ "compat", "module", "optimization", @@ -72,7 +72,7 @@ swc_ecma_transforms = {version = "0.78.0", path = "./ecmascript/transforms", fea swc_ecma_transforms_base = {version = "0.35.0", path = "./ecmascript/transforms/base"} swc_ecma_utils = {version = "0.46.0", path = "./ecmascript/utils"} swc_ecma_visit = {version = "0.40.0", path = "./ecmascript/visit"} -swc_ecmascript = {version = "0.70.0", path = "./ecmascript"} +swc_ecmascript = {version = "0.71.0", path = "./ecmascript"} swc_visit = {version = "0.2.3", path = "./visit"} tracing = "0.1.28" diff --git a/bundler/Cargo.toml b/bundler/Cargo.toml index a268a131226..c2778fdd9ea 100644 --- a/bundler/Cargo.toml +++ b/bundler/Cargo.toml @@ -9,7 +9,7 @@ include = ["Cargo.toml", "build.rs", "src/**/*.rs", "src/**/*.js"] license = "Apache-2.0/MIT" name = "swc_bundler" repository = "https://github.com/swc-project/swc.git" -version = "0.65.0" +version = "0.66.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] @@ -36,7 +36,7 @@ swc_ecma_ast = {version = "0.54.0", path = "../ecmascript/ast"} swc_ecma_codegen = {version = "0.74.0", path = "../ecmascript/codegen"} swc_ecma_loader = {version = "0.20.0", path = "../ecmascript/loader"} swc_ecma_parser = {version = "0.73.0", path = "../ecmascript/parser"} -swc_ecma_transforms = {version = "0.78.0", path = "../ecmascript/transforms", features = ["optimization"]} +swc_ecma_transforms = {version = "0.79.0", path = "../ecmascript/transforms", features = ["optimization"]} swc_ecma_utils = {version = "0.46.0", path = "../ecmascript/utils"} swc_ecma_visit = {version = "0.40.0", path = "../ecmascript/visit"} tracing = "0.1.28" @@ -46,7 +46,7 @@ hex = "0.4" ntest = "0.7.2" reqwest = {version = "0.11.4", features = ["blocking"]} sha-1 = "0.9" -swc_ecma_transforms = {version = "0.78.0", path = "../ecmascript/transforms", features = ["react", "typescript"]} +swc_ecma_transforms = {version = "0.79.0", path = "../ecmascript/transforms", features = ["react", "typescript"]} tempfile = "3.1.0" testing = {version = "0.14.0", path = "../testing"} url = "2.1.1" diff --git a/bundler/tests/common/mod.rs b/bundler/tests/common/mod.rs index 56999063a1f..192e6620d47 100644 --- a/bundler/tests/common/mod.rs +++ b/bundler/tests/common/mod.rs @@ -12,7 +12,7 @@ use swc_common::{ comments::SingleThreadedComments, errors::{ColorConfig, Handler}, sync::Lrc, - FileName, SourceMap, + FileName, Mark, SourceMap, }; use swc_ecma_parser::{lexer::Lexer, JscTarget, Parser, StringInput, Syntax, TsConfig}; use swc_ecma_transforms::{react, typescript::strip}; @@ -83,6 +83,8 @@ impl Load for Loader { fn load(&self, f: &FileName) -> Result { eprintln!("load: {}", f); + let top_level_mark = Mark::fresh(Mark::root()); + let tsx; let fm = match f { FileName::Real(path) => { @@ -129,6 +131,7 @@ impl Load for Loader { self.cm.clone(), None, Default::default(), + top_level_mark, )); Ok(ModuleData { diff --git a/ecmascript/Cargo.toml b/ecmascript/Cargo.toml index d283169c956..20ec54b1bcb 100644 --- a/ecmascript/Cargo.toml +++ b/ecmascript/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" license = "Apache-2.0/MIT" name = "swc_ecmascript" repository = "https://github.com/swc-project/swc.git" -version = "0.70.0" +version = "0.71.0" [package.metadata.docs.rs] all-features = true @@ -35,10 +35,10 @@ typescript = ["typescript-parser", "swc_ecma_transforms/typescript"] swc_ecma_ast = {version = "0.54.0", path = "./ast"} swc_ecma_codegen = {version = "0.74.0", path = "./codegen", optional = true} swc_ecma_dep_graph = {version = "0.42.0", path = "./dep-graph", optional = true} -swc_ecma_minifier = {version = "0.34.0", path = "./minifier", optional = true} +swc_ecma_minifier = {version = "0.35.0", path = "./minifier", optional = true} swc_ecma_parser = {version = "0.73.0", path = "./parser", optional = true, default-features = false} -swc_ecma_preset_env = {version = "0.49.0", path = "./preset-env", optional = true} -swc_ecma_transforms = {version = "0.78.0", path = "./transforms", optional = true} +swc_ecma_preset_env = {version = "0.50.0", path = "./preset-env", optional = true} +swc_ecma_transforms = {version = "0.79.0", path = "./transforms", optional = true} swc_ecma_utils = {version = "0.46.0", path = "./utils", optional = true} swc_ecma_visit = {version = "0.40.0", path = "./visit", optional = true} diff --git a/ecmascript/minifier/Cargo.toml b/ecmascript/minifier/Cargo.toml index 30643d755cd..57ca96c0b33 100644 --- a/ecmascript/minifier/Cargo.toml +++ b/ecmascript/minifier/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/lists/*.json"] license = "Apache-2.0/MIT" name = "swc_ecma_minifier" repository = "https://github.com/swc-project/swc.git" -version = "0.34.2" +version = "0.35.0" [features] debug = ["backtrace"] @@ -29,7 +29,7 @@ swc_common = {version = "0.13.0", path = "../../common"} swc_ecma_ast = {version = "0.54.0", path = "../ast"} swc_ecma_codegen = {version = "0.74.0", path = "../codegen"} swc_ecma_parser = {version = "0.73.0", path = "../parser"} -swc_ecma_transforms = {version = "0.78.0", path = "../transforms/", features = ["optimization"]} +swc_ecma_transforms = {version = "0.79.0", path = "../transforms/", features = ["optimization"]} swc_ecma_transforms_base = {version = "0.35.0", path = "../transforms/base"} swc_ecma_utils = {version = "0.46.0", path = "../utils"} swc_ecma_visit = {version = "0.40.0", path = "../visit"} diff --git a/ecmascript/preset-env/Cargo.toml b/ecmascript/preset-env/Cargo.toml index 183f2092c5f..07eba89d0ef 100644 --- a/ecmascript/preset-env/Cargo.toml +++ b/ecmascript/preset-env/Cargo.toml @@ -5,7 +5,7 @@ documentation = "https://rustdoc.swc.rs/swc_ecma_preset_env/" edition = "2018" license = "Apache-2.0/MIT" name = "swc_ecma_preset_env" -version = "0.49.0" +version = "0.50.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -22,7 +22,7 @@ string_enum = {version = "0.3.1", path = "../../macros/string_enum"} swc_atoms = {version = "0.2", path = "../../atoms"} swc_common = {version = "0.13.0", path = "../../common"} swc_ecma_ast = {version = "0.54.0", path = "../ast"} -swc_ecma_transforms = {version = "0.78.0", path = "../transforms", features = ["compat", "proposal"]} +swc_ecma_transforms = {version = "0.79.0", path = "../transforms", features = ["compat", "proposal"]} swc_ecma_utils = {version = "0.46.0", path = "../utils"} swc_ecma_visit = {version = "0.40.0", path = "../visit"} walkdir = "2" diff --git a/ecmascript/transforms/Cargo.toml b/ecmascript/transforms/Cargo.toml index 7423a513f5e..08541732df9 100644 --- a/ecmascript/transforms/Cargo.toml +++ b/ecmascript/transforms/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" license = "Apache-2.0/MIT" name = "swc_ecma_transforms" repository = "https://github.com/swc-project/swc.git" -version = "0.78.0" +version = "0.79.0" [package.metadata.docs.rs] all-features = true @@ -28,9 +28,9 @@ swc_ecma_parser = {version = "0.73.0", path = "../parser"} swc_ecma_transforms_base = {version = "0.35.0", path = "./base"} swc_ecma_transforms_compat = {version = "0.40.0", path = "./compat", optional = true} swc_ecma_transforms_module = {version = "0.44.0", path = "./module", optional = true} -swc_ecma_transforms_optimization = {version = "0.48.0", path = "./optimization", optional = true} +swc_ecma_transforms_optimization = {version = "0.49.0", path = "./optimization", optional = true} swc_ecma_transforms_proposal = {version = "0.44.0", path = "./proposal", optional = true} -swc_ecma_transforms_react = {version = "0.45.0", path = "./react", optional = true} +swc_ecma_transforms_react = {version = "0.46.0", path = "./react", optional = true} swc_ecma_transforms_typescript = {version = "0.46.0", path = "./typescript", optional = true} swc_ecma_utils = {version = "0.46.0", path = "../utils"} swc_ecma_visit = {version = "0.40.0", path = "../visit"} diff --git a/ecmascript/transforms/module/src/util.rs b/ecmascript/transforms/module/src/util.rs index 1a088198861..a695d6016c0 100644 --- a/ecmascript/transforms/module/src/util.rs +++ b/ecmascript/transforms/module/src/util.rs @@ -14,12 +14,12 @@ use swc_atoms::{js_word, JsWord}; use swc_common::{ collections::{AHashMap, AHashSet}, util::take::Take, - FileName, Mark, Span, SyntaxContext, DUMMY_SP, + FileName, Mark, Span, DUMMY_SP, }; use swc_ecma_ast::*; use swc_ecma_utils::{ ident::IdentLike, member_expr, private_ident, quote_ident, quote_str, undefined, - DestructuringFinder, ExprFactory, + DestructuringFinder, ExprFactory, Id, }; use swc_ecma_visit::{Fold, FoldWith, VisitWith}; @@ -115,10 +115,10 @@ pub struct Scope { /// /// - `import foo from 'bar';` /// -> `{foo: ('bar', default)}` - pub(crate) idents: FxHashMap<(JsWord, SyntaxContext), (JsWord, JsWord)>, + pub(crate) idents: FxHashMap, /// Declared variables except const. - pub(crate) declared_vars: Vec<(JsWord, SyntaxContext)>, + pub(crate) declared_vars: Vec, /// Maps of exported variables. /// @@ -129,7 +129,7 @@ pub struct Scope { /// /// - `export { a as b }` /// -> `{ a: [b] }` - pub(crate) exported_vars: AHashMap<(JsWord, SyntaxContext), Vec<(JsWord, SyntaxContext)>>, + pub(crate) exported_vars: AHashMap>, /// This is required to handle /// `export * from 'foo';` diff --git a/ecmascript/transforms/optimization/Cargo.toml b/ecmascript/transforms/optimization/Cargo.toml index 4a46a9e448a..adb6bc86e7b 100644 --- a/ecmascript/transforms/optimization/Cargo.toml +++ b/ecmascript/transforms/optimization/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" license = "Apache-2.0/MIT" name = "swc_ecma_transforms_optimization" repository = "https://github.com/swc-project/swc.git" -version = "0.48.0" +version = "0.49.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] @@ -29,7 +29,7 @@ tracing = "0.1.28" swc_ecma_transforms_compat = {version = "0.40.0", path = "../compat"} swc_ecma_transforms_module = {version = "0.44.0", path = "../module"} swc_ecma_transforms_proposal = {version = "0.44.0", path = "../proposal"} -swc_ecma_transforms_react = {version = "0.45.0", path = "../react"} +swc_ecma_transforms_react = {version = "0.46.0", path = "../react"} swc_ecma_transforms_testing = {version = "0.36.0", path = "../testing"} swc_ecma_transforms_typescript = {version = "0.46.0", path = "../typescript"} testing = {version = "0.14.0", path = "../../../testing"} diff --git a/ecmascript/transforms/react/Cargo.toml b/ecmascript/transforms/react/Cargo.toml index abe9a2e0d1c..7adbce30c48 100644 --- a/ecmascript/transforms/react/Cargo.toml +++ b/ecmascript/transforms/react/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"] license = "Apache-2.0/MIT" name = "swc_ecma_transforms_react" repository = "https://github.com/swc-project/swc.git" -version = "0.45.0" +version = "0.46.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/ecmascript/transforms/react/src/jsx/mod.rs b/ecmascript/transforms/react/src/jsx/mod.rs index 139a9a579f7..9b48c1f99d8 100644 --- a/ecmascript/transforms/react/src/jsx/mod.rs +++ b/ecmascript/transforms/react/src/jsx/mod.rs @@ -1,4 +1,5 @@ use self::static_check::should_use_create_element; +use crate::refresh::options::{deserialize_refresh, RefreshOptions}; use dashmap::DashMap; use once_cell::sync::Lazy; use regex::Regex; @@ -11,7 +12,7 @@ use swc_common::{ iter::IdentifyLast, sync::Lrc, util::take::Take, - FileName, SourceMap, Spanned, DUMMY_SP, + FileName, Mark, SourceMap, Spanned, DUMMY_SP, }; use swc_ecma_ast::*; use swc_ecma_parser::{Parser, StringInput, Syntax}; @@ -21,8 +22,6 @@ use swc_ecma_utils::{ }; use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith}; -use crate::refresh::options::{deserialize_refresh, RefreshOptions}; - mod static_check; #[cfg(test)] mod tests; @@ -116,15 +115,21 @@ fn default_throw_if_namespace() -> bool { true } -fn parse_classic_option(cm: &SourceMap, name: &str, src: String) -> Box { - static CACHE: Lazy>> = Lazy::new(|| DashMap::with_capacity(2)); +fn parse_classic_option( + cm: &SourceMap, + name: &str, + src: String, + top_level_mark: Mark, +) -> Box { + static CACHE: Lazy>> = + Lazy::new(|| DashMap::with_capacity(2)); let fm = cm.new_source_file(FileName::Custom(format!("", name)), src); - if let Some(expr) = CACHE.get(&**fm.src) { + if let Some(expr) = CACHE.get(&((*fm.src).clone(), top_level_mark)) { return expr.clone(); } - let expr = Parser::new(Syntax::default(), StringInput::from(&*fm), None) + let mut expr = Parser::new(Syntax::default(), StringInput::from(&*fm), None) .parse_expr() .map_err(|e| { if HANDLER.is_set() { @@ -139,20 +144,46 @@ fn parse_classic_option(cm: &SourceMap, name: &str, src: String) -> Box { ) }); - CACHE.insert((*fm.src).clone(), expr.clone()); + apply_mark(&mut expr, top_level_mark); + CACHE.insert(((*fm.src).clone(), top_level_mark), expr.clone()); expr } +fn apply_mark(e: &mut Expr, mark: Mark) { + match e { + Expr::Ident(i) => { + i.span = i.span.apply_mark(mark); + } + Expr::Member(MemberExpr { + obj: ExprOrSuper::Expr(obj), + .. + }) => { + apply_mark(&mut **obj, mark); + } + _ => {} + } +} + /// `@babel/plugin-transform-react-jsx` /// /// Turn JSX into React function calls -pub fn jsx(cm: Lrc, comments: Option, options: Options) -> impl Fold + VisitMut +/// +/// +/// `top_level_mark` should be [Mark] passed to +/// [swc_ecma_transforms_base::resolver::resolver_with_mark]. +pub fn jsx( + cm: Lrc, + comments: Option, + options: Options, + top_level_mark: Mark, +) -> impl Fold + VisitMut where C: Comments, { as_folder(Jsx { cm: cm.clone(), + top_level_mark, next: options.next, runtime: options.runtime.unwrap_or_default(), import_source: options.import_source.into(), @@ -161,11 +192,16 @@ where import_fragment: None, import_create_element: None, - pragma: ExprOrSuper::Expr(parse_classic_option(&cm, "pragma", options.pragma)), + pragma: ExprOrSuper::Expr(parse_classic_option( + &cm, + "pragma", + options.pragma, + top_level_mark, + )), comments, pragma_frag: ExprOrSpread { spread: None, - expr: parse_classic_option(&cm, "pragmaFrag", options.pragma_frag), + expr: parse_classic_option(&cm, "pragmaFrag", options.pragma_frag, top_level_mark), }, use_builtins: options.use_builtins, use_spread: options.use_spread, @@ -180,6 +216,8 @@ where { cm: Lrc, + top_level_mark: Mark, + next: bool, runtime: Runtime, /// For automatic runtime. @@ -750,7 +788,12 @@ where let src = line.replace("@jsxFrag", "").trim().to_string(); self.pragma_frag = ExprOrSpread { - expr: parse_classic_option(&self.cm, "module-jsx-pragma-frag", src), + expr: parse_classic_option( + &self.cm, + "module-jsx-pragma-frag", + src, + self.top_level_mark, + ), spread: None, }; } else if line.starts_with("@jsx ") { @@ -772,6 +815,7 @@ where &self.cm, "module-jsx-pragma", src, + self.top_level_mark, )); } } diff --git a/ecmascript/transforms/react/src/jsx/tests.rs b/ecmascript/transforms/react/src/jsx/tests.rs index e6fe860efbe..3e81f7e20e6 100644 --- a/ecmascript/transforms/react/src/jsx/tests.rs +++ b/ecmascript/transforms/react/src/jsx/tests.rs @@ -5,6 +5,7 @@ use crate::display_name; use std::path::PathBuf; use swc_common::{chain, Mark}; use swc_ecma_parser::EsConfig; +use swc_ecma_transforms_base::resolver::resolver_with_mark; use swc_ecma_transforms_compat::{ es2015::{arrow, classes}, es3::property_literals, @@ -12,9 +13,15 @@ use swc_ecma_transforms_compat::{ use swc_ecma_transforms_module::common_js::common_js; use swc_ecma_transforms_testing::{parse_options, test, test_fixture, Tester}; -fn tr(t: &mut Tester, options: Options) -> impl Fold { +fn tr(t: &mut Tester, options: Options, top_level_mark: Mark) -> impl Fold { chain!( - jsx(t.cm.clone(), Some(t.comments.clone()), options), + resolver_with_mark(top_level_mark), + jsx( + t.cm.clone(), + Some(t.comments.clone()), + options, + top_level_mark + ), display_name(), classes(Some(t.comments.clone())), arrow(), @@ -45,6 +52,8 @@ fn true_by_default() -> bool { } fn fixture_tr(t: &mut Tester, mut options: FixtureOptions) -> impl Fold { + let top_level_mark = Mark::fresh(Mark::root()); + options.options.next = options.babel_8_breaking || options.options.runtime.is_some(); if !options.babel_8_breaking && options.options.runtime.is_none() { @@ -53,7 +62,12 @@ fn fixture_tr(t: &mut Tester, mut options: FixtureOptions) -> impl Fold { options.options.use_builtins |= options.use_builtins; chain!( - jsx(t.cm.clone(), Some(t.comments.clone()), options.options), + jsx( + t.cm.clone(), + Some(t.comments.clone()), + options.options, + top_level_mark + ), display_name(), ) } @@ -62,7 +76,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_add_appropriate_newlines, r#" @@ -332,7 +346,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_honor_custom_jsx_comment_if_jsx_pragma_option_set, r#"/** @jsx dom */ @@ -356,7 +370,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_honor_custom_jsx_comment, r#" /** @jsx dom */ @@ -388,7 +402,8 @@ test!( Options { pragma: "dom".into(), ..Default::default() - } + }, + Mark::fresh(Mark::root()) ), react_honor_custom_jsx_pragma_option, r#" @@ -412,7 +427,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_jsx_with_retainlines_option, r#"var div =
test
;"#, r#"var div = React.createElement("div", null, "test");"# @@ -423,7 +438,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_jsx_without_retainlines_option, r#"var div =
test
;"#, r#"var div = React.createElement("div", null, "test");"# @@ -436,7 +451,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_optimisation_react_constant_elements, r#" class App extends React.Component { @@ -500,7 +515,10 @@ test!( jsx: true, ..Default::default() }), - |t| chain!(tr(t, Default::default()), property_literals()), + |t| chain!( + tr(t, Default::default(), Mark::fresh(Mark::root())), + property_literals(), + ), react_should_add_quotes_es3, r#"var es3 = ;"#, r#" @@ -520,7 +538,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_allow_constructor_as_prop, r#";"#, r#" @@ -535,7 +553,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_allow_deeper_js_namespacing, r#";"#, r#"React.createElement(Namespace.DeepNamespace.Component, null);"# @@ -546,7 +564,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_allow_elements_as_attributes, r#"
/>"#, r#" @@ -560,7 +578,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_allow_js_namespacing, r#";"#, r#"React.createElement(Namespace.Component, null);"# @@ -571,7 +589,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_allow_nested_fragments, r#"
@@ -606,7 +624,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_allow_no_pragmafrag_if_frag_unused, r#" /** @jsx dom */ @@ -624,7 +642,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_allow_pragmafrag_and_frag, r#" /** @jsx dom */ @@ -645,7 +663,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_avoid_wrapping_in_extra_parens_if_not_needed, r#" var x =
@@ -677,7 +695,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_convert_simple_tags, r#"var x =
;"#, r#"var x = React.createElement("div", null);"# @@ -688,7 +706,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_convert_simple_text, r#"var x =
text
;"#, r#"var x = React.createElement("div", null, "text");"# @@ -699,7 +717,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_escape_xhtml_jsxattribute, r#"
; @@ -725,7 +743,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_escape_xhtml_jsxtext_1, r#"
wow
; @@ -756,7 +774,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_escape_xhtml_jsxtext_2, r#"
this should not parse as unicode: \u00a0
; @@ -772,7 +790,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_escape_unicode_chars_in_attribute, r#""#, r#"React.createElement(Bla, { @@ -787,7 +805,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_escape_xhtml_jsxtext_3, r#"
this should parse as nbsp:
; @@ -802,7 +820,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_handle_attributed_elements, r#" var HelloMessage = React.createClass({ @@ -838,7 +856,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_handle_has_own_property_correctly, r#"testing;"#, r#"React.createElement("hasOwnProperty", null, "testing");"# @@ -849,7 +867,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_have_correct_comma_in_nested_children, r#" var x =
@@ -873,7 +891,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_insert_commas_after_expressions_before_whitespace, r#" var x = @@ -908,7 +926,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_not_add_quotes_to_identifier_names, r#"var e = ;"#, r#" @@ -928,7 +946,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_not_mangle_expressioncontainer_attribute_values, r#";"#, r#" @@ -943,7 +961,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_not_strip_nbsp_even_coupled_with_other_whitespace, r#"
 
;"#, r#"React.createElement("div", null, "\xA0 ");"#, @@ -955,7 +973,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_not_strip_tags_with_a_single_child_of_nbsp, r#"
 
;"#, r#"React.createElement("div", null, "\xA0");"#, @@ -968,7 +986,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_properly_handle_comments_between_props, r#" var x = ( @@ -999,7 +1017,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_quote_jsx_attributes, r#";"#, r#" @@ -1021,6 +1039,7 @@ test!( throw_if_namespace: false, ..Default::default() }, + Mark::fresh(Mark::root()) ), react_should_support_xml_namespaces_if_flag, r#";"#, @@ -1034,7 +1053,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_should_transform_known_hyphenated_tags, r#";"#, r#"React.createElement("font-face", null);"# @@ -1045,7 +1064,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_wraps_props_in_react_spread_for_first_spread_attributes, r#" "#, r#" @@ -1080,7 +1099,7 @@ test!( jsx: true, ..Default::default() }), - |t| tr(t, Default::default()), + |t| tr(t, Default::default(), Mark::fresh(Mark::root())), react_wraps_props_in_react_spread_for_middle_spread_attributes, r#""#, r#" @@ -1102,6 +1121,7 @@ test!( use_builtins: true, ..Default::default() }, + Mark::fresh(Mark::root()) ), use_builtins_assignment, r#"var div = "#, @@ -1123,6 +1143,7 @@ test!( use_spread: true, ..Default::default() }, + Mark::fresh(Mark::root()) ), use_spread_assignment, r#""#, @@ -1141,6 +1162,7 @@ test!( use_builtins: true, ..Default::default() }, + Mark::fresh(Mark::root()) ), issue_229, "const a = <>test @@ -1154,16 +1176,20 @@ test!( jsx: true, ..Default::default() }), - |t| chain!( - tr( - t, - Options { - use_builtins: true, - ..Default::default() - } - ), - common_js(Mark::fresh(Mark::root()), Default::default(), None) - ), + |t| { + let top_level_mark = Mark::fresh(Mark::root()); + chain!( + tr( + t, + Options { + use_builtins: true, + ..Default::default() + }, + top_level_mark + ), + common_js(top_level_mark, Default::default(), None) + ) + }, issue_351, "import React from 'react'; @@ -1183,7 +1209,8 @@ test!( Options { use_builtins: true, ..Default::default() - } + }, + Mark::fresh(Mark::root()) ), issue_481, " {foo};", @@ -1196,16 +1223,20 @@ test!( jsx: true, ..Default::default() }), - |t| chain!( - tr( - t, - Options { - use_builtins: true, - ..Default::default() - } - ), - common_js(Mark::fresh(Mark::root()), Default::default(), None) - ), + |t| { + let top_level_mark = Mark::fresh(Mark::root()); + chain!( + tr( + t, + Options { + use_builtins: true, + ..Default::default() + }, + top_level_mark + ), + common_js(Mark::fresh(Mark::root()), Default::default(), None) + ) + }, issue_517, "import React from 'react';
Hello World
;", @@ -1234,7 +1265,8 @@ test!( Options { use_builtins: true, ..Default::default() - } + }, + Mark::fresh(Mark::root()) ), issue_542, "let page =

Click New melody listen to a randomly generated melody

", @@ -1250,10 +1282,19 @@ test!( jsx: true, ..Default::default() }), - |t| chain!( - classes(Some(t.comments.clone())), - jsx(t.cm.clone(), Some(t.comments.clone()), Default::default()) - ), + |t| { + let top_level_mark = Mark::fresh(Mark::root()); + + chain!( + classes(Some(t.comments.clone())), + jsx( + t.cm.clone(), + Some(t.comments.clone()), + Default::default(), + top_level_mark + ) + ) + }, regression_2775, r#" import React, {Component} from 'react'; diff --git a/ecmascript/transforms/react/src/lib.rs b/ecmascript/transforms/react/src/lib.rs index af84c716dea..ca4edb6daac 100644 --- a/ecmascript/transforms/react/src/lib.rs +++ b/ecmascript/transforms/react/src/lib.rs @@ -7,7 +7,7 @@ pub use self::{ refresh::{options::RefreshOptions, refresh}, }; use std::mem; -use swc_common::{chain, comments::Comments, sync::Lrc, SourceMap}; +use swc_common::{chain, comments::Comments, sync::Lrc, Mark, SourceMap}; use swc_ecma_visit::Fold; mod display_name; @@ -20,7 +20,16 @@ mod refresh; /// `@babel/preset-react` /// /// Preset for all React plugins. -pub fn react(cm: Lrc, comments: Option, mut options: Options) -> impl Fold +/// +/// +/// `top_level_mark` should be [Mark] passed to +/// [swc_ecma_transforms_base::resolver::resolver_with_mark]. +pub fn react( + cm: Lrc, + comments: Option, + mut options: Options, + top_level_mark: Mark, +) -> impl Fold where C: Comments + Clone, { @@ -32,7 +41,7 @@ where jsx_src(development, cm.clone()), jsx_self(development), refresh(development, refresh_options, cm.clone(), comments.clone()), - jsx(cm.clone(), comments.clone(), options), + jsx(cm.clone(), comments.clone(), options, top_level_mark), display_name(), pure_annotations(comments), ) diff --git a/ecmascript/transforms/react/src/pure_annotations/tests.rs b/ecmascript/transforms/react/src/pure_annotations/tests.rs index cbfe79917d5..e26c2074de8 100644 --- a/ecmascript/transforms/react/src/pure_annotations/tests.rs +++ b/ecmascript/transforms/react/src/pure_annotations/tests.rs @@ -1,5 +1,5 @@ use super::*; -use swc_common::{comments::SingleThreadedComments, sync::Lrc, FileName, SourceMap}; +use swc_common::{comments::SingleThreadedComments, sync::Lrc, FileName, Mark, SourceMap}; use swc_ecma_codegen::{text_writer::JsWriter, Emitter}; use swc_ecma_parser::{Parser, StringInput}; use swc_ecma_transforms_base::resolver; @@ -63,6 +63,8 @@ fn emit( fn run_test(input: &str, expected: &str) { Tester::run(|tester| { + let top_level_mark = Mark::fresh(Mark::root()); + let (actual, actual_sm, actual_comments) = parse(tester, input)?; let actual = actual .fold_with(&mut resolver::resolver()) @@ -70,6 +72,7 @@ fn run_test(input: &str, expected: &str) { actual_sm.clone(), Some(&actual_comments), Default::default(), + top_level_mark, )); let actual_src = emit(actual_sm, actual_comments, &actual); diff --git a/src/builder.rs b/src/builder.rs index 2c84369f3ea..b6cb5e3b4ed 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -14,14 +14,8 @@ use swc_ecma_ast::{EsVersion, Module}; use swc_ecma_minifier::option::MinifyOptions; use swc_ecma_parser::Syntax; use swc_ecma_transforms::{ - compat, fixer, helpers, hygiene, - hygiene::hygiene_with_config, - modules, - modules::util::Scope, - optimization::const_modules, - pass::Optional, - proposals::{import_assertions, private_in_object}, - typescript, + compat, fixer, helpers, hygiene, hygiene::hygiene_with_config, modules, modules::util::Scope, + optimization::const_modules, pass::Optional, proposals::private_in_object, }; use swc_ecma_visit::{as_folder, noop_visit_mut_type, VisitMut}; @@ -32,7 +26,7 @@ pub struct PassBuilder<'a, 'b, P: swc_ecma_visit::Fold> { env: Option, pass: P, /// [Mark] for top level bindings and unresolved identifier references. - global_mark: Mark, + top_level_mark: Mark, target: JscTarget, loose: bool, hygiene: Option, @@ -46,7 +40,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> { cm: &'a Arc, handler: &'b Handler, loose: bool, - global_mark: Mark, + top_level_mark: Mark, pass: P, ) -> Self { PassBuilder { @@ -54,7 +48,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> { handler, env: None, pass, - global_mark, + top_level_mark, target: JscTarget::Es5, loose, hygiene: Some(Default::default()), @@ -74,7 +68,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> { handler: self.handler, env: self.env, pass, - global_mark: self.global_mark, + top_level_mark: self.top_level_mark, target: self.target, loose: self.loose, hygiene: self.hygiene, @@ -154,7 +148,6 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> { syntax: Syntax, module: Option, comments: Option<&'cmt SwcComments>, - custom_before_pass: impl 'cmt + swc_ecma_visit::Fold, ) -> impl 'cmt + swc_ecma_visit::Fold where P: 'cmt, @@ -168,17 +161,13 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> { // compat let compat_pass = if let Some(env) = self.env { - Either::Left(chain!( - import_assertions(), - Optional::new(typescript::strip(), syntax.typescript()), - custom_before_pass, - swc_ecma_preset_env::preset_env(self.global_mark, comments.clone(), env) + Either::Left(swc_ecma_preset_env::preset_env( + self.top_level_mark, + comments.clone(), + env, )) } else { Either::Right(chain!( - import_assertions(), - Optional::new(typescript::strip(), syntax.typescript()), - custom_before_pass, Optional::new( compat::es2021::es2021(), should_enable(self.target, JscTarget::Es2021) @@ -205,7 +194,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> { ), Optional::new( compat::es2015( - self.global_mark, + self.top_level_mark, comments.clone(), compat::es2015::Config { for_of: compat::es2015::for_of::Config { @@ -244,7 +233,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> { base_url, paths, base, - self.global_mark, + self.top_level_mark, module, Rc::clone(&module_scope) ), @@ -252,7 +241,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> { options: self.minify, cm: self.cm.clone(), comments: comments.cloned(), - top_level_mark: self.global_mark, + top_level_mark: self.top_level_mark, }), Optional::new( hygiene_with_config(self.hygiene.clone().unwrap_or_default()), diff --git a/src/config/mod.rs b/src/config/mod.rs index a466b055930..45fbbab6d39 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -36,7 +36,7 @@ use swc_ecma_transforms::{ modules::{hoist::import_hoister, path::NodeImportResolver, util::Scope}, optimization::{const_modules, inline_globals, json_parse, simplifier}, pass::{noop, Optional}, - proposals::{decorators, export_default_from}, + proposals::{decorators, export_default_from, import_assertions}, react, resolver_with_mark, typescript, }; use swc_ecma_visit::Fold; @@ -249,21 +249,6 @@ impl Options { .unwrap_or_else(|| Mark::fresh(Mark::root())); let pass = chain!( - // handle jsx - Optional::new( - react::react(cm.clone(), comments.clone(), transform.react), - syntax.jsx() - ), - // Decorators may use type information - Optional::new( - decorators(decorators::Config { - legacy: transform.legacy_decorator, - emit_metadata: transform.decorator_metadata, - }), - syntax.decorators() - ), - Optional::new(typescript::strip(), syntax.typescript()), - resolver_with_mark(top_level_mark), const_modules, optimization, Optional::new(export_default_from(), syntax.export_default_from()), @@ -289,10 +274,34 @@ impl Options { syntax, config.module, comments, - custom_before_pass, ); - let pass = chain!(pass, Optional::new(jest::jest(), transform.hidden.jest)); + let pass = chain!( + // Decorators may use type information + Optional::new( + decorators(decorators::Config { + legacy: transform.legacy_decorator, + emit_metadata: transform.decorator_metadata, + }), + syntax.decorators() + ), + import_assertions(), + Optional::new(typescript::strip(), syntax.typescript()), + resolver_with_mark(top_level_mark), + custom_before_pass, + // handle jsx + Optional::new( + react::react( + cm.clone(), + comments.clone(), + transform.react, + top_level_mark + ), + syntax.jsx() + ), + pass, + Optional::new(jest::jest(), transform.hidden.jest) + ); BuiltConfig { minify: config.minify, diff --git a/tests/fixture/issue-1782/case1/output/index.tsx b/tests/fixture/issue-1782/case1/output/index.tsx index fabbbc4f8c9..26a37e95e99 100644 --- a/tests/fixture/issue-1782/case1/output/index.tsx +++ b/tests/fixture/issue-1782/case1/output/index.tsx @@ -1,4 +1,3 @@ -import React from "react"; export var HelloWorld = function() { return(/*#__PURE__*/ React.createElement("div", { title: "您好SWC" diff --git a/tests/rust-users.rs b/tests/rust_api.rs similarity index 100% rename from tests/rust-users.rs rename to tests/rust_api.rs