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