diff --git a/crates/swc/tests/fixture/issues-8xxx/8594/input/.swcrc b/crates/swc/tests/fixture/issues-8xxx/8594/input/.swcrc new file mode 100644 index 000000000000..63a04f741e14 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8594/input/.swcrc @@ -0,0 +1,19 @@ +{ + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": true + }, + "target": "es2015", + "loose": false, + "minify": { + "compress": false, + "mangle": false + } + }, + "module": { + "type": "es6" + }, + "minify": false, + "isModule": true +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-8xxx/8594/input/index.tsx b/crates/swc/tests/fixture/issues-8xxx/8594/input/index.tsx new file mode 100644 index 000000000000..29299e8f061b --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8594/input/index.tsx @@ -0,0 +1,6 @@ +import * as React from 'react'; + +export namespace FooNs { + export const Shared = () => 'I\'m shared component'; + export const Main = () => ; +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-8xxx/8594/output/index.tsx b/crates/swc/tests/fixture/issues-8xxx/8594/output/index.tsx new file mode 100644 index 000000000000..1f804f6d5982 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8594/output/index.tsx @@ -0,0 +1,6 @@ +import * as React from 'react'; +export var FooNs; +(function(FooNs) { + FooNs.Shared = ()=>'I\'m shared component'; + FooNs.Main = ()=>React.createElement(FooNs.Shared, null); +})(FooNs || (FooNs = {})); diff --git a/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs b/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs index 0e3c659d589e..f4c01babe675 100644 --- a/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs +++ b/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs @@ -71,6 +71,11 @@ impl QueryRef for ImportQuery { None } + fn query_jsx(&self, _: &Ident) -> Option { + // We do not need to handle JSX since there is no jsx preserve option in swc + None + } + fn should_fix_this(&self, ident: &Ident) -> bool { if self.helper_ctxt.iter().any(|ctxt| ctxt == &ident.span.ctxt) { return false; diff --git a/crates/swc_ecma_transforms_typescript/src/transform.rs b/crates/swc_ecma_transforms_typescript/src/transform.rs index c6b4e643e6cf..7381191b1f63 100644 --- a/crates/swc_ecma_transforms_typescript/src/transform.rs +++ b/crates/swc_ecma_transforms_typescript/src/transform.rs @@ -1231,6 +1231,16 @@ impl QueryRef for ExportQuery { self.query_ref(ident) } + fn query_jsx(&self, ident: &Ident) -> Option { + self.export_id_list.contains(&ident.to_id()).then(|| { + JSXMemberExpr { + obj: JSXObject::Ident(self.namesapce_id.clone().into()), + prop: ident.clone(), + } + .into() + }) + } + fn should_fix_this(&self, _: &Ident) -> bool { // tsc does not care about `this` in namespace. false diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs index 287268f6bdea..4f2cace4c418 100644 --- a/crates/swc_ecma_utils/src/lib.rs +++ b/crates/swc_ecma_utils/src/lib.rs @@ -3021,11 +3021,21 @@ impl VisitMut for IdentRenamer<'_> { } pub trait QueryRef { - fn query_ref(&self, ident: &Ident) -> Option; - fn query_lhs(&self, ident: &Ident) -> Option; + fn query_ref(&self, _ident: &Ident) -> Option { + None + } + fn query_lhs(&self, _ident: &Ident) -> Option { + None + } + /// ref used in JSX + fn query_jsx(&self, _ident: &Ident) -> Option { + None + } /// when `foo()` is replaced with `bar.baz()`, /// should `bar.baz` be indirect call? - fn should_fix_this(&self, ident: &Ident) -> bool; + fn should_fix_this(&self, _ident: &Ident) -> bool { + false + } } /// Replace `foo` with `bar` or `bar.baz` @@ -3129,6 +3139,16 @@ where *n = n.take().into_indirect() } } + + fn visit_mut_jsx_element_name(&mut self, n: &mut JSXElementName) { + n.visit_mut_children_with(self); + + if let JSXElementName::Ident(ident) = n { + if let Some(expr) = self.query.query_jsx(ident) { + *n = expr; + } + } + } } #[cfg(test)]