diff --git a/crates/swc/src/config/mod.rs b/crates/swc/src/config/mod.rs index 00e68913c169..93194b8bd4b0 100644 --- a/crates/swc/src/config/mod.rs +++ b/crates/swc/src/config/mod.rs @@ -365,7 +365,9 @@ impl Options { }), syntax.decorators() ), - import_assertions(), + // The transform strips import assertions, so it's only enabled if + // keep_import_assertions is false. + Optional::new(import_assertions(), !experimental.keep_import_assertions), // Do a resolver pass after decorators as it might // emit runtime declarations and do it before // type stripping as we need to know scope information @@ -932,6 +934,9 @@ pub struct JscExperimental { /// This requires cargo feature `plugin`. #[serde(default)] pub plugins: Option>, + /// If true, keeps import assertions in the output. + #[serde(default)] + pub keep_import_assertions: bool, } impl Merge for JscExperimental { diff --git a/crates/swc_ecma_codegen/src/lib.rs b/crates/swc_ecma_codegen/src/lib.rs index d225524299a4..1819c44e0394 100644 --- a/crates/swc_ecma_codegen/src/lib.rs +++ b/crates/swc_ecma_codegen/src/lib.rs @@ -275,6 +275,14 @@ where } emit!(n.src); + + if let Some(asserts) = &n.asserts { + formatting_space!(); + keyword!("assert"); + formatting_space!(); + emit!(asserts); + } + formatting_semi!(); } @@ -402,6 +410,13 @@ where keyword!("from"); formatting_space!(); emit!(src); + + if let Some(asserts) = &node.asserts { + formatting_space!(); + keyword!("assert"); + formatting_space!(); + emit!(asserts); + } } formatting_semi!(); } @@ -417,6 +432,14 @@ where keyword!("from"); formatting_space!(); emit!(node.src); + + if let Some(asserts) = &node.asserts { + formatting_space!(); + keyword!("assert"); + formatting_space!(); + emit!(asserts); + } + formatting_semi!(); } diff --git a/crates/swc_ecma_codegen/tests/fixture/issues/3110/input.js b/crates/swc_ecma_codegen/tests/fixture/issues/3110/input.js new file mode 100644 index 000000000000..bcf5550b85df --- /dev/null +++ b/crates/swc_ecma_codegen/tests/fixture/issues/3110/input.js @@ -0,0 +1,5 @@ +import data from "./data.json" assert { type: "json" }; +export { default as data2 } from "./data2.json" assert { type: "json" }; +export * as data3 from "./data3.json" assert { type: "json" }; + +console.log(data); diff --git a/crates/swc_ecma_codegen/tests/fixture/issues/3110/output.js b/crates/swc_ecma_codegen/tests/fixture/issues/3110/output.js new file mode 100644 index 000000000000..626916ffe099 --- /dev/null +++ b/crates/swc_ecma_codegen/tests/fixture/issues/3110/output.js @@ -0,0 +1,10 @@ +import data from "./data.json" assert { + type: "json" +}; +export { default as data2 } from "./data2.json" assert { + type: "json" +}; +export * as data3 from "./data3.json" assert { + type: "json" +}; +console.log(data); diff --git a/crates/swc_ecma_codegen/tests/fixture/issues/3110/output.min.js b/crates/swc_ecma_codegen/tests/fixture/issues/3110/output.min.js new file mode 100644 index 000000000000..d66307562435 --- /dev/null +++ b/crates/swc_ecma_codegen/tests/fixture/issues/3110/output.min.js @@ -0,0 +1 @@ +import data from"./data.json"assert{type:"json"};export{default as data2}from"./data2.json"assert{type:"json"};export*as data3 from"./data3.json"assert{type:"json"};console.log(data) diff --git a/crates/swc_ecma_transforms_proposal/src/import_assertions.rs b/crates/swc_ecma_transforms_proposal/src/import_assertions.rs index b25eb2653111..78aecc05757f 100644 --- a/crates/swc_ecma_transforms_proposal/src/import_assertions.rs +++ b/crates/swc_ecma_transforms_proposal/src/import_assertions.rs @@ -1,4 +1,4 @@ -use swc_ecma_ast::ImportDecl; +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 { @@ -12,4 +12,12 @@ impl VisitMut for ImportAssertions { fn visit_mut_import_decl(&mut self, n: &mut ImportDecl) { n.asserts = None; } + + fn visit_mut_export_all(&mut self, n: &mut ExportAll) { + n.asserts = None; + } + + fn visit_mut_named_export(&mut self, n: &mut NamedExport) { + n.asserts = None; + } } diff --git a/crates/swc_ecma_transforms_proposal/tests/import_assertions.rs b/crates/swc_ecma_transforms_proposal/tests/import_assertions.rs new file mode 100644 index 000000000000..2756c4455a9b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/import_assertions.rs @@ -0,0 +1,39 @@ +use swc_ecma_parser::{EsConfig, Syntax}; +use swc_ecma_transforms_proposal::import_assertions; +use swc_ecma_transforms_testing::test; +use swc_ecma_visit::Fold; + +fn tr() -> impl Fold { + import_assertions() +} + +fn syntax() -> Syntax { + Syntax::Es(EsConfig { + import_assertions: true, + ..Default::default() + }) +} + +test!( + syntax(), + |_| tr(), + import_with_assertions, + r#"import test from "./test.json" assert {type: "json"};"#, + r#"import test from "./test.json";"# +); + +test!( + syntax(), + |_| tr(), + named_export_with_assertions, + r#"export {default as test} from "./test.json" assert {type: "json"};"#, + r#"export {default as test} from "./test.json";"# +); + +test!( + syntax(), + |_| tr(), + export_all_with_assertions, + r#"export * from "./test.json" assert {type: "json"};"#, + r#"export * from "./test.json";"# +); diff --git a/crates/swc_ecma_transforms_typescript/tests/strip_correctness.rs b/crates/swc_ecma_transforms_typescript/tests/strip_correctness.rs index d563bd765d3a..88e13a6280f4 100644 --- a/crates/swc_ecma_transforms_typescript/tests/strip_correctness.rs +++ b/crates/swc_ecma_transforms_typescript/tests/strip_correctness.rs @@ -156,6 +156,7 @@ fn identity(entry: PathBuf) { decorators_before_export: true, export_default_from: true, private_in_object: true, + import_assertions: true, ..Default::default() }), (&*js_fm).into(), diff --git a/node-swc/src/types.ts b/node-swc/src/types.ts index 075d71297a13..b645cebdc815 100644 --- a/node-swc/src/types.ts +++ b/node-swc/src/types.ts @@ -490,8 +490,9 @@ export interface JscConfig { */ keepClassNames?: boolean - experimetal?: { - optimizeHygiene?: boolean + experimental?: { + optimizeHygiene?: boolean, + keepImportAssertions?: boolean }, baseUrl?: string