source: imaps-frontend/node_modules/@eslint-community/eslint-utils/index.js@ d565449

main
Last change on this file since d565449 was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

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