fix(transformer): TS namespace transform do not track var decl names (#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
This commit is contained in:
overlookmotel 2024-06-03 12:35:56 +00:00
parent 8d2beff2fe
commit 837776e1ab
3 changed files with 42 additions and 57 deletions

View file

@ -30,7 +30,7 @@ impl<'a> TypeScript<'a> {
return; 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(); let mut names: FxHashSet<Atom<'a>> = FxHashSet::default();
// Recreate the statements vec for memory efficiency. // Recreate the statements vec for memory efficiency.
@ -59,12 +59,11 @@ impl<'a> TypeScript<'a> {
} }
} }
new_stmts.push(Statement::TSModuleDeclaration(decl)); new_stmts.push(Statement::TSModuleDeclaration(decl));
continue;
} }
match_module_declaration!(Statement) => { Statement::ExportNamedDeclaration(ref export_decl) => {
if let Statement::ExportNamedDeclaration(export_decl) = &stmt { match &export_decl.declaration {
if let Some(Declaration::TSModuleDeclaration(decl)) = Some(Declaration::TSModuleDeclaration(decl)) => {
&export_decl.declaration
{
if !decl.modifiers.is_contains_declare() { if !decl.modifiers.is_contains_declare() {
if !self.options.allow_namespaces { if !self.options.allow_namespaces {
self.ctx.error(namespace_not_supported(decl.span)); self.ctx.error(namespace_not_supported(decl.span));
@ -91,37 +90,32 @@ impl<'a> TypeScript<'a> {
continue; continue;
} }
} }
}
}
stmt.to_module_declaration().bound_names(&mut |id| { if let TSModuleDeclarationName::Identifier(id) = &decl.id {
names.insert(id.name.clone()); names.insert(id.name.clone());
}); }
new_stmts.push(stmt); }
Some(decl) => match decl {
Declaration::FunctionDeclaration(_)
| Declaration::ClassDeclaration(_)
| Declaration::TSEnumDeclaration(_) => {
names.insert(decl.id().as_ref().unwrap().name.clone());
}
_ => {}
},
_ => {}
}
} }
// Collect bindings from class, function, variable and enum declarations // Collect bindings from class, function and enum declarations
Statement::FunctionDeclaration(ref decl) => { Statement::FunctionDeclaration(_)
names.insert(decl.id.as_ref().unwrap().name.clone()); | Statement::ClassDeclaration(_)
new_stmts.push(stmt); | Statement::TSEnumDeclaration(_) => {
} names.insert(stmt.to_declaration().id().as_ref().unwrap().name.clone());
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);
} }
_ => {}
} }
new_stmts.push(stmt);
} }
program.body = new_stmts; program.body = new_stmts;
@ -185,24 +179,7 @@ impl<'a> TypeScript<'a> {
} }
new_stmts.push(transformed); new_stmts.push(transformed);
} }
} continue;
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);
} }
Statement::ExportNamedDeclaration(export_decl) => { Statement::ExportNamedDeclaration(export_decl) => {
// NB: `ExportNamedDeclaration` with no declaration (e.g. `export {x}`) is not // NB: `ExportNamedDeclaration` with no declaration (e.g. `export {x}`) is not
@ -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::TSTypeAliasDeclaration(_)
| Statement::TSInterfaceDeclaration(_) | Statement::TSInterfaceDeclaration(_)
| Statement::TSImportEqualsDeclaration(_) => {} | Statement::TSImportEqualsDeclaration(_) => continue,
_ => { _ => {}
new_stmts.push(stmt);
}
} }
new_stmts.push(stmt);
} }
if new_stmts.is_empty() { if new_stmts.is_empty() {

View file

@ -1,6 +1,6 @@
commit: 4bd1b2c2 commit: 4bd1b2c2
Passed: 480/928 Passed: 478/926
# All Passed: # All Passed:
* babel-preset-react * babel-preset-react
@ -445,7 +445,7 @@ Passed: 480/928
* opts/optimizeConstEnums/input.ts * opts/optimizeConstEnums/input.ts
* opts/rewriteImportExtensions/input.ts * opts/rewriteImportExtensions/input.ts
# babel-plugin-transform-typescript (136/152) # babel-plugin-transform-typescript (134/150)
* enum/mix-references/input.ts * enum/mix-references/input.ts
* enum/ts5.0-const-foldable/input.ts * enum/ts5.0-const-foldable/input.ts
* exports/declared-types/input.ts * exports/declared-types/input.ts

View file

@ -91,5 +91,7 @@ pub(crate) const SKIP_TESTS: &[&str] = &[
"typescript/test/fixtures/namespace/nested-shorthand-export/input.ts", "typescript/test/fixtures/namespace/nested-shorthand-export/input.ts",
"react-jsx-development/test/fixtures/cross-platform/self-inside-arrow/input.mjs", "react-jsx-development/test/fixtures/cross-platform/self-inside-arrow/input.mjs",
// Babel outputs is not correct // 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", "typescript/test/fixtures/namespace/nested-destructuring/input.ts",
]; ];