| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 | /** * @fileoverview Traverser to traverse AST trees. * @author Nicholas C. Zakas * @author Toru Nagashima */"use strict";//------------------------------------------------------------------------------// Requirements//------------------------------------------------------------------------------const vk = require("eslint-visitor-keys");const debug = require("debug")("eslint:traverser");//------------------------------------------------------------------------------// Helpers//------------------------------------------------------------------------------/** * Do nothing. * @returns {void} */function noop() {    // do nothing.}/** * Check whether the given value is an ASTNode or not. * @param {any} x The value to check. * @returns {boolean} `true` if the value is an ASTNode. */function isNode(x) {    return x !== null && typeof x === "object" && typeof x.type === "string";}/** * Get the visitor keys of a given node. * @param {Object} visitorKeys The map of visitor keys. * @param {ASTNode} node The node to get their visitor keys. * @returns {string[]} The visitor keys of the node. */function getVisitorKeys(visitorKeys, node) {    let keys = visitorKeys[node.type];    if (!keys) {        keys = vk.getKeys(node);        debug("Unknown node type \"%s\": Estimated visitor keys %j", node.type, keys);    }    return keys;}/** * The traverser class to traverse AST trees. */class Traverser {    constructor() {        this._current = null;        this._parents = [];        this._skipped = false;        this._broken = false;        this._visitorKeys = null;        this._enter = null;        this._leave = null;    }    /**     * Gives current node.     * @returns {ASTNode} The current node.     */    current() {        return this._current;    }    /**     * Gives a copy of the ancestor nodes.     * @returns {ASTNode[]} The ancestor nodes.     */    parents() {        return this._parents.slice(0);    }    /**     * Break the current traversal.     * @returns {void}     */    break() {        this._broken = true;    }    /**     * Skip child nodes for the current traversal.     * @returns {void}     */    skip() {        this._skipped = true;    }    /**     * Traverse the given AST tree.     * @param {ASTNode} node The root node to traverse.     * @param {Object} options The option object.     * @param {Object} [options.visitorKeys=DEFAULT_VISITOR_KEYS] The keys of each node types to traverse child nodes. Default is `./default-visitor-keys.json`.     * @param {Function} [options.enter=noop] The callback function which is called on entering each node.     * @param {Function} [options.leave=noop] The callback function which is called on leaving each node.     * @returns {void}     */    traverse(node, options) {        this._current = null;        this._parents = [];        this._skipped = false;        this._broken = false;        this._visitorKeys = options.visitorKeys || vk.KEYS;        this._enter = options.enter || noop;        this._leave = options.leave || noop;        this._traverse(node, null);    }    /**     * Traverse the given AST tree recursively.     * @param {ASTNode} node The current node.     * @param {ASTNode|null} parent The parent node.     * @returns {void}     * @private     */    _traverse(node, parent) {        if (!isNode(node)) {            return;        }        this._current = node;        this._skipped = false;        this._enter(node, parent);        if (!this._skipped && !this._broken) {            const keys = getVisitorKeys(this._visitorKeys, node);            if (keys.length >= 1) {                this._parents.push(node);                for (let i = 0; i < keys.length && !this._broken; ++i) {                    const child = node[keys[i]];                    if (Array.isArray(child)) {                        for (let j = 0; j < child.length && !this._broken; ++j) {                            this._traverse(child[j], node);                        }                    } else {                        this._traverse(child, node);                    }                }                this._parents.pop();            }        }        if (!this._broken) {            this._leave(node, parent);        }        this._current = parent;    }    /**     * Calculates the keys to use for traversal.     * @param {ASTNode} node The node to read keys from.     * @returns {string[]} An array of keys to visit on the node.     * @private     */    static getKeys(node) {        return vk.getKeys(node);    }    /**     * Traverse the given AST tree.     * @param {ASTNode} node The root node to traverse.     * @param {Object} options The option object.     * @param {Object} [options.visitorKeys=DEFAULT_VISITOR_KEYS] The keys of each node types to traverse child nodes. Default is `./default-visitor-keys.json`.     * @param {Function} [options.enter=noop] The callback function which is called on entering each node.     * @param {Function} [options.leave=noop] The callback function which is called on leaving each node.     * @returns {void}     */    static traverse(node, options) {        new Traverser().traverse(node, options);    }    /**     * The default visitor keys.     * @type {Object}     */    static get DEFAULT_VISITOR_KEYS() {        return vk.KEYS;    }}module.exports = Traverser;
 |