diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 929516c3c180d..afa948663aa4b 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -490,6 +490,7 @@ impl<'a> SemanticBuilder<'a> { references.retain(|&reference_id| { let reference = &mut self.symbols.references[reference_id]; + let flags = reference.flags(); if flags.is_type() && symbol_flags.can_be_referenced_by_type() || flags.is_value() && symbol_flags.can_be_referenced_by_value() @@ -1852,15 +1853,15 @@ impl<'a> SemanticBuilder<'a> { self.current_reference_flags = ReferenceFlags::Read | ReferenceFlags::Type; } } - AstKind::ExportNamedDeclaration(decl) => { - if decl.export_kind.is_type() { - self.current_reference_flags = ReferenceFlags::Type; - } - } AstKind::ExportSpecifier(s) => { - if self.current_reference_flags.is_type() || s.export_kind.is_type() { + if s.export_kind.is_type() + || matches!(self.nodes.parent_kind(self.current_node_id), Some(AstKind::ExportNamedDeclaration(decl)) if decl.export_kind.is_type()) + { self.current_reference_flags = ReferenceFlags::Type; } else { + // If the export specifier is not a explicit type export, we consider it as a potential + // type and value reference. If it references to a value in the end, we would delete the + // `ReferenceFlags::Type` flag in `fn resolve_references_for_current_scope`. self.current_reference_flags = ReferenceFlags::Read | ReferenceFlags::Type; } self.current_node_flags |= NodeFlags::ExportSpecifier; @@ -2023,9 +2024,7 @@ impl<'a> SemanticBuilder<'a> { self.class_table_builder.pop_class(); } AstKind::ExportSpecifier(_) => { - if !self.current_reference_flags.is_type_only() { - self.current_reference_flags = ReferenceFlags::empty(); - } + self.current_reference_flags = ReferenceFlags::empty(); self.current_node_flags -= NodeFlags::ExportSpecifier; } AstKind::Function(_) | AstKind::ArrowFunctionExpression(_) => { diff --git a/crates/oxc_semantic/tests/fixtures/oxc/ts/export/named/type-and-non-type.snap b/crates/oxc_semantic/tests/fixtures/oxc/ts/export/named/type-and-non-type.snap new file mode 100644 index 0000000000000..0858fc9ddc8e2 --- /dev/null +++ b/crates/oxc_semantic/tests/fixtures/oxc/ts/export/named/type-and-non-type.snap @@ -0,0 +1,50 @@ +--- +source: crates/oxc_semantic/tests/main.rs +input_file: crates/oxc_semantic/tests/fixtures/oxc/ts/export/named/type-and-non-type.ts +--- +[ + { + "children": [ + { + "children": [], + "flags": "ScopeFlags(StrictMode)", + "id": 1, + "node": "TSTypeAliasDeclaration", + "symbols": [] + } + ], + "flags": "ScopeFlags(StrictMode | Top)", + "id": 0, + "node": "Program", + "symbols": [ + { + "flags": "SymbolFlags(BlockScopedVariable | ConstVariable)", + "id": 0, + "name": "ToastViewport", + "node": "VariableDeclarator(ToastViewport)", + "references": [ + { + "flags": "ReferenceFlags(Read)", + "id": 1, + "name": "ToastViewport", + "node_id": 14 + } + ] + }, + { + "flags": "SymbolFlags(TypeAlias)", + "id": 1, + "name": "ToastProps", + "node": "TSTypeAliasDeclaration", + "references": [ + { + "flags": "ReferenceFlags(Type)", + "id": 0, + "name": "ToastProps", + "node_id": 11 + } + ] + } + ] + } +] diff --git a/crates/oxc_semantic/tests/fixtures/oxc/ts/export/named/type-and-non-type.ts b/crates/oxc_semantic/tests/fixtures/oxc/ts/export/named/type-and-non-type.ts new file mode 100644 index 0000000000000..9cb41349ce73c --- /dev/null +++ b/crates/oxc_semantic/tests/fixtures/oxc/ts/export/named/type-and-non-type.ts @@ -0,0 +1,4 @@ +const ToastViewport = 1; +type ToastProps = string; + +export { type ToastProps, ToastViewport }; diff --git a/tasks/coverage/snapshots/semantic_typescript.snap b/tasks/coverage/snapshots/semantic_typescript.snap index 5755c54c1643f..6a91b4dbeaa23 100644 --- a/tasks/coverage/snapshots/semantic_typescript.snap +++ b/tasks/coverage/snapshots/semantic_typescript.snap @@ -25302,15 +25302,15 @@ tasks/coverage/typescript/tests/cases/compiler/noCircularDefinitionOnExportOfPri semantic error: Scope children mismatch: after transform: ScopeId(0): [ScopeId(1), ScopeId(2)] rebuilt : ScopeId(0): [ScopeId(1)] +Symbol reference IDs mismatch for "cat": +after transform: SymbolId(0): [ReferenceId(1)] +rebuilt : SymbolId(0): [] Symbol flags mismatch for "Foo": after transform: SymbolId(1): SymbolFlags(Class | NameSpaceModule | Ambient) rebuilt : SymbolId(1): SymbolFlags(Class) Symbol redeclarations mismatch for "Foo": after transform: SymbolId(1): [Span { start: 61, end: 64 }] rebuilt : SymbolId(1): [] -Unresolved references mismatch: -after transform: ["cat", "module"] -rebuilt : ["module"] tasks/coverage/typescript/tests/cases/compiler/noCollisionThisExpressionAndLocalVarInFunction.ts semantic error: Scope children mismatch: diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 2612af6f909ad..be452dd4654e3 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: 54a8389f -Passed: 108/121 +Passed: 108/122 # All Passed: * babel-plugin-transform-class-static-block @@ -33,7 +33,7 @@ rebuilt : SymbolId(0): [ReferenceId(0), ReferenceId(2), ReferenceId(6), R x Output mismatch -# babel-plugin-transform-typescript (2/9) +# babel-plugin-transform-typescript (2/10) * class-property-definition/input.ts Unresolved references mismatch: after transform: ["const"] @@ -144,6 +144,14 @@ Reference symbol mismatch for "Name": after transform: SymbolId(7) "Name" rebuilt : SymbolId(5) "Name" +* exports/type-and-non-type/input.ts +Bindings mismatch: +after transform: ScopeId(0): ["ToastProps", "ToastViewport"] +rebuilt : ScopeId(0): ["ToastViewport"] +Scope children mismatch: +after transform: ScopeId(0): [ScopeId(1)] +rebuilt : ScopeId(0): [] + * redeclarations/input.ts Scope children mismatch: after transform: ScopeId(0): [ScopeId(1), ScopeId(2)] diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/exports/type-and-non-type/input.ts b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/exports/type-and-non-type/input.ts new file mode 100644 index 0000000000000..9cb41349ce73c --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/exports/type-and-non-type/input.ts @@ -0,0 +1,4 @@ +const ToastViewport = 1; +type ToastProps = string; + +export { type ToastProps, ToastViewport }; diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/exports/type-and-non-type/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/exports/type-and-non-type/output.js new file mode 100644 index 0000000000000..a7978f29fd3a1 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/exports/type-and-non-type/output.js @@ -0,0 +1,2 @@ +const ToastViewport = 1; +export { ToastViewport }; \ No newline at end of file