Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2ba8f10
fix(1632): erase const enums after inlining
a-tarasyuk Aug 27, 2025
1050065
use GetIsolatedModules
a-tarasyuk Aug 27, 2025
d6d6d58
Merge branch 'main' into fix/1632
a-tarasyuk Aug 27, 2025
3e3384c
restore variable reference emission for module declarations
a-tarasyuk Aug 28, 2025
ac5a131
Merge branch 'fix/1632' of https://github.com/a-tarasyuk/typescript-g…
a-tarasyuk Aug 28, 2025
37d672b
treat NotEmittedStatement as EmptyStatement in EmbeddedStatement tran…
a-tarasyuk Aug 28, 2025
3eb7e8e
Merge branch 'main' of https://github.com/microsoft/typescript-go int…
a-tarasyuk Aug 28, 2025
046bd93
fix VisitIterationBody
a-tarasyuk Aug 28, 2025
946df75
Merge branch 'main' into fix/1632
a-tarasyuk Aug 28, 2025
5c2206c
Merge branch 'main' into fix/1632
a-tarasyuk Aug 29, 2025
f729313
Merge branch 'main' into fix/1632
a-tarasyuk Aug 29, 2025
3b65035
Merge branch 'main' into fix/1632
a-tarasyuk Aug 31, 2025
f6aa1df
Merge branch 'main' into fix/1632
a-tarasyuk Sep 2, 2025
d991f93
Merge branch 'main' into fix/1632
a-tarasyuk Sep 2, 2025
e281903
Merge branch 'main' into fix/1632
a-tarasyuk Sep 3, 2025
5b9e5a3
elide const enums in modules based on preserveConstEnums
a-tarasyuk Sep 3, 2025
bc345c6
Merge branch 'main' of https://github.com/microsoft/typescript-go int…
a-tarasyuk Sep 3, 2025
8e3cb00
Merge branch 'main' into fix/1632
a-tarasyuk Sep 4, 2025
60a9d1f
add NewNotEmittedStatement to EmitContext
a-tarasyuk Sep 4, 2025
c283cdb
Merge branch 'fix/1632' of https://github.com/a-tarasyuk/typescript-g…
a-tarasyuk Sep 4, 2025
c02f91e
preserve text/comment ranges on empty statements
a-tarasyuk Sep 10, 2025
82bf47e
Merge branch 'main' of https://github.com/microsoft/typescript-go int…
a-tarasyuk Sep 10, 2025
8e83902
Merge branch 'main' into fix/1632
a-tarasyuk Sep 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/core/compileroptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ func (options *CompilerOptions) GetResolveJsonModule() bool {
}

func (options *CompilerOptions) ShouldPreserveConstEnums() bool {
return options.PreserveConstEnums == TSTrue || options.IsolatedModules == TSTrue
return options.PreserveConstEnums == TSTrue || options.GetIsolatedModules()
}

func (options *CompilerOptions) GetAllowJS() bool {
Expand Down
26 changes: 25 additions & 1 deletion internal/printer/emitcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func (c *EmitContext) NewNodeVisitor(visit func(node *ast.Node) *ast.Node) *ast.
VisitFunctionBody: c.VisitFunctionBody,
VisitIterationBody: c.VisitIterationBody,
VisitTopLevelStatements: c.VisitVariableEnvironment,
VisitEmbeddedStatement: c.VisitEmbeddedStatement,
})
}

Expand Down Expand Up @@ -908,7 +909,7 @@ func (c *EmitContext) VisitIterationBody(body *ast.Statement, visitor *ast.NodeV
}

c.StartLexicalEnvironment()
updated := visitor.VisitEmbeddedStatement(body)
updated := c.VisitEmbeddedStatement(body, visitor)
if updated == nil {
panic("Expected visitor to return a statement.")
}
Expand All @@ -928,6 +929,21 @@ func (c *EmitContext) VisitIterationBody(body *ast.Statement, visitor *ast.NodeV
return updated
}

func (c *EmitContext) VisitEmbeddedStatement(node *ast.Statement, visitor *ast.NodeVisitor) *ast.Statement {
embeddedStatement := visitor.VisitEmbeddedStatement(node)
if embeddedStatement == nil {
return nil
}
if ast.IsNotEmittedStatement(embeddedStatement) {
emptyStatement := visitor.Factory.NewEmptyStatement()
emptyStatement.Loc = node.Loc
c.SetOriginal(emptyStatement, node)
c.AssignCommentRange(emptyStatement, node)
return emptyStatement
}
return embeddedStatement
}

func (c *EmitContext) SetSyntheticLeadingComments(node *ast.Node, comments []SynthesizedComment) *ast.Node {
c.emitNodes.Get(node).leadingComments = comments
return node
Expand Down Expand Up @@ -961,3 +977,11 @@ func (c *EmitContext) GetSyntheticTrailingComments(node *ast.Node) []Synthesized
}
return nil
}

func (c *EmitContext) NewNotEmittedStatement(node *ast.Node) *ast.Statement {
statement := c.Factory.NewNotEmittedStatement()
statement.Loc = node.Loc
c.SetOriginal(statement, node)
c.AssignCommentRange(statement, node)
return statement
}
23 changes: 22 additions & 1 deletion internal/transformers/tstransforms/runtimesyntax.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (tx *RuntimeSyntaxTransformer) pushScope(node *ast.Node) (savedCurrentScope
case ast.KindCaseBlock, ast.KindModuleBlock, ast.KindBlock:
tx.currentScope = node
tx.currentScopeFirstDeclarationsOfName = nil
case ast.KindFunctionDeclaration, ast.KindClassDeclaration, ast.KindEnumDeclaration, ast.KindModuleDeclaration, ast.KindVariableStatement:
case ast.KindFunctionDeclaration, ast.KindClassDeclaration, ast.KindVariableStatement:
tx.recordDeclarationInScope(node)
}
return savedCurrentScope, savedCurrentScopeFirstDeclarationsOfName
Expand Down Expand Up @@ -309,6 +309,10 @@ func (tx *RuntimeSyntaxTransformer) addVarForDeclaration(statements []*ast.State
}

func (tx *RuntimeSyntaxTransformer) visitEnumDeclaration(node *ast.EnumDeclaration) *ast.Node {
if !tx.shouldEmitEnumDeclaration(node) {
return tx.EmitContext().NewNotEmittedStatement(node.AsNode())
}

statements := []*ast.Statement{}

// If needed, we should emit a variable declaration for the enum:
Expand Down Expand Up @@ -553,6 +557,10 @@ func (tx *RuntimeSyntaxTransformer) transformEnumMember(
}

func (tx *RuntimeSyntaxTransformer) visitModuleDeclaration(node *ast.ModuleDeclaration) *ast.Node {
if !tx.shouldEmitModuleDeclaration(node) {
return tx.EmitContext().NewNotEmittedStatement(node.AsNode())
}

statements := []*ast.Statement{}

// If needed, we should emit a variable declaration for the module:
Expand Down Expand Up @@ -1130,6 +1138,19 @@ func (tx *RuntimeSyntaxTransformer) evaluateEntity(node *ast.Node, location *ast
return result
}

func (tx *RuntimeSyntaxTransformer) shouldEmitEnumDeclaration(node *ast.EnumDeclaration) bool {
return !ast.IsEnumConst(node.AsNode()) || tx.compilerOptions.ShouldPreserveConstEnums()
}

func (tx *RuntimeSyntaxTransformer) shouldEmitModuleDeclaration(node *ast.ModuleDeclaration) bool {
pn := tx.EmitContext().ParseNode(node.AsNode())
if pn == nil {
// If we can't find a parse tree node, assume the node is instantiated.
return true
}
return isInstantiatedModule(node.AsNode(), tx.compilerOptions.ShouldPreserveConstEnums())
}

func getInnermostModuleDeclarationFromDottedModule(moduleDeclaration *ast.ModuleDeclaration) *ast.ModuleDeclaration {
for moduleDeclaration.Body != nil && moduleDeclaration.Body.Kind == ast.KindModuleDeclaration {
moduleDeclaration = moduleDeclaration.Body.AsModuleDeclaration()
Expand Down
24 changes: 4 additions & 20 deletions internal/transformers/tstransforms/runtimesyntax_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,7 @@ var E;
E[E["B"] = 1] = "B";
})(E || (E = {}));`},

{title: "const enum", input: "const enum E {A, B}", output: `var E;
(function (E) {
E[E["A"] = 0] = "A";
E[E["B"] = 1] = "B";
})(E || (E = {}));`},
{title: "const enum", input: "const enum E {A, B}", output: ""},

{title: "merged enum", input: "enum E {A} enum E {B=A}", output: `var E;
(function (E) {
Expand Down Expand Up @@ -250,9 +246,7 @@ func TestNamespaceTransformer(t *testing.T) {
input string
output string
}{
{title: "empty namespace", input: "namespace N {}", output: `var N;
(function (N) {
})(N || (N = {}));`},
{title: "empty namespace", input: "namespace N {}", output: ``},

{title: "export var", input: "namespace N { export var x = 1; }", output: `var N;
(function (N) {
Expand Down Expand Up @@ -363,19 +357,9 @@ func TestNamespaceTransformer(t *testing.T) {
})(E = N.E || (N.E = {}));
})(N || (N = {}));`},

{title: "export namespace", input: "namespace N { export namespace N2 {} }", output: `var N;
(function (N) {
let N2;
(function (N2) {
})(N2 = N.N2 || (N.N2 = {}));
})(N || (N = {}));`},
{title: "export namespace", input: "namespace N { export namespace N2 {} }", output: ``},

{title: "nested namespace", input: "namespace N.N2 { }", output: `var N;
(function (N) {
let N2;
(function (N2) {
})(N2 = N.N2 || (N.N2 = {}));
})(N || (N = {}));`},
{title: "nested namespace", input: "namespace N.N2 { }", output: ``},

{title: "import=", input: "import X = Y.X;", output: `var X = Y.X;`},

Expand Down
11 changes: 7 additions & 4 deletions internal/transformers/tstransforms/typeeraser.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ func (tx *TypeEraserTransformer) popNode(grandparentNode *ast.Node) {
}

func (tx *TypeEraserTransformer) elide(node *ast.Statement) *ast.Statement {
statement := tx.Factory().NewNotEmittedStatement()
tx.EmitContext().SetOriginal(statement, node)
statement.Loc = node.Loc
return statement
return tx.EmitContext().NewNotEmittedStatement(node.AsNode())
}

func (tx *TypeEraserTransformer) visit(node *ast.Node) *ast.Node {
Expand Down Expand Up @@ -343,6 +340,12 @@ func (tx *TypeEraserTransformer) visit(node *ast.Node) *ast.Node {
}
return node

case ast.KindEnumDeclaration:
if ast.IsEnumConst(node) {
return node
}
return tx.Visitor().VisitEachChild(node)

default:
return tx.Visitor().VisitEachChild(node)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//// [tests/cases/compiler/constEnumInEmbeddedStatements.ts] ////

//// [constEnumInEmbeddedStatements.ts]
function t(x: number) {
if (x)
/* before E */ const enum E { A = 1 } /* after E */
}


//// [constEnumInEmbeddedStatements.js]
function t(x) {
if (x)
/* before E */ ; /* after E */
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//// [tests/cases/compiler/constEnumInEmbeddedStatements.ts] ////

=== constEnumInEmbeddedStatements.ts ===
function t(x: number) {
>t : Symbol(t, Decl(constEnumInEmbeddedStatements.ts, 0, 0))
>x : Symbol(x, Decl(constEnumInEmbeddedStatements.ts, 0, 11))

if (x)
>x : Symbol(x, Decl(constEnumInEmbeddedStatements.ts, 0, 11))

/* before E */ const enum E { A = 1 } /* after E */
>E : Symbol(E, Decl(constEnumInEmbeddedStatements.ts, 1, 10))
>A : Symbol(E.A, Decl(constEnumInEmbeddedStatements.ts, 2, 37))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//// [tests/cases/compiler/constEnumInEmbeddedStatements.ts] ////

=== constEnumInEmbeddedStatements.ts ===
function t(x: number) {
>t : (x: number) => void
>x : number

if (x)
>x : number

/* before E */ const enum E { A = 1 } /* after E */
>E : E
>A : E.A
>1 : 1
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//// [tests/cases/conformance/constEnums/constEnumInNamespace.ts] ////

//// [constEnumInNamespace.ts]
namespace N {
export const enum E { A = 0 }
}


//// [constEnumInNamespace.js]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//// [tests/cases/conformance/constEnums/constEnumInNamespace.ts] ////

=== constEnumInNamespace.ts ===
namespace N {
>N : Symbol(N, Decl(constEnumInNamespace.ts, 0, 0))

export const enum E { A = 0 }
>E : Symbol(E, Decl(constEnumInNamespace.ts, 0, 13))
>A : Symbol(E.A, Decl(constEnumInNamespace.ts, 1, 23))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//// [tests/cases/conformance/constEnums/constEnumInNamespace.ts] ////

=== constEnumInNamespace.ts ===
namespace N {
export const enum E { A = 0 }
>E : E
>A : E.A
>0 : 0
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//// [tests/cases/conformance/constEnums/constEnumInNamespace.ts] ////

//// [constEnumInNamespace.ts]
namespace N {
export const enum E { A = 0 }
}


//// [constEnumInNamespace.js]
var N;
(function (N) {
let E;
(function (E) {
E[E["A"] = 0] = "A";
})(E = N.E || (N.E = {}));
})(N || (N = {}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//// [tests/cases/conformance/constEnums/constEnumInNamespace.ts] ////

=== constEnumInNamespace.ts ===
namespace N {
>N : Symbol(N, Decl(constEnumInNamespace.ts, 0, 0))

export const enum E { A = 0 }
>E : Symbol(E, Decl(constEnumInNamespace.ts, 0, 13))
>A : Symbol(E.A, Decl(constEnumInNamespace.ts, 1, 23))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//// [tests/cases/conformance/constEnums/constEnumInNamespace.ts] ////

=== constEnumInNamespace.ts ===
namespace N {
export const enum E { A = 0 }
>E : E
>A : E.A
>0 : 0
}

Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@ bar(new B);


//// [assignmentNonObjectTypeConstraints.js]
var E;
(function (E) {
E[E["A"] = 0] = "A";
E[E["B"] = 1] = "B";
E[E["C"] = 2] = "C";
})(E || (E = {}));
function foo(x) {
var y = x; // Ok
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
--- old.assignmentNonObjectTypeConstraints.js
+++ new.assignmentNonObjectTypeConstraints.js
@@= skipped -21, +21 lines =@@


//// [assignmentNonObjectTypeConstraints.js]
+var E;
+(function (E) {
+ E[E["A"] = 0] = "A";
+ E[E["B"] = 1] = "B";
+ E[E["C"] = 2] = "C";
+})(E || (E = {}));
function foo(x) {
var y = x; // Ok
}
@@= skipped -27, +27 lines =@@
foo(5);
foo(0 /* E.A */);
class A {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,7 @@ function foo1() {
}
function foo2() {
return 0 /* E.A */;
let E;
(function (E) {
E[E["A"] = 0] = "A";
})(E || (E = {}));
}
const config = {
a: 2 /* AfterObject.A */,
};
var AfterObject;
(function (AfterObject) {
AfterObject[AfterObject["A"] = 2] = "A";
})(AfterObject || (AfterObject = {}));

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,5 @@ function foo(node) {
function bar(node) {
const a = tryCast(node, isExpression); // tryCast<Expression, Node>
}
// Repro from #49924
var SyntaxKind1;
(function (SyntaxKind1) {
SyntaxKind1[SyntaxKind1["ClassExpression"] = 0] = "ClassExpression";
SyntaxKind1[SyntaxKind1["ClassStatement"] = 1] = "ClassStatement";
})(SyntaxKind1 || (SyntaxKind1 = {}));
const maybeClassStatement = tryCast(statement, isClassLike); // ClassLike1
const x = tryCast(types, isNodeArray); // NodeAray<TypeNode>
Loading
Loading