-
-
Save kdy1/047e7e5537c34180d446cb3d5b95fce8 to your computer and use it in GitHub Desktop.
diff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/bindings/binding_core_node/src/bundle.rs b/bindings/binding_core_node/src/bundle.rs | |
index c2378b1698..2fe29702c9 100644 | |
--- a/bindings/binding_core_node/src/bundle.rs | |
+++ b/bindings/binding_core_node/src/bundle.rs | |
@@ -129,16 +129,16 @@ impl Task for BundleTask { | |
None, | |
None, | |
true, | |
- codegen_target, | |
SourceMapsConfig::Bool(true), | |
// TODO | |
&Default::default(), | |
None, | |
- minify, | |
None, | |
true, | |
- false, | |
Default::default(), | |
+ swc_core::ecma::codegen::Config::default() | |
+ .with_target(codegen_target) | |
+ .with_minify(minify), | |
)?; | |
Ok((k, output)) | |
diff --git a/bindings/binding_core_node/src/print.rs b/bindings/binding_core_node/src/print.rs | |
index 983cad30e1..720c23e57f 100644 | |
--- a/bindings/binding_core_node/src/print.rs | |
+++ b/bindings/binding_core_node/src/print.rs | |
@@ -40,18 +40,18 @@ impl Task for PrintTask { | |
None, | |
options.output_path.clone(), | |
true, | |
- options.config.jsc.target.unwrap_or(EsVersion::Es2020), | |
options | |
.source_maps | |
.clone() | |
.unwrap_or(SourceMapsConfig::Bool(false)), | |
&Default::default(), | |
None, | |
- options.config.minify.into_bool(), | |
None, | |
options.config.emit_source_map_columns.into_bool(), | |
- false, | |
Default::default(), | |
+ swc_core::ecma::codegen::Config::default() | |
+ .with_target(options.config.jsc.target.unwrap_or(EsVersion::Es2020)) | |
+ .with_minify(options.config.minify.into_bool()), | |
) | |
.convert_err() | |
}) | |
@@ -102,18 +102,18 @@ pub fn print_sync(program: String, options: Buffer) -> napi::Result<TransformOut | |
None, | |
options.output_path, | |
true, | |
- codegen_target, | |
options | |
.source_maps | |
.clone() | |
.unwrap_or(SourceMapsConfig::Bool(false)), | |
&Default::default(), | |
None, | |
- options.config.minify.into_bool(), | |
None, | |
options.config.emit_source_map_columns.into_bool(), | |
- false, | |
Default::default(), | |
+ swc_core::ecma::codegen::Config::default() | |
+ .with_target(codegen_target) | |
+ .with_minify(options.config.minify.into_bool()), | |
) | |
.convert_err() | |
}) | |
diff --git a/crates/binding_macros/src/wasm.rs b/crates/binding_macros/src/wasm.rs | |
index cfb25ab747..8aef150de0 100644 | |
--- a/crates/binding_macros/src/wasm.rs | |
+++ b/crates/binding_macros/src/wasm.rs | |
@@ -248,17 +248,17 @@ macro_rules! build_print_sync { | |
None, | |
None, | |
true, | |
- opts.codegen_target().unwrap_or($crate::wasm::EsVersion::Es2020), | |
opts.source_maps | |
.clone() | |
.unwrap_or($crate::wasm::SourceMapsConfig::Bool(false)), | |
&Default::default(), | |
None, | |
- opts.config.minify.into(), | |
None, | |
opts.config.emit_source_map_columns.into_bool(), | |
- false, | |
Default::default(), | |
+ swc_core::ecma::codegen::Config::default() | |
+ .with_target(opts.codegen_target().unwrap_or($crate::wasm::EsVersion::Es2020)) | |
+ .with_minify(opts.config.minify.into()) | |
),"failed to print code")?; | |
serde_wasm_bindgen::to_value(&s) | |
diff --git a/crates/dbg-swc/src/util/mod.rs b/crates/dbg-swc/src/util/mod.rs | |
index 8acfd2d05a..00f0bb3033 100644 | |
--- a/crates/dbg-swc/src/util/mod.rs | |
+++ b/crates/dbg-swc/src/util/mod.rs | |
@@ -89,10 +89,7 @@ pub fn print_js(cm: Arc<SourceMap>, m: &Module, minify: bool) -> Result<String> | |
} | |
let mut e = swc_ecma_codegen::Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(true), | |
cm, | |
comments: None, | |
wr, | |
diff --git a/crates/swc/benches/typescript.rs b/crates/swc/benches/typescript.rs | |
index cde28c9da5..b87bfc8ccb 100644 | |
--- a/crates/swc/benches/typescript.rs | |
+++ b/crates/swc/benches/typescript.rs | |
@@ -115,15 +115,13 @@ fn bench_codegen(b: &mut Bencher, _target: EsVersion) { | |
None, | |
None, | |
false, | |
- EsVersion::Es2020, | |
SourceMapsConfig::Bool(false), | |
&Default::default(), | |
None, | |
- false, | |
None, | |
false, | |
- false, | |
Default::default(), | |
+ swc_ecma_codegen::Config::default().with_target(EsVersion::Es2020), | |
) | |
.unwrap() | |
})); | |
diff --git a/crates/swc/src/builder.rs b/crates/swc/src/builder.rs | |
index 45fbaa764b..e335ee6fd3 100644 | |
--- a/crates/swc/src/builder.rs | |
+++ b/crates/swc/src/builder.rs | |
@@ -187,8 +187,8 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> { | |
(true, c.config.import_interop(), c.config.ignore_dynamic) | |
} | |
Some(ModuleConfig::SystemJs(_)) | |
- | Some(ModuleConfig::Es6) | |
- | Some(ModuleConfig::NodeNext) | |
+ | Some(ModuleConfig::Es6(..)) | |
+ | Some(ModuleConfig::NodeNext(..)) | |
| None => (false, true.into(), true), | |
}; | |
@@ -233,15 +233,18 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> { | |
should_enable(self.target, EsVersion::Es2021) | |
), | |
Optional::new( | |
- compat::es2020::es2020(compat::es2020::Config { | |
- nullish_coalescing: compat::es2020::nullish_coalescing::Config { | |
- no_document_all: assumptions.no_document_all | |
+ compat::es2020::es2020( | |
+ compat::es2020::Config { | |
+ nullish_coalescing: compat::es2020::nullish_coalescing::Config { | |
+ no_document_all: assumptions.no_document_all | |
+ }, | |
+ optional_chaining: compat::es2020::optional_chaining::Config { | |
+ no_document_all: assumptions.no_document_all, | |
+ pure_getter: assumptions.pure_getters | |
+ } | |
}, | |
- optional_chaining: compat::es2020::optional_chaining::Config { | |
- no_document_all: assumptions.no_document_all, | |
- pure_getter: assumptions.pure_getters | |
- } | |
- }), | |
+ self.unresolved_mark | |
+ ), | |
should_enable(self.target, EsVersion::Es2020) | |
), | |
Optional::new( | |
diff --git a/crates/swc/src/config/mod.rs b/crates/swc/src/config/mod.rs | |
index 38f8bae512..1a79edfdf0 100644 | |
--- a/crates/swc/src/config/mod.rs | |
+++ b/crates/swc/src/config/mod.rs | |
@@ -10,7 +10,7 @@ use std::{ | |
usize, | |
}; | |
-use anyhow::{bail, Error}; | |
+use anyhow::{bail, Context, Error}; | |
use dashmap::DashMap; | |
use either::Either; | |
use indexmap::IndexMap; | |
@@ -54,10 +54,13 @@ use swc_ecma_parser::{parse_file_as_expr, Syntax, TsConfig}; | |
use swc_ecma_transforms::{ | |
feature::FeatureFlag, | |
hygiene, modules, | |
- modules::{path::NodeImportResolver, rewriter::import_rewriter}, | |
+ modules::{path::NodeImportResolver, rewriter::import_rewriter, EsModuleConfig}, | |
optimization::{const_modules, json_parse, simplifier}, | |
pass::{noop, Optional}, | |
- proposals::{decorators, export_default_from, import_assertions}, | |
+ proposals::{ | |
+ decorators, explicit_resource_management::explicit_resource_management, | |
+ export_default_from, import_assertions, | |
+ }, | |
react::{self, default_pragma, default_pragma_frag}, | |
resolver, | |
typescript::{self, TsEnumConfig, TsImportExportAssignConfig}, | |
@@ -324,7 +327,7 @@ impl Options { | |
config: Option<Config>, | |
comments: Option<&'a SingleThreadedComments>, | |
custom_before_pass: impl FnOnce(&Program) -> P, | |
- ) -> Result<BuiltInput<impl 'a + swc_ecma_visit::Fold>, Error> | |
+ ) -> Result<BuiltInput<Box<dyn 'a + Fold>>, Error> | |
where | |
P: 'a + swc_ecma_visit::Fold, | |
{ | |
@@ -416,7 +419,7 @@ impl Options { | |
if matches!( | |
cfg.module, | |
- None | Some(ModuleConfig::Es6 | ModuleConfig::NodeNext) | |
+ None | Some(ModuleConfig::Es6(..) | ModuleConfig::NodeNext(..)) | |
) { | |
c.module = true; | |
} | |
@@ -527,7 +530,7 @@ impl Options { | |
.as_ref() | |
.map(|v| match v.format.comments.clone().into_inner() { | |
Some(v) => v, | |
- None => BoolOr::Bool(false), | |
+ None => BoolOr::Bool(true), | |
}) | |
.unwrap_or_else(|| { | |
BoolOr::Data(if cfg.minify.into_bool() { | |
@@ -606,11 +609,11 @@ impl Options { | |
); | |
let import_export_assign_config = match cfg.module { | |
- Some(ModuleConfig::Es6) => TsImportExportAssignConfig::EsNext, | |
+ Some(ModuleConfig::Es6(..)) => TsImportExportAssignConfig::EsNext, | |
Some(ModuleConfig::CommonJs(..)) | |
| Some(ModuleConfig::Amd(..)) | |
| Some(ModuleConfig::Umd(..)) => TsImportExportAssignConfig::Preserve, | |
- Some(ModuleConfig::NodeNext) => TsImportExportAssignConfig::NodeNext, | |
+ Some(ModuleConfig::NodeNext(..)) => TsImportExportAssignConfig::NodeNext, | |
// TODO: should Preserve for SystemJS | |
_ => TsImportExportAssignConfig::Classic, | |
}; | |
@@ -664,7 +667,7 @@ impl Options { | |
comments.map(|v| v as _), | |
); | |
- let keep_import_assertions = experimental.keep_import_assertions.into_bool(); | |
+ let keep_import_attributes = experimental.keep_import_attributes.into_bool(); | |
#[cfg(feature = "plugin")] | |
let plugin_transforms = { | |
@@ -759,88 +762,99 @@ impl Options { | |
noop() | |
}; | |
- let pass = chain!( | |
- lint_to_fold(swc_ecma_lints::rules::all(LintParams { | |
- program: &program, | |
- lint_config: &lints, | |
- top_level_ctxt, | |
- unresolved_ctxt, | |
- es_version, | |
- source_map: cm.clone(), | |
- })), | |
- // Decorators may use type information | |
- Optional::new( | |
- match transform.decorator_version.unwrap_or_default() { | |
- DecoratorVersion::V202112 => { | |
- Either::Left(decorators(decorators::Config { | |
- legacy: transform.legacy_decorator.into_bool(), | |
- emit_metadata: transform.decorator_metadata.into_bool(), | |
- use_define_for_class_fields: !assumptions.set_public_class_fields, | |
- })) | |
- } | |
- DecoratorVersion::V202203 => { | |
- Either::Right( | |
+ let pass: Box<dyn Fold> = if experimental | |
+ .disable_builtin_transforms_for_internal_testing | |
+ .into_bool() | |
+ { | |
+ Box::new(plugin_transforms) | |
+ } else { | |
+ Box::new(chain!( | |
+ lint_to_fold(swc_ecma_lints::rules::all(LintParams { | |
+ program: &program, | |
+ lint_config: &lints, | |
+ top_level_ctxt, | |
+ unresolved_ctxt, | |
+ es_version, | |
+ source_map: cm.clone(), | |
+ })), | |
+ // Decorators may use type information | |
+ Optional::new( | |
+ match transform.decorator_version.unwrap_or_default() { | |
+ DecoratorVersion::V202112 => { | |
+ Either::Left(decorators(decorators::Config { | |
+ legacy: transform.legacy_decorator.into_bool(), | |
+ emit_metadata: transform.decorator_metadata.into_bool(), | |
+ use_define_for_class_fields: !assumptions.set_public_class_fields, | |
+ })) | |
+ } | |
+ DecoratorVersion::V202203 => { | |
+ Either::Right( | |
swc_ecma_transforms::proposals::decorator_2022_03::decorator_2022_03(), | |
) | |
- } | |
- }, | |
- syntax.decorators() | |
- ), | |
- // The transform strips import assertions, so it's only enabled if | |
- // keep_import_assertions is false. | |
- Optional::new(import_assertions(), !keep_import_assertions), | |
- Optional::new( | |
- typescript::strip_with_jsx::<Option<&dyn Comments>>( | |
- cm.clone(), | |
- typescript::Config { | |
- pragma: Some( | |
- transform | |
- .react | |
- .pragma | |
- .clone() | |
- .unwrap_or_else(default_pragma) | |
- ), | |
- pragma_frag: Some( | |
- transform | |
- .react | |
- .pragma_frag | |
- .clone() | |
- .unwrap_or_else(default_pragma_frag) | |
- ), | |
- ts_enum_config: TsEnumConfig { | |
- treat_const_enum_as_enum: transform | |
- .treat_const_enum_as_enum | |
- .into_bool(), | |
- ts_enum_is_readonly: assumptions.ts_enum_is_readonly, | |
- }, | |
- import_export_assign_config, | |
- ..Default::default() | |
+ } | |
}, | |
- comments.map(|v| v as _), | |
- top_level_mark | |
+ syntax.decorators() | |
), | |
- syntax.typescript() | |
- ), | |
- plugin_transforms, | |
- custom_before_pass(&program), | |
- // handle jsx | |
- Optional::new( | |
- react::react::<&dyn Comments>( | |
- cm.clone(), | |
- comments.map(|v| v as _), | |
- transform.react, | |
- top_level_mark, | |
- unresolved_mark | |
+ Optional::new( | |
+ explicit_resource_management(), | |
+ syntax.explicit_resource_management() | |
), | |
- syntax.jsx() | |
- ), | |
- pass, | |
- Optional::new(jest::jest(), transform.hidden.jest.into_bool()), | |
- Optional::new( | |
- dropped_comments_preserver(comments.cloned()), | |
- preserve_all_comments | |
- ), | |
- ); | |
+ // The transform strips import assertions, so it's only enabled if | |
+ // keep_import_assertions is false. | |
+ Optional::new(import_assertions(), !keep_import_attributes), | |
+ Optional::new( | |
+ typescript::strip_with_jsx::<Option<&dyn Comments>>( | |
+ cm.clone(), | |
+ typescript::Config { | |
+ pragma: Some( | |
+ transform | |
+ .react | |
+ .pragma | |
+ .clone() | |
+ .unwrap_or_else(default_pragma) | |
+ ), | |
+ pragma_frag: Some( | |
+ transform | |
+ .react | |
+ .pragma_frag | |
+ .clone() | |
+ .unwrap_or_else(default_pragma_frag) | |
+ ), | |
+ ts_enum_config: TsEnumConfig { | |
+ treat_const_enum_as_enum: transform | |
+ .treat_const_enum_as_enum | |
+ .into_bool(), | |
+ ts_enum_is_readonly: assumptions.ts_enum_is_readonly, | |
+ }, | |
+ import_export_assign_config, | |
+ ..Default::default() | |
+ }, | |
+ comments.map(|v| v as _), | |
+ top_level_mark | |
+ ), | |
+ syntax.typescript() | |
+ ), | |
+ plugin_transforms, | |
+ custom_before_pass(&program), | |
+ // handle jsx | |
+ Optional::new( | |
+ react::react::<&dyn Comments>( | |
+ cm.clone(), | |
+ comments.map(|v| v as _), | |
+ transform.react, | |
+ top_level_mark, | |
+ unresolved_mark | |
+ ), | |
+ syntax.jsx() | |
+ ), | |
+ pass, | |
+ Optional::new(jest::jest(), transform.hidden.jest.into_bool()), | |
+ Optional::new( | |
+ dropped_comments_preserver(comments.cloned()), | |
+ preserve_all_comments | |
+ ), | |
+ )) | |
+ }; | |
Ok(BuiltInput { | |
program, | |
@@ -859,6 +873,9 @@ impl Options { | |
preserve_comments, | |
emit_source_map_columns: cfg.emit_source_map_columns.into_bool(), | |
output: JscOutputConfig { charset, preamble }, | |
+ emit_assert_for_import_attributes: experimental | |
+ .emit_assert_for_import_attributes | |
+ .into_bool(), | |
}) | |
} | |
} | |
@@ -1231,6 +1248,9 @@ pub struct JsMinifyFormatOptions { | |
/// Not implemented yet. | |
#[serde(default, alias = "wrap_func_args")] | |
pub wrap_func_args: bool, | |
+ | |
+ #[serde(default)] | |
+ pub emit_assert_for_import_attributes: bool, | |
} | |
fn default_comments() -> BoolOrDataConfig<JsMinifyCommentOption> { | |
@@ -1340,6 +1360,7 @@ impl Config { | |
} | |
/// One `BuiltConfig` per a directory with swcrc | |
+#[non_exhaustive] | |
pub struct BuiltInput<P: swc_ecma_visit::Fold> { | |
pub program: Program, | |
pub pass: P, | |
@@ -1363,6 +1384,37 @@ pub struct BuiltInput<P: swc_ecma_visit::Fold> { | |
pub emit_source_map_columns: bool, | |
pub output: JscOutputConfig, | |
+ pub emit_assert_for_import_attributes: bool, | |
+} | |
+ | |
+impl<P> BuiltInput<P> | |
+where | |
+ P: swc_ecma_visit::Fold, | |
+{ | |
+ pub fn with_pass<N>(self, map: impl FnOnce(P) -> N) -> BuiltInput<N> | |
+ where | |
+ N: swc_ecma_visit::Fold, | |
+ { | |
+ BuiltInput { | |
+ program: self.program, | |
+ pass: map(self.pass), | |
+ syntax: self.syntax, | |
+ target: self.target, | |
+ minify: self.minify, | |
+ external_helpers: self.external_helpers, | |
+ source_maps: self.source_maps, | |
+ input_source_map: self.input_source_map, | |
+ is_module: self.is_module, | |
+ output_path: self.output_path, | |
+ source_file_name: self.source_file_name, | |
+ preserve_comments: self.preserve_comments, | |
+ inline_sources_content: self.inline_sources_content, | |
+ comments: self.comments, | |
+ emit_source_map_columns: self.emit_source_map_columns, | |
+ output: self.output, | |
+ emit_assert_for_import_attributes: self.emit_assert_for_import_attributes, | |
+ } | |
+ } | |
} | |
/// `jsc` in `.swcrc`. | |
@@ -1446,7 +1498,10 @@ pub struct JscExperimental { | |
pub plugins: Option<Vec<PluginConfig>>, | |
/// If true, keeps import assertions in the output. | |
#[serde(default)] | |
- pub keep_import_assertions: BoolConfig<false>, | |
+ pub keep_import_attributes: BoolConfig<false>, | |
+ | |
+ #[serde(default)] | |
+ pub emit_assert_for_import_attributes: BoolConfig<false>, | |
/// Location where swc may stores its intermediate cache. | |
/// Currently this is only being used for wasm plugin's bytecache. | |
/// Path should be absolute directory, which will be created if not exist. | |
@@ -1454,6 +1509,9 @@ pub struct JscExperimental { | |
/// and will not be considered as breaking changes. | |
#[serde(default)] | |
pub cache_root: Option<String>, | |
+ | |
+ #[serde(default)] | |
+ pub disable_builtin_transforms_for_internal_testing: BoolConfig<false>, | |
} | |
#[derive(Debug, Clone, Copy, Serialize, Deserialize)] | |
@@ -1513,9 +1571,9 @@ pub enum ModuleConfig { | |
#[serde(rename = "systemjs")] | |
SystemJs(modules::system_js::Config), | |
#[serde(rename = "es6")] | |
- Es6, | |
+ Es6(EsModuleConfig), | |
#[serde(rename = "nodenext")] | |
- NodeNext, | |
+ NodeNext(EsModuleConfig), | |
} | |
impl ModuleConfig { | |
@@ -1538,11 +1596,20 @@ impl ModuleConfig { | |
let skip_resolver = base_url.as_os_str().is_empty() && paths.is_empty(); | |
match config { | |
- None | Some(ModuleConfig::Es6) | Some(ModuleConfig::NodeNext) => { | |
+ None => { | |
+ if skip_resolver { | |
+ Box::new(noop()) | |
+ } else { | |
+ let resolver = build_resolver(base_url, paths, false); | |
+ | |
+ Box::new(import_rewriter(base, resolver)) | |
+ } | |
+ } | |
+ Some(ModuleConfig::Es6(config)) | Some(ModuleConfig::NodeNext(config)) => { | |
if skip_resolver { | |
Box::new(noop()) | |
} else { | |
- let resolver = build_resolver(base_url, paths); | |
+ let resolver = build_resolver(base_url, paths, config.resolve_fully); | |
Box::new(import_rewriter(base, resolver)) | |
} | |
@@ -1556,7 +1623,7 @@ impl ModuleConfig { | |
comments, | |
)) | |
} else { | |
- let resolver = build_resolver(base_url, paths); | |
+ let resolver = build_resolver(base_url, paths, config.resolve_fully); | |
Box::new(modules::common_js::common_js_with_resolver( | |
resolver, | |
base, | |
@@ -1577,7 +1644,7 @@ impl ModuleConfig { | |
comments, | |
)) | |
} else { | |
- let resolver = build_resolver(base_url, paths); | |
+ let resolver = build_resolver(base_url, paths, config.config.resolve_fully); | |
Box::new(modules::umd::umd_with_resolver( | |
cm, | |
@@ -1599,7 +1666,7 @@ impl ModuleConfig { | |
comments, | |
)) | |
} else { | |
- let resolver = build_resolver(base_url, paths); | |
+ let resolver = build_resolver(base_url, paths, config.config.resolve_fully); | |
Box::new(modules::amd::amd_with_resolver( | |
resolver, | |
@@ -1615,7 +1682,7 @@ impl ModuleConfig { | |
if skip_resolver { | |
Box::new(modules::system_js::system_js(unresolved_mark, config)) | |
} else { | |
- let resolver = build_resolver(base_url, paths); | |
+ let resolver = build_resolver(base_url, paths, config.resolve_fully); | |
Box::new(modules::system_js::system_js_with_resolver( | |
resolver, | |
@@ -1941,27 +2008,51 @@ fn default_env_name() -> String { | |
} | |
} | |
-fn build_resolver(base_url: PathBuf, paths: CompiledPaths) -> Box<SwcImportResolver> { | |
- static CACHE: Lazy<DashMap<(PathBuf, CompiledPaths), SwcImportResolver, ARandomState>> = | |
+fn build_resolver( | |
+ mut base_url: PathBuf, | |
+ paths: CompiledPaths, | |
+ resolve_fully: bool, | |
+) -> Box<SwcImportResolver> { | |
+ static CACHE: Lazy<DashMap<(PathBuf, CompiledPaths, bool), SwcImportResolver, ARandomState>> = | |
Lazy::new(Default::default); | |
- if let Some(cached) = CACHE.get(&(base_url.clone(), paths.clone())) { | |
+ // On Windows, we need to normalize path as UNC path. | |
+ if cfg!(target_os = "windows") { | |
+ base_url = base_url | |
+ .canonicalize() | |
+ .with_context(|| { | |
+ format!( | |
+ "failed to canonicalize jsc.baseUrl(`{}`)\nThis is required on Windows \ | |
+ because of UNC path.", | |
+ base_url.display() | |
+ ) | |
+ }) | |
+ .unwrap(); | |
+ } | |
+ | |
+ if let Some(cached) = CACHE.get(&(base_url.clone(), paths.clone(), resolve_fully)) { | |
return Box::new((*cached).clone()); | |
} | |
let r = { | |
let r = TsConfigResolver::new( | |
- NodeModulesResolver::new(Default::default(), Default::default(), true), | |
+ NodeModulesResolver::without_node_modules(Default::default(), Default::default(), true), | |
base_url.clone(), | |
paths.clone(), | |
); | |
let r = CachingResolver::new(40, r); | |
- let r = NodeImportResolver::with_base_dir(r, Some(base_url.clone())); | |
+ let r = NodeImportResolver::with_config( | |
+ r, | |
+ swc_ecma_transforms::modules::path::Config { | |
+ base_dir: Some(base_url.clone()), | |
+ resolve_fully, | |
+ }, | |
+ ); | |
Arc::new(r) | |
}; | |
- CACHE.insert((base_url, paths), r.clone()); | |
+ CACHE.insert((base_url, paths, resolve_fully), r.clone()); | |
Box::new(r) | |
} | |
diff --git a/crates/swc/src/lib.rs b/crates/swc/src/lib.rs | |
index 00782b1b30..9843855f58 100644 | |
--- a/crates/swc/src/lib.rs | |
+++ b/crates/swc/src/lib.rs | |
@@ -193,7 +193,7 @@ pub mod resolver { | |
preserve_symlinks: bool, | |
) -> CachingResolver<TsConfigResolver<NodeModulesResolver>> { | |
let r = TsConfigResolver::new( | |
- NodeModulesResolver::new(target_env, alias, preserve_symlinks), | |
+ NodeModulesResolver::without_node_modules(target_env, alias, preserve_symlinks), | |
base_url, | |
paths, | |
); | |
@@ -501,15 +501,13 @@ impl Compiler { | |
source_file_name: Option<&str>, | |
output_path: Option<PathBuf>, | |
inline_sources_content: bool, | |
- target: EsVersion, | |
source_map: SourceMapsConfig, | |
source_map_names: &AHashMap<BytePos, JsWord>, | |
orig: Option<&sourcemap::SourceMap>, | |
- minify: bool, | |
comments: Option<&dyn Comments>, | |
emit_source_map_columns: bool, | |
- ascii_only: bool, | |
preamble: &str, | |
+ codegen_config: swc_ecma_codegen::Config, | |
) -> Result<TransformOutput, Error> | |
where | |
T: Node + VisitWith<IdentCollector>, | |
@@ -535,17 +533,12 @@ impl Compiler { | |
w.preamble(preamble).unwrap(); | |
let mut wr = Box::new(w) as Box<dyn WriteJs>; | |
- if minify { | |
+ if codegen_config.minify { | |
wr = Box::new(swc_ecma_codegen::text_writer::omit_trailing_semi(wr)); | |
} | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- target, | |
- ascii_only, | |
- ..Default::default() | |
- }, | |
+ cfg: codegen_config, | |
comments, | |
cm: self.cm.clone(), | |
wr, | |
@@ -681,10 +674,10 @@ impl SourceMapGenConfig for SwcSourceMapConfig<'_> { | |
} | |
fn skip(&self, f: &FileName) -> bool { | |
- if let FileName::Custom(s) = f { | |
- s.starts_with('<') | |
- } else { | |
- false | |
+ match f { | |
+ FileName::Internal(..) => true, | |
+ FileName::Custom(s) => s.starts_with('<'), | |
+ _ => false, | |
} | |
} | |
} | |
@@ -733,7 +726,7 @@ impl Compiler { | |
} | |
} | |
- #[tracing::instrument(level = "info", skip_all)] | |
+ #[tracing::instrument(skip_all)] | |
pub fn read_config(&self, opts: &Options, name: &FileName) -> Result<Option<Config>, Error> { | |
static CUR_DIR: Lazy<PathBuf> = Lazy::new(|| { | |
if cfg!(target_arch = "wasm32") { | |
@@ -845,7 +838,7 @@ impl Compiler { | |
/// This method handles merging of config. | |
/// | |
/// This method does **not** parse module. | |
- #[tracing::instrument(level = "info", skip_all)] | |
+ #[tracing::instrument(skip_all)] | |
pub fn parse_js_as_input<'a, P>( | |
&'a self, | |
fm: Lrc<SourceFile>, | |
@@ -908,7 +901,7 @@ impl Compiler { | |
}) | |
} | |
- #[tracing::instrument(level = "info", skip_all)] | |
+ #[tracing::instrument(skip_all)] | |
pub fn transform( | |
&self, | |
handler: &Handler, | |
@@ -936,7 +929,7 @@ impl Compiler { | |
/// | |
/// This means, you can use `noop_visit_type`, `noop_fold_type` and | |
/// `noop_visit_mut_type` in your visitor to reduce the binary size. | |
- #[tracing::instrument(level = "info", skip_all)] | |
+ #[tracing::instrument(skip_all)] | |
pub fn process_js_with_custom_pass<P1, P2>( | |
&self, | |
fm: Arc<SourceFile>, | |
@@ -970,26 +963,9 @@ impl Compiler { | |
} | |
}; | |
- let pass = chain!(config.pass, custom_after_pass(&config.program)); | |
- | |
- let config = BuiltInput { | |
- program: config.program, | |
- pass, | |
- syntax: config.syntax, | |
- target: config.target, | |
- minify: config.minify, | |
- external_helpers: config.external_helpers, | |
- source_maps: config.source_maps, | |
- input_source_map: config.input_source_map, | |
- is_module: config.is_module, | |
- output_path: config.output_path, | |
- source_file_name: config.source_file_name, | |
- preserve_comments: config.preserve_comments, | |
- inline_sources_content: config.inline_sources_content, | |
- comments: config.comments, | |
- emit_source_map_columns: config.emit_source_map_columns, | |
- output: config.output, | |
- }; | |
+ let after_pass = custom_after_pass(&config.program); | |
+ | |
+ let config = config.with_pass(|pass| chain!(pass, after_pass)); | |
let orig = if config.source_maps.enabled() { | |
self.get_orig_src_map(&fm, &config.input_source_map, false)? | |
@@ -997,11 +973,11 @@ impl Compiler { | |
None | |
}; | |
- self.process_js_inner(handler, orig.as_ref(), config) | |
+ self.apply_transforms(handler, orig.as_ref(), config) | |
}) | |
} | |
- #[tracing::instrument(level = "info", skip(self, handler, opts))] | |
+ #[tracing::instrument(skip(self, handler, opts))] | |
pub fn process_js_file( | |
&self, | |
fm: Arc<SourceFile>, | |
@@ -1019,7 +995,7 @@ impl Compiler { | |
) | |
} | |
- #[tracing::instrument(level = "info", skip_all)] | |
+ #[tracing::instrument(skip_all)] | |
pub fn minify( | |
&self, | |
fm: Arc<SourceFile>, | |
@@ -1110,10 +1086,10 @@ impl Compiler { | |
jsx: true, | |
decorators: true, | |
decorators_before_export: true, | |
- import_assertions: true, | |
+ import_attributes: true, | |
..Default::default() | |
}), | |
- IsModule::Bool(true), | |
+ IsModule::Bool(opts.module), | |
Some(&comments), | |
) | |
.context("failed to parse input file")?; | |
@@ -1170,15 +1146,19 @@ impl Compiler { | |
Some(&fm.name.to_string()), | |
opts.output_path.clone().map(From::from), | |
opts.inline_sources_content, | |
- target, | |
source_map, | |
&source_map_names, | |
orig.as_ref(), | |
- true, | |
Some(&comments), | |
opts.emit_source_map_columns, | |
- opts.format.ascii_only, | |
&opts.format.preamble, | |
+ swc_ecma_codegen::Config::default() | |
+ .with_target(target) | |
+ .with_minify(true) | |
+ .with_ascii_only(opts.format.ascii_only) | |
+ .with_emit_assert_for_import_attributes( | |
+ opts.format.emit_assert_for_import_attributes, | |
+ ), | |
) | |
}) | |
} | |
@@ -1186,7 +1166,7 @@ impl Compiler { | |
/// You can use custom pass with this method. | |
/// | |
/// There exists a [PassBuilder] to help building custom passes. | |
- #[tracing::instrument(level = "info", skip_all)] | |
+ #[tracing::instrument(skip_all)] | |
pub fn process_js( | |
&self, | |
handler: &Handler, | |
@@ -1207,8 +1187,8 @@ impl Compiler { | |
) | |
} | |
- #[tracing::instrument(level = "info", skip_all)] | |
- fn process_js_inner( | |
+ #[tracing::instrument(name = "swc::Compiler::apply_transforms", skip_all)] | |
+ fn apply_transforms( | |
&self, | |
handler: &Handler, | |
orig: Option<&sourcemap::SourceMap>, | |
@@ -1245,19 +1225,25 @@ impl Compiler { | |
config.source_file_name.as_deref(), | |
config.output_path, | |
config.inline_sources_content, | |
- config.target, | |
config.source_maps, | |
&source_map_names, | |
orig, | |
- config.minify, | |
config.comments.as_ref().map(|v| v as _), | |
config.emit_source_map_columns, | |
- config | |
- .output | |
- .charset | |
- .map(|v| matches!(v, OutputCharset::Ascii)) | |
- .unwrap_or(false), | |
&config.output.preamble, | |
+ swc_ecma_codegen::Config::default() | |
+ .with_target(config.target) | |
+ .with_minify(config.minify) | |
+ .with_ascii_only( | |
+ config | |
+ .output | |
+ .charset | |
+ .map(|v| matches!(v, OutputCharset::Ascii)) | |
+ .unwrap_or(false), | |
+ ) | |
+ .with_emit_assert_for_import_attributes( | |
+ config.emit_assert_for_import_attributes, | |
+ ), | |
) | |
}) | |
} | |
@@ -1281,7 +1267,7 @@ fn find_swcrc(path: &Path, root: &Path, root_mode: RootMode) -> Option<PathBuf> | |
None | |
} | |
-#[tracing::instrument(level = "info", skip_all)] | |
+#[tracing::instrument(skip_all)] | |
fn load_swcrc(path: &Path) -> Result<Rc, Error> { | |
let content = read_to_string(path).context("failed to read config (.swcrc) file")?; | |
diff --git a/crates/swc/tests/exec.rs b/crates/swc/tests/exec.rs | |
index 6fa8403871..a21cbfe6cd 100644 | |
--- a/crates/swc/tests/exec.rs | |
+++ b/crates/swc/tests/exec.rs | |
@@ -194,7 +194,7 @@ fn create_matrix(entry: &Path) -> Vec<Options> { | |
..Default::default() | |
}, | |
module: if entry.extension().unwrap() == "mjs" { | |
- Some(ModuleConfig::Es6) | |
+ Some(ModuleConfig::Es6(Default::default())) | |
} else { | |
Some(ModuleConfig::CommonJs(Default::default())) | |
}, | |
diff --git a/crates/swc/tests/projects.rs b/crates/swc/tests/projects.rs | |
index 2a2594d519..e49497cf37 100644 | |
--- a/crates/swc/tests/projects.rs | |
+++ b/crates/swc/tests/projects.rs | |
@@ -7,8 +7,8 @@ use anyhow::Context; | |
use rayon::prelude::*; | |
use swc::{ | |
config::{ | |
- BuiltInput, Config, FileMatcher, JsMinifyOptions, JscConfig, ModuleConfig, Options, | |
- SourceMapsConfig, TransformConfig, | |
+ Config, FileMatcher, JsMinifyOptions, JscConfig, ModuleConfig, Options, SourceMapsConfig, | |
+ TransformConfig, | |
}, | |
try_with_handler, BoolOrDataConfig, Compiler, TransformOutput, | |
}; | |
@@ -719,24 +719,7 @@ fn should_visit() { | |
dbg!(config.syntax); | |
- let config = BuiltInput { | |
- program: config.program, | |
- pass: chain!(Panicking, config.pass), | |
- syntax: config.syntax, | |
- target: config.target, | |
- minify: config.minify, | |
- external_helpers: config.external_helpers, | |
- source_maps: config.source_maps, | |
- input_source_map: config.input_source_map, | |
- is_module: config.is_module, | |
- output_path: config.output_path, | |
- source_file_name: config.source_file_name, | |
- preserve_comments: config.preserve_comments, | |
- inline_sources_content: config.inline_sources_content, | |
- comments: config.comments, | |
- emit_source_map_columns: config.emit_source_map_columns, | |
- output: config.output, | |
- }; | |
+ let config = config.with_pass(|pass| chain!(Panicking, pass)); | |
if config.minify { | |
let preserve_excl = |_: &BytePos, vc: &mut Vec<Comment>| -> bool { | |
@@ -760,16 +743,16 @@ fn should_visit() { | |
None, | |
config.output_path, | |
config.inline_sources_content, | |
- config.target, | |
config.source_maps, | |
&Default::default(), | |
None, | |
// TODO: figure out sourcemaps | |
- config.minify, | |
Some(&comments), | |
config.emit_source_map_columns, | |
- false, | |
Default::default(), | |
+ swc_ecma_codegen::Config::default() | |
+ .with_target(config.target) | |
+ .with_minify(config.minify), | |
) | |
.unwrap() | |
.code) | |
@@ -1108,6 +1091,7 @@ fn issue_7513_2() { | |
fm, | |
handler, | |
&JsMinifyOptions { | |
+ module: true, | |
compress: BoolOrDataConfig::from_bool(true), | |
mangle: BoolOrDataConfig::from_obj(MangleOptions { | |
props: None, | |
diff --git a/crates/swc/tests/tsc.rs b/crates/swc/tests/tsc.rs | |
index ecf12920d7..7f2818b953 100644 | |
--- a/crates/swc/tests/tsc.rs | |
+++ b/crates/swc/tests/tsc.rs | |
@@ -315,8 +315,8 @@ fn matrix(input: &Path) -> Vec<TestUnitData> { | |
Self::Umd => ModuleConfig::Umd(Default::default()), | |
Self::Amd => ModuleConfig::Amd(Default::default()), | |
Self::SystemJs => ModuleConfig::SystemJs(Default::default()), | |
- Self::Es6 => ModuleConfig::Es6, | |
- Self::NodeNext => ModuleConfig::NodeNext, | |
+ Self::Es6 => ModuleConfig::Es6(Default::default()), | |
+ Self::NodeNext => ModuleConfig::NodeNext(Default::default()), | |
} | |
} | |
} | |
diff --git a/crates/swc_bundler/examples/bundle.rs b/crates/swc_bundler/examples/bundle.rs | |
index 8e1b606f15..8bbd9d6c02 100644 | |
--- a/crates/swc_bundler/examples/bundle.rs | |
+++ b/crates/swc_bundler/examples/bundle.rs | |
@@ -42,10 +42,7 @@ fn print_bundles(cm: Lrc<SourceMap>, modules: Vec<Bundle>, minify: bool) { | |
{ | |
let wr = JsWriter::new(cm.clone(), "\n", &mut buf, None); | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(true), | |
cm: cm.clone(), | |
comments: None, | |
wr: if minify { | |
diff --git a/crates/swc_bundler/examples/path.rs b/crates/swc_bundler/examples/path.rs | |
index 48ad850d84..7857b6902b 100644 | |
--- a/crates/swc_bundler/examples/path.rs | |
+++ b/crates/swc_bundler/examples/path.rs | |
@@ -46,10 +46,7 @@ fn main() { | |
let wr = stdout(); | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify: false, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default(), | |
cm: cm.clone(), | |
comments: None, | |
wr: Box::new(JsWriter::new(cm, "\n", wr.lock(), None)), | |
diff --git a/crates/swc_bundler/src/bundler/chunk/computed_key.rs b/crates/swc_bundler/src/bundler/chunk/computed_key.rs | |
index 27ea5f3f70..660d1140a3 100644 | |
--- a/crates/swc_bundler/src/bundler/chunk/computed_key.rs | |
+++ b/crates/swc_bundler/src/bundler/chunk/computed_key.rs | |
@@ -84,7 +84,7 @@ where | |
specifiers: vec![specifier], | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
})), | |
)); | |
} | |
diff --git a/crates/swc_bundler/src/bundler/chunk/merge.rs b/crates/swc_bundler/src/bundler/chunk/merge.rs | |
index d8c08cb833..281725d4b8 100644 | |
--- a/crates/swc_bundler/src/bundler/chunk/merge.rs | |
+++ b/crates/swc_bundler/src/bundler/chunk/merge.rs | |
@@ -768,7 +768,7 @@ where | |
specifiers: vec![specifier], | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
))); | |
} | |
@@ -816,7 +816,7 @@ where | |
specifiers: vec![specifier], | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
))); | |
} | |
@@ -883,7 +883,7 @@ where | |
.collect(), | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
})); | |
extra.push(export); | |
continue; | |
@@ -925,7 +925,7 @@ where | |
specifiers: vec![specifier], | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
))); | |
} | |
@@ -1140,7 +1140,7 @@ where | |
span: ns.span, | |
specifiers: vec![specifier], | |
src: None, | |
- asserts: None, | |
+ with: None, | |
type_only: false, | |
}), | |
)); | |
diff --git a/crates/swc_bundler/src/bundler/import/mod.rs b/crates/swc_bundler/src/bundler/import/mod.rs | |
index 7c3a56c98f..be8ab29a2c 100644 | |
--- a/crates/swc_bundler/src/bundler/import/mod.rs | |
+++ b/crates/swc_bundler/src/bundler/import/mod.rs | |
@@ -250,7 +250,7 @@ where | |
specifiers: vec![], | |
src: Box::new(src.clone()), | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}; | |
if self.top_level { | |
@@ -657,7 +657,7 @@ where | |
.collect(), | |
src: Box::new(src), | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}; | |
// if self.top_level { | |
diff --git a/crates/swc_bundler/src/bundler/load.rs b/crates/swc_bundler/src/bundler/load.rs | |
index 19edeb4a91..a50f6d0f2b 100644 | |
--- a/crates/swc_bundler/src/bundler/load.rs | |
+++ b/crates/swc_bundler/src/bundler/load.rs | |
@@ -304,7 +304,7 @@ where | |
specifiers: vec![], | |
src: Box::new(src), | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
true, | |
false, | |
diff --git a/crates/swc_bundler/src/debug/mod.rs b/crates/swc_bundler/src/debug/mod.rs | |
index 372fbcd5a6..eca3c6ae12 100644 | |
--- a/crates/swc_bundler/src/debug/mod.rs | |
+++ b/crates/swc_bundler/src/debug/mod.rs | |
@@ -19,10 +19,7 @@ pub(crate) fn print_hygiene(event: &str, cm: &Lrc<SourceMap>, t: &Module) { | |
writeln!(w, "==================== @ {} ====================", event).unwrap(); | |
Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify: false, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default(), | |
cm: cm.clone(), | |
comments: None, | |
wr: Box::new(JsWriter::new(cm.clone(), "\n", &mut w, None)), | |
diff --git a/crates/swc_bundler/tests/deno.rs b/crates/swc_bundler/tests/deno.rs | |
index 4431ad4eed..ad593a30c7 100644 | |
--- a/crates/swc_bundler/tests/deno.rs | |
+++ b/crates/swc_bundler/tests/deno.rs | |
@@ -1085,10 +1085,7 @@ fn bundle(url: &str, minify: bool) -> String { | |
} | |
Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(minify), | |
cm: cm.clone(), | |
comments: None, | |
wr, | |
diff --git a/crates/swc_common/src/input.rs b/crates/swc_common/src/input.rs | |
index 246a98b1d9..b08277c4ca 100644 | |
--- a/crates/swc_common/src/input.rs | |
+++ b/crates/swc_common/src/input.rs | |
@@ -46,7 +46,10 @@ impl<'a> StringInput<'a> { | |
#[inline] | |
pub fn bump_bytes(&mut self, n: usize) { | |
- self.reset_to(self.last_pos + BytePos(n as u32)); | |
+ unsafe { | |
+ // Safety: We only proceed, not go back. | |
+ self.reset_to(self.last_pos + BytePos(n as u32)); | |
+ } | |
} | |
} | |
@@ -78,7 +81,7 @@ impl<'a> Input for StringInput<'a> { | |
} | |
#[inline] | |
- fn bump(&mut self) { | |
+ unsafe fn bump(&mut self) { | |
if let Some((i, c)) = self.iter.next() { | |
self.last_pos = self.start_pos_of_iter + BytePos((i + c.len_utf8()) as u32); | |
} else { | |
@@ -115,7 +118,7 @@ impl<'a> Input for StringInput<'a> { | |
} | |
#[inline] | |
- fn slice(&mut self, start: BytePos, end: BytePos) -> &str { | |
+ unsafe fn slice(&mut self, start: BytePos, end: BytePos) -> &str { | |
debug_assert!(start <= end, "Cannot slice {:?}..{:?}", start, end); | |
let s = self.orig; | |
@@ -184,7 +187,7 @@ impl<'a> Input for StringInput<'a> { | |
} | |
#[inline] | |
- fn reset_to(&mut self, to: BytePos) { | |
+ unsafe fn reset_to(&mut self, to: BytePos) { | |
let orig = self.orig; | |
let idx = (to - self.orig_start).0 as usize; | |
@@ -197,12 +200,12 @@ impl<'a> Input for StringInput<'a> { | |
#[inline] | |
fn is_byte(&mut self, c: u8) -> bool { | |
- if self.iter.as_str().is_empty() { | |
- false | |
- } else { | |
- // Safety: We checked that `self.iter.as_str().len() > 0` | |
- unsafe { *self.iter.as_str().as_bytes().get_unchecked(0) == c } | |
- } | |
+ self.iter | |
+ .as_str() | |
+ .as_bytes() | |
+ .first() | |
+ .map(|b| *b == c) | |
+ .unwrap_or(false) | |
} | |
#[inline] | |
@@ -233,7 +236,12 @@ pub trait Input: Clone { | |
fn cur(&mut self) -> Option<char>; | |
fn peek(&mut self) -> Option<char>; | |
fn peek_ahead(&mut self) -> Option<char>; | |
- fn bump(&mut self); | |
+ | |
+ /// # Safety | |
+ /// | |
+ /// This should be called only when `cur()` returns `Some`. i.e. | |
+ /// when the Input is not empty. | |
+ unsafe fn bump(&mut self); | |
/// Returns [None] if it's end of input **or** current character is not an | |
/// ascii character. | |
@@ -253,7 +261,11 @@ pub trait Input: Clone { | |
fn last_pos(&self) -> BytePos; | |
- fn slice(&mut self, start: BytePos, end: BytePos) -> &str; | |
+ /// # Safety | |
+ /// | |
+ /// - start should be less than or equal to end. | |
+ /// - start and end should be in the valid range of input. | |
+ unsafe fn slice(&mut self, start: BytePos, end: BytePos) -> &str; | |
/// Takes items from stream, testing each one with predicate. returns the | |
/// range of items which passed predicate. | |
@@ -266,7 +278,10 @@ pub trait Input: Clone { | |
where | |
F: FnMut(char) -> bool; | |
- fn reset_to(&mut self, to: BytePos); | |
+ /// # Safety | |
+ /// | |
+ /// - `to` be in the valid range of input. | |
+ unsafe fn reset_to(&mut self, to: BytePos); | |
/// Implementors can override the method to make it faster. | |
/// | |
@@ -291,7 +306,10 @@ pub trait Input: Clone { | |
#[inline] | |
fn eat_byte(&mut self, c: u8) -> bool { | |
if self.is_byte(c) { | |
- self.bump(); | |
+ unsafe { | |
+ // Safety: We are sure that the input is not empty | |
+ self.bump(); | |
+ } | |
true | |
} else { | |
false | |
@@ -319,13 +337,13 @@ mod tests { | |
#[test] | |
fn src_input_slice_1() { | |
with_test_sess("foo/d", |mut i| { | |
- assert_eq!(i.slice(BytePos(1), BytePos(2)), "f"); | |
+ assert_eq!(unsafe { i.slice(BytePos(1), BytePos(2)) }, "f"); | |
assert_eq!(i.last_pos, BytePos(2)); | |
assert_eq!(i.start_pos_of_iter, BytePos(2)); | |
assert_eq!(i.cur(), Some('o')); | |
- assert_eq!(i.slice(BytePos(2), BytePos(4)), "oo"); | |
- assert_eq!(i.slice(BytePos(1), BytePos(4)), "foo"); | |
+ assert_eq!(unsafe { i.slice(BytePos(2), BytePos(4)) }, "oo"); | |
+ assert_eq!(unsafe { i.slice(BytePos(1), BytePos(4)) }, "foo"); | |
assert_eq!(i.last_pos, BytePos(4)); | |
assert_eq!(i.start_pos_of_iter, BytePos(4)); | |
assert_eq!(i.cur(), Some('/')); | |
@@ -335,11 +353,11 @@ mod tests { | |
#[test] | |
fn src_input_reset_to_1() { | |
with_test_sess("load", |mut i| { | |
- assert_eq!(i.slice(BytePos(1), BytePos(3)), "lo"); | |
+ assert_eq!(unsafe { i.slice(BytePos(1), BytePos(3)) }, "lo"); | |
assert_eq!(i.last_pos, BytePos(3)); | |
assert_eq!(i.start_pos_of_iter, BytePos(3)); | |
assert_eq!(i.cur(), Some('a')); | |
- i.reset_to(BytePos(1)); | |
+ unsafe { i.reset_to(BytePos(1)) }; | |
assert_eq!(i.cur(), Some('l')); | |
assert_eq!(i.last_pos, BytePos(1)); | |
@@ -360,11 +378,15 @@ mod tests { | |
assert_eq!(i.start_pos_of_iter, BytePos(4)); | |
assert_eq!(i.cur(), Some('/')); | |
- i.bump(); | |
+ unsafe { | |
+ i.bump(); | |
+ } | |
assert_eq!(i.last_pos, BytePos(5)); | |
assert_eq!(i.cur(), Some('d')); | |
- i.bump(); | |
+ unsafe { | |
+ i.bump(); | |
+ } | |
assert_eq!(i.last_pos, BytePos(6)); | |
assert_eq!(i.cur(), None); | |
}); | |
diff --git a/crates/swc_common/src/source_map.rs b/crates/swc_common/src/source_map.rs | |
index 1b8c97f8aa..cc121bee11 100644 | |
--- a/crates/swc_common/src/source_map.rs | |
+++ b/crates/swc_common/src/source_map.rs | |
@@ -1266,6 +1266,9 @@ impl SourceMap { | |
Some(ref f) if f.start_pos <= pos && pos < f.end_pos => f, | |
_ => { | |
f = self.lookup_source_file(pos); | |
+ if config.skip(&f.name) { | |
+ continue; | |
+ } | |
src_id = builder.add_source(&config.file_name_to_source(&f.name)); | |
inline_sources_content = config.inline_sources_content(&f.name); | |
@@ -1447,8 +1450,9 @@ pub trait SourceMapGenConfig { | |
true | |
} | |
- fn skip(&self, _f: &FileName) -> bool { | |
- false | |
+ /// By default, we skip internal files. | |
+ fn skip(&self, f: &FileName) -> bool { | |
+ matches!(f, FileName::Internal(..)) | |
} | |
} | |
diff --git a/crates/swc_css_ast/src/at_rule.rs b/crates/swc_css_ast/src/at_rule.rs | |
index 612454ccab..460ad0b509 100644 | |
--- a/crates/swc_css_ast/src/at_rule.rs | |
+++ b/crates/swc_css_ast/src/at_rule.rs | |
@@ -4,8 +4,9 @@ use swc_atoms::{Atom, JsWord}; | |
use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span}; | |
use crate::{ | |
- CustomIdent, CustomPropertyName, DashedIdent, Declaration, Dimension, FamilyName, Function, | |
- Ident, ListOfComponentValues, Number, Percentage, Ratio, SelectorList, SimpleBlock, Str, Url, | |
+ CustomIdent, CustomPropertyName, DashedIdent, Declaration, Dimension, FamilyName, | |
+ ForgivingSelectorList, Function, Ident, ListOfComponentValues, Number, Percentage, Ratio, | |
+ SelectorList, SimpleBlock, Str, Url, | |
}; | |
#[ast_node("AtRule")] | |
@@ -84,6 +85,18 @@ pub enum AtRulePrelude { | |
ContainerPrelude(ContainerCondition), | |
#[tag("CustomMedia")] | |
CustomMediaPrelude(CustomMediaQuery), | |
+ #[tag("ScopeRange")] | |
+ ScopePrelude(ScopeRange), | |
+} | |
+ | |
+#[ast_node("ScopeRange")] | |
+#[derive(Eq, Hash, EqIgnoreSpan)] | |
+pub struct ScopeRange { | |
+ pub span: Span, | |
+ /// https://drafts.csswg.org/css-cascade-6/#typedef-scope-start | |
+ pub scope_start: Option<ForgivingSelectorList>, | |
+ /// https://drafts.csswg.org/css-cascade-6/#typedef-scope-end | |
+ pub scope_end: Option<ForgivingSelectorList>, | |
} | |
#[ast_node] | |
diff --git a/crates/swc_css_codegen/src/lib.rs b/crates/swc_css_codegen/src/lib.rs | |
index f3ff1339ca..dd4bf349ae 100644 | |
--- a/crates/swc_css_codegen/src/lib.rs | |
+++ b/crates/swc_css_codegen/src/lib.rs | |
@@ -324,6 +324,9 @@ where | |
n | |
) | |
} | |
+ AtRulePrelude::ScopePrelude(n) => { | |
+ emit!(self, n); | |
+ } | |
} | |
} | |
@@ -2459,6 +2462,23 @@ where | |
} | |
} | |
+ #[emitter] | |
+ fn emit_scope_range(&mut self, n: &ScopeRange) -> Result { | |
+ if let Some(start) = &n.scope_start { | |
+ formatting_space!(self); | |
+ write_raw!(self, "("); | |
+ emit!(self, start); | |
+ write_raw!(self, ")"); | |
+ } | |
+ if let Some(end) = &n.scope_end { | |
+ write_raw!(self, " to"); | |
+ space!(self); | |
+ write_raw!(self, "("); | |
+ emit!(self, end); | |
+ write_raw!(self, ")"); | |
+ } | |
+ } | |
+ | |
fn emit_list_pseudo_element_selector_children( | |
&mut self, | |
nodes: &[PseudoElementSelectorChildren], | |
diff --git a/crates/swc_css_modules/src/lib.rs b/crates/swc_css_modules/src/lib.rs | |
index 81f4da7056..49678021c4 100644 | |
--- a/crates/swc_css_modules/src/lib.rs | |
+++ b/crates/swc_css_modules/src/lib.rs | |
@@ -204,13 +204,13 @@ where | |
n.visit_mut_children_with(self); | |
if let QualifiedRulePrelude::SelectorList(sel) = &n.prelude { | |
- // | |
- if sel.children.len() == 1 && sel.children[0].children.len() == 1 { | |
- if let ComplexSelectorChildren::CompoundSelector(sel) = &sel.children[0].children[0] | |
- { | |
- if sel.subclass_selectors.len() == 1 { | |
- if let SubclassSelector::Class(class_sel) = &sel.subclass_selectors[0] { | |
- if let Some(composes) = self.data.composes_for_current.take() { | |
+ let composes = self.data.composes_for_current.take(); | |
+ | |
+ for child in &sel.children { | |
+ if let ComplexSelectorChildren::CompoundSelector(sel) = &child.children[0] { | |
+ for subclass_sel in &sel.subclass_selectors { | |
+ if let SubclassSelector::Class(class_sel) = &subclass_sel { | |
+ if let Some(composes) = &composes { | |
let key = self | |
.data | |
.renamed_to_orig | |
@@ -218,7 +218,27 @@ where | |
.cloned(); | |
if let Some(key) = key { | |
- self.result.renamed.entry(key).or_default().extend(composes); | |
+ let mut renamed = self.result.renamed.clone(); | |
+ let class_names = self.result.renamed.entry(key).or_default(); | |
+ | |
+ class_names.extend(composes.clone()); | |
+ | |
+ for composed_class_name in composes.iter() { | |
+ if let CssClassName::Local { name } = composed_class_name { | |
+ if let Some(original_class_name) = | |
+ self.data.renamed_to_orig.get(&name.value) | |
+ { | |
+ class_names.extend( | |
+ renamed | |
+ .entry(original_class_name.clone()) | |
+ .or_default() | |
+ .split_at(1) | |
+ .1 | |
+ .to_vec(), | |
+ ); | |
+ } | |
+ } | |
+ } | |
} | |
} | |
} | |
diff --git a/crates/swc_css_parser/src/error.rs b/crates/swc_css_parser/src/error.rs | |
index 56b0857860..6ebdf85e4c 100644 | |
--- a/crates/swc_css_parser/src/error.rs | |
+++ b/crates/swc_css_parser/src/error.rs | |
@@ -71,6 +71,7 @@ impl Error { | |
ErrorKind::InvalidKeyframesName(s) => { | |
format!("{} is not valid name for keyframes", s).into() | |
} | |
+ ErrorKind::InvalidScopeAtRule => "Invalid @scope at-rule".into(), | |
} | |
} | |
@@ -115,6 +116,7 @@ pub enum ErrorKind { | |
InvalidAnPlusBMicrosyntax, | |
InvalidCustomIdent(JsWord), | |
InvalidKeyframesName(&'static str), | |
+ InvalidScopeAtRule, | |
UnknownAtRuleNotTerminated, | |
} | |
diff --git a/crates/swc_css_parser/src/lexer/mod.rs b/crates/swc_css_parser/src/lexer/mod.rs | |
index 3fb292d6f4..ad05725ceb 100644 | |
--- a/crates/swc_css_parser/src/lexer/mod.rs | |
+++ b/crates/swc_css_parser/src/lexer/mod.rs | |
@@ -139,7 +139,10 @@ where | |
} | |
fn reset(&mut self, state: &Self::State) { | |
- self.input.reset_to(state.pos); | |
+ unsafe { | |
+ // Safety: state.pos is created from a valid position. | |
+ self.input.reset_to(state.pos); | |
+ } | |
} | |
fn take_errors(&mut self) -> Vec<Error> { | |
@@ -199,7 +202,10 @@ where | |
self.cur_pos = self.input.last_pos(); | |
if cur.is_some() { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur is Some | |
+ self.input.bump(); | |
+ } | |
} | |
cur | |
@@ -207,7 +213,11 @@ where | |
#[inline(always)] | |
fn reconsume(&mut self) { | |
- self.input.reset_to(self.cur_pos); | |
+ unsafe { | |
+ // Safety: self.cur_pos is a position generated by self.input, meaning it is | |
+ // valid. | |
+ self.input.reset_to(self.cur_pos); | |
+ } | |
} | |
#[cold] | |
diff --git a/crates/swc_css_parser/src/macros.rs b/crates/swc_css_parser/src/macros.rs | |
index 8aca0cdfe9..4a8f21bb09 100644 | |
--- a/crates/swc_css_parser/src/macros.rs | |
+++ b/crates/swc_css_parser/src/macros.rs | |
@@ -146,4 +146,8 @@ macro_rules! tok { | |
(">") => { | |
swc_css_ast::Token::Delim { value: '>' } | |
}; | |
+ | |
+ ("to") => { | |
+ swc_css_ast::Token::Ident { value: js_word!("to"), .. } | |
+ }; | |
} | |
diff --git a/crates/swc_css_parser/src/parser/at_rules/mod.rs b/crates/swc_css_parser/src/parser/at_rules/mod.rs | |
index 46f25c7a8e..fee6245cc5 100644 | |
--- a/crates/swc_css_parser/src/parser/at_rules/mod.rs | |
+++ b/crates/swc_css_parser/src/parser/at_rules/mod.rs | |
@@ -424,6 +424,15 @@ where | |
None | |
} | |
+ js_word!("scope") => { | |
+ self.input.skip_ws(); | |
+ | |
+ let prelude = AtRulePrelude::ScopePrelude(self.parse()?); | |
+ | |
+ self.input.skip_ws(); | |
+ | |
+ Some(prelude) | |
+ } | |
_ => { | |
return Err(Error::new(Default::default(), ErrorKind::Ignore)); | |
} | |
@@ -756,6 +765,13 @@ where | |
rule_list | |
} | |
+ js_word!("scope") => { | |
+ let rule_list = self.parse_as::<Vec<Rule>>()?; | |
+ let rule_list: Vec<ComponentValue> = | |
+ rule_list.into_iter().map(ComponentValue::from).collect(); | |
+ | |
+ rule_list | |
+ } | |
_ => { | |
return Err(Error::new(Default::default(), ErrorKind::Ignore)); | |
} | |
@@ -2625,3 +2641,67 @@ where | |
}) | |
} | |
} | |
+ | |
+impl<I> Parse<ScopeRange> for Parser<I> | |
+where | |
+ I: ParserInput, | |
+{ | |
+ fn parse(&mut self) -> PResult<ScopeRange> { | |
+ let span = self.input.cur_span(); | |
+ | |
+ if is!(self, EOF) { | |
+ return Ok(ScopeRange { | |
+ span: span!(self, span.lo), | |
+ scope_start: None, | |
+ scope_end: None, | |
+ }); | |
+ } | |
+ | |
+ match cur!(self) { | |
+ tok!("(") => { | |
+ bump!(self); | |
+ let start = self.parse()?; | |
+ expect!(self, ")"); | |
+ self.input.skip_ws(); | |
+ | |
+ let end = if is!(self, EOF) { | |
+ None | |
+ } else if is_case_insensitive_ident!(self, "to") { | |
+ bump!(self); | |
+ self.input.skip_ws(); | |
+ expect!(self, "("); | |
+ let result = self.parse()?; | |
+ expect!(self, ")"); | |
+ Some(result) | |
+ } else { | |
+ None | |
+ }; | |
+ | |
+ Ok(ScopeRange { | |
+ span: span!(self, span.lo), | |
+ scope_start: Some(start), | |
+ scope_end: end, | |
+ }) | |
+ } | |
+ _ => { | |
+ if is_case_insensitive_ident!(self, "to") { | |
+ bump!(self); | |
+ | |
+ self.input.skip_ws(); | |
+ | |
+ expect!(self, "("); | |
+ let end = self.parse()?; | |
+ expect!(self, ")"); | |
+ | |
+ return Ok(ScopeRange { | |
+ span: span!(self, span.lo), | |
+ scope_start: None, | |
+ scope_end: Some(end), | |
+ }); | |
+ } | |
+ | |
+ return Err(Error::new(span, ErrorKind::InvalidScopeAtRule)); | |
+ } | |
+ } | |
+ } | |
+} | |
diff --git a/crates/swc_css_visit/src/lib.rs b/crates/swc_css_visit/src/lib.rs | |
index 672907ad44..e0bbf0ce63 100644 | |
--- a/crates/swc_css_visit/src/lib.rs | |
+++ b/crates/swc_css_visit/src/lib.rs | |
@@ -641,6 +641,13 @@ define!({ | |
LayerPrelude(LayerPrelude), | |
ContainerPrelude(ContainerCondition), | |
CustomMediaPrelude(CustomMediaQuery), | |
+ ScopePrelude(ScopeRange), | |
+ } | |
+ | |
+ pub struct ScopeRange { | |
+ pub span: Span, | |
+ pub scope_start: Option<ForgivingSelectorList>, | |
+ pub scope_end: Option<ForgivingSelectorList>, | |
} | |
pub struct ListOfComponentValues { | |
diff --git a/crates/swc_ecma_ast/src/module_decl.rs b/crates/swc_ecma_ast/src/module_decl.rs | |
index 2de8963636..368299b140 100644 | |
--- a/crates/swc_ecma_ast/src/module_decl.rs | |
+++ b/crates/swc_ecma_ast/src/module_decl.rs | |
@@ -84,7 +84,7 @@ pub struct ImportDecl { | |
pub type_only: bool, | |
#[cfg_attr(feature = "serde-impl", serde(default))] | |
- pub asserts: Option<Box<ObjectLit>>, | |
+ pub with: Option<Box<ObjectLit>>, | |
} | |
impl Take for ImportDecl { | |
@@ -94,7 +94,7 @@ impl Take for ImportDecl { | |
specifiers: Take::dummy(), | |
src: Take::dummy(), | |
type_only: Default::default(), | |
- asserts: Take::dummy(), | |
+ with: Take::dummy(), | |
} | |
} | |
} | |
@@ -113,7 +113,7 @@ pub struct ExportAll { | |
pub type_only: bool, | |
#[cfg_attr(feature = "serde-impl", serde(default))] | |
- pub asserts: Option<Box<ObjectLit>>, | |
+ pub with: Option<Box<ObjectLit>>, | |
} | |
impl Take for ExportAll { | |
@@ -122,7 +122,7 @@ impl Take for ExportAll { | |
span: DUMMY_SP, | |
src: Take::dummy(), | |
type_only: Default::default(), | |
- asserts: Take::dummy(), | |
+ with: Take::dummy(), | |
} | |
} | |
} | |
@@ -144,7 +144,7 @@ pub struct NamedExport { | |
pub type_only: bool, | |
#[cfg_attr(feature = "serde-impl", serde(default))] | |
- pub asserts: Option<Box<ObjectLit>>, | |
+ pub with: Option<Box<ObjectLit>>, | |
} | |
impl Take for NamedExport { | |
@@ -154,7 +154,7 @@ impl Take for NamedExport { | |
specifiers: Take::dummy(), | |
src: Take::dummy(), | |
type_only: Default::default(), | |
- asserts: Take::dummy(), | |
+ with: Take::dummy(), | |
} | |
} | |
} | |
diff --git a/crates/swc_ecma_codegen/src/config.rs b/crates/swc_ecma_codegen/src/config.rs | |
index 204d77a041..90ff3f84d4 100644 | |
--- a/crates/swc_ecma_codegen/src/config.rs | |
+++ b/crates/swc_ecma_codegen/src/config.rs | |
@@ -5,6 +5,7 @@ use swc_ecma_ast::EsVersion; | |
#[derive(Debug, Clone, Copy)] | |
#[cfg_attr(feature = "serde-impl", derive(Serialize, Deserialize))] | |
#[cfg_attr(feature = "serde-impl", serde(rename_all = "camelCase"))] | |
+#[non_exhaustive] | |
pub struct Config { | |
/// The target runtime environment. | |
/// | |
@@ -32,6 +33,9 @@ pub struct Config { | |
/// Defaults to `false`. | |
#[cfg_attr(feature = "serde-impl", serde(default))] | |
pub omit_last_semi: bool, | |
+ | |
+ #[cfg_attr(feature = "serde-impl", serde(default))] | |
+ pub emit_assert_for_import_attributes: bool, | |
} | |
impl Default for Config { | |
@@ -41,6 +45,37 @@ impl Default for Config { | |
minify: false, | |
ascii_only: false, | |
omit_last_semi: false, | |
+ emit_assert_for_import_attributes: false, | |
} | |
} | |
} | |
+ | |
+impl Config { | |
+ pub fn with_target(mut self, target: EsVersion) -> Self { | |
+ self.target = target; | |
+ self | |
+ } | |
+ | |
+ pub fn with_minify(mut self, minify: bool) -> Self { | |
+ self.minify = minify; | |
+ self | |
+ } | |
+ | |
+ pub fn with_ascii_only(mut self, ascii_only: bool) -> Self { | |
+ self.ascii_only = ascii_only; | |
+ self | |
+ } | |
+ | |
+ pub fn with_omit_last_semi(mut self, omit_last_semi: bool) -> Self { | |
+ self.omit_last_semi = omit_last_semi; | |
+ self | |
+ } | |
+ | |
+ pub fn with_emit_assert_for_import_attributes( | |
+ mut self, | |
+ emit_assert_for_import_attributes: bool, | |
+ ) -> Self { | |
+ self.emit_assert_for_import_attributes = emit_assert_for_import_attributes; | |
+ self | |
+ } | |
+} | |
diff --git a/crates/swc_ecma_codegen/src/lib.rs b/crates/swc_ecma_codegen/src/lib.rs | |
index 72a7dc387a..a1522134f8 100644 | |
--- a/crates/swc_ecma_codegen/src/lib.rs | |
+++ b/crates/swc_ecma_codegen/src/lib.rs | |
@@ -308,11 +308,15 @@ where | |
emit!(n.src); | |
- if let Some(asserts) = &n.asserts { | |
+ if let Some(with) = &n.with { | |
formatting_space!(); | |
- keyword!("assert"); | |
+ if self.cfg.emit_assert_for_import_attributes { | |
+ keyword!("assert"); | |
+ } else { | |
+ keyword!("with") | |
+ }; | |
formatting_space!(); | |
- emit!(asserts); | |
+ emit!(with); | |
} | |
semi!(); | |
@@ -451,11 +455,15 @@ where | |
formatting_space!(); | |
emit!(src); | |
- if let Some(asserts) = &node.asserts { | |
+ if let Some(with) = &node.with { | |
formatting_space!(); | |
- keyword!("assert"); | |
+ if self.cfg.emit_assert_for_import_attributes { | |
+ keyword!("assert"); | |
+ } else { | |
+ keyword!("with") | |
+ }; | |
formatting_space!(); | |
- emit!(asserts); | |
+ emit!(with); | |
} | |
} | |
semi!(); | |
@@ -477,11 +485,15 @@ where | |
formatting_space!(); | |
emit!(node.src); | |
- if let Some(asserts) = &node.asserts { | |
+ if let Some(with) = &node.with { | |
formatting_space!(); | |
- keyword!("assert"); | |
+ if self.cfg.emit_assert_for_import_attributes { | |
+ keyword!("assert"); | |
+ } else { | |
+ keyword!("with") | |
+ }; | |
formatting_space!(); | |
- emit!(asserts); | |
+ emit!(with); | |
} | |
semi!(); | |
@@ -1879,12 +1891,23 @@ where | |
} | |
if let Some(ref arg) = node.arg { | |
- if !node.delegate && arg.starts_with_alpha_num() { | |
+ let need_paren = node | |
+ .arg | |
+ .as_deref() | |
+ .map(|expr| self.has_leading_comment(expr)) | |
+ .unwrap_or(false); | |
+ if need_paren { | |
+ punct!("(") | |
+ } else if !node.delegate && arg.starts_with_alpha_num() { | |
space!() | |
} else { | |
formatting_space!() | |
} | |
+ | |
emit!(node.arg); | |
+ if need_paren { | |
+ punct!(")") | |
+ } | |
} | |
} | |
@@ -2743,6 +2766,8 @@ where | |
#[emitter] | |
#[tracing::instrument(skip_all)] | |
fn emit_expr_stmt(&mut self, e: &ExprStmt) -> Result { | |
+ self.emit_leading_comments_of_span(e.span, false)?; | |
+ | |
emit!(e.expr); | |
semi!(); | |
diff --git a/crates/swc_ecma_codegen/tests/fixture.rs b/crates/swc_ecma_codegen/tests/fixture.rs | |
index d162af295e..aba025d528 100644 | |
--- a/crates/swc_ecma_codegen/tests/fixture.rs | |
+++ b/crates/swc_ecma_codegen/tests/fixture.rs | |
@@ -49,10 +49,7 @@ fn run(input: &Path, minify: bool) { | |
} | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(minify), | |
cm, | |
comments: None, | |
wr, | |
diff --git a/crates/swc_ecma_codegen/tests/sourcemap.rs b/crates/swc_ecma_codegen/tests/sourcemap.rs | |
index b8d2e7af2d..dd8358b06d 100644 | |
--- a/crates/swc_ecma_codegen/tests/sourcemap.rs | |
+++ b/crates/swc_ecma_codegen/tests/sourcemap.rs | |
@@ -322,12 +322,10 @@ fn identity(entry: PathBuf) { | |
wr = Box::new(swc_ecma_codegen::text_writer::omit_trailing_semi(wr)); | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify: true, | |
- target: EsVersion::Es5, | |
- ascii_only: true, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default() | |
+ .with_minify(true) | |
+ .with_ascii_only(true) | |
+ .with_target(EsVersion::Es5), | |
cm: cm.clone(), | |
wr, | |
comments: None, | |
diff --git a/crates/swc_ecma_codegen/tests/test262.rs b/crates/swc_ecma_codegen/tests/test262.rs | |
index 8e0b270283..b8e60b4e4a 100644 | |
--- a/crates/swc_ecma_codegen/tests/test262.rs | |
+++ b/crates/swc_ecma_codegen/tests/test262.rs | |
@@ -136,11 +136,9 @@ fn do_test(entry: &Path, minify: bool) { | |
} | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- target: EsVersion::Es5, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default() | |
+ .with_minify(minify) | |
+ .with_target(EsVersion::Es5), | |
cm, | |
wr, | |
comments: if minify { None } else { Some(&comments) }, | |
diff --git a/crates/swc_ecma_dep_graph/src/lib.rs b/crates/swc_ecma_dep_graph/src/lib.rs | |
index db84d697fa..e94780e9a5 100644 | |
--- a/crates/swc_ecma_dep_graph/src/lib.rs | |
+++ b/crates/swc_ecma_dep_graph/src/lib.rs | |
@@ -41,7 +41,7 @@ pub enum ImportAssertion { | |
} | |
#[derive(Clone, Debug, Eq, PartialEq)] | |
-pub enum ImportAssertions { | |
+pub enum ImportAttributes { | |
/// There was no import assertions object literal. | |
None, | |
/// The set of assertion keys could not be statically analyzed. | |
@@ -51,16 +51,16 @@ pub enum ImportAssertions { | |
Known(HashMap<String, ImportAssertion>), | |
} | |
-impl Default for ImportAssertions { | |
+impl Default for ImportAttributes { | |
fn default() -> Self { | |
- ImportAssertions::None | |
+ ImportAttributes::None | |
} | |
} | |
-impl ImportAssertions { | |
+impl ImportAttributes { | |
pub fn get(&self, key: &str) -> Option<&String> { | |
match self { | |
- ImportAssertions::Known(map) => match map.get(key) { | |
+ ImportAttributes::Known(map) => match map.get(key) { | |
Some(ImportAssertion::Known(value)) => Some(value), | |
_ => None, | |
}, | |
@@ -84,7 +84,7 @@ pub struct DependencyDescriptor { | |
/// The span of the specifier. | |
pub specifier_span: Span, | |
/// Import assertions for this dependency. | |
- pub import_assertions: ImportAssertions, | |
+ pub import_attributes: ImportAttributes, | |
} | |
struct DependencyCollector<'a> { | |
@@ -110,7 +110,7 @@ impl<'a> Visit for DependencyCollector<'a> { | |
} else { | |
DependencyKind::Import | |
}; | |
- let import_assertions = parse_import_assertions(node.asserts.as_deref()); | |
+ let import_attributes = parse_import_attributes(node.with.as_deref()); | |
self.items.push(DependencyDescriptor { | |
kind, | |
is_dynamic: false, | |
@@ -118,7 +118,7 @@ impl<'a> Visit for DependencyCollector<'a> { | |
span: node.span, | |
specifier, | |
specifier_span: node.src.span, | |
- import_assertions, | |
+ import_attributes, | |
}); | |
} | |
@@ -131,7 +131,7 @@ impl<'a> Visit for DependencyCollector<'a> { | |
} else { | |
DependencyKind::Export | |
}; | |
- let import_assertions = parse_import_assertions(node.asserts.as_deref()); | |
+ let import_attributes = parse_import_attributes(node.with.as_deref()); | |
self.items.push(DependencyDescriptor { | |
kind, | |
is_dynamic: false, | |
@@ -139,7 +139,7 @@ impl<'a> Visit for DependencyCollector<'a> { | |
span: node.span, | |
specifier, | |
specifier_span: src.span, | |
- import_assertions, | |
+ import_attributes, | |
}); | |
} | |
} | |
@@ -152,7 +152,7 @@ impl<'a> Visit for DependencyCollector<'a> { | |
} else { | |
DependencyKind::Export | |
}; | |
- let import_assertions = parse_import_assertions(node.asserts.as_deref()); | |
+ let import_attributes = parse_import_attributes(node.with.as_deref()); | |
self.items.push(DependencyDescriptor { | |
kind, | |
is_dynamic: false, | |
@@ -160,7 +160,7 @@ impl<'a> Visit for DependencyCollector<'a> { | |
span: node.span, | |
specifier, | |
specifier_span: node.src.span, | |
- import_assertions, | |
+ import_attributes, | |
}); | |
} | |
@@ -175,8 +175,9 @@ impl<'a> Visit for DependencyCollector<'a> { | |
span: node.span, | |
specifier, | |
specifier_span: node.arg.span, | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}); | |
+ node.visit_children_with(self); | |
} | |
fn visit_module_items(&mut self, items: &[ast::ModuleItem]) { | |
@@ -230,7 +231,7 @@ impl<'a> Visit for DependencyCollector<'a> { | |
span: node.span, | |
specifier, | |
specifier_span: str_.span, | |
- import_assertions: dynamic_import_assertions, | |
+ import_attributes: dynamic_import_assertions, | |
}); | |
} | |
} | |
@@ -259,7 +260,7 @@ impl<'a> Visit for DependencyCollector<'a> { | |
span: node.span, | |
specifier, | |
specifier_span: expr.span, | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}); | |
} | |
} | |
@@ -268,13 +269,13 @@ impl<'a> Visit for DependencyCollector<'a> { | |
/// Parses import assertions into a hashmap. According to proposal the values | |
/// can only be strings (https://github.com/tc39/proposal-import-assertions#should-more-than-just-strings-be-supported-as-attribute-values) | |
/// and thus non-string values are skipped. | |
-fn parse_import_assertions(asserts: Option<&ast::ObjectLit>) -> ImportAssertions { | |
- let asserts = match asserts { | |
- Some(asserts) => asserts, | |
- None => return ImportAssertions::None, | |
+fn parse_import_attributes(attrs: Option<&ast::ObjectLit>) -> ImportAttributes { | |
+ let attrs = match attrs { | |
+ Some(with) => with, | |
+ None => return ImportAttributes::None, | |
}; | |
let mut import_assertions = HashMap::new(); | |
- for prop in asserts.props.iter() { | |
+ for prop in attrs.props.iter() { | |
if let ast::PropOrSpread::Prop(prop) = prop { | |
if let ast::Prop::KeyValue(key_value) = &**prop { | |
let maybe_key = match &key_value.key { | |
@@ -292,23 +293,23 @@ fn parse_import_assertions(asserts: Option<&ast::ObjectLit>) -> ImportAssertions | |
} | |
} | |
} | |
- ImportAssertions::Known(import_assertions) | |
+ ImportAttributes::Known(import_assertions) | |
} | |
/// Parses import assertions from the second arg of a dynamic import. | |
-fn parse_dynamic_import_assertions(arg: Option<&ast::ExprOrSpread>) -> ImportAssertions { | |
+fn parse_dynamic_import_assertions(arg: Option<&ast::ExprOrSpread>) -> ImportAttributes { | |
let arg = match arg { | |
Some(arg) => arg, | |
- None => return ImportAssertions::None, | |
+ None => return ImportAttributes::None, | |
}; | |
if arg.spread.is_some() { | |
- return ImportAssertions::Unknown; | |
+ return ImportAttributes::Unknown; | |
} | |
let object_lit = match &*arg.expr { | |
ast::Expr::Object(object_lit) => object_lit, | |
- _ => return ImportAssertions::Unknown, | |
+ _ => return ImportAttributes::Unknown, | |
}; | |
let mut assertions_map = HashMap::new(); | |
@@ -317,37 +318,37 @@ fn parse_dynamic_import_assertions(arg: Option<&ast::ExprOrSpread>) -> ImportAss | |
for prop in object_lit.props.iter() { | |
let prop = match prop { | |
ast::PropOrSpread::Prop(prop) => prop, | |
- _ => return ImportAssertions::Unknown, | |
+ _ => return ImportAttributes::Unknown, | |
}; | |
let key_value = match &**prop { | |
ast::Prop::KeyValue(key_value) => key_value, | |
- _ => return ImportAssertions::Unknown, | |
+ _ => return ImportAttributes::Unknown, | |
}; | |
let key = match &key_value.key { | |
ast::PropName::Str(key) => key.value.to_string(), | |
ast::PropName::Ident(ident) => ident.sym.to_string(), | |
- _ => return ImportAssertions::Unknown, | |
+ _ => return ImportAttributes::Unknown, | |
}; | |
- if key == "assert" { | |
+ if key == "assert" || key == "with" { | |
had_assert_key = true; | |
let assertions_lit = match &*key_value.value { | |
ast::Expr::Object(assertions_lit) => assertions_lit, | |
- _ => return ImportAssertions::Unknown, | |
+ _ => return ImportAttributes::Unknown, | |
}; | |
for prop in assertions_lit.props.iter() { | |
let prop = match prop { | |
ast::PropOrSpread::Prop(prop) => prop, | |
- _ => return ImportAssertions::Unknown, | |
+ _ => return ImportAttributes::Unknown, | |
}; | |
let key_value = match &**prop { | |
ast::Prop::KeyValue(key_value) => key_value, | |
- _ => return ImportAssertions::Unknown, | |
+ _ => return ImportAttributes::Unknown, | |
}; | |
let key = match &key_value.key { | |
ast::PropName::Str(key) => key.value.to_string(), | |
ast::PropName::Ident(ident) => ident.sym.to_string(), | |
- _ => return ImportAssertions::Unknown, | |
+ _ => return ImportAttributes::Unknown, | |
}; | |
if let ast::Expr::Lit(value_lit) = &*key_value.value { | |
assertions_map.insert( | |
@@ -366,9 +367,9 @@ fn parse_dynamic_import_assertions(arg: Option<&ast::ExprOrSpread>) -> ImportAss | |
} | |
if had_assert_key { | |
- ImportAssertions::Known(assertions_map) | |
+ ImportAttributes::Known(assertions_map) | |
} else { | |
- ImportAssertions::None | |
+ ImportAttributes::None | |
} | |
} | |
@@ -477,7 +478,7 @@ try { | |
span: Span::new(BytePos(1), BytePos(34), Default::default()), | |
specifier: JsWord::from("./test.ts"), | |
specifier_span: Span::new(BytePos(22), BytePos(33), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::ImportType, | |
@@ -490,7 +491,7 @@ try { | |
span: Span::new(BytePos(48), BytePos(86), Default::default()), | |
specifier: JsWord::from("./foo.d.ts"), | |
specifier_span: Span::new(BytePos(73), BytePos(85), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Export, | |
@@ -503,7 +504,7 @@ try { | |
span: Span::new(BytePos(115), BytePos(149), Default::default()), | |
specifier: JsWord::from("./buzz.ts"), | |
specifier_span: Span::new(BytePos(137), BytePos(148), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::ExportType, | |
@@ -523,7 +524,7 @@ try { | |
span: Span::new(BytePos(181), BytePos(221), Default::default()), | |
specifier: JsWord::from("./fizz.d.ts"), | |
specifier_span: Span::new(BytePos(207), BytePos(220), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Require, | |
@@ -532,7 +533,7 @@ try { | |
span: Span::new(BytePos(239), BytePos(254), Default::default()), | |
specifier: JsWord::from("path"), | |
specifier_span: Span::new(BytePos(247), BytePos(253), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -541,7 +542,7 @@ try { | |
span: Span::new(BytePos(274), BytePos(293), Default::default()), | |
specifier: JsWord::from("./foo1.ts"), | |
specifier_span: Span::new(BytePos(281), BytePos(292), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -550,7 +551,7 @@ try { | |
span: Span::new(BytePos(324), BytePos(342), Default::default()), | |
specifier: JsWord::from("./foo.ts"), | |
specifier_span: Span::new(BytePos(331), BytePos(341), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Require, | |
@@ -559,7 +560,7 @@ try { | |
span: Span::new(BytePos(395), BytePos(418), Default::default()), | |
specifier: JsWord::from("some_package"), | |
specifier_span: Span::new(BytePos(403), BytePos(417), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::ImportEquals, | |
@@ -568,7 +569,7 @@ try { | |
span: Span::new(BytePos(449), BytePos(491), Default::default()), | |
specifier: JsWord::from("some_package_foo"), | |
specifier_span: Span::new(BytePos(471), BytePos(489), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::ImportType, | |
@@ -577,7 +578,7 @@ try { | |
span: Span::new(BytePos(492), BytePos(547), Default::default()), | |
specifier: JsWord::from("some_package_foo_type"), | |
specifier_span: Span::new(BytePos(522), BytePos(545), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::ExportEquals, | |
@@ -586,7 +587,7 @@ try { | |
span: Span::new(BytePos(548), BytePos(597), Default::default()), | |
specifier: JsWord::from("some_package_bar"), | |
specifier_span: Span::new(BytePos(577), BytePos(595), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Require, | |
@@ -595,7 +596,7 @@ try { | |
span: Span::new(BytePos(612), BytePos(651), Default::default()), | |
specifier: JsWord::from("some_package_resolve"), | |
specifier_span: Span::new(BytePos(628), BytePos(650), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Require, | |
@@ -604,7 +605,7 @@ try { | |
span: Span::new(BytePos(676), BytePos(719), Default::default()), | |
specifier: JsWord::from("some_package_resolve_foo"), | |
specifier_span: Span::new(BytePos(692), BytePos(718), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
] | |
); | |
@@ -630,7 +631,7 @@ const d9 = await import("./d9.json", { assert: { type: "json", ...bar } }); | |
const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" } }); | |
"#; | |
let (module, comments) = helper("test.ts", source).unwrap(); | |
- let expected_assertions1 = ImportAssertions::Known({ | |
+ let expected_assertions1 = ImportAttributes::Known({ | |
let mut map = HashMap::new(); | |
map.insert( | |
"type".to_string(), | |
@@ -638,7 +639,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
); | |
map | |
}); | |
- let expected_assertions2 = ImportAssertions::Known({ | |
+ let expected_assertions2 = ImportAttributes::Known({ | |
let mut map = HashMap::new(); | |
map.insert( | |
"type".to_string(), | |
@@ -646,7 +647,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
); | |
map | |
}); | |
- let dynamic_expected_assertions2 = ImportAssertions::Known({ | |
+ let dynamic_expected_assertions2 = ImportAttributes::Known({ | |
let mut map = HashMap::new(); | |
map.insert( | |
"type".to_string(), | |
@@ -666,7 +667,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(1), BytePos(66), Default::default()), | |
specifier: JsWord::from("./test.ts"), | |
specifier_span: Span::new(BytePos(22), BytePos(33), Default::default()), | |
- import_assertions: expected_assertions1.clone(), | |
+ import_attributes: expected_assertions1.clone(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Export, | |
@@ -675,7 +676,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(67), BytePos(125), Default::default()), | |
specifier: JsWord::from("./test.ts"), | |
specifier_span: Span::new(BytePos(81), BytePos(92), Default::default()), | |
- import_assertions: expected_assertions1, | |
+ import_attributes: expected_assertions1, | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Export, | |
@@ -684,7 +685,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(126), BytePos(186), Default::default()), | |
specifier: JsWord::from("./test.json"), | |
specifier_span: Span::new(BytePos(146), BytePos(159), Default::default()), | |
- import_assertions: expected_assertions2.clone(), | |
+ import_attributes: expected_assertions2.clone(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -693,7 +694,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(187), BytePos(240), Default::default()), | |
specifier: JsWord::from("./foo.json"), | |
specifier_span: Span::new(BytePos(203), BytePos(215), Default::default()), | |
- import_assertions: expected_assertions2, | |
+ import_attributes: expected_assertions2, | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -702,7 +703,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(260), BytePos(313), Default::default()), | |
specifier: JsWord::from("./fizz.json"), | |
specifier_span: Span::new(BytePos(267), BytePos(280), Default::default()), | |
- import_assertions: dynamic_expected_assertions2.clone(), | |
+ import_attributes: dynamic_expected_assertions2.clone(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -711,7 +712,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(334), BytePos(387), Default::default()), | |
specifier: JsWord::from("./buzz.json"), | |
specifier_span: Span::new(BytePos(341), BytePos(354), Default::default()), | |
- import_assertions: dynamic_expected_assertions2, | |
+ import_attributes: dynamic_expected_assertions2, | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -720,7 +721,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(406), BytePos(425), Default::default()), | |
specifier: JsWord::from("./d1.json"), | |
specifier_span: Span::new(BytePos(413), BytePos(424), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -729,7 +730,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(444), BytePos(467), Default::default()), | |
specifier: JsWord::from("./d2.json"), | |
specifier_span: Span::new(BytePos(451), BytePos(462), Default::default()), | |
- import_assertions: Default::default(), | |
+ import_attributes: Default::default(), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -738,7 +739,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(486), BytePos(510), Default::default()), | |
specifier: JsWord::from("./d3.json"), | |
specifier_span: Span::new(BytePos(493), BytePos(504), Default::default()), | |
- import_assertions: ImportAssertions::Unknown, | |
+ import_attributes: ImportAttributes::Unknown, | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -747,7 +748,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(529), BytePos(564), Default::default()), | |
specifier: JsWord::from("./d4.json"), | |
specifier_span: Span::new(BytePos(536), BytePos(547), Default::default()), | |
- import_assertions: ImportAssertions::Known(HashMap::new()), | |
+ import_attributes: ImportAttributes::Known(HashMap::new()), | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -756,7 +757,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(583), BytePos(619), Default::default()), | |
specifier: JsWord::from("./d5.json"), | |
specifier_span: Span::new(BytePos(590), BytePos(601), Default::default()), | |
- import_assertions: ImportAssertions::Unknown, | |
+ import_attributes: ImportAttributes::Unknown, | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -765,7 +766,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(638), BytePos(681), Default::default()), | |
specifier: JsWord::from("./d6.json"), | |
specifier_span: Span::new(BytePos(645), BytePos(656), Default::default()), | |
- import_assertions: ImportAssertions::Unknown, | |
+ import_attributes: ImportAttributes::Unknown, | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -774,7 +775,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(700), BytePos(754), Default::default()), | |
specifier: JsWord::from("./d7.json"), | |
specifier_span: Span::new(BytePos(707), BytePos(718), Default::default()), | |
- import_assertions: ImportAssertions::Unknown, | |
+ import_attributes: ImportAttributes::Unknown, | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -783,7 +784,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(773), BytePos(819), Default::default()), | |
specifier: JsWord::from("./d8.json"), | |
specifier_span: Span::new(BytePos(780), BytePos(791), Default::default()), | |
- import_assertions: ImportAssertions::Known({ | |
+ import_attributes: ImportAttributes::Known({ | |
let mut map = HashMap::new(); | |
map.insert("type".to_string(), ImportAssertion::Unknown); | |
map | |
@@ -796,7 +797,7 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(838), BytePos(895), Default::default()), | |
specifier: JsWord::from("./d9.json"), | |
specifier_span: Span::new(BytePos(845), BytePos(856), Default::default()), | |
- import_assertions: ImportAssertions::Unknown, | |
+ import_attributes: ImportAttributes::Unknown, | |
}, | |
DependencyDescriptor { | |
kind: DependencyKind::Import, | |
@@ -805,9 +806,52 @@ const d10 = await import("./d10.json", { assert: { type: "json", ["type"]: "bad" | |
span: Span::new(BytePos(915), BytePos(982), Default::default()), | |
specifier: JsWord::from("./d10.json"), | |
specifier_span: Span::new(BytePos(922), BytePos(934), Default::default()), | |
- import_assertions: ImportAssertions::Unknown, | |
+ import_attributes: ImportAttributes::Unknown, | |
}, | |
] | |
); | |
} | |
+ | |
+ #[test] | |
+ fn ts_import_object_lit_property() { | |
+ let source = r#" | |
+export declare const SomeValue: typeof Core & import("./a.d.ts").Constructor<{ | |
+ paginate: import("./b.d.ts").PaginateInterface; | |
+} & import("./c.d.ts").RestEndpointMethods>; | |
+"#; | |
+ let (module, comments) = helper("test.ts", source).unwrap(); | |
+ let dependencies = analyze_dependencies(&module, &comments); | |
+ assert_eq!( | |
+ dependencies, | |
+ vec![ | |
+ DependencyDescriptor { | |
+ kind: DependencyKind::ImportType, | |
+ is_dynamic: false, | |
+ leading_comments: Vec::new(), | |
+ span: Span::new(BytePos(48), BytePos(176), Default::default()), | |
+ specifier: JsWord::from("./a.d.ts"), | |
+ specifier_span: Span::new(BytePos(55), BytePos(65), Default::default()), | |
+ import_attributes: ImportAttributes::None, | |
+ }, | |
+ DependencyDescriptor { | |
+ kind: DependencyKind::ImportType, | |
+ is_dynamic: false, | |
+ leading_comments: Vec::new(), | |
+ span: Span::new(BytePos(95), BytePos(131), Default::default()), | |
+ specifier: JsWord::from("./b.d.ts"), | |
+ specifier_span: Span::new(BytePos(102), BytePos(112), Default::default()), | |
+ import_attributes: ImportAttributes::None, | |
+ }, | |
+ DependencyDescriptor { | |
+ kind: DependencyKind::ImportType, | |
+ is_dynamic: false, | |
+ leading_comments: Vec::new(), | |
+ span: Span::new(BytePos(137), BytePos(175), Default::default()), | |
+ specifier: JsWord::from("./c.d.ts"), | |
+ specifier_span: Span::new(BytePos(144), BytePos(154), Default::default()), | |
+ import_attributes: ImportAttributes::None, | |
+ } | |
+ ] | |
+ ); | |
+ } | |
} | |
diff --git a/crates/swc_ecma_loader/src/resolvers/node.rs b/crates/swc_ecma_loader/src/resolvers/node.rs | |
index 94a3468f51..80ade412a9 100644 | |
--- a/crates/swc_ecma_loader/src/resolvers/node.rs | |
+++ b/crates/swc_ecma_loader/src/resolvers/node.rs | |
@@ -103,6 +103,7 @@ pub struct NodeModulesResolver { | |
alias: AHashMap<String, String>, | |
// if true do not resolve symlink | |
preserve_symlinks: bool, | |
+ ignore_node_modules: bool, | |
} | |
static EXTENSIONS: &[&str] = &["ts", "tsx", "js", "jsx", "json", "node"]; | |
@@ -118,6 +119,21 @@ impl NodeModulesResolver { | |
target_env, | |
alias, | |
preserve_symlinks, | |
+ ignore_node_modules: false, | |
+ } | |
+ } | |
+ | |
+ /// Create a node modules resolver which does not care about `node_modules` | |
+ pub fn without_node_modules( | |
+ target_env: TargetEnv, | |
+ alias: AHashMap<String, String>, | |
+ preserve_symlinks: bool, | |
+ ) -> Self { | |
+ Self { | |
+ target_env, | |
+ alias, | |
+ preserve_symlinks, | |
+ ignore_node_modules: true, | |
} | |
} | |
@@ -369,6 +385,10 @@ impl NodeModulesResolver { | |
base_dir: &Path, | |
target: &str, | |
) -> Result<Option<PathBuf>, Error> { | |
+ if self.ignore_node_modules { | |
+ return Ok(None); | |
+ } | |
+ | |
let absolute_path = to_absolute_path(base_dir)?; | |
let mut path = Some(&*absolute_path); | |
while let Some(dir) = path { | |
@@ -394,7 +414,7 @@ impl NodeModulesResolver { | |
impl Resolve for NodeModulesResolver { | |
fn resolve(&self, base: &FileName, target: &str) -> Result<FileName, Error> { | |
debug!( | |
- "Resolve {} from {:#?} for {:#?}", | |
+ "Resolving {} from {:#?} for {:#?}", | |
target, base, self.target_env | |
); | |
diff --git a/crates/swc_ecma_loader/src/resolvers/tsc.rs b/crates/swc_ecma_loader/src/resolvers/tsc.rs | |
index 995afaf87a..357c5550f0 100644 | |
--- a/crates/swc_ecma_loader/src/resolvers/tsc.rs | |
+++ b/crates/swc_ecma_loader/src/resolvers/tsc.rs | |
@@ -1,8 +1,8 @@ | |
-use std::path::{Component, PathBuf}; | |
+use std::path::{Component, Path, PathBuf}; | |
use anyhow::{bail, Context, Error}; | |
use swc_common::FileName; | |
-use tracing::{debug, info, trace, Level}; | |
+use tracing::{debug, info, trace, warn, Level}; | |
use crate::resolve::Resolve; | |
@@ -99,6 +99,58 @@ where | |
paths, | |
} | |
} | |
+ | |
+ fn invoke_inner_resolver( | |
+ &self, | |
+ base: &FileName, | |
+ module_specifier: &str, | |
+ ) -> Result<FileName, Error> { | |
+ let res = self.inner.resolve(base, module_specifier).with_context(|| { | |
+ format!( | |
+ "failed to resolve `{module_specifier}` from `{base}` using inner \ | |
+ resolver\nbase_url={}", | |
+ self.base_url_filename | |
+ ) | |
+ }); | |
+ | |
+ match res { | |
+ Ok(resolved) => { | |
+ info!( | |
+ "Resolved `{}` as `{}` from `{}`", | |
+ module_specifier, resolved, base | |
+ ); | |
+ | |
+ let is_base_in_node_modules = if let FileName::Real(v) = base { | |
+ v.components().any(|c| match c { | |
+ Component::Normal(v) => v == "node_modules", | |
+ _ => false, | |
+ }) | |
+ } else { | |
+ false | |
+ }; | |
+ let is_target_in_node_modules = if let FileName::Real(v) = &resolved { | |
+ v.components().any(|c| match c { | |
+ Component::Normal(v) => v == "node_modules", | |
+ _ => false, | |
+ }) | |
+ } else { | |
+ false | |
+ }; | |
+ | |
+ // If node_modules is in path, we should return module specifier. | |
+ if !is_base_in_node_modules && is_target_in_node_modules { | |
+ return Ok(FileName::Real(module_specifier.into())); | |
+ } | |
+ | |
+ Ok(resolved) | |
+ } | |
+ | |
+ Err(err) => { | |
+ warn!("{:?}", err); | |
+ Err(err) | |
+ } | |
+ } | |
+ } | |
} | |
impl<R> Resolve for TsConfigResolver<R> | |
@@ -110,7 +162,7 @@ where | |
Some( | |
tracing::span!( | |
Level::ERROR, | |
- "tsc.resolve", | |
+ "TsConfigResolver::resolve", | |
base_url = tracing::field::display(self.base_url.display()), | |
base = tracing::field::display(base), | |
src = tracing::field::display(module_specifier), | |
@@ -127,30 +179,29 @@ where | |
|| module_specifier.starts_with("../")) | |
{ | |
return self | |
- .inner | |
- .resolve(base, module_specifier) | |
+ .invoke_inner_resolver(base, module_specifier) | |
.context("not processed by tsc resolver because it's relative import"); | |
} | |
- if cfg!(debug_assertions) { | |
- debug!("non-relative import"); | |
- } | |
- | |
if let FileName::Real(v) = base { | |
if v.components().any(|c| match c { | |
Component::Normal(v) => v == "node_modules", | |
_ => false, | |
}) { | |
- return self.inner.resolve(base, module_specifier).context( | |
+ return self.invoke_inner_resolver(base, module_specifier).context( | |
"not processed by tsc resolver because base module is in node_modules", | |
); | |
} | |
} | |
+ info!("Checking `jsc.paths`"); | |
+ | |
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping | |
for (from, to) in &self.paths { | |
match from { | |
Pattern::Wildcard { prefix } => { | |
+ debug!("Checking `{}` in `jsc.paths`", prefix); | |
+ | |
let extra = module_specifier.strip_prefix(prefix); | |
let extra = match extra { | |
Some(v) => v, | |
@@ -163,35 +214,53 @@ where | |
}; | |
if cfg!(debug_assertions) { | |
- trace!("extra = {}", extra); | |
+ debug!("Extra: `{}`", extra); | |
} | |
let mut errors = vec![]; | |
for target in to { | |
let mut replaced = target.replace('*', extra); | |
- let rel = format!("./{}", replaced); | |
- let res = self.inner.resolve(base, &rel).with_context(|| { | |
- format!( | |
- "failed to resolve `{}`, which is expanded from `{}`", | |
- replaced, module_specifier | |
+ let _tracing = if cfg!(debug_assertions) { | |
+ Some( | |
+ tracing::span!( | |
+ Level::ERROR, | |
+ "TsConfigResolver::resolve::jsc.paths", | |
+ replaced = tracing::field::display(&replaced), | |
+ ) | |
+ .entered(), | |
) | |
- }); | |
+ } else { | |
+ None | |
+ }; | |
+ | |
+ let relative = format!("./{}", replaced); | |
+ | |
+ let res = self | |
+ .invoke_inner_resolver(base, module_specifier) | |
+ .or_else(|_| { | |
+ self.invoke_inner_resolver(&self.base_url_filename, &relative) | |
+ }) | |
+ .or_else(|_| { | |
+ self.invoke_inner_resolver(&self.base_url_filename, &replaced) | |
+ }); | |
errors.push(match res { | |
- Ok(v) => return Ok(v), | |
+ Ok(resolved) => return Ok(resolved), | |
Err(err) => err, | |
}); | |
if cfg!(target_os = "windows") { | |
- if replaced.starts_with("./") { | |
- replaced = replaced[2..].to_string(); | |
- } | |
replaced = replaced.replace('/', "\\"); | |
} | |
if to.len() == 1 { | |
- return Ok(FileName::Real(self.base_url.join(replaced))); | |
+ info!( | |
+ "Using `{}` for `{}` because the length of the jsc.paths entry is \ | |
+ 1", | |
+ replaced, module_specifier | |
+ ); | |
+ return Ok(FileName::Real(replaced.into())); | |
} | |
} | |
@@ -204,33 +273,29 @@ where | |
} | |
Pattern::Exact(from) => { | |
// Should be exactly matched | |
- if module_specifier == from { | |
- let replaced = self.base_url.join(&to[0]); | |
- if replaced.exists() { | |
- return Ok(FileName::Real(replaced)); | |
- } | |
+ if module_specifier != from { | |
+ continue; | |
+ } | |
- return self | |
- .inner | |
- .resolve(base, &format!("./{}", &to[0])) | |
- .with_context(|| { | |
- format!( | |
- "tried to resolve `{}` because `{}` was exactly matched", | |
- to[0], from | |
- ) | |
- }); | |
+ let tp = Path::new(&to[0]); | |
+ if tp.is_absolute() { | |
+ return Ok(FileName::Real(tp.into())); | |
} | |
+ | |
+ if let Ok(res) = self.resolve(&self.base_url_filename, &format!("./{}", &to[0])) | |
+ { | |
+ return Ok(res); | |
+ } | |
+ | |
+ return Ok(FileName::Real(self.base_url.join(&to[0]))); | |
} | |
} | |
} | |
- if let Ok(v) = self | |
- .inner | |
- .resolve(&self.base_url_filename, module_specifier) | |
- { | |
+ if let Ok(v) = self.invoke_inner_resolver(&self.base_url_filename, module_specifier) { | |
return Ok(v); | |
} | |
- self.inner.resolve(base, module_specifier) | |
+ self.invoke_inner_resolver(base, module_specifier) | |
} | |
} | |
diff --git a/crates/swc_ecma_loader/tests/tsc_resolver.rs b/crates/swc_ecma_loader/tests/tsc_resolver.rs | |
index 220563e77e..5ff4cd0c68 100644 | |
--- a/crates/swc_ecma_loader/tests/tsc_resolver.rs | |
+++ b/crates/swc_ecma_loader/tests/tsc_resolver.rs | |
@@ -38,14 +38,8 @@ fn exact() { | |
} | |
{ | |
- let err = r | |
- .resolve(&FileName::Anon, "unrelated") | |
+ r.resolve(&FileName::Anon, "unrelated") | |
.expect_err("should not touch error"); | |
- | |
- assert!( | |
- err.source().is_none(), | |
- "should not touch error if src is not related" | |
- ); | |
} | |
} | |
diff --git a/crates/swc_ecma_minifier/benches/full.rs b/crates/swc_ecma_minifier/benches/full.rs | |
index f0c0935256..17eba4f4e7 100644 | |
--- a/crates/swc_ecma_minifier/benches/full.rs | |
+++ b/crates/swc_ecma_minifier/benches/full.rs | |
@@ -112,10 +112,7 @@ fn print<N: swc_ecma_codegen::Node>(cm: Lrc<SourceMap>, nodes: &[N], minify: boo | |
{ | |
let mut emitter = swc_ecma_codegen::Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(minify), | |
cm: cm.clone(), | |
comments: None, | |
wr: Box::new(JsWriter::new(cm, "\n", &mut buf, None)), | |
diff --git a/crates/swc_ecma_minifier/examples/compress.rs b/crates/swc_ecma_minifier/examples/compress.rs | |
index f141fc2345..705ac90247 100644 | |
--- a/crates/swc_ecma_minifier/examples/compress.rs | |
+++ b/crates/swc_ecma_minifier/examples/compress.rs | |
@@ -75,10 +75,7 @@ fn print<N: swc_ecma_codegen::Node>(cm: Lrc<SourceMap>, nodes: &[N], minify: boo | |
{ | |
let mut emitter = swc_ecma_codegen::Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(minify), | |
cm: cm.clone(), | |
comments: None, | |
wr: Box::new(JsWriter::new(cm, "\n", &mut buf, None)), | |
diff --git a/crates/swc_ecma_minifier/examples/minifier.rs b/crates/swc_ecma_minifier/examples/minifier.rs | |
index 73708705cb..395f6ebdd2 100644 | |
--- a/crates/swc_ecma_minifier/examples/minifier.rs | |
+++ b/crates/swc_ecma_minifier/examples/minifier.rs | |
@@ -76,10 +76,7 @@ fn print<N: swc_ecma_codegen::Node>(cm: Lrc<SourceMap>, nodes: &[N], minify: boo | |
{ | |
let mut emitter = swc_ecma_codegen::Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(minify), | |
cm: cm.clone(), | |
comments: None, | |
wr: omit_trailing_semi(JsWriter::new(cm, "\n", &mut buf, None)), | |
diff --git a/crates/swc_ecma_minifier/examples/minify-all.rs b/crates/swc_ecma_minifier/examples/minify-all.rs | |
index a770bc11b0..6a94bbcecc 100644 | |
--- a/crates/swc_ecma_minifier/examples/minify-all.rs | |
+++ b/crates/swc_ecma_minifier/examples/minify-all.rs | |
@@ -122,10 +122,7 @@ fn print<N: swc_ecma_codegen::Node>(cm: Lrc<SourceMap>, nodes: &[N], minify: boo | |
{ | |
let mut emitter = swc_ecma_codegen::Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(minify), | |
cm: cm.clone(), | |
comments: None, | |
wr: Box::new(JsWriter::new(cm, "\n", &mut buf, None)), | |
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/dead_code.rs b/crates/swc_ecma_minifier/src/compress/optimize/dead_code.rs | |
index 79f94304d1..614a2fc5a4 100644 | |
--- a/crates/swc_ecma_minifier/src/compress/optimize/dead_code.rs | |
+++ b/crates/swc_ecma_minifier/src/compress/optimize/dead_code.rs | |
@@ -47,7 +47,6 @@ impl Optimizer<'_> { | |
// We only handle identifiers on lhs for now. | |
if let Some(lhs) = assign.left.as_ident() { | |
- // | |
if self | |
.data | |
.vars | |
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs b/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs | |
index d671f5ef38..77aa659d64 100644 | |
--- a/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs | |
+++ b/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs | |
@@ -40,7 +40,7 @@ impl Optimizer<'_> { | |
let usage = self.data.vars.get(&obj.to_id())?; | |
- if usage.reassigned() { | |
+ if usage.reassigned { | |
return None; | |
} | |
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/iife.rs b/crates/swc_ecma_minifier/src/compress/optimize/iife.rs | |
index 21063b5f71..7b7eeece51 100644 | |
--- a/crates/swc_ecma_minifier/src/compress/optimize/iife.rs | |
+++ b/crates/swc_ecma_minifier/src/compress/optimize/iife.rs | |
@@ -181,7 +181,7 @@ impl Optimizer<'_> { | |
match &mut **param { | |
Pat::Ident(param) => { | |
if let Some(usage) = self.data.vars.get(¶m.to_id()) { | |
- if usage.reassigned() { | |
+ if usage.reassigned { | |
continue; | |
} | |
if usage.ref_count != 1 { | |
@@ -222,7 +222,7 @@ impl Optimizer<'_> { | |
Pat::Rest(rest_pat) => { | |
if let Pat::Ident(param_id) = &*rest_pat.arg { | |
if let Some(usage) = self.data.vars.get(¶m_id.to_id()) { | |
- if usage.reassigned() | |
+ if usage.reassigned | |
|| usage.ref_count != 1 | |
|| !usage.has_property_access | |
{ | |
@@ -906,7 +906,7 @@ impl Optimizer<'_> { | |
if let Some(arg) = arg { | |
if let Some(usage) = self.data.vars.get(&orig_params[idx].to_id()) { | |
if usage.ref_count == 1 | |
- && !usage.reassigned() | |
+ && !usage.reassigned | |
&& !usage.has_property_mutation | |
&& matches!( | |
&*arg, | |
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/inline.rs b/crates/swc_ecma_minifier/src/compress/optimize/inline.rs | |
index 2e12bdb081..0bd90c936e 100644 | |
--- a/crates/swc_ecma_minifier/src/compress/optimize/inline.rs | |
+++ b/crates/swc_ecma_minifier/src/compress/optimize/inline.rs | |
@@ -98,9 +98,7 @@ impl Optimizer<'_> { | |
// | |
// TODO: Allow `length` in usage.accessed_props | |
if usage.declared | |
- && !usage.reassigned() | |
- && !usage.mutated | |
- && !usage.has_property_mutation | |
+ && !usage.mutated() | |
&& usage.accessed_props.is_empty() | |
&& !usage.is_infected() | |
&& is_inline_enabled | |
@@ -153,7 +151,7 @@ impl Optimizer<'_> { | |
} | |
} | |
- if !usage.reassigned() { | |
+ if !usage.reassigned { | |
match init { | |
Expr::Fn(..) | Expr::Arrow(..) => { | |
self.typeofs.insert(ident.to_id(), js_word!("function")); | |
@@ -165,7 +163,7 @@ impl Optimizer<'_> { | |
} | |
} | |
- if !usage.mutated { | |
+ if !usage.mutated() { | |
self.mode.store(ident.to_id(), &*init); | |
} | |
@@ -177,7 +175,8 @@ impl Optimizer<'_> { | |
// new variant is added for multi inline, think carefully | |
if is_inline_enabled | |
&& usage.declared_count == 1 | |
- && usage.can_inline_var() | |
+ && usage.assign_count == 0 | |
+ && (!usage.has_property_mutation || !usage.reassigned) | |
&& match init { | |
Expr::Ident(Ident { | |
sym: js_word!("eval"), | |
@@ -188,7 +187,7 @@ impl Optimizer<'_> { | |
if !usage.assigned_fn_local { | |
false | |
} else if let Some(u) = self.data.vars.get(&id.to_id()) { | |
- let mut should_inline = !u.reassigned() && u.declared; | |
+ let mut should_inline = !u.reassigned && u.declared; | |
should_inline &= | |
// Function declarations are hoisted | |
@@ -322,8 +321,8 @@ impl Optimizer<'_> { | |
&& is_inline_enabled | |
&& usage.declared | |
&& may_remove | |
- && !usage.reassigned() | |
- && (usage.can_inline_var() || usage.is_mutated_only_by_one_call()) | |
+ && !usage.reassigned | |
+ && usage.assign_count == 0 | |
&& ref_count == 1 | |
{ | |
match init { | |
@@ -371,7 +370,7 @@ impl Optimizer<'_> { | |
continue; | |
} | |
if let Some(v_usage) = self.data.vars.get(&id) { | |
- if v_usage.reassigned() { | |
+ if v_usage.reassigned { | |
return; | |
} | |
} else { | |
@@ -388,7 +387,7 @@ impl Optimizer<'_> { | |
continue; | |
} | |
if let Some(v_usage) = self.data.vars.get(&id) { | |
- if v_usage.reassigned() { | |
+ if v_usage.reassigned { | |
return; | |
} | |
} else { | |
@@ -400,7 +399,7 @@ impl Optimizer<'_> { | |
Expr::Object(..) if self.options.pristine_globals => { | |
for id in idents_used_by_ignoring_nested(init) { | |
if let Some(v_usage) = self.data.vars.get(&id) { | |
- if v_usage.reassigned() { | |
+ if v_usage.reassigned { | |
return; | |
} | |
} | |
@@ -413,7 +412,7 @@ impl Optimizer<'_> { | |
} | |
if let Some(init_usage) = self.data.vars.get(&id.to_id()) { | |
- if init_usage.reassigned() || !init_usage.declared { | |
+ if init_usage.reassigned || !init_usage.declared { | |
return; | |
} | |
} | |
@@ -422,7 +421,7 @@ impl Optimizer<'_> { | |
_ => { | |
for id in idents_used_by(init) { | |
if let Some(v_usage) = self.data.vars.get(&id) { | |
- if v_usage.reassigned() || v_usage.has_property_mutation { | |
+ if v_usage.reassigned || v_usage.has_property_mutation { | |
return; | |
} | |
} | |
@@ -534,7 +533,7 @@ impl Optimizer<'_> { | |
} | |
if let Some(usage) = self.data.vars.get(&i.to_id()) { | |
- if !usage.reassigned() { | |
+ if !usage.reassigned { | |
trace_op!("typeofs: Storing typeof `{}{:?}`", i.sym, i.span.ctxt); | |
match &*decl { | |
Decl::Fn(..) => { | |
@@ -601,10 +600,10 @@ impl Optimizer<'_> { | |
return; | |
} | |
- if usage.reassigned() || usage.inline_prevented { | |
+ if usage.reassigned || usage.inline_prevented { | |
log_abort!( | |
"inline: [x] reassigned = {}, inline_prevented = {}", | |
- usage.reassigned(), | |
+ usage.reassigned, | |
usage.inline_prevented | |
); | |
return; | |
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs | |
index cabd31c354..f9f5ce88db 100644 | |
--- a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs | |
+++ b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs | |
@@ -318,6 +318,10 @@ impl From<&Function> for FnMetadata { | |
impl Optimizer<'_> { | |
fn may_remove_ident(&self, id: &Ident) -> bool { | |
+ if self.ctx.is_exported { | |
+ return false; | |
+ } | |
+ | |
if id.span.ctxt != self.marks.top_level_ctxt { | |
return true; | |
} | |
@@ -842,7 +846,7 @@ impl Optimizer<'_> { | |
if let Expr::Ident(callee) = &**callee { | |
if self.options.reduce_vars && self.options.side_effects { | |
if let Some(usage) = self.data.vars.get(&callee.to_id()) { | |
- if !usage.reassigned() && usage.pure_fn { | |
+ if !usage.reassigned && usage.pure_fn { | |
self.changed = true; | |
report_change!("Reducing function call to a variable"); | |
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/props.rs b/crates/swc_ecma_minifier/src/compress/optimize/props.rs | |
index fd8fcba54b..fc529c4b5a 100644 | |
--- a/crates/swc_ecma_minifier/src/compress/optimize/props.rs | |
+++ b/crates/swc_ecma_minifier/src/compress/optimize/props.rs | |
@@ -29,13 +29,11 @@ impl Optimizer<'_> { | |
.vars | |
.get(&name.to_id()) | |
.map(|v| { | |
- !v.mutated | |
- && v.mutation_by_call_count == 0 | |
+ !v.mutated() | |
&& !v.used_as_ref | |
&& !v.used_as_arg | |
&& !v.used_in_cond | |
&& (!v.is_fn_local || !self.mode.should_be_very_correct()) | |
- && !v.reassigned() | |
&& !v.is_infected() | |
}) | |
.unwrap_or(false) | |
@@ -153,8 +151,7 @@ impl Optimizer<'_> { | |
.map(|v| { | |
v.ref_count == 1 | |
&& v.has_property_access | |
- && !v.mutated | |
- && v.mutation_by_call_count == 0 | |
+ && !v.mutated() | |
&& v.is_fn_local | |
&& !v.executed_multiple_time | |
&& !v.used_as_arg | |
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs | |
index bf24de9006..aa2d29ec36 100644 | |
--- a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs | |
+++ b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs | |
@@ -1469,7 +1469,7 @@ impl Optimizer<'_> { | |
} | |
_ => a.may_have_side_effects(&self.expr_ctx), | |
}; | |
- if has_side_effect && !usgae.is_fn_local && (usgae.exported || usgae.reassigned()) { | |
+ if has_side_effect && !usgae.is_fn_local && (usgae.exported || usgae.reassigned) { | |
log_abort!("a (expr) has side effect"); | |
return false; | |
} | |
@@ -1478,7 +1478,7 @@ impl Optimizer<'_> { | |
if let Some(init) = &a.init { | |
if init.may_have_side_effects(&self.expr_ctx) | |
&& !usgae.is_fn_local | |
- && (usgae.exported || usgae.reassigned()) | |
+ && (usgae.exported || usgae.reassigned) | |
{ | |
log_abort!("a (var) init has side effect"); | |
return false; | |
@@ -2210,7 +2210,7 @@ impl Optimizer<'_> { | |
} | |
// We can remove this variable same as unused pass | |
- if !usage.reassigned() | |
+ if !usage.reassigned | |
&& usage.usage_count == 1 | |
&& usage.declared | |
&& !usage.used_recursively | |
@@ -2239,7 +2239,7 @@ impl Optimizer<'_> { | |
_ => false, | |
}; | |
- if usage.ref_count != 1 || usage.reassigned() || !usage.is_fn_local { | |
+ if usage.ref_count != 1 || usage.reassigned || !usage.is_fn_local { | |
if is_lit { | |
can_take_init = false | |
} else { | |
@@ -2271,7 +2271,7 @@ impl Optimizer<'_> { | |
Mergable::FnDecl(a) => { | |
if let Some(usage) = self.data.vars.get(&a.ident.to_id()) { | |
- if usage.ref_count != 1 || usage.reassigned() || !usage.is_fn_local { | |
+ if usage.ref_count != 1 || usage.reassigned || !usage.is_fn_local { | |
return Ok(false); | |
} | |
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/unused.rs b/crates/swc_ecma_minifier/src/compress/optimize/unused.rs | |
index 75c5ca591b..6d113adcbf 100644 | |
--- a/crates/swc_ecma_minifier/src/compress/optimize/unused.rs | |
+++ b/crates/swc_ecma_minifier/src/compress/optimize/unused.rs | |
@@ -150,7 +150,7 @@ impl Optimizer<'_> { | |
if let Some(v) = self.data.vars.get(&i.to_id()).cloned() { | |
if v.ref_count == 0 | |
&& v.usage_count == 0 | |
- && !v.reassigned() | |
+ && !v.reassigned | |
&& !v.has_property_mutation | |
&& !v.declared_as_catch_param | |
{ | |
@@ -215,10 +215,7 @@ impl Optimizer<'_> { | |
return true; | |
} | |
- if !usage.mutated | |
- && !usage.reassigned() | |
- && usage.no_side_effect_for_member_access | |
- { | |
+ if !usage.mutated() && usage.no_side_effect_for_member_access { | |
return false; | |
} | |
} | |
diff --git a/crates/swc_ecma_minifier/src/pass/merge_exports.rs b/crates/swc_ecma_minifier/src/pass/merge_exports.rs | |
index 6b9958083b..7e9b0bf5c5 100644 | |
--- a/crates/swc_ecma_minifier/src/pass/merge_exports.rs | |
+++ b/crates/swc_ecma_minifier/src/pass/merge_exports.rs | |
@@ -48,7 +48,7 @@ impl VisitMut for Merger { | |
specifiers: self.specifiers.take(), | |
span: DUMMY_SP, | |
type_only: Default::default(), | |
- asserts: Default::default(), | |
+ with: Default::default(), | |
}, | |
))); | |
} | |
@@ -61,7 +61,7 @@ impl VisitMut for Merger { | |
specifiers: Default::default(), | |
span: DUMMY_SP, | |
type_only: Default::default(), | |
- asserts: Default::default(), | |
+ with: Default::default(), | |
}, | |
))); | |
} | |
diff --git a/crates/swc_ecma_minifier/src/program_data.rs b/crates/swc_ecma_minifier/src/program_data.rs | |
index e258732abe..b43191105a 100644 | |
--- a/crates/swc_ecma_minifier/src/program_data.rs | |
+++ b/crates/swc_ecma_minifier/src/program_data.rs | |
@@ -65,7 +65,6 @@ pub(crate) struct VarUsageInfo { | |
pub(crate) declared_as_for_init: bool, | |
pub(crate) assign_count: u32, | |
- pub(crate) mutation_by_call_count: u32, | |
/// The number of direct and indirect reference to this identifier. | |
/// ## Things to note | |
@@ -74,9 +73,7 @@ pub(crate) struct VarUsageInfo { | |
pub(crate) usage_count: u32, | |
/// The variable itself is assigned after reference. | |
- reassigned: bool, | |
- /// The variable itself or a property of it is modified. | |
- pub(crate) mutated: bool, | |
+ pub(crate) reassigned: bool, | |
pub(crate) has_property_access: bool, | |
pub(crate) has_property_mutation: bool, | |
@@ -139,10 +136,8 @@ impl Default for VarUsageInfo { | |
declared_as_fn_expr: Default::default(), | |
declared_as_for_init: Default::default(), | |
assign_count: Default::default(), | |
- mutation_by_call_count: Default::default(), | |
usage_count: Default::default(), | |
reassigned: Default::default(), | |
- mutated: Default::default(), | |
has_property_access: Default::default(), | |
has_property_mutation: Default::default(), | |
exported: Default::default(), | |
@@ -170,31 +165,23 @@ impl Default for VarUsageInfo { | |
} | |
impl VarUsageInfo { | |
- pub(crate) fn is_mutated_only_by_one_call(&self) -> bool { | |
- self.assign_count == 0 && self.mutation_by_call_count == 1 | |
- } | |
- | |
pub(crate) fn is_infected(&self) -> bool { | |
!self.infects_to.is_empty() | |
} | |
- pub(crate) fn reassigned(&self) -> bool { | |
- self.reassigned | |
- || (u32::from(self.var_initialized) | |
- + u32::from(self.declared_as_catch_param) | |
- + u32::from(self.declared_as_fn_param) | |
- + self.assign_count) | |
- > 1 | |
- } | |
- | |
- pub(crate) fn can_inline_var(&self) -> bool { | |
- !self.mutated || (self.assign_count == 0 && !self.reassigned()) | |
+ /// The variable itself or a property of it is modified. | |
+ pub(crate) fn mutated(&self) -> bool { | |
+ self.assign_count > 0 || self.has_property_mutation | |
} | |
pub(crate) fn can_inline_fn_once(&self) -> bool { | |
self.callee_count > 0 | |
|| !self.executed_multiple_time && (self.is_fn_local || !self.used_in_non_child_fn) | |
} | |
+ | |
+ fn initialized(&self) -> bool { | |
+ self.var_initialized || self.declared_as_fn_param || self.declared_as_catch_param | |
+ } | |
} | |
impl Storage for ProgramData { | |
@@ -235,6 +222,8 @@ impl Storage for ProgramData { | |
|| (var_info.var_initialized && !e.get().var_initialized); | |
if var_info.var_initialized { | |
+ // If it is inited in some other child scope and also inited in current | |
+ // scope | |
if e.get().var_initialized || e.get().ref_count > 0 { | |
e.get_mut().assign_count += 1; | |
e.get_mut().reassigned = true; | |
@@ -247,6 +236,8 @@ impl Storage for ProgramData { | |
// If it is inited in some other child scope, but referenced in | |
// current child scope | |
if !inited && e.get().var_initialized && var_info.ref_count > 0 { | |
+ e.get_mut().var_initialized = false; | |
+ e.get_mut().assign_count += 1; | |
e.get_mut().reassigned = true | |
} | |
} | |
@@ -255,7 +246,11 @@ impl Storage for ProgramData { | |
e.get_mut().reassigned |= var_info.reassigned; | |
- e.get_mut().mutated |= var_info.mutated; | |
+ if var_info.assign_count > 0 { | |
+ if e.get().initialized() { | |
+ e.get_mut().reassigned = true | |
+ } | |
+ } | |
e.get_mut().has_property_access |= var_info.has_property_access; | |
e.get_mut().has_property_mutation |= var_info.has_property_mutation; | |
@@ -275,7 +270,6 @@ impl Storage for ProgramData { | |
e.get_mut().executed_multiple_time |= var_info.executed_multiple_time; | |
e.get_mut().used_in_cond |= var_info.used_in_cond; | |
e.get_mut().assign_count += var_info.assign_count; | |
- e.get_mut().mutation_by_call_count += var_info.mutation_by_call_count; | |
e.get_mut().usage_count += var_info.usage_count; | |
e.get_mut().infects_to.extend(var_info.infects_to); | |
@@ -314,7 +308,7 @@ impl Storage for ProgramData { | |
} | |
} | |
ScopeKind::Block => { | |
- if var_info.used_in_non_child_fn { | |
+ if e.get().used_in_non_child_fn { | |
e.get_mut().is_fn_local = false; | |
e.get_mut().used_in_non_child_fn = true; | |
} | |
@@ -354,13 +348,13 @@ impl Storage for ProgramData { | |
let v = self.vars.entry(i.to_id()).or_default(); | |
v.is_top_level |= ctx.is_top_level; | |
- if has_init && (v.declared || v.var_initialized) { | |
+ // assigned or declared before this declaration | |
+ if has_init && (v.declared || v.var_initialized || v.assign_count > 0) { | |
#[cfg(feature = "debug")] | |
{ | |
tracing::trace!("declare_decl(`{}`): Already declared", i); | |
} | |
- v.mutated = true; | |
v.reassigned = true; | |
v.assign_count += 1; | |
} | |
@@ -396,7 +390,7 @@ impl Storage for ProgramData { | |
self.initialized_vars.truncate(len) | |
} | |
- fn mark_property_mutattion(&mut self, id: Id, ctx: Ctx) { | |
+ fn mark_property_mutation(&mut self, id: Id, ctx: Ctx) { | |
let e = self.vars.entry(id).or_default(); | |
e.has_property_mutation = true; | |
@@ -482,14 +476,6 @@ impl VarDataLike for VarUsageInfo { | |
*self.accessed_props.entry(name).or_default() += 1; | |
} | |
- fn mark_mutated(&mut self) { | |
- self.mutated = true; | |
- } | |
- | |
- fn mark_reassigned(&mut self) { | |
- self.reassigned = true; | |
- } | |
- | |
fn mark_used_as_ref(&mut self) { | |
self.used_as_ref = true; | |
} | |
@@ -612,46 +598,45 @@ impl ProgramData { | |
let call_may_mutate = ctx.in_call_arg_of == Some(CalleeKind::Unknown); | |
- // Passing object as a argument is possibly modification. | |
- e.mutated |= is_modify || (call_may_mutate && ctx.is_exact_arg); | |
- | |
e.executed_multiple_time |= ctx.executed_multiple_time; | |
e.used_in_cond |= ctx.in_cond; | |
if is_modify && ctx.is_exact_reassignment { | |
if is_first { | |
+ if e.assign_count > 0 || e.initialized() { | |
+ e.reassigned = true | |
+ } | |
+ | |
e.assign_count += 1; | |
+ | |
+ if !ctx.is_op_assign { | |
+ if e.ref_count == 1 | |
+ && ctx.in_assign_lhs | |
+ && e.var_kind != Some(VarDeclKind::Const) | |
+ && !inited | |
+ { | |
+ self.initialized_vars.insert(i.clone()); | |
+ e.assign_count -= 1; | |
+ e.var_initialized = true; | |
+ } else { | |
+ e.reassigned = true | |
+ } | |
+ } | |
} | |
if ctx.is_op_assign { | |
e.usage_count += 1; | |
- } else if is_first { | |
- if e.ref_count == 1 | |
- && ctx.in_assign_lhs | |
- && e.var_kind != Some(VarDeclKind::Const) | |
- && !inited | |
- { | |
- self.initialized_vars.insert(i.clone()); | |
- e.assign_count -= 1; | |
- e.var_initialized = true; | |
- } else { | |
- e.reassigned = true | |
- } | |
} | |
for other in e.infects_to.clone() { | |
self.report(other.0, ctx, true, dejavu) | |
} | |
} else { | |
- if call_may_mutate && ctx.is_exact_arg { | |
- e.mutation_by_call_count += 1; | |
- } | |
- | |
e.usage_count += 1; | |
} | |
if call_may_mutate && ctx.is_exact_arg { | |
- self.mark_property_mutattion(i, ctx) | |
+ self.mark_property_mutation(i, ctx) | |
} | |
} | |
} | |
diff --git a/crates/swc_ecma_minifier/src/util/base54.rs b/crates/swc_ecma_minifier/src/util/base54.rs | |
index 7b0820a6f8..d98dfa98b9 100644 | |
--- a/crates/swc_ecma_minifier/src/util/base54.rs | |
+++ b/crates/swc_ecma_minifier/src/util/base54.rs | |
@@ -227,12 +227,9 @@ impl CharFreq { | |
{ | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- target: EsVersion::latest(), | |
- ascii_only: false, | |
- minify: true, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default() | |
+ .with_target(EsVersion::latest()) | |
+ .with_minify(true), | |
cm, | |
comments: None, | |
wr: &mut freq, | |
diff --git a/crates/swc_ecma_minifier/tests/compress.rs b/crates/swc_ecma_minifier/tests/compress.rs | |
index c3ba509b84..1ac887200a 100644 | |
--- a/crates/swc_ecma_minifier/tests/compress.rs | |
+++ b/crates/swc_ecma_minifier/tests/compress.rs | |
@@ -630,10 +630,7 @@ fn print<N: swc_ecma_codegen::Node>( | |
} | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(minify), | |
cm, | |
comments: None, | |
wr, | |
diff --git a/crates/swc_ecma_minifier/tests/exec.rs b/crates/swc_ecma_minifier/tests/exec.rs | |
index 98fab543f6..a02d73b4c2 100644 | |
--- a/crates/swc_ecma_minifier/tests/exec.rs | |
+++ b/crates/swc_ecma_minifier/tests/exec.rs | |
@@ -77,10 +77,7 @@ fn print<N: swc_ecma_codegen::Node>( | |
} | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(minify), | |
cm, | |
comments: None, | |
wr, | |
diff --git a/crates/swc_ecma_minifier/tests/mangle.rs b/crates/swc_ecma_minifier/tests/mangle.rs | |
index 480f48248e..140f3c16d3 100644 | |
--- a/crates/swc_ecma_minifier/tests/mangle.rs | |
+++ b/crates/swc_ecma_minifier/tests/mangle.rs | |
@@ -33,10 +33,7 @@ fn print(cm: Lrc<SourceMap>, m: &Module, minify: bool) -> String { | |
} | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(minify), | |
cm, | |
comments: None, | |
wr, | |
diff --git a/crates/swc_ecma_minifier/tests/terser_exec.rs b/crates/swc_ecma_minifier/tests/terser_exec.rs | |
index dd8d2ed84a..df809bf1af 100644 | |
--- a/crates/swc_ecma_minifier/tests/terser_exec.rs | |
+++ b/crates/swc_ecma_minifier/tests/terser_exec.rs | |
@@ -304,10 +304,7 @@ fn print<N: swc_ecma_codegen::Node>( | |
} | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_minify(minify), | |
cm, | |
comments: None, | |
wr, | |
diff --git a/crates/swc_ecma_parser/src/lexer/jsx.rs b/crates/swc_ecma_parser/src/lexer/jsx.rs | |
index ea64b0c188..e10f0870e6 100644 | |
--- a/crates/swc_ecma_parser/src/lexer/jsx.rs | |
+++ b/crates/swc_ecma_parser/src/lexer/jsx.rs | |
@@ -33,12 +33,18 @@ impl<'a> Lexer<'a> { | |
// | |
if cur_pos == self.state.start { | |
if cur == '<' && self.state.is_expr_allowed { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() was Some('<') | |
+ self.input.bump(); | |
+ } | |
return Ok(Token::JSXTagStart).map(Some); | |
} | |
return self.read_token(); | |
} | |
- out.push_str(self.input.slice(chunk_start, cur_pos)); | |
+ out.push_str(unsafe { | |
+ // Safety: We already checked for the range | |
+ self.input.slice(chunk_start, cur_pos) | |
+ }); | |
return Ok(Token::JSXText { | |
raw: Atom::new(out), | |
@@ -52,7 +58,10 @@ impl<'a> Lexer<'a> { | |
candidate_list: vec!["`{'>'}`", "`>`"], | |
}, | |
); | |
- self.input.bump() | |
+ unsafe { | |
+ // Safety: cur() was Some('>') | |
+ self.input.bump() | |
+ } | |
} | |
'}' => { | |
self.emit_error( | |
@@ -61,10 +70,16 @@ impl<'a> Lexer<'a> { | |
candidate_list: vec!["`{'}'}`", "`}`"], | |
}, | |
); | |
- self.input.bump() | |
+ unsafe { | |
+ // Safety: cur() was Some('}') | |
+ self.input.bump() | |
+ } | |
} | |
'&' => { | |
- out.push_str(self.input.slice(chunk_start, cur_pos)); | |
+ out.push_str(unsafe { | |
+ // Safety: We already checked for the range | |
+ self.input.slice(chunk_start, cur_pos) | |
+ }); | |
let jsx_entity = self.read_jsx_entity()?; | |
@@ -74,14 +89,20 @@ impl<'a> Lexer<'a> { | |
_ => { | |
if cur.is_line_terminator() { | |
- out.push_str(self.input.slice(chunk_start, cur_pos)); | |
+ out.push_str(unsafe { | |
+ // Safety: We already checked for the range | |
+ self.input.slice(chunk_start, cur_pos) | |
+ }); | |
match self.read_jsx_new_line(true)? { | |
Either::Left(s) => out.push_str(s), | |
Either::Right(c) => out.push(c), | |
} | |
chunk_start = cur_pos; | |
} else { | |
- self.input.bump() | |
+ unsafe { | |
+ // Safety: cur() was Some(c) | |
+ self.input.bump() | |
+ } | |
} | |
} | |
} | |
@@ -113,7 +134,10 @@ impl<'a> Lexer<'a> { | |
let c = self.input.cur(); | |
debug_assert_eq!(c, Some('&')); | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() was Some('&') | |
+ self.input.bump(); | |
+ } | |
let start_pos = self.input.cur_pos(); | |
@@ -122,7 +146,10 @@ impl<'a> Lexer<'a> { | |
Some(c) => c, | |
None => break, | |
}; | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() was Some(c) | |
+ self.input.bump(); | |
+ } | |
if c == ';' { | |
if let Some(stripped) = s.strip_prefix('#') { | |
@@ -147,7 +174,10 @@ impl<'a> Lexer<'a> { | |
s.push(c) | |
} | |
- self.input.reset_to(start_pos); | |
+ unsafe { | |
+ // Safety: start_pos is a valid position because we got it from self.input | |
+ self.input.reset_to(start_pos); | |
+ } | |
Ok(('&', "&".to_string())) | |
} | |
@@ -159,10 +189,16 @@ impl<'a> Lexer<'a> { | |
debug_assert!(self.syntax.jsx()); | |
let ch = self.input.cur().unwrap(); | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() was Some(ch) | |
+ self.input.bump(); | |
+ } | |
let out = if ch == '\r' && self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() was Some('\n') | |
+ self.input.bump(); | |
+ } | |
Either::Left(if normalize_crlf { "\n" } else { "\r\n" }) | |
} else { | |
Either::Right(ch) | |
@@ -181,7 +217,10 @@ impl<'a> Lexer<'a> { | |
raw.push(quote); | |
- self.input.bump(); // `quote` | |
+ unsafe { | |
+ // Safety: cur() was Some(quote) | |
+ self.input.bump(); // `quote` | |
+ } | |
let mut out = String::new(); | |
let mut chunk_start = self.input.cur_pos(); | |
@@ -199,7 +238,10 @@ impl<'a> Lexer<'a> { | |
let cur_pos = self.input.cur_pos(); | |
if ch == '\\' { | |
- let value = self.input.slice(chunk_start, cur_pos); | |
+ let value = unsafe { | |
+ // Safety: We already checked for the range | |
+ self.input.slice(chunk_start, cur_pos) | |
+ }; | |
out.push_str(value); | |
out.push('\\'); | |
@@ -218,7 +260,10 @@ impl<'a> Lexer<'a> { | |
} | |
if ch == '&' { | |
- let value = self.input.slice(chunk_start, cur_pos); | |
+ let value = unsafe { | |
+ // Safety: We already checked for the range | |
+ self.input.slice(chunk_start, cur_pos) | |
+ }; | |
out.push_str(value); | |
raw.push_str(value); | |
@@ -230,7 +275,10 @@ impl<'a> Lexer<'a> { | |
chunk_start = self.input.cur_pos(); | |
} else if ch.is_line_terminator() { | |
- let value = self.input.slice(chunk_start, cur_pos); | |
+ let value = unsafe { | |
+ // Safety: We already checked for the range | |
+ self.input.slice(chunk_start, cur_pos) | |
+ }; | |
out.push_str(value); | |
raw.push_str(value); | |
@@ -248,12 +296,18 @@ impl<'a> Lexer<'a> { | |
chunk_start = cur_pos + BytePos(ch.len_utf8() as _); | |
} else { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() was Some(ch) | |
+ self.input.bump(); | |
+ } | |
} | |
} | |
let cur_pos = self.input.cur_pos(); | |
- let value = self.input.slice(chunk_start, cur_pos); | |
+ let value = unsafe { | |
+ // Safety: We already checked for the range | |
+ self.input.slice(chunk_start, cur_pos) | |
+ }; | |
out.push_str(value); | |
raw.push_str(value); | |
@@ -261,7 +315,10 @@ impl<'a> Lexer<'a> { | |
// it might be at the end of the file when | |
// the string literal is unterminated | |
if self.input.peek_ahead().is_some() { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: We called peek_ahead() which means cur() was Some | |
+ self.input.bump(); | |
+ } | |
} | |
raw.push(quote); | |
diff --git a/crates/swc_ecma_parser/src/lexer/mod.rs b/crates/swc_ecma_parser/src/lexer/mod.rs | |
index 387389f9b1..992a8b2c21 100644 | |
--- a/crates/swc_ecma_parser/src/lexer/mod.rs | |
+++ b/crates/swc_ecma_parser/src/lexer/mod.rs | |
@@ -201,7 +201,10 @@ impl<'a> Lexer<'a> { | |
fn read_token_number_sign(&mut self) -> LexResult<Option<Token>> { | |
debug_assert!(self.cur().is_some()); | |
- self.input.bump(); // '#' | |
+ unsafe { | |
+ // Safety: cur() is Some('#') | |
+ self.input.bump(); // '#' | |
+ } | |
// `#` can also be a part of shebangs, however they should have been | |
// handled by `read_shebang()` | |
@@ -221,7 +224,10 @@ impl<'a> Lexer<'a> { | |
let next = match self.input.peek() { | |
Some(next) => next, | |
None => { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some(',') | |
+ self.input.bump(); | |
+ } | |
return Ok(tok!('.')); | |
} | |
}; | |
@@ -232,11 +238,19 @@ impl<'a> Lexer<'a> { | |
}); | |
} | |
- self.input.bump(); // 1st `.` | |
+ unsafe { | |
+ // Safety: cur() is Some | |
+ // 1st `.` | |
+ self.input.bump(); | |
+ } | |
if next == '.' && self.input.peek() == Some('.') { | |
- self.input.bump(); // 2nd `.` | |
- self.input.bump(); // 3rd `.` | |
+ unsafe { | |
+ // Safety: peek() was Some | |
+ | |
+ self.input.bump(); // 2nd `.` | |
+ self.input.bump(); // 3rd `.` | |
+ } | |
return Ok(tok!("...")); | |
} | |
@@ -251,16 +265,26 @@ impl<'a> Lexer<'a> { | |
fn read_token_question_mark(&mut self) -> LexResult<Token> { | |
match self.input.peek() { | |
Some('?') => { | |
- self.input.bump(); | |
- self.input.bump(); | |
- if self.input.cur() == Some('=') { | |
+ unsafe { | |
+ // Safety: peek() was some | |
+ self.input.bump(); | |
self.input.bump(); | |
+ } | |
+ if self.input.cur() == Some('=') { | |
+ unsafe { | |
+ // Safety: cur() was some | |
+ self.input.bump(); | |
+ } | |
+ | |
return Ok(tok!("??=")); | |
} | |
Ok(tok!("??")) | |
} | |
_ => { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: peek() is callable only if cur() is Some | |
+ self.input.bump(); | |
+ } | |
Ok(tok!('?')) | |
} | |
} | |
@@ -271,7 +295,10 @@ impl<'a> Lexer<'a> { | |
/// This is extracted as a method to reduce size of `read_token`. | |
#[inline(never)] | |
fn read_token_colon(&mut self) -> LexResult<Token> { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some(':') | |
+ self.input.bump(); | |
+ } | |
Ok(tok!(':')) | |
} | |
@@ -308,7 +335,10 @@ impl<'a> Lexer<'a> { | |
let had_line_break_before_last = self.had_line_break_before_last(); | |
let start = self.cur_pos(); | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some(c as char) | |
+ self.input.bump(); | |
+ } | |
let token = if c == b'&' { BitAnd } else { BitOr }; | |
// '|=', '&=' | |
@@ -322,10 +352,16 @@ impl<'a> Lexer<'a> { | |
// '||', '&&' | |
if self.input.cur() == Some(c as char) { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some(c) | |
+ self.input.bump(); | |
+ } | |
if self.input.cur() == Some('=') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('=') | |
+ self.input.bump(); | |
+ } | |
return Ok(AssignOp(match token { | |
BitAnd => op!("&&="), | |
BitOr => op!("||="), | |
@@ -359,7 +395,10 @@ impl<'a> Lexer<'a> { | |
#[inline(never)] | |
fn read_token_mul_mod(&mut self, c: u8) -> LexResult<Token> { | |
let is_mul = c == b'*'; | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some(c) | |
+ self.input.bump(); | |
+ } | |
let mut token = if is_mul { BinOp(Mul) } else { BinOp(Mod) }; | |
// check for ** | |
@@ -521,7 +560,10 @@ impl<'a> Lexer<'a> { | |
} | |
}; | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some(c) if this method is called. | |
+ self.input.bump(); | |
+ } | |
Ok(Some(vec![c.into()])) | |
} | |
@@ -529,11 +571,17 @@ impl<'a> Lexer<'a> { | |
fn read_token_plus_minus(&mut self, c: u8) -> LexResult<Option<Token>> { | |
let start = self.cur_pos(); | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some(c), if this method is called. | |
+ self.input.bump(); | |
+ } | |
// '++', '--' | |
Ok(Some(if self.input.cur() == Some(c as char) { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some(c) | |
+ self.input.bump(); | |
+ } | |
// Handle --> | |
if self.state.had_line_break && c == b'-' && self.eat(b'>') { | |
@@ -559,7 +607,10 @@ impl<'a> Lexer<'a> { | |
let start = self.cur_pos(); | |
let had_line_break_before_last = self.had_line_break_before_last(); | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some(c) if this method is called. | |
+ self.input.bump(); | |
+ } | |
Ok(Some(if self.input.eat_byte(b'=') { | |
// "==" | |
@@ -911,7 +962,10 @@ impl<'a> Lexer<'a> { | |
chars.push(c.into()); | |
} | |
_ => { | |
- self.input.reset_to(state); | |
+ unsafe { | |
+ // Safety: state is valid position because we got it from cur_pos() | |
+ self.input.reset_to(state); | |
+ } | |
chars.push(Char::from('\\')); | |
chars.push(Char::from('u')); | |
@@ -1029,7 +1083,10 @@ impl<'a> Lexer<'a> { | |
/// Expects current char to be '/' | |
fn read_regexp(&mut self, start: BytePos) -> LexResult<Token> { | |
- self.input.reset_to(start); | |
+ unsafe { | |
+ // Safety: start is valid position, and cur() is Some('/') | |
+ self.input.reset_to(start); | |
+ } | |
debug_assert_eq!(self.cur(), Some('/')); | |
@@ -1104,8 +1161,12 @@ impl<'a> Lexer<'a> { | |
if self.input.cur() != Some('#') || self.input.peek() != Some('!') { | |
return Ok(None); | |
} | |
- self.input.bump(); | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('#') | |
+ self.input.bump(); | |
+ // Safety: cur() is Some('!') | |
+ self.input.bump(); | |
+ } | |
let s = self.input.uncons_while(|c| !c.is_line_terminator()); | |
Ok(Some(Atom::new(s))) | |
} | |
diff --git a/crates/swc_ecma_parser/src/lexer/number.rs b/crates/swc_ecma_parser/src/lexer/number.rs | |
index 67194ca496..e2df37e195 100644 | |
--- a/crates/swc_ecma_parser/src/lexer/number.rs | |
+++ b/crates/swc_ecma_parser/src/lexer/number.rs | |
@@ -491,7 +491,10 @@ impl<'a> Lexer<'a> { | |
} | |
// Ignore this _ character | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() returns Some(c) where c is a valid char | |
+ self.input.bump(); | |
+ } | |
raw.push(c); | |
continue; | |
diff --git a/crates/swc_ecma_parser/src/lexer/state.rs b/crates/swc_ecma_parser/src/lexer/state.rs | |
index c632be1df7..06062d18ef 100644 | |
--- a/crates/swc_ecma_parser/src/lexer/state.rs | |
+++ b/crates/swc_ecma_parser/src/lexer/state.rs | |
@@ -286,7 +286,10 @@ impl<'a> Iterator for Lexer<'a> { | |
} | |
if c == '>' { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('>') | |
+ self.input.bump(); | |
+ } | |
return Ok(Some(Token::JSXTagEnd)); | |
} | |
@@ -301,7 +304,10 @@ impl<'a> Iterator for Lexer<'a> { | |
let had_line_break_before_last = self.had_line_break_before_last(); | |
let cur_pos = self.input.cur_pos(); | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('<') | |
+ self.input.bump(); | |
+ } | |
if had_line_break_before_last && self.is_str("<<<<<< ") { | |
let span = Span::new(cur_pos, cur_pos + BytePos(7), Default::default()); | |
diff --git a/crates/swc_ecma_parser/src/lexer/table.rs b/crates/swc_ecma_parser/src/lexer/table.rs | |
index 2e7072e6d5..155c783aa0 100644 | |
--- a/crates/swc_ecma_parser/src/lexer/table.rs | |
+++ b/crates/swc_ecma_parser/src/lexer/table.rs | |
@@ -51,7 +51,10 @@ const ERR: ByteHandler = Some(|lexer| { | |
}; | |
let start = lexer.cur_pos(); | |
- lexer.input.bump(); | |
+ unsafe { | |
+ // Safety: Byte handler is only called for non-last chracters | |
+ lexer.input.bump(); | |
+ } | |
lexer.error_span(pos_span(start), SyntaxError::UnexpectedChar { c })? | |
}); | |
@@ -89,7 +92,10 @@ const UNI: ByteHandler = Some(|lexer| { | |
} | |
let start = lexer.cur_pos(); | |
- lexer.input.bump(); | |
+ unsafe { | |
+ // Safety: Byte handler is only called for non-last chracters | |
+ lexer.input.bump(); | |
+ } | |
lexer.error_span(pos_span(start), SyntaxError::UnexpectedChar { c })? | |
}); | |
diff --git a/crates/swc_ecma_parser/src/lexer/util.rs b/crates/swc_ecma_parser/src/lexer/util.rs | |
index d31fddc594..694c0b81c2 100644 | |
--- a/crates/swc_ecma_parser/src/lexer/util.rs | |
+++ b/crates/swc_ecma_parser/src/lexer/util.rs | |
@@ -69,7 +69,10 @@ impl<'a> Lexer<'a> { | |
#[inline(always)] | |
pub(super) fn bump(&mut self) { | |
- self.input.bump() | |
+ unsafe { | |
+ // Safety: Actually this is not safe but this is an internal method. | |
+ self.input.bump() | |
+ } | |
} | |
#[inline(always)] | |
@@ -246,7 +249,10 @@ impl<'a> Lexer<'a> { | |
let end = self.cur_pos(); | |
if let Some(comments) = self.comments_buffer.as_mut() { | |
- let s = self.input.slice(slice_start, end); | |
+ let s = unsafe { | |
+ // Safety: We know that the start and the end are valid | |
+ self.input.slice(slice_start, end) | |
+ }; | |
let cmt = Comment { | |
kind: CommentKind::Line, | |
span: Span::new(start, end, SyntaxContext::empty()), | |
@@ -264,7 +270,10 @@ impl<'a> Lexer<'a> { | |
} | |
} | |
- self.input.reset_to(end); | |
+ unsafe { | |
+ // Safety: We got end from self.input | |
+ self.input.reset_to(end); | |
+ } | |
} | |
/// Expects current char to be '/' and next char to be '*'. | |
@@ -302,7 +311,10 @@ impl<'a> Lexer<'a> { | |
} | |
if let Some(comments) = self.comments_buffer.as_mut() { | |
- let src = self.input.slice(slice_start, end); | |
+ let src = unsafe { | |
+ // Safety: We got slice_start and end from self.input so those are valid. | |
+ self.input.slice(slice_start, end) | |
+ }; | |
let s = &src[..src.len() - 2]; | |
let cmt = Comment { | |
kind: CommentKind::Block, | |
diff --git a/crates/swc_ecma_parser/src/lib.rs b/crates/swc_ecma_parser/src/lib.rs | |
index fe50ea65dc..415dc49606 100644 | |
--- a/crates/swc_ecma_parser/src/lib.rs | |
+++ b/crates/swc_ecma_parser/src/lib.rs | |
@@ -175,11 +175,11 @@ impl Syntax { | |
} | |
} | |
- pub fn import_assertions(self) -> bool { | |
+ pub fn import_attributes(self) -> bool { | |
match self { | |
Syntax::Es(EsConfig { | |
- import_assertions, .. | |
- }) => import_assertions, | |
+ import_attributes, .. | |
+ }) => import_attributes, | |
Syntax::Typescript(_) => true, | |
} | |
} | |
@@ -282,9 +282,12 @@ impl Syntax { | |
} | |
} | |
- fn using_decl(&self) -> bool { | |
+ pub fn explicit_resource_management(&self) -> bool { | |
match self { | |
- Syntax::Es(EsConfig { using_decl, .. }) => *using_decl, | |
+ Syntax::Es(EsConfig { | |
+ explicit_resource_management: using_decl, | |
+ .. | |
+ }) => *using_decl, | |
Syntax::Typescript(_) => true, | |
} | |
} | |
@@ -341,8 +344,8 @@ pub struct EsConfig { | |
pub export_default_from: bool, | |
/// Stage 3. | |
- #[serde(default)] | |
- pub import_assertions: bool, | |
+ #[serde(default, alias = "importAssertions")] | |
+ pub import_attributes: bool, | |
#[serde(default, rename = "allowSuperOutsideMethod")] | |
pub allow_super_outside_method: bool, | |
@@ -354,7 +357,7 @@ pub struct EsConfig { | |
pub auto_accessors: bool, | |
#[serde(default)] | |
- pub using_decl: bool, | |
+ pub explicit_resource_management: bool, | |
} | |
/// Syntactic context. | |
diff --git a/crates/swc_ecma_parser/src/parser/expr.rs b/crates/swc_ecma_parser/src/parser/expr.rs | |
index f6d6d4dfac..b077d891f5 100644 | |
--- a/crates/swc_ecma_parser/src/parser/expr.rs | |
+++ b/crates/swc_ecma_parser/src/parser/expr.rs | |
@@ -740,7 +740,7 @@ impl<I: Tokens> Parser<I> { | |
expect!(p, ','); | |
// Handle trailing comma. | |
if is!(p, ')') { | |
- if is_dynamic_import && !p.input.syntax().import_assertions() { | |
+ if is_dynamic_import && !p.input.syntax().import_attributes() { | |
syntax_error!( | |
p, | |
span!(p, start), | |
diff --git a/crates/swc_ecma_parser/src/parser/stmt.rs b/crates/swc_ecma_parser/src/parser/stmt.rs | |
index 273d447843..00f0c164cd 100644 | |
--- a/crates/swc_ecma_parser/src/parser/stmt.rs | |
+++ b/crates/swc_ecma_parser/src/parser/stmt.rs | |
@@ -816,7 +816,7 @@ impl<'a, I: Tokens> Parser<I> { | |
decls.push(self.parse_var_declarator(false, VarDeclKind::Var)?); | |
} | |
- if !self.syntax().using_decl() { | |
+ if !self.syntax().explicit_resource_management() { | |
self.emit_err(span!(self, start), SyntaxError::UsingDeclNotEnabled); | |
} | |
@@ -1272,7 +1272,7 @@ impl<'a, I: Tokens> Parser<I> { | |
let start = cur_pos!(self); | |
let init = self.include_in_expr(false).parse_for_head_prefix()?; | |
- let is_using_decl = self.input.syntax().using_decl() | |
+ let is_using_decl = self.input.syntax().explicit_resource_management() | |
&& match *init { | |
Expr::Ident(Ident { | |
sym: js_word!("using"), | |
@@ -2434,7 +2434,7 @@ export default function waitUntil(callback, options = {}) { | |
test_parser( | |
src, | |
Syntax::Es(EsConfig { | |
- import_assertions: true, | |
+ import_attributes: true, | |
..Default::default() | |
}), | |
|p| p.parse_expr(), | |
diff --git a/crates/swc_ecma_parser/src/parser/stmt/module_item.rs b/crates/swc_ecma_parser/src/parser/stmt/module_item.rs | |
index d2b2003f2d..9ddc999e36 100644 | |
--- a/crates/swc_ecma_parser/src/parser/stmt/module_item.rs | |
+++ b/crates/swc_ecma_parser/src/parser/stmt/module_item.rs | |
@@ -63,9 +63,9 @@ impl<I: Tokens> Parser<I> { | |
_ => unreachable!(), | |
}; | |
let _ = cur!(self, false); | |
- let asserts = if self.input.syntax().import_assertions() | |
+ let with = if self.input.syntax().import_attributes() | |
&& !self.input.had_line_break_before_cur() | |
- && eat!(self, "assert") | |
+ && (eat!(self, "assert") || eat!(self, "with")) | |
{ | |
match *self.parse_object::<Box<Expr>>()? { | |
Expr::Object(v) => Some(Box::new(v)), | |
@@ -80,7 +80,7 @@ impl<I: Tokens> Parser<I> { | |
src, | |
specifiers: vec![], | |
type_only: false, | |
- asserts, | |
+ with, | |
})) | |
.map(ModuleItem::from); | |
} | |
@@ -157,9 +157,9 @@ impl<I: Tokens> Parser<I> { | |
}; | |
let _ = cur!(self, false); | |
- let asserts = if self.input.syntax().import_assertions() | |
+ let with = if self.input.syntax().import_attributes() | |
&& !self.input.had_line_break_before_cur() | |
- && eat!(self, "assert") | |
+ && (eat!(self, "assert") || eat!(self, "with")) | |
{ | |
match *self.parse_object::<Box<Expr>>()? { | |
Expr::Object(v) => Some(Box::new(v)), | |
@@ -176,7 +176,7 @@ impl<I: Tokens> Parser<I> { | |
specifiers, | |
src, | |
type_only, | |
- asserts, | |
+ with, | |
})) | |
.map(ModuleItem::from) | |
} | |
@@ -570,12 +570,12 @@ impl<I: Tokens> Parser<I> { | |
assert_and_bump!(self, '*'); | |
// improve error message for `export * from foo` | |
- let (src, asserts) = self.parse_from_clause_and_semi()?; | |
+ let (src, with) = self.parse_from_clause_and_semi()?; | |
return Ok(ModuleDecl::ExportAll(ExportAll { | |
span: span!(self, start), | |
src, | |
type_only, | |
- asserts, | |
+ with, | |
})); | |
} | |
@@ -617,13 +617,13 @@ impl<I: Tokens> Parser<I> { | |
if has_default || has_ns { | |
if is!(self, "from") { | |
- let (src, asserts) = self.parse_from_clause_and_semi()?; | |
+ let (src, with) = self.parse_from_clause_and_semi()?; | |
return Ok(ModuleDecl::ExportNamed(NamedExport { | |
span: span!(self, start), | |
specifiers, | |
src: Some(src), | |
type_only, | |
- asserts, | |
+ with, | |
})); | |
} else if !self.input.syntax().export_default_from() { | |
// emit error | |
@@ -667,7 +667,7 @@ impl<I: Tokens> Parser<I> { | |
} | |
None | |
}; | |
- let (src, asserts) = match opt { | |
+ let (src, with) = match opt { | |
Some(v) => (Some(v.0), v.1), | |
None => (None, None), | |
}; | |
@@ -676,7 +676,7 @@ impl<I: Tokens> Parser<I> { | |
specifiers, | |
src, | |
type_only, | |
- asserts, | |
+ with, | |
})); | |
}; | |
@@ -793,7 +793,7 @@ impl<I: Tokens> Parser<I> { | |
}) | |
} | |
- /// Parses `from 'foo.js' assert {};` | |
+ /// Parses `from 'foo.js' with {};` or `from 'foo.js' assert {};` | |
fn parse_from_clause_and_semi(&mut self) -> PResult<(Box<Str>, Option<Box<ObjectLit>>)> { | |
expect!(self, "from"); | |
@@ -810,9 +810,9 @@ impl<I: Tokens> Parser<I> { | |
_ => unexpected!(self, "a string literal"), | |
}; | |
let _ = cur!(self, false); | |
- let asserts = if self.input.syntax().import_assertions() | |
+ let with = if self.input.syntax().import_attributes() | |
&& !self.input.had_line_break_before_cur() | |
- && eat!(self, "assert") | |
+ && (eat!(self, "assert") || eat!(self, "with")) | |
{ | |
match *self.parse_object::<Box<Expr>>()? { | |
Expr::Object(v) => Some(Box::new(v)), | |
@@ -822,7 +822,7 @@ impl<I: Tokens> Parser<I> { | |
None | |
}; | |
expect!(self, ';'); | |
- Ok((src, asserts)) | |
+ Ok((src, with)) | |
} | |
} | |
diff --git a/crates/swc_ecma_parser/tests/comments.rs b/crates/swc_ecma_parser/tests/comments.rs | |
index 397571d2f8..65b7f9b198 100644 | |
--- a/crates/swc_ecma_parser/tests/comments.rs | |
+++ b/crates/swc_ecma_parser/tests/comments.rs | |
@@ -29,7 +29,7 @@ fn test(input: PathBuf) { | |
decorators: true, | |
decorators_before_export: false, | |
export_default_from: true, | |
- import_assertions: true, | |
+ import_attributes: true, | |
..Default::default() | |
}), | |
"ts" | "tsx" => Syntax::Typescript(TsConfig { | |
diff --git a/crates/swc_ecma_parser/tests/errors.rs b/crates/swc_ecma_parser/tests/errors.rs | |
index ff68922564..973b5c9bd1 100644 | |
--- a/crates/swc_ecma_parser/tests/errors.rs | |
+++ b/crates/swc_ecma_parser/tests/errors.rs | |
@@ -47,7 +47,7 @@ where | |
} else { | |
::swc_ecma_parser::Syntax::Es(::swc_ecma_parser::EsConfig { | |
jsx: is_jsx, | |
- using_decl: true, | |
+ explicit_resource_management: true, | |
..Default::default() | |
}) | |
}; | |
diff --git a/crates/swc_ecma_parser/tests/js.rs b/crates/swc_ecma_parser/tests/js.rs | |
index 507c532da4..a7de707d50 100644 | |
--- a/crates/swc_ecma_parser/tests/js.rs | |
+++ b/crates/swc_ecma_parser/tests/js.rs | |
@@ -91,7 +91,8 @@ where | |
let lexer = Lexer::new( | |
Syntax::Es(EsConfig { | |
- using_decl: true, | |
+ explicit_resource_management: true, | |
+ import_attributes: true, | |
..Default::default() | |
}), | |
EsVersion::Es2015, | |
diff --git a/crates/swc_ecma_preset_env/src/lib.rs b/crates/swc_ecma_preset_env/src/lib.rs | |
index 4b14862b72..826b7f4a50 100644 | |
--- a/crates/swc_ecma_preset_env/src/lib.rs | |
+++ b/crates/swc_ecma_preset_env/src/lib.rs | |
@@ -173,10 +173,13 @@ where | |
let pass = add!( | |
pass, | |
OptionalChaining, | |
- es2020::optional_chaining(es2020::optional_chaining::Config { | |
- no_document_all: loose || assumptions.no_document_all, | |
- pure_getter: loose || assumptions.pure_getters | |
- }) | |
+ es2020::optional_chaining( | |
+ es2020::optional_chaining::Config { | |
+ no_document_all: loose || assumptions.no_document_all, | |
+ pure_getter: loose || assumptions.pure_getters | |
+ }, | |
+ global_mark | |
+ ) | |
); | |
// ES2019 | |
@@ -452,7 +455,7 @@ impl VisitMut for Polyfills { | |
} | |
.into(), | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
})) | |
}), | |
); | |
@@ -470,7 +473,7 @@ impl VisitMut for Polyfills { | |
} | |
.into(), | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
})) | |
}), | |
); | |
diff --git a/crates/swc_ecma_preset_env/tests/test.rs b/crates/swc_ecma_preset_env/tests/test.rs | |
index f4bf64eb8c..1379699a01 100644 | |
--- a/crates/swc_ecma_preset_env/tests/test.rs | |
+++ b/crates/swc_ecma_preset_env/tests/test.rs | |
@@ -159,10 +159,7 @@ fn exec(c: PresetConfig, dir: PathBuf) -> Result<(), Error> { | |
let mut buf = vec![]; | |
{ | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify: false, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default(), | |
comments: None, | |
cm: cm.clone(), | |
wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::new( | |
diff --git a/crates/swc_ecma_quote_macros/src/ast/module_decl.rs b/crates/swc_ecma_quote_macros/src/ast/module_decl.rs | |
index 56503a53c0..17b2ebcfa1 100644 | |
--- a/crates/swc_ecma_quote_macros/src/ast/module_decl.rs | |
+++ b/crates/swc_ecma_quote_macros/src/ast/module_decl.rs | |
@@ -15,12 +15,12 @@ impl_enum!( | |
] | |
); | |
-impl_struct!(ImportDecl, [span, specifiers, src, type_only, asserts]); | |
+impl_struct!(ImportDecl, [span, specifiers, src, type_only, with]); | |
impl_struct!(ExportDecl, [span, decl]); | |
impl_struct!(ExportDefaultDecl, [span, decl]); | |
impl_struct!(ExportDefaultExpr, [span, expr]); | |
-impl_struct!(ExportAll, [span, src, asserts]); | |
-impl_struct!(NamedExport, [span, specifiers, src, type_only, asserts]); | |
+impl_struct!(ExportAll, [span, src, with]); | |
+impl_struct!(NamedExport, [span, specifiers, src, type_only, with]); | |
impl_enum!(ImportSpecifier, [Named, Default, Namespace]); | |
diff --git a/crates/swc_ecma_transforms_base/src/helpers/mod.rs b/crates/swc_ecma_transforms_base/src/helpers/mod.rs | |
index 29e8f5160f..c29b1fe4f4 100644 | |
--- a/crates/swc_ecma_transforms_base/src/helpers/mod.rs | |
+++ b/crates/swc_ecma_transforms_base/src/helpers/mod.rs | |
@@ -86,7 +86,7 @@ macro_rules! add_import_to { | |
span: DUMMY_SP, | |
specifiers: vec![s], | |
src: Box::new(src), | |
- asserts: Default::default(), | |
+ with: Default::default(), | |
type_only: Default::default(), | |
}))) | |
} | |
diff --git a/crates/swc_ecma_transforms_base/src/rename/ops.rs b/crates/swc_ecma_transforms_base/src/rename/ops.rs | |
index 6ab3af91ec..c2e35bf962 100644 | |
--- a/crates/swc_ecma_transforms_base/src/rename/ops.rs | |
+++ b/crates/swc_ecma_transforms_base/src/rename/ops.rs | |
@@ -223,7 +223,7 @@ impl<'a> VisitMut for Operator<'a> { | |
})], | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
))); | |
}; | |
@@ -343,7 +343,7 @@ impl<'a> VisitMut for Operator<'a> { | |
specifiers: renamed, | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
))); | |
} | |
diff --git a/crates/swc_ecma_transforms_base/src/resolver/mod.rs b/crates/swc_ecma_transforms_base/src/resolver/mod.rs | |
index c947a89cc5..d20afdff4e 100644 | |
--- a/crates/swc_ecma_transforms_base/src/resolver/mod.rs | |
+++ b/crates/swc_ecma_transforms_base/src/resolver/mod.rs | |
@@ -1,5 +1,5 @@ | |
use rustc_hash::FxHashSet; | |
-use swc_atoms::{js_word, JsWord}; | |
+use swc_atoms::JsWord; | |
use swc_common::{ | |
collections::{AHashMap, AHashSet}, | |
Mark, Span, SyntaxContext, | |
@@ -269,11 +269,6 @@ impl<'a> Resolver<'a> { | |
} | |
fn mark_for_ref_inner(&self, sym: &JsWord, stop_an_fn_scope: bool) -> Option<Mark> { | |
- // NaN always points the globals | |
- if *sym == js_word!("NaN") { | |
- return Some(self.config.unresolved_mark); | |
- } | |
- | |
if self.config.handle_types && self.in_type { | |
let mut mark = self.current.mark; | |
let mut scope = Some(&self.current); | |
@@ -307,7 +302,16 @@ impl<'a> Resolver<'a> { | |
if mark == Mark::root() { | |
return None; | |
} | |
- return Some(mark); | |
+ | |
+ return match &**sym { | |
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects#value_properties | |
+ "undefined" | "NaN" | "Infinity" | "globalThis" | |
+ if mark == self.config.top_level_mark => | |
+ { | |
+ Some(self.config.unresolved_mark) | |
+ } | |
+ _ => Some(mark), | |
+ }; | |
} | |
if cur.kind == ScopeKind::Fn && stop_an_fn_scope { | |
diff --git a/crates/swc_ecma_transforms_base/tests/fixer_test262.rs b/crates/swc_ecma_transforms_base/tests/fixer_test262.rs | |
index 60822e4bb2..4afd9b651f 100644 | |
--- a/crates/swc_ecma_transforms_base/tests/fixer_test262.rs | |
+++ b/crates/swc_ecma_transforms_base/tests/fixer_test262.rs | |
@@ -175,10 +175,7 @@ fn identity_tests(tests: &mut Vec<TestDescAndFn>) -> Result<(), io::Error> { | |
{ | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify: false, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default(), | |
cm: cm.clone(), | |
wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::new( | |
cm.clone(), | |
@@ -189,10 +186,7 @@ fn identity_tests(tests: &mut Vec<TestDescAndFn>) -> Result<(), io::Error> { | |
comments: None, | |
}; | |
let mut expected_emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify: false, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default(), | |
cm: cm.clone(), | |
wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::new( | |
cm, "\n", &mut wr2, None, | |
diff --git a/crates/swc_ecma_transforms_compat/src/es2015/block_scoping/mod.rs b/crates/swc_ecma_transforms_compat/src/es2015/block_scoping/mod.rs | |
index 4c80ceefd3..ce18711f7e 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es2015/block_scoping/mod.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es2015/block_scoping/mod.rs | |
@@ -431,13 +431,6 @@ impl VisitMut for BlockScoping { | |
self.handle_capture_of_vars(&mut node.body); | |
} | |
- fn visit_mut_while_stmt(&mut self, node: &mut WhileStmt) { | |
- self.visit_mut_with_scope(ScopeKind::new_loop(), &mut node.body); | |
- | |
- node.test.visit_mut_with(self); | |
- self.handle_capture_of_vars(&mut node.body); | |
- } | |
- | |
fn visit_mut_for_in_stmt(&mut self, node: &mut ForInStmt) { | |
let blockifyed = self.blockify_for_stmt_body(&mut node.body); | |
let lexical_var = if let ForHead::VarDecl(decl) = &node.left { | |
@@ -544,6 +537,14 @@ impl VisitMut for BlockScoping { | |
self.visit_mut_stmt_like(n); | |
} | |
+ fn visit_mut_switch_case(&mut self, n: &mut SwitchCase) { | |
+ let old_vars = self.vars.take(); | |
+ | |
+ n.visit_mut_children_with(self); | |
+ | |
+ self.vars = old_vars; | |
+ } | |
+ | |
fn visit_mut_var_decl(&mut self, var: &mut VarDecl) { | |
let old = self.var_decl_kind; | |
self.var_decl_kind = var.kind; | |
@@ -569,6 +570,13 @@ impl VisitMut for BlockScoping { | |
} | |
} | |
} | |
+ | |
+ fn visit_mut_while_stmt(&mut self, node: &mut WhileStmt) { | |
+ self.visit_mut_with_scope(ScopeKind::new_loop(), &mut node.body); | |
+ | |
+ node.test.visit_mut_with(self); | |
+ self.handle_capture_of_vars(&mut node.body); | |
+ } | |
} | |
impl BlockScoping { | |
diff --git a/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs b/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs | |
index dc27b327ce..e9660266cc 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs | |
@@ -154,7 +154,7 @@ where | |
.into()], | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
)) { | |
Ok(t) => t, | |
diff --git a/crates/swc_ecma_transforms_compat/src/es2015/for_of.rs b/crates/swc_ecma_transforms_compat/src/es2015/for_of.rs | |
index b509443934..d7ddb6be38 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es2015/for_of.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es2015/for_of.rs | |
@@ -670,7 +670,7 @@ impl VisitMut for ForOf { | |
*s = self.fold_for_stmt(Some(label.clone()), stmt.take()); | |
} | |
_ => { | |
- body.visit_mut_children_with(self); | |
+ body.visit_mut_with(self); | |
} | |
} | |
} | |
diff --git a/crates/swc_ecma_transforms_compat/src/es2015/generator.rs b/crates/swc_ecma_transforms_compat/src/es2015/generator.rs | |
index a6da0916a0..a409203a50 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es2015/generator.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es2015/generator.rs | |
@@ -572,72 +572,70 @@ impl VisitMut for Generator { | |
e.visit_mut_children_with(self); | |
} | |
- Expr::Assign(node) => { | |
- if contains_yield(&node.right) { | |
- match node.left.as_expr_mut() { | |
- Some(Expr::Member(left)) => { | |
- match &mut left.prop { | |
- MemberProp::Ident(..) | MemberProp::PrivateName(..) => { | |
- // a.b = yield; | |
- // | |
- // [intermediate] | |
- // .local _a | |
- // _a = a; | |
- // .yield resumeLabel | |
- // .mark resumeLabel | |
- // _a.b = %sent%; | |
- | |
- left.obj.visit_mut_with(self); | |
- let obj = self.cache_expression(left.obj.take()); | |
- | |
- left.obj = Box::new(Expr::Ident(obj)); | |
- } | |
- MemberProp::Computed(prop) => { | |
- // [source] | |
- // a[b] = yield; | |
- // | |
- // [intermediate] | |
- // .local _a, _b | |
- // _a = a; | |
- // _b = b; | |
- // .yield resumeLabel | |
- // .mark resumeLabel | |
- // _a[_b] = %sent%; | |
- let prop_span = prop.span; | |
- | |
- left.obj.visit_mut_with(self); | |
- let obj = self.cache_expression(left.obj.take()); | |
- | |
- prop.visit_mut_with(self); | |
- let prop = self.cache_expression(prop.expr.take()); | |
- | |
- left.obj = Box::new(Expr::Ident(obj)); | |
- left.prop = MemberProp::Computed(ComputedPropName { | |
- span: prop_span, | |
- expr: Box::new(Expr::Ident(prop)), | |
- }); | |
- } | |
+ Expr::Assign(node) if contains_yield(&node.right) => { | |
+ match node.left.as_expr_mut() { | |
+ Some(Expr::Member(left)) => { | |
+ match &mut left.prop { | |
+ MemberProp::Ident(..) | MemberProp::PrivateName(..) => { | |
+ // a.b = yield; | |
+ // | |
+ // [intermediate] | |
+ // .local _a | |
+ // _a = a; | |
+ // .yield resumeLabel | |
+ // .mark resumeLabel | |
+ // _a.b = %sent%; | |
+ | |
+ left.obj.visit_mut_with(self); | |
+ let obj = self.cache_expression(left.obj.take()); | |
+ | |
+ left.obj = Box::new(Expr::Ident(obj)); | |
+ } | |
+ MemberProp::Computed(prop) => { | |
+ // [source] | |
+ // a[b] = yield; | |
+ // | |
+ // [intermediate] | |
+ // .local _a, _b | |
+ // _a = a; | |
+ // _b = b; | |
+ // .yield resumeLabel | |
+ // .mark resumeLabel | |
+ // _a[_b] = %sent%; | |
+ let prop_span = prop.span; | |
+ | |
+ left.obj.visit_mut_with(self); | |
+ let obj = self.cache_expression(left.obj.take()); | |
+ | |
+ prop.visit_mut_with(self); | |
+ let prop = self.cache_expression(prop.expr.take()); | |
+ | |
+ left.obj = Box::new(Expr::Ident(obj)); | |
+ left.prop = MemberProp::Computed(ComputedPropName { | |
+ span: prop_span, | |
+ expr: Box::new(Expr::Ident(prop)), | |
+ }); | |
} | |
- // [source] | |
- } | |
- _ => { | |
- node.left.visit_mut_with(self); | |
} | |
+ // [source] | |
+ } | |
+ _ => { | |
+ node.left.visit_mut_with(self); | |
} | |
- if node.op != op!("=") { | |
- let left_of_right = self.cache_expression(node.left.take().expect_expr()); | |
+ } | |
+ if node.op != op!("=") { | |
+ let left_of_right = self.cache_expression(node.left.take().expect_expr()); | |
- node.right.visit_mut_with(self); | |
+ node.right.visit_mut_with(self); | |
- *e = Expr::Assign(AssignExpr { | |
- span: node.right.span(), | |
- op: node.op, | |
- left: left_of_right.into(), | |
- right: node.right.take(), | |
- }); | |
- } else { | |
- node.right.visit_mut_with(self); | |
- } | |
+ *e = Expr::Assign(AssignExpr { | |
+ span: node.right.span(), | |
+ op: node.op, | |
+ left: left_of_right.into(), | |
+ right: node.right.take(), | |
+ }); | |
+ } else { | |
+ node.right.visit_mut_with(self); | |
} | |
} | |
diff --git a/crates/swc_ecma_transforms_compat/src/es2018/object_rest.rs b/crates/swc_ecma_transforms_compat/src/es2018/object_rest.rs | |
index 269d987bd6..39e6fc1253 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es2018/object_rest.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es2018/object_rest.rs | |
@@ -291,7 +291,7 @@ impl VisitMut for ObjectRest { | |
specifiers, | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}; | |
var_decl.visit_mut_with(self); | |
diff --git a/crates/swc_ecma_transforms_compat/src/es2020/export_namespace_from.rs b/crates/swc_ecma_transforms_compat/src/es2020/export_namespace_from.rs | |
index 3ca62e97c3..98ea8e3f57 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es2020/export_namespace_from.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es2020/export_namespace_from.rs | |
@@ -40,7 +40,7 @@ impl VisitMut for ExportNamespaceFrom { | |
specifiers, | |
src: Some(src), | |
type_only: false, | |
- asserts, | |
+ with, | |
})) if specifiers.iter().any(|s| s.is_namespace()) => { | |
let mut origin_specifiers = vec![]; | |
@@ -79,7 +79,7 @@ impl VisitMut for ExportNamespaceFrom { | |
specifiers: import_specifiers, | |
src: src.clone(), | |
type_only: false, | |
- asserts: asserts.clone(), | |
+ with: with.clone(), | |
}))); | |
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed( | |
@@ -88,7 +88,7 @@ impl VisitMut for ExportNamespaceFrom { | |
specifiers: export_specifiers, | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
))); | |
@@ -99,7 +99,7 @@ impl VisitMut for ExportNamespaceFrom { | |
specifiers: origin_specifiers, | |
src: Some(src), | |
type_only: false, | |
- asserts, | |
+ with, | |
}, | |
))); | |
} | |
diff --git a/crates/swc_ecma_transforms_compat/src/es2020/mod.rs b/crates/swc_ecma_transforms_compat/src/es2020/mod.rs | |
index 39d5c67409..c116b3c6de 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es2020/mod.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es2020/mod.rs | |
@@ -1,5 +1,5 @@ | |
use serde::Deserialize; | |
-use swc_common::chain; | |
+use swc_common::{chain, Mark}; | |
use swc_ecma_visit::Fold; | |
pub use self::{ | |
@@ -11,10 +11,10 @@ mod export_namespace_from; | |
pub mod nullish_coalescing; | |
pub mod optional_chaining; | |
-pub fn es2020(config: Config) -> impl Fold { | |
+pub fn es2020(config: Config, unresolved_mark: Mark) -> impl Fold { | |
chain!( | |
nullish_coalescing(config.nullish_coalescing), | |
- optional_chaining(config.optional_chaining), | |
+ optional_chaining(config.optional_chaining, unresolved_mark), | |
export_namespace_from(), | |
) | |
} | |
diff --git a/crates/swc_ecma_transforms_compat/src/es2020/optional_chaining.rs b/crates/swc_ecma_transforms_compat/src/es2020/optional_chaining.rs | |
index 1ce54d2184..034907e4a2 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es2020/optional_chaining.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es2020/optional_chaining.rs | |
@@ -1,16 +1,17 @@ | |
use std::mem; | |
use serde::Deserialize; | |
-use swc_common::{util::take::Take, DUMMY_SP}; | |
+use swc_common::{util::take::Take, Mark, SyntaxContext, DUMMY_SP}; | |
use swc_ecma_ast::*; | |
use swc_ecma_utils::{ | |
alias_ident_for, prepend_stmt, quote_ident, undefined, ExprFactory, StmtLike, | |
}; | |
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith}; | |
-pub fn optional_chaining(c: Config) -> impl Fold + VisitMut { | |
+pub fn optional_chaining(c: Config, unresolved_mark: Mark) -> impl Fold + VisitMut { | |
as_folder(OptChaining { | |
c, | |
+ unresolved: SyntaxContext::empty().apply_mark(unresolved_mark), | |
..Default::default() | |
}) | |
} | |
@@ -18,6 +19,7 @@ pub fn optional_chaining(c: Config) -> impl Fold + VisitMut { | |
#[derive(Default)] | |
struct OptChaining { | |
vars: Vec<VarDeclarator>, | |
+ unresolved: SyntaxContext, | |
c: Config, | |
} | |
@@ -63,7 +65,7 @@ impl VisitMut for OptChaining { | |
// foo?.bar -> foo == null ? void 0 : foo.bar | |
Expr::OptChain(v) => { | |
let data = self.gather(v.take(), vec![]); | |
- *e = self.construct(data, false, self.c.no_document_all); | |
+ *e = self.construct(data, false); | |
} | |
Expr::Unary(UnaryExpr { | |
@@ -75,7 +77,7 @@ impl VisitMut for OptChaining { | |
// delete foo?.bar -> foo == null ? true : delete foo.bar | |
Expr::OptChain(v) => { | |
let data = self.gather(v.take(), vec![]); | |
- *e = self.construct(data, true, self.c.no_document_all); | |
+ *e = self.construct(data, true); | |
} | |
_ => e.visit_mut_children_with(self), | |
} | |
@@ -145,12 +147,27 @@ impl VisitMut for OptChaining { | |
} | |
} | |
+#[derive(Debug, Clone)] | |
+enum Memo { | |
+ Cache(Ident), | |
+ Raw(Box<Expr>), | |
+} | |
+ | |
+impl Memo { | |
+ fn into_expr(self) -> Expr { | |
+ match self { | |
+ Memo::Cache(i) => Expr::Ident(i), | |
+ Memo::Raw(e) => *e, | |
+ } | |
+ } | |
+} | |
+ | |
#[derive(Debug)] | |
enum Gathering { | |
Call(CallExpr), | |
Member(MemberExpr), | |
- OptCall(CallExpr, Ident), | |
- OptMember(MemberExpr, Ident), | |
+ OptCall(CallExpr, Memo), | |
+ OptMember(MemberExpr, Memo), | |
} | |
impl OptChaining { | |
@@ -181,7 +198,7 @@ impl OptChaining { | |
next = m.obj.take(); | |
m.prop.visit_mut_with(self); | |
chain.push(if optional { | |
- Gathering::OptMember(m.take(), self.memoize(&next)) | |
+ Gathering::OptMember(m.take(), self.memoize(&next, false)) | |
} else { | |
Gathering::Member(m.take()) | |
}); | |
@@ -192,7 +209,7 @@ impl OptChaining { | |
c.args.visit_mut_with(self); | |
// I don't know why c is an OptCall instead of a CallExpr. | |
chain.push(if optional { | |
- Gathering::OptCall(c.take().into(), self.memoize(&next)) | |
+ Gathering::OptCall(c.take().into(), self.memoize(&next, true)) | |
} else { | |
Gathering::Call(c.take().into()) | |
}); | |
@@ -213,12 +230,7 @@ impl OptChaining { | |
/// Constructs a rightward nested conditional expression out of our | |
/// flattened chain. | |
- fn construct( | |
- &mut self, | |
- data: (Expr, usize, Vec<Gathering>), | |
- is_delete: bool, | |
- no_document_all: bool, | |
- ) -> Expr { | |
+ fn construct(&mut self, data: (Expr, usize, Vec<Gathering>), is_delete: bool) -> Expr { | |
let (mut current, count, chain) = data; | |
// Stores partially constructed CondExprs for us to assemble later on. | |
@@ -260,16 +272,22 @@ impl OptChaining { | |
Expr::Member(m) => { | |
call = true; | |
let this = ctx.unwrap_or_else(|| { | |
- let this = self.memoize(&m.obj); | |
- m.obj = Box::new(Expr::Assign(AssignExpr { | |
- span: DUMMY_SP, | |
- op: op!("="), | |
- left: this.clone().into(), | |
- right: m.obj.take(), | |
- })); | |
- this | |
+ let this = self.memoize(&m.obj, true); | |
+ | |
+ match &this { | |
+ Memo::Cache(i) => { | |
+ m.obj = Box::new(Expr::Assign(AssignExpr { | |
+ span: DUMMY_SP, | |
+ op: op!("="), | |
+ left: i.clone().into(), | |
+ right: m.obj.take(), | |
+ })); | |
+ this | |
+ } | |
+ Memo::Raw(_) => this, | |
+ } | |
}); | |
- c.args.insert(0, this.as_arg()); | |
+ c.args.insert(0, this.into_expr().as_arg()); | |
} | |
Expr::SuperProp(s) => { | |
call = true; | |
@@ -280,7 +298,7 @@ impl OptChaining { | |
committed_cond.push(CondExpr { | |
span: DUMMY_SP, | |
- test: init_and_eq_null_or_undefined(&memo, current, no_document_all), | |
+ test: init_and_eq_null_or_undefined(&memo, current, self.c.no_document_all), | |
cons: if is_delete { | |
true.into() | |
} else { | |
@@ -289,9 +307,11 @@ impl OptChaining { | |
alt: Take::dummy(), | |
}); | |
c.callee = if call { | |
- memo.make_member(quote_ident!("call")).as_callee() | |
+ memo.into_expr() | |
+ .make_member(quote_ident!("call")) | |
+ .as_callee() | |
} else { | |
- memo.as_callee() | |
+ memo.into_expr().as_callee() | |
}; | |
ctx = None; | |
Expr::Call(c) | |
@@ -299,7 +319,7 @@ impl OptChaining { | |
Gathering::OptMember(mut m, memo) => { | |
committed_cond.push(CondExpr { | |
span: DUMMY_SP, | |
- test: init_and_eq_null_or_undefined(&memo, current, no_document_all), | |
+ test: init_and_eq_null_or_undefined(&memo, current, self.c.no_document_all), | |
cons: if is_delete { | |
true.into() | |
} else { | |
@@ -308,7 +328,7 @@ impl OptChaining { | |
alt: Take::dummy(), | |
}); | |
ctx = Some(memo.clone()); | |
- m.obj = memo.into(); | |
+ m.obj = memo.into_expr().into(); | |
Expr::Member(m) | |
} | |
}; | |
@@ -331,15 +351,41 @@ impl OptChaining { | |
current | |
} | |
- fn memoize(&mut self, expr: &Expr) -> Ident { | |
- let memo = alias_ident_for(expr, "_this"); | |
- self.vars.push(VarDeclarator { | |
- span: DUMMY_SP, | |
- name: memo.clone().into(), | |
- init: None, | |
- definite: false, | |
- }); | |
- memo | |
+ fn should_memo(&self, expr: &Expr, is_call: bool) -> bool { | |
+ fn is_simple_member(e: &Expr) -> bool { | |
+ match e { | |
+ Expr::Ident(_) => true, | |
+ Expr::SuperProp(s) if !s.prop.is_computed() => true, | |
+ Expr::Member(m) if !m.prop.is_computed() => is_simple_member(&m.obj), | |
+ _ => false, | |
+ } | |
+ } | |
+ | |
+ match expr { | |
+ Expr::Ident(i) if i.span.ctxt != self.unresolved => false, | |
+ _ => { | |
+ if is_call && self.c.pure_getter { | |
+ !is_simple_member(expr) | |
+ } else { | |
+ true | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+ fn memoize(&mut self, expr: &Expr, is_call: bool) -> Memo { | |
+ if self.should_memo(expr, is_call) { | |
+ let memo = alias_ident_for(expr, "_this"); | |
+ self.vars.push(VarDeclarator { | |
+ span: DUMMY_SP, | |
+ name: memo.clone().into(), | |
+ init: None, | |
+ definite: false, | |
+ }); | |
+ Memo::Cache(memo) | |
+ } else { | |
+ Memo::Raw(Box::new(expr.to_owned())) | |
+ } | |
} | |
fn visit_mut_stmt_like<T>(&mut self, stmts: &mut Vec<T>) | |
@@ -371,13 +417,16 @@ impl OptChaining { | |
} | |
} | |
-fn init_and_eq_null_or_undefined(i: &Ident, init: Expr, no_document_all: bool) -> Box<Expr> { | |
- let lhs = Box::new(Expr::Assign(AssignExpr { | |
- span: DUMMY_SP, | |
- op: op!("="), | |
- left: PatOrExpr::Pat(i.clone().into()), | |
- right: Box::new(init), | |
- })); | |
+fn init_and_eq_null_or_undefined(i: &Memo, init: Expr, no_document_all: bool) -> Box<Expr> { | |
+ let lhs = match i { | |
+ Memo::Cache(i) => Box::new(Expr::Assign(AssignExpr { | |
+ span: DUMMY_SP, | |
+ op: op!("="), | |
+ left: PatOrExpr::Pat(i.clone().into()), | |
+ right: Box::new(init), | |
+ })), | |
+ Memo::Raw(e) => e.to_owned(), | |
+ }; | |
if no_document_all { | |
return Box::new(Expr::Bin(BinExpr { | |
@@ -395,9 +444,14 @@ fn init_and_eq_null_or_undefined(i: &Ident, init: Expr, no_document_all: bool) - | |
right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))), | |
})); | |
+ let left_expr = match i { | |
+ Memo::Cache(i) => Box::new(i.clone().into()), | |
+ Memo::Raw(e) => e.to_owned(), | |
+ }; | |
+ | |
let void_cmp = Box::new(Expr::Bin(BinExpr { | |
span: DUMMY_SP, | |
- left: Box::new(Expr::Ident(i.clone())), | |
+ left: left_expr, | |
op: op!("==="), | |
right: undefined(DUMMY_SP), | |
})); | |
diff --git a/crates/swc_ecma_transforms_compat/src/es2022/class_properties/mod.rs b/crates/swc_ecma_transforms_compat/src/es2022/class_properties/mod.rs | |
index 5ba50de0c4..c83ebc2316 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es2022/class_properties/mod.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es2022/class_properties/mod.rs | |
@@ -365,7 +365,7 @@ impl<C: Comments> ClassProperties<C> { | |
.into()], | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
)) { | |
Ok(t) => t, | |
diff --git a/crates/swc_ecma_transforms_compat/src/es2022/static_blocks.rs b/crates/swc_ecma_transforms_compat/src/es2022/static_blocks.rs | |
index 5a35cbbf4f..ef47681494 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es2022/static_blocks.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es2022/static_blocks.rs | |
@@ -17,11 +17,40 @@ pub fn static_blocks(mark: Mark) -> impl Fold + VisitMut { | |
impl ClassStaticBlock { | |
fn visit_mut_static_block( | |
&mut self, | |
- static_block: StaticBlock, | |
+ mut static_block: StaticBlock, | |
private_id: JsWord, | |
) -> PrivateProp { | |
+ let mut stmts = static_block.body.stmts.take(); | |
+ let span = static_block.span; | |
+ | |
+ // We special-case the single expression case to avoid the iife, since it's | |
+ // common. | |
+ let value = if stmts.len() == 1 && stmts[0].is_expr() { | |
+ stmts[0].take().expr().map(|expr_stmt| expr_stmt.expr) | |
+ } else { | |
+ static_block.body.stmts = stmts; | |
+ | |
+ let expr = Expr::Call(CallExpr { | |
+ span: DUMMY_SP, | |
+ callee: ArrowExpr { | |
+ span: DUMMY_SP, | |
+ params: Vec::new(), | |
+ is_async: false, | |
+ is_generator: false, | |
+ type_params: None, | |
+ return_type: None, | |
+ body: Box::new(BlockStmtOrExpr::BlockStmt(static_block.body)), | |
+ } | |
+ .as_callee(), | |
+ args: Vec::new(), | |
+ type_args: None, | |
+ }); | |
+ | |
+ Some(Box::new(expr)) | |
+ }; | |
+ | |
PrivateProp { | |
- span: DUMMY_SP.apply_mark(self.mark), | |
+ span: span.apply_mark(self.mark), | |
is_static: true, | |
is_optional: false, | |
is_override: false, | |
@@ -37,21 +66,7 @@ impl ClassStaticBlock { | |
optional: false, | |
}, | |
}, | |
- value: Some(Box::new(Expr::Call(CallExpr { | |
- span: DUMMY_SP, | |
- callee: ArrowExpr { | |
- span: DUMMY_SP, | |
- params: Vec::new(), | |
- is_async: false, | |
- is_generator: false, | |
- type_params: None, | |
- return_type: None, | |
- body: Box::new(BlockStmtOrExpr::BlockStmt(static_block.body)), | |
- } | |
- .as_callee(), | |
- args: Vec::new(), | |
- type_args: None, | |
- }))), | |
+ value, | |
definite: false, | |
} | |
} | |
diff --git a/crates/swc_ecma_transforms_compat/src/es3/reserved_word.rs b/crates/swc_ecma_transforms_compat/src/es3/reserved_word.rs | |
index 7df077e4b3..c1f8dbd679 100644 | |
--- a/crates/swc_ecma_transforms_compat/src/es3/reserved_word.rs | |
+++ b/crates/swc_ecma_transforms_compat/src/es3/reserved_word.rs | |
@@ -72,7 +72,7 @@ impl VisitMut for ReservedWord { | |
specifiers: extra_exports, | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
} | |
.into(), | |
); | |
diff --git a/crates/swc_ecma_transforms_compat/tests/es2015_generator.rs b/crates/swc_ecma_transforms_compat/tests/es2015_generator.rs | |
index 1b7a8f5499..4a29cfb36d 100644 | |
--- a/crates/swc_ecma_transforms_compat/tests/es2015_generator.rs | |
+++ b/crates/swc_ecma_transforms_compat/tests/es2015_generator.rs | |
@@ -1937,3 +1937,47 @@ test_exec!( | |
await res; | |
" | |
); | |
+ | |
+test!( | |
+ Syntax::default(), | |
+ |_| { | |
+ let mark = Mark::fresh(Mark::root()); | |
+ es2015::<SingleThreadedComments>(mark, None, Default::default()) | |
+ }, | |
+ issue_7809, | |
+ r#" | |
+ function a(fn) { | |
+ return _a.apply(this, arguments); | |
+ } | |
+ function _a() { | |
+ _a = _async_to_generator(function*(fn) { | |
+ (yield fn()).a = 1; | |
+ }); | |
+ return _a.apply(this, arguments); | |
+ } | |
+ "#, | |
+ r#" | |
+ function a(fn) { | |
+ return _a.apply(this, arguments); | |
+ } | |
+ function _a() { | |
+ _a = _async_to_generator(function(fn) { | |
+ return _ts_generator(this, function(_state) { | |
+ switch(_state.label){ | |
+ case 0: | |
+ return [ | |
+ 4, | |
+ fn() | |
+ ]; | |
+ case 1: | |
+ _state.sent().a = 1; | |
+ return [ | |
+ 2 | |
+ ]; | |
+ } | |
+ }); | |
+ }); | |
+ return _a.apply(this, arguments); | |
+ } | |
+ "# | |
+); | |
diff --git a/crates/swc_ecma_transforms_compat/tests/es2020_optional_chaining.rs b/crates/swc_ecma_transforms_compat/tests/es2020_optional_chaining.rs | |
index 63b6d96ca4..5f8161c5d8 100644 | |
--- a/crates/swc_ecma_transforms_compat/tests/es2020_optional_chaining.rs | |
+++ b/crates/swc_ecma_transforms_compat/tests/es2020_optional_chaining.rs | |
@@ -1,12 +1,19 @@ | |
use std::{fs::read_to_string, path::PathBuf}; | |
+use swc_common::{chain, Mark}; | |
use swc_ecma_parser::Syntax; | |
+use swc_ecma_transforms_base::resolver; | |
use swc_ecma_transforms_compat::es2020::{optional_chaining, optional_chaining::Config}; | |
use swc_ecma_transforms_testing::{compare_stdout, test, test_exec, test_fixture}; | |
use swc_ecma_visit::Fold; | |
fn tr(c: Config) -> impl Fold { | |
- optional_chaining(c) | |
+ let unresolved_mark = Mark::new(); | |
+ let top_level_mark = Mark::new(); | |
+ chain!( | |
+ resolver(unresolved_mark, top_level_mark, false), | |
+ optional_chaining(c, unresolved_mark) | |
+ ) | |
} | |
fn syntax() -> Syntax { | |
@@ -264,10 +271,18 @@ fn exec(input: PathBuf) { | |
compare_stdout( | |
Default::default(), | |
|_| { | |
- optional_chaining(Config { | |
- no_document_all: true, | |
- ..Default::default() | |
- }) | |
+ let unresolved_mark = Mark::new(); | |
+ let top_level_mark = Mark::new(); | |
+ chain!( | |
+ resolver(unresolved_mark, top_level_mark, false), | |
+ optional_chaining( | |
+ Config { | |
+ no_document_all: true, | |
+ ..Default::default() | |
+ }, | |
+ Mark::new(), | |
+ ) | |
+ ) | |
}, | |
&src, | |
); | |
@@ -279,7 +294,14 @@ fn fixture(input: PathBuf) { | |
test_fixture( | |
Default::default(), | |
- &|_| optional_chaining(Default::default()), | |
+ &|_| { | |
+ let unresolved_mark = Mark::new(); | |
+ let top_level_mark = Mark::new(); | |
+ chain!( | |
+ resolver(unresolved_mark, top_level_mark, false), | |
+ optional_chaining(Default::default(), unresolved_mark) | |
+ ) | |
+ }, | |
&input, | |
&output, | |
Default::default(), | |
@@ -293,10 +315,18 @@ fn fixture_loose(input: PathBuf) { | |
test_fixture( | |
Default::default(), | |
&|_| { | |
- optional_chaining(Config { | |
- no_document_all: true, | |
- pure_getter: true, | |
- }) | |
+ let unresolved_mark = Mark::new(); | |
+ let top_level_mark = Mark::new(); | |
+ chain!( | |
+ resolver(unresolved_mark, top_level_mark, false), | |
+ optional_chaining( | |
+ Config { | |
+ no_document_all: true, | |
+ pure_getter: true, | |
+ }, | |
+ Mark::new(), | |
+ ) | |
+ ) | |
}, | |
&input, | |
&output, | |
diff --git a/crates/swc_ecma_transforms_macros/src/parallel.rs b/crates/swc_ecma_transforms_macros/src/parallel.rs | |
index 006ee04400..2a0da6eddb 100644 | |
--- a/crates/swc_ecma_transforms_macros/src/parallel.rs | |
+++ b/crates/swc_ecma_transforms_macros/src/parallel.rs | |
@@ -1,3 +1,5 @@ | |
+#![allow(non_snake_case)] | |
+ | |
use pmutil::q; | |
use proc_macro2::{Span, TokenStream}; | |
use syn::{Expr, Ident, ImplItem, ImplItemFn, ItemImpl, Meta, Type}; | |
@@ -29,11 +31,9 @@ pub fn expand(attr: TokenStream, mut item: ItemImpl) -> ItemImpl { | |
mode, | |
"module_items", | |
explode, | |
- 100, | |
- ))); | |
- item.items.push(ImplItem::Fn(make_par_visit_method( | |
- mode, "stmts", explode, 100, | |
))); | |
+ item.items | |
+ .push(ImplItem::Fn(make_par_visit_method(mode, "stmts", explode))); | |
item | |
} | |
@@ -85,20 +85,15 @@ fn explode_hook_method_name(explode: bool, suffix: &str) -> Option<Ident> { | |
} | |
} | |
-fn make_par_visit_method(mode: Mode, suffix: &str, explode: bool, threshold: usize) -> ImplItemFn { | |
+fn make_par_visit_method(mode: Mode, suffix: &str, explode: bool) -> ImplItemFn { | |
let method_name = Ident::new(&format!("{}_{}", mode.prefix(), suffix), Span::call_site()); | |
let hook = post_visit_hook(mode, suffix); | |
let explode_method_name = explode_hook_method_name(explode, suffix); | |
- let threshold = q!(Vars { threshold }, { | |
- (swc_ecma_transforms_base::perf::cpu_count() * threshold) | |
- }); | |
- | |
match (mode, explode_method_name) { | |
(Mode::Fold, Some(explode_method_name)) => q!( | |
Vars { | |
NodeType: node_type(suffix), | |
- threshold, | |
method_name, | |
hook, | |
explode_method_name, | |
@@ -109,63 +104,6 @@ fn make_par_visit_method(mode: Mode, suffix: &str, explode: bool, threshold: usi | |
use swc_ecma_transforms_base::perf::{ParExplode, Parallel}; | |
use swc_ecma_visit::FoldWith; | |
- #[cfg(feature = "rayon")] | |
- if nodes.len() >= threshold || option_env!("SWC_FORCE_CONCURRENT") == Some("1") | |
- { | |
- use rayon::prelude::*; | |
- | |
- let (visitor, mut nodes) = ::swc_common::GLOBALS.with(|globals| { | |
- swc_ecma_transforms_base::helpers::HELPERS.with(|helpers| { | |
- HANDLER.with(|handler| { | |
- nodes | |
- .into_par_iter() | |
- .map(|node| { | |
- ::swc_common::GLOBALS.set(&globals, || { | |
- swc_ecma_transforms_base::helpers::HELPERS.set( | |
- helpers, | |
- || { | |
- HANDLER.set(handler, || { | |
- let mut visitor = | |
- Parallel::create(&*self); | |
- let node = node.fold_with(&mut visitor); | |
- let mut nodes = Vec::with_capacity(4); | |
- | |
- ParExplode::explode_method_name( | |
- &mut visitor, | |
- &mut nodes, | |
- ); | |
- | |
- nodes.push(node); | |
- | |
- (visitor, nodes) | |
- }) | |
- }, | |
- ) | |
- }) | |
- }) | |
- .reduce( | |
- || (Parallel::create(&*self), vec![]), | |
- |mut a, b| { | |
- Parallel::merge(&mut a.0, b.0); | |
- | |
- a.1.extend(b.1); | |
- | |
- a | |
- }, | |
- ) | |
- }) | |
- }) | |
- }); | |
- | |
- Parallel::merge(self, visitor); | |
- | |
- { | |
- hook; | |
- } | |
- | |
- return nodes; | |
- } | |
- | |
let mut buf = Vec::with_capacity(nodes.len()); | |
for node in nodes { | |
@@ -189,7 +127,6 @@ fn make_par_visit_method(mode: Mode, suffix: &str, explode: bool, threshold: usi | |
(Mode::Fold, None) => q!( | |
Vars { | |
NodeType: node_type(suffix), | |
- threshold, | |
method_name, | |
hook, | |
}, | |
@@ -199,65 +136,6 @@ fn make_par_visit_method(mode: Mode, suffix: &str, explode: bool, threshold: usi | |
use swc_ecma_transforms_base::perf::Parallel; | |
use swc_ecma_visit::FoldWith; | |
- #[cfg(feature = "rayon")] | |
- if nodes.len() >= threshold || option_env!("SWC_FORCE_CONCURRENT") == Some("1") | |
- { | |
- use rayon::prelude::*; | |
- | |
- let (visitor, mut nodes) = ::swc_common::GLOBALS.with(|globals| { | |
- swc_ecma_transforms_base::helpers::HELPERS.with(|helpers| { | |
- HANDLER.with(|handler| { | |
- nodes | |
- .into_par_iter() | |
- .map(|node| { | |
- ::swc_common::GLOBALS.set(&globals, || { | |
- swc_ecma_transforms_base::helpers::HELPERS.set( | |
- helpers, | |
- || { | |
- HANDLER.set(handler, || { | |
- let mut visitor = | |
- Parallel::create(&*self); | |
- let node = node.fold_with(&mut visitor); | |
- | |
- (visitor, node) | |
- }) | |
- }, | |
- ) | |
- }) | |
- }) | |
- .fold( | |
- || (Parallel::create(&*self), vec![]), | |
- |mut a, b| { | |
- Parallel::merge(&mut a.0, b.0); | |
- | |
- a.1.push(b.1); | |
- | |
- a | |
- }, | |
- ) | |
- .reduce( | |
- || (Parallel::create(&*self), vec![]), | |
- |mut a, b| { | |
- Parallel::merge(&mut a.0, b.0); | |
- | |
- a.1.extend(b.1); | |
- | |
- a | |
- }, | |
- ) | |
- }) | |
- }) | |
- }); | |
- | |
- Parallel::merge(self, visitor); | |
- | |
- { | |
- hook; | |
- } | |
- | |
- return nodes; | |
- } | |
- | |
let mut nodes = nodes.fold_children_with(self); | |
{ | |
hook; | |
@@ -272,7 +150,6 @@ fn make_par_visit_method(mode: Mode, suffix: &str, explode: bool, threshold: usi | |
(Mode::VisitMut, Some(explode_method_name)) => q!( | |
Vars { | |
NodeType: node_type(suffix), | |
- threshold, | |
method_name, | |
hook, | |
explode_method_name | |
@@ -285,66 +162,6 @@ fn make_par_visit_method(mode: Mode, suffix: &str, explode: bool, threshold: usi | |
use swc_ecma_transforms_base::perf::{ParExplode, Parallel}; | |
use swc_ecma_visit::VisitMutWith; | |
- #[cfg(feature = "rayon")] | |
- if nodes.len() >= threshold || option_env!("SWC_FORCE_CONCURRENT") == Some("1") | |
- { | |
- ::swc_common::GLOBALS.with(|globals| { | |
- swc_ecma_transforms_base::helpers::HELPERS.with(|helpers| { | |
- HANDLER.with(|handler| { | |
- use rayon::prelude::*; | |
- | |
- let (visitor, new_nodes) = take(nodes) | |
- .into_par_iter() | |
- .map(|mut node| { | |
- ::swc_common::GLOBALS.set(&globals, || { | |
- swc_ecma_transforms_base::helpers::HELPERS.set( | |
- helpers, | |
- || { | |
- HANDLER.set(handler, || { | |
- let mut visitor = | |
- Parallel::create(&*self); | |
- node.visit_mut_with(&mut visitor); | |
- | |
- let mut nodes = Vec::with_capacity(4); | |
- | |
- ParExplode::explode_method_name( | |
- &mut visitor, | |
- &mut nodes, | |
- ); | |
- | |
- nodes.push(node); | |
- | |
- (visitor, nodes) | |
- }) | |
- }, | |
- ) | |
- }) | |
- }) | |
- .reduce( | |
- || (Parallel::create(&*self), vec![]), | |
- |mut a, b| { | |
- Parallel::merge(&mut a.0, b.0); | |
- | |
- a.1.extend(b.1); | |
- | |
- a | |
- }, | |
- ); | |
- | |
- Parallel::merge(self, visitor); | |
- | |
- { | |
- hook; | |
- } | |
- | |
- *nodes = new_nodes; | |
- }) | |
- }) | |
- }); | |
- | |
- return; | |
- } | |
- | |
let mut buf = Vec::with_capacity(nodes.len()); | |
for mut node in take(nodes) { | |
@@ -367,7 +184,6 @@ fn make_par_visit_method(mode: Mode, suffix: &str, explode: bool, threshold: usi | |
(Mode::VisitMut, None) => q!( | |
Vars { | |
NodeType: node_type(suffix), | |
- threshold, | |
method_name, | |
hook, | |
}, | |
@@ -377,53 +193,6 @@ fn make_par_visit_method(mode: Mode, suffix: &str, explode: bool, threshold: usi | |
use swc_ecma_transforms_base::perf::Parallel; | |
use swc_ecma_visit::VisitMutWith; | |
- #[cfg(feature = "rayon")] | |
- if nodes.len() >= threshold || option_env!("SWC_FORCE_CONCURRENT") == Some("1") | |
- { | |
- ::swc_common::GLOBALS.with(|globals| { | |
- swc_ecma_transforms_base::helpers::HELPERS.with(|helpers| { | |
- HANDLER.with(|handler| { | |
- use rayon::prelude::*; | |
- | |
- let visitor = nodes | |
- .into_par_iter() | |
- .map(|node| { | |
- ::swc_common::GLOBALS.set(&globals, || { | |
- swc_ecma_transforms_base::helpers::HELPERS.set( | |
- helpers, | |
- || { | |
- HANDLER.set(handler, || { | |
- let mut visitor = | |
- Parallel::create(&*self); | |
- node.visit_mut_with(&mut visitor); | |
- | |
- visitor | |
- }) | |
- }, | |
- ) | |
- }) | |
- }) | |
- .reduce( | |
- || Parallel::create(&*self), | |
- |mut a, b| { | |
- Parallel::merge(&mut a, b); | |
- | |
- a | |
- }, | |
- ); | |
- | |
- Parallel::merge(self, visitor); | |
- | |
- { | |
- hook; | |
- } | |
- }) | |
- }) | |
- }); | |
- | |
- return; | |
- } | |
- | |
nodes.visit_mut_children_with(self); | |
{ | |
hook; | |
diff --git a/crates/swc_ecma_transforms_module/src/lib.rs b/crates/swc_ecma_transforms_module/src/lib.rs | |
index 6c73f690dd..bfc8b3869f 100644 | |
--- a/crates/swc_ecma_transforms_module/src/lib.rs | |
+++ b/crates/swc_ecma_transforms_module/src/lib.rs | |
@@ -3,6 +3,8 @@ | |
#![allow(clippy::needless_lifetimes)] | |
#![allow(clippy::vec_box)] | |
+use serde::{Deserialize, Serialize}; | |
+ | |
pub use self::{amd::amd, common_js::common_js, system_js::system_js, umd::umd}; | |
#[macro_use] | |
@@ -16,3 +18,10 @@ pub mod path; | |
pub mod rewriter; | |
pub mod system_js; | |
pub mod umd; | |
+ | |
+#[derive(Debug, Default, Clone, Serialize, Deserialize)] | |
+#[serde(deny_unknown_fields, rename_all = "camelCase")] | |
+pub struct EsModuleConfig { | |
+ #[serde(default)] | |
+ pub resolve_fully: bool, | |
+} | |
diff --git a/crates/swc_ecma_transforms_module/src/path.rs b/crates/swc_ecma_transforms_module/src/path.rs | |
index 7f10d7e527..7c33109ef7 100644 | |
--- a/crates/swc_ecma_transforms_module/src/path.rs | |
+++ b/crates/swc_ecma_transforms_module/src/path.rs | |
@@ -14,7 +14,7 @@ use swc_common::{FileName, Mark, Span, DUMMY_SP}; | |
use swc_ecma_ast::*; | |
use swc_ecma_loader::resolve::Resolve; | |
use swc_ecma_utils::{quote_ident, ExprFactory}; | |
-use tracing::{debug, trace, warn, Level}; | |
+use tracing::{debug, info, warn, Level}; | |
pub(crate) enum Resolver { | |
Real { | |
@@ -86,21 +86,38 @@ where | |
R: Resolve, | |
{ | |
resolver: R, | |
- base_dir: Option<PathBuf>, | |
+ config: Config, | |
+} | |
+ | |
+#[derive(Debug, Clone, Default)] | |
+pub struct Config { | |
+ pub base_dir: Option<PathBuf>, | |
+ pub resolve_fully: bool, | |
} | |
impl<R> NodeImportResolver<R> | |
where | |
R: Resolve, | |
{ | |
- #[deprecated(note = "Use `with_base_dir`")] | |
+ #[deprecated(note = "Use `with_config`")] | |
pub fn new(resolver: R) -> Self { | |
- Self::with_base_dir(resolver, None) | |
+ Self::with_config(resolver, Default::default()) | |
} | |
+ #[deprecated(note = "Use `with_config`")] | |
pub fn with_base_dir(resolver: R, base_dir: Option<PathBuf>) -> Self { | |
+ Self::with_config( | |
+ resolver, | |
+ Config { | |
+ base_dir, | |
+ ..Default::default() | |
+ }, | |
+ ) | |
+ } | |
+ | |
+ pub fn with_config(resolver: R, config: Config) -> Self { | |
#[cfg(not(target_arch = "wasm32"))] | |
- if let Some(base_dir) = &base_dir { | |
+ if let Some(base_dir) = &config.base_dir { | |
assert!( | |
base_dir.is_absolute(), | |
"base_dir(`{}`) must be absolute. Please ensure that `jsc.baseUrl` is specified \ | |
@@ -115,43 +132,69 @@ where | |
); | |
} | |
- Self { resolver, base_dir } | |
+ Self { resolver, config } | |
} | |
} | |
-impl<R> ImportResolver for NodeImportResolver<R> | |
+impl<R> NodeImportResolver<R> | |
where | |
R: Resolve, | |
{ | |
- fn resolve_import(&self, base: &FileName, module_specifier: &str) -> Result<JsWord, Error> { | |
- fn to_specifier(target_path: &str, orig_ext: Option<&str>) -> JsWord { | |
- let mut p = PathBuf::from(target_path); | |
+ fn to_specifier(&self, mut target_path: PathBuf, orig_filename: Option<&str>) -> JsWord { | |
+ debug!( | |
+ "Creating a specifier for `{}` with original filename `{:?}`", | |
+ target_path.display(), | |
+ orig_filename | |
+ ); | |
- if cfg!(debug_assertions) { | |
- trace!("to_specifier({target_path}): orig_ext={:?}", orig_ext); | |
- } | |
+ if let Some(orig_filename) = orig_filename { | |
+ let is_resolved_as_index = if let Some(stem) = target_path.file_stem() { | |
+ stem == "index" | |
+ } else { | |
+ false | |
+ }; | |
- if let Some(orig_ext) = orig_ext { | |
- let use_orig = if let Some(ext) = p.extension() { | |
- ext == "ts" || ext == "tsx" | |
+ let is_resolved_as_ts = if let Some(ext) = target_path.extension() { | |
+ ext == "ts" || ext == "tsx" | |
+ } else { | |
+ false | |
+ }; | |
+ | |
+ let is_exact = if let Some(filename) = target_path.file_name() { | |
+ filename == orig_filename | |
+ } else { | |
+ false | |
+ }; | |
+ | |
+ if !is_resolved_as_index && !is_exact { | |
+ target_path.set_file_name(orig_filename); | |
+ } else if is_resolved_as_ts && is_exact { | |
+ if let Some(ext) = Path::new(orig_filename).extension() { | |
+ target_path.set_extension(ext); | |
} else { | |
- false | |
- }; | |
- | |
- if use_orig { | |
- if matches!(orig_ext, "js" | "mjs" | "cjs" | "jsx") { | |
- p.set_extension(orig_ext); | |
- } else { | |
- p.set_extension(""); | |
- } | |
+ target_path.set_extension("js"); | |
+ } | |
+ } else if self.config.resolve_fully && is_resolved_as_ts { | |
+ target_path.set_extension("js"); | |
+ } else if is_resolved_as_ts && is_resolved_as_index { | |
+ if orig_filename == "index" { | |
+ target_path.set_extension(""); | |
+ } else { | |
+ target_path.pop(); | |
} | |
- } else { | |
- p.set_extension(""); | |
} | |
+ } else { | |
+ target_path.set_extension(""); | |
+ } | |
- p.display().to_string().into() | |
+ if cfg!(target_os = "windows") { | |
+ target_path.display().to_string().replace('\\', "/").into() | |
+ } else { | |
+ target_path.display().to_string().into() | |
} | |
+ } | |
+ fn try_resolve_import(&self, base: &FileName, module_specifier: &str) -> Result<JsWord, Error> { | |
let _tracing = if cfg!(debug_assertions) { | |
Some( | |
tracing::span!( | |
@@ -166,17 +209,7 @@ where | |
None | |
}; | |
- if cfg!(debug_assertions) { | |
- debug!("invoking resolver"); | |
- } | |
- | |
- let orig_ext = module_specifier.split('/').last().and_then(|s| { | |
- if s.contains('.') { | |
- s.split('.').last() | |
- } else { | |
- None | |
- } | |
- }); | |
+ let orig_filename = module_specifier.split('/').last(); | |
let target = self.resolver.resolve(base, module_specifier); | |
let target = match target { | |
@@ -187,9 +220,18 @@ where | |
} | |
}; | |
+ info!("Resolved to {}", target); | |
+ | |
let mut target = match target { | |
- FileName::Real(v) => v, | |
- FileName::Custom(s) => return Ok(to_specifier(&s, orig_ext)), | |
+ FileName::Real(v) => { | |
+ // @nestjs/common should be preserved as a whole | |
+ if v.starts_with(".") || v.starts_with("..") || v.is_absolute() { | |
+ v | |
+ } else { | |
+ return Ok(self.to_specifier(v, orig_filename)); | |
+ } | |
+ } | |
+ FileName::Custom(s) => return Ok(self.to_specifier(s.into(), orig_filename)), | |
_ => { | |
unreachable!( | |
"Node path provider does not support using `{:?}` as a target file name", | |
@@ -215,10 +257,16 @@ where | |
}; | |
if base.is_absolute() != target.is_absolute() { | |
- base = Cow::Owned(absolute_path(self.base_dir.as_deref(), &base)?); | |
- target = absolute_path(self.base_dir.as_deref(), &target)?; | |
+ base = Cow::Owned(absolute_path(self.config.base_dir.as_deref(), &base)?); | |
+ target = absolute_path(self.config.base_dir.as_deref(), &target)?; | |
} | |
+ debug!( | |
+ "Comparing values (after normalizing absoluteness)\nbase={}\ntarget={}", | |
+ base.display(), | |
+ target.display() | |
+ ); | |
+ | |
let rel_path = diff_paths( | |
&target, | |
match base.parent() { | |
@@ -229,9 +277,11 @@ where | |
let rel_path = match rel_path { | |
Some(v) => v, | |
- None => return Ok(to_specifier(&target.display().to_string(), orig_ext)), | |
+ None => return Ok(self.to_specifier(target, orig_filename)), | |
}; | |
+ debug!("Relative path: {}", rel_path.display()); | |
+ | |
{ | |
// Check for `node_modules`. | |
@@ -256,11 +306,21 @@ where | |
} else { | |
Cow::Owned(format!("./{}", s)) | |
}; | |
- if cfg!(target_os = "windows") { | |
- Ok(to_specifier(&s.replace('\\', "/"), orig_ext)) | |
- } else { | |
- Ok(to_specifier(&s, orig_ext)) | |
- } | |
+ | |
+ Ok(self.to_specifier(s.into_owned().into(), orig_filename)) | |
+ } | |
+} | |
+ | |
+impl<R> ImportResolver for NodeImportResolver<R> | |
+where | |
+ R: Resolve, | |
+{ | |
+ fn resolve_import(&self, base: &FileName, module_specifier: &str) -> Result<JsWord, Error> { | |
+ self.try_resolve_import(base, module_specifier) | |
+ .or_else(|err| { | |
+ warn!("Failed to resolve import: {}", err); | |
+ Ok(module_specifier.into()) | |
+ }) | |
} | |
} | |
diff --git a/crates/swc_ecma_transforms_module/src/system_js.rs b/crates/swc_ecma_transforms_module/src/system_js.rs | |
index 520eb06b7d..758e8c524e 100644 | |
--- a/crates/swc_ecma_transforms_module/src/system_js.rs | |
+++ b/crates/swc_ecma_transforms_module/src/system_js.rs | |
@@ -17,6 +17,9 @@ use crate::{ | |
pub struct Config { | |
#[serde(default)] | |
pub allow_top_level_this: bool, | |
+ | |
+ #[serde(default)] | |
+ pub resolve_fully: bool, | |
} | |
struct SystemJs { | |
diff --git a/crates/swc_ecma_transforms_module/src/umd/config.rs b/crates/swc_ecma_transforms_module/src/umd/config.rs | |
index 3fb840eef0..1564b7283b 100644 | |
--- a/crates/swc_ecma_transforms_module/src/umd/config.rs | |
+++ b/crates/swc_ecma_transforms_module/src/umd/config.rs | |
@@ -29,8 +29,10 @@ impl Config { | |
.into_iter() | |
.map(|(k, v)| { | |
let parse = |s| { | |
- let fm = cm | |
- .new_source_file(FileName::Custom(format!("<umd-config-{}.js>", s)), s); | |
+ let fm = cm.new_source_file( | |
+ FileName::Internal(format!("<umd-config-{}.js>", s)), | |
+ s, | |
+ ); | |
parse_file_as_expr( | |
&fm, | |
diff --git a/crates/swc_ecma_transforms_module/src/util.rs b/crates/swc_ecma_transforms_module/src/util.rs | |
index ee607d1b95..823f9a2ef0 100644 | |
--- a/crates/swc_ecma_transforms_module/src/util.rs | |
+++ b/crates/swc_ecma_transforms_module/src/util.rs | |
@@ -38,6 +38,9 @@ pub struct Config { | |
pub ignore_dynamic: bool, | |
#[serde(default)] | |
pub preserve_import_meta: bool, | |
+ | |
+ #[serde(default)] | |
+ pub resolve_fully: bool, | |
} | |
impl Default for Config { | |
@@ -52,6 +55,7 @@ impl Default for Config { | |
no_interop: false, | |
ignore_dynamic: false, | |
preserve_import_meta: false, | |
+ resolve_fully: false, | |
} | |
} | |
} | |
diff --git a/crates/swc_ecma_transforms_module/tests/path_node.rs b/crates/swc_ecma_transforms_module/tests/path_node.rs | |
index 6ce2a4388f..32c80dc58e 100644 | |
--- a/crates/swc_ecma_transforms_module/tests/path_node.rs | |
+++ b/crates/swc_ecma_transforms_module/tests/path_node.rs | |
@@ -84,24 +84,23 @@ fn issue_4730() { | |
type JscPathsProvider = NodeImportResolver<TsConfigResolver<NodeModulesResolver>>; | |
-fn paths_resolver( | |
- base_url: impl AsRef<Path>, | |
- rules: Vec<(String, Vec<String>)>, | |
-) -> JscPathsProvider { | |
- let base_url = base_url | |
- .as_ref() | |
+fn paths_resolver(base_dir: &Path, rules: Vec<(String, Vec<String>)>) -> JscPathsProvider { | |
+ let base_dir = base_dir | |
.to_path_buf() | |
.canonicalize() | |
.expect("failed to canonicalize"); | |
- dbg!(&base_url); | |
+ dbg!(&base_dir); | |
- NodeImportResolver::with_base_dir( | |
+ NodeImportResolver::with_config( | |
TsConfigResolver::new( | |
NodeModulesResolver::new(swc_ecma_loader::TargetEnv::Node, Default::default(), true), | |
- base_url.clone(), | |
+ base_dir.clone(), | |
rules, | |
), | |
- Some(base_url), | |
+ swc_ecma_transforms_module::path::Config { | |
+ base_dir: Some(base_dir), | |
+ resolve_fully: false, | |
+ }, | |
) | |
} | |
@@ -134,7 +133,7 @@ fn fixture(input_dir: PathBuf) { | |
let rules = config.paths.clone().into_iter().collect(); | |
let resolver = | |
- paths_resolver(config.base_url.clone().unwrap_or(input_dir.clone()), rules); | |
+ paths_resolver(&config.base_url.clone().unwrap_or(input_dir.clone()), rules); | |
import_rewriter(FileName::Real(index_path.clone()), resolver) | |
}, | |
diff --git a/crates/swc_ecma_transforms_module/tests/system_js.rs b/crates/swc_ecma_transforms_module/tests/system_js.rs | |
index 40aeae243f..998178ab3c 100644 | |
--- a/crates/swc_ecma_transforms_module/tests/system_js.rs | |
+++ b/crates/swc_ecma_transforms_module/tests/system_js.rs | |
@@ -45,7 +45,8 @@ test!( | |
|tester| tr( | |
tester, | |
Config { | |
- allow_top_level_this: true | |
+ allow_top_level_this: true, | |
+ ..Default::default() | |
} | |
), | |
allow_top_level_this_true, | |
@@ -67,7 +68,8 @@ test!( | |
|tester| tr( | |
tester, | |
Config { | |
- allow_top_level_this: false | |
+ allow_top_level_this: false, | |
+ ..Default::default() | |
} | |
), | |
iife, | |
@@ -94,7 +96,8 @@ test!( | |
|tester| tr( | |
tester, | |
Config { | |
- allow_top_level_this: false | |
+ allow_top_level_this: false, | |
+ ..Default::default() | |
} | |
), | |
top_level_this_false_class, | |
@@ -133,7 +136,8 @@ test!( | |
|tester| tr( | |
tester, | |
Config { | |
- allow_top_level_this: false | |
+ allow_top_level_this: false, | |
+ ..Default::default() | |
} | |
), | |
allow_top_level_this_false, | |
diff --git a/crates/swc_ecma_transforms_optimization/src/const_modules.rs b/crates/swc_ecma_transforms_optimization/src/const_modules.rs | |
index 5e578e07c1..ed71111e62 100644 | |
--- a/crates/swc_ecma_transforms_optimization/src/const_modules.rs | |
+++ b/crates/swc_ecma_transforms_optimization/src/const_modules.rs | |
@@ -46,7 +46,10 @@ pub fn const_modules( | |
fn parse_option(cm: &SourceMap, name: &str, src: String) -> Arc<Expr> { | |
static CACHE: Lazy<DashMap<String, Arc<Expr>, ARandomState>> = Lazy::new(DashMap::default); | |
- let fm = cm.new_source_file(FileName::Custom(format!("<const-module-{}.js>", name)), src); | |
+ let fm = cm.new_source_file( | |
+ FileName::Internal(format!("<const-module-{}.js>", name)), | |
+ src, | |
+ ); | |
if let Some(expr) = CACHE.get(&**fm.src) { | |
return expr.clone(); | |
} | |
diff --git a/crates/swc_ecma_transforms_optimization/src/inline_globals.rs b/crates/swc_ecma_transforms_optimization/src/inline_globals.rs | |
index 434ff49600..6e67a0afd4 100644 | |
--- a/crates/swc_ecma_transforms_optimization/src/inline_globals.rs | |
+++ b/crates/swc_ecma_transforms_optimization/src/inline_globals.rs | |
@@ -4,9 +4,8 @@ use swc_common::{ | |
sync::Lrc, | |
}; | |
use swc_ecma_ast::*; | |
-use swc_ecma_transforms_base::perf::Parallel; | |
-use swc_ecma_transforms_macros::parallel; | |
-use swc_ecma_utils::{collect_decls, NodeIgnoringSpan}; | |
+use swc_ecma_transforms_base::perf::{ParVisitMut, Parallel}; | |
+use swc_ecma_utils::{collect_decls, parallel::cpu_count, NodeIgnoringSpan}; | |
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith}; | |
/// The key will be compared using [EqIgnoreSpan::eq_ignore_span], and matched | |
@@ -63,7 +62,6 @@ impl Parallel for InlineGlobals { | |
fn merge(&mut self, _: Self) {} | |
} | |
-#[parallel] | |
impl VisitMut for InlineGlobals { | |
noop_visit_mut_type!(); | |
@@ -208,6 +206,22 @@ impl VisitMut for InlineGlobals { | |
script.visit_mut_children_with(self); | |
} | |
+ | |
+ fn visit_mut_prop_or_spreads(&mut self, n: &mut Vec<PropOrSpread>) { | |
+ self.visit_mut_par(cpu_count() * 8, n); | |
+ } | |
+ | |
+ fn visit_mut_expr_or_spreads(&mut self, n: &mut Vec<ExprOrSpread>) { | |
+ self.visit_mut_par(cpu_count() * 8, n); | |
+ } | |
+ | |
+ fn visit_mut_opt_vec_expr_or_spreads(&mut self, n: &mut Vec<Option<ExprOrSpread>>) { | |
+ self.visit_mut_par(cpu_count() * 8, n); | |
+ } | |
+ | |
+ fn visit_mut_exprs(&mut self, n: &mut Vec<Box<Expr>>) { | |
+ self.visit_mut_par(cpu_count() * 8, n); | |
+ } | |
} | |
#[cfg(test)] | |
diff --git a/crates/swc_ecma_transforms_optimization/src/json_parse.rs b/crates/swc_ecma_transforms_optimization/src/json_parse.rs | |
index 05e15cd2bc..2306961b8f 100644 | |
--- a/crates/swc_ecma_transforms_optimization/src/json_parse.rs | |
+++ b/crates/swc_ecma_transforms_optimization/src/json_parse.rs | |
@@ -4,7 +4,6 @@ use serde_json::Value; | |
use swc_common::{util::take::Take, Spanned, DUMMY_SP}; | |
use swc_ecma_ast::*; | |
use swc_ecma_transforms_base::perf::Parallel; | |
-use swc_ecma_transforms_macros::parallel; | |
use swc_ecma_utils::{calc_literal_cost, member_expr, ExprFactory}; | |
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith}; | |
@@ -54,7 +53,6 @@ impl Default for JsonParse { | |
} | |
} | |
-#[parallel] | |
impl VisitMut for JsonParse { | |
noop_visit_mut_type!(); | |
diff --git a/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs b/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs | |
index b08bb7522c..9545436f92 100644 | |
--- a/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs | |
+++ b/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs | |
@@ -1505,7 +1505,7 @@ impl VisitMut for Decorator202203 { | |
specifiers: self.extra_exports.take(), | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
))); | |
} | |
diff --git a/crates/swc_ecma_transforms_proposal/src/decorators/legacy/mod.rs b/crates/swc_ecma_transforms_proposal/src/decorators/legacy/mod.rs | |
index 1f19f83fa4..cabada213e 100644 | |
--- a/crates/swc_ecma_transforms_proposal/src/decorators/legacy/mod.rs | |
+++ b/crates/swc_ecma_transforms_proposal/src/decorators/legacy/mod.rs | |
@@ -526,7 +526,7 @@ impl VisitMut for TscDecorator { | |
specifiers: self.exports.take(), | |
src: None, | |
type_only: Default::default(), | |
- asserts: Default::default(), | |
+ with: Default::default(), | |
}, | |
))); | |
} | |
diff --git a/crates/swc_ecma_transforms_proposal/src/decorators/mod.rs b/crates/swc_ecma_transforms_proposal/src/decorators/mod.rs | |
index 692c4d7021..026effac83 100644 | |
--- a/crates/swc_ecma_transforms_proposal/src/decorators/mod.rs | |
+++ b/crates/swc_ecma_transforms_proposal/src/decorators/mod.rs | |
@@ -212,7 +212,7 @@ impl Fold for Decorators { | |
.into()], | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
))); | |
}}; | |
diff --git a/crates/swc_ecma_transforms_proposal/src/explicit_resource_management.rs b/crates/swc_ecma_transforms_proposal/src/explicit_resource_management.rs | |
index 344975aaeb..e860053898 100644 | |
--- a/crates/swc_ecma_transforms_proposal/src/explicit_resource_management.rs | |
+++ b/crates/swc_ecma_transforms_proposal/src/explicit_resource_management.rs | |
@@ -113,7 +113,7 @@ impl ExplicitResourceManagement { | |
})], | |
src: None, | |
type_only: Default::default(), | |
- asserts: None, | |
+ with: None, | |
})) | |
.unwrap(), | |
); | |
@@ -152,7 +152,7 @@ impl ExplicitResourceManagement { | |
})], | |
src: None, | |
type_only: Default::default(), | |
- asserts: None, | |
+ with: None, | |
})) | |
.unwrap(), | |
); | |
diff --git a/crates/swc_ecma_transforms_proposal/src/export_default_from.rs b/crates/swc_ecma_transforms_proposal/src/export_default_from.rs | |
index a310918f3f..6718a6d9ac 100644 | |
--- a/crates/swc_ecma_transforms_proposal/src/export_default_from.rs | |
+++ b/crates/swc_ecma_transforms_proposal/src/export_default_from.rs | |
@@ -39,7 +39,7 @@ impl VisitMut for ExportDefaultFrom { | |
specifiers, | |
src: Some(src), | |
type_only: false, | |
- asserts, | |
+ with, | |
})) if specifiers.iter().any(|s| s.is_default()) => { | |
let mut origin_specifiers = vec![]; | |
@@ -79,7 +79,7 @@ impl VisitMut for ExportDefaultFrom { | |
specifiers: export_specifiers, | |
src: Some(src.clone()), | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
))); | |
@@ -90,7 +90,7 @@ impl VisitMut for ExportDefaultFrom { | |
specifiers: origin_specifiers, | |
src: Some(src), | |
type_only: false, | |
- asserts, | |
+ with, | |
}, | |
))); | |
} | |
diff --git a/crates/swc_ecma_transforms_proposal/src/import_assertions.rs b/crates/swc_ecma_transforms_proposal/src/import_assertions.rs | |
index 78aecc0575..5612a312f1 100644 | |
--- a/crates/swc_ecma_transforms_proposal/src/import_assertions.rs | |
+++ b/crates/swc_ecma_transforms_proposal/src/import_assertions.rs | |
@@ -1,23 +1,27 @@ | |
use swc_ecma_ast::{ExportAll, ImportDecl, NamedExport}; | |
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut}; | |
-pub fn import_assertions() -> impl VisitMut + Fold { | |
+#[deprecated(note = "Please use `import_assertions` instead")] | |
+pub use self::import_attributes as import_assertions; | |
+ | |
+pub fn import_attributes() -> impl VisitMut + Fold { | |
as_folder(ImportAssertions) | |
} | |
+ | |
struct ImportAssertions; | |
impl VisitMut for ImportAssertions { | |
noop_visit_mut_type!(); | |
fn visit_mut_import_decl(&mut self, n: &mut ImportDecl) { | |
- n.asserts = None; | |
+ n.with = None; | |
} | |
fn visit_mut_export_all(&mut self, n: &mut ExportAll) { | |
- n.asserts = None; | |
+ n.with = None; | |
} | |
fn visit_mut_named_export(&mut self, n: &mut NamedExport) { | |
- n.asserts = None; | |
+ n.with = None; | |
} | |
} | |
diff --git a/crates/swc_ecma_transforms_proposal/tests/explicit_resource_management.rs b/crates/swc_ecma_transforms_proposal/tests/explicit_resource_management.rs | |
index e546b724f4..df568a7209 100644 | |
--- a/crates/swc_ecma_transforms_proposal/tests/explicit_resource_management.rs | |
+++ b/crates/swc_ecma_transforms_proposal/tests/explicit_resource_management.rs | |
@@ -12,7 +12,7 @@ fn exec(input: PathBuf) { | |
exec_tr( | |
"explicit-resource-management", | |
Syntax::Es(EsConfig { | |
- using_decl: true, | |
+ explicit_resource_management: true, | |
..Default::default() | |
}), | |
|_| { | |
@@ -42,7 +42,7 @@ fn run_fixture(input: PathBuf) { | |
test_fixture( | |
Syntax::Es(EsConfig { | |
- using_decl: true, | |
+ explicit_resource_management: true, | |
..Default::default() | |
}), | |
&|_t| { | |
diff --git a/crates/swc_ecma_transforms_proposal/tests/import_assertions.rs b/crates/swc_ecma_transforms_proposal/tests/import_assertions.rs | |
index e4165c0b35..b4b79c980d 100644 | |
--- a/crates/swc_ecma_transforms_proposal/tests/import_assertions.rs | |
+++ b/crates/swc_ecma_transforms_proposal/tests/import_assertions.rs | |
@@ -9,7 +9,7 @@ fn tr() -> impl Fold { | |
fn syntax() -> Syntax { | |
Syntax::Es(EsConfig { | |
- import_assertions: true, | |
+ import_attributes: true, | |
..Default::default() | |
}) | |
} | |
diff --git a/crates/swc_ecma_transforms_react/src/jsx/mod.rs b/crates/swc_ecma_transforms_react/src/jsx/mod.rs | |
index 2fd57a788a..ea53f552cd 100644 | |
--- a/crates/swc_ecma_transforms_react/src/jsx/mod.rs | |
+++ b/crates/swc_ecma_transforms_react/src/jsx/mod.rs | |
@@ -118,7 +118,7 @@ pub fn parse_expr_for_jsx( | |
src: String, | |
top_level_mark: Mark, | |
) -> Arc<Box<Expr>> { | |
- let fm = cm.new_source_file(FileName::Custom(format!("<jsx-config-{}.js>", name)), src); | |
+ let fm = cm.new_source_file(FileName::Internal(format!("<jsx-config-{}.js>", name)), src); | |
parse_file_as_expr( | |
&fm, | |
@@ -1059,7 +1059,7 @@ where | |
} | |
.into(), | |
type_only: Default::default(), | |
- asserts: Default::default(), | |
+ with: Default::default(), | |
})), | |
) | |
}); | |
diff --git a/crates/swc_ecma_transforms_react/src/jsx/tests.rs b/crates/swc_ecma_transforms_react/src/jsx/tests.rs | |
index 7ab15dd9f0..acf91be34d 100644 | |
--- a/crates/swc_ecma_transforms_react/src/jsx/tests.rs | |
+++ b/crates/swc_ecma_transforms_react/src/jsx/tests.rs | |
@@ -1499,12 +1499,9 @@ fn test_script(src: &str, output: &Path, options: Options) { | |
let mut buf = vec![]; | |
let mut emitter = Emitter { | |
- cfg: Config { | |
- target: Default::default(), | |
- ascii_only: true, | |
- minify: false, | |
- omit_last_semi: true, | |
- }, | |
+ cfg: Config::default() | |
+ .with_ascii_only(true) | |
+ .with_omit_last_semi(true), | |
cm: tester.cm.clone(), | |
wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::new( | |
tester.cm.clone(), | |
diff --git a/crates/swc_ecma_transforms_typescript/benches/compat.rs b/crates/swc_ecma_transforms_typescript/benches/compat.rs | |
index 9b4e2ca9e7..705cb879ac 100644 | |
--- a/crates/swc_ecma_transforms_typescript/benches/compat.rs | |
+++ b/crates/swc_ecma_transforms_typescript/benches/compat.rs | |
@@ -152,7 +152,7 @@ fn es2020_nullish_coalescing(b: &mut Bencher) { | |
fn es2020_optional_chaining(b: &mut Bencher) { | |
run(b, || { | |
- swc_ecma_transforms_compat::es2020::optional_chaining(Default::default()) | |
+ swc_ecma_transforms_compat::es2020::optional_chaining(Default::default(), Mark::new()) | |
}); | |
} | |
diff --git a/crates/swc_ecma_transforms_typescript/examples/ts_to_js.rs b/crates/swc_ecma_transforms_typescript/examples/ts_to_js.rs | |
index 7edfc18cad..680d3ab0e0 100644 | |
--- a/crates/swc_ecma_transforms_typescript/examples/ts_to_js.rs | |
+++ b/crates/swc_ecma_transforms_typescript/examples/ts_to_js.rs | |
@@ -80,10 +80,7 @@ fn main() { | |
let mut buf = vec![]; | |
{ | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify: false, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default(), | |
cm: cm.clone(), | |
comments: Some(&comments), | |
wr: JsWriter::new(cm.clone(), "\n", &mut buf, None), | |
diff --git a/crates/swc_ecma_transforms_typescript/src/import_export_assign.rs b/crates/swc_ecma_transforms_typescript/src/import_export_assign.rs | |
index 25f8b58c8b..5e9a3acc20 100644 | |
--- a/crates/swc_ecma_transforms_typescript/src/import_export_assign.rs | |
+++ b/crates/swc_ecma_transforms_typescript/src/import_export_assign.rs | |
@@ -56,7 +56,7 @@ impl VisitMut for ImportExportAssign { | |
.into()], | |
src: Box::new(quote_str!("module")), | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}) | |
.into(), | |
); | |
@@ -160,7 +160,7 @@ impl VisitMut for ImportExportAssign { | |
.into()], | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
} | |
.into(), | |
)) | |
diff --git a/crates/swc_ecma_transforms_typescript/src/strip.rs b/crates/swc_ecma_transforms_typescript/src/strip.rs | |
index 6c7419892f..97bbf218cc 100644 | |
--- a/crates/swc_ecma_transforms_typescript/src/strip.rs | |
+++ b/crates/swc_ecma_transforms_typescript/src/strip.rs | |
@@ -2205,7 +2205,7 @@ where | |
specifiers: vec![], | |
src: None, | |
type_only: false, | |
- asserts: None, | |
+ with: None, | |
}, | |
))) | |
} | |
diff --git a/crates/swc_ecma_transforms_typescript/tests/strip.rs b/crates/swc_ecma_transforms_typescript/tests/strip.rs | |
index 549a7ee9a6..08326e3ff0 100644 | |
--- a/crates/swc_ecma_transforms_typescript/tests/strip.rs | |
+++ b/crates/swc_ecma_transforms_typescript/tests/strip.rs | |
@@ -729,7 +729,7 @@ test!( | |
constructor(a) { | |
} | |
} | |
- (()=>{ A.b = 'foo'; })();" | |
+ A.b = 'foo';" | |
); | |
test!( | |
@@ -3146,7 +3146,20 @@ test!( | |
decorators: true, | |
..Default::default() | |
}), | |
- |_| chain!(tr(), optional_chaining(Default::default())), | |
+ |_| { | |
+ let unresolved_mark = Mark::new(); | |
+ let top_level_mark = Mark::new(); | |
+ let config = strip::Config { | |
+ no_empty_export: true, | |
+ ..Default::default() | |
+ }; | |
+ chain!( | |
+ Optional::new(decorators(Default::default()), false,), | |
+ resolver(unresolved_mark, top_level_mark, true), | |
+ strip_with_config(config, top_level_mark), | |
+ optional_chaining(Default::default(), unresolved_mark) | |
+ ) | |
+ }, | |
issue_1149_1, | |
" | |
const tmp = tt?.map((t: any) => t).join((v: any) => v); | |
@@ -3668,9 +3681,7 @@ to!( | |
prop = (console.log(1), 'a'); | |
prop1 = (console.log(2), 'b'); | |
})(); | |
- (()=>{ | |
- A[prop1] = 2; | |
- })(); | |
+ A[prop1] = 2; | |
" | |
); | |
@@ -3696,9 +3707,7 @@ to!( | |
prop = (console.log(1), 'a'); | |
prop1 = (console.log(2), 'b'); | |
})(); | |
- (()=>{ | |
- A[prop1] = 2; | |
- })(); | |
+ A[prop1] = 2; | |
" | |
); | |
@@ -3769,7 +3778,7 @@ to!( | |
" | |
var _class; | |
const A = (_class = class {}, | |
- (()=>{ _class.a = 1; })(), | |
+ _class.a = 1, | |
_class); | |
" | |
); | |
@@ -4144,9 +4153,9 @@ to!( | |
var _TestClass; | |
var _class; | |
let TestClass = _class = someClassDecorator((_class = (_TestClass = class TestClass { | |
- }, (()=>{ _TestClass.Something = 'hello'; })(), (()=>{ _TestClass.SomeProperties = { | |
+ }, _TestClass.Something = 'hello', _TestClass.SomeProperties = { | |
firstProp: _TestClass.Something | |
- };})(), _TestClass)) || _class) || _class; | |
+ }, _TestClass)) || _class) || _class; | |
function someClassDecorator(c) { | |
return c; | |
} | |
@@ -4210,7 +4219,7 @@ class Foo { | |
const identifier = 'bar'; | |
class Foo { | |
} | |
-(()=>{ Foo.identifier = 5; })(); | |
+Foo.identifier = 5; | |
" | |
); | |
diff --git a/crates/swc_ecma_transforms_typescript/tests/strip_correctness.rs b/crates/swc_ecma_transforms_typescript/tests/strip_correctness.rs | |
index fe22e0b1e6..21f42d1011 100644 | |
--- a/crates/swc_ecma_transforms_typescript/tests/strip_correctness.rs | |
+++ b/crates/swc_ecma_transforms_typescript/tests/strip_correctness.rs | |
@@ -188,10 +188,7 @@ fn identity(entry: PathBuf) { | |
{ | |
let mut emitter = Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- minify: false, | |
- ..Default::default() | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default(), | |
cm: cm.clone(), | |
wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::new( | |
cm.clone(), | |
@@ -239,7 +236,7 @@ fn identity(entry: PathBuf) { | |
decorators: true, | |
decorators_before_export: true, | |
export_default_from: true, | |
- import_assertions: true, | |
+ import_attributes: true, | |
allow_super_outside_method: true, | |
..Default::default() | |
}), | |
diff --git a/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs b/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs | |
index a8fa1cdbd8..c4fa2462bc 100644 | |
--- a/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs | |
+++ b/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs | |
@@ -919,8 +919,8 @@ where | |
v.add_accessed_property(prop.sym.clone()); | |
} | |
- if self.ctx.in_assign_lhs || self.ctx.is_delete_arg { | |
- self.data.mark_property_mutattion(obj.to_id(), self.ctx) | |
+ if self.ctx.in_assign_lhs || self.ctx.in_update_arg || self.ctx.is_delete_arg { | |
+ self.data.mark_property_mutation(obj.to_id(), self.ctx) | |
} | |
}) | |
} | |
diff --git a/crates/swc_ecma_usage_analyzer/src/analyzer/storage.rs b/crates/swc_ecma_usage_analyzer/src/analyzer/storage.rs | |
index c15bcfdb41..3abb2c422e 100644 | |
--- a/crates/swc_ecma_usage_analyzer/src/analyzer/storage.rs | |
+++ b/crates/swc_ecma_usage_analyzer/src/analyzer/storage.rs | |
@@ -30,7 +30,7 @@ pub trait Storage: Sized + Default { | |
fn get_initialized_cnt(&self) -> usize; | |
fn truncate_initialized_cnt(&mut self, len: usize); | |
- fn mark_property_mutattion(&mut self, id: Id, ctx: Ctx); | |
+ fn mark_property_mutation(&mut self, id: Id, ctx: Ctx); | |
} | |
pub trait ScopeDataLike: Sized + Default + Clone { | |
@@ -65,10 +65,6 @@ pub trait VarDataLike: Sized { | |
fn add_accessed_property(&mut self, name: JsWord); | |
- fn mark_mutated(&mut self); | |
- | |
- fn mark_reassigned(&mut self); | |
- | |
fn mark_used_as_ref(&mut self); | |
fn add_infects_to(&mut self, other: Access); | |
diff --git a/crates/swc_ecma_visit/src/lib.rs b/crates/swc_ecma_visit/src/lib.rs | |
index 346d91364e..788cd818c4 100644 | |
--- a/crates/swc_ecma_visit/src/lib.rs | |
+++ b/crates/swc_ecma_visit/src/lib.rs | |
@@ -1095,20 +1095,20 @@ define!({ | |
pub specifiers: Vec<ImportSpecifier>, | |
pub src: Box<Str>, | |
pub type_only: bool, | |
- pub asserts: Option<Box<ObjectLit>>, | |
+ pub with: Option<Box<ObjectLit>>, | |
} | |
pub struct ExportAll { | |
pub span: Span, | |
pub src: Box<Str>, | |
pub type_only: bool, | |
- pub asserts: Option<Box<ObjectLit>>, | |
+ pub with: Option<Box<ObjectLit>>, | |
} | |
pub struct NamedExport { | |
pub span: Span, | |
pub specifiers: Vec<ExportSpecifier>, | |
pub src: Option<Box<Str>>, | |
pub type_only: bool, | |
- pub asserts: Option<Box<ObjectLit>>, | |
+ pub with: Option<Box<ObjectLit>>, | |
} | |
pub struct ExportDefaultDecl { | |
pub span: Span, | |
diff --git a/crates/swc_estree_ast/src/module.rs b/crates/swc_estree_ast/src/module.rs | |
index 70fd9ba1ff..54e75758e7 100644 | |
--- a/crates/swc_estree_ast/src/module.rs | |
+++ b/crates/swc_estree_ast/src/module.rs | |
@@ -143,7 +143,7 @@ pub struct ExportAllDeclaration { | |
pub base: BaseNode, | |
pub source: StringLiteral, | |
#[serde(default)] | |
- pub assertions: Option<Vec<ImportAttribute>>, | |
+ pub with: Option<Vec<ImportAttribute>>, | |
#[serde(default)] | |
pub export_kind: Option<ExportKind>, | |
} | |
@@ -192,7 +192,7 @@ pub struct ExportNamedDeclaration { | |
#[serde(default)] | |
pub source: Option<StringLiteral>, | |
#[serde(default)] | |
- pub assertions: Option<Vec<ImportAttribute>>, | |
+ pub with: Option<Vec<ImportAttribute>>, | |
#[serde(default)] | |
pub export_kind: Option<ExportKind>, | |
} | |
@@ -270,7 +270,7 @@ pub struct ImportDeclaration { | |
pub specifiers: Vec<ImportSpecifierType>, | |
pub source: StringLiteral, | |
#[serde(default)] | |
- pub assertions: Option<Vec<ImportAttribute>>, | |
+ pub with: Option<Vec<ImportAttribute>>, | |
#[serde(default)] | |
pub import_kind: Option<ImportKind>, | |
} | |
diff --git a/crates/swc_estree_compat/benches/babelify.rs b/crates/swc_estree_compat/benches/babelify.rs | |
index 7b0b94f68c..5076f7615e 100644 | |
--- a/crates/swc_estree_compat/benches/babelify.rs | |
+++ b/crates/swc_estree_compat/benches/babelify.rs | |
@@ -55,7 +55,7 @@ fn babelify_only(b: &mut Bencher) { | |
module | |
.fold_with(&mut resolver(unresolved_mark, top_level_mark, true)) | |
.fold_with(&mut typescript::strip(top_level_mark)) | |
- .fold_with(&mut es2020(Default::default())) | |
+ .fold_with(&mut es2020(Default::default(), unresolved_mark)) | |
}); | |
b.iter(|| { | |
diff --git a/crates/swc_estree_compat/src/babelify/module_decl.rs b/crates/swc_estree_compat/src/babelify/module_decl.rs | |
index 4d49dc8c37..91fea257b3 100644 | |
--- a/crates/swc_estree_compat/src/babelify/module_decl.rs | |
+++ b/crates/swc_estree_compat/src/babelify/module_decl.rs | |
@@ -90,13 +90,13 @@ impl Babelify for ExportDecl { | |
declaration: Some(Box::alloc().init(self.decl.babelify(ctx))), | |
specifiers: Default::default(), | |
source: Default::default(), | |
- assertions: Default::default(), | |
+ with: Default::default(), | |
export_kind: Default::default(), | |
} | |
} | |
} | |
-fn convert_import_asserts( | |
+fn convert_import_attrs( | |
asserts: Option<Box<ObjectLit>>, | |
ctx: &Context, | |
) -> Option<Vec<ImportAttribute>> { | |
@@ -161,7 +161,7 @@ impl Babelify for ImportDecl { | |
base: ctx.base(self.span), | |
specifiers: self.specifiers.babelify(ctx), | |
source: self.src.babelify(ctx), | |
- assertions: convert_import_asserts(self.asserts, ctx), | |
+ with: convert_import_attrs(self.with, ctx), | |
import_kind: if self.type_only { | |
Some(ImportKind::Type) | |
} else { | |
@@ -178,7 +178,7 @@ impl Babelify for ExportAll { | |
ExportAllDeclaration { | |
base: ctx.base(self.span), | |
source: self.src.babelify(ctx), | |
- assertions: convert_import_asserts(self.asserts, ctx), | |
+ with: convert_import_attrs(self.with, ctx), | |
export_kind: if self.type_only { | |
Some(ExportKind::Type) | |
} else { | |
@@ -197,7 +197,7 @@ impl Babelify for NamedExport { | |
declaration: Default::default(), | |
specifiers: self.specifiers.babelify(ctx), | |
source: self.src.map(|s| s.babelify(ctx)), | |
- assertions: convert_import_asserts(self.asserts, ctx), | |
+ with: convert_import_attrs(self.with, ctx), | |
export_kind: if self.type_only { | |
Some(ExportKind::Type) | |
} else { | |
diff --git a/crates/swc_estree_compat/src/swcify/stmt.rs b/crates/swc_estree_compat/src/swcify/stmt.rs | |
index 80bae36d8e..4b806296ec 100644 | |
--- a/crates/swc_estree_compat/src/swcify/stmt.rs | |
+++ b/crates/swc_estree_compat/src/swcify/stmt.rs | |
@@ -436,8 +436,8 @@ impl Swcify for ExportAllDeclaration { | |
span: ctx.span(&self.base), | |
src: self.source.swcify(ctx).into(), | |
type_only: self.export_kind == Some(ExportKind::Type), | |
- asserts: self | |
- .assertions | |
+ with: self | |
+ .with | |
.swcify(ctx) | |
.map(|props| { | |
props | |
@@ -528,8 +528,8 @@ impl Swcify for ExportNamedDeclaration { | |
specifiers: self.specifiers.swcify(ctx), | |
src: self.source.swcify(ctx).map(Box::new), | |
type_only: false, | |
- asserts: self | |
- .assertions | |
+ with: self | |
+ .with | |
.swcify(ctx) | |
.map(|props| { | |
props | |
@@ -625,8 +625,8 @@ impl Swcify for ImportDeclaration { | |
specifiers: self.specifiers.swcify(ctx), | |
src: self.source.swcify(ctx).into(), | |
type_only: false, | |
- asserts: self | |
- .assertions | |
+ with: self | |
+ .with | |
.swcify(ctx) | |
.map(|props| { | |
props | |
@@ -779,7 +779,7 @@ impl Swcify for DeclareExportAllDeclaration { | |
span: ctx.span(&self.base), | |
src: self.source.swcify(ctx).into(), | |
type_only: self.export_kind == Some(ExportKind::Type), | |
- asserts: Default::default(), | |
+ with: Default::default(), | |
} | |
} | |
} | |
diff --git a/crates/swc_html_minifier/src/lib.rs b/crates/swc_html_minifier/src/lib.rs | |
index bca0f876bf..4a83a7d9aa 100644 | |
--- a/crates/swc_html_minifier/src/lib.rs | |
+++ b/crates/swc_html_minifier/src/lib.rs | |
@@ -2114,12 +2114,7 @@ impl Minifier<'_> { | |
)) as Box<dyn swc_ecma_codegen::text_writer::WriteJs>; | |
let mut emitter = swc_ecma_codegen::Emitter { | |
- cfg: swc_ecma_codegen::Config { | |
- target, | |
- minify: false, | |
- ascii_only: false, | |
- omit_last_semi: false, | |
- }, | |
+ cfg: swc_ecma_codegen::Config::default().with_target(target), | |
cm, | |
comments: Some(&comments), | |
wr, | |
diff --git a/crates/swc_html_parser/src/lexer/mod.rs b/crates/swc_html_parser/src/lexer/mod.rs | |
index eb03d36877..f63a2eec62 100644 | |
--- a/crates/swc_html_parser/src/lexer/mod.rs | |
+++ b/crates/swc_html_parser/src/lexer/mod.rs | |
@@ -152,7 +152,10 @@ where | |
// A leading Byte Order Mark (BOM) causes the character encoding argument to be | |
// ignored and will itself be skipped. | |
if lexer.input.is_at_start() && lexer.input.cur() == Some('\u{feff}') { | |
- lexer.input.bump(); | |
+ unsafe { | |
+ // Safety: We know that the current character is '\u{feff}'. | |
+ lexer.input.bump(); | |
+ } | |
} | |
lexer | |
@@ -240,13 +243,19 @@ where | |
self.cur_pos = self.input.cur_pos(); | |
if self.cur.is_some() { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: self.cur is Some() | |
+ self.input.bump(); | |
+ } | |
} | |
} | |
#[inline(always)] | |
fn reconsume(&mut self) { | |
- self.input.reset_to(self.cur_pos); | |
+ unsafe { | |
+ // Safety: self.cur_pos is valid position because we got it from self.input | |
+ self.input.reset_to(self.cur_pos); | |
+ } | |
} | |
#[inline(always)] | |
@@ -401,7 +410,10 @@ where | |
sub_buf.push(c); | |
if self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
sub_buf.push('\n'); | |
} | |
@@ -466,7 +478,10 @@ where | |
sub_buf.push(c); | |
if self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
sub_buf.push('\n'); | |
} | |
@@ -497,7 +512,10 @@ where | |
sub_buf.push(c); | |
if self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
sub_buf.push('\n'); | |
} | |
@@ -795,7 +813,10 @@ where | |
sub_buf.push('\r'); | |
if self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
sub_buf.push('\n'); | |
} | |
@@ -826,7 +847,10 @@ where | |
sub_buf.push(c); | |
if self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
sub_buf.push('\n'); | |
} | |
@@ -955,7 +979,10 @@ where | |
sub_buf.push(c); | |
if self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
sub_buf.push('\n'); | |
} | |
@@ -1022,8 +1049,10 @@ where | |
buf.push(c); | |
if self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
- | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
buf.push('\n'); | |
} | |
@@ -2861,7 +2890,10 @@ where | |
lexer.state = State::BogusComment; | |
lexer.cur_pos = cur_pos; | |
// We don't validate input here because we reset position | |
- lexer.input.reset_to(cur_pos); | |
+ unsafe { | |
+ // Safety: We reset position to the previous one | |
+ lexer.input.reset_to(cur_pos); | |
+ } | |
}; | |
// If the next few characters are: | |
@@ -3536,7 +3568,11 @@ where | |
_ => { | |
buf.clear(); | |
self.cur_pos = cur_pos; | |
- self.input.reset_to(cur_pos); | |
+ unsafe { | |
+ // Safety: We got cur_pos from self.input.cur_pos() above, so | |
+ // it's a valid position. | |
+ self.input.reset_to(cur_pos); | |
+ } | |
self.emit_error( | |
ErrorKind::InvalidCharacterSequenceAfterDoctypeName, | |
); | |
@@ -4393,10 +4429,16 @@ where | |
if entity.is_some() { | |
self.cur_pos = entity_cur_pos.unwrap(); | |
- self.input.reset_to(entity_cur_pos.unwrap()); | |
+ unsafe { | |
+ // Safety: We got entity_cur_pos from the input, so it's valid | |
+ self.input.reset_to(entity_cur_pos.unwrap()); | |
+ } | |
} else { | |
self.cur_pos = initial_cur_pos; | |
- self.input.reset_to(initial_cur_pos); | |
+ unsafe { | |
+ // Safety: We got initial_cur_pos from the input, so it's valid | |
+ self.input.reset_to(initial_cur_pos); | |
+ } | |
} | |
let is_last_semicolon = self.temporary_buffer.ends_with(';'); | |
@@ -4814,7 +4856,10 @@ where | |
#[inline(always)] | |
fn skip_whitespaces(&mut self, c: char) { | |
if c == '\r' && self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some | |
+ self.input.bump(); | |
+ } | |
} | |
} | |
} | |
diff --git a/crates/swc_node_bundler/tests/fixture.rs b/crates/swc_node_bundler/tests/fixture.rs | |
index 9ecac943b3..237f37a622 100644 | |
--- a/crates/swc_node_bundler/tests/fixture.rs | |
+++ b/crates/swc_node_bundler/tests/fixture.rs | |
@@ -91,15 +91,13 @@ fn pass(input_dir: PathBuf) { | |
None, | |
None, | |
false, | |
- EsVersion::Es2020, | |
SourceMapsConfig::Bool(false), | |
&Default::default(), | |
None, | |
- false, | |
Some(&comments), | |
false, | |
- false, | |
Default::default(), | |
+ swc_ecma_codegen::Config::default().with_target(EsVersion::Es2020), | |
) | |
.expect("failed to print?") | |
.code; | |
diff --git a/crates/swc_plugin_runner/src/wasix_runtime.rs b/crates/swc_plugin_runner/src/wasix_runtime.rs | |
index 09e8d0b54e..1fa2fb936a 100644 | |
--- a/crates/swc_plugin_runner/src/wasix_runtime.rs | |
+++ b/crates/swc_plugin_runner/src/wasix_runtime.rs | |
@@ -1,3 +1,5 @@ | |
+#![allow(unused)] | |
+ | |
use std::{path::PathBuf, sync::Arc}; | |
use parking_lot::Mutex; | |
diff --git a/crates/swc_xml_parser/src/lexer/mod.rs b/crates/swc_xml_parser/src/lexer/mod.rs | |
index 1b259f65ad..85eb3e0659 100644 | |
--- a/crates/swc_xml_parser/src/lexer/mod.rs | |
+++ b/crates/swc_xml_parser/src/lexer/mod.rs | |
@@ -171,7 +171,10 @@ where | |
// A leading Byte Order Mark (BOM) causes the character encoding argument to be | |
// ignored and will itself be skipped. | |
if lexer.input.is_at_start() && lexer.input.cur() == Some('\u{feff}') { | |
- lexer.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\u{feff}') | |
+ lexer.input.bump(); | |
+ } | |
} | |
lexer | |
@@ -247,13 +250,19 @@ where | |
self.cur_pos = self.input.cur_pos(); | |
if self.cur.is_some() { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some(c) | |
+ self.input.bump(); | |
+ } | |
} | |
} | |
#[inline(always)] | |
fn reconsume(&mut self) { | |
- self.input.reset_to(self.cur_pos); | |
+ unsafe { | |
+ // Safety: We got cur_pos from self.input | |
+ self.input.reset_to(self.cur_pos); | |
+ } | |
} | |
#[inline(always)] | |
@@ -299,7 +308,10 @@ where | |
let anything_else = |lexer: &mut Lexer<I>| { | |
lexer.emit_error(ErrorKind::InvalidEntityCharacter); | |
lexer.cur_pos = cur_pos; | |
- lexer.input.reset_to(cur_pos); | |
+ unsafe { | |
+ // Safety: We got cur_post from self.input | |
+ lexer.input.reset_to(cur_pos); | |
+ } | |
}; | |
// This section defines how to consume a character reference, optionally with an | |
@@ -318,7 +330,10 @@ where | |
Some(c) if self.additional_allowed_character == Some(c) => { | |
self.emit_error(ErrorKind::InvalidEntityCharacter); | |
self.cur_pos = cur_pos; | |
- self.input.reset_to(cur_pos); | |
+ unsafe { | |
+ // Safety: We got cur_post from self.input | |
+ self.input.reset_to(cur_pos); | |
+ } | |
} | |
Some('l') => match self.consume_next_char() { | |
Some('t') => { | |
@@ -467,7 +482,10 @@ where | |
if characters.is_empty() { | |
// TODO | |
self.cur_pos = cur_pos; | |
- self.input.reset_to(cur_pos); | |
+ unsafe { | |
+ // Safety: We got cur_post from self.input | |
+ self.input.reset_to(cur_pos); | |
+ } | |
return None; | |
} | |
@@ -553,7 +571,10 @@ where | |
raw.push(c); | |
if self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
raw.push('\n'); | |
} | |
@@ -873,7 +894,10 @@ where | |
raw_c.push(c); | |
if self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
raw_c.push('\n'); | |
} | |
@@ -937,7 +961,10 @@ where | |
raw.push(c); | |
if self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
raw.push('\n'); | |
} | |
@@ -1236,7 +1263,10 @@ where | |
lexer.state = State::BogusComment; | |
lexer.cur_pos = cur_pos; | |
// We don't validate input here because we reset position | |
- lexer.input.reset_to(cur_pos); | |
+ unsafe { | |
+ // Safety: cur_pos is in the range of input | |
+ lexer.input.reset_to(cur_pos); | |
+ } | |
}; | |
// If the next few characters are: | |
@@ -2464,7 +2494,10 @@ where | |
} | |
_ => { | |
self.cur_pos = cur_pos; | |
- self.input.reset_to(cur_pos); | |
+ unsafe { | |
+ // Safety: We got cur_pos from self.input.cur_pos() | |
+ self.input.reset_to(cur_pos); | |
+ } | |
self.emit_error( | |
ErrorKind::InvalidCharacterSequenceAfterDoctypeName, | |
); | |
@@ -3074,7 +3107,10 @@ where | |
#[inline(always)] | |
fn skip_next_lf(&mut self, c: char) { | |
if c == '\r' && self.input.cur() == Some('\n') { | |
- self.input.bump(); | |
+ unsafe { | |
+ // Safety: cur() is Some('\n') | |
+ self.input.bump(); | |
+ } | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment