mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
feat(transformer): transform TypeScript namespace (#2942)
This commit is contained in:
parent
c250b288ef
commit
0c04bf743f
9 changed files with 325 additions and 13 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1737,6 +1737,8 @@ dependencies = [
|
||||||
"oxc_parser",
|
"oxc_parser",
|
||||||
"oxc_semantic",
|
"oxc_semantic",
|
||||||
"oxc_span",
|
"oxc_span",
|
||||||
|
"oxc_syntax",
|
||||||
|
"rustc-hash",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -822,6 +822,14 @@ impl<'a> AstBuilder<'a> {
|
||||||
self.alloc(FormalParameters { span, kind, items, rest })
|
self.alloc(FormalParameters { span, kind, items, rest })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn plain_formal_parameter(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
pattern: BindingPattern<'a>,
|
||||||
|
) -> FormalParameter<'a> {
|
||||||
|
self.formal_parameter(span, pattern, None, false, false, self.new_vec())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn formal_parameter(
|
pub fn formal_parameter(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -843,6 +851,29 @@ impl<'a> AstBuilder<'a> {
|
||||||
TSThisParameter { span, this, type_annotation }
|
TSThisParameter { span, this, type_annotation }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn plain_function(
|
||||||
|
&self,
|
||||||
|
r#type: FunctionType,
|
||||||
|
span: Span,
|
||||||
|
id: Option<BindingIdentifier<'a>>,
|
||||||
|
params: Box<'a, FormalParameters<'a>>,
|
||||||
|
body: Option<Box<'a, FunctionBody<'a>>>,
|
||||||
|
) -> Box<'a, Function<'a>> {
|
||||||
|
self.function(
|
||||||
|
r#type,
|
||||||
|
span,
|
||||||
|
id,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
params,
|
||||||
|
body,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Modifiers::empty(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn function(
|
pub fn function(
|
||||||
&self,
|
&self,
|
||||||
r#type: FunctionType,
|
r#type: FunctionType,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ oxc_span = { workspace = true }
|
||||||
oxc_allocator = { workspace = true }
|
oxc_allocator = { workspace = true }
|
||||||
oxc_semantic = { workspace = true }
|
oxc_semantic = { workspace = true }
|
||||||
oxc_diagnostics = { workspace = true }
|
oxc_diagnostics = { workspace = true }
|
||||||
|
oxc_syntax = { workspace = true }
|
||||||
|
|
||||||
|
rustc-hash = { workspace = true }
|
||||||
|
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ impl<'a> TransformCtx<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an Error
|
/// Add an Error
|
||||||
#[allow(unused)]
|
|
||||||
pub fn error<T: Into<Error>>(&self, error: T) {
|
pub fn error<T: Into<Error>>(&self, error: T) {
|
||||||
self.errors.borrow_mut().push(error.into());
|
self.errors.borrow_mut().push(error.into());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ mod typescript;
|
||||||
|
|
||||||
use std::{path::Path, rc::Rc};
|
use std::{path::Path, rc::Rc};
|
||||||
|
|
||||||
use oxc_allocator::Allocator;
|
use oxc_allocator::{Allocator, Vec};
|
||||||
use oxc_ast::{
|
use oxc_ast::{
|
||||||
ast::*,
|
ast::*,
|
||||||
visit::{walk_mut, VisitMut},
|
visit::{walk_mut, VisitMut},
|
||||||
|
|
@ -81,7 +81,7 @@ impl<'a> Transformer<'a> {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns `Vec<Error>` if any errors were collected during the transformation.
|
/// Returns `Vec<Error>` if any errors were collected during the transformation.
|
||||||
pub fn build(mut self, program: &mut Program<'a>) -> Result<(), Vec<Error>> {
|
pub fn build(mut self, program: &mut Program<'a>) -> Result<(), std::vec::Vec<Error>> {
|
||||||
self.visit_program(program);
|
self.visit_program(program);
|
||||||
let errors = self.ctx.take_errors();
|
let errors = self.ctx.take_errors();
|
||||||
if errors.is_empty() {
|
if errors.is_empty() {
|
||||||
|
|
@ -93,8 +93,12 @@ impl<'a> Transformer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VisitMut<'a> for Transformer<'a> {
|
impl<'a> VisitMut<'a> for Transformer<'a> {
|
||||||
|
fn visit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||||
|
self.x0_typescript.transform_statements(stmts);
|
||||||
|
walk_mut::walk_statements_mut(self, stmts);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_statement(&mut self, stmt: &mut Statement<'a>) {
|
fn visit_statement(&mut self, stmt: &mut Statement<'a>) {
|
||||||
self.x0_typescript.transform_statement(stmt);
|
|
||||||
self.x2_decorators.transform_statement(stmt);
|
self.x2_decorators.transform_statement(stmt);
|
||||||
walk_mut::walk_statement_mut(self, stmt);
|
walk_mut::walk_statement_mut(self, stmt);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
mod namespace;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use oxc_allocator::Vec;
|
||||||
use oxc_ast::ast::*;
|
use oxc_ast::ast::*;
|
||||||
|
|
||||||
use crate::context::Ctx;
|
use crate::context::Ctx;
|
||||||
|
|
@ -43,7 +46,9 @@ impl<'a> TypeScript<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transformers
|
// Transforms
|
||||||
impl<'a> TypeScript<'a> {
|
impl<'a> TypeScript<'a> {
|
||||||
pub fn transform_statement(&mut self, _stmt: &mut Statement<'a>) {}
|
pub fn transform_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||||
|
self.transform_statements_for_namespace(stmts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
223
crates/oxc_transformer/src/typescript/namespace.rs
Normal file
223
crates/oxc_transformer/src/typescript/namespace.rs
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
|
use super::TypeScript;
|
||||||
|
|
||||||
|
use oxc_allocator::{Box, Vec};
|
||||||
|
use oxc_ast::ast::*;
|
||||||
|
use oxc_span::{Atom, SPAN};
|
||||||
|
use oxc_syntax::operator::{AssignmentOperator, LogicalOperator};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct State<'a> {
|
||||||
|
/// Deduplicate the `let` declarations` for namespace concatenation.
|
||||||
|
/// `namespace foo {}; namespace {}` creates a single `let foo;`.
|
||||||
|
names: FxHashSet<Atom<'a>>,
|
||||||
|
|
||||||
|
/// Increment the argument name to avoid name clashes.
|
||||||
|
arg_names: FxHashMap<Atom<'a>, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_namespace(decl: &Declaration<'_>) -> bool {
|
||||||
|
matches!(decl, Declaration::TSModuleDeclaration(decl) if !decl.modifiers.is_contains_declare())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// 1. register scope for the newly created function: <https://github.com/babel/babel/blob/08b0472069cd207f043dd40a4d157addfdd36011/packages/babel-plugin-transform-typescript/src/namespace.ts#L38>
|
||||||
|
impl<'a> TypeScript<'a> {
|
||||||
|
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
|
||||||
|
pub(super) fn transform_statements_for_namespace(&self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||||
|
// Only do the transform if a namespace declaration is found.
|
||||||
|
if !stmts.iter().any(|stmt| match stmt {
|
||||||
|
Statement::Declaration(decl) => is_namespace(decl),
|
||||||
|
Statement::ModuleDeclaration(decl) => match &**decl {
|
||||||
|
ModuleDeclaration::ExportNamedDeclaration(decl) => {
|
||||||
|
decl.declaration.as_ref().is_some_and(is_namespace)
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recreate the statements vec for memory efficiency.
|
||||||
|
// Inserting the `let` declaration multiple times will reallocate the whole statements vec
|
||||||
|
// every time a namespace declaration is encountered.
|
||||||
|
let mut new_stmts = self.ctx.ast.new_vec();
|
||||||
|
|
||||||
|
let mut state = State::default();
|
||||||
|
|
||||||
|
for mut stmt in self.ctx.ast.move_statement_vec(stmts) {
|
||||||
|
if !self.transform_statement_for_namespace(&mut state, &mut new_stmts, &mut stmt) {
|
||||||
|
new_stmts.push(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*stmts = new_stmts;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform_statement_for_namespace(
|
||||||
|
&self,
|
||||||
|
state: &mut State<'a>,
|
||||||
|
new_stmts: &mut Vec<'a, Statement<'a>>,
|
||||||
|
stmt: &mut Statement<'a>,
|
||||||
|
) -> bool {
|
||||||
|
let mut is_export = false;
|
||||||
|
let ts_module_decl = match stmt {
|
||||||
|
Statement::Declaration(Declaration::TSModuleDeclaration(ts_module_decl)) => {
|
||||||
|
ts_module_decl
|
||||||
|
}
|
||||||
|
Statement::ModuleDeclaration(decl) => match &mut **decl {
|
||||||
|
ModuleDeclaration::ExportNamedDeclaration(decl) => {
|
||||||
|
if let Some(Declaration::TSModuleDeclaration(ts_module_decl)) =
|
||||||
|
decl.declaration.as_mut()
|
||||||
|
{
|
||||||
|
is_export = true;
|
||||||
|
ts_module_decl
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return false,
|
||||||
|
},
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ts_module_decl.modifiers.is_contains_declare() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = ts_module_decl.id.name().clone();
|
||||||
|
|
||||||
|
if state.names.insert(name.clone()) {
|
||||||
|
let stmt = self.create_variable_declaration_statement(&name, is_export);
|
||||||
|
new_stmts.push(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
let namespace = self.transform_namespace(state, ts_module_decl);
|
||||||
|
new_stmts.push(namespace);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
|
||||||
|
// ^^^^^^^
|
||||||
|
fn create_variable_declaration_statement(
|
||||||
|
&self,
|
||||||
|
name: &Atom<'a>,
|
||||||
|
is_export: bool,
|
||||||
|
) -> Statement<'a> {
|
||||||
|
let kind = VariableDeclarationKind::Let;
|
||||||
|
let declarators = {
|
||||||
|
let ident = BindingIdentifier::new(SPAN, name.clone());
|
||||||
|
let pattern_kind = self.ctx.ast.binding_pattern_identifier(ident);
|
||||||
|
let binding = self.ctx.ast.binding_pattern(pattern_kind, None, false);
|
||||||
|
let decl = self.ctx.ast.variable_declarator(SPAN, kind, binding, None, false);
|
||||||
|
self.ctx.ast.new_vec_single(decl)
|
||||||
|
};
|
||||||
|
let decl = Declaration::VariableDeclaration(self.ctx.ast.variable_declaration(
|
||||||
|
SPAN,
|
||||||
|
kind,
|
||||||
|
declarators,
|
||||||
|
Modifiers::empty(),
|
||||||
|
));
|
||||||
|
if is_export {
|
||||||
|
self.ctx.ast.module_declaration(ModuleDeclaration::ExportNamedDeclaration(
|
||||||
|
self.ctx.ast.export_named_declaration(
|
||||||
|
SPAN,
|
||||||
|
Some(decl),
|
||||||
|
self.ctx.ast.new_vec(),
|
||||||
|
None,
|
||||||
|
ImportOrExportKind::Value,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Statement::Declaration(decl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
fn transform_namespace(
|
||||||
|
&self,
|
||||||
|
state: &mut State<'a>,
|
||||||
|
block: &mut Box<'a, TSModuleDeclaration<'a>>,
|
||||||
|
) -> Statement<'a> {
|
||||||
|
let body_statements = match &mut block.body {
|
||||||
|
Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => {
|
||||||
|
let transformed_module_block = self.transform_namespace(state, decl);
|
||||||
|
self.ctx.ast.new_vec_single(transformed_module_block)
|
||||||
|
}
|
||||||
|
Some(TSModuleDeclarationBody::TSModuleBlock(ts_module_block)) => {
|
||||||
|
self.ctx.ast.move_statement_vec(&mut ts_module_block.body)
|
||||||
|
}
|
||||||
|
None => self.ctx.ast.new_vec(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let name = block.id.name();
|
||||||
|
|
||||||
|
// `(function (_N) { var x; })(N || (N = {}))`;
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
let callee = {
|
||||||
|
let body = self.ctx.ast.function_body(SPAN, self.ctx.ast.new_vec(), body_statements);
|
||||||
|
let arg_name = self.get_namespace_arg_name(state, name);
|
||||||
|
let params = {
|
||||||
|
let ident =
|
||||||
|
self.ctx.ast.binding_pattern_identifier(BindingIdentifier::new(SPAN, arg_name));
|
||||||
|
let pattern = self.ctx.ast.binding_pattern(ident, None, false);
|
||||||
|
let items =
|
||||||
|
self.ctx.ast.new_vec_single(self.ctx.ast.plain_formal_parameter(SPAN, pattern));
|
||||||
|
self.ctx.ast.formal_parameters(
|
||||||
|
SPAN,
|
||||||
|
FormalParameterKind::FormalParameter,
|
||||||
|
items,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let function = self.ctx.ast.plain_function(
|
||||||
|
FunctionType::FunctionExpression,
|
||||||
|
SPAN,
|
||||||
|
None,
|
||||||
|
params,
|
||||||
|
Some(body),
|
||||||
|
);
|
||||||
|
let function_expr = self.ctx.ast.function_expression(function);
|
||||||
|
self.ctx.ast.parenthesized_expression(SPAN, function_expr)
|
||||||
|
};
|
||||||
|
|
||||||
|
// `(function (_N) { var x; })(N || (N = {}))`;
|
||||||
|
// ^^^^^^^^^^^^^
|
||||||
|
let arguments = {
|
||||||
|
let logical_left = {
|
||||||
|
let ident = IdentifierReference::new(SPAN, name.clone());
|
||||||
|
self.ctx.ast.identifier_reference_expression(ident)
|
||||||
|
};
|
||||||
|
let logical_right = {
|
||||||
|
let assign_left = self.ctx.ast.simple_assignment_target_identifier(
|
||||||
|
IdentifierReference::new(SPAN, name.clone()),
|
||||||
|
);
|
||||||
|
let assign_right =
|
||||||
|
self.ctx.ast.object_expression(SPAN, self.ctx.ast.new_vec(), None);
|
||||||
|
let op = AssignmentOperator::Assign;
|
||||||
|
let assign_expr =
|
||||||
|
self.ctx.ast.assignment_expression(SPAN, op, assign_left, assign_right);
|
||||||
|
self.ctx.ast.parenthesized_expression(SPAN, assign_expr)
|
||||||
|
};
|
||||||
|
self.ctx.ast.new_vec_single(Argument::Expression(self.ctx.ast.logical_expression(
|
||||||
|
SPAN,
|
||||||
|
logical_left,
|
||||||
|
LogicalOperator::Or,
|
||||||
|
logical_right,
|
||||||
|
)))
|
||||||
|
};
|
||||||
|
let expr = self.ctx.ast.call_expression(SPAN, callee, arguments, false, None);
|
||||||
|
self.ctx.ast.expression_statement(SPAN, expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_namespace_arg_name(&self, state: &mut State<'a>, name: &Atom<'a>) -> Atom<'a> {
|
||||||
|
let count = state.arg_names.entry(name.clone()).or_insert(0);
|
||||||
|
*count += 1;
|
||||||
|
let name = if *count > 1 { format!("_{name}{count}") } else { format!("_{name}") };
|
||||||
|
self.ctx.ast.new_atom(&name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
Passed: 70/174
|
Passed: 75/174
|
||||||
|
|
||||||
# All Passed:
|
# All Passed:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# babel-plugin-transform-typescript (55/158)
|
# babel-plugin-transform-typescript (60/158)
|
||||||
* 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
|
||||||
|
|
@ -74,14 +74,10 @@ Passed: 70/174
|
||||||
* namespace/clobber-export/input.ts
|
* namespace/clobber-export/input.ts
|
||||||
* namespace/clobber-import/input.ts
|
* namespace/clobber-import/input.ts
|
||||||
* namespace/contentious-names/input.ts
|
* namespace/contentious-names/input.ts
|
||||||
* namespace/declare/input.ts
|
|
||||||
* namespace/declare-global-nested-namespace/input.ts
|
|
||||||
* namespace/empty-removed/input.ts
|
* namespace/empty-removed/input.ts
|
||||||
* namespace/export/input.ts
|
|
||||||
* namespace/export-type-only/input.ts
|
* namespace/export-type-only/input.ts
|
||||||
* namespace/module-nested/input.ts
|
* namespace/module-nested/input.ts
|
||||||
* namespace/module-nested-export/input.ts
|
* namespace/module-nested-export/input.ts
|
||||||
* namespace/multiple/input.ts
|
|
||||||
* namespace/mutable-fail/input.ts
|
* namespace/mutable-fail/input.ts
|
||||||
* namespace/namespace-flag/input.ts
|
* namespace/namespace-flag/input.ts
|
||||||
* namespace/namespace-nested-module/input.ts
|
* namespace/namespace-nested-module/input.ts
|
||||||
|
|
@ -91,7 +87,6 @@ Passed: 70/174
|
||||||
* namespace/nested-shorthand/input.ts
|
* namespace/nested-shorthand/input.ts
|
||||||
* namespace/nested-shorthand-export/input.ts
|
* namespace/nested-shorthand-export/input.ts
|
||||||
* namespace/same-name/input.ts
|
* namespace/same-name/input.ts
|
||||||
* namespace/undeclared/input.ts
|
|
||||||
* optimize-const-enums/custom-values/input.ts
|
* optimize-const-enums/custom-values/input.ts
|
||||||
* optimize-const-enums/custom-values-exported/input.ts
|
* optimize-const-enums/custom-values-exported/input.ts
|
||||||
* optimize-const-enums/declare/input.ts
|
* optimize-const-enums/declare/input.ts
|
||||||
|
|
|
||||||
|
|
@ -83,11 +83,61 @@ const {value='123'} = thing;
|
||||||
|
|
||||||
# typescript/tests/cases/conformance/enums/enumMerging.ts
|
# typescript/tests/cases/conformance/enums/enumMerging.ts
|
||||||
```typescript
|
```typescript
|
||||||
|
let M1;
|
||||||
|
(function(_M1) {
|
||||||
|
var x = [EConst1.A, EConst1.B, EConst1.C, EConst1.D, EConst1.E, EConst1.F];
|
||||||
|
})(M1 || (M1 = {}));
|
||||||
|
let M2;
|
||||||
|
(function(_M2) {
|
||||||
|
var x = [EComp2.A, EComp2.B, EComp2.C, EComp2.D, EComp2.E, EComp2.F];
|
||||||
|
})(M2 || (M2 = {}));
|
||||||
|
let M3;
|
||||||
|
(function(_M3) {
|
||||||
|
})(M3 || (M3 = {}));
|
||||||
|
let M4;
|
||||||
|
(function(_M4) {
|
||||||
|
})(M4 || (M4 = {}));
|
||||||
|
let M5;
|
||||||
|
(function(_M5) {
|
||||||
|
})(M5 || (M5 = {}));
|
||||||
|
let M6;
|
||||||
|
(function(_M6) {
|
||||||
|
(function(_A) {
|
||||||
|
})(A || (A = {}));
|
||||||
|
})(M6 || (M6 = {}));
|
||||||
|
(function(_M62) {
|
||||||
|
export let A;
|
||||||
|
(function(_A) {
|
||||||
|
})(A || (A = {}));
|
||||||
|
var t = A.Color.Yellow;
|
||||||
|
t = A.Color.Red;
|
||||||
|
})(M6 || (M6 = {}));
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# typescript/tests/cases/conformance/enums/enumMergingErrors.ts
|
# typescript/tests/cases/conformance/enums/enumMergingErrors.ts
|
||||||
```typescript
|
```typescript
|
||||||
|
let M;
|
||||||
|
(function(_M) {
|
||||||
|
})(M || (M = {}));
|
||||||
|
(function(_M2) {
|
||||||
|
})(M || (M = {}));
|
||||||
|
(function(_M3) {
|
||||||
|
})(M || (M = {}));
|
||||||
|
let M1;
|
||||||
|
(function(_M1) {
|
||||||
|
})(M1 || (M1 = {}));
|
||||||
|
(function(_M12) {
|
||||||
|
})(M1 || (M1 = {}));
|
||||||
|
(function(_M13) {
|
||||||
|
})(M1 || (M1 = {}));
|
||||||
|
let M2;
|
||||||
|
(function(_M2) {
|
||||||
|
})(M2 || (M2 = {}));
|
||||||
|
(function(_M22) {
|
||||||
|
})(M2 || (M2 = {}));
|
||||||
|
(function(_M23) {
|
||||||
|
})(M2 || (M2 = {}));
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue