/// /// /// namespace ts { /** * Visits a Node using the supplied visitor, possibly returning a new Node in its place. * * @param node The Node to visit. * @param visitor The callback used to visit the Node. * @param test A callback to execute to verify the Node is valid. * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ export function visitNode(node: T, visitor: Visitor, test?: (node: Node) => boolean, lift?: (node: NodeArray) => T): T; /** * Visits a Node using the supplied visitor, possibly returning a new Node in its place. * * @param node The Node to visit. * @param visitor The callback used to visit the Node. * @param test A callback to execute to verify the Node is valid. * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ export function visitNode(node: T | undefined, visitor: Visitor, test?: (node: Node) => boolean, lift?: (node: NodeArray) => T): T | undefined; export function visitNode(node: T | undefined, visitor: Visitor, test?: (node: Node) => boolean, lift?: (node: NodeArray) => T): T | undefined { if (node === undefined || visitor === undefined) { return node; } aggregateTransformFlags(node); const visited = visitor(node); if (visited === node) { return node; } let visitedNode: Node; if (visited === undefined) { return undefined; } else if (isArray(visited)) { visitedNode = (lift || extractSingleNode)(visited); } else { visitedNode = visited; } Debug.assertNode(visitedNode, test); aggregateTransformFlags(visitedNode); return visitedNode; } /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. * * @param nodes The NodeArray to visit. * @param visitor The callback used to visit a Node. * @param test A node test to execute for each node. * @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: Visitor, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. * * @param nodes The NodeArray to visit. * @param visitor The callback used to visit a Node. * @param test A node test to execute for each node. * @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 | undefined, visitor: Visitor, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. * * @param nodes The NodeArray to visit. * @param visitor The callback used to visit a Node. * @param test A node test to execute for each node. * @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 | undefined, visitor: Visitor, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined { if (nodes === undefined || visitor === undefined) { return nodes; } let updated: NodeArray; // Ensure start and count have valid values const length = nodes.length; if (start === undefined || start < 0) { start = 0; } if (count === undefined || count > length - start) { count = length - start; } if (start > 0 || count < length) { // 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); } // Visit each original node. for (let i = 0; i < count; i++) { const node = nodes[i + start]; aggregateTransformFlags(node); const visited = node !== undefined ? visitor(node) : undefined; if (updated !== undefined || visited === undefined || visited !== node) { if (updated === undefined) { // Ensure we have a copy of `nodes`, up to the current index. updated = createNodeArray(nodes.slice(0, i), nodes.hasTrailingComma); setTextRange(updated, nodes); } if (visited) { if (isArray(visited)) { for (const visitedNode of visited) { Debug.assertNode(visitedNode, test); aggregateTransformFlags(visitedNode); updated.push(visitedNode); } } else { Debug.assertNode(visited, test); aggregateTransformFlags(visited); updated.push(visited); } } } } return updated || nodes; } /** * Starts a new lexical environment and visits a statement list, ending the lexical environment * and merging hoisted declarations upon completion. */ export function visitLexicalEnvironment(statements: NodeArray, visitor: Visitor, context: TransformationContext, start?: number, ensureUseStrict?: boolean) { context.startLexicalEnvironment(); statements = visitNodes(statements, visitor, isStatement, start); if (ensureUseStrict && !startsWithUseStrict(statements)) { statements = setTextRange(createNodeArray([createStatement(createLiteral("use strict")), ...statements]), statements); } const declarations = context.endLexicalEnvironment(); return setTextRange(createNodeArray(concatenate(statements, declarations)), statements); } /** * Starts a new lexical environment and visits a parameter list, suspending the lexical * environment upon completion. */ export function visitParameterList(nodes: NodeArray, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes) { context.startLexicalEnvironment(); const updated = nodesVisitor(nodes, visitor, isParameterDeclaration); context.suspendLexicalEnvironment(); return updated; } /** * Resumes a suspended lexical environment and visits a function body, ending the lexical * environment and merging hoisted declarations upon completion. */ export function visitFunctionBody(node: FunctionBody, visitor: Visitor, context: TransformationContext): FunctionBody; /** * Resumes a suspended lexical environment and visits a function body, ending the lexical * environment and merging hoisted declarations upon completion. */ export function visitFunctionBody(node: FunctionBody | undefined, visitor: Visitor, context: TransformationContext): FunctionBody | undefined; /** * Resumes a suspended lexical environment and visits a concise body, ending the lexical * environment and merging hoisted declarations upon completion. */ export function visitFunctionBody(node: ConciseBody, visitor: Visitor, context: TransformationContext): ConciseBody; export function visitFunctionBody(node: ConciseBody, visitor: Visitor, context: TransformationContext): ConciseBody { context.resumeLexicalEnvironment(); const updated = visitNode(node, visitor, isConciseBody); const declarations = context.endLexicalEnvironment(); if (some(declarations)) { const block = convertToFunctionBody(updated); const statements = mergeLexicalEnvironment(block.statements, declarations); return updateBlock(block, statements); } return updated; } /** * Visits each child of a Node using the supplied visitor, possibly returning a new Node of the same kind in its place. * * @param node The Node whose children will be visited. * @param visitor The callback used to visit each child. * @param context A lexical environment context for the visitor. */ export function visitEachChild(node: T, visitor: Visitor, context: TransformationContext): T; /** * Visits each child of a Node using the supplied visitor, possibly returning a new Node of the same kind in its place. * * @param node The Node whose children will be visited. * @param visitor The callback used to visit each child. * @param context A lexical environment context for the visitor. */ export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes): T | undefined; export function visitEachChild(node: Node, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes): Node { if (node === undefined) { return undefined; } const kind = node.kind; // No need to visit nodes with no children. if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken)) { return node; } // We do not yet support types. if ((kind >= SyntaxKind.TypePredicate && kind <= SyntaxKind.LiteralType)) { return node; } switch (node.kind) { case SyntaxKind.SemicolonClassElement: case SyntaxKind.EmptyStatement: case SyntaxKind.OmittedExpression: case SyntaxKind.DebuggerStatement: // No need to visit nodes with no children. 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 updateParameter(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), (node).dotDotDotToken, visitNode((node).name, visitor, isBindingName), visitNode((node).type, visitor, isTypeNode), visitNode((node).initializer, visitor, isExpression)); case SyntaxKind.Decorator: return updateDecorator(node, visitNode((node).expression, visitor, isExpression)); // Type member case SyntaxKind.PropertyDeclaration: return updateProperty(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), visitNode((node).type, visitor, isTypeNode), visitNode((node).initializer, visitor, isExpression)); case SyntaxKind.MethodDeclaration: return updateMethod(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), (node).asteriskToken, visitNode((node).name, visitor, isPropertyName), nodesVisitor((node).typeParameters, visitor, isTypeParameter), visitParameterList((node).parameters, visitor, context, nodesVisitor), visitNode((node).type, visitor, isTypeNode), visitFunctionBody((node).body, visitor, context)); case SyntaxKind.Constructor: return updateConstructor(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitParameterList((node).parameters, visitor, context, nodesVisitor), visitFunctionBody((node).body, visitor, context)); case SyntaxKind.GetAccessor: return updateGetAccessor(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), visitParameterList((node).parameters, visitor, context, nodesVisitor), visitNode((node).type, visitor, isTypeNode), visitFunctionBody((node).body, visitor, context)); case SyntaxKind.SetAccessor: return updateSetAccessor(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), visitParameterList((node).parameters, visitor, context, nodesVisitor), visitFunctionBody((node).body, visitor, context)); // Binding patterns case SyntaxKind.ObjectBindingPattern: return updateObjectBindingPattern(node, nodesVisitor((node).elements, visitor, isBindingElement)); case SyntaxKind.ArrayBindingPattern: return updateArrayBindingPattern(node, nodesVisitor((node).elements, visitor, isArrayBindingElement)); case SyntaxKind.BindingElement: return updateBindingElement(node, (node).dotDotDotToken, visitNode((node).propertyName, visitor, isPropertyName), visitNode((node).name, visitor, isBindingName), visitNode((node).initializer, visitor, isExpression)); // Expression case SyntaxKind.ArrayLiteralExpression: return updateArrayLiteral(node, nodesVisitor((node).elements, visitor, isExpression)); case SyntaxKind.ObjectLiteralExpression: return updateObjectLiteral(node, nodesVisitor((node).properties, visitor, isObjectLiteralElementLike)); case SyntaxKind.PropertyAccessExpression: return updatePropertyAccess(node, visitNode((node).expression, visitor, isExpression), visitNode((node).name, visitor, isIdentifier)); case SyntaxKind.ElementAccessExpression: return updateElementAccess(node, visitNode((node).expression, visitor, isExpression), visitNode((node).argumentExpression, visitor, isExpression)); case SyntaxKind.CallExpression: return updateCall(node, visitNode((node).expression, visitor, isExpression), nodesVisitor((node).typeArguments, visitor, isTypeNode), nodesVisitor((node).arguments, visitor, isExpression)); case SyntaxKind.NewExpression: return updateNew(node, visitNode((node).expression, visitor, isExpression), nodesVisitor((node).typeArguments, visitor, isTypeNode), nodesVisitor((node).arguments, visitor, isExpression)); case SyntaxKind.TaggedTemplateExpression: return updateTaggedTemplate(node, 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)); case SyntaxKind.FunctionExpression: return updateFunctionExpression(node, nodesVisitor((node).modifiers, visitor, isModifier), (node).asteriskToken, visitNode((node).name, visitor, isIdentifier), nodesVisitor((node).typeParameters, visitor, isTypeParameter), visitParameterList((node).parameters, visitor, context, nodesVisitor), visitNode((node).type, visitor, isTypeNode), visitFunctionBody((node).body, visitor, context)); case SyntaxKind.ArrowFunction: return updateArrowFunction(node, nodesVisitor((node).modifiers, visitor, isModifier), nodesVisitor((node).typeParameters, visitor, isTypeParameter), visitParameterList((node).parameters, visitor, context, nodesVisitor), visitNode((node).type, visitor, isTypeNode), visitFunctionBody((node).body, visitor, context)); case SyntaxKind.DeleteExpression: return updateDelete(node, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.TypeOfExpression: return updateTypeOf(node, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.VoidExpression: return updateVoid(node, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.AwaitExpression: return updateAwait(node, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.BinaryExpression: return updateBinary(node, visitNode((node).left, visitor, isExpression), visitNode((node).right, visitor, isExpression)); case SyntaxKind.PrefixUnaryExpression: return updatePrefix(node, visitNode((node).operand, visitor, isExpression)); case SyntaxKind.PostfixUnaryExpression: return updatePostfix(node, visitNode((node).operand, visitor, isExpression)); case SyntaxKind.ConditionalExpression: return updateConditional(node, visitNode((node).condition, visitor, isExpression), visitNode((node).whenTrue, visitor, isExpression), visitNode((node).whenFalse, visitor, isExpression)); case SyntaxKind.TemplateExpression: return updateTemplateExpression(node, visitNode((node).head, visitor, isTemplateHead), nodesVisitor((node).templateSpans, visitor, isTemplateSpan)); case SyntaxKind.YieldExpression: return updateYield(node, (node).asteriskToken, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.SpreadElement: return updateSpread(node, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.ClassExpression: return updateClassExpression(node, nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isIdentifier), nodesVisitor((node).typeParameters, visitor, isTypeParameter), nodesVisitor((node).heritageClauses, visitor, isHeritageClause), nodesVisitor((node).members, visitor, isClassElement)); case SyntaxKind.ExpressionWithTypeArguments: return updateExpressionWithTypeArguments(node, nodesVisitor((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, visitNode((node).expression, visitor, isExpression), visitNode((node).literal, visitor, isTemplateMiddleOrTemplateTail)); // Element case SyntaxKind.Block: return updateBlock(node, nodesVisitor((node).statements, visitor, isStatement)); case SyntaxKind.VariableStatement: return updateVariableStatement(node, nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).declarationList, visitor, isVariableDeclarationList)); case SyntaxKind.ExpressionStatement: return updateStatement(node, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.IfStatement: return updateIf(node, visitNode((node).expression, visitor, isExpression), visitNode((node).thenStatement, visitor, isStatement, liftToBlock), visitNode((node).elseStatement, visitor, isStatement, liftToBlock)); case SyntaxKind.DoStatement: return updateDo(node, visitNode((node).statement, visitor, isStatement, liftToBlock), visitNode((node).expression, visitor, isExpression)); case SyntaxKind.WhileStatement: return updateWhile(node, visitNode((node).expression, visitor, isExpression), visitNode((node).statement, visitor, isStatement, liftToBlock)); case SyntaxKind.ForStatement: return updateFor(node, visitNode((node).initializer, visitor, isForInitializer), visitNode((node).condition, visitor, isExpression), visitNode((node).incrementor, visitor, isExpression), visitNode((node).statement, visitor, isStatement, liftToBlock)); case SyntaxKind.ForInStatement: return updateForIn(node, visitNode((node).initializer, visitor, isForInitializer), visitNode((node).expression, visitor, isExpression), visitNode((node).statement, visitor, isStatement, liftToBlock)); case SyntaxKind.ForOfStatement: return updateForOf(node, (node).awaitModifier, visitNode((node).initializer, visitor, isForInitializer), visitNode((node).expression, visitor, isExpression), visitNode((node).statement, visitor, isStatement, liftToBlock)); case SyntaxKind.ContinueStatement: return updateContinue(node, visitNode((node).label, visitor, isIdentifier)); case SyntaxKind.BreakStatement: return updateBreak(node, visitNode((node).label, visitor, isIdentifier)); case SyntaxKind.ReturnStatement: return updateReturn(node, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.WithStatement: return updateWith(node, visitNode((node).expression, visitor, isExpression), visitNode((node).statement, visitor, isStatement, liftToBlock)); case SyntaxKind.SwitchStatement: return updateSwitch(node, visitNode((node).expression, visitor, isExpression), visitNode((node).caseBlock, visitor, isCaseBlock)); case SyntaxKind.LabeledStatement: return updateLabel(node, visitNode((node).label, visitor, isIdentifier), visitNode((node).statement, visitor, isStatement, liftToBlock)); case SyntaxKind.ThrowStatement: return updateThrow(node, visitNode((node).expression, visitor, isExpression)); case SyntaxKind.TryStatement: return updateTry(node, visitNode((node).tryBlock, visitor, isBlock), visitNode((node).catchClause, visitor, isCatchClause), visitNode((node).finallyBlock, visitor, isBlock)); case SyntaxKind.VariableDeclaration: return updateVariableDeclaration(node, visitNode((node).name, visitor, isBindingName), visitNode((node).type, visitor, isTypeNode), visitNode((node).initializer, visitor, isExpression)); case SyntaxKind.VariableDeclarationList: return updateVariableDeclarationList(node, nodesVisitor((node).declarations, visitor, isVariableDeclaration)); case SyntaxKind.FunctionDeclaration: return updateFunctionDeclaration(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), (node).asteriskToken, visitNode((node).name, visitor, isIdentifier), nodesVisitor((node).typeParameters, visitor, isTypeParameter), visitParameterList((node).parameters, visitor, context, nodesVisitor), visitNode((node).type, visitor, isTypeNode), visitFunctionBody((node).body, visitor, context)); case SyntaxKind.ClassDeclaration: return updateClassDeclaration(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isIdentifier), nodesVisitor((node).typeParameters, visitor, isTypeParameter), nodesVisitor((node).heritageClauses, visitor, isHeritageClause), nodesVisitor((node).members, visitor, isClassElement)); case SyntaxKind.EnumDeclaration: return updateEnumDeclaration(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isIdentifier), nodesVisitor((node).members, visitor, isEnumMember)); case SyntaxKind.ModuleDeclaration: return updateModuleDeclaration(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isIdentifier), visitNode((node).body, visitor, isModuleBody)); case SyntaxKind.ModuleBlock: return updateModuleBlock(node, nodesVisitor((node).statements, visitor, isStatement)); case SyntaxKind.CaseBlock: return updateCaseBlock(node, nodesVisitor((node).clauses, visitor, isCaseOrDefaultClause)); case SyntaxKind.ImportEqualsDeclaration: return updateImportEqualsDeclaration(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isIdentifier), visitNode((node).moduleReference, visitor, isModuleReference)); case SyntaxKind.ImportDeclaration: return updateImportDeclaration(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).importClause, visitor, isImportClause), visitNode((node).moduleSpecifier, visitor, isExpression)); case SyntaxKind.ImportClause: return updateImportClause(node, visitNode((node).name, visitor, isIdentifier), visitNode((node).namedBindings, visitor, isNamedImportBindings)); case SyntaxKind.NamespaceImport: return updateNamespaceImport(node, visitNode((node).name, visitor, isIdentifier)); case SyntaxKind.NamedImports: return updateNamedImports(node, nodesVisitor((node).elements, visitor, isImportSpecifier)); case SyntaxKind.ImportSpecifier: return updateImportSpecifier(node, visitNode((node).propertyName, visitor, isIdentifier), visitNode((node).name, visitor, isIdentifier)); case SyntaxKind.ExportAssignment: return updateExportAssignment(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).expression, visitor, isExpression)); case SyntaxKind.ExportDeclaration: return updateExportDeclaration(node, nodesVisitor((node).decorators, visitor, isDecorator), nodesVisitor((node).modifiers, visitor, isModifier), visitNode((node).exportClause, visitor, isNamedExports), visitNode((node).moduleSpecifier, visitor, isExpression)); case SyntaxKind.NamedExports: return updateNamedExports(node, nodesVisitor((node).elements, visitor, isExportSpecifier)); case SyntaxKind.ExportSpecifier: return updateExportSpecifier(node, visitNode((node).propertyName, visitor, isIdentifier), 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, visitNode((node).openingElement, visitor, isJsxOpeningElement), nodesVisitor((node).children, visitor, isJsxChild), visitNode((node).closingElement, visitor, isJsxClosingElement)); case SyntaxKind.JsxAttributes: return updateJsxAttributes(node, nodesVisitor((node).properties, visitor, isJsxAttributeLike)); case SyntaxKind.JsxSelfClosingElement: return updateJsxSelfClosingElement(node, visitNode((node).tagName, visitor, isJsxTagNameExpression), visitNode((node).attributes, visitor, isJsxAttributes)); case SyntaxKind.JsxOpeningElement: return updateJsxOpeningElement(node, visitNode((node).tagName, visitor, isJsxTagNameExpression), visitNode((node).attributes, visitor, isJsxAttributes)); 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, visitNode((node).expression, visitor, isExpression), nodesVisitor((node).statements, visitor, isStatement)); case SyntaxKind.DefaultClause: return updateDefaultClause(node, nodesVisitor((node).statements, visitor, isStatement)); case SyntaxKind.HeritageClause: return updateHeritageClause(node, nodesVisitor((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, visitNode((node).name, visitor, isPropertyName), visitNode((node).initializer, visitor, isExpression)); case SyntaxKind.ShorthandPropertyAssignment: return updateShorthandPropertyAssignment(node, visitNode((node).name, visitor, isIdentifier), visitNode((node).objectAssignmentInitializer, visitor, isExpression)); case SyntaxKind.SpreadAssignment: return updateSpreadAssignment(node, visitNode((node).expression, visitor, isExpression)); // Enum case SyntaxKind.EnumMember: return updateEnumMember(node, visitNode((node).name, visitor, isPropertyName), visitNode((node).initializer, visitor, isExpression)); // Top-level nodes case SyntaxKind.SourceFile: return updateSourceFileNode(node, visitLexicalEnvironment((node).statements, visitor, context)); // Transformation nodes case SyntaxKind.PartiallyEmittedExpression: return updatePartiallyEmittedExpression(node, visitNode((node).expression, visitor, isExpression)); default: return node; } } /** * Extracts the single node from a NodeArray. * * @param nodes The NodeArray. */ function extractSingleNode(nodes: Node[]): Node { Debug.assert(nodes.length <= 1, "Too many nodes written to output."); return singleOrUndefined(nodes); } } /* @internal */ namespace ts { function reduceNode(node: Node, f: (memo: T, node: Node) => T, initial: T) { return node ? f(initial, node) : initial; } function reduceNodeArray(nodes: NodeArray, f: (memo: T, nodes: NodeArray) => T, initial: T) { return nodes ? f(initial, nodes) : initial; } /** * Similar to `reduceLeft`, performs a reduction against each child of a node. * 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. * @param f The callback function */ export function reduceEachChild(node: Node, initial: T, cbNode: (memo: T, node: Node) => T, cbNodeArray?: (memo: T, nodes: NodeArray) => T): T { if (node === undefined) { return initial; } const reduceNodes: (nodes: NodeArray, f: (memo: T, node: Node | NodeArray) => T, initial: T) => T = cbNodeArray ? reduceNodeArray : reduceLeft; const cbNodes = cbNodeArray || cbNode; const kind = node.kind; // No need to visit nodes with no children. if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken)) { return initial; } // We do not yet support types. if ((kind >= SyntaxKind.TypePredicate && kind <= SyntaxKind.LiteralType)) { return initial; } let result = initial; switch (node.kind) { // Leaf nodes 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, cbNode, result); result = reduceNode((node).right, cbNode, result); break; case SyntaxKind.ComputedPropertyName: result = reduceNode((node).expression, cbNode, result); break; // Signature elements case SyntaxKind.Parameter: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNode((node).name, cbNode, result); result = reduceNode((node).type, cbNode, result); result = reduceNode((node).initializer, cbNode, result); break; case SyntaxKind.Decorator: result = reduceNode((node).expression, cbNode, result); break; // Type member case SyntaxKind.PropertyDeclaration: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNode((node).name, cbNode, result); result = reduceNode((node).type, cbNode, result); result = reduceNode((node).initializer, cbNode, result); break; case SyntaxKind.MethodDeclaration: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNode((node).name, cbNode, result); result = reduceNodes((node).typeParameters, cbNodes, result); result = reduceNodes((node).parameters, cbNodes, result); result = reduceNode((node).type, cbNode, result); result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.Constructor: result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNodes((node).parameters, cbNodes, result); result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.GetAccessor: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNode((node).name, cbNode, result); result = reduceNodes((node).parameters, cbNodes, result); result = reduceNode((node).type, cbNode, result); result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.SetAccessor: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNode((node).name, cbNode, result); result = reduceNodes((node).parameters, cbNodes, result); result = reduceNode((node).body, cbNode, result); break; // Binding patterns case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: result = reduceNodes((node).elements, cbNodes, result); break; case SyntaxKind.BindingElement: result = reduceNode((node).propertyName, cbNode, result); result = reduceNode((node).name, cbNode, result); result = reduceNode((node).initializer, cbNode, result); break; // Expression case SyntaxKind.ArrayLiteralExpression: result = reduceNodes((node).elements, cbNodes, result); break; case SyntaxKind.ObjectLiteralExpression: result = reduceNodes((node).properties, cbNodes, result); break; case SyntaxKind.PropertyAccessExpression: result = reduceNode((node).expression, cbNode, result); result = reduceNode((node).name, cbNode, result); break; case SyntaxKind.ElementAccessExpression: result = reduceNode((node).expression, cbNode, result); result = reduceNode((node).argumentExpression, cbNode, result); break; case SyntaxKind.CallExpression: result = reduceNode((node).expression, cbNode, result); result = reduceNodes((node).typeArguments, cbNodes, result); result = reduceNodes((node).arguments, cbNodes, result); break; case SyntaxKind.NewExpression: result = reduceNode((node).expression, cbNode, result); result = reduceNodes((node).typeArguments, cbNodes, result); result = reduceNodes((node).arguments, cbNodes, result); break; case SyntaxKind.TaggedTemplateExpression: result = reduceNode((node).tag, cbNode, result); 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); result = reduceNodes((node).typeParameters, cbNodes, result); result = reduceNodes((node).parameters, cbNodes, result); result = reduceNode((node).type, cbNode, result); result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.ArrowFunction: result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNodes((node).typeParameters, cbNodes, result); result = reduceNodes((node).parameters, cbNodes, result); result = reduceNode((node).type, cbNode, result); result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.ParenthesizedExpression: case SyntaxKind.DeleteExpression: case SyntaxKind.TypeOfExpression: case SyntaxKind.VoidExpression: case SyntaxKind.AwaitExpression: case SyntaxKind.YieldExpression: case SyntaxKind.SpreadElement: case SyntaxKind.NonNullExpression: result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: result = reduceNode((node).operand, cbNode, result); break; case SyntaxKind.BinaryExpression: result = reduceNode((node).left, cbNode, result); result = reduceNode((node).right, cbNode, result); break; case SyntaxKind.ConditionalExpression: result = reduceNode((node).condition, cbNode, result); result = reduceNode((node).whenTrue, cbNode, result); result = reduceNode((node).whenFalse, cbNode, result); break; case SyntaxKind.TemplateExpression: result = reduceNode((node).head, cbNode, result); result = reduceNodes((node).templateSpans, cbNodes, result); break; case SyntaxKind.ClassExpression: result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNode((node).name, cbNode, result); result = reduceNodes((node).typeParameters, cbNodes, result); result = reduceNodes((node).heritageClauses, cbNodes, result); result = reduceNodes((node).members, cbNodes, result); break; case SyntaxKind.ExpressionWithTypeArguments: result = reduceNode((node).expression, cbNode, result); 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); result = reduceNode((node).literal, cbNode, result); break; // Element case SyntaxKind.Block: result = reduceNodes((node).statements, cbNodes, result); break; case SyntaxKind.VariableStatement: result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNode((node).declarationList, cbNode, result); break; case SyntaxKind.ExpressionStatement: result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.IfStatement: result = reduceNode((node).expression, cbNode, result); result = reduceNode((node).thenStatement, cbNode, result); result = reduceNode((node).elseStatement, cbNode, result); break; case SyntaxKind.DoStatement: result = reduceNode((node).statement, cbNode, result); result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.WhileStatement: case SyntaxKind.WithStatement: result = reduceNode((node).expression, cbNode, result); result = reduceNode((node).statement, cbNode, result); break; case SyntaxKind.ForStatement: result = reduceNode((node).initializer, cbNode, result); result = reduceNode((node).condition, cbNode, result); result = reduceNode((node).incrementor, cbNode, result); result = reduceNode((node).statement, cbNode, result); break; case SyntaxKind.ForInStatement: case SyntaxKind.ForOfStatement: result = reduceNode((node).initializer, cbNode, result); result = reduceNode((node).expression, cbNode, result); result = reduceNode((node).statement, cbNode, result); break; case SyntaxKind.ReturnStatement: case SyntaxKind.ThrowStatement: result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.SwitchStatement: result = reduceNode((node).expression, cbNode, result); result = reduceNode((node).caseBlock, cbNode, result); break; case SyntaxKind.LabeledStatement: result = reduceNode((node).label, cbNode, result); result = reduceNode((node).statement, cbNode, result); break; case SyntaxKind.TryStatement: result = reduceNode((node).tryBlock, cbNode, result); result = reduceNode((node).catchClause, cbNode, result); result = reduceNode((node).finallyBlock, cbNode, result); break; case SyntaxKind.VariableDeclaration: result = reduceNode((node).name, cbNode, result); result = reduceNode((node).type, cbNode, result); result = reduceNode((node).initializer, cbNode, result); break; case SyntaxKind.VariableDeclarationList: result = reduceNodes((node).declarations, cbNodes, result); break; case SyntaxKind.FunctionDeclaration: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNode((node).name, cbNode, result); result = reduceNodes((node).typeParameters, cbNodes, result); result = reduceNodes((node).parameters, cbNodes, result); result = reduceNode((node).type, cbNode, result); result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.ClassDeclaration: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result); result = reduceNode((node).name, cbNode, result); result = reduceNodes((node).typeParameters, cbNodes, result); result = reduceNodes((node).heritageClauses, cbNodes, result); 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); result = reduceNode((node).importClause, cbNode, result); result = reduceNode((node).moduleSpecifier, cbNode, result); break; case SyntaxKind.ImportClause: result = reduceNode((node).name, cbNode, result); result = reduceNode((node).namedBindings, cbNode, result); break; case SyntaxKind.NamespaceImport: result = reduceNode((node).name, cbNode, result); break; case SyntaxKind.NamedImports: case SyntaxKind.NamedExports: result = reduceNodes((node).elements, cbNodes, result); break; case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: result = reduceNode((node).propertyName, cbNode, result); result = reduceNode((node).name, cbNode, result); break; case SyntaxKind.ExportAssignment: result = reduceLeft((node).decorators, cbNode, result); result = reduceLeft((node).modifiers, cbNode, result); result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.ExportDeclaration: result = reduceLeft((node).decorators, cbNode, result); result = reduceLeft((node).modifiers, cbNode, result); result = reduceNode((node).exportClause, cbNode, result); 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); result = reduceLeft((node).children, cbNode, result); result = reduceNode((node).closingElement, cbNode, result); break; case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxOpeningElement: result = reduceNode((node).tagName, cbNode, result); result = reduceNode((node).attributes, cbNode, result); break; case SyntaxKind.JsxAttributes: result = reduceNodes((node).properties, cbNodes, result); case SyntaxKind.JsxClosingElement: result = reduceNode((node).tagName, cbNode, result); break; case SyntaxKind.JsxAttribute: result = reduceNode((node).name, cbNode, result); result = reduceNode((node).initializer, cbNode, result); break; case SyntaxKind.JsxSpreadAttribute: result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.JsxExpression: result = reduceNode((node).expression, cbNode, result); break; // Clauses case SyntaxKind.CaseClause: result = reduceNode((node).expression, cbNode, result); // fall-through case SyntaxKind.DefaultClause: result = reduceNodes((node).statements, cbNodes, result); break; case SyntaxKind.HeritageClause: result = reduceNodes((node).types, cbNodes, result); break; case SyntaxKind.CatchClause: result = reduceNode((node).variableDeclaration, cbNode, result); result = reduceNode((node).block, cbNode, result); break; // Property assignments case SyntaxKind.PropertyAssignment: result = reduceNode((node).name, cbNode, result); result = reduceNode((node).initializer, cbNode, result); break; case SyntaxKind.ShorthandPropertyAssignment: result = reduceNode((node).name, cbNode, result); result = reduceNode((node).objectAssignmentInitializer, cbNode, result); break; case SyntaxKind.SpreadAssignment: 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: break; } return result; } /** * Merges generated lexical declarations into a new statement list. */ export function mergeLexicalEnvironment(statements: NodeArray, declarations: Statement[]): NodeArray; /** * Appends generated lexical declarations to an array of statements. */ export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]): Statement[]; export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]) { if (!some(declarations)) { return statements; } return isNodeArray(statements) ? setTextRange(createNodeArray(concatenate(statements, declarations)), statements) : addRange(statements, declarations); } /** * Lifts a NodeArray containing only Statement nodes to a block. * * @param nodes The NodeArray. */ export function liftToBlock(nodes: Node[]): Statement { Debug.assert(every(nodes, isStatement), "Cannot lift nodes to a Block."); return singleOrUndefined(nodes) || createBlock(>nodes); } /** * Aggregates the TransformFlags for a Node and its subtree. */ export function aggregateTransformFlags(node: T): T { aggregateTransformFlagsForNode(node); return node; } /** * Aggregates the TransformFlags for a Node and its subtree. The flags for the subtree are * computed first, then the transform flags for the current node are computed from the subtree * flags and the state of the current node. Finally, the transform flags of the node are * returned, excluding any flags that should not be included in its parent node's subtree * flags. */ function aggregateTransformFlagsForNode(node: Node): TransformFlags { if (node === undefined) { return TransformFlags.None; } if (node.transformFlags & TransformFlags.HasComputedFlags) { return node.transformFlags & ~getTransformFlagsSubtreeExclusions(node.kind); } const subtreeFlags = aggregateTransformFlagsForSubtree(node); return computeTransformFlagsForNode(node, subtreeFlags); } function aggregateTransformFlagsForNodeArray(nodes: NodeArray): TransformFlags { if (nodes === undefined) { return TransformFlags.None; } let subtreeFlags = TransformFlags.None; let nodeArrayFlags = TransformFlags.None; for (const node of nodes) { subtreeFlags |= aggregateTransformFlagsForNode(node); nodeArrayFlags |= node.transformFlags & ~TransformFlags.HasComputedFlags; } nodes.transformFlags = nodeArrayFlags | TransformFlags.HasComputedFlags; return subtreeFlags; } /** * Aggregates the transform flags for the subtree of a node. */ function aggregateTransformFlagsForSubtree(node: Node): TransformFlags { // We do not transform ambient declarations or types, so there is no need to // recursively aggregate transform flags. if (hasModifier(node, ModifierFlags.Ambient) || (isTypeNode(node) && node.kind !== SyntaxKind.ExpressionWithTypeArguments)) { return TransformFlags.None; } // Aggregate the transform flags of each child. return reduceEachChild(node, TransformFlags.None, aggregateTransformFlagsForChildNode, aggregateTransformFlagsForChildNodes); } /** * Aggregates the TransformFlags of a child node with the TransformFlags of its * siblings. */ function aggregateTransformFlagsForChildNode(transformFlags: TransformFlags, node: Node): TransformFlags { return transformFlags | aggregateTransformFlagsForNode(node); } function aggregateTransformFlagsForChildNodes(transformFlags: TransformFlags, nodes: NodeArray): TransformFlags { return transformFlags | aggregateTransformFlagsForNodeArray(nodes); } export namespace Debug { export const failBadSyntaxKind = shouldAssert(AssertionLevel.Normal) ? (node: Node, message?: string) => assert(false, message || "Unexpected node.", () => `Node ${formatSyntaxKind(node.kind)} was unexpected.`) : noop; export const assertEachNode = shouldAssert(AssertionLevel.Normal) ? (nodes: Node[], test: (node: Node) => boolean, message?: string) => assert( test === undefined || every(nodes, test), message || "Unexpected node.", () => `Node array did not pass test '${getFunctionName(test)}'.`) : noop; export const assertNode = shouldAssert(AssertionLevel.Normal) ? (node: Node, test: (node: Node) => boolean, message?: string) => assert( test === undefined || test(node), message || "Unexpected node.", () => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`) : noop; export const assertOptionalNode = shouldAssert(AssertionLevel.Normal) ? (node: Node, test: (node: Node) => boolean, message?: string) => assert( test === undefined || node === undefined || test(node), message || "Unexpected node.", () => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`) : noop; export const assertOptionalToken = shouldAssert(AssertionLevel.Normal) ? (node: Node, kind: SyntaxKind, message?: string) => assert( kind === undefined || node === undefined || node.kind === kind, message || "Unexpected node.", () => `Node ${formatSyntaxKind(node.kind)} was not a '${formatSyntaxKind(kind)}' token.`) : noop; export const assertMissingNode = shouldAssert(AssertionLevel.Normal) ? (node: Node, message?: string) => assert( node === undefined, message || "Unexpected node.", () => `Node ${formatSyntaxKind(node.kind)} was unexpected'.`) : noop; function getFunctionName(func: Function) { if (typeof func !== "function") { return ""; } else if (func.hasOwnProperty("name")) { return (func).name; } else { const text = Function.prototype.toString.call(func); const match = /^function\s+([\w\$]+)\s*\(/.exec(text); return match ? match[1] : ""; } } } }