Skip to content
Merged
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
14 changes: 13 additions & 1 deletion src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2002,10 +2002,16 @@ namespace ts {
return visitEachChild(node, visitor, context);
}

function isVariableStatementOfTypeScriptClassWrapper(node: VariableStatement) {
return node.declarationList.declarations.length === 1
&& !!node.declarationList.declarations[0].initializer
&& !!(getEmitFlags(node.declarationList.declarations[0].initializer) & EmitFlags.TypeScriptClassWrapper);
}

function visitVariableStatement(node: VariableStatement): Statement | undefined {
const ancestorFacts = enterSubtree(HierarchyFacts.None, hasModifier(node, ModifierFlags.Export) ? HierarchyFacts.ExportedVariableStatement : HierarchyFacts.None);
let updated: Statement | undefined;
if (convertedLoopState && (node.declarationList.flags & NodeFlags.BlockScoped) === 0) {
if (convertedLoopState && (node.declarationList.flags & NodeFlags.BlockScoped) === 0 && !isVariableStatementOfTypeScriptClassWrapper(node)) {
// we are inside a converted loop - hoist variable declarations
let assignments: Expression[] | undefined;
for (const decl of node.declarationList.declarations) {
Expand Down Expand Up @@ -3606,7 +3612,13 @@ namespace ts {
// The class statements are the statements generated by visiting the first statement with initializer of the
// body (1), while all other statements are added to remainingStatements (2)
const isVariableStatementWithInitializer = (stmt: Statement) => isVariableStatement(stmt) && !!first(stmt.declarationList.declarations).initializer;

// visit the class body statements outside of any converted loop body.
const savedConvertedLoopState = convertedLoopState;
convertedLoopState = undefined;
const bodyStatements = visitNodes(body.statements, visitor, isStatement);
convertedLoopState = savedConvertedLoopState;

const classStatements = filter(bodyStatements, isVariableStatementWithInitializer);
const remainingStatements = filter(bodyStatements, stmt => !isVariableStatementWithInitializer(stmt));
const varStatement = cast(first(classStatements), isVariableStatement);
Expand Down
27 changes: 27 additions & 0 deletions tests/baselines/reference/classInConvertedLoopES5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//// [classInConvertedLoopES5.ts]
const classesByRow: Record<string, object> = {};
for (const row of ['1', '2', '3', '4', '5']) {
class RowClass {
row = row;
static factory = () => new RowClass();
}

classesByRow[row] = RowClass;
}

//// [classInConvertedLoopES5.js]
var classesByRow = {};
var _loop_1 = function (row) {
var RowClass = /** @class */ (function () {
function RowClass() {
this.row = row;
}
RowClass.factory = function () { return new RowClass(); };
return RowClass;
}());
classesByRow[row] = RowClass;
};
for (var _i = 0, _a = ['1', '2', '3', '4', '5']; _i < _a.length; _i++) {
var row = _a[_i];
_loop_1(row);
}
25 changes: 25 additions & 0 deletions tests/baselines/reference/classInConvertedLoopES5.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
=== tests/cases/compiler/classInConvertedLoopES5.ts ===
const classesByRow: Record<string, object> = {};
>classesByRow : Symbol(classesByRow, Decl(classInConvertedLoopES5.ts, 0, 5))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))

for (const row of ['1', '2', '3', '4', '5']) {
>row : Symbol(row, Decl(classInConvertedLoopES5.ts, 1, 10))

class RowClass {
>RowClass : Symbol(RowClass, Decl(classInConvertedLoopES5.ts, 1, 46))

row = row;
>row : Symbol(RowClass.row, Decl(classInConvertedLoopES5.ts, 2, 18))
>row : Symbol(row, Decl(classInConvertedLoopES5.ts, 1, 10))

static factory = () => new RowClass();
>factory : Symbol(RowClass.factory, Decl(classInConvertedLoopES5.ts, 3, 14))
>RowClass : Symbol(RowClass, Decl(classInConvertedLoopES5.ts, 1, 46))
}

classesByRow[row] = RowClass;
>classesByRow : Symbol(classesByRow, Decl(classInConvertedLoopES5.ts, 0, 5))
>row : Symbol(row, Decl(classInConvertedLoopES5.ts, 1, 10))
>RowClass : Symbol(RowClass, Decl(classInConvertedLoopES5.ts, 1, 46))
}
35 changes: 35 additions & 0 deletions tests/baselines/reference/classInConvertedLoopES5.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
=== tests/cases/compiler/classInConvertedLoopES5.ts ===
const classesByRow: Record<string, object> = {};
>classesByRow : Record<string, object>
>{} : {}

for (const row of ['1', '2', '3', '4', '5']) {
>row : string
>['1', '2', '3', '4', '5'] : string[]
>'1' : "1"
>'2' : "2"
>'3' : "3"
>'4' : "4"
>'5' : "5"

class RowClass {
>RowClass : RowClass

row = row;
>row : string
>row : string

static factory = () => new RowClass();
>factory : () => RowClass
>() => new RowClass() : () => RowClass
>new RowClass() : RowClass
>RowClass : typeof RowClass
}

classesByRow[row] = RowClass;
>classesByRow[row] = RowClass : typeof RowClass
>classesByRow[row] : object
>classesByRow : Record<string, object>
>row : string
>RowClass : typeof RowClass
}
10 changes: 10 additions & 0 deletions tests/cases/compiler/classInConvertedLoopES5.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @target: es5
const classesByRow: Record<string, object> = {};
for (const row of ['1', '2', '3', '4', '5']) {
class RowClass {
row = row;
static factory = () => new RowClass();
}

classesByRow[row] = RowClass;
}