silphius/app/astride/traverse.js
2024-07-25 09:00:54 -05:00

57 lines
1.7 KiB
JavaScript

export const TRAVERSAL_PATH = {
ArrayExpression: ['elements'],
ArrayPattern: ['elements'],
AssignmentExpression: ['left', 'right'],
AwaitExpression: ['argument'],
BinaryExpression: ['left', 'right'],
BlockStatement: ['body'],
BreakStatement: [],
CallExpression: ['arguments', 'callee'],
ChainExpression: ['expression'],
ConditionalExpression: ['alternate', 'consequent', 'test'],
DoWhileStatement: ['body', 'test'],
ExpressionStatement: ['expression'],
ForOfStatement: ['body', 'left', 'right'],
ForStatement: ['body', 'init', 'test', 'update'],
Identifier: [],
IfStatement: ['alternate', 'consequent', 'test'],
MemberExpression: ['object', 'property'],
NewExpression: ['arguments', 'callee'],
Literal: [],
LogicalExpression: ['left', 'right'],
ObjectExpression: ['properties'],
ObjectPattern: ['properties'],
Program: ['body'],
Property: ['key', 'value'],
ReturnStatement: ['argument'],
SpreadElement: ['argument'],
UnaryExpression: ['argument'],
UpdateExpression: ['argument'],
VariableDeclaration: ['declarations'],
VariableDeclarator: ['id', 'init'],
WhileStatement: ['body', 'test'],
};
export default function traverse(node, visitor) {
/* v8 ignore next 3 */
if (!(node.type in TRAVERSAL_PATH)) {
throw new Error(`node type ${node.type} not traversable. (${Object.keys(node).join(', ')})`);
}
visitor(node, 'enter');
for (const key of TRAVERSAL_PATH[node.type]) {
if (Array.isArray(node[key])) {
for (const child of node[key]) {
if (child) {
traverse(child, visitor);
}
}
}
else {
if (node[key]) {
traverse(node[key], visitor);
}
}
}
visitor(node, 'exit');
}