diff --git a/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-class-expr/input.js b/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-class-expr/input.js new file mode 100644 index 000000000000..ccdfd1922466 --- /dev/null +++ b/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-class-expr/input.js @@ -0,0 +1,2 @@ +export default class Foo{} +let Foo = 1; // error diff --git a/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-class-expr/output.swc-stderr b/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-class-expr/output.swc-stderr new file mode 100644 index 000000000000..41cf007ebfb0 --- /dev/null +++ b/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-class-expr/output.swc-stderr @@ -0,0 +1,10 @@ + + x the name `Foo` is defined multiple times + ,-[1:1] + 1 | export default class Foo{} + : ^|^ + : `-- previous definition of `Foo` here + 2 | let Foo = 1; // error + : ^|^ + : `-- `Foo` redefined here + `---- diff --git a/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-fn-expr/input.js b/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-fn-expr/input.js new file mode 100644 index 000000000000..bcf118c3d3cc --- /dev/null +++ b/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-fn-expr/input.js @@ -0,0 +1,2 @@ +export default function foo(){} +let foo = 1; // error \ No newline at end of file diff --git a/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-fn-expr/output.swc-stderr b/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-fn-expr/output.swc-stderr new file mode 100644 index 000000000000..163efffaa472 --- /dev/null +++ b/crates/swc/tests/errors/lints/duplicate-bindings/module/export-default-fn-expr/output.swc-stderr @@ -0,0 +1,10 @@ + + x the name `foo` is defined multiple times + ,-[1:1] + 1 | export default function foo(){} + : ^|^ + : `-- previous definition of `foo` here + 2 | let foo = 1; // error + : ^|^ + : `-- `foo` redefined here + `---- diff --git a/crates/swc/tests/tsc-references/multipleDefaultExports03.1.normal.js b/crates/swc/tests/tsc-references/multipleDefaultExports03.1.normal.js index 395b14189709..2507ae4bb976 100644 --- a/crates/swc/tests/tsc-references/multipleDefaultExports03.1.normal.js +++ b/crates/swc/tests/tsc-references/multipleDefaultExports03.1.normal.js @@ -1,5 +1,19 @@ //// [multipleDefaultExports03.ts] //! +//! x the name `C` is defined multiple times +//! ,-[1:1] +//! 1 | +//! 2 | export default class C { +//! : | +//! : `-- previous definition of `C` here +//! 3 | } +//! 4 | +//! 5 | export default class C { +//! : | +//! : `-- `C` redefined here +//! 6 | } +//! `---- +//! //! x the name `default` is exported multiple times //! ,-[1:1] //! 1 | diff --git a/crates/swc/tests/tsc-references/multipleDefaultExports03.2.minified.js b/crates/swc/tests/tsc-references/multipleDefaultExports03.2.minified.js index 395b14189709..2507ae4bb976 100644 --- a/crates/swc/tests/tsc-references/multipleDefaultExports03.2.minified.js +++ b/crates/swc/tests/tsc-references/multipleDefaultExports03.2.minified.js @@ -1,5 +1,19 @@ //// [multipleDefaultExports03.ts] //! +//! x the name `C` is defined multiple times +//! ,-[1:1] +//! 1 | +//! 2 | export default class C { +//! : | +//! : `-- previous definition of `C` here +//! 3 | } +//! 4 | +//! 5 | export default class C { +//! : | +//! : `-- `C` redefined here +//! 6 | } +//! `---- +//! //! x the name `default` is exported multiple times //! ,-[1:1] //! 1 | diff --git a/crates/swc_ecma_lints/src/rules/duplicate_bindings.rs b/crates/swc_ecma_lints/src/rules/duplicate_bindings.rs index c96cad81031d..1f196773bef8 100644 --- a/crates/swc_ecma_lints/src/rules/duplicate_bindings.rs +++ b/crates/swc_ecma_lints/src/rules/duplicate_bindings.rs @@ -239,6 +239,37 @@ impl Visit for DuplicateBindings { s.visit_children_with(self); } + fn visit_export_default_decl(&mut self, e: &ExportDefaultDecl) { + // export default function foo() {} should be treated as hoisted + match &e.decl { + DefaultDecl::Class(ClassExpr { + ident: Some(ident), .. + }) => self.add( + ident.sym.clone(), + BindingInfo { + span: ident.span, + unique: true, + is_function: false, + }, + ), + DefaultDecl::Fn(FnExpr { + ident: Some(ident), + function: f, + .. + }) if f.body.is_some() => self.add( + ident.sym.clone(), + BindingInfo { + span: ident.span, + unique: self.lexical_function, + is_function: true, + }, + ), + _ => {} + } + + e.visit_children_with(self); + } + fn visit_import_default_specifier(&mut self, s: &ImportDefaultSpecifier) { s.visit_children_with(self); diff --git a/crates/swc_ecma_lints/tests/pass/export/export_default_class_expr/1/input.js b/crates/swc_ecma_lints/tests/pass/export/export_default_class_expr/1/input.js new file mode 100644 index 000000000000..99caf09c769f --- /dev/null +++ b/crates/swc_ecma_lints/tests/pass/export/export_default_class_expr/1/input.js @@ -0,0 +1,2 @@ +export default class Foo{}; +let bar = function Foo(){}; \ No newline at end of file diff --git a/crates/swc_ecma_lints/tests/pass/export/export_default_fn_expr/1/input.js b/crates/swc_ecma_lints/tests/pass/export/export_default_fn_expr/1/input.js new file mode 100644 index 000000000000..8023e014448b --- /dev/null +++ b/crates/swc_ecma_lints/tests/pass/export/export_default_fn_expr/1/input.js @@ -0,0 +1,2 @@ +export default function foo(){}; +let bar = function foo(){}; \ No newline at end of file diff --git a/crates/swc_ecma_lints/tests/pass/export/export_default_fn_expr/2/input.ts b/crates/swc_ecma_lints/tests/pass/export/export_default_fn_expr/2/input.ts new file mode 100644 index 000000000000..7b86de46a398 --- /dev/null +++ b/crates/swc_ecma_lints/tests/pass/export/export_default_fn_expr/2/input.ts @@ -0,0 +1,2 @@ +export default function foo(); +let foo = 1; \ No newline at end of file