.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint-utils / index.mjs
1 /*! @author Toru Nagashima <https://github.com/mysticatea> */
2 import evk from 'eslint-visitor-keys';
3
4 /**
5  * Get the innermost scope which contains a given location.
6  * @param {Scope} initialScope The initial scope to search.
7  * @param {Node} node The location to search.
8  * @returns {Scope} The innermost scope.
9  */
10 function getInnermostScope(initialScope, node) {
11     const location = node.range[0];
12
13     let scope = initialScope;
14     let found = false;
15     do {
16         found = false;
17         for (const childScope of scope.childScopes) {
18             const range = childScope.block.range;
19
20             if (range[0] <= location && location < range[1]) {
21                 scope = childScope;
22                 found = true;
23                 break
24             }
25         }
26     } while (found)
27
28     return scope
29 }
30
31 /**
32  * Find the variable of a given name.
33  * @param {Scope} initialScope The scope to start finding.
34  * @param {string|Node} nameOrNode The variable name to find. If this is a Node object then it should be an Identifier node.
35  * @returns {Variable|null} The found variable or null.
36  */
37 function findVariable(initialScope, nameOrNode) {
38     let name = "";
39     let scope = initialScope;
40
41     if (typeof nameOrNode === "string") {
42         name = nameOrNode;
43     } else {
44         name = nameOrNode.name;
45         scope = getInnermostScope(scope, nameOrNode);
46     }
47
48     while (scope != null) {
49         const variable = scope.set.get(name);
50         if (variable != null) {
51             return variable
52         }
53         scope = scope.upper;
54     }
55
56     return null
57 }
58
59 /**
60  * Negate the result of `this` calling.
61  * @param {Token} token The token to check.
62  * @returns {boolean} `true` if the result of `this(token)` is `false`.
63  */
64 function negate0(token) {
65     return !this(token) //eslint-disable-line no-invalid-this
66 }
67
68 /**
69  * Creates the negate function of the given function.
70  * @param {function(Token):boolean} f - The function to negate.
71  * @returns {function(Token):boolean} Negated function.
72  */
73 function negate(f) {
74     return negate0.bind(f)
75 }
76
77 /**
78  * Checks if the given token is an arrow token or not.
79  * @param {Token} token - The token to check.
80  * @returns {boolean} `true` if the token is an arrow token.
81  */
82 function isArrowToken(token) {
83     return token.value === "=>" && token.type === "Punctuator"
84 }
85
86 /**
87  * Checks if the given token is a comma token or not.
88  * @param {Token} token - The token to check.
89  * @returns {boolean} `true` if the token is a comma token.
90  */
91 function isCommaToken(token) {
92     return token.value === "," && token.type === "Punctuator"
93 }
94
95 /**
96  * Checks if the given token is a semicolon token or not.
97  * @param {Token} token - The token to check.
98  * @returns {boolean} `true` if the token is a semicolon token.
99  */
100 function isSemicolonToken(token) {
101     return token.value === ";" && token.type === "Punctuator"
102 }
103
104 /**
105  * Checks if the given token is a colon token or not.
106  * @param {Token} token - The token to check.
107  * @returns {boolean} `true` if the token is a colon token.
108  */
109 function isColonToken(token) {
110     return token.value === ":" && token.type === "Punctuator"
111 }
112
113 /**
114  * Checks if the given token is an opening parenthesis token or not.
115  * @param {Token} token - The token to check.
116  * @returns {boolean} `true` if the token is an opening parenthesis token.
117  */
118 function isOpeningParenToken(token) {
119     return token.value === "(" && token.type === "Punctuator"
120 }
121
122 /**
123  * Checks if the given token is a closing parenthesis token or not.
124  * @param {Token} token - The token to check.
125  * @returns {boolean} `true` if the token is a closing parenthesis token.
126  */
127 function isClosingParenToken(token) {
128     return token.value === ")" && token.type === "Punctuator"
129 }
130
131 /**
132  * Checks if the given token is an opening square bracket token or not.
133  * @param {Token} token - The token to check.
134  * @returns {boolean} `true` if the token is an opening square bracket token.
135  */
136 function isOpeningBracketToken(token) {
137     return token.value === "[" && token.type === "Punctuator"
138 }
139
140 /**
141  * Checks if the given token is a closing square bracket token or not.
142  * @param {Token} token - The token to check.
143  * @returns {boolean} `true` if the token is a closing square bracket token.
144  */
145 function isClosingBracketToken(token) {
146     return token.value === "]" && token.type === "Punctuator"
147 }
148
149 /**
150  * Checks if the given token is an opening brace token or not.
151  * @param {Token} token - The token to check.
152  * @returns {boolean} `true` if the token is an opening brace token.
153  */
154 function isOpeningBraceToken(token) {
155     return token.value === "{" && token.type === "Punctuator"
156 }
157
158 /**
159  * Checks if the given token is a closing brace token or not.
160  * @param {Token} token - The token to check.
161  * @returns {boolean} `true` if the token is a closing brace token.
162  */
163 function isClosingBraceToken(token) {
164     return token.value === "}" && token.type === "Punctuator"
165 }
166
167 /**
168  * Checks if the given token is a comment token or not.
169  * @param {Token} token - The token to check.
170  * @returns {boolean} `true` if the token is a comment token.
171  */
172 function isCommentToken(token) {
173     return (
174         token.type === "Line" ||
175         token.type === "Block" ||
176         token.type === "Shebang"
177     )
178 }
179
180 const isNotArrowToken = negate(isArrowToken);
181 const isNotCommaToken = negate(isCommaToken);
182 const isNotSemicolonToken = negate(isSemicolonToken);
183 const isNotColonToken = negate(isColonToken);
184 const isNotOpeningParenToken = negate(isOpeningParenToken);
185 const isNotClosingParenToken = negate(isClosingParenToken);
186 const isNotOpeningBracketToken = negate(isOpeningBracketToken);
187 const isNotClosingBracketToken = negate(isClosingBracketToken);
188 const isNotOpeningBraceToken = negate(isOpeningBraceToken);
189 const isNotClosingBraceToken = negate(isClosingBraceToken);
190 const isNotCommentToken = negate(isCommentToken);
191
192 /**
193  * Get the `(` token of the given function node.
194  * @param {Node} node - The function node to get.
195  * @param {SourceCode} sourceCode - The source code object to get tokens.
196  * @returns {Token} `(` token.
197  */
198 function getOpeningParenOfParams(node, sourceCode) {
199     return node.id
200         ? sourceCode.getTokenAfter(node.id, isOpeningParenToken)
201         : sourceCode.getFirstToken(node, isOpeningParenToken)
202 }
203
204 /**
205  * Get the location of the given function node for reporting.
206  * @param {Node} node - The function node to get.
207  * @param {SourceCode} sourceCode - The source code object to get tokens.
208  * @returns {string} The location of the function node for reporting.
209  */
210 function getFunctionHeadLocation(node, sourceCode) {
211     const parent = node.parent;
212     let start = null;
213     let end = null;
214
215     if (node.type === "ArrowFunctionExpression") {
216         const arrowToken = sourceCode.getTokenBefore(node.body, isArrowToken);
217
218         start = arrowToken.loc.start;
219         end = arrowToken.loc.end;
220     } else if (
221         parent.type === "Property" ||
222         parent.type === "MethodDefinition"
223     ) {
224         start = parent.loc.start;
225         end = getOpeningParenOfParams(node, sourceCode).loc.start;
226     } else {
227         start = node.loc.start;
228         end = getOpeningParenOfParams(node, sourceCode).loc.start;
229     }
230
231     return {
232         start: Object.assign({}, start),
233         end: Object.assign({}, end),
234     }
235 }
236
237 /* globals BigInt, globalThis, global, self, window */
238
239 const globalObject =
240     typeof globalThis !== "undefined"
241         ? globalThis
242         : typeof self !== "undefined"
243         ? self
244         : typeof window !== "undefined"
245         ? window
246         : typeof global !== "undefined"
247         ? global
248         : {};
249
250 const builtinNames = Object.freeze(
251     new Set([
252         "Array",
253         "ArrayBuffer",
254         "BigInt",
255         "BigInt64Array",
256         "BigUint64Array",
257         "Boolean",
258         "DataView",
259         "Date",
260         "decodeURI",
261         "decodeURIComponent",
262         "encodeURI",
263         "encodeURIComponent",
264         "escape",
265         "Float32Array",
266         "Float64Array",
267         "Function",
268         "Infinity",
269         "Int16Array",
270         "Int32Array",
271         "Int8Array",
272         "isFinite",
273         "isNaN",
274         "isPrototypeOf",
275         "JSON",
276         "Map",
277         "Math",
278         "NaN",
279         "Number",
280         "Object",
281         "parseFloat",
282         "parseInt",
283         "Promise",
284         "Proxy",
285         "Reflect",
286         "RegExp",
287         "Set",
288         "String",
289         "Symbol",
290         "Uint16Array",
291         "Uint32Array",
292         "Uint8Array",
293         "Uint8ClampedArray",
294         "undefined",
295         "unescape",
296         "WeakMap",
297         "WeakSet",
298     ])
299 );
300 const callAllowed = new Set(
301     [
302         Array.isArray,
303         typeof BigInt === "function" ? BigInt : undefined,
304         Boolean,
305         Date,
306         Date.parse,
307         decodeURI,
308         decodeURIComponent,
309         encodeURI,
310         encodeURIComponent,
311         escape,
312         isFinite,
313         isNaN,
314         isPrototypeOf,
315         ...Object.getOwnPropertyNames(Math)
316             .map(k => Math[k])
317             .filter(f => typeof f === "function"),
318         Number,
319         Number.isFinite,
320         Number.isNaN,
321         Number.parseFloat,
322         Number.parseInt,
323         Object,
324         Object.entries,
325         Object.is,
326         Object.isExtensible,
327         Object.isFrozen,
328         Object.isSealed,
329         Object.keys,
330         Object.values,
331         parseFloat,
332         parseInt,
333         RegExp,
334         String,
335         String.fromCharCode,
336         String.fromCodePoint,
337         String.raw,
338         Symbol,
339         Symbol.for,
340         Symbol.keyFor,
341         unescape,
342     ].filter(f => typeof f === "function")
343 );
344 const callPassThrough = new Set([
345     Object.freeze,
346     Object.preventExtensions,
347     Object.seal,
348 ]);
349
350 /**
351  * Get the property descriptor.
352  * @param {object} object The object to get.
353  * @param {string|number|symbol} name The property name to get.
354  */
355 function getPropertyDescriptor(object, name) {
356     let x = object;
357     while ((typeof x === "object" || typeof x === "function") && x !== null) {
358         const d = Object.getOwnPropertyDescriptor(x, name);
359         if (d) {
360             return d
361         }
362         x = Object.getPrototypeOf(x);
363     }
364     return null
365 }
366
367 /**
368  * Check if a property is getter or not.
369  * @param {object} object The object to check.
370  * @param {string|number|symbol} name The property name to check.
371  */
372 function isGetter(object, name) {
373     const d = getPropertyDescriptor(object, name);
374     return d != null && d.get != null
375 }
376
377 /**
378  * Get the element values of a given node list.
379  * @param {Node[]} nodeList The node list to get values.
380  * @param {Scope|undefined} initialScope The initial scope to find variables.
381  * @returns {any[]|null} The value list if all nodes are constant. Otherwise, null.
382  */
383 function getElementValues(nodeList, initialScope) {
384     const valueList = [];
385
386     for (let i = 0; i < nodeList.length; ++i) {
387         const elementNode = nodeList[i];
388
389         if (elementNode == null) {
390             valueList.length = i + 1;
391         } else if (elementNode.type === "SpreadElement") {
392             const argument = getStaticValueR(elementNode.argument, initialScope);
393             if (argument == null) {
394                 return null
395             }
396             valueList.push(...argument.value);
397         } else {
398             const element = getStaticValueR(elementNode, initialScope);
399             if (element == null) {
400                 return null
401             }
402             valueList.push(element.value);
403         }
404     }
405
406     return valueList
407 }
408
409 const operations = Object.freeze({
410     ArrayExpression(node, initialScope) {
411         const elements = getElementValues(node.elements, initialScope);
412         return elements != null ? { value: elements } : null
413     },
414
415     AssignmentExpression(node, initialScope) {
416         if (node.operator === "=") {
417             return getStaticValueR(node.right, initialScope)
418         }
419         return null
420     },
421
422     //eslint-disable-next-line complexity
423     BinaryExpression(node, initialScope) {
424         if (node.operator === "in" || node.operator === "instanceof") {
425             // Not supported.
426             return null
427         }
428
429         const left = getStaticValueR(node.left, initialScope);
430         const right = getStaticValueR(node.right, initialScope);
431         if (left != null && right != null) {
432             switch (node.operator) {
433                 case "==":
434                     return { value: left.value == right.value } //eslint-disable-line eqeqeq
435                 case "!=":
436                     return { value: left.value != right.value } //eslint-disable-line eqeqeq
437                 case "===":
438                     return { value: left.value === right.value }
439                 case "!==":
440                     return { value: left.value !== right.value }
441                 case "<":
442                     return { value: left.value < right.value }
443                 case "<=":
444                     return { value: left.value <= right.value }
445                 case ">":
446                     return { value: left.value > right.value }
447                 case ">=":
448                     return { value: left.value >= right.value }
449                 case "<<":
450                     return { value: left.value << right.value }
451                 case ">>":
452                     return { value: left.value >> right.value }
453                 case ">>>":
454                     return { value: left.value >>> right.value }
455                 case "+":
456                     return { value: left.value + right.value }
457                 case "-":
458                     return { value: left.value - right.value }
459                 case "*":
460                     return { value: left.value * right.value }
461                 case "/":
462                     return { value: left.value / right.value }
463                 case "%":
464                     return { value: left.value % right.value }
465                 case "**":
466                     return { value: Math.pow(left.value, right.value) }
467                 case "|":
468                     return { value: left.value | right.value }
469                 case "^":
470                     return { value: left.value ^ right.value }
471                 case "&":
472                     return { value: left.value & right.value }
473
474                 // no default
475             }
476         }
477
478         return null
479     },
480
481     CallExpression(node, initialScope) {
482         const calleeNode = node.callee;
483         const args = getElementValues(node.arguments, initialScope);
484
485         if (args != null) {
486             if (calleeNode.type === "MemberExpression") {
487                 const object = getStaticValueR(calleeNode.object, initialScope);
488                 if (object != null) {
489                     if (
490                         object.value == null &&
491                         (object.optional || node.optional)
492                     ) {
493                         return { value: undefined, optional: true }
494                     }
495                     const property = calleeNode.computed
496                         ? getStaticValueR(calleeNode.property, initialScope)
497                         : { value: calleeNode.property.name };
498
499                     if (property != null) {
500                         const receiver = object.value;
501                         const methodName = property.value;
502                         if (callAllowed.has(receiver[methodName])) {
503                             return { value: receiver[methodName](...args) }
504                         }
505                         if (callPassThrough.has(receiver[methodName])) {
506                             return { value: args[0] }
507                         }
508                     }
509                 }
510             } else {
511                 const callee = getStaticValueR(calleeNode, initialScope);
512                 if (callee != null) {
513                     if (callee.value == null && node.optional) {
514                         return { value: undefined, optional: true }
515                     }
516                     const func = callee.value;
517                     if (callAllowed.has(func)) {
518                         return { value: func(...args) }
519                     }
520                     if (callPassThrough.has(func)) {
521                         return { value: args[0] }
522                     }
523                 }
524             }
525         }
526
527         return null
528     },
529
530     ConditionalExpression(node, initialScope) {
531         const test = getStaticValueR(node.test, initialScope);
532         if (test != null) {
533             return test.value
534                 ? getStaticValueR(node.consequent, initialScope)
535                 : getStaticValueR(node.alternate, initialScope)
536         }
537         return null
538     },
539
540     ExpressionStatement(node, initialScope) {
541         return getStaticValueR(node.expression, initialScope)
542     },
543
544     Identifier(node, initialScope) {
545         if (initialScope != null) {
546             const variable = findVariable(initialScope, node);
547
548             // Built-in globals.
549             if (
550                 variable != null &&
551                 variable.defs.length === 0 &&
552                 builtinNames.has(variable.name) &&
553                 variable.name in globalObject
554             ) {
555                 return { value: globalObject[variable.name] }
556             }
557
558             // Constants.
559             if (variable != null && variable.defs.length === 1) {
560                 const def = variable.defs[0];
561                 if (
562                     def.parent &&
563                     def.parent.kind === "const" &&
564                     // TODO(mysticatea): don't support destructuring here.
565                     def.node.id.type === "Identifier"
566                 ) {
567                     return getStaticValueR(def.node.init, initialScope)
568                 }
569             }
570         }
571         return null
572     },
573
574     Literal(node) {
575         //istanbul ignore if : this is implementation-specific behavior.
576         if ((node.regex != null || node.bigint != null) && node.value == null) {
577             // It was a RegExp/BigInt literal, but Node.js didn't support it.
578             return null
579         }
580         return { value: node.value }
581     },
582
583     LogicalExpression(node, initialScope) {
584         const left = getStaticValueR(node.left, initialScope);
585         if (left != null) {
586             if (
587                 (node.operator === "||" && Boolean(left.value) === true) ||
588                 (node.operator === "&&" && Boolean(left.value) === false) ||
589                 (node.operator === "??" && left.value != null)
590             ) {
591                 return left
592             }
593
594             const right = getStaticValueR(node.right, initialScope);
595             if (right != null) {
596                 return right
597             }
598         }
599
600         return null
601     },
602
603     MemberExpression(node, initialScope) {
604         const object = getStaticValueR(node.object, initialScope);
605         if (object != null) {
606             if (object.value == null && (object.optional || node.optional)) {
607                 return { value: undefined, optional: true }
608             }
609             const property = node.computed
610                 ? getStaticValueR(node.property, initialScope)
611                 : { value: node.property.name };
612
613             if (property != null && !isGetter(object.value, property.value)) {
614                 return { value: object.value[property.value] }
615             }
616         }
617         return null
618     },
619
620     ChainExpression(node, initialScope) {
621         const expression = getStaticValueR(node.expression, initialScope);
622         if (expression != null) {
623             return { value: expression.value }
624         }
625         return null
626     },
627
628     NewExpression(node, initialScope) {
629         const callee = getStaticValueR(node.callee, initialScope);
630         const args = getElementValues(node.arguments, initialScope);
631
632         if (callee != null && args != null) {
633             const Func = callee.value;
634             if (callAllowed.has(Func)) {
635                 return { value: new Func(...args) }
636             }
637         }
638
639         return null
640     },
641
642     ObjectExpression(node, initialScope) {
643         const object = {};
644
645         for (const propertyNode of node.properties) {
646             if (propertyNode.type === "Property") {
647                 if (propertyNode.kind !== "init") {
648                     return null
649                 }
650                 const key = propertyNode.computed
651                     ? getStaticValueR(propertyNode.key, initialScope)
652                     : { value: propertyNode.key.name };
653                 const value = getStaticValueR(propertyNode.value, initialScope);
654                 if (key == null || value == null) {
655                     return null
656                 }
657                 object[key.value] = value.value;
658             } else if (
659                 propertyNode.type === "SpreadElement" ||
660                 propertyNode.type === "ExperimentalSpreadProperty"
661             ) {
662                 const argument = getStaticValueR(
663                     propertyNode.argument,
664                     initialScope
665                 );
666                 if (argument == null) {
667                     return null
668                 }
669                 Object.assign(object, argument.value);
670             } else {
671                 return null
672             }
673         }
674
675         return { value: object }
676     },
677
678     SequenceExpression(node, initialScope) {
679         const last = node.expressions[node.expressions.length - 1];
680         return getStaticValueR(last, initialScope)
681     },
682
683     TaggedTemplateExpression(node, initialScope) {
684         const tag = getStaticValueR(node.tag, initialScope);
685         const expressions = getElementValues(
686             node.quasi.expressions,
687             initialScope
688         );
689
690         if (tag != null && expressions != null) {
691             const func = tag.value;
692             const strings = node.quasi.quasis.map(q => q.value.cooked);
693             strings.raw = node.quasi.quasis.map(q => q.value.raw);
694
695             if (func === String.raw) {
696                 return { value: func(strings, ...expressions) }
697             }
698         }
699
700         return null
701     },
702
703     TemplateLiteral(node, initialScope) {
704         const expressions = getElementValues(node.expressions, initialScope);
705         if (expressions != null) {
706             let value = node.quasis[0].value.cooked;
707             for (let i = 0; i < expressions.length; ++i) {
708                 value += expressions[i];
709                 value += node.quasis[i + 1].value.cooked;
710             }
711             return { value }
712         }
713         return null
714     },
715
716     UnaryExpression(node, initialScope) {
717         if (node.operator === "delete") {
718             // Not supported.
719             return null
720         }
721         if (node.operator === "void") {
722             return { value: undefined }
723         }
724
725         const arg = getStaticValueR(node.argument, initialScope);
726         if (arg != null) {
727             switch (node.operator) {
728                 case "-":
729                     return { value: -arg.value }
730                 case "+":
731                     return { value: +arg.value } //eslint-disable-line no-implicit-coercion
732                 case "!":
733                     return { value: !arg.value }
734                 case "~":
735                     return { value: ~arg.value }
736                 case "typeof":
737                     return { value: typeof arg.value }
738
739                 // no default
740             }
741         }
742
743         return null
744     },
745 });
746
747 /**
748  * Get the value of a given node if it's a static value.
749  * @param {Node} node The node to get.
750  * @param {Scope|undefined} initialScope The scope to start finding variable.
751  * @returns {{value:any}|{value:undefined,optional?:true}|null} The static value of the node, or `null`.
752  */
753 function getStaticValueR(node, initialScope) {
754     if (node != null && Object.hasOwnProperty.call(operations, node.type)) {
755         return operations[node.type](node, initialScope)
756     }
757     return null
758 }
759
760 /**
761  * Get the value of a given node if it's a static value.
762  * @param {Node} node The node to get.
763  * @param {Scope} [initialScope] The scope to start finding variable. Optional. If this scope was given, this tries to resolve identifier references which are in the given node as much as possible.
764  * @returns {{value:any}|{value:undefined,optional?:true}|null} The static value of the node, or `null`.
765  */
766 function getStaticValue(node, initialScope = null) {
767     try {
768         return getStaticValueR(node, initialScope)
769     } catch (_error) {
770         return null
771     }
772 }
773
774 /**
775  * Get the value of a given node if it's a literal or a template literal.
776  * @param {Node} node The node to get.
777  * @param {Scope} [initialScope] The scope to start finding variable. Optional. If the node is an Identifier node and this scope was given, this checks the variable of the identifier, and returns the value of it if the variable is a constant.
778  * @returns {string|null} The value of the node, or `null`.
779  */
780 function getStringIfConstant(node, initialScope = null) {
781     // Handle the literals that the platform doesn't support natively.
782     if (node && node.type === "Literal" && node.value === null) {
783         if (node.regex) {
784             return `/${node.regex.pattern}/${node.regex.flags}`
785         }
786         if (node.bigint) {
787             return node.bigint
788         }
789     }
790
791     const evaluated = getStaticValue(node, initialScope);
792     return evaluated && String(evaluated.value)
793 }
794
795 /**
796  * Get the property name from a MemberExpression node or a Property node.
797  * @param {Node} node The node to get.
798  * @param {Scope} [initialScope] The scope to start finding variable. Optional. If the node is a computed property node and this scope was given, this checks the computed property name by the `getStringIfConstant` function with the scope, and returns the value of it.
799  * @returns {string|null} The property name of the node.
800  */
801 function getPropertyName(node, initialScope) {
802     switch (node.type) {
803         case "MemberExpression":
804             if (node.computed) {
805                 return getStringIfConstant(node.property, initialScope)
806             }
807             return node.property.name
808
809         case "Property":
810         case "MethodDefinition":
811             if (node.computed) {
812                 return getStringIfConstant(node.key, initialScope)
813             }
814             if (node.key.type === "Literal") {
815                 return String(node.key.value)
816             }
817             return node.key.name
818
819         // no default
820     }
821
822     return null
823 }
824
825 /**
826  * Get the name and kind of the given function node.
827  * @param {ASTNode} node - The function node to get.
828  * @returns {string} The name and kind of the function node.
829  */
830 function getFunctionNameWithKind(node) {
831     const parent = node.parent;
832     const tokens = [];
833
834     if (parent.type === "MethodDefinition" && parent.static) {
835         tokens.push("static");
836     }
837     if (node.async) {
838         tokens.push("async");
839     }
840     if (node.generator) {
841         tokens.push("generator");
842     }
843
844     if (node.type === "ArrowFunctionExpression") {
845         tokens.push("arrow", "function");
846     } else if (
847         parent.type === "Property" ||
848         parent.type === "MethodDefinition"
849     ) {
850         if (parent.kind === "constructor") {
851             return "constructor"
852         }
853         if (parent.kind === "get") {
854             tokens.push("getter");
855         } else if (parent.kind === "set") {
856             tokens.push("setter");
857         } else {
858             tokens.push("method");
859         }
860     } else {
861         tokens.push("function");
862     }
863
864     if (node.id) {
865         tokens.push(`'${node.id.name}'`);
866     } else {
867         const name = getPropertyName(parent);
868
869         if (name) {
870             tokens.push(`'${name}'`);
871         }
872     }
873
874     if (node.type === "ArrowFunctionExpression") {
875         if (
876             parent.type === "VariableDeclarator" &&
877             parent.id &&
878             parent.id.type === "Identifier"
879         ) {
880             tokens.push(`'${parent.id.name}'`);
881         }
882         if (
883             parent.type === "AssignmentExpression" &&
884             parent.left &&
885             parent.left.type === "Identifier"
886         ) {
887             tokens.push(`'${parent.left.name}'`);
888         }
889     }
890
891     return tokens.join(" ")
892 }
893
894 const typeConversionBinaryOps = Object.freeze(
895     new Set([
896         "==",
897         "!=",
898         "<",
899         "<=",
900         ">",
901         ">=",
902         "<<",
903         ">>",
904         ">>>",
905         "+",
906         "-",
907         "*",
908         "/",
909         "%",
910         "|",
911         "^",
912         "&",
913         "in",
914     ])
915 );
916 const typeConversionUnaryOps = Object.freeze(new Set(["-", "+", "!", "~"]));
917
918 /**
919  * Check whether the given value is an ASTNode or not.
920  * @param {any} x The value to check.
921  * @returns {boolean} `true` if the value is an ASTNode.
922  */
923 function isNode(x) {
924     return x !== null && typeof x === "object" && typeof x.type === "string"
925 }
926
927 const visitor = Object.freeze(
928     Object.assign(Object.create(null), {
929         $visit(node, options, visitorKeys) {
930             const { type } = node;
931
932             if (typeof this[type] === "function") {
933                 return this[type](node, options, visitorKeys)
934             }
935
936             return this.$visitChildren(node, options, visitorKeys)
937         },
938
939         $visitChildren(node, options, visitorKeys) {
940             const { type } = node;
941
942             for (const key of visitorKeys[type] || evk.getKeys(node)) {
943                 const value = node[key];
944
945                 if (Array.isArray(value)) {
946                     for (const element of value) {
947                         if (
948                             isNode(element) &&
949                             this.$visit(element, options, visitorKeys)
950                         ) {
951                             return true
952                         }
953                     }
954                 } else if (
955                     isNode(value) &&
956                     this.$visit(value, options, visitorKeys)
957                 ) {
958                     return true
959                 }
960             }
961
962             return false
963         },
964
965         ArrowFunctionExpression() {
966             return false
967         },
968         AssignmentExpression() {
969             return true
970         },
971         AwaitExpression() {
972             return true
973         },
974         BinaryExpression(node, options, visitorKeys) {
975             if (
976                 options.considerImplicitTypeConversion &&
977                 typeConversionBinaryOps.has(node.operator) &&
978                 (node.left.type !== "Literal" || node.right.type !== "Literal")
979             ) {
980                 return true
981             }
982             return this.$visitChildren(node, options, visitorKeys)
983         },
984         CallExpression() {
985             return true
986         },
987         FunctionExpression() {
988             return false
989         },
990         ImportExpression() {
991             return true
992         },
993         MemberExpression(node, options, visitorKeys) {
994             if (options.considerGetters) {
995                 return true
996             }
997             if (
998                 options.considerImplicitTypeConversion &&
999                 node.computed &&
1000                 node.property.type !== "Literal"
1001             ) {
1002                 return true
1003             }
1004             return this.$visitChildren(node, options, visitorKeys)
1005         },
1006         MethodDefinition(node, options, visitorKeys) {
1007             if (
1008                 options.considerImplicitTypeConversion &&
1009                 node.computed &&
1010                 node.key.type !== "Literal"
1011             ) {
1012                 return true
1013             }
1014             return this.$visitChildren(node, options, visitorKeys)
1015         },
1016         NewExpression() {
1017             return true
1018         },
1019         Property(node, options, visitorKeys) {
1020             if (
1021                 options.considerImplicitTypeConversion &&
1022                 node.computed &&
1023                 node.key.type !== "Literal"
1024             ) {
1025                 return true
1026             }
1027             return this.$visitChildren(node, options, visitorKeys)
1028         },
1029         UnaryExpression(node, options, visitorKeys) {
1030             if (node.operator === "delete") {
1031                 return true
1032             }
1033             if (
1034                 options.considerImplicitTypeConversion &&
1035                 typeConversionUnaryOps.has(node.operator) &&
1036                 node.argument.type !== "Literal"
1037             ) {
1038                 return true
1039             }
1040             return this.$visitChildren(node, options, visitorKeys)
1041         },
1042         UpdateExpression() {
1043             return true
1044         },
1045         YieldExpression() {
1046             return true
1047         },
1048     })
1049 );
1050
1051 /**
1052  * Check whether a given node has any side effect or not.
1053  * @param {Node} node The node to get.
1054  * @param {SourceCode} sourceCode The source code object.
1055  * @param {object} [options] The option object.
1056  * @param {boolean} [options.considerGetters=false] If `true` then it considers member accesses as the node which has side effects.
1057  * @param {boolean} [options.considerImplicitTypeConversion=false] If `true` then it considers implicit type conversion as the node which has side effects.
1058  * @param {object} [options.visitorKeys=evk.KEYS] The keys to traverse nodes. Use `context.getSourceCode().visitorKeys`.
1059  * @returns {boolean} `true` if the node has a certain side effect.
1060  */
1061 function hasSideEffect(
1062     node,
1063     sourceCode,
1064     { considerGetters = false, considerImplicitTypeConversion = false } = {}
1065 ) {
1066     return visitor.$visit(
1067         node,
1068         { considerGetters, considerImplicitTypeConversion },
1069         sourceCode.visitorKeys || evk.KEYS
1070     )
1071 }
1072
1073 /**
1074  * Get the left parenthesis of the parent node syntax if it exists.
1075  * E.g., `if (a) {}` then the `(`.
1076  * @param {Node} node The AST node to check.
1077  * @param {SourceCode} sourceCode The source code object to get tokens.
1078  * @returns {Token|null} The left parenthesis of the parent node syntax
1079  */
1080 function getParentSyntaxParen(node, sourceCode) {
1081     const parent = node.parent;
1082
1083     switch (parent.type) {
1084         case "CallExpression":
1085         case "NewExpression":
1086             if (parent.arguments.length === 1 && parent.arguments[0] === node) {
1087                 return sourceCode.getTokenAfter(
1088                     parent.callee,
1089                     isOpeningParenToken
1090                 )
1091             }
1092             return null
1093
1094         case "DoWhileStatement":
1095             if (parent.test === node) {
1096                 return sourceCode.getTokenAfter(
1097                     parent.body,
1098                     isOpeningParenToken
1099                 )
1100             }
1101             return null
1102
1103         case "IfStatement":
1104         case "WhileStatement":
1105             if (parent.test === node) {
1106                 return sourceCode.getFirstToken(parent, 1)
1107             }
1108             return null
1109
1110         case "ImportExpression":
1111             if (parent.source === node) {
1112                 return sourceCode.getFirstToken(parent, 1)
1113             }
1114             return null
1115
1116         case "SwitchStatement":
1117             if (parent.discriminant === node) {
1118                 return sourceCode.getFirstToken(parent, 1)
1119             }
1120             return null
1121
1122         case "WithStatement":
1123             if (parent.object === node) {
1124                 return sourceCode.getFirstToken(parent, 1)
1125             }
1126             return null
1127
1128         default:
1129             return null
1130     }
1131 }
1132
1133 /**
1134  * Check whether a given node is parenthesized or not.
1135  * @param {number} times The number of parantheses.
1136  * @param {Node} node The AST node to check.
1137  * @param {SourceCode} sourceCode The source code object to get tokens.
1138  * @returns {boolean} `true` if the node is parenthesized the given times.
1139  */
1140 /**
1141  * Check whether a given node is parenthesized or not.
1142  * @param {Node} node The AST node to check.
1143  * @param {SourceCode} sourceCode The source code object to get tokens.
1144  * @returns {boolean} `true` if the node is parenthesized.
1145  */
1146 function isParenthesized(
1147     timesOrNode,
1148     nodeOrSourceCode,
1149     optionalSourceCode
1150 ) {
1151     let times, node, sourceCode, maybeLeftParen, maybeRightParen;
1152     if (typeof timesOrNode === "number") {
1153         times = timesOrNode | 0;
1154         node = nodeOrSourceCode;
1155         sourceCode = optionalSourceCode;
1156         if (!(times >= 1)) {
1157             throw new TypeError("'times' should be a positive integer.")
1158         }
1159     } else {
1160         times = 1;
1161         node = timesOrNode;
1162         sourceCode = nodeOrSourceCode;
1163     }
1164
1165     if (node == null) {
1166         return false
1167     }
1168
1169     maybeLeftParen = maybeRightParen = node;
1170     do {
1171         maybeLeftParen = sourceCode.getTokenBefore(maybeLeftParen);
1172         maybeRightParen = sourceCode.getTokenAfter(maybeRightParen);
1173     } while (
1174         maybeLeftParen != null &&
1175         maybeRightParen != null &&
1176         isOpeningParenToken(maybeLeftParen) &&
1177         isClosingParenToken(maybeRightParen) &&
1178         // Avoid false positive such as `if (a) {}`
1179         maybeLeftParen !== getParentSyntaxParen(node, sourceCode) &&
1180         --times > 0
1181     )
1182
1183     return times === 0
1184 }
1185
1186 /**
1187  * @author Toru Nagashima <https://github.com/mysticatea>
1188  * See LICENSE file in root directory for full license.
1189  */
1190
1191 const placeholder = /\$(?:[$&`']|[1-9][0-9]?)/gu;
1192
1193 /** @type {WeakMap<PatternMatcher, {pattern:RegExp,escaped:boolean}>} */
1194 const internal = new WeakMap();
1195
1196 /**
1197  * Check whether a given character is escaped or not.
1198  * @param {string} str The string to check.
1199  * @param {number} index The location of the character to check.
1200  * @returns {boolean} `true` if the character is escaped.
1201  */
1202 function isEscaped(str, index) {
1203     let escaped = false;
1204     for (let i = index - 1; i >= 0 && str.charCodeAt(i) === 0x5c; --i) {
1205         escaped = !escaped;
1206     }
1207     return escaped
1208 }
1209
1210 /**
1211  * Replace a given string by a given matcher.
1212  * @param {PatternMatcher} matcher The pattern matcher.
1213  * @param {string} str The string to be replaced.
1214  * @param {string} replacement The new substring to replace each matched part.
1215  * @returns {string} The replaced string.
1216  */
1217 function replaceS(matcher, str, replacement) {
1218     const chunks = [];
1219     let index = 0;
1220
1221     /** @type {RegExpExecArray} */
1222     let match = null;
1223
1224     /**
1225      * @param {string} key The placeholder.
1226      * @returns {string} The replaced string.
1227      */
1228     function replacer(key) {
1229         switch (key) {
1230             case "$$":
1231                 return "$"
1232             case "$&":
1233                 return match[0]
1234             case "$`":
1235                 return str.slice(0, match.index)
1236             case "$'":
1237                 return str.slice(match.index + match[0].length)
1238             default: {
1239                 const i = key.slice(1);
1240                 if (i in match) {
1241                     return match[i]
1242                 }
1243                 return key
1244             }
1245         }
1246     }
1247
1248     for (match of matcher.execAll(str)) {
1249         chunks.push(str.slice(index, match.index));
1250         chunks.push(replacement.replace(placeholder, replacer));
1251         index = match.index + match[0].length;
1252     }
1253     chunks.push(str.slice(index));
1254
1255     return chunks.join("")
1256 }
1257
1258 /**
1259  * Replace a given string by a given matcher.
1260  * @param {PatternMatcher} matcher The pattern matcher.
1261  * @param {string} str The string to be replaced.
1262  * @param {(...strs[])=>string} replace The function to replace each matched part.
1263  * @returns {string} The replaced string.
1264  */
1265 function replaceF(matcher, str, replace) {
1266     const chunks = [];
1267     let index = 0;
1268
1269     for (const match of matcher.execAll(str)) {
1270         chunks.push(str.slice(index, match.index));
1271         chunks.push(String(replace(...match, match.index, match.input)));
1272         index = match.index + match[0].length;
1273     }
1274     chunks.push(str.slice(index));
1275
1276     return chunks.join("")
1277 }
1278
1279 /**
1280  * The class to find patterns as considering escape sequences.
1281  */
1282 class PatternMatcher {
1283     /**
1284      * Initialize this matcher.
1285      * @param {RegExp} pattern The pattern to match.
1286      * @param {{escaped:boolean}} options The options.
1287      */
1288     constructor(pattern, { escaped = false } = {}) {
1289         if (!(pattern instanceof RegExp)) {
1290             throw new TypeError("'pattern' should be a RegExp instance.")
1291         }
1292         if (!pattern.flags.includes("g")) {
1293             throw new Error("'pattern' should contains 'g' flag.")
1294         }
1295
1296         internal.set(this, {
1297             pattern: new RegExp(pattern.source, pattern.flags),
1298             escaped: Boolean(escaped),
1299         });
1300     }
1301
1302     /**
1303      * Find the pattern in a given string.
1304      * @param {string} str The string to find.
1305      * @returns {IterableIterator<RegExpExecArray>} The iterator which iterate the matched information.
1306      */
1307     *execAll(str) {
1308         const { pattern, escaped } = internal.get(this);
1309         let match = null;
1310         let lastIndex = 0;
1311
1312         pattern.lastIndex = 0;
1313         while ((match = pattern.exec(str)) != null) {
1314             if (escaped || !isEscaped(str, match.index)) {
1315                 lastIndex = pattern.lastIndex;
1316                 yield match;
1317                 pattern.lastIndex = lastIndex;
1318             }
1319         }
1320     }
1321
1322     /**
1323      * Check whether the pattern is found in a given string.
1324      * @param {string} str The string to check.
1325      * @returns {boolean} `true` if the pattern was found in the string.
1326      */
1327     test(str) {
1328         const it = this.execAll(str);
1329         const ret = it.next();
1330         return !ret.done
1331     }
1332
1333     /**
1334      * Replace a given string.
1335      * @param {string} str The string to be replaced.
1336      * @param {(string|((...strs:string[])=>string))} replacer The string or function to replace. This is the same as the 2nd argument of `String.prototype.replace`.
1337      * @returns {string} The replaced string.
1338      */
1339     [Symbol.replace](str, replacer) {
1340         return typeof replacer === "function"
1341             ? replaceF(this, String(str), replacer)
1342             : replaceS(this, String(str), String(replacer))
1343     }
1344 }
1345
1346 const IMPORT_TYPE = /^(?:Import|Export(?:All|Default|Named))Declaration$/u;
1347 const has = Function.call.bind(Object.hasOwnProperty);
1348
1349 const READ = Symbol("read");
1350 const CALL = Symbol("call");
1351 const CONSTRUCT = Symbol("construct");
1352 const ESM = Symbol("esm");
1353
1354 const requireCall = { require: { [CALL]: true } };
1355
1356 /**
1357  * Check whether a given variable is modified or not.
1358  * @param {Variable} variable The variable to check.
1359  * @returns {boolean} `true` if the variable is modified.
1360  */
1361 function isModifiedGlobal(variable) {
1362     return (
1363         variable == null ||
1364         variable.defs.length !== 0 ||
1365         variable.references.some(r => r.isWrite())
1366     )
1367 }
1368
1369 /**
1370  * Check if the value of a given node is passed through to the parent syntax as-is.
1371  * For example, `a` and `b` in (`a || b` and `c ? a : b`) are passed through.
1372  * @param {Node} node A node to check.
1373  * @returns {boolean} `true` if the node is passed through.
1374  */
1375 function isPassThrough(node) {
1376     const parent = node.parent;
1377
1378     switch (parent && parent.type) {
1379         case "ConditionalExpression":
1380             return parent.consequent === node || parent.alternate === node
1381         case "LogicalExpression":
1382             return true
1383         case "SequenceExpression":
1384             return parent.expressions[parent.expressions.length - 1] === node
1385         case "ChainExpression":
1386             return true
1387
1388         default:
1389             return false
1390     }
1391 }
1392
1393 /**
1394  * The reference tracker.
1395  */
1396 class ReferenceTracker {
1397     /**
1398      * Initialize this tracker.
1399      * @param {Scope} globalScope The global scope.
1400      * @param {object} [options] The options.
1401      * @param {"legacy"|"strict"} [options.mode="strict"] The mode to determine the ImportDeclaration's behavior for CJS modules.
1402      * @param {string[]} [options.globalObjectNames=["global","globalThis","self","window"]] The variable names for Global Object.
1403      */
1404     constructor(
1405         globalScope,
1406         {
1407             mode = "strict",
1408             globalObjectNames = ["global", "globalThis", "self", "window"],
1409         } = {}
1410     ) {
1411         this.variableStack = [];
1412         this.globalScope = globalScope;
1413         this.mode = mode;
1414         this.globalObjectNames = globalObjectNames.slice(0);
1415     }
1416
1417     /**
1418      * Iterate the references of global variables.
1419      * @param {object} traceMap The trace map.
1420      * @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
1421      */
1422     *iterateGlobalReferences(traceMap) {
1423         for (const key of Object.keys(traceMap)) {
1424             const nextTraceMap = traceMap[key];
1425             const path = [key];
1426             const variable = this.globalScope.set.get(key);
1427
1428             if (isModifiedGlobal(variable)) {
1429                 continue
1430             }
1431
1432             yield* this._iterateVariableReferences(
1433                 variable,
1434                 path,
1435                 nextTraceMap,
1436                 true
1437             );
1438         }
1439
1440         for (const key of this.globalObjectNames) {
1441             const path = [];
1442             const variable = this.globalScope.set.get(key);
1443
1444             if (isModifiedGlobal(variable)) {
1445                 continue
1446             }
1447
1448             yield* this._iterateVariableReferences(
1449                 variable,
1450                 path,
1451                 traceMap,
1452                 false
1453             );
1454         }
1455     }
1456
1457     /**
1458      * Iterate the references of CommonJS modules.
1459      * @param {object} traceMap The trace map.
1460      * @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
1461      */
1462     *iterateCjsReferences(traceMap) {
1463         for (const { node } of this.iterateGlobalReferences(requireCall)) {
1464             const key = getStringIfConstant(node.arguments[0]);
1465             if (key == null || !has(traceMap, key)) {
1466                 continue
1467             }
1468
1469             const nextTraceMap = traceMap[key];
1470             const path = [key];
1471
1472             if (nextTraceMap[READ]) {
1473                 yield {
1474                     node,
1475                     path,
1476                     type: READ,
1477                     info: nextTraceMap[READ],
1478                 };
1479             }
1480             yield* this._iteratePropertyReferences(node, path, nextTraceMap);
1481         }
1482     }
1483
1484     /**
1485      * Iterate the references of ES modules.
1486      * @param {object} traceMap The trace map.
1487      * @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
1488      */
1489     *iterateEsmReferences(traceMap) {
1490         const programNode = this.globalScope.block;
1491
1492         for (const node of programNode.body) {
1493             if (!IMPORT_TYPE.test(node.type) || node.source == null) {
1494                 continue
1495             }
1496             const moduleId = node.source.value;
1497
1498             if (!has(traceMap, moduleId)) {
1499                 continue
1500             }
1501             const nextTraceMap = traceMap[moduleId];
1502             const path = [moduleId];
1503
1504             if (nextTraceMap[READ]) {
1505                 yield { node, path, type: READ, info: nextTraceMap[READ] };
1506             }
1507
1508             if (node.type === "ExportAllDeclaration") {
1509                 for (const key of Object.keys(nextTraceMap)) {
1510                     const exportTraceMap = nextTraceMap[key];
1511                     if (exportTraceMap[READ]) {
1512                         yield {
1513                             node,
1514                             path: path.concat(key),
1515                             type: READ,
1516                             info: exportTraceMap[READ],
1517                         };
1518                     }
1519                 }
1520             } else {
1521                 for (const specifier of node.specifiers) {
1522                     const esm = has(nextTraceMap, ESM);
1523                     const it = this._iterateImportReferences(
1524                         specifier,
1525                         path,
1526                         esm
1527                             ? nextTraceMap
1528                             : this.mode === "legacy"
1529                             ? Object.assign(
1530                                   { default: nextTraceMap },
1531                                   nextTraceMap
1532                               )
1533                             : { default: nextTraceMap }
1534                     );
1535
1536                     if (esm) {
1537                         yield* it;
1538                     } else {
1539                         for (const report of it) {
1540                             report.path = report.path.filter(exceptDefault);
1541                             if (
1542                                 report.path.length >= 2 ||
1543                                 report.type !== READ
1544                             ) {
1545                                 yield report;
1546                             }
1547                         }
1548                     }
1549                 }
1550             }
1551         }
1552     }
1553
1554     /**
1555      * Iterate the references for a given variable.
1556      * @param {Variable} variable The variable to iterate that references.
1557      * @param {string[]} path The current path.
1558      * @param {object} traceMap The trace map.
1559      * @param {boolean} shouldReport = The flag to report those references.
1560      * @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
1561      */
1562     *_iterateVariableReferences(variable, path, traceMap, shouldReport) {
1563         if (this.variableStack.includes(variable)) {
1564             return
1565         }
1566         this.variableStack.push(variable);
1567         try {
1568             for (const reference of variable.references) {
1569                 if (!reference.isRead()) {
1570                     continue
1571                 }
1572                 const node = reference.identifier;
1573
1574                 if (shouldReport && traceMap[READ]) {
1575                     yield { node, path, type: READ, info: traceMap[READ] };
1576                 }
1577                 yield* this._iteratePropertyReferences(node, path, traceMap);
1578             }
1579         } finally {
1580             this.variableStack.pop();
1581         }
1582     }
1583
1584     /**
1585      * Iterate the references for a given AST node.
1586      * @param rootNode The AST node to iterate references.
1587      * @param {string[]} path The current path.
1588      * @param {object} traceMap The trace map.
1589      * @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
1590      */
1591     //eslint-disable-next-line complexity
1592     *_iteratePropertyReferences(rootNode, path, traceMap) {
1593         let node = rootNode;
1594         while (isPassThrough(node)) {
1595             node = node.parent;
1596         }
1597
1598         const parent = node.parent;
1599         if (parent.type === "MemberExpression") {
1600             if (parent.object === node) {
1601                 const key = getPropertyName(parent);
1602                 if (key == null || !has(traceMap, key)) {
1603                     return
1604                 }
1605
1606                 path = path.concat(key); //eslint-disable-line no-param-reassign
1607                 const nextTraceMap = traceMap[key];
1608                 if (nextTraceMap[READ]) {
1609                     yield {
1610                         node: parent,
1611                         path,
1612                         type: READ,
1613                         info: nextTraceMap[READ],
1614                     };
1615                 }
1616                 yield* this._iteratePropertyReferences(
1617                     parent,
1618                     path,
1619                     nextTraceMap
1620                 );
1621             }
1622             return
1623         }
1624         if (parent.type === "CallExpression") {
1625             if (parent.callee === node && traceMap[CALL]) {
1626                 yield { node: parent, path, type: CALL, info: traceMap[CALL] };
1627             }
1628             return
1629         }
1630         if (parent.type === "NewExpression") {
1631             if (parent.callee === node && traceMap[CONSTRUCT]) {
1632                 yield {
1633                     node: parent,
1634                     path,
1635                     type: CONSTRUCT,
1636                     info: traceMap[CONSTRUCT],
1637                 };
1638             }
1639             return
1640         }
1641         if (parent.type === "AssignmentExpression") {
1642             if (parent.right === node) {
1643                 yield* this._iterateLhsReferences(parent.left, path, traceMap);
1644                 yield* this._iteratePropertyReferences(parent, path, traceMap);
1645             }
1646             return
1647         }
1648         if (parent.type === "AssignmentPattern") {
1649             if (parent.right === node) {
1650                 yield* this._iterateLhsReferences(parent.left, path, traceMap);
1651             }
1652             return
1653         }
1654         if (parent.type === "VariableDeclarator") {
1655             if (parent.init === node) {
1656                 yield* this._iterateLhsReferences(parent.id, path, traceMap);
1657             }
1658         }
1659     }
1660
1661     /**
1662      * Iterate the references for a given Pattern node.
1663      * @param {Node} patternNode The Pattern node to iterate references.
1664      * @param {string[]} path The current path.
1665      * @param {object} traceMap The trace map.
1666      * @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
1667      */
1668     *_iterateLhsReferences(patternNode, path, traceMap) {
1669         if (patternNode.type === "Identifier") {
1670             const variable = findVariable(this.globalScope, patternNode);
1671             if (variable != null) {
1672                 yield* this._iterateVariableReferences(
1673                     variable,
1674                     path,
1675                     traceMap,
1676                     false
1677                 );
1678             }
1679             return
1680         }
1681         if (patternNode.type === "ObjectPattern") {
1682             for (const property of patternNode.properties) {
1683                 const key = getPropertyName(property);
1684
1685                 if (key == null || !has(traceMap, key)) {
1686                     continue
1687                 }
1688
1689                 const nextPath = path.concat(key);
1690                 const nextTraceMap = traceMap[key];
1691                 if (nextTraceMap[READ]) {
1692                     yield {
1693                         node: property,
1694                         path: nextPath,
1695                         type: READ,
1696                         info: nextTraceMap[READ],
1697                     };
1698                 }
1699                 yield* this._iterateLhsReferences(
1700                     property.value,
1701                     nextPath,
1702                     nextTraceMap
1703                 );
1704             }
1705             return
1706         }
1707         if (patternNode.type === "AssignmentPattern") {
1708             yield* this._iterateLhsReferences(patternNode.left, path, traceMap);
1709         }
1710     }
1711
1712     /**
1713      * Iterate the references for a given ModuleSpecifier node.
1714      * @param {Node} specifierNode The ModuleSpecifier node to iterate references.
1715      * @param {string[]} path The current path.
1716      * @param {object} traceMap The trace map.
1717      * @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references.
1718      */
1719     *_iterateImportReferences(specifierNode, path, traceMap) {
1720         const type = specifierNode.type;
1721
1722         if (type === "ImportSpecifier" || type === "ImportDefaultSpecifier") {
1723             const key =
1724                 type === "ImportDefaultSpecifier"
1725                     ? "default"
1726                     : specifierNode.imported.name;
1727             if (!has(traceMap, key)) {
1728                 return
1729             }
1730
1731             path = path.concat(key); //eslint-disable-line no-param-reassign
1732             const nextTraceMap = traceMap[key];
1733             if (nextTraceMap[READ]) {
1734                 yield {
1735                     node: specifierNode,
1736                     path,
1737                     type: READ,
1738                     info: nextTraceMap[READ],
1739                 };
1740             }
1741             yield* this._iterateVariableReferences(
1742                 findVariable(this.globalScope, specifierNode.local),
1743                 path,
1744                 nextTraceMap,
1745                 false
1746             );
1747
1748             return
1749         }
1750
1751         if (type === "ImportNamespaceSpecifier") {
1752             yield* this._iterateVariableReferences(
1753                 findVariable(this.globalScope, specifierNode.local),
1754                 path,
1755                 traceMap,
1756                 false
1757             );
1758             return
1759         }
1760
1761         if (type === "ExportSpecifier") {
1762             const key = specifierNode.local.name;
1763             if (!has(traceMap, key)) {
1764                 return
1765             }
1766
1767             path = path.concat(key); //eslint-disable-line no-param-reassign
1768             const nextTraceMap = traceMap[key];
1769             if (nextTraceMap[READ]) {
1770                 yield {
1771                     node: specifierNode,
1772                     path,
1773                     type: READ,
1774                     info: nextTraceMap[READ],
1775                 };
1776             }
1777         }
1778     }
1779 }
1780
1781 ReferenceTracker.READ = READ;
1782 ReferenceTracker.CALL = CALL;
1783 ReferenceTracker.CONSTRUCT = CONSTRUCT;
1784 ReferenceTracker.ESM = ESM;
1785
1786 /**
1787  * This is a predicate function for Array#filter.
1788  * @param {string} name A name part.
1789  * @param {number} index The index of the name.
1790  * @returns {boolean} `false` if it's default.
1791  */
1792 function exceptDefault(name, index) {
1793     return !(index === 1 && name === "default")
1794 }
1795
1796 var index = {
1797     CALL,
1798     CONSTRUCT,
1799     ESM,
1800     findVariable,
1801     getFunctionHeadLocation,
1802     getFunctionNameWithKind,
1803     getInnermostScope,
1804     getPropertyName,
1805     getStaticValue,
1806     getStringIfConstant,
1807     hasSideEffect,
1808     isArrowToken,
1809     isClosingBraceToken,
1810     isClosingBracketToken,
1811     isClosingParenToken,
1812     isColonToken,
1813     isCommaToken,
1814     isCommentToken,
1815     isNotArrowToken,
1816     isNotClosingBraceToken,
1817     isNotClosingBracketToken,
1818     isNotClosingParenToken,
1819     isNotColonToken,
1820     isNotCommaToken,
1821     isNotCommentToken,
1822     isNotOpeningBraceToken,
1823     isNotOpeningBracketToken,
1824     isNotOpeningParenToken,
1825     isNotSemicolonToken,
1826     isOpeningBraceToken,
1827     isOpeningBracketToken,
1828     isOpeningParenToken,
1829     isParenthesized,
1830     isSemicolonToken,
1831     PatternMatcher,
1832     READ,
1833     ReferenceTracker,
1834 };
1835
1836 export default index;
1837 export { CALL, CONSTRUCT, ESM, PatternMatcher, READ, ReferenceTracker, findVariable, getFunctionHeadLocation, getFunctionNameWithKind, getInnermostScope, getPropertyName, getStaticValue, getStringIfConstant, hasSideEffect, isArrowToken, isClosingBraceToken, isClosingBracketToken, isClosingParenToken, isColonToken, isCommaToken, isCommentToken, isNotArrowToken, isNotClosingBraceToken, isNotClosingBracketToken, isNotClosingParenToken, isNotColonToken, isNotCommaToken, isNotCommentToken, isNotOpeningBraceToken, isNotOpeningBracketToken, isNotOpeningParenToken, isNotSemicolonToken, isOpeningBraceToken, isOpeningBracketToken, isOpeningParenToken, isParenthesized, isSemicolonToken };
1838 //# sourceMappingURL=index.mjs.map