From ff4c72de00335109af3d31094139b23be840892e Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 1 Feb 2017 16:36:10 -0800 Subject: [PATCH 1/6] Make most current Node factory functions public --- src/compiler/factory.ts | 2372 ++++++++++---------- src/compiler/program.ts | 9 +- src/compiler/transformers/destructuring.ts | 23 +- src/compiler/transformers/es2015.ts | 363 +-- src/compiler/transformers/es2016.ts | 48 +- src/compiler/transformers/es2017.ts | 41 +- src/compiler/transformers/es5.ts | 4 +- src/compiler/transformers/esnext.ts | 28 +- src/compiler/transformers/generators.ts | 216 +- src/compiler/transformers/jsx.ts | 6 +- src/compiler/transformers/module/es2015.ts | 2 +- src/compiler/transformers/module/module.ts | 452 ++-- src/compiler/transformers/module/system.ts | 141 +- src/compiler/transformers/ts.ts | 257 ++- src/compiler/types.ts | 6 +- src/compiler/utilities.ts | 8 + src/compiler/visitor.ts | 28 +- 17 files changed, 2131 insertions(+), 1873 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index f2a8de3a93b4d..ec1e0dafb795e 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1,28 +1,18 @@ /// /// -/* @internal */ 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 { - const ConstructorForKind = kind === SyntaxKind.SourceFile - ? (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor())) - : (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor())); - - const node = location - ? new ConstructorForKind(kind, location.pos, location.end) - : new ConstructorForKind(kind, /*pos*/ -1, /*end*/ -1); - - node.flags = flags | NodeFlags.Synthesized; - + function createSynthesizedNode(kind: SyntaxKind): Node { + const node = createNode(kind, -1, -1); + node.flags |= NodeFlags.Synthesized; return node; } + /* @internal */ export function updateNode(updated: T, original: T): T { if (updated !== original) { setOriginalNode(updated, original); + setTextRange(updated, original); if (original.startsOnNewLine) { updated.startsOnNewLine = true; } @@ -31,7 +21,10 @@ namespace ts { return updated; } - export function createNodeArray(elements?: T[], location?: TextRange, hasTrailingComma?: boolean): NodeArray { + /** + * Make `elements` into a `NodeArray`. If `elements` is `undefined`, returns an empty `NodeArray`. + */ + export function createNodeArray(elements?: T[], hasTrailingComma?: boolean): NodeArray { if (elements) { if (isNodeArray(elements)) { return elements; @@ -42,40 +35,22 @@ namespace ts { } const array = >elements; - if (location) { - array.pos = location.pos; - array.end = location.end; - } - else { - array.pos = -1; - array.end = -1; - } - - if (hasTrailingComma) { - array.hasTrailingComma = true; - } - + array.pos = -1; + array.end = -1; + array.hasTrailingComma = hasTrailingComma; return array; } - export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node { - const node = createNode(kind, /*location*/ undefined); - node.startsOnNewLine = startsOnNewLine; - return node; - } - - export function createSynthesizedNodeArray(elements?: T[]): NodeArray { - return createNodeArray(elements, /*location*/ undefined); - } - /** * Creates a shallow, memberwise clone of a node with no source map location. */ + /* @internal */ export function getSynthesizedClone(node: T): T { // 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 = createNode(node.kind, /*location*/ undefined, node.flags); + const clone = createSynthesizedNode(node.kind); + clone.flags |= node.flags; setOriginalNode(clone, node); for (const key in node) { @@ -89,63 +64,62 @@ namespace ts { return clone; } - /** - * Creates a shallow, memberwise clone of a node for mutation. - */ - export function getMutableClone(node: T): T { - const clone = getSynthesizedClone(node); - clone.pos = node.pos; - clone.end = node.end; - clone.parent = node.parent; - return clone; - } - // Literals - export function createLiteral(textSource: StringLiteral | NumericLiteral | Identifier, location?: TextRange): StringLiteral; - export function createLiteral(value: string, location?: TextRange): StringLiteral; - export function createLiteral(value: number, location?: TextRange): NumericLiteral; - export function createLiteral(value: boolean, location?: TextRange): BooleanLiteral; - export function createLiteral(value: string | number | boolean, location?: TextRange): PrimaryExpression; - export function createLiteral(value: string | number | boolean | StringLiteral | NumericLiteral | Identifier, location?: TextRange): PrimaryExpression { + export function createLiteral(value: string): StringLiteral; + export function createLiteral(value: number): NumericLiteral; + export function createLiteral(value: boolean): BooleanLiteral; + /** Create a string literal whose source text is read from a source node during emit. */ + export function createLiteral(sourceNode: StringLiteral | NumericLiteral | Identifier): StringLiteral; + export function createLiteral(value: string | number | boolean): PrimaryExpression; + export function createLiteral(value: string | number | boolean | StringLiteral | NumericLiteral | Identifier): PrimaryExpression { if (typeof value === "number") { - const node = createNode(SyntaxKind.NumericLiteral, location, /*flags*/ undefined); - node.text = value.toString(); - return node; - } - else if (typeof value === "boolean") { - return createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword, location, /*flags*/ undefined); + return createNumericLiteral(value + ""); } - else if (typeof value === "string") { - const node = createNode(SyntaxKind.StringLiteral, location, /*flags*/ undefined); - node.text = value; - return node; + if (typeof value === "boolean") { + return value ? createTrue() : createFalse(); } - else if (value) { - const node = createNode(SyntaxKind.StringLiteral, location, /*flags*/ undefined); - node.textSourceNode = value; - node.text = value.text; - return node; + if (typeof value === "string") { + return createStringLiteral(value); } + return createLiteralFromNode(value); } - // Identifiers + export function createNumericLiteral(value: string): NumericLiteral { + const node = createSynthesizedNode(SyntaxKind.NumericLiteral); + node.text = value; + return node; + } - let nextAutoGenerateId = 0; + function createStringLiteral(text: string): StringLiteral { + const node = createSynthesizedNode(SyntaxKind.StringLiteral); + node.text = text; + return node; + } - export function createIdentifier(text: string, location?: TextRange): Identifier { - const node = createNode(SyntaxKind.Identifier, location); - node.text = escapeIdentifier(text); - node.originalKeywordKind = stringToToken(text); + function createLiteralFromNode(sourceNode: StringLiteral | NumericLiteral | Identifier): StringLiteral { + const node = createStringLiteral(sourceNode.text); + node.textSourceNode = sourceNode; + return node; + } + + + // Identifiers + + export function createIdentifier(text: string): Identifier { + const node = createSynthesizedNode(SyntaxKind.Identifier); + node.text = text ? escapeIdentifier(text) : undefined; + node.originalKeywordKind = text ? stringToToken(text) : SyntaxKind.Unknown; node.autoGenerateKind = GeneratedIdentifierKind.None; node.autoGenerateId = 0; return node; } - export function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, location?: TextRange): Identifier { - const name = createNode(SyntaxKind.Identifier, location); - name.text = ""; - name.originalKeywordKind = SyntaxKind.Unknown; + let nextAutoGenerateId = 0; + + /** Create a unique temporary variable. */ + export function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined): Identifier { + const name = createIdentifier(""); name.autoGenerateKind = GeneratedIdentifierKind.Auto; name.autoGenerateId = nextAutoGenerateId; nextAutoGenerateId++; @@ -155,33 +129,31 @@ namespace ts { return name; } - export function createLoopVariable(location?: TextRange): Identifier { - const name = createNode(SyntaxKind.Identifier, location); - name.text = ""; - name.originalKeywordKind = SyntaxKind.Unknown; + /** Create a unique temporary variable for use in a loop. */ + export function createLoopVariable(): Identifier { + const name = createIdentifier(""); name.autoGenerateKind = GeneratedIdentifierKind.Loop; name.autoGenerateId = nextAutoGenerateId; nextAutoGenerateId++; return name; } - export function createUniqueName(text: string, location?: TextRange): Identifier { - const name = createNode(SyntaxKind.Identifier, location); + /** Create a unique name based on the supplied text. */ + export function createUniqueName(text: string): Identifier { + const name = createIdentifier(""); name.text = text; - name.originalKeywordKind = SyntaxKind.Unknown; name.autoGenerateKind = GeneratedIdentifierKind.Unique; name.autoGenerateId = nextAutoGenerateId; nextAutoGenerateId++; return name; } - export function getGeneratedNameForNode(node: Node, location?: TextRange): Identifier { - const name = createNode(SyntaxKind.Identifier, location); - name.original = node; - name.text = ""; - name.originalKeywordKind = SyntaxKind.Unknown; + /** Create a unique name generated for a node. */ + export function getGeneratedNameForNode(node: Node): Identifier { + const name = createIdentifier(""); name.autoGenerateKind = GeneratedIdentifierKind.Node; name.autoGenerateId = nextAutoGenerateId; + name.original = node; nextAutoGenerateId++; return name; } @@ -189,49 +161,53 @@ namespace ts { // Punctuation export function createToken(token: TKind) { - return >createNode(token); + return >createSynthesizedNode(token); } // Reserved words export function createSuper() { - const node = createNode(SyntaxKind.SuperKeyword); - return node; + return createSynthesizedNode(SyntaxKind.SuperKeyword); } - export function createThis(location?: TextRange) { - const node = createNode(SyntaxKind.ThisKeyword, location); - return node; + export function createThis() { + return createSynthesizedNode(SyntaxKind.ThisKeyword); } export function createNull() { - const node = createNode(SyntaxKind.NullKeyword); - return node; + return createSynthesizedNode(SyntaxKind.NullKeyword); + } + + export function createTrue() { + return createSynthesizedNode(SyntaxKind.TrueKeyword); + } + + export function createFalse() { + return createSynthesizedNode(SyntaxKind.FalseKeyword); } // Names - export function createComputedPropertyName(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.ComputedPropertyName, location); + export function createComputedPropertyName(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.ComputedPropertyName); node.expression = expression; return node; } export function updateComputedPropertyName(node: ComputedPropertyName, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createComputedPropertyName(expression, node), node); - } - return node; + return node.expression !== expression + ? updateNode(createComputedPropertyName(expression), node) + : node; } // 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 = createNode(SyntaxKind.Parameter, location, flags); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + export function createParameter(decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: DotDotDotToken, name: string | Identifier | BindingPattern, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression) { + const node = createSynthesizedNode(SyntaxKind.Parameter); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); node.dotDotDotToken = dotDotDotToken; - node.name = typeof name === "string" ? createIdentifier(name) : name; + node.name = asName(name); node.questionToken = questionToken; node.type = type; node.initializer = initializer ? parenthesizeExpressionForList(initializer) : undefined; @@ -239,20 +215,35 @@ namespace ts { } export function updateParameter(node: ParameterDeclaration, decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: DotDotDotToken, name: BindingName, type: TypeNode, initializer: Expression) { - if (node.decorators !== decorators || node.modifiers !== modifiers || node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.type !== type || node.initializer !== initializer) { - return updateNode(createParameter(decorators, modifiers, dotDotDotToken, name, node.questionToken, type, initializer, /*location*/ node, /*flags*/ node.flags), node); - } - + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.dotDotDotToken !== dotDotDotToken + || node.name !== name + || node.type !== type + || node.initializer !== initializer + ? updateNode(createParameter(decorators, modifiers, dotDotDotToken, name, node.questionToken, type, initializer), node) + : node; + } + + export function createDecorator(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.Decorator); + node.expression = parenthesizeForAccess(expression); return node; } + export function updateDecorator(node: Decorator, expression: Expression) { + return node.expression !== expression + ? updateNode(createDecorator(expression), node) + : node; + } + // Type members - export function createProperty(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, questionToken: QuestionToken, type: TypeNode, initializer: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.PropertyDeclaration, location); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; - node.name = typeof name === "string" ? createIdentifier(name) : name; + export function createProperty(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, questionToken: QuestionToken, type: TypeNode, initializer: Expression) { + const node = createSynthesizedNode(SyntaxKind.PropertyDeclaration); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); + node.name = asName(name); node.questionToken = questionToken; node.type = type; node.initializer = initializer; @@ -260,19 +251,22 @@ namespace ts { } export function updateProperty(node: PropertyDeclaration, decorators: Decorator[], modifiers: Modifier[], name: PropertyName, type: TypeNode, initializer: Expression) { - if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.type !== type || node.initializer !== initializer) { - return updateNode(createProperty(decorators, modifiers, name, node.questionToken, type, initializer, node), node); - } - 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 = createNode(SyntaxKind.MethodDeclaration, location, flags); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.name !== name + || node.type !== type + || node.initializer !== initializer + ? updateNode(createProperty(decorators, modifiers, name, node.questionToken, type, initializer), node) + : node; + } + + export function createMethod(decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | PropertyName, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) { + const node = createSynthesizedNode(SyntaxKind.MethodDeclaration); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); node.asteriskToken = asteriskToken; - node.name = typeof name === "string" ? createIdentifier(name) : name; - node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined; + node.name = asName(name); + node.typeParameters = asNodeArray(typeParameters); node.parameters = createNodeArray(parameters); node.type = type; node.body = body; @@ -280,16 +274,21 @@ 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 node; - } - - export function createConstructor(decorators: Decorator[], modifiers: Modifier[], parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) { - const node = createNode(SyntaxKind.Constructor, location, flags); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.name !== name + || node.typeParameters !== typeParameters + || node.parameters !== parameters + || node.type !== type + || node.body !== body + ? updateNode(createMethod(decorators, modifiers, node.asteriskToken, name, typeParameters, parameters, type, body), node) + : node; + } + + export function createConstructor(decorators: Decorator[], modifiers: Modifier[], parameters: ParameterDeclaration[], body: Block) { + const node = createSynthesizedNode(SyntaxKind.Constructor); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); node.typeParameters = undefined; node.parameters = createNodeArray(parameters); node.type = undefined; @@ -298,17 +297,19 @@ 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 node; - } - - export function createGetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange, flags?: NodeFlags) { - const node = createNode(SyntaxKind.GetAccessor, location, flags); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; - node.name = typeof name === "string" ? createIdentifier(name) : name; + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.parameters !== parameters + || node.body !== body + ? updateNode(createConstructor(decorators, modifiers, parameters, body), node) + : node; + } + + export function createGetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], type: TypeNode, body: Block) { + const node = createSynthesizedNode(SyntaxKind.GetAccessor); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); + node.name = asName(name); node.typeParameters = undefined; node.parameters = createNodeArray(parameters); node.type = type; @@ -317,17 +318,21 @@ 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 node; - } - - export function createSetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) { - const node = createNode(SyntaxKind.SetAccessor, location, flags); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; - node.name = typeof name === "string" ? createIdentifier(name) : name; + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.name !== name + || node.parameters !== parameters + || node.type !== type + || node.body !== body + ? updateNode(createGetAccessor(decorators, modifiers, name, parameters, type, body), node) + : node; + } + + export function createSetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block) { + const node = createSynthesizedNode(SyntaxKind.SetAccessor); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); + node.name = asName(name); node.typeParameters = undefined; node.parameters = createNodeArray(parameters); node.body = body; @@ -335,60 +340,63 @@ 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 node; + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.name !== name + || node.parameters !== parameters + || node.body !== body + ? updateNode(createSetAccessor(decorators, modifiers, name, parameters, body), node) + : node; } // Binding Patterns - export function createObjectBindingPattern(elements: BindingElement[], location?: TextRange) { - const node = createNode(SyntaxKind.ObjectBindingPattern, location); + export function createObjectBindingPattern(elements: BindingElement[]) { + const node = createSynthesizedNode(SyntaxKind.ObjectBindingPattern); node.elements = createNodeArray(elements); return node; } export function updateObjectBindingPattern(node: ObjectBindingPattern, elements: BindingElement[]) { - if (node.elements !== elements) { - return updateNode(createObjectBindingPattern(elements, node), node); - } - return node; + return node.elements !== elements + ? updateNode(createObjectBindingPattern(elements), node) + : node; } - export function createArrayBindingPattern(elements: ArrayBindingElement[], location?: TextRange) { - const node = createNode(SyntaxKind.ArrayBindingPattern, location); + export function createArrayBindingPattern(elements: ArrayBindingElement[]) { + const node = createSynthesizedNode(SyntaxKind.ArrayBindingPattern); node.elements = createNodeArray(elements); return node; } export function updateArrayBindingPattern(node: ArrayBindingPattern, elements: ArrayBindingElement[]) { - if (node.elements !== elements) { - return updateNode(createArrayBindingPattern(elements, node), node); - } - return node; + return node.elements !== elements + ? updateNode(createArrayBindingPattern(elements), node) + : node; } - export function createBindingElement(propertyName: string | PropertyName, dotDotDotToken: DotDotDotToken, name: string | BindingName, initializer?: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.BindingElement, location); - node.propertyName = typeof propertyName === "string" ? createIdentifier(propertyName) : propertyName; + export function createBindingElement(propertyName: string | PropertyName, dotDotDotToken: DotDotDotToken, name: string | BindingName, initializer?: Expression) { + const node = createSynthesizedNode(SyntaxKind.BindingElement); + node.propertyName = asName(propertyName); node.dotDotDotToken = dotDotDotToken; - node.name = typeof name === "string" ? createIdentifier(name) : name; + node.name = asName(name); node.initializer = initializer; return node; } export function updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken, propertyName: PropertyName, name: BindingName, initializer: Expression) { - if (node.propertyName !== propertyName || node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.initializer !== initializer) { - return updateNode(createBindingElement(propertyName, dotDotDotToken, name, initializer, node), node); - } - return node; + return node.propertyName !== propertyName + || node.dotDotDotToken !== dotDotDotToken + || node.name !== name + || node.initializer !== initializer + ? updateNode(createBindingElement(propertyName, dotDotDotToken, name, initializer), node) + : node; } // Expression - export function createArrayLiteral(elements?: Expression[], location?: TextRange, multiLine?: boolean) { - const node = createNode(SyntaxKind.ArrayLiteralExpression, location); + export function createArrayLiteral(elements?: Expression[], multiLine?: boolean) { + const node = createSynthesizedNode(SyntaxKind.ArrayLiteralExpression); node.elements = parenthesizeListElements(createNodeArray(elements)); if (multiLine) { node.multiLine = true; @@ -398,14 +406,13 @@ namespace ts { } export function updateArrayLiteral(node: ArrayLiteralExpression, elements: Expression[]) { - if (node.elements !== elements) { - return updateNode(createArrayLiteral(elements, node, node.multiLine), node); - } - return node; + return node.elements !== elements + ? updateNode(createArrayLiteral(elements, node.multiLine), node) + : node; } - export function createObjectLiteral(properties?: ObjectLiteralElementLike[], location?: TextRange, multiLine?: boolean) { - const node = createNode(SyntaxKind.ObjectLiteralExpression, location); + export function createObjectLiteral(properties?: ObjectLiteralElementLike[], multiLine?: boolean) { + const node = createSynthesizedNode(SyntaxKind.ObjectLiteralExpression); node.properties = createNodeArray(properties); if (multiLine) { node.multiLine = true; @@ -414,110 +421,106 @@ namespace ts { } export function updateObjectLiteral(node: ObjectLiteralExpression, properties: ObjectLiteralElementLike[]) { - if (node.properties !== properties) { - return updateNode(createObjectLiteral(properties, node, node.multiLine), node); - } - return node; + return node.properties !== properties + ? updateNode(createObjectLiteral(properties, node.multiLine), node) + : node; } - export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange, flags?: NodeFlags) { - const node = createNode(SyntaxKind.PropertyAccessExpression, location, flags); + export function createPropertyAccess(expression: Expression, name: string | Identifier) { + const node = createSynthesizedNode(SyntaxKind.PropertyAccessExpression); node.expression = parenthesizeForAccess(expression); - (node.emitNode || (node.emitNode = {})).flags |= EmitFlags.NoIndentation; - node.name = typeof name === "string" ? createIdentifier(name) : name; + node.name = asName(name); + setEmitFlags(node, EmitFlags.NoIndentation); return node; } 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); - // 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); - } - return node; + // Because we are updating existed propertyAccess we want to inherit its emitFlags + // instead of using the default from createPropertyAccess + return node.expression !== expression + || node.name !== name + ? updateNode(setEmitFlags(createPropertyAccess(expression, name), getEmitFlags(node)), node) + : node; } - export function createElementAccess(expression: Expression, index: number | Expression, location?: TextRange) { - const node = createNode(SyntaxKind.ElementAccessExpression, location); + export function createElementAccess(expression: Expression, index: number | Expression) { + const node = createSynthesizedNode(SyntaxKind.ElementAccessExpression); node.expression = parenthesizeForAccess(expression); - node.argumentExpression = typeof index === "number" ? createLiteral(index) : index; + node.argumentExpression = asExpression(index); return node; } export function updateElementAccess(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression) { - if (node.expression !== expression || node.argumentExpression !== argumentExpression) { - return updateNode(createElementAccess(expression, argumentExpression, node), node); - } - return node; + return node.expression !== expression + || node.argumentExpression !== argumentExpression + ? updateNode(createElementAccess(expression, argumentExpression), node) + : node; } - export function createCall(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[], location?: TextRange, flags?: NodeFlags) { - const node = createNode(SyntaxKind.CallExpression, location, flags); + export function createCall(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[]) { + const node = createSynthesizedNode(SyntaxKind.CallExpression); node.expression = parenthesizeForAccess(expression); - if (typeArguments) { - node.typeArguments = createNodeArray(typeArguments); - } - + node.typeArguments = asNodeArray(typeArguments); node.arguments = parenthesizeListElements(createNodeArray(argumentsArray)); return node; } 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 node; + return expression !== node.expression + || typeArguments !== node.typeArguments + || argumentsArray !== node.arguments + ? updateNode(createCall(expression, typeArguments, argumentsArray), node) + : node; } - export function createNew(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[], location?: TextRange, flags?: NodeFlags) { - const node = createNode(SyntaxKind.NewExpression, location, flags); + export function createNew(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[]) { + const node = createSynthesizedNode(SyntaxKind.NewExpression); node.expression = parenthesizeForNew(expression); - node.typeArguments = typeArguments ? createNodeArray(typeArguments) : undefined; + node.typeArguments = asNodeArray(typeArguments); node.arguments = argumentsArray ? parenthesizeListElements(createNodeArray(argumentsArray)) : undefined; return node; } 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 node; + return node.expression !== expression + || node.typeArguments !== typeArguments + || node.arguments !== argumentsArray + ? updateNode(createNew(expression, typeArguments, argumentsArray), node) + : node; } - export function createTaggedTemplate(tag: Expression, template: TemplateLiteral, location?: TextRange) { - const node = createNode(SyntaxKind.TaggedTemplateExpression, location); + export function createTaggedTemplate(tag: Expression, template: TemplateLiteral) { + const node = createSynthesizedNode(SyntaxKind.TaggedTemplateExpression); node.tag = parenthesizeForAccess(tag); node.template = template; return node; } export function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, template: TemplateLiteral) { - if (node.tag !== tag || node.template !== template) { - return updateNode(createTaggedTemplate(tag, template, node), node); - } - return node; + return node.tag !== tag + || node.template !== template + ? updateNode(createTaggedTemplate(tag, template), node) + : node; } - export function createParen(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.ParenthesizedExpression, location); + export function createParen(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.ParenthesizedExpression); node.expression = expression; return node; } export function updateParen(node: ParenthesizedExpression, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createParen(expression, node), node); - } - return node; + return node.expression !== expression + ? updateNode(createParen(expression), node) + : 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 = createNode(SyntaxKind.FunctionExpression, location, flags); - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + export function createFunctionExpression(modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) { + const node = createSynthesizedNode(SyntaxKind.FunctionExpression); + node.modifiers = asNodeArray(modifiers); node.asteriskToken = asteriskToken; - node.name = typeof name === "string" ? createIdentifier(name) : name; - node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined; + node.name = asName(name); + node.typeParameters = asNodeArray(typeParameters); node.parameters = createNodeArray(parameters); node.type = type; node.body = body; @@ -525,16 +528,20 @@ 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 node; - } - - export function createArrowFunction(modifiers: Modifier[], typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody, location?: TextRange, flags?: NodeFlags) { - const node = createNode(SyntaxKind.ArrowFunction, location, flags); - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; - node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined; + return node.name !== name + || node.modifiers !== modifiers + || node.typeParameters !== typeParameters + || node.parameters !== parameters + || node.type !== type + || node.body !== body + ? updateNode(createFunctionExpression(modifiers, node.asteriskToken, name, typeParameters, parameters, type, body), node) + : node; + } + + export function createArrowFunction(modifiers: Modifier[], typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody) { + const node = createSynthesizedNode(SyntaxKind.ArrowFunction); + node.modifiers = asNodeArray(modifiers); + node.typeParameters = asNodeArray(typeParameters); node.parameters = createNodeArray(parameters); node.type = type; node.equalsGreaterThanToken = equalsGreaterThanToken || createToken(SyntaxKind.EqualsGreaterThanToken); @@ -543,96 +550,93 @@ 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 node; + return node.modifiers !== modifiers + || node.typeParameters !== typeParameters + || node.parameters !== parameters + || node.type !== type + || node.body !== body + ? updateNode(createArrowFunction(modifiers, typeParameters, parameters, type, node.equalsGreaterThanToken, body), node) + : node; } - export function createDelete(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.DeleteExpression, location); + export function createDelete(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.DeleteExpression); node.expression = parenthesizePrefixOperand(expression); return node; } export function updateDelete(node: DeleteExpression, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createDelete(expression, node), expression); - } - return node; + return node.expression !== expression + ? updateNode(createDelete(expression), node) + : node; } - export function createTypeOf(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.TypeOfExpression, location); + export function createTypeOf(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.TypeOfExpression); node.expression = parenthesizePrefixOperand(expression); return node; } export function updateTypeOf(node: TypeOfExpression, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createTypeOf(expression, node), expression); - } - return node; + return node.expression !== expression + ? updateNode(createTypeOf(expression), node) + : node; } - export function createVoid(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.VoidExpression, location); + export function createVoid(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.VoidExpression); node.expression = parenthesizePrefixOperand(expression); return node; } export function updateVoid(node: VoidExpression, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createVoid(expression, node), node); - } - return node; + return node.expression !== expression + ? updateNode(createVoid(expression), node) + : node; } - export function createAwait(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.AwaitExpression, location); + export function createAwait(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.AwaitExpression); node.expression = parenthesizePrefixOperand(expression); return node; } export function updateAwait(node: AwaitExpression, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createAwait(expression, node), node); - } - return node; + return node.expression !== expression + ? updateNode(createAwait(expression), node) + : node; } - export function createPrefix(operator: PrefixUnaryOperator, operand: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.PrefixUnaryExpression, location); + export function createPrefix(operator: PrefixUnaryOperator, operand: Expression) { + const node = createSynthesizedNode(SyntaxKind.PrefixUnaryExpression); node.operator = operator; node.operand = parenthesizePrefixOperand(operand); return node; } export function updatePrefix(node: PrefixUnaryExpression, operand: Expression) { - if (node.operand !== operand) { - return updateNode(createPrefix(node.operator, operand, node), node); - } - return node; + return node.operand !== operand + ? updateNode(createPrefix(node.operator, operand), node) + : node; } - export function createPostfix(operand: Expression, operator: PostfixUnaryOperator, location?: TextRange) { - const node = createNode(SyntaxKind.PostfixUnaryExpression, location); + export function createPostfix(operand: Expression, operator: PostfixUnaryOperator) { + const node = createSynthesizedNode(SyntaxKind.PostfixUnaryExpression); node.operand = parenthesizePostfixOperand(operand); node.operator = operator; return node; } export function updatePostfix(node: PostfixUnaryExpression, operand: Expression) { - if (node.operand !== operand) { - return updateNode(createPostfix(operand, node.operator, node), node); - } - return node; + return node.operand !== operand + ? updateNode(createPostfix(operand, node.operator), node) + : node; } - export function createBinary(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression, location?: TextRange) { - const operatorToken = typeof operator === "number" ? createToken(operator) : operator; + export function createBinary(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression) { + const node = createSynthesizedNode(SyntaxKind.BinaryExpression); + const operatorToken = asToken(operator); const operatorKind = operatorToken.kind; - const node = createNode(SyntaxKind.BinaryExpression, location); node.left = parenthesizeBinaryOperand(operatorKind, left, /*isLeftSideOfBinary*/ true, /*leftOperand*/ undefined); node.operatorToken = operatorToken; node.right = parenthesizeBinaryOperand(operatorKind, right, /*isLeftSideOfBinary*/ false, node.left); @@ -640,218 +644,205 @@ namespace ts { } export function updateBinary(node: BinaryExpression, left: Expression, right: Expression) { - if (node.left !== left || node.right !== right) { - return updateNode(createBinary(left, node.operatorToken, right, /*location*/ node), node); - } - return node; + return node.left !== left + || node.right !== right + ? updateNode(createBinary(left, node.operatorToken, right), node) + : node; } - export function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression, location?: TextRange): ConditionalExpression; - export function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression, location?: TextRange): ConditionalExpression; - export function createConditional(condition: Expression, questionTokenOrWhenTrue: QuestionToken | Expression, whenTrueOrWhenFalse: Expression, colonTokenOrLocation?: ColonToken | TextRange, whenFalse?: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.ConditionalExpression, whenFalse ? location : colonTokenOrLocation); + export function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression; + export function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression; + export function createConditional(condition: Expression, questionTokenOrWhenTrue: QuestionToken | Expression, whenTrueOrWhenFalse: Expression, colonToken?: ColonToken, whenFalse?: Expression) { + const node = createSynthesizedNode(SyntaxKind.ConditionalExpression); node.condition = parenthesizeForConditionalHead(condition); - if (whenFalse) { - // second overload - node.questionToken = questionTokenOrWhenTrue; - node.whenTrue = parenthesizeSubexpressionOfConditionalExpression(whenTrueOrWhenFalse); - node.colonToken = colonTokenOrLocation; - node.whenFalse = parenthesizeSubexpressionOfConditionalExpression(whenFalse); - } - else { - // first overload - node.questionToken = createToken(SyntaxKind.QuestionToken); - node.whenTrue = parenthesizeSubexpressionOfConditionalExpression(questionTokenOrWhenTrue); - node.colonToken = createToken(SyntaxKind.ColonToken); - node.whenFalse = parenthesizeSubexpressionOfConditionalExpression(whenTrueOrWhenFalse); - } + node.questionToken = whenFalse ? questionTokenOrWhenTrue : createToken(SyntaxKind.QuestionToken); + node.whenTrue = parenthesizeSubexpressionOfConditionalExpression(whenFalse ? whenTrueOrWhenFalse : questionTokenOrWhenTrue); + node.colonToken = whenFalse ? colonToken : createToken(SyntaxKind.ColonToken); + node.whenFalse = parenthesizeSubexpressionOfConditionalExpression(whenFalse ? whenFalse : whenTrueOrWhenFalse); return node; } export function updateConditional(node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression) { - if (node.condition !== condition || node.whenTrue !== whenTrue || node.whenFalse !== whenFalse) { - return updateNode(createConditional(condition, node.questionToken, whenTrue, node.colonToken, whenFalse, node), node); - } - return node; + return node.condition !== condition + || node.whenTrue !== whenTrue + || node.whenFalse !== whenFalse + ? updateNode(createConditional(condition, node.questionToken, whenTrue, node.colonToken, whenFalse), node) + : node; } - export function createTemplateExpression(head: TemplateHead, templateSpans: TemplateSpan[], location?: TextRange) { - const node = createNode(SyntaxKind.TemplateExpression, location); + export function createTemplateExpression(head: TemplateHead, templateSpans: TemplateSpan[]) { + const node = createSynthesizedNode(SyntaxKind.TemplateExpression); node.head = head; node.templateSpans = createNodeArray(templateSpans); return node; } export function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: TemplateSpan[]) { - if (node.head !== head || node.templateSpans !== templateSpans) { - return updateNode(createTemplateExpression(head, templateSpans, node), node); - } - return node; + return node.head !== head + || node.templateSpans !== templateSpans + ? updateNode(createTemplateExpression(head, templateSpans), node) + : node; } - export function createYield(asteriskToken: AsteriskToken, expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.YieldExpression, location); - node.asteriskToken = asteriskToken; - node.expression = expression; + export function createYield(expression?: Expression): YieldExpression; + export function createYield(asteriskToken: AsteriskToken, expression: Expression): YieldExpression; + export function createYield(asteriskTokenOrExpression?: AsteriskToken | Expression, expression?: Expression) { + const node = createSynthesizedNode(SyntaxKind.YieldExpression); + node.asteriskToken = asteriskTokenOrExpression && asteriskTokenOrExpression.kind === SyntaxKind.AsteriskToken ? asteriskTokenOrExpression : undefined; + node.expression = asteriskTokenOrExpression && asteriskTokenOrExpression.kind !== SyntaxKind.AsteriskToken ? asteriskTokenOrExpression : expression; return node; } export function updateYield(node: YieldExpression, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createYield(node.asteriskToken, expression, node), node); - } - return node; + return node.expression !== expression + ? updateNode(createYield(node.asteriskToken, expression), node) + : node; } - export function createSpread(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.SpreadElement, location); + export function createSpread(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.SpreadElement); node.expression = parenthesizeExpressionForList(expression); return node; } export function updateSpread(node: SpreadElement, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createSpread(expression, node), node); - } - return node; + return node.expression !== expression + ? updateNode(createSpread(expression), node) + : node; } - export function createClassExpression(modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], heritageClauses: HeritageClause[], members: ClassElement[], location?: TextRange) { - const node = createNode(SyntaxKind.ClassExpression, location); + export function createClassExpression(modifiers: Modifier[], name: string | Identifier, typeParameters: TypeParameterDeclaration[], heritageClauses: HeritageClause[], members: ClassElement[]) { + const node = createSynthesizedNode(SyntaxKind.ClassExpression); node.decorators = undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; - node.name = name; - node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined; - node.heritageClauses = createNodeArray(heritageClauses); + node.modifiers = asNodeArray(modifiers); + node.name = asName(name); + node.typeParameters = asNodeArray(typeParameters); + node.heritageClauses = asNodeArray(heritageClauses); node.members = createNodeArray(members); return node; } export function updateClassExpression(node: ClassExpression, modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], heritageClauses: HeritageClause[], members: ClassElement[]) { - if (node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.heritageClauses !== heritageClauses || node.members !== members) { - return updateNode(createClassExpression(modifiers, name, typeParameters, heritageClauses, members, node), node); - } - return node; + return node.modifiers !== modifiers + || node.name !== name + || node.typeParameters !== typeParameters + || node.heritageClauses !== heritageClauses + || node.members !== members + ? updateNode(createClassExpression(modifiers, name, typeParameters, heritageClauses, members), node) + : node; } - export function createOmittedExpression(location?: TextRange) { - const node = createNode(SyntaxKind.OmittedExpression, location); - return node; + export function createOmittedExpression() { + return createSynthesizedNode(SyntaxKind.OmittedExpression); } - export function createExpressionWithTypeArguments(typeArguments: TypeNode[], expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.ExpressionWithTypeArguments, location); - node.typeArguments = typeArguments ? createNodeArray(typeArguments) : undefined; + export function createExpressionWithTypeArguments(typeArguments: TypeNode[], expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.ExpressionWithTypeArguments); node.expression = parenthesizeForAccess(expression); + node.typeArguments = asNodeArray(typeArguments); return node; } export function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, typeArguments: TypeNode[], expression: Expression) { - if (node.typeArguments !== typeArguments || node.expression !== expression) { - return updateNode(createExpressionWithTypeArguments(typeArguments, expression, node), node); - } - return node; + return node.typeArguments !== typeArguments + || node.expression !== expression + ? updateNode(createExpressionWithTypeArguments(typeArguments, expression), node) + : node; } - // Misc - export function createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail, location?: TextRange) { - const node = createNode(SyntaxKind.TemplateSpan, location); + export function createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail) { + const node = createSynthesizedNode(SyntaxKind.TemplateSpan); node.expression = expression; node.literal = literal; return node; } export function updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail) { - if (node.expression !== expression || node.literal !== literal) { - return updateNode(createTemplateSpan(expression, literal, node), node); - } - return node; + return node.expression !== expression + || node.literal !== literal + ? updateNode(createTemplateSpan(expression, literal), node) + : node; } // Element - export function createBlock(statements: Statement[], location?: TextRange, multiLine?: boolean, flags?: NodeFlags): Block { - const block = createNode(SyntaxKind.Block, location, flags); + export function createBlock(statements: Statement[], multiLine?: boolean): Block { + const block = createSynthesizedNode(SyntaxKind.Block); block.statements = createNodeArray(statements); - if (multiLine) { - block.multiLine = true; - } + if (multiLine) block.multiLine = multiLine; return block; } export function updateBlock(node: Block, statements: Statement[]) { - if (statements !== node.statements) { - return updateNode(createBlock(statements, /*location*/ node, node.multiLine, node.flags), node); - } - - return node; + return statements !== node.statements + ? updateNode(createBlock(statements, node.multiLine), node) + : node; } - export function createVariableStatement(modifiers: Modifier[], declarationList: VariableDeclarationList | VariableDeclaration[], location?: TextRange, flags?: NodeFlags): VariableStatement { - const node = createNode(SyntaxKind.VariableStatement, location, flags); + export function createVariableStatement(modifiers: Modifier[], declarationList: VariableDeclarationList | VariableDeclaration[]): VariableStatement { + const node = createSynthesizedNode(SyntaxKind.VariableStatement); node.decorators = undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + node.modifiers = asNodeArray(modifiers); node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) : declarationList; return node; } 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 node; + return node.modifiers !== modifiers + || node.declarationList !== declarationList + ? updateNode(createVariableStatement(modifiers, declarationList), node) + : node; } - export function createVariableDeclarationList(declarations: VariableDeclaration[], location?: TextRange, flags?: NodeFlags): VariableDeclarationList { - const node = createNode(SyntaxKind.VariableDeclarationList, location, flags); + export function createVariableDeclarationList(declarations: VariableDeclaration[], flags?: NodeFlags): VariableDeclarationList { + const node = createSynthesizedNode(SyntaxKind.VariableDeclarationList); + node.flags |= flags; node.declarations = createNodeArray(declarations); return node; } export function updateVariableDeclarationList(node: VariableDeclarationList, declarations: VariableDeclaration[]) { - if (node.declarations !== declarations) { - return updateNode(createVariableDeclarationList(declarations, /*location*/ node, node.flags), node); - } - return node; + return node.declarations !== declarations + ? updateNode(createVariableDeclarationList(declarations, node.flags), node) + : node; } - export function createVariableDeclaration(name: string | BindingPattern | Identifier, type?: TypeNode, initializer?: Expression, location?: TextRange, flags?: NodeFlags): VariableDeclaration { - const node = createNode(SyntaxKind.VariableDeclaration, location, flags); - node.name = typeof name === "string" ? createIdentifier(name) : name; + export function createVariableDeclaration(name: string | BindingName, type?: TypeNode, initializer?: Expression): VariableDeclaration { + const node = createSynthesizedNode(SyntaxKind.VariableDeclaration); + node.name = asName(name); node.type = type; node.initializer = initializer !== undefined ? parenthesizeExpressionForList(initializer) : undefined; return node; } 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 node; + return node.name !== name + || node.type !== type + || node.initializer !== initializer + ? updateNode(createVariableDeclaration(name, type, initializer), node) + : node; } - export function createEmptyStatement(location: TextRange) { - return createNode(SyntaxKind.EmptyStatement, location); + export function createEmptyStatement() { + return createSynthesizedNode(SyntaxKind.EmptyStatement); } - export function createStatement(expression: Expression, location?: TextRange, flags?: NodeFlags): ExpressionStatement { - const node = createNode(SyntaxKind.ExpressionStatement, location, flags); + export function createStatement(expression: Expression): ExpressionStatement { + const node = createSynthesizedNode(SyntaxKind.ExpressionStatement); 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 node; + return node.expression !== expression + ? updateNode(createStatement(expression), node) + : node; } - export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement, location?: TextRange) { - const node = createNode(SyntaxKind.IfStatement, location); + export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement) { + const node = createSynthesizedNode(SyntaxKind.IfStatement); node.expression = expression; node.thenStatement = thenStatement; node.elseStatement = elseStatement; @@ -859,42 +850,43 @@ namespace ts { } export function updateIf(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement) { - if (node.expression !== expression || node.thenStatement !== thenStatement || node.elseStatement !== elseStatement) { - return updateNode(createIf(expression, thenStatement, elseStatement, /*location*/ node), node); - } - return node; + return node.expression !== expression + || node.thenStatement !== thenStatement + || node.elseStatement !== elseStatement + ? updateNode(createIf(expression, thenStatement, elseStatement), node) + : node; } - export function createDo(statement: Statement, expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.DoStatement, location); + export function createDo(statement: Statement, expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.DoStatement); node.statement = statement; node.expression = expression; return node; } export function updateDo(node: DoStatement, statement: Statement, expression: Expression) { - if (node.statement !== statement || node.expression !== expression) { - return updateNode(createDo(statement, expression, node), node); - } - return node; + return node.statement !== statement + || node.expression !== expression + ? updateNode(createDo(statement, expression), node) + : node; } - export function createWhile(expression: Expression, statement: Statement, location?: TextRange) { - const node = createNode(SyntaxKind.WhileStatement, location); + export function createWhile(expression: Expression, statement: Statement) { + const node = createSynthesizedNode(SyntaxKind.WhileStatement); node.expression = expression; node.statement = statement; return node; } export function updateWhile(node: WhileStatement, expression: Expression, statement: Statement) { - if (node.expression !== expression || node.statement !== statement) { - return updateNode(createWhile(expression, statement, node), node); - } - return node; + return node.expression !== expression + || node.statement !== statement + ? updateNode(createWhile(expression, statement), node) + : node; } - export function createFor(initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement, location?: TextRange) { - const node = createNode(SyntaxKind.ForStatement, location, /*flags*/ undefined); + export function createFor(initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement) { + const node = createSynthesizedNode(SyntaxKind.ForStatement); node.initializer = initializer; node.condition = condition; node.incrementor = incrementor; @@ -903,14 +895,16 @@ namespace ts { } export function updateFor(node: ForStatement, initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement) { - if (node.initializer !== initializer || node.condition !== condition || node.incrementor !== incrementor || node.statement !== statement) { - return updateNode(createFor(initializer, condition, incrementor, statement, node), node); - } - return node; + return node.initializer !== initializer + || node.condition !== condition + || node.incrementor !== incrementor + || node.statement !== statement + ? updateNode(createFor(initializer, condition, incrementor, statement), node) + : node; } - export function createForIn(initializer: ForInitializer, expression: Expression, statement: Statement, location?: TextRange) { - const node = createNode(SyntaxKind.ForInStatement, location); + export function createForIn(initializer: ForInitializer, expression: Expression, statement: Statement) { + const node = createSynthesizedNode(SyntaxKind.ForInStatement); node.initializer = initializer; node.expression = expression; node.statement = statement; @@ -918,14 +912,15 @@ namespace ts { } export function updateForIn(node: ForInStatement, initializer: ForInitializer, expression: Expression, statement: Statement) { - if (node.initializer !== initializer || node.expression !== expression || node.statement !== statement) { - return updateNode(createForIn(initializer, expression, statement, node), node); - } - return node; + return node.initializer !== initializer + || node.expression !== expression + || node.statement !== statement + ? updateNode(createForIn(initializer, expression, statement), node) + : node; } - export function createForOf(initializer: ForInitializer, expression: Expression, statement: Statement, location?: TextRange) { - const node = createNode(SyntaxKind.ForOfStatement, location); + export function createForOf(initializer: ForInitializer, expression: Expression, statement: Statement) { + const node = createSynthesizedNode(SyntaxKind.ForOfStatement); node.initializer = initializer; node.expression = expression; node.statement = statement; @@ -933,112 +928,105 @@ namespace ts { } export function updateForOf(node: ForOfStatement, initializer: ForInitializer, expression: Expression, statement: Statement) { - if (node.initializer !== initializer || node.expression !== expression || node.statement !== statement) { - return updateNode(createForOf(initializer, expression, statement, node), node); - } - return node; + return node.initializer !== initializer + || node.expression !== expression + || node.statement !== statement + ? updateNode(createForOf(initializer, expression, statement), node) + : node; } - export function createContinue(label?: Identifier, location?: TextRange): ContinueStatement { - const node = createNode(SyntaxKind.ContinueStatement, location); - if (label) { - node.label = label; - } + export function createContinue(label?: string | Identifier): ContinueStatement { + const node = createSynthesizedNode(SyntaxKind.ContinueStatement); + node.label = asName(label); return node; } export function updateContinue(node: ContinueStatement, label: Identifier) { - if (node.label !== label) { - return updateNode(createContinue(label, node), node); - } - return node; + return node.label !== label + ? updateNode(createContinue(label), node) + : node; } - export function createBreak(label?: Identifier, location?: TextRange): BreakStatement { - const node = createNode(SyntaxKind.BreakStatement, location); - if (label) { - node.label = label; - } + export function createBreak(label?: string | Identifier): BreakStatement { + const node = createSynthesizedNode(SyntaxKind.BreakStatement); + node.label = asName(label); return node; } export function updateBreak(node: BreakStatement, label: Identifier) { - if (node.label !== label) { - return updateNode(createBreak(label, node), node); - } - return node; + return node.label !== label + ? updateNode(createBreak(label), node) + : node; } - export function createReturn(expression?: Expression, location?: TextRange): ReturnStatement { - const node = createNode(SyntaxKind.ReturnStatement, location); + export function createReturn(expression?: Expression): ReturnStatement { + const node = createSynthesizedNode(SyntaxKind.ReturnStatement); node.expression = expression; return node; } export function updateReturn(node: ReturnStatement, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createReturn(expression, /*location*/ node), node); - } - return node; + return node.expression !== expression + ? updateNode(createReturn(expression), node) + : node; } - export function createWith(expression: Expression, statement: Statement, location?: TextRange) { - const node = createNode(SyntaxKind.WithStatement, location); + export function createWith(expression: Expression, statement: Statement) { + const node = createSynthesizedNode(SyntaxKind.WithStatement); node.expression = expression; node.statement = statement; return node; } export function updateWith(node: WithStatement, expression: Expression, statement: Statement) { - if (node.expression !== expression || node.statement !== statement) { - return updateNode(createWith(expression, statement, node), node); - } - return node; + return node.expression !== expression + || node.statement !== statement + ? updateNode(createWith(expression, statement), node) + : node; } - export function createSwitch(expression: Expression, caseBlock: CaseBlock, location?: TextRange): SwitchStatement { - const node = createNode(SyntaxKind.SwitchStatement, location); + export function createSwitch(expression: Expression, caseBlock: CaseBlock): SwitchStatement { + const node = createSynthesizedNode(SyntaxKind.SwitchStatement); node.expression = parenthesizeExpressionForList(expression); node.caseBlock = caseBlock; return node; } export function updateSwitch(node: SwitchStatement, expression: Expression, caseBlock: CaseBlock) { - if (node.expression !== expression || node.caseBlock !== caseBlock) { - return updateNode(createSwitch(expression, caseBlock, node), node); - } - return node; + return node.expression !== expression + || node.caseBlock !== caseBlock + ? updateNode(createSwitch(expression, caseBlock), node) + : node; } - export function createLabel(label: string | Identifier, statement: Statement, location?: TextRange) { - const node = createNode(SyntaxKind.LabeledStatement, location); - node.label = typeof label === "string" ? createIdentifier(label) : label; + export function createLabel(label: string | Identifier, statement: Statement) { + const node = createSynthesizedNode(SyntaxKind.LabeledStatement); + node.label = asName(label); node.statement = statement; return node; } export function updateLabel(node: LabeledStatement, label: Identifier, statement: Statement) { - if (node.label !== label || node.statement !== statement) { - return updateNode(createLabel(label, statement, node), node); - } - return node; + return node.label !== label + || node.statement !== statement + ? updateNode(createLabel(label, statement), node) + : node; } - export function createThrow(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.ThrowStatement, location); + export function createThrow(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.ThrowStatement); node.expression = expression; return node; } export function updateThrow(node: ThrowStatement, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createThrow(expression, node), node); - } - return node; + return node.expression !== expression + ? updateNode(createThrow(expression), node) + : node; } - export function createTry(tryBlock: Block, catchClause: CatchClause, finallyBlock: Block, location?: TextRange) { - const node = createNode(SyntaxKind.TryStatement, location); + export function createTry(tryBlock: Block, catchClause: CatchClause, finallyBlock: Block) { + const node = createSynthesizedNode(SyntaxKind.TryStatement); node.tryBlock = tryBlock; node.catchClause = catchClause; node.finallyBlock = finallyBlock; @@ -1046,32 +1034,32 @@ namespace ts { } export function updateTry(node: TryStatement, tryBlock: Block, catchClause: CatchClause, finallyBlock: Block) { - if (node.tryBlock !== tryBlock || node.catchClause !== catchClause || node.finallyBlock !== finallyBlock) { - return updateNode(createTry(tryBlock, catchClause, finallyBlock, node), node); - } - return node; + return node.tryBlock !== tryBlock + || node.catchClause !== catchClause + || node.finallyBlock !== finallyBlock + ? updateNode(createTry(tryBlock, catchClause, finallyBlock), node) + : node; } - export function createCaseBlock(clauses: CaseOrDefaultClause[], location?: TextRange): CaseBlock { - const node = createNode(SyntaxKind.CaseBlock, location); + export function createCaseBlock(clauses: CaseOrDefaultClause[]): CaseBlock { + const node = createSynthesizedNode(SyntaxKind.CaseBlock); node.clauses = createNodeArray(clauses); return node; } export function updateCaseBlock(node: CaseBlock, clauses: CaseOrDefaultClause[]) { - if (node.clauses !== clauses) { - return updateNode(createCaseBlock(clauses, node), node); - } - return node; + return node.clauses !== clauses + ? updateNode(createCaseBlock(clauses), node) + : 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 = createNode(SyntaxKind.FunctionDeclaration, location, flags); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + export function createFunctionDeclaration(decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) { + const node = createSynthesizedNode(SyntaxKind.FunctionDeclaration); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); node.asteriskToken = asteriskToken; - node.name = typeof name === "string" ? createIdentifier(name) : name; - node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined; + node.name = asName(name); + node.typeParameters = asNodeArray(typeParameters); node.parameters = createNodeArray(parameters); node.type = type; node.body = body; @@ -1079,163 +1067,172 @@ 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 node; - } - - export function createClassDeclaration(decorators: Decorator[], modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], heritageClauses: HeritageClause[], members: ClassElement[], location?: TextRange) { - const node = createNode(SyntaxKind.ClassDeclaration, location); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; - node.name = name; - node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined; - node.heritageClauses = createNodeArray(heritageClauses); + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.name !== name + || node.typeParameters !== typeParameters + || node.parameters !== parameters + || node.type !== type + || node.body !== body + ? updateNode(createFunctionDeclaration(decorators, modifiers, node.asteriskToken, name, typeParameters, parameters, type, body), node) + : node; + } + + export function createClassDeclaration(decorators: Decorator[], modifiers: Modifier[], name: string | Identifier, typeParameters: TypeParameterDeclaration[], heritageClauses: HeritageClause[], members: ClassElement[]) { + const node = createSynthesizedNode(SyntaxKind.ClassDeclaration); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); + node.name = asName(name); + node.typeParameters = asNodeArray(typeParameters); + node.heritageClauses = asNodeArray(heritageClauses); node.members = createNodeArray(members); return node; } export function updateClassDeclaration(node: ClassDeclaration, decorators: Decorator[], modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], heritageClauses: HeritageClause[], members: ClassElement[]) { - if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.heritageClauses !== heritageClauses || node.members !== members) { - return updateNode(createClassDeclaration(decorators, modifiers, name, typeParameters, heritageClauses, members, node), node); - } - return node; - } - - export function createImportDeclaration(decorators: Decorator[], modifiers: Modifier[], importClause: ImportClause, moduleSpecifier?: Expression, location?: TextRange): ImportDeclaration { - const node = createNode(SyntaxKind.ImportDeclaration, location); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.name !== name + || node.typeParameters !== typeParameters + || node.heritageClauses !== heritageClauses + || node.members !== members + ? updateNode(createClassDeclaration(decorators, modifiers, name, typeParameters, heritageClauses, members), node) + : node; + } + + export function createImportDeclaration(decorators: Decorator[], modifiers: Modifier[], importClause: ImportClause, moduleSpecifier?: Expression): ImportDeclaration { + const node = createSynthesizedNode(SyntaxKind.ImportDeclaration); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); node.importClause = importClause; node.moduleSpecifier = moduleSpecifier; return node; } export function updateImportDeclaration(node: ImportDeclaration, decorators: Decorator[], modifiers: Modifier[], importClause: ImportClause, moduleSpecifier: Expression) { - if (node.decorators !== decorators || node.modifiers !== modifiers || node.importClause !== importClause || node.moduleSpecifier !== moduleSpecifier) { - return updateNode(createImportDeclaration(decorators, modifiers, importClause, moduleSpecifier, node), node); - } - return node; + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.importClause !== importClause || node.moduleSpecifier !== moduleSpecifier + ? updateNode(createImportDeclaration(decorators, modifiers, importClause, moduleSpecifier), node) + : node; } - export function createImportClause(name: Identifier, namedBindings: NamedImportBindings, location?: TextRange): ImportClause { - const node = createNode(SyntaxKind.ImportClause, location); + export function createImportClause(name: Identifier, namedBindings: NamedImportBindings): ImportClause { + const node = createSynthesizedNode(SyntaxKind.ImportClause); node.name = name; node.namedBindings = namedBindings; return node; } export function updateImportClause(node: ImportClause, name: Identifier, namedBindings: NamedImportBindings) { - if (node.name !== name || node.namedBindings !== namedBindings) { - return updateNode(createImportClause(name, namedBindings, node), node); - } - return node; + return node.name !== name + || node.namedBindings !== namedBindings + ? updateNode(createImportClause(name, namedBindings), node) + : node; } - export function createNamespaceImport(name: Identifier, location?: TextRange): NamespaceImport { - const node = createNode(SyntaxKind.NamespaceImport, location); + export function createNamespaceImport(name: Identifier): NamespaceImport { + const node = createSynthesizedNode(SyntaxKind.NamespaceImport); node.name = name; return node; } export function updateNamespaceImport(node: NamespaceImport, name: Identifier) { - if (node.name !== name) { - return updateNode(createNamespaceImport(name, node), node); - } - return node; + return node.name !== name + ? updateNode(createNamespaceImport(name), node) + : node; } - export function createNamedImports(elements: ImportSpecifier[], location?: TextRange): NamedImports { - const node = createNode(SyntaxKind.NamedImports, location); + export function createNamedImports(elements: ImportSpecifier[]): NamedImports { + const node = createSynthesizedNode(SyntaxKind.NamedImports); node.elements = createNodeArray(elements); return node; } export function updateNamedImports(node: NamedImports, elements: ImportSpecifier[]) { - if (node.elements !== elements) { - return updateNode(createNamedImports(elements, node), node); - } - return node; + return node.elements !== elements + ? updateNode(createNamedImports(elements), node) + : node; } - export function createImportSpecifier(propertyName: Identifier, name: Identifier, location?: TextRange) { - const node = createNode(SyntaxKind.ImportSpecifier, location); + export function createImportSpecifier(propertyName: Identifier, name: Identifier) { + const node = createSynthesizedNode(SyntaxKind.ImportSpecifier); node.propertyName = propertyName; node.name = name; return node; } export function updateImportSpecifier(node: ImportSpecifier, propertyName: Identifier, name: Identifier) { - if (node.propertyName !== propertyName || node.name !== name) { - return updateNode(createImportSpecifier(propertyName, name, node), node); - } - return node; + return node.propertyName !== propertyName + || node.name !== name + ? updateNode(createImportSpecifier(propertyName, name), node) + : node; } - export function createExportAssignment(decorators: Decorator[], modifiers: Modifier[], isExportEquals: boolean, expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.ExportAssignment, location); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + export function createExportAssignment(decorators: Decorator[], modifiers: Modifier[], isExportEquals: boolean, expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.ExportAssignment); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); node.isExportEquals = isExportEquals; node.expression = expression; return node; } export function updateExportAssignment(node: ExportAssignment, decorators: Decorator[], modifiers: Modifier[], expression: Expression) { - if (node.decorators !== decorators || node.modifiers !== modifiers || node.expression !== expression) { - return updateNode(createExportAssignment(decorators, modifiers, node.isExportEquals, expression, node), node); - } - return node; + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.expression !== expression + ? updateNode(createExportAssignment(decorators, modifiers, node.isExportEquals, expression), node) + : node; } - export function createExportDeclaration(decorators: Decorator[], modifiers: Modifier[], exportClause: NamedExports, moduleSpecifier?: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.ExportDeclaration, location); - node.decorators = decorators ? createNodeArray(decorators) : undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + export function createExportDeclaration(decorators: Decorator[], modifiers: Modifier[], exportClause: NamedExports, moduleSpecifier?: Expression) { + const node = createSynthesizedNode(SyntaxKind.ExportDeclaration); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); node.exportClause = exportClause; node.moduleSpecifier = moduleSpecifier; return node; } export function updateExportDeclaration(node: ExportDeclaration, decorators: Decorator[], modifiers: Modifier[], exportClause: NamedExports, moduleSpecifier: Expression) { - if (node.decorators !== decorators || node.modifiers !== modifiers || node.exportClause !== exportClause || node.moduleSpecifier !== moduleSpecifier) { - return updateNode(createExportDeclaration(decorators, modifiers, exportClause, moduleSpecifier, node), node); - } - return node; + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.exportClause !== exportClause + || node.moduleSpecifier !== moduleSpecifier + ? updateNode(createExportDeclaration(decorators, modifiers, exportClause, moduleSpecifier), node) + : node; } - export function createNamedExports(elements: ExportSpecifier[], location?: TextRange) { - const node = createNode(SyntaxKind.NamedExports, location); + export function createNamedExports(elements: ExportSpecifier[]) { + const node = createSynthesizedNode(SyntaxKind.NamedExports); node.elements = createNodeArray(elements); return node; } export function updateNamedExports(node: NamedExports, elements: ExportSpecifier[]) { - if (node.elements !== elements) { - return updateNode(createNamedExports(elements, node), node); - } - return node; + return node.elements !== elements + ? updateNode(createNamedExports(elements), node) + : node; } - export function createExportSpecifier(name: string | Identifier, propertyName?: string | Identifier, location?: TextRange) { - const node = createNode(SyntaxKind.ExportSpecifier, location); - node.name = typeof name === "string" ? createIdentifier(name) : name; - node.propertyName = typeof propertyName === "string" ? createIdentifier(propertyName) : propertyName; + export function createExportSpecifier(name: string | Identifier, propertyName?: string | Identifier) { + const node = createSynthesizedNode(SyntaxKind.ExportSpecifier); + node.name = asName(name); + node.propertyName = asName(propertyName); return node; } export function updateExportSpecifier(node: ExportSpecifier, name: Identifier, propertyName: Identifier) { - if (node.name !== name || node.propertyName !== propertyName) { - return updateNode(createExportSpecifier(name, propertyName, node), node); - } - return node; + return node.name !== name || node.propertyName !== propertyName + ? updateNode(createExportSpecifier(name, propertyName), node) + : node; } // JSX - export function createJsxElement(openingElement: JsxOpeningElement, children: JsxChild[], closingElement: JsxClosingElement, location?: TextRange) { - const node = createNode(SyntaxKind.JsxElement, location); + export function createJsxElement(openingElement: JsxOpeningElement, children: JsxChild[], closingElement: JsxClosingElement) { + const node = createSynthesizedNode(SyntaxKind.JsxElement); node.openingElement = openingElement; node.children = createNodeArray(children); node.closingElement = closingElement; @@ -1243,98 +1240,96 @@ namespace ts { } export function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: JsxChild[], closingElement: JsxClosingElement) { - if (node.openingElement !== openingElement || node.children !== children || node.closingElement !== closingElement) { - return updateNode(createJsxElement(openingElement, children, closingElement, node), node); - } - return node; + return node.openingElement !== openingElement + || node.children !== children + || node.closingElement !== closingElement + ? updateNode(createJsxElement(openingElement, children, closingElement), node) + : node; } - export function createJsxSelfClosingElement(tagName: JsxTagNameExpression, attributes: JsxAttributeLike[], location?: TextRange) { - const node = createNode(SyntaxKind.JsxSelfClosingElement, location); + export function createJsxSelfClosingElement(tagName: JsxTagNameExpression, attributes: JsxAttributeLike[]) { + const node = createSynthesizedNode(SyntaxKind.JsxSelfClosingElement); node.tagName = tagName; node.attributes = createNodeArray(attributes); return node; } export function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, attributes: JsxAttributeLike[]) { - if (node.tagName !== tagName || node.attributes !== attributes) { - return updateNode(createJsxSelfClosingElement(tagName, attributes, node), node); - } - return node; + return node.tagName !== tagName + || node.attributes !== attributes + ? updateNode(createJsxSelfClosingElement(tagName, attributes), node) + : node; } - export function createJsxOpeningElement(tagName: JsxTagNameExpression, attributes: JsxAttributeLike[], location?: TextRange) { - const node = createNode(SyntaxKind.JsxOpeningElement, location); + export function createJsxOpeningElement(tagName: JsxTagNameExpression, attributes: JsxAttributeLike[]) { + const node = createSynthesizedNode(SyntaxKind.JsxOpeningElement); node.tagName = tagName; node.attributes = createNodeArray(attributes); return node; } export function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, attributes: JsxAttributeLike[]) { - if (node.tagName !== tagName || node.attributes !== attributes) { - return updateNode(createJsxOpeningElement(tagName, attributes, node), node); - } - return node; + return node.tagName !== tagName + || node.attributes !== attributes + ? updateNode(createJsxOpeningElement(tagName, attributes), node) + : node; } - export function createJsxClosingElement(tagName: JsxTagNameExpression, location?: TextRange) { - const node = createNode(SyntaxKind.JsxClosingElement, location); + export function createJsxClosingElement(tagName: JsxTagNameExpression) { + const node = createSynthesizedNode(SyntaxKind.JsxClosingElement); node.tagName = tagName; return node; } export function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression) { - if (node.tagName !== tagName) { - return updateNode(createJsxClosingElement(tagName, node), node); - } - return node; + return node.tagName !== tagName + ? updateNode(createJsxClosingElement(tagName), node) + : node; } - export function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression, location?: TextRange) { - const node = createNode(SyntaxKind.JsxAttribute, location); + export function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression) { + const node = createSynthesizedNode(SyntaxKind.JsxAttribute); node.name = name; node.initializer = initializer; return node; } export function updateJsxAttribute(node: JsxAttribute, name: Identifier, initializer: StringLiteral | JsxExpression) { - if (node.name !== name || node.initializer !== initializer) { - return updateNode(createJsxAttribute(name, initializer, node), node); - } - return node; + return node.name !== name + || node.initializer !== initializer + ? updateNode(createJsxAttribute(name, initializer), node) + : node; } - export function createJsxSpreadAttribute(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.JsxSpreadAttribute, location); + export function createJsxSpreadAttribute(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.JsxSpreadAttribute); node.expression = expression; return node; } export function updateJsxSpreadAttribute(node: JsxSpreadAttribute, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createJsxSpreadAttribute(expression, node), node); - } - return node; + return node.expression !== expression + ? updateNode(createJsxSpreadAttribute(expression), node) + : node; } - export function createJsxExpression(expression: Expression, dotDotDotToken: Token, location?: TextRange) { - const node = createNode(SyntaxKind.JsxExpression, location); + export function createJsxExpression(expression: Expression, dotDotDotToken: DotDotDotToken) { + const node = createSynthesizedNode(SyntaxKind.JsxExpression); node.dotDotDotToken = dotDotDotToken; node.expression = expression; return node; } export function updateJsxExpression(node: JsxExpression, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createJsxExpression(expression, node.dotDotDotToken, node), node); - } - return node; + return node.expression !== expression + ? updateNode(createJsxExpression(expression, node.dotDotDotToken), node) + : node; } // Clauses - export function createHeritageClause(token: SyntaxKind, types: ExpressionWithTypeArguments[], location?: TextRange) { - const node = createNode(SyntaxKind.HeritageClause, location); + export function createHeritageClause(token: SyntaxKind, types: ExpressionWithTypeArguments[]) { + const node = createSynthesizedNode(SyntaxKind.HeritageClause); node.token = token; node.types = createNodeArray(types); return node; @@ -1342,13 +1337,13 @@ namespace ts { export function updateHeritageClause(node: HeritageClause, types: ExpressionWithTypeArguments[]) { if (node.types !== types) { - return updateNode(createHeritageClause(node.token, types, node), node); + return updateNode(createHeritageClause(node.token, types), node); } return node; } - export function createCaseClause(expression: Expression, statements: Statement[], location?: TextRange) { - const node = createNode(SyntaxKind.CaseClause, location); + export function createCaseClause(expression: Expression, statements: Statement[]) { + const node = createSynthesizedNode(SyntaxKind.CaseClause); node.expression = parenthesizeExpressionForList(expression); node.statements = createNodeArray(statements); return node; @@ -1356,26 +1351,26 @@ namespace ts { export function updateCaseClause(node: CaseClause, expression: Expression, statements: Statement[]) { if (node.expression !== expression || node.statements !== statements) { - return updateNode(createCaseClause(expression, statements, node), node); + return updateNode(createCaseClause(expression, statements), node); } return node; } - export function createDefaultClause(statements: Statement[], location?: TextRange) { - const node = createNode(SyntaxKind.DefaultClause, location); + export function createDefaultClause(statements: Statement[]) { + const node = createSynthesizedNode(SyntaxKind.DefaultClause); node.statements = createNodeArray(statements); return node; } export function updateDefaultClause(node: DefaultClause, statements: Statement[]) { if (node.statements !== statements) { - return updateNode(createDefaultClause(statements, node), node); + return updateNode(createDefaultClause(statements), node); } return node; } - export function createCatchClause(variableDeclaration: string | VariableDeclaration, block: Block, location?: TextRange) { - const node = createNode(SyntaxKind.CatchClause, location); + export function createCatchClause(variableDeclaration: string | VariableDeclaration, block: Block) { + const node = createSynthesizedNode(SyntaxKind.CatchClause); node.variableDeclaration = typeof variableDeclaration === "string" ? createVariableDeclaration(variableDeclaration) : variableDeclaration; node.block = block; return node; @@ -1383,16 +1378,16 @@ namespace ts { export function updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration, block: Block) { if (node.variableDeclaration !== variableDeclaration || node.block !== block) { - return updateNode(createCatchClause(variableDeclaration, block, node), node); + return updateNode(createCatchClause(variableDeclaration, block), node); } return node; } // Property assignments - export function createPropertyAssignment(name: string | PropertyName, initializer: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.PropertyAssignment, location); - node.name = typeof name === "string" ? createIdentifier(name) : name; + export function createPropertyAssignment(name: string | PropertyName, initializer: Expression) { + const node = createSynthesizedNode(SyntaxKind.PropertyAssignment); + node.name = asName(name); node.questionToken = undefined; node.initializer = initializer !== undefined ? parenthesizeExpressionForList(initializer) : undefined; return node; @@ -1400,34 +1395,34 @@ namespace ts { export function updatePropertyAssignment(node: PropertyAssignment, name: PropertyName, initializer: Expression) { if (node.name !== name || node.initializer !== initializer) { - return updateNode(createPropertyAssignment(name, initializer, node), node); + return updateNode(createPropertyAssignment(name, initializer), node); } return node; } - export function createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.ShorthandPropertyAssignment, location); - node.name = typeof name === "string" ? createIdentifier(name) : name; + export function createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer: Expression) { + const node = createSynthesizedNode(SyntaxKind.ShorthandPropertyAssignment); + node.name = asName(name); node.objectAssignmentInitializer = objectAssignmentInitializer !== undefined ? parenthesizeExpressionForList(objectAssignmentInitializer) : undefined; return node; } - export function createSpreadAssignment(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.SpreadAssignment, location); + export function createSpreadAssignment(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.SpreadAssignment); node.expression = expression !== undefined ? parenthesizeExpressionForList(expression) : undefined; return node; } export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression) { if (node.name !== name || node.objectAssignmentInitializer !== objectAssignmentInitializer) { - return updateNode(createShorthandPropertyAssignment(name, objectAssignmentInitializer, node), node); + return updateNode(createShorthandPropertyAssignment(name, objectAssignmentInitializer), node); } return node; } export function updateSpreadAssignment(node: SpreadAssignment, expression: Expression) { if (node.expression !== expression) { - return updateNode(createSpreadAssignment(expression, node), node); + return updateNode(createSpreadAssignment(expression), node); } return node; } @@ -1436,7 +1431,8 @@ namespace ts { export function updateSourceFileNode(node: SourceFile, statements: Statement[]) { if (node.statements !== statements) { - const updated = createNode(SyntaxKind.SourceFile, /*location*/ node, node.flags); + const updated = createSynthesizedNode(SyntaxKind.SourceFile); + updated.flags |= node.flags; updated.statements = createNodeArray(statements); updated.endOfFileToken = node.endOfFileToken; updated.fileName = node.fileName; @@ -1472,17 +1468,29 @@ namespace ts { return node; } - // Transformation nodes - /** - * Creates a synthetic statement to act as a placeholder for a not-emitted statement in - * order to preserve comments. - * - * @param original The original statement. + * Creates a shallow, memberwise clone of a node for mutation. + */ + export function getMutableClone(node: T): T { + const clone = getSynthesizedClone(node); + clone.pos = node.pos; + clone.end = node.end; + clone.parent = node.parent; + return clone; + } + + // Transformation nodes + + /** + * Creates a synthetic statement to act as a placeholder for a not-emitted statement in + * order to preserve comments. + * + * @param original The original statement. */ export function createNotEmittedStatement(original: Node) { - const node = createNode(SyntaxKind.NotEmittedStatement, /*location*/ original); + const node = createSynthesizedNode(SyntaxKind.NotEmittedStatement); node.original = original; + setTextRange(node, original); return node; } @@ -1490,8 +1498,9 @@ namespace ts { * Creates a synthetic element to act as a placeholder for the end of an emitted declaration in * order to properly emit exports. */ + /* @internal */ export function createEndOfDeclarationMarker(original: Node) { - const node = createNode(SyntaxKind.EndOfDeclarationMarker); + const node = createSynthesizedNode(SyntaxKind.EndOfDeclarationMarker); node.emitNode = {}; node.original = original; return node; @@ -1501,8 +1510,9 @@ namespace ts { * Creates a synthetic element to act as a placeholder for the beginning of a merged declaration in * order to properly emit exports. */ + /* @internal */ export function createMergeDeclarationMarker(original: Node) { - const node = createNode(SyntaxKind.MergeDeclarationMarker); + const node = createSynthesizedNode(SyntaxKind.MergeDeclarationMarker); node.emitNode = {}; node.original = original; return node; @@ -1516,16 +1526,17 @@ namespace ts { * @param original The original outer expression. * @param location The location for the expression. Defaults to the positions from "original" if provided. */ - export function createPartiallyEmittedExpression(expression: Expression, original?: Node, location?: TextRange) { - const node = createNode(SyntaxKind.PartiallyEmittedExpression, /*location*/ location || original); + export function createPartiallyEmittedExpression(expression: Expression, original?: Node) { + const node = createSynthesizedNode(SyntaxKind.PartiallyEmittedExpression); node.expression = expression; node.original = original; + setTextRange(node, original); return node; } export function updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression) { if (node.expression !== expression) { - return updateNode(createPartiallyEmittedExpression(expression, node.original, node), node); + return updateNode(createPartiallyEmittedExpression(expression, node.original), node); } return node; } @@ -1549,14 +1560,14 @@ namespace ts { return createBinary(left, SyntaxKind.CommaToken, right); } - export function createLessThan(left: Expression, right: Expression, location?: TextRange) { - return createBinary(left, SyntaxKind.LessThanToken, right, location); + export function createLessThan(left: Expression, right: Expression) { + return createBinary(left, SyntaxKind.LessThanToken, right); } - export function createAssignment(left: ObjectLiteralExpression | ArrayLiteralExpression, right: Expression, location?: TextRange): DestructuringAssignment; - export function createAssignment(left: Expression, right: Expression, location?: TextRange): BinaryExpression; - export function createAssignment(left: Expression, right: Expression, location?: TextRange) { - return createBinary(left, SyntaxKind.EqualsToken, right, location); + export function createAssignment(left: ObjectLiteralExpression | ArrayLiteralExpression, right: Expression): DestructuringAssignment; + export function createAssignment(left: Expression, right: Expression): BinaryExpression; + export function createAssignment(left: Expression, right: Expression) { + return createBinary(left, SyntaxKind.EqualsToken, right); } export function createStrictEquality(left: Expression, right: Expression) { @@ -1575,8 +1586,8 @@ namespace ts { return createBinary(left, SyntaxKind.MinusToken, right); } - export function createPostfixIncrement(operand: Expression, location?: TextRange) { - return createPostfix(operand, SyntaxKind.PlusPlusToken, location); + export function createPostfixIncrement(operand: Expression) { + return createPostfix(operand, SyntaxKind.PlusPlusToken); } export function createLogicalAnd(left: Expression, right: Expression) { @@ -1595,6 +1606,321 @@ namespace ts { return createVoid(createLiteral(0)); } + export function createExportDefault(expression: Expression) { + return createExportAssignment(/*decorators*/ undefined, /*modifiers*/ undefined, /*isExportEquals*/ false, expression); + } + + export function createExternalModuleExport(exportName: Identifier) { + return createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([createExportSpecifier(exportName)])); + } + + // Utilities + + function asName(name: string): Identifier; + function asName(name: Identifier): Identifier; + function asName(name: string | Identifier): Identifier; + function asName(name: string | BindingName): BindingName; + function asName(name: string | PropertyName): PropertyName; + function asName(name: string | Identifier | BindingName | PropertyName) { + return typeof name === "string" ? createIdentifier(name) : name; + } + + function asExpression(value: string | number | Expression) { + return typeof value === "string" || typeof value === "number" ? createLiteral(value) : value; + } + + function asNodeArray(array: T[] | undefined): NodeArray | undefined { + return array ? createNodeArray(array) : undefined; + } + + function asToken(value: TKind | Token): Token { + return typeof value === "number" ? createToken(value) : value; + } + + /** + * Clears any EmitNode entries from parse-tree nodes. + * @param sourceFile A source file. + */ + export function disposeEmitNodes(sourceFile: SourceFile) { + // During transformation we may need to annotate a parse tree node with transient + // transformation properties. As parse tree nodes live longer than transformation + // nodes, we need to make sure we reclaim any memory allocated for custom ranges + // from these nodes to ensure we do not hold onto entire subtrees just for position + // information. We also need to reset these nodes to a pre-transformation state + // for incremental parsing scenarios so that we do not impact later emit. + sourceFile = getSourceFileOfNode(getParseTreeNode(sourceFile)); + const emitNode = sourceFile && sourceFile.emitNode; + const annotatedNodes = emitNode && emitNode.annotatedNodes; + if (annotatedNodes) { + for (const node of annotatedNodes) { + node.emitNode = undefined; + } + } + } + + /** + * Associates a node with the current transformation, initializing + * various transient transformation properties. + * + * @param node The node. + */ + /* @internal */ + export function getOrCreateEmitNode(node: Node) { + if (!node.emitNode) { + if (isParseTreeNode(node)) { + // To avoid holding onto transformation artifacts, we keep track of any + // parse tree node we are annotating. This allows us to clean them up after + // all transformations have completed. + if (node.kind === SyntaxKind.SourceFile) { + return node.emitNode = { annotatedNodes: [node] }; + } + + const sourceFile = getSourceFileOfNode(node); + getOrCreateEmitNode(sourceFile).annotatedNodes.push(node); + } + + node.emitNode = {}; + } + + return node.emitNode; + } + + export function setTextRange(range: T, location: TextRange | undefined): T { + if (location) { + range.pos = location.pos; + range.end = location.end; + } + return range; + } + + /** + * Gets flags that control emit behavior of a node. + * + * @param node The node. + */ + export function getEmitFlags(node: Node) { + const emitNode = node.emitNode; + return emitNode && emitNode.flags; + } + + /** + * Sets flags that control emit behavior of a node. + * + * @param node The node. + * @param emitFlags The NodeEmitFlags for the node. + */ + export function setEmitFlags(node: T, emitFlags: EmitFlags) { + getOrCreateEmitNode(node).flags = emitFlags; + return node; + } + + /** + * Gets a custom text range to use when emitting source maps. + * + * @param node The node. + */ + export function getSourceMapRange(node: Node) { + const emitNode = node.emitNode; + return (emitNode && emitNode.sourceMapRange) || node; + } + + /** + * Sets a custom text range to use when emitting source maps. + * + * @param node The node. + * @param range The text range. + */ + export function setSourceMapRange(node: T, range: TextRange) { + getOrCreateEmitNode(node).sourceMapRange = range; + return node; + } + + /** + * Gets the TextRange to use for source maps for a token of a node. + * + * @param node The node. + * @param token The token. + */ + export function getTokenSourceMapRange(node: Node, token: SyntaxKind) { + const emitNode = node.emitNode; + const tokenSourceMapRanges = emitNode && emitNode.tokenSourceMapRanges; + return tokenSourceMapRanges && tokenSourceMapRanges[token]; + } + + /** + * Sets the TextRange to use for source maps for a token of a node. + * + * @param node The node. + * @param token The token. + * @param range The text range. + */ + export function setTokenSourceMapRange(node: T, token: SyntaxKind, range: TextRange) { + const emitNode = getOrCreateEmitNode(node); + const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = []); + tokenSourceMapRanges[token] = range; + return node; + } + + /** + * Gets a custom text range to use when emitting comments. + * + * @param node The node. + */ + export function getCommentRange(node: Node) { + const emitNode = node.emitNode; + return (emitNode && emitNode.commentRange) || node; + } + + /** + * Sets a custom text range to use when emitting comments. + */ + export function setCommentRange(node: T, range: TextRange) { + getOrCreateEmitNode(node).commentRange = range; + return node; + } + + /** + * Gets the constant value to emit for an expression. + */ + export function getConstantValue(node: PropertyAccessExpression | ElementAccessExpression) { + const emitNode = node.emitNode; + return emitNode && emitNode.constantValue; + } + + /** + * Sets the constant value to emit for an expression. + */ + export function setConstantValue(node: PropertyAccessExpression | ElementAccessExpression, value: number) { + const emitNode = getOrCreateEmitNode(node); + emitNode.constantValue = value; + return node; + } + + /** + * Adds an EmitHelper to a node. + */ + export function addEmitHelper(node: T, helper: EmitHelper): T { + const emitNode = getOrCreateEmitNode(node); + emitNode.helpers = append(emitNode.helpers, helper); + return node; + } + + /** + * Add EmitHelpers to a node. + */ + export function addEmitHelpers(node: T, helpers: EmitHelper[] | undefined): T { + if (some(helpers)) { + const emitNode = getOrCreateEmitNode(node); + for (const helper of helpers) { + if (!contains(emitNode.helpers, helper)) { + emitNode.helpers = append(emitNode.helpers, helper); + } + } + } + return node; + } + + /** + * Removes an EmitHelper from a node. + */ + export function removeEmitHelper(node: Node, helper: EmitHelper): boolean { + const emitNode = node.emitNode; + if (emitNode) { + const helpers = emitNode.helpers; + if (helpers) { + return orderedRemoveItem(helpers, helper); + } + } + return false; + } + + /** + * Gets the EmitHelpers of a node. + */ + export function getEmitHelpers(node: Node): EmitHelper[] | undefined { + const emitNode = node.emitNode; + return emitNode && emitNode.helpers; + } + + /** + * Moves matching emit helpers from a source node to a target node. + */ + export function moveEmitHelpers(source: Node, target: Node, predicate: (helper: EmitHelper) => boolean) { + const sourceEmitNode = source.emitNode; + const sourceEmitHelpers = sourceEmitNode && sourceEmitNode.helpers; + if (!some(sourceEmitHelpers)) return; + + const targetEmitNode = getOrCreateEmitNode(target); + let helpersRemoved = 0; + for (let i = 0; i < sourceEmitHelpers.length; i++) { + const helper = sourceEmitHelpers[i]; + if (predicate(helper)) { + helpersRemoved++; + if (!contains(targetEmitNode.helpers, helper)) { + targetEmitNode.helpers = append(targetEmitNode.helpers, helper); + } + } + else if (helpersRemoved > 0) { + sourceEmitHelpers[i - helpersRemoved] = helper; + } + } + + if (helpersRemoved > 0) { + sourceEmitHelpers.length -= helpersRemoved; + } + } + + /* @internal */ + export function compareEmitHelpers(x: EmitHelper, y: EmitHelper) { + if (x === y) return Comparison.EqualTo; + if (x.priority === y.priority) return Comparison.EqualTo; + if (x.priority === undefined) return Comparison.GreaterThan; + if (y.priority === undefined) return Comparison.LessThan; + return compareValues(x.priority, y.priority); + } + + export function setOriginalNode(node: T, original: Node): T { + node.original = original; + if (original) { + const emitNode = original.emitNode; + if (emitNode) node.emitNode = mergeEmitNode(emitNode, node.emitNode); + } + return node; + } + + function mergeEmitNode(sourceEmitNode: EmitNode, destEmitNode: EmitNode) { + const { + flags, + commentRange, + sourceMapRange, + tokenSourceMapRanges, + constantValue, + helpers + } = sourceEmitNode; + if (!destEmitNode) destEmitNode = {}; + if (flags) destEmitNode.flags = flags; + if (commentRange) destEmitNode.commentRange = commentRange; + if (sourceMapRange) destEmitNode.sourceMapRange = sourceMapRange; + if (tokenSourceMapRanges) destEmitNode.tokenSourceMapRanges = mergeTokenSourceMapRanges(tokenSourceMapRanges, destEmitNode.tokenSourceMapRanges); + if (constantValue !== undefined) destEmitNode.constantValue = constantValue; + if (helpers) destEmitNode.helpers = addRange(destEmitNode.helpers, helpers); + return destEmitNode; + } + + function mergeTokenSourceMapRanges(sourceRanges: TextRange[], destRanges: TextRange[]) { + if (!destRanges) destRanges = []; + for (const key in sourceRanges) { + destRanges[key] = sourceRanges[key]; + } + return destRanges; + } +} + +/* @internal */ +namespace ts { + + // Compound nodes + export type TypeOfTag = "undefined" | "number" | "boolean" | "string" | "symbol" | "object" | "function"; export function createTypeCheck(value: Expression, tag: TypeOfTag) { @@ -1605,35 +1931,43 @@ namespace ts { export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, location?: TextRange): MemberExpression { if (isComputedPropertyName(memberName)) { - return createElementAccess(target, memberName.expression, location); + return setTextRange(createElementAccess(target, memberName.expression), location); } else { - const expression = isIdentifier(memberName) ? createPropertyAccess(target, memberName, location) : createElementAccess(target, memberName, location); - (expression.emitNode || (expression.emitNode = {})).flags |= EmitFlags.NoNestedSourceMaps; + const expression = setTextRange( + isIdentifier(memberName) + ? createPropertyAccess(target, memberName) + : createElementAccess(target, memberName), + memberName + ); + getOrCreateEmitNode(expression).flags |= EmitFlags.NoNestedSourceMaps; return expression; } } export function createFunctionCall(func: Expression, thisArg: Expression, argumentsList: Expression[], location?: TextRange) { - return createCall( - createPropertyAccess(func, "call"), - /*typeArguments*/ undefined, - [ - thisArg, - ...argumentsList - ], + return setTextRange( + createCall( + createPropertyAccess(func, "call"), + /*typeArguments*/ undefined, + [ + thisArg, + ...argumentsList + ]), location ); } export function createFunctionApply(func: Expression, thisArg: Expression, argumentsExpression: Expression, location?: TextRange) { - return createCall( - createPropertyAccess(func, "apply"), - /*typeArguments*/ undefined, - [ - thisArg, - argumentsExpression - ], + return setTextRange( + createCall( + createPropertyAccess(func, "apply"), + /*typeArguments*/ undefined, + [ + thisArg, + argumentsExpression + ] + ), location ); } @@ -1656,10 +1990,12 @@ namespace ts { } export function createMathPow(left: Expression, right: Expression, location?: TextRange) { - return createCall( - createPropertyAccess(createIdentifier("Math"), "pow"), - /*typeArguments*/ undefined, - [left, right], + return setTextRange( + createCall( + createPropertyAccess(createIdentifier("Math"), "pow"), + /*typeArguments*/ undefined, + [left, right] + ), location ); } @@ -1679,7 +2015,7 @@ namespace ts { function createJsxFactoryExpressionFromEntityName(jsxFactory: EntityName, parent: JsxOpeningLikeElement): Expression { if (isQualifiedName(jsxFactory)) { const left = createJsxFactoryExpressionFromEntityName(jsxFactory.left, parent); - const right = createSynthesizedNode(SyntaxKind.Identifier); + const right = createIdentifier(jsxFactory.right.text); right.text = jsxFactory.right.text; return createPropertyAccess(left, right); } @@ -1719,34 +2055,16 @@ namespace ts { } } - return createCall( - createJsxFactoryExpression(jsxFactoryEntity, reactNamespace, parentElement), - /*typeArguments*/ undefined, - argumentsList, + return setTextRange( + createCall( + createJsxFactoryExpression(jsxFactoryEntity, reactNamespace, parentElement), + /*typeArguments*/ undefined, + argumentsList + ), location ); } - export function createExportDefault(expression: Expression) { - return createExportAssignment(/*decorators*/ undefined, /*modifiers*/ undefined, /*isExportEquals*/ false, expression); - } - - export function createExternalModuleExport(exportName: Identifier) { - return createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([createExportSpecifier(exportName)])); - } - - export function createLetStatement(name: Identifier, initializer: Expression, location?: TextRange) { - return createVariableStatement(/*modifiers*/ undefined, createLetDeclarationList([createVariableDeclaration(name, /*type*/ undefined, initializer)]), location); - } - - export function createLetDeclarationList(declarations: VariableDeclaration[], location?: TextRange) { - return createVariableDeclarationList(declarations, location, NodeFlags.Let); - } - - export function createConstDeclarationList(declarations: VariableDeclaration[], location?: TextRange) { - return createVariableDeclarationList(declarations, location, NodeFlags.Const); - } - // Helpers export function getHelperName(name: string) { @@ -1809,7 +2127,9 @@ namespace ts { } else if (callee.kind === SyntaxKind.SuperKeyword) { thisArg = createThis(); - target = languageVersion < ScriptTarget.ES2015 ? createIdentifier("_super", /*location*/ callee) : callee; + target = languageVersion < ScriptTarget.ES2015 + ? setTextRange(createIdentifier("_super"), callee) + : callee; } else { switch (callee.kind) { @@ -1818,14 +2138,16 @@ namespace ts { // for `a.b()` target is `(_a = a).b` and thisArg is `_a` thisArg = createTempVariable(recordTempVariable); target = createPropertyAccess( - createAssignment( - thisArg, - (callee).expression, - /*location*/ (callee).expression + setTextRange( + createAssignment( + thisArg, + (callee).expression + ), + (callee).expression ), - (callee).name, - /*location*/ callee + (callee).name ); + setTextRange(target, callee); } else { thisArg = (callee).expression; @@ -1839,14 +2161,16 @@ namespace ts { // for `a[b]()` target is `(_a = a)[b]` and thisArg is `_a` thisArg = createTempVariable(recordTempVariable); target = createElementAccess( - createAssignment( - thisArg, - (callee).expression, - /*location*/ (callee).expression + setTextRange( + createAssignment( + thisArg, + (callee).expression + ), + (callee).expression ), - (callee).argumentExpression, - /*location*/ callee + (callee).argumentExpression ); + setTextRange(target, callee); } else { thisArg = (callee).expression; @@ -1876,7 +2200,7 @@ namespace ts { if (isQualifiedName(node)) { const left = createExpressionFromEntityName(node.left); const right = getMutableClone(node.right); - return createPropertyAccess(left, right, /*location*/ node); + return setTextRange(createPropertyAccess(left, right), node); } else { return getMutableClone(node); @@ -1885,7 +2209,7 @@ namespace ts { export function createExpressionForPropertyName(memberName: PropertyName): Expression { if (isIdentifier(memberName)) { - return createLiteral(memberName, /*location*/ undefined); + return createLiteral(memberName); } else if (isComputedPropertyName(memberName)) { return getMutableClone(memberName.expression); @@ -1921,9 +2245,9 @@ namespace ts { /*typeParameters*/ undefined, getAccessor.parameters, /*type*/ undefined, - getAccessor.body, - /*location*/ getAccessor + getAccessor.body ); + setTextRange(getterFunction, getAccessor); setOriginalNode(getterFunction, getAccessor); const getter = createPropertyAssignment("get", getterFunction); properties.push(getter); @@ -1937,25 +2261,27 @@ namespace ts { /*typeParameters*/ undefined, setAccessor.parameters, /*type*/ undefined, - setAccessor.body, - /*location*/ setAccessor + setAccessor.body ); + setTextRange(setterFunction, setAccessor); setOriginalNode(setterFunction, setAccessor); const setter = createPropertyAssignment("set", setterFunction); properties.push(setter); } - properties.push(createPropertyAssignment("enumerable", createLiteral(true))); - properties.push(createPropertyAssignment("configurable", createLiteral(true))); - - const expression = createCall( - createPropertyAccess(createIdentifier("Object"), "defineProperty"), - /*typeArguments*/ undefined, - [ - receiver, - createExpressionForPropertyName(property.name), - createObjectLiteral(properties, /*location*/ undefined, multiLine) - ], + properties.push(createPropertyAssignment("enumerable", createTrue())); + properties.push(createPropertyAssignment("configurable", createTrue())); + + const expression = setTextRange( + createCall( + createPropertyAccess(createIdentifier("Object"), "defineProperty"), + /*typeArguments*/ undefined, + [ + receiver, + createExpressionForPropertyName(property.name), + createObjectLiteral(properties, multiLine) + ] + ), /*location*/ firstAccessor ); @@ -1968,12 +2294,14 @@ namespace ts { function createExpressionForPropertyAssignment(property: PropertyAssignment, receiver: Expression) { return aggregateTransformFlags( setOriginalNode( - createAssignment( - createMemberAccessForPropertyName(receiver, property.name, /*location*/ property.name), - property.initializer, - /*location*/ property + setTextRange( + createAssignment( + createMemberAccessForPropertyName(receiver, property.name, /*location*/ property.name), + property.initializer + ), + property ), - /*original*/ property + property ) ); } @@ -1981,9 +2309,11 @@ namespace ts { function createExpressionForShorthandPropertyAssignment(property: ShorthandPropertyAssignment, receiver: Expression) { return aggregateTransformFlags( setOriginalNode( - createAssignment( - createMemberAccessForPropertyName(receiver, property.name, /*location*/ property.name), - getSynthesizedClone(property.name), + setTextRange( + createAssignment( + createMemberAccessForPropertyName(receiver, property.name, /*location*/ property.name), + getSynthesizedClone(property.name) + ), /*location*/ property ), /*original*/ property @@ -1994,20 +2324,24 @@ namespace ts { function createExpressionForMethodDeclaration(method: MethodDeclaration, receiver: Expression) { return aggregateTransformFlags( setOriginalNode( - createAssignment( - createMemberAccessForPropertyName(receiver, method.name, /*location*/ method.name), - setOriginalNode( - createFunctionExpression( - method.modifiers, - method.asteriskToken, - /*name*/ undefined, - /*typeParameters*/ undefined, - method.parameters, - /*type*/ undefined, - method.body, - /*location*/ method - ), - /*original*/ method + setTextRange( + createAssignment( + createMemberAccessForPropertyName(receiver, method.name, /*location*/ method.name), + setOriginalNode( + setTextRange( + createFunctionExpression( + method.modifiers, + method.asteriskToken, + /*name*/ undefined, + /*typeParameters*/ undefined, + method.parameters, + /*type*/ undefined, + method.body + ), + /*location*/ method + ), + /*original*/ method + ) ), /*location*/ method ), @@ -2109,7 +2443,8 @@ namespace ts { * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ export function getNamespaceMemberName(ns: Identifier, name: Identifier, allowComments?: boolean, allowSourceMaps?: boolean): PropertyAccessExpression { - const qualifiedName = createPropertyAccess(ns, nodeIsSynthesized(name) ? name : getSynthesizedClone(name), /*location*/ name); + const qualifiedName = createPropertyAccess(ns, nodeIsSynthesized(name) ? name : getSynthesizedClone(name)); + setTextRange(qualifiedName, name); let emitFlags: EmitFlags; if (!allowSourceMaps) emitFlags |= EmitFlags.NoSourceMap; if (!allowComments) emitFlags |= EmitFlags.NoComments; @@ -2118,7 +2453,7 @@ namespace ts { } export function convertToFunctionBody(node: ConciseBody, multiLine?: boolean) { - return isBlock(node) ? node : createBlock([createReturn(node, /*location*/ node)], /*location*/ node, multiLine); + return isBlock(node) ? node : setTextRange(createBlock([setTextRange(createReturn(node), node)], multiLine), node); } function isUseStrictPrologue(node: ExpressionStatement): boolean { @@ -2197,10 +2532,13 @@ namespace ts { } if (!foundUseStrict) { - return createNodeArray([ - startOnNewLine(createStatement(createLiteral("use strict"))), - ...statements - ], statements); + return setTextRange( + createNodeArray([ + startOnNewLine(createStatement(createLiteral("use strict"))), + ...statements + ]), + statements + ); } return statements; @@ -2393,7 +2731,7 @@ namespace ts { return condition; } - function parenthesizeSubexpressionOfConditionalExpression(e: Expression): Expression { + export function parenthesizeSubexpressionOfConditionalExpression(e: Expression): Expression { // per ES grammar both 'whenTrue' and 'whenFalse' parts of conditional expression are assignment expressions // so in case when comma expression is introduced as a part of previous transformations // if should be wrapped in parens since comma operator has the lowest precedence @@ -2445,22 +2783,22 @@ namespace ts { return expression; } - return createParen(expression, /*location*/ expression); + return setTextRange(createParen(expression), expression); } export function parenthesizePostfixOperand(operand: Expression) { return isLeftHandSideExpression(operand) ? operand - : createParen(operand, /*location*/ operand); + : setTextRange(createParen(operand), operand); } export function parenthesizePrefixOperand(operand: Expression) { return isUnaryExpression(operand) ? operand - : createParen(operand, /*location*/ operand); + : setTextRange(createParen(operand), operand); } - function parenthesizeListElements(elements: NodeArray) { + export function parenthesizeListElements(elements: NodeArray) { let result: Expression[]; for (let i = 0; i < elements.length; i++) { const element = parenthesizeExpressionForList(elements[i]); @@ -2474,7 +2812,7 @@ namespace ts { } if (result !== undefined) { - return createNodeArray(result, elements, elements.hasTrailingComma); + return setTextRange(createNodeArray(result, elements.hasTrailingComma), elements); } return elements; @@ -2486,7 +2824,7 @@ namespace ts { const commaPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, SyntaxKind.CommaToken); return expressionPrecedence > commaPrecedence ? expression - : createParen(expression, /*location*/ expression); + : setTextRange(createParen(expression), expression); } export function parenthesizeExpressionForExpressionStatement(expression: Expression) { @@ -2496,14 +2834,14 @@ namespace ts { const kind = skipPartiallyEmittedExpressions(callee).kind; if (kind === SyntaxKind.FunctionExpression || kind === SyntaxKind.ArrowFunction) { const mutableCall = getMutableClone(emittedExpression); - mutableCall.expression = createParen(callee, /*location*/ callee); + mutableCall.expression = setTextRange(createParen(callee), callee); return recreatePartiallyEmittedExpressions(expression, mutableCall); } } else { const leftmostExpressionKind = getLeftmostExpression(emittedExpression).kind; if (leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression || leftmostExpressionKind === SyntaxKind.FunctionExpression) { - return createParen(expression, /*location*/ expression); + return setTextRange(createParen(expression), expression); } } @@ -2551,269 +2889,83 @@ namespace ts { node = (node).expression; continue; } - - return node; - } - } - - export function parenthesizeConciseBody(body: ConciseBody): ConciseBody { - const emittedBody = skipPartiallyEmittedExpressions(body); - if (emittedBody.kind === SyntaxKind.ObjectLiteralExpression) { - return createParen(body, /*location*/ body); - } - - return body; - } - - export const enum OuterExpressionKinds { - Parentheses = 1 << 0, - Assertions = 1 << 1, - PartiallyEmittedExpressions = 1 << 2, - - All = Parentheses | Assertions | PartiallyEmittedExpressions - } - - export function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKinds): Expression; - export function skipOuterExpressions(node: Node, kinds?: OuterExpressionKinds): Node; - export function skipOuterExpressions(node: Node, kinds = OuterExpressionKinds.All) { - let previousNode: Node; - do { - previousNode = node; - if (kinds & OuterExpressionKinds.Parentheses) { - node = skipParentheses(node); - } - - if (kinds & OuterExpressionKinds.Assertions) { - node = skipAssertions(node); - } - - if (kinds & OuterExpressionKinds.PartiallyEmittedExpressions) { - node = skipPartiallyEmittedExpressions(node); - } - } - while (previousNode !== node); - - return node; - } - - export function skipParentheses(node: Expression): Expression; - export function skipParentheses(node: Node): Node; - export function skipParentheses(node: Node): Node { - while (node.kind === SyntaxKind.ParenthesizedExpression) { - node = (node).expression; - } - - return node; - } - - export function skipAssertions(node: Expression): Expression; - export function skipAssertions(node: Node): Node; - export function skipAssertions(node: Node): Node { - while (isAssertionExpression(node)) { - node = (node).expression; - } - - return node; - } - - export function skipPartiallyEmittedExpressions(node: Expression): Expression; - export function skipPartiallyEmittedExpressions(node: Node): Node; - export function skipPartiallyEmittedExpressions(node: Node) { - while (node.kind === SyntaxKind.PartiallyEmittedExpression) { - node = (node).expression; - } - - return node; - } - - export function startOnNewLine(node: T): T { - node.startsOnNewLine = true; - return node; - } - - export function setOriginalNode(node: T, original: Node): T { - node.original = original; - if (original) { - const emitNode = original.emitNode; - if (emitNode) node.emitNode = mergeEmitNode(emitNode, node.emitNode); - } - return node; - } - - function mergeEmitNode(sourceEmitNode: EmitNode, destEmitNode: EmitNode) { - const { - flags, - commentRange, - sourceMapRange, - tokenSourceMapRanges, - constantValue, - helpers - } = sourceEmitNode; - if (!destEmitNode) destEmitNode = {}; - if (flags) destEmitNode.flags = flags; - if (commentRange) destEmitNode.commentRange = commentRange; - if (sourceMapRange) destEmitNode.sourceMapRange = sourceMapRange; - if (tokenSourceMapRanges) destEmitNode.tokenSourceMapRanges = mergeTokenSourceMapRanges(tokenSourceMapRanges, destEmitNode.tokenSourceMapRanges); - if (constantValue !== undefined) destEmitNode.constantValue = constantValue; - if (helpers) destEmitNode.helpers = addRange(destEmitNode.helpers, helpers); - return destEmitNode; - } - - function mergeTokenSourceMapRanges(sourceRanges: TextRange[], destRanges: TextRange[]) { - if (!destRanges) destRanges = []; - for (const key in sourceRanges) { - destRanges[key] = sourceRanges[key]; - } - return destRanges; - } - - /** - * Clears any EmitNode entries from parse-tree nodes. - * @param sourceFile A source file. - */ - export function disposeEmitNodes(sourceFile: SourceFile) { - // During transformation we may need to annotate a parse tree node with transient - // transformation properties. As parse tree nodes live longer than transformation - // nodes, we need to make sure we reclaim any memory allocated for custom ranges - // from these nodes to ensure we do not hold onto entire subtrees just for position - // information. We also need to reset these nodes to a pre-transformation state - // for incremental parsing scenarios so that we do not impact later emit. - sourceFile = getSourceFileOfNode(getParseTreeNode(sourceFile)); - const emitNode = sourceFile && sourceFile.emitNode; - const annotatedNodes = emitNode && emitNode.annotatedNodes; - if (annotatedNodes) { - for (const node of annotatedNodes) { - node.emitNode = undefined; - } + + return node; } } - /** - * Associates a node with the current transformation, initializing - * various transient transformation properties. - * - * @param node The node. - */ - export function getOrCreateEmitNode(node: Node) { - if (!node.emitNode) { - if (isParseTreeNode(node)) { - // To avoid holding onto transformation artifacts, we keep track of any - // parse tree node we are annotating. This allows us to clean them up after - // all transformations have completed. - if (node.kind === SyntaxKind.SourceFile) { - return node.emitNode = { annotatedNodes: [node] }; - } - - const sourceFile = getSourceFileOfNode(node); - getOrCreateEmitNode(sourceFile).annotatedNodes.push(node); - } - - node.emitNode = {}; + export function parenthesizeConciseBody(body: ConciseBody): ConciseBody { + const emittedBody = skipPartiallyEmittedExpressions(body); + if (emittedBody.kind === SyntaxKind.ObjectLiteralExpression) { + return setTextRange(createParen(body), body); } - return node.emitNode; + return body; } - /** - * Gets flags that control emit behavior of a node. - * - * @param node The node. - */ - export function getEmitFlags(node: Node) { - const emitNode = node.emitNode; - return emitNode && emitNode.flags; - } + export const enum OuterExpressionKinds { + Parentheses = 1 << 0, + Assertions = 1 << 1, + PartiallyEmittedExpressions = 1 << 2, - /** - * Sets flags that control emit behavior of a node. - * - * @param node The node. - * @param emitFlags The NodeEmitFlags for the node. - */ - export function setEmitFlags(node: T, emitFlags: EmitFlags) { - getOrCreateEmitNode(node).flags = emitFlags; - return node; + All = Parentheses | Assertions | PartiallyEmittedExpressions } - /** - * Gets a custom text range to use when emitting source maps. - * - * @param node The node. - */ - export function getSourceMapRange(node: Node) { - const emitNode = node.emitNode; - return (emitNode && emitNode.sourceMapRange) || node; - } + export function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKinds): Expression; + export function skipOuterExpressions(node: Node, kinds?: OuterExpressionKinds): Node; + export function skipOuterExpressions(node: Node, kinds = OuterExpressionKinds.All) { + let previousNode: Node; + do { + previousNode = node; + if (kinds & OuterExpressionKinds.Parentheses) { + node = skipParentheses(node); + } + + if (kinds & OuterExpressionKinds.Assertions) { + node = skipAssertions(node); + } + + if (kinds & OuterExpressionKinds.PartiallyEmittedExpressions) { + node = skipPartiallyEmittedExpressions(node); + } + } + while (previousNode !== node); - /** - * Sets a custom text range to use when emitting source maps. - * - * @param node The node. - * @param range The text range. - */ - export function setSourceMapRange(node: T, range: TextRange) { - getOrCreateEmitNode(node).sourceMapRange = range; return node; } - /** - * Gets the TextRange to use for source maps for a token of a node. - * - * @param node The node. - * @param token The token. - */ - export function getTokenSourceMapRange(node: Node, token: SyntaxKind) { - const emitNode = node.emitNode; - const tokenSourceMapRanges = emitNode && emitNode.tokenSourceMapRanges; - return tokenSourceMapRanges && tokenSourceMapRanges[token]; - } + export function skipParentheses(node: Expression): Expression; + export function skipParentheses(node: Node): Node; + export function skipParentheses(node: Node): Node { + while (node.kind === SyntaxKind.ParenthesizedExpression) { + node = (node).expression; + } - /** - * Sets the TextRange to use for source maps for a token of a node. - * - * @param node The node. - * @param token The token. - * @param range The text range. - */ - export function setTokenSourceMapRange(node: T, token: SyntaxKind, range: TextRange) { - const emitNode = getOrCreateEmitNode(node); - const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = []); - tokenSourceMapRanges[token] = range; return node; } - /** - * Gets a custom text range to use when emitting comments. - * - * @param node The node. - */ - export function getCommentRange(node: Node) { - const emitNode = node.emitNode; - return (emitNode && emitNode.commentRange) || node; - } + export function skipAssertions(node: Expression): Expression; + export function skipAssertions(node: Node): Node; + export function skipAssertions(node: Node): Node { + while (isAssertionExpression(node)) { + node = (node).expression; + } - /** - * Sets a custom text range to use when emitting comments. - */ - export function setCommentRange(node: T, range: TextRange) { - getOrCreateEmitNode(node).commentRange = range; return node; } - /** - * Gets the constant value to emit for an expression. - */ - export function getConstantValue(node: PropertyAccessExpression | ElementAccessExpression) { - const emitNode = node.emitNode; - return emitNode && emitNode.constantValue; + export function skipPartiallyEmittedExpressions(node: Expression): Expression; + export function skipPartiallyEmittedExpressions(node: Node): Node; + export function skipPartiallyEmittedExpressions(node: Node) { + while (node.kind === SyntaxKind.PartiallyEmittedExpression) { + node = (node).expression; + } + + return node; } - /** - * Sets the constant value to emit for an expression. - */ - export function setConstantValue(node: PropertyAccessExpression | ElementAccessExpression, value: number) { - const emitNode = getOrCreateEmitNode(node); - emitNode.constantValue = value; + export function startOnNewLine(node: T): T { + node.startsOnNewLine = true; return node; } @@ -2842,110 +2994,6 @@ namespace ts { } } } - /** - * Adds an EmitHelper to a node. - */ - export function addEmitHelper(node: T, helper: EmitHelper): T { - const emitNode = getOrCreateEmitNode(node); - emitNode.helpers = append(emitNode.helpers, helper); - return node; - } - - /** - * Adds an EmitHelper to a node. - */ - export function addEmitHelpers(node: T, helpers: EmitHelper[] | undefined): T { - if (some(helpers)) { - const emitNode = getOrCreateEmitNode(node); - for (const helper of helpers) { - if (!contains(emitNode.helpers, helper)) { - emitNode.helpers = append(emitNode.helpers, helper); - } - } - } - return node; - } - - /** - * Removes an EmitHelper from a node. - */ - export function removeEmitHelper(node: Node, helper: EmitHelper): boolean { - const emitNode = node.emitNode; - if (emitNode) { - const helpers = emitNode.helpers; - if (helpers) { - return orderedRemoveItem(helpers, helper); - } - } - return false; - } - - /** - * Gets the EmitHelpers of a node. - */ - export function getEmitHelpers(node: Node): EmitHelper[] | undefined { - const emitNode = node.emitNode; - return emitNode && emitNode.helpers; - } - - /** - * Moves matching emit helpers from a source node to a target node. - */ - export function moveEmitHelpers(source: Node, target: Node, predicate: (helper: EmitHelper) => boolean) { - const sourceEmitNode = source.emitNode; - const sourceEmitHelpers = sourceEmitNode && sourceEmitNode.helpers; - if (!some(sourceEmitHelpers)) return; - - const targetEmitNode = getOrCreateEmitNode(target); - let helpersRemoved = 0; - for (let i = 0; i < sourceEmitHelpers.length; i++) { - const helper = sourceEmitHelpers[i]; - if (predicate(helper)) { - helpersRemoved++; - if (!contains(targetEmitNode.helpers, helper)) { - targetEmitNode.helpers = append(targetEmitNode.helpers, helper); - } - } - else if (helpersRemoved > 0) { - sourceEmitHelpers[i - helpersRemoved] = helper; - } - } - - if (helpersRemoved > 0) { - sourceEmitHelpers.length -= helpersRemoved; - } - } - - export function compareEmitHelpers(x: EmitHelper, y: EmitHelper) { - if (x === y) return Comparison.EqualTo; - if (x.priority === y.priority) return Comparison.EqualTo; - if (x.priority === undefined) return Comparison.GreaterThan; - if (y.priority === undefined) return Comparison.LessThan; - return compareValues(x.priority, y.priority); - } - - export function setTextRange(node: T, location: TextRange): T { - if (location) { - node.pos = location.pos; - node.end = location.end; - } - return node; - } - - export function setNodeFlags(node: T, flags: NodeFlags): T { - node.flags = flags; - return node; - } - - export function setMultiLine(node: T, multiLine: boolean): T { - node.multiLine = multiLine; - return node; - } - - export function setHasTrailingComma(nodes: NodeArray, hasTrailingComma: boolean): NodeArray { - nodes.hasTrailingComma = hasTrailingComma; - return nodes; - } /** * Get the name of that target module from an import or export declaration @@ -3223,10 +3271,18 @@ namespace ts { if (isBindingElement(element)) { if (element.dotDotDotToken) { Debug.assertNode(element.name, isIdentifier); - return setOriginalNode(createSpread(element.name, element), element); + return setOriginalNode(setTextRange(createSpread(element.name), element), element); } const expression = convertToAssignmentElementTarget(element.name); - return element.initializer ? setOriginalNode(createAssignment(expression, element.initializer, element), element) : expression; + return element.initializer + ? setOriginalNode( + setTextRange( + createAssignment(expression, element.initializer), + element + ), + element + ) + : expression; } Debug.assertNode(element, isExpression); return element; @@ -3236,14 +3292,14 @@ namespace ts { if (isBindingElement(element)) { if (element.dotDotDotToken) { Debug.assertNode(element.name, isIdentifier); - return setOriginalNode(createSpreadAssignment(element.name, element), element); + return setOriginalNode(setTextRange(createSpreadAssignment(element.name), element), element); } if (element.propertyName) { const expression = convertToAssignmentElementTarget(element.name); - return setOriginalNode(createPropertyAssignment(element.propertyName, element.initializer ? createAssignment(expression, element.initializer) : expression, element), element); + return setOriginalNode(setTextRange(createPropertyAssignment(element.propertyName, element.initializer ? createAssignment(expression, element.initializer) : expression), element), element); } Debug.assertNode(element.name, isIdentifier); - return setOriginalNode(createShorthandPropertyAssignment(element.name, element.initializer, element), element); + return setOriginalNode(setTextRange(createShorthandPropertyAssignment(element.name, element.initializer), element), element); } Debug.assertNode(element, isObjectLiteralElementLike); return element; @@ -3263,7 +3319,13 @@ namespace ts { export function convertToObjectAssignmentPattern(node: ObjectBindingOrAssignmentPattern) { if (isObjectBindingPattern(node)) { - return setOriginalNode(createObjectLiteral(map(node.elements, convertToObjectAssignmentElement), node), node); + return setOriginalNode( + setTextRange( + createObjectLiteral(map(node.elements, convertToObjectAssignmentElement)), + node + ), + node + ); } Debug.assertNode(node, isObjectLiteralExpression); return node; @@ -3271,7 +3333,13 @@ namespace ts { export function convertToArrayAssignmentPattern(node: ArrayBindingOrAssignmentPattern) { if (isArrayBindingPattern(node)) { - return setOriginalNode(createArrayLiteral(map(node.elements, convertToArrayAssignmentElement), node), node); + return setOriginalNode( + setTextRange( + createArrayLiteral(map(node.elements, convertToArrayAssignmentElement)), + node + ), + node + ); } Debug.assertNode(node, isArrayLiteralExpression); return node; diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 650711afc790a..62f3c06644276 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1152,13 +1152,10 @@ namespace ts { && (options.isolatedModules || isExternalModuleFile) && !file.isDeclarationFile) { // synthesize 'import "tslib"' declaration - const externalHelpersModuleReference = createSynthesizedNode(SyntaxKind.StringLiteral); - externalHelpersModuleReference.text = externalHelpersModuleNameText; - const importDecl = createSynthesizedNode(SyntaxKind.ImportDeclaration); - - importDecl.parent = file; + const externalHelpersModuleReference = createLiteral(externalHelpersModuleNameText); + const importDecl = createImportDeclaration(undefined, undefined, undefined); externalHelpersModuleReference.parent = importDecl; - + importDecl.parent = file; imports = [externalHelpersModuleReference]; } diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 8e32259ff0f2d..b4473e6a261e9 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -112,7 +112,10 @@ namespace ts { Debug.assertNode(target, createAssignmentCallback ? isIdentifier : isExpression); const expression = createAssignmentCallback ? createAssignmentCallback(target, value, location) - : createAssignment(visitNode(target, visitor, isExpression), value, location); + : setTextRange( + createAssignment(visitNode(target, visitor, isExpression), value), + location + ); expression.original = original; emitExpression(expression); } @@ -174,9 +177,10 @@ namespace ts { const variable = createVariableDeclaration( name, /*type*/ undefined, - pendingExpressions ? inlineExpressions(append(pendingExpressions, value)) : value, - location); + pendingExpressions ? inlineExpressions(append(pendingExpressions, value)) : value + ); variable.original = original; + setTextRange(variable, location); if (isIdentifier(name)) { setEmitFlags(variable, EmitFlags.NoNestedSourceMaps); } @@ -416,7 +420,7 @@ namespace ts { const temp = createTempVariable(/*recordTempVariable*/ undefined); if (flattenContext.hoistTempVariables) { flattenContext.context.hoistVariableDeclaration(temp); - flattenContext.emitExpression(createAssignment(temp, value, location)); + flattenContext.emitExpression(setTextRange(createAssignment(temp, value), location)); } else { flattenContext.emitBindingOrAssignment(temp, value, location, /*original*/ undefined); @@ -492,6 +496,15 @@ namespace ts { } } } - return createCall(getHelperName("__rest"), undefined, [value, createArrayLiteral(propertyNames, location)]); + return createCall( + getHelperName("__rest"), + undefined, + [ + value, + setTextRange( + createArrayLiteral(propertyNames), + location + ) + ]); } } diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 10ebe648fe2ed..6d0c9b3c5fa73 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -514,7 +514,7 @@ namespace ts { exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); return updateSourceFileNode( node, - createNodeArray(statements, node.statements) + setTextRange(createNodeArray(statements), node.statements) ); } @@ -671,9 +671,10 @@ namespace ts { setOriginalNode(variable, node); const statements: Statement[] = []; - const statement = createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([variable]), /*location*/ node); + const statement = createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([variable])); setOriginalNode(statement, node); + setTextRange(statement, node); startOnNewLine(statement); statements.push(statement); @@ -818,7 +819,7 @@ namespace ts { addRange(statements, endLexicalEnvironment()); - const block = createBlock(createNodeArray(statements, /*location*/ node.members), /*location*/ undefined, /*multiLine*/ true); + const block = createBlock(setTextRange(createNodeArray(statements), /*location*/ node.members), /*multiLine*/ true); setEmitFlags(block, EmitFlags.NoComments); return block; } @@ -833,8 +834,10 @@ namespace ts { function addExtendsHelperIfNeeded(statements: Statement[], node: ClassExpression | ClassDeclaration, extendsClauseElement: ExpressionWithTypeArguments): void { if (extendsClauseElement) { statements.push( - createStatement( - createExtendsHelper(context, getLocalName(node)), + setTextRange( + createStatement( + createExtendsHelper(context, getLocalName(node)) + ), /*location*/ extendsClauseElement ) ); @@ -854,19 +857,18 @@ namespace ts { const ancestorFacts = enterSubtree(HierarchyFacts.ConstructorExcludes, HierarchyFacts.ConstructorIncludes); const constructor = getFirstConstructorWithBody(node); const hasSynthesizedSuper = hasSynthesizedDefaultSuperCall(constructor, extendsClauseElement !== undefined); - const constructorFunction = - createFunctionDeclaration( - /*decorators*/ undefined, - /*modifiers*/ undefined, - /*asteriskToken*/ undefined, - getDeclarationName(node), - /*typeParameters*/ undefined, - transformConstructorParameters(constructor, hasSynthesizedSuper), - /*type*/ undefined, - transformConstructorBody(constructor, node, extendsClauseElement, hasSynthesizedSuper), - /*location*/ constructor || node - ); + const constructorFunction = createFunctionDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + getDeclarationName(node), + /*typeParameters*/ undefined, + transformConstructorParameters(constructor, hasSynthesizedSuper), + /*type*/ undefined, + transformConstructorBody(constructor, node, extendsClauseElement, hasSynthesizedSuper) + ); + setTextRange(constructorFunction, constructor || node); if (extendsClauseElement) { setEmitFlags(constructorFunction, EmitFlags.CapturesThis); } @@ -962,14 +964,16 @@ namespace ts { } const block = createBlock( - createNodeArray( - statements, + setTextRange( + createNodeArray( + statements + ), /*location*/ constructor ? constructor.body.statements : node.members ), - /*location*/ constructor ? constructor.body : node, /*multiLine*/ true ); + setTextRange(block, constructor ? constructor.body : node); if (!constructor) { setEmitFlags(block, EmitFlags.NoComments); } @@ -1139,14 +1143,16 @@ namespace ts { // Binding patterns are converted into a generated name and are // evaluated inside the function body. return setOriginalNode( - createParameter( - /*decorators*/ undefined, - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - getGeneratedNameForNode(node), - /*questionToken*/ undefined, - /*type*/ undefined, - /*initializer*/ undefined, + setTextRange( + createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + getGeneratedNameForNode(node), + /*questionToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined + ), /*location*/ node ), /*original*/ node @@ -1155,14 +1161,16 @@ namespace ts { else if (node.initializer) { // Initializers are elided return setOriginalNode( - createParameter( - /*decorators*/ undefined, - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - node.name, - /*questionToken*/ undefined, - /*type*/ undefined, - /*initializer*/ undefined, + setTextRange( + createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + node.name, + /*questionToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined + ), /*location*/ node ), /*original*/ node @@ -1274,21 +1282,25 @@ namespace ts { const statement = createIf( createTypeCheck(getSynthesizedClone(name), "undefined"), setEmitFlags( - createBlock([ - createStatement( - createAssignment( - setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap), - setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)), - /*location*/ parameter + setTextRange( + createBlock([ + createStatement( + setTextRange( + createAssignment( + setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap), + setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)) + ), + parameter + ) ) - ) - ], /*location*/ parameter), + ]), + parameter + ), EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps - ), - /*elseStatement*/ undefined, - /*location*/ parameter + ) ); statement.startsOnNewLine = true; + setTextRange(statement, parameter); setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue); statements.push(statement); } @@ -1332,15 +1344,17 @@ namespace ts { // var param = []; statements.push( setEmitFlags( - createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList([ - createVariableDeclaration( - declarationName, - /*type*/ undefined, - createArrayLiteral([]) - ) - ]), + setTextRange( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + declarationName, + /*type*/ undefined, + createArrayLiteral([]) + ) + ]) + ), /*location*/ parameter ), EmitFlags.CustomPrologue @@ -1351,26 +1365,33 @@ namespace ts { // param[_i - restIndex] = arguments[_i]; // } const forStatement = createFor( - createVariableDeclarationList([ - createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex)) - ], /*location*/ parameter), - createLessThan( - temp, - createPropertyAccess(createIdentifier("arguments"), "length"), - /*location*/ parameter + setTextRange( + createVariableDeclarationList([ + createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex)) + ]), + parameter + ), + setTextRange( + createLessThan( + temp, + createPropertyAccess(createIdentifier("arguments"), "length") + ), + parameter ), - createPostfixIncrement(temp, /*location*/ parameter), + setTextRange(createPostfixIncrement(temp), parameter), createBlock([ startOnNewLine( - createStatement( - createAssignment( - createElementAccess( - expressionName, - restIndex === 0 - ? temp - : createSubtract(temp, createLiteral(restIndex)) - ), - createElementAccess(createIdentifier("arguments"), temp) + setTextRange( + createStatement( + createAssignment( + createElementAccess( + expressionName, + restIndex === 0 + ? temp + : createSubtract(temp, createLiteral(restIndex)) + ), + createElementAccess(createIdentifier("arguments"), temp) + ) ), /*location*/ parameter ) @@ -1405,11 +1426,10 @@ namespace ts { /*type*/ undefined, initializer ) - ]), - originalStatement + ]) ); - setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue); + setTextRange(captureThisStatement, originalStatement); setSourceMapRange(captureThisStatement, node); statements.push(captureThisStatement); } @@ -1529,7 +1549,7 @@ namespace ts { * @param member The SemicolonClassElement node. */ function transformSemicolonClassElementToStatement(member: SemicolonClassElement) { - return createEmptyStatement(/*location*/ member); + return setTextRange(createEmptyStatement(), member); } /** @@ -1547,8 +1567,10 @@ namespace ts { setEmitFlags(memberFunction, EmitFlags.NoComments); setSourceMapRange(memberFunction, sourceMapRange); - const statement = createStatement( - createAssignment(memberName, memberFunction), + const statement = setTextRange( + createStatement( + createAssignment(memberName, memberFunction) + ), /*location*/ member ); @@ -1571,15 +1593,12 @@ namespace ts { * @param accessors The set of related get/set accessors. */ function transformAccessorsToStatement(receiver: LeftHandSideExpression, accessors: AllAccessorDeclarations, container: Node): Statement { - const statement = createStatement( - transformAccessorsToExpression(receiver, accessors, container, /*startsOnNewLine*/ false), - /*location*/ getSourceMapRange(accessors.firstAccessor) - ); - + const statement = createStatement(transformAccessorsToExpression(receiver, accessors, container, /*startsOnNewLine*/ false)); // The location for the statement is used to emit source maps only. // No comments should be emitted for this statement to align with the // old emitter. setEmitFlags(statement, EmitFlags.NoComments); + setSourceMapRange(statement, getSourceMapRange(accessors.firstAccessor)); return statement; } @@ -1622,8 +1641,8 @@ namespace ts { } properties.push( - createPropertyAssignment("enumerable", createLiteral(true)), - createPropertyAssignment("configurable", createLiteral(true)) + createPropertyAssignment("enumerable", createTrue()), + createPropertyAssignment("configurable", createTrue()) ); const call = createCall( @@ -1632,7 +1651,7 @@ namespace ts { [ target, propertyName, - createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true) + createObjectLiteral(properties, /*multiLine*/ true) ] ); if (startsOnNewLine) { @@ -1662,9 +1681,9 @@ namespace ts { /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - transformFunctionBody(node), - node + transformFunctionBody(node) ); + setTextRange(func, node); setOriginalNode(func, node); setEmitFlags(func, EmitFlags.CapturesThis); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); @@ -1758,14 +1777,16 @@ namespace ts { exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, HierarchyFacts.None); convertedLoopState = savedConvertedLoopState; return setOriginalNode( - createFunctionExpression( - /*modifiers*/ undefined, - node.asteriskToken, - name, - /*typeParameters*/ undefined, - parameters, - /*type*/ undefined, - body, + setTextRange( + createFunctionExpression( + /*modifiers*/ undefined, + node.asteriskToken, + name, + /*typeParameters*/ undefined, + parameters, + /*type*/ undefined, + body + ), location ), /*original*/ node @@ -1832,7 +1853,8 @@ namespace ts { } const expression = visitNode(body, visitor, isExpression); - const returnStatement = createReturn(expression, /*location*/ body); + const returnStatement = createReturn(expression); + setTextRange(returnStatement, body); setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments); statements.push(returnStatement); @@ -1851,7 +1873,8 @@ namespace ts { multiLine = true; } - const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine); + const block = createBlock(setTextRange(createNodeArray(statements), statementsLocation), multiLine); + setTextRange(block, node.body); if (!multiLine && singleLine) { setEmitFlags(block, EmitFlags.SingleLine); } @@ -1868,8 +1891,10 @@ namespace ts { const updated = visitFunctionBody(node.body, functionBodyVisitor, context); return updateBlock( updated, - createNodeArray( - prependCaptureNewTargetIfNeeded(updated.statements, node, /*copyOnWrite*/ true), + setTextRange( + createNodeArray( + prependCaptureNewTargetIfNeeded(updated.statements, node, /*copyOnWrite*/ true) + ), /*location*/ updated.statements ) ); @@ -1969,7 +1994,7 @@ namespace ts { } } if (assignments) { - updated = createStatement(reduceLeft(assignments, (acc, v) => createBinary(v, SyntaxKind.CommaToken, acc)), node); + updated = setTextRange(createStatement(reduceLeft(assignments, (acc, v) => createBinary(v, SyntaxKind.CommaToken, acc))), node); } else { // none of declarations has initializer - the entire variable statement can be deleted @@ -1999,8 +2024,9 @@ namespace ts { ? visitVariableDeclarationInLetDeclarationList : visitVariableDeclaration)); - const declarationList = createVariableDeclarationList(declarations, /*location*/ node); + const declarationList = createVariableDeclarationList(declarations); setOriginalNode(declarationList, node); + setTextRange(declarationList, node); setCommentRange(declarationList, node); if (node.transformFlags & TransformFlags.ContainsBindingPattern @@ -2248,8 +2274,9 @@ namespace ts { elementAccess ); - const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer); + const declarationList = createVariableDeclarationList(declarations); setOriginalNode(declarationList, initializer); + setTextRange(declarationList, initializer); // Adjust the source map range for the first declaration to align with the old // emitter. @@ -2268,19 +2295,24 @@ namespace ts { // The following call does not include the initializer, so we have // to emit it separately. statements.push( - createVariableStatement( - /*modifiers*/ undefined, - setOriginalNode( - createVariableDeclarationList([ - createVariableDeclaration( - firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined), - /*type*/ undefined, - createElementAccess(rhsReference, counter) - ) - ], /*location*/ moveRangePos(initializer, -1)), - initializer + setTextRange( + createVariableStatement( + /*modifiers*/ undefined, + setOriginalNode( + setTextRange( + createVariableDeclarationList([ + createVariableDeclaration( + firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined), + /*type*/ undefined, + createElementAccess(rhsReference, counter) + ) + ]), + moveRangePos(initializer, -1) + ), + initializer + ) ), - /*location*/ moveRangeEnd(initializer, -1) + moveRangeEnd(initializer, -1) ) ); } @@ -2306,7 +2338,7 @@ namespace ts { // Currently there is not way to check that assignment is binary expression of destructing assignment // so we have to cast never type to binaryExpression (assignment).end = initializer.end; - statements.push(createStatement(assignment, /*location*/ moveRangeEnd(initializer, -1))); + statements.push(setTextRange(createStatement(assignment), moveRangeEnd(initializer, -1))); } } @@ -2332,33 +2364,38 @@ namespace ts { // The old emitter does not emit source maps for the block. // We add the location to preserve comments. - const body = createBlock( - createNodeArray(statements, /*location*/ statementsLocation), - /*location*/ bodyLocation - ); - + const body = createBlock(setTextRange(createNodeArray(statements), /*location*/ statementsLocation)); + setTextRange(body, bodyLocation); setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps); const forStatement = createFor( setEmitFlags( - createVariableDeclarationList([ - createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)), - createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression) - ], /*location*/ node.expression), + setTextRange( + createVariableDeclarationList([ + setTextRange(createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0)), moveRangePos(node.expression, -1)), + setTextRange(createVariableDeclaration(rhsReference, /*type*/ undefined, expression), node.expression) + ]), + node.expression + ), EmitFlags.NoHoisting ), - createLessThan( - counter, - createPropertyAccess(rhsReference, "length"), - /*location*/ node.expression + setTextRange( + createLessThan( + counter, + createPropertyAccess(rhsReference, "length") + ), + node.expression ), - createPostfixIncrement(counter, /*location*/ node.expression), - body, - /*location*/ node + setTextRange( + createPostfixIncrement(counter), + node.expression + ), + body ); // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter. setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps); + setTextRange(forStatement, node); return restoreEnclosingLabel(forStatement, outermostLabeledStatement, convertedLoopState && resetLabel); } @@ -2418,7 +2455,6 @@ namespace ts { setEmitFlags( createObjectLiteral( visitNodes(properties, visitor, isObjectLiteralElementLike, 0, numInitialProperties), - /*location*/ undefined, node.multiLine ), EmitFlags.Indented @@ -2546,14 +2582,14 @@ namespace ts { copyOutParameters(loopOutParameters, CopyDirection.ToOutParameter, statements); } addRange(statements, lexicalEnvironment) - loopBody = createBlock(statements, /*location*/ undefined, /*multiline*/ true); + loopBody = createBlock(statements, /*multiline*/ true); } if (isBlock(loopBody)) { loopBody.multiLine = true; } else { - loopBody = createBlock([loopBody], /*location*/ undefined, /*multiline*/ true); + loopBody = createBlock([loopBody], /*multiline*/ true); } const isAsyncBlockContainingAwait = @@ -2687,12 +2723,7 @@ namespace ts { // visit childnodes to transform initializer/condition/incrementor parts clone = visitEachChild(clone, visitor, context); // set loop statement - clone.statement = createBlock( - convertedLoopBodyStatements, - /*location*/ undefined, - /*multiline*/ true - ); - + clone.statement = createBlock(convertedLoopBodyStatements, /*multiline*/ true); // reset and re-aggregate the transform flags clone.transformFlags = 0; aggregateTransformFlags(clone); @@ -2903,9 +2934,9 @@ namespace ts { receiver, visitNode(property.name, visitor, isPropertyName) ), - visitNode(property.initializer, visitor, isExpression), - /*location*/ property + visitNode(property.initializer, visitor, isExpression) ); + setTextRange(expression, property); if (startsOnNewLine) { expression.startsOnNewLine = true; } @@ -2925,9 +2956,9 @@ namespace ts { receiver, visitNode(property.name, visitor, isPropertyName) ), - getSynthesizedClone(property.name), - /*location*/ property + getSynthesizedClone(property.name) ); + setTextRange(expression, property); if (startsOnNewLine) { expression.startsOnNewLine = true; } @@ -2948,9 +2979,9 @@ namespace ts { receiver, visitNode(method.name, visitor, isPropertyName) ), - transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined, container), - /*location*/ method + transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined, container) ); + setTextRange(expression, method); if (startsOnNewLine) { expression.startsOnNewLine = true; } @@ -2963,7 +2994,8 @@ namespace ts { let updated: CatchClause; if (isBindingPattern(node.variableDeclaration.name)) { const temp = createTempVariable(undefined); - const newVariableDeclaration = createVariableDeclaration(temp, undefined, undefined, node.variableDeclaration); + const newVariableDeclaration = createVariableDeclaration(temp); + setTextRange(newVariableDeclaration, node.variableDeclaration); const vars = flattenDestructuringBinding( node.variableDeclaration, visitor, @@ -2971,8 +3003,9 @@ namespace ts { FlattenLevel.All, temp ); - const list = createVariableDeclarationList(vars, /*location*/node.variableDeclaration, /*flags*/node.variableDeclaration.flags); - const destructure = createVariableStatement(undefined, list); + const list = createVariableDeclarationList(vars); + setTextRange(list, node.variableDeclaration); + const destructure = createVariableStatement(/*modifiers*/ undefined, list); updated = updateCatchClause(node, newVariableDeclaration, addStatementToStartOfBlock(node.block, destructure)); } else { @@ -3001,9 +3034,11 @@ namespace ts { Debug.assert(!isComputedPropertyName(node.name)); const functionExpression = transformFunctionLikeToExpression(node, /*location*/ moveRangePos(node, -1), /*name*/ undefined, /*container*/ undefined); setEmitFlags(functionExpression, EmitFlags.NoLeadingComments | getEmitFlags(functionExpression)); - return createPropertyAssignment( - node.name, - functionExpression, + return setTextRange( + createPropertyAssignment( + node.name, + functionExpression + ), /*location*/ node ); } @@ -3030,9 +3065,11 @@ namespace ts { * @param node A ShorthandPropertyAssignment node. */ function visitShorthandPropertyAssignment(node: ShorthandPropertyAssignment): ObjectLiteralElementLike { - return createPropertyAssignment( - node.name, - getSynthesizedClone(node.name), + return setTextRange( + createPropertyAssignment( + node.name, + getSynthesizedClone(node.name) + ), /*location*/ node ); } @@ -3225,8 +3262,7 @@ namespace ts { function visitSpanOfNonSpreads(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult { return createArrayLiteral( - visitNodes(createNodeArray(chunk, /*location*/ undefined, hasTrailingComma), visitor, isExpression), - /*location*/ undefined, + visitNodes(createNodeArray(chunk, hasTrailingComma), visitor, isExpression), multiLine ); } @@ -3250,7 +3286,7 @@ namespace ts { * @param node A template literal. */ function visitTemplateLiteral(node: LiteralExpression): LeftHandSideExpression { - return createLiteral(node.text, /*location*/ node); + return setTextRange(createLiteral(node.text), node); } /** @@ -3318,7 +3354,7 @@ namespace ts { // ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's // and LineTerminatorSequences are normalized to for both TV and TRV. text = text.replace(/\r\n?/g, "\n"); - return createLiteral(text, /*location*/ node); + return setTextRange(createLiteral(text), node); } /** @@ -3342,7 +3378,8 @@ namespace ts { // "abc" + (1 << 2) + "" const expression = reduceLeft(expressions, createAdd); if (nodeIsSynthesized(expression)) { - setTextRange(expression, node); + expression.pos = node.pos; + expression.end = node.end; } return expression; @@ -3580,7 +3617,7 @@ namespace ts { function substituteThisKeyword(node: PrimaryExpression): PrimaryExpression { if (enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis && hierarchyFacts & HierarchyFacts.CapturesThis) { - return createIdentifier("_this", /*location*/ node); + return setTextRange(createIdentifier("_this"), node); } return node; } diff --git a/src/compiler/transformers/es2016.ts b/src/compiler/transformers/es2016.ts index 5959753fcef96..1118e6ad9b672 100644 --- a/src/compiler/transformers/es2016.ts +++ b/src/compiler/transformers/es2016.ts @@ -48,29 +48,37 @@ namespace ts { // Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)` const expressionTemp = createTempVariable(hoistVariableDeclaration); const argumentExpressionTemp = createTempVariable(hoistVariableDeclaration); - target = createElementAccess( - createAssignment(expressionTemp, left.expression, /*location*/ left.expression), - createAssignment(argumentExpressionTemp, left.argumentExpression, /*location*/ left.argumentExpression), - /*location*/ left + target = setTextRange( + createElementAccess( + setTextRange(createAssignment(expressionTemp, left.expression), left.expression), + setTextRange(createAssignment(argumentExpressionTemp, left.argumentExpression), left.argumentExpression) + ), + left ); - value = createElementAccess( - expressionTemp, - argumentExpressionTemp, - /*location*/ left + value = setTextRange( + createElementAccess( + expressionTemp, + argumentExpressionTemp + ), + left ); } else if (isPropertyAccessExpression(left)) { // Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)` const expressionTemp = createTempVariable(hoistVariableDeclaration); - target = createPropertyAccess( - createAssignment(expressionTemp, left.expression, /*location*/ left.expression), - left.name, - /*location*/ left + target = setTextRange( + createPropertyAccess( + setTextRange(createAssignment(expressionTemp, left.expression), left.expression), + left.name + ), + left ); - value = createPropertyAccess( - expressionTemp, - left.name, - /*location*/ left + value = setTextRange( + createPropertyAccess( + expressionTemp, + left.name + ), + left ); } else { @@ -78,7 +86,13 @@ namespace ts { target = left; value = left; } - return createAssignment(target, createMathPow(value, right, /*location*/ node), /*location*/ node); + return setTextRange( + createAssignment( + target, + createMathPow(value, right, /*location*/ node) + ), + node + ); } function visitExponentiationExpression(node: BinaryExpression) { diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index a7f7b0da0ea64..b437298656c5d 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -104,10 +104,12 @@ namespace ts { */ function visitAwaitExpression(node: AwaitExpression): Expression { return setOriginalNode( - createYield( - /*asteriskToken*/ undefined, - visitNode(node.expression, visitor, isExpression), - /*location*/ node + setTextRange( + createYield( + /*asteriskToken*/ undefined, + visitNode(node.expression, visitor, isExpression) + ), + node ), node ); @@ -238,7 +240,8 @@ namespace ts { addRange(statements, endLexicalEnvironment()); - const block = createBlock(statements, /*location*/ node.body, /*multiLine*/ true); + const block = createBlock(statements, /*multiLine*/ true); + setTextRange(block, node.body); // Minor optimization, emit `_super` helper to capture `super` access in an arrow. // This step isn't needed if we eventually transform this to ES5. @@ -266,7 +269,7 @@ namespace ts { const declarations = endLexicalEnvironment(); if (some(declarations)) { const block = convertToFunctionBody(expression); - return updateBlock(block, createNodeArray(concatenate(block.statements, declarations), block.statements)); + return updateBlock(block, setTextRange(createNodeArray(concatenate(block.statements, declarations)), block.statements)); } return expression; @@ -281,7 +284,7 @@ namespace ts { startLexicalEnvironment(); const visited = convertToFunctionBody(visitNode(body, visitor, isConciseBody)); const declarations = endLexicalEnvironment(); - return updateBlock(visited, createNodeArray(concatenate(visited.statements, declarations), visited.statements)); + return updateBlock(visited, setTextRange(createNodeArray(concatenate(visited.statements, declarations)), visited.statements)); } } @@ -431,21 +434,25 @@ namespace ts { function createSuperAccessInAsyncMethod(argumentExpression: Expression, flags: NodeCheckFlags, location: TextRange): LeftHandSideExpression { if (flags & NodeCheckFlags.AsyncMethodWithSuperBinding) { - return createPropertyAccess( - createCall( - createIdentifier("_super"), - /*typeArguments*/ undefined, - [argumentExpression] + return setTextRange( + createPropertyAccess( + createCall( + createIdentifier("_super"), + /*typeArguments*/ undefined, + [argumentExpression] + ), + "value" ), - "value", location ); } else { - return createCall( - createIdentifier("_super"), - /*typeArguments*/ undefined, - [argumentExpression], + return setTextRange( + createCall( + createIdentifier("_super"), + /*typeArguments*/ undefined, + [argumentExpression] + ), location ); } diff --git a/src/compiler/transformers/es5.ts b/src/compiler/transformers/es5.ts index 8b030642a89c6..bcecb86e75d87 100644 --- a/src/compiler/transformers/es5.ts +++ b/src/compiler/transformers/es5.ts @@ -87,7 +87,7 @@ namespace ts { function substitutePropertyAccessExpression(node: PropertyAccessExpression): Expression { const literalName = trySubstituteReservedName(node.name); if (literalName) { - return createElementAccess(node.expression, literalName, /*location*/ node); + return setTextRange(createElementAccess(node.expression, literalName), node); } return node; } @@ -113,7 +113,7 @@ namespace ts { function trySubstituteReservedName(name: Identifier) { const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(name.text) : undefined); if (token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) { - return createLiteral(name, /*location*/ name); + return setTextRange(createLiteral(name), name); } return undefined; } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 8b5a095a17ea5..f058e627df701 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -210,36 +210,40 @@ namespace ts { const statement = createVariableStatement( /*modifiers*/ undefined, updateVariableDeclarationList(initializer, declarations), - /*location*/ initializer ); + setTextRange(statement, initializer); leadingStatements = append(leadingStatements, statement); } } else if (isAssignmentPattern(initializer)) { temp = createTempVariable(/*recordTempVariable*/ undefined); const expression = flattenDestructuringAssignment( - aggregateTransformFlags(createAssignment(initializer, temp, /*location*/ node.initializer)), + aggregateTransformFlags( + setTextRange( + createAssignment(initializer, temp), + node.initializer + ) + ), visitor, context, FlattenLevel.ObjectRest ); - leadingStatements = append(leadingStatements, createStatement(expression, /*location*/ node.initializer)); + leadingStatements = append(leadingStatements, setTextRange(createStatement(expression), node.initializer)); } } if (temp) { const expression = visitNode(node.expression, visitor, isExpression); const statement = visitNode(node.statement, visitor, isStatement); const block = isBlock(statement) - ? updateBlock(statement, createNodeArray(concatenate(leadingStatements, statement.statements), statement.statements)) - : createBlock(append(leadingStatements, statement), statement, /*multiLine*/ true); + ? updateBlock(statement, setTextRange(createNodeArray(concatenate(leadingStatements, statement.statements)), statement.statements)) + : setTextRange(createBlock(append(leadingStatements, statement), /*multiLine*/ true), statement); return updateForOf( node, - createVariableDeclarationList( - [ - createVariableDeclaration(temp, /*type*/ undefined, /*initializer*/ undefined, node.initializer) - ], - node.initializer, - NodeFlags.Let + setTextRange( + createVariableDeclarationList([ + setTextRange(createVariableDeclaration(temp), node.initializer) + ], NodeFlags.Let), + node.initializer ), expression, block @@ -380,7 +384,7 @@ namespace ts { const trailingStatements = endLexicalEnvironment(); if (some(leadingStatements) || some(trailingStatements)) { const block = convertToFunctionBody(body, /*multiLine*/ true); - return updateBlock(block, createNodeArray(concatenate(concatenate(leadingStatements, block.statements), trailingStatements), block.statements)); + return updateBlock(block, setTextRange(createNodeArray(concatenate(concatenate(leadingStatements, block.statements), trailingStatements)), block.statements)); } return body; } diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index ee17bdacbaf5b..cabd5d2a96d01 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -450,15 +450,17 @@ namespace ts { // Currently, we only support generators that were originally async functions. if (node.asteriskToken && getEmitFlags(node) & EmitFlags.AsyncFunctionBody) { node = setOriginalNode( - createFunctionDeclaration( - /*decorators*/ undefined, - node.modifiers, - /*asteriskToken*/ undefined, - node.name, - /*typeParameters*/ undefined, - visitParameterList(node.parameters, visitor, context), - /*type*/ undefined, - transformGeneratorFunctionBody(node.body), + setTextRange( + createFunctionDeclaration( + /*decorators*/ undefined, + node.modifiers, + /*asteriskToken*/ undefined, + node.name, + /*typeParameters*/ undefined, + visitParameterList(node.parameters, visitor, context), + /*type*/ undefined, + transformGeneratorFunctionBody(node.body) + ), /*location*/ node ), node @@ -498,14 +500,16 @@ namespace ts { // Currently, we only support generators that were originally async functions. if (node.asteriskToken && getEmitFlags(node) & EmitFlags.AsyncFunctionBody) { node = setOriginalNode( - createFunctionExpression( - /*modifiers*/ undefined, - /*asteriskToken*/ undefined, - node.name, - /*typeParameters*/ undefined, - visitParameterList(node.parameters, visitor, context), - /*type*/ undefined, - transformGeneratorFunctionBody(node.body), + setTextRange( + createFunctionExpression( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + node.name, + /*typeParameters*/ undefined, + visitParameterList(node.parameters, visitor, context), + /*type*/ undefined, + transformGeneratorFunctionBody(node.body) + ), /*location*/ node ), node @@ -606,7 +610,7 @@ namespace ts { operationLocations = savedOperationLocations; state = savedState; - return createBlock(statements, /*location*/ body, body.multiLine); + return setTextRange(createBlock(statements, body.multiLine), body); } /** @@ -739,14 +743,17 @@ namespace ts { const operator = node.operatorToken.kind; if (isCompoundAssignment(operator)) { - return createBinary( - target, - SyntaxKind.EqualsToken, - createBinary( - cacheExpression(target), - getOperatorForCompoundAssignment(operator), - visitNode(right, visitor, isExpression), - node + return setTextRange( + createAssignment( + target, + setTextRange( + createBinary( + cacheExpression(target), + getOperatorForCompoundAssignment(operator), + visitNode(right, visitor, isExpression) + ), + node + ) ), node ); @@ -988,8 +995,11 @@ namespace ts { const expressions = reduceLeft(elements, reduceElement, [], numInitialElements); return hasAssignedTemp - ? createArrayConcat(temp, [createArrayLiteral(expressions, /*location*/ undefined, multiLine)]) - : createArrayLiteral(leadingElement ? [leadingElement, ...expressions] : expressions, location, multiLine); + ? createArrayConcat(temp, [createArrayLiteral(expressions, multiLine)]) + : setTextRange( + createArrayLiteral(leadingElement ? [leadingElement, ...expressions] : expressions, multiLine), + location + ); function reduceElement(expressions: Expression[], element: Expression) { if (containsYield(element) && expressions.length > 0) { @@ -998,11 +1008,10 @@ namespace ts { hasAssignedTemp ? createArrayConcat( temp, - [createArrayLiteral(expressions, /*location*/ undefined, multiLine)] + [createArrayLiteral(expressions, multiLine)] ) : createArrayLiteral( leadingElement ? [leadingElement, ...expressions] : expressions, - /*location*/ undefined, multiLine ) ); @@ -1043,7 +1052,6 @@ namespace ts { emitAssignment(temp, createObjectLiteral( visitNodes(properties, visitor, isObjectLiteralElementLike, 0, numInitialProperties), - /*location*/ undefined, multiLine ) ); @@ -1139,18 +1147,20 @@ namespace ts { const { target, thisArg } = createCallBinding(createPropertyAccess(node.expression, "bind"), hoistVariableDeclaration); return setOriginalNode( - createNew( - createFunctionApply( - cacheExpression(visitNode(target, visitor, isExpression)), - thisArg, - visitElements( - node.arguments, - /*leadingElement*/ createVoidZero() - ) + setTextRange( + createNew( + createFunctionApply( + cacheExpression(visitNode(target, visitor, isExpression)), + thisArg, + visitElements( + node.arguments, + /*leadingElement*/ createVoidZero() + ) + ), + /*typeArguments*/ undefined, + [] ), - /*typeArguments*/ undefined, - [], - /*location*/ node + node ), node ); @@ -1423,9 +1433,11 @@ namespace ts { } else { emitStatement( - createStatement( - visitNode(initializer, visitor, isExpression), - /*location*/ initializer + setTextRange( + createStatement( + visitNode(initializer, visitor, isExpression) + ), + initializer ) ); } @@ -1441,9 +1453,11 @@ namespace ts { markLabel(incrementLabel); if (node.incrementor) { emitStatement( - createStatement( - visitNode(node.incrementor, visitor, isExpression), - /*location*/ node.incrementor + setTextRange( + createStatement( + visitNode(node.incrementor, visitor, isExpression) + ), + node.incrementor ) ); } @@ -2417,11 +2431,13 @@ namespace ts { */ function createInlineBreak(label: Label, location?: TextRange): ReturnStatement { Debug.assert(label > 0, `Invalid label: ${label}`); - return createReturn( - createArrayLiteral([ - createInstruction(Instruction.Break), - createLabel(label) - ]), + return setTextRange( + createReturn( + createArrayLiteral([ + createInstruction(Instruction.Break), + createLabel(label) + ]) + ), location ); } @@ -2433,10 +2449,12 @@ namespace ts { * @param location An optional source map location for the statement. */ function createInlineReturn(expression?: Expression, location?: TextRange): ReturnStatement { - return createReturn( - createArrayLiteral(expression - ? [createInstruction(Instruction.Return), expression] - : [createInstruction(Instruction.Return)] + return setTextRange( + createReturn( + createArrayLiteral(expression + ? [createInstruction(Instruction.Return), expression] + : [createInstruction(Instruction.Return)] + ) ), location ); @@ -2446,7 +2464,14 @@ namespace ts { * Creates an expression that can be used to resume from a Yield operation. */ function createGeneratorResume(location?: TextRange): LeftHandSideExpression { - return createCall(createPropertyAccess(state, "sent"), /*typeArguments*/ undefined, [], location); + return setTextRange( + createCall( + createPropertyAccess(state, "sent"), + /*typeArguments*/ undefined, + [] + ), + location + ); } /** @@ -2614,7 +2639,6 @@ namespace ts { /*type*/ undefined, createBlock( buildResult, - /*location*/ undefined, /*multiLine*/ buildResult.length > 0 ) ), @@ -2944,7 +2968,7 @@ namespace ts { * @param operationLocation The source map location for the operation. */ function writeAssign(left: Expression, right: Expression, operationLocation: TextRange): void { - writeStatement(createStatement(createAssignment(left, right), operationLocation)); + writeStatement(setTextRange(createStatement(createAssignment(left, right)), operationLocation)); } /** @@ -2956,7 +2980,7 @@ namespace ts { function writeThrow(expression: Expression, operationLocation: TextRange): void { lastOperationWasAbrupt = true; lastOperationWasCompletion = true; - writeStatement(createThrow(expression, operationLocation)); + writeStatement(setTextRange(createThrow(expression), operationLocation)); } /** @@ -2970,10 +2994,12 @@ namespace ts { lastOperationWasCompletion = true; writeStatement( setEmitFlags( - createReturn( - createArrayLiteral(expression - ? [createInstruction(Instruction.Return), expression] - : [createInstruction(Instruction.Return)] + setTextRange( + createReturn( + createArrayLiteral(expression + ? [createInstruction(Instruction.Return), expression] + : [createInstruction(Instruction.Return)] + ) ), operationLocation ), @@ -2992,11 +3018,13 @@ namespace ts { lastOperationWasAbrupt = true; writeStatement( setEmitFlags( - createReturn( - createArrayLiteral([ - createInstruction(Instruction.Break), - createLabel(label) - ]), + setTextRange( + createReturn( + createArrayLiteral([ + createInstruction(Instruction.Break), + createLabel(label) + ]) + ), operationLocation ), EmitFlags.NoTokenSourceMaps @@ -3017,11 +3045,13 @@ namespace ts { createIf( condition, setEmitFlags( - createReturn( - createArrayLiteral([ - createInstruction(Instruction.Break), - createLabel(label) - ]), + setTextRange( + createReturn( + createArrayLiteral([ + createInstruction(Instruction.Break), + createLabel(label) + ]) + ), operationLocation ), EmitFlags.NoTokenSourceMaps @@ -3045,11 +3075,13 @@ namespace ts { createIf( createLogicalNot(condition), setEmitFlags( - createReturn( - createArrayLiteral([ - createInstruction(Instruction.Break), - createLabel(label) - ]), + setTextRange( + createReturn( + createArrayLiteral([ + createInstruction(Instruction.Break), + createLabel(label) + ]) + ), operationLocation ), EmitFlags.NoTokenSourceMaps @@ -3070,11 +3102,13 @@ namespace ts { lastOperationWasAbrupt = true; writeStatement( setEmitFlags( - createReturn( - createArrayLiteral( - expression - ? [createInstruction(Instruction.Yield), expression] - : [createInstruction(Instruction.Yield)] + setTextRange( + createReturn( + createArrayLiteral( + expression + ? [createInstruction(Instruction.Yield), expression] + : [createInstruction(Instruction.Yield)] + ) ), operationLocation ), @@ -3093,11 +3127,13 @@ namespace ts { lastOperationWasAbrupt = true; writeStatement( setEmitFlags( - createReturn( - createArrayLiteral([ - createInstruction(Instruction.YieldStar), - expression - ]), + setTextRange( + createReturn( + createArrayLiteral([ + createInstruction(Instruction.YieldStar), + expression + ]) + ), operationLocation ), EmitFlags.NoTokenSourceMaps diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index 1307a7f8551f9..60053d98e57d6 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -143,15 +143,15 @@ namespace ts { function transformJsxAttributeInitializer(node: StringLiteral | JsxExpression) { if (node === undefined) { - return createLiteral(true); + return createTrue(); } else if (node.kind === SyntaxKind.StringLiteral) { const decoded = tryDecodeEntities((node).text); - return decoded ? createLiteral(decoded, /*location*/ node) : node; + return decoded ? setTextRange(createLiteral(decoded), node) : node; } else if (node.kind === SyntaxKind.JsxExpression) { if (node.expression === undefined) { - return createLiteral(true); + return createTrue(); } return visitJsxExpression(node); } diff --git a/src/compiler/transformers/module/es2015.ts b/src/compiler/transformers/module/es2015.ts index 86fa1295f7b7d..cc197073c32e5 100644 --- a/src/compiler/transformers/module/es2015.ts +++ b/src/compiler/transformers/module/es2015.ts @@ -37,7 +37,7 @@ namespace ts { addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset)); return updateSourceFileNode( node, - createNodeArray(statements, node.statements)); + setTextRange(createNodeArray(statements), node.statements)); } else { return visitEachChild(node, visitor, context); diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index e072429292aab..f6e51fa9fddff 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -88,7 +88,7 @@ namespace ts { addRange(statements, endLexicalEnvironment()); addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false); - const updated = updateSourceFileNode(node, createNodeArray(statements, node.statements)); + const updated = updateSourceFileNode(node, setTextRange(createNodeArray(statements), node.statements)); if (currentModuleInfo.hasExportStarsToExportValues) { addEmitHelper(updated, exportStarHelper); } @@ -131,47 +131,49 @@ namespace ts { // Create an updated SourceFile: // // define(moduleName?, ["module1", "module2"], function ... - return updateSourceFileNode(node, createNodeArray( - [ - createStatement( - createCall( - define, - /*typeArguments*/ undefined, - [ - // Add the module name (if provided). - ...(moduleName ? [moduleName] : []), - - // Add the dependency array argument: - // - // ["require", "exports", module1", "module2", ...] - createArrayLiteral([ - createLiteral("require"), - createLiteral("exports"), - ...aliasedModuleNames, - ...unaliasedModuleNames - ]), + return updateSourceFileNode(node, + setTextRange( + createNodeArray([ + createStatement( + createCall( + define, + /*typeArguments*/ undefined, + [ + // Add the module name (if provided). + ...(moduleName ? [moduleName] : []), - // Add the module body function argument: - // - // function (require, exports, module1, module2) ... - createFunctionExpression( - /*modifiers*/ undefined, - /*asteriskToken*/ undefined, - /*name*/ undefined, - /*typeParameters*/ undefined, - [ - createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"), - createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"), - ...importAliasNames - ], - /*type*/ undefined, - transformAsynchronousModuleBody(node) - ) - ] + // Add the dependency array argument: + // + // ["require", "exports", module1", "module2", ...] + createArrayLiteral([ + createLiteral("require"), + createLiteral("exports"), + ...aliasedModuleNames, + ...unaliasedModuleNames + ]), + + // Add the module body function argument: + // + // function (require, exports, module1, module2) ... + createFunctionExpression( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + /*name*/ undefined, + /*typeParameters*/ undefined, + [ + createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"), + createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"), + ...importAliasNames + ], + /*type*/ undefined, + transformAsynchronousModuleBody(node) + ) + ] + ) ) - ) - ], - /*location*/ node.statements) + ]), + /*location*/ node.statements + ) ); } @@ -189,74 +191,76 @@ namespace ts { /*typeParameters*/ undefined, [createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "factory")], /*type*/ undefined, - createBlock( - [ - createIf( - createLogicalAnd( - createTypeCheck(createIdentifier("module"), "object"), - createTypeCheck(createPropertyAccess(createIdentifier("module"), "exports"), "object") - ), - createBlock([ - createVariableStatement( - /*modifiers*/ undefined, - [ - createVariableDeclaration( - "v", - /*type*/ undefined, + setTextRange( + createBlock( + [ + createIf( + createLogicalAnd( + createTypeCheck(createIdentifier("module"), "object"), + createTypeCheck(createPropertyAccess(createIdentifier("module"), "exports"), "object") + ), + createBlock([ + createVariableStatement( + /*modifiers*/ undefined, + [ + createVariableDeclaration( + "v", + /*type*/ undefined, + createCall( + createIdentifier("factory"), + /*typeArguments*/ undefined, + [ + createIdentifier("require"), + createIdentifier("exports") + ] + ) + ) + ] + ), + setEmitFlags( + createIf( + createStrictInequality( + createIdentifier("v"), + createIdentifier("undefined") + ), + createStatement( + createAssignment( + createPropertyAccess(createIdentifier("module"), "exports"), + createIdentifier("v") + ) + ) + ), + EmitFlags.SingleLine + ) + ]), + createIf( + createLogicalAnd( + createTypeCheck(createIdentifier("define"), "function"), + createPropertyAccess(createIdentifier("define"), "amd") + ), + createBlock([ + createStatement( createCall( - createIdentifier("factory"), + createIdentifier("define"), /*typeArguments*/ undefined, [ - createIdentifier("require"), - createIdentifier("exports") + createArrayLiteral([ + createLiteral("require"), + createLiteral("exports"), + ...aliasedModuleNames, + ...unaliasedModuleNames + ]), + createIdentifier("factory") ] ) ) - ] - ), - setEmitFlags( - createIf( - createStrictInequality( - createIdentifier("v"), - createIdentifier("undefined") - ), - createStatement( - createAssignment( - createPropertyAccess(createIdentifier("module"), "exports"), - createIdentifier("v") - ) - ) - ), - EmitFlags.SingleLine + ]) ) - ]), - createIf( - createLogicalAnd( - createTypeCheck(createIdentifier("define"), "function"), - createPropertyAccess(createIdentifier("define"), "amd") - ), - createBlock([ - createStatement( - createCall( - createIdentifier("define"), - /*typeArguments*/ undefined, - [ - createArrayLiteral([ - createLiteral("require"), - createLiteral("exports"), - ...aliasedModuleNames, - ...unaliasedModuleNames - ]), - createIdentifier("factory") - ] - ) - ) - ]) ) - ) - ], - /*location*/ undefined, - /*multiLine*/ true + ], + /*multiLine*/ true + ), + /*location*/ undefined ) ); @@ -274,8 +278,8 @@ namespace ts { return updateSourceFileNode( node, - createNodeArray( - [ + setTextRange( + createNodeArray([ createStatement( createCall( umdHeader, @@ -300,7 +304,7 @@ namespace ts { ] ) ) - ], + ]), /*location*/ node.statements ) ); @@ -378,7 +382,7 @@ namespace ts { // Append the 'export =' statement if provided. addExportEqualsIfNeeded(statements, /*emitAsReturn*/ true); - const body = createBlock(statements, /*location*/ undefined, /*multiLine*/ true); + const body = createBlock(statements, /*multiLine*/ true); if (currentModuleInfo.hasExportStarsToExportValues) { // If we have any `export * from ...` declarations // we need to inform the emitter to add the __export helper. @@ -399,11 +403,8 @@ namespace ts { function addExportEqualsIfNeeded(statements: Statement[], emitAsReturn: boolean) { if (currentModuleInfo.exportEquals) { if (emitAsReturn) { - const statement = createReturn( - currentModuleInfo.exportEquals.expression, - /*location*/ currentModuleInfo.exportEquals - ); - + const statement = createReturn(currentModuleInfo.exportEquals.expression); + setTextRange(statement, currentModuleInfo.exportEquals); setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments); statements.push(statement); } @@ -415,10 +416,10 @@ namespace ts { "exports" ), currentModuleInfo.exportEquals.expression - ), - /*location*/ currentModuleInfo.exportEquals + ) ); + setTextRange(statement, currentModuleInfo.exportEquals); setEmitFlags(statement, EmitFlags.NoComments); statements.push(statement); } @@ -481,7 +482,7 @@ namespace ts { if (moduleKind !== ModuleKind.AMD) { if (!node.importClause) { // import "mod"; - return createStatement(createRequireCall(node), /*location*/ node); + return setTextRange(createStatement(createRequireCall(node)), node); } else { const variables: VariableDeclaration[] = []; @@ -520,12 +521,13 @@ namespace ts { } statements = append(statements, - createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList( - variables, - /*location*/ undefined, - languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None + setTextRange( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + variables, + languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None + ) ), /*location*/ node ) @@ -539,14 +541,15 @@ namespace ts { /*modifiers*/ undefined, createVariableDeclarationList( [ - createVariableDeclaration( - getSynthesizedClone(namespaceDeclaration.name), - /*type*/ undefined, - getGeneratedNameForNode(node), + setTextRange( + createVariableDeclaration( + getSynthesizedClone(namespaceDeclaration.name), + /*type*/ undefined, + getGeneratedNameForNode(node) + ), /*location*/ node ) ], - /*location*/ undefined, languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None ) ) @@ -592,31 +595,34 @@ namespace ts { if (moduleKind !== ModuleKind.AMD) { if (hasModifier(node, ModifierFlags.Export)) { statements = append(statements, - createStatement( - createExportExpression( - node.name, - createRequireCall(node) + setTextRange( + createStatement( + createExportExpression( + node.name, + createRequireCall(node) + ) ), - /*location*/ node + node ) ); } else { statements = append(statements, - createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList( - [ - createVariableDeclaration( - getSynthesizedClone(node.name), - /*type*/ undefined, - createRequireCall(node) - ) - ], - /*location*/ undefined, - /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None + setTextRange( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + [ + createVariableDeclaration( + getSynthesizedClone(node.name), + /*type*/ undefined, + createRequireCall(node) + ) + ], + /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None + ) ), - /*location*/ node + node ) ); } @@ -624,9 +630,11 @@ namespace ts { else { if (hasModifier(node, ModifierFlags.Export)) { statements = append(statements, - createStatement( - createExportExpression(getExportName(node), getLocalName(node)), - /*location*/ node + setTextRange( + createStatement( + createExportExpression(getExportName(node), getLocalName(node)) + ), + node ) ); } @@ -662,15 +670,17 @@ namespace ts { // export { x, y } from "mod"; if (moduleKind !== ModuleKind.AMD) { statements.push( - createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList([ - createVariableDeclaration( - generatedName, - /*type*/ undefined, - createRequireCall(node) - ) - ]), + setTextRange( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + generatedName, + /*type*/ undefined, + createRequireCall(node) + ) + ]) + ), /*location*/ node ) ); @@ -681,9 +691,11 @@ namespace ts { specifier.propertyName || specifier.name ); statements.push( - createStatement( - createExportExpression(getExportName(specifier), exportedValue), - /*location*/ specifier + setTextRange( + createStatement( + createExportExpression(getExportName(specifier), exportedValue) + ), + specifier ) ); } @@ -692,17 +704,19 @@ namespace ts { } else { // export * from "mod"; - return createStatement( - createCall( - createIdentifier("__export"), - /*typeArguments*/ undefined, - [ - moduleKind !== ModuleKind.AMD - ? createRequireCall(node) - : generatedName - ] + return setTextRange( + createStatement( + createCall( + createIdentifier("__export"), + /*typeArguments*/ undefined, + [ + moduleKind !== ModuleKind.AMD + ? createRequireCall(node) + : generatedName + ] + ) ), - /*location*/ node + node ); } } @@ -741,15 +755,17 @@ namespace ts { if (hasModifier(node, ModifierFlags.Export)) { statements = append(statements, setOriginalNode( - createFunctionDeclaration( - /*decorators*/ undefined, - visitNodes(node.modifiers, modifierVisitor, isModifier), - node.asteriskToken, - getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), - /*typeParameters*/ undefined, - node.parameters, - /*type*/ undefined, - node.body, + setTextRange( + createFunctionDeclaration( + /*decorators*/ undefined, + visitNodes(node.modifiers, modifierVisitor, isModifier), + node.asteriskToken, + getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), + /*typeParameters*/ undefined, + node.parameters, + /*type*/ undefined, + node.body + ), /*location*/ node ), /*original*/ node @@ -782,16 +798,18 @@ namespace ts { if (hasModifier(node, ModifierFlags.Export)) { statements = append(statements, setOriginalNode( - createClassDeclaration( - /*decorators*/ undefined, - visitNodes(node.modifiers, modifierVisitor, isModifier), - getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), - /*typeParameters*/ undefined, - node.heritageClauses, - node.members, - /*location*/ node + setTextRange( + createClassDeclaration( + /*decorators*/ undefined, + visitNodes(node.modifiers, modifierVisitor, isModifier), + getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), + /*typeParameters*/ undefined, + node.heritageClauses, + node.members + ), + node ), - /*original*/ node + node ) ); } @@ -843,7 +861,7 @@ namespace ts { } if (expressions) { - statements = append(statements, createStatement(inlineExpressions(expressions), /*location*/ node)); + statements = append(statements, setTextRange(createStatement(inlineExpressions(expressions)), node)); } } else { @@ -880,9 +898,11 @@ namespace ts { } else { return createAssignment( - createPropertyAccess( - createIdentifier("exports"), - node.name, + setTextRange( + createPropertyAccess( + createIdentifier("exports"), + node.name + ), /*location*/ node.name ), node.initializer @@ -1115,7 +1135,7 @@ namespace ts { createStatement( createExportExpression( createIdentifier("__esModule"), - createLiteral(true) + createTrue() ) ) ); @@ -1130,7 +1150,7 @@ namespace ts { createIdentifier("exports"), createLiteral("__esModule"), createObjectLiteral([ - createPropertyAssignment("value", createLiteral(true)) + createPropertyAssignment("value", createTrue()) ]) ] ) @@ -1153,7 +1173,7 @@ namespace ts { * @param allowComments An optional value indicating whether to emit comments for the statement. */ function createExportStatement(name: Identifier, value: Expression, location?: TextRange, allowComments?: boolean) { - const statement = createStatement(createExportExpression(name, value), location); + const statement = setTextRange(createStatement(createExportExpression(name, value)), location); startOnNewLine(statement); if (!allowComments) { setEmitFlags(statement, EmitFlags.NoComments); @@ -1170,12 +1190,14 @@ namespace ts { * @param location The location to use for source maps and comments for the export. */ function createExportExpression(name: Identifier, value: Expression, location?: TextRange) { - return createAssignment( - createPropertyAccess( - createIdentifier("exports"), - getSynthesizedClone(name) + return setTextRange( + createAssignment( + createPropertyAccess( + createIdentifier("exports"), + getSynthesizedClone(name) + ), + value ), - value, location ); } @@ -1268,9 +1290,9 @@ namespace ts { // destructuring assignment if (node.objectAssignmentInitializer) { const initializer = createAssignment(exportedOrImportedName, node.objectAssignmentInitializer); - return createPropertyAssignment(name, initializer, /*location*/ node); + return setTextRange(createPropertyAssignment(name, initializer), node); } - return createPropertyAssignment(name, exportedOrImportedName, /*location*/ node); + return setTextRange(createPropertyAssignment(name, exportedOrImportedName), node); } return node; } @@ -1312,9 +1334,11 @@ namespace ts { if (!isGeneratedIdentifier(node) && !isLocalName(node)) { const exportContainer = resolver.getReferencedExportContainer(node, isExportName(node)); if (exportContainer && exportContainer.kind === SyntaxKind.SourceFile) { - return createPropertyAccess( - createIdentifier("exports"), - getSynthesizedClone(node), + return setTextRange( + createPropertyAccess( + createIdentifier("exports"), + getSynthesizedClone(node) + ), /*location*/ node ); } @@ -1322,17 +1346,21 @@ namespace ts { const importDeclaration = resolver.getReferencedImportDeclaration(node); if (importDeclaration) { if (isImportClause(importDeclaration)) { - return createPropertyAccess( - getGeneratedNameForNode(importDeclaration.parent), - createIdentifier("default"), + return setTextRange( + createPropertyAccess( + getGeneratedNameForNode(importDeclaration.parent), + createIdentifier("default") + ), /*location*/ node ); } else if (isImportSpecifier(importDeclaration)) { const name = importDeclaration.propertyName || importDeclaration.name; - return createPropertyAccess( - getGeneratedNameForNode(importDeclaration.parent.parent.parent), - getSynthesizedClone(name), + return setTextRange( + createPropertyAccess( + getGeneratedNameForNode(importDeclaration.parent.parent.parent), + getSynthesizedClone(name) + ), /*location*/ node ); } @@ -1400,10 +1428,12 @@ namespace ts { const exportedNames = getExports(node.operand); if (exportedNames) { let expression: Expression = node.kind === SyntaxKind.PostfixUnaryExpression - ? createBinary( - node.operand, - createToken(node.operator === SyntaxKind.PlusPlusToken ? SyntaxKind.PlusEqualsToken : SyntaxKind.MinusEqualsToken), - createLiteral(1), + ? setTextRange( + createBinary( + node.operand, + createToken(node.operator === SyntaxKind.PlusPlusToken ? SyntaxKind.PlusEqualsToken : SyntaxKind.MinusEqualsToken), + createLiteral(1) + ), /*location*/ node) : node; for (const exportName of exportedNames) { diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 6c59ea194cb0d..b29992015041f 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -105,17 +105,20 @@ namespace ts { const updated = setEmitFlags( updateSourceFileNode( node, - createNodeArray([ - createStatement( - createCall( - createPropertyAccess(createIdentifier("System"), "register"), - /*typeArguments*/ undefined, - moduleName - ? [moduleName, dependencies, moduleBodyFunction] - : [dependencies, moduleBodyFunction] + setTextRange( + createNodeArray([ + createStatement( + createCall( + createPropertyAccess(createIdentifier("System"), "register"), + /*typeArguments*/ undefined, + moduleName + ? [moduleName, dependencies, moduleBodyFunction] + : [dependencies, moduleBodyFunction] + ) ) - ) - ], node.statements) + ]), + node.statements + ) ), EmitFlags.NoTrailingComments); if (!(compilerOptions.outFile || compilerOptions.out)) { @@ -260,35 +263,26 @@ namespace ts { addRange(statements, endLexicalEnvironment()); const exportStarFunction = addExportStarIfNeeded(statements); - statements.push( - createReturn( - setMultiLine( - createObjectLiteral([ - createPropertyAssignment("setters", - createSettersArray(exportStarFunction, dependencyGroups) - ), - createPropertyAssignment("execute", - createFunctionExpression( - /*modifiers*/ undefined, - /*asteriskToken*/ undefined, - /*name*/ undefined, - /*typeParameters*/ undefined, - /*parameters*/ [], - /*type*/ undefined, - createBlock( - executeStatements, - /*location*/ undefined, - /*multiLine*/ true - ) - ) - ) - ]), - /*multiLine*/ true + const moduleObject = createObjectLiteral([ + createPropertyAssignment("setters", + createSettersArray(exportStarFunction, dependencyGroups) + ), + createPropertyAssignment("execute", + createFunctionExpression( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + /*name*/ undefined, + /*typeParameters*/ undefined, + /*parameters*/ [], + /*type*/ undefined, + createBlock(executeStatements, /*multiLine*/ true) ) ) - ); + ]); - return createBlock(statements, /*location*/ undefined, /*multiLine*/ true); + moduleObject.multiLine = true; + statements.push(createReturn(moduleObject)); + return createBlock(statements, /*multiLine*/ true); } /** @@ -337,7 +331,7 @@ namespace ts { exportedNames.push( createPropertyAssignment( createLiteral(exportedLocalName), - createLiteral(true) + createTrue() ) ); } @@ -359,7 +353,7 @@ namespace ts { exportedNames.push( createPropertyAssignment( createLiteral((element.name || element.propertyName).text), - createLiteral(true) + createTrue() ) ); } @@ -373,7 +367,7 @@ namespace ts { createVariableDeclaration( exportedNamesStorageRef, /*type*/ undefined, - createObjectLiteral(exportedNames, /*location*/ undefined, /*multiline*/ true) + createObjectLiteral(exportedNames, /*multiline*/ true) ) ]) ) @@ -456,9 +450,7 @@ namespace ts { [exports] ) ) - ], - /*location*/ undefined, - /*multiline*/ true) + ], /*multiline*/ true) ); } @@ -525,7 +517,7 @@ namespace ts { createCall( exportFunction, /*typeArguments*/ undefined, - [createObjectLiteral(properties, /*location*/ undefined, /*multiline*/ true)] + [createObjectLiteral(properties, /*multiline*/ true)] ) ) ); @@ -558,12 +550,12 @@ namespace ts { /*typeParameters*/ undefined, [createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, parameterName)], /*type*/ undefined, - createBlock(statements, /*location*/ undefined, /*multiLine*/ true) + createBlock(statements, /*multiLine*/ true) ) ); } - return createArrayLiteral(setters, /*location*/ undefined, /*multiLine*/ true); + return createArrayLiteral(setters, /*multiLine*/ true); } // @@ -713,19 +705,23 @@ namespace ts { // Rewrite the class declaration into an assignment of a class expression. statements = append(statements, - createStatement( - createAssignment( - name, - createClassExpression( - /*modifiers*/ undefined, - node.name, - /*typeParameters*/ undefined, - visitNodes(node.heritageClauses, destructuringVisitor, isHeritageClause), - visitNodes(node.members, destructuringVisitor, isClassElement), - /*location*/ node + setTextRange( + createStatement( + createAssignment( + name, + setTextRange( + createClassExpression( + /*modifiers*/ undefined, + node.name, + /*typeParameters*/ undefined, + visitNodes(node.heritageClauses, destructuringVisitor, isHeritageClause), + visitNodes(node.members, destructuringVisitor, isClassElement) + ), + node + ) ) ), - /*location*/ node + node ) ); @@ -766,7 +762,7 @@ namespace ts { let statements: Statement[]; if (expressions) { - statements = append(statements, createStatement(inlineExpressions(expressions), /*location*/ node)); + statements = append(statements, setTextRange(createStatement(inlineExpressions(expressions)), node)); } if (isMarkedDeclaration) { @@ -864,8 +860,8 @@ namespace ts { function createVariableAssignment(name: Identifier, value: Expression, location: TextRange, isExportedDeclaration: boolean) { hoistVariableDeclaration(getSynthesizedClone(name)); return isExportedDeclaration - ? createExportExpression(name, preventSubstitution(createAssignment(name, value, location))) - : preventSubstitution(createAssignment(name, value, location)); + ? createExportExpression(name, preventSubstitution(setTextRange(createAssignment(name, value), location))) + : preventSubstitution(setTextRange(createAssignment(name, value), location)); } /** @@ -1642,16 +1638,20 @@ namespace ts { const importDeclaration = resolver.getReferencedImportDeclaration(node); if (importDeclaration) { if (isImportClause(importDeclaration)) { - return createPropertyAccess( - getGeneratedNameForNode(importDeclaration.parent), - createIdentifier("default"), + return setTextRange( + createPropertyAccess( + getGeneratedNameForNode(importDeclaration.parent), + createIdentifier("default") + ), /*location*/ node ); } else if (isImportSpecifier(importDeclaration)) { - return createPropertyAccess( - getGeneratedNameForNode(importDeclaration.parent.parent.parent), - getSynthesizedClone(importDeclaration.propertyName || importDeclaration.name), + return setTextRange( + createPropertyAccess( + getGeneratedNameForNode(importDeclaration.parent.parent.parent), + getSynthesizedClone(importDeclaration.propertyName || importDeclaration.name) + ), /*location*/ node ); } @@ -1718,10 +1718,13 @@ namespace ts { const exportedNames = getExports(node.operand); if (exportedNames) { let expression: Expression = node.kind === SyntaxKind.PostfixUnaryExpression - ? createPrefix( - node.operator, - node.operand, - /*location*/ node) + ? setTextRange( + createPrefix( + node.operator, + node.operand + ), + node + ) : node; for (const exportName of exportedNames) { diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index a61998e8af984..b18ab67381e50 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -588,17 +588,17 @@ namespace ts { name, /*typeParameters*/ undefined, visitNodes(node.heritageClauses, visitor, isHeritageClause), - transformClassMembers(node, hasExtendsClause), - node); - - let emitFlags = getEmitFlags(node); + transformClassMembers(node, hasExtendsClause) + ); // To better align with the old emitter, we should not emit a trailing source map // entry if the class has static properties. + let emitFlags = getEmitFlags(node); if (hasStaticProperties) { emitFlags |= EmitFlags.NoTrailingSourceMap; } + setTextRange(classDeclaration, node); setOriginalNode(classDeclaration, node); setEmitFlags(classDeclaration, emitFlags); return classDeclaration; @@ -709,13 +709,24 @@ namespace ts { // } const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause); const members = transformClassMembers(node, hasExtendsClause); - const classExpression = createClassExpression(/*modifiers*/ undefined, name, /*typeParameters*/ undefined, heritageClauses, members, location); + const classExpression = createClassExpression(/*modifiers*/ undefined, name, /*typeParameters*/ undefined, heritageClauses, members); setOriginalNode(classExpression, node); + setTextRange(classExpression, location); // let ${name} = ${classExpression} where name is either declaredName if the class doesn't contain self-reference // or decoratedClassAlias if the class contain self-reference. - const statement = createLetStatement(declName, classAlias ? createAssignment(classAlias, classExpression) : classExpression, location); + const statement = createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + declName, + /*type*/ undefined, + classAlias ? createAssignment(classAlias, classExpression) : classExpression + ) + ], NodeFlags.Let) + ); setOriginalNode(statement, node); + setTextRange(statement, location); setCommentRange(statement, node); return statement; } @@ -734,18 +745,17 @@ namespace ts { const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause); const members = transformClassMembers(node, some(heritageClauses, c => c.token === SyntaxKind.ExtendsKeyword)); - const classExpression = setOriginalNode( - createClassExpression( - /*modifiers*/ undefined, - node.name, - /*typeParameters*/ undefined, - heritageClauses, - members, - /*location*/ node - ), - node + const classExpression = createClassExpression( + /*modifiers*/ undefined, + node.name, + /*typeParameters*/ undefined, + heritageClauses, + members ); + setOriginalNode(classExpression, node); + setTextRange(classExpression, node); + if (staticProperties.length > 0) { const expressions: Expression[] = []; const temp = createTempVariable(hoistVariableDeclaration); @@ -781,7 +791,7 @@ namespace ts { } addRange(members, visitNodes(node.members, classElementVisitor, isClassElement)); - return createNodeArray(members, /*location*/ node.members); + return setTextRange(createNodeArray(members), /*location*/ node.members); } /** @@ -812,12 +822,14 @@ namespace ts { // } return startOnNewLine( setOriginalNode( - createConstructor( - /*decorators*/ undefined, - /*modifiers*/ undefined, - parameters, - body, - /*location*/ constructor || node + setTextRange( + createConstructor( + /*decorators*/ undefined, + /*modifiers*/ undefined, + parameters, + body + ), + constructor || node ), constructor ) @@ -919,13 +931,15 @@ namespace ts { // End the lexical environment. addRange(statements, endLexicalEnvironment()); - return createBlock( - createNodeArray( - statements, - /*location*/ constructor ? constructor.body.statements : node.members + return setTextRange( + createBlock( + setTextRange( + createNodeArray(statements), + /*location*/ constructor ? constructor.body.statements : node.members + ), + /*multiLine*/ true ), - /*location*/ constructor ? constructor.body : /*location*/ undefined, - /*multiLine*/ true + /*location*/ constructor ? constructor.body : undefined ); } @@ -991,16 +1005,20 @@ namespace ts { setEmitFlags(localName, EmitFlags.NoComments); return startOnNewLine( - createStatement( - createAssignment( - createPropertyAccess( - createThis(), - propertyName, - /*location*/ node.name - ), - localName + setTextRange( + createStatement( + createAssignment( + setTextRange( + createPropertyAccess( + createThis(), + propertyName + ), + node.name + ), + localName + ) ), - /*location*/ moveRangePos(node, -1) + moveRangePos(node, -1) ) ); } @@ -1504,7 +1522,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(context, "design:typeinfo", createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true))); + decoratorExpressions.push(createMetadataHelper(context, "design:typeinfo", createObjectLiteral(properties, /*multiLine*/ true))); } } } @@ -1939,10 +1957,7 @@ namespace ts { expression = createAssignment(generatedName, expression); } - return setOriginalNode( - createComputedPropertyName(expression, /*location*/ name), - name - ); + return updateComputedPropertyName(name, expression); } else { return name; @@ -1961,9 +1976,11 @@ namespace ts { function visitHeritageClause(node: HeritageClause): HeritageClause { if (node.token === SyntaxKind.ExtendsKeyword) { const types = visitNodes(node.types, visitor, isExpressionWithTypeArguments, 0, 1); - return createHeritageClause( - SyntaxKind.ExtendsKeyword, - types, + return setTextRange( + createHeritageClause( + SyntaxKind.ExtendsKeyword, + types + ), node ); } @@ -1980,11 +1997,10 @@ namespace ts { * @param node The ExpressionWithTypeArguments to transform. */ function visitExpressionWithTypeArguments(node: ExpressionWithTypeArguments): ExpressionWithTypeArguments { - const expression = visitNode(node.expression, visitor, isLeftHandSideExpression); - return createExpressionWithTypeArguments( + return updateExpressionWithTypeArguments( + node, /*typeArguments*/ undefined, - expression, - node + visitNode(node.expression, visitor, isLeftHandSideExpression) ); } @@ -2205,13 +2221,13 @@ namespace ts { visitNode(node.name, visitor, isBindingName), /*questionToken*/ undefined, /*type*/ undefined, - visitNode(node.initializer, visitor, isExpression), - /*location*/ moveRangePastModifiers(node) + visitNode(node.initializer, visitor, isExpression) ); // 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(parameter, node); + setTextRange(parameter, moveRangePastModifiers(node)); setCommentRange(parameter, node); setSourceMapRange(parameter, moveRangePastModifiers(node)); setEmitFlags(parameter.name, EmitFlags.NoTrailingSourceMap); @@ -2233,11 +2249,13 @@ namespace ts { return undefined; } - return createStatement( - inlineExpressions( - map(variables, transformInitializedVariable) + return setTextRange( + createStatement( + inlineExpressions( + map(variables, transformInitializedVariable) + ) ), - /*location*/ node + node ); } else { @@ -2258,9 +2276,11 @@ namespace ts { ); } else { - return createAssignment( - getNamespaceMemberNameWithSourceMapsAndWithoutComments(name), - visitNode(node.initializer, visitor, isExpression), + return setTextRange( + createAssignment( + getNamespaceMemberNameWithSourceMapsAndWithoutComments(name), + visitNode(node.initializer, visitor, isExpression) + ), /*location*/ node ); } @@ -2418,11 +2438,11 @@ namespace ts { ), /*typeArguments*/ undefined, [moduleArg] - ), - /*location*/ node + ) ); setOriginalNode(enumStatement, node); + setTextRange(enumStatement, node); setEmitFlags(enumStatement, emitFlags); statements.push(enumStatement); @@ -2448,8 +2468,7 @@ namespace ts { currentNamespaceContainerName = savedCurrentNamespaceLocalName; return createBlock( - createNodeArray(statements, /*location*/ node.members), - /*location*/ undefined, + setTextRange(createNodeArray(statements), /*location*/ node.members), /*multiLine*/ true ); } @@ -2464,22 +2483,26 @@ namespace ts { // we pass false as 'generateNameForComputedPropertyName' for a backward compatibility purposes // old emitter always generate 'expression' part of the name as-is. const name = getExpressionForPropertyName(member, /*generateNameForComputedPropertyName*/ false); - return createStatement( - createAssignment( - createElementAccess( - currentNamespaceContainerName, + return setTextRange( + createStatement( + setTextRange( createAssignment( createElementAccess( currentNamespaceContainerName, - name + createAssignment( + createElementAccess( + currentNamespaceContainerName, + name + ), + transformEnumMemberDeclarationValue(member) + ) ), - transformEnumMemberDeclarationValue(member) - ) - ), - name, - /*location*/ member + name + ), + member + ) ), - /*location*/ member + member ); } @@ -2697,11 +2720,11 @@ namespace ts { ), /*typeArguments*/ undefined, [moduleArg] - ), - /*location*/ node + ) ); setOriginalNode(moduleStatement, node); + setTextRange(moduleStatement, node); setEmitFlags(moduleStatement, emitFlags); statements.push(moduleStatement); @@ -2756,13 +2779,13 @@ namespace ts { currentScopeFirstDeclarationsOfName = savedCurrentScopeFirstDeclarationsOfName; const block = createBlock( - createNodeArray( - statements, + setTextRange( + createNodeArray(statements), /*location*/ statementsLocation ), - /*location*/ blockLocation, /*multiLine*/ true ); + setTextRange(block, blockLocation); // namespace hello.hi.world { // function foo() {} @@ -2962,18 +2985,20 @@ namespace ts { // export var ${name} = ${moduleReference}; // var ${name} = ${moduleReference}; return setOriginalNode( - createVariableStatement( - visitNodes(node.modifiers, modifierVisitor, isModifier), - createVariableDeclarationList([ - setOriginalNode( - createVariableDeclaration( - node.name, - /*type*/ undefined, - moduleReference - ), - node - ) - ]), + setTextRange( + createVariableStatement( + visitNodes(node.modifiers, modifierVisitor, isModifier), + createVariableDeclarationList([ + setOriginalNode( + createVariableDeclaration( + node.name, + /*type*/ undefined, + moduleReference + ), + node + ) + ]) + ), node ), node @@ -3034,7 +3059,7 @@ namespace ts { * Creates a statement for the provided expression. This is used in calls to `map`. */ function expressionToStatement(expression: Expression) { - return createStatement(expression, /*location*/ undefined); + return createStatement(expression); } function addExportMemberAssignment(statements: Statement[], node: ClassDeclaration | FunctionDeclaration) { @@ -3050,17 +3075,19 @@ namespace ts { } function createNamespaceExport(exportName: Identifier, exportValue: Expression, location?: TextRange) { - return createStatement( - createAssignment( - getNamespaceMemberName(currentNamespaceContainerName, exportName, /*allowComments*/ false, /*allowSourceMaps*/ true), - exportValue + return setTextRange( + createStatement( + createAssignment( + getNamespaceMemberName(currentNamespaceContainerName, exportName, /*allowComments*/ false, /*allowSourceMaps*/ true), + exportValue + ) ), location ); } function createNamespaceExportExpression(exportName: Identifier, exportValue: Expression, location?: TextRange) { - return createAssignment(getNamespaceMemberNameWithSourceMapsAndWithoutComments(exportName), exportValue, location); + return setTextRange(createAssignment(getNamespaceMemberNameWithSourceMapsAndWithoutComments(exportName), exportValue), location); } function getNamespaceMemberNameWithSourceMapsAndWithoutComments(name: Identifier) { @@ -3201,9 +3228,9 @@ namespace ts { // destructuring assignment if (node.objectAssignmentInitializer) { const initializer = createAssignment(exportedName, node.objectAssignmentInitializer); - return createPropertyAssignment(name, initializer, /*location*/ node); + return setTextRange(createPropertyAssignment(name, initializer), node); } - return createPropertyAssignment(name, exportedName, /*location*/ node); + return setTextRange(createPropertyAssignment(name, exportedName), node); } } return node; @@ -3263,7 +3290,10 @@ namespace ts { (applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) || (applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration); if (substitute) { - return createPropertyAccess(getGeneratedNameForNode(container), node, /*location*/ node); + return setTextRange( + createPropertyAccess(getGeneratedNameForNode(container), node), + /*location*/ node + ); } } } @@ -3322,13 +3352,15 @@ namespace ts { function createParamHelper(context: TransformationContext, expression: Expression, parameterOffset: number, location?: TextRange) { context.requestEmitHelper(paramHelper); - return createCall( - getHelperName("__param"), - /*typeArguments*/ undefined, - [ - createLiteral(parameterOffset), - expression - ], + return setTextRange( + createCall( + getHelperName("__param"), + /*typeArguments*/ undefined, + [ + createLiteral(parameterOffset), + expression + ] + ), location ); } @@ -3371,7 +3403,7 @@ namespace ts { function createDecorateHelper(context: TransformationContext, decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression, location?: TextRange) { context.requestEmitHelper(decorateHelper); const argumentsArray: Expression[] = []; - argumentsArray.push(createArrayLiteral(decoratorExpressions, /*location*/ undefined, /*multiLine*/ true)); + argumentsArray.push(createArrayLiteral(decoratorExpressions, /*multiLine*/ true)); argumentsArray.push(target); if (memberName) { argumentsArray.push(memberName); @@ -3380,6 +3412,13 @@ namespace ts { } } - return createCall(getHelperName("__decorate"), /*typeArguments*/ undefined, argumentsArray, location); + return setTextRange( + createCall( + getHelperName("__decorate"), + /*typeArguments*/ undefined, + argumentsArray + ), + location + ); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8660e6138cdad..ae678f429f133 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -958,8 +958,7 @@ } // Represents an expression that is elided as part of a transformation to emit comments on a - // not-emitted node. The 'expression' property of a NotEmittedExpression should be emitted. - // @internal + // not-emitted node. The 'expression' property of a PartiallyEmittedExpression should be emitted. export interface PartiallyEmittedExpression extends LeftHandSideExpression { kind: SyntaxKind.PartiallyEmittedExpression; expression: Expression; @@ -1538,7 +1537,6 @@ // Represents a statement that is elided as part of a transformation to emit comments on a // not-emitted node. - // @internal export interface NotEmittedStatement extends Statement { kind: SyntaxKind.NotEmittedStatement; } @@ -3730,7 +3728,6 @@ helpers?: EmitHelper[]; // Emit helpers for the node } - /* @internal */ export const enum EmitFlags { SingleLine = 1 << 0, // The contents of this node should be emitted on a single line. AdviseOnEmitNode = 1 << 1, // The printer should invoke the onEmitNode callback when printing this node. @@ -3759,7 +3756,6 @@ HasEndOfDeclarationMarker = 1 << 21, // Declaration has an associated NotEmittedStatement to mark the end of the declaration } - /* @internal */ export interface EmitHelper { readonly name: string; // A unique name for this helper. readonly scoped: boolean; // Indicates whether ther helper MUST be emitted in the current scope. diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 01cfcb08047ed..6004bee466a0f 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3331,6 +3331,14 @@ namespace ts { } } + export function getRangePos(range: TextRange | undefined) { + return range ? range.pos : -1; + } + + export function getRangeEnd(range: TextRange | undefined) { + return range ? range.end : -1; + } + /** * Increases (or decreases) a position by the provided amount. * diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index f3efc040e3595..b6e0adc129417 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -627,8 +627,7 @@ namespace ts { // If we are not visiting all of the original nodes, we must always create a new array. // Since this is a fragment of a node array, we do not copy over the previous location // and will only copy over `hasTrailingComma` if we are including the last element. - updated = createNodeArray([], /*location*/ undefined, - /*hasTrailingComma*/ nodes.hasTrailingComma && start + count === length); + updated = createNodeArray([], /*hasTrailingComma*/ nodes.hasTrailingComma && start + count === length); } // Visit each original node. @@ -639,7 +638,8 @@ namespace ts { if (updated !== undefined || visited === undefined || visited !== node) { if (updated === undefined) { // Ensure we have a copy of `nodes`, up to the current index. - updated = createNodeArray(nodes.slice(0, i), /*location*/ nodes, nodes.hasTrailingComma); + updated = createNodeArray(nodes.slice(0, i), nodes.hasTrailingComma); + setTextRange(updated, nodes); } if (visited) { if (isArray(visited)) { @@ -675,10 +675,10 @@ namespace ts { context.startLexicalEnvironment(); statements = visitNodes(statements, visitor, isStatement, start); if (ensureUseStrict && !startsWithUseStrict(statements)) { - statements = createNodeArray([createStatement(createLiteral("use strict")), ...statements], statements); + statements = setTextRange(createNodeArray([createStatement(createLiteral("use strict")), ...statements]), statements); } const declarations = context.endLexicalEnvironment(); - return createNodeArray(concatenate(statements, declarations), statements); + return setTextRange(createNodeArray(concatenate(statements, declarations)), statements); } /** @@ -1228,7 +1228,7 @@ namespace ts { return statements; } return isNodeArray(statements) - ? createNodeArray(concatenate(statements, declarations), statements) + ? setTextRange(createNodeArray(concatenate(statements, declarations)), statements) : addRange(statements, declarations); } @@ -1252,13 +1252,19 @@ namespace ts { 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)); + return updateBlock(body, setTextRange(createNodeArray(concatenate(body.statements, declarations)), body.statements)); } else { - return createBlock( - createNodeArray([createReturn(body, /*location*/ body), ...declarations], body), - /*location*/ body, - /*multiLine*/ true); + return setTextRange( + createBlock( + setTextRange( + createNodeArray([setTextRange(createReturn(body), body), ...declarations]), + body + ), + /*multiLine*/ true + ), + /*location*/ body + ); } } return body; From a72abc8ebc5c4c76122126b2212449fafa1277db Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 1 Feb 2017 19:41:28 -0800 Subject: [PATCH 2/6] Make getOriginalNode/getParseTreeNode public --- src/compiler/utilities.ts | 102 +++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 6004bee466a0f..66efce4fef84a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2042,57 +2042,6 @@ namespace ts { || positionIsSynthesized(node.end); } - export function getOriginalNode(node: Node): Node; - export function getOriginalNode(node: Node, nodeTest: (node: Node) => node is T): T; - export function getOriginalNode(node: Node, nodeTest?: (node: Node) => boolean): Node { - if (node) { - while (node.original !== undefined) { - node = node.original; - } - } - - return !nodeTest || nodeTest(node) ? node : undefined; - } - - /** - * Gets a value indicating whether a node originated in the parse tree. - * - * @param node The node to test. - */ - export function isParseTreeNode(node: Node): boolean { - return (node.flags & NodeFlags.Synthesized) === 0; - } - - /** - * Gets the original parse tree node for a node. - * - * @param node The original node. - * @returns The original parse tree node if found; otherwise, undefined. - */ - export function getParseTreeNode(node: Node): Node; - - /** - * Gets the original parse tree node for a node. - * - * @param node The original node. - * @param nodeTest A callback used to ensure the correct type of parse tree node is returned. - * @returns The original parse tree node if found; otherwise, undefined. - */ - export function getParseTreeNode(node: Node, nodeTest?: (node: Node) => node is T): T; - export function getParseTreeNode(node: Node, nodeTest?: (node: Node) => boolean): Node { - if (isParseTreeNode(node)) { - return node; - } - - node = getOriginalNode(node); - - if (isParseTreeNode(node) && (!nodeTest || nodeTest(node))) { - return node; - } - - return undefined; - } - export function getOriginalSourceFileOrBundle(sourceFileOrBundle: SourceFile | Bundle) { if (sourceFileOrBundle.kind === SyntaxKind.Bundle) { return updateBundle(sourceFileOrBundle, sameMap(sourceFileOrBundle.sourceFiles, getOriginalSourceFile)); @@ -4530,4 +4479,55 @@ namespace ts { return true; } } + + export function getOriginalNode(node: Node): Node; + export function getOriginalNode(node: Node, nodeTest: (node: Node) => node is T): T; + export function getOriginalNode(node: Node, nodeTest?: (node: Node) => boolean): Node { + if (node) { + while (node.original !== undefined) { + node = node.original; + } + } + + return !nodeTest || nodeTest(node) ? node : undefined; + } + + /** + * Gets a value indicating whether a node originated in the parse tree. + * + * @param node The node to test. + */ + export function isParseTreeNode(node: Node): boolean { + return (node.flags & NodeFlags.Synthesized) === 0; + } + + /** + * Gets the original parse tree node for a node. + * + * @param node The original node. + * @returns The original parse tree node if found; otherwise, undefined. + */ + export function getParseTreeNode(node: Node): Node; + + /** + * Gets the original parse tree node for a node. + * + * @param node The original node. + * @param nodeTest A callback used to ensure the correct type of parse tree node is returned. + * @returns The original parse tree node if found; otherwise, undefined. + */ + export function getParseTreeNode(node: Node, nodeTest?: (node: Node) => node is T): T; + export function getParseTreeNode(node: Node, nodeTest?: (node: Node) => boolean): Node { + if (isParseTreeNode(node)) { + return node; + } + + node = getOriginalNode(node); + + if (isParseTreeNode(node) && (!nodeTest || nodeTest(node))) { + return node; + } + + return undefined; + } } From 7a539d0b85bbf5da197660f0ad4246820c4dbe59 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Fri, 3 Feb 2017 12:40:39 -0800 Subject: [PATCH 3/6] Identifier escaping/unescaping for unique names --- src/compiler/emitter.ts | 20 ++++++++++---------- src/compiler/factory.ts | 5 ++--- src/compiler/transformers/es2015.ts | 4 ++-- src/compiler/transformers/ts.ts | 2 +- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 498f65ad36658..700102a706962 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2565,7 +2565,7 @@ namespace ts { // Node names generate unique names based on their original node // and are cached based on that node's id. const node = getNodeForGeneratedName(name); - return generateNameCached(node, getTextOfNode); + return generateNameCached(node); } else { // Auto, Loop, and Unique names are cached based on their unique @@ -2575,9 +2575,9 @@ namespace ts { } } - function generateNameCached(node: Node, getTextOfNode: (node: Node, includeTrivia?: boolean) => string) { + function generateNameCached(node: Node) { const nodeId = getNodeId(node); - return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node, getTextOfNode))); + return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node))); } /** @@ -2659,7 +2659,7 @@ namespace ts { /** * Generates a unique name for a ModuleDeclaration or EnumDeclaration. */ - function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration, getTextOfNode: (node: Node, includeTrivia?: boolean) => string) { + function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { const name = getTextOfNode(node.name); // Use module/enum name itself if it is unique, otherwise make a unique variation return isUniqueLocalName(name, node) ? name : makeUniqueName(name); @@ -2689,9 +2689,9 @@ namespace ts { return makeUniqueName("class"); } - function generateNameForMethodOrAccessor(node: MethodDeclaration | AccessorDeclaration, getTextOfNode: (node: Node, includeTrivia?: boolean) => string) { + function generateNameForMethodOrAccessor(node: MethodDeclaration | AccessorDeclaration) { if (isIdentifier(node.name)) { - return generateNameCached(node.name, getTextOfNode); + return generateNameCached(node.name); } return makeTempVariableName(TempFlags.Auto); } @@ -2699,13 +2699,13 @@ namespace ts { /** * Generates a unique name from a node. */ - function generateNameForNode(node: Node, getTextOfNode: (node: Node, includeTrivia?: boolean) => string): string { + function generateNameForNode(node: Node): string { switch (node.kind) { case SyntaxKind.Identifier: return makeUniqueName(getTextOfNode(node)); case SyntaxKind.ModuleDeclaration: case SyntaxKind.EnumDeclaration: - return generateNameForModuleOrEnum(node, getTextOfNode); + return generateNameForModuleOrEnum(node); case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: return generateNameForImportOrExportDeclaration(node); @@ -2718,7 +2718,7 @@ namespace ts { case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return generateNameForMethodOrAccessor(node, getTextOfNode); + return generateNameForMethodOrAccessor(node); default: return makeTempVariableName(TempFlags.Auto); } @@ -2734,7 +2734,7 @@ namespace ts { case GeneratedIdentifierKind.Loop: return makeTempVariableName(TempFlags._i); case GeneratedIdentifierKind.Unique: - return makeUniqueName(name.text); + return makeUniqueName(unescapeIdentifier(name.text)); } Debug.fail("Unsupported GeneratedIdentifierKind."); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index ec1e0dafb795e..d5f3d92043698 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -108,7 +108,7 @@ namespace ts { export function createIdentifier(text: string): Identifier { const node = createSynthesizedNode(SyntaxKind.Identifier); - node.text = text ? escapeIdentifier(text) : undefined; + node.text = escapeIdentifier(text); node.originalKeywordKind = text ? stringToToken(text) : SyntaxKind.Unknown; node.autoGenerateKind = GeneratedIdentifierKind.None; node.autoGenerateId = 0; @@ -140,8 +140,7 @@ namespace ts { /** Create a unique name based on the supplied text. */ export function createUniqueName(text: string): Identifier { - const name = createIdentifier(""); - name.text = text; + const name = createIdentifier(text); name.autoGenerateKind = GeneratedIdentifierKind.Unique; name.autoGenerateId = nextAutoGenerateId; nextAutoGenerateId++; diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 6d0c9b3c5fa73..e0fd435a90dc6 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -2251,7 +2251,7 @@ namespace ts { // we don't want to emit a temporary variable for the RHS, just use it directly. const counter = createLoopVariable(); const rhsReference = expression.kind === SyntaxKind.Identifier - ? createUniqueName((expression).text) + ? createUniqueName(unescapeIdentifier((expression).text)) : createTempVariable(/*recordTempVariable*/ undefined); const elementAccess = createElementAccess(rhsReference, counter); @@ -2872,7 +2872,7 @@ namespace ts { else { loopParameters.push(createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name)); if (resolver.getNodeCheckFlags(decl) & NodeCheckFlags.NeedsLoopOutParameter) { - const outParamName = createUniqueName("out_" + name.text); + const outParamName = createUniqueName("out_" + unescapeIdentifier(name.text)); loopOutParameters.push({ originalName: name, outParamName }); } } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index b18ab67381e50..4ef3bd5c067d9 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -3119,7 +3119,7 @@ namespace ts { function getClassAliasIfNeeded(node: ClassDeclaration) { if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) { enableSubstitutionForClassAliases(); - const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? node.name.text : "default"); + const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? unescapeIdentifier(node.name.text) : "default"); classAliases[getOriginalNodeId(node)] = classAlias; hoistVariableDeclaration(classAlias); return classAlias; From bd98bc97bdf637d5b0c0cf2b90cb9139e3802d81 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Fri, 3 Feb 2017 14:12:50 -0800 Subject: [PATCH 4/6] Add factory functions for rest of NodeEdgeTraversal --- src/compiler/factory.ts | 175 +++++++++++++++++++++-- src/compiler/types.ts | 14 +- src/compiler/utilities.ts | 13 ++ src/compiler/visitor.ts | 285 +++++++++++++++++--------------------- 4 files changed, 315 insertions(+), 172 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index d5f3d92043698..4c7693dd846f0 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -187,6 +187,20 @@ namespace ts { // Names + export function createQualifiedName(left: EntityName, right: string | Identifier) { + const node = createSynthesizedNode(SyntaxKind.QualifiedName); + node.left = left; + node.right = asName(right); + return node; + } + + export function updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier) { + return node.left !== left + || node.right !== right + ? updateNode(createQualifiedName(left, right), node) + : node; + } + export function createComputedPropertyName(expression: Expression) { const node = createSynthesizedNode(SyntaxKind.ComputedPropertyName); node.expression = expression; @@ -502,6 +516,20 @@ namespace ts { : node; } + export function createTypeAssertion(type: TypeNode, expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.TypeAssertionExpression); + node.type = type; + node.expression = parenthesizePrefixOperand(expression); + return node; + } + + export function updateTypeAssertion(node: TypeAssertion, type: TypeNode, expression: Expression) { + return node.type !== type + || node.expression !== expression + ? updateNode(createTypeAssertion(type, expression), node) + : node; + } + export function createParen(expression: Expression) { const node = createSynthesizedNode(SyntaxKind.ParenthesizedExpression); node.expression = expression; @@ -749,6 +777,32 @@ namespace ts { : node; } + export function createAsExpression(expression: Expression, type: TypeNode) { + const node = createSynthesizedNode(SyntaxKind.AsExpression); + node.expression = expression; + node.type = type; + return node; + } + + export function updateAsExpression(node: AsExpression, expression: Expression, type: TypeNode) { + return node.expression !== expression + || node.type !== type + ? updateNode(createAsExpression(expression, type), node) + : node; + } + + export function createNonNullExpression(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.NonNullExpression); + node.expression = parenthesizeForAccess(expression); + return node; + } + + export function updateNonNullExpression(node: NonNullExpression, expression: Expression) { + return node.expression !== expression + ? updateNode(createNonNullExpression(expression), node) + : node; + } + // Misc export function createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail) { @@ -1040,18 +1094,6 @@ namespace ts { : node; } - export function createCaseBlock(clauses: CaseOrDefaultClause[]): CaseBlock { - const node = createSynthesizedNode(SyntaxKind.CaseBlock); - node.clauses = createNodeArray(clauses); - return node; - } - - export function updateCaseBlock(node: CaseBlock, clauses: CaseOrDefaultClause[]) { - return node.clauses !== clauses - ? updateNode(createCaseBlock(clauses), node) - : node; - } - export function createFunctionDeclaration(decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) { const node = createSynthesizedNode(SyntaxKind.FunctionDeclaration); node.decorators = asNodeArray(decorators); @@ -1099,6 +1141,85 @@ namespace ts { : node; } + export function createEnumDeclaration(decorators: Decorator[], modifiers: Modifier[], name: string | Identifier, members: EnumMember[]) { + const node = createSynthesizedNode(SyntaxKind.EnumDeclaration); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); + node.name = asName(name); + node.members = createNodeArray(members); + return node; + } + + export function updateEnumDeclaration(node: EnumDeclaration, decorators: Decorator[], modifiers: Modifier[], name: Identifier, members: EnumMember[]) { + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.name !== name + || node.members !== members + ? updateNode(createEnumDeclaration(decorators, modifiers, name, members), node) + : node; + } + + export function createModuleDeclaration(decorators: Decorator[], modifiers: Modifier[], name: ModuleName, body: ModuleBody, flags?: NodeFlags) { + const node = createSynthesizedNode(SyntaxKind.ModuleDeclaration); + node.flags |= flags; + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); + node.name = name; + node.body = body; + return node; + } + + export function updateModuleDeclaration(node: ModuleDeclaration, decorators: Decorator[], modifiers: Modifier[], name: ModuleName, body: ModuleBody) { + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.name !== name + || node.body !== body + ? updateNode(createModuleDeclaration(decorators, modifiers, name, body, node.flags), node) + : node; + } + + export function createModuleBlock(statements: Statement[]) { + const node = createSynthesizedNode(SyntaxKind.CaseBlock); + node.statements = createNodeArray(statements); + return node; + } + + export function updateModuleBlock(node: ModuleBlock, statements: Statement[]) { + return node.statements !== statements + ? updateNode(createModuleBlock(statements), node) + : node; + } + + export function createCaseBlock(clauses: CaseOrDefaultClause[]): CaseBlock { + const node = createSynthesizedNode(SyntaxKind.CaseBlock); + node.clauses = createNodeArray(clauses); + return node; + } + + export function updateCaseBlock(node: CaseBlock, clauses: CaseOrDefaultClause[]) { + return node.clauses !== clauses + ? updateNode(createCaseBlock(clauses), node) + : node; + } + + export function createImportEqualsDeclaration(decorators: Decorator[], modifiers: Modifier[], name: string | Identifier, moduleReference: ModuleReference) { + const node = createSynthesizedNode(SyntaxKind.ImportEqualsDeclaration); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); + node.name = asName(name); + node.moduleReference = moduleReference; + return node; + } + + export function updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: Decorator[], modifiers: Modifier[], name: Identifier, moduleReference: ModuleReference) { + return node.decorators !== decorators + || node.modifiers !== modifiers + || node.name !== name + || node.moduleReference !== moduleReference + ? updateNode(createImportEqualsDeclaration(decorators, modifiers, name, moduleReference), node) + : node; + } + export function createImportDeclaration(decorators: Decorator[], modifiers: Modifier[], importClause: ImportClause, moduleSpecifier?: Expression): ImportDeclaration { const node = createSynthesizedNode(SyntaxKind.ImportDeclaration); node.decorators = asNodeArray(decorators); @@ -1228,6 +1349,20 @@ namespace ts { : node; } + // Module references + + export function createExternalModuleReference(expression: Expression) { + const node = createSynthesizedNode(SyntaxKind.ExternalModuleReference); + node.expression = expression; + return node; + } + + export function updateExternalModuleReference(node: ExternalModuleReference, expression: Expression) { + return node.expression !== expression + ? updateNode(createExternalModuleReference(expression), node) + : node; + } + // JSX export function createJsxElement(openingElement: JsxOpeningElement, children: JsxChild[], closingElement: JsxClosingElement) { @@ -1426,6 +1561,22 @@ namespace ts { return node; } + // Enum + + export function createEnumMember(name: string | PropertyName, initializer?: Expression) { + const node = createSynthesizedNode(SyntaxKind.EnumMember); + node.name = asName(name); + node.initializer = initializer && parenthesizeExpressionForList(initializer); + return node; + } + + export function updateEnumMember(node: EnumMember, name: PropertyName, initializer: Expression | undefined) { + return node.name !== name + || node.initializer !== initializer + ? updateNode(createEnumMember(name, initializer), node) + : node; + } + // Top-level nodes export function updateSourceFileNode(node: SourceFile, statements: Statement[]) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ae678f429f133..49e744682bc1d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1771,24 +1771,28 @@ members: NodeArray; } - export type ModuleBody = ModuleBlock | ModuleDeclaration; - export type ModuleName = Identifier | StringLiteral; + export type ModuleBody = NamespaceBody | JSDocNamespaceBody; + export interface ModuleDeclaration extends DeclarationStatement { kind: SyntaxKind.ModuleDeclaration; name: Identifier | StringLiteral; - body?: ModuleBlock | NamespaceDeclaration | JSDocNamespaceDeclaration | Identifier; + body?: ModuleBody | JSDocNamespaceDeclaration | Identifier; } + export type NamespaceBody = ModuleBlock | NamespaceDeclaration; + export interface NamespaceDeclaration extends ModuleDeclaration { name: Identifier; - body: ModuleBlock | NamespaceDeclaration; + body: NamespaceBody; } + export type JSDocNamespaceBody = Identifier | JSDocNamespaceDeclaration; + export interface JSDocNamespaceDeclaration extends ModuleDeclaration { name: Identifier; - body: JSDocNamespaceDeclaration | Identifier; + body: JSDocNamespaceBody; } export interface ModuleBlock extends Node, Statement { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 66efce4fef84a..91cd6a89b8b82 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3887,6 +3887,19 @@ namespace ts { export function isModuleBody(node: Node): node is ModuleBody { const kind = node.kind; return kind === SyntaxKind.ModuleBlock + || kind === SyntaxKind.ModuleDeclaration + || kind === SyntaxKind.Identifier; + } + + export function isNamespaceBody(node: Node): node is NamespaceBody { + const kind = node.kind; + return kind === SyntaxKind.ModuleBlock + || kind === SyntaxKind.ModuleDeclaration; + } + + export function isJSDocNamespaceBody(node: Node): node is JSDocNamespaceBody { + const kind = node.kind; + return kind === SyntaxKind.Identifier || kind === SyntaxKind.ModuleDeclaration; } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index b6e0adc129417..63c3726fc103a 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -6,97 +6,6 @@ namespace ts { export type VisitResult = T | T[]; - /** - * Describes an edge of a Node, used when traversing a syntax tree. - */ - interface NodeEdge { - /** The property name for the edge. */ - name: string; - - /** Indicates that the result is optional. */ - optional?: boolean; - - /** A callback used to test whether a node is valid. */ - test?: (node: Node) => node is Node; - - /** A callback used to lift a NodeArrayNode into a valid node. */ - lift?: (nodes: NodeArray) => Node; - - /** A callback used to parenthesize a node to preserve the intended order of operations. */ - parenthesize?: (value: Node, parentNode: Node) => Node; - }; - - /** - * Describes the shape of a Node. - */ - type NodeTraversalPath = NodeEdge[]; - - /** - * This map contains information about the shape of each Node in "types.ts" pertaining to how - * each node should be traversed during a transformation. - * - * Each edge corresponds to a property in a Node subtype that should be traversed when visiting - * each child. The properties are assigned in the order in which traversal should occur. - * - * We only add entries for nodes that do not have a create/update pair defined in factory.ts - * - * NOTE: This needs to be kept up to date with changes to nodes in "types.ts". Currently, this - * map is not comprehensive. Only node edges relevant to tree transformation are - * currently defined. We may extend this to be more comprehensive, and eventually - * supplant the existing `forEachChild` implementation if performance is not - * significantly impacted. - */ - function getNodeEdgeTraversal(kind: SyntaxKind): NodeTraversalPath { - switch (kind) { - case SyntaxKind.QualifiedName: return [ - { name: "left", test: isEntityName }, - { name: "right", test: isIdentifier } - ]; - case SyntaxKind.Decorator: return [ - { name: "expression", test: isLeftHandSideExpression } - ]; - case SyntaxKind.TypeAssertionExpression: return [ - { name: "type", test: isTypeNode }, - { name: "expression", test: isUnaryExpression } - ]; - case SyntaxKind.AsExpression: return [ - { name: "expression", test: isExpression }, - { name: "type", test: isTypeNode } - ]; - case SyntaxKind.NonNullExpression: return [ - { name: "expression", test: isLeftHandSideExpression } - ]; - case SyntaxKind.EnumDeclaration: return [ - { name: "decorators", test: isDecorator }, - { name: "modifiers", test: isModifier }, - { name: "name", test: isIdentifier }, - { name: "members", test: isEnumMember } - ]; - case SyntaxKind.ModuleDeclaration: return [ - { name: "decorators", test: isDecorator }, - { name: "modifiers", test: isModifier }, - { name: "name", test: isModuleName }, - { name: "body", test: isModuleBody } - ]; - case SyntaxKind.ModuleBlock: return [ - { name: "statements", test: isStatement } - ]; - case SyntaxKind.ImportEqualsDeclaration: return [ - { name: "decorators", test: isDecorator }, - { name: "modifiers", test: isModifier }, - { name: "name", test: isIdentifier }, - { name: "moduleReference", test: isModuleReference } - ]; - case SyntaxKind.ExternalModuleReference: return [ - { name: "expression", test: isExpression, optional: true } - ]; - case SyntaxKind.EnumMember: return [ - { name: "name", test: isPropertyName }, - { name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList } - ]; - } - } - function reduceNode(node: Node, f: (memo: T, node: Node) => T, initial: T) { return node ? f(initial, node) : initial; } @@ -107,8 +16,7 @@ namespace ts { /** * Similar to `reduceLeft`, performs a reduction against each child of a node. - * NOTE: Unlike `forEachChild`, this does *not* visit every node. Only nodes added to the - * `nodeEdgeTraversalMap` above will be visited. + * NOTE: Unlike `forEachChild`, this does *not* visit every node. * * @param node The node containing the children to reduce. * @param initial The initial value to supply to the reduction. @@ -145,6 +53,11 @@ namespace ts { break; // Names + case SyntaxKind.QualifiedName: + result = reduceNode((node).left, cbNode, result); + result = reduceNode((node).right, cbNode, result); + break; + case SyntaxKind.ComputedPropertyName: result = reduceNode((node).expression, cbNode, result); break; @@ -252,6 +165,11 @@ namespace ts { result = reduceNode((node).template, cbNode, result); break; + case SyntaxKind.TypeAssertionExpression: + result = reduceNode((node).type, cbNode, result); + result = reduceNode((node).expression, cbNode, result); + break; + case SyntaxKind.FunctionExpression: result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNode((node).name, cbNode, result); @@ -314,6 +232,15 @@ namespace ts { result = reduceNodes((node).typeArguments, cbNodes, result); break; + case SyntaxKind.AsExpression: + result = reduceNode((node).expression, cbNode, result); + result = reduceNode((node).type, cbNode, result); + break; + + case SyntaxKind.NonNullExpression: + result = reduceNode((node).expression, cbNode, result); + break; + // Misc case SyntaxKind.TemplateSpan: result = reduceNode((node).expression, cbNode, result); @@ -415,10 +342,35 @@ namespace ts { result = reduceNodes((node).members, cbNodes, result); break; + case SyntaxKind.EnumDeclaration: + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNodes((node).members, cbNodes, result); + break; + + case SyntaxKind.ModuleDeclaration: + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).body, cbNode, result); + break; + + case SyntaxKind.ModuleBlock: + result = reduceNodes((node).statements, cbNodes, result); + break; + case SyntaxKind.CaseBlock: result = reduceNodes((node).clauses, cbNodes, result); break; + case SyntaxKind.ImportEqualsDeclaration: + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).moduleReference, cbNode, result); + break; + case SyntaxKind.ImportDeclaration: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); @@ -459,6 +411,11 @@ namespace ts { result = reduceNode((node).moduleSpecifier, cbNode, result); break; + // Module references + case SyntaxKind.ExternalModuleReference: + result = reduceNode((node).expression, cbNode, result); + break; + // JSX case SyntaxKind.JsxElement: result = reduceNode((node).openingElement, cbNode, result); @@ -519,30 +476,25 @@ namespace ts { break; case SyntaxKind.SpreadAssignment: - result = reduceNode((node as SpreadAssignment).expression, cbNode, result); + result = reduceNode((node).expression, cbNode, result); break; + // Enum + case SyntaxKind.EnumMember: + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).initializer, cbNode, result); + // Top-level nodes case SyntaxKind.SourceFile: result = reduceNodes((node).statements, cbNodes, result); break; + // Transformation nodes case SyntaxKind.PartiallyEmittedExpression: result = reduceNode((node).expression, cbNode, result); break; default: - const edgeTraversalPath = getNodeEdgeTraversal(kind); - if (edgeTraversalPath) { - for (const edge of edgeTraversalPath) { - const value = (>node)[edge.name]; - if (value !== undefined) { - result = isArray(value) - ? reduceNodes(>value, cbNodes, result) - : cbNode(result, value); - } - } - } break; } @@ -556,11 +508,9 @@ namespace ts { * @param visitor The callback used to visit the Node. * @param test A callback to execute to verify the Node is valid. * @param optional An optional value indicating whether the Node is itself optional. - * @param lift An optional callback to execute to lift a NodeArrayNode into a valid Node. + * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ - export function visitNode(node: T, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray) => T): T; - export function visitNode(node: T, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, optional: boolean, lift: (node: NodeArray) => T, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node): T; - export function visitNode(node: Node, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, optional?: boolean, lift?: (node: Node[]) => Node, parenthesize?: (node: Node, parentNode: Node) => Node, parentNode?: Node): Node { + export function visitNode(node: T, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray) => T): T { if (node === undefined || visitor === undefined) { return node; } @@ -586,13 +536,9 @@ namespace ts { visitedNode = visited; } - if (parenthesize !== undefined) { - visitedNode = parenthesize(visitedNode, parentNode); - } - Debug.assertNode(visitedNode, test); aggregateTransformFlags(visitedNode); - return visitedNode; + return visitedNode; } /** @@ -604,14 +550,12 @@ namespace ts { * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ - export function visitNodes(nodes: NodeArray, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, start?: number, count?: number): NodeArray; - export function visitNodes(nodes: NodeArray, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, start: number, count: number, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node): NodeArray; - export function visitNodes(nodes: NodeArray, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, start?: number, count?: number, parenthesize?: (node: Node, parentNode: Node) => Node, parentNode?: Node): NodeArray { + export function visitNodes(nodes: NodeArray, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, start?: number, count?: number): NodeArray { if (nodes === undefined) { return undefined; } - let updated: NodeArray; + let updated: NodeArray; // Ensure start and count have valid values const length = nodes.length; @@ -627,7 +571,7 @@ namespace ts { // If we are not visiting all of the original nodes, we must always create a new array. // Since this is a fragment of a node array, we do not copy over the previous location // and will only copy over `hasTrailingComma` if we are including the last element. - updated = createNodeArray([], /*hasTrailingComma*/ nodes.hasTrailingComma && start + count === length); + updated = createNodeArray([], /*hasTrailingComma*/ nodes.hasTrailingComma && start + count === length); } // Visit each original node. @@ -644,21 +588,15 @@ namespace ts { if (visited) { if (isArray(visited)) { for (let visitedNode of visited) { - visitedNode = parenthesize - ? parenthesize(visitedNode, parentNode) - : visitedNode; Debug.assertNode(visitedNode, test); aggregateTransformFlags(visitedNode); - updated.push(visitedNode); + updated.push(visitedNode); } } else { - const visitedNode = parenthesize - ? parenthesize(visited, parentNode) - : visited; - Debug.assertNode(visitedNode, test); - aggregateTransformFlags(visitedNode); - updated.push(visitedNode); + Debug.assertNode(visited, test); + aggregateTransformFlags(visited); + updated.push(visited); } } } @@ -747,6 +685,11 @@ namespace ts { return node; // Names + case SyntaxKind.QualifiedName: + return updateQualifiedName(node, + visitNode((node).left, visitor, isEntityName), + visitNode((node).right, visitor, isIdentifier)); + case SyntaxKind.ComputedPropertyName: return updateComputedPropertyName(node, visitNode((node).expression, visitor, isExpression)); @@ -761,6 +704,10 @@ namespace ts { visitNode((node).type, visitor, isTypeNode, /*optional*/ true), visitNode((node).initializer, visitor, isExpression, /*optional*/ true)); + case SyntaxKind.Decorator: + return updateDecorator(node, + visitNode((node).expression, visitor, isExpression)); + // Type member case SyntaxKind.PropertyDeclaration: return updateProperty(node, @@ -856,6 +803,11 @@ namespace ts { visitNode((node).tag, visitor, isExpression), visitNode((node).template, visitor, isTemplateLiteral)); + case SyntaxKind.TypeAssertionExpression: + return updateTypeAssertion(node, + visitNode((node).type, visitor, isTypeNode), + visitNode((node).expression, visitor, isExpression)); + case SyntaxKind.ParenthesizedExpression: return updateParen(node, visitNode((node).expression, visitor, isExpression)); @@ -938,6 +890,15 @@ namespace ts { visitNodes((node).typeArguments, visitor, isTypeNode), visitNode((node).expression, visitor, isExpression)); + case SyntaxKind.AsExpression: + return updateAsExpression(node, + visitNode((node).expression, visitor, isExpression), + visitNode((node).type, visitor, isTypeNode)); + + case SyntaxKind.NonNullExpression: + return updateNonNullExpression(node, + visitNode((node).expression, visitor, isExpression)); + // Misc case SyntaxKind.TemplateSpan: return updateTemplateSpan(node, @@ -1059,10 +1020,35 @@ namespace ts { visitNodes((node).heritageClauses, visitor, isHeritageClause), visitNodes((node).members, visitor, isClassElement)); + case SyntaxKind.EnumDeclaration: + return updateEnumDeclaration(node, + visitNodes((node).decorators, visitor, isDecorator), + visitNodes((node).modifiers, visitor, isModifier), + visitNode((node).name, visitor, isIdentifier), + visitNodes((node).members, visitor, isEnumMember)); + + case SyntaxKind.ModuleDeclaration: + return updateModuleDeclaration(node, + visitNodes((node).decorators, visitor, isDecorator), + visitNodes((node).modifiers, visitor, isModifier), + visitNode((node).name, visitor, isIdentifier), + visitNode((node).body, visitor, isModuleBody)); + + case SyntaxKind.ModuleBlock: + return updateModuleBlock(node, + visitNodes((node).statements, visitor, isStatement)); + case SyntaxKind.CaseBlock: return updateCaseBlock(node, visitNodes((node).clauses, visitor, isCaseOrDefaultClause)); + case SyntaxKind.ImportEqualsDeclaration: + return updateImportEqualsDeclaration(node, + visitNodes((node).decorators, visitor, isDecorator), + visitNodes((node).modifiers, visitor, isModifier), + visitNode((node).name, visitor, isIdentifier), + visitNode((node).moduleReference, visitor, isModuleReference)); + case SyntaxKind.ImportDeclaration: return updateImportDeclaration(node, visitNodes((node).decorators, visitor, isDecorator), @@ -1110,6 +1096,11 @@ namespace ts { visitNode((node).propertyName, visitor, isIdentifier, /*optional*/ true), visitNode((node).name, visitor, isIdentifier)); + // Module references + case SyntaxKind.ExternalModuleReference: + return updateExternalModuleReference(node, + visitNode((node).expression, visitor, isExpression)); + // JSX case SyntaxKind.JsxElement: return updateJsxElement(node, @@ -1175,10 +1166,16 @@ namespace ts { visitNode((node).objectAssignmentInitializer, visitor, isExpression)); case SyntaxKind.SpreadAssignment: - return updateSpreadAssignment(node as SpreadAssignment, - visitNode((node as SpreadAssignment).expression, visitor, isExpression)); + return updateSpreadAssignment(node, + visitNode((node).expression, visitor, isExpression)); - // Top-level nodes + // Enum + case SyntaxKind.EnumMember: + return updateEnumMember(node, + visitNode((node).name, visitor, isPropertyName), + visitNode((node).initializer, visitor, isExpression, /*optional*/ true)); + + // Top-level nodes case SyntaxKind.SourceFile: return updateSourceFileNode(node, visitLexicalEnvironment((node).statements, visitor, context)); @@ -1189,30 +1186,8 @@ namespace ts { visitNode((node).expression, visitor, isExpression)); default: - let updated: Node & MapLike; - const edgeTraversalPath = getNodeEdgeTraversal(kind); - if (edgeTraversalPath) { - for (const edge of edgeTraversalPath) { - const value = >(>node)[edge.name]; - if (value !== undefined) { - const visited = isArray(value) - ? visitNodes(value, visitor, edge.test, 0, value.length, edge.parenthesize, node) - : visitNode(value, visitor, edge.test, edge.optional, edge.lift, edge.parenthesize, node); - if (updated !== undefined || visited !== value) { - if (updated === undefined) { - updated = getMutableClone(node); - } - if (visited !== value) { - updated[edge.name] = visited; - } - } - } - } - } - return updated ? updateNode(updated, node) : node; + return node; } - - // return node; } /** From 9a65a6642315d014c8a132a068f80ceaf71b7ac7 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Sat, 4 Feb 2017 22:46:38 -0800 Subject: [PATCH 5/6] Fix linter error --- src/compiler/visitor.ts | 2 +- src/services/transform.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/services/transform.ts diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 63c3726fc103a..fd2b0314dda74 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -587,7 +587,7 @@ namespace ts { } if (visited) { if (isArray(visited)) { - for (let visitedNode of visited) { + for (const visitedNode of visited) { Debug.assertNode(visitedNode, test); aggregateTransformFlags(visitedNode); updated.push(visitedNode); diff --git a/src/services/transform.ts b/src/services/transform.ts new file mode 100644 index 0000000000000..c9107eea8534d --- /dev/null +++ b/src/services/transform.ts @@ -0,0 +1,29 @@ +/// +/// +namespace ts { + /** + * Transform one or more source files using the supplied transformers. + * @param source A `SourceFile` or an array of `SourceFiles`. + * @param transformers An array of `Transformer` callbacks used to process the transformation. + */ + export function transform(source: SourceFile | SourceFile[], transformers: Transformer[]) { + const diagnostics: Diagnostic[] = []; + const compilerOptions: CompilerOptions = {}; + const sourceFiles = isArray(source) ? source : [source]; + const fileMap = arrayToMap(sourceFiles, sourceFile => sourceFile.fileName); + const emitHost: EmitHost = { + getCompilerOptions: () => compilerOptions, + getCanonicalFileName: fileName => fileName, + getCommonSourceDirectory: () => "", + getCurrentDirectory: () => "", + getNewLine: () => "\n", + getSourceFile: fileName => fileMap.get(fileName), + getSourceFileByPath: fileName => fileMap.get(fileName), + getSourceFiles: () => sourceFiles, + isSourceFileFromExternalLibrary: () => false, + isEmitBlocked: () => false, + writeFile: () => Debug.fail("'writeFile()' is not supported during transformation.") + }; + return transformFiles(/*resolver*/ undefined, emitHost, sourceFiles, transformers); + } +} \ No newline at end of file From eedc2619dbf343dd9e269eb75afb026e6464f449 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 6 Feb 2017 15:28:54 -0800 Subject: [PATCH 6/6] Minor PR feedback --- src/compiler/factory.ts | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 4c7693dd846f0..d5d8482a0babd 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1766,8 +1766,6 @@ namespace ts { // Utilities - function asName(name: string): Identifier; - function asName(name: Identifier): Identifier; function asName(name: string | Identifier): Identifier; function asName(name: string | BindingName): BindingName; function asName(name: string | PropertyName): PropertyName; @@ -1811,8 +1809,6 @@ namespace ts { /** * Associates a node with the current transformation, initializing * various transient transformation properties. - * - * @param node The node. */ /* @internal */ export function getOrCreateEmitNode(node: Node) { @@ -1845,8 +1841,6 @@ namespace ts { /** * Gets flags that control emit behavior of a node. - * - * @param node The node. */ export function getEmitFlags(node: Node) { const emitNode = node.emitNode; @@ -1855,9 +1849,6 @@ namespace ts { /** * Sets flags that control emit behavior of a node. - * - * @param node The node. - * @param emitFlags The NodeEmitFlags for the node. */ export function setEmitFlags(node: T, emitFlags: EmitFlags) { getOrCreateEmitNode(node).flags = emitFlags; @@ -1866,8 +1857,6 @@ namespace ts { /** * Gets a custom text range to use when emitting source maps. - * - * @param node The node. */ export function getSourceMapRange(node: Node) { const emitNode = node.emitNode; @@ -1876,9 +1865,6 @@ namespace ts { /** * Sets a custom text range to use when emitting source maps. - * - * @param node The node. - * @param range The text range. */ export function setSourceMapRange(node: T, range: TextRange) { getOrCreateEmitNode(node).sourceMapRange = range; @@ -1887,9 +1873,6 @@ namespace ts { /** * Gets the TextRange to use for source maps for a token of a node. - * - * @param node The node. - * @param token The token. */ export function getTokenSourceMapRange(node: Node, token: SyntaxKind) { const emitNode = node.emitNode; @@ -1899,10 +1882,6 @@ namespace ts { /** * Sets the TextRange to use for source maps for a token of a node. - * - * @param node The node. - * @param token The token. - * @param range The text range. */ export function setTokenSourceMapRange(node: T, token: SyntaxKind, range: TextRange) { const emitNode = getOrCreateEmitNode(node); @@ -1913,8 +1892,6 @@ namespace ts { /** * Gets a custom text range to use when emitting comments. - * - * @param node The node. */ export function getCommentRange(node: Node) { const emitNode = node.emitNode;