Emit for full down-level generators

This commit is contained in:
Ron Buckton
2016-10-25 18:55:54 -07:00
parent 86091d7217
commit a2e0b19a94
17 changed files with 1424 additions and 882 deletions

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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.

View File

@@ -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;
}
}
}
}

View File

@@ -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

View File

@@ -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(),

View File

@@ -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.");

View File

@@ -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
);

View File

@@ -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;
}
}
}

View File

@@ -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) {

View File

@@ -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.

View File

@@ -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,

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}
/**