From f8565ae3cd23ce9c08149aa438a2f00fbacca538 Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Thu, 18 Jul 2024 16:44:37 +0000 Subject: [PATCH] fix(transformer/typescript): unexpectedly removed class binding from ExportNamedDeclaration (#4351) The original `SymbolFlags` methods were a bit confusing I renamed and re-implemented them. --- crates/oxc_semantic/src/builder.rs | 10 +++++----- .../typescript-eslint/export/named-dual.snap | 2 +- crates/oxc_syntax/src/symbol.rs | 18 +++++++++++++----- tasks/transform_conformance/oxc.snap.md | 2 +- .../test/fixtures/class-export/input.ts | 11 +++++++++++ .../test/fixtures/class-export/output.ts | 9 +++++++++ 6 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/class-export/input.ts create mode 100644 tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/class-export/output.ts diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index da7a1b47b9d68..117d1bbdaf0aa 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -399,12 +399,12 @@ impl<'a> SemanticBuilder<'a> { resolved_references.reserve(references.len()); references.retain(|(id, flag)| { - if flag.is_type() && symbol_flag.is_can_be_referenced_by_type() - || flag.is_value() && symbol_flag.is_value() + if flag.is_type() && symbol_flag.can_be_referenced_by_type() + || flag.is_value() && symbol_flag.can_be_referenced_by_value() { - // The non type-only ExportSpecifier can reference a type, - // If the reference is not a type, remove the type flag from the reference - if !symbol_flag.is_type() && !flag.is_type_only() { + // The non type-only ExportSpecifier can reference a type/value symbol, + // If the symbol is a value symbol and reference flag is not type-only, remove the type flag. + if symbol_flag.is_value() && !flag.is_type_only() { *self.symbols.references[*id].flag_mut() -= ReferenceFlag::Type; } diff --git a/crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named-dual.snap b/crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named-dual.snap index e36a88fe05e15..5590723c7434d 100644 --- a/crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named-dual.snap +++ b/crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named-dual.snap @@ -24,7 +24,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named-du "node": "VariableDeclarator", "references": [ { - "flag": "ReferenceFlag(Read | Type)", + "flag": "ReferenceFlag(Read)", "id": 0, "name": "T", "node_id": 12 diff --git a/crates/oxc_syntax/src/symbol.rs b/crates/oxc_syntax/src/symbol.rs index 57ad2db74cb67..5f9e53a18ab21 100644 --- a/crates/oxc_syntax/src/symbol.rs +++ b/crates/oxc_syntax/src/symbol.rs @@ -94,14 +94,12 @@ impl SymbolFlags { self.intersects(Self::Variable) } + /// If true, then the symbol is a type, such as a TypeAlias, Interface, or Enum pub fn is_type(&self) -> bool { - self.intersects(Self::Type | Self::TypeImport) - } - - pub fn is_can_be_referenced_by_type(&self) -> bool { - self.is_type() || self.contains(Self::Import) + self.intersects((Self::TypeImport | Self::Type) - Self::Value) } + /// If true, then the symbol is a value, such as a Variable, Function, or Class pub fn is_value(&self) -> bool { self.intersects(Self::Value | Self::Import | Self::Function) } @@ -133,4 +131,14 @@ impl SymbolFlags { pub fn is_import(&self) -> bool { self.intersects(Self::Import | Self::TypeImport) } + + /// If true, then the symbol can be referenced by a type + pub fn can_be_referenced_by_type(&self) -> bool { + self.intersects(Self::Type | Self::TypeImport | Self::Import) + } + + /// If true, then the symbol can be referenced by a value + pub fn can_be_referenced_by_value(&self) -> bool { + self.intersects(Self::Value | Self::Import | Self::Function) + } } diff --git a/tasks/transform_conformance/oxc.snap.md b/tasks/transform_conformance/oxc.snap.md index 4445a5f29aa64..a520ee4c368b4 100644 --- a/tasks/transform_conformance/oxc.snap.md +++ b/tasks/transform_conformance/oxc.snap.md @@ -1,6 +1,6 @@ commit: 12619ffe -Passed: 6/6 +Passed: 7/7 # All Passed: * babel-plugin-transform-typescript diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/class-export/input.ts b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/class-export/input.ts new file mode 100644 index 0000000000000..59cafb2987a48 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/class-export/input.ts @@ -0,0 +1,11 @@ +import Im, {Ok} from 'a'; +class Foo {} +const Bar = 0; +function Func() {} +type Baz = any; +interface Baq {} +namespace Name { + export const Q = 0; +} + +export { Im, Ok, Foo, Bar, Func, Baz, Baq, Name }; \ No newline at end of file diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/class-export/output.ts b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/class-export/output.ts new file mode 100644 index 0000000000000..3439410750831 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/class-export/output.ts @@ -0,0 +1,9 @@ +import Im, { Ok } from "a"; +class Foo {} +const Bar = 0; +function Func() {} +let Name; +(function(_Name) { + const Q = _Name.Q = 0; +})(Name || (Name = {})); +export { Im, Ok, Foo, Bar, Func, Name };