From 80fab7c5a41534e3c506a90b7375a3cb753aae05 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 12 Apr 2016 15:19:05 -0700 Subject: [PATCH 01/14] elide exports with no value side --- src/compiler/transformers/module/es6.ts | 36 ++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/compiler/transformers/module/es6.ts b/src/compiler/transformers/module/es6.ts index 9355b476247..d2f4ca4f224 100644 --- a/src/compiler/transformers/module/es6.ts +++ b/src/compiler/transformers/module/es6.ts @@ -34,12 +34,18 @@ namespace ts { return visitImportSpecifier(node); case SyntaxKind.ExportAssignment: return visitExportAssignment(node); + case SyntaxKind.ExportDeclaration: + return visitExportDeclaration(node); + case SyntaxKind.NamedExports: + return visitNamedExports(node); + case SyntaxKind.ExportSpecifier: + return visitExportSpecifier(node); } return node; } - function visitExportAssignment(node: ExportAssignment): ExportDeclaration { + function visitExportAssignment(node: ExportAssignment): ExportAssignment { if (node.isExportEquals) { return undefined; // do not emit export equals for ES6 } @@ -47,6 +53,34 @@ namespace ts { return nodeIsSynthesized(original) || resolver.isValueAliasDeclaration(original) ? node: undefined; } + function visitExportDeclaration(node: ExportDeclaration): ExportDeclaration { + if (!node.exportClause) { + return node; // export * is always emitted + } + if (!resolver.isValueAliasDeclaration(node)) { + return undefined; + } + const newExportClause = visitNode(node.exportClause, visitor, isNamedExports, /*optional*/ true); + if (node.exportClause === newExportClause) { + return node; + } + return newExportClause + ? createExportDeclaration(newExportClause, node.moduleSpecifier) + : undefined; + } + + function visitNamedExports(node: NamedExports): NamedExports { + const newExports = visitNodes(node.elements, visitor, isExportSpecifier); + if (node.elements === newExports) { + return node; + } + return newExports.length ? createNamedExports(newExports) : undefined; + } + + function visitExportSpecifier(node: ExportSpecifier): ExportSpecifier { + return resolver.isValueAliasDeclaration(node) ? node : undefined; + } + function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): ImportEqualsDeclaration { return !isExternalModuleImportEqualsDeclaration(node) || resolver.isReferencedAliasDeclaration(node) ? node : undefined; } From 7b07d3ce27e75c165b60b4dc06a84352941f793c Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 13 Apr 2016 11:59:29 -0700 Subject: [PATCH 02/14] Fix the trailing comment emit for module declaration Fixes #8045 Fixes: - tests\cases\compiler\augmentedTypesClass3.ts - tests\cases\compiler\augmentedTypesModules.ts - tests\cases\compiler\commentsModules.ts --- src/compiler/comments.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts index 1baf1847f04..4ecf2dd6935 100644 --- a/src/compiler/comments.ts +++ b/src/compiler/comments.ts @@ -117,6 +117,25 @@ namespace ts { return undefined; } + const node = range as Node; + if (node.kind === SyntaxKind.VariableStatement && + node.original && + node.original.kind === SyntaxKind.ModuleDeclaration) { + // Trailing comments for module declaration should be emitted with function closure instead of variable statement + // /** Module comment*/ + // module m1 { + // function foo4Export() { + // } + // } // trailing comment module + // Should emit + // /** Module comment*/ + // var m1; + // (function (m1) { + // function foo4Export() { + // } + // })(m1 || (m1 = {})); // trailing comment module + return undefined; + } return getTrailingCommentsOfPosition(range.end); } From 27adb8c363c6a172a5a489929251f569666bd2d2 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 13 Apr 2016 12:05:21 -0700 Subject: [PATCH 03/14] Fix the trailing comments for enum declaration Fixes #8045 Tests fixed: - tests\cases\compiler\augmentedTypesClass.ts - tests\cases\compiler\augmentedTypesEnum.ts - tests\cases\compiler\augmentedTypesEnum2.ts - tests\cases\compiler\augmentedTypesFunction.ts - tests\cases\compiler\augmentedTypesVar.ts - tests\cases\compiler\commentsEnums.ts --- src/compiler/comments.ts | 2 +- src/compiler/transformers/ts.ts | 26 ++++---------------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts index 4ecf2dd6935..f5f8549dd28 100644 --- a/src/compiler/comments.ts +++ b/src/compiler/comments.ts @@ -120,7 +120,7 @@ namespace ts { const node = range as Node; if (node.kind === SyntaxKind.VariableStatement && node.original && - node.original.kind === SyntaxKind.ModuleDeclaration) { + (node.original.kind === SyntaxKind.ModuleDeclaration || node.original.kind === SyntaxKind.EnumDeclaration)) { // Trailing comments for module declaration should be emitted with function closure instead of variable statement // /** Module comment*/ // module m1 { diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 0b8c11a66e2..8a915484a79 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2213,24 +2213,6 @@ namespace ts { || (isES6ExportedDeclaration(node) && isFirstDeclarationOfKind(node, node.kind)); } - /** - * Adds a leading VariableStatement for an enum or module declaration. - */ - function addVarForEnumDeclaration(statements: Statement[], node: EnumDeclaration) { - // Emit a variable statement for the enum. - statements.push( - createVariableStatement( - isES6ExportedDeclaration(node) - ? visitNodes(node.modifiers, visitor, isModifier) - : undefined, - [createVariableDeclaration( - getDeclarationName(node) - )], - /*location*/ node - ) - ); - } - /** * Adds a trailing VariableStatement for an enum or module declaration. */ @@ -2261,7 +2243,7 @@ namespace ts { const statements: Statement[] = []; if (shouldEmitVarForEnumDeclaration(node)) { - addVarForEnumDeclaration(statements, node); + addVarForEnumOrModuleDeclaration(statements, node); } const localName = getGeneratedNameForNode(node); @@ -2395,9 +2377,9 @@ namespace ts { } /** - * Adds a leading VariableStatement for a module declaration. + * Adds a leading VariableStatement for a enum or module declaration. */ - function addVarForModuleDeclaration(statements: Statement[], node: ModuleDeclaration) { + function addVarForEnumOrModuleDeclaration(statements: Statement[], node: ModuleDeclaration | EnumDeclaration) { // Emit a variable statement for the module. statements.push( setOriginalNode( @@ -2433,7 +2415,7 @@ namespace ts { const statements: Statement[] = []; if (shouldEmitVarForModuleDeclaration(node)) { - addVarForModuleDeclaration(statements, node); + addVarForEnumOrModuleDeclaration(statements, node); } const localName = getGeneratedNameForNode(node); From 2e47f22fcc75cc0989dfb5f44ec372896bb38447 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 13 Apr 2016 14:14:00 -0700 Subject: [PATCH 04/14] Set the end position of variable statement as -1 so the trailing comments are not emitted --- src/compiler/comments.ts | 19 ------------------- src/compiler/transformers/ts.ts | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts index f5f8549dd28..1baf1847f04 100644 --- a/src/compiler/comments.ts +++ b/src/compiler/comments.ts @@ -117,25 +117,6 @@ namespace ts { return undefined; } - const node = range as Node; - if (node.kind === SyntaxKind.VariableStatement && - node.original && - (node.original.kind === SyntaxKind.ModuleDeclaration || node.original.kind === SyntaxKind.EnumDeclaration)) { - // Trailing comments for module declaration should be emitted with function closure instead of variable statement - // /** Module comment*/ - // module m1 { - // function foo4Export() { - // } - // } // trailing comment module - // Should emit - // /** Module comment*/ - // var m1; - // (function (m1) { - // function foo4Export() { - // } - // })(m1 || (m1 = {})); // trailing comment module - return undefined; - } return getTrailingCommentsOfPosition(range.end); } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 8a915484a79..539061dd481 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2390,7 +2390,21 @@ namespace ts { [createVariableDeclaration( getDeclarationName(node) )], - /*location*/ node + // Trailing comments for module declaration should be emitted with function closure instead of variable statement + // So do not set the end position for the variable statement node + // /** Module comment*/ + // module m1 { + // function foo4Export() { + // } + // } // trailing comment module + // Should emit + // /** Module comment*/ + // var m1; + // (function (m1) { + // function foo4Export() { + // } + // })(m1 || (m1 = {})); // trailing comment module + /*location*/ { pos: node.pos, end: -1 } ), node ) From 3de310af066b852008b0462fd271d4357970bf3e Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 13 Apr 2016 15:14:35 -0700 Subject: [PATCH 06/14] emit 'export *' for es6 only if module exports some value --- src/compiler/transformers/module/es6.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/transformers/module/es6.ts b/src/compiler/transformers/module/es6.ts index d2f4ca4f224..742f208d61c 100644 --- a/src/compiler/transformers/module/es6.ts +++ b/src/compiler/transformers/module/es6.ts @@ -55,7 +55,7 @@ namespace ts { function visitExportDeclaration(node: ExportDeclaration): ExportDeclaration { if (!node.exportClause) { - return node; // export * is always emitted + return resolver.moduleExportsSomeValue(node.moduleSpecifier) ? node : undefined; } if (!resolver.isValueAliasDeclaration(node)) { return undefined; From 8fa44c3b06c798b6d4399d7836320df38f5fb4ec Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 13 Apr 2016 15:49:02 -0700 Subject: [PATCH 07/14] Capture `this` in computed property names in arrow functions --- src/compiler/binder.ts | 12 ++++++++++++ src/compiler/types.ts | 15 ++++++++------- .../reference/computedPropertyNames29_ES5.js | 3 ++- .../reference/computedPropertyNames31_ES5.js | 3 ++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1cff02ffc48..b48b320d0d1 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1910,6 +1910,9 @@ namespace ts { // This is so that they can flow through PropertyName transforms unaffected. // Instead, we mark the container as ES6, so that it can properly handle the transform. transformFlags = TransformFlags.ContainsComputedPropertyName; + if (subtreeFlags & TransformFlags.ContainsLexicalThis) { + transformFlags |= TransformFlags.ContainsLexicalThisInComputedPropertyName; + } break; case SyntaxKind.SpreadElementExpression: @@ -1945,6 +1948,9 @@ namespace ts { // is an ES6 node. transformFlags = TransformFlags.AssertES6; } + if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) { + transformFlags |= TransformFlags.ContainsLexicalThis; + } break; case SyntaxKind.CallExpression: @@ -2256,6 +2262,9 @@ namespace ts { || hasModifier(node, ModifierFlags.Export)) { transformFlags |= TransformFlags.AssertTypeScript; } + if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) { + transformFlags |= TransformFlags.ContainsLexicalThis; + } return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ClassExcludes); } @@ -2272,6 +2281,9 @@ namespace ts { | TransformFlags.ContainsDecorators)) { transformFlags |= TransformFlags.AssertTypeScript; } + if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) { + transformFlags |= TransformFlags.ContainsLexicalThis; + } return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ClassExcludes); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 627b33f0d34..4c99417950d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2830,11 +2830,12 @@ namespace ts { ContainsPropertyInitializer = 1 << 10, ContainsLexicalThis = 1 << 11, ContainsCapturedLexicalThis = 1 << 12, - ContainsDefaultValueAssignments = 1 << 13, - ContainsParameterPropertyAssignments = 1 << 14, - ContainsSpreadElementExpression = 1 << 15, - ContainsComputedPropertyName = 1 << 16, - ContainsBlockScopedBinding = 1 << 17, + ContainsLexicalThisInComputedPropertyName = 1 << 13, + ContainsDefaultValueAssignments = 1 << 14, + ContainsParameterPropertyAssignments = 1 << 15, + ContainsSpreadElementExpression = 1 << 16, + ContainsComputedPropertyName = 1 << 17, + ContainsBlockScopedBinding = 1 << 18, HasComputedFlags = 1 << 31, // Transform flags have been computed. @@ -2853,10 +2854,10 @@ namespace ts { FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding, ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding, MethodOrAccessorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding, - ClassExcludes = ContainsDecorators | ContainsPropertyInitializer | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsParameterPropertyAssignments, + ClassExcludes = ContainsDecorators | ContainsPropertyInitializer | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsParameterPropertyAssignments | ContainsLexicalThisInComputedPropertyName, ModuleExcludes = ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding, TypeExcludes = ~ContainsTypeScript, - ObjectLiteralExcludes = ContainsDecorators | ContainsComputedPropertyName, + ObjectLiteralExcludes = ContainsDecorators | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName, ArrayLiteralOrCallOrNewExcludes = ContainsSpreadElementExpression, } diff --git a/tests/baselines/reference/computedPropertyNames29_ES5.js b/tests/baselines/reference/computedPropertyNames29_ES5.js index af6f93c8ad9..966081ae035 100644 --- a/tests/baselines/reference/computedPropertyNames29_ES5.js +++ b/tests/baselines/reference/computedPropertyNames29_ES5.js @@ -18,7 +18,8 @@ var C = (function () { var _this = this; (function () { var obj = (_a = {}, - _a[_this.bar()] = function () { }, + _a[_this.bar()] = function () { } // needs capture + , _a); var _a; }); diff --git a/tests/baselines/reference/computedPropertyNames31_ES5.js b/tests/baselines/reference/computedPropertyNames31_ES5.js index 86fb6655a27..2e38e2a131f 100644 --- a/tests/baselines/reference/computedPropertyNames31_ES5.js +++ b/tests/baselines/reference/computedPropertyNames31_ES5.js @@ -38,7 +38,8 @@ var C = (function (_super) { var _this = this; (function () { var obj = (_a = {}, - _a[_super.prototype.bar.call(_this)] = function () { }, + _a[_super.prototype.bar.call(_this)] = function () { } // needs capture + , _a); var _a; }); From 7bb3a5a514dd7e6800f9f9a8adc346c85b6afe5a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 13 Apr 2016 16:03:53 -0700 Subject: [PATCH 08/14] Fix case of mocha TAP -> tap --- Jakefile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jakefile.js b/Jakefile.js index 46f2a0fca96..9106c3c619d 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -717,7 +717,7 @@ function runTestsAndWriteOutput(file) { } var args = []; - args.push("-R", "TAP"); + args.push("-R", "tap"); args.push("--no-colors"); args.push("-t", testTimeout); if (tests) { @@ -1272,4 +1272,4 @@ function environmentVariableIsEnabled(name) { function environmentVariableIsDisabled(name) { return /^(no?|f(alse)?|off|disabled?|0|-)$/.test(process.env[name]); -} \ No newline at end of file +} From e5e8c6b0b936d07365bfcc07b7363380998da163 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 13 Apr 2016 16:14:29 -0700 Subject: [PATCH 09/14] Add explanatory comment when adding ContainsLexicalThisInComputedPropertyName --- src/compiler/binder.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b48b320d0d1..5ed1e9665d5 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1911,6 +1911,9 @@ namespace ts { // Instead, we mark the container as ES6, so that it can properly handle the transform. transformFlags = TransformFlags.ContainsComputedPropertyName; if (subtreeFlags & TransformFlags.ContainsLexicalThis) { + // A computed method name that contains `this` needs to + // distinguish itself from the normal case of a method body containing `this`. + // So convert ContainsLexicalThis to ContainsLexicalThisInComputedPropertyName transformFlags |= TransformFlags.ContainsLexicalThisInComputedPropertyName; } break; From 2c95ea966cb347373b033c557855d40deca9da17 Mon Sep 17 00:00:00 2001 From: Yui Date: Thu, 14 Apr 2016 09:27:08 -0700 Subject: [PATCH 10/14] [Transforms] fix Not correctly emitting local name for exported class (#8048) * Fix 7864: by set emitFlags to not substitute the node * Address PR: fix comment --- src/compiler/transformers/module/module.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 9d7dc0b2a82..563733a9c97 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -358,6 +358,9 @@ namespace ts { return undefined; } + // Set emitFlags on the name of the importEqualsDeclaration + // This is so the printer will not substitute the identifier + setNodeEmitFlags(node.name, NodeEmitFlags.NoSubstitution); const statements: Statement[] = []; if (moduleKind !== ModuleKind.AMD) { if (hasModifier(node, ModifierFlags.Export)) { @@ -639,6 +642,9 @@ namespace ts { function visitClassDeclaration(node: ClassDeclaration): VisitResult { const statements: Statement[] = []; const name = node.name || getGeneratedNameForNode(node); + // Set emitFlags on the name of the classDeclaration + // This is so that when printer will not substitute the identifier + setNodeEmitFlags(name, NodeEmitFlags.NoSubstitution); if (hasModifier(node, ModifierFlags.Export)) { statements.push( createClassDeclaration( @@ -834,6 +840,9 @@ namespace ts { // Find the name of the module alias, if there is one const importAliasName = getLocalNameForExternalImport(importNode, currentSourceFile); if (includeNonAmdDependencies && importAliasName) { + // Set emitFlags on the name of the classDeclaration + // This is so that when printer will not substitute the identifier + setNodeEmitFlags(importAliasName, NodeEmitFlags.NoSubstitution); aliasedModuleNames.push(externalModuleName); importAliasNames.push(createParameter(importAliasName)); } From c21ff6421cff8896358a0f134965c4fabbe215c2 Mon Sep 17 00:00:00 2001 From: Yui Date: Thu, 14 Apr 2016 09:30:19 -0700 Subject: [PATCH 11/14] [Transforms] fix8038 and 8047 (#8071) * Fix 8047: stop "require" is paranthesized * Fix 8038: quote "default" in es3 output --- src/compiler/transformers/module/module.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 563733a9c97..83604946102 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -755,11 +755,20 @@ namespace ts { else if (declaration.kind === SyntaxKind.ImportSpecifier) { const name = (declaration).propertyName || (declaration).name; - return createPropertyAccess( - getGeneratedNameForNode(declaration.parent.parent.parent), - getSynthesizedClone(name), - /*location*/ node - ); + if (name.originalKeywordKind === SyntaxKind.DefaultKeyword && languageVersion <= ScriptTarget.ES3) { + return createElementAccess( + getGeneratedNameForNode(declaration.parent.parent.parent), + createLiteral(name.text), + /*location*/ node + ); + } + else { + return createPropertyAccess( + getGeneratedNameForNode(declaration.parent.parent.parent), + getSynthesizedClone(name), + /*location*/ node + ); + } } } } @@ -791,7 +800,7 @@ namespace ts { function createExportAssignment(name: Identifier, value: Expression) { return createAssignment( - name.originalKeywordKind && languageVersion === ScriptTarget.ES3 + name.originalKeywordKind === SyntaxKind.DefaultKeyword && languageVersion === ScriptTarget.ES3 ? createElementAccess( createIdentifier("exports"), createLiteral(name.text) From d56ac44a27d54a7050ffaa8c29d037e0a8ffc466 Mon Sep 17 00:00:00 2001 From: Yui Date: Thu, 14 Apr 2016 09:41:12 -0700 Subject: [PATCH 12/14] [Transforms] fix `_this = this` capture emitted before `"use strict"` directives in AMD module output (#7953) * Fix 7913: emit prologue directives as a first statement in emitted AMD module * Do not ensure that prologue-directive is added when using it when transforming function body * Address PR: preserve prologue directives location and make sure it is the first statement in the result statements array * Address PR: fix comment --- src/compiler/factory.ts | 11 +++++++++++ src/compiler/transformers/es6.ts | 11 +++++++++-- src/compiler/transformers/module/system.ts | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index e35c5a08297..928ba76699e 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1252,7 +1252,18 @@ namespace ts { return (node.expression as StringLiteral).text === "use strict"; } + /** + * Add any necessary prologue-directives into target statement-array. + * The function needs to be called during each transformation step. + * This function needs to be called whenever we transform the statement + * list of a source file, namespace, or function-like body. + * + * @param target: result statements array + * @param source: origin statements array + * @param ensureUseStrict: boolean determining whether the function need to add prologue-directives + */ export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean): number { + Debug.assert(target.length === 0, "PrologueDirectives should be at the first statement in the target statements array"); let foundUseStrict = false; for (let i = 0; i < source.length; i++) { if (isPrologueDirective(source[i])) { diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts index 796dd9529ad..7b769889dca 100644 --- a/src/compiler/transformers/es6.ts +++ b/src/compiler/transformers/es6.ts @@ -1211,7 +1211,15 @@ namespace ts { let statementsLocation: TextRange; const statements: Statement[] = []; + const body = node.body; + let statementOffset: number; + startLexicalEnvironment(); + if (isBlock(body)) { + // ensureUseStrict is false because no new prologue-directive should be added. + // addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array + statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false); + } addCaptureThisForNodeIfNeeded(statements, node); addDefaultValueAssignmentsIfNeeded(statements, node); addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false); @@ -1221,10 +1229,9 @@ namespace ts { multiLine = true; } - const body = node.body; if (isBlock(body)) { statementsLocation = body.statements; - addRange(statements, visitNodes(body.statements, visitor, isStatement)); + addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset)); // If the original body was a multi-line block, this must be a multi-line block. if (!multiLine && body.multiLine) { diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 663917170ef..eee50781f32 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -193,7 +193,7 @@ namespace ts { startLexicalEnvironment(); // Add any prologue directives. - const statementOffset = addPrologueDirectives(statements, node.statements, !compilerOptions.noImplicitUseStrict); + const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict); // var __moduleName = context_1 && context_1.id; addNode(statements, From 0d5bf0ee32a39288cee795f190cae5c36eaf2c86 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 14 Apr 2016 09:51:21 -0700 Subject: [PATCH 13/14] Improve comment explaining ContainsLexicalThisInComputedPropertyName --- src/compiler/binder.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 5ed1e9665d5..f92f6789d29 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1911,9 +1911,14 @@ namespace ts { // Instead, we mark the container as ES6, so that it can properly handle the transform. transformFlags = TransformFlags.ContainsComputedPropertyName; if (subtreeFlags & TransformFlags.ContainsLexicalThis) { - // A computed method name that contains `this` needs to - // distinguish itself from the normal case of a method body containing `this`. - // So convert ContainsLexicalThis to ContainsLexicalThisInComputedPropertyName + // A computed method name like `[this.getName()](x: string) { ... }` needs to + // distinguish itself from the normal case of a method body containing `this`: + // `this` inside a method doesn't need to be rewritten (the method provides `this`), + // whereas `this` inside a computed name *might* need to be rewritten if the class/object + // is inside an arrow function: + // `_this = this; () => class K { [_this.getName()]() { ... } }` + // To make this distinction, use ContainsLexicalThisInComputedPropertyName + // instead of ContainsLexicalThis for computed property names transformFlags |= TransformFlags.ContainsLexicalThisInComputedPropertyName; } break; @@ -1952,6 +1957,8 @@ namespace ts { transformFlags = TransformFlags.AssertES6; } if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) { + // A computed property name containing `this` might need to be rewritten, + // so propagate the ContainsLexicalThis flag upward. transformFlags |= TransformFlags.ContainsLexicalThis; } break; @@ -2266,6 +2273,8 @@ namespace ts { transformFlags |= TransformFlags.AssertTypeScript; } if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) { + // A computed property name containing `this` might need to be rewritten, + // so propagate the ContainsLexicalThis flag upward. transformFlags |= TransformFlags.ContainsLexicalThis; } @@ -2285,6 +2294,8 @@ namespace ts { transformFlags |= TransformFlags.AssertTypeScript; } if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) { + // A computed property name containing `this` might need to be rewritten, + // so propagate the ContainsLexicalThis flag upward. transformFlags |= TransformFlags.ContainsLexicalThis; } From 0b890901df3ca03c2750cfa2ea398a9181f6073f Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 14 Apr 2016 10:57:26 -0700 Subject: [PATCH 14/14] Add calls to unescapeIdentifier for destructured identifiers --- src/compiler/transformers/destructuring.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 06e8a354d85..e1374c13ad3 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -370,16 +370,19 @@ namespace ts { ); } else if (isLiteralExpression(propertyName)) { - return createElementAccess( - expression, - getSynthesizedClone(propertyName) - ); + const clone = getSynthesizedClone(propertyName); + clone.text = unescapeIdentifier(clone.text); + return createElementAccess(expression, clone); } else { - return createPropertyAccess( - expression, - isGeneratedIdentifier(propertyName) ? getSynthesizedClone(propertyName) : createIdentifier(propertyName.text) - ); + if (isGeneratedIdentifier(propertyName)) { + const clone = getSynthesizedClone(propertyName); + clone.text = unescapeIdentifier(clone.text); + return createPropertyAccess(expression, clone); + } + else { + return createPropertyAccess(expression, createIdentifier(unescapeIdentifier(propertyName.text))); + } } } }