From 6732e8b9af75a2a80ee9837b9cc1311d1b9b90d2 Mon Sep 17 00:00:00 2001 From: Dunqing Date: Tue, 16 Apr 2024 14:39:37 +0800 Subject: [PATCH] feat(transformer/typescript): support for transform enum (#2997) The current implementation is copied from the previous implementation --- crates/oxc_transformer/src/lib.rs | 6 + crates/oxc_transformer/src/typescript/enum.rs | 230 +++++ crates/oxc_transformer/src/typescript/mod.rs | 18 + crates/oxc_transformer/src/utils.rs | 12 + .../transform_conformance/typescript.snap.md | 843 ++++++++++++++++++ 5 files changed, 1109 insertions(+) create mode 100644 crates/oxc_transformer/src/typescript/enum.rs create mode 100644 crates/oxc_transformer/src/utils.rs diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index b77fe8b2a..4af6da26b 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -14,6 +14,7 @@ mod options; // Presets: mod react; mod typescript; +mod utils; mod helpers { pub mod module_imports; @@ -210,4 +211,9 @@ impl<'a> VisitMut<'a> for Transformer<'a> { self.x0_typescript.transform_statement(stmt); walk_mut::walk_statement_mut(self, stmt); } + + fn visit_declaration(&mut self, decl: &mut Declaration<'a>) { + self.x0_typescript.transform_declaration(decl); + walk_mut::walk_declaration_mut(self, decl); + } } diff --git a/crates/oxc_transformer/src/typescript/enum.rs b/crates/oxc_transformer/src/typescript/enum.rs new file mode 100644 index 000000000..fda6b11fd --- /dev/null +++ b/crates/oxc_transformer/src/typescript/enum.rs @@ -0,0 +1,230 @@ +use std::mem; + +use oxc_allocator::{Box, Vec}; +use oxc_ast::ast::*; +use oxc_span::{Atom, SPAN}; +use oxc_syntax::{ + operator::{AssignmentOperator, BinaryOperator, LogicalOperator}, + NumberBase, +}; + +use crate::utils::is_valid_identifier; + +use super::TypeScript; + +impl<'a> TypeScript<'a> { + /// ```TypeScript + /// enum Foo { + /// X + /// } + /// ``` + /// ```JavaScript + /// var Foo = ((Foo) => { + /// const X = 0; Foo[Foo["X"] = X] = "X"; + /// return Foo; + /// })(Foo || {}); + /// ``` + pub fn transform_ts_enum( + &self, + decl: &mut Box<'a, TSEnumDeclaration<'a>>, + ) -> Option> { + if decl.modifiers.contains(ModifierKind::Declare) { + return None; + } + + let span = decl.span; + let ident = decl.id.clone(); + let kind = self.ctx.ast.binding_pattern_identifier(ident); + let id = self.ctx.ast.binding_pattern(kind, None, false); + + let mut params = self.ctx.ast.new_vec(); + + // ((Foo) => { + params.push(self.ctx.ast.formal_parameter( + SPAN, + id, + None, + false, + false, + self.ctx.ast.new_vec(), + )); + + let params = self.ctx.ast.formal_parameters( + SPAN, + FormalParameterKind::ArrowFormalParameters, + params, + None, + ); + + // Foo[Foo["X"] = 0] = "X"; + let enum_name = decl.id.name.clone(); + let statements = self.transform_ts_enum_members(&mut decl.members, &enum_name); + let body = self.ctx.ast.function_body(decl.span, self.ctx.ast.new_vec(), statements); + + let callee = + self.ctx.ast.arrow_function_expression(SPAN, false, false, params, body, None, None); + + // })(Foo || {}); + let mut arguments = self.ctx.ast.new_vec(); + let op = LogicalOperator::Or; + let left = self + .ctx + .ast + .identifier_reference_expression(IdentifierReference::new(SPAN, enum_name.clone())); + let right = self.ctx.ast.object_expression(SPAN, self.ctx.ast.new_vec(), None); + let expression = self.ctx.ast.logical_expression(SPAN, left, op, right); + arguments.push(Argument::Expression(expression)); + + let call_expression = self.ctx.ast.call_expression(SPAN, callee, arguments, false, None); + + let kind = VariableDeclarationKind::Var; + let decls = { + let mut decls = self.ctx.ast.new_vec(); + + let binding_identifier = BindingIdentifier::new(SPAN, enum_name.clone()); + let binding_pattern_kind = self.ctx.ast.binding_pattern_identifier(binding_identifier); + let binding = self.ctx.ast.binding_pattern(binding_pattern_kind, None, false); + let decl = + self.ctx.ast.variable_declarator(SPAN, kind, binding, Some(call_expression), false); + + decls.push(decl); + decls + }; + let variable_declaration = + self.ctx.ast.variable_declaration(span, kind, decls, Modifiers::empty()); + + Some(Declaration::VariableDeclaration(variable_declaration)) + } + + pub fn transform_ts_enum_members( + &self, + members: &mut Vec<'a, TSEnumMember<'a>>, + enum_name: &Atom<'a>, + ) -> Vec<'a, Statement<'a>> { + let mut default_init = self.ctx.ast.literal_number_expression(NumericLiteral { + span: SPAN, + value: 0.0, + raw: "0", + base: NumberBase::Decimal, + }); + let mut statements = self.ctx.ast.new_vec(); + + for member in members.iter_mut() { + let (member_name, member_span) = match &member.id { + TSEnumMemberName::Identifier(id) => (&id.name, id.span), + TSEnumMemberName::StringLiteral(str) => (&str.value, str.span), + TSEnumMemberName::ComputedPropertyName(..) + | TSEnumMemberName::NumericLiteral(..) => unreachable!(), + }; + + let mut init = self + .ctx + .ast + .move_expression(member.initializer.as_mut().unwrap_or(&mut default_init)); + + let is_str = init.is_string_literal(); + + let mut self_ref = { + let obj = self.ctx.ast.identifier_reference_expression(IdentifierReference::new( + SPAN, + enum_name.clone(), + )); + let expr = self + .ctx + .ast + .literal_string_expression(StringLiteral::new(SPAN, member_name.clone())); + self.ctx.ast.computed_member_expression(SPAN, obj, expr, false) + }; + + if is_valid_identifier(member_name, true) { + let ident = IdentifierReference::new(member_span, member_name.clone()); + + self_ref = self.ctx.ast.identifier_reference_expression(ident.clone()); + let init = + mem::replace(&mut init, self.ctx.ast.identifier_reference_expression(ident)); + + let kind = VariableDeclarationKind::Const; + let decls = { + let mut decls = self.ctx.ast.new_vec(); + + let binding_identifier = BindingIdentifier::new(SPAN, member_name.clone()); + let binding_pattern_kind = + self.ctx.ast.binding_pattern_identifier(binding_identifier); + let binding = self.ctx.ast.binding_pattern(binding_pattern_kind, None, false); + let decl = + self.ctx.ast.variable_declarator(SPAN, kind, binding, Some(init), false); + + decls.push(decl); + decls + }; + let decl = self.ctx.ast.variable_declaration(SPAN, kind, decls, Modifiers::empty()); + let stmt: Statement<'_> = + Statement::Declaration(Declaration::VariableDeclaration(decl)); + + statements.push(stmt); + } + + // Foo["x"] = init + let member_expr = { + let obj = self.ctx.ast.identifier_reference_expression(IdentifierReference::new( + SPAN, + enum_name.clone(), + )); + let expr = self + .ctx + .ast + .literal_string_expression(StringLiteral::new(SPAN, member_name.clone())); + + self.ctx.ast.computed_member(SPAN, obj, expr, false) + }; + let left = self.ctx.ast.simple_assignment_target_member_expression(member_expr); + let mut expr = + self.ctx.ast.assignment_expression(SPAN, AssignmentOperator::Assign, left, init); + + // Foo[Foo["x"] = init] = "x" + if !is_str { + let member_expr = { + let obj = self.ctx.ast.identifier_reference_expression( + IdentifierReference::new(SPAN, enum_name.clone()), + ); + self.ctx.ast.computed_member(SPAN, obj, expr, false) + }; + let left = self.ctx.ast.simple_assignment_target_member_expression(member_expr); + let right = self + .ctx + .ast + .literal_string_expression(StringLiteral::new(SPAN, member_name.clone())); + expr = self.ctx.ast.assignment_expression( + SPAN, + AssignmentOperator::Assign, + left, + right, + ); + } + + statements.push(self.ctx.ast.expression_statement(member.span, expr)); + + // 1 + Foo["x"] + default_init = { + let one = self.ctx.ast.literal_number_expression(NumericLiteral { + span: SPAN, + value: 1.0, + raw: "1", + base: NumberBase::Decimal, + }); + + self.ctx.ast.binary_expression(SPAN, one, BinaryOperator::Addition, self_ref) + }; + } + + let enum_ref = self + .ctx + .ast + .identifier_reference_expression(IdentifierReference::new(SPAN, enum_name.clone())); + // return Foo; + let return_stmt = self.ctx.ast.return_statement(SPAN, Some(enum_ref)); + statements.push(return_stmt); + + statements + } +} diff --git a/crates/oxc_transformer/src/typescript/mod.rs b/crates/oxc_transformer/src/typescript/mod.rs index d38c4b3c1..cb95d5913 100644 --- a/crates/oxc_transformer/src/typescript/mod.rs +++ b/crates/oxc_transformer/src/typescript/mod.rs @@ -1,5 +1,6 @@ mod annotations; mod collector; +mod r#enum; mod namespace; use std::rc::Rc; @@ -148,4 +149,21 @@ impl<'a> TypeScript<'a> { pub fn transform_statement(&mut self, stmt: &mut Statement<'a>) { self.annotations.transform_statement(stmt); } + + pub fn transform_declaration(&mut self, decl: &mut Declaration<'a>) { + match decl { + Declaration::TSImportEqualsDeclaration(ts_import_equals) + if ts_import_equals.import_kind.is_value() => + { + // TODO: support for transform_ts_import_equals function + // *decl = self.transform_ts_import_equals(ts_import_equals); + } + Declaration::TSEnumDeclaration(ts_enum_declaration) => { + if let Some(expr) = self.transform_ts_enum(ts_enum_declaration) { + *decl = expr; + } + } + _ => {} + } + } } diff --git a/crates/oxc_transformer/src/utils.rs b/crates/oxc_transformer/src/utils.rs new file mode 100644 index 000000000..31a4190f5 --- /dev/null +++ b/crates/oxc_transformer/src/utils.rs @@ -0,0 +1,12 @@ +use oxc_syntax::{identifier::is_identifier_name, keyword::is_keyword}; + +pub fn is_valid_identifier(name: &str, reserved: bool) -> bool { + if reserved && (is_keyword(name) || is_reserved_word(name, true)) { + return false; + } + is_identifier_name(name) +} + +pub fn is_reserved_word(name: &str, in_module: bool) -> bool { + (in_module && name == "await") || name == "enum" +} diff --git a/tasks/transform_conformance/typescript.snap.md b/tasks/transform_conformance/typescript.snap.md index 65fa5da49..ebf98b5cb 100644 --- a/tasks/transform_conformance/typescript.snap.md +++ b/tasks/transform_conformance/typescript.snap.md @@ -14,12 +14,83 @@ # typescript/tests/cases/conformance/enums/enumBasics.ts ```typescript +var E1 = (E1 => { + const A = 0; + E1[E1['A'] = A] = 'A'; + const B = 1 + A; + E1[E1['B'] = B] = 'B'; + const C = 1 + B; + E1[E1['C'] = C] = 'C'; + return E1; +})(E1 || {}); var x = E1.A; var e = E1; var e; var e; var s = E1[e.A]; var s; +var E2 = (E2 => { + const A = 1; + E2[E2['A'] = A] = 'A'; + const B = 2; + E2[E2['B'] = B] = 'B'; + const C = 3; + E2[E2['C'] = C] = 'C'; + return E2; +})(E2 || {}); +var E3 = (E3 => { + const X = 'foo'.length; + E3[E3['X'] = X] = 'X'; + const Y = 4 + 3; + E3[E3['Y'] = Y] = 'Y'; + const Z = +'foo'; + E3[E3['Z'] = Z] = 'Z'; + return E3; +})(E3 || {}); +var E4 = (E4 => { + const X = 0; + E4[E4['X'] = X] = 'X'; + const Y = 1 + X; + E4[E4['Y'] = Y] = 'Y'; + const Z = 'foo'.length; + E4[E4['Z'] = Z] = 'Z'; + return E4; +})(E4 || {}); +var E5 = (E5 => { + const A = 0; + E5[E5['A'] = A] = 'A'; + const B = 3; + E5[E5['B'] = B] = 'B'; + const C = 1 + B; + E5[E5['C'] = C] = 'C'; + return E5; +})(E5 || {}); +var E6 = (E6 => { + const A = 0; + E6[E6['A'] = A] = 'A'; + const B = 0; + E6[E6['B'] = B] = 'B'; + const C = 1 + B; + E6[E6['C'] = C] = 'C'; + return E6; +})(E6 || {}); +var E7 = (E7 => { + const A = 'foo'['foo']; + E7[E7['A'] = A] = 'A'; + return E7; +})(E7 || {}); +var E8 = (E8 => { + const B = 'foo'['foo']; + E8[E8['B'] = B] = 'B'; + return E8; +})(E8 || {}); +var E9 = (E9 => { + const A = 0; + E9[E9['A'] = A] = 'A'; + const B = A; + E9[E9['B'] = B] = 'B'; + return E9; +})(E9 || {}); var doNotPropagate = [E8.B, E7.A, E4.Z, E3.X, E3.Y, E3.Z]; var doPropagate = [E9.A, E9.B, E6.B, E6.C, E6.A, E5.A, E5.B, E5.C]; @@ -27,37 +98,381 @@ var doPropagate = [E9.A, E9.B, E6.B, E6.C, E6.A, E5.A, E5.B, E5.C]; # typescript/tests/cases/conformance/enums/enumClassification.ts ```typescript +var E01 = (E01 => { + const A = 0; + E01[E01['A'] = A] = 'A'; + return E01; +})(E01 || {}); +var E02 = (E02 => { + const A = 123; + E02[E02['A'] = A] = 'A'; + return E02; +})(E02 || {}); +var E03 = (E03 => { + const A = 'hello'; + E03['A'] = A; + return E03; +})(E03 || {}); +var E04 = (E04 => { + const A = 0; + E04[E04['A'] = A] = 'A'; + const B = 1 + A; + E04[E04['B'] = B] = 'B'; + const C = 1 + B; + E04[E04['C'] = C] = 'C'; + return E04; +})(E04 || {}); +var E05 = (E05 => { + const A = 0; + E05[E05['A'] = A] = 'A'; + const B = 10; + E05[E05['B'] = B] = 'B'; + const C = 1 + B; + E05[E05['C'] = C] = 'C'; + return E05; +})(E05 || {}); +var E06 = (E06 => { + const A = 'one'; + E06['A'] = A; + const B = 'two'; + E06['B'] = B; + const C = 'three'; + E06['C'] = C; + return E06; +})(E06 || {}); +var E07 = (E07 => { + const A = 0; + E07[E07['A'] = A] = 'A'; + const B = 1 + A; + E07[E07['B'] = B] = 'B'; + const C = 'hi'; + E07['C'] = C; + const D = 10; + E07[E07['D'] = D] = 'D'; + const E = 1 + D; + E07[E07['E'] = E] = 'E'; + const F = 'bye'; + E07['F'] = F; + return E07; +})(E07 || {}); +var E08 = (E08 => { + const A = 10; + E08[E08['A'] = A] = 'A'; + const B = 'hello'; + E08['B'] = B; + const C = A; + E08[E08['C'] = C] = 'C'; + const D = B; + E08[E08['D'] = D] = 'D'; + const E = C; + E08[E08['E'] = E] = 'E'; + return E08; +})(E08 || {}); +var E10 = (E10 => { + return E10; +})(E10 || {}); +var E11 = (E11 => { + const A = +0; + E11[E11['A'] = A] = 'A'; + const B = 1 + A; + E11[E11['B'] = B] = 'B'; + const C = 1 + B; + E11[E11['C'] = C] = 'C'; + return E11; +})(E11 || {}); +var E12 = (E12 => { + const A = 1 << 0; + E12[E12['A'] = A] = 'A'; + const B = 1 << 1; + E12[E12['B'] = B] = 'B'; + const C = 1 << 2; + E12[E12['C'] = C] = 'C'; + return E12; +})(E12 || {}); +var E20 = (E20 => { + const A = 'foo'.length; + E20[E20['A'] = A] = 'A'; + const B = A + 1; + E20[E20['B'] = B] = 'B'; + const C = +'123'; + E20[E20['C'] = C] = 'C'; + const D = Math.sin(1); + E20[E20['D'] = D] = 'D'; + return E20; +})(E20 || {}); ``` # typescript/tests/cases/conformance/enums/enumConstantMemberWithString.ts ```typescript +var T1 = (T1 => { + const a = '1'; + T1['a'] = a; + const b = '1' + '2'; + T1[T1['b'] = b] = 'b'; + const c = '1' + '2' + '3'; + T1[T1['c'] = c] = 'c'; + const d = 'a' - 'a'; + T1[T1['d'] = d] = 'd'; + const e = 'a' + 1; + T1[T1['e'] = e] = 'e'; + return T1; +})(T1 || {}); +var T2 = (T2 => { + const a = '1'; + T2['a'] = a; + const b = '1' + '2'; + T2[T2['b'] = b] = 'b'; + return T2; +})(T2 || {}); +var T3 = (T3 => { + const a = '1'; + T3['a'] = a; + const b = '1' + '2'; + T3[T3['b'] = b] = 'b'; + const c = 1; + T3[T3['c'] = c] = 'c'; + const d = 1 + 2; + T3[T3['d'] = d] = 'd'; + return T3; +})(T3 || {}); +var T4 = (T4 => { + const a = '1'; + T4['a'] = a; + return T4; +})(T4 || {}); +var T5 = (T5 => { + const a = '1' + '2'; + T5[T5['a'] = a] = 'a'; + return T5; +})(T5 || {}); ``` # typescript/tests/cases/conformance/enums/enumConstantMemberWithStringEmitDeclaration.ts ```typescript +var T1 = (T1 => { + const a = '1'; + T1['a'] = a; + const b = '1' + '2'; + T1[T1['b'] = b] = 'b'; + const c = '1' + '2' + '3'; + T1[T1['c'] = c] = 'c'; + return T1; +})(T1 || {}); +var T2 = (T2 => { + const a = '1'; + T2['a'] = a; + const b = '1' + '2'; + T2[T2['b'] = b] = 'b'; + return T2; +})(T2 || {}); +var T3 = (T3 => { + const a = '1'; + T3['a'] = a; + const b = '1' + '2'; + T3[T3['b'] = b] = 'b'; + return T3; +})(T3 || {}); +var T4 = (T4 => { + const a = '1'; + T4['a'] = a; + return T4; +})(T4 || {}); +var T5 = (T5 => { + const a = '1' + '2'; + T5[T5['a'] = a] = 'a'; + return T5; +})(T5 || {}); ``` # typescript/tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts ```typescript +var T1 = (T1 => { + const a = `1`; + T1['a'] = a; + return T1; +})(T1 || {}); +var T2 = (T2 => { + const a = `1`; + T2['a'] = a; + const b = '2'; + T2['b'] = b; + const c = 3; + T2[T2['c'] = c] = 'c'; + return T2; +})(T2 || {}); +var T3 = (T3 => { + const a = `1` + `1`; + T3[T3['a'] = a] = 'a'; + return T3; +})(T3 || {}); +var T4 = (T4 => { + const a = `1`; + T4['a'] = a; + const b = `1` + `1`; + T4[T4['b'] = b] = 'b'; + const c = `1` + '2'; + T4[T4['c'] = c] = 'c'; + const d = '2' + `1`; + T4[T4['d'] = d] = 'd'; + const e = '2' + `1` + `1`; + T4[T4['e'] = e] = 'e'; + return T4; +})(T4 || {}); +var T5 = (T5 => { + const a = `1`; + T5['a'] = a; + const b = `1` + `2`; + T5[T5['b'] = b] = 'b'; + const c = `1` + `2` + `3`; + T5[T5['c'] = c] = 'c'; + const d = 1; + T5[T5['d'] = d] = 'd'; + const e = `1` - `1`; + T5[T5['e'] = e] = 'e'; + const f = `1` + 1; + T5[T5['f'] = f] = 'f'; + const g = `1${'2'}3`; + T5['g'] = g; + const h = `1`.length; + T5[T5['h'] = h] = 'h'; + return T5; +})(T5 || {}); +var T6 = (T6 => { + const a = 1; + T6[T6['a'] = a] = 'a'; + const b = `12`.length; + T6[T6['b'] = b] = 'b'; + return T6; +})(T6 || {}); ``` # typescript/tests/cases/conformance/enums/enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts ```typescript +var T1 = (T1 => { + const a = `1`; + T1['a'] = a; + return T1; +})(T1 || {}); +var T2 = (T2 => { + const a = `1`; + T2['a'] = a; + const b = '2'; + T2['b'] = b; + const c = 3; + T2[T2['c'] = c] = 'c'; + return T2; +})(T2 || {}); +var T3 = (T3 => { + const a = `1` + `1`; + T3[T3['a'] = a] = 'a'; + return T3; +})(T3 || {}); +var T4 = (T4 => { + const a = `1`; + T4['a'] = a; + const b = `1` + `1`; + T4[T4['b'] = b] = 'b'; + const c = `1` + '2'; + T4[T4['c'] = c] = 'c'; + const d = '2' + `1`; + T4[T4['d'] = d] = 'd'; + const e = '2' + `1` + `1`; + T4[T4['e'] = e] = 'e'; + return T4; +})(T4 || {}); +var T5 = (T5 => { + const a = `1`; + T5['a'] = a; + const b = `1` + `2`; + T5[T5['b'] = b] = 'b'; + const c = `1` + `2` + `3`; + T5[T5['c'] = c] = 'c'; + const d = 1; + T5[T5['d'] = d] = 'd'; + return T5; +})(T5 || {}); +var T6 = (T6 => { + const a = 1; + T6[T6['a'] = a] = 'a'; + const b = `12`.length; + T6[T6['b'] = b] = 'b'; + return T6; +})(T6 || {}); ``` # typescript/tests/cases/conformance/enums/enumConstantMembers.ts ```typescript +var E1 = (E1 => { + const a = 1; + E1[E1['a'] = a] = 'a'; + const b = 1 + a; + E1[E1['b'] = b] = 'b'; + return E1; +})(E1 || {}); +var E2 = (E2 => { + const a = -1; + E2[E2['a'] = a] = 'a'; + const b = 1 + a; + E2[E2['b'] = b] = 'b'; + return E2; +})(E2 || {}); +var E3 = (E3 => { + const a = 0.1; + E3[E3['a'] = a] = 'a'; + const b = 1 + a; + E3[E3['b'] = b] = 'b'; + return E3; +})(E3 || {}); +var E5 = (E5 => { + const a = 1 / 0; + E5[E5['a'] = a] = 'a'; + const b = 2 / 0.0; + E5[E5['b'] = b] = 'b'; + const c = 1.0 / 0.0; + E5[E5['c'] = c] = 'c'; + const d = 0.0 / 0.0; + E5[E5['d'] = d] = 'd'; + const e = NaN; + E5[E5['e'] = e] = 'e'; + const f = Infinity; + E5[E5['f'] = f] = 'f'; + const g = -Infinity; + E5[E5['g'] = g] = 'g'; + return E5; +})(E5 || {}); +var E6 = (E6 => { + const a = 1 / 0; + E6[E6['a'] = a] = 'a'; + const b = 2 / 0.0; + E6[E6['b'] = b] = 'b'; + const c = 1.0 / 0.0; + E6[E6['c'] = c] = 'c'; + const d = 0.0 / 0.0; + E6[E6['d'] = d] = 'd'; + const e = NaN; + E6[E6['e'] = e] = 'e'; + const f = Infinity; + E6[E6['f'] = f] = 'f'; + const g = -Infinity; + E6[E6['g'] = g] = 'g'; + return E6; +})(E6 || {}); ``` # typescript/tests/cases/conformance/enums/enumErrorOnConstantBindingWithInitializer.ts ```typescript const {value='123'} = thing; +var E = (E => { + const test = value; + E[E['test'] = test] = 'test'; + return E; +})(E || {}); ``` @@ -78,6 +493,21 @@ const {value='123'} = thing; # typescript/tests/cases/conformance/enums/enumExportMergingES6.ts ```typescript +export var Animals = (Animals => { + const Cat = 1; + Animals[Animals['Cat'] = Cat] = 'Cat'; + return Animals; +})(Animals || {}); +export var Animals = (Animals => { + const Dog = 2; + Animals[Animals['Dog'] = Dog] = 'Dog'; + return Animals; +})(Animals || {}); +export var Animals = (Animals => { + const CatDog = Cat | Dog; + Animals[Animals['CatDog'] = CatDog] = 'CatDog'; + return Animals; +})(Animals || {}); ``` @@ -85,29 +515,131 @@ const {value='123'} = thing; ```typescript let M1; (function(_M1) { + var EImpl1 = (EImpl1 => { + const A = 0; + EImpl1[EImpl1['A'] = A] = 'A'; + const B = 1 + A; + EImpl1[EImpl1['B'] = B] = 'B'; + const C = 1 + B; + EImpl1[EImpl1['C'] = C] = 'C'; + return EImpl1; + })(EImpl1 || {}); + var EImpl1 = (EImpl1 => { + const D = 1; + EImpl1[EImpl1['D'] = D] = 'D'; + const E = 1 + D; + EImpl1[EImpl1['E'] = E] = 'E'; + const F = 1 + E; + EImpl1[EImpl1['F'] = F] = 'F'; + return EImpl1; + })(EImpl1 || {}); +export var EConst1 = (EConst1 => { + const A = 3; + EConst1[EConst1['A'] = A] = 'A'; + const B = 2; + EConst1[EConst1['B'] = B] = 'B'; + const C = 1; + EConst1[EConst1['C'] = C] = 'C'; + return EConst1; + })(EConst1 || {}); +export var EConst1 = (EConst1 => { + const D = 7; + EConst1[EConst1['D'] = D] = 'D'; + const E = 9; + EConst1[EConst1['E'] = E] = 'E'; + const F = 8; + EConst1[EConst1['F'] = F] = 'F'; + return EConst1; + })(EConst1 || {}); var x = [EConst1.A, EConst1.B, EConst1.C, EConst1.D, EConst1.E, EConst1.F]; })(M1 || (M1 = {})); let M2; (function(_M2) { +export var EComp2 = (EComp2 => { + const A = 'foo'.length; + EComp2[EComp2['A'] = A] = 'A'; + const B = 'foo'.length; + EComp2[EComp2['B'] = B] = 'B'; + const C = 'foo'.length; + EComp2[EComp2['C'] = C] = 'C'; + return EComp2; + })(EComp2 || {}); +export var EComp2 = (EComp2 => { + const D = 'foo'.length; + EComp2[EComp2['D'] = D] = 'D'; + const E = 'foo'.length; + EComp2[EComp2['E'] = E] = 'E'; + const F = 'foo'.length; + EComp2[EComp2['F'] = F] = 'F'; + return EComp2; + })(EComp2 || {}); var x = [EComp2.A, EComp2.B, EComp2.C, EComp2.D, EComp2.E, EComp2.F]; })(M2 || (M2 = {})); let M3; (function(_M3) { + var EInit = (EInit => { + const A = 0; + EInit[EInit['A'] = A] = 'A'; + const B = 1 + A; + EInit[EInit['B'] = B] = 'B'; + return EInit; + })(EInit || {}); + var EInit = (EInit => { + const C = 1; + EInit[EInit['C'] = C] = 'C'; + const D = 1 + C; + EInit[EInit['D'] = D] = 'D'; + const E = 1 + D; + EInit[EInit['E'] = E] = 'E'; + return EInit; + })(EInit || {}); })(M3 || (M3 = {})); let M4; (function(_M4) { +export var Color = (Color => { + const Red = 0; + Color[Color['Red'] = Red] = 'Red'; + const Green = 1 + Red; + Color[Color['Green'] = Green] = 'Green'; + const Blue = 1 + Green; + Color[Color['Blue'] = Blue] = 'Blue'; + return Color; + })(Color || {}); })(M4 || (M4 = {})); let M5; (function(_M5) { +export var Color = (Color => { + const Red = 0; + Color[Color['Red'] = Red] = 'Red'; + const Green = 1 + Red; + Color[Color['Green'] = Green] = 'Green'; + const Blue = 1 + Green; + Color[Color['Blue'] = Blue] = 'Blue'; + return Color; + })(Color || {}); })(M5 || (M5 = {})); let M6; (function(_M6) { (function(_A) { +export var Color = (Color => { + const Red = 0; + Color[Color['Red'] = Red] = 'Red'; + const Green = 1 + Red; + Color[Color['Green'] = Green] = 'Green'; + const Blue = 1 + Green; + Color[Color['Blue'] = Blue] = 'Blue'; + return Color; + })(Color || {}); })(A || (A = {})); })(M6 || (M6 = {})); (function(_M62) { export let A; (function(_A) { +export var Color = (Color => { + const Yellow = 1; + Color[Color['Yellow'] = Yellow] = 'Yellow'; + return Color; + })(Color || {}); })(A || (A = {})); var t = A.Color.Yellow; t = A.Color.Red; @@ -119,24 +651,99 @@ export let A; ```typescript let M; (function(_M) { +export var E1 = (E1 => { + const A = 0; + E1[E1['A'] = A] = 'A'; + return E1; + })(E1 || {}); +export var E2 = (E2 => { + const C = 0; + E2[E2['C'] = C] = 'C'; + return E2; + })(E2 || {}); +export var E3 = (E3 => { + const A = 0; + E3[E3['A'] = A] = 'A'; + return E3; + })(E3 || {}); })(M || (M = {})); (function(_M2) { +export var E1 = (E1 => { + const B = 'foo'.length; + E1[E1['B'] = B] = 'B'; + return E1; + })(E1 || {}); +export var E2 = (E2 => { + const B = 'foo'.length; + E2[E2['B'] = B] = 'B'; + return E2; + })(E2 || {}); +export var E3 = (E3 => { + const C = 0; + E3[E3['C'] = C] = 'C'; + return E3; + })(E3 || {}); })(M || (M = {})); (function(_M3) { +export var E1 = (E1 => { + const C = 0; + E1[E1['C'] = C] = 'C'; + return E1; + })(E1 || {}); +export var E2 = (E2 => { + const A = 0; + E2[E2['A'] = A] = 'A'; + return E2; + })(E2 || {}); +export var E3 = (E3 => { + const B = 'foo'.length; + E3[E3['B'] = B] = 'B'; + return E3; + })(E3 || {}); })(M || (M = {})); let M1; (function(_M1) { +export var E1 = (E1 => { + const A = 0; + E1[E1['A'] = A] = 'A'; + return E1; + })(E1 || {}); })(M1 || (M1 = {})); (function(_M12) { +export var E1 = (E1 => { + const B = 0; + E1[E1['B'] = B] = 'B'; + return E1; + })(E1 || {}); })(M1 || (M1 = {})); (function(_M13) { +export var E1 = (E1 => { + const C = 0; + E1[E1['C'] = C] = 'C'; + return E1; + })(E1 || {}); })(M1 || (M1 = {})); let M2; (function(_M2) { +export var E1 = (E1 => { + const A = 0; + E1[E1['A'] = A] = 'A'; + return E1; + })(E1 || {}); })(M2 || (M2 = {})); (function(_M22) { +export var E1 = (E1 => { + const B = 0; + E1[E1['B'] = B] = 'B'; + return E1; + })(E1 || {}); })(M2 || (M2 = {})); (function(_M23) { +export var E1 = (E1 => { + const C = 0; + E1[E1['C'] = C] = 'C'; + return E1; + })(E1 || {}); })(M2 || (M2 = {})); ``` @@ -145,30 +752,99 @@ let M2; ```typescript { let Infinity = {}; + var En = (En => { + const X = Infinity; + En[En['X'] = X] = 'X'; + return En; + })(En || {}); } { let NaN = {}; + var En = (En => { + const X = NaN; + En[En['X'] = X] = 'X'; + return En; + })(En || {}); } ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/input.ts ```typescript +var E = (E => { + const A = true; + E[E['A'] = A] = 'A'; + return E; +})(E || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/const/input.ts ```typescript +var E = (E => { + return E; +})(E || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/input.ts ```typescript +var E = (E => { + const a = 0; + E[E['a'] = a] = 'a'; + const b = 1 | 2; + E[E['b'] = b] = 'b'; + const c = 1 & 3; + E[E['c'] = c] = 'c'; + const d = 4 >> 1; + E[E['d'] = d] = 'd'; + const e = 8 >>> 1; + E[E['e'] = e] = 'e'; + const f = 1 << 3; + E[E['f'] = f] = 'f'; + const g = 2 ^ 7; + E[E['g'] = g] = 'g'; + const h = 2 * 3; + E[E['h'] = h] = 'h'; + const i = 2 / 3; + E[E['i'] = i] = 'i'; + const j = 2 + 5; + E[E['j'] = j] = 'j'; + const k = 2 - 4; + E[E['k'] = k] = 'k'; + const l = 2.5 % 2; + E[E['l'] = l] = 'l'; + const m = 2 ** 33; + E[E['m'] = m] = 'm'; + const n = +9; + E[E['n'] = n] = 'n'; + const o = -1; + E[E['o'] = o] = 'o'; + const p = ~2; + E[E['p'] = p] = 'p'; + const q = 1 + 2 - 3 * 4 / -5; + E[E['q'] = q] = 'q'; + const r = 1 + q; + E[E['r'] = r] = 'r'; + return E; +})(E || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/enum-merging-inner-references/input.ts ```typescript +var Animals = (Animals => { + const Cat = 1; + Animals[Animals['Cat'] = Cat] = 'Cat'; + const Dog = 2; + Animals[Animals['Dog'] = Dog] = 'Dog'; + return Animals; +})(Animals || {}); +var Animals = (Animals => { + const CatDog = Cat - Dog; + Animals[Animals['CatDog'] = CatDog] = 'CatDog'; + return Animals; +})(Animals || {}); ``` @@ -176,64 +852,211 @@ let M2; ```typescript const Cat = 10; const Dog = 20; +var Animals = (Animals => { + const Cat = 1; + Animals[Animals['Cat'] = Cat] = 'Cat'; + return Animals; +})(Animals || {}); +var Animals = (Animals => { + const Dog = 2; + Animals[Animals['Dog'] = Dog] = 'Dog'; + return Animals; +})(Animals || {}); +var Animals = (Animals => { + const CatDog = Cat | Dog; + Animals[Animals['CatDog'] = CatDog] = 'CatDog'; + return Animals; +})(Animals || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/export/input.ts ```typescript +export var E = (E => { + const A = 1; + E[E['A'] = A] = 'A'; + return E; +})(E || {}); +export var E = (E => { + const B = 2; + E[E['B'] = B] = 'B'; + return E; +})(E || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/input.ts ```typescript +var E = (E => { + const x = 0; + E[E['x'] = x] = 'x'; + const y = 1 + x; + E[E['y'] = y] = 'y'; + return E; +})(E || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/input.ts ```typescript +var E = (E => { + const a = 10; + E[E['a'] = a] = 'a'; + const b = a; + E[E['b'] = b] = 'b'; + return E; +})(E || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/mix-references/input.ts ```typescript var x = 10; +var Foo = (Foo => { + const a = 10; + Foo[Foo['a'] = a] = 'a'; + const b = a; + Foo[Foo['b'] = b] = 'b'; + const c = b + x; + Foo[Foo['c'] = c] = 'c'; + return Foo; +})(Foo || {}); +var Bar = (Bar => { + const D = Foo.a; + Bar[Bar['D'] = D] = 'D'; + const E = D; + Bar[Bar['E'] = E] = 'E'; + const F = Math.E; + Bar[Bar['F'] = F] = 'F'; + const G = E + Foo.c; + Bar[Bar['G'] = G] = 'G'; + return Bar; +})(Bar || {}); +var Baz = (Baz => { + const a = 0; + Baz[Baz['a'] = a] = 'a'; + const b = 1; + Baz[Baz['b'] = b] = 'b'; + const x = a.toString(); + Baz[Baz['x'] = x] = 'x'; + return Baz; +})(Baz || {}); +var A = (A => { + const a = 0; + A[A['a'] = a] = 'a'; + const b = (() => { + let a = 1; + return a + 1; + })(); + A[A['b'] = b] = 'b'; + const c = (() => { + return a + 2; + })(); + A[A['c'] = c] = 'c'; + return A; +})(A || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/input.ts ```typescript +var E = (E => { + const a = Math.sin(1); + E[E['a'] = a] = 'a'; + const b = 1 + a; + E[E['b'] = b] = 'b'; + return E; +})(E || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/input.ts ```typescript +var E = (E => { + const x = 1; + E[E['x'] = x] = 'x'; + const y = 2; + E[E['y'] = y] = 'y'; + return E; +})(E || {}); +var E = (E => { + const z = 3; + E[E['z'] = z] = 'z'; + return E; +})(E || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/input.ts ```typescript +var socketType = (socketType => { + const SOCKET = 0; + socketType[socketType['SOCKET'] = SOCKET] = 'SOCKET'; + const SERVER = 1 + SOCKET; + socketType[socketType['SERVER'] = SERVER] = 'SERVER'; + const IPC = 1 + SERVER; + socketType[socketType['IPC'] = IPC] = 'IPC'; + return socketType; +})(socketType || {}); +var constants = (constants => { + const SOCKET = socketType.SOCKET; + constants[constants['SOCKET'] = SOCKET] = 'SOCKET'; + const SERVER = socketType.SERVER; + constants[constants['SERVER'] = SERVER] = 'SERVER'; + const IPC = socketType.IPC; + constants[constants['IPC'] = IPC] = 'IPC'; + const UV_READABLE = 1 + IPC; + constants[constants['UV_READABLE'] = UV_READABLE] = 'UV_READABLE'; + const UV_WRITABLE = 1 + UV_READABLE; + constants[constants['UV_WRITABLE'] = UV_WRITABLE] = 'UV_WRITABLE'; + return constants; +})(constants || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/scoped/input.ts ```typescript { + var E = (E => { + return E; + })(E || {}); } ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value/input.ts ```typescript +var E = (E => { + const A = 0; + E[E['A'] = A] = 'A'; + const B = ''; + E['B'] = B; + const A2 = A; + E[E['A2'] = A2] = 'A2'; + const B2 = B; + E[E['B2'] = B2] = 'B2'; + return E; +})(E || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value-template/input.ts ```typescript +var E = (E => { + const A = `Hey`; + E['A'] = A; + return E; +})(E || {}); ``` # babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/input.ts ```typescript +var E = (E => { + const A = 'HALLO' + 'WERLD'; + E[E['A'] = A] = 'A'; + return E; +})(E || {}); ``` @@ -241,8 +1064,28 @@ var x = 10; ```typescript const BaseValue = 10; const Prefix = '/data'; +var Values = (Values => { + const First = BaseValue; + Values[Values['First'] = First] = 'First'; + const Second = 1 + First; + Values[Values['Second'] = Second] = 'Second'; + const Third = 1 + Second; + Values[Values['Third'] = Third] = 'Third'; + return Values; +})(Values || {}); const xxx = 100 + Values.First; const yyy = xxx; +var Routes = (Routes => { + const Parts = `${Prefix}/parts`; + Routes['Parts'] = Parts; + const Invoices = `${Prefix}/invoices`; + Routes['Invoices'] = Invoices; + const x = `${Values.First}/x`; + Routes['x'] = x; + const y = `${yyy}/y`; + Routes['y'] = y; + return Routes; +})(Routes || {}); ```