diff --git a/.github/generated/ast_changes_watch_list.yml b/.github/generated/ast_changes_watch_list.yml index d629ebcbff853..245f5466aaa24 100644 --- a/.github/generated/ast_changes_watch_list.yml +++ b/.github/generated/ast_changes_watch_list.yml @@ -73,6 +73,9 @@ src: - 'napi/parser/generated/lazy/types.mjs' - 'napi/parser/generated/lazy/walk.mjs' - 'napi/parser/generated/visit/keys.mjs' + - 'napi/parser/generated/visit/types.mjs' + - 'napi/parser/generated/visit/visitor.d.ts' + - 'napi/parser/generated/visit/walk.mjs' - 'napi/parser/src/generated/assert_layouts.rs' - 'napi/parser/src/generated/derive_estree.rs' - 'napi/parser/src/generated/raw_transfer_constants.rs' diff --git a/napi/parser/README.md b/napi/parser/README.md index a704dccb6d4a3..5c93cf882259b 100644 --- a/napi/parser/README.md +++ b/napi/parser/README.md @@ -39,9 +39,9 @@ import { Statement } from '@oxc-project/types'; ### Visitor -[oxc-walker](https://www.npmjs.com/package/oxc-walker) or [estree-walker](https://www.npmjs.com/package/estree-walker) can be used. +An AST visitor is provided. See example below. -This package exports visitor keys which can be used with any ESTree walker. +This package also exports visitor keys which can be used with any other ESTree walker. ```js import { visitorKeys } from 'oxc-parser'; @@ -99,7 +99,7 @@ export interface EcmaScriptModule { ## API ```javascript -import { parseSync } from 'oxc-parser'; +import { parseSync, Visitor } from 'oxc-parser'; const code = 'const url: String = /* 🤨 */ import.meta.url;'; @@ -117,6 +117,26 @@ console.log(result.program, result.comments); // ESM information - imports, exports, `import.meta`s. console.log(result.module); + +// Visit the AST +const visitations = []; + +const visitor = new Visitor({ + VariableDeclaration(decl) { + visitations.push(`enter ${decl.kind}`); + }, + 'VariableDeclaration:exit'(decl) { + visitations.push(`exit ${decl.kind}`); + }, + Identifier(ident) { + visitations.push(ident.name); + }, +}); + +visitor.visit(result.program); + +// Logs: [ 'enter const', 'url', 'String', 'import', 'meta', 'url', 'exit const' ] +console.log(visitations); ``` ### Options diff --git a/napi/parser/generated/visit/types.mjs b/napi/parser/generated/visit/types.mjs new file mode 100644 index 0000000000000..177a7fe4fe7f9 --- /dev/null +++ b/napi/parser/generated/visit/types.mjs @@ -0,0 +1,176 @@ +// Auto-generated code, DO NOT EDIT DIRECTLY! +// To edit this generated file you have to edit `tasks/ast_tools/src/generators/estree_visit.rs`. + +// Mapping from node type name to node type ID +export const NODE_TYPE_IDS_MAP = new Map([ + // Leaf nodes + ['DebuggerStatement', 0], + ['EmptyStatement', 1], + ['Literal', 2], + ['PrivateIdentifier', 3], + ['Super', 4], + ['TemplateElement', 5], + ['ThisExpression', 6], + ['JSXClosingFragment', 7], + ['JSXEmptyExpression', 8], + ['JSXIdentifier', 9], + ['JSXOpeningFragment', 10], + ['JSXText', 11], + ['TSAnyKeyword', 12], + ['TSBigIntKeyword', 13], + ['TSBooleanKeyword', 14], + ['TSIntrinsicKeyword', 15], + ['TSJSDocUnknownType', 16], + ['TSNeverKeyword', 17], + ['TSNullKeyword', 18], + ['TSNumberKeyword', 19], + ['TSObjectKeyword', 20], + ['TSStringKeyword', 21], + ['TSSymbolKeyword', 22], + ['TSThisType', 23], + ['TSUndefinedKeyword', 24], + ['TSUnknownKeyword', 25], + ['TSVoidKeyword', 26], + // Non-leaf nodes + ['AccessorProperty', 27], + ['ArrayExpression', 28], + ['ArrayPattern', 29], + ['ArrowFunctionExpression', 30], + ['AssignmentExpression', 31], + ['AssignmentPattern', 32], + ['AwaitExpression', 33], + ['BinaryExpression', 34], + ['BlockStatement', 35], + ['BreakStatement', 36], + ['CallExpression', 37], + ['CatchClause', 38], + ['ChainExpression', 39], + ['ClassBody', 40], + ['ClassDeclaration', 41], + ['ClassExpression', 42], + ['ConditionalExpression', 43], + ['ContinueStatement', 44], + ['Decorator', 45], + ['DoWhileStatement', 46], + ['ExportAllDeclaration', 47], + ['ExportDefaultDeclaration', 48], + ['ExportNamedDeclaration', 49], + ['ExportSpecifier', 50], + ['ExpressionStatement', 51], + ['ForInStatement', 52], + ['ForOfStatement', 53], + ['ForStatement', 54], + ['FunctionDeclaration', 55], + ['FunctionExpression', 56], + ['Identifier', 57], + ['IfStatement', 58], + ['ImportAttribute', 59], + ['ImportDeclaration', 60], + ['ImportDefaultSpecifier', 61], + ['ImportExpression', 62], + ['ImportNamespaceSpecifier', 63], + ['ImportSpecifier', 64], + ['LabeledStatement', 65], + ['LogicalExpression', 66], + ['MemberExpression', 67], + ['MetaProperty', 68], + ['MethodDefinition', 69], + ['NewExpression', 70], + ['ObjectExpression', 71], + ['ObjectPattern', 72], + ['ParenthesizedExpression', 73], + ['Program', 74], + ['Property', 75], + ['PropertyDefinition', 76], + ['RestElement', 77], + ['ReturnStatement', 78], + ['SequenceExpression', 79], + ['SpreadElement', 80], + ['StaticBlock', 81], + ['SwitchCase', 82], + ['SwitchStatement', 83], + ['TaggedTemplateExpression', 84], + ['TemplateLiteral', 85], + ['ThrowStatement', 86], + ['TryStatement', 87], + ['UnaryExpression', 88], + ['UpdateExpression', 89], + ['V8IntrinsicExpression', 90], + ['VariableDeclaration', 91], + ['VariableDeclarator', 92], + ['WhileStatement', 93], + ['WithStatement', 94], + ['YieldExpression', 95], + ['JSXAttribute', 96], + ['JSXClosingElement', 97], + ['JSXElement', 98], + ['JSXExpressionContainer', 99], + ['JSXFragment', 100], + ['JSXMemberExpression', 101], + ['JSXNamespacedName', 102], + ['JSXOpeningElement', 103], + ['JSXSpreadAttribute', 104], + ['JSXSpreadChild', 105], + ['TSAbstractAccessorProperty', 106], + ['TSAbstractMethodDefinition', 107], + ['TSAbstractPropertyDefinition', 108], + ['TSArrayType', 109], + ['TSAsExpression', 110], + ['TSCallSignatureDeclaration', 111], + ['TSClassImplements', 112], + ['TSConditionalType', 113], + ['TSConstructSignatureDeclaration', 114], + ['TSConstructorType', 115], + ['TSDeclareFunction', 116], + ['TSEmptyBodyFunctionExpression', 117], + ['TSEnumBody', 118], + ['TSEnumDeclaration', 119], + ['TSEnumMember', 120], + ['TSExportAssignment', 121], + ['TSExternalModuleReference', 122], + ['TSFunctionType', 123], + ['TSImportEqualsDeclaration', 124], + ['TSImportType', 125], + ['TSIndexSignature', 126], + ['TSIndexedAccessType', 127], + ['TSInferType', 128], + ['TSInstantiationExpression', 129], + ['TSInterfaceBody', 130], + ['TSInterfaceDeclaration', 131], + ['TSInterfaceHeritage', 132], + ['TSIntersectionType', 133], + ['TSJSDocNonNullableType', 134], + ['TSJSDocNullableType', 135], + ['TSLiteralType', 136], + ['TSMappedType', 137], + ['TSMethodSignature', 138], + ['TSModuleBlock', 139], + ['TSModuleDeclaration', 140], + ['TSNamedTupleMember', 141], + ['TSNamespaceExportDeclaration', 142], + ['TSNonNullExpression', 143], + ['TSOptionalType', 144], + ['TSParameterProperty', 145], + ['TSParenthesizedType', 146], + ['TSPropertySignature', 147], + ['TSQualifiedName', 148], + ['TSRestType', 149], + ['TSSatisfiesExpression', 150], + ['TSTemplateLiteralType', 151], + ['TSTupleType', 152], + ['TSTypeAliasDeclaration', 153], + ['TSTypeAnnotation', 154], + ['TSTypeAssertion', 155], + ['TSTypeLiteral', 156], + ['TSTypeOperator', 157], + ['TSTypeParameter', 158], + ['TSTypeParameterDeclaration', 159], + ['TSTypeParameterInstantiation', 160], + ['TSTypePredicate', 161], + ['TSTypeQuery', 162], + ['TSTypeReference', 163], + ['TSUnionType', 164], +]); + +export const NODE_TYPES_COUNT = 165; +export const LEAF_NODE_TYPES_COUNT = 27; diff --git a/napi/parser/generated/visit/visitor.d.ts b/napi/parser/generated/visit/visitor.d.ts new file mode 100644 index 0000000000000..b21cc13fc67ea --- /dev/null +++ b/napi/parser/generated/visit/visitor.d.ts @@ -0,0 +1,383 @@ +// Auto-generated code, DO NOT EDIT DIRECTLY! +// To edit this generated file you have to edit `tasks/ast_tools/src/generators/estree_visit.rs`. + +import * as ESTree from '@oxc-project/types'; + +export interface VisitorObject { + DebuggerStatement?: (node: ESTree.DebuggerStatement) => void; + 'DebuggerStatement:exit'?: (node: ESTree.DebuggerStatement) => void; + EmptyStatement?: (node: ESTree.EmptyStatement) => void; + 'EmptyStatement:exit'?: (node: ESTree.EmptyStatement) => void; + Literal?: ( + node: + | ESTree.BooleanLiteral + | ESTree.NullLiteral + | ESTree.NumericLiteral + | ESTree.StringLiteral + | ESTree.BigIntLiteral + | ESTree.RegExpLiteral, + ) => void; + 'Literal:exit'?: ( + node: + | ESTree.BooleanLiteral + | ESTree.NullLiteral + | ESTree.NumericLiteral + | ESTree.StringLiteral + | ESTree.BigIntLiteral + | ESTree.RegExpLiteral, + ) => void; + PrivateIdentifier?: (node: ESTree.PrivateIdentifier) => void; + 'PrivateIdentifier:exit'?: (node: ESTree.PrivateIdentifier) => void; + Super?: (node: ESTree.Super) => void; + 'Super:exit'?: (node: ESTree.Super) => void; + TemplateElement?: (node: ESTree.TemplateElement) => void; + 'TemplateElement:exit'?: (node: ESTree.TemplateElement) => void; + ThisExpression?: (node: ESTree.ThisExpression) => void; + 'ThisExpression:exit'?: (node: ESTree.ThisExpression) => void; + JSXClosingFragment?: (node: ESTree.JSXClosingFragment) => void; + 'JSXClosingFragment:exit'?: (node: ESTree.JSXClosingFragment) => void; + JSXEmptyExpression?: (node: ESTree.JSXEmptyExpression) => void; + 'JSXEmptyExpression:exit'?: (node: ESTree.JSXEmptyExpression) => void; + JSXIdentifier?: (node: ESTree.JSXIdentifier) => void; + 'JSXIdentifier:exit'?: (node: ESTree.JSXIdentifier) => void; + JSXOpeningFragment?: (node: ESTree.JSXOpeningFragment) => void; + 'JSXOpeningFragment:exit'?: (node: ESTree.JSXOpeningFragment) => void; + JSXText?: (node: ESTree.JSXText) => void; + 'JSXText:exit'?: (node: ESTree.JSXText) => void; + TSAnyKeyword?: (node: ESTree.TSAnyKeyword) => void; + 'TSAnyKeyword:exit'?: (node: ESTree.TSAnyKeyword) => void; + TSBigIntKeyword?: (node: ESTree.TSBigIntKeyword) => void; + 'TSBigIntKeyword:exit'?: (node: ESTree.TSBigIntKeyword) => void; + TSBooleanKeyword?: (node: ESTree.TSBooleanKeyword) => void; + 'TSBooleanKeyword:exit'?: (node: ESTree.TSBooleanKeyword) => void; + TSIntrinsicKeyword?: (node: ESTree.TSIntrinsicKeyword) => void; + 'TSIntrinsicKeyword:exit'?: (node: ESTree.TSIntrinsicKeyword) => void; + TSJSDocUnknownType?: (node: ESTree.JSDocUnknownType) => void; + 'TSJSDocUnknownType:exit'?: (node: ESTree.JSDocUnknownType) => void; + TSNeverKeyword?: (node: ESTree.TSNeverKeyword) => void; + 'TSNeverKeyword:exit'?: (node: ESTree.TSNeverKeyword) => void; + TSNullKeyword?: (node: ESTree.TSNullKeyword) => void; + 'TSNullKeyword:exit'?: (node: ESTree.TSNullKeyword) => void; + TSNumberKeyword?: (node: ESTree.TSNumberKeyword) => void; + 'TSNumberKeyword:exit'?: (node: ESTree.TSNumberKeyword) => void; + TSObjectKeyword?: (node: ESTree.TSObjectKeyword) => void; + 'TSObjectKeyword:exit'?: (node: ESTree.TSObjectKeyword) => void; + TSStringKeyword?: (node: ESTree.TSStringKeyword) => void; + 'TSStringKeyword:exit'?: (node: ESTree.TSStringKeyword) => void; + TSSymbolKeyword?: (node: ESTree.TSSymbolKeyword) => void; + 'TSSymbolKeyword:exit'?: (node: ESTree.TSSymbolKeyword) => void; + TSThisType?: (node: ESTree.TSThisType) => void; + 'TSThisType:exit'?: (node: ESTree.TSThisType) => void; + TSUndefinedKeyword?: (node: ESTree.TSUndefinedKeyword) => void; + 'TSUndefinedKeyword:exit'?: (node: ESTree.TSUndefinedKeyword) => void; + TSUnknownKeyword?: (node: ESTree.TSUnknownKeyword) => void; + 'TSUnknownKeyword:exit'?: (node: ESTree.TSUnknownKeyword) => void; + TSVoidKeyword?: (node: ESTree.TSVoidKeyword) => void; + 'TSVoidKeyword:exit'?: (node: ESTree.TSVoidKeyword) => void; + AccessorProperty?: (node: ESTree.AccessorProperty) => void; + 'AccessorProperty:exit'?: (node: ESTree.AccessorProperty) => void; + ArrayExpression?: (node: ESTree.ArrayExpression) => void; + 'ArrayExpression:exit'?: (node: ESTree.ArrayExpression) => void; + ArrayPattern?: (node: ESTree.ArrayPattern) => void; + 'ArrayPattern:exit'?: (node: ESTree.ArrayPattern) => void; + ArrowFunctionExpression?: (node: ESTree.ArrowFunctionExpression) => void; + 'ArrowFunctionExpression:exit'?: (node: ESTree.ArrowFunctionExpression) => void; + AssignmentExpression?: (node: ESTree.AssignmentExpression) => void; + 'AssignmentExpression:exit'?: (node: ESTree.AssignmentExpression) => void; + AssignmentPattern?: (node: ESTree.AssignmentPattern) => void; + 'AssignmentPattern:exit'?: (node: ESTree.AssignmentPattern) => void; + AwaitExpression?: (node: ESTree.AwaitExpression) => void; + 'AwaitExpression:exit'?: (node: ESTree.AwaitExpression) => void; + BinaryExpression?: (node: ESTree.BinaryExpression) => void; + 'BinaryExpression:exit'?: (node: ESTree.BinaryExpression) => void; + BlockStatement?: (node: ESTree.BlockStatement) => void; + 'BlockStatement:exit'?: (node: ESTree.BlockStatement) => void; + BreakStatement?: (node: ESTree.BreakStatement) => void; + 'BreakStatement:exit'?: (node: ESTree.BreakStatement) => void; + CallExpression?: (node: ESTree.CallExpression) => void; + 'CallExpression:exit'?: (node: ESTree.CallExpression) => void; + CatchClause?: (node: ESTree.CatchClause) => void; + 'CatchClause:exit'?: (node: ESTree.CatchClause) => void; + ChainExpression?: (node: ESTree.ChainExpression) => void; + 'ChainExpression:exit'?: (node: ESTree.ChainExpression) => void; + ClassBody?: (node: ESTree.ClassBody) => void; + 'ClassBody:exit'?: (node: ESTree.ClassBody) => void; + ClassDeclaration?: (node: ESTree.Class) => void; + 'ClassDeclaration:exit'?: (node: ESTree.Class) => void; + ClassExpression?: (node: ESTree.Class) => void; + 'ClassExpression:exit'?: (node: ESTree.Class) => void; + ConditionalExpression?: (node: ESTree.ConditionalExpression) => void; + 'ConditionalExpression:exit'?: (node: ESTree.ConditionalExpression) => void; + ContinueStatement?: (node: ESTree.ContinueStatement) => void; + 'ContinueStatement:exit'?: (node: ESTree.ContinueStatement) => void; + Decorator?: (node: ESTree.Decorator) => void; + 'Decorator:exit'?: (node: ESTree.Decorator) => void; + DoWhileStatement?: (node: ESTree.DoWhileStatement) => void; + 'DoWhileStatement:exit'?: (node: ESTree.DoWhileStatement) => void; + ExportAllDeclaration?: (node: ESTree.ExportAllDeclaration) => void; + 'ExportAllDeclaration:exit'?: (node: ESTree.ExportAllDeclaration) => void; + ExportDefaultDeclaration?: (node: ESTree.ExportDefaultDeclaration) => void; + 'ExportDefaultDeclaration:exit'?: (node: ESTree.ExportDefaultDeclaration) => void; + ExportNamedDeclaration?: (node: ESTree.ExportNamedDeclaration) => void; + 'ExportNamedDeclaration:exit'?: (node: ESTree.ExportNamedDeclaration) => void; + ExportSpecifier?: (node: ESTree.ExportSpecifier) => void; + 'ExportSpecifier:exit'?: (node: ESTree.ExportSpecifier) => void; + ExpressionStatement?: (node: ESTree.ExpressionStatement) => void; + 'ExpressionStatement:exit'?: (node: ESTree.ExpressionStatement) => void; + ForInStatement?: (node: ESTree.ForInStatement) => void; + 'ForInStatement:exit'?: (node: ESTree.ForInStatement) => void; + ForOfStatement?: (node: ESTree.ForOfStatement) => void; + 'ForOfStatement:exit'?: (node: ESTree.ForOfStatement) => void; + ForStatement?: (node: ESTree.ForStatement) => void; + 'ForStatement:exit'?: (node: ESTree.ForStatement) => void; + FunctionDeclaration?: (node: ESTree.Function) => void; + 'FunctionDeclaration:exit'?: (node: ESTree.Function) => void; + FunctionExpression?: (node: ESTree.Function) => void; + 'FunctionExpression:exit'?: (node: ESTree.Function) => void; + Identifier?: ( + node: + | ESTree.IdentifierName + | ESTree.IdentifierReference + | ESTree.BindingIdentifier + | ESTree.LabelIdentifier + | ESTree.TSThisParameter + | ESTree.TSIndexSignatureName, + ) => void; + 'Identifier:exit'?: ( + node: + | ESTree.IdentifierName + | ESTree.IdentifierReference + | ESTree.BindingIdentifier + | ESTree.LabelIdentifier + | ESTree.TSThisParameter + | ESTree.TSIndexSignatureName, + ) => void; + IfStatement?: (node: ESTree.IfStatement) => void; + 'IfStatement:exit'?: (node: ESTree.IfStatement) => void; + ImportAttribute?: (node: ESTree.ImportAttribute) => void; + 'ImportAttribute:exit'?: (node: ESTree.ImportAttribute) => void; + ImportDeclaration?: (node: ESTree.ImportDeclaration) => void; + 'ImportDeclaration:exit'?: (node: ESTree.ImportDeclaration) => void; + ImportDefaultSpecifier?: (node: ESTree.ImportDefaultSpecifier) => void; + 'ImportDefaultSpecifier:exit'?: (node: ESTree.ImportDefaultSpecifier) => void; + ImportExpression?: (node: ESTree.ImportExpression) => void; + 'ImportExpression:exit'?: (node: ESTree.ImportExpression) => void; + ImportNamespaceSpecifier?: (node: ESTree.ImportNamespaceSpecifier) => void; + 'ImportNamespaceSpecifier:exit'?: (node: ESTree.ImportNamespaceSpecifier) => void; + ImportSpecifier?: (node: ESTree.ImportSpecifier) => void; + 'ImportSpecifier:exit'?: (node: ESTree.ImportSpecifier) => void; + LabeledStatement?: (node: ESTree.LabeledStatement) => void; + 'LabeledStatement:exit'?: (node: ESTree.LabeledStatement) => void; + LogicalExpression?: (node: ESTree.LogicalExpression) => void; + 'LogicalExpression:exit'?: (node: ESTree.LogicalExpression) => void; + MemberExpression?: (node: ESTree.MemberExpression) => void; + 'MemberExpression:exit'?: (node: ESTree.MemberExpression) => void; + MetaProperty?: (node: ESTree.MetaProperty) => void; + 'MetaProperty:exit'?: (node: ESTree.MetaProperty) => void; + MethodDefinition?: (node: ESTree.MethodDefinition) => void; + 'MethodDefinition:exit'?: (node: ESTree.MethodDefinition) => void; + NewExpression?: (node: ESTree.NewExpression) => void; + 'NewExpression:exit'?: (node: ESTree.NewExpression) => void; + ObjectExpression?: (node: ESTree.ObjectExpression) => void; + 'ObjectExpression:exit'?: (node: ESTree.ObjectExpression) => void; + ObjectPattern?: (node: ESTree.ObjectPattern) => void; + 'ObjectPattern:exit'?: (node: ESTree.ObjectPattern) => void; + ParenthesizedExpression?: (node: ESTree.ParenthesizedExpression) => void; + 'ParenthesizedExpression:exit'?: (node: ESTree.ParenthesizedExpression) => void; + Program?: (node: ESTree.Program) => void; + 'Program:exit'?: (node: ESTree.Program) => void; + Property?: ( + node: + | ESTree.ObjectProperty + | ESTree.AssignmentTargetProperty + | ESTree.AssignmentTargetPropertyProperty + | ESTree.BindingProperty, + ) => void; + 'Property:exit'?: ( + node: + | ESTree.ObjectProperty + | ESTree.AssignmentTargetProperty + | ESTree.AssignmentTargetPropertyProperty + | ESTree.BindingProperty, + ) => void; + PropertyDefinition?: (node: ESTree.PropertyDefinition) => void; + 'PropertyDefinition:exit'?: (node: ESTree.PropertyDefinition) => void; + RestElement?: (node: ESTree.AssignmentTargetRest | ESTree.BindingRestElement | ESTree.FormalParameterRest) => void; + 'RestElement:exit'?: ( + node: ESTree.AssignmentTargetRest | ESTree.BindingRestElement | ESTree.FormalParameterRest, + ) => void; + ReturnStatement?: (node: ESTree.ReturnStatement) => void; + 'ReturnStatement:exit'?: (node: ESTree.ReturnStatement) => void; + SequenceExpression?: (node: ESTree.SequenceExpression) => void; + 'SequenceExpression:exit'?: (node: ESTree.SequenceExpression) => void; + SpreadElement?: (node: ESTree.SpreadElement) => void; + 'SpreadElement:exit'?: (node: ESTree.SpreadElement) => void; + StaticBlock?: (node: ESTree.StaticBlock) => void; + 'StaticBlock:exit'?: (node: ESTree.StaticBlock) => void; + SwitchCase?: (node: ESTree.SwitchCase) => void; + 'SwitchCase:exit'?: (node: ESTree.SwitchCase) => void; + SwitchStatement?: (node: ESTree.SwitchStatement) => void; + 'SwitchStatement:exit'?: (node: ESTree.SwitchStatement) => void; + TaggedTemplateExpression?: (node: ESTree.TaggedTemplateExpression) => void; + 'TaggedTemplateExpression:exit'?: (node: ESTree.TaggedTemplateExpression) => void; + TemplateLiteral?: (node: ESTree.TemplateLiteral) => void; + 'TemplateLiteral:exit'?: (node: ESTree.TemplateLiteral) => void; + ThrowStatement?: (node: ESTree.ThrowStatement) => void; + 'ThrowStatement:exit'?: (node: ESTree.ThrowStatement) => void; + TryStatement?: (node: ESTree.TryStatement) => void; + 'TryStatement:exit'?: (node: ESTree.TryStatement) => void; + UnaryExpression?: (node: ESTree.UnaryExpression) => void; + 'UnaryExpression:exit'?: (node: ESTree.UnaryExpression) => void; + UpdateExpression?: (node: ESTree.UpdateExpression) => void; + 'UpdateExpression:exit'?: (node: ESTree.UpdateExpression) => void; + V8IntrinsicExpression?: (node: ESTree.V8IntrinsicExpression) => void; + 'V8IntrinsicExpression:exit'?: (node: ESTree.V8IntrinsicExpression) => void; + VariableDeclaration?: (node: ESTree.VariableDeclaration) => void; + 'VariableDeclaration:exit'?: (node: ESTree.VariableDeclaration) => void; + VariableDeclarator?: (node: ESTree.VariableDeclarator) => void; + 'VariableDeclarator:exit'?: (node: ESTree.VariableDeclarator) => void; + WhileStatement?: (node: ESTree.WhileStatement) => void; + 'WhileStatement:exit'?: (node: ESTree.WhileStatement) => void; + WithStatement?: (node: ESTree.WithStatement) => void; + 'WithStatement:exit'?: (node: ESTree.WithStatement) => void; + YieldExpression?: (node: ESTree.YieldExpression) => void; + 'YieldExpression:exit'?: (node: ESTree.YieldExpression) => void; + JSXAttribute?: (node: ESTree.JSXAttribute) => void; + 'JSXAttribute:exit'?: (node: ESTree.JSXAttribute) => void; + JSXClosingElement?: (node: ESTree.JSXClosingElement) => void; + 'JSXClosingElement:exit'?: (node: ESTree.JSXClosingElement) => void; + JSXElement?: (node: ESTree.JSXElement) => void; + 'JSXElement:exit'?: (node: ESTree.JSXElement) => void; + JSXExpressionContainer?: (node: ESTree.JSXExpressionContainer) => void; + 'JSXExpressionContainer:exit'?: (node: ESTree.JSXExpressionContainer) => void; + JSXFragment?: (node: ESTree.JSXFragment) => void; + 'JSXFragment:exit'?: (node: ESTree.JSXFragment) => void; + JSXMemberExpression?: (node: ESTree.JSXMemberExpression) => void; + 'JSXMemberExpression:exit'?: (node: ESTree.JSXMemberExpression) => void; + JSXNamespacedName?: (node: ESTree.JSXNamespacedName) => void; + 'JSXNamespacedName:exit'?: (node: ESTree.JSXNamespacedName) => void; + JSXOpeningElement?: (node: ESTree.JSXOpeningElement) => void; + 'JSXOpeningElement:exit'?: (node: ESTree.JSXOpeningElement) => void; + JSXSpreadAttribute?: (node: ESTree.JSXSpreadAttribute) => void; + 'JSXSpreadAttribute:exit'?: (node: ESTree.JSXSpreadAttribute) => void; + JSXSpreadChild?: (node: ESTree.JSXSpreadChild) => void; + 'JSXSpreadChild:exit'?: (node: ESTree.JSXSpreadChild) => void; + TSAbstractAccessorProperty?: (node: ESTree.AccessorProperty) => void; + 'TSAbstractAccessorProperty:exit'?: (node: ESTree.AccessorProperty) => void; + TSAbstractMethodDefinition?: (node: ESTree.MethodDefinition) => void; + 'TSAbstractMethodDefinition:exit'?: (node: ESTree.MethodDefinition) => void; + TSAbstractPropertyDefinition?: (node: ESTree.PropertyDefinition) => void; + 'TSAbstractPropertyDefinition:exit'?: (node: ESTree.PropertyDefinition) => void; + TSArrayType?: (node: ESTree.TSArrayType) => void; + 'TSArrayType:exit'?: (node: ESTree.TSArrayType) => void; + TSAsExpression?: (node: ESTree.TSAsExpression) => void; + 'TSAsExpression:exit'?: (node: ESTree.TSAsExpression) => void; + TSCallSignatureDeclaration?: (node: ESTree.TSCallSignatureDeclaration) => void; + 'TSCallSignatureDeclaration:exit'?: (node: ESTree.TSCallSignatureDeclaration) => void; + TSClassImplements?: (node: ESTree.TSClassImplements) => void; + 'TSClassImplements:exit'?: (node: ESTree.TSClassImplements) => void; + TSConditionalType?: (node: ESTree.TSConditionalType) => void; + 'TSConditionalType:exit'?: (node: ESTree.TSConditionalType) => void; + TSConstructSignatureDeclaration?: (node: ESTree.TSConstructSignatureDeclaration) => void; + 'TSConstructSignatureDeclaration:exit'?: (node: ESTree.TSConstructSignatureDeclaration) => void; + TSConstructorType?: (node: ESTree.TSConstructorType) => void; + 'TSConstructorType:exit'?: (node: ESTree.TSConstructorType) => void; + TSDeclareFunction?: (node: ESTree.Function) => void; + 'TSDeclareFunction:exit'?: (node: ESTree.Function) => void; + TSEmptyBodyFunctionExpression?: (node: ESTree.Function) => void; + 'TSEmptyBodyFunctionExpression:exit'?: (node: ESTree.Function) => void; + TSEnumBody?: (node: ESTree.TSEnumBody) => void; + 'TSEnumBody:exit'?: (node: ESTree.TSEnumBody) => void; + TSEnumDeclaration?: (node: ESTree.TSEnumDeclaration) => void; + 'TSEnumDeclaration:exit'?: (node: ESTree.TSEnumDeclaration) => void; + TSEnumMember?: (node: ESTree.TSEnumMember) => void; + 'TSEnumMember:exit'?: (node: ESTree.TSEnumMember) => void; + TSExportAssignment?: (node: ESTree.TSExportAssignment) => void; + 'TSExportAssignment:exit'?: (node: ESTree.TSExportAssignment) => void; + TSExternalModuleReference?: (node: ESTree.TSExternalModuleReference) => void; + 'TSExternalModuleReference:exit'?: (node: ESTree.TSExternalModuleReference) => void; + TSFunctionType?: (node: ESTree.TSFunctionType) => void; + 'TSFunctionType:exit'?: (node: ESTree.TSFunctionType) => void; + TSImportEqualsDeclaration?: (node: ESTree.TSImportEqualsDeclaration) => void; + 'TSImportEqualsDeclaration:exit'?: (node: ESTree.TSImportEqualsDeclaration) => void; + TSImportType?: (node: ESTree.TSImportType) => void; + 'TSImportType:exit'?: (node: ESTree.TSImportType) => void; + TSIndexSignature?: (node: ESTree.TSIndexSignature) => void; + 'TSIndexSignature:exit'?: (node: ESTree.TSIndexSignature) => void; + TSIndexedAccessType?: (node: ESTree.TSIndexedAccessType) => void; + 'TSIndexedAccessType:exit'?: (node: ESTree.TSIndexedAccessType) => void; + TSInferType?: (node: ESTree.TSInferType) => void; + 'TSInferType:exit'?: (node: ESTree.TSInferType) => void; + TSInstantiationExpression?: (node: ESTree.TSInstantiationExpression) => void; + 'TSInstantiationExpression:exit'?: (node: ESTree.TSInstantiationExpression) => void; + TSInterfaceBody?: (node: ESTree.TSInterfaceBody) => void; + 'TSInterfaceBody:exit'?: (node: ESTree.TSInterfaceBody) => void; + TSInterfaceDeclaration?: (node: ESTree.TSInterfaceDeclaration) => void; + 'TSInterfaceDeclaration:exit'?: (node: ESTree.TSInterfaceDeclaration) => void; + TSInterfaceHeritage?: (node: ESTree.TSInterfaceHeritage) => void; + 'TSInterfaceHeritage:exit'?: (node: ESTree.TSInterfaceHeritage) => void; + TSIntersectionType?: (node: ESTree.TSIntersectionType) => void; + 'TSIntersectionType:exit'?: (node: ESTree.TSIntersectionType) => void; + TSJSDocNonNullableType?: (node: ESTree.JSDocNonNullableType) => void; + 'TSJSDocNonNullableType:exit'?: (node: ESTree.JSDocNonNullableType) => void; + TSJSDocNullableType?: (node: ESTree.JSDocNullableType) => void; + 'TSJSDocNullableType:exit'?: (node: ESTree.JSDocNullableType) => void; + TSLiteralType?: (node: ESTree.TSLiteralType) => void; + 'TSLiteralType:exit'?: (node: ESTree.TSLiteralType) => void; + TSMappedType?: (node: ESTree.TSMappedType) => void; + 'TSMappedType:exit'?: (node: ESTree.TSMappedType) => void; + TSMethodSignature?: (node: ESTree.TSMethodSignature) => void; + 'TSMethodSignature:exit'?: (node: ESTree.TSMethodSignature) => void; + TSModuleBlock?: (node: ESTree.TSModuleBlock) => void; + 'TSModuleBlock:exit'?: (node: ESTree.TSModuleBlock) => void; + TSModuleDeclaration?: (node: ESTree.TSModuleDeclaration) => void; + 'TSModuleDeclaration:exit'?: (node: ESTree.TSModuleDeclaration) => void; + TSNamedTupleMember?: (node: ESTree.TSNamedTupleMember) => void; + 'TSNamedTupleMember:exit'?: (node: ESTree.TSNamedTupleMember) => void; + TSNamespaceExportDeclaration?: (node: ESTree.TSNamespaceExportDeclaration) => void; + 'TSNamespaceExportDeclaration:exit'?: (node: ESTree.TSNamespaceExportDeclaration) => void; + TSNonNullExpression?: (node: ESTree.TSNonNullExpression) => void; + 'TSNonNullExpression:exit'?: (node: ESTree.TSNonNullExpression) => void; + TSOptionalType?: (node: ESTree.TSOptionalType) => void; + 'TSOptionalType:exit'?: (node: ESTree.TSOptionalType) => void; + TSParameterProperty?: (node: ESTree.TSParameterProperty) => void; + 'TSParameterProperty:exit'?: (node: ESTree.TSParameterProperty) => void; + TSParenthesizedType?: (node: ESTree.TSParenthesizedType) => void; + 'TSParenthesizedType:exit'?: (node: ESTree.TSParenthesizedType) => void; + TSPropertySignature?: (node: ESTree.TSPropertySignature) => void; + 'TSPropertySignature:exit'?: (node: ESTree.TSPropertySignature) => void; + TSQualifiedName?: (node: ESTree.TSQualifiedName) => void; + 'TSQualifiedName:exit'?: (node: ESTree.TSQualifiedName) => void; + TSRestType?: (node: ESTree.TSRestType) => void; + 'TSRestType:exit'?: (node: ESTree.TSRestType) => void; + TSSatisfiesExpression?: (node: ESTree.TSSatisfiesExpression) => void; + 'TSSatisfiesExpression:exit'?: (node: ESTree.TSSatisfiesExpression) => void; + TSTemplateLiteralType?: (node: ESTree.TSTemplateLiteralType) => void; + 'TSTemplateLiteralType:exit'?: (node: ESTree.TSTemplateLiteralType) => void; + TSTupleType?: (node: ESTree.TSTupleType) => void; + 'TSTupleType:exit'?: (node: ESTree.TSTupleType) => void; + TSTypeAliasDeclaration?: (node: ESTree.TSTypeAliasDeclaration) => void; + 'TSTypeAliasDeclaration:exit'?: (node: ESTree.TSTypeAliasDeclaration) => void; + TSTypeAnnotation?: (node: ESTree.TSTypeAnnotation) => void; + 'TSTypeAnnotation:exit'?: (node: ESTree.TSTypeAnnotation) => void; + TSTypeAssertion?: (node: ESTree.TSTypeAssertion) => void; + 'TSTypeAssertion:exit'?: (node: ESTree.TSTypeAssertion) => void; + TSTypeLiteral?: (node: ESTree.TSTypeLiteral) => void; + 'TSTypeLiteral:exit'?: (node: ESTree.TSTypeLiteral) => void; + TSTypeOperator?: (node: ESTree.TSTypeOperator) => void; + 'TSTypeOperator:exit'?: (node: ESTree.TSTypeOperator) => void; + TSTypeParameter?: (node: ESTree.TSTypeParameter) => void; + 'TSTypeParameter:exit'?: (node: ESTree.TSTypeParameter) => void; + TSTypeParameterDeclaration?: (node: ESTree.TSTypeParameterDeclaration) => void; + 'TSTypeParameterDeclaration:exit'?: (node: ESTree.TSTypeParameterDeclaration) => void; + TSTypeParameterInstantiation?: (node: ESTree.TSTypeParameterInstantiation) => void; + 'TSTypeParameterInstantiation:exit'?: (node: ESTree.TSTypeParameterInstantiation) => void; + TSTypePredicate?: (node: ESTree.TSTypePredicate) => void; + 'TSTypePredicate:exit'?: (node: ESTree.TSTypePredicate) => void; + TSTypeQuery?: (node: ESTree.TSTypeQuery) => void; + 'TSTypeQuery:exit'?: (node: ESTree.TSTypeQuery) => void; + TSTypeReference?: (node: ESTree.TSTypeReference) => void; + 'TSTypeReference:exit'?: (node: ESTree.TSTypeReference) => void; + TSUnionType?: (node: ESTree.TSUnionType) => void; + 'TSUnionType:exit'?: (node: ESTree.TSUnionType) => void; +} diff --git a/napi/parser/generated/visit/walk.mjs b/napi/parser/generated/visit/walk.mjs new file mode 100644 index 0000000000000..c4620f304bbb1 --- /dev/null +++ b/napi/parser/generated/visit/walk.mjs @@ -0,0 +1,2460 @@ +// Auto-generated code, DO NOT EDIT DIRECTLY! +// To edit this generated file you have to edit `tasks/ast_tools/src/generators/estree_visit.rs`. + +export { walkProgram }; + +const { isArray } = Array; + +function walkNode(node, visitors) { + if (node == null) return; + if (isArray(node)) { + const len = node.length; + for (let i = 0; i < len; i++) { + walkNode(node[i], visitors); + } + } else { + switch (node.type) { + case 'DebuggerStatement': + walkDebuggerStatement(node, visitors); + break; + case 'EmptyStatement': + walkEmptyStatement(node, visitors); + break; + case 'Literal': + walkLiteral(node, visitors); + break; + case 'PrivateIdentifier': + walkPrivateIdentifier(node, visitors); + break; + case 'Super': + walkSuper(node, visitors); + break; + case 'TemplateElement': + walkTemplateElement(node, visitors); + break; + case 'ThisExpression': + walkThisExpression(node, visitors); + break; + case 'JSXClosingFragment': + walkJSXClosingFragment(node, visitors); + break; + case 'JSXEmptyExpression': + walkJSXEmptyExpression(node, visitors); + break; + case 'JSXIdentifier': + walkJSXIdentifier(node, visitors); + break; + case 'JSXOpeningFragment': + walkJSXOpeningFragment(node, visitors); + break; + case 'JSXText': + walkJSXText(node, visitors); + break; + case 'TSAnyKeyword': + walkTSAnyKeyword(node, visitors); + break; + case 'TSBigIntKeyword': + walkTSBigIntKeyword(node, visitors); + break; + case 'TSBooleanKeyword': + walkTSBooleanKeyword(node, visitors); + break; + case 'TSIntrinsicKeyword': + walkTSIntrinsicKeyword(node, visitors); + break; + case 'TSJSDocUnknownType': + walkTSJSDocUnknownType(node, visitors); + break; + case 'TSNeverKeyword': + walkTSNeverKeyword(node, visitors); + break; + case 'TSNullKeyword': + walkTSNullKeyword(node, visitors); + break; + case 'TSNumberKeyword': + walkTSNumberKeyword(node, visitors); + break; + case 'TSObjectKeyword': + walkTSObjectKeyword(node, visitors); + break; + case 'TSStringKeyword': + walkTSStringKeyword(node, visitors); + break; + case 'TSSymbolKeyword': + walkTSSymbolKeyword(node, visitors); + break; + case 'TSThisType': + walkTSThisType(node, visitors); + break; + case 'TSUndefinedKeyword': + walkTSUndefinedKeyword(node, visitors); + break; + case 'TSUnknownKeyword': + walkTSUnknownKeyword(node, visitors); + break; + case 'TSVoidKeyword': + walkTSVoidKeyword(node, visitors); + break; + case 'AccessorProperty': + walkAccessorProperty(node, visitors); + break; + case 'ArrayExpression': + walkArrayExpression(node, visitors); + break; + case 'ArrayPattern': + walkArrayPattern(node, visitors); + break; + case 'ArrowFunctionExpression': + walkArrowFunctionExpression(node, visitors); + break; + case 'AssignmentExpression': + walkAssignmentExpression(node, visitors); + break; + case 'AssignmentPattern': + walkAssignmentPattern(node, visitors); + break; + case 'AwaitExpression': + walkAwaitExpression(node, visitors); + break; + case 'BinaryExpression': + walkBinaryExpression(node, visitors); + break; + case 'BlockStatement': + walkBlockStatement(node, visitors); + break; + case 'BreakStatement': + walkBreakStatement(node, visitors); + break; + case 'CallExpression': + walkCallExpression(node, visitors); + break; + case 'CatchClause': + walkCatchClause(node, visitors); + break; + case 'ChainExpression': + walkChainExpression(node, visitors); + break; + case 'ClassBody': + walkClassBody(node, visitors); + break; + case 'ClassDeclaration': + walkClassDeclaration(node, visitors); + break; + case 'ClassExpression': + walkClassExpression(node, visitors); + break; + case 'ConditionalExpression': + walkConditionalExpression(node, visitors); + break; + case 'ContinueStatement': + walkContinueStatement(node, visitors); + break; + case 'Decorator': + walkDecorator(node, visitors); + break; + case 'DoWhileStatement': + walkDoWhileStatement(node, visitors); + break; + case 'ExportAllDeclaration': + walkExportAllDeclaration(node, visitors); + break; + case 'ExportDefaultDeclaration': + walkExportDefaultDeclaration(node, visitors); + break; + case 'ExportNamedDeclaration': + walkExportNamedDeclaration(node, visitors); + break; + case 'ExportSpecifier': + walkExportSpecifier(node, visitors); + break; + case 'ExpressionStatement': + walkExpressionStatement(node, visitors); + break; + case 'ForInStatement': + walkForInStatement(node, visitors); + break; + case 'ForOfStatement': + walkForOfStatement(node, visitors); + break; + case 'ForStatement': + walkForStatement(node, visitors); + break; + case 'FunctionDeclaration': + walkFunctionDeclaration(node, visitors); + break; + case 'FunctionExpression': + walkFunctionExpression(node, visitors); + break; + case 'Identifier': + walkIdentifier(node, visitors); + break; + case 'IfStatement': + walkIfStatement(node, visitors); + break; + case 'ImportAttribute': + walkImportAttribute(node, visitors); + break; + case 'ImportDeclaration': + walkImportDeclaration(node, visitors); + break; + case 'ImportDefaultSpecifier': + walkImportDefaultSpecifier(node, visitors); + break; + case 'ImportExpression': + walkImportExpression(node, visitors); + break; + case 'ImportNamespaceSpecifier': + walkImportNamespaceSpecifier(node, visitors); + break; + case 'ImportSpecifier': + walkImportSpecifier(node, visitors); + break; + case 'LabeledStatement': + walkLabeledStatement(node, visitors); + break; + case 'LogicalExpression': + walkLogicalExpression(node, visitors); + break; + case 'MemberExpression': + walkMemberExpression(node, visitors); + break; + case 'MetaProperty': + walkMetaProperty(node, visitors); + break; + case 'MethodDefinition': + walkMethodDefinition(node, visitors); + break; + case 'NewExpression': + walkNewExpression(node, visitors); + break; + case 'ObjectExpression': + walkObjectExpression(node, visitors); + break; + case 'ObjectPattern': + walkObjectPattern(node, visitors); + break; + case 'ParenthesizedExpression': + walkParenthesizedExpression(node, visitors); + break; + case 'Program': + walkProgram(node, visitors); + break; + case 'Property': + walkProperty(node, visitors); + break; + case 'PropertyDefinition': + walkPropertyDefinition(node, visitors); + break; + case 'RestElement': + walkRestElement(node, visitors); + break; + case 'ReturnStatement': + walkReturnStatement(node, visitors); + break; + case 'SequenceExpression': + walkSequenceExpression(node, visitors); + break; + case 'SpreadElement': + walkSpreadElement(node, visitors); + break; + case 'StaticBlock': + walkStaticBlock(node, visitors); + break; + case 'SwitchCase': + walkSwitchCase(node, visitors); + break; + case 'SwitchStatement': + walkSwitchStatement(node, visitors); + break; + case 'TaggedTemplateExpression': + walkTaggedTemplateExpression(node, visitors); + break; + case 'TemplateLiteral': + walkTemplateLiteral(node, visitors); + break; + case 'ThrowStatement': + walkThrowStatement(node, visitors); + break; + case 'TryStatement': + walkTryStatement(node, visitors); + break; + case 'UnaryExpression': + walkUnaryExpression(node, visitors); + break; + case 'UpdateExpression': + walkUpdateExpression(node, visitors); + break; + case 'V8IntrinsicExpression': + walkV8IntrinsicExpression(node, visitors); + break; + case 'VariableDeclaration': + walkVariableDeclaration(node, visitors); + break; + case 'VariableDeclarator': + walkVariableDeclarator(node, visitors); + break; + case 'WhileStatement': + walkWhileStatement(node, visitors); + break; + case 'WithStatement': + walkWithStatement(node, visitors); + break; + case 'YieldExpression': + walkYieldExpression(node, visitors); + break; + case 'JSXAttribute': + walkJSXAttribute(node, visitors); + break; + case 'JSXClosingElement': + walkJSXClosingElement(node, visitors); + break; + case 'JSXElement': + walkJSXElement(node, visitors); + break; + case 'JSXExpressionContainer': + walkJSXExpressionContainer(node, visitors); + break; + case 'JSXFragment': + walkJSXFragment(node, visitors); + break; + case 'JSXMemberExpression': + walkJSXMemberExpression(node, visitors); + break; + case 'JSXNamespacedName': + walkJSXNamespacedName(node, visitors); + break; + case 'JSXOpeningElement': + walkJSXOpeningElement(node, visitors); + break; + case 'JSXSpreadAttribute': + walkJSXSpreadAttribute(node, visitors); + break; + case 'JSXSpreadChild': + walkJSXSpreadChild(node, visitors); + break; + case 'TSAbstractAccessorProperty': + walkTSAbstractAccessorProperty(node, visitors); + break; + case 'TSAbstractMethodDefinition': + walkTSAbstractMethodDefinition(node, visitors); + break; + case 'TSAbstractPropertyDefinition': + walkTSAbstractPropertyDefinition(node, visitors); + break; + case 'TSArrayType': + walkTSArrayType(node, visitors); + break; + case 'TSAsExpression': + walkTSAsExpression(node, visitors); + break; + case 'TSCallSignatureDeclaration': + walkTSCallSignatureDeclaration(node, visitors); + break; + case 'TSClassImplements': + walkTSClassImplements(node, visitors); + break; + case 'TSConditionalType': + walkTSConditionalType(node, visitors); + break; + case 'TSConstructSignatureDeclaration': + walkTSConstructSignatureDeclaration(node, visitors); + break; + case 'TSConstructorType': + walkTSConstructorType(node, visitors); + break; + case 'TSDeclareFunction': + walkTSDeclareFunction(node, visitors); + break; + case 'TSEmptyBodyFunctionExpression': + walkTSEmptyBodyFunctionExpression(node, visitors); + break; + case 'TSEnumBody': + walkTSEnumBody(node, visitors); + break; + case 'TSEnumDeclaration': + walkTSEnumDeclaration(node, visitors); + break; + case 'TSEnumMember': + walkTSEnumMember(node, visitors); + break; + case 'TSExportAssignment': + walkTSExportAssignment(node, visitors); + break; + case 'TSExternalModuleReference': + walkTSExternalModuleReference(node, visitors); + break; + case 'TSFunctionType': + walkTSFunctionType(node, visitors); + break; + case 'TSImportEqualsDeclaration': + walkTSImportEqualsDeclaration(node, visitors); + break; + case 'TSImportType': + walkTSImportType(node, visitors); + break; + case 'TSIndexSignature': + walkTSIndexSignature(node, visitors); + break; + case 'TSIndexedAccessType': + walkTSIndexedAccessType(node, visitors); + break; + case 'TSInferType': + walkTSInferType(node, visitors); + break; + case 'TSInstantiationExpression': + walkTSInstantiationExpression(node, visitors); + break; + case 'TSInterfaceBody': + walkTSInterfaceBody(node, visitors); + break; + case 'TSInterfaceDeclaration': + walkTSInterfaceDeclaration(node, visitors); + break; + case 'TSInterfaceHeritage': + walkTSInterfaceHeritage(node, visitors); + break; + case 'TSIntersectionType': + walkTSIntersectionType(node, visitors); + break; + case 'TSJSDocNonNullableType': + walkTSJSDocNonNullableType(node, visitors); + break; + case 'TSJSDocNullableType': + walkTSJSDocNullableType(node, visitors); + break; + case 'TSLiteralType': + walkTSLiteralType(node, visitors); + break; + case 'TSMappedType': + walkTSMappedType(node, visitors); + break; + case 'TSMethodSignature': + walkTSMethodSignature(node, visitors); + break; + case 'TSModuleBlock': + walkTSModuleBlock(node, visitors); + break; + case 'TSModuleDeclaration': + walkTSModuleDeclaration(node, visitors); + break; + case 'TSNamedTupleMember': + walkTSNamedTupleMember(node, visitors); + break; + case 'TSNamespaceExportDeclaration': + walkTSNamespaceExportDeclaration(node, visitors); + break; + case 'TSNonNullExpression': + walkTSNonNullExpression(node, visitors); + break; + case 'TSOptionalType': + walkTSOptionalType(node, visitors); + break; + case 'TSParameterProperty': + walkTSParameterProperty(node, visitors); + break; + case 'TSParenthesizedType': + walkTSParenthesizedType(node, visitors); + break; + case 'TSPropertySignature': + walkTSPropertySignature(node, visitors); + break; + case 'TSQualifiedName': + walkTSQualifiedName(node, visitors); + break; + case 'TSRestType': + walkTSRestType(node, visitors); + break; + case 'TSSatisfiesExpression': + walkTSSatisfiesExpression(node, visitors); + break; + case 'TSTemplateLiteralType': + walkTSTemplateLiteralType(node, visitors); + break; + case 'TSTupleType': + walkTSTupleType(node, visitors); + break; + case 'TSTypeAliasDeclaration': + walkTSTypeAliasDeclaration(node, visitors); + break; + case 'TSTypeAnnotation': + walkTSTypeAnnotation(node, visitors); + break; + case 'TSTypeAssertion': + walkTSTypeAssertion(node, visitors); + break; + case 'TSTypeLiteral': + walkTSTypeLiteral(node, visitors); + break; + case 'TSTypeOperator': + walkTSTypeOperator(node, visitors); + break; + case 'TSTypeParameter': + walkTSTypeParameter(node, visitors); + break; + case 'TSTypeParameterDeclaration': + walkTSTypeParameterDeclaration(node, visitors); + break; + case 'TSTypeParameterInstantiation': + walkTSTypeParameterInstantiation(node, visitors); + break; + case 'TSTypePredicate': + walkTSTypePredicate(node, visitors); + break; + case 'TSTypeQuery': + walkTSTypeQuery(node, visitors); + break; + case 'TSTypeReference': + walkTSTypeReference(node, visitors); + break; + case 'TSUnionType': + walkTSUnionType(node, visitors); + break; + } + } +} + +function walkDebuggerStatement(node, visitors) { + const visit = visitors[0]; + if (visit !== null) visit(node); +} + +function walkEmptyStatement(node, visitors) { + const visit = visitors[1]; + if (visit !== null) visit(node); +} + +function walkLiteral(node, visitors) { + const visit = visitors[2]; + if (visit !== null) visit(node); +} + +function walkPrivateIdentifier(node, visitors) { + const visit = visitors[3]; + if (visit !== null) visit(node); +} + +function walkSuper(node, visitors) { + const visit = visitors[4]; + if (visit !== null) visit(node); +} + +function walkTemplateElement(node, visitors) { + const visit = visitors[5]; + if (visit !== null) visit(node); +} + +function walkThisExpression(node, visitors) { + const visit = visitors[6]; + if (visit !== null) visit(node); +} + +function walkJSXClosingFragment(node, visitors) { + const visit = visitors[7]; + if (visit !== null) visit(node); +} + +function walkJSXEmptyExpression(node, visitors) { + const visit = visitors[8]; + if (visit !== null) visit(node); +} + +function walkJSXIdentifier(node, visitors) { + const visit = visitors[9]; + if (visit !== null) visit(node); +} + +function walkJSXOpeningFragment(node, visitors) { + const visit = visitors[10]; + if (visit !== null) visit(node); +} + +function walkJSXText(node, visitors) { + const visit = visitors[11]; + if (visit !== null) visit(node); +} + +function walkTSAnyKeyword(node, visitors) { + const visit = visitors[12]; + if (visit !== null) visit(node); +} + +function walkTSBigIntKeyword(node, visitors) { + const visit = visitors[13]; + if (visit !== null) visit(node); +} + +function walkTSBooleanKeyword(node, visitors) { + const visit = visitors[14]; + if (visit !== null) visit(node); +} + +function walkTSIntrinsicKeyword(node, visitors) { + const visit = visitors[15]; + if (visit !== null) visit(node); +} + +function walkTSJSDocUnknownType(node, visitors) { + const visit = visitors[16]; + if (visit !== null) visit(node); +} + +function walkTSNeverKeyword(node, visitors) { + const visit = visitors[17]; + if (visit !== null) visit(node); +} + +function walkTSNullKeyword(node, visitors) { + const visit = visitors[18]; + if (visit !== null) visit(node); +} + +function walkTSNumberKeyword(node, visitors) { + const visit = visitors[19]; + if (visit !== null) visit(node); +} + +function walkTSObjectKeyword(node, visitors) { + const visit = visitors[20]; + if (visit !== null) visit(node); +} + +function walkTSStringKeyword(node, visitors) { + const visit = visitors[21]; + if (visit !== null) visit(node); +} + +function walkTSSymbolKeyword(node, visitors) { + const visit = visitors[22]; + if (visit !== null) visit(node); +} + +function walkTSThisType(node, visitors) { + const visit = visitors[23]; + if (visit !== null) visit(node); +} + +function walkTSUndefinedKeyword(node, visitors) { + const visit = visitors[24]; + if (visit !== null) visit(node); +} + +function walkTSUnknownKeyword(node, visitors) { + const visit = visitors[25]; + if (visit !== null) visit(node); +} + +function walkTSVoidKeyword(node, visitors) { + const visit = visitors[26]; + if (visit !== null) visit(node); +} + +function walkAccessorProperty(node, visitors) { + const enterExit = visitors[27]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.key, visitors); + walkNode(node.typeAnnotation, visitors); + walkNode(node.value, visitors); + if (exit !== null) exit(node); +} + +function walkArrayExpression(node, visitors) { + const enterExit = visitors[28]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.elements, visitors); + if (exit !== null) exit(node); +} + +function walkArrayPattern(node, visitors) { + const enterExit = visitors[29]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.elements, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkArrowFunctionExpression(node, visitors) { + const enterExit = visitors[30]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeParameters, visitors); + walkNode(node.params, visitors); + walkNode(node.returnType, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkAssignmentExpression(node, visitors) { + const enterExit = visitors[31]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.left, visitors); + walkNode(node.right, visitors); + if (exit !== null) exit(node); +} + +function walkAssignmentPattern(node, visitors) { + const enterExit = visitors[32]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.left, visitors); + walkNode(node.right, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkAwaitExpression(node, visitors) { + const enterExit = visitors[33]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.argument, visitors); + if (exit !== null) exit(node); +} + +function walkBinaryExpression(node, visitors) { + const enterExit = visitors[34]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.left, visitors); + walkNode(node.right, visitors); + if (exit !== null) exit(node); +} + +function walkBlockStatement(node, visitors) { + const enterExit = visitors[35]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkBreakStatement(node, visitors) { + const enterExit = visitors[36]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.label, visitors); + if (exit !== null) exit(node); +} + +function walkCallExpression(node, visitors) { + const enterExit = visitors[37]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.callee, visitors); + walkNode(node.typeArguments, visitors); + walkNode(node.arguments, visitors); + if (exit !== null) exit(node); +} + +function walkCatchClause(node, visitors) { + const enterExit = visitors[38]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.param, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkChainExpression(node, visitors) { + const enterExit = visitors[39]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + if (exit !== null) exit(node); +} + +function walkClassBody(node, visitors) { + const enterExit = visitors[40]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkClassDeclaration(node, visitors) { + const enterExit = visitors[41]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.id, visitors); + walkNode(node.typeParameters, visitors); + walkNode(node.superClass, visitors); + walkNode(node.superTypeArguments, visitors); + walkNode(node.implements, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkClassExpression(node, visitors) { + const enterExit = visitors[42]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.id, visitors); + walkNode(node.typeParameters, visitors); + walkNode(node.superClass, visitors); + walkNode(node.superTypeArguments, visitors); + walkNode(node.implements, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkConditionalExpression(node, visitors) { + const enterExit = visitors[43]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.test, visitors); + walkNode(node.consequent, visitors); + walkNode(node.alternate, visitors); + if (exit !== null) exit(node); +} + +function walkContinueStatement(node, visitors) { + const enterExit = visitors[44]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.label, visitors); + if (exit !== null) exit(node); +} + +function walkDecorator(node, visitors) { + const enterExit = visitors[45]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + if (exit !== null) exit(node); +} + +function walkDoWhileStatement(node, visitors) { + const enterExit = visitors[46]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.body, visitors); + walkNode(node.test, visitors); + if (exit !== null) exit(node); +} + +function walkExportAllDeclaration(node, visitors) { + const enterExit = visitors[47]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.exported, visitors); + walkNode(node.source, visitors); + walkNode(node.attributes, visitors); + if (exit !== null) exit(node); +} + +function walkExportDefaultDeclaration(node, visitors) { + const enterExit = visitors[48]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.declaration, visitors); + if (exit !== null) exit(node); +} + +function walkExportNamedDeclaration(node, visitors) { + const enterExit = visitors[49]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.declaration, visitors); + walkNode(node.specifiers, visitors); + walkNode(node.source, visitors); + walkNode(node.attributes, visitors); + if (exit !== null) exit(node); +} + +function walkExportSpecifier(node, visitors) { + const enterExit = visitors[50]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.local, visitors); + walkNode(node.exported, visitors); + if (exit !== null) exit(node); +} + +function walkExpressionStatement(node, visitors) { + const enterExit = visitors[51]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + if (exit !== null) exit(node); +} + +function walkForInStatement(node, visitors) { + const enterExit = visitors[52]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.left, visitors); + walkNode(node.right, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkForOfStatement(node, visitors) { + const enterExit = visitors[53]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.left, visitors); + walkNode(node.right, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkForStatement(node, visitors) { + const enterExit = visitors[54]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.init, visitors); + walkNode(node.test, visitors); + walkNode(node.update, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkFunctionDeclaration(node, visitors) { + const enterExit = visitors[55]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.typeParameters, visitors); + walkNode(node.params, visitors); + walkNode(node.returnType, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkFunctionExpression(node, visitors) { + const enterExit = visitors[56]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.typeParameters, visitors); + walkNode(node.params, visitors); + walkNode(node.returnType, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkIdentifier(node, visitors) { + const enterExit = visitors[57]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkIfStatement(node, visitors) { + const enterExit = visitors[58]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.test, visitors); + walkNode(node.consequent, visitors); + walkNode(node.alternate, visitors); + if (exit !== null) exit(node); +} + +function walkImportAttribute(node, visitors) { + const enterExit = visitors[59]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.key, visitors); + walkNode(node.value, visitors); + if (exit !== null) exit(node); +} + +function walkImportDeclaration(node, visitors) { + const enterExit = visitors[60]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.specifiers, visitors); + walkNode(node.source, visitors); + walkNode(node.attributes, visitors); + if (exit !== null) exit(node); +} + +function walkImportDefaultSpecifier(node, visitors) { + const enterExit = visitors[61]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.local, visitors); + if (exit !== null) exit(node); +} + +function walkImportExpression(node, visitors) { + const enterExit = visitors[62]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.source, visitors); + walkNode(node.options, visitors); + if (exit !== null) exit(node); +} + +function walkImportNamespaceSpecifier(node, visitors) { + const enterExit = visitors[63]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.local, visitors); + if (exit !== null) exit(node); +} + +function walkImportSpecifier(node, visitors) { + const enterExit = visitors[64]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.imported, visitors); + walkNode(node.local, visitors); + if (exit !== null) exit(node); +} + +function walkLabeledStatement(node, visitors) { + const enterExit = visitors[65]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.label, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkLogicalExpression(node, visitors) { + const enterExit = visitors[66]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.left, visitors); + walkNode(node.right, visitors); + if (exit !== null) exit(node); +} + +function walkMemberExpression(node, visitors) { + const enterExit = visitors[67]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.object, visitors); + walkNode(node.property, visitors); + if (exit !== null) exit(node); +} + +function walkMetaProperty(node, visitors) { + const enterExit = visitors[68]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.meta, visitors); + walkNode(node.property, visitors); + if (exit !== null) exit(node); +} + +function walkMethodDefinition(node, visitors) { + const enterExit = visitors[69]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.key, visitors); + walkNode(node.value, visitors); + if (exit !== null) exit(node); +} + +function walkNewExpression(node, visitors) { + const enterExit = visitors[70]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.callee, visitors); + walkNode(node.typeArguments, visitors); + walkNode(node.arguments, visitors); + if (exit !== null) exit(node); +} + +function walkObjectExpression(node, visitors) { + const enterExit = visitors[71]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.properties, visitors); + if (exit !== null) exit(node); +} + +function walkObjectPattern(node, visitors) { + const enterExit = visitors[72]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.properties, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkParenthesizedExpression(node, visitors) { + const enterExit = visitors[73]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + if (exit !== null) exit(node); +} + +function walkProgram(node, visitors) { + const enterExit = visitors[74]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkProperty(node, visitors) { + const enterExit = visitors[75]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.key, visitors); + walkNode(node.value, visitors); + if (exit !== null) exit(node); +} + +function walkPropertyDefinition(node, visitors) { + const enterExit = visitors[76]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.key, visitors); + walkNode(node.typeAnnotation, visitors); + walkNode(node.value, visitors); + if (exit !== null) exit(node); +} + +function walkRestElement(node, visitors) { + const enterExit = visitors[77]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.argument, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkReturnStatement(node, visitors) { + const enterExit = visitors[78]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.argument, visitors); + if (exit !== null) exit(node); +} + +function walkSequenceExpression(node, visitors) { + const enterExit = visitors[79]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expressions, visitors); + if (exit !== null) exit(node); +} + +function walkSpreadElement(node, visitors) { + const enterExit = visitors[80]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.argument, visitors); + if (exit !== null) exit(node); +} + +function walkStaticBlock(node, visitors) { + const enterExit = visitors[81]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkSwitchCase(node, visitors) { + const enterExit = visitors[82]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.test, visitors); + walkNode(node.consequent, visitors); + if (exit !== null) exit(node); +} + +function walkSwitchStatement(node, visitors) { + const enterExit = visitors[83]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.discriminant, visitors); + walkNode(node.cases, visitors); + if (exit !== null) exit(node); +} + +function walkTaggedTemplateExpression(node, visitors) { + const enterExit = visitors[84]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.tag, visitors); + walkNode(node.typeArguments, visitors); + walkNode(node.quasi, visitors); + if (exit !== null) exit(node); +} + +function walkTemplateLiteral(node, visitors) { + const enterExit = visitors[85]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.quasis, visitors); + walkNode(node.expressions, visitors); + if (exit !== null) exit(node); +} + +function walkThrowStatement(node, visitors) { + const enterExit = visitors[86]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.argument, visitors); + if (exit !== null) exit(node); +} + +function walkTryStatement(node, visitors) { + const enterExit = visitors[87]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.block, visitors); + walkNode(node.handler, visitors); + walkNode(node.finalizer, visitors); + if (exit !== null) exit(node); +} + +function walkUnaryExpression(node, visitors) { + const enterExit = visitors[88]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.argument, visitors); + if (exit !== null) exit(node); +} + +function walkUpdateExpression(node, visitors) { + const enterExit = visitors[89]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.argument, visitors); + if (exit !== null) exit(node); +} + +function walkV8IntrinsicExpression(node, visitors) { + const enterExit = visitors[90]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.name, visitors); + walkNode(node.arguments, visitors); + if (exit !== null) exit(node); +} + +function walkVariableDeclaration(node, visitors) { + const enterExit = visitors[91]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.declarations, visitors); + if (exit !== null) exit(node); +} + +function walkVariableDeclarator(node, visitors) { + const enterExit = visitors[92]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.init, visitors); + if (exit !== null) exit(node); +} + +function walkWhileStatement(node, visitors) { + const enterExit = visitors[93]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.test, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkWithStatement(node, visitors) { + const enterExit = visitors[94]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.object, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkYieldExpression(node, visitors) { + const enterExit = visitors[95]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.argument, visitors); + if (exit !== null) exit(node); +} + +function walkJSXAttribute(node, visitors) { + const enterExit = visitors[96]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.name, visitors); + walkNode(node.value, visitors); + if (exit !== null) exit(node); +} + +function walkJSXClosingElement(node, visitors) { + const enterExit = visitors[97]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.name, visitors); + if (exit !== null) exit(node); +} + +function walkJSXElement(node, visitors) { + const enterExit = visitors[98]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.openingElement, visitors); + walkNode(node.children, visitors); + walkNode(node.closingElement, visitors); + if (exit !== null) exit(node); +} + +function walkJSXExpressionContainer(node, visitors) { + const enterExit = visitors[99]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + if (exit !== null) exit(node); +} + +function walkJSXFragment(node, visitors) { + const enterExit = visitors[100]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.openingFragment, visitors); + walkNode(node.children, visitors); + walkNode(node.closingFragment, visitors); + if (exit !== null) exit(node); +} + +function walkJSXMemberExpression(node, visitors) { + const enterExit = visitors[101]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.object, visitors); + walkNode(node.property, visitors); + if (exit !== null) exit(node); +} + +function walkJSXNamespacedName(node, visitors) { + const enterExit = visitors[102]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.namespace, visitors); + walkNode(node.name, visitors); + if (exit !== null) exit(node); +} + +function walkJSXOpeningElement(node, visitors) { + const enterExit = visitors[103]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.name, visitors); + walkNode(node.typeArguments, visitors); + walkNode(node.attributes, visitors); + if (exit !== null) exit(node); +} + +function walkJSXSpreadAttribute(node, visitors) { + const enterExit = visitors[104]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.argument, visitors); + if (exit !== null) exit(node); +} + +function walkJSXSpreadChild(node, visitors) { + const enterExit = visitors[105]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + if (exit !== null) exit(node); +} + +function walkTSAbstractAccessorProperty(node, visitors) { + const enterExit = visitors[106]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.key, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSAbstractMethodDefinition(node, visitors) { + const enterExit = visitors[107]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.key, visitors); + walkNode(node.value, visitors); + if (exit !== null) exit(node); +} + +function walkTSAbstractPropertyDefinition(node, visitors) { + const enterExit = visitors[108]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.key, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSArrayType(node, visitors) { + const enterExit = visitors[109]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.elementType, visitors); + if (exit !== null) exit(node); +} + +function walkTSAsExpression(node, visitors) { + const enterExit = visitors[110]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSCallSignatureDeclaration(node, visitors) { + const enterExit = visitors[111]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeParameters, visitors); + walkNode(node.params, visitors); + walkNode(node.returnType, visitors); + if (exit !== null) exit(node); +} + +function walkTSClassImplements(node, visitors) { + const enterExit = visitors[112]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + walkNode(node.typeArguments, visitors); + if (exit !== null) exit(node); +} + +function walkTSConditionalType(node, visitors) { + const enterExit = visitors[113]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.checkType, visitors); + walkNode(node.extendsType, visitors); + walkNode(node.trueType, visitors); + walkNode(node.falseType, visitors); + if (exit !== null) exit(node); +} + +function walkTSConstructSignatureDeclaration(node, visitors) { + const enterExit = visitors[114]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeParameters, visitors); + walkNode(node.params, visitors); + walkNode(node.returnType, visitors); + if (exit !== null) exit(node); +} + +function walkTSConstructorType(node, visitors) { + const enterExit = visitors[115]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeParameters, visitors); + walkNode(node.params, visitors); + walkNode(node.returnType, visitors); + if (exit !== null) exit(node); +} + +function walkTSDeclareFunction(node, visitors) { + const enterExit = visitors[116]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.typeParameters, visitors); + walkNode(node.params, visitors); + walkNode(node.returnType, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkTSEmptyBodyFunctionExpression(node, visitors) { + const enterExit = visitors[117]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.typeParameters, visitors); + walkNode(node.params, visitors); + walkNode(node.returnType, visitors); + if (exit !== null) exit(node); +} + +function walkTSEnumBody(node, visitors) { + const enterExit = visitors[118]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.members, visitors); + if (exit !== null) exit(node); +} + +function walkTSEnumDeclaration(node, visitors) { + const enterExit = visitors[119]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkTSEnumMember(node, visitors) { + const enterExit = visitors[120]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.initializer, visitors); + if (exit !== null) exit(node); +} + +function walkTSExportAssignment(node, visitors) { + const enterExit = visitors[121]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + if (exit !== null) exit(node); +} + +function walkTSExternalModuleReference(node, visitors) { + const enterExit = visitors[122]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + if (exit !== null) exit(node); +} + +function walkTSFunctionType(node, visitors) { + const enterExit = visitors[123]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeParameters, visitors); + walkNode(node.params, visitors); + walkNode(node.returnType, visitors); + if (exit !== null) exit(node); +} + +function walkTSImportEqualsDeclaration(node, visitors) { + const enterExit = visitors[124]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.moduleReference, visitors); + if (exit !== null) exit(node); +} + +function walkTSImportType(node, visitors) { + const enterExit = visitors[125]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.argument, visitors); + walkNode(node.options, visitors); + walkNode(node.qualifier, visitors); + walkNode(node.typeArguments, visitors); + if (exit !== null) exit(node); +} + +function walkTSIndexSignature(node, visitors) { + const enterExit = visitors[126]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.parameters, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSIndexedAccessType(node, visitors) { + const enterExit = visitors[127]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.objectType, visitors); + walkNode(node.indexType, visitors); + if (exit !== null) exit(node); +} + +function walkTSInferType(node, visitors) { + const enterExit = visitors[128]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeParameter, visitors); + if (exit !== null) exit(node); +} + +function walkTSInstantiationExpression(node, visitors) { + const enterExit = visitors[129]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + walkNode(node.typeArguments, visitors); + if (exit !== null) exit(node); +} + +function walkTSInterfaceBody(node, visitors) { + const enterExit = visitors[130]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkTSInterfaceDeclaration(node, visitors) { + const enterExit = visitors[131]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.typeParameters, visitors); + walkNode(node.extends, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkTSInterfaceHeritage(node, visitors) { + const enterExit = visitors[132]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + walkNode(node.typeArguments, visitors); + if (exit !== null) exit(node); +} + +function walkTSIntersectionType(node, visitors) { + const enterExit = visitors[133]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.types, visitors); + if (exit !== null) exit(node); +} + +function walkTSJSDocNonNullableType(node, visitors) { + const enterExit = visitors[134]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSJSDocNullableType(node, visitors) { + const enterExit = visitors[135]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSLiteralType(node, visitors) { + const enterExit = visitors[136]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.literal, visitors); + if (exit !== null) exit(node); +} + +function walkTSMappedType(node, visitors) { + const enterExit = visitors[137]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.key, visitors); + walkNode(node.constraint, visitors); + walkNode(node.nameType, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSMethodSignature(node, visitors) { + const enterExit = visitors[138]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.key, visitors); + walkNode(node.typeParameters, visitors); + walkNode(node.params, visitors); + walkNode(node.returnType, visitors); + if (exit !== null) exit(node); +} + +function walkTSModuleBlock(node, visitors) { + const enterExit = visitors[139]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkTSModuleDeclaration(node, visitors) { + const enterExit = visitors[140]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.body, visitors); + if (exit !== null) exit(node); +} + +function walkTSNamedTupleMember(node, visitors) { + const enterExit = visitors[141]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.label, visitors); + walkNode(node.elementType, visitors); + if (exit !== null) exit(node); +} + +function walkTSNamespaceExportDeclaration(node, visitors) { + const enterExit = visitors[142]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + if (exit !== null) exit(node); +} + +function walkTSNonNullExpression(node, visitors) { + const enterExit = visitors[143]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + if (exit !== null) exit(node); +} + +function walkTSOptionalType(node, visitors) { + const enterExit = visitors[144]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSParameterProperty(node, visitors) { + const enterExit = visitors[145]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.decorators, visitors); + walkNode(node.parameter, visitors); + if (exit !== null) exit(node); +} + +function walkTSParenthesizedType(node, visitors) { + const enterExit = visitors[146]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSPropertySignature(node, visitors) { + const enterExit = visitors[147]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.key, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSQualifiedName(node, visitors) { + const enterExit = visitors[148]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.left, visitors); + walkNode(node.right, visitors); + if (exit !== null) exit(node); +} + +function walkTSRestType(node, visitors) { + const enterExit = visitors[149]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSSatisfiesExpression(node, visitors) { + const enterExit = visitors[150]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.expression, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSTemplateLiteralType(node, visitors) { + const enterExit = visitors[151]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.quasis, visitors); + walkNode(node.types, visitors); + if (exit !== null) exit(node); +} + +function walkTSTupleType(node, visitors) { + const enterExit = visitors[152]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.elementTypes, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypeAliasDeclaration(node, visitors) { + const enterExit = visitors[153]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.id, visitors); + walkNode(node.typeParameters, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypeAnnotation(node, visitors) { + const enterExit = visitors[154]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypeAssertion(node, visitors) { + const enterExit = visitors[155]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeAnnotation, visitors); + walkNode(node.expression, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypeLiteral(node, visitors) { + const enterExit = visitors[156]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.members, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypeOperator(node, visitors) { + const enterExit = visitors[157]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypeParameter(node, visitors) { + const enterExit = visitors[158]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.name, visitors); + walkNode(node.constraint, visitors); + walkNode(node.default, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypeParameterDeclaration(node, visitors) { + const enterExit = visitors[159]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.params, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypeParameterInstantiation(node, visitors) { + const enterExit = visitors[160]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.params, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypePredicate(node, visitors) { + const enterExit = visitors[161]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.parameterName, visitors); + walkNode(node.typeAnnotation, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypeQuery(node, visitors) { + const enterExit = visitors[162]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.exprName, visitors); + walkNode(node.typeArguments, visitors); + if (exit !== null) exit(node); +} + +function walkTSTypeReference(node, visitors) { + const enterExit = visitors[163]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.typeName, visitors); + walkNode(node.typeArguments, visitors); + if (exit !== null) exit(node); +} + +function walkTSUnionType(node, visitors) { + const enterExit = visitors[164]; + let exit = null; + if (enterExit !== null) { + let enter; + ({ enter, exit } = enterExit); + if (enter !== null) enter(node); + } + walkNode(node.types, visitors); + if (exit !== null) exit(node); +} diff --git a/napi/parser/package.json b/napi/parser/package.json index 7129a2d50149b..eb3e57fc3dfc7 100644 --- a/napi/parser/package.json +++ b/napi/parser/package.json @@ -45,6 +45,9 @@ "generated/lazy/types.mjs", "generated/lazy/walk.mjs", "generated/visit/keys.mjs", + "generated/visit/types.mjs", + "generated/visit/visitor.d.ts", + "generated/visit/walk.mjs", "src-js/bindings.mjs", "src-js/index.d.ts", "src-js/index.mjs", @@ -57,7 +60,9 @@ "src-js/raw-transfer/lazy-common.mjs", "src-js/raw-transfer/node-array.mjs", "src-js/raw-transfer/supported.mjs", - "src-js/raw-transfer/visitor.mjs" + "src-js/raw-transfer/visitor.mjs", + "src-js/visit/index.mjs", + "src-js/visit/visitor.mjs" ], "publishConfig": { "registry": "https://registry.npmjs.org/", @@ -102,6 +107,6 @@ "fs": false } }, - "dtsHeaderFile": "src-js/header.js" + "dtsHeaderFile": "src-js/header.d.ts" } } diff --git a/napi/parser/src-js/header.d.ts b/napi/parser/src-js/header.d.ts new file mode 100644 index 0000000000000..7773551b02753 --- /dev/null +++ b/napi/parser/src-js/header.d.ts @@ -0,0 +1,14 @@ +/* auto-generated by NAPI-RS */ +/* eslint-disable */ + +import type { Program } from '@oxc-project/types'; +import type { VisitorObject } from '../generated/visit/visitor.d.ts'; + +export * from '@oxc-project/types'; + +export { VisitorObject }; + +export class Visitor { + constructor(visitor: VisitorObject); + visit(program: Program): void; +} diff --git a/napi/parser/src-js/header.js b/napi/parser/src-js/header.js deleted file mode 100644 index a89dec6b1a1e3..0000000000000 --- a/napi/parser/src-js/header.js +++ /dev/null @@ -1,4 +0,0 @@ -/* auto-generated by NAPI-RS */ -/* eslint-disable */ - -export * from '@oxc-project/types'; diff --git a/napi/parser/src-js/index.d.ts b/napi/parser/src-js/index.d.ts index a57863391a57e..d74fc0834f38d 100644 --- a/napi/parser/src-js/index.d.ts +++ b/napi/parser/src-js/index.d.ts @@ -1,7 +1,17 @@ /* auto-generated by NAPI-RS */ /* eslint-disable */ +import type { Program } from '@oxc-project/types'; +import type { VisitorObject } from '../generated/visit/visitor.d.ts'; + export * from '@oxc-project/types'; + +export { VisitorObject }; + +export class Visitor { + constructor(visitor: VisitorObject); + visit(program: Program): void; +} export interface Comment { type: 'Line' | 'Block' value: string diff --git a/napi/parser/src-js/index.mjs b/napi/parser/src-js/index.mjs index 5b956cca538ea..f289f65ef5620 100644 --- a/napi/parser/src-js/index.mjs +++ b/napi/parser/src-js/index.mjs @@ -3,6 +3,7 @@ import { parseAsync as parseAsyncBinding, parseSync as parseSyncBinding } from ' import { wrap } from './wrap.mjs'; export { default as visitorKeys } from '../generated/visit/keys.mjs'; +export { Visitor } from './visit/index.mjs'; export { ExportExportNameKind, @@ -21,7 +22,7 @@ let parseSyncRaw = null, parseAsyncRaw, parseSyncLazy = null, parseAsyncLazy, - Visitor; + LazyVisitor; /** * Lazy-load code related to raw transfer. @@ -39,7 +40,7 @@ function loadRawTransfer() { */ function loadRawTransferLazy() { if (parseSyncLazy === null) { - ({ parseSyncLazy, parseAsyncLazy, Visitor } = require('./raw-transfer/lazy.mjs')); + ({ parseSyncLazy, parseAsyncLazy, Visitor: LazyVisitor } = require('./raw-transfer/lazy.mjs')); } } @@ -103,5 +104,5 @@ export async function parseAsync(filename, sourceText, options) { */ export function experimentalGetLazyVisitor() { loadRawTransferLazy(); - return Visitor; + return LazyVisitor; } diff --git a/napi/parser/src-js/visit/index.mjs b/napi/parser/src-js/visit/index.mjs new file mode 100644 index 0000000000000..4468184657870 --- /dev/null +++ b/napi/parser/src-js/visit/index.mjs @@ -0,0 +1,34 @@ +import { createRequire } from 'node:module'; + +// Lazy-loaded when first construct a `Visitor` +let walkProgram = null, addVisitorToCompiled, createCompiledVisitor, finalizeCompiledVisitor; + +/** + * Visitor class for traversing AST. + */ +export class Visitor { + #compiledVisitor = null; + + constructor(visitor) { + if (walkProgram === null) { + const require = createRequire(import.meta.url); + ({ walkProgram } = require('../../generated/visit/walk.mjs')); + ({ addVisitorToCompiled, createCompiledVisitor, finalizeCompiledVisitor } = require('./visitor.mjs')); + } + + const compiledVisitor = createCompiledVisitor(); + addVisitorToCompiled(visitor); + const needsVisit = finalizeCompiledVisitor(); + if (needsVisit) this.#compiledVisitor = compiledVisitor; + } + + /** + * Visit AST. + * @param program - The AST to visit. + * @returns {undefined} + */ + visit(program) { + const compiledVisitor = this.#compiledVisitor; + if (compiledVisitor !== null) walkProgram(program, compiledVisitor); + } +} diff --git a/napi/parser/src-js/visit/visitor.mjs b/napi/parser/src-js/visit/visitor.mjs new file mode 100644 index 0000000000000..cb2ed2ddbea50 --- /dev/null +++ b/napi/parser/src-js/visit/visitor.mjs @@ -0,0 +1,402 @@ +// Functions to compile 1 or more visitor objects into a single compiled visitor. +// +// # Visitor objects +// +// Visitor objects which are generated by rules' `create` functions have keys being either: +// * Name of an AST type. or +// * Name of an AST type postfixed with `:exit`. +// +// Each property value must be a function that handles that AST node. +// +// e.g.: +// +// ``` +// { +// BinaryExpression(node) { +// // Do stuff on enter +// }, +// 'BinaryExpression:exit'(node) { +// // Do stuff on exit +// }, +// } +// ``` +// +// # Compiled visitor +// +// Compiled visitor is an array with `NODE_TYPES_COUNT` length, keyed by the ID of the node type. +// `NODE_TYPE_IDS_MAP` maps from type name to ID. +// +// Each element of compiled array is one of: +// * No visitor for this type = `null`. +// * Visitor for leaf node = visit function. +// * Visitor for non-leaf node = object of form `{ enter, exit }`, +// where each property is either a visitor function or `null`. +// +// e.g.: +// +// ``` +// [ +// // Leaf nodes +// function(node) { /* do stuff */ }, +// // ... +// +// // Non-leaf nodes +// { +// enter: function(node) { /* do stuff */ }, +// exit: null, +// }, +// // ... +// ] +// ``` +// +// # Object reuse +// +// No more than 1 compiled visitor exists at any time, so we reuse a single array `compiledVisitor`, +// rather than creating a new array for each file being linted. +// +// To compile visitors, call: +// * `initCompiledVisitor` once. +// * `addVisitorToCompiled` with each visitor object. +// * `finalizeCompiledVisitor` once. +// +// After this sequence of calls, `compiledVisitor` is ready to be used to walk the AST. +// +// We also recycle: +// +// * `{ enter, exit }` objects which are stored in compiled visitor. +// * Temporary arrays used to store multiple visit functions, which are merged into a single function +// in `finalizeCompiledVisitor`. +// +// The aim is to reduce pressure on the garbage collector. All these recycled objects are long-lived +// and will graduate to "old space", which leaves as much capacity as possible in "new space" +// for objects created by user code in visitors. If ephemeral user-created objects all fit in new space, +// it will avoid full GC runs, which should greatly improve performance. + +// TODO(camc314): we need to generate `.d.ts` file for this module. +// @ts-expect-error +import { LEAF_NODE_TYPES_COUNT, NODE_TYPE_IDS_MAP, NODE_TYPES_COUNT } from '../../generated/visit/types.mjs'; + +const { isArray } = Array; + +// Compiled visitor used for visiting each file. +// Same array is reused for each file. +// +// Initialized with `.push()` to ensure V8 treats the array as "packed" (linear array), +// not "holey" (hash map). This is critical, as looking up elements in this array is a very hot path +// during AST visitation, and holey arrays are much slower. +// https://v8.dev/blog/elements-kinds +let compiledVisitor; + +export function createCompiledVisitor() { + // Create a new compiled visitor array + compiledVisitor = []; + for (let i = NODE_TYPES_COUNT; i !== 0; i--) { + compiledVisitor.push(null); + } + return compiledVisitor; +} + +// Arrays containing type IDs of types which have multiple visit functions defined for them. +// +// Filled with `0` initially up to maximum size they could ever need to be so: +// 1. These arrays never need to grow. +// 2. V8 treats these arrays as "PACKED_SMI_ELEMENTS". +const mergedLeafVisitorTypeIds = [], + mergedEnterVisitorTypeIds = [], + mergedExitVisitorTypeIds = []; + +for (let i = LEAF_NODE_TYPES_COUNT; i !== 0; i--) { + mergedLeafVisitorTypeIds.push(0); +} + +for (let i = NODE_TYPES_COUNT - LEAF_NODE_TYPES_COUNT; i !== 0; i--) { + mergedEnterVisitorTypeIds.push(0); + mergedExitVisitorTypeIds.push(0); +} + +mergedLeafVisitorTypeIds.length = 0; +mergedEnterVisitorTypeIds.length = 0; +mergedExitVisitorTypeIds.length = 0; + +// `true` if `addVisitor` has been called with a visitor which visits at least one AST type +let hasActiveVisitors = false; + +// Enter+exit object cache. +// +// `compiledVisitor` may contain many `{ enter, exit }` objects. +// Use this cache to reuse those objects across all visitor compilations. +// +// `enterExitObjectCacheNextIndex` is the index of first object in cache which is currently unused. +// It may point to the end of the cache array. +const enterExitObjectCache = []; +let enterExitObjectCacheNextIndex = 0; + +function getEnterExitObject() { + if (enterExitObjectCacheNextIndex < enterExitObjectCache.length) { + return enterExitObjectCache[enterExitObjectCacheNextIndex++]; + } + + const enterExit = { enter: null, exit: null }; + enterExitObjectCache.push(enterExit); + enterExitObjectCacheNextIndex++; + return enterExit; +} + +// Visit function arrays cache. +// +// During compilation, many arrays may be used temporarily to store multiple visit functions for same AST type. +// The functions in each array are merged into a single function in `finalizeCompiledVisitor`, +// after which these arrays aren't used again. +// +// Use this cache to reuse these arrays across each visitor compilation. +// +// `visitFnArrayCacheNextIndex` is the index of first array in cache which is currently unused. +// It may point to the end of the cache array. +const visitFnArrayCache = []; +let visitFnArrayCacheNextIndex = 0; + +function createVisitFnArray(visit1, visit2) { + if (visitFnArrayCacheNextIndex < visitFnArrayCache.length) { + const arr = visitFnArrayCache[visitFnArrayCacheNextIndex++]; + arr.push(visit1, visit2); + return arr; + } + + const arr = [visit1, visit2]; + visitFnArrayCache.push(arr); + visitFnArrayCacheNextIndex++; + return arr; +} + +/** + * Initialize compiled visitor, ready for calls to `addVisitor`. + */ +export function initCompiledVisitor() { + // Reset `compiledVisitor` array after previous compilation + for (let i = 0; i < NODE_TYPES_COUNT; i++) { + compiledVisitor[i] = null; + } + + // Reset enter+exit objects which were used in previous compilation + for (let i = 0; i < enterExitObjectCacheNextIndex; i++) { + const enterExit = enterExitObjectCache[i]; + enterExit.enter = null; + enterExit.exit = null; + } + enterExitObjectCacheNextIndex = 0; +} + +/** + * Add a visitor to compiled visitor. + * + * @param visitor - Visitor object + */ +export function addVisitorToCompiled(visitor) { + if (visitor === null || typeof visitor !== 'object') throw new TypeError('Visitor must be an object'); + + // Exit if is empty visitor + const keys = Object.keys(visitor), + keysLen = keys.length; + if (keysLen === 0) return; + + hasActiveVisitors = true; + + // Populate visitors array from provided object + for (let i = 0; i < keysLen; i++) { + let name = keys[i]; + + const visitFn = visitor[name]; + if (typeof visitFn !== 'function') { + throw new TypeError(`'${name}' property of visitor object is not a function`); + } + + const isExit = name.endsWith(':exit'); + if (isExit) name = name.slice(0, -5); + + const typeId = NODE_TYPE_IDS_MAP.get(name); + if (typeId === void 0) throw new Error(`Unknown node type '${name}' in visitor object`); + + const existing = compiledVisitor[typeId]; + if (typeId < LEAF_NODE_TYPES_COUNT) { + // Leaf node - store just 1 function, not enter+exit pair + if (existing === null) { + compiledVisitor[typeId] = visitFn; + } else if (isArray(existing)) { + if (isExit) { + existing.push(visitFn); + } else { + // Insert before last in array in case last was enter visit function from the current rule, + // to ensure enter is called before exit. + // It could also be either an enter or exit visitor function for another rule, but the order + // rules are called in doesn't matter. We only need to make sure that a rule's exit visitor + // isn't called before enter visitor *for that same rule*. + existing.splice(existing.length - 1, 0, visitFn); + } + } else { + // Same as above, enter visitor is put to front of list to make sure enter is called before exit + compiledVisitor[typeId] = isExit + ? createVisitFnArray(existing, visitFn) + : createVisitFnArray(visitFn, existing); + mergedLeafVisitorTypeIds.push(typeId); + } + } else { + // Not leaf node - store enter+exit pair + if (existing === null) { + const enterExit = compiledVisitor[typeId] = getEnterExitObject(); + if (isExit) { + enterExit.exit = visitFn; + } else { + enterExit.enter = visitFn; + } + } else if (isExit) { + const { exit } = existing; + if (exit === null) { + existing.exit = visitFn; + } else if (isArray(exit)) { + exit.push(visitFn); + } else { + existing.exit = createVisitFnArray(exit, visitFn); + mergedExitVisitorTypeIds.push(typeId); + } + } else { + const { enter } = existing; + if (enter === null) { + existing.enter = visitFn; + } else if (isArray(enter)) { + enter.push(visitFn); + } else { + existing.enter = createVisitFnArray(enter, visitFn); + mergedEnterVisitorTypeIds.push(typeId); + } + } + } + } +} + +/** + * Finalize compiled visitor. + * + * After calling this function, `compiledVisitor` is ready to be used to walk the AST. + * + * @returns {boolean} - `true` if compiled visitor visits at least 1 AST type + */ +export function finalizeCompiledVisitor() { + if (hasActiveVisitors === false) return false; + + // Merge visit functions for node types which have multiple visitors from different rules, + // or enter+exit functions for leaf nodes + for (let i = mergedLeafVisitorTypeIds.length - 1; i >= 0; i--) { + const typeId = mergedLeafVisitorTypeIds[i]; + compiledVisitor[typeId] = mergeVisitFns(compiledVisitor[typeId]); + } + + for (let i = mergedEnterVisitorTypeIds.length - 1; i >= 0; i--) { + const typeId = mergedEnterVisitorTypeIds[i]; + const enterExit = compiledVisitor[typeId]; + enterExit.enter = mergeVisitFns(enterExit.enter); + } + + for (let i = mergedExitVisitorTypeIds.length - 1; i >= 0; i--) { + const typeId = mergedExitVisitorTypeIds[i]; + const enterExit = compiledVisitor[typeId]; + enterExit.exit = mergeVisitFns(enterExit.exit); + } + + // Reset state, ready for next time + mergedLeafVisitorTypeIds.length = 0; + mergedEnterVisitorTypeIds.length = 0; + mergedExitVisitorTypeIds.length = 0; + + // Note: Visit function arrays have been emptied in `mergeVisitFns`, so all arrays in `visitFnArrayCache` + // are now empty and ready for reuse. We just need to reset the index. + visitFnArrayCacheNextIndex = 0; + + hasActiveVisitors = false; + + return true; +} + +/** + * Merge array of visit functions into a single function, which calls each of input functions in turn. + * + * The array passed is cleared (length set to 0), so the array can be reused. + * + * The merged function is statically defined and does not contain a loop, to hopefully allow + * JS engine to heavily optimize it. + * + * `mergers` contains pre-defined functions to merge up to 5 visit functions. + * Merger functions for merging more than 5 visit functions are created dynamically on demand. + * + * @param visitFns - Array of visit functions + * @returns Function which calls all of `visitFns` in turn. + */ +function mergeVisitFns(visitFns) { + const numVisitFns = visitFns.length; + + // Get or create merger for merging `numVisitFns` functions + let merger; + if (mergers.length <= numVisitFns) { + while (mergers.length < numVisitFns) { + mergers.push(null); + } + merger = createMerger(numVisitFns); + mergers.push(merger); + } else { + merger = mergers[numVisitFns]; + if (merger === null) merger = mergers[numVisitFns] = createMerger(numVisitFns); + } + + // Merge functions + const mergedFn = merger(...visitFns); + + // Empty `visitFns` array, so it can be reused + visitFns.length = 0; + + return mergedFn; +} + +/** + * Create a merger function that merges `fnCount` functions. + * + * @param fnCount - Number of functions to be merged + * @returns Function to merge `fnCount` functions + */ +function createMerger(fnCount) { + const args = []; + let body = 'return node=>{'; + for (let i = 1; i <= fnCount; i++) { + args.push(`visit${i}`); + body += `visit${i}(node);`; + } + body += '}'; + args.push(body); + return new Function(...args); +} + +// Pre-defined mergers for merging up to 5 functions +const mergers = [ + null, // No merger for 0 functions + null, // No merger for 1 function + (visit1, visit2) => (node) => { + visit1(node); + visit2(node); + }, + (visit1, visit2, visit3) => (node) => { + visit1(node); + visit2(node); + visit3(node); + }, + (visit1, visit2, visit3, visit4) => (node) => { + visit1(node); + visit2(node); + visit3(node); + visit4(node); + }, + (visit1, visit2, visit3, visit4, visit5) => (node) => { + visit1(node); + visit2(node); + visit3(node); + visit4(node); + visit5(node); + }, +]; diff --git a/napi/parser/test/parse.test.ts b/napi/parser/test/parse.test.ts index 94765001b6ac4..9d7f6f84c4798 100644 --- a/napi/parser/test/parse.test.ts +++ b/napi/parser/test/parse.test.ts @@ -874,14 +874,6 @@ describe('error', () => { }); }); -it('visitor keys', () => { - expect(visitorKeys.Literal).toEqual([]); - expect(visitorKeys.VariableDeclaration).toEqual(['declarations']); - expect(visitorKeys.ObjectPattern).toEqual(['decorators', 'properties', 'typeAnnotation']); - expect(visitorKeys.ParenthesizedExpression).toEqual(['expression']); - expect(visitorKeys.V8IntrinsicExpression).toEqual(['name', 'arguments']); -}); - describe('worker', () => { it('should run', async () => { const code = await new Promise((resolve, reject) => { diff --git a/napi/parser/test/visit.test.ts b/napi/parser/test/visit.test.ts new file mode 100644 index 0000000000000..32c099729ab0a --- /dev/null +++ b/napi/parser/test/visit.test.ts @@ -0,0 +1,257 @@ +import { describe, expect, it } from 'vitest'; + +import { parseSync, Visitor, visitorKeys } from '../src-js/index.mjs'; + +describe('visit', () => { + it('empty visitor', () => { + const code = 'const x = { y: 123 }'; + const { program } = parseSync('test.js', code); + const visitor = new Visitor({}); + visitor.visit(program); + }); + + describe('invalid visitor', () => { + it('undefined visitor object', () => { + expect(() => new Visitor()).toThrow(new TypeError('Visitor must be an object')); + }); + + it('null visitor object', () => { + expect(() => new Visitor(null)).toThrow(new TypeError('Visitor must be an object')); + }); + + it('boolean visitor object', () => { + expect(() => new Visitor(true)).toThrow(new TypeError('Visitor must be an object')); + }); + + it('unknown type in entry', () => { + expect(() => new Visitor({ Foo() {} })).toThrow(new Error("Unknown node type 'Foo' in visitor object")); + }); + + it('unknown type in exit', () => { + expect(() => new Visitor({ 'Foo:exit'() {} })).toThrow(new Error("Unknown node type 'Foo' in visitor object")); + }); + + it('invalid postfix', () => { + expect(() => new Visitor({ 'Identifier:foo'() {} })).toThrow( + new Error("Unknown node type 'Identifier:foo' in visitor object"), + ); + }); + }); + + it('visit JS code', () => { + const code = 'const x = { y: 123 }'; + const { program } = parseSync('test.js', code); + + const visited = []; + const visitor = new Visitor({ + Program(node) { + visited.push(`enter: ${node.type}`); + }, + 'Program:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + VariableDeclaration(node) { + visited.push(`enter: ${node.type}`); + }, + 'VariableDeclaration:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + VariableDeclarator(node) { + visited.push(`enter: ${node.type}`); + }, + 'VariableDeclarator:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + Identifier(node) { + visited.push(`enter: ${node.type} ${node.name}`); + }, + 'Identifier:exit'(node) { + visited.push(`exit: ${node.type} ${node.name}`); + }, + ObjectExpression(node) { + visited.push(`enter: ${node.type}`); + }, + 'ObjectExpression:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + Property(node) { + visited.push(`enter: ${node.type}`); + }, + 'Property:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + Literal(node) { + visited.push(`enter: ${node.type} ${node.value}`); + }, + 'Literal:exit'(node) { + visited.push(`exit: ${node.type} ${node.value}`); + }, + // Should not be visited + DebuggerStatement(node) { + visited.push(`enter: ${node.type}`); + }, + 'DebuggerStatement:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + ClassExpression(node) { + visited.push(`enter: ${node.type}`); + }, + 'ClassExpression:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + }); + visitor.visit(program); + + expect(visited).toStrictEqual([ + 'enter: Program', + 'enter: VariableDeclaration', + 'enter: VariableDeclarator', + 'enter: Identifier x', + 'exit: Identifier x', + 'enter: ObjectExpression', + 'enter: Property', + 'enter: Identifier y', + 'exit: Identifier y', + 'enter: Literal 123', + 'exit: Literal 123', + 'exit: Property', + 'exit: ObjectExpression', + 'exit: VariableDeclarator', + 'exit: VariableDeclaration', + 'exit: Program', + ]); + }); + + it('visit TS code', () => { + const code = 'type T = string | Q;'; + const { program } = parseSync('test.ts', code); + + const visited = []; + const visitor = new Visitor({ + Program(node) { + visited.push(`enter: ${node.type}`); + }, + 'Program:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + TSTypeAliasDeclaration(node) { + visited.push(`enter: ${node.type}`); + }, + 'TSTypeAliasDeclaration:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + Identifier(node) { + visited.push(`enter: ${node.type} ${node.name}`); + }, + 'Identifier:exit'(node) { + visited.push(`exit: ${node.type} ${node.name}`); + }, + TSUnionType(node) { + visited.push(`enter: ${node.type}`); + }, + 'TSUnionType:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + TSStringKeyword(node) { + visited.push(`enter: ${node.type}`); + }, + 'TSStringKeyword:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + TSTypeReference(node) { + visited.push(`enter: ${node.type}`); + }, + 'TSTypeReference:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + // Should not be visited + DebuggerStatement(node) { + visited.push(`enter: ${node.type}`); + }, + 'DebuggerStatement:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + ClassExpression(node) { + visited.push(`enter: ${node.type}`); + }, + 'ClassExpression:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + }); + visitor.visit(program); + + expect(visited).toStrictEqual([ + 'enter: Program', + 'enter: TSTypeAliasDeclaration', + 'enter: Identifier T', + 'exit: Identifier T', + 'enter: TSUnionType', + 'enter: TSStringKeyword', + 'exit: TSStringKeyword', + 'enter: TSTypeReference', + 'enter: Identifier Q', + 'exit: Identifier Q', + 'exit: TSTypeReference', + 'exit: TSUnionType', + 'exit: TSTypeAliasDeclaration', + 'exit: Program', + ]); + }); + + it('reuse visitor', () => { + const visited = []; + const visitor = new Visitor({ + Program(node) { + visited.push(`enter: ${node.type}`); + }, + 'Program:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + Identifier(node) { + visited.push(`enter: ${node.type} ${node.name}`); + }, + 'Identifier:exit'(node) { + visited.push(`exit: ${node.type} ${node.name}`); + }, + // Should not be visited + DebuggerStatement(node) { + visited.push(`enter: ${node.type}`); + }, + 'DebuggerStatement:exit'(node) { + visited.push(`exit: ${node.type}`); + }, + }); + + const code = 'const x = { y: 123 }'; + const { program } = parseSync('test.js', code); + visitor.visit(program); + expect(visited).toStrictEqual([ + 'enter: Program', + 'enter: Identifier x', + 'exit: Identifier x', + 'enter: Identifier y', + 'exit: Identifier y', + 'exit: Program', + ]); + + visited.length = 0; + + const code2 = 'let z'; + const program2 = parseSync('test.js', code2).program; + visitor.visit(program2); + expect(visited).toStrictEqual([ + 'enter: Program', + 'enter: Identifier z', + 'exit: Identifier z', + 'exit: Program', + ]); + }); +}); + +it('visitor keys', () => { + expect(visitorKeys.Literal).toEqual([]); + expect(visitorKeys.VariableDeclaration).toEqual(['declarations']); + expect(visitorKeys.ObjectPattern).toEqual(['decorators', 'properties', 'typeAnnotation']); + expect(visitorKeys.ParenthesizedExpression).toEqual(['expression']); + expect(visitorKeys.V8IntrinsicExpression).toEqual(['name', 'arguments']); +}); diff --git a/tasks/ast_tools/src/generators/estree_visit.rs b/tasks/ast_tools/src/generators/estree_visit.rs index fe17147495b8f..773261154d985 100644 --- a/tasks/ast_tools/src/generators/estree_visit.rs +++ b/tasks/ast_tools/src/generators/estree_visit.rs @@ -1,6 +1,7 @@ -//! Generator of ESTree visitor keys. +//! Generator of ESTree visitor. use std::{ + borrow::Cow, cmp::Ordering, fmt::{self, Display}, process::{Command, Stdio}, @@ -35,15 +36,37 @@ define_generator!(ESTreeVisitGenerator); impl Generator for ESTreeVisitGenerator { fn generate_many(&self, _schema: &Schema, codegen: &Codegen) -> Vec { - let visitor_keys = generate(codegen); + let Codes { walk, visitor_keys, type_ids_map, visitor_type } = generate(codegen); - vec![Output::Javascript { - path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/visit/keys.mjs"), - code: visitor_keys, - }] + vec![ + Output::Javascript { + path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/visit/walk.mjs"), + code: walk, + }, + Output::Javascript { + path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/visit/keys.mjs"), + code: visitor_keys, + }, + Output::Javascript { + path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/visit/types.mjs"), + code: type_ids_map, + }, + Output::Javascript { + path: format!("{NAPI_PARSER_PACKAGE_PATH}/generated/visit/visitor.d.ts"), + code: visitor_type, + }, + ] } } +/// Output code. +struct Codes { + walk: String, + visitor_keys: String, + type_ids_map: String, + visitor_type: String, +} + /// Details of a node's name and visitor keys. #[derive(Deserialize, Debug)] struct NodeKeys { @@ -51,8 +74,12 @@ struct NodeKeys { keys: Vec, } -/// Generate visitor keys. -fn generate(codegen: &Codegen) -> String { +/// Generate: +/// * Walk functions. +/// * Visitor keys. +/// * `Map` from node type name to node type ID. +/// * Visitor type definition. +fn generate(codegen: &Codegen) -> Codes { // Run `napi/parser/scripts/visitor-keys.mjs` to get visitor keys from TS-ESLint let script_path = codegen.root_path().join("napi/parser/scripts/visitor-keys.mjs"); @@ -121,26 +148,169 @@ fn generate(codegen: &Codegen) -> String { } }); + // Generate code + #[rustfmt::skip] + let mut walk = string!(" + export { walkProgram } + + const { isArray } = Array; + + function walkNode(node, visitors) { + if (node == null) return; + if (isArray(node)) { + const len = node.length; + for (let i = 0; i < len; i++) { + walkNode(node[i], visitors); + } + } else { + switch (node.type) { + "); + + let mut walk_fns = string!(""); + #[rustfmt::skip] let mut visitor_keys = string!(" export default { // Leaf nodes "); + #[rustfmt::skip] + let mut type_ids_map = string!(" + // Mapping from node type name to node type ID + export const NODE_TYPE_IDS_MAP = new Map([ + // Leaf nodes + "); + + #[rustfmt::skip] + let mut visitor_type = string!(" + import * as ESTree from '@oxc-project/types'; + + export interface VisitorObject { + "); + let mut leaf_nodes_count = None; for (node_id, node) in nodes.iter_enumerated() { let is_leaf = node.keys.is_empty(); if leaf_nodes_count.is_none() && !is_leaf { leaf_nodes_count = Some(node_id.raw()); visitor_keys.push_str("// Non-leaf nodes\n"); + type_ids_map.push_str("// Non-leaf nodes\n"); } let node_name = node.name.as_str(); + write_it!(walk, "case \"{node_name}\": walk{node_name}(node, visitors); break;\n"); + + #[rustfmt::skip] + let walk_fn_body = if is_leaf { + format!(" + const visit = visitors[{node_id}]; + if (visit !== null) visit(node); + ") + } else { + let mut walk_fn_body = format!(" + const enterExit = visitors[{node_id}]; + let exit = null; + if (enterExit !== null) {{ + let enter; + ({{ enter, exit }} = enterExit); + if (enter !== null) enter(node); + }} + "); + + for key in &node.keys { + write_it!(walk_fn_body, "walkNode(node.{key}, visitors);\n"); + } + + walk_fn_body.push_str("if (exit !== null) exit(node);\n"); + + walk_fn_body + }; + + #[rustfmt::skip] + write_it!(walk_fns, " + function walk{node_name}(node, visitors) {{ + {walk_fn_body} + }} + "); + let keys = &node.keys; write_it!(visitor_keys, "{node_name}: {keys:?},\n"); + write_it!(type_ids_map, "[\"{node_name}\", {node_id}],\n"); + + // Convert ESTree type name to Oxc type names where they diverge + let type_names: Option<&[&str]> = match node_name { + "Literal" => Some(&[ + "BooleanLiteral", + "NullLiteral", + "NumericLiteral", + "StringLiteral", + "BigIntLiteral", + "RegExpLiteral", + ]), + "Identifier" => Some(&[ + "IdentifierName", + "IdentifierReference", + "BindingIdentifier", + "LabelIdentifier", + "TSThisParameter", + "TSIndexSignatureName", + ]), + "Property" => Some(&[ + "ObjectProperty", + "AssignmentTargetProperty", + "AssignmentTargetPropertyProperty", + "BindingProperty", + ]), + "RestElement" => { + Some(&["AssignmentTargetRest", "BindingRestElement", "FormalParameterRest"]) + } + _ => None, + }; + let type_def = if let Some(type_names) = type_names { + Cow::Owned(type_names.join(" | ESTree.")) + } else { + let type_name = match node_name { + "FunctionDeclaration" + | "FunctionExpression" + | "TSDeclareFunction" + | "TSEmptyBodyFunctionExpression" => "Function", + "ClassDeclaration" | "ClassExpression" => "Class", + _ if node_name.starts_with("TSJSDoc") => &node_name[2..], + _ if node_name.starts_with("TSAbstract") => &node_name[10..], + _ => node_name, + }; + Cow::Borrowed(type_name) + }; + + write_it!( + visitor_type, + "{node_name}?: (node: ESTree.{type_def}) => void; + '{node_name}:exit'?: (node: ESTree.{type_def}) => void; + " + ); } + #[rustfmt::skip] + write_it!(walk, " + }} + }} + }} + + {walk_fns} + "); + visitor_keys.push_str("};"); - visitor_keys + let nodes_count = nodes.len(); + let leaf_nodes_count = leaf_nodes_count.unwrap(); + #[rustfmt::skip] + write_it!(type_ids_map, "]); + + export const NODE_TYPES_COUNT = {nodes_count}; + export const LEAF_NODE_TYPES_COUNT = {leaf_nodes_count}; + "); + + visitor_type.push('}'); + + Codes { walk, visitor_keys, type_ids_map, visitor_type } }