Skip to content

Commit 913545e

Browse files
committed
Adds implicit "use strict" for amd modules and fixes issues with variable names and classes.
1 parent e5e2340 commit 913545e

4 files changed

Lines changed: 129 additions & 84 deletions

File tree

src/compiler/factory.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,32 @@ namespace ts {
10971097

10981098
// Utilities
10991099

1100+
function isUseStrictPrologue(node: ExpressionStatement): boolean {
1101+
return !!(node.expression as StringLiteral).text.match(/use strict/);
1102+
}
1103+
1104+
export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean): number {
1105+
let foundUseStrict = false;
1106+
for (let i = 0; i < source.length; i++) {
1107+
if (isPrologueDirective(source[i])) {
1108+
if (isUseStrictPrologue(source[i] as ExpressionStatement)) {
1109+
foundUseStrict = true;
1110+
}
1111+
1112+
target.push(source[i]);
1113+
}
1114+
else {
1115+
if (ensureUseStrict && !foundUseStrict) {
1116+
target.push(startOnNewLine(createStatement(createLiteral("use strict"))));
1117+
}
1118+
1119+
return i;
1120+
}
1121+
}
1122+
1123+
return source.length;
1124+
}
1125+
11001126
/**
11011127
* Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended
11021128
* order of operations.

src/compiler/transformers/module/module.ts

Lines changed: 102 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ namespace ts {
1515
startLexicalEnvironment,
1616
endLexicalEnvironment,
1717
hoistVariableDeclaration,
18-
setNodeEmitFlags
18+
setNodeEmitFlags,
19+
getNodeEmitFlags,
1920
} = context;
2021

2122
const compilerOptions = context.getCompilerOptions();
@@ -48,6 +49,7 @@ namespace ts {
4849

4950
// Perform the transformation.
5051
const updated = transformModuleDelegates[moduleKind](node);
52+
aggregateTransformFlags(updated);
5153

5254
currentSourceFile = undefined;
5355
externalImports = undefined;
@@ -67,17 +69,19 @@ namespace ts {
6769
*/
6870
function transformCommonJSModule(node: SourceFile) {
6971
startLexicalEnvironment();
70-
return setNodeEmitFlags(
71-
updateSourceFile(
72-
node,
73-
[
74-
...visitNodes(node.statements, visitor, isStatement),
75-
...(endLexicalEnvironment() || []),
76-
tryCreateExportEquals(/*emitAsReturn*/ false)
77-
]
78-
),
79-
hasExportStars ? NodeEmitFlags.EmitExportStar : 0
80-
);
72+
73+
const statements: Statement[] = [];
74+
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict);
75+
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
76+
addRange(statements, endLexicalEnvironment());
77+
addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false);
78+
79+
const updated = updateSourceFile(node, statements);
80+
if (hasExportStars) {
81+
setNodeEmitFlags(updated, NodeEmitFlags.EmitExportStar | getNodeEmitFlags(node));
82+
}
83+
84+
return updated;
8185
}
8286

8387
/**
@@ -123,9 +127,9 @@ namespace ts {
123127
createStatement(
124128
createCall(
125129
define,
126-
flatten([
130+
[
127131
// Add the module name (if provided).
128-
moduleName,
132+
...(moduleName ? [moduleName] : []),
129133

130134
// Add the dependency array argument:
131135
//
@@ -139,53 +143,64 @@ namespace ts {
139143
/*asteriskToken*/ undefined,
140144
/*name*/ undefined,
141145
importAliasNames,
142-
setNodeEmitFlags(
143-
setMultiLine(
144-
createBlock(
145-
flatten([
146-
// Visit each statement of the module body.
147-
...visitNodes(node.statements, visitor, isStatement),
148-
149-
// End the lexical environment for the module body
150-
// and merge any new lexical declarations.
151-
...(endLexicalEnvironment() || []),
152-
153-
// Append the 'export =' statement if provided.
154-
tryCreateExportEquals(/*emitAsReturn*/ true)
155-
])
156-
),
157-
/*multiLine*/ true
158-
),
159-
160-
// If we have any `export * from ...` declarations
161-
// we need to inform the emitter to add the __export helper.
162-
hasExportStars ? NodeEmitFlags.EmitExportStar : 0
163-
)
146+
transformAsynchronousModuleBody(node)
164147
)
165-
])
148+
]
166149
)
167150
)
168151
]);
169152
}
170153

171-
function tryCreateExportEquals(emitAsReturn: boolean) {
154+
function transformAsynchronousModuleBody(node: SourceFile) {
155+
const statements: Statement[] = [];
156+
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict);
157+
158+
// Visit each statement of the module body.
159+
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
160+
161+
// End the lexical environment for the module body
162+
// and merge any new lexical declarations.
163+
addRange(statements, endLexicalEnvironment());
164+
165+
// Append the 'export =' statement if provided.
166+
addExportEqualsIfNeeded(statements, /*emitAsReturn*/ true);
167+
168+
const body = createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
169+
170+
if (hasExportStars) {
171+
// If we have any `export * from ...` declarations
172+
// we need to inform the emitter to add the __export helper.
173+
setNodeEmitFlags(body, NodeEmitFlags.EmitExportStar);
174+
}
175+
176+
return body;
177+
}
178+
179+
function addExportEqualsIfNeeded(statements: Statement[], emitAsReturn: boolean) {
172180
if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) {
173181
if (emitAsReturn) {
174-
return createReturn(exportEquals.expression);
182+
statements.push(
183+
startOnNewLine(
184+
createReturn(exportEquals.expression)
185+
)
186+
);
175187
}
176188
else {
177-
return createStatement(
178-
createAssignment(
179-
createPropertyAccess(
180-
createIdentifier("module"),
181-
"exports"
182-
),
183-
exportEquals.expression
189+
statements.push(
190+
startOnNewLine(
191+
createStatement(
192+
createAssignment(
193+
createPropertyAccess(
194+
createIdentifier("module"),
195+
"exports"
196+
),
197+
exportEquals.expression
198+
)
199+
)
184200
)
185201
);
186202
}
187203
}
188-
return undefined;
189204
}
190205

191206
/**
@@ -480,28 +495,49 @@ namespace ts {
480495
function addExportMemberAssignments(statements: Statement[], name: Identifier): void {
481496
if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) {
482497
for (const specifier of exportSpecifiers[name.text]) {
483-
addNode(statements,
484-
createStatement(
485-
createExportAssignment(specifier.name, name),
486-
/*location*/ specifier.name
498+
statements.push(
499+
startOnNewLine(
500+
createStatement(
501+
createExportAssignment(specifier.name, name),
502+
/*location*/ specifier.name
503+
)
487504
)
488505
);
489506
}
490507
}
491508
}
492509

493-
function visitVariableStatement(node: VariableStatement): VisitResult<Statement> {
494-
const variables = getInitializedVariables(node.declarationList);
495-
if (variables.length === 0) {
496-
// elide statement if there are no initialized variables
497-
return undefined;
510+
function addExportMemberAssignment(statements: Statement[], node: FunctionDeclaration | ClassDeclaration) {
511+
if (hasModifier(node, ModifierFlags.Default)) {
512+
addExportDefault(statements, getSynthesizedClone(node.name), /*location*/ node);
513+
}
514+
else {
515+
statements.push(
516+
startOnNewLine(
517+
createStatement(
518+
createExportAssignment(node.name, node.name),
519+
/*location*/ node
520+
)
521+
)
522+
);
498523
}
524+
}
499525

500-
return createStatement(
501-
inlineExpressions(
502-
map(variables, transformInitializedVariable)
503-
)
504-
);
526+
function visitVariableStatement(node: VariableStatement): VisitResult<Statement> {
527+
if (hasModifier(node, ModifierFlags.Export)) {
528+
const variables = getInitializedVariables(node.declarationList);
529+
if (variables.length === 0) {
530+
// elide statement if there are no initialized variables
531+
return undefined;
532+
}
533+
534+
return createStatement(
535+
inlineExpressions(
536+
map(variables, transformInitializedVariable)
537+
)
538+
);
539+
}
540+
return node;
505541
}
506542

507543
function transformInitializedVariable(node: VariableDeclaration): Expression {
@@ -526,7 +562,7 @@ namespace ts {
526562
const statements: Statement[] = [];
527563
if (node.name) {
528564
if (hasModifier(node, ModifierFlags.Export)) {
529-
addNode(statements,
565+
statements.push(
530566
createFunctionDeclaration(
531567
/*modifiers*/ undefined,
532568
/*asteriskToken*/ undefined,
@@ -537,12 +573,10 @@ namespace ts {
537573
)
538574
);
539575

540-
if (hasModifier(node, ModifierFlags.Default)) {
541-
addExportDefault(statements, getSynthesizedClone(node.name), /*location*/ node);
542-
}
576+
addExportMemberAssignment(statements, node);
543577
}
544578
else {
545-
addNode(statements, node);
579+
statements.push(node);
546580
}
547581

548582
addExportMemberAssignments(statements, node.name);
@@ -567,7 +601,7 @@ namespace ts {
567601
const statements: Statement[] = [];
568602
if (node.name) {
569603
if (hasModifier(node, ModifierFlags.Export)) {
570-
addNode(statements,
604+
statements.push(
571605
createClassDeclaration(
572606
/*modifiers*/ undefined,
573607
node.name,
@@ -577,9 +611,7 @@ namespace ts {
577611
)
578612
);
579613

580-
if (hasModifier(node, ModifierFlags.Default)) {
581-
addExportDefault(statements, getSynthesizedClone(node.name), /*location*/ node);
582-
}
614+
addExportMemberAssignment(statements, node);
583615
}
584616
else {
585617
addNode(statements, node);

src/compiler/transformers/module/system.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ namespace ts {
8888
const statements: Statement[] = [];
8989

9090
// Add any prologue directives.
91-
const statementOffset = copyPrologueDirectives(node.statements, statements);
91+
const statementOffset = addPrologueDirectives(statements, node.statements);
9292

9393
// var __moduleName = context_1 && context_1.id;
9494
addNode(statements,

src/compiler/utilities.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3025,19 +3025,6 @@ namespace ts {
30253025
return { externalImports, exportSpecifiers, exportEquals, hasExportStars };
30263026
}
30273027

3028-
export function copyPrologueDirectives(from: Statement[], to: Statement[]): number {
3029-
for (let i = 0; i < from.length; i++) {
3030-
if (isPrologueDirective(from[i])) {
3031-
addNode(to, from[i]);
3032-
}
3033-
else {
3034-
return i;
3035-
}
3036-
}
3037-
3038-
return from.length;
3039-
}
3040-
30413028
export function getInitializedVariables(node: VariableDeclarationList) {
30423029
return filter(node.declarations, isInitializedVariable);
30433030
}

0 commit comments

Comments
 (0)