mirror of
https://github.com/swc-project/swc.git
synced 2024-12-26 07:02:28 +03:00
7100 lines
277 KiB
Plaintext
7100 lines
277 KiB
Plaintext
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();
|
|
+ }
|
|
}
|
|
}
|
|
}
|