diff --git a/packages/typescript/src/api/node/node.generated.ts b/packages/typescript/src/api/node/node.generated.ts index aa31609a065..a5f2991ae00 100644 --- a/packages/typescript/src/api/node/node.generated.ts +++ b/packages/typescript/src/api/node/node.generated.ts @@ -69,6 +69,10 @@ export class RemoteNodeList extends Array implements NodeArray implements NodeArray(): Generator { + if (this.hasChildren()) { + let next = this.index + 1; + do { + const child = this.getOrCreateChildAtNodeIndex(next); + if (child instanceof RemoteNodeList) { + if (child.length) { + let listNext = child.firstNodeIndex; + while (listNext) { + const node = child.getOrCreateChildAtNodeIndex(listNext) as RemoteNode; + listNext = node.next; + const result = yield node; + if (result) { + return result; + } + } + } + } + else if (child.kind !== SyntaxKind.JSDoc) { + const result = yield child; + if (result) { + return result; + } + } + next = child.next; + } + while (next); + } + } + get jsDoc(): readonly Node[] | undefined { if (!this.hasChildren()) { return undefined; diff --git a/packages/typescript/src/ast/ast.ts b/packages/typescript/src/ast/ast.ts index 39433d7b228..01d810f8a2d 100644 --- a/packages/typescript/src/ast/ast.ts +++ b/packages/typescript/src/ast/ast.ts @@ -90,6 +90,7 @@ export interface Node extends ReadonlyTextRange { readonly flags: NodeFlags; readonly parent: Node; readonly jsDoc?: readonly Node[] | undefined; + childrenIter(): Generator; forEachChild(visitor: (node: Node) => T, visitArray?: (nodes: NodeArray) => T): T | undefined; getSourceFile(): SourceFile; getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number; diff --git a/packages/typescript/src/ast/factory.generated.ts b/packages/typescript/src/ast/factory.generated.ts index fa11c564e58..1908faff433 100644 --- a/packages/typescript/src/ast/factory.generated.ts +++ b/packages/typescript/src/ast/factory.generated.ts @@ -268,6 +268,8 @@ import { cloneSourceFileData } from "./utils.ts"; import { forEachChildOfJSDocParameterTag, forEachChildOfJSDocPropertyTag, + yieldEachChildOfJSDocParameterTag, + yieldEachChildOfJSDocPropertyTag, } from "./visitor.ts"; export class NodeObject { @@ -691,6 +693,11 @@ export class NodeObject { return fn ? fn(this._data, visitor, visitArray) : undefined; } + childrenIter(): Generator { + const fn = yieldEachChildTable[this.kind]; + return fn ? fn(this._data) : emptyChildrenIter(); + } + getSourceFile(): SourceFile { let node: Node = this as unknown as Node; while (node.parent) node = node.parent; @@ -1690,6 +1697,2231 @@ const forEachChildTable: Record = { visitNode(cbNode, data.endOfFileToken), }; +type YieldEachChildFunction = (data: any) => Generator; + +function* emptyChildrenIter(): Generator { + return undefined; +} + +const yieldEachChildTable: Record = { + [SyntaxKind.QualifiedName]: function* (data) { + if (data.left) { + const res = yield data.left; + if (res) return res; + } + if (data.right) { + const res = yield data.right; + if (res) return res; + } + }, + [SyntaxKind.ComputedPropertyName]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.Decorator]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.IfStatement]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.thenStatement) { + const res = yield data.thenStatement; + if (res) return res; + } + if (data.elseStatement) { + const res = yield data.elseStatement; + if (res) return res; + } + }, + [SyntaxKind.DoStatement]: function* (data) { + if (data.statement) { + const res = yield data.statement; + if (res) return res; + } + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.WhileStatement]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.statement) { + const res = yield data.statement; + if (res) return res; + } + }, + [SyntaxKind.ForStatement]: function* (data) { + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + if (data.condition) { + const res = yield data.condition; + if (res) return res; + } + if (data.incrementor) { + const res = yield data.incrementor; + if (res) return res; + } + if (data.statement) { + const res = yield data.statement; + if (res) return res; + } + }, + [SyntaxKind.BreakStatement]: function* (data) { + if (data.label) { + const res = yield data.label; + if (res) return res; + } + }, + [SyntaxKind.ContinueStatement]: function* (data) { + if (data.label) { + const res = yield data.label; + if (res) return res; + } + }, + [SyntaxKind.ReturnStatement]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.WithStatement]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.statement) { + const res = yield data.statement; + if (res) return res; + } + }, + [SyntaxKind.SwitchStatement]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.caseBlock) { + const res = yield data.caseBlock; + if (res) return res; + } + }, + [SyntaxKind.CaseBlock]: function* (data) { + for (const n of data.clauses) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.ThrowStatement]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.TryStatement]: function* (data) { + if (data.tryBlock) { + const res = yield data.tryBlock; + if (res) return res; + } + if (data.catchClause) { + const res = yield data.catchClause; + if (res) return res; + } + if (data.finallyBlock) { + const res = yield data.finallyBlock; + if (res) return res; + } + }, + [SyntaxKind.CatchClause]: function* (data) { + if (data.variableDeclaration) { + const res = yield data.variableDeclaration; + if (res) return res; + } + if (data.block) { + const res = yield data.block; + if (res) return res; + } + }, + [SyntaxKind.LabeledStatement]: function* (data) { + if (data.label) { + const res = yield data.label; + if (res) return res; + } + if (data.statement) { + const res = yield data.statement; + if (res) return res; + } + }, + [SyntaxKind.ExpressionStatement]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.Block]: function* (data) { + for (const n of data.statements) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.VariableStatement]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.declarationList) { + const res = yield data.declarationList; + if (res) return res; + } + }, + [SyntaxKind.VariableDeclaration]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.exclamationToken) { + const res = yield data.exclamationToken; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + }, + [SyntaxKind.VariableDeclarationList]: function* (data) { + for (const n of data.declarations) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.Parameter]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.dotDotDotToken) { + const res = yield data.dotDotDotToken; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.questionToken) { + const res = yield data.questionToken; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + }, + [SyntaxKind.BindingElement]: function* (data) { + if (data.dotDotDotToken) { + const res = yield data.dotDotDotToken; + if (res) return res; + } + if (data.propertyName) { + const res = yield data.propertyName; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + }, + [SyntaxKind.MissingDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.FunctionDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.asteriskToken) { + const res = yield data.asteriskToken; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.body) { + const res = yield data.body; + if (res) return res; + } + }, + [SyntaxKind.ClassDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + if (data.heritageClauses) { + for (const n of data.heritageClauses) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.members) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.ClassExpression]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + if (data.heritageClauses) { + for (const n of data.heritageClauses) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.members) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.HeritageClause]: function* (data) { + for (const n of data.types) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.InterfaceDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + if (data.heritageClauses) { + for (const n of data.heritageClauses) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.members) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.TypeAliasDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.JSTypeAliasDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.EnumMember]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + }, + [SyntaxKind.EnumDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + for (const n of data.members) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.ModuleBlock]: function* (data) { + for (const n of data.statements) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.ImportDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.importClause) { + const res = yield data.importClause; + if (res) return res; + } + if (data.moduleSpecifier) { + const res = yield data.moduleSpecifier; + if (res) return res; + } + if (data.attributes) { + const res = yield data.attributes; + if (res) return res; + } + }, + [SyntaxKind.JSImportDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.importClause) { + const res = yield data.importClause; + if (res) return res; + } + if (data.moduleSpecifier) { + const res = yield data.moduleSpecifier; + if (res) return res; + } + if (data.attributes) { + const res = yield data.attributes; + if (res) return res; + } + }, + [SyntaxKind.ExternalModuleReference]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.NamespaceImport]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.NamedImports]: function* (data) { + for (const n of data.elements) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.ExportAssignment]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.NamespaceExportDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.NamespaceExport]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.NamedExports]: function* (data) { + for (const n of data.elements) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.ExportSpecifier]: function* (data) { + if (data.propertyName) { + const res = yield data.propertyName; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.CallSignature]: function* (data) { + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.ConstructSignature]: function* (data) { + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.Constructor]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.body) { + const res = yield data.body; + if (res) return res; + } + }, + [SyntaxKind.GetAccessor]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.body) { + const res = yield data.body; + if (res) return res; + } + }, + [SyntaxKind.SetAccessor]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.body) { + const res = yield data.body; + if (res) return res; + } + }, + [SyntaxKind.IndexSignature]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.MethodSignature]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.postfixToken) { + const res = yield data.postfixToken; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.MethodDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.asteriskToken) { + const res = yield data.asteriskToken; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.postfixToken) { + const res = yield data.postfixToken; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.body) { + const res = yield data.body; + if (res) return res; + } + }, + [SyntaxKind.PropertySignature]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.postfixToken) { + const res = yield data.postfixToken; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + }, + [SyntaxKind.PropertyDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.postfixToken) { + const res = yield data.postfixToken; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + }, + [SyntaxKind.ClassStaticBlockDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.body) { + const res = yield data.body; + if (res) return res; + } + }, + [SyntaxKind.BinaryExpression]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.left) { + const res = yield data.left; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.operatorToken) { + const res = yield data.operatorToken; + if (res) return res; + } + if (data.right) { + const res = yield data.right; + if (res) return res; + } + }, + [SyntaxKind.PrefixUnaryExpression]: function* (data) { + if (data.operand) { + const res = yield data.operand; + if (res) return res; + } + }, + [SyntaxKind.PostfixUnaryExpression]: function* (data) { + if (data.operand) { + const res = yield data.operand; + if (res) return res; + } + }, + [SyntaxKind.YieldExpression]: function* (data) { + if (data.asteriskToken) { + const res = yield data.asteriskToken; + if (res) return res; + } + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.ArrowFunction]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.equalsGreaterThanToken) { + const res = yield data.equalsGreaterThanToken; + if (res) return res; + } + if (data.body) { + const res = yield data.body; + if (res) return res; + } + }, + [SyntaxKind.FunctionExpression]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.asteriskToken) { + const res = yield data.asteriskToken; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.body) { + const res = yield data.body; + if (res) return res; + } + }, + [SyntaxKind.AsExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.SatisfiesExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.ConditionalExpression]: function* (data) { + if (data.condition) { + const res = yield data.condition; + if (res) return res; + } + if (data.questionToken) { + const res = yield data.questionToken; + if (res) return res; + } + if (data.whenTrue) { + const res = yield data.whenTrue; + if (res) return res; + } + if (data.colonToken) { + const res = yield data.colonToken; + if (res) return res; + } + if (data.whenFalse) { + const res = yield data.whenFalse; + if (res) return res; + } + }, + [SyntaxKind.PropertyAccessExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.questionDotToken) { + const res = yield data.questionDotToken; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.ElementAccessExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.questionDotToken) { + const res = yield data.questionDotToken; + if (res) return res; + } + if (data.argumentExpression) { + const res = yield data.argumentExpression; + if (res) return res; + } + }, + [SyntaxKind.CallExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.questionDotToken) { + const res = yield data.questionDotToken; + if (res) return res; + } + if (data.typeArguments) { + for (const n of data.typeArguments) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.arguments) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.NewExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.typeArguments) { + for (const n of data.typeArguments) { + const res = yield n; + if (res) return res; + } + } + if (data.arguments) { + for (const n of data.arguments) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.MetaProperty]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.NonNullExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.SpreadElement]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.TemplateExpression]: function* (data) { + if (data.head) { + const res = yield data.head; + if (res) return res; + } + for (const n of data.templateSpans) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.TemplateSpan]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.literal) { + const res = yield data.literal; + if (res) return res; + } + }, + [SyntaxKind.TaggedTemplateExpression]: function* (data) { + if (data.tag) { + const res = yield data.tag; + if (res) return res; + } + if (data.questionDotToken) { + const res = yield data.questionDotToken; + if (res) return res; + } + if (data.typeArguments) { + for (const n of data.typeArguments) { + const res = yield n; + if (res) return res; + } + } + if (data.template) { + const res = yield data.template; + if (res) return res; + } + }, + [SyntaxKind.ParenthesizedExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.ArrayLiteralExpression]: function* (data) { + for (const n of data.elements) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.ObjectLiteralExpression]: function* (data) { + for (const n of data.properties) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.SpreadAssignment]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.PropertyAssignment]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.postfixToken) { + const res = yield data.postfixToken; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + }, + [SyntaxKind.ShorthandPropertyAssignment]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.postfixToken) { + const res = yield data.postfixToken; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.equalsToken) { + const res = yield data.equalsToken; + if (res) return res; + } + if (data.objectAssignmentInitializer) { + const res = yield data.objectAssignmentInitializer; + if (res) return res; + } + }, + [SyntaxKind.DeleteExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.TypeOfExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.VoidExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.AwaitExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.TypeAssertionExpression]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.UnionType]: function* (data) { + for (const n of data.types) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.IntersectionType]: function* (data) { + for (const n of data.types) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.ConditionalType]: function* (data) { + if (data.checkType) { + const res = yield data.checkType; + if (res) return res; + } + if (data.extendsType) { + const res = yield data.extendsType; + if (res) return res; + } + if (data.trueType) { + const res = yield data.trueType; + if (res) return res; + } + if (data.falseType) { + const res = yield data.falseType; + if (res) return res; + } + }, + [SyntaxKind.TypeOperator]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.InferType]: function* (data) { + if (data.typeParameter) { + const res = yield data.typeParameter; + if (res) return res; + } + }, + [SyntaxKind.ArrayType]: function* (data) { + if (data.elementType) { + const res = yield data.elementType; + if (res) return res; + } + }, + [SyntaxKind.IndexedAccessType]: function* (data) { + if (data.objectType) { + const res = yield data.objectType; + if (res) return res; + } + if (data.indexType) { + const res = yield data.indexType; + if (res) return res; + } + }, + [SyntaxKind.TypeReference]: function* (data) { + if (data.typeName) { + const res = yield data.typeName; + if (res) return res; + } + if (data.typeArguments) { + for (const n of data.typeArguments) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.ExpressionWithTypeArguments]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.typeArguments) { + for (const n of data.typeArguments) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.LiteralType]: function* (data) { + if (data.literal) { + const res = yield data.literal; + if (res) return res; + } + }, + [SyntaxKind.TypePredicate]: function* (data) { + if (data.assertsModifier) { + const res = yield data.assertsModifier; + if (res) return res; + } + if (data.parameterName) { + const res = yield data.parameterName; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.ImportAttribute]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.value) { + const res = yield data.value; + if (res) return res; + } + }, + [SyntaxKind.ImportAttributes]: function* (data) { + for (const n of data.attributes) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.TypeQuery]: function* (data) { + if (data.exprName) { + const res = yield data.exprName; + if (res) return res; + } + if (data.typeArguments) { + for (const n of data.typeArguments) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.MappedType]: function* (data) { + if (data.readonlyToken) { + const res = yield data.readonlyToken; + if (res) return res; + } + if (data.typeParameter) { + const res = yield data.typeParameter; + if (res) return res; + } + if (data.nameType) { + const res = yield data.nameType; + if (res) return res; + } + if (data.questionToken) { + const res = yield data.questionToken; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.members) { + for (const n of data.members) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.TypeLiteral]: function* (data) { + for (const n of data.members) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.TupleType]: function* (data) { + for (const n of data.elements) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.NamedTupleMember]: function* (data) { + if (data.dotDotDotToken) { + const res = yield data.dotDotDotToken; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.questionToken) { + const res = yield data.questionToken; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.OptionalType]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.RestType]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.ParenthesizedType]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.FunctionType]: function* (data) { + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.ConstructorType]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.TemplateLiteralType]: function* (data) { + if (data.head) { + const res = yield data.head; + if (res) return res; + } + for (const n of data.templateSpans) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.TemplateLiteralTypeSpan]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + if (data.literal) { + const res = yield data.literal; + if (res) return res; + } + }, + [SyntaxKind.SyntheticExpression]: function* (data) { + if (data.tupleNameSource) { + const res = yield data.tupleNameSource; + if (res) return res; + } + }, + [SyntaxKind.PartiallyEmittedExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.JsxElement]: function* (data) { + if (data.openingElement) { + const res = yield data.openingElement; + if (res) return res; + } + for (const n of data.children) { + const res = yield n; + if (res) return res; + } + if (data.closingElement) { + const res = yield data.closingElement; + if (res) return res; + } + }, + [SyntaxKind.JsxAttributes]: function* (data) { + for (const n of data.properties) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.JsxNamespacedName]: function* (data) { + if (data.namespace) { + const res = yield data.namespace; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.JsxOpeningElement]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.typeArguments) { + for (const n of data.typeArguments) { + const res = yield n; + if (res) return res; + } + } + if (data.attributes) { + const res = yield data.attributes; + if (res) return res; + } + }, + [SyntaxKind.JsxSelfClosingElement]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.typeArguments) { + for (const n of data.typeArguments) { + const res = yield n; + if (res) return res; + } + } + if (data.attributes) { + const res = yield data.attributes; + if (res) return res; + } + }, + [SyntaxKind.JsxFragment]: function* (data) { + if (data.openingFragment) { + const res = yield data.openingFragment; + if (res) return res; + } + for (const n of data.children) { + const res = yield n; + if (res) return res; + } + if (data.closingFragment) { + const res = yield data.closingFragment; + if (res) return res; + } + }, + [SyntaxKind.JsxAttribute]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + }, + [SyntaxKind.JsxSpreadAttribute]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.JsxClosingElement]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + }, + [SyntaxKind.JsxExpression]: function* (data) { + if (data.dotDotDotToken) { + const res = yield data.dotDotDotToken; + if (res) return res; + } + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + }, + [SyntaxKind.SyntaxList]: function* (data) { + for (const n of data.children) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.JSDoc]: function* (data) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + if (data.tags) { + for (const n of data.tags) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocTypeExpression]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.JSDocNonNullableType]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.JSDocNullableType]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.JSDocVariadicType]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.JSDocOptionalType]: function* (data) { + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.JSDocTypeTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.typeExpression) { + const res = yield data.typeExpression; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocUnknownTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocTemplateTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.constraint) { + const res = yield data.constraint; + if (res) return res; + } + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocReturnTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.typeExpression) { + const res = yield data.typeExpression; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocPublicTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocPrivateTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocProtectedTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocReadonlyTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocOverrideTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocDeprecatedTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocSeeTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.nameExpression) { + const res = yield data.nameExpression; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocImplementsTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.className) { + const res = yield data.className; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocAugmentsTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.className) { + const res = yield data.className; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocSatisfiesTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.typeExpression) { + const res = yield data.typeExpression; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocThrowsTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.typeExpression) { + const res = yield data.typeExpression; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocThisTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.typeExpression) { + const res = yield data.typeExpression; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocImportTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.importClause) { + const res = yield data.importClause; + if (res) return res; + } + if (data.moduleSpecifier) { + const res = yield data.moduleSpecifier; + if (res) return res; + } + if (data.attributes) { + const res = yield data.attributes; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocCallbackTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.typeExpression) { + const res = yield data.typeExpression; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocOverloadTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.typeExpression) { + const res = yield data.typeExpression; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocTypedefTag]: function* (data) { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.typeExpression) { + const res = yield data.typeExpression; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.comment) { + for (const n of data.comment) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.JSDocSignature]: function* (data) { + if (data.typeParameters) { + for (const n of data.typeParameters) { + const res = yield n; + if (res) return res; + } + } + for (const n of data.parameters) { + const res = yield n; + if (res) return res; + } + if (data.type) { + const res = yield data.type; + if (res) return res; + } + }, + [SyntaxKind.JSDocNameReference]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.ModuleDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.attributes) { + const res = yield data.attributes; + if (res) return res; + } + if (data.body) { + const res = yield data.body; + if (res) return res; + } + }, + [SyntaxKind.ImportEqualsDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.moduleReference) { + const res = yield data.moduleReference; + if (res) return res; + } + }, + [SyntaxKind.ExportDeclaration]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.exportClause) { + const res = yield data.exportClause; + if (res) return res; + } + if (data.moduleSpecifier) { + const res = yield data.moduleSpecifier; + if (res) return res; + } + if (data.attributes) { + const res = yield data.attributes; + if (res) return res; + } + }, + [SyntaxKind.ImportType]: function* (data) { + if (data.argument) { + const res = yield data.argument; + if (res) return res; + } + if (data.attributes) { + const res = yield data.attributes; + if (res) return res; + } + if (data.qualifier) { + const res = yield data.qualifier; + if (res) return res; + } + if (data.typeArguments) { + for (const n of data.typeArguments) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.ImportClause]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.namedBindings) { + const res = yield data.namedBindings; + if (res) return res; + } + }, + [SyntaxKind.ImportSpecifier]: function* (data) { + if (data.propertyName) { + const res = yield data.propertyName; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.JSDocLink]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.JSDocLinkPlain]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.JSDocLinkCode]: function* (data) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + }, + [SyntaxKind.TypeParameter]: function* (data) { + if (data.modifiers) { + for (const n of data.modifiers) { + const res = yield n; + if (res) return res; + } + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.constraint) { + const res = yield data.constraint; + if (res) return res; + } + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.defaultType) { + const res = yield data.defaultType; + if (res) return res; + } + }, + [SyntaxKind.SyntheticReferenceExpression]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.thisArg) { + const res = yield data.thisArg; + if (res) return res; + } + }, + [SyntaxKind.JSDocTypeLiteral]: function* (data) { + if (data.jsdocPropertyTags) { + for (const n of data.jsdocPropertyTags) { + const res = yield n; + if (res) return res; + } + } + }, + [SyntaxKind.ForInStatement]: function* (data) { + if (data.awaitModifier) { + const res = yield data.awaitModifier; + if (res) return res; + } + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.statement) { + const res = yield data.statement; + if (res) return res; + } + }, + [SyntaxKind.ForOfStatement]: function* (data) { + if (data.awaitModifier) { + const res = yield data.awaitModifier; + if (res) return res; + } + if (data.initializer) { + const res = yield data.initializer; + if (res) return res; + } + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + if (data.statement) { + const res = yield data.statement; + if (res) return res; + } + }, + [SyntaxKind.CaseClause]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + for (const n of data.statements) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.DefaultClause]: function* (data) { + if (data.expression) { + const res = yield data.expression; + if (res) return res; + } + for (const n of data.statements) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.ObjectBindingPattern]: function* (data) { + for (const n of data.elements) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.ArrayBindingPattern]: function* (data) { + for (const n of data.elements) { + const res = yield n; + if (res) return res; + } + }, + [SyntaxKind.JSDocParameterTag]: yieldEachChildOfJSDocParameterTag, + [SyntaxKind.JSDocPropertyTag]: yieldEachChildOfJSDocPropertyTag, + [SyntaxKind.SourceFile]: function* (data) { + for (const n of data.statements) { + const res = yield n; + if (res) return res; + } + const res = yield data.endOfFileToken; + if (res) return res; + }, +}; + function visitNode(cbNode: (node: Node) => T, node: Node | undefined): T | undefined { return node ? cbNode(node) : undefined; } diff --git a/packages/typescript/src/ast/visitor.ts b/packages/typescript/src/ast/visitor.ts index 09438ab524a..c26259a4651 100644 --- a/packages/typescript/src/ast/visitor.ts +++ b/packages/typescript/src/ast/visitor.ts @@ -59,6 +59,43 @@ function forEachChildOfJSDocParameterOrPropertyTag(data: any, cbNode: (node: export { forEachChildOfJSDocParameterOrPropertyTag as forEachChildOfJSDocParameterTag, forEachChildOfJSDocParameterOrPropertyTag as forEachChildOfJSDocPropertyTag }; +// ── yieldEachChild implementations ── + +function* yieldEachChildOfJSDocParameterOrPropertyTag(data: any): Generator { + if (data.tagName) { + const res = yield data.tagName; + if (res) return res; + } + if (data.isNameFirst) { + if (data.name) { + const res = yield data.name; + if (res) return res; + } + if (data.typeExpression) { + const res = yield data.typeExpression; + if (res) return res; + } + } + else { + if (data.typeExpression) { + const res = yield data.typeExpression; + if (res) return res; + } + if (data.name) { + const res = yield data.name; + if (res) return res; + } + } + if (data.comment) { + for (const node of data.comment) { + const res = yield node; + if (res) return res; + } + } +} + +export { yieldEachChildOfJSDocParameterOrPropertyTag as yieldEachChildOfJSDocParameterTag, yieldEachChildOfJSDocParameterOrPropertyTag as yieldEachChildOfJSDocPropertyTag }; + // ── visitEachChild implementations ── function visitEachChildOfJSDocParameterOrPropertyTag(node: JSDocParameterOrPropertyTag, visitor: Visitor): JSDocParameterOrPropertyTag { diff --git a/packages/typescript/test/sync/ast.bench.ts b/packages/typescript/test/sync/ast.bench.ts new file mode 100644 index 00000000000..96ed71526ec --- /dev/null +++ b/packages/typescript/test/sync/ast.bench.ts @@ -0,0 +1,218 @@ +// Benchmarks Node.childrenIter against Node.forEachChild for local factory nodes +// and RemoteNodes fetched through the sync API. +// +// Run with: +// npm run node -- test/sync/ast.bench.ts +// npm run node -- test/sync/ast.bench.ts --filter "remote recursive" + +import type { + Block, + Identifier, + Node, +} from "@typescript/typescript/unstable/ast"; +import { + isBlock, + isIdentifier, +} from "@typescript/typescript/unstable/ast"; +import { + createBlock, + createExpressionStatement, + createIdentifier, + createIfStatement, +} from "@typescript/typescript/unstable/ast/factory"; +import { createVirtualFileSystem } from "@typescript/typescript/unstable/fs"; +import { API } from "@typescript/typescript/unstable/sync"; +import assert from "node:assert/strict"; +import { fileURLToPath } from "node:url"; +import { parseArgs } from "node:util"; +import { Bench } from "tinybench"; + +const treeDepth = 5; +const expressionsPerBlock = 6; +const earlyTargetName = "earlyTargetIdentifier"; +const midpointTargetName = "midpointTargetIdentifier"; + +const isMain = process.argv[1] === fileURLToPath(import.meta.url); +if (isMain) { + const { values } = parseArgs({ + options: { + filter: { type: "string" }, + singleIteration: { type: "boolean", default: false }, + }, + }); + runBenchmarks(values); +} + +interface Tree { + node: Block; + source: string; +} + +function createTree(depth = treeDepth, path = "root"): Tree { + const statements = []; + const sourceStatements: string[] = []; + for (let i = 0; i < expressionsPerBlock; i++) { + const name = path === "root" && i === 0 + ? earlyTargetName + : path === "root_1" && i === 0 + ? midpointTargetName + : `value_${path}_${i}`; + statements.push(createExpressionStatement(createIdentifier(name))); + sourceStatements.push(`${name};`); + } + + if (depth > 0) { + const thenTree = createTree(depth - 1, `${path}_0`); + const elseTree = createTree(depth - 1, `${path}_1`); + const conditionName = `condition_${path}`; + statements.push(createIfStatement( + createIdentifier(conditionName), + thenTree.node, + elseTree.node, + )); + sourceStatements.push(`if (${conditionName}) ${thenTree.source} else ${elseTree.source}`); + } + + return { + node: createBlock(statements), + source: `{${sourceStatements.join("\n")}}`, + }; +} + +function collectWithForEachChild(node: Node): Node[] { + const children: Node[] = []; + node.forEachChild(child => { + children.push(child); + return undefined; + }); + return children; +} + +function collectWithChildrenIter(node: Node): Node[] { + const children: Node[] = []; + for (const child of node.childrenIter()) { + children.push(child); + } + return children; +} + +function walkWithForEachChild(node: Node): number { + let count = 1; + node.forEachChild(child => { + count += walkWithForEachChild(child); + }); + return count; +} + +function walkWithChildrenIter(node: Node): number { + let count = 1; + for (const child of node.childrenIter()) { + count += walkWithChildrenIter(child); + } + return count; +} + +function findWithForEachChild(node: Node, targetName: string): Identifier | undefined { + return node.forEachChild(child => { + if (isIdentifier(child) && child.text === targetName) return child; + return findWithForEachChild(child, targetName); + }); +} + +function findWithChildrenIter(node: Node, targetName: string): Identifier | undefined { + for (const child of node.childrenIter()) { + if (isIdentifier(child) && child.text === targetName) return child; + const result = findWithChildrenIter(child, targetName); + if (result) return result; + } + return undefined; +} + +export function runBenchmarks(options?: { filter?: string; singleIteration?: boolean; }): void { + const { filter, singleIteration } = options ?? {}; + const localTree = createTree(); + const repoRoot = fileURLToPath(new URL("../../../../", import.meta.url).toString()); + const configPath = "/tsconfig.json"; + const sourcePath = "/src/bench.ts"; + using api = new API({ + cwd: repoRoot, + tsserverPath: fileURLToPath(new URL(`../../../../built/local/tsc${process.platform === "win32" ? ".exe" : ""}`, import.meta.url).toString()), + fs: createVirtualFileSystem({ + [configPath]: "{}", + [sourcePath]: localTree.source, + }), + }); + + const snapshot = api.createSnapshot({ openProject: configPath }); + const remoteSourceFile = snapshot.getConfiguredProject(configPath)!.program.getSourceFile(sourcePath)!; + assert.ok(remoteSourceFile.statements); + const remoteTree = remoteSourceFile.statements[0]; + assert.ok(isBlock(remoteTree)); + + assert.deepStrictEqual( + collectWithChildrenIter(localTree.node).map(node => node.kind), + collectWithForEachChild(localTree.node).map(node => node.kind), + ); + assert.strictEqual(walkWithChildrenIter(localTree.node), walkWithForEachChild(localTree.node)); + assert.strictEqual(walkWithChildrenIter(remoteTree), walkWithForEachChild(remoteTree)); + assert.strictEqual(walkWithChildrenIter(localTree.node), walkWithChildrenIter(remoteTree)); + for (const targetName of [earlyTargetName, midpointTargetName]) { + assert.strictEqual(findWithChildrenIter(localTree.node, targetName)?.text, targetName); + assert.strictEqual(findWithForEachChild(remoteTree, targetName)?.text, targetName); + } + + const bench = new Bench({ + name: "AST child traversal", + iterations: 30, + warmupIterations: 10, + ...singleIteration ? { + iterations: 1, + warmup: false, + time: 0, + } : undefined, + }); + const isAsync = false; + + for (const [nodeType, node] of [["factory", localTree.node], ["remote", remoteTree]] as const) { + bench + .add(`${nodeType} immediate children - forEachChild`, () => { + assert.strictEqual(collectWithForEachChild(node).length, node.statements.length); + }, { async: isAsync }) + .add(`${nodeType} immediate children - childrenIter`, () => { + assert.strictEqual(collectWithChildrenIter(node).length, node.statements.length); + }, { async: isAsync }) + .add(`${nodeType} recursive walk - forEachChild`, () => { + assert.ok(walkWithForEachChild(node) > 1); + }, { async: isAsync }) + .add(`${nodeType} recursive walk - childrenIter`, () => { + assert.ok(walkWithChildrenIter(node) > 1); + }, { async: isAsync }) + .add(`${nodeType} recursive early exit - forEachChild`, () => { + assert.strictEqual(findWithForEachChild(node, earlyTargetName)?.text, earlyTargetName); + }, { async: isAsync }) + .add(`${nodeType} recursive early exit - childrenIter`, () => { + assert.strictEqual(findWithChildrenIter(node, earlyTargetName)?.text, earlyTargetName); + }, { async: isAsync }) + .add(`${nodeType} recursive midpoint exit - forEachChild`, () => { + assert.strictEqual(findWithForEachChild(node, midpointTargetName)?.text, midpointTargetName); + }, { async: isAsync }) + .add(`${nodeType} recursive midpoint exit - childrenIter`, () => { + assert.strictEqual(findWithChildrenIter(node, midpointTargetName)?.text, midpointTargetName); + }, { async: isAsync }); + } + + if (filter) { + const pattern = filter.toLowerCase(); + for (const task of [...bench.tasks]) { + if (!task.name.toLowerCase().includes(pattern)) { + bench.remove(task.name); + } + } + } + + bench.runSync(); + for (const task of bench.tasks) { + if (task.result && "error" in task.result) throw task.result.error; + } + console.table(bench.table()); +} diff --git a/packages/typescript/test/sync/ast.test.ts b/packages/typescript/test/sync/ast.test.ts index 59c8a6fb460..f5284f5b223 100644 --- a/packages/typescript/test/sync/ast.test.ts +++ b/packages/typescript/test/sync/ast.test.ts @@ -31,6 +31,7 @@ import { createExpressionStatement, createIdentifier, createIfStatement, + createMissingDeclaration, createNodeArray, createNumericLiteral, createSourceFile, @@ -44,13 +45,18 @@ import { visitNodes, } from "@typescript/typescript/unstable/ast/visitor"; import { createVirtualFileSystem } from "@typescript/typescript/unstable/fs"; -import { API } from "@typescript/typescript/unstable/sync"; +import { + API, + Checker, + TypeFlags, +} from "@typescript/typescript/unstable/sync"; import assert from "node:assert"; import { describe, test, } from "node:test"; import { fileURLToPath } from "node:url"; +import { runBenchmarks } from "./ast.bench.ts"; // --------------------------------------------------------------------------- // Helpers @@ -65,6 +71,17 @@ function collectKinds(node: Node): SyntaxKind[] { return kinds; } +describe("NodeObject + childrenIter", () => { + test("skips absent optional child lists", () => { + const node = createMissingDeclaration(); + assert.deepStrictEqual([...node.childrenIter()], []); + }); +}); + +test("Benchmarks", async () => { + await runBenchmarks({ singleIteration: true }); +}); + // --------------------------------------------------------------------------- // cloneNode // --------------------------------------------------------------------------- @@ -575,10 +592,14 @@ function spawnAPI(files: Record = { }); } -function getRemoteSourceFile(api: API, configPath: string, filePath: string) { +function getRemoteSourceFileAndChecker(api: API, configPath: string, filePath: string) { const snapshot = api.createSnapshot({ openProject: configPath }); const project = snapshot.getConfiguredProject(configPath)!; - return project.program.getSourceFile(filePath)!; + return [project.program.getSourceFile(filePath)!, project.checker] as const; +} + +function getRemoteSourceFile(api: API, configPath: string, filePath: string) { + return getRemoteSourceFileAndChecker(api, configPath, filePath)[0]; } describe("RemoteNode + cloneNode", () => { @@ -1051,6 +1072,17 @@ describe("RemoteNode + child/token getters", () => { } } + async function withFirstStatementAsync(source: string, fn: (stmt: Node, sf: SourceFile, api: API, checker: Checker) => Promise) { + const api = spawnAPI({ "/tsconfig.json": "{}", "/src/children.ts": source }); + try { + const [sf, checker] = getRemoteSourceFileAndChecker(api, "/tsconfig.json", "/src/children.ts"); + await fn(sf.statements[0], sf, api, checker); + } + finally { + api.close(); + } + } + function findFirstOfKind(node: Node, kind: SyntaxKind): Node | undefined { let found: Node | undefined; const walk = (n: Node): undefined => { @@ -1065,6 +1097,54 @@ describe("RemoteNode + child/token getters", () => { return found; } + test("childrenIter generates all node children and supports early return value passthru", () => { + withFirstStatement("if (x) {}", stmt => { + const texts: string[] = []; + for (const c of stmt.childrenIter()) { + texts.push(c.getText()); + } + assert.deepStrictEqual(texts, ["x", "{}"]); + const cGen = stmt.childrenIter(); + let state = cGen.next(); + while (!state.done) { + const n = state.value; + let foundX: Node | undefined; + if (n.getText() === "x") { + foundX = n; + } + state = cGen.next(foundX); + } + assert.strictEqual( + state.value, + stmt.forEachChild(n => { + return n; + }), + ); + }); + }); + + test("childrenIter works with async generators", async () => { + await withFirstStatementAsync("class X { p: any }", async (stmt, sf, api, checker) => { + async function* visitNodeForFirstAnyChild(node: Node): AsyncGenerator { + for (const n of node.childrenIter()) { + const t = await checker.getTypeAtLocation(n); + if (t.flags & TypeFlags.Any) return n; + const res = yield* visitNodeForFirstAnyChild(n); + if (res) return res; + } + } + const res = (await visitNodeForFirstAnyChild(stmt).next()).value; + assert.strictEqual(res!.getText(), "p: any"); + }); + }); + + test("childrenIter skips empty NodeArrays", () => { + withFirstStatement("function f() {}", stmt => { + const body = findFirstOfKind(stmt, SyntaxKind.Block)!; + assert.deepStrictEqual([...body.childrenIter()], []); + }); + }); + test("getChildren materializes the punctuation/keyword tokens the AST omits", () => { withFirstStatement("if (x) {}", stmt => { const texts = stmt.getChildren().map(c => c.getText()); diff --git a/tools/scripts/tsc/generate-encoder.ts b/tools/scripts/tsc/generate-encoder.ts index b0c9f9e5f57..b7d7157423f 100644 --- a/tools/scripts/tsc/generate-encoder.ts +++ b/tools/scripts/tsc/generate-encoder.ts @@ -1544,6 +1544,10 @@ function emitRemoteNodeList(w: CodeWriter) { w.write(` return this.view.getUint32(this._byteIndex + NODE_OFFSET_NEXT, true);`); w.write(` }`); w.write(``); + w.write(` get firstNodeIndex(): number {`); + w.write(` return this.index + 1;`); + w.write(` }`); + w.write(``); w.write(` private get data(): number {`); w.write(` return this.view.getUint32(this._byteIndex + NODE_OFFSET_DATA, true);`); w.write(` }`); @@ -1635,7 +1639,7 @@ function emitRemoteNodeList(w: CodeWriter) { w.write(` return this.getOrCreateChildAtNodeIndex(next) as RemoteNode;`); w.write(` }`); w.write(``); - w.write(` private getOrCreateChildAtNodeIndex(index: number): RemoteNode | RemoteNodeList {`); + w.write(` getOrCreateChildAtNodeIndex(index: number): RemoteNode | RemoteNodeList {`); w.write(` let child = this.sourceFile.nodes[index];`); w.write(` if (!child) {`); w.write(` const kind = this.view.getUint32(this.sourceFile._offsetNodes + index * NODE_LEN + NODE_OFFSET_KIND, true);`); @@ -1708,6 +1712,36 @@ function emitRemoteNodeClassOpen(w: CodeWriter) { w.write(` }`); w.write(` }`); w.write(``); + w.write(` *childrenIter(): Generator {`); + w.write(` if (this.hasChildren()) {`); + w.write(` let next = this.index + 1;`); + w.write(` do {`); + w.write(` const child = this.getOrCreateChildAtNodeIndex(next);`); + w.write(` if (child instanceof RemoteNodeList) {`); + w.write(` if (child.length) {`); + w.write(` let listNext = child.firstNodeIndex;`); + w.write(` while (listNext) {`); + w.write(` const node = child.getOrCreateChildAtNodeIndex(listNext) as RemoteNode;`); + w.write(` listNext = node.next;`); + w.write(` const result = yield node;`); + w.write(` if (result) {`); + w.write(` return result;`); + w.write(` }`); + w.write(` }`); + w.write(` }`); + w.write(` }`); + w.write(` else if (child.kind !== SyntaxKind.JSDoc) {`); + w.write(` const result = yield child;`); + w.write(` if (result) {`); + w.write(` return result;`); + w.write(` }`); + w.write(` }`); + w.write(` next = child.next;`); + w.write(` }`); + w.write(` while (next);`); + w.write(` }`); + w.write(` }`); + w.write(``); w.write(` get jsDoc(): readonly Node[] | undefined {`); w.write(` if (!this.hasChildren()) {`); w.write(` return undefined;`); diff --git a/tools/scripts/tsc/generate-ts-ast.ts b/tools/scripts/tsc/generate-ts-ast.ts index 13f5bd3f1f0..fdbbfb2f09a 100644 --- a/tools/scripts/tsc/generate-ts-ast.ts +++ b/tools/scripts/tsc/generate-ts-ast.ts @@ -679,6 +679,7 @@ function generateFactory(): string { if (members.filter(m => m.isChild()).length > 0) { for (const kind of node.kindTypes()) { handWrittenForEachChildImports.push(`forEachChildOf${kind.name}`); + handWrittenForEachChildImports.push(`yieldEachChildOf${kind.name}`); } } } @@ -721,6 +722,11 @@ function generateFactory(): string { out.push(` return fn ? fn(this._data, visitor, visitArray) : undefined;`); out.push(` }`); out.push(``); + out.push(` childrenIter(): Generator {`); + out.push(` const fn = yieldEachChildTable[this.kind];`); + out.push(` return fn ? fn(this._data) : emptyChildrenIter();`); + out.push(` }`); + out.push(``); out.push(` getSourceFile(): SourceFile {`); out.push(` let node: Node = this as unknown as Node;`); out.push(` while (node.parent) node = node.parent;`); @@ -901,6 +907,75 @@ function generateFactory(): string { out.push(`};`); out.push(``); + // ── yieldEachChildTable ── + out.push(`type YieldEachChildFunction = (data: any) => Generator;`); + out.push(``); + out.push(`function* emptyChildrenIter(): Generator {`); + out.push(` return undefined;`); + out.push(`}`); + out.push(``); + out.push(`const yieldEachChildTable: Record = {`); + // Schema nodes + for (const node of api.nodes()) { + if (node.handWritten) continue; + if (isVariantNode(node)) continue; + const members = tsMembers(node); + const childMembers = members.filter(m => m.isChild()); + if (childMembers.length === 0) continue; + const syntaxKinds = node.allKinds(); + if (node.handWrittenVisitor) { + for (const sk of syntaxKinds) { + out.push(` [${sk.formatTypeScript()}]: yieldEachChildOf${node.name},`); + } + continue; + } + const visits = childMembers.map(m => { + const propName = api.uncapitalize(m.name); + const listKind = m.listKind; + if (listKind) { + const visit = `for (const n of data.${propName}) { const res = yield n; if (res) return res; }`; + return m.optional ? `if (data.${propName}) { ${visit} }` : visit; + } + return `if (data.${propName}) { const res = yield data.${propName}; if (res) return res; }`; + }); + const body = visits.join("\n "); + for (const sk of syntaxKinds) { + out.push(` [${sk.formatTypeScript()}]: function* (data) {`); + out.push(` ${body}`); + out.push(` },`); + } + } + // Variant nodes + for (const v of tsVariants) { + if (!v.members) continue; + const childMembers = v.members.filter(m => m.type.baseKind() === "node" || m.type.baseKind() === "list"); + if (childMembers.length === 0) continue; + if (v.handWrittenVisitor) { + out.push(` [SyntaxKind.${v.syntaxKind}]: yieldEachChildOf${v.tsName},`); + continue; + } + const visits = childMembers.map(m => { + const propName = api.uncapitalize(m.name); + const listKind = m.listKind; + if (listKind) { + const visit = `for (const n of data.${propName}) { const res = yield n; if (res) return res; }`; + return m.optional ? `if (data.${propName}) { ${visit} }` : visit; + } + return `if (data.${propName}) { const res = yield data.${propName}; if (res) return res; }`; + }); + const body = visits.join("\n "); + out.push(` [SyntaxKind.${v.syntaxKind}]: function* (data) {`); + out.push(` ${body}`); + out.push(` },`); + } + // SourceFile is handWritten so we add its yieldEachChild entry manually + out.push(` [SyntaxKind.SourceFile]: function* (data) {`); + out.push(` for (const n of data.statements) { const res = yield n; if (res) return res; }`); + out.push(` const res = yield data.endOfFileToken; if (res) return res;`); + out.push(` },`); + out.push(`};`); + out.push(``); + // ── visitNode / visitNodes ── out.push(`function visitNode(cbNode: (node: Node) => T, node: Node | undefined): T | undefined {`); out.push(` return node ? cbNode(node) : undefined;`);