Skip to content

Commit

Permalink
feat(es/lints): Detect duplicate bindings in export defaults (#8760)
Browse files Browse the repository at this point in the history
**Description:**
add DefaultDecl's FnExpr and ClassExpr's ident to bindings. 
because all of them should be treated as hoisted Fn/Class Declare

```txt
  × the name `x` is defined multiple times
   ╭─[examples/all.js:1:1]
 1 │ export default class x{}
   ·                      ┬
   ·                      ╰── previous definition of `x` here
 2 │
 3 │ let x = 1;
   ·     ┬
   ·     ╰── `x` redefined here
 4 │ let t = function x(){};
   ╰────
```



**Related issue:**

 - Closes #8755
  • Loading branch information
stormslowly committed Mar 19, 2024
1 parent 2067677 commit c9c971a
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 0 deletions.
@@ -0,0 +1,2 @@
export default class Foo{}
let Foo = 1; // error
@@ -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
`----
@@ -0,0 +1,2 @@
export default function foo(){}
let foo = 1; // error
@@ -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
`----
@@ -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 |
Expand Down
@@ -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 |
Expand Down
31 changes: 31 additions & 0 deletions crates/swc_ecma_lints/src/rules/duplicate_bindings.rs
Expand Up @@ -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);

Expand Down
@@ -0,0 +1,2 @@
export default class Foo{};
let bar = function Foo(){};
@@ -0,0 +1,2 @@
export default function foo(){};
let bar = function foo(){};
@@ -0,0 +1,2 @@
export default function foo();
let foo = 1;

0 comments on commit c9c971a

Please sign in to comment.