From 5496096ee36c4305007639df424ab9f04d4ea1ab Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 13 Apr 2017 10:29:32 -0700 Subject: [PATCH] Split addPrologue into string + custom directives The original function is now named addPrologue. There are then three places than need to call the two split functions separately. --- src/compiler/factory.ts | 27 ++++++++++++++++++++-- src/compiler/transformers/es2015.ts | 22 +++++++++++++----- src/compiler/transformers/es2017.ts | 2 +- src/compiler/transformers/esnext.ts | 15 ++++++++---- src/compiler/transformers/generators.ts | 2 +- src/compiler/transformers/module/es2015.ts | 2 +- src/compiler/transformers/module/module.ts | 4 ++-- src/compiler/transformers/module/system.ts | 2 +- src/compiler/transformers/ts.ts | 2 +- 9 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 5a4c4c032ee..a945f7c7c10 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3058,14 +3058,26 @@ namespace ts { * @param ensureUseStrict: boolean determining whether the function need to add prologue-directives * @param visitor: Optional callback used to visit any custom prologue directives. */ - export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number { + export function addPrologue(target: Statement[], source: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number { + const offset = addPrologueDirectives(target, source, ensureUseStrict); + return addCustomPrologue(target, source, offset, visitor); + } + + /** + * Add just the standard (string-expression) 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. + */ + export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean): number { + Debug.assert(target.length === 0, "Prologue directives should be at the first statement in the target statements array"); let foundUseStrict = false; let statementOffset = 0; const numStatements = source.length; while (statementOffset < numStatements) { const statement = source[statementOffset]; if (isPrologueDirective(statement)) { - if (isUseStrictPrologue(statement as ExpressionStatement)) { + if (isUseStrictPrologue(statement)) { foundUseStrict = true; } target.push(statement); @@ -3078,6 +3090,17 @@ namespace ts { if (ensureUseStrict && !foundUseStrict) { target.push(startOnNewLine(createStatement(createLiteral("use strict")))); } + return statementOffset; + } + + /** + * Add just the custom 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. + */ + export function addCustomPrologue(target: Statement[], source: Statement[], statementOffset: number, visitor?: (node: Node) => VisitResult): number { + const numStatements = source.length; while (statementOffset < numStatements) { const statement = source[statementOffset]; if (getEmitFlags(statement) & EmitFlags.CustomPrologue) { diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 3675571b720..897a4a57502 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -515,8 +515,9 @@ namespace ts { const ancestorFacts = enterSubtree(HierarchyFacts.SourceFileExcludes, HierarchyFacts.SourceFileIncludes); const statements: Statement[] = []; startLexicalEnvironment(); + let statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ false); addCaptureThisForNodeIfNeeded(statements, node); - const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ false, visitor); + statementOffset = addCustomPrologue(statements, node.statements, statementOffset, visitor); addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset)); addRange(statements, endLexicalEnvironment()); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); @@ -923,13 +924,16 @@ namespace ts { // The assumption is that no prior step in the pipeline has added any prologue directives. statementOffset = 0; } + else if (constructor) { + statementOffset = addPrologueDirectives(statements, constructor.body.statements, /*ensureUseStrict*/ false); + } if (constructor) { addDefaultValueAssignmentsIfNeeded(statements, constructor); addRestParameterIfNeeded(statements, constructor, hasSynthesizedSuper); if (!hasSynthesizedSuper) { - // If no super call has been synthesized, try to emit all potential prologue directives. - statementOffset = addPrologueDirectives(statements, constructor.body.statements, /*ensureUseStrict*/ false, visitor); + // If no super call has been synthesized, emit custom prologue directives. + statementOffset = addCustomPrologue(statements, constructor.body.statements, statementOffset, visitor); } Debug.assert(statementOffset >= 0, "statementOffset not initialized correctly!"); @@ -1816,8 +1820,15 @@ namespace ts { const statements: Statement[] = []; const body = node.body; + let statementOffset: number; resumeLexicalEnvironment(); + if (isBlock(body)) { + // ensureUseStrict is false because no new prologue-directive should be added. + // addPrologueDirectives will 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); @@ -1828,9 +1839,8 @@ namespace ts { } 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 - const statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor); + // addCustomPrologue puts already-existing directives at the beginning of the target statement-array + statementOffset = addCustomPrologue(statements, body.statements, statementOffset, visitor); statementsLocation = body.statements; addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset)); diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 088c57866d0..3bbb3b3123f 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -222,7 +222,7 @@ namespace ts { if (!isArrowFunction) { const statements: Statement[] = []; - const statementOffset = addPrologueDirectives(statements, (node.body).statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = addPrologue(statements, (node.body).statements, /*ensureUseStrict*/ false, visitor); statements.push( createReturn( createAwaiterHelper( diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 83e84e6eab5..b0e8b527820 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -618,7 +618,7 @@ namespace ts { function transformAsyncGeneratorFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody { resumeLexicalEnvironment(); const statements: Statement[] = []; - const statementOffset = addPrologueDirectives(statements, node.body.statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = addPrologue(statements, node.body.statements, /*ensureUseStrict*/ false, visitor); appendObjectRestAssignmentsIfNeeded(statements, node); statements.push( @@ -663,12 +663,19 @@ namespace ts { function transformFunctionBody(node: ArrowFunction): ConciseBody; function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody { resumeLexicalEnvironment(); - const leadingStatements = appendObjectRestAssignmentsIfNeeded(/*statements*/ undefined, node); + let statementOffset = 0; + const statements: Statement[] = []; const body = visitNode(node.body, visitor, isConciseBody); + if (isBlock(body)) { + statementOffset = addPrologue(statements, body.statements, /*ensureUseStrict*/ false, visitor); + } + addRange(statements, appendObjectRestAssignmentsIfNeeded(/*statements*/ undefined, node)); const trailingStatements = endLexicalEnvironment(); - if (some(leadingStatements) || some(trailingStatements)) { + if (statementOffset > 0 || some(statements) || some(trailingStatements)) { const block = convertToFunctionBody(body, /*multiLine*/ true); - return updateBlock(block, setTextRange(createNodeArray(concatenate(concatenate(leadingStatements, block.statements), trailingStatements)), block.statements)); + addRange(statements, block.statements.slice(statementOffset)); + addRange(statements, trailingStatements); + return updateBlock(block, setTextRange(createNodeArray(statements), block.statements)); } return body; } diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index d2f2162f455..3b361b1d524 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -587,7 +587,7 @@ namespace ts { // Build the generator resumeLexicalEnvironment(); - const statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = addPrologue(statements, body.statements, /*ensureUseStrict*/ false, visitor); transformAndEmitStatements(body.statements, statementOffset); diff --git a/src/compiler/transformers/module/es2015.ts b/src/compiler/transformers/module/es2015.ts index 7028e235961..660293e074f 100644 --- a/src/compiler/transformers/module/es2015.ts +++ b/src/compiler/transformers/module/es2015.ts @@ -24,7 +24,7 @@ namespace ts { const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(node, compilerOptions); if (externalHelpersModuleName) { const statements: Statement[] = []; - const statementOffset = addPrologueDirectives(statements, node.statements); + const statementOffset = addPrologue(statements, node.statements); append(statements, createImportDeclaration( /*decorators*/ undefined, diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 4fe7b027e93..d387a1a3a24 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -90,7 +90,7 @@ namespace ts { const statements: Statement[] = []; const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); - const statementOffset = addPrologueDirectives(statements, node.statements, ensureUseStrict, sourceElementVisitor); + const statementOffset = addPrologue(statements, node.statements, ensureUseStrict, sourceElementVisitor); if (shouldEmitUnderscoreUnderscoreESModule()) { append(statements, createUnderscoreUnderscoreESModule()); @@ -388,7 +388,7 @@ namespace ts { startLexicalEnvironment(); const statements: Statement[] = []; - const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor); + const statementOffset = addPrologue(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor); if (shouldEmitUnderscoreUnderscoreESModule()) { append(statements, createUnderscoreUnderscoreESModule()); diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 56341f482ff..cde4fcad57e 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -228,7 +228,7 @@ namespace ts { // Add any prologue directives. const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); - const statementOffset = addPrologueDirectives(statements, node.statements, ensureUseStrict, sourceElementVisitor); + const statementOffset = addPrologue(statements, node.statements, ensureUseStrict, sourceElementVisitor); // var __moduleName = context_1 && context_1.id; statements.push( diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 8df760d51c0..0daf76fa9ec 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -954,7 +954,7 @@ namespace ts { if (ctor.body) { const statements = ctor.body.statements; // add prologue directives to the list (if any) - const index = addPrologueDirectives(result, statements, /*ensureUseStrict*/ false, visitor); + const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor); if (index === statements.length) { // list contains nothing but prologue directives (or empty) - exit return index;