From d11916765333cca50952f315de130ea9cc5add66 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 20 Jul 2016 17:36:18 -0700 Subject: [PATCH] Add more commonly used nodes, reduce less frequently used nodes. --- src/compiler/factory.ts | 331 ++++++++++---- src/compiler/transformers/es6.ts | 72 +-- src/compiler/transformers/generators.ts | 14 +- src/compiler/transformers/module/es6.ts | 12 +- src/compiler/transformers/module/system.ts | 40 +- src/compiler/transformers/ts.ts | 64 ++- src/compiler/utilities.ts | 7 + src/compiler/visitor.ts | 509 +++++++++++---------- 8 files changed, 646 insertions(+), 403 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 41a87955207..13ca26c7835 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -210,20 +210,6 @@ namespace ts { // Names - export function createQualifiedName(left: EntityName, right: Identifier, location?: TextRange) { - const node = createNode(SyntaxKind.QualifiedName, location); - node.left = left; - node.right = right; - return node; - } - - export function updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier) { - if (node.left !== left || node.right !== right) { - return updateNode(createQualifiedName(left, right, node), node); - } - return node; - } - export function createComputedPropertyName(expression: Expression, location?: TextRange) { const node = createNode(SyntaxKind.ComputedPropertyName, location); node.expression = expression; @@ -272,19 +258,6 @@ namespace ts { return node; } - export function createDecorator(expression: LeftHandSideExpression, location?: TextRange) { - const node = createNode(SyntaxKind.Decorator, location); - node.expression = expression; - return node; - } - - export function updateDecorator(node: Decorator, expression: LeftHandSideExpression) { - if (node.expression !== expression) { - return updateNode(createDecorator(expression, node), node); - } - return node; - } - // Type members export function createProperty(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, questionToken: Node, type: TypeNode, initializer: Expression, location?: TextRange) { @@ -506,7 +479,6 @@ namespace ts { if (expression !== node.expression || typeArguments !== node.typeArguments || argumentsArray !== node.arguments) { return updateNode(createCall(expression, typeArguments, argumentsArray, /*location*/ node, node.flags), node); } - return node; } @@ -628,6 +600,19 @@ namespace ts { return node; } + export function createAwait(expression: Expression, location?: TextRange) { + const node = createNode(SyntaxKind.AwaitExpression, location); + 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; + } + export function createPrefix(operator: SyntaxKind, operand: Expression, location?: TextRange) { const node = createNode(SyntaxKind.PrefixUnaryExpression, location); node.operator = operator; @@ -768,6 +753,7 @@ namespace ts { return node; } + // Misc export function createTemplateSpan(expression: Expression, literal: TemplateLiteralFragment, location?: TextRange) { @@ -831,14 +817,6 @@ namespace ts { return node; } - 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); - } - 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; @@ -997,22 +975,6 @@ namespace ts { return node; } - export function createTryCatchFinally(tryBlock: Block, catchClause: CatchClause, finallyBlock: Block, location?: TextRange) { - const node = createNode(SyntaxKind.TryStatement, location); - node.tryBlock = tryBlock; - node.catchClause = catchClause; - node.finallyBlock = finallyBlock; - return node; - } - - export function createTryCatch(tryBlock: Block, catchClause: CatchClause, location?: TextRange) { - return createTryCatchFinally(tryBlock, catchClause, /*finallyBlock*/ undefined, location); - } - - export function createTryFinally(tryBlock: Block, finallyBlock: Block, location?: TextRange) { - return createTryCatchFinally(tryBlock, /*catchClause*/ undefined, finallyBlock, location); - } - export function updateReturn(node: ReturnStatement, expression: Expression) { if (node.expression !== expression) { return updateNode(createReturn(expression, /*location*/ node), node); @@ -1075,6 +1037,21 @@ namespace ts { return node; } + export function createTry(tryBlock: Block, catchClause: CatchClause, finallyBlock: Block, location?: TextRange) { + const node = createNode(SyntaxKind.TryStatement, location); + node.tryBlock = tryBlock; + node.catchClause = catchClause; + node.finallyBlock = finallyBlock; + return node; + } + + 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; + } + export function createCaseBlock(clauses: CaseOrDefaultClause[], location?: TextRange): CaseBlock { const node = createNode(SyntaxKind.CaseBlock, location); node.clauses = createNodeArray(clauses); @@ -1126,30 +1103,104 @@ namespace ts { return node; } - export function createExportAssignment(isExportEquals: boolean, expression: Expression, location?: TextRange) { + 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; + 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; + } + + export function createImportClause(name: Identifier, namedBindings: NamedImportBindings, location?: TextRange): ImportClause { + const node = createNode(SyntaxKind.ImportClause, location); + 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; + } + + export function createNamespaceImport(name: Identifier, location?: TextRange): NamespaceImport { + const node = createNode(SyntaxKind.NamespaceImport, location); + node.name = name; + return node; + } + + export function updateNamespaceImport(node: NamespaceImport, name: Identifier) { + if (node.name !== name) { + return updateNode(createNamespaceImport(name, node), node); + } + return node; + } + + export function createNamedImports(elements: ImportSpecifier[], location?: TextRange): NamedImports { + const node = createNode(SyntaxKind.NamedImports, location); + 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; + } + + export function createImportSpecifier(propertyName: Identifier, name: Identifier, location?: TextRange) { + const node = createNode(SyntaxKind.ImportSpecifier, location); + 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; + } + + 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; node.isExportEquals = isExportEquals; node.expression = expression; return node; } - export function updateExportAssignment(node: ExportAssignment, expression: Expression) { - if (node.expression !== expression) { - return updateNode(createExportAssignment(node.isExportEquals, expression, node), 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; } - export function createExportDeclaration(exportClause: NamedExports, moduleSpecifier?: Expression, location?: TextRange) { + 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; node.exportClause = exportClause; node.moduleSpecifier = moduleSpecifier; return node; } - export function updateExportDeclaration(node: ExportDeclaration, exportClause: NamedExports, moduleSpecifier: Expression) { - if (node.exportClause !== exportClause || node.moduleSpecifier !== moduleSpecifier) { - return updateNode(createExportDeclaration(exportClause, moduleSpecifier, node), 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; } @@ -1181,6 +1232,104 @@ namespace ts { return node; } + // JSX + + export function createJsxElement(openingElement: JsxOpeningElement, children: JsxChild[], closingElement: JsxClosingElement, location?: TextRange) { + const node = createNode(SyntaxKind.JsxElement, location); + node.openingElement = openingElement; + node.children = createNodeArray(children); + node.closingElement = closingElement; + return node; + } + + 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; + } + + export function createJsxSelfClosingElement(tagName: JsxTagNameExpression, attributes: JsxAttributeLike[], location?: TextRange) { + const node = createNode(SyntaxKind.JsxSelfClosingElement, location); + 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; + } + + export function createJsxOpeningElement(tagName: JsxTagNameExpression, attributes: JsxAttributeLike[], location?: TextRange) { + const node = createNode(SyntaxKind.JsxOpeningElement, location); + 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; + } + + export function createJsxClosingElement(tagName: JsxTagNameExpression, location?: TextRange) { + const node = createNode(SyntaxKind.JsxClosingElement, location); + node.tagName = tagName; + return node; + } + + export function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression) { + if (node.tagName !== tagName) { + return updateNode(createJsxClosingElement(tagName, node), node); + } + return node; + } + + export function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression, location?: TextRange) { + const node = createNode(SyntaxKind.JsxAttribute, location); + 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; + } + + export function createJsxSpreadAttribute(expression: Expression, location?: TextRange) { + const node = createNode(SyntaxKind.JsxSpreadAttribute, location); + node.expression = expression; + return node; + } + + export function updateJsxSpreadAttribute(node: JsxSpreadAttribute, expression: Expression) { + if (node.expression !== expression) { + return updateNode(createJsxSpreadAttribute(expression, node), node); + } + return node; + } + + export function createJsxExpression(expression: Expression, location?: TextRange) { + const node = createNode(SyntaxKind.JsxExpression, location); + node.expression = expression; + return node; + } + + export function updateJsxExpression(node: JsxExpression, expression: Expression) { + if (node.expression !== expression) { + return updateNode(createJsxExpression(expression, node), node); + } + return node; + } + // Clauses export function createHeritageClause(token: SyntaxKind, types: ExpressionWithTypeArguments[], location?: TextRange) { @@ -1224,6 +1373,20 @@ namespace ts { return node; } + export function createCatchClause(variableDeclaration: string | VariableDeclaration, block: Block, location?: TextRange) { + const node = createNode(SyntaxKind.CatchClause, location); + node.variableDeclaration = typeof variableDeclaration === "string" ? createVariableDeclaration(variableDeclaration) : variableDeclaration; + node.block = block; + return node; + } + + export function updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration, block: Block) { + if (node.variableDeclaration !== variableDeclaration || node.block !== block) { + return updateNode(createCatchClause(variableDeclaration, block, node), node); + } + return node; + } + // Property assignments export function createPropertyAssignment(name: string | PropertyName, initializer: Expression, location?: TextRange) { @@ -1382,32 +1545,6 @@ namespace ts { return createVoid(createLiteral(0)); } - export function createImportDeclaration(importClause: ImportClause, moduleSpecifier?: Expression, location?: TextRange): ImportDeclaration { - const node = createNode(SyntaxKind.ImportDeclaration, location); - node.importClause = importClause; - node.moduleSpecifier = moduleSpecifier; - return node; - } - - export function createImportClause(name: Identifier, namedBindings: NamedImportBindings, location?: TextRange): ImportClause { - const node = createNode(SyntaxKind.ImportClause, location); - node.name = name; - node.namedBindings = namedBindings; - return node; - } - - export function createNamespaceImport(name: Identifier): NamespaceImport { - const node = createNode(SyntaxKind.NamespaceImport); - node.name = name; - return node; - } - - export function createNamedImports(elements: NodeArray, location?: TextRange): NamedImports { - const node = createNode(SyntaxKind.NamedImports, location); - node.elements = elements; - return node; - } - export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, location?: TextRange): MemberExpression { if (isComputedPropertyName(memberName)) { return createElementAccess(target, memberName.expression, location); @@ -1502,7 +1639,15 @@ namespace ts { argumentsList.push(createNull()); } - addNodes(argumentsList, children, /*startOnNewLine*/ children.length > 1); + if (children.length > 1) { + for (const child of children) { + child.startsOnNewLine = true; + argumentsList.push(child); + } + } + else { + argumentsList.push(children[0]); + } } return createCall( @@ -1516,6 +1661,14 @@ namespace ts { ); } + 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 createHelperName(externalHelpersModuleName: Identifier | undefined, name: string) { @@ -2482,8 +2635,8 @@ namespace ts { return node; } - export function startOnNewLine(node: T): T { - node.startsOnNewLine = true; + export function startOnNewLine(node: T, startsOnNewLine?: boolean): T { + node.startsOnNewLine = startsOnNewLine !== false; return node; } diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts index 7deaa38d148..a347282afa0 100644 --- a/src/compiler/transformers/es6.ts +++ b/src/compiler/transformers/es6.ts @@ -1196,7 +1196,7 @@ namespace ts { */ function transformAccessorsToStatement(receiver: LeftHandSideExpression, accessors: AllAccessorDeclarations): Statement { const statement = createStatement( - transformAccessorsToExpression(receiver, accessors), + transformAccessorsToExpression(receiver, accessors, /*startsOnNewLine*/ false), /*location*/ getSourceMapRange(accessors.firstAccessor) ); @@ -1213,7 +1213,7 @@ namespace ts { * * @param receiver The receiver for the member. */ - function transformAccessorsToExpression(receiver: LeftHandSideExpression, { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations): Expression { + function transformAccessorsToExpression(receiver: LeftHandSideExpression, { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations, startsOnNewLine: boolean): Expression { // To align with source maps in the old emitter, the receiver and property name // arguments are both mapped contiguously to the accessor name. const target = getMutableClone(receiver); @@ -1246,7 +1246,7 @@ namespace ts { createPropertyAssignment("configurable", createLiteral(true)) ); - return createCall( + const call = createCall( createPropertyAccess(createIdentifier("Object"), "defineProperty"), /*typeArguments*/ undefined, [ @@ -1255,6 +1255,10 @@ namespace ts { createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true) ] ); + if (startsOnNewLine) { + call.startsOnNewLine = true; + } + return call; } /** @@ -1895,26 +1899,28 @@ namespace ts { // Write out the first non-computed properties, then emit the rest through indexing on the temp variable. const expressions: Expression[] = []; - addNode(expressions, - createAssignment( - temp, - setNodeEmitFlags( - createObjectLiteral( - visitNodes(properties, visitor, isObjectLiteralElement, 0, numInitialProperties), - /*location*/ undefined, - node.multiLine - ), - NodeEmitFlags.Indented - ) - ), - node.multiLine + expressions.push( + startOnNewLine( + createAssignment( + temp, + setNodeEmitFlags( + createObjectLiteral( + visitNodes(properties, visitor, isObjectLiteralElement, 0, numInitialProperties), + /*location*/ undefined, + node.multiLine + ), + NodeEmitFlags.Indented + ) + ), + node.multiLine + ) ); addObjectLiteralMembers(expressions, node, temp, numInitialProperties); // We need to clone the temporary identifier so that we can write it on a // new line - addNode(expressions, getMutableClone(temp), node.multiLine); + expressions.push(startOnNewLine(getMutableClone(temp), node.multiLine)); return inlineExpressions(expressions); } @@ -2313,21 +2319,21 @@ namespace ts { case SyntaxKind.SetAccessor: const accessors = getAllAccessorDeclarations(node.properties, property); if (property === accessors.firstAccessor) { - addNode(expressions, transformAccessorsToExpression(receiver, accessors), node.multiLine); + expressions.push(transformAccessorsToExpression(receiver, accessors, node.multiLine)); } break; case SyntaxKind.PropertyAssignment: - addNode(expressions, transformPropertyAssignmentToExpression(node, property, receiver), node.multiLine); + expressions.push(transformPropertyAssignmentToExpression(node, property, receiver, node.multiLine)); break; case SyntaxKind.ShorthandPropertyAssignment: - addNode(expressions, transformShorthandPropertyAssignmentToExpression(node, property, receiver), node.multiLine); + expressions.push(transformShorthandPropertyAssignmentToExpression(node, property, receiver, node.multiLine)); break; case SyntaxKind.MethodDeclaration: - addNode(expressions, transformObjectLiteralMethodDeclarationToExpression(node, property, receiver), node.multiLine); + expressions.push(transformObjectLiteralMethodDeclarationToExpression(node, property, receiver, node.multiLine)); break; default: @@ -2344,8 +2350,8 @@ namespace ts { * @param property The PropertyAssignment node. * @param receiver The receiver for the assignment. */ - function transformPropertyAssignmentToExpression(node: ObjectLiteralExpression, property: PropertyAssignment, receiver: Expression) { - return createAssignment( + function transformPropertyAssignmentToExpression(node: ObjectLiteralExpression, property: PropertyAssignment, receiver: Expression, startsOnNewLine: boolean) { + const expression = createAssignment( createMemberAccessForPropertyName( receiver, visitNode(property.name, visitor, isPropertyName) @@ -2353,6 +2359,10 @@ namespace ts { visitNode(property.initializer, visitor, isExpression), /*location*/ property ); + if (startsOnNewLine) { + expression.startsOnNewLine = true; + } + return expression; } /** @@ -2362,8 +2372,8 @@ namespace ts { * @param property The ShorthandPropertyAssignment node. * @param receiver The receiver for the assignment. */ - function transformShorthandPropertyAssignmentToExpression(node: ObjectLiteralExpression, property: ShorthandPropertyAssignment, receiver: Expression) { - return createAssignment( + function transformShorthandPropertyAssignmentToExpression(node: ObjectLiteralExpression, property: ShorthandPropertyAssignment, receiver: Expression, startsOnNewLine: boolean) { + const expression = createAssignment( createMemberAccessForPropertyName( receiver, visitNode(property.name, visitor, isPropertyName) @@ -2371,6 +2381,10 @@ namespace ts { getSynthesizedClone(property.name), /*location*/ property ); + if (startsOnNewLine) { + expression.startsOnNewLine = true; + } + return expression; } /** @@ -2380,8 +2394,8 @@ namespace ts { * @param method The MethodDeclaration node. * @param receiver The receiver for the assignment. */ - function transformObjectLiteralMethodDeclarationToExpression(node: ObjectLiteralExpression, method: MethodDeclaration, receiver: Expression) { - return createAssignment( + function transformObjectLiteralMethodDeclarationToExpression(node: ObjectLiteralExpression, method: MethodDeclaration, receiver: Expression, startsOnNewLine: boolean) { + const expression = createAssignment( createMemberAccessForPropertyName( receiver, visitNode(method.name, visitor, isPropertyName) @@ -2389,6 +2403,10 @@ namespace ts { transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined), /*location*/ method ); + if (startsOnNewLine) { + expression.startsOnNewLine = true; + } + return expression; } /** diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index f96aacdce45..d161eb907a4 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -580,8 +580,8 @@ namespace ts { transformAndEmitStatements(body.statements, statementOffset); const buildResult = build(); - addNodes(statements, endLexicalEnvironment()); - addNode(statements, createReturn(buildResult)); + addRange(statements, endLexicalEnvironment()); + statements.push(createReturn(buildResult)); // Restore previous generator state inGeneratorFunctionBody = savedInGeneratorFunctionBody; @@ -1019,7 +1019,7 @@ namespace ts { ); const expressions = reduceLeft(properties, reduceProperty, [], numInitialProperties); - addNode(expressions, getMutableClone(temp), multiLine); + expressions.push(multiLine ? startOnNewLine(getMutableClone(temp)) : temp); return inlineExpressions(expressions); function reduceProperty(expressions: Expression[], property: ObjectLiteralElement) { @@ -1029,7 +1029,13 @@ namespace ts { } const expression = createExpressionForObjectLiteralElement(node, property, temp); - addNode(expressions, visitNode(expression, visitor, isExpression), multiLine); + const visited = visitNode(expression, visitor, isExpression); + if (visited) { + if (multiLine) { + visited.startsOnNewLine = true; + } + expressions.push(visited); + } return expressions; } } diff --git a/src/compiler/transformers/module/es6.ts b/src/compiler/transformers/module/es6.ts index 5bf8a972aff..2716165f2d3 100644 --- a/src/compiler/transformers/module/es6.ts +++ b/src/compiler/transformers/module/es6.ts @@ -65,7 +65,11 @@ namespace ts { return node; } return newExportClause - ? createExportDeclaration(newExportClause, node.moduleSpecifier) + ? createExportDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + newExportClause, + node.moduleSpecifier) : undefined; } @@ -92,7 +96,11 @@ namespace ts { return undefined; } else if (newImportClause !== node.importClause) { - return createImportDeclaration(newImportClause, node.moduleSpecifier); + return createImportDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + newImportClause, + node.moduleSpecifier); } } return node; diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 851dd2dd62d..1f7897b760c 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -197,7 +197,7 @@ namespace ts { const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, visitSourceElement); // var __moduleName = context_1 && context_1.id; - addNode(statements, + statements.push( createVariableStatement( /*modifiers*/ undefined, createVariableDeclarationList([ @@ -226,14 +226,14 @@ namespace ts { // - Temporary variables will appear at the top rather than at the bottom of the file // - Calls to the exporter for exported function declarations are grouped after // the declarations. - addNodes(statements, endLexicalEnvironment()); + addRange(statements, endLexicalEnvironment()); // Emit early exports for function declarations. - addNodes(statements, exportedFunctionDeclarations); + addRange(statements, exportedFunctionDeclarations); const exportStarFunction = addExportStarIfNeeded(statements); - addNode(statements, + statements.push( createReturn( setMultiLine( createObjectLiteral([ @@ -292,7 +292,7 @@ namespace ts { if (exportedLocalNames) { for (const exportedLocalName of exportedLocalNames) { // write name of exported declaration, i.e 'export var x...' - addNode(exportedNames, + exportedNames.push( createPropertyAssignment( createLiteral(exportedLocalName.text), createLiteral(true) @@ -314,7 +314,7 @@ namespace ts { for (const element of exportDecl.exportClause.elements) { // write name of indirectly exported entry, i.e. 'export {x} from ...' - addNode(exportedNames, + exportedNames.push( createPropertyAssignment( createLiteral((element.name || element.propertyName).text), createLiteral(true) @@ -324,7 +324,7 @@ namespace ts { } const exportedNamesStorageRef = createUniqueName("exportedNames"); - addNode(statements, + statements.push( createVariableStatement( /*modifiers*/ undefined, createVariableDeclarationList([ @@ -365,7 +365,7 @@ namespace ts { case SyntaxKind.ImportEqualsDeclaration: Debug.assert(importVariableName !== undefined); // save import into the local - addNode(statements, + statements.push( createStatement( createAssignment(importVariableName, parameterName) ) @@ -396,7 +396,7 @@ namespace ts { ); } - addNode(statements, + statements.push( createStatement( createCall( exportFunctionForFile, @@ -412,7 +412,7 @@ namespace ts { // emit as: // // exportStar(foo_1_1); - addNode(statements, + statements.push( createStatement( createCall( exportStarFunction, @@ -426,7 +426,7 @@ namespace ts { } } - addNode(setters, + setters.push( createFunctionExpression( /*asteriskToken*/ undefined, /*name*/ undefined, @@ -563,7 +563,7 @@ namespace ts { function visitExportDeclaration(node: ExportDeclaration): VisitResult { if (!node.moduleSpecifier) { const statements: Statement[] = []; - addNodes(statements, map(node.exportClause.elements, visitExportSpecifier)); + addRange(statements, map(node.exportClause.elements, visitExportSpecifier)); return statements; } @@ -612,7 +612,10 @@ namespace ts { const isExported = hasModifier(node, ModifierFlags.Export); const expressions: Expression[] = []; for (const variable of node.declarationList.declarations) { - addNode(expressions, transformVariable(variable, isExported)); + const visited = transformVariable(variable, isExported); + if (visited) { + expressions.push(visited); + } } if (expressions.length) { @@ -715,7 +718,7 @@ namespace ts { const statements: Statement[] = []; // Rewrite the class declaration into an assignment of a class expression. - addNode(statements, + statements.push( createStatement( createAssignment( name, @@ -738,7 +741,7 @@ namespace ts { recordExportName(name); } - addNode(statements, createDeclarationExport(node)); + statements.push(createDeclarationExport(node)); } return statements; @@ -758,7 +761,10 @@ namespace ts { if (shouldHoistLoopInitializer(initializer)) { const expressions: Expression[] = []; for (const variable of (initializer).declarations) { - addNode(expressions, transformVariable(variable, /*isExported*/ false)); + const visited = transformVariable(variable, /*isExported*/ false); + if (visited) { + expressions.push(visited); + } }; return createFor( @@ -1209,7 +1215,7 @@ namespace ts { ); } - addNode(statements, + statements.push( createFunctionDeclaration( /*decorators*/ undefined, /*modifiers*/ undefined, diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 1b2fff3e7e5..ee69e5927c8 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -428,6 +428,8 @@ namespace ts { const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ false, visitor); const externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText); const externalHelpersModuleImport = createImportDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)), createLiteral(externalHelpersModuleNameText) ); @@ -550,7 +552,11 @@ namespace ts { } else if (isDecoratedClass) { if (isDefaultExternalModuleExport(node)) { - statements.push(createExportAssignment(/*isExportEquals*/ false, getLocalName(node))); + statements.push(createExportAssignment( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*isExportEquals*/ false, + getLocalName(node))); } else if (isNamedExternalModuleExport(node)) { statements.push(createExternalModuleExport(name)); @@ -688,7 +694,7 @@ namespace ts { // let ${name} = ${classExpression} where name is either declaredName if the class doesn't contain self-reference // or decoratedClassAlias if the class contain self-reference. - addNode(statements, + statements.push( setOriginalNode( createVariableStatement( /*modifiers*/ undefined, @@ -710,7 +716,7 @@ namespace ts { // TDZ as the class. // let ${declaredName} = ${decoratedClassAlias} - addNode(statements, + statements.push( setOriginalNode( createVariableStatement( /*modifiers*/ undefined, @@ -763,15 +769,15 @@ namespace ts { if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) { // record an alias as the class name is not in scope for statics. enableSubstitutionForClassAliases(); - classAliases[getOriginalNodeId(node)] = temp; + classAliases[getOriginalNodeId(node)] = getSynthesizedClone(temp); } // To preserve the behavior of the old emitter, we explicitly indent // the body of a class with static initializers. setNodeEmitFlags(classExpression, NodeEmitFlags.Indented | getNodeEmitFlags(classExpression)); - addNode(expressions, createAssignment(temp, classExpression), true); - addNodes(expressions, generateInitializedPropertyExpressions(node, staticProperties, temp), true); - addNode(expressions, temp, true); + expressions.push(startOnNewLine(createAssignment(temp, classExpression))); + addRange(expressions, generateInitializedPropertyExpressions(node, staticProperties, temp)); + expressions.push(startOnNewLine(temp)); return inlineExpressions(expressions); } @@ -786,8 +792,12 @@ namespace ts { */ function transformClassMembers(node: ClassDeclaration | ClassExpression, hasExtendsClause: boolean) { const members: ClassElement[] = []; - addNode(members, transformConstructor(node, hasExtendsClause)); - addNodes(members, visitNodes(node.members, classElementVisitor, isClassElement)); + const constructor = transformConstructor(node, hasExtendsClause); + if (constructor) { + members.push(constructor); + } + + addRange(members, visitNodes(node.members, classElementVisitor, isClassElement)); return createNodeArray(members, /*location*/ node.members); } @@ -876,7 +886,7 @@ namespace ts { // } // const propertyAssignments = getParametersWithPropertyAssignments(constructor); - addNodes(statements, map(propertyAssignments, transformParameterWithPropertyAssignment)); + addRange(statements, map(propertyAssignments, transformParameterWithPropertyAssignment)); } else if (hasExtendsClause) { Debug.assert(parameters.length === 1 && isIdentifier(parameters[0].name)); @@ -885,7 +895,7 @@ namespace ts { // // super(...args); // - addNode(statements, + statements.push( createStatement( createCall( createSuper(), @@ -911,11 +921,11 @@ namespace ts { if (constructor) { // The class already had a constructor, so we should add the existing statements, skipping the initial super call. - addNodes(statements, visitNodes(constructor.body.statements, visitor, isStatement, indexOfFirstStatement)); + addRange(statements, visitNodes(constructor.body.statements, visitor, isStatement, indexOfFirstStatement)); } // End the lexical environment. - addNodes(statements, endLexicalEnvironment()); + addRange(statements, endLexicalEnvironment()); return setMultiLine( createBlock( createNodeArray( @@ -1071,6 +1081,7 @@ namespace ts { const expressions: Expression[] = []; for (const property of properties) { const expression = transformInitializedProperty(node, property, receiver); + expression.startsOnNewLine = true; setSourceMapRange(expression, moveRangePastModifiers(property)); setCommentRange(expression, property); expressions.push(expression); @@ -1283,8 +1294,8 @@ namespace ts { } const decoratorExpressions: Expression[] = []; - addNodes(decoratorExpressions, map(allDecorators.decorators, transformDecorator)); - addNodes(decoratorExpressions, flatMap(allDecorators.parameters, transformDecoratorsOfParameter)); + addRange(decoratorExpressions, map(allDecorators.decorators, transformDecorator)); + addRange(decoratorExpressions, flatMap(allDecorators.parameters, transformDecoratorsOfParameter)); addTypeMetadata(node, decoratorExpressions); return decoratorExpressions; } @@ -2217,7 +2228,7 @@ namespace ts { startLexicalEnvironment(); const visited: Expression | Block = visitNode(body, visitor, isConciseBody); const declarations = endLexicalEnvironment(); - const merged = mergeConciseBodyLexicalEnvironment(visited, declarations); + const merged = mergeFunctionBodyLexicalEnvironment(visited, declarations); if (forceBlockFunctionBody && !isBlock(merged)) { return createBlock([ createReturn(merged) @@ -2556,8 +2567,8 @@ namespace ts { const statements: Statement[] = []; startLexicalEnvironment(); - addNodes(statements, map(node.members, transformEnumMember)); - addNodes(statements, endLexicalEnvironment()); + addRange(statements, map(node.members, transformEnumMember)); + addRange(statements, endLexicalEnvironment()); currentNamespaceContainerName = savedCurrentNamespaceLocalName; return createBlock( @@ -2794,17 +2805,26 @@ namespace ts { let blockLocation: TextRange; const body = node.body; if (body.kind === SyntaxKind.ModuleBlock) { - addNodes(statements, visitNodes((body).statements, namespaceElementVisitor, isStatement)); + addRange(statements, visitNodes((body).statements, namespaceElementVisitor, isStatement)); statementsLocation = (body).statements; blockLocation = body; } else { - addNode(statements, visitModuleDeclaration(body)); + const result = visitModuleDeclaration(body); + if (result) { + if (isArray(result)) { + addRange(statements, result); + } + else { + statements.push(result); + } + } + const moduleBlock = getInnerMostModuleDeclarationFromDottedModule(node).body; statementsLocation = moveRangePos(moduleBlock.statements, -1); } - addNodes(statements, endLexicalEnvironment()); + addRange(statements, endLexicalEnvironment()); currentNamespaceContainerName = savedCurrentNamespaceContainerName; currentNamespace = savedCurrentNamespace; @@ -2965,6 +2985,8 @@ namespace ts { function createExternalModuleExport(exportName: Identifier) { return createExportDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, createNamedExports([ createExportSpecifier(exportName) ]) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a8222d0ebc5..7ab126556ec 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4057,6 +4057,13 @@ namespace ts { return node.kind === SyntaxKind.JsxClosingElement; } + export function isJsxTagNameExpression(node: Node): node is JsxTagNameExpression { + const kind = node.kind; + return kind === SyntaxKind.ThisKeyword + || kind === SyntaxKind.Identifier + || kind === SyntaxKind.PropertyAccessExpression; + } + export function isJsxChild(node: Node): node is JsxChild { const kind = node.kind; return kind === SyntaxKind.JsxElement diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index b2a5a1742c8..70789e22455 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -38,6 +38,8 @@ namespace ts { * 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 @@ -45,13 +47,17 @@ namespace ts { * significantly impacted. */ const nodeEdgeTraversalMap: Map = { + [SyntaxKind.QualifiedName]: [ + { name: "left", test: isEntityName }, + { name: "right", test: isIdentifier } + ], + [SyntaxKind.Decorator]: [ + { name: "expression", test: isLeftHandSideExpression } + ], [SyntaxKind.TypeAssertionExpression]: [ { name: "type", test: isTypeNode }, { name: "expression", test: isUnaryExpression } ], - [SyntaxKind.AwaitExpression]: [ - { name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand } - ], [SyntaxKind.AsExpression]: [ { name: "expression", test: isExpression }, { name: "type", test: isTypeNode } @@ -59,11 +65,6 @@ namespace ts { [SyntaxKind.NonNullExpression]: [ { name: "expression", test: isLeftHandSideExpression } ], - [SyntaxKind.TryStatement]: [ - { name: "tryBlock", test: isBlock }, - { name: "catchClause", test: isCatchClause, optional: true }, - { name: "finallyBlock", test: isBlock, optional: true } - ], [SyntaxKind.EnumDeclaration]: [ { name: "decorators", test: isDecorator }, { name: "modifiers", test: isModifier }, @@ -85,77 +86,9 @@ namespace ts { { name: "name", test: isIdentifier }, { name: "moduleReference", test: isModuleReference } ], - [SyntaxKind.ImportDeclaration]: [ - { name: "decorators", test: isDecorator }, - { name: "modifiers", test: isModifier }, - { name: "importClause", test: isImportClause, optional: true }, - { name: "moduleSpecifier", test: isExpression } - ], - [SyntaxKind.ImportClause]: [ - { name: "name", test: isIdentifier, optional: true }, - { name: "namedBindings", test: isNamedImportBindings, optional: true } - ], - [SyntaxKind.NamespaceImport]: [ - { name: "name", test: isIdentifier } - ], - [SyntaxKind.NamedImports]: [ - { name: "elements", test: isImportSpecifier } - ], - [SyntaxKind.ImportSpecifier]: [ - { name: "propertyName", test: isIdentifier, optional: true }, - { name: "name", test: isIdentifier } - ], - [SyntaxKind.ExportAssignment]: [ - { name: "decorators", test: isDecorator }, - { name: "modifiers", test: isModifier }, - { name: "expression", test: isExpression } - ], - [SyntaxKind.ExportDeclaration]: [ - { name: "decorators", test: isDecorator }, - { name: "modifiers", test: isModifier }, - { name: "exportClause", test: isNamedExports, optional: true }, - { name: "moduleSpecifier", test: isExpression, optional: true } - ], - [SyntaxKind.NamedExports]: [ - { name: "elements", test: isExportSpecifier } - ], - [SyntaxKind.ExportSpecifier]: [ - { name: "propertyName", test: isIdentifier, optional: true }, - { name: "name", test: isIdentifier } - ], [SyntaxKind.ExternalModuleReference]: [ { name: "expression", test: isExpression, optional: true } ], - [SyntaxKind.JsxElement]: [ - { name: "openingElement", test: isJsxOpeningElement }, - { name: "children", test: isJsxChild }, - { name: "closingElement", test: isJsxClosingElement } - ], - [SyntaxKind.JsxSelfClosingElement]: [ - { name: "tagName", test: isEntityName }, - { name: "attributes", test: isJsxAttributeLike } - ], - [SyntaxKind.JsxOpeningElement]: [ - { name: "tagName", test: isEntityName }, - { name: "attributes", test: isJsxAttributeLike } - ], - [SyntaxKind.JsxClosingElement]: [ - { name: "tagName", test: isEntityName } - ], - [SyntaxKind.JsxAttribute]: [ - { name: "name", test: isIdentifier }, - { name: "initializer", test: isStringLiteralOrJsxExpression, optional: true } - ], - [SyntaxKind.JsxSpreadAttribute]: [ - { name: "expression", test: isExpression } - ], - [SyntaxKind.JsxExpression]: [ - { name: "expression", test: isExpression, optional: true } - ], - [SyntaxKind.CatchClause]: [ - { name: "variableDeclaration", test: isVariableDeclaration }, - { name: "block", test: isBlock } - ], [SyntaxKind.EnumMember]: [ { name: "name", test: isPropertyName }, { name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList } @@ -187,24 +120,23 @@ namespace ts { return initial; } + // We do not yet support types. + if ((kind >= SyntaxKind.TypePredicate && kind <= SyntaxKind.StringLiteralType)) { + return initial; + } + let result = initial; - switch (kind) { + switch (node.kind) { // Leaf nodes - case SyntaxKind.ThisType: - case SyntaxKind.StringLiteralType: case SyntaxKind.SemicolonClassElement: case SyntaxKind.EmptyStatement: case SyntaxKind.OmittedExpression: case SyntaxKind.DebuggerStatement: + case SyntaxKind.NotEmittedStatement: // No need to visit nodes with no children. break; // Names - case SyntaxKind.QualifiedName: - result = reduceNode((node).left, f, result); - result = reduceNode((node).right, f, result); - break; - case SyntaxKind.ComputedPropertyName: result = reduceNode((node).expression, f, result); break; @@ -290,6 +222,11 @@ namespace ts { result = reduceNode((node).name, f, result); break; + case SyntaxKind.ElementAccessExpression: + result = reduceNode((node).expression, f, result); + result = reduceNode((node).argumentExpression, f, result); + break; + case SyntaxKind.CallExpression: result = reduceNode((node).expression, f, result); result = reduceLeft((node).typeArguments, f, result); @@ -331,7 +268,8 @@ namespace ts { case SyntaxKind.AwaitExpression: case SyntaxKind.YieldExpression: case SyntaxKind.SpreadElementExpression: - result = reduceNode((node).expression, f, result); + case SyntaxKind.NonNullExpression: + result = reduceNode((node).expression, f, result); break; case SyntaxKind.PrefixUnaryExpression: @@ -375,7 +313,6 @@ namespace ts { break; // Element - case SyntaxKind.Block: result = reduceLeft((node).statements, f, result); break; @@ -474,10 +411,81 @@ namespace ts { result = reduceLeft((node).clauses, f, result); break; + case SyntaxKind.ImportDeclaration: + result = reduceLeft((node).decorators, f, result); + result = reduceLeft((node).modifiers, f, result); + result = reduceNode((node).importClause, f, result); + result = reduceNode((node).moduleSpecifier, f, result); + break; + + case SyntaxKind.ImportClause: + result = reduceNode((node).name, f, result); + result = reduceNode((node).namedBindings, f, result); + break; + + case SyntaxKind.NamespaceImport: + result = reduceNode((node).name, f, result); + break; + + case SyntaxKind.NamedImports: + case SyntaxKind.NamedExports: + result = reduceLeft((node).elements, f, result); + break; + + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: + result = reduceNode((node).propertyName, f, result); + result = reduceNode((node).name, f, result); + break; + + case SyntaxKind.ExportAssignment: + result = reduceLeft((node).decorators, f, result); + result = reduceLeft((node).modifiers, f, result); + result = reduceNode((node).expression, f, result); + break; + + case SyntaxKind.ExportDeclaration: + result = reduceLeft((node).decorators, f, result); + result = reduceLeft((node).modifiers, f, result); + result = reduceNode((node).exportClause, f, result); + result = reduceNode((node).moduleSpecifier, f, result); + break; + + // JSX + case SyntaxKind.JsxElement: + result = reduceNode((node).openingElement, f, result); + result = reduceLeft((node).children, f, result); + result = reduceNode((node).closingElement, f, result); + break; + + case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxOpeningElement: + result = reduceNode((node).tagName, f, result); + result = reduceLeft((node).attributes, f, result); + break; + + case SyntaxKind.JsxClosingElement: + result = reduceNode((node).tagName, f, result); + break; + + case SyntaxKind.JsxAttribute: + result = reduceNode((node).name, f, result); + result = reduceNode((node).initializer, f, result); + break; + + case SyntaxKind.JsxSpreadAttribute: + result = reduceNode((node).expression, f, result); + break; + + case SyntaxKind.JsxExpression: + result = reduceNode((node).expression, f, result); + break; + // Clauses case SyntaxKind.CaseClause: result = reduceNode((node).expression, f, result); // fall-through + case SyntaxKind.DefaultClause: result = reduceLeft((node).statements, f, result); break; @@ -507,6 +515,10 @@ namespace ts { result = reduceLeft((node).statements, f, result); break; + case SyntaxKind.PartiallyEmittedExpression: + result = reduceNode((node).expression, f, result); + break; + default: const edgeTraversalPath = nodeEdgeTraversalMap[kind]; if (edgeTraversalPath) { @@ -523,7 +535,6 @@ namespace ts { } return result; - } /** @@ -616,8 +627,26 @@ namespace ts { // Ensure we have a copy of `nodes`, up to the current index. updated = createNodeArray(nodes.slice(0, i), /*location*/ nodes, nodes.hasTrailingComma); } - - addNode(updated, visited, /*addOnNewLine*/ undefined, test, parenthesize, parentNode, /*isVisiting*/ visited !== node); + 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); + } + } + else { + const visitedNode = parenthesize + ? parenthesize(visited, parentNode) + : visited; + Debug.assertNode(visitedNode, test); + aggregateTransformFlags(visitedNode); + updated.push(visitedNode); + } + } } } @@ -643,10 +672,12 @@ namespace ts { return node; } - // Special cases for frequent visitors to improve performance. - switch (kind) { - case SyntaxKind.ThisType: - case SyntaxKind.StringLiteralType: + // We do not yet support types. + if ((kind >= SyntaxKind.TypePredicate && kind <= SyntaxKind.StringLiteralType)) { + return node; + } + + switch (node.kind) { case SyntaxKind.SemicolonClassElement: case SyntaxKind.EmptyStatement: case SyntaxKind.OmittedExpression: @@ -655,28 +686,19 @@ 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)); // Signature elements case SyntaxKind.Parameter: - return updateParameterDeclaration((node), + return updateParameterDeclaration(node, visitNodes((node).decorators, visitor, isDecorator), visitNodes((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isBindingName), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), visitNode((node).initializer, visitor, isExpression, /*optional*/ true)); - case SyntaxKind.Decorator: - return updateDecorator(node, - visitNode((node).expression, visitor, isLeftHandSideExpression)); - // Type member case SyntaxKind.PropertyDeclaration: return updateProperty(node, @@ -692,41 +714,41 @@ namespace ts { visitNodes((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), visitNodes((node).typeParameters, visitor, isTypeParameter), - startLexicalEnvironmentAndVisitParameters((node).parameters, visitor, context), + (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), - endLexicalEnvironmentAndUpdateBody( + mergeFunctionBodyLexicalEnvironment( visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context)); + context.endLexicalEnvironment())); case SyntaxKind.Constructor: return updateConstructor(node, visitNodes((node).decorators, visitor, isDecorator), visitNodes((node).modifiers, visitor, isModifier), - startLexicalEnvironmentAndVisitParameters((node).parameters, visitor, context), - endLexicalEnvironmentAndUpdateBody( + (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), + mergeFunctionBodyLexicalEnvironment( visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context)); + context.endLexicalEnvironment())); case SyntaxKind.GetAccessor: return updateGetAccessor(node, visitNodes((node).decorators, visitor, isDecorator), visitNodes((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), - startLexicalEnvironmentAndVisitParameters((node).parameters, visitor, context), + (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), - endLexicalEnvironmentAndUpdateBody( + mergeFunctionBodyLexicalEnvironment( visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context)); + context.endLexicalEnvironment())); case SyntaxKind.SetAccessor: return updateSetAccessor(node, visitNodes((node).decorators, visitor, isDecorator), visitNodes((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), - startLexicalEnvironmentAndVisitParameters((node).parameters, visitor, context), - endLexicalEnvironmentAndUpdateBody( + (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), + mergeFunctionBodyLexicalEnvironment( visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context)); + context.endLexicalEnvironment())); // Binding patterns case SyntaxKind.ObjectBindingPattern: @@ -750,10 +772,10 @@ namespace ts { case SyntaxKind.ObjectLiteralExpression: return updateObjectLiteral(node, - visitNodes((node).properties, visitor, isExpression)); + visitNodes((node).properties, visitor, isObjectLiteralElement)); case SyntaxKind.PropertyAccessExpression: - return updatePropertyAccess((node), + return updatePropertyAccess(node, visitNode((node).expression, visitor, isExpression), visitNode((node).name, visitor, isIdentifier)); @@ -763,13 +785,13 @@ namespace ts { visitNode((node).argumentExpression, visitor, isExpression)); case SyntaxKind.CallExpression: - return updateCall((node), + return updateCall(node, visitNode((node).expression, visitor, isExpression), visitNodes((node).typeArguments, visitor, isTypeNode), visitNodes((node).arguments, visitor, isExpression)); case SyntaxKind.NewExpression: - return updateNew((node), + return updateNew(node, visitNode((node).expression, visitor, isExpression), visitNodes((node).typeArguments, visitor, isTypeNode), visitNodes((node).arguments, visitor, isExpression)); @@ -780,28 +802,28 @@ namespace ts { visitNode((node).template, visitor, isTemplate)); case SyntaxKind.ParenthesizedExpression: - return updateParen((node), + return updateParen(node, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.FunctionExpression: return updateFunctionExpression(node, visitNode((node).name, visitor, isPropertyName), visitNodes((node).typeParameters, visitor, isTypeParameter), - startLexicalEnvironmentAndVisitParameters((node).parameters, visitor, context), + (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), - endLexicalEnvironmentAndUpdateBody( + mergeFunctionBodyLexicalEnvironment( visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context)); + context.endLexicalEnvironment())); case SyntaxKind.ArrowFunction: return updateArrowFunction(node, visitNodes((node).modifiers, visitor, isModifier), visitNodes((node).typeParameters, visitor, isTypeParameter), - startLexicalEnvironmentAndVisitParameters((node).parameters, visitor, context), + (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), - endLexicalEnvironmentAndUpdateBody( + mergeFunctionBodyLexicalEnvironment( visitNode((node).body, visitor, isConciseBody, /*optional*/ true), - context)); + context.endLexicalEnvironment())); case SyntaxKind.DeleteExpression: return updateDelete(node, @@ -815,8 +837,12 @@ namespace ts { return updateVoid(node, visitNode((node).expression, visitor, isUnaryExpression)); + case SyntaxKind.AwaitExpression: + return updateAwait(node, + visitNode((node).expression, visitor, isUnaryExpression)); + case SyntaxKind.BinaryExpression: - return updateBinary((node), + return updateBinary(node, visitNode((node).left, visitor, isExpression), visitNode((node).right, visitor, isExpression)); @@ -868,20 +894,20 @@ namespace ts { // Element case SyntaxKind.Block: - return updateBlock((node), + return updateBlock(node, visitNodes((node).statements, visitor, isStatement)); case SyntaxKind.VariableStatement: - return updateVariableStatement((node), + return updateVariableStatement(node, visitNodes((node).modifiers, visitor, isModifier), visitNode((node).declarationList, visitor, isVariableDeclarationList)); case SyntaxKind.ExpressionStatement: - return updateStatement((node), + return updateStatement(node, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.IfStatement: - return updateIf((node), + return updateIf(node, visitNode((node).expression, visitor, isExpression), visitNode((node).thenStatement, visitor, isStatement, /*optional*/ false, liftToBlock), visitNode((node).elseStatement, visitor, isStatement, /*optional*/ true, liftToBlock)); @@ -946,14 +972,20 @@ namespace ts { return updateThrow(node, visitNode((node).expression, visitor, isExpression)); + case SyntaxKind.TryStatement: + return updateTry(node, + visitNode((node).tryBlock, visitor, isBlock), + visitNode((node).catchClause, visitor, isCatchClause, /*optional*/ true), + visitNode((node).finallyBlock, visitor, isBlock, /*optional*/ true)); + case SyntaxKind.VariableDeclaration: - return updateVariableDeclaration((node), + return updateVariableDeclaration(node, visitNode((node).name, visitor, isBindingName), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), visitNode((node).initializer, visitor, isExpression, /*optional*/ true)); case SyntaxKind.VariableDeclarationList: - return updateVariableDeclarationList((node), + return updateVariableDeclarationList(node, visitNodes((node).declarations, visitor, isVariableDeclaration)); case SyntaxKind.FunctionDeclaration: @@ -962,11 +994,11 @@ namespace ts { visitNodes((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), visitNodes((node).typeParameters, visitor, isTypeParameter), - startLexicalEnvironmentAndVisitParameters((node).parameters, visitor, context), + (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), - endLexicalEnvironmentAndUpdateBody( + mergeFunctionBodyLexicalEnvironment( visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context)); + context.endLexicalEnvironment())); case SyntaxKind.ClassDeclaration: return updateClassDeclaration(node, @@ -981,6 +1013,87 @@ namespace ts { return updateCaseBlock(node, visitNodes((node).clauses, visitor, isCaseOrDefaultClause)); + case SyntaxKind.ImportDeclaration: + return updateImportDeclaration(node, + visitNodes((node).decorators, visitor, isDecorator), + visitNodes((node).modifiers, visitor, isModifier), + visitNode((node).importClause, visitor, isImportClause, /*optional*/ true), + visitNode((node).moduleSpecifier, visitor, isExpression)); + + case SyntaxKind.ImportClause: + return updateImportClause(node, + visitNode((node).name, visitor, isIdentifier, /*optional*/ true), + visitNode((node).namedBindings, visitor, isNamedImportBindings, /*optional*/ true)); + + case SyntaxKind.NamespaceImport: + return updateNamespaceImport(node, + visitNode((node).name, visitor, isIdentifier)); + + case SyntaxKind.NamedImports: + return updateNamedImports(node, + visitNodes((node).elements, visitor, isImportSpecifier)); + + case SyntaxKind.ImportSpecifier: + return updateImportSpecifier(node, + visitNode((node).propertyName, visitor, isIdentifier, /*optional*/ true), + visitNode((node).name, visitor, isIdentifier)); + + case SyntaxKind.ExportAssignment: + return updateExportAssignment(node, + visitNodes((node).decorators, visitor, isDecorator), + visitNodes((node).modifiers, visitor, isModifier), + visitNode((node).expression, visitor, isExpression)); + + case SyntaxKind.ExportDeclaration: + return updateExportDeclaration(node, + visitNodes((node).decorators, visitor, isDecorator), + visitNodes((node).modifiers, visitor, isModifier), + visitNode((node).exportClause, visitor, isNamedExports, /*optional*/ true), + visitNode((node).moduleSpecifier, visitor, isExpression, /*optional*/ true)); + + case SyntaxKind.NamedExports: + return updateNamedExports(node, + visitNodes((node).elements, visitor, isExportSpecifier)); + + case SyntaxKind.ExportSpecifier: + return updateExportSpecifier(node, + visitNode((node).propertyName, visitor, isIdentifier, /*optional*/ true), + visitNode((node).name, visitor, isIdentifier)); + + // JSX + case SyntaxKind.JsxElement: + return updateJsxElement(node, + visitNode((node).openingElement, visitor, isJsxOpeningElement), + visitNodes((node).children, visitor, isJsxChild), + visitNode((node).closingElement, visitor, isJsxClosingElement)); + + case SyntaxKind.JsxSelfClosingElement: + return updateJsxSelfClosingElement(node, + visitNode((node).tagName, visitor, isJsxTagNameExpression), + visitNodes((node).attributes, visitor, isJsxAttributeLike)); + + case SyntaxKind.JsxOpeningElement: + return updateJsxOpeningElement(node, + visitNode((node).tagName, visitor, isJsxTagNameExpression), + visitNodes((node).attributes, visitor, isJsxAttributeLike)); + + case SyntaxKind.JsxClosingElement: + return updateJsxClosingElement(node, + visitNode((node).tagName, visitor, isJsxTagNameExpression)); + + case SyntaxKind.JsxAttribute: + return updateJsxAttribute(node, + visitNode((node).name, visitor, isIdentifier), + visitNode((node).initializer, visitor, isStringLiteralOrJsxExpression)); + + case SyntaxKind.JsxSpreadAttribute: + return updateJsxSpreadAttribute(node, + visitNode((node).expression, visitor, isExpression)); + + case SyntaxKind.JsxExpression: + return updateJsxExpression(node, + visitNode((node).expression, visitor, isExpression)); + // Clauses case SyntaxKind.CaseClause: return updateCaseClause(node, @@ -995,6 +1108,11 @@ namespace ts { return updateHeritageClause(node, visitNodes((node).types, visitor, isExpressionWithTypeArguments)); + case SyntaxKind.CatchClause: + return updateCatchClause(node, + visitNode((node).variableDeclaration, visitor, isVariableDeclaration), + visitNode((node).block, visitor, isBlock)); + // Property assignments case SyntaxKind.PropertyAssignment: return updatePropertyAssignment(node, @@ -1009,7 +1127,7 @@ namespace ts { // Top-level nodes case SyntaxKind.SourceFile: context.startLexicalEnvironment(); - return updateSourceFileNode((node), + return updateSourceFileNode(node, createNodeArray( concatenate( visitNodes((node).statements, visitor, isStatement), @@ -1044,76 +1162,8 @@ namespace ts { } return updated ? updateNode(updated, node) : node; } - } - function startLexicalEnvironmentAndVisitParameters(nodes: NodeArray, visitor: (node: Node) => VisitResult, context: LexicalEnvironment): NodeArray { - context.startLexicalEnvironment(); - return visitNodes(nodes, visitor, isParameter); - } - - function endLexicalEnvironmentAndUpdateBody(body: FunctionBody, context: LexicalEnvironment): FunctionBody; - function endLexicalEnvironmentAndUpdateBody(body: ConciseBody, context: LexicalEnvironment): ConciseBody; - function endLexicalEnvironmentAndUpdateBody(body: ConciseBody, context: LexicalEnvironment) { - const declarations = context.endLexicalEnvironment(); - if (body && declarations && declarations.length) { - if (isBlock(body)) { - return updateBlock(body, createNodeArray(concatenate(body.statements, declarations), body.statements)); - } - return createBlock( - createNodeArray([createReturn(body, /*location*/ body), ...declarations], body), - /*location*/ body, - /*multiLine*/ true); - } - return body; - } - - /** - * Appends a node to an array. - * - * @param to The destination array. - * @param from The source Node or NodeArrayNode. - */ - export function addNode(to: T[], from: VisitResult, startOnNewLine?: boolean): void; - export function addNode(to: Node[], from: VisitResult, startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean): void; - export function addNode(to: Node[], from: VisitResult, startOnNewLine?: boolean, test?: (node: Node) => boolean, parenthesize?: (node: Node, parentNode: Node) => Node, parentNode?: Node, isVisiting?: boolean): void { - if (to && from) { - if (isArray(from)) { - addNodes(to, from, startOnNewLine, test, parenthesize, parentNode, isVisiting); - } - else { - const node = parenthesize !== undefined - ? parenthesize(from, parentNode) - : from; - - Debug.assertNode(node, test); - - if (startOnNewLine) { - node.startsOnNewLine = true; - } - - if (isVisiting) { - aggregateTransformFlags(node); - } - - to.push(node); - } - } - } - - /** - * Appends an array of nodes to an array. - * - * @param to The destination NodeArray. - * @param from The source array of Node or NodeArrayNode. - */ - export function addNodes(to: T[], from: VisitResult[], startOnNewLine?: boolean): void; - export function addNodes(to: Node[], from: VisitResult[], startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean): void; - export function addNodes(to: Node[], from: VisitResult[], startOnNewLine?: boolean, test?: (node: Node) => boolean, parenthesize?: (node: Node, parentNode: Node) => Node, parentNode?: Node, isVisiting?: boolean): void { - if (to && from) { - for (const node of from) { - addNode(to, node, startOnNewLine, test, parenthesize, parentNode, isVisiting); - } - } + // return node; } /** @@ -1122,13 +1172,7 @@ namespace ts { * @param node The ConciseBody of an arrow function. * @param declarations The lexical declarations to merge. */ - export function mergeFunctionBodyLexicalEnvironment(body: FunctionBody, declarations: Statement[]): FunctionBody { - if (declarations !== undefined && declarations.length > 0) { - return mergeBlockLexicalEnvironment(body, declarations); - } - - return body; - } + export function mergeFunctionBodyLexicalEnvironment(body: FunctionBody, declarations: Statement[]): FunctionBody; /** * Merges generated lexical declarations into the ConciseBody of an ArrowFunction. @@ -1136,44 +1180,23 @@ namespace ts { * @param node The ConciseBody of an arrow function. * @param declarations The lexical declarations to merge. */ - export function mergeConciseBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]): ConciseBody { - if (declarations !== undefined && declarations.length > 0) { + export function mergeFunctionBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]): ConciseBody; + + export function mergeFunctionBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]): ConciseBody { + if (body && declarations !== undefined && declarations.length > 0) { if (isBlock(body)) { - return mergeBlockLexicalEnvironment(body, declarations); + return updateBlock(body, createNodeArray(concatenate(body.statements, declarations), body.statements)); } else { - return createBlock([ - createReturn(body), - ...declarations - ]); + return createBlock( + createNodeArray([createReturn(body, /*location*/ body), ...declarations], body), + /*location*/ body, + /*multiLine*/ true); } } - return body; } - /** - * Merge generated declarations of a lexical environment into a FunctionBody or ModuleBlock. - * - * @param node The block into which to merge lexical declarations. - * @param declarations The lexical declarations to merge. - */ - function mergeBlockLexicalEnvironment(node: T, declarations: Statement[]): T { - const mutableNode = getMutableClone(node); - mutableNode.statements = mergeStatements(node.statements, declarations); - return mutableNode; - } - - /** - * Merge generated declarations of a lexical environment into a NodeArray of Statement. - * - * @param statements The node array to concatentate with the supplied lexical declarations. - * @param declarations The lexical declarations to merge. - */ - function mergeStatements(statements: NodeArray, declarations: Statement[]): NodeArray { - return createNodeArray(concatenate(statements, declarations), /*location*/ statements); - } - /** * Lifts a NodeArray containing only Statement nodes to a block. *