Skip to content

Commit

Permalink
fix(transformer): TS namespace transform do not track var decl names (#…
Browse files Browse the repository at this point in the history
…3501)

Don't track variable declaration or import binding names in TS namespace transform.

Babel does, but it appears to be wrong. It's illegal to have a `var`/`let`/`const` declaration or import in same scope as a TS namespace declaration with same binding.

https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAQTgMyhEcDkUCmBDAYxkwG4AoAOzxBwGcxCdE4BvAXzLIIgtvgCE4AXjgBGclRr1GcQSzJxFcADY54AD3Icyq+AGFhYidToMCTA-KUq1cTWW0A3PFDgARQ+Monp596wUlXTstMiA
  • Loading branch information
overlookmotel committed Jun 3, 2024
1 parent 8d2beff commit 837776e
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 56 deletions.
91 changes: 37 additions & 54 deletions crates/oxc_transformer/src/typescript/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl<'a> TypeScript<'a> {
return;
}

// Collect all binding names. Such as function name and class name.
// Collect function/class/enum/namespace binding names
let mut names: FxHashSet<Atom<'a>> = FxHashSet::default();

// Recreate the statements vec for memory efficiency.
Expand Down Expand Up @@ -59,12 +59,11 @@ impl<'a> TypeScript<'a> {
}
}
new_stmts.push(Statement::TSModuleDeclaration(decl));
continue;
}
match_module_declaration!(Statement) => {
if let Statement::ExportNamedDeclaration(export_decl) = &stmt {
if let Some(Declaration::TSModuleDeclaration(decl)) =
&export_decl.declaration
{
Statement::ExportNamedDeclaration(ref export_decl) => {
match &export_decl.declaration {
Some(Declaration::TSModuleDeclaration(decl)) => {
if !decl.modifiers.is_contains_declare() {
if !self.options.allow_namespaces {
self.ctx.error(namespace_not_supported(decl.span));
Expand All @@ -91,37 +90,32 @@ impl<'a> TypeScript<'a> {
continue;
}
}

if let TSModuleDeclarationName::Identifier(id) = &decl.id {
names.insert(id.name.clone());
}
}
Some(decl) => match decl {
Declaration::FunctionDeclaration(_)
| Declaration::ClassDeclaration(_)
| Declaration::TSEnumDeclaration(_) => {
names.insert(decl.id().as_ref().unwrap().name.clone());
}
_ => {}
},
_ => {}
}

stmt.to_module_declaration().bound_names(&mut |id| {
names.insert(id.name.clone());
});
new_stmts.push(stmt);
}
// Collect bindings from class, function, variable and enum declarations
Statement::FunctionDeclaration(ref decl) => {
names.insert(decl.id.as_ref().unwrap().name.clone());
new_stmts.push(stmt);
}
Statement::ClassDeclaration(ref decl) => {
names.insert(decl.id.as_ref().unwrap().name.clone());
new_stmts.push(stmt);
}
Statement::TSEnumDeclaration(ref decl) => {
names.insert(decl.id.name.clone());
new_stmts.push(stmt);
}
Statement::VariableDeclaration(ref decl) => {
decl.bound_names(&mut |id| {
names.insert(id.name.clone());
});
new_stmts.push(stmt);
}
_ => {
new_stmts.push(stmt);
// Collect bindings from class, function and enum declarations
Statement::FunctionDeclaration(_)
| Statement::ClassDeclaration(_)
| Statement::TSEnumDeclaration(_) => {
names.insert(stmt.to_declaration().id().as_ref().unwrap().name.clone());
}
_ => {}
}

new_stmts.push(stmt);
}

program.body = new_stmts;
Expand Down Expand Up @@ -185,24 +179,7 @@ impl<'a> TypeScript<'a> {
}
new_stmts.push(transformed);
}
}
Statement::ClassDeclaration(ref decl) => {
names.insert(decl.id.as_ref().unwrap().name.clone());
new_stmts.push(stmt);
}
Statement::FunctionDeclaration(ref decl) => {
names.insert(decl.id.as_ref().unwrap().name.clone());
new_stmts.push(stmt);
}
Statement::TSEnumDeclaration(ref enum_decl) => {
names.insert(enum_decl.id.name.clone());
new_stmts.push(stmt);
}
Statement::VariableDeclaration(ref decl) => {
decl.bound_names(&mut |id| {
names.insert(id.name.clone());
});
new_stmts.push(stmt);
continue;
}
Statement::ExportNamedDeclaration(export_decl) => {
// NB: `ExportNamedDeclaration` with no declaration (e.g. `export {x}`) is not
Expand Down Expand Up @@ -252,14 +229,20 @@ impl<'a> TypeScript<'a> {
_ => {}
}
}
continue;
}
// Collect bindings from class, function and enum declarations
Statement::ClassDeclaration(_)
| Statement::FunctionDeclaration(_)
| Statement::TSEnumDeclaration(_) => {
names.insert(stmt.to_declaration().id().as_ref().unwrap().name.clone());
}
Statement::TSTypeAliasDeclaration(_)
| Statement::TSInterfaceDeclaration(_)
| Statement::TSImportEqualsDeclaration(_) => {}
_ => {
new_stmts.push(stmt);
}
| Statement::TSImportEqualsDeclaration(_) => continue,
_ => {}
}
new_stmts.push(stmt);
}

if new_stmts.is_empty() {
Expand Down
4 changes: 2 additions & 2 deletions tasks/transform_conformance/babel.snap.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
commit: 4bd1b2c2

Passed: 480/928
Passed: 478/926

# All Passed:
* babel-preset-react
Expand Down Expand Up @@ -445,7 +445,7 @@ Passed: 480/928
* opts/optimizeConstEnums/input.ts
* opts/rewriteImportExtensions/input.ts

# babel-plugin-transform-typescript (136/152)
# babel-plugin-transform-typescript (134/150)
* enum/mix-references/input.ts
* enum/ts5.0-const-foldable/input.ts
* exports/declared-types/input.ts
Expand Down
2 changes: 2 additions & 0 deletions tasks/transform_conformance/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,7 @@ pub(crate) const SKIP_TESTS: &[&str] = &[
"typescript/test/fixtures/namespace/nested-shorthand-export/input.ts",
"react-jsx-development/test/fixtures/cross-platform/self-inside-arrow/input.mjs",
// Babel outputs is not correct
"typescript/test/fixtures/namespace/clobber-import/input.ts",
"typescript/test/fixtures/namespace/namespace-nested-module/input.ts",
"typescript/test/fixtures/namespace/nested-destructuring/input.ts",
];

0 comments on commit 837776e

Please sign in to comment.