mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Remove EmitHelperState, general helper cleanup.
This commit is contained in:
+32
-25
@@ -1695,23 +1695,8 @@ namespace ts {
|
||||
|
||||
// Helpers
|
||||
|
||||
export interface EmitHelperState {
|
||||
currentSourceFile: SourceFile;
|
||||
compilerOptions: CompilerOptions;
|
||||
requestedHelpers?: EmitHelper[];
|
||||
}
|
||||
|
||||
export function getHelperName(helperState: EmitHelperState, name: string) {
|
||||
const externalHelpersModuleName = getOrCreateExternalHelpersModuleName(helperState.currentSourceFile, helperState.compilerOptions);
|
||||
return externalHelpersModuleName
|
||||
? createPropertyAccess(externalHelpersModuleName, name)
|
||||
: createIdentifier(name);
|
||||
}
|
||||
|
||||
export function requestEmitHelper(helperState: EmitHelperState, helper: EmitHelper) {
|
||||
if (!contains(helperState.requestedHelpers, helper)) {
|
||||
helperState.requestedHelpers = append(helperState.requestedHelpers, helper);
|
||||
}
|
||||
export function getHelperName(name: string) {
|
||||
return setEmitFlags(createIdentifier(name), EmitFlags.HelperName | EmitFlags.AdviseOnEmitNode);
|
||||
}
|
||||
|
||||
export interface CallBinding {
|
||||
@@ -2061,6 +2046,10 @@ namespace ts {
|
||||
|
||||
// Utilities
|
||||
|
||||
export function convertToFunctionBody(node: ConciseBody) {
|
||||
return isBlock(node) ? node : createBlock([createReturn(node, /*location*/ node)], /*location*/ node);
|
||||
}
|
||||
|
||||
function isUseStrictPrologue(node: ExpressionStatement): boolean {
|
||||
return (node.expression as StringLiteral).text === "use strict";
|
||||
}
|
||||
@@ -2110,6 +2099,13 @@ namespace ts {
|
||||
return statementOffset;
|
||||
}
|
||||
|
||||
export function startsWithUseStrict(statements: Statement[]) {
|
||||
const firstStatement = firstOrUndefined(statements);
|
||||
return firstStatement !== undefined
|
||||
&& isPrologueDirective(firstStatement)
|
||||
&& isUseStrictPrologue(firstStatement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures "use strict" directive is added
|
||||
*
|
||||
@@ -2606,7 +2602,7 @@ namespace ts {
|
||||
*
|
||||
* @param node The node.
|
||||
*/
|
||||
function getOrCreateEmitNode(node: Node) {
|
||||
export function getOrCreateEmitNode(node: Node) {
|
||||
if (!node.emitNode) {
|
||||
if (isParseTreeNode(node)) {
|
||||
// To avoid holding onto transformation artifacts, we keep track of any
|
||||
@@ -2735,14 +2731,25 @@ namespace ts {
|
||||
return emitNode && emitNode.externalHelpersModuleName;
|
||||
}
|
||||
|
||||
export function getOrCreateExternalHelpersModuleName(node: SourceFile, compilerOptions: CompilerOptions) {
|
||||
export function getOrCreateExternalHelpersModuleNameIfNeeded(node: SourceFile, compilerOptions: CompilerOptions) {
|
||||
if (compilerOptions.importHelpers && (isExternalModule(node) || compilerOptions.isolatedModules)) {
|
||||
const parseNode = getOriginalNode(node, isSourceFile);
|
||||
const emitNode = getOrCreateEmitNode(parseNode);
|
||||
return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText));
|
||||
const externalHelpersModuleName = getExternalHelpersModuleName(node);
|
||||
if (externalHelpersModuleName) {
|
||||
return externalHelpersModuleName;
|
||||
}
|
||||
|
||||
const helpers = getEmitHelpers(node);
|
||||
if (helpers) {
|
||||
for (const helper of helpers) {
|
||||
if (!helper.scoped) {
|
||||
const parseNode = getOriginalNode(node, isSourceFile);
|
||||
const emitNode = getOrCreateEmitNode(parseNode);
|
||||
return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an EmitHelper to a node.
|
||||
*/
|
||||
@@ -2930,7 +2937,7 @@ namespace ts {
|
||||
hasExportStarsToExportValues: boolean; // whether this module contains export*
|
||||
}
|
||||
|
||||
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver): ExternalModuleInfo {
|
||||
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo {
|
||||
const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = [];
|
||||
const exportSpecifiers = createMap<ExportSpecifier[]>();
|
||||
const exportedBindings = createMap<Identifier[]>();
|
||||
@@ -2940,7 +2947,7 @@ namespace ts {
|
||||
let exportEquals: ExportAssignment = undefined;
|
||||
let hasExportStarsToExportValues = false;
|
||||
|
||||
const externalHelpersModuleName = getExternalHelpersModuleName(sourceFile);
|
||||
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions);
|
||||
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
|
||||
+71
-107
@@ -26,84 +26,6 @@ namespace ts {
|
||||
EmitNotifications = 1 << 1,
|
||||
}
|
||||
|
||||
export interface TransformationResult {
|
||||
/**
|
||||
* Gets the transformed source files.
|
||||
*/
|
||||
transformed: SourceFile[];
|
||||
|
||||
/**
|
||||
* Emits the substitute for a node, if one is available; otherwise, emits the node.
|
||||
*
|
||||
* @param emitContext The current emit context.
|
||||
* @param node The node to substitute.
|
||||
* @param emitCallback A callback used to emit the node or its substitute.
|
||||
*/
|
||||
emitNodeWithSubstitution(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
|
||||
|
||||
/**
|
||||
* Emits a node with possible notification.
|
||||
*
|
||||
* @param emitContext The current emit context.
|
||||
* @param node The node to emit.
|
||||
* @param emitCallback A callback used to emit the node.
|
||||
*/
|
||||
emitNodeWithNotification(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
|
||||
}
|
||||
|
||||
export interface TransformationContext extends LexicalEnvironment {
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getEmitResolver(): EmitResolver;
|
||||
getEmitHost(): EmitHost;
|
||||
|
||||
/**
|
||||
* Hoists a function declaration to the containing scope.
|
||||
*/
|
||||
hoistFunctionDeclaration(node: FunctionDeclaration): void;
|
||||
|
||||
/**
|
||||
* Hoists a variable declaration to the containing scope.
|
||||
*/
|
||||
hoistVariableDeclaration(node: Identifier): void;
|
||||
|
||||
/**
|
||||
* Enables expression substitutions in the pretty printer for the provided SyntaxKind.
|
||||
*/
|
||||
enableSubstitution(kind: SyntaxKind): void;
|
||||
|
||||
/**
|
||||
* Determines whether expression substitutions are enabled for the provided node.
|
||||
*/
|
||||
isSubstitutionEnabled(node: Node): boolean;
|
||||
|
||||
/**
|
||||
* Hook used by transformers to substitute expressions just before they
|
||||
* are emitted by the pretty printer.
|
||||
*/
|
||||
onSubstituteNode?: (emitContext: EmitContext, node: Node) => Node;
|
||||
|
||||
/**
|
||||
* Enables before/after emit notifications in the pretty printer for the provided
|
||||
* SyntaxKind.
|
||||
*/
|
||||
enableEmitNotification(kind: SyntaxKind): void;
|
||||
|
||||
/**
|
||||
* Determines whether before/after emit notifications should be raised in the pretty
|
||||
* printer when it emits a node.
|
||||
*/
|
||||
isEmitNotificationEnabled(node: Node): boolean;
|
||||
|
||||
/**
|
||||
* Hook used to allow transformers to capture state before or after
|
||||
* the printer emits a node.
|
||||
*/
|
||||
onEmitNode?: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export type Transformer = (context: TransformationContext) => (node: SourceFile) => SourceFile;
|
||||
|
||||
export function getTransformers(compilerOptions: CompilerOptions) {
|
||||
const jsx = compilerOptions.jsx;
|
||||
const languageVersion = getEmitScriptTarget(compilerOptions);
|
||||
@@ -149,14 +71,18 @@ namespace ts {
|
||||
* @param transforms An array of Transformers.
|
||||
*/
|
||||
export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]): TransformationResult {
|
||||
const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
|
||||
const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
|
||||
const enabledSyntaxKindFeatures = new Array<SyntaxKindFeatureFlags>(SyntaxKind.Count);
|
||||
|
||||
let scopeModificationDisabled = false;
|
||||
|
||||
let lexicalEnvironmentVariableDeclarations: VariableDeclaration[];
|
||||
let lexicalEnvironmentFunctionDeclarations: FunctionDeclaration[];
|
||||
let lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
|
||||
let lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
|
||||
let lexicalEnvironmentStackOffset = 0;
|
||||
let hoistedVariableDeclarations: VariableDeclaration[];
|
||||
let hoistedFunctionDeclarations: FunctionDeclaration[];
|
||||
let lexicalEnvironmentDisabled: boolean;
|
||||
let lexicalEnvironmentSuspended = false;
|
||||
|
||||
let emitHelpers: EmitHelper[];
|
||||
|
||||
// The transformation context is provided to each transformer as part of transformer
|
||||
// initialization.
|
||||
@@ -164,10 +90,14 @@ namespace ts {
|
||||
getCompilerOptions: () => host.getCompilerOptions(),
|
||||
getEmitResolver: () => resolver,
|
||||
getEmitHost: () => host,
|
||||
startLexicalEnvironment,
|
||||
suspendLexicalEnvironment,
|
||||
resumeLexicalEnvironment,
|
||||
endLexicalEnvironment,
|
||||
hoistVariableDeclaration,
|
||||
hoistFunctionDeclaration,
|
||||
startLexicalEnvironment,
|
||||
endLexicalEnvironment,
|
||||
requestEmitHelper,
|
||||
readEmitHelpers,
|
||||
onSubstituteNode: (_emitContext, node) => node,
|
||||
enableSubstitution,
|
||||
isSubstitutionEnabled,
|
||||
@@ -183,7 +113,7 @@ namespace ts {
|
||||
const transformed = map(sourceFiles, transformSourceFile);
|
||||
|
||||
// Disable modification of the lexical environment.
|
||||
lexicalEnvironmentDisabled = true;
|
||||
scopeModificationDisabled = true;
|
||||
|
||||
return {
|
||||
transformed,
|
||||
@@ -278,13 +208,13 @@ namespace ts {
|
||||
* Records a hoisted variable declaration for the provided name within a lexical environment.
|
||||
*/
|
||||
function hoistVariableDeclaration(name: Identifier): void {
|
||||
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
|
||||
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
|
||||
const decl = createVariableDeclaration(name);
|
||||
if (!hoistedVariableDeclarations) {
|
||||
hoistedVariableDeclarations = [decl];
|
||||
if (!lexicalEnvironmentVariableDeclarations) {
|
||||
lexicalEnvironmentVariableDeclarations = [decl];
|
||||
}
|
||||
else {
|
||||
hoistedVariableDeclarations.push(decl);
|
||||
lexicalEnvironmentVariableDeclarations.push(decl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,31 +222,46 @@ namespace ts {
|
||||
* Records a hoisted function declaration within a lexical environment.
|
||||
*/
|
||||
function hoistFunctionDeclaration(func: FunctionDeclaration): void {
|
||||
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
|
||||
if (!hoistedFunctionDeclarations) {
|
||||
hoistedFunctionDeclarations = [func];
|
||||
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
|
||||
if (!lexicalEnvironmentFunctionDeclarations) {
|
||||
lexicalEnvironmentFunctionDeclarations = [func];
|
||||
}
|
||||
else {
|
||||
hoistedFunctionDeclarations.push(func);
|
||||
lexicalEnvironmentFunctionDeclarations.push(func);
|
||||
}
|
||||
}
|
||||
|
||||
/** Suspends the current lexical environment, usually after visiting a parameter list. */
|
||||
function suspendLexicalEnvironment(): void {
|
||||
Debug.assert(!scopeModificationDisabled, "Cannot suspend a lexical environment during the print phase.");
|
||||
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is already suspended.");
|
||||
lexicalEnvironmentSuspended = true;
|
||||
}
|
||||
|
||||
/** Resumes a suspended lexical environment, usually before visiting a function body. */
|
||||
function resumeLexicalEnvironment(): void {
|
||||
Debug.assert(!scopeModificationDisabled, "Cannot resume a lexical environment during the print phase.");
|
||||
Debug.assert(lexicalEnvironmentSuspended, "Lexical environment is not suspended suspended.");
|
||||
lexicalEnvironmentSuspended = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new lexical environment. Any existing hoisted variable or function declarations
|
||||
* are pushed onto a stack, and the related storage variables are reset.
|
||||
*/
|
||||
function startLexicalEnvironment(): void {
|
||||
Debug.assert(!lexicalEnvironmentDisabled, "Cannot start a lexical environment during the print phase.");
|
||||
Debug.assert(!scopeModificationDisabled, "Cannot start a lexical environment during the print phase.");
|
||||
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");
|
||||
|
||||
// Save the current lexical environment. Rather than resizing the array we adjust the
|
||||
// stack size variable. This allows us to reuse existing array slots we've
|
||||
// already allocated between transformations to avoid allocation and GC overhead during
|
||||
// transformation.
|
||||
lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = hoistedVariableDeclarations;
|
||||
lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = hoistedFunctionDeclarations;
|
||||
lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentVariableDeclarations;
|
||||
lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFunctionDeclarations;
|
||||
lexicalEnvironmentStackOffset++;
|
||||
hoistedVariableDeclarations = undefined;
|
||||
hoistedFunctionDeclarations = undefined;
|
||||
lexicalEnvironmentVariableDeclarations = undefined;
|
||||
lexicalEnvironmentFunctionDeclarations = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,18 +269,19 @@ namespace ts {
|
||||
* any hoisted declarations added in this environment are returned.
|
||||
*/
|
||||
function endLexicalEnvironment(): Statement[] {
|
||||
Debug.assert(!lexicalEnvironmentDisabled, "Cannot end a lexical environment during the print phase.");
|
||||
Debug.assert(!scopeModificationDisabled, "Cannot end a lexical environment during the print phase.");
|
||||
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");
|
||||
|
||||
let statements: Statement[];
|
||||
if (hoistedVariableDeclarations || hoistedFunctionDeclarations) {
|
||||
if (hoistedFunctionDeclarations) {
|
||||
statements = [...hoistedFunctionDeclarations];
|
||||
if (lexicalEnvironmentVariableDeclarations || lexicalEnvironmentFunctionDeclarations) {
|
||||
if (lexicalEnvironmentFunctionDeclarations) {
|
||||
statements = [...lexicalEnvironmentFunctionDeclarations];
|
||||
}
|
||||
|
||||
if (hoistedVariableDeclarations) {
|
||||
if (lexicalEnvironmentVariableDeclarations) {
|
||||
const statement = createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
createVariableDeclarationList(hoistedVariableDeclarations)
|
||||
createVariableDeclarationList(lexicalEnvironmentVariableDeclarations)
|
||||
);
|
||||
|
||||
if (!statements) {
|
||||
@@ -349,9 +295,27 @@ namespace ts {
|
||||
|
||||
// Restore the previous lexical environment.
|
||||
lexicalEnvironmentStackOffset--;
|
||||
hoistedVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
|
||||
hoistedFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
|
||||
lexicalEnvironmentVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
|
||||
lexicalEnvironmentFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
|
||||
if (lexicalEnvironmentStackOffset === 0) {
|
||||
lexicalEnvironmentVariableDeclarationsStack = [];
|
||||
lexicalEnvironmentFunctionDeclarationsStack = [];
|
||||
}
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
function requestEmitHelper(helper: EmitHelper): void {
|
||||
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
|
||||
Debug.assert(!helper.scoped, "Cannot request a scoped emit helper.");
|
||||
emitHelpers = append(emitHelpers, helper);
|
||||
}
|
||||
|
||||
function readEmitHelpers(): EmitHelper[] | undefined {
|
||||
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
|
||||
const helpers = emitHelpers;
|
||||
emitHelpers = undefined;
|
||||
return helpers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+131
-115
@@ -165,11 +165,11 @@ namespace ts {
|
||||
export function transformES2015(context: TransformationContext) {
|
||||
const {
|
||||
startLexicalEnvironment,
|
||||
resumeLexicalEnvironment,
|
||||
endLexicalEnvironment,
|
||||
hoistVariableDeclaration,
|
||||
} = context;
|
||||
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
const resolver = context.getEmitResolver();
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
@@ -187,7 +187,6 @@ namespace ts {
|
||||
let enclosingNonArrowFunction: FunctionLikeDeclaration;
|
||||
let enclosingNonAsyncFunctionBody: FunctionLikeDeclaration | ClassElement;
|
||||
let isInConstructorWithCapturedSuper: boolean;
|
||||
let helperState: EmitHelperState;
|
||||
|
||||
/**
|
||||
* Used to track if we are emitting body of the converted loop
|
||||
@@ -210,14 +209,12 @@ namespace ts {
|
||||
|
||||
currentSourceFile = node;
|
||||
currentText = node.text;
|
||||
helperState = { currentSourceFile, compilerOptions };
|
||||
|
||||
const visited = visitNode(node, visitor, isSourceFile);
|
||||
addEmitHelpers(visited, helperState.requestedHelpers);
|
||||
const visited = saveStateAndInvoke(node, visitSourceFile);
|
||||
addEmitHelpers(visited, context.readEmitHelpers());
|
||||
|
||||
currentSourceFile = undefined;
|
||||
currentText = undefined;
|
||||
helperState = undefined;
|
||||
return visited;
|
||||
}
|
||||
|
||||
@@ -264,6 +261,47 @@ namespace ts {
|
||||
return visited;
|
||||
}
|
||||
|
||||
function onBeforeVisitNode(node: Node) {
|
||||
if (currentNode) {
|
||||
if (isBlockScope(currentNode, currentParent)) {
|
||||
enclosingBlockScopeContainer = currentNode;
|
||||
enclosingBlockScopeContainerParent = currentParent;
|
||||
}
|
||||
|
||||
if (isFunctionLike(currentNode)) {
|
||||
enclosingFunction = currentNode;
|
||||
if (currentNode.kind !== SyntaxKind.ArrowFunction) {
|
||||
enclosingNonArrowFunction = currentNode;
|
||||
if (!(getEmitFlags(currentNode) & EmitFlags.AsyncFunctionBody)) {
|
||||
enclosingNonAsyncFunctionBody = currentNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// keep track of the enclosing variable statement when in the context of
|
||||
// variable statements, variable declarations, binding elements, and binding
|
||||
// patterns.
|
||||
switch (currentNode.kind) {
|
||||
case SyntaxKind.VariableStatement:
|
||||
enclosingVariableStatement = <VariableStatement>currentNode;
|
||||
break;
|
||||
|
||||
case SyntaxKind.VariableDeclarationList:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
break;
|
||||
|
||||
default:
|
||||
enclosingVariableStatement = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
currentParent = currentNode;
|
||||
currentNode = node;
|
||||
}
|
||||
|
||||
function returnCapturedThis(node: Node): Node {
|
||||
return setOriginalNode(createReturn(createIdentifier("_this")), node);
|
||||
}
|
||||
@@ -288,7 +326,7 @@ namespace ts {
|
||||
else if (node.transformFlags & TransformFlags.ContainsES2015 || (isInConstructorWithCapturedSuper && !isExpression(node))) {
|
||||
// we want to dive in this branch either if node has children with ES2015 specific syntax
|
||||
// or we are inside constructor that captures result of the super call so all returns without expression should be
|
||||
// rewritten. Note: we skip expressions since returns should never appear there
|
||||
// rewritten. Note: we skip expressions since returns should never appear there
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
else {
|
||||
@@ -426,6 +464,9 @@ namespace ts {
|
||||
case SyntaxKind.YieldExpression:
|
||||
return visitYieldExpression(<YieldExpression>node);
|
||||
|
||||
case SyntaxKind.SpreadElementExpression:
|
||||
return visitSpreadElementExpression(<SpreadElementExpression>node);
|
||||
|
||||
case SyntaxKind.SuperKeyword:
|
||||
return visitSuperKeyword();
|
||||
|
||||
@@ -436,9 +477,6 @@ namespace ts {
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
return visitMethodDeclaration(<MethodDeclaration>node);
|
||||
|
||||
case SyntaxKind.SourceFile:
|
||||
return visitSourceFileNode(<SourceFile>node);
|
||||
|
||||
case SyntaxKind.VariableStatement:
|
||||
return visitVariableStatement(<VariableStatement>node);
|
||||
|
||||
@@ -446,48 +484,19 @@ namespace ts {
|
||||
Debug.failBadSyntaxKind(node);
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onBeforeVisitNode(node: Node) {
|
||||
if (currentNode) {
|
||||
if (isBlockScope(currentNode, currentParent)) {
|
||||
enclosingBlockScopeContainer = currentNode;
|
||||
enclosingBlockScopeContainerParent = currentParent;
|
||||
}
|
||||
|
||||
if (isFunctionLike(currentNode)) {
|
||||
enclosingFunction = currentNode;
|
||||
if (currentNode.kind !== SyntaxKind.ArrowFunction) {
|
||||
enclosingNonArrowFunction = currentNode;
|
||||
if (!(getEmitFlags(currentNode) & EmitFlags.AsyncFunctionBody)) {
|
||||
enclosingNonAsyncFunctionBody = currentNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// keep track of the enclosing variable statement when in the context of
|
||||
// variable statements, variable declarations, binding elements, and binding
|
||||
// patterns.
|
||||
switch (currentNode.kind) {
|
||||
case SyntaxKind.VariableStatement:
|
||||
enclosingVariableStatement = <VariableStatement>currentNode;
|
||||
break;
|
||||
|
||||
case SyntaxKind.VariableDeclarationList:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
break;
|
||||
|
||||
default:
|
||||
enclosingVariableStatement = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
currentParent = currentNode;
|
||||
currentNode = node;
|
||||
function visitSourceFile(node: SourceFile): SourceFile {
|
||||
const statements: Statement[] = [];
|
||||
startLexicalEnvironment();
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ false, visitor);
|
||||
addCaptureThisForNodeIfNeeded(statements, node);
|
||||
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
|
||||
addRange(statements, endLexicalEnvironment());
|
||||
return updateSourceFileNode(
|
||||
node,
|
||||
createNodeArray(statements, node.statements)
|
||||
);
|
||||
}
|
||||
|
||||
function visitSwitchStatement(node: SwitchStatement): SwitchStatement {
|
||||
@@ -787,7 +796,7 @@ namespace ts {
|
||||
if (extendsClauseElement) {
|
||||
statements.push(
|
||||
createStatement(
|
||||
createExtendsHelper(helperState, getLocalName(node)),
|
||||
createExtendsHelper(context, getLocalName(node)),
|
||||
/*location*/ extendsClauseElement
|
||||
)
|
||||
);
|
||||
@@ -837,11 +846,8 @@ namespace ts {
|
||||
// `super` call.
|
||||
// If this is the case, we do not include the synthetic `...args` parameter and
|
||||
// will instead use the `arguments` object in ES5/3.
|
||||
if (constructor && !hasSynthesizedSuper) {
|
||||
return visitNodes(constructor.parameters, visitor, isParameter);
|
||||
}
|
||||
|
||||
return [];
|
||||
return visitParameterList(constructor && !hasSynthesizedSuper && constructor.parameters, visitor, context)
|
||||
|| [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -855,14 +861,14 @@ namespace ts {
|
||||
*/
|
||||
function transformConstructorBody(constructor: ConstructorDeclaration | undefined, node: ClassDeclaration | ClassExpression, extendsClauseElement: ExpressionWithTypeArguments, hasSynthesizedSuper: boolean) {
|
||||
const statements: Statement[] = [];
|
||||
startLexicalEnvironment();
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
let statementOffset = -1;
|
||||
if (hasSynthesizedSuper) {
|
||||
// If a super call has already been synthesized,
|
||||
// we're going to assume that we should just transform everything after that.
|
||||
// The assumption is that no prior step in the pipeline has added any prologue directives.
|
||||
statementOffset = 1;
|
||||
statementOffset = 0;
|
||||
}
|
||||
else if (constructor) {
|
||||
// Otherwise, try to emit all potential prologue directives first.
|
||||
@@ -1386,20 +1392,13 @@ namespace ts {
|
||||
function transformClassMethodDeclarationToStatement(receiver: LeftHandSideExpression, member: MethodDeclaration) {
|
||||
const commentRange = getCommentRange(member);
|
||||
const sourceMapRange = getSourceMapRange(member);
|
||||
|
||||
const func = transformFunctionLikeToExpression(member, /*location*/ member, /*name*/ undefined);
|
||||
setEmitFlags(func, EmitFlags.NoComments);
|
||||
setSourceMapRange(func, sourceMapRange);
|
||||
const memberName = createMemberAccessForPropertyName(receiver, visitNode(member.name, visitor, isPropertyName), /*location*/ member.name);
|
||||
const memberFunction = transformFunctionLikeToExpression(member, /*location*/ member, /*name*/ undefined);
|
||||
setEmitFlags(memberFunction, EmitFlags.NoComments);
|
||||
setSourceMapRange(memberFunction, sourceMapRange);
|
||||
|
||||
const statement = createStatement(
|
||||
createAssignment(
|
||||
createMemberAccessForPropertyName(
|
||||
receiver,
|
||||
visitNode(member.name, visitor, isPropertyName),
|
||||
/*location*/ member.name
|
||||
),
|
||||
func
|
||||
),
|
||||
createAssignment(memberName, memberFunction),
|
||||
/*location*/ member
|
||||
);
|
||||
|
||||
@@ -1497,8 +1496,17 @@ namespace ts {
|
||||
if (node.transformFlags & TransformFlags.ContainsLexicalThis) {
|
||||
enableSubstitutionsForCapturedThis();
|
||||
}
|
||||
|
||||
const func = transformFunctionLikeToExpression(node, /*location*/ node, /*name*/ undefined);
|
||||
const func = createFunctionExpression(
|
||||
/*modifiers*/ undefined,
|
||||
/*asteriskToken*/ undefined,
|
||||
/*name*/ undefined,
|
||||
/*typeParameters*/ undefined,
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
node
|
||||
);
|
||||
setOriginalNode(func, node);
|
||||
setEmitFlags(func, EmitFlags.CapturesThis);
|
||||
return func;
|
||||
}
|
||||
@@ -1509,7 +1517,17 @@ namespace ts {
|
||||
* @param node a FunctionExpression node.
|
||||
*/
|
||||
function visitFunctionExpression(node: FunctionExpression): Expression {
|
||||
return transformFunctionLikeToExpression(node, /*location*/ node, node.name);
|
||||
return updateFunctionExpression(
|
||||
node,
|
||||
/*modifiers*/ undefined,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
node.transformFlags & TransformFlags.ES2015
|
||||
? transformFunctionBody(node)
|
||||
: visitFunctionBody(node.body, visitor, context)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1518,19 +1536,18 @@ namespace ts {
|
||||
* @param node a FunctionDeclaration node.
|
||||
*/
|
||||
function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration {
|
||||
return setOriginalNode(
|
||||
createFunctionDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
node.modifiers,
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
),
|
||||
/*original*/ node);
|
||||
return updateFunctionDeclaration(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
node.modifiers,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
node.transformFlags & TransformFlags.ES2015
|
||||
? transformFunctionBody(node)
|
||||
: visitFunctionBody(node.body, visitor, context)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1552,7 +1569,7 @@ namespace ts {
|
||||
node.asteriskToken,
|
||||
name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
saveStateAndInvoke(node, transformFunctionBody),
|
||||
location
|
||||
@@ -1579,7 +1596,8 @@ namespace ts {
|
||||
const body = node.body;
|
||||
let statementOffset: number;
|
||||
|
||||
startLexicalEnvironment();
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
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
|
||||
@@ -1633,15 +1651,21 @@ namespace ts {
|
||||
closeBraceLocation = body;
|
||||
}
|
||||
|
||||
const lexicalEnvironment = endLexicalEnvironment();
|
||||
addRange(statements, lexicalEnvironment);
|
||||
const declarations = endLexicalEnvironment();
|
||||
addRange(statements, declarations);
|
||||
|
||||
// If we added any final generated statements, this must be a multi-line block
|
||||
if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) {
|
||||
if (!multiLine && declarations && declarations.length) {
|
||||
multiLine = true;
|
||||
}
|
||||
|
||||
const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine);
|
||||
const block = createBlock(
|
||||
createNodeArray(statements, statementsLocation),
|
||||
node.body,
|
||||
multiLine);
|
||||
|
||||
setOriginalNode(block, node.body);
|
||||
|
||||
if (!multiLine && singleLine) {
|
||||
setEmitFlags(block, EmitFlags.SingleLine);
|
||||
}
|
||||
@@ -1650,7 +1674,6 @@ namespace ts {
|
||||
setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation);
|
||||
}
|
||||
|
||||
setOriginalNode(block, node.body);
|
||||
return block;
|
||||
}
|
||||
|
||||
@@ -1659,7 +1682,7 @@ namespace ts {
|
||||
*
|
||||
* @param node An ExpressionStatement node.
|
||||
*/
|
||||
function visitExpressionStatement(node: ExpressionStatement): ExpressionStatement {
|
||||
function visitExpressionStatement(node: ExpressionStatement): Statement {
|
||||
// If we are here it is most likely because our expression is a destructuring assignment.
|
||||
switch (node.expression.kind) {
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
@@ -1713,8 +1736,11 @@ namespace ts {
|
||||
*/
|
||||
function visitBinaryExpression(node: BinaryExpression, needsDestructuringValue: boolean): Expression {
|
||||
// If we are here it is because this is a destructuring assignment.
|
||||
Debug.assert(isDestructuringAssignment(node));
|
||||
return flattenDestructuringAssignment(context, node, needsDestructuringValue, hoistVariableDeclaration, visitor);
|
||||
if (isDestructuringAssignment(node)) {
|
||||
return flattenDestructuringAssignment(context, node, needsDestructuringValue, hoistVariableDeclaration, visitor);
|
||||
}
|
||||
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitVariableStatement(node: VariableStatement): Statement {
|
||||
@@ -2894,6 +2920,10 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function visitSpreadElementExpression(node: SpreadElementExpression) {
|
||||
return visitNode(node.expression, visitor, isExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the expression of a SpreadElementExpression node.
|
||||
*
|
||||
@@ -3080,19 +3110,6 @@ namespace ts {
|
||||
: createIdentifier("_super");
|
||||
}
|
||||
|
||||
function visitSourceFileNode(node: SourceFile): SourceFile {
|
||||
const [prologue, remaining] = span(node.statements, isPrologueDirective);
|
||||
const statements: Statement[] = [];
|
||||
startLexicalEnvironment();
|
||||
addRange(statements, prologue);
|
||||
addCaptureThisForNodeIfNeeded(statements, node);
|
||||
addRange(statements, visitNodes(createNodeArray(remaining), visitor, isStatement));
|
||||
addRange(statements, endLexicalEnvironment());
|
||||
const clone = getMutableClone(node);
|
||||
clone.statements = createNodeArray(statements, /*location*/ node.statements);
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the printer just before a node is printed.
|
||||
*
|
||||
@@ -3254,8 +3271,7 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parameter = singleOrUndefined(constructor.parameters);
|
||||
if (!parameter || !nodeIsSynthesized(parameter) || !parameter.dotDotDotToken) {
|
||||
if (some(constructor.parameters)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3280,14 +3296,14 @@ namespace ts {
|
||||
}
|
||||
|
||||
const expression = (<SpreadElementExpression>callArgument).expression;
|
||||
return isIdentifier(expression) && expression === parameter.name;
|
||||
return isIdentifier(expression) && expression.text === "arguments";
|
||||
}
|
||||
}
|
||||
|
||||
function createExtendsHelper(helperState: EmitHelperState, name: Identifier) {
|
||||
requestEmitHelper(helperState, extendsHelper);
|
||||
function createExtendsHelper(context: TransformationContext, name: Identifier) {
|
||||
context.requestEmitHelper(extendsHelper);
|
||||
return createCall(
|
||||
getHelperName(helperState, "__extends"),
|
||||
getHelperName("__extends"),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
name,
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace ts {
|
||||
export function transformES2017(context: TransformationContext) {
|
||||
const {
|
||||
startLexicalEnvironment,
|
||||
resumeLexicalEnvironment,
|
||||
endLexicalEnvironment,
|
||||
} = context;
|
||||
|
||||
@@ -22,7 +23,6 @@ namespace ts {
|
||||
|
||||
// These variables contain state that changes as we descend into the tree.
|
||||
let currentSourceFile: SourceFile;
|
||||
let helperState: EmitHelperState;
|
||||
|
||||
/**
|
||||
* Keeps track of whether expression substitution has been enabled for specific edge cases.
|
||||
@@ -50,8 +50,6 @@ namespace ts {
|
||||
context.onEmitNode = onEmitNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
|
||||
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
|
||||
|
||||
return transformSourceFile;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
@@ -60,14 +58,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
currentSourceFile = node;
|
||||
helperState = { currentSourceFile, compilerOptions };
|
||||
|
||||
const visited = visitEachChild(node, visitor, context);
|
||||
|
||||
addEmitHelpers(visited, helperState.requestedHelpers);
|
||||
addEmitHelpers(visited, context.readEmitHelpers());
|
||||
|
||||
currentSourceFile = undefined;
|
||||
helperState = undefined;
|
||||
return visited;
|
||||
}
|
||||
|
||||
@@ -142,22 +137,17 @@ namespace ts {
|
||||
*/
|
||||
function visitMethodDeclaration(node: MethodDeclaration) {
|
||||
Debug.assert(hasModifier(node, ModifierFlags.Async));
|
||||
const method = createMethod(
|
||||
const updated = updateMethod(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
transformFunctionBody(node)
|
||||
);
|
||||
|
||||
// While we emit the source map for the node after skipping decorators and modifiers,
|
||||
// we need to emit the comments for the original range.
|
||||
setOriginalNode(method, node);
|
||||
return method;
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,20 +160,17 @@ namespace ts {
|
||||
*/
|
||||
function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult<Statement> {
|
||||
Debug.assert(hasModifier(node, ModifierFlags.Async));
|
||||
const func = createFunctionDeclaration(
|
||||
const updated = updateFunctionDeclaration(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
transformFunctionBody(node)
|
||||
);
|
||||
|
||||
setOriginalNode(func, node);
|
||||
return func;
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,20 +186,18 @@ namespace ts {
|
||||
if (nodeIsMissing(node.body)) {
|
||||
return createOmittedExpression();
|
||||
}
|
||||
|
||||
const func = createFunctionExpression(
|
||||
/*modifiers*/ undefined,
|
||||
node.asteriskToken,
|
||||
const updated = updateFunctionExpression(
|
||||
node,
|
||||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
transformFunctionBody(node)
|
||||
);
|
||||
|
||||
setOriginalNode(func, node);
|
||||
return func;
|
||||
setOriginalNode(updated, node);
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,42 +210,24 @@ namespace ts {
|
||||
*/
|
||||
function visitArrowFunction(node: ArrowFunction) {
|
||||
Debug.assert(hasModifier(node, ModifierFlags.Async));
|
||||
const func = createArrowFunction(
|
||||
const updated = updateArrowFunction(
|
||||
node,
|
||||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
node.equalsGreaterThanToken,
|
||||
transformConciseBody(node),
|
||||
/*location*/ node
|
||||
transformFunctionBody(node)
|
||||
);
|
||||
|
||||
setOriginalNode(func, node);
|
||||
return func;
|
||||
setOriginalNode(updated, node);
|
||||
return updated;
|
||||
}
|
||||
|
||||
function transformFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody {
|
||||
return <FunctionBody>transformAsyncFunctionBody(node);
|
||||
}
|
||||
|
||||
function transformConciseBody(node: ArrowFunction): ConciseBody {
|
||||
return transformAsyncFunctionBody(node);
|
||||
}
|
||||
|
||||
function transformFunctionBodyWorker(body: Block, start = 0) {
|
||||
const savedCurrentScope = currentScope;
|
||||
currentScope = body;
|
||||
startLexicalEnvironment();
|
||||
|
||||
const statements = visitNodes(body.statements, visitor, isStatement, start);
|
||||
const visited = updateBlock(body, statements);
|
||||
const declarations = endLexicalEnvironment();
|
||||
currentScope = savedCurrentScope;
|
||||
return mergeFunctionBodyLexicalEnvironment(visited, declarations);
|
||||
}
|
||||
|
||||
function transformAsyncFunctionBody(node: FunctionLikeDeclaration): ConciseBody | FunctionBody {
|
||||
const nodeType = node.original ? (<FunctionLikeDeclaration>node.original).type : node.type;
|
||||
function transformFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody;
|
||||
function transformFunctionBody(node: ArrowFunction): ConciseBody;
|
||||
function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody {
|
||||
const original = getOriginalNode(node, isFunctionLike);
|
||||
const nodeType = original.type;
|
||||
const promiseConstructor = languageVersion < ScriptTarget.ES2015 ? getPromiseConstructor(nodeType) : undefined;
|
||||
const isArrowFunction = node.kind === SyntaxKind.ArrowFunction;
|
||||
const hasLexicalArguments = (resolver.getNodeCheckFlags(node) & NodeCheckFlags.CaptureArguments) !== 0;
|
||||
@@ -271,6 +238,7 @@ namespace ts {
|
||||
// passed to `__awaiter` is executed inside of the callback to the
|
||||
// promise constructor.
|
||||
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
if (!isArrowFunction) {
|
||||
const statements: Statement[] = [];
|
||||
@@ -278,7 +246,7 @@ namespace ts {
|
||||
statements.push(
|
||||
createReturn(
|
||||
createAwaiterHelper(
|
||||
helperState,
|
||||
context,
|
||||
hasLexicalArguments,
|
||||
promiseConstructor,
|
||||
transformFunctionBodyWorker(<Block>node.body, statementOffset)
|
||||
@@ -286,6 +254,8 @@ namespace ts {
|
||||
)
|
||||
);
|
||||
|
||||
addRange(statements, endLexicalEnvironment());
|
||||
|
||||
const block = createBlock(statements, /*location*/ node.body, /*multiLine*/ true);
|
||||
|
||||
// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
|
||||
@@ -304,37 +274,40 @@ namespace ts {
|
||||
return block;
|
||||
}
|
||||
else {
|
||||
return createAwaiterHelper(
|
||||
helperState,
|
||||
const expression = createAwaiterHelper(
|
||||
context,
|
||||
hasLexicalArguments,
|
||||
promiseConstructor,
|
||||
<Block>transformConciseBodyWorker(node.body, /*forceBlockFunctionBody*/ true)
|
||||
transformFunctionBodyWorker(node.body)
|
||||
);
|
||||
|
||||
const declarations = endLexicalEnvironment();
|
||||
if (some(declarations)) {
|
||||
const block = convertToFunctionBody(expression);
|
||||
const statements = mergeLexicalEnvironment(block.statements, declarations);
|
||||
return updateBlock(block, statements);
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
function transformConciseBodyWorker(body: Block | Expression, forceBlockFunctionBody: boolean) {
|
||||
function transformFunctionBodyWorker(body: ConciseBody, start?: number) {
|
||||
if (isBlock(body)) {
|
||||
return transformFunctionBodyWorker(body);
|
||||
return updateBlock(
|
||||
body,
|
||||
visitLexicalEnvironment(body.statements, visitor, context, start));
|
||||
}
|
||||
else {
|
||||
startLexicalEnvironment();
|
||||
const visited: Expression | Block = visitNode(body, visitor, isConciseBody);
|
||||
const declarations = endLexicalEnvironment();
|
||||
const merged = mergeFunctionBodyLexicalEnvironment(visited, declarations);
|
||||
if (forceBlockFunctionBody && !isBlock(merged)) {
|
||||
return createBlock([
|
||||
createReturn(<Expression>merged)
|
||||
]);
|
||||
}
|
||||
else {
|
||||
return merged;
|
||||
}
|
||||
const visited = convertToFunctionBody(visitNode(body, visitor, isConciseBody));
|
||||
const statements = mergeLexicalEnvironment(visited.statements, endLexicalEnvironment());
|
||||
return updateBlock(visited, statements);
|
||||
}
|
||||
}
|
||||
|
||||
function getPromiseConstructor(type: TypeNode) {
|
||||
const typeName = getEntityNameFromTypeNode(type);
|
||||
const typeName = type && getEntityNameFromTypeNode(type);
|
||||
if (typeName && isEntityName(typeName)) {
|
||||
const serializationKind = resolver.getTypeReferenceSerializationKind(typeName);
|
||||
if (serializationKind === TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue
|
||||
@@ -506,7 +479,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createAwaiterHelper(helperState: EmitHelperState, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression, body: Block) {
|
||||
function createAwaiterHelper(context: TransformationContext, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression, body: Block) {
|
||||
context.requestEmitHelper(awaiterHelper);
|
||||
const generatorFunc = createFunctionExpression(
|
||||
/*modifiers*/ undefined,
|
||||
createToken(SyntaxKind.AsteriskToken),
|
||||
@@ -520,9 +494,8 @@ namespace ts {
|
||||
// Mark this node as originally an async function
|
||||
(generatorFunc.emitNode || (generatorFunc.emitNode = {})).flags |= EmitFlags.AsyncFunctionBody;
|
||||
|
||||
requestEmitHelper(helperState, awaiterHelper);
|
||||
return createCall(
|
||||
getHelperName(helperState, "__awaiter"),
|
||||
getHelperName("__awaiter"),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
createThis(),
|
||||
|
||||
@@ -242,7 +242,6 @@ namespace ts {
|
||||
let currentSourceFile: SourceFile;
|
||||
let renamedCatchVariables: Map<boolean>;
|
||||
let renamedCatchVariableDeclarations: Map<Identifier>;
|
||||
let helperState: EmitHelperState;
|
||||
|
||||
let inGeneratorFunctionBody: boolean;
|
||||
let inStatementContainingYield: boolean;
|
||||
@@ -298,13 +297,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
currentSourceFile = node;
|
||||
helperState = { currentSourceFile, compilerOptions };
|
||||
|
||||
const visited = visitEachChild(node, visitor, context);
|
||||
addEmitHelpers(visited, helperState.requestedHelpers);
|
||||
addEmitHelpers(visited, context.readEmitHelpers());
|
||||
|
||||
currentSourceFile = undefined;
|
||||
helperState = undefined;
|
||||
return visited;
|
||||
}
|
||||
|
||||
@@ -2590,7 +2587,7 @@ namespace ts {
|
||||
|
||||
const buildResult = buildStatements();
|
||||
return createGeneratorHelper(
|
||||
helperState,
|
||||
context,
|
||||
setEmitFlags(
|
||||
createFunctionExpression(
|
||||
/*modifiers*/ undefined,
|
||||
@@ -3083,10 +3080,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createGeneratorHelper(helperState: EmitHelperState, body: FunctionExpression) {
|
||||
requestEmitHelper(helperState, generatorHelper);
|
||||
function createGeneratorHelper(context: TransformationContext, body: FunctionExpression) {
|
||||
context.requestEmitHelper(generatorHelper);
|
||||
return createCall(
|
||||
getHelperName(helperState, "__generator"),
|
||||
getHelperName("__generator"),
|
||||
/*typeArguments*/ undefined,
|
||||
[createThis(), body]);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace ts {
|
||||
export function transformJsx(context: TransformationContext) {
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
let currentSourceFile: SourceFile;
|
||||
let helperState: EmitHelperState;
|
||||
|
||||
return transformSourceFile;
|
||||
|
||||
@@ -21,13 +20,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
currentSourceFile = node;
|
||||
helperState = { currentSourceFile, compilerOptions };
|
||||
|
||||
const visited = visitEachChild(node, visitor, context);
|
||||
addEmitHelpers(visited, helperState.requestedHelpers);
|
||||
addEmitHelpers(visited, context.readEmitHelpers());
|
||||
|
||||
currentSourceFile = undefined;
|
||||
helperState = undefined;
|
||||
return visited;
|
||||
}
|
||||
|
||||
@@ -116,7 +113,7 @@ namespace ts {
|
||||
// a call to the __assign helper.
|
||||
objectProperties = singleOrUndefined(segments);
|
||||
if (!objectProperties) {
|
||||
objectProperties = createAssignHelper(helperState, segments);
|
||||
objectProperties = createAssignHelper(context, segments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,10 +535,10 @@ namespace ts {
|
||||
"diams": 0x2666
|
||||
});
|
||||
|
||||
function createAssignHelper(helperState: EmitHelperState, attributesSegments: Expression[]) {
|
||||
requestEmitHelper(helperState, assignHelper);
|
||||
function createAssignHelper(context: TransformationContext, attributesSegments: Expression[]) {
|
||||
context.requestEmitHelper(assignHelper);
|
||||
return createCall(
|
||||
getHelperName(helperState, "__assign"),
|
||||
getHelperName("__assign"),
|
||||
/*typeArguments*/ undefined,
|
||||
attributesSegments
|
||||
);
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
namespace ts {
|
||||
export function transformES2015Module(context: TransformationContext) {
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
context.enableEmitNotification(SyntaxKind.SourceFile);
|
||||
context.enableSubstitution(SyntaxKind.Identifier);
|
||||
|
||||
let currentSourceFile: SourceFile;
|
||||
return transformSourceFile;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
@@ -13,7 +21,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (isExternalModule(node) || compilerOptions.isolatedModules) {
|
||||
const externalHelpersModuleName = getExternalHelpersModuleName(node);
|
||||
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(node, compilerOptions);
|
||||
if (externalHelpersModuleName) {
|
||||
const statements: Statement[] = [];
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements);
|
||||
@@ -55,5 +63,55 @@ namespace ts {
|
||||
// Elide `export=` as it is not legal with --module ES6
|
||||
return node.isExportEquals ? undefined : node;
|
||||
}
|
||||
|
||||
//
|
||||
// Emit Notification
|
||||
//
|
||||
|
||||
/**
|
||||
* Hook for node emit.
|
||||
*
|
||||
* @param emitContext A context hint for the emitter.
|
||||
* @param node The node to emit.
|
||||
* @param emit A callback used to emit the node in the printer.
|
||||
*/
|
||||
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
|
||||
if (isSourceFile(node)) {
|
||||
currentSourceFile = node;
|
||||
previousOnEmitNode(emitContext, node, emitCallback);
|
||||
currentSourceFile = undefined;
|
||||
}
|
||||
else {
|
||||
previousOnEmitNode(emitContext, node, emitCallback);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Substitutions
|
||||
//
|
||||
|
||||
/**
|
||||
* Hooks node substitutions.
|
||||
*
|
||||
* @param emitContext A context hint for the emitter.
|
||||
* @param node The node to substitute.
|
||||
*/
|
||||
function onSubstituteNode(emitContext: EmitContext, node: Node) {
|
||||
node = previousOnSubstituteNode(emitContext, node);
|
||||
if (isIdentifier(node) && emitContext === EmitContext.Expression) {
|
||||
return substituteExpressionIdentifier(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function substituteExpressionIdentifier(node: Identifier): Expression {
|
||||
if (getEmitFlags(node) & EmitFlags.HelperName) {
|
||||
const externalHelpersModuleName = getExternalHelpersModuleName(currentSourceFile);
|
||||
if (externalHelpersModuleName) {
|
||||
return createPropertyAccess(externalHelpersModuleName, node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
currentSourceFile = node;
|
||||
currentModuleInfo = moduleInfoMap[getOriginalNodeId(node)] = collectExternalModuleInfo(node, resolver);
|
||||
currentModuleInfo = moduleInfoMap[getOriginalNodeId(node)] = collectExternalModuleInfo(node, resolver, compilerOptions);
|
||||
|
||||
// Perform the transformation.
|
||||
const transformModule = transformModuleDelegates[moduleKind] || transformModuleDelegates[ModuleKind.None];
|
||||
@@ -1187,6 +1187,14 @@ namespace ts {
|
||||
* @param node The node to substitute.
|
||||
*/
|
||||
function substituteExpressionIdentifier(node: Identifier): Expression {
|
||||
if (getEmitFlags(node) & EmitFlags.HelperName) {
|
||||
const externalHelpersModuleName = getExternalHelpersModuleName(currentSourceFile);
|
||||
if (externalHelpersModuleName) {
|
||||
return createPropertyAccess(externalHelpersModuleName, node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
if (!isGeneratedIdentifier(node) && !isLocalName(node)) {
|
||||
const exportContainer = resolver.getReferencedExportContainer(node, isExportName(node));
|
||||
if (exportContainer && exportContainer.kind === SyntaxKind.SourceFile) {
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace ts {
|
||||
// see comment to 'substitutePostfixUnaryExpression' for more details
|
||||
|
||||
// Collect information about the external module and dependency groups.
|
||||
moduleInfo = moduleInfoMap[id] = collectExternalModuleInfo(node, resolver);
|
||||
moduleInfo = moduleInfoMap[id] = collectExternalModuleInfo(node, resolver, compilerOptions);
|
||||
|
||||
// Make sure that the name of the 'exports' function does not conflict with
|
||||
// existing identifiers.
|
||||
@@ -1609,6 +1609,14 @@ namespace ts {
|
||||
* @param node The node to substitute.
|
||||
*/
|
||||
function substituteExpressionIdentifier(node: Identifier): Expression {
|
||||
if (getEmitFlags(node) & EmitFlags.HelperName) {
|
||||
const externalHelpersModuleName = getExternalHelpersModuleName(currentSourceFile);
|
||||
if (externalHelpersModuleName) {
|
||||
return createPropertyAccess(externalHelpersModuleName, node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
// When we see an identifier in an expression position that
|
||||
// points to an imported symbol, we should substitute a qualified
|
||||
// reference to the imported symbol if one is needed.
|
||||
|
||||
+138
-207
@@ -21,6 +21,7 @@ namespace ts {
|
||||
export function transformTypeScript(context: TransformationContext) {
|
||||
const {
|
||||
startLexicalEnvironment,
|
||||
resumeLexicalEnvironment,
|
||||
endLexicalEnvironment,
|
||||
hoistVariableDeclaration,
|
||||
} = context;
|
||||
@@ -48,7 +49,6 @@ namespace ts {
|
||||
let currentNamespaceContainerName: Identifier;
|
||||
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
|
||||
let currentScopeFirstDeclarationsOfName: Map<Node>;
|
||||
let helperState: EmitHelperState;
|
||||
|
||||
/**
|
||||
* Keeps track of whether expression substitution has been enabled for specific edge cases.
|
||||
@@ -81,21 +81,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
currentSourceFile = node;
|
||||
currentScope = node;
|
||||
currentScopeFirstDeclarationsOfName = createMap<Node>();
|
||||
helperState = { currentSourceFile, compilerOptions };
|
||||
|
||||
let visited = visitEachChild(node, sourceElementVisitor, context);
|
||||
if (compilerOptions.alwaysStrict) {
|
||||
visited = updateSourceFileNode(visited, ensureUseStrict(visited.statements));
|
||||
}
|
||||
|
||||
addEmitHelpers(visited, helperState.requestedHelpers);
|
||||
const visited = saveStateAndInvoke(node, visitSourceFile);
|
||||
addEmitHelpers(visited, context.readEmitHelpers());
|
||||
|
||||
currentSourceFile = undefined;
|
||||
currentScope = undefined;
|
||||
currentScopeFirstDeclarationsOfName = undefined;
|
||||
helperState = undefined;
|
||||
return visited;
|
||||
}
|
||||
|
||||
@@ -123,6 +113,32 @@ namespace ts {
|
||||
return visited;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs actions that should always occur immediately before visiting a node.
|
||||
*
|
||||
* @param node The node to visit.
|
||||
*/
|
||||
function onBeforeVisitNode(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.CaseBlock:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
case SyntaxKind.Block:
|
||||
currentScope = <SourceFile | CaseBlock | ModuleBlock | Block>node;
|
||||
currentScopeFirstDeclarationsOfName = undefined;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
if (hasModifier(node, ModifierFlags.Ambient)) {
|
||||
break;
|
||||
}
|
||||
|
||||
recordEmittedDeclarationInScope(node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* General-purpose node visitor.
|
||||
*
|
||||
@@ -451,29 +467,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs actions that should always occur immediately before visiting a node.
|
||||
*
|
||||
* @param node The node to visit.
|
||||
*/
|
||||
function onBeforeVisitNode(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.CaseBlock:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
case SyntaxKind.Block:
|
||||
currentScope = <SourceFile | CaseBlock | ModuleBlock | Block>node;
|
||||
currentScopeFirstDeclarationsOfName = undefined;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
if (hasModifier(node, ModifierFlags.Ambient)) {
|
||||
break;
|
||||
}
|
||||
|
||||
recordEmittedDeclarationInScope(node);
|
||||
break;
|
||||
}
|
||||
function visitSourceFile(node: SourceFile) {
|
||||
return updateSourceFileNode(
|
||||
node,
|
||||
visitLexicalEnvironment(node.statements, sourceElementVisitor, context, /*start*/ 0, compilerOptions.alwaysStrict));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -845,9 +842,8 @@ namespace ts {
|
||||
// downlevel the '...args' portion less efficiently by naively copying the contents of 'arguments' to an array.
|
||||
// Instead, we'll avoid using a rest parameter and spread into the super call as
|
||||
// 'super(...arguments)' instead of 'super(...args)', as you can see in "transformConstructorBody".
|
||||
return constructor
|
||||
? visitNodes(constructor.parameters, visitor, isParameter)
|
||||
: <ParameterDeclaration[]>[];
|
||||
return visitParameterList(constructor && constructor.parameters, visitor, context)
|
||||
|| <ParameterDeclaration[]>[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -863,7 +859,7 @@ namespace ts {
|
||||
let indexOfFirstStatement = 0;
|
||||
|
||||
// The body of a constructor is a new lexical environment
|
||||
startLexicalEnvironment();
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
if (constructor) {
|
||||
indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements);
|
||||
@@ -919,15 +915,13 @@ namespace ts {
|
||||
|
||||
// End the lexical environment.
|
||||
addRange(statements, endLexicalEnvironment());
|
||||
return setMultiLine(
|
||||
createBlock(
|
||||
createNodeArray(
|
||||
statements,
|
||||
/*location*/ constructor ? constructor.body.statements : node.members
|
||||
),
|
||||
/*location*/ constructor ? constructor.body : /*location*/ undefined
|
||||
return createBlock(
|
||||
createNodeArray(
|
||||
statements,
|
||||
/*location*/ constructor ? constructor.body.statements : node.members
|
||||
),
|
||||
true
|
||||
/*location*/ constructor ? constructor.body : /*location*/ undefined,
|
||||
/*multiLine*/ true
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1385,7 +1379,7 @@ namespace ts {
|
||||
: undefined;
|
||||
|
||||
const helper = createDecorateHelper(
|
||||
helperState,
|
||||
context,
|
||||
decoratorExpressions,
|
||||
prefix,
|
||||
memberName,
|
||||
@@ -1423,7 +1417,7 @@ namespace ts {
|
||||
|
||||
const classAlias = classAliases && classAliases[getOriginalNodeId(node)];
|
||||
const localName = getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true);
|
||||
const decorate = createDecorateHelper(helperState, decoratorExpressions, localName);
|
||||
const decorate = createDecorateHelper(context, decoratorExpressions, localName);
|
||||
const expression = createAssignment(localName, classAlias ? createAssignment(classAlias, decorate) : decorate);
|
||||
setEmitFlags(expression, EmitFlags.NoComments);
|
||||
setSourceMapRange(expression, moveRangePastDecorators(node));
|
||||
@@ -1451,7 +1445,7 @@ namespace ts {
|
||||
expressions = [];
|
||||
for (const decorator of decorators) {
|
||||
const helper = createParamHelper(
|
||||
helperState,
|
||||
context,
|
||||
transformDecorator(decorator),
|
||||
parameterOffset,
|
||||
/*location*/ decorator.expression);
|
||||
@@ -1481,13 +1475,13 @@ namespace ts {
|
||||
function addOldTypeMetadata(node: Declaration, decoratorExpressions: Expression[]) {
|
||||
if (compilerOptions.emitDecoratorMetadata) {
|
||||
if (shouldAddTypeMetadata(node)) {
|
||||
decoratorExpressions.push(createMetadataHelper(helperState, "design:type", serializeTypeOfNode(node)));
|
||||
decoratorExpressions.push(createMetadataHelper(context, "design:type", serializeTypeOfNode(node)));
|
||||
}
|
||||
if (shouldAddParamTypesMetadata(node)) {
|
||||
decoratorExpressions.push(createMetadataHelper(helperState, "design:paramtypes", serializeParameterTypesOfNode(node)));
|
||||
decoratorExpressions.push(createMetadataHelper(context, "design:paramtypes", serializeParameterTypesOfNode(node)));
|
||||
}
|
||||
if (shouldAddReturnTypeMetadata(node)) {
|
||||
decoratorExpressions.push(createMetadataHelper(helperState, "design:returntype", serializeReturnTypeOfNode(node)));
|
||||
decoratorExpressions.push(createMetadataHelper(context, "design:returntype", serializeReturnTypeOfNode(node)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1505,7 +1499,7 @@ namespace ts {
|
||||
(properties || (properties = [])).push(createPropertyAssignment("returnType", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, createToken(SyntaxKind.EqualsGreaterThanToken), serializeReturnTypeOfNode(node))));
|
||||
}
|
||||
if (properties) {
|
||||
decoratorExpressions.push(createMetadataHelper(helperState, "design:typeinfo", createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true)));
|
||||
decoratorExpressions.push(createMetadataHelper(context, "design:typeinfo", createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2020,26 +2014,23 @@ namespace ts {
|
||||
if (!shouldEmitFunctionLikeDeclaration(node)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const method = createMethod(
|
||||
const updated = updateMethod(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
visitNodes(node.modifiers, modifierVisitor, isModifier),
|
||||
node.asteriskToken,
|
||||
visitPropertyNameOfClassElement(node),
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
visitFunctionBody(node.body, visitor, context)
|
||||
);
|
||||
|
||||
// While we emit the source map for the node after skipping decorators and modifiers,
|
||||
// we need to emit the comments for the original range.
|
||||
setCommentRange(method, node);
|
||||
setSourceMapRange(method, moveRangePastDecorators(node));
|
||||
setOriginalNode(method, node);
|
||||
|
||||
return method;
|
||||
if (updated !== node) {
|
||||
// While we emit the source map for the node after skipping decorators and modifiers,
|
||||
// we need to emit the comments for the original range.
|
||||
setCommentRange(updated, node);
|
||||
setSourceMapRange(updated, moveRangePastDecorators(node));
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2065,24 +2056,22 @@ namespace ts {
|
||||
if (!shouldEmitAccessorDeclaration(node)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const accessor = createGetAccessor(
|
||||
const updated = updateGetAccessor(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
visitNodes(node.modifiers, modifierVisitor, isModifier),
|
||||
visitPropertyNameOfClassElement(node),
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
node.body ? visitEachChild(node.body, visitor, context) : createBlock([]),
|
||||
/*location*/ node
|
||||
visitFunctionBody(node.body, visitor, context) || createBlock([])
|
||||
);
|
||||
|
||||
// While we emit the source map for the node after skipping decorators and modifiers,
|
||||
// we need to emit the comments for the original range.
|
||||
setOriginalNode(accessor, node);
|
||||
setCommentRange(accessor, node);
|
||||
setSourceMapRange(accessor, moveRangePastDecorators(node));
|
||||
|
||||
return accessor;
|
||||
if (updated !== node) {
|
||||
// While we emit the source map for the node after skipping decorators and modifiers,
|
||||
// we need to emit the comments for the original range.
|
||||
setCommentRange(updated, node);
|
||||
setSourceMapRange(updated, moveRangePastDecorators(node));
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2098,23 +2087,21 @@ namespace ts {
|
||||
if (!shouldEmitAccessorDeclaration(node)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const accessor = createSetAccessor(
|
||||
const updated = updateSetAccessor(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
visitNodes(node.modifiers, modifierVisitor, isModifier),
|
||||
visitPropertyNameOfClassElement(node),
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
node.body ? visitEachChild(node.body, visitor, context) : createBlock([]),
|
||||
/*location*/ node
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
visitFunctionBody(node.body, visitor, context) || createBlock([])
|
||||
);
|
||||
|
||||
// While we emit the source map for the node after skipping decorators and modifiers,
|
||||
// we need to emit the comments for the original range.
|
||||
setOriginalNode(accessor, node);
|
||||
setCommentRange(accessor, node);
|
||||
setSourceMapRange(accessor, moveRangePastDecorators(node));
|
||||
|
||||
return accessor;
|
||||
if (updated !== node) {
|
||||
// While we emit the source map for the node after skipping decorators and modifiers,
|
||||
// we need to emit the comments for the original range.
|
||||
setCommentRange(updated, node);
|
||||
setSourceMapRange(updated, moveRangePastDecorators(node));
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2131,27 +2118,22 @@ namespace ts {
|
||||
if (!shouldEmitFunctionLikeDeclaration(node)) {
|
||||
return createNotEmittedStatement(node);
|
||||
}
|
||||
|
||||
const func = createFunctionDeclaration(
|
||||
const updated = updateFunctionDeclaration(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
visitNodes(node.modifiers, modifierVisitor, isModifier),
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
visitFunctionBody(node.body, visitor, context) || createBlock([])
|
||||
);
|
||||
setOriginalNode(func, node);
|
||||
|
||||
if (isNamespaceExport(node)) {
|
||||
const statements: Statement[] = [func];
|
||||
const statements: Statement[] = [updated];
|
||||
addExportMemberAssignment(statements, node);
|
||||
return statements;
|
||||
}
|
||||
|
||||
return func;
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2166,21 +2148,16 @@ namespace ts {
|
||||
if (nodeIsMissing(node.body)) {
|
||||
return createOmittedExpression();
|
||||
}
|
||||
|
||||
const func = createFunctionExpression(
|
||||
const updated = updateFunctionExpression(
|
||||
node,
|
||||
visitNodes(node.modifiers, modifierVisitor, isModifier),
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
visitFunctionBody(node.body, visitor, context)
|
||||
);
|
||||
|
||||
setOriginalNode(func, node);
|
||||
|
||||
return func;
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2189,62 +2166,15 @@ namespace ts {
|
||||
* - The node has type annotations
|
||||
*/
|
||||
function visitArrowFunction(node: ArrowFunction) {
|
||||
const func = createArrowFunction(
|
||||
const updated = updateArrowFunction(
|
||||
node,
|
||||
visitNodes(node.modifiers, modifierVisitor, isModifier),
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
node.equalsGreaterThanToken,
|
||||
transformConciseBody(node),
|
||||
/*location*/ node
|
||||
visitFunctionBody(node.body, visitor, context)
|
||||
);
|
||||
|
||||
setOriginalNode(func, node);
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
function transformFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody {
|
||||
return transformFunctionBodyWorker(node.body);
|
||||
}
|
||||
|
||||
function transformFunctionBodyWorker(body: Block, start = 0) {
|
||||
const savedCurrentScope = currentScope;
|
||||
const savedCurrentScopeFirstDeclarationsOfName = currentScopeFirstDeclarationsOfName;
|
||||
currentScope = body;
|
||||
currentScopeFirstDeclarationsOfName = createMap<Node>();
|
||||
startLexicalEnvironment();
|
||||
|
||||
const statements = visitNodes(body.statements, visitor, isStatement, start);
|
||||
const visited = updateBlock(body, statements);
|
||||
const declarations = endLexicalEnvironment();
|
||||
currentScope = savedCurrentScope;
|
||||
currentScopeFirstDeclarationsOfName = savedCurrentScopeFirstDeclarationsOfName;
|
||||
return mergeFunctionBodyLexicalEnvironment(visited, declarations);
|
||||
}
|
||||
|
||||
function transformConciseBody(node: ArrowFunction): ConciseBody {
|
||||
return transformConciseBodyWorker(node.body, /*forceBlockFunctionBody*/ false);
|
||||
}
|
||||
|
||||
function transformConciseBodyWorker(body: Block | Expression, forceBlockFunctionBody: boolean) {
|
||||
if (isBlock(body)) {
|
||||
return transformFunctionBodyWorker(body);
|
||||
}
|
||||
else {
|
||||
startLexicalEnvironment();
|
||||
const visited: Expression | Block = visitNode(body, visitor, isConciseBody);
|
||||
const declarations = endLexicalEnvironment();
|
||||
const merged = mergeFunctionBodyLexicalEnvironment(visited, declarations);
|
||||
if (forceBlockFunctionBody && !isBlock(merged)) {
|
||||
return createBlock([
|
||||
createReturn(<Expression>merged)
|
||||
]);
|
||||
}
|
||||
else {
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3316,7 +3246,7 @@ namespace ts {
|
||||
|
||||
function trySubstituteNamespaceExportedName(node: Identifier): Expression {
|
||||
// If this is explicitly a local name, do not substitute.
|
||||
if (enabledSubstitutions & applicableSubstitutions && !isLocalName(node)) {
|
||||
if (enabledSubstitutions & applicableSubstitutions && !isGeneratedIdentifier(node) && !isLocalName(node)) {
|
||||
// If we are nested within a namespace declaration, we may need to qualifiy
|
||||
// an identifier that is exported from a merged namespace.
|
||||
const container = resolver.getReferencedExportContainer(node, /*prefixLocals*/ false);
|
||||
@@ -3372,10 +3302,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createParamHelper(helperState: EmitHelperState, expression: Expression, parameterOffset: number, location?: TextRange) {
|
||||
requestEmitHelper(helperState, paramHelper);
|
||||
const paramHelper: EmitHelper = {
|
||||
name: "typescript:param",
|
||||
scoped: false,
|
||||
priority: 4,
|
||||
text: `
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};`
|
||||
};
|
||||
|
||||
function createParamHelper(context: TransformationContext, expression: Expression, parameterOffset: number, location?: TextRange) {
|
||||
context.requestEmitHelper(paramHelper);
|
||||
return createCall(
|
||||
getHelperName(helperState, "__param"),
|
||||
getHelperName("__param"),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
createLiteral(parameterOffset),
|
||||
@@ -3385,10 +3325,20 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function createMetadataHelper(helperState: EmitHelperState, metadataKey: string, metadataValue: Expression) {
|
||||
requestEmitHelper(helperState, metadataHelper);
|
||||
const metadataHelper: EmitHelper = {
|
||||
name: "typescript:metadata",
|
||||
scoped: false,
|
||||
priority: 3,
|
||||
text: `
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};`
|
||||
};
|
||||
|
||||
function createMetadataHelper(context: TransformationContext, metadataKey: string, metadataValue: Expression) {
|
||||
context.requestEmitHelper(metadataHelper);
|
||||
return createCall(
|
||||
getHelperName(helperState, "__metadata"),
|
||||
getHelperName("__metadata"),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
createLiteral(metadataKey),
|
||||
@@ -3397,20 +3347,6 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function createDecorateHelper(helperState: EmitHelperState, decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression, location?: TextRange) {
|
||||
const argumentsArray: Expression[] = [];
|
||||
argumentsArray.push(createArrayLiteral(decoratorExpressions, /*location*/ undefined, /*multiLine*/ true));
|
||||
argumentsArray.push(target);
|
||||
if (memberName) {
|
||||
argumentsArray.push(memberName);
|
||||
if (descriptor) {
|
||||
argumentsArray.push(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
requestEmitHelper(helperState, decorateHelper);
|
||||
return createCall(getHelperName(helperState, "__decorate"), /*typeArguments*/ undefined, argumentsArray, location);
|
||||
}
|
||||
|
||||
const decorateHelper: EmitHelper = {
|
||||
name: "typescript:decorate",
|
||||
@@ -3425,23 +3361,18 @@ namespace ts {
|
||||
};`
|
||||
};
|
||||
|
||||
const metadataHelper: EmitHelper = {
|
||||
name: "typescript:metadata",
|
||||
scoped: false,
|
||||
priority: 3,
|
||||
text: `
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};`
|
||||
};
|
||||
function createDecorateHelper(context: TransformationContext, decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression, location?: TextRange) {
|
||||
context.requestEmitHelper(decorateHelper);
|
||||
const argumentsArray: Expression[] = [];
|
||||
argumentsArray.push(createArrayLiteral(decoratorExpressions, /*location*/ undefined, /*multiLine*/ true));
|
||||
argumentsArray.push(target);
|
||||
if (memberName) {
|
||||
argumentsArray.push(memberName);
|
||||
if (descriptor) {
|
||||
argumentsArray.push(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
const paramHelper: EmitHelper = {
|
||||
name: "typescript:param",
|
||||
scoped: false,
|
||||
priority: 4,
|
||||
text: `
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};`
|
||||
};
|
||||
return createCall(getHelperName("__decorate"), /*typeArguments*/ undefined, argumentsArray, location);
|
||||
}
|
||||
}
|
||||
|
||||
+124
-11
@@ -1503,6 +1503,11 @@ namespace ts {
|
||||
expression: Expression;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface PrologueDirective extends ExpressionStatement {
|
||||
expression: StringLiteral;
|
||||
}
|
||||
|
||||
export interface IfStatement extends Statement {
|
||||
kind: SyntaxKind.IfStatement;
|
||||
expression: Expression;
|
||||
@@ -3541,15 +3546,16 @@ namespace ts {
|
||||
NoTrailingComments = 1 << 10, // Do not emit trailing comments for this node.
|
||||
NoComments = NoLeadingComments | NoTrailingComments, // Do not emit comments for this node.
|
||||
NoNestedComments = 1 << 11,
|
||||
ExportName = 1 << 12, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal).
|
||||
LocalName = 1 << 13, // Ensure an export prefix is not added for an identifier that points to an exported declaration.
|
||||
Indented = 1 << 14, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter).
|
||||
NoIndentation = 1 << 15, // Do not indent the node.
|
||||
AsyncFunctionBody = 1 << 16,
|
||||
ReuseTempVariableScope = 1 << 17, // Reuse the existing temp variable scope during emit.
|
||||
CustomPrologue = 1 << 18, // Treat the statement as if it were a prologue directive (NOTE: Prologue directives are *not* transformed).
|
||||
NoHoisting = 1 << 19, // Do not hoist this declaration in --module system
|
||||
HasEndOfDeclarationMarker = 1 << 20, // Declaration has an associated NotEmittedStatement to mark the end of the declaration
|
||||
HelperName = 1 << 12,
|
||||
ExportName = 1 << 13, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal).
|
||||
LocalName = 1 << 14, // Ensure an export prefix is not added for an identifier that points to an exported declaration.
|
||||
Indented = 1 << 15, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter).
|
||||
NoIndentation = 1 << 16, // Do not indent the node.
|
||||
AsyncFunctionBody = 1 << 17,
|
||||
ReuseTempVariableScope = 1 << 18, // Reuse the existing temp variable scope during emit.
|
||||
CustomPrologue = 1 << 19, // Treat the statement as if it were a prologue directive (NOTE: Prologue directives are *not* transformed).
|
||||
NoHoisting = 1 << 20, // Do not hoist this declaration in --module system
|
||||
HasEndOfDeclarationMarker = 1 << 21, // Declaration has an associated NotEmittedStatement to mark the end of the declaration
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -3568,16 +3574,123 @@ namespace ts {
|
||||
Unspecified, // Emitting an otherwise unspecified node
|
||||
}
|
||||
|
||||
/** Additional context provided to `visitEachChild` */
|
||||
/* @internal */
|
||||
export interface LexicalEnvironment {
|
||||
export interface EmitHost extends ScriptReferenceHost {
|
||||
getSourceFiles(): SourceFile[];
|
||||
|
||||
/* @internal */
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
|
||||
getCommonSourceDirectory(): string;
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
getNewLine(): string;
|
||||
|
||||
isEmitBlocked(emitFileName: string): boolean;
|
||||
|
||||
writeFile: WriteFileCallback;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface TransformationContext {
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getEmitResolver(): EmitResolver;
|
||||
getEmitHost(): EmitHost;
|
||||
|
||||
/** Starts a new lexical environment. */
|
||||
startLexicalEnvironment(): void;
|
||||
|
||||
/** Suspends the current lexical environment, usually after visiting a parameter list. */
|
||||
suspendLexicalEnvironment(): void;
|
||||
|
||||
/** Resumes a suspended lexical environment, usually before visiting a function body. */
|
||||
resumeLexicalEnvironment(): void;
|
||||
|
||||
/** Ends a lexical environment, returning any declarations. */
|
||||
endLexicalEnvironment(): Statement[];
|
||||
|
||||
/**
|
||||
* Hoists a function declaration to the containing scope.
|
||||
*/
|
||||
hoistFunctionDeclaration(node: FunctionDeclaration): void;
|
||||
|
||||
/**
|
||||
* Hoists a variable declaration to the containing scope.
|
||||
*/
|
||||
hoistVariableDeclaration(node: Identifier): void;
|
||||
|
||||
/**
|
||||
* Records a request for a non-scoped emit helper in the current context.
|
||||
*/
|
||||
requestEmitHelper(helper: EmitHelper): void;
|
||||
|
||||
/**
|
||||
* Gets and resets the requested non-scoped emit helpers.
|
||||
*/
|
||||
readEmitHelpers(): EmitHelper[] | undefined;
|
||||
|
||||
/**
|
||||
* Enables expression substitutions in the pretty printer for the provided SyntaxKind.
|
||||
*/
|
||||
enableSubstitution(kind: SyntaxKind): void;
|
||||
|
||||
/**
|
||||
* Determines whether expression substitutions are enabled for the provided node.
|
||||
*/
|
||||
isSubstitutionEnabled(node: Node): boolean;
|
||||
|
||||
/**
|
||||
* Hook used by transformers to substitute expressions just before they
|
||||
* are emitted by the pretty printer.
|
||||
*/
|
||||
onSubstituteNode?: (emitContext: EmitContext, node: Node) => Node;
|
||||
|
||||
/**
|
||||
* Enables before/after emit notifications in the pretty printer for the provided
|
||||
* SyntaxKind.
|
||||
*/
|
||||
enableEmitNotification(kind: SyntaxKind): void;
|
||||
|
||||
/**
|
||||
* Determines whether before/after emit notifications should be raised in the pretty
|
||||
* printer when it emits a node.
|
||||
*/
|
||||
isEmitNotificationEnabled(node: Node): boolean;
|
||||
|
||||
/**
|
||||
* Hook used to allow transformers to capture state before or after
|
||||
* the printer emits a node.
|
||||
*/
|
||||
onEmitNode?: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface TransformationResult {
|
||||
/**
|
||||
* Gets the transformed source files.
|
||||
*/
|
||||
transformed: SourceFile[];
|
||||
|
||||
/**
|
||||
* Emits the substitute for a node, if one is available; otherwise, emits the node.
|
||||
*
|
||||
* @param emitContext The current emit context.
|
||||
* @param node The node to substitute.
|
||||
* @param emitCallback A callback used to emit the node or its substitute.
|
||||
*/
|
||||
emitNodeWithSubstitution(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
|
||||
|
||||
/**
|
||||
* Emits a node with possible notification.
|
||||
*
|
||||
* @param emitContext The current emit context.
|
||||
* @param node The node to emit.
|
||||
* @param emitCallback A callback used to emit the node.
|
||||
*/
|
||||
emitNodeWithNotification(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export type Transformer = (context: TransformationContext) => (node: SourceFile) => SourceFile;
|
||||
|
||||
export interface TextSpan {
|
||||
start: number;
|
||||
|
||||
@@ -28,21 +28,6 @@ namespace ts {
|
||||
string(): string;
|
||||
}
|
||||
|
||||
export interface EmitHost extends ScriptReferenceHost {
|
||||
getSourceFiles(): SourceFile[];
|
||||
|
||||
/* @internal */
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
|
||||
getCommonSourceDirectory(): string;
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
getNewLine(): string;
|
||||
|
||||
isEmitBlocked(emitFileName: string): boolean;
|
||||
|
||||
writeFile: WriteFileCallback;
|
||||
}
|
||||
|
||||
// Pool writers to avoid needing to allocate them for every symbol we write.
|
||||
const stringWriters: StringSymbolWriter[] = [];
|
||||
export function getSingleLineStringWriter(): StringSymbolWriter {
|
||||
@@ -595,8 +580,9 @@ namespace ts {
|
||||
return n.kind === SyntaxKind.CallExpression && (<CallExpression>n).expression.kind === SyntaxKind.SuperKeyword;
|
||||
}
|
||||
|
||||
export function isPrologueDirective(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.ExpressionStatement && (<ExpressionStatement>node).expression.kind === SyntaxKind.StringLiteral;
|
||||
export function isPrologueDirective(node: Node): node is PrologueDirective {
|
||||
return node.kind === SyntaxKind.ExpressionStatement
|
||||
&& (<ExpressionStatement>node).expression.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
|
||||
export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode: SourceFile) {
|
||||
|
||||
+82
-35
@@ -653,6 +653,53 @@ namespace ts {
|
||||
return updated || nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new lexical environment and visits a statement list, ending the lexical environment
|
||||
* and merging hoisted declarations upon completion.
|
||||
*/
|
||||
export function visitLexicalEnvironment(statements: NodeArray<Statement>, visitor: (node: Node) => VisitResult<Node>, context: TransformationContext, start?: number, ensureUseStrict?: boolean) {
|
||||
context.startLexicalEnvironment();
|
||||
statements = visitNodes(statements, visitor, isStatement, start);
|
||||
if (ensureUseStrict && !startsWithUseStrict(statements)) {
|
||||
statements = createNodeArray([createStatement(createLiteral("use strict")), ...statements], statements);
|
||||
}
|
||||
statements = mergeLexicalEnvironment(statements, context.endLexicalEnvironment());
|
||||
return statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new lexical environment and visits a parameter list, suspending the lexical
|
||||
* environment upon completion.
|
||||
*/
|
||||
export function visitParameterList(nodes: NodeArray<ParameterDeclaration>, visitor: (node: Node) => VisitResult<Node>, context: TransformationContext) {
|
||||
context.startLexicalEnvironment();
|
||||
const updated = visitNodes(nodes, visitor, isParameterDeclaration);
|
||||
context.suspendLexicalEnvironment();
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes a suspended lexical environment and visits a function body, ending the lexical
|
||||
* environment and merging hoisted declarations upon completion.
|
||||
*/
|
||||
export function visitFunctionBody(node: FunctionBody, visitor: (node: Node) => VisitResult<Node>, context: TransformationContext, optional?: boolean): FunctionBody;
|
||||
/**
|
||||
* Resumes a suspended lexical environment and visits a concise body, ending the lexical
|
||||
* environment and merging hoisted declarations upon completion.
|
||||
*/
|
||||
export function visitFunctionBody(node: ConciseBody, visitor: (node: Node) => VisitResult<Node>, context: TransformationContext): ConciseBody;
|
||||
export function visitFunctionBody(node: ConciseBody, visitor: (node: Node) => VisitResult<Node>, context: TransformationContext, optional?: boolean): ConciseBody {
|
||||
context.resumeLexicalEnvironment();
|
||||
const updated = visitNode(node, visitor, isConciseBody, optional);
|
||||
const declarations = context.endLexicalEnvironment();
|
||||
if (some(declarations)) {
|
||||
const block = convertToFunctionBody(updated);
|
||||
const statements = mergeLexicalEnvironment(block.statements, declarations);
|
||||
return updateBlock(block, statements);
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits each child of a Node using the supplied visitor, possibly returning a new Node of the same kind in its place.
|
||||
*
|
||||
@@ -660,8 +707,8 @@ namespace ts {
|
||||
* @param visitor The callback used to visit each child.
|
||||
* @param context A lexical environment context for the visitor.
|
||||
*/
|
||||
export function visitEachChild<T extends Node>(node: T, visitor: (node: Node) => VisitResult<Node>, context: LexicalEnvironment): T;
|
||||
export function visitEachChild(node: Node, visitor: (node: Node) => VisitResult<Node>, context: LexicalEnvironment): Node {
|
||||
export function visitEachChild<T extends Node>(node: T, visitor: (node: Node) => VisitResult<Node>, context: TransformationContext): T;
|
||||
export function visitEachChild(node: Node, visitor: (node: Node) => VisitResult<Node>, context: TransformationContext): Node {
|
||||
if (node === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -714,41 +761,33 @@ namespace ts {
|
||||
visitNodes((<MethodDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<MethodDeclaration>node).name, visitor, isPropertyName),
|
||||
visitNodes((<MethodDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
(context.startLexicalEnvironment(), visitNodes((<MethodDeclaration>node).parameters, visitor, isParameter)),
|
||||
visitParameterList((<MethodDeclaration>node).parameters, visitor, context),
|
||||
visitNode((<MethodDeclaration>node).type, visitor, isTypeNode, /*optional*/ true),
|
||||
mergeFunctionBodyLexicalEnvironment(
|
||||
visitNode((<MethodDeclaration>node).body, visitor, isFunctionBody, /*optional*/ true),
|
||||
context.endLexicalEnvironment()));
|
||||
visitFunctionBody((<MethodDeclaration>node).body, visitor, context, /*optional*/ true));
|
||||
|
||||
case SyntaxKind.Constructor:
|
||||
return updateConstructor(<ConstructorDeclaration>node,
|
||||
visitNodes((<ConstructorDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<ConstructorDeclaration>node).modifiers, visitor, isModifier),
|
||||
(context.startLexicalEnvironment(), visitNodes((<ConstructorDeclaration>node).parameters, visitor, isParameter)),
|
||||
mergeFunctionBodyLexicalEnvironment(
|
||||
visitNode((<ConstructorDeclaration>node).body, visitor, isFunctionBody, /*optional*/ true),
|
||||
context.endLexicalEnvironment()));
|
||||
visitParameterList((<ConstructorDeclaration>node).parameters, visitor, context),
|
||||
visitFunctionBody((<ConstructorDeclaration>node).body, visitor, context, /*optional*/ true));
|
||||
|
||||
case SyntaxKind.GetAccessor:
|
||||
return updateGetAccessor(<GetAccessorDeclaration>node,
|
||||
visitNodes((<GetAccessorDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<GetAccessorDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<GetAccessorDeclaration>node).name, visitor, isPropertyName),
|
||||
(context.startLexicalEnvironment(), visitNodes((<GetAccessorDeclaration>node).parameters, visitor, isParameter)),
|
||||
visitParameterList((<GetAccessorDeclaration>node).parameters, visitor, context),
|
||||
visitNode((<GetAccessorDeclaration>node).type, visitor, isTypeNode, /*optional*/ true),
|
||||
mergeFunctionBodyLexicalEnvironment(
|
||||
visitNode((<GetAccessorDeclaration>node).body, visitor, isFunctionBody, /*optional*/ true),
|
||||
context.endLexicalEnvironment()));
|
||||
visitFunctionBody((<GetAccessorDeclaration>node).body, visitor, context, /*optional*/ true));
|
||||
|
||||
case SyntaxKind.SetAccessor:
|
||||
return updateSetAccessor(<SetAccessorDeclaration>node,
|
||||
visitNodes((<SetAccessorDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<SetAccessorDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<SetAccessorDeclaration>node).name, visitor, isPropertyName),
|
||||
(context.startLexicalEnvironment(), visitNodes((<SetAccessorDeclaration>node).parameters, visitor, isParameter)),
|
||||
mergeFunctionBodyLexicalEnvironment(
|
||||
visitNode((<SetAccessorDeclaration>node).body, visitor, isFunctionBody, /*optional*/ true),
|
||||
context.endLexicalEnvironment()));
|
||||
visitParameterList((<SetAccessorDeclaration>node).parameters, visitor, context),
|
||||
visitFunctionBody((<SetAccessorDeclaration>node).body, visitor, context, /*optional*/ true));
|
||||
|
||||
// Binding patterns
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
@@ -810,21 +849,17 @@ namespace ts {
|
||||
visitNodes((<FunctionExpression>node).modifiers, visitor, isModifier),
|
||||
visitNode((<FunctionExpression>node).name, visitor, isPropertyName),
|
||||
visitNodes((<FunctionExpression>node).typeParameters, visitor, isTypeParameter),
|
||||
(context.startLexicalEnvironment(), visitNodes((<FunctionExpression>node).parameters, visitor, isParameter)),
|
||||
visitParameterList((<FunctionExpression>node).parameters, visitor, context),
|
||||
visitNode((<FunctionExpression>node).type, visitor, isTypeNode, /*optional*/ true),
|
||||
mergeFunctionBodyLexicalEnvironment(
|
||||
visitNode((<FunctionExpression>node).body, visitor, isFunctionBody, /*optional*/ true),
|
||||
context.endLexicalEnvironment()));
|
||||
visitFunctionBody((<FunctionExpression>node).body, visitor, context, /*optional*/ true));
|
||||
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return updateArrowFunction(<ArrowFunction>node,
|
||||
visitNodes((<ArrowFunction>node).modifiers, visitor, isModifier),
|
||||
visitNodes((<ArrowFunction>node).typeParameters, visitor, isTypeParameter),
|
||||
(context.startLexicalEnvironment(), visitNodes((<ArrowFunction>node).parameters, visitor, isParameter)),
|
||||
visitParameterList((<ArrowFunction>node).parameters, visitor, context),
|
||||
visitNode((<ArrowFunction>node).type, visitor, isTypeNode, /*optional*/ true),
|
||||
mergeFunctionBodyLexicalEnvironment(
|
||||
visitNode((<ArrowFunction>node).body, visitor, isConciseBody, /*optional*/ true),
|
||||
context.endLexicalEnvironment()));
|
||||
visitFunctionBody((<ArrowFunction>node).body, visitor, context));
|
||||
|
||||
case SyntaxKind.DeleteExpression:
|
||||
return updateDelete(<DeleteExpression>node,
|
||||
@@ -995,11 +1030,9 @@ namespace ts {
|
||||
visitNodes((<FunctionDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<FunctionDeclaration>node).name, visitor, isPropertyName),
|
||||
visitNodes((<FunctionDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
(context.startLexicalEnvironment(), visitNodes((<FunctionDeclaration>node).parameters, visitor, isParameter)),
|
||||
visitParameterList((<FunctionDeclaration>node).parameters, visitor, context),
|
||||
visitNode((<FunctionDeclaration>node).type, visitor, isTypeNode, /*optional*/ true),
|
||||
mergeFunctionBodyLexicalEnvironment(
|
||||
visitNode((<FunctionDeclaration>node).body, visitor, isFunctionBody, /*optional*/ true),
|
||||
context.endLexicalEnvironment()));
|
||||
visitFunctionBody((<FunctionExpression>node).body, visitor, context, /*optional*/ true));
|
||||
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return updateClassDeclaration(<ClassDeclaration>node,
|
||||
@@ -1129,11 +1162,7 @@ namespace ts {
|
||||
case SyntaxKind.SourceFile:
|
||||
context.startLexicalEnvironment();
|
||||
return updateSourceFileNode(<SourceFile>node,
|
||||
createNodeArray(
|
||||
concatenate(
|
||||
visitNodes((<SourceFile>node).statements, visitor, isStatement),
|
||||
context.endLexicalEnvironment()),
|
||||
(<SourceFile>node).statements));
|
||||
visitLexicalEnvironment((<SourceFile>node).statements, visitor, context));
|
||||
|
||||
// Transformation nodes
|
||||
case SyntaxKind.PartiallyEmittedExpression:
|
||||
@@ -1167,6 +1196,24 @@ namespace ts {
|
||||
// return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges generated lexical declarations into a new statement list.
|
||||
*/
|
||||
export function mergeLexicalEnvironment(statements: NodeArray<Statement>, declarations: Statement[]): NodeArray<Statement>;
|
||||
/**
|
||||
* Appends generated lexical declarations to an array of statements.
|
||||
*/
|
||||
export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]): Statement[];
|
||||
export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]) {
|
||||
if (!some(declarations)) {
|
||||
return statements;
|
||||
}
|
||||
return isNodeArray(statements)
|
||||
? createNodeArray(concatenate(statements, declarations), statements)
|
||||
: addRange(statements, declarations);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merges generated lexical declarations into the FunctionBody of a non-arrow function-like declaration.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user