feat(transform): TypeScript Enum (#1173)

This commit is contained in:
magic-akari 2023-11-28 10:33:01 +08:00 committed by GitHub
parent cda0b97ade
commit 92c1d9d527
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1258 additions and 23 deletions

1
Cargo.lock generated
View file

@ -1922,6 +1922,7 @@ dependencies = [
"oxc_span", "oxc_span",
"oxc_syntax", "oxc_syntax",
"phf", "phf",
"rustc-hash",
"serde", "serde",
] ]

View file

@ -90,6 +90,17 @@ impl<'a> AstBuilder<'a> {
mem::replace(target, dummy) mem::replace(target, dummy)
} }
pub fn move_declaration(&self, decl: &mut Declaration<'a>) -> Declaration<'a> {
let empty_decl = self.variable_declaration(
Span::default(),
VariableDeclarationKind::Var,
self.new_vec(),
Modifiers::empty(),
);
let empty_decl = Declaration::VariableDeclaration(empty_decl);
mem::replace(decl, empty_decl)
}
pub fn program( pub fn program(
&self, &self,
span: Span, span: Span,

View file

@ -966,6 +966,10 @@ pub trait VisitMut<'a>: Sized {
} }
fn visit_declaration(&mut self, decl: &mut Declaration<'a>) { fn visit_declaration(&mut self, decl: &mut Declaration<'a>) {
self.visit_declaration_match(decl);
}
fn visit_declaration_match(&mut self, decl: &mut Declaration<'a>) {
match decl { match decl {
Declaration::VariableDeclaration(decl) => self.visit_variable_declaration(decl), Declaration::VariableDeclaration(decl) => self.visit_variable_declaration(decl),
Declaration::FunctionDeclaration(func) => self.visit_function(func), Declaration::FunctionDeclaration(func) => self.visit_function(func),

View file

@ -25,6 +25,7 @@ oxc_allocator = { workspace = true }
oxc_syntax = { workspace = true } oxc_syntax = { workspace = true }
oxc_semantic = { workspace = true } oxc_semantic = { workspace = true }
oxc_diagnostics = { workspace = true } oxc_diagnostics = { workspace = true }
rustc-hash = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }

View file

@ -139,6 +139,16 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
self.es2016_exponentiation_operator.as_mut().map(|t| t.add_vars_to_statements(stmts)); self.es2016_exponentiation_operator.as_mut().map(|t| t.add_vars_to_statements(stmts));
} }
fn visit_statement(&mut self, stmt: &mut Statement<'a>) {
self.typescript.as_mut().map(|t| t.transform_statement(stmt));
self.visit_statement_match(stmt);
}
fn visit_declaration(&mut self, decl: &mut Declaration<'a>) {
self.visit_declaration_match(decl);
self.typescript.as_mut().map(|t| t.transform_declaration(decl));
}
fn visit_expression(&mut self, expr: &mut Expression<'a>) { fn visit_expression(&mut self, expr: &mut Expression<'a>) {
// self.typescript.as_mut().map(|t| t.transform_expression(expr)); // self.typescript.as_mut().map(|t| t.transform_expression(expr));
self.react_jsx.as_mut().map(|t| t.transform_expression(expr)); self.react_jsx.as_mut().map(|t| t.transform_expression(expr));

View file

@ -1,9 +1,14 @@
use oxc_allocator::Vec;
use oxc_ast::{ast::*, AstBuilder}; use oxc_ast::{ast::*, AstBuilder};
use oxc_span::{Atom, SPAN}; use oxc_span::{Atom, SPAN};
use oxc_syntax::{
operator::{AssignmentOperator, BinaryOperator, LogicalOperator},
NumberBase,
};
use rustc_hash::FxHashSet;
use std::{mem, rc::Rc};
use std::rc::Rc; use crate::{context::TransformerCtx, utils::is_valid_identifier};
use crate::context::TransformerCtx;
/// Transform TypeScript /// Transform TypeScript
/// ///
@ -15,6 +20,8 @@ pub struct TypeScript<'a> {
ast: Rc<AstBuilder<'a>>, ast: Rc<AstBuilder<'a>>,
ctx: TransformerCtx<'a>, ctx: TransformerCtx<'a>,
verbatim_module_syntax: bool, verbatim_module_syntax: bool,
export_name_set: FxHashSet<Atom>,
} }
impl<'a> TypeScript<'a> { impl<'a> TypeScript<'a> {
@ -23,7 +30,7 @@ impl<'a> TypeScript<'a> {
ctx: TransformerCtx<'a>, ctx: TransformerCtx<'a>,
verbatim_module_syntax: bool, verbatim_module_syntax: bool,
) -> Self { ) -> Self {
Self { ast, ctx, verbatim_module_syntax } Self { ast, ctx, verbatim_module_syntax, export_name_set: FxHashSet::default() }
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
@ -33,6 +40,132 @@ 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_declaration(&mut self, decl: &mut Declaration<'a>) {
let Declaration::TSEnumDeclaration(ts_enum_declaration) = decl else {
return;
};
if ts_enum_declaration.modifiers.contains(ModifierKind::Declare) {
return;
}
let span = ts_enum_declaration.span;
let ident = ts_enum_declaration.id.clone();
let kind = self.ast.binding_pattern_identifier(ident);
let id = self.ast.binding_pattern(kind, None, false);
let mut params = self.ast.new_vec();
// ((Foo) => {
params.push(self.ast.formal_parameter(SPAN, id, None, false, self.ast.new_vec()));
let params = self.ast.formal_parameters(
SPAN,
FormalParameterKind::ArrowFormalParameters,
params,
None,
);
// Foo[Foo["X"] = 0] = "X";
let enum_name = ts_enum_declaration.id.name.clone();
let statements =
self.transform_ts_enum_members(&mut ts_enum_declaration.body.members, &enum_name);
let body =
self.ast.function_body(ts_enum_declaration.body.span, self.ast.new_vec(), statements);
let callee = self.ast.arrow_expression(SPAN, false, false, false, params, body, None, None);
// })(Foo || {});
let mut arguments = self.ast.new_vec();
let op = LogicalOperator::Or;
let left = self
.ast
.identifier_reference_expression(IdentifierReference::new(SPAN, enum_name.clone()));
let right = self.ast.object_expression(SPAN, self.ast.new_vec(), None);
let expression = self.ast.logical_expression(SPAN, left, op, right);
arguments.push(Argument::Expression(expression));
let call_expression = self.ast.call_expression(SPAN, callee, arguments, false, None);
let kind = VariableDeclarationKind::Var;
let decls = {
let mut decls = self.ast.new_vec();
let binding_identifier = BindingIdentifier::new(SPAN, enum_name.clone());
let binding_pattern_kind = self.ast.binding_pattern_identifier(binding_identifier);
let binding = self.ast.binding_pattern(binding_pattern_kind, None, false);
let decl =
self.ast.variable_declarator(SPAN, kind, binding, Some(call_expression), false);
decls.push(decl);
decls
};
let variable_declaration =
self.ast.variable_declaration(span, kind, decls, Modifiers::empty());
*decl = Declaration::VariableDeclaration(variable_declaration);
}
/// Remove `export` from merged declaration.
/// We only preserve the first one.
/// for example:
/// ```TypeScript
/// export enum Foo {}
/// export enum Foo {}
/// ```
/// ```JavaScript
/// export enum Foo {}
/// enum Foo {}
/// ```
pub fn transform_statement(&mut self, stmt: &mut Statement<'a>) {
let Statement::ModuleDeclaration(module_decl) = stmt else {
return;
};
let ModuleDeclaration::ExportNamedDeclaration(export_decl) = &mut **module_decl else {
return;
};
let ExportNamedDeclaration {
declaration: Some(declaration),
source: None,
export_kind: ImportOrExportKind::Value,
..
} = &mut **export_decl
else {
return;
};
let id = match &declaration {
Declaration::TSEnumDeclaration(decl) => decl.id.name.clone(),
Declaration::TSModuleDeclaration(decl) => {
let TSModuleDeclarationName::Identifier(id) = &decl.id else {
return;
};
id.name.clone()
}
_ => return,
};
if self.export_name_set.insert(id) {
return;
}
*stmt = Statement::Declaration(self.ast.move_declaration(declaration));
}
/// * Remove the top level import / export statements that are types /// * Remove the top level import / export statements that are types
/// * Adds `export {}` if all import / export statements are removed, this is used to tell /// * Adds `export {}` if all import / export statements are removed, this is used to tell
/// downstream tools that this file is in ESM. /// downstream tools that this file is in ESM.
@ -142,3 +275,130 @@ impl<'a> TypeScript<'a> {
.unwrap_or_default() .unwrap_or_default()
} }
} }
impl<'a> TypeScript<'a> {
fn transform_ts_enum_members(
&self,
members: &mut Vec<'a, TSEnumMember<'a>>,
enum_name: &Atom,
) -> Vec<'a, Statement<'a>> {
let mut default_init = self.ast.literal_number_expression(NumberLiteral {
span: SPAN,
value: 0.0,
raw: "0",
base: NumberBase::Decimal,
});
let mut statements = self.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::NumberLiteral(..) => unreachable!(),
};
let mut init =
self.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.ast.identifier_reference_expression(IdentifierReference::new(
SPAN,
enum_name.clone(),
));
let expr = self
.ast
.literal_string_expression(StringLiteral::new(SPAN, member_name.clone()));
self.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.ast.identifier_reference_expression(ident.clone());
let init = mem::replace(&mut init, self.ast.identifier_reference_expression(ident));
let kind = VariableDeclarationKind::Const;
let decls = {
let mut decls = self.ast.new_vec();
let binding_identifier = BindingIdentifier::new(SPAN, member_name.clone());
let binding_pattern_kind =
self.ast.binding_pattern_identifier(binding_identifier);
let binding = self.ast.binding_pattern(binding_pattern_kind, None, false);
let decl = self.ast.variable_declarator(SPAN, kind, binding, Some(init), false);
decls.push(decl);
decls
};
let decl = self.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.ast.identifier_reference_expression(IdentifierReference::new(
SPAN,
enum_name.clone(),
));
let expr = self
.ast
.literal_string_expression(StringLiteral::new(SPAN, member_name.clone()));
self.ast.computed_member(SPAN, obj, expr, false)
};
let left = AssignmentTarget::SimpleAssignmentTarget(
self.ast.simple_assignment_target_member_expression(member_expr),
);
let mut expr =
self.ast.assignment_expression(SPAN, AssignmentOperator::Assign, left, init);
// Foo[Foo["x"] = init] = "x"
if !is_str {
let member_expr = {
let obj = self.ast.identifier_reference_expression(IdentifierReference::new(
SPAN,
enum_name.clone(),
));
self.ast.computed_member(SPAN, obj, expr, false)
};
let left = AssignmentTarget::SimpleAssignmentTarget(
self.ast.simple_assignment_target_member_expression(member_expr),
);
let right = self
.ast
.literal_string_expression(StringLiteral::new(SPAN, member_name.clone()));
expr =
self.ast.assignment_expression(SPAN, AssignmentOperator::Assign, left, right);
}
statements.push(self.ast.expression_statement(member.span, expr));
// 1 + Foo["x"]
default_init = {
let one = self.ast.literal_number_expression(NumberLiteral {
span: SPAN,
value: 1.0,
raw: "1",
base: NumberBase::Decimal,
});
self.ast.binary_expression(SPAN, one, BinaryOperator::Addition, self_ref)
};
}
let enum_ref = self
.ast
.identifier_reference_expression(IdentifierReference::new(SPAN, enum_name.clone()));
// return Foo;
let return_stmt = self.ast.return_statement(SPAN, Some(enum_ref));
statements.push(return_stmt);
statements
}
}

View file

@ -1,4 +1,4 @@
Passed: 269/1081 Passed: 269/1066
# All Passed: # All Passed:
* babel-plugin-transform-numeric-separator * babel-plugin-transform-numeric-separator
@ -740,7 +740,7 @@ Passed: 269/1081
* loose/ignoreToPrimitiveHint/input.js * loose/ignoreToPrimitiveHint/input.js
* loose/mutableTemplateObject/input.js * loose/mutableTemplateObject/input.js
# babel-plugin-transform-typescript (66/168) # babel-plugin-transform-typescript (66/153)
* class/abstract-class-decorated/input.ts * class/abstract-class-decorated/input.ts
* class/abstract-class-decorated-method/input.ts * class/abstract-class-decorated-method/input.ts
* class/abstract-class-decorated-parameter/input.ts * class/abstract-class-decorated-parameter/input.ts
@ -759,21 +759,6 @@ Passed: 269/1081
* declarations/erased/input.ts * declarations/erased/input.ts
* declarations/export-declare-enum/input.ts * declarations/export-declare-enum/input.ts
* declarations/nested-namespace/input.mjs * declarations/nested-namespace/input.mjs
* enum/boolean-value/input.ts
* enum/const/input.ts
* enum/constant-folding/input.ts
* enum/export/input.ts
* enum/inferred/input.ts
* enum/inner-references/input.ts
* enum/mix-references/input.ts
* enum/non-foldable-constant/input.ts
* enum/non-scoped/input.ts
* enum/outer-references/input.ts
* enum/scoped/input.ts
* enum/string-value/input.ts
* enum/string-value-template/input.ts
* enum/string-values-computed/input.ts
* enum/ts5.0-const-foldable/input.ts
* exports/declared-types/input.ts * exports/declared-types/input.ts
* exports/export-const-enums/input.ts * exports/export-const-enums/input.ts
* exports/export-type-star-from/input.ts * exports/export-type-star-from/input.ts

View file

@ -17,7 +17,7 @@ fn test() {
TestRunner::new(TestRunnerOptions::default()).run(); TestRunner::new(TestRunnerOptions::default()).run();
} }
#[derive(Default)] #[derive(Default, Clone)]
pub struct TestRunnerOptions { pub struct TestRunnerOptions {
pub filter: Option<String>, pub filter: Option<String>,
pub exec: bool, pub exec: bool,
@ -86,6 +86,8 @@ const CASES: &[&str] = &[
"babel-plugin-transform-react-jsx", "babel-plugin-transform-react-jsx",
]; ];
const EXCLUDE_TESTS: &[&str] = &["babel-plugin-transform-typescript/test/fixtures/enum"];
const CONFORMANCE_SNAPSHOT: &str = "babel.snap.md"; const CONFORMANCE_SNAPSHOT: &str = "babel.snap.md";
const EXEC_SNAPSHOT: &str = "babel_exec.snap.md"; const EXEC_SNAPSHOT: &str = "babel_exec.snap.md";
@ -142,6 +144,10 @@ impl TestRunner {
} }
} }
if EXCLUDE_TESTS.iter().any(|p| path.to_string_lossy().contains(p)) {
return None;
}
let test_case = TestCaseKind::from_path(path); let test_case = TestCaseKind::from_path(path);
if let Some(test_case) = test_case { if let Some(test_case) = test_case {
if test_case.skip_test_case() { if test_case.skip_test_case() {

View file

@ -1,3 +1,5 @@
mod ts_fixtures;
#[cfg(not(target_env = "msvc"))] #[cfg(not(target_env = "msvc"))]
#[global_allocator] #[global_allocator]
static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc; static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;
@ -8,6 +10,7 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
use oxc_transform_conformance::{TestRunner, TestRunnerOptions}; use oxc_transform_conformance::{TestRunner, TestRunnerOptions};
use pico_args::Arguments; use pico_args::Arguments;
use ts_fixtures::TypeScriptFixtures;
fn main() { fn main() {
let mut args = Arguments::from_env(); let mut args = Arguments::from_env();
@ -17,5 +20,6 @@ fn main() {
exec: args.contains("--exec"), exec: args.contains("--exec"),
}; };
TestRunner::new(options).run(); TestRunner::new(options.clone()).run();
TypeScriptFixtures::new(options).run();
} }

View file

@ -0,0 +1,130 @@
use std::{
fs::{self},
path::{Path, PathBuf},
};
use walkdir::WalkDir;
use oxc_allocator::Allocator;
use oxc_codegen::{Codegen, CodegenOptions};
use oxc_diagnostics::miette::{GraphicalReportHandler, GraphicalTheme, NamedSource};
use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use oxc_span::SourceType;
use oxc_tasks_common::{normalize_path, project_root};
use oxc_transform_conformance::TestRunnerOptions;
use oxc_transformer::{TransformOptions, Transformer};
fn root() -> PathBuf {
project_root().join("tasks/coverage")
}
fn snap_root() -> PathBuf {
project_root().join("tasks/transform_conformance")
}
const CASES: &[&str] = &[
"typescript/tests/cases/conformance/enums",
"babel/packages/babel-plugin-transform-typescript/test/fixtures/enum",
];
const CONFORMANCE_SNAPSHOT: &str = "typescript.snap.md";
fn filter_ext(p: &Path) -> bool {
p.to_string_lossy().ends_with(".ts")
}
pub struct TypeScriptFixtures {
options: TestRunnerOptions,
}
impl TypeScriptFixtures {
pub fn new(options: TestRunnerOptions) -> Self {
Self { options }
}
pub fn run(self) {
let mut snapshot = String::new();
for case in CASES {
for path in Self::glob_files(&root().join(case), self.options.filter.as_ref()) {
snapshot.push_str("# ");
snapshot.push_str(&normalize_path(path.strip_prefix(&root()).unwrap()));
snapshot.push('\n');
snapshot.push_str("```");
let (content, lang) = match Self::transform(&path) {
Ok(content) => (content, "typescript"),
Err(err) => (err, "error"),
};
snapshot.push_str(lang);
snapshot.push('\n');
snapshot.push_str(&content);
snapshot.push_str("\n```\n\n");
}
}
fs::write(snap_root().join(CONFORMANCE_SNAPSHOT), snapshot).unwrap();
}
}
impl TypeScriptFixtures {
fn transform_options() -> TransformOptions {
// TODO: read options from slash directives
TransformOptions::default()
}
fn glob_files(root: &Path, filter: Option<&String>) -> Vec<PathBuf> {
let mut list: Vec<PathBuf> = WalkDir::new(root)
.into_iter()
.filter_map(Result::ok)
.map(walkdir::DirEntry::into_path)
.filter(|p| p.is_file())
.filter(|p| filter_ext(p.as_path()))
.filter(|p| filter.map_or(true, |f| p.to_string_lossy().contains(f)))
.collect();
list.sort_unstable();
list
}
fn transform(path: &Path) -> Result<String, String> {
let allocator = Allocator::default();
let source_text = fs::read_to_string(path).unwrap();
let source_type = SourceType::from_path(path).unwrap();
let parser_ret = Parser::new(&allocator, &source_text, source_type).parse();
let semantic_ret = SemanticBuilder::new(&source_text, source_type)
.with_trivias(parser_ret.trivias)
.with_check_syntax_error(true)
.build(&parser_ret.program);
let errors = parser_ret.errors.into_iter().chain(semantic_ret.errors).collect::<Vec<_>>();
if !errors.is_empty() {
let handler = GraphicalReportHandler::new_themed(GraphicalTheme::unicode_nocolor());
let mut output = String::new();
for error in errors {
let error = error.with_source_code(NamedSource::new(
&normalize_path(path.strip_prefix(&root()).unwrap()),
source_text.to_string(),
));
handler.render_report(&mut output, error.as_ref()).unwrap();
output.push('\n');
}
return Err(output);
}
let semantic = semantic_ret.semantic;
let transformed_program = allocator.alloc(parser_ret.program);
let result = Transformer::new(&allocator, source_type, semantic, Self::transform_options())
.build(transformed_program);
result
.map(|()| {
Codegen::<false>::new(source_text.len(), CodegenOptions).build(transformed_program)
})
.map_err(|e| e.iter().map(ToString::to_string).collect())
}
}

View file

@ -0,0 +1,823 @@
# typescript/tests/cases/conformance/enums/awaitAndYield.ts
```error
× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/conformance/enums/awaitAndYield.ts:4:1]
4 │ enum E {
5 │ foo = await x,
· ─────
6 │ baz = yield 1,
╰────
```
# 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];
```
# 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:value='123'} = thing;
var E = (E => {
const test = value;
E[E['test'] = test] = 'test';
return E;
})(E || {});
```
# typescript/tests/cases/conformance/enums/enumErrors.ts
```error
× Expected `,` but found `;`
╭─[typescript/tests/cases/conformance/enums/enumErrors.ts:47:1]
47 │
48 │ postSemicolon;
· ┬
· ╰── `,` expected
49 │ postColonValueComma: 2,
╰────
```
# typescript/tests/cases/conformance/enums/enumExportMergingES6.ts
```typescript
export 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 || {});
```
# typescript/tests/cases/conformance/enums/enumMerging.ts
```typescript
```
# typescript/tests/cases/conformance/enums/enumMergingErrors.ts
```typescript
```
# typescript/tests/cases/conformance/enums/enumShadowedInfinityNaN.ts
```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/export/input.ts
```typescript
export var E = (E => {
const A = 1;
E[E['A'] = A] = 'A';
return E;
})(E || {});
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 || {});
```
# babel/packages/babel-plugin-transform-typescript/test/fixtures/enum/ts5.0-const-foldable/input.ts
```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 || {});
```