Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
66 changes: 38 additions & 28 deletions internal/binder/binder.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,32 +46,33 @@ type Binder struct {
bindFunc func(*ast.Node) bool
unreachableFlow *ast.FlowNode

container *ast.Node
thisContainer *ast.Node
blockScopeContainer *ast.Node
lastContainer *ast.Node
currentFlow *ast.FlowNode
currentBreakTarget *ast.FlowLabel
currentContinueTarget *ast.FlowLabel
currentReturnTarget *ast.FlowLabel
currentTrueTarget *ast.FlowLabel
currentFalseTarget *ast.FlowLabel
currentExceptionTarget *ast.FlowLabel
preSwitchCaseFlow *ast.FlowNode
activeLabelList *ActiveLabel
emitFlags ast.NodeFlags
seenThisKeyword bool
hasExplicitReturn bool
hasFlowEffects bool
inStrictMode bool
inAssignmentPattern bool
seenParseError bool
symbolCount int
classifiableNames collections.Set[string]
symbolPool core.Pool[ast.Symbol]
flowNodePool core.Pool[ast.FlowNode]
flowListPool core.Pool[ast.FlowList]
singleDeclarationsPool core.Pool[*ast.Node]
container *ast.Node
thisContainer *ast.Node
blockScopeContainer *ast.Node
lastContainer *ast.Node
currentFlow *ast.FlowNode
currentBreakTarget *ast.FlowLabel
currentContinueTarget *ast.FlowLabel
currentReturnTarget *ast.FlowLabel
currentTrueTarget *ast.FlowLabel
currentFalseTarget *ast.FlowLabel
currentExceptionTarget *ast.FlowLabel
preSwitchCaseFlow *ast.FlowNode
activeLabelList *ActiveLabel
emitFlags ast.NodeFlags
seenThisKeyword bool
hasExplicitReturn bool
hasFlowEffects bool
inStrictMode bool
inAssignmentPattern bool
seenParseError bool
symbolCount int
classifiableNames collections.Set[string]
notConstEnumOnlyModules collections.Set[*ast.Symbol]
symbolPool core.Pool[ast.Symbol]
flowNodePool core.Pool[ast.FlowNode]
flowListPool core.Pool[ast.FlowList]
singleDeclarationsPool core.Pool[*ast.Node]
}

func (b *Binder) options() core.SourceFileAffectingCompilerOptions {
Expand Down Expand Up @@ -794,9 +795,17 @@ func (b *Binder) bindModuleDeclaration(node *ast.Node) {
state := b.declareModuleSymbol(node)
if state != ast.ModuleInstanceStateNonInstantiated {
symbol := node.Symbol()
if symbol.Flags&(ast.SymbolFlagsFunction|ast.SymbolFlagsClass|ast.SymbolFlagsRegularEnum) != 0 || state != ast.ModuleInstanceStateConstEnumOnly {
// if module was already merged with some function, class or non-const enum, treat it as non-const-enum-only
// if module was already merged with some function, class or non-const enum, treat it as non-const-enum-only
constEnumOnlyModule := (symbol.Flags&(ast.SymbolFlagsFunction|ast.SymbolFlagsClass|ast.SymbolFlagsRegularEnum) == 0) &&
// Current must be `const enum` only
state == ast.ModuleInstanceStateConstEnumOnly &&
// Can't have been set to 'false' in a previous merged symbol. ('undefined' OK)
!b.notConstEnumOnlyModules.Has(symbol)
if constEnumOnlyModule {
symbol.Flags |= ast.SymbolFlagsConstEnumOnlyModule
} else {
symbol.Flags &^= ast.SymbolFlagsConstEnumOnlyModule
b.notConstEnumOnlyModules.Add(symbol)
}
}
}
Expand Down Expand Up @@ -2424,6 +2433,7 @@ func (b *Binder) addDeclarationToSymbol(symbol *ast.Symbol, node *ast.Node, symb
// On merge of const enum module with class or function, reset const enum only flag (namespaces will already recalculate)
if symbol.Flags&ast.SymbolFlagsConstEnumOnlyModule != 0 && symbol.Flags&(ast.SymbolFlagsFunction|ast.SymbolFlagsClass|ast.SymbolFlagsRegularEnum) != 0 {
symbol.Flags &^= ast.SymbolFlagsConstEnumOnlyModule
b.notConstEnumOnlyModules.Add(symbol)
}
if symbolFlags&ast.SymbolFlagsValue != 0 {
SetValueDeclaration(symbol, node)
Expand Down
2 changes: 1 addition & 1 deletion internal/checker/emitresolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ func (r *EmitResolver) IsTopLevelValueImportEqualsWithEntityName(node *ast.Node)
return false
}
if ast.IsImportEqualsDeclaration(node) &&
(ast.NodeIsMissing(node.AsImportEqualsDeclaration().ModuleReference) || node.AsImportEqualsDeclaration().ModuleReference.Kind != ast.KindExternalModuleReference) {
(ast.NodeIsMissing(node.AsImportEqualsDeclaration().ModuleReference) || node.AsImportEqualsDeclaration().ModuleReference.Kind == ast.KindExternalModuleReference) {
return false
}

Expand Down
22 changes: 22 additions & 0 deletions internal/transformers/moduletransforms/commonjsmodule.go
Original file line number Diff line number Diff line change
Expand Up @@ -1074,7 +1074,14 @@ func (tx *CommonJSModuleTransformer) visitTopLevelVariableStatement(node *ast.Va
propertyAccess,
v.Name().Clone(tx.Factory()),
))
} else if ast.IsIdentifier(v.Name()) {
expression := tx.transformInitializedVariable(v)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old compiler had this func instead which did something special with exports, unlike ConvertVariableDeclarationToAssignmentExpression which is new. Not extremely familiar, though.

if expression != nil {
pushExpression(tx.Visitor().VisitNode(expression))
}
} else {
// For binding patterns, we can't do exports.{pattern} = value
// Just emit the assignment and let appendExportsOfVariableStatement handle the exports
expression := transformers.ConvertVariableDeclarationToAssignmentExpression(tx.EmitContext(), v)
if expression != nil {
pushExpression(tx.Visitor().VisitNode(expression))
Expand All @@ -1090,6 +1097,21 @@ func (tx *CommonJSModuleTransformer) visitTopLevelVariableStatement(node *ast.Va
return tx.visitTopLevelNestedVariableStatement(node)
}

func (tx *CommonJSModuleTransformer) transformInitializedVariable(node *ast.VariableDeclaration) *ast.Expression {
if node.Initializer == nil {
return nil
}
name := node.Name()
propertyAccess := tx.Factory().NewPropertyAccessExpression(
tx.Factory().NewIdentifier("exports"),
nil, /*questionDotToken*/
name,
ast.NodeFlagsNone,
)
tx.EmitContext().AssignCommentAndSourceMapRanges(propertyAccess, name)
return tx.Factory().NewAssignmentExpression(propertyAccess, node.Initializer)
}

// Visits a top-level nested variable statement as it may contain `var` declarations that are hoisted and may still be
// exported with `export {}`.
func (tx *CommonJSModuleTransformer) visitTopLevelNestedVariableStatement(node *ast.VariableStatement) *ast.Node {
Expand Down
20 changes: 11 additions & 9 deletions internal/transformers/tstransforms/importelision.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,16 @@ func NewImportElisionTransformer(opt *transformers.TransformOptions) *transforme
func (tx *ImportElisionTransformer) visit(node *ast.Node) *ast.Node {
switch node.Kind {
case ast.KindImportEqualsDeclaration:
if !tx.isElisionBlocked(node) && !tx.shouldEmitImportEqualsDeclaration(node.AsImportEqualsDeclaration()) {
return nil
if !tx.isElisionBlocked(node) {
if ast.IsExternalModuleImportEqualsDeclaration(node) {
if !tx.shouldEmitAliasDeclaration(node) {
return nil
}
} else {
if !tx.shouldEmitImportEqualsDeclaration(node.AsImportEqualsDeclaration()) {
return nil
}
}
}
return tx.Visitor().VisitEachChild(node)
case ast.KindImportDeclaration:
Expand Down Expand Up @@ -124,16 +132,10 @@ func (tx *ImportElisionTransformer) shouldEmitAliasDeclaration(node *ast.Node) b
}

func (tx *ImportElisionTransformer) shouldEmitImportEqualsDeclaration(node *ast.ImportEqualsDeclaration) bool {
if !tx.shouldEmitAliasDeclaration(node.AsNode()) {
return false
}
if node.ModuleReference.Kind == ast.KindExternalModuleReference {
return true
}
// preserve old compiler's behavior: emit import declaration (even if we do not consider them referenced) when
// - current file is not external module
// - import declaration is top level and target is value imported by entity name
return tx.currentSourceFile != nil && ast.IsExternalModule(tx.currentSourceFile) && tx.isTopLevelValueImportEqualsWithEntityName(node.AsNode())
return tx.shouldEmitAliasDeclaration(node.AsNode()) || (!ast.IsExternalModule(tx.currentSourceFile) && tx.isTopLevelValueImportEqualsWithEntityName(node.AsNode()))
}

func (tx *ImportElisionTransformer) isReferencedAliasDeclaration(node *ast.Node) bool {
Expand Down
13 changes: 13 additions & 0 deletions testdata/baselines/reference/compiler/exportDestructuring.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//// [tests/cases/compiler/exportDestructuring.ts] ////

//// [exportDestructuring.ts]
const arr = [1, 2];
export const [a, b] = arr;


//// [exportDestructuring.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.b = exports.a = void 0;
const arr = [1, 2];
[exports.a, exports.b] = arr;
11 changes: 11 additions & 0 deletions testdata/baselines/reference/compiler/exportDestructuring.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//// [tests/cases/compiler/exportDestructuring.ts] ////

=== exportDestructuring.ts ===
const arr = [1, 2];
>arr : Symbol(arr, Decl(exportDestructuring.ts, 0, 5))

export const [a, b] = arr;
>a : Symbol(a, Decl(exportDestructuring.ts, 1, 14))
>b : Symbol(b, Decl(exportDestructuring.ts, 1, 16))
>arr : Symbol(arr, Decl(exportDestructuring.ts, 0, 5))

14 changes: 14 additions & 0 deletions testdata/baselines/reference/compiler/exportDestructuring.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//// [tests/cases/compiler/exportDestructuring.ts] ////

=== exportDestructuring.ts ===
const arr = [1, 2];
>arr : number[]
>[1, 2] : number[]
>1 : 1
>2 : 2

export const [a, b] = arr;
>a : number
>b : number
>arr : number[]

2 changes: 2 additions & 0 deletions testdata/baselines/reference/submodule/compiler/aliasBug.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ var foo;
})(baz = bar.baz || (bar.baz = {}));
})(bar = foo.bar || (foo.bar = {}));
})(foo || (foo = {}));
var provide = foo;
var booz = foo.bar.baz;
var p = new provide.Provide();
function use() {
var p1; // error here, but should be okay
Expand Down
11 changes: 0 additions & 11 deletions testdata/baselines/reference/submodule/compiler/aliasBug.js.diff

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,15 @@ var foo;
})(baz = bar.baz || (bar.baz = {}));
})(bar = foo.bar || (foo.bar = {}));
})(foo || (foo = {}));
var provide = foo;
var booz = foo.bar.baz;
var beez = foo.bar;
var m = no;
var m2 = no.mod;
5;
"s";
null;
var r = undefined;
var p = new provide.Provide();
function use() {
beez.baz.boo;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ var m;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const x = require("./chainedImportAlias_file0");
var y = x;
y.m.foo();

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ var mOfGloalFile;
}
mOfGloalFile.c = c;
})(mOfGloalFile || (mOfGloalFile = {}));
var exports = mOfGloalFile.c;
var require = mOfGloalFile.c;
new exports();
new require();
var m1;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ var a;
a.b = 10;
})(a || (a = {}));
var f = () => this;
var _this = a; // Error

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ var A2;
})(C = B.C || (B.C = {}));
})(B = A2.B || (A2.B = {}));
})(A2 || (A2 = {}));
var I2 = A2.B;
function foo0(e) {
if (e === 1 /* I.V1 */) {
}
Expand Down
10 changes: 0 additions & 10 deletions testdata/baselines/reference/submodule/compiler/constEnums.js.diff

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ TypeScriptAllInOne.Program.Main();


//// [constructorWithIncompleteTypeAnnotation.js]
var fs = module;
("fs");
var TypeScriptAllInOne;
(function (TypeScriptAllInOne) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
--- old.constructorWithIncompleteTypeAnnotation.js
+++ new.constructorWithIncompleteTypeAnnotation.js
@@= skipped -281, +281 lines =@@


//// [constructorWithIncompleteTypeAnnotation.js]
-var fs = module;
("fs");
@@= skipped -286, +286 lines =@@
var TypeScriptAllInOne;
(function (TypeScriptAllInOne) {
class Program {
Expand All @@ -15,7 +10,7 @@
static Main(...args) {
try {
var bfs = new BasicFeatures();
@@= skipped -15, +11 lines =@@
@@= skipped -10, +7 lines =@@
retValue = bfs.VARIABLES();
if (retValue != 0)
^= {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export = m;
var m3;
(function (m3) {
})(m3 || (m3 = {}));
var m = m3;
module.exports = m;


Expand Down

This file was deleted.

Loading