diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index d5f3d920436..4c7693dd846 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 ae678f429f1..49e744682bc 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 66efce4fef8..91cd6a89b8b 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 b6e0adc1294..63c3726fc10 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; } /**