Add a new utility for traversing the AST.

This commit is contained in:
Logan Smyth
2017-10-11 23:03:14 -04:00
parent ef185feb35
commit 191624d800
4 changed files with 126 additions and 31 deletions

View File

@@ -66,6 +66,9 @@ export { VISITOR_KEYS, ALIAS_KEYS, NODE_FIELDS, BUILDER_KEYS, DEPRECATED_KEYS };
import * as _react from "./react";
export { _react as react };
import { traverse, traverseFast } from "./traverse";
export { traverse, traverseFast };
/**
* Registers `is[Type]` and `assert[Type]` for all types.
*/
@@ -534,36 +537,6 @@ export function isNode(node?): boolean {
toFastProperties(t);
toFastProperties(t.VISITOR_KEYS);
/**
* A prefix AST traversal implementation implementation.
*/
export function traverseFast(
node: Node,
enter: (node: Node) => void,
opts?: Object,
) {
if (!node) return;
const keys = t.VISITOR_KEYS[node.type];
if (!keys) return;
opts = opts || {};
enter(node, opts);
for (const key of keys) {
const subNode = node[key];
if (Array.isArray(subNode)) {
for (const node of subNode) {
traverseFast(node, enter, opts);
}
} else {
traverseFast(subNode, enter, opts);
}
}
}
const CLEAR_KEYS: Array = ["tokens", "start", "end", "loc", "raw", "rawValue"];
const CLEAR_KEYS_PLUS_COMMENTS: Array = t.COMMENT_KEYS

View File

@@ -0,0 +1,99 @@
import { VISITOR_KEYS } from "./index";
/**
* A prefix AST traversal implementation meant for simple searching
* and processing.
*/
export function traverseFast(
node: Node,
enter: (node: Node) => void,
opts?: Object,
) {
if (!node) return;
const keys = VISITOR_KEYS[node.type];
if (!keys) return;
opts = opts || {};
enter(node, opts);
for (const key of keys) {
const subNode = node[key];
if (Array.isArray(subNode)) {
for (const node of subNode) {
traverseFast(node, enter, opts);
}
} else {
traverseFast(subNode, enter, opts);
}
}
}
export type TraversalAncestors = Array<{
node: BabelNode,
key: string,
index?: number,
}>;
export type TraversalHandler<T> = (BabelNode, TraversalAncestors, T) => void;
export type TraversalHandlers<T> = {
enter?: TraversalHandler<T>,
exit?: TraversalHandler<T>,
};
/**
* A general AST traversal with both prefix and postfix handlers, and a
* state object. Exposes ancestry data to each handler so that more complex
* AST data can be taken into account.
*/
export function traverse<T>(
node: BabelNode,
handlers: TraversalHandler<T> | TraversalHandlers<T>,
state?: T,
) {
if (typeof handlers === "function") {
handlers = { enter: handlers };
}
const { enter, exit } = handlers;
traverseSimpleImpl(node, enter, exit, state, []);
}
function traverseSimpleImpl(node, enter, exit, state, ancestors) {
const keys = VISITOR_KEYS[node.type];
if (!keys) return;
if (enter) enter(node, ancestors, state);
for (const key of keys) {
const subNode = node[key];
if (Array.isArray(subNode)) {
for (let i = 0; i < subNode.length; i++) {
const child = subNode[i];
if (!child) continue;
ancestors.push({
node,
key,
index: i,
});
traverseSimpleImpl(child, enter, exit, state, ancestors);
ancestors.pop();
}
} else if (subNode) {
ancestors.push({
node,
key,
});
traverseSimpleImpl(subNode, enter, exit, state, ancestors);
ancestors.pop();
}
}
if (exit) exit(node, ancestors, state);
}