2 * @fileoverview Traverser to traverse AST trees.
3 * @author Nicholas C. Zakas
4 * @author Toru Nagashima
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const vk = require("eslint-visitor-keys");
13 const debug = require("debug")("eslint:traverser");
15 //------------------------------------------------------------------------------
17 //------------------------------------------------------------------------------
29 * Check whether the given value is an ASTNode or not.
30 * @param {any} x The value to check.
31 * @returns {boolean} `true` if the value is an ASTNode.
34 return x !== null && typeof x === "object" && typeof x.type === "string";
38 * Get the visitor keys of a given node.
39 * @param {Object} visitorKeys The map of visitor keys.
40 * @param {ASTNode} node The node to get their visitor keys.
41 * @returns {string[]} The visitor keys of the node.
43 function getVisitorKeys(visitorKeys, node) {
44 let keys = visitorKeys[node.type];
47 keys = vk.getKeys(node);
48 debug("Unknown node type \"%s\": Estimated visitor keys %j", node.type, keys);
55 * The traverser class to traverse AST trees.
61 this._skipped = false;
63 this._visitorKeys = null;
68 // eslint-disable-next-line jsdoc/require-description
70 * @returns {ASTNode} The current node.
76 // eslint-disable-next-line jsdoc/require-description
78 * @returns {ASTNode[]} The ancestor nodes.
81 return this._parents.slice(0);
85 * Break the current traversal.
93 * Skip child nodes for the current traversal.
101 * Traverse the given AST tree.
102 * @param {ASTNode} node The root node to traverse.
103 * @param {Object} options The option object.
104 * @param {Object} [options.visitorKeys=DEFAULT_VISITOR_KEYS] The keys of each node types to traverse child nodes. Default is `./default-visitor-keys.json`.
105 * @param {Function} [options.enter=noop] The callback function which is called on entering each node.
106 * @param {Function} [options.leave=noop] The callback function which is called on leaving each node.
109 traverse(node, options) {
110 this._current = null;
112 this._skipped = false;
113 this._broken = false;
114 this._visitorKeys = options.visitorKeys || vk.KEYS;
115 this._enter = options.enter || noop;
116 this._leave = options.leave || noop;
117 this._traverse(node, null);
121 * Traverse the given AST tree recursively.
122 * @param {ASTNode} node The current node.
123 * @param {ASTNode|null} parent The parent node.
127 _traverse(node, parent) {
132 this._current = node;
133 this._skipped = false;
134 this._enter(node, parent);
136 if (!this._skipped && !this._broken) {
137 const keys = getVisitorKeys(this._visitorKeys, node);
139 if (keys.length >= 1) {
140 this._parents.push(node);
141 for (let i = 0; i < keys.length && !this._broken; ++i) {
142 const child = node[keys[i]];
144 if (Array.isArray(child)) {
145 for (let j = 0; j < child.length && !this._broken; ++j) {
146 this._traverse(child[j], node);
149 this._traverse(child, node);
157 this._leave(node, parent);
160 this._current = parent;
164 * Calculates the keys to use for traversal.
165 * @param {ASTNode} node The node to read keys from.
166 * @returns {string[]} An array of keys to visit on the node.
169 static getKeys(node) {
170 return vk.getKeys(node);
174 * Traverse the given AST tree.
175 * @param {ASTNode} node The root node to traverse.
176 * @param {Object} options The option object.
177 * @param {Object} [options.visitorKeys=DEFAULT_VISITOR_KEYS] The keys of each node types to traverse child nodes. Default is `./default-visitor-keys.json`.
178 * @param {Function} [options.enter=noop] The callback function which is called on entering each node.
179 * @param {Function} [options.leave=noop] The callback function which is called on leaving each node.
182 static traverse(node, options) {
183 new Traverser().traverse(node, options);
187 * The default visitor keys.
190 static get DEFAULT_VISITOR_KEYS() {
195 module.exports = Traverser;