mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-19 20:37:00 -05:00
Emit for full down-level generators
This commit is contained in:
@@ -2698,7 +2698,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Currently, we only support generators that were originally async function bodies.
|
||||
if (node.asteriskToken && getEmitFlags(node) & EmitFlags.AsyncFunctionBody) {
|
||||
if (node.asteriskToken) {
|
||||
transformFlags |= TransformFlags.AssertGenerator;
|
||||
}
|
||||
|
||||
@@ -2774,7 +2774,7 @@ namespace ts {
|
||||
// down-level generator.
|
||||
// Currently we do not support transforming any other generator fucntions
|
||||
// down level.
|
||||
if (node.asteriskToken && getEmitFlags(node) & EmitFlags.AsyncFunctionBody) {
|
||||
if (node.asteriskToken) {
|
||||
transformFlags |= TransformFlags.AssertGenerator;
|
||||
}
|
||||
}
|
||||
@@ -2811,7 +2811,7 @@ namespace ts {
|
||||
// down-level generator.
|
||||
// Currently we do not support transforming any other generator fucntions
|
||||
// down level.
|
||||
if (node.asteriskToken && getEmitFlags(node) & EmitFlags.AsyncFunctionBody) {
|
||||
if (node.asteriskToken) {
|
||||
transformFlags |= TransformFlags.AssertGenerator;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace ts {
|
||||
let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[];
|
||||
let hasWrittenComment = false;
|
||||
let disabled: boolean = compilerOptions.removeComments;
|
||||
// let leadingCommentPositions: Map<boolean>;
|
||||
// let trailingCommentPositions: Map<boolean>;
|
||||
|
||||
return {
|
||||
reset,
|
||||
@@ -259,7 +261,8 @@ namespace ts {
|
||||
|
||||
function forEachLeadingCommentToEmit(pos: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) {
|
||||
// Emit the leading comments only if the container's pos doesn't match because the container should take care of emitting these comments
|
||||
if (containerPos === -1 || pos !== containerPos) {
|
||||
if ((containerPos === -1 || pos !== containerPos) /* && !leadingCommentPositions[pos] */) {
|
||||
// leadingCommentPositions[pos] = true;
|
||||
if (hasDetachedComments(pos)) {
|
||||
forEachLeadingCommentWithoutDetachedComments(cb);
|
||||
}
|
||||
@@ -271,7 +274,8 @@ namespace ts {
|
||||
|
||||
function forEachTrailingCommentToEmit(end: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean) => void) {
|
||||
// Emit the trailing comments only if the container's end doesn't match because the container should take care of emitting these comments
|
||||
if (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd)) {
|
||||
if ((containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd)) /*&& !trailingCommentPositions[end] */) {
|
||||
// trailingCommentPositions[end] = true;
|
||||
forEachTrailingCommentRange(currentText, end, cb);
|
||||
}
|
||||
}
|
||||
@@ -281,6 +285,8 @@ namespace ts {
|
||||
currentText = undefined;
|
||||
currentLineMap = undefined;
|
||||
detachedCommentsInfo = undefined;
|
||||
// leadingCommentPositions = undefined;
|
||||
// trailingCommentPositions = undefined;
|
||||
}
|
||||
|
||||
function setSourceFile(sourceFile: SourceFile) {
|
||||
@@ -288,6 +294,8 @@ namespace ts {
|
||||
currentText = currentSourceFile.text;
|
||||
currentLineMap = getLineStarts(currentSourceFile);
|
||||
detachedCommentsInfo = undefined;
|
||||
// leadingCommentPositions = createMap<boolean>();
|
||||
// trailingCommentPositions = createMap<boolean>();
|
||||
}
|
||||
|
||||
function hasDetachedComments(pos: number) {
|
||||
|
||||
@@ -1276,28 +1276,28 @@ namespace ts {
|
||||
writeToken(SyntaxKind.OpenParenToken, openParenPos, node);
|
||||
emitExpression(node.expression);
|
||||
writeToken(SyntaxKind.CloseParenToken, node.expression.end, node);
|
||||
emitEmbeddedStatement(node.thenStatement);
|
||||
emitEmbeddedStatement(node, node.thenStatement);
|
||||
if (node.elseStatement) {
|
||||
writeLine();
|
||||
writeLineOrSpace(node);
|
||||
writeToken(SyntaxKind.ElseKeyword, node.thenStatement.end, node);
|
||||
if (node.elseStatement.kind === SyntaxKind.IfStatement) {
|
||||
write(" ");
|
||||
emit(node.elseStatement);
|
||||
}
|
||||
else {
|
||||
emitEmbeddedStatement(node.elseStatement);
|
||||
emitEmbeddedStatement(node, node.elseStatement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitDoStatement(node: DoStatement) {
|
||||
write("do");
|
||||
emitEmbeddedStatement(node.statement);
|
||||
emitEmbeddedStatement(node, node.statement);
|
||||
if (isBlock(node.statement)) {
|
||||
write(" ");
|
||||
}
|
||||
else {
|
||||
writeLine();
|
||||
writeLineOrSpace(node);
|
||||
}
|
||||
|
||||
write("while (");
|
||||
@@ -1309,7 +1309,7 @@ namespace ts {
|
||||
write("while (");
|
||||
emitExpression(node.expression);
|
||||
write(")");
|
||||
emitEmbeddedStatement(node.statement);
|
||||
emitEmbeddedStatement(node, node.statement);
|
||||
}
|
||||
|
||||
function emitForStatement(node: ForStatement) {
|
||||
@@ -1322,7 +1322,7 @@ namespace ts {
|
||||
write(";");
|
||||
emitExpressionWithPrefix(" ", node.incrementor);
|
||||
write(")");
|
||||
emitEmbeddedStatement(node.statement);
|
||||
emitEmbeddedStatement(node, node.statement);
|
||||
}
|
||||
|
||||
function emitForInStatement(node: ForInStatement) {
|
||||
@@ -1333,7 +1333,7 @@ namespace ts {
|
||||
write(" in ");
|
||||
emitExpression(node.expression);
|
||||
writeToken(SyntaxKind.CloseParenToken, node.expression.end);
|
||||
emitEmbeddedStatement(node.statement);
|
||||
emitEmbeddedStatement(node, node.statement);
|
||||
}
|
||||
|
||||
function emitForOfStatement(node: ForOfStatement) {
|
||||
@@ -1344,7 +1344,7 @@ namespace ts {
|
||||
write(" of ");
|
||||
emitExpression(node.expression);
|
||||
writeToken(SyntaxKind.CloseParenToken, node.expression.end);
|
||||
emitEmbeddedStatement(node.statement);
|
||||
emitEmbeddedStatement(node, node.statement);
|
||||
}
|
||||
|
||||
function emitForBinding(node: VariableDeclarationList | Expression) {
|
||||
@@ -1380,7 +1380,7 @@ namespace ts {
|
||||
write("with (");
|
||||
emitExpression(node.expression);
|
||||
write(")");
|
||||
emitEmbeddedStatement(node.statement);
|
||||
emitEmbeddedStatement(node, node.statement);
|
||||
}
|
||||
|
||||
function emitSwitchStatement(node: SwitchStatement) {
|
||||
@@ -1408,9 +1408,13 @@ namespace ts {
|
||||
function emitTryStatement(node: TryStatement) {
|
||||
write("try ");
|
||||
emit(node.tryBlock);
|
||||
emit(node.catchClause);
|
||||
if (node.catchClause) {
|
||||
writeLineOrSpace(node);
|
||||
emit(node.catchClause);
|
||||
}
|
||||
|
||||
if (node.finallyBlock) {
|
||||
writeLine();
|
||||
writeLineOrSpace(node);
|
||||
write("finally ");
|
||||
emit(node.finallyBlock);
|
||||
}
|
||||
@@ -1880,7 +1884,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emitCatchClause(node: CatchClause) {
|
||||
writeLine();
|
||||
const openParenPos = writeToken(SyntaxKind.CatchKeyword, node.pos);
|
||||
write(" ");
|
||||
writeToken(SyntaxKind.OpenParenToken, openParenPos);
|
||||
@@ -2087,8 +2090,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitEmbeddedStatement(node: Statement) {
|
||||
if (isBlock(node)) {
|
||||
function emitEmbeddedStatement(parent: Node, node: Statement) {
|
||||
if (isBlock(node) || getEmitFlags(parent) & EmitFlags.SingleLine) {
|
||||
write(" ");
|
||||
emit(node);
|
||||
}
|
||||
@@ -2253,6 +2256,15 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function writeLineOrSpace(node: Node) {
|
||||
if (getEmitFlags(node) & EmitFlags.SingleLine) {
|
||||
write(" ");
|
||||
}
|
||||
else {
|
||||
writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
function writeIfAny(nodes: NodeArray<Node>, text: string) {
|
||||
if (nodes && nodes.length > 0) {
|
||||
write(text);
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace ts {
|
||||
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
|
||||
let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
|
||||
|
||||
function createNode(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags): Node {
|
||||
function createNode(kind: SyntaxKind, location?: TextRange): Node {
|
||||
const ConstructorForKind = kind === SyntaxKind.SourceFile
|
||||
? (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))
|
||||
: (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()));
|
||||
@@ -15,7 +15,7 @@ namespace ts {
|
||||
? new ConstructorForKind(kind, location.pos, location.end)
|
||||
: new ConstructorForKind(kind, /*pos*/ -1, /*end*/ -1);
|
||||
|
||||
node.flags = flags | NodeFlags.Synthesized;
|
||||
node.flags |= NodeFlags.Synthesized;
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -65,7 +65,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createSynthesizedNodeArray<T extends Node>(elements?: T[]): NodeArray<T> {
|
||||
return createNodeArray(elements, /*location*/ undefined);
|
||||
return createNodeArray(isNodeArray(elements) ? elements.slice(0) : elements, /*location*/ undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +75,8 @@ namespace ts {
|
||||
// We don't use "clone" from core.ts here, as we need to preserve the prototype chain of
|
||||
// the original node. We also need to exclude specific properties and only include own-
|
||||
// properties (to skip members already defined on the shared prototype).
|
||||
const clone = <T>createNode(node.kind, /*location*/ undefined, node.flags);
|
||||
const clone = <T>createNode(node.kind, /*location*/ undefined);
|
||||
clone.flags |= node.flags;
|
||||
setOriginalNode(clone, node);
|
||||
|
||||
for (const key in node) {
|
||||
@@ -109,20 +110,20 @@ namespace ts {
|
||||
export function createLiteral(value: string | number | boolean, location?: TextRange): PrimaryExpression;
|
||||
export function createLiteral(value: string | number | boolean | StringLiteral | Identifier, location?: TextRange): PrimaryExpression {
|
||||
if (typeof value === "number") {
|
||||
const node = <NumericLiteral>createNode(SyntaxKind.NumericLiteral, location, /*flags*/ undefined);
|
||||
const node = <NumericLiteral>createNode(SyntaxKind.NumericLiteral, location);
|
||||
node.text = value.toString();
|
||||
return node;
|
||||
}
|
||||
else if (typeof value === "boolean") {
|
||||
return <BooleanLiteral>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword, location, /*flags*/ undefined);
|
||||
return <BooleanLiteral>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword, location);
|
||||
}
|
||||
else if (typeof value === "string") {
|
||||
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location, /*flags*/ undefined);
|
||||
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location);
|
||||
node.text = value;
|
||||
return node;
|
||||
}
|
||||
else if (value) {
|
||||
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location, /*flags*/ undefined);
|
||||
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location);
|
||||
node.textSourceNode = value;
|
||||
node.text = value.text;
|
||||
return node;
|
||||
@@ -226,8 +227,8 @@ namespace ts {
|
||||
|
||||
// Signature elements
|
||||
|
||||
export function createParameter(decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: DotDotDotToken, name: string | Identifier | BindingPattern, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression, location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <ParameterDeclaration>createNode(SyntaxKind.Parameter, location, flags);
|
||||
export function createParameter(decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: DotDotDotToken, name: string | Identifier | BindingPattern, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression, location?: TextRange) {
|
||||
const node = <ParameterDeclaration>createNode(SyntaxKind.Parameter, location);
|
||||
node.decorators = decorators ? createNodeArray(decorators) : undefined;
|
||||
node.modifiers = modifiers ? createNodeArray(modifiers) : undefined;
|
||||
node.dotDotDotToken = dotDotDotToken;
|
||||
@@ -240,7 +241,7 @@ namespace ts {
|
||||
|
||||
export function updateParameter(node: ParameterDeclaration, decorators: Decorator[], modifiers: Modifier[], name: BindingName, type: TypeNode, initializer: Expression) {
|
||||
if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.type !== type || node.initializer !== initializer) {
|
||||
return updateNode(createParameter(decorators, modifiers, node.dotDotDotToken, name, node.questionToken, type, initializer, /*location*/ node, /*flags*/ node.flags), node);
|
||||
return updateNode(createParameter(decorators, modifiers, node.dotDotDotToken, name, node.questionToken, type, initializer, /*location*/ node), node);
|
||||
}
|
||||
|
||||
return node;
|
||||
@@ -266,8 +267,8 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createMethod(decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | PropertyName, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <MethodDeclaration>createNode(SyntaxKind.MethodDeclaration, location, flags);
|
||||
export function createMethod(decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | PropertyName, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange) {
|
||||
const node = <MethodDeclaration>createNode(SyntaxKind.MethodDeclaration, location);
|
||||
node.decorators = decorators ? createNodeArray(decorators) : undefined;
|
||||
node.modifiers = modifiers ? createNodeArray(modifiers) : undefined;
|
||||
node.asteriskToken = asteriskToken;
|
||||
@@ -281,13 +282,13 @@ namespace ts {
|
||||
|
||||
export function updateMethod(node: MethodDeclaration, decorators: Decorator[], modifiers: Modifier[], name: PropertyName, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
|
||||
if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) {
|
||||
return updateNode(createMethod(decorators, modifiers, node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node, node.flags), node);
|
||||
return updateNode(createMethod(decorators, modifiers, node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createConstructor(decorators: Decorator[], modifiers: Modifier[], parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <ConstructorDeclaration>createNode(SyntaxKind.Constructor, location, flags);
|
||||
export function createConstructor(decorators: Decorator[], modifiers: Modifier[], parameters: ParameterDeclaration[], body: Block, location?: TextRange) {
|
||||
const node = <ConstructorDeclaration>createNode(SyntaxKind.Constructor, location);
|
||||
node.decorators = decorators ? createNodeArray(decorators) : undefined;
|
||||
node.modifiers = modifiers ? createNodeArray(modifiers) : undefined;
|
||||
node.typeParameters = undefined;
|
||||
@@ -299,13 +300,13 @@ namespace ts {
|
||||
|
||||
export function updateConstructor(node: ConstructorDeclaration, decorators: Decorator[], modifiers: Modifier[], parameters: ParameterDeclaration[], body: Block) {
|
||||
if (node.decorators !== decorators || node.modifiers !== modifiers || node.parameters !== parameters || node.body !== body) {
|
||||
return updateNode(createConstructor(decorators, modifiers, parameters, body, /*location*/ node, node.flags), node);
|
||||
return updateNode(createConstructor(decorators, modifiers, parameters, body, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createGetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <GetAccessorDeclaration>createNode(SyntaxKind.GetAccessor, location, flags);
|
||||
export function createGetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange) {
|
||||
const node = <GetAccessorDeclaration>createNode(SyntaxKind.GetAccessor, location);
|
||||
node.decorators = decorators ? createNodeArray(decorators) : undefined;
|
||||
node.modifiers = modifiers ? createNodeArray(modifiers) : undefined;
|
||||
node.name = typeof name === "string" ? createIdentifier(name) : name;
|
||||
@@ -318,13 +319,13 @@ namespace ts {
|
||||
|
||||
export function updateGetAccessor(node: GetAccessorDeclaration, decorators: Decorator[], modifiers: Modifier[], name: PropertyName, parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
|
||||
if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.parameters !== parameters || node.type !== type || node.body !== body) {
|
||||
return updateNode(createGetAccessor(decorators, modifiers, name, parameters, type, body, /*location*/ node, node.flags), node);
|
||||
return updateNode(createGetAccessor(decorators, modifiers, name, parameters, type, body, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createSetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <SetAccessorDeclaration>createNode(SyntaxKind.SetAccessor, location, flags);
|
||||
export function createSetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange) {
|
||||
const node = <SetAccessorDeclaration>createNode(SyntaxKind.SetAccessor, location);
|
||||
node.decorators = decorators ? createNodeArray(decorators) : undefined;
|
||||
node.modifiers = modifiers ? createNodeArray(modifiers) : undefined;
|
||||
node.name = typeof name === "string" ? createIdentifier(name) : name;
|
||||
@@ -336,7 +337,7 @@ namespace ts {
|
||||
|
||||
export function updateSetAccessor(node: SetAccessorDeclaration, decorators: Decorator[], modifiers: Modifier[], name: PropertyName, parameters: ParameterDeclaration[], body: Block) {
|
||||
if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.parameters !== parameters || node.body !== body) {
|
||||
return updateNode(createSetAccessor(decorators, modifiers, name, parameters, body, /*location*/ node, node.flags), node);
|
||||
return updateNode(createSetAccessor(decorators, modifiers, name, parameters, body, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -420,8 +421,8 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, location, flags);
|
||||
export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange) {
|
||||
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, location);
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
(node.emitNode || (node.emitNode = {})).flags |= EmitFlags.NoIndentation;
|
||||
node.name = typeof name === "string" ? createIdentifier(name) : name;
|
||||
@@ -430,7 +431,7 @@ namespace ts {
|
||||
|
||||
export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier) {
|
||||
if (node.expression !== expression || node.name !== name) {
|
||||
const propertyAccess = createPropertyAccess(expression, name, /*location*/ node, node.flags);
|
||||
const propertyAccess = createPropertyAccess(expression, name, /*location*/ node);
|
||||
// Because we are updating existed propertyAccess we want to inherit its emitFlags instead of using default from createPropertyAccess
|
||||
(propertyAccess.emitNode || (propertyAccess.emitNode = {})).flags = getEmitFlags(node);
|
||||
return updateNode(propertyAccess, node);
|
||||
@@ -452,8 +453,8 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createCall(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[], location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <CallExpression>createNode(SyntaxKind.CallExpression, location, flags);
|
||||
export function createCall(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[], location?: TextRange) {
|
||||
const node = <CallExpression>createNode(SyntaxKind.CallExpression, location);
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
if (typeArguments) {
|
||||
node.typeArguments = createNodeArray(typeArguments);
|
||||
@@ -465,13 +466,13 @@ namespace ts {
|
||||
|
||||
export function updateCall(node: CallExpression, expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[]) {
|
||||
if (expression !== node.expression || typeArguments !== node.typeArguments || argumentsArray !== node.arguments) {
|
||||
return updateNode(createCall(expression, typeArguments, argumentsArray, /*location*/ node, node.flags), node);
|
||||
return updateNode(createCall(expression, typeArguments, argumentsArray, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createNew(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[], location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <NewExpression>createNode(SyntaxKind.NewExpression, location, flags);
|
||||
export function createNew(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[], location?: TextRange) {
|
||||
const node = <NewExpression>createNode(SyntaxKind.NewExpression, location);
|
||||
node.expression = parenthesizeForNew(expression);
|
||||
node.typeArguments = typeArguments ? createNodeArray(typeArguments) : undefined;
|
||||
node.arguments = argumentsArray ? parenthesizeListElements(createNodeArray(argumentsArray)) : undefined;
|
||||
@@ -480,7 +481,7 @@ namespace ts {
|
||||
|
||||
export function updateNew(node: NewExpression, expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[]) {
|
||||
if (node.expression !== expression || node.typeArguments !== typeArguments || node.arguments !== argumentsArray) {
|
||||
return updateNode(createNew(expression, typeArguments, argumentsArray, /*location*/ node, node.flags), node);
|
||||
return updateNode(createNew(expression, typeArguments, argumentsArray, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -512,8 +513,8 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createFunctionExpression(modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <FunctionExpression>createNode(SyntaxKind.FunctionExpression, location, flags);
|
||||
export function createFunctionExpression(modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange) {
|
||||
const node = <FunctionExpression>createNode(SyntaxKind.FunctionExpression, location);
|
||||
node.modifiers = modifiers ? createNodeArray(modifiers) : undefined;
|
||||
node.asteriskToken = asteriskToken;
|
||||
node.name = typeof name === "string" ? createIdentifier(name) : name;
|
||||
@@ -526,13 +527,13 @@ namespace ts {
|
||||
|
||||
export function updateFunctionExpression(node: FunctionExpression, modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
|
||||
if (node.name !== name || node.modifiers !== modifiers || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) {
|
||||
return updateNode(createFunctionExpression(modifiers, node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node, node.flags), node);
|
||||
return updateNode(createFunctionExpression(modifiers, node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createArrowFunction(modifiers: Modifier[], typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody, location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, location, flags);
|
||||
export function createArrowFunction(modifiers: Modifier[], typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody, location?: TextRange) {
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, location);
|
||||
node.modifiers = modifiers ? createNodeArray(modifiers) : undefined;
|
||||
node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined;
|
||||
node.parameters = createNodeArray(parameters);
|
||||
@@ -544,7 +545,7 @@ namespace ts {
|
||||
|
||||
export function updateArrowFunction(node: ArrowFunction, modifiers: Modifier[], typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: ConciseBody) {
|
||||
if (node.modifiers !== modifiers || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) {
|
||||
return updateNode(createArrowFunction(modifiers, typeParameters, parameters, type, node.equalsGreaterThanToken, body, /*location*/ node, node.flags), node);
|
||||
return updateNode(createArrowFunction(modifiers, typeParameters, parameters, type, node.equalsGreaterThanToken, body, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -648,7 +649,7 @@ namespace ts {
|
||||
|
||||
export function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression, location?: TextRange) {
|
||||
const node = <ConditionalExpression>createNode(SyntaxKind.ConditionalExpression, location);
|
||||
node.condition = condition;
|
||||
node.condition = parenthesizeConditionalHead(condition);
|
||||
node.questionToken = questionToken;
|
||||
node.whenTrue = whenTrue;
|
||||
node.colonToken = colonToken;
|
||||
@@ -760,8 +761,8 @@ namespace ts {
|
||||
|
||||
// Element
|
||||
|
||||
export function createBlock(statements: Statement[], location?: TextRange, multiLine?: boolean, flags?: NodeFlags): Block {
|
||||
const block = <Block>createNode(SyntaxKind.Block, location, flags);
|
||||
export function createBlock(statements: Statement[], location?: TextRange, multiLine?: boolean): Block {
|
||||
const block = <Block>createNode(SyntaxKind.Block, location);
|
||||
block.statements = createNodeArray(statements);
|
||||
if (multiLine) {
|
||||
block.multiLine = true;
|
||||
@@ -771,14 +772,14 @@ namespace ts {
|
||||
|
||||
export function updateBlock(node: Block, statements: Statement[]) {
|
||||
if (statements !== node.statements) {
|
||||
return updateNode(createBlock(statements, /*location*/ node, node.multiLine, node.flags), node);
|
||||
return updateNode(createBlock(statements, /*location*/ node, node.multiLine), node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createVariableStatement(modifiers: Modifier[], declarationList: VariableDeclarationList | VariableDeclaration[], location?: TextRange, flags?: NodeFlags): VariableStatement {
|
||||
const node = <VariableStatement>createNode(SyntaxKind.VariableStatement, location, flags);
|
||||
export function createVariableStatement(modifiers: Modifier[], declarationList: VariableDeclarationList | VariableDeclaration[], location?: TextRange): VariableStatement {
|
||||
const node = <VariableStatement>createNode(SyntaxKind.VariableStatement, location);
|
||||
node.decorators = undefined;
|
||||
node.modifiers = modifiers ? createNodeArray(modifiers) : undefined;
|
||||
node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) : declarationList;
|
||||
@@ -787,13 +788,14 @@ namespace ts {
|
||||
|
||||
export function updateVariableStatement(node: VariableStatement, modifiers: Modifier[], declarationList: VariableDeclarationList): VariableStatement {
|
||||
if (node.modifiers !== modifiers || node.declarationList !== declarationList) {
|
||||
return updateNode(createVariableStatement(modifiers, declarationList, /*location*/ node, node.flags), node);
|
||||
return updateNode(createVariableStatement(modifiers, declarationList, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createVariableDeclarationList(declarations: VariableDeclaration[], location?: TextRange, flags?: NodeFlags): VariableDeclarationList {
|
||||
const node = <VariableDeclarationList>createNode(SyntaxKind.VariableDeclarationList, location, flags);
|
||||
const node = <VariableDeclarationList>createNode(SyntaxKind.VariableDeclarationList, location);
|
||||
node.flags |= flags;
|
||||
node.declarations = createNodeArray(declarations);
|
||||
return node;
|
||||
}
|
||||
@@ -805,8 +807,8 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createVariableDeclaration(name: string | BindingPattern | Identifier, type?: TypeNode, initializer?: Expression, location?: TextRange, flags?: NodeFlags): VariableDeclaration {
|
||||
const node = <VariableDeclaration>createNode(SyntaxKind.VariableDeclaration, location, flags);
|
||||
export function createVariableDeclaration(name: string | BindingPattern | Identifier, type?: TypeNode, initializer?: Expression, location?: TextRange): VariableDeclaration {
|
||||
const node = <VariableDeclaration>createNode(SyntaxKind.VariableDeclaration, location);
|
||||
node.name = typeof name === "string" ? createIdentifier(name) : name;
|
||||
node.type = type;
|
||||
node.initializer = initializer !== undefined ? parenthesizeExpressionForList(initializer) : undefined;
|
||||
@@ -815,7 +817,7 @@ namespace ts {
|
||||
|
||||
export function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, type: TypeNode, initializer: Expression) {
|
||||
if (node.name !== name || node.type !== type || node.initializer !== initializer) {
|
||||
return updateNode(createVariableDeclaration(name, type, initializer, /*location*/ node, node.flags), node);
|
||||
return updateNode(createVariableDeclaration(name, type, initializer, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -824,15 +826,15 @@ namespace ts {
|
||||
return <EmptyStatement>createNode(SyntaxKind.EmptyStatement, location);
|
||||
}
|
||||
|
||||
export function createStatement(expression: Expression, location?: TextRange, flags?: NodeFlags): ExpressionStatement {
|
||||
const node = <ExpressionStatement>createNode(SyntaxKind.ExpressionStatement, location, flags);
|
||||
export function createStatement(expression: Expression, location?: TextRange): ExpressionStatement {
|
||||
const node = <ExpressionStatement>createNode(SyntaxKind.ExpressionStatement, location);
|
||||
node.expression = parenthesizeExpressionForExpressionStatement(expression);
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateStatement(node: ExpressionStatement, expression: Expression) {
|
||||
if (node.expression !== expression) {
|
||||
return updateNode(createStatement(expression, /*location*/ node, node.flags), node);
|
||||
return updateNode(createStatement(expression, /*location*/ node), node);
|
||||
}
|
||||
|
||||
return node;
|
||||
@@ -882,7 +884,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createFor(initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement, location?: TextRange) {
|
||||
const node = <ForStatement>createNode(SyntaxKind.ForStatement, location, /*flags*/ undefined);
|
||||
const node = <ForStatement>createNode(SyntaxKind.ForStatement, location);
|
||||
node.initializer = initializer;
|
||||
node.condition = condition;
|
||||
node.incrementor = incrementor;
|
||||
@@ -1053,8 +1055,8 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createFunctionDeclaration(decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange, flags?: NodeFlags) {
|
||||
const node = <FunctionDeclaration>createNode(SyntaxKind.FunctionDeclaration, location, flags);
|
||||
export function createFunctionDeclaration(decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange) {
|
||||
const node = <FunctionDeclaration>createNode(SyntaxKind.FunctionDeclaration, location);
|
||||
node.decorators = decorators ? createNodeArray(decorators) : undefined;
|
||||
node.modifiers = modifiers ? createNodeArray(modifiers) : undefined;
|
||||
node.asteriskToken = asteriskToken;
|
||||
@@ -1068,7 +1070,7 @@ namespace ts {
|
||||
|
||||
export function updateFunctionDeclaration(node: FunctionDeclaration, decorators: Decorator[], modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
|
||||
if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) {
|
||||
return updateNode(createFunctionDeclaration(decorators, modifiers, node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node, node.flags), node);
|
||||
return updateNode(createFunctionDeclaration(decorators, modifiers, node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -1361,9 +1363,11 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createCatchClause(variableDeclaration: string | VariableDeclaration, block: Block, location?: TextRange) {
|
||||
export function createCatchClause(variableDeclaration: string | Identifier | VariableDeclaration, block: Block, location?: TextRange) {
|
||||
const node = <CatchClause>createNode(SyntaxKind.CatchClause, location);
|
||||
node.variableDeclaration = typeof variableDeclaration === "string" ? createVariableDeclaration(variableDeclaration) : variableDeclaration;
|
||||
node.variableDeclaration = typeof variableDeclaration === "string" || isIdentifier(variableDeclaration)
|
||||
? createVariableDeclaration(variableDeclaration)
|
||||
: variableDeclaration;
|
||||
node.block = block;
|
||||
return node;
|
||||
}
|
||||
@@ -1410,7 +1414,8 @@ namespace ts {
|
||||
|
||||
export function updateSourceFileNode(node: SourceFile, statements: Statement[]) {
|
||||
if (node.statements !== statements) {
|
||||
const updated = <SourceFile>createNode(SyntaxKind.SourceFile, /*location*/ node, node.flags);
|
||||
const updated = <SourceFile>createNode(SyntaxKind.SourceFile, /*location*/ node);
|
||||
updated.flags |= node.flags;
|
||||
updated.statements = createNodeArray(statements);
|
||||
updated.endOfFileToken = node.endOfFileToken;
|
||||
updated.fileName = node.fileName;
|
||||
@@ -1680,27 +1685,125 @@ namespace ts {
|
||||
|
||||
// Helpers
|
||||
|
||||
export interface EmitHelperState {
|
||||
currentSourceFile: SourceFile;
|
||||
compilerOptions: CompilerOptions;
|
||||
requestedHelpers?: EmitHelper[];
|
||||
export function getHelperName(name: string) {
|
||||
return setEmitFlags(createIdentifier(name), EmitFlags.HelperName | EmitFlags.AdviseOnEmitNode);
|
||||
}
|
||||
|
||||
export function getHelperName(helperState: EmitHelperState, name: string) {
|
||||
const externalHelpersModuleName = getOrCreateExternalHelpersModuleName(helperState.currentSourceFile, helperState.compilerOptions);
|
||||
return externalHelpersModuleName
|
||||
? createPropertyAccess(externalHelpersModuleName, name)
|
||||
: createIdentifier(name);
|
||||
const valuesHelper: EmitHelper = {
|
||||
name: "typescript:values",
|
||||
scoped: false,
|
||||
text: `
|
||||
var __values = (this && this.__values) || function (o) {
|
||||
var i = o.__iterator__ || 0, d;
|
||||
return i ? i.call(o) : { next: function () { return { done: d = d || i >= o.length, value: d ? void 0 : o[i++] }; } };
|
||||
};`
|
||||
};
|
||||
|
||||
export function createValuesHelper(context: TransformationContext, expression: Expression, location?: TextRange) {
|
||||
context.requestEmitHelper(valuesHelper);
|
||||
return createCall(
|
||||
getHelperName("__values"),
|
||||
/*typeArguments*/ undefined,
|
||||
[expression],
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
export function requestEmitHelper(helperState: EmitHelperState, helper: EmitHelper) {
|
||||
if (!contains(helperState.requestedHelpers, helper)) {
|
||||
helperState.requestedHelpers = append(helperState.requestedHelpers, helper);
|
||||
}
|
||||
const stepHelper: EmitHelper = {
|
||||
name: "typescript:step",
|
||||
scoped: false,
|
||||
text: `
|
||||
var __step = (this && this.__step) || function (r) {
|
||||
return !(r.done || (r.done = (r.result = r.iterator.next()).done));
|
||||
};`
|
||||
};
|
||||
|
||||
export function createStepHelper(context: TransformationContext, iteratorRecord: Expression, location?: TextRange) {
|
||||
context.requestEmitHelper(stepHelper);
|
||||
return createCall(
|
||||
getHelperName("__step"),
|
||||
/*typeArguments*/ undefined,
|
||||
[iteratorRecord],
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
const closeHelper: EmitHelper = {
|
||||
name: "typescript:close",
|
||||
scoped: false,
|
||||
text: `
|
||||
var __close = (this && this.__close) || function (r) {
|
||||
var m = !(r && r.done) && r.iterator["return"];
|
||||
if (m) m.call(r.iterator);
|
||||
};`
|
||||
};
|
||||
|
||||
export function createCloseHelper(context: TransformationContext, iteratorRecord: Expression, location?: TextRange) {
|
||||
context.requestEmitHelper(closeHelper);
|
||||
return createCall(
|
||||
getHelperName("__close"),
|
||||
/*typeArguments*/ undefined,
|
||||
[iteratorRecord],
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
const readHelper: EmitHelper = {
|
||||
name: "typescript:read",
|
||||
scoped: false,
|
||||
text: `
|
||||
var __read = (this && this.__read) || function (o, n) {
|
||||
var m = o.__iterator__;
|
||||
if (!m) return o;
|
||||
var r = { iterator: m.call(o) }, ar = [], e;
|
||||
try { while ((n === void 0 || n-- > 0) && __step(r)) ar.push(r.result.value); }
|
||||
catch (error) { e = { error: error }; }
|
||||
finally { try { __close(r); } finally { if (e) throw e.error; } }
|
||||
return ar;
|
||||
};`
|
||||
};
|
||||
|
||||
export function createReadHelper(context: TransformationContext, iteratorRecord: Expression, count: number | undefined, location?: TextRange) {
|
||||
context.requestEmitHelper(stepHelper);
|
||||
context.requestEmitHelper(readHelper);
|
||||
context.requestEmitHelper(closeHelper);
|
||||
return createCall(
|
||||
getHelperName("__read"),
|
||||
/*typeArguments*/ undefined,
|
||||
count !== undefined
|
||||
? [iteratorRecord, createLiteral(count)]
|
||||
: [iteratorRecord],
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
const spreadHelper: EmitHelper = {
|
||||
name: "typescript:spread",
|
||||
scoped: false,
|
||||
text: `
|
||||
var __spread = (this && this.__spread) || function () {
|
||||
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
|
||||
return ar;
|
||||
};`
|
||||
};
|
||||
|
||||
export function createSpreadHelper(context: TransformationContext, argumentList: Expression[], location?: TextRange) {
|
||||
context.requestEmitHelper(readHelper);
|
||||
context.requestEmitHelper(spreadHelper);
|
||||
return createCall(
|
||||
getHelperName("__spread"),
|
||||
/*typeArguments*/ undefined,
|
||||
argumentList,
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
// Utilities
|
||||
|
||||
export function toFunctionBody(node: ConciseBody) {
|
||||
return isBlock(node) ? node : createBlock([createReturn(node, /*location*/ node)], /*location*/ node);
|
||||
}
|
||||
|
||||
export interface CallBinding {
|
||||
target: LeftHandSideExpression;
|
||||
thisArg: Expression;
|
||||
@@ -2063,7 +2166,7 @@ namespace ts {
|
||||
* @param ensureUseStrict: boolean determining whether the function need to add prologue-directives
|
||||
* @param visitor: Optional callback used to visit any custom prologue directives.
|
||||
*/
|
||||
export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult<Node>): number {
|
||||
export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean, ignoreCustomPrologue?: boolean, visitor?: (node: Node) => VisitResult<Node>): number {
|
||||
Debug.assert(target.length === 0, "Prologue directives should be at the first statement in the target statements array");
|
||||
let foundUseStrict = false;
|
||||
let statementOffset = 0;
|
||||
@@ -2084,19 +2187,28 @@ namespace ts {
|
||||
if (ensureUseStrict && !foundUseStrict) {
|
||||
target.push(startOnNewLine(createStatement(createLiteral("use strict"))));
|
||||
}
|
||||
while (statementOffset < numStatements) {
|
||||
const statement = source[statementOffset];
|
||||
if (getEmitFlags(statement) & EmitFlags.CustomPrologue) {
|
||||
target.push(visitor ? visitNode(statement, visitor, isStatement) : statement);
|
||||
if (!ignoreCustomPrologue) {
|
||||
while (statementOffset < numStatements) {
|
||||
const statement = source[statementOffset];
|
||||
if (getEmitFlags(statement) & EmitFlags.CustomPrologue) {
|
||||
target.push(visitor ? visitNode(statement, visitor, isStatement) : statement);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
statementOffset++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
statementOffset++;
|
||||
}
|
||||
return statementOffset;
|
||||
}
|
||||
|
||||
export function startsWithUseStrict(statements: Statement[]) {
|
||||
const firstStatement = firstOrUndefined(statements);
|
||||
return firstStatement !== undefined
|
||||
&& isPrologueDirective(firstStatement)
|
||||
&& isUseStrictPrologue(firstStatement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures "use strict" directive is added
|
||||
*
|
||||
@@ -2126,6 +2238,16 @@ namespace ts {
|
||||
return statements;
|
||||
}
|
||||
|
||||
export function parenthesizeConditionalHead(condition: Expression) {
|
||||
const conditionalPrecedence = getOperatorPrecedence(SyntaxKind.ConditionalExpression, SyntaxKind.QuestionToken);
|
||||
const emittedCondition = skipPartiallyEmittedExpressions(condition);
|
||||
const conditionPrecedence = getExpressionPrecedence(emittedCondition);
|
||||
if (compareValues(conditionPrecedence, conditionalPrecedence) === Comparison.LessThan) {
|
||||
return createParen(condition);
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended
|
||||
* order of operations.
|
||||
|
||||
@@ -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,19 @@ 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: boolean;
|
||||
|
||||
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 nonScopedEmitHelpers: EmitHelper[];
|
||||
let scopedEmitHelpers: EmitHelper[];
|
||||
|
||||
// The transformation context is provided to each transformer as part of transformer
|
||||
// initialization.
|
||||
@@ -167,7 +94,11 @@ namespace ts {
|
||||
hoistVariableDeclaration,
|
||||
hoistFunctionDeclaration,
|
||||
startLexicalEnvironment,
|
||||
suspendLexicalEnvironment,
|
||||
resumeLexicalEnvironment,
|
||||
endLexicalEnvironment,
|
||||
requestEmitHelper,
|
||||
readEmitHelpers,
|
||||
onSubstituteNode: (_emitContext, node) => node,
|
||||
enableSubstitution,
|
||||
isSubstitutionEnabled,
|
||||
@@ -183,7 +114,7 @@ namespace ts {
|
||||
const transformed = map(sourceFiles, transformSourceFile);
|
||||
|
||||
// Disable modification of the lexical environment.
|
||||
lexicalEnvironmentDisabled = true;
|
||||
scopeModificationDisabled = true;
|
||||
|
||||
return {
|
||||
transformed,
|
||||
@@ -278,13 +209,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,12 +223,12 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,17 +237,29 @@ namespace ts {
|
||||
* 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;
|
||||
}
|
||||
|
||||
function suspendLexicalEnvironment(): void {
|
||||
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is already suspended.");
|
||||
lexicalEnvironmentSuspended = true;
|
||||
}
|
||||
|
||||
function resumeLexicalEnvironment(): void {
|
||||
Debug.assert(lexicalEnvironmentSuspended, "Lexical environment was not previously suspended.");
|
||||
lexicalEnvironmentSuspended = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,18 +267,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 +293,38 @@ namespace ts {
|
||||
|
||||
// Restore the previous lexical environment.
|
||||
lexicalEnvironmentStackOffset--;
|
||||
hoistedVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
|
||||
hoistedFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
|
||||
lexicalEnvironmentVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
|
||||
lexicalEnvironmentFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
|
||||
if (lexicalEnvironmentStackOffset === 0) {
|
||||
lexicalEnvironmentVariableDeclarations = [];
|
||||
lexicalEnvironmentFunctionDeclarations = [];
|
||||
}
|
||||
return statements;
|
||||
}
|
||||
|
||||
function requestEmitHelper(helper: EmitHelper): void {
|
||||
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
|
||||
if (helper.scoped) {
|
||||
scopedEmitHelpers = append(scopedEmitHelpers, helper);
|
||||
}
|
||||
else {
|
||||
nonScopedEmitHelpers = append(nonScopedEmitHelpers, helper);
|
||||
}
|
||||
}
|
||||
|
||||
function readEmitHelpers(onlyScoped: boolean): EmitHelper[] {
|
||||
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
|
||||
if (onlyScoped) {
|
||||
const helpers = scopedEmitHelpers;
|
||||
scopedEmitHelpers = undefined;
|
||||
return helpers;
|
||||
}
|
||||
else {
|
||||
const helpers = concatenate(nonScopedEmitHelpers, scopedEmitHelpers);
|
||||
scopedEmitHelpers = undefined;
|
||||
nonScopedEmitHelpers = undefined;
|
||||
return helpers;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,10 +42,10 @@ namespace ts {
|
||||
* @param visitor An optional visitor used to visit default value initializers of binding patterns.
|
||||
*/
|
||||
export function flattenDestructuringToExpression(
|
||||
context: TransformationContext,
|
||||
node: VariableDeclaration | DestructuringAssignment,
|
||||
needsValue: boolean,
|
||||
createAssignmentCallback: (target: Expression, value: Expression, location?: TextRange) => Expression,
|
||||
recordTempVariable: (node: Identifier) => void,
|
||||
visitor?: (node: Node) => VisitResult<Node>): Expression {
|
||||
|
||||
let location: TextRange = node;
|
||||
@@ -87,7 +87,16 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
flattenEffectiveBindingElement(node, value, isDestructuringAssignment(node), emitAssignment, emitTempVariableAssignment, visitor, location);
|
||||
flattenEffectiveBindingElement(
|
||||
context,
|
||||
node,
|
||||
value,
|
||||
isDestructuringAssignment(node),
|
||||
emitAssignment,
|
||||
emitTempVariableAssignment,
|
||||
emitExpression,
|
||||
visitor,
|
||||
location);
|
||||
|
||||
if (value && needsValue) {
|
||||
expressions.push(value);
|
||||
@@ -98,22 +107,21 @@ namespace ts {
|
||||
function emitAssignment(target: Expression, value: Expression, location: TextRange, original: Node) {
|
||||
const expression = createAssignmentCallback(target, value, location);
|
||||
expression.original = original;
|
||||
// NOTE: this completely disables source maps, but aligns with the behavior of
|
||||
// `emitAssignment` in the old emitter.
|
||||
setEmitFlags(expression, EmitFlags.NoNestedSourceMaps);
|
||||
aggregateTransformFlags(expression);
|
||||
expressions.push(expression);
|
||||
emitExpression(expression);
|
||||
}
|
||||
|
||||
function emitTempVariableAssignment(value: Expression, location: TextRange) {
|
||||
const name = createTempVariable(recordTempVariable);
|
||||
const expression = createAssignment(name, value, location);
|
||||
const name = createTempVariable(context.hoistVariableDeclaration);
|
||||
emitExpression(createAssignment(name, value, location));
|
||||
return name;
|
||||
}
|
||||
|
||||
function emitExpression(expression: Expression) {
|
||||
// NOTE: this completely disables source maps, but aligns with the behavior of
|
||||
// `emitAssignment` in the old emitter.
|
||||
setEmitFlags(expression, EmitFlags.NoNestedSourceMaps);
|
||||
aggregateTransformFlags(expression);
|
||||
expressions.push(expression);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,14 +135,62 @@ namespace ts {
|
||||
* declaring them inline.
|
||||
*/
|
||||
export function flattenDestructuring(
|
||||
context: TransformationContext,
|
||||
node: VariableDeclaration | ParameterDeclaration,
|
||||
boundValue?: Expression,
|
||||
recordTempVariable?: (node: Identifier) => void,
|
||||
boundValue: Expression | undefined,
|
||||
recordTempVariablesInLine: boolean,
|
||||
visitor?: (node: Node) => VisitResult<Node>) {
|
||||
|
||||
let pendingAssignments: Expression[];
|
||||
let pendingExpressions: Expression[];
|
||||
const pendingDeclarations: { pendingExpressions?: Expression[], name: Identifier, value: Expression, location?: TextRange, original?: Node }[] = [];
|
||||
const declarations: VariableDeclaration[] = [];
|
||||
flattenEffectiveBindingElement(node, boundValue, /*skipInitializer*/ false, emitAssignment, emitTempVariableAssignment, visitor, /*location*/ node);
|
||||
|
||||
flattenEffectiveBindingElement(
|
||||
context,
|
||||
node,
|
||||
boundValue,
|
||||
/*skipInitializer*/ false,
|
||||
emitAssignment,
|
||||
emitTempVariableAssignment,
|
||||
emitExpression,
|
||||
visitor,
|
||||
/*location*/ node);
|
||||
|
||||
if (pendingExpressions) {
|
||||
const name = createTempVariable(/*recordTempVariable*/ undefined);
|
||||
if (recordTempVariablesInLine) {
|
||||
pendingDeclarations.push({ name, value: inlineExpressions(pendingExpressions) });
|
||||
}
|
||||
else {
|
||||
context.hoistVariableDeclaration(name);
|
||||
const pendingDeclaration = lastOrUndefined(pendingDeclarations);
|
||||
pendingDeclaration.pendingExpressions = append(
|
||||
pendingDeclaration.pendingExpressions,
|
||||
createAssignment(name, pendingDeclaration.value)
|
||||
);
|
||||
addRange(pendingDeclaration.pendingExpressions, pendingExpressions);
|
||||
pendingDeclaration.value = name;
|
||||
}
|
||||
}
|
||||
|
||||
for (const { pendingExpressions, name, value, location, original} of pendingDeclarations) {
|
||||
const declaration = createVariableDeclaration(
|
||||
name,
|
||||
/*type*/ undefined,
|
||||
// pendingExpressions
|
||||
// ? inlineExpressions(append(pendingExpressions, value))
|
||||
// : value,
|
||||
inlineExpressions(append(pendingExpressions, value)),
|
||||
location
|
||||
);
|
||||
|
||||
declaration.original = original;
|
||||
|
||||
// NOTE: this completely disables source maps, but aligns with the behavior of
|
||||
// `emitAssignment` in the old emitter.
|
||||
declarations.push(aggregateTransformFlags(setEmitFlags(declaration, EmitFlags.NoNestedSourceMaps)));
|
||||
}
|
||||
|
||||
return declarations;
|
||||
|
||||
function emitAssignment(name: Expression, value: Expression, location: TextRange, original: Node) {
|
||||
@@ -143,38 +199,35 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingAssignments) {
|
||||
pendingAssignments.push(value);
|
||||
value = inlineExpressions(pendingAssignments);
|
||||
pendingAssignments = undefined;
|
||||
}
|
||||
|
||||
const declaration = createVariableDeclaration(name, /*type*/ undefined, value, location);
|
||||
declaration.original = original;
|
||||
|
||||
// NOTE: this completely disables source maps, but aligns with the behavior of
|
||||
// `emitAssignment` in the old emitter.
|
||||
declarations.push(aggregateTransformFlags(setEmitFlags(declaration, EmitFlags.NoNestedSourceMaps)));
|
||||
pendingDeclarations.push({ pendingExpressions, name, value, location, original });
|
||||
pendingExpressions = undefined;
|
||||
}
|
||||
|
||||
function emitTempVariableAssignment(value: Expression, location: TextRange) {
|
||||
const name = createTempVariable(recordTempVariable);
|
||||
if (recordTempVariable) {
|
||||
pendingAssignments = append(pendingAssignments, createAssignment(name, value, location));
|
||||
}
|
||||
else {
|
||||
const name = createTempVariable(/*recordTempVariable*/ undefined);
|
||||
if (recordTempVariablesInLine) {
|
||||
emitAssignment(name, value, location, /*original*/ undefined);
|
||||
}
|
||||
else {
|
||||
context.hoistVariableDeclaration(name);
|
||||
emitExpression(createAssignment(name, value, location));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
function emitExpression(expression: Expression) {
|
||||
pendingExpressions = append(pendingExpressions, expression);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenEffectiveBindingElement(
|
||||
context: TransformationContext,
|
||||
bindingElement: EffectiveBindingElement,
|
||||
boundValue: Expression | undefined,
|
||||
skipInitializer: boolean,
|
||||
emitAssignment: (target: Expression, value: Expression, location: TextRange, original: Node) => void,
|
||||
emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier,
|
||||
emitExpression: (value: Expression) => void,
|
||||
visitor: ((node: Node) => VisitResult<Node>) | undefined,
|
||||
location: TextRange) {
|
||||
|
||||
@@ -194,19 +247,20 @@ namespace ts {
|
||||
if (isEffectiveBindingPattern(bindingTarget)) {
|
||||
const elements = getElementsOfEffectiveBindingPattern(bindingTarget);
|
||||
const numElements = elements.length;
|
||||
if (numElements !== 1) {
|
||||
// For anything other than a single-element destructuring we need to generate a temporary
|
||||
// to ensure value is evaluated exactly once. Additionally, if we have zero elements
|
||||
// we need to emit *something* to ensure that in case a 'var' keyword was already emitted,
|
||||
// so in that case, we'll intentionally create that temporary.
|
||||
const reuseIdentifierExpressions = !isDeclarationBindingElement(bindingElement) || numElements !== 0;
|
||||
boundValue = ensureIdentifier(boundValue, reuseIdentifierExpressions, emitTempVariableAssignment, location);
|
||||
}
|
||||
|
||||
if (isEffectiveObjectBindingPattern(bindingTarget)) {
|
||||
if (numElements !== 1) {
|
||||
// For anything other than a single-element destructuring we need to generate a temporary
|
||||
// to ensure value is evaluated exactly once. Additionally, if we have zero elements
|
||||
// we need to emit *something* to ensure that in case a 'var' keyword was already emitted,
|
||||
// so in that case, we'll intentionally create that temporary.
|
||||
const reuseIdentifierExpressions = !isDeclarationBindingElement(bindingElement) || numElements !== 0;
|
||||
boundValue = ensureIdentifier(boundValue, reuseIdentifierExpressions, emitTempVariableAssignment, location);
|
||||
}
|
||||
|
||||
for (const element of elements) {
|
||||
// Rewrite element to a declaration with an initializer that fetches property
|
||||
flattenEffectiveBindingElement(
|
||||
context,
|
||||
element,
|
||||
createDestructuringPropertyAccess(
|
||||
boundValue,
|
||||
@@ -215,35 +269,55 @@ namespace ts {
|
||||
/*skipInitializer*/ false,
|
||||
emitAssignment,
|
||||
emitTempVariableAssignment,
|
||||
emitExpression,
|
||||
visitor,
|
||||
/*location*/ element);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!isArrayLiteralExpression(boundValue)) {
|
||||
// Read the elements of the iterable into an array
|
||||
boundValue = emitTempVariableAssignment(
|
||||
createReadHelper(
|
||||
context,
|
||||
boundValue,
|
||||
isEffectiveBindingElementWithRest(elements[numElements - 1])
|
||||
? undefined
|
||||
: numElements,
|
||||
location
|
||||
),
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
for (let i = 0; i < numElements; i++) {
|
||||
const element = elements[i];
|
||||
if (!isOmittedExpression(element)) {
|
||||
if (!isEffectiveBindingElementWithRest(element)) {
|
||||
// Rewrite element to a declaration that accesses array element at index i
|
||||
flattenEffectiveBindingElement(
|
||||
element,
|
||||
createElementAccess(boundValue, i),
|
||||
/*skipInitializer*/ false,
|
||||
emitAssignment,
|
||||
emitTempVariableAssignment,
|
||||
visitor,
|
||||
/*location*/ element);
|
||||
}
|
||||
else if (i === numElements - 1) {
|
||||
flattenEffectiveBindingElement(
|
||||
element,
|
||||
createArraySlice(boundValue, i),
|
||||
/*skipInitializer*/ false,
|
||||
emitAssignment,
|
||||
emitTempVariableAssignment,
|
||||
visitor,
|
||||
/*location*/ element);
|
||||
}
|
||||
if (isOmittedExpression(element)) {
|
||||
continue;
|
||||
}
|
||||
else if (!isEffectiveBindingElementWithRest(element)) {
|
||||
flattenEffectiveBindingElement(
|
||||
context,
|
||||
element,
|
||||
createElementAccess(boundValue, i),
|
||||
/*skipInitializer*/ false,
|
||||
emitAssignment,
|
||||
emitTempVariableAssignment,
|
||||
emitExpression,
|
||||
visitor,
|
||||
/*location*/ element);
|
||||
}
|
||||
else if (i === numElements - 1) {
|
||||
flattenEffectiveBindingElement(
|
||||
context,
|
||||
element,
|
||||
createArraySlice(boundValue, i),
|
||||
/*skipInitializer*/ false,
|
||||
emitAssignment,
|
||||
emitTempVariableAssignment,
|
||||
emitExpression,
|
||||
visitor,
|
||||
/*location*/ element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,8 @@ namespace ts {
|
||||
export function transformES2017(context: TransformationContext) {
|
||||
const {
|
||||
startLexicalEnvironment,
|
||||
endLexicalEnvironment,
|
||||
resumeLexicalEnvironment,
|
||||
endLexicalEnvironment
|
||||
} = context;
|
||||
|
||||
const resolver = context.getEmitResolver();
|
||||
@@ -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(/*onlyScoped*/ false));
|
||||
|
||||
currentSourceFile = undefined;
|
||||
helperState = undefined;
|
||||
return visited;
|
||||
}
|
||||
|
||||
@@ -148,7 +143,7 @@ namespace ts {
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
@@ -176,7 +171,7 @@ namespace ts {
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
@@ -205,7 +200,7 @@ namespace ts {
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
@@ -228,10 +223,10 @@ namespace ts {
|
||||
const func = createArrowFunction(
|
||||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.parameters, visitor, isParameter),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
node.equalsGreaterThanToken,
|
||||
transformConciseBody(node),
|
||||
transformFunctionBody(node),
|
||||
/*location*/ node
|
||||
);
|
||||
|
||||
@@ -239,27 +234,9 @@ namespace ts {
|
||||
return func;
|
||||
}
|
||||
|
||||
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 {
|
||||
function transformFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody;
|
||||
function transformFunctionBody(node: ArrowFunction): ConciseBody;
|
||||
function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody | FunctionBody {
|
||||
const nodeType = node.original ? (<FunctionLikeDeclaration>node.original).type : node.type;
|
||||
const promiseConstructor = languageVersion < ScriptTarget.ES2015 ? getPromiseConstructor(nodeType) : undefined;
|
||||
const isArrowFunction = node.kind === SyntaxKind.ArrowFunction;
|
||||
@@ -271,14 +248,15 @@ namespace ts {
|
||||
// passed to `__awaiter` is executed inside of the callback to the
|
||||
// promise constructor.
|
||||
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
if (!isArrowFunction) {
|
||||
const statements: Statement[] = [];
|
||||
const statementOffset = addPrologueDirectives(statements, (<Block>node.body).statements, /*ensureUseStrict*/ false, visitor);
|
||||
let statements: Statement[] = [];
|
||||
const statementOffset = addPrologueDirectives(statements, (<Block>node.body).statements, /*ensureUseStrict*/ false, /*ignoreCustomPrologue*/ false, visitor);
|
||||
statements.push(
|
||||
createReturn(
|
||||
createAwaiterHelper(
|
||||
helperState,
|
||||
context,
|
||||
hasLexicalArguments,
|
||||
promiseConstructor,
|
||||
transformFunctionBodyWorker(<Block>node.body, statementOffset)
|
||||
@@ -286,6 +264,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,32 +284,36 @@ 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 = toFunctionBody(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 = 0) {
|
||||
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 = toFunctionBody(visitNode(body, visitor, isConciseBody));
|
||||
const statements = mergeLexicalEnvironment(visited.statements, endLexicalEnvironment());
|
||||
return updateBlock(visited, statements);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,7 +490,9 @@ 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 +506,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(),
|
||||
|
||||
@@ -231,6 +231,7 @@ namespace ts {
|
||||
endLexicalEnvironment,
|
||||
hoistFunctionDeclaration,
|
||||
hoistVariableDeclaration,
|
||||
readEmitHelpers
|
||||
} = context;
|
||||
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
@@ -242,7 +243,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 +298,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
currentSourceFile = node;
|
||||
helperState = { currentSourceFile, compilerOptions };
|
||||
|
||||
const visited = visitEachChild(node, visitor, context);
|
||||
addEmitHelpers(visited, helperState.requestedHelpers);
|
||||
addEmitHelpers(visited, readEmitHelpers(/*onlyScoped*/ false));
|
||||
|
||||
currentSourceFile = undefined;
|
||||
helperState = undefined;
|
||||
return visited;
|
||||
}
|
||||
|
||||
@@ -449,7 +447,7 @@ namespace ts {
|
||||
*/
|
||||
function visitFunctionDeclaration(node: FunctionDeclaration): Statement {
|
||||
// Currently, we only support generators that were originally async functions.
|
||||
if (node.asteriskToken && getEmitFlags(node) & EmitFlags.AsyncFunctionBody) {
|
||||
if (node.asteriskToken) {
|
||||
node = setOriginalNode(
|
||||
createFunctionDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
@@ -497,7 +495,7 @@ namespace ts {
|
||||
*/
|
||||
function visitFunctionExpression(node: FunctionExpression): Expression {
|
||||
// Currently, we only support generators that were originally async functions.
|
||||
if (node.asteriskToken && getEmitFlags(node) & EmitFlags.AsyncFunctionBody) {
|
||||
if (node.asteriskToken) {
|
||||
node = setOriginalNode(
|
||||
createFunctionExpression(
|
||||
/*modifiers*/ undefined,
|
||||
@@ -584,7 +582,7 @@ namespace ts {
|
||||
// Build the generator
|
||||
startLexicalEnvironment();
|
||||
|
||||
const statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor);
|
||||
const statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, /*ignoreCustomPrologue*/ false, visitor);
|
||||
|
||||
transformAndEmitStatements(body.statements, statementOffset);
|
||||
|
||||
@@ -934,7 +932,7 @@ namespace ts {
|
||||
const resumeLabel = defineLabel();
|
||||
const expression = visitNode(node.expression, visitor, isExpression);
|
||||
if (node.asteriskToken) {
|
||||
emitYieldStar(expression, /*location*/ node);
|
||||
emitYieldStar(createValuesHelper(context, expression, /*location*/ node), /*location*/ node);
|
||||
}
|
||||
else {
|
||||
emitYield(expression, /*location*/ node);
|
||||
@@ -2590,7 +2588,7 @@ namespace ts {
|
||||
|
||||
const buildResult = buildStatements();
|
||||
return createGeneratorHelper(
|
||||
helperState,
|
||||
context,
|
||||
setEmitFlags(
|
||||
createFunctionExpression(
|
||||
/*modifiers*/ undefined,
|
||||
@@ -3083,10 +3081,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]);
|
||||
}
|
||||
@@ -3157,7 +3155,7 @@ namespace ts {
|
||||
text: `
|
||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t;
|
||||
return { next: verb(0), "throw": verb(1), "return": verb(2) };
|
||||
return { next: verb(0), "throw": verb(1), "return": verb(2), __iterator__: function () { return this; } };
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
namespace ts {
|
||||
export function transformJsx(context: TransformationContext) {
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
let currentSourceFile: SourceFile;
|
||||
let helperState: EmitHelperState;
|
||||
|
||||
return transformSourceFile;
|
||||
|
||||
@@ -20,14 +18,8 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
currentSourceFile = node;
|
||||
helperState = { currentSourceFile, compilerOptions };
|
||||
|
||||
const visited = visitEachChild(node, visitor, context);
|
||||
addEmitHelpers(visited, helperState.requestedHelpers);
|
||||
|
||||
currentSourceFile = undefined;
|
||||
helperState = undefined;
|
||||
addEmitHelpers(visited, context.readEmitHelpers(/*onlyScoped*/ false));
|
||||
return visited;
|
||||
}
|
||||
|
||||
@@ -116,7 +108,7 @@ namespace ts {
|
||||
// a call to the __assign helper.
|
||||
objectProperties = singleOrUndefined(segments);
|
||||
if (!objectProperties) {
|
||||
objectProperties = createAssignHelper(helperState, segments);
|
||||
objectProperties = createAssignHelper(context, segments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,10 +530,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,13 @@
|
||||
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.enableSubstitution(SyntaxKind.SourceFile);
|
||||
|
||||
let currentSourceFile: SourceFile;
|
||||
return transformSourceFile;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
@@ -55,5 +62,56 @@ namespace ts {
|
||||
// Elide `export=` as it is not legal with --module ES6
|
||||
return node.isExportEquals ? undefined : node;
|
||||
}
|
||||
|
||||
//
|
||||
// Emit Notification
|
||||
//
|
||||
|
||||
/**
|
||||
* Hook for node emit notifications.
|
||||
*
|
||||
* @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 = getOrCreateExternalHelpersModuleName(currentSourceFile, compilerOptions);
|
||||
if (externalHelpersModuleName) {
|
||||
return createPropertyAccess(externalHelpersModuleName, node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace ts {
|
||||
const {
|
||||
startLexicalEnvironment,
|
||||
endLexicalEnvironment,
|
||||
hoistVariableDeclaration,
|
||||
} = context;
|
||||
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
@@ -46,7 +45,6 @@ namespace ts {
|
||||
let currentSourceFile: SourceFile; // The current file.
|
||||
let currentModuleInfo: ExternalModuleInfo; // The ExternalModuleInfo for the current file.
|
||||
let noSubstitution: Map<boolean>; // Set of nodes for which substitution rules should be ignored.
|
||||
let helperState: EmitHelperState;
|
||||
|
||||
return transformSourceFile;
|
||||
|
||||
@@ -64,15 +62,14 @@ namespace ts {
|
||||
|
||||
currentSourceFile = node;
|
||||
currentModuleInfo = moduleInfoMap[getOriginalNodeId(node)] = collectExternalModuleInfo(node, resolver);
|
||||
helperState = { currentSourceFile, compilerOptions };
|
||||
|
||||
// Perform the transformation.
|
||||
const transformModule = transformModuleDelegates[moduleKind] || transformModuleDelegates[ModuleKind.None];
|
||||
const updated = transformModule(node);
|
||||
addEmitHelpers(updated, context.readEmitHelpers(/*onlyScoped*/ false));
|
||||
|
||||
currentSourceFile = undefined;
|
||||
currentModuleInfo = undefined;
|
||||
helperState = undefined;
|
||||
return aggregateTransformFlags(updated);
|
||||
}
|
||||
|
||||
@@ -84,15 +81,17 @@ namespace ts {
|
||||
function transformCommonJSModule(node: SourceFile) {
|
||||
startLexicalEnvironment();
|
||||
|
||||
const statements: Statement[] = [];
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
|
||||
let statements: Statement[] = [];
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, /*ignoreCustomPrologue*/ false, sourceElementVisitor);
|
||||
append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement, /*optional*/ true));
|
||||
addRange(statements, visitNodes(node.statements, sourceElementVisitor, isStatement, statementOffset));
|
||||
addRange(statements, endLexicalEnvironment());
|
||||
addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false);
|
||||
addRange(statements, endLexicalEnvironment());
|
||||
|
||||
const updated = updateSourceFileNode(node, createNodeArray(statements, node.statements));
|
||||
if (currentModuleInfo.hasExportStarsToExportValues) {
|
||||
// If we have any `export * from ...` declarations
|
||||
// we need to inform the emitter to add the __export helper.
|
||||
addEmitHelper(updated, exportStarHelper);
|
||||
}
|
||||
|
||||
@@ -258,20 +257,20 @@ namespace ts {
|
||||
function transformAsynchronousModuleBody(node: SourceFile) {
|
||||
startLexicalEnvironment();
|
||||
|
||||
const statements: Statement[] = [];
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
|
||||
let statements: Statement[] = [];
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, /*ignoreCustomPrologue*/ false, sourceElementVisitor);
|
||||
|
||||
// Visit each statement of the module body.
|
||||
append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement, /*optional*/ true));
|
||||
addRange(statements, visitNodes(node.statements, sourceElementVisitor, isStatement, statementOffset));
|
||||
|
||||
// Append the 'export =' statement if provided.
|
||||
addExportEqualsIfNeeded(statements, /*emitAsReturn*/ true);
|
||||
|
||||
// End the lexical environment for the module body
|
||||
// and merge any new lexical declarations.
|
||||
addRange(statements, endLexicalEnvironment());
|
||||
|
||||
// Append the 'export =' statement if provided.
|
||||
addExportEqualsIfNeeded(statements, /*emitAsReturn*/ true);
|
||||
|
||||
const body = createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
|
||||
if (currentModuleInfo.hasExportStarsToExportValues) {
|
||||
// If we have any `export * from ...` declarations
|
||||
@@ -764,10 +763,10 @@ namespace ts {
|
||||
function transformInitializedVariable(node: VariableDeclaration): Expression {
|
||||
if (isBindingPattern(node.name)) {
|
||||
return flattenDestructuringToExpression(
|
||||
context,
|
||||
node,
|
||||
/*needsValue*/ false,
|
||||
createExportExpression,
|
||||
hoistVariableDeclaration,
|
||||
/*visitor*/ undefined
|
||||
);
|
||||
}
|
||||
@@ -1194,6 +1193,15 @@ namespace ts {
|
||||
* @param node The node to substitute.
|
||||
*/
|
||||
function substituteExpressionIdentifier(node: Identifier): Expression {
|
||||
if (getEmitFlags(node) & EmitFlags.HelperName) {
|
||||
const externalHelpersModuleName = getOrCreateExternalHelpersModuleName(currentSourceFile, compilerOptions);
|
||||
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) {
|
||||
|
||||
@@ -41,7 +41,6 @@ namespace ts {
|
||||
let hoistedStatements: Statement[];
|
||||
let enclosingBlockScopedContainer: Node;
|
||||
let noSubstitution: Map<boolean>; // Set of nodes for which substitution rules should be ignored.
|
||||
let helperState: EmitHelperState;
|
||||
|
||||
return transformSourceFile;
|
||||
|
||||
@@ -60,7 +59,6 @@ namespace ts {
|
||||
const id = getOriginalNodeId(node);
|
||||
currentSourceFile = node;
|
||||
enclosingBlockScopedContainer = node;
|
||||
helperState = { currentSourceFile, compilerOptions };
|
||||
|
||||
// System modules have the following shape:
|
||||
//
|
||||
@@ -121,6 +119,10 @@ namespace ts {
|
||||
|
||||
if (!(compilerOptions.outFile || compilerOptions.out)) {
|
||||
moveEmitHelpers(updated, moduleBodyBlock, helper => !helper.scoped);
|
||||
addEmitHelpers(moduleBodyBlock, context.readEmitHelpers(/*onlyScoped*/ false));
|
||||
}
|
||||
else {
|
||||
addEmitHelpers(updated, context.readEmitHelpers(/*onlyScoped*/ false));
|
||||
}
|
||||
|
||||
if (noSubstitution) {
|
||||
@@ -134,8 +136,6 @@ namespace ts {
|
||||
contextObject = undefined;
|
||||
hoistedStatements = undefined;
|
||||
enclosingBlockScopedContainer = undefined;
|
||||
helperState = undefined;
|
||||
|
||||
return aggregateTransformFlags(updated);
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace ts {
|
||||
startLexicalEnvironment();
|
||||
|
||||
// Add any prologue directives.
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, /*ignoreCustomPrologue*/ false, sourceElementVisitor);
|
||||
|
||||
// var __moduleName = context_1 && context_1.id;
|
||||
statements.push(
|
||||
@@ -822,7 +822,12 @@ namespace ts {
|
||||
function transformInitializedVariable(node: VariableDeclaration, isExportedDeclaration: boolean): Expression {
|
||||
const createAssignment = isExportedDeclaration ? createExportedVariableAssignment : createNonExportedVariableAssignment;
|
||||
return isBindingPattern(node.name)
|
||||
? flattenDestructuringToExpression(node, /*needsValue*/ false, createAssignment, hoistVariableDeclaration, destructuringVisitor)
|
||||
? flattenDestructuringToExpression(
|
||||
context,
|
||||
node,
|
||||
/*needsValue*/ false,
|
||||
createAssignment,
|
||||
destructuringVisitor)
|
||||
: createAssignment(node.name, visitNode(node.initializer, destructuringVisitor, isExpression));
|
||||
}
|
||||
|
||||
@@ -1473,7 +1478,12 @@ namespace ts {
|
||||
*/
|
||||
function visitDestructuringAssignment(node: DestructuringAssignment): VisitResult<Expression> {
|
||||
if (hasExportedReferenceInDestructuringTarget(node.left)) {
|
||||
return flattenDestructuringToExpression(node, /*needsValue*/ true, createAssignment, hoistVariableDeclaration, destructuringVisitor);
|
||||
return flattenDestructuringToExpression(
|
||||
context,
|
||||
node,
|
||||
/*needsValue*/ true,
|
||||
createAssignment,
|
||||
destructuringVisitor);
|
||||
}
|
||||
return visitEachChild(node, destructuringVisitor, context);
|
||||
}
|
||||
@@ -1612,6 +1622,15 @@ namespace ts {
|
||||
* @param node The node to substitute.
|
||||
*/
|
||||
function substituteExpressionIdentifier(node: Identifier): Expression {
|
||||
if (getEmitFlags(node) & EmitFlags.HelperName) {
|
||||
const externalHelpersModuleName = getOrCreateExternalHelpersModuleName(currentSourceFile, compilerOptions);
|
||||
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.
|
||||
|
||||
@@ -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(/*onlyScoped*/ false));
|
||||
|
||||
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[]>[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -859,11 +855,11 @@ namespace ts {
|
||||
* @param hasExtendsClause A value indicating whether the class has an extends clause.
|
||||
*/
|
||||
function transformConstructorBody(node: ClassExpression | ClassDeclaration, constructor: ConstructorDeclaration, hasExtendsClause: boolean) {
|
||||
const statements: Statement[] = [];
|
||||
let statements: Statement[] = [];
|
||||
let indexOfFirstStatement = 0;
|
||||
|
||||
// The body of a constructor is a new lexical environment
|
||||
startLexicalEnvironment();
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
if (constructor) {
|
||||
indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements);
|
||||
@@ -918,16 +914,14 @@ 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
|
||||
statements = mergeLexicalEnvironment(statements, endLexicalEnvironment());
|
||||
return createBlock(
|
||||
createNodeArray(
|
||||
statements,
|
||||
/*location*/ constructor ? constructor.body.statements : node.members
|
||||
),
|
||||
true
|
||||
/*location*/ constructor ? constructor.body : /*location*/ undefined,
|
||||
/*multiLine*/ true
|
||||
);
|
||||
}
|
||||
|
||||
@@ -941,7 +935,7 @@ namespace ts {
|
||||
if (ctor.body) {
|
||||
const statements = ctor.body.statements;
|
||||
// add prologue directives to the list (if any)
|
||||
const index = addPrologueDirectives(result, statements, /*ensureUseStrict*/ false, visitor);
|
||||
const index = addPrologueDirectives(result, statements, /*ensureUseStrict*/ false, /*ignoreCustomPrologue*/ false, visitor);
|
||||
if (index === statements.length) {
|
||||
// list contains nothing but prologue directives (or empty) - exit
|
||||
return index;
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2003,7 +1997,13 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return visitEachChild(node, visitor, context);
|
||||
return updateConstructor(
|
||||
node,
|
||||
visitNodes(node.decorators, visitor, isDecorator),
|
||||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
visitFunctionBody(node.body, visitor, context)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2020,26 +2020,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 +2062,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 +2093,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 +2124,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2163,24 +2151,19 @@ namespace ts {
|
||||
* @param node The function expression node.
|
||||
*/
|
||||
function visitFunctionExpression(node: FunctionExpression): Expression {
|
||||
if (nodeIsMissing(node.body)) {
|
||||
if (!shouldEmitFunctionLikeDeclaration(node)) {
|
||||
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) || createBlock([])
|
||||
);
|
||||
|
||||
setOriginalNode(func, node);
|
||||
|
||||
return func;
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2189,62 +2172,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2312,7 +2248,12 @@ namespace ts {
|
||||
function transformInitializedVariable(node: VariableDeclaration): Expression {
|
||||
const name = node.name;
|
||||
if (isBindingPattern(name)) {
|
||||
return flattenDestructuringToExpression(node, /*needsValue*/ false, createNamespaceExportExpression, hoistVariableDeclaration, visitor);
|
||||
return flattenDestructuringToExpression(
|
||||
context,
|
||||
node,
|
||||
/*needsValue*/ false,
|
||||
createNamespaceExportExpression,
|
||||
visitor);
|
||||
}
|
||||
else {
|
||||
return createAssignment(
|
||||
@@ -2498,7 +2439,7 @@ namespace ts {
|
||||
const savedCurrentNamespaceLocalName = currentNamespaceContainerName;
|
||||
currentNamespaceContainerName = localName;
|
||||
|
||||
const statements: Statement[] = [];
|
||||
let statements: Statement[] = [];
|
||||
startLexicalEnvironment();
|
||||
addRange(statements, map(node.members, transformEnumMember));
|
||||
addRange(statements, endLexicalEnvironment());
|
||||
@@ -2781,7 +2722,7 @@ namespace ts {
|
||||
currentNamespace = node;
|
||||
currentScopeFirstDeclarationsOfName = undefined;
|
||||
|
||||
const statements: Statement[] = [];
|
||||
let statements: Statement[] = [];
|
||||
startLexicalEnvironment();
|
||||
|
||||
let statementsLocation: TextRange;
|
||||
@@ -3217,6 +3158,11 @@ namespace ts {
|
||||
*/
|
||||
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
|
||||
const savedApplicableSubstitutions = applicableSubstitutions;
|
||||
const savedCurrentSourceFile = currentSourceFile;
|
||||
|
||||
if (isSourceFile(node)) {
|
||||
currentSourceFile = node;
|
||||
}
|
||||
|
||||
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) {
|
||||
applicableSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports;
|
||||
@@ -3229,6 +3175,7 @@ namespace ts {
|
||||
previousOnEmitNode(emitContext, node, emitCallback);
|
||||
|
||||
applicableSubstitutions = savedApplicableSubstitutions;
|
||||
currentSourceFile = savedCurrentSourceFile;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3300,6 +3247,7 @@ namespace ts {
|
||||
const clone = getSynthesizedClone(classAlias);
|
||||
setSourceMapRange(clone, node);
|
||||
setCommentRange(clone, node);
|
||||
debugger;
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
@@ -3311,7 +3259,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);
|
||||
@@ -3367,32 +3315,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createParamHelper(helperState: EmitHelperState, expression: Expression, parameterOffset: number, location?: TextRange) {
|
||||
requestEmitHelper(helperState, paramHelper);
|
||||
return createCall(
|
||||
getHelperName(helperState, "__param"),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
createLiteral(parameterOffset),
|
||||
expression
|
||||
],
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
function createMetadataHelper(helperState: EmitHelperState, metadataKey: string, metadataValue: Expression) {
|
||||
requestEmitHelper(helperState, metadataHelper);
|
||||
return createCall(
|
||||
getHelperName(helperState, "__metadata"),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
createLiteral(metadataKey),
|
||||
metadataValue
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function createDecorateHelper(helperState: EmitHelperState, decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression, location?: TextRange) {
|
||||
function createDecorateHelper(context: TransformationContext, decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression, location?: TextRange) {
|
||||
const argumentsArray: Expression[] = [];
|
||||
argumentsArray.push(createArrayLiteral(decoratorExpressions, /*location*/ undefined, /*multiLine*/ true));
|
||||
argumentsArray.push(target);
|
||||
@@ -3403,8 +3326,12 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
requestEmitHelper(helperState, decorateHelper);
|
||||
return createCall(getHelperName(helperState, "__decorate"), /*typeArguments*/ undefined, argumentsArray, location);
|
||||
context.requestEmitHelper(decorateHelper);
|
||||
return createCall(
|
||||
getHelperName("__decorate"),
|
||||
/*typeArguments*/ undefined,
|
||||
argumentsArray,
|
||||
location);
|
||||
}
|
||||
|
||||
const decorateHelper: EmitHelper = {
|
||||
@@ -3420,6 +3347,18 @@ namespace ts {
|
||||
};`
|
||||
};
|
||||
|
||||
function createMetadataHelper(context: TransformationContext, metadataKey: string, metadataValue: Expression) {
|
||||
context.requestEmitHelper(metadataHelper);
|
||||
return createCall(
|
||||
getHelperName("__metadata"),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
createLiteral(metadataKey),
|
||||
metadataValue
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
const metadataHelper: EmitHelper = {
|
||||
name: "typescript:metadata",
|
||||
scoped: false,
|
||||
@@ -3430,6 +3369,19 @@ namespace ts {
|
||||
};`
|
||||
};
|
||||
|
||||
function createParamHelper(context: TransformationContext, expression: Expression, parameterOffset: number, location?: TextRange) {
|
||||
context.requestEmitHelper(paramHelper);
|
||||
return createCall(
|
||||
getHelperName("__param"),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
createLiteral(parameterOffset),
|
||||
expression
|
||||
],
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
const paramHelper: EmitHelper = {
|
||||
name: "typescript:param",
|
||||
scoped: false,
|
||||
|
||||
@@ -1497,6 +1497,10 @@ namespace ts {
|
||||
expression: Expression;
|
||||
}
|
||||
|
||||
export interface PrologueDirective extends ExpressionStatement {
|
||||
expression: StringLiteral;
|
||||
}
|
||||
|
||||
export interface IfStatement extends Statement {
|
||||
kind: SyntaxKind.IfStatement;
|
||||
expression: Expression;
|
||||
@@ -3474,6 +3478,7 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
export const enum EmitFlags {
|
||||
HelperName = 1 << 0,
|
||||
UMDDefine = 1 << 4, // This node should be replaced with the UMD define helper.
|
||||
SingleLine = 1 << 5, // The contents of this node should be emitted on a single line.
|
||||
AdviseOnEmitNode = 1 << 6, // The printer should invoke the onEmitNode callback when printing this node.
|
||||
@@ -3517,16 +3522,128 @@ namespace ts {
|
||||
Unspecified, // Emitting an otherwise unspecified node
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
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;
|
||||
}
|
||||
|
||||
/** Additional context provided to `visitEachChild` */
|
||||
/* @internal */
|
||||
export interface LexicalEnvironment {
|
||||
/** Starts a new lexical environment. */
|
||||
export interface TransformationContext {
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getEmitResolver(): EmitResolver;
|
||||
getEmitHost(): EmitHost;
|
||||
|
||||
/**
|
||||
* Hoists a function declaration to the current lexical environment.
|
||||
*/
|
||||
hoistFunctionDeclaration(node: FunctionDeclaration): void;
|
||||
|
||||
/**
|
||||
* Hoists a variable declaration to the current lexical environment.
|
||||
*/
|
||||
hoistVariableDeclaration(name: Identifier): void;
|
||||
|
||||
/**
|
||||
* Starts tracking hoisted declarations in a new lexical environment.
|
||||
*/
|
||||
startLexicalEnvironment(): void;
|
||||
|
||||
/** Ends a lexical environment, returning any declarations. */
|
||||
suspendLexicalEnvironment(): void;
|
||||
resumeLexicalEnvironment(): void;
|
||||
|
||||
/**
|
||||
* Ends a lexical environment, returning any declarations.
|
||||
*/
|
||||
endLexicalEnvironment(): Statement[];
|
||||
|
||||
/**
|
||||
* Requests an emit helper.
|
||||
*/
|
||||
requestEmitHelper(helper: EmitHelper): void;
|
||||
|
||||
/**
|
||||
* Gets and resets the requested emit helpers.
|
||||
*
|
||||
* @param onlyScoped Only read emit helpers whose `scoped` property is `true`.
|
||||
*/
|
||||
readEmitHelpers(onlyScoped: boolean): EmitHelper[];
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
@@ -613,7 +598,7 @@ namespace ts {
|
||||
return n.kind === SyntaxKind.CallExpression && (<CallExpression>n).expression.kind === SyntaxKind.SuperKeyword;
|
||||
}
|
||||
|
||||
export function isPrologueDirective(node: Node): boolean {
|
||||
export function isPrologueDirective(node: Node): node is PrologueDirective {
|
||||
return node.kind === SyntaxKind.ExpressionStatement && (<ExpressionStatement>node).expression.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
|
||||
@@ -886,6 +871,19 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getEnclosedStatement(node: LabeledStatement): { statement: Statement; enclosingLabeledStatements: LabeledStatement[]; } {
|
||||
switch (node.statement.kind) {
|
||||
case SyntaxKind.LabeledStatement:
|
||||
const result = getEnclosedStatement(<LabeledStatement>node.statement);
|
||||
if (result) {
|
||||
result.enclosingLabeledStatements.push(node);
|
||||
}
|
||||
return result;
|
||||
default:
|
||||
return { statement: <IterationStatement>node.statement, enclosingLabeledStatements: [node] };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function isFunctionBlock(node: Node) {
|
||||
return node && node.kind === SyntaxKind.Block && isFunctionLike(node.parent);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export type VisitResult<T extends Node> = T | T[];
|
||||
export type VisitResult<T extends Node> = T[] | T | undefined;
|
||||
|
||||
/**
|
||||
* Describes an edge of a Node, used when traversing a syntax tree.
|
||||
@@ -653,6 +653,54 @@ 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) {
|
||||
context.resumeLexicalEnvironment();
|
||||
const updated = visitNode(node, visitor, isConciseBody, optional);
|
||||
const declarations = context.endLexicalEnvironment();
|
||||
if (some(declarations)) {
|
||||
const block = toFunctionBody(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 +708,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 +762,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));
|
||||
|
||||
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 +850,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));
|
||||
|
||||
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 +1031,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((<FunctionDeclaration>node).body, visitor, context, /*optional*/ true));
|
||||
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return updateClassDeclaration(<ClassDeclaration>node,
|
||||
@@ -1127,13 +1161,8 @@ namespace ts {
|
||||
|
||||
// Top-level nodes
|
||||
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:
|
||||
@@ -1163,39 +1192,31 @@ namespace ts {
|
||||
}
|
||||
return updated ? updateNode(updated, node) : node;
|
||||
}
|
||||
|
||||
// return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges generated lexical declarations into the FunctionBody of a non-arrow function-like declaration.
|
||||
* Merges generated lexical declarations into a statement list, creating a new statement list.
|
||||
*
|
||||
* @param node The ConciseBody of an arrow function.
|
||||
* @param statements The statements.
|
||||
* @param declarations The lexical declarations to merge.
|
||||
*/
|
||||
export function mergeFunctionBodyLexicalEnvironment(body: FunctionBody, declarations: Statement[]): FunctionBody;
|
||||
export function mergeLexicalEnvironment(statements: NodeArray<Statement>, declarations: Statement[]): NodeArray<Statement>;
|
||||
|
||||
/**
|
||||
* Merges generated lexical declarations into the ConciseBody of an ArrowFunction.
|
||||
* Appends generated lexical declarations to an array of statements.
|
||||
*
|
||||
* @param node The ConciseBody of an arrow function.
|
||||
* @param statements The statements.
|
||||
* @param declarations The lexical declarations to merge.
|
||||
*/
|
||||
export function mergeFunctionBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]): ConciseBody;
|
||||
|
||||
export function mergeFunctionBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]): ConciseBody {
|
||||
if (body && declarations !== undefined && declarations.length > 0) {
|
||||
if (isBlock(body)) {
|
||||
return updateBlock(body, createNodeArray(concatenate(body.statements, declarations), body.statements));
|
||||
}
|
||||
else {
|
||||
return createBlock(
|
||||
createNodeArray([createReturn(body, /*location*/ body), ...declarations], body),
|
||||
/*location*/ body,
|
||||
/*multiLine*/ true);
|
||||
}
|
||||
export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]): Statement[];
|
||||
export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]) {
|
||||
if (!some(declarations)) {
|
||||
return statements;
|
||||
}
|
||||
return body;
|
||||
|
||||
return isNodeArray(statements)
|
||||
? createNodeArray(concatenate(statements, declarations), statements)
|
||||
: addRange(statements, declarations);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user