///
///
///
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((