diff --git a/crates/oxc_transformer/src/decorator/legacy/metadata.rs b/crates/oxc_transformer/src/decorator/legacy/metadata.rs index cba110c0fb1d8..d825051c10d83 100644 --- a/crates/oxc_transformer/src/decorator/legacy/metadata.rs +++ b/crates/oxc_transformer/src/decorator/legacy/metadata.rs @@ -245,18 +245,6 @@ impl<'a> LegacyDecoratorMetadata<'a, '_> { } } - /// Check if an expression is a numeric expression (including unary expressions) - fn is_numeric_expression(expr: &Expression<'a>) -> bool { - expr.is_number_literal() - || matches!( - expr, Expression::UnaryExpression(unary) if - matches!( - // These operators still produce numeric results. - unary.operator, UnaryOperator::UnaryNegation | UnaryOperator::UnaryPlus | UnaryOperator::BitwiseNot - ) && unary.argument.is_number_literal() - ) - } - /// Infer the type of an enum based on its members fn infer_enum_type(members: &[TSEnumMember<'a>]) -> EnumType { let mut enum_type = EnumType::Object; @@ -269,7 +257,13 @@ impl<'a> LegacyDecoratorMetadata<'a, '_> { { enum_type = EnumType::String; } - expr if Self::is_numeric_expression(expr) && enum_type != EnumType::String => { + // TS considers `+x`, `-x`, `~x` to be `Number` type, no matter what `x` is. + // All other unary expressions (`!x`, `void x`, `typeof x`, `delete x`) are illegal in enum initializers, + // so we can ignore those cases here and just say all `UnaryExpression`s are numeric. + // Bigint literals are also illegal in enum initializers, so we don't need to consider them here. + Expression::NumericLiteral(_) | Expression::UnaryExpression(_) + if enum_type != EnumType::String => + { enum_type = EnumType::Number; } // For other expressions, we can't determine the type statically diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index e03821a2c4baa..91bb1f304cf39 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -582,83 +582,83 @@ Scope flags mismatch: after transform: ScopeId(3): ScopeFlags(0x0) rebuilt : ScopeId(3): ScopeFlags(Function) Bindings mismatch: -after transform: ScopeId(4): ["BigIntEnum", "big", "bigger"] -rebuilt : ScopeId(4): ["BigIntEnum"] +after transform: ScopeId(4): ["UnaryEnum", "bitwise", "negative", "positive"] +rebuilt : ScopeId(4): ["UnaryEnum"] Scope flags mismatch: after transform: ScopeId(4): ScopeFlags(0x0) rebuilt : ScopeId(4): ScopeFlags(Function) Bindings mismatch: -after transform: ScopeId(5): ["UnaryEnum", "bitwise", "negative", "positive"] -rebuilt : ScopeId(5): ["UnaryEnum"] -Scope flags mismatch: -after transform: ScopeId(5): ScopeFlags(0x0) -rebuilt : ScopeId(5): ScopeFlags(Function) -Bindings mismatch: -after transform: ScopeId(6): ["AutoIncrementEnum", "first", "second", "third"] -rebuilt : ScopeId(6): ["AutoIncrementEnum"] +after transform: ScopeId(6): ["UnaryOtherEnum", "bitwise", "negative", "positive"] +rebuilt : ScopeId(6): ["UnaryOtherEnum"] Scope flags mismatch: after transform: ScopeId(6): ScopeFlags(0x0) rebuilt : ScopeId(6): ScopeFlags(Function) Bindings mismatch: -after transform: ScopeId(7): ["MixedEnum", "num", "str"] -rebuilt : ScopeId(7): ["MixedEnum"] +after transform: ScopeId(7): ["AutoIncrementEnum", "first", "second", "third"] +rebuilt : ScopeId(7): ["AutoIncrementEnum"] Scope flags mismatch: after transform: ScopeId(7): ScopeFlags(0x0) rebuilt : ScopeId(7): ScopeFlags(Function) Bindings mismatch: -after transform: ScopeId(8): ["ComputedEnum", "computed", "expression"] -rebuilt : ScopeId(8): ["ComputedEnum"] +after transform: ScopeId(8): ["MixedEnum", "num", "str"] +rebuilt : ScopeId(8): ["MixedEnum"] Scope flags mismatch: after transform: ScopeId(8): ScopeFlags(0x0) rebuilt : ScopeId(8): ScopeFlags(Function) +Bindings mismatch: +after transform: ScopeId(9): ["ComputedEnum", "computed", "expression"] +rebuilt : ScopeId(9): ["ComputedEnum"] +Scope flags mismatch: +after transform: ScopeId(9): ScopeFlags(0x0) +rebuilt : ScopeId(9): ScopeFlags(Function) Symbol flags mismatch for "StringEnum": after transform: SymbolId(0): SymbolFlags(RegularEnum) rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) Symbol reference IDs mismatch for "StringEnum": -after transform: SymbolId(0): [ReferenceId(2), ReferenceId(18), ReferenceId(24)] +after transform: SymbolId(0): [ReferenceId(5), ReferenceId(21), ReferenceId(27)] rebuilt : SymbolId(0): [ReferenceId(3)] Symbol flags mismatch for "TemplateStringEnum": after transform: SymbolId(3): SymbolFlags(RegularEnum) rebuilt : SymbolId(2): SymbolFlags(FunctionScopedVariable) Symbol reference IDs mismatch for "TemplateStringEnum": -after transform: SymbolId(3): [ReferenceId(4), ReferenceId(28)] +after transform: SymbolId(3): [ReferenceId(7), ReferenceId(31)] rebuilt : SymbolId(2): [ReferenceId(7)] Symbol flags mismatch for "NumberEnum": after transform: SymbolId(6): SymbolFlags(RegularEnum) rebuilt : SymbolId(4): SymbolFlags(FunctionScopedVariable) Symbol reference IDs mismatch for "NumberEnum": -after transform: SymbolId(6): [ReferenceId(6), ReferenceId(19), ReferenceId(20), ReferenceId(34)] -rebuilt : SymbolId(4): [ReferenceId(13), ReferenceId(48)] -Symbol flags mismatch for "BigIntEnum": +after transform: SymbolId(6): [ReferenceId(9), ReferenceId(22), ReferenceId(23), ReferenceId(37)] +rebuilt : SymbolId(4): [ReferenceId(13), ReferenceId(53)] +Symbol flags mismatch for "UnaryEnum": after transform: SymbolId(9): SymbolFlags(RegularEnum) rebuilt : SymbolId(6): SymbolFlags(FunctionScopedVariable) -Symbol reference IDs mismatch for "BigIntEnum": -after transform: SymbolId(9): [ReferenceId(8), ReferenceId(40)] -rebuilt : SymbolId(6): [ReferenceId(19)] -Symbol flags mismatch for "UnaryEnum": -after transform: SymbolId(12): SymbolFlags(RegularEnum) -rebuilt : SymbolId(8): SymbolFlags(FunctionScopedVariable) Symbol reference IDs mismatch for "UnaryEnum": -after transform: SymbolId(12): [ReferenceId(10), ReferenceId(48)] -rebuilt : SymbolId(8): [ReferenceId(27)] +after transform: SymbolId(9): [ReferenceId(11), ReferenceId(45)] +rebuilt : SymbolId(6): [ReferenceId(21)] +Symbol flags mismatch for "UnaryOtherEnum": +after transform: SymbolId(14): SymbolFlags(RegularEnum) +rebuilt : SymbolId(9): SymbolFlags(FunctionScopedVariable) +Symbol reference IDs mismatch for "UnaryOtherEnum": +after transform: SymbolId(14): [ReferenceId(13), ReferenceId(53)] +rebuilt : SymbolId(9): [ReferenceId(32)] Symbol flags mismatch for "AutoIncrementEnum": -after transform: SymbolId(16): SymbolFlags(RegularEnum) -rebuilt : SymbolId(10): SymbolFlags(FunctionScopedVariable) +after transform: SymbolId(18): SymbolFlags(RegularEnum) +rebuilt : SymbolId(11): SymbolFlags(FunctionScopedVariable) Symbol reference IDs mismatch for "AutoIncrementEnum": -after transform: SymbolId(16): [ReferenceId(12), ReferenceId(56)] -rebuilt : SymbolId(10): [ReferenceId(35)] +after transform: SymbolId(18): [ReferenceId(15), ReferenceId(61)] +rebuilt : SymbolId(11): [ReferenceId(40)] Symbol flags mismatch for "MixedEnum": -after transform: SymbolId(20): SymbolFlags(RegularEnum) -rebuilt : SymbolId(12): SymbolFlags(FunctionScopedVariable) +after transform: SymbolId(22): SymbolFlags(RegularEnum) +rebuilt : SymbolId(13): SymbolFlags(FunctionScopedVariable) Symbol reference IDs mismatch for "MixedEnum": -after transform: SymbolId(20): [ReferenceId(14), ReferenceId(61)] -rebuilt : SymbolId(12): [ReferenceId(40)] +after transform: SymbolId(22): [ReferenceId(17), ReferenceId(66)] +rebuilt : SymbolId(13): [ReferenceId(45)] Symbol flags mismatch for "ComputedEnum": -after transform: SymbolId(23): SymbolFlags(RegularEnum) -rebuilt : SymbolId(14): SymbolFlags(FunctionScopedVariable) +after transform: SymbolId(25): SymbolFlags(RegularEnum) +rebuilt : SymbolId(15): SymbolFlags(FunctionScopedVariable) Symbol reference IDs mismatch for "ComputedEnum": -after transform: SymbolId(23): [ReferenceId(16), ReferenceId(67)] -rebuilt : SymbolId(14): [ReferenceId(47)] +after transform: SymbolId(25): [ReferenceId(19), ReferenceId(72)] +rebuilt : SymbolId(15): [ReferenceId(52)] * oxc/metadata/imports/input.ts Bindings mismatch: diff --git a/tasks/transform_conformance/tests/legacy-decorators/test/fixtures/oxc/metadata/enum-types/input.ts b/tasks/transform_conformance/tests/legacy-decorators/test/fixtures/oxc/metadata/enum-types/input.ts index cf430a9570d0a..0b3fec6db3c3b 100644 --- a/tasks/transform_conformance/tests/legacy-decorators/test/fixtures/oxc/metadata/enum-types/input.ts +++ b/tasks/transform_conformance/tests/legacy-decorators/test/fixtures/oxc/metadata/enum-types/input.ts @@ -13,17 +13,20 @@ enum NumberEnum { b = 2 } -enum BigIntEnum { - big = 100n, - bigger = 200n -} - enum UnaryEnum { negative = -1, positive = +2, bitwise = ~3 } +function getString() { return 'string'; } + +enum UnaryOtherEnum { + negative = -getString(), + positive = +getString(), + bitwise = ~getString(), +} + enum AutoIncrementEnum { first, // 0 second, // 1 @@ -45,28 +48,28 @@ function decorate(target: any, property: string) {} export class Foo { @decorate stringProp: StringEnum; - + @decorate templateProp: TemplateStringEnum; - + @decorate numberProp: NumberEnum; - - @decorate - bigintProp: BigIntEnum; - + @decorate unaryProp: UnaryEnum; - + + @decorate + unaryOtherProp: UnaryOtherEnum; + @decorate autoProp: AutoIncrementEnum; - + @decorate mixedProp: MixedEnum; - + @decorate computedProp: ComputedEnum; @decorate method(param: StringEnum): NumberEnum { return NumberEnum.a; } -} \ No newline at end of file +} diff --git a/tasks/transform_conformance/tests/legacy-decorators/test/fixtures/oxc/metadata/enum-types/output.js b/tasks/transform_conformance/tests/legacy-decorators/test/fixtures/oxc/metadata/enum-types/output.js index e34076a11c4cd..10cd064564064 100644 --- a/tasks/transform_conformance/tests/legacy-decorators/test/fixtures/oxc/metadata/enum-types/output.js +++ b/tasks/transform_conformance/tests/legacy-decorators/test/fixtures/oxc/metadata/enum-types/output.js @@ -16,12 +16,6 @@ var NumberEnum = /* @__PURE__ */ function(NumberEnum) { return NumberEnum; }(NumberEnum || {}); -var BigIntEnum = /* @__PURE__ */ function(BigIntEnum) { - BigIntEnum[BigIntEnum["big"] = 100n] = "big"; - BigIntEnum[BigIntEnum["bigger"] = 200n] = "bigger"; - return BigIntEnum; -}(BigIntEnum || {}); - var UnaryEnum = /* @__PURE__ */ function(UnaryEnum) { UnaryEnum[UnaryEnum["negative"] = -1] = "negative"; UnaryEnum[UnaryEnum["positive"] = 2] = "positive"; @@ -29,6 +23,17 @@ var UnaryEnum = /* @__PURE__ */ function(UnaryEnum) { return UnaryEnum; }(UnaryEnum || {}); +function getString() { + return "string"; +} + +var UnaryOtherEnum = /* @__PURE__ */ function(UnaryOtherEnum) { + UnaryOtherEnum[UnaryOtherEnum["negative"] = -getString()] = "negative"; + UnaryOtherEnum[UnaryOtherEnum["positive"] = +getString()] = "positive"; + UnaryOtherEnum[UnaryOtherEnum["bitwise"] = ~getString()] = "bitwise"; + return UnaryOtherEnum; +}(UnaryOtherEnum || {}); + var AutoIncrementEnum = /* @__PURE__ */ function(AutoIncrementEnum) { AutoIncrementEnum[AutoIncrementEnum["first"] = 0] = "first"; AutoIncrementEnum[AutoIncrementEnum["second"] = 1] = "second"; @@ -54,8 +59,8 @@ export class Foo { stringProp; templateProp; numberProp; - bigintProp; unaryProp; + unaryOtherProp; autoProp; mixedProp; computedProp; @@ -67,8 +72,8 @@ export class Foo { babelHelpers.decorate([decorate, babelHelpers.decorateMetadata("design:type", String)], Foo.prototype, "stringProp", void 0); babelHelpers.decorate([decorate, babelHelpers.decorateMetadata("design:type", String)], Foo.prototype, "templateProp", void 0); babelHelpers.decorate([decorate, babelHelpers.decorateMetadata("design:type", Number)], Foo.prototype, "numberProp", void 0); -babelHelpers.decorate([decorate, babelHelpers.decorateMetadata("design:type", Number)], Foo.prototype, "bigintProp", void 0); babelHelpers.decorate([decorate, babelHelpers.decorateMetadata("design:type", Number)], Foo.prototype, "unaryProp", void 0); +babelHelpers.decorate([decorate, babelHelpers.decorateMetadata("design:type", Number)], Foo.prototype, "unaryOtherProp", void 0); babelHelpers.decorate([decorate, babelHelpers.decorateMetadata("design:type", Number)], Foo.prototype, "autoProp", void 0); babelHelpers.decorate([decorate, babelHelpers.decorateMetadata("design:type", Object)], Foo.prototype, "mixedProp", void 0); babelHelpers.decorate([decorate, babelHelpers.decorateMetadata("design:type", Object)], Foo.prototype, "computedProp", void 0);