.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / shared / traverser.js
1 /**
2  * @fileoverview Traverser to traverse AST trees.
3  * @author Nicholas C. Zakas
4  * @author Toru Nagashima
5  */
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const vk = require("eslint-visitor-keys");
13 const debug = require("debug")("eslint:traverser");
14
15 //------------------------------------------------------------------------------
16 // Helpers
17 //------------------------------------------------------------------------------
18
19 /**
20  * Do nothing.
21  * @returns {void}
22  */
23 function noop() {
24
25     // do nothing.
26 }
27
28 /**
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.
32  */
33 function isNode(x) {
34     return x !== null && typeof x === "object" && typeof x.type === "string";
35 }
36
37 /**
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.
42  */
43 function getVisitorKeys(visitorKeys, node) {
44     let keys = visitorKeys[node.type];
45
46     if (!keys) {
47         keys = vk.getKeys(node);
48         debug("Unknown node type \"%s\": Estimated visitor keys %j", node.type, keys);
49     }
50
51     return keys;
52 }
53
54 /**
55  * The traverser class to traverse AST trees.
56  */
57 class Traverser {
58     constructor() {
59         this._current = null;
60         this._parents = [];
61         this._skipped = false;
62         this._broken = false;
63         this._visitorKeys = null;
64         this._enter = null;
65         this._leave = null;
66     }
67
68     // eslint-disable-next-line jsdoc/require-description
69     /**
70      * @returns {ASTNode} The current node.
71      */
72     current() {
73         return this._current;
74     }
75
76     // eslint-disable-next-line jsdoc/require-description
77     /**
78      * @returns {ASTNode[]} The ancestor nodes.
79      */
80     parents() {
81         return this._parents.slice(0);
82     }
83
84     /**
85      * Break the current traversal.
86      * @returns {void}
87      */
88     break() {
89         this._broken = true;
90     }
91
92     /**
93      * Skip child nodes for the current traversal.
94      * @returns {void}
95      */
96     skip() {
97         this._skipped = true;
98     }
99
100     /**
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.
107      * @returns {void}
108      */
109     traverse(node, options) {
110         this._current = null;
111         this._parents = [];
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);
118     }
119
120     /**
121      * Traverse the given AST tree recursively.
122      * @param {ASTNode} node The current node.
123      * @param {ASTNode|null} parent The parent node.
124      * @returns {void}
125      * @private
126      */
127     _traverse(node, parent) {
128         if (!isNode(node)) {
129             return;
130         }
131
132         this._current = node;
133         this._skipped = false;
134         this._enter(node, parent);
135
136         if (!this._skipped && !this._broken) {
137             const keys = getVisitorKeys(this._visitorKeys, node);
138
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]];
143
144                     if (Array.isArray(child)) {
145                         for (let j = 0; j < child.length && !this._broken; ++j) {
146                             this._traverse(child[j], node);
147                         }
148                     } else {
149                         this._traverse(child, node);
150                     }
151                 }
152                 this._parents.pop();
153             }
154         }
155
156         if (!this._broken) {
157             this._leave(node, parent);
158         }
159
160         this._current = parent;
161     }
162
163     /**
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.
167      * @private
168      */
169     static getKeys(node) {
170         return vk.getKeys(node);
171     }
172
173     /**
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.
180      * @returns {void}
181      */
182     static traverse(node, options) {
183         new Traverser().traverse(node, options);
184     }
185
186     /**
187      * The default visitor keys.
188      * @type {Object}
189      */
190     static get DEFAULT_VISITOR_KEYS() {
191         return vk.KEYS;
192     }
193 }
194
195 module.exports = Traverser;