1import { visitorKeys } from '@typescript-eslint/visitor-keys'; 2import { TSESTree } from './ts-estree'; 3 4// eslint-disable-next-line @typescript-eslint/no-explicit-any 5function isValidNode(x: any): x is TSESTree.Node { 6 return x !== null && typeof x === 'object' && typeof x.type === 'string'; 7} 8 9function getVisitorKeysForNode( 10 allVisitorKeys: typeof visitorKeys, 11 node: TSESTree.Node, 12): readonly (keyof TSESTree.Node)[] { 13 const keys = allVisitorKeys[node.type]; 14 return (keys ?? []) as never; 15} 16 17type SimpleTraverseOptions = 18 | { 19 enter: (node: TSESTree.Node, parent: TSESTree.Node | undefined) => void; 20 } 21 | { 22 [key: string]: ( 23 node: TSESTree.Node, 24 parent: TSESTree.Node | undefined, 25 ) => void; 26 }; 27 28class SimpleTraverser { 29 private readonly allVisitorKeys = visitorKeys; 30 private readonly selectors: SimpleTraverseOptions; 31 private readonly setParentPointers: boolean; 32 33 constructor(selectors: SimpleTraverseOptions, setParentPointers = false) { 34 this.selectors = selectors; 35 this.setParentPointers = setParentPointers; 36 } 37 38 traverse(node: unknown, parent: TSESTree.Node | undefined): void { 39 if (!isValidNode(node)) { 40 return; 41 } 42 43 if (this.setParentPointers) { 44 node.parent = parent; 45 } 46 47 if ('enter' in this.selectors) { 48 this.selectors.enter(node, parent); 49 } else if (node.type in this.selectors) { 50 this.selectors[node.type](node, parent); 51 } 52 53 const keys = getVisitorKeysForNode(this.allVisitorKeys, node); 54 if (keys.length < 1) { 55 return; 56 } 57 58 for (const key of keys) { 59 const childOrChildren = node[key]; 60 61 if (Array.isArray(childOrChildren)) { 62 for (const child of childOrChildren) { 63 this.traverse(child, node); 64 } 65 } else { 66 this.traverse(childOrChildren, node); 67 } 68 } 69 } 70} 71 72export function simpleTraverse( 73 startingNode: TSESTree.Node, 74 options: SimpleTraverseOptions, 75 setParentPointers = false, 76): void { 77 new SimpleTraverser(options, setParentPointers).traverse( 78 startingNode, 79 undefined, 80 ); 81} 82