• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * @fileoverview Common utils for AST.
3 * @author Gyandeep Singh
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Requirements
10//------------------------------------------------------------------------------
11
12const esutils = require("esutils");
13const espree = require("espree");
14const lodash = require("lodash");
15const {
16    breakableTypePattern,
17    createGlobalLinebreakMatcher,
18    lineBreakPattern,
19    shebangPattern
20} = require("../../shared/ast-utils");
21
22//------------------------------------------------------------------------------
23// Helpers
24//------------------------------------------------------------------------------
25
26const anyFunctionPattern = /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/u;
27const anyLoopPattern = /^(?:DoWhile|For|ForIn|ForOf|While)Statement$/u;
28const arrayOrTypedArrayPattern = /Array$/u;
29const arrayMethodPattern = /^(?:every|filter|find|findIndex|forEach|map|some)$/u;
30const bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/u;
31const thisTagPattern = /^[\s*]*@this/mu;
32
33
34const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/u;
35const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
36
37// A set of node types that can contain a list of statements
38const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]);
39
40const DECIMAL_INTEGER_PATTERN = /^(?:0|0[0-7]*[89]\d*|[1-9](?:_?\d)*)$/u;
41const OCTAL_ESCAPE_PATTERN = /^(?:[^\\]|\\[^0-7]|\\0(?![0-9]))*\\(?:[1-7]|0[0-9])/u;
42
43const LOGICAL_ASSIGNMENT_OPERATORS = new Set(["&&=", "||=", "??="]);
44
45/**
46 * Checks reference if is non initializer and writable.
47 * @param {Reference} reference A reference to check.
48 * @param {int} index The index of the reference in the references.
49 * @param {Reference[]} references The array that the reference belongs to.
50 * @returns {boolean} Success/Failure
51 * @private
52 */
53function isModifyingReference(reference, index, references) {
54    const identifier = reference.identifier;
55
56    /*
57     * Destructuring assignments can have multiple default value, so
58     * possibly there are multiple writeable references for the same
59     * identifier.
60     */
61    const modifyingDifferentIdentifier = index === 0 ||
62        references[index - 1].identifier !== identifier;
63
64    return (identifier &&
65        reference.init === false &&
66        reference.isWrite() &&
67        modifyingDifferentIdentifier
68    );
69}
70
71/**
72 * Checks whether the given string starts with uppercase or not.
73 * @param {string} s The string to check.
74 * @returns {boolean} `true` if the string starts with uppercase.
75 */
76function startsWithUpperCase(s) {
77    return s[0] !== s[0].toLocaleLowerCase();
78}
79
80/**
81 * Checks whether or not a node is a constructor.
82 * @param {ASTNode} node A function node to check.
83 * @returns {boolean} Wehether or not a node is a constructor.
84 */
85function isES5Constructor(node) {
86    return (node.id && startsWithUpperCase(node.id.name));
87}
88
89/**
90 * Finds a function node from ancestors of a node.
91 * @param {ASTNode} node A start node to find.
92 * @returns {Node|null} A found function node.
93 */
94function getUpperFunction(node) {
95    for (let currentNode = node; currentNode; currentNode = currentNode.parent) {
96        if (anyFunctionPattern.test(currentNode.type)) {
97            return currentNode;
98        }
99    }
100    return null;
101}
102
103/**
104 * Checks whether a given node is a function node or not.
105 * The following types are function nodes:
106 *
107 * - ArrowFunctionExpression
108 * - FunctionDeclaration
109 * - FunctionExpression
110 * @param {ASTNode|null} node A node to check.
111 * @returns {boolean} `true` if the node is a function node.
112 */
113function isFunction(node) {
114    return Boolean(node && anyFunctionPattern.test(node.type));
115}
116
117/**
118 * Checks whether a given node is a loop node or not.
119 * The following types are loop nodes:
120 *
121 * - DoWhileStatement
122 * - ForInStatement
123 * - ForOfStatement
124 * - ForStatement
125 * - WhileStatement
126 * @param {ASTNode|null} node A node to check.
127 * @returns {boolean} `true` if the node is a loop node.
128 */
129function isLoop(node) {
130    return Boolean(node && anyLoopPattern.test(node.type));
131}
132
133/**
134 * Checks whether the given node is in a loop or not.
135 * @param {ASTNode} node The node to check.
136 * @returns {boolean} `true` if the node is in a loop.
137 */
138function isInLoop(node) {
139    for (let currentNode = node; currentNode && !isFunction(currentNode); currentNode = currentNode.parent) {
140        if (isLoop(currentNode)) {
141            return true;
142        }
143    }
144
145    return false;
146}
147
148/**
149 * Determines whether the given node is a `null` literal.
150 * @param {ASTNode} node The node to check
151 * @returns {boolean} `true` if the node is a `null` literal
152 */
153function isNullLiteral(node) {
154
155    /*
156     * Checking `node.value === null` does not guarantee that a literal is a null literal.
157     * When parsing values that cannot be represented in the current environment (e.g. unicode
158     * regexes in Node 4), `node.value` is set to `null` because it wouldn't be possible to
159     * set `node.value` to a unicode regex. To make sure a literal is actually `null`, check
160     * `node.regex` instead. Also see: https://github.com/eslint/eslint/issues/8020
161     */
162    return node.type === "Literal" && node.value === null && !node.regex && !node.bigint;
163}
164
165/**
166 * Checks whether or not a node is `null` or `undefined`.
167 * @param {ASTNode} node A node to check.
168 * @returns {boolean} Whether or not the node is a `null` or `undefined`.
169 * @public
170 */
171function isNullOrUndefined(node) {
172    return (
173        isNullLiteral(node) ||
174        (node.type === "Identifier" && node.name === "undefined") ||
175        (node.type === "UnaryExpression" && node.operator === "void")
176    );
177}
178
179/**
180 * Checks whether or not a node is callee.
181 * @param {ASTNode} node A node to check.
182 * @returns {boolean} Whether or not the node is callee.
183 */
184function isCallee(node) {
185    return node.parent.type === "CallExpression" && node.parent.callee === node;
186}
187
188/**
189 * Returns the result of the string conversion applied to the evaluated value of the given expression node,
190 * if it can be determined statically.
191 *
192 * This function returns a `string` value for all `Literal` nodes and simple `TemplateLiteral` nodes only.
193 * In all other cases, this function returns `null`.
194 * @param {ASTNode} node Expression node.
195 * @returns {string|null} String value if it can be determined. Otherwise, `null`.
196 */
197function getStaticStringValue(node) {
198    switch (node.type) {
199        case "Literal":
200            if (node.value === null) {
201                if (isNullLiteral(node)) {
202                    return String(node.value); // "null"
203                }
204                if (node.regex) {
205                    return `/${node.regex.pattern}/${node.regex.flags}`;
206                }
207                if (node.bigint) {
208                    return node.bigint;
209                }
210
211                // Otherwise, this is an unknown literal. The function will return null.
212
213            } else {
214                return String(node.value);
215            }
216            break;
217        case "TemplateLiteral":
218            if (node.expressions.length === 0 && node.quasis.length === 1) {
219                return node.quasis[0].value.cooked;
220            }
221            break;
222
223            // no default
224    }
225
226    return null;
227}
228
229/**
230 * Gets the property name of a given node.
231 * The node can be a MemberExpression, a Property, or a MethodDefinition.
232 *
233 * If the name is dynamic, this returns `null`.
234 *
235 * For examples:
236 *
237 *     a.b           // => "b"
238 *     a["b"]        // => "b"
239 *     a['b']        // => "b"
240 *     a[`b`]        // => "b"
241 *     a[100]        // => "100"
242 *     a[b]          // => null
243 *     a["a" + "b"]  // => null
244 *     a[tag`b`]     // => null
245 *     a[`${b}`]     // => null
246 *
247 *     let a = {b: 1}            // => "b"
248 *     let a = {["b"]: 1}        // => "b"
249 *     let a = {['b']: 1}        // => "b"
250 *     let a = {[`b`]: 1}        // => "b"
251 *     let a = {[100]: 1}        // => "100"
252 *     let a = {[b]: 1}          // => null
253 *     let a = {["a" + "b"]: 1}  // => null
254 *     let a = {[tag`b`]: 1}     // => null
255 *     let a = {[`${b}`]: 1}     // => null
256 * @param {ASTNode} node The node to get.
257 * @returns {string|null} The property name if static. Otherwise, null.
258 */
259function getStaticPropertyName(node) {
260    let prop;
261
262    switch (node && node.type) {
263        case "ChainExpression":
264            return getStaticPropertyName(node.expression);
265
266        case "Property":
267        case "MethodDefinition":
268            prop = node.key;
269            break;
270
271        case "MemberExpression":
272            prop = node.property;
273            break;
274
275            // no default
276    }
277
278    if (prop) {
279        if (prop.type === "Identifier" && !node.computed) {
280            return prop.name;
281        }
282
283        return getStaticStringValue(prop);
284    }
285
286    return null;
287}
288
289/**
290 * Retrieve `ChainExpression#expression` value if the given node a `ChainExpression` node. Otherwise, pass through it.
291 * @param {ASTNode} node The node to address.
292 * @returns {ASTNode} The `ChainExpression#expression` value if the node is a `ChainExpression` node. Otherwise, the node.
293 */
294function skipChainExpression(node) {
295    return node && node.type === "ChainExpression" ? node.expression : node;
296}
297
298/**
299 * Check if the `actual` is an expected value.
300 * @param {string} actual The string value to check.
301 * @param {string | RegExp} expected The expected string value or pattern.
302 * @returns {boolean} `true` if the `actual` is an expected value.
303 */
304function checkText(actual, expected) {
305    return typeof expected === "string"
306        ? actual === expected
307        : expected.test(actual);
308}
309
310/**
311 * Check if a given node is an Identifier node with a given name.
312 * @param {ASTNode} node The node to check.
313 * @param {string | RegExp} name The expected name or the expected pattern of the object name.
314 * @returns {boolean} `true` if the node is an Identifier node with the name.
315 */
316function isSpecificId(node, name) {
317    return node.type === "Identifier" && checkText(node.name, name);
318}
319
320/**
321 * Check if a given node is member access with a given object name and property name pair.
322 * This is regardless of optional or not.
323 * @param {ASTNode} node The node to check.
324 * @param {string | RegExp | null} objectName The expected name or the expected pattern of the object name. If this is nullish, this method doesn't check object.
325 * @param {string | RegExp | null} propertyName The expected name or the expected pattern of the property name. If this is nullish, this method doesn't check property.
326 * @returns {boolean} `true` if the node is member access with the object name and property name pair.
327 * The node is a `MemberExpression` or `ChainExpression`.
328 */
329function isSpecificMemberAccess(node, objectName, propertyName) {
330    const checkNode = skipChainExpression(node);
331
332    if (checkNode.type !== "MemberExpression") {
333        return false;
334    }
335
336    if (objectName && !isSpecificId(checkNode.object, objectName)) {
337        return false;
338    }
339
340    if (propertyName) {
341        const actualPropertyName = getStaticPropertyName(checkNode);
342
343        if (typeof actualPropertyName !== "string" || !checkText(actualPropertyName, propertyName)) {
344            return false;
345        }
346    }
347
348    return true;
349}
350
351/**
352 * Check if two literal nodes are the same value.
353 * @param {ASTNode} left The Literal node to compare.
354 * @param {ASTNode} right The other Literal node to compare.
355 * @returns {boolean} `true` if the two literal nodes are the same value.
356 */
357function equalLiteralValue(left, right) {
358
359    // RegExp literal.
360    if (left.regex || right.regex) {
361        return Boolean(
362            left.regex &&
363            right.regex &&
364            left.regex.pattern === right.regex.pattern &&
365            left.regex.flags === right.regex.flags
366        );
367    }
368
369    // BigInt literal.
370    if (left.bigint || right.bigint) {
371        return left.bigint === right.bigint;
372    }
373
374    return left.value === right.value;
375}
376
377/**
378 * Check if two expressions reference the same value. For example:
379 *     a = a
380 *     a.b = a.b
381 *     a[0] = a[0]
382 *     a['b'] = a['b']
383 * @param {ASTNode} left The left side of the comparison.
384 * @param {ASTNode} right The right side of the comparison.
385 * @param {boolean} [disableStaticComputedKey] Don't address `a.b` and `a["b"]` are the same if `true`. For backward compatibility.
386 * @returns {boolean} `true` if both sides match and reference the same value.
387 */
388function isSameReference(left, right, disableStaticComputedKey = false) {
389    if (left.type !== right.type) {
390
391        // Handle `a.b` and `a?.b` are samely.
392        if (left.type === "ChainExpression") {
393            return isSameReference(left.expression, right, disableStaticComputedKey);
394        }
395        if (right.type === "ChainExpression") {
396            return isSameReference(left, right.expression, disableStaticComputedKey);
397        }
398
399        return false;
400    }
401
402    switch (left.type) {
403        case "Super":
404        case "ThisExpression":
405            return true;
406
407        case "Identifier":
408            return left.name === right.name;
409        case "Literal":
410            return equalLiteralValue(left, right);
411
412        case "ChainExpression":
413            return isSameReference(left.expression, right.expression, disableStaticComputedKey);
414
415        case "MemberExpression": {
416            if (!disableStaticComputedKey) {
417                const nameA = getStaticPropertyName(left);
418
419                // x.y = x["y"]
420                if (nameA !== null) {
421                    return (
422                        isSameReference(left.object, right.object, disableStaticComputedKey) &&
423                        nameA === getStaticPropertyName(right)
424                    );
425                }
426            }
427
428            /*
429             * x[0] = x[0]
430             * x[y] = x[y]
431             * x.y = x.y
432             */
433            return (
434                left.computed === right.computed &&
435                isSameReference(left.object, right.object, disableStaticComputedKey) &&
436                isSameReference(left.property, right.property, disableStaticComputedKey)
437            );
438        }
439
440        default:
441            return false;
442    }
443}
444
445/**
446 * Checks whether or not a node is `Reflect.apply`.
447 * @param {ASTNode} node A node to check.
448 * @returns {boolean} Whether or not the node is a `Reflect.apply`.
449 */
450function isReflectApply(node) {
451    return isSpecificMemberAccess(node, "Reflect", "apply");
452}
453
454/**
455 * Checks whether or not a node is `Array.from`.
456 * @param {ASTNode} node A node to check.
457 * @returns {boolean} Whether or not the node is a `Array.from`.
458 */
459function isArrayFromMethod(node) {
460    return isSpecificMemberAccess(node, arrayOrTypedArrayPattern, "from");
461}
462
463/**
464 * Checks whether or not a node is a method which has `thisArg`.
465 * @param {ASTNode} node A node to check.
466 * @returns {boolean} Whether or not the node is a method which has `thisArg`.
467 */
468function isMethodWhichHasThisArg(node) {
469    return isSpecificMemberAccess(node, null, arrayMethodPattern);
470}
471
472/**
473 * Creates the negate function of the given function.
474 * @param {Function} f The function to negate.
475 * @returns {Function} Negated function.
476 */
477function negate(f) {
478    return token => !f(token);
479}
480
481/**
482 * Checks whether or not a node has a `@this` tag in its comments.
483 * @param {ASTNode} node A node to check.
484 * @param {SourceCode} sourceCode A SourceCode instance to get comments.
485 * @returns {boolean} Whether or not the node has a `@this` tag in its comments.
486 */
487function hasJSDocThisTag(node, sourceCode) {
488    const jsdocComment = sourceCode.getJSDocComment(node);
489
490    if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
491        return true;
492    }
493
494    // Checks `@this` in its leading comments for callbacks,
495    // because callbacks don't have its JSDoc comment.
496    // e.g.
497    //     sinon.test(/* @this sinon.Sandbox */function() { this.spy(); });
498    return sourceCode.getCommentsBefore(node).some(comment => thisTagPattern.test(comment.value));
499}
500
501/**
502 * Determines if a node is surrounded by parentheses.
503 * @param {SourceCode} sourceCode The ESLint source code object
504 * @param {ASTNode} node The node to be checked.
505 * @returns {boolean} True if the node is parenthesised.
506 * @private
507 */
508function isParenthesised(sourceCode, node) {
509    const previousToken = sourceCode.getTokenBefore(node),
510        nextToken = sourceCode.getTokenAfter(node);
511
512    return Boolean(previousToken && nextToken) &&
513        previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
514        nextToken.value === ")" && nextToken.range[0] >= node.range[1];
515}
516
517/**
518 * Checks if the given token is an arrow token or not.
519 * @param {Token} token The token to check.
520 * @returns {boolean} `true` if the token is an arrow token.
521 */
522function isArrowToken(token) {
523    return token.value === "=>" && token.type === "Punctuator";
524}
525
526/**
527 * Checks if the given token is a comma token or not.
528 * @param {Token} token The token to check.
529 * @returns {boolean} `true` if the token is a comma token.
530 */
531function isCommaToken(token) {
532    return token.value === "," && token.type === "Punctuator";
533}
534
535/**
536 * Checks if the given token is a dot token or not.
537 * @param {Token} token The token to check.
538 * @returns {boolean} `true` if the token is a dot token.
539 */
540function isDotToken(token) {
541    return token.value === "." && token.type === "Punctuator";
542}
543
544/**
545 * Checks if the given token is a `?.` token or not.
546 * @param {Token} token The token to check.
547 * @returns {boolean} `true` if the token is a `?.` token.
548 */
549function isQuestionDotToken(token) {
550    return token.value === "?." && token.type === "Punctuator";
551}
552
553/**
554 * Checks if the given token is a semicolon token or not.
555 * @param {Token} token The token to check.
556 * @returns {boolean} `true` if the token is a semicolon token.
557 */
558function isSemicolonToken(token) {
559    return token.value === ";" && token.type === "Punctuator";
560}
561
562/**
563 * Checks if the given token is a colon token or not.
564 * @param {Token} token The token to check.
565 * @returns {boolean} `true` if the token is a colon token.
566 */
567function isColonToken(token) {
568    return token.value === ":" && token.type === "Punctuator";
569}
570
571/**
572 * Checks if the given token is an opening parenthesis token or not.
573 * @param {Token} token The token to check.
574 * @returns {boolean} `true` if the token is an opening parenthesis token.
575 */
576function isOpeningParenToken(token) {
577    return token.value === "(" && token.type === "Punctuator";
578}
579
580/**
581 * Checks if the given token is a closing parenthesis token or not.
582 * @param {Token} token The token to check.
583 * @returns {boolean} `true` if the token is a closing parenthesis token.
584 */
585function isClosingParenToken(token) {
586    return token.value === ")" && token.type === "Punctuator";
587}
588
589/**
590 * Checks if the given token is an opening square bracket token or not.
591 * @param {Token} token The token to check.
592 * @returns {boolean} `true` if the token is an opening square bracket token.
593 */
594function isOpeningBracketToken(token) {
595    return token.value === "[" && token.type === "Punctuator";
596}
597
598/**
599 * Checks if the given token is a closing square bracket token or not.
600 * @param {Token} token The token to check.
601 * @returns {boolean} `true` if the token is a closing square bracket token.
602 */
603function isClosingBracketToken(token) {
604    return token.value === "]" && token.type === "Punctuator";
605}
606
607/**
608 * Checks if the given token is an opening brace token or not.
609 * @param {Token} token The token to check.
610 * @returns {boolean} `true` if the token is an opening brace token.
611 */
612function isOpeningBraceToken(token) {
613    return token.value === "{" && token.type === "Punctuator";
614}
615
616/**
617 * Checks if the given token is a closing brace token or not.
618 * @param {Token} token The token to check.
619 * @returns {boolean} `true` if the token is a closing brace token.
620 */
621function isClosingBraceToken(token) {
622    return token.value === "}" && token.type === "Punctuator";
623}
624
625/**
626 * Checks if the given token is a comment token or not.
627 * @param {Token} token The token to check.
628 * @returns {boolean} `true` if the token is a comment token.
629 */
630function isCommentToken(token) {
631    return token.type === "Line" || token.type === "Block" || token.type === "Shebang";
632}
633
634/**
635 * Checks if the given token is a keyword token or not.
636 * @param {Token} token The token to check.
637 * @returns {boolean} `true` if the token is a keyword token.
638 */
639function isKeywordToken(token) {
640    return token.type === "Keyword";
641}
642
643/**
644 * Gets the `(` token of the given function node.
645 * @param {ASTNode} node The function node to get.
646 * @param {SourceCode} sourceCode The source code object to get tokens.
647 * @returns {Token} `(` token.
648 */
649function getOpeningParenOfParams(node, sourceCode) {
650    return node.id
651        ? sourceCode.getTokenAfter(node.id, isOpeningParenToken)
652        : sourceCode.getFirstToken(node, isOpeningParenToken);
653}
654
655/**
656 * Checks whether or not the tokens of two given nodes are same.
657 * @param {ASTNode} left A node 1 to compare.
658 * @param {ASTNode} right A node 2 to compare.
659 * @param {SourceCode} sourceCode The ESLint source code object.
660 * @returns {boolean} the source code for the given node.
661 */
662function equalTokens(left, right, sourceCode) {
663    const tokensL = sourceCode.getTokens(left);
664    const tokensR = sourceCode.getTokens(right);
665
666    if (tokensL.length !== tokensR.length) {
667        return false;
668    }
669    for (let i = 0; i < tokensL.length; ++i) {
670        if (tokensL[i].type !== tokensR[i].type ||
671            tokensL[i].value !== tokensR[i].value
672        ) {
673            return false;
674        }
675    }
676
677    return true;
678}
679
680/**
681 * Check if the given node is a true logical expression or not.
682 *
683 * The three binary expressions logical-or (`||`), logical-and (`&&`), and
684 * coalesce (`??`) are known as `ShortCircuitExpression`.
685 * But ESTree represents those by `LogicalExpression` node.
686 *
687 * This function rejects coalesce expressions of `LogicalExpression` node.
688 * @param {ASTNode} node The node to check.
689 * @returns {boolean} `true` if the node is `&&` or `||`.
690 * @see https://tc39.es/ecma262/#prod-ShortCircuitExpression
691 */
692function isLogicalExpression(node) {
693    return (
694        node.type === "LogicalExpression" &&
695            (node.operator === "&&" || node.operator === "||")
696    );
697}
698
699/**
700 * Check if the given node is a nullish coalescing expression or not.
701 *
702 * The three binary expressions logical-or (`||`), logical-and (`&&`), and
703 * coalesce (`??`) are known as `ShortCircuitExpression`.
704 * But ESTree represents those by `LogicalExpression` node.
705 *
706 * This function finds only coalesce expressions of `LogicalExpression` node.
707 * @param {ASTNode} node The node to check.
708 * @returns {boolean} `true` if the node is `??`.
709 */
710function isCoalesceExpression(node) {
711    return node.type === "LogicalExpression" && node.operator === "??";
712}
713
714/**
715 * Check if given two nodes are the pair of a logical expression and a coalesce expression.
716 * @param {ASTNode} left A node to check.
717 * @param {ASTNode} right Another node to check.
718 * @returns {boolean} `true` if the two nodes are the pair of a logical expression and a coalesce expression.
719 */
720function isMixedLogicalAndCoalesceExpressions(left, right) {
721    return (
722        (isLogicalExpression(left) && isCoalesceExpression(right)) ||
723            (isCoalesceExpression(left) && isLogicalExpression(right))
724    );
725}
726
727/**
728 * Checks if the given operator is a logical assignment operator.
729 * @param {string} operator The operator to check.
730 * @returns {boolean} `true` if the operator is a logical assignment operator.
731 */
732function isLogicalAssignmentOperator(operator) {
733    return LOGICAL_ASSIGNMENT_OPERATORS.has(operator);
734}
735
736//------------------------------------------------------------------------------
737// Public Interface
738//------------------------------------------------------------------------------
739
740module.exports = {
741    COMMENTS_IGNORE_PATTERN,
742    LINEBREAKS,
743    LINEBREAK_MATCHER: lineBreakPattern,
744    SHEBANG_MATCHER: shebangPattern,
745    STATEMENT_LIST_PARENTS,
746
747    /**
748     * Determines whether two adjacent tokens are on the same line.
749     * @param {Object} left The left token object.
750     * @param {Object} right The right token object.
751     * @returns {boolean} Whether or not the tokens are on the same line.
752     * @public
753     */
754    isTokenOnSameLine(left, right) {
755        return left.loc.end.line === right.loc.start.line;
756    },
757
758    isNullOrUndefined,
759    isCallee,
760    isES5Constructor,
761    getUpperFunction,
762    isFunction,
763    isLoop,
764    isInLoop,
765    isArrayFromMethod,
766    isParenthesised,
767    createGlobalLinebreakMatcher,
768    equalTokens,
769
770    isArrowToken,
771    isClosingBraceToken,
772    isClosingBracketToken,
773    isClosingParenToken,
774    isColonToken,
775    isCommaToken,
776    isCommentToken,
777    isDotToken,
778    isQuestionDotToken,
779    isKeywordToken,
780    isNotClosingBraceToken: negate(isClosingBraceToken),
781    isNotClosingBracketToken: negate(isClosingBracketToken),
782    isNotClosingParenToken: negate(isClosingParenToken),
783    isNotColonToken: negate(isColonToken),
784    isNotCommaToken: negate(isCommaToken),
785    isNotDotToken: negate(isDotToken),
786    isNotQuestionDotToken: negate(isQuestionDotToken),
787    isNotOpeningBraceToken: negate(isOpeningBraceToken),
788    isNotOpeningBracketToken: negate(isOpeningBracketToken),
789    isNotOpeningParenToken: negate(isOpeningParenToken),
790    isNotSemicolonToken: negate(isSemicolonToken),
791    isOpeningBraceToken,
792    isOpeningBracketToken,
793    isOpeningParenToken,
794    isSemicolonToken,
795
796    /**
797     * Checks whether or not a given node is a string literal.
798     * @param {ASTNode} node A node to check.
799     * @returns {boolean} `true` if the node is a string literal.
800     */
801    isStringLiteral(node) {
802        return (
803            (node.type === "Literal" && typeof node.value === "string") ||
804            node.type === "TemplateLiteral"
805        );
806    },
807
808    /**
809     * Checks whether a given node is a breakable statement or not.
810     * The node is breakable if the node is one of the following type:
811     *
812     * - DoWhileStatement
813     * - ForInStatement
814     * - ForOfStatement
815     * - ForStatement
816     * - SwitchStatement
817     * - WhileStatement
818     * @param {ASTNode} node A node to check.
819     * @returns {boolean} `true` if the node is breakable.
820     */
821    isBreakableStatement(node) {
822        return breakableTypePattern.test(node.type);
823    },
824
825    /**
826     * Gets references which are non initializer and writable.
827     * @param {Reference[]} references An array of references.
828     * @returns {Reference[]} An array of only references which are non initializer and writable.
829     * @public
830     */
831    getModifyingReferences(references) {
832        return references.filter(isModifyingReference);
833    },
834
835    /**
836     * Validate that a string passed in is surrounded by the specified character
837     * @param  {string} val The text to check.
838     * @param  {string} character The character to see if it's surrounded by.
839     * @returns {boolean} True if the text is surrounded by the character, false if not.
840     * @private
841     */
842    isSurroundedBy(val, character) {
843        return val[0] === character && val[val.length - 1] === character;
844    },
845
846    /**
847     * Returns whether the provided node is an ESLint directive comment or not
848     * @param {Line|Block} node The comment token to be checked
849     * @returns {boolean} `true` if the node is an ESLint directive comment
850     */
851    isDirectiveComment(node) {
852        const comment = node.value.trim();
853
854        return (
855            node.type === "Line" && comment.indexOf("eslint-") === 0 ||
856            node.type === "Block" && (
857                comment.indexOf("global ") === 0 ||
858                comment.indexOf("eslint ") === 0 ||
859                comment.indexOf("eslint-") === 0
860            )
861        );
862    },
863
864    /**
865     * Gets the trailing statement of a given node.
866     *
867     *     if (code)
868     *         consequent;
869     *
870     * When taking this `IfStatement`, returns `consequent;` statement.
871     * @param {ASTNode} A node to get.
872     * @returns {ASTNode|null} The trailing statement's node.
873     */
874    getTrailingStatement: esutils.ast.trailingStatement,
875
876    /**
877     * Finds the variable by a given name in a given scope and its upper scopes.
878     * @param {eslint-scope.Scope} initScope A scope to start find.
879     * @param {string} name A variable name to find.
880     * @returns {eslint-scope.Variable|null} A found variable or `null`.
881     */
882    getVariableByName(initScope, name) {
883        let scope = initScope;
884
885        while (scope) {
886            const variable = scope.set.get(name);
887
888            if (variable) {
889                return variable;
890            }
891
892            scope = scope.upper;
893        }
894
895        return null;
896    },
897
898    /**
899     * Checks whether or not a given function node is the default `this` binding.
900     *
901     * First, this checks the node:
902     *
903     * - The function name does not start with uppercase. It's a convention to capitalize the names
904     *   of constructor functions. This check is not performed if `capIsConstructor` is set to `false`.
905     * - The function does not have a JSDoc comment that has a @this tag.
906     *
907     * Next, this checks the location of the node.
908     * If the location is below, this judges `this` is valid.
909     *
910     * - The location is not on an object literal.
911     * - The location is not assigned to a variable which starts with an uppercase letter. Applies to anonymous
912     *   functions only, as the name of the variable is considered to be the name of the function in this case.
913     *   This check is not performed if `capIsConstructor` is set to `false`.
914     * - The location is not on an ES2015 class.
915     * - Its `bind`/`call`/`apply` method is not called directly.
916     * - The function is not a callback of array methods (such as `.forEach()`) if `thisArg` is given.
917     * @param {ASTNode} node A function node to check.
918     * @param {SourceCode} sourceCode A SourceCode instance to get comments.
919     * @param {boolean} [capIsConstructor = true] `false` disables the assumption that functions which name starts
920     * with an uppercase or are assigned to a variable which name starts with an uppercase are constructors.
921     * @returns {boolean} The function node is the default `this` binding.
922     */
923    isDefaultThisBinding(node, sourceCode, { capIsConstructor = true } = {}) {
924        if (
925            (capIsConstructor && isES5Constructor(node)) ||
926            hasJSDocThisTag(node, sourceCode)
927        ) {
928            return false;
929        }
930        const isAnonymous = node.id === null;
931        let currentNode = node;
932
933        while (currentNode) {
934            const parent = currentNode.parent;
935
936            switch (parent.type) {
937
938                /*
939                 * Looks up the destination.
940                 * e.g., obj.foo = nativeFoo || function foo() { ... };
941                 */
942                case "LogicalExpression":
943                case "ConditionalExpression":
944                case "ChainExpression":
945                    currentNode = parent;
946                    break;
947
948                /*
949                 * If the upper function is IIFE, checks the destination of the return value.
950                 * e.g.
951                 *   obj.foo = (function() {
952                 *     // setup...
953                 *     return function foo() { ... };
954                 *   })();
955                 *   obj.foo = (() =>
956                 *     function foo() { ... }
957                 *   )();
958                 */
959                case "ReturnStatement": {
960                    const func = getUpperFunction(parent);
961
962                    if (func === null || !isCallee(func)) {
963                        return true;
964                    }
965                    currentNode = func.parent;
966                    break;
967                }
968                case "ArrowFunctionExpression":
969                    if (currentNode !== parent.body || !isCallee(parent)) {
970                        return true;
971                    }
972                    currentNode = parent.parent;
973                    break;
974
975                /*
976                 * e.g.
977                 *   var obj = { foo() { ... } };
978                 *   var obj = { foo: function() { ... } };
979                 *   class A { constructor() { ... } }
980                 *   class A { foo() { ... } }
981                 *   class A { get foo() { ... } }
982                 *   class A { set foo() { ... } }
983                 *   class A { static foo() { ... } }
984                 */
985                case "Property":
986                case "MethodDefinition":
987                    return parent.value !== currentNode;
988
989                /*
990                 * e.g.
991                 *   obj.foo = function foo() { ... };
992                 *   Foo = function() { ... };
993                 *   [obj.foo = function foo() { ... }] = a;
994                 *   [Foo = function() { ... }] = a;
995                 */
996                case "AssignmentExpression":
997                case "AssignmentPattern":
998                    if (parent.left.type === "MemberExpression") {
999                        return false;
1000                    }
1001                    if (
1002                        capIsConstructor &&
1003                        isAnonymous &&
1004                        parent.left.type === "Identifier" &&
1005                        startsWithUpperCase(parent.left.name)
1006                    ) {
1007                        return false;
1008                    }
1009                    return true;
1010
1011                /*
1012                 * e.g.
1013                 *   var Foo = function() { ... };
1014                 */
1015                case "VariableDeclarator":
1016                    return !(
1017                        capIsConstructor &&
1018                        isAnonymous &&
1019                        parent.init === currentNode &&
1020                        parent.id.type === "Identifier" &&
1021                        startsWithUpperCase(parent.id.name)
1022                    );
1023
1024                /*
1025                 * e.g.
1026                 *   var foo = function foo() { ... }.bind(obj);
1027                 *   (function foo() { ... }).call(obj);
1028                 *   (function foo() { ... }).apply(obj, []);
1029                 */
1030                case "MemberExpression":
1031                    if (
1032                        parent.object === currentNode &&
1033                        isSpecificMemberAccess(parent, null, bindOrCallOrApplyPattern)
1034                    ) {
1035                        const maybeCalleeNode = parent.parent.type === "ChainExpression"
1036                            ? parent.parent
1037                            : parent;
1038
1039                        return !(
1040                            isCallee(maybeCalleeNode) &&
1041                            maybeCalleeNode.parent.arguments.length >= 1 &&
1042                            !isNullOrUndefined(maybeCalleeNode.parent.arguments[0])
1043                        );
1044                    }
1045                    return true;
1046
1047                /*
1048                 * e.g.
1049                 *   Reflect.apply(function() {}, obj, []);
1050                 *   Array.from([], function() {}, obj);
1051                 *   list.forEach(function() {}, obj);
1052                 */
1053                case "CallExpression":
1054                    if (isReflectApply(parent.callee)) {
1055                        return (
1056                            parent.arguments.length !== 3 ||
1057                            parent.arguments[0] !== currentNode ||
1058                            isNullOrUndefined(parent.arguments[1])
1059                        );
1060                    }
1061                    if (isArrayFromMethod(parent.callee)) {
1062                        return (
1063                            parent.arguments.length !== 3 ||
1064                            parent.arguments[1] !== currentNode ||
1065                            isNullOrUndefined(parent.arguments[2])
1066                        );
1067                    }
1068                    if (isMethodWhichHasThisArg(parent.callee)) {
1069                        return (
1070                            parent.arguments.length !== 2 ||
1071                            parent.arguments[0] !== currentNode ||
1072                            isNullOrUndefined(parent.arguments[1])
1073                        );
1074                    }
1075                    return true;
1076
1077                // Otherwise `this` is default.
1078                default:
1079                    return true;
1080            }
1081        }
1082
1083        /* istanbul ignore next */
1084        return true;
1085    },
1086
1087    /**
1088     * Get the precedence level based on the node type
1089     * @param {ASTNode} node node to evaluate
1090     * @returns {int} precedence level
1091     * @private
1092     */
1093    getPrecedence(node) {
1094        switch (node.type) {
1095            case "SequenceExpression":
1096                return 0;
1097
1098            case "AssignmentExpression":
1099            case "ArrowFunctionExpression":
1100            case "YieldExpression":
1101                return 1;
1102
1103            case "ConditionalExpression":
1104                return 3;
1105
1106            case "LogicalExpression":
1107                switch (node.operator) {
1108                    case "||":
1109                    case "??":
1110                        return 4;
1111                    case "&&":
1112                        return 5;
1113
1114                    // no default
1115                }
1116
1117                /* falls through */
1118
1119            case "BinaryExpression":
1120
1121                switch (node.operator) {
1122                    case "|":
1123                        return 6;
1124                    case "^":
1125                        return 7;
1126                    case "&":
1127                        return 8;
1128                    case "==":
1129                    case "!=":
1130                    case "===":
1131                    case "!==":
1132                        return 9;
1133                    case "<":
1134                    case "<=":
1135                    case ">":
1136                    case ">=":
1137                    case "in":
1138                    case "instanceof":
1139                        return 10;
1140                    case "<<":
1141                    case ">>":
1142                    case ">>>":
1143                        return 11;
1144                    case "+":
1145                    case "-":
1146                        return 12;
1147                    case "*":
1148                    case "/":
1149                    case "%":
1150                        return 13;
1151                    case "**":
1152                        return 15;
1153
1154                    // no default
1155                }
1156
1157                /* falls through */
1158
1159            case "UnaryExpression":
1160            case "AwaitExpression":
1161                return 16;
1162
1163            case "UpdateExpression":
1164                return 17;
1165
1166            case "CallExpression":
1167            case "ChainExpression":
1168            case "ImportExpression":
1169                return 18;
1170
1171            case "NewExpression":
1172                return 19;
1173
1174            default:
1175                return 20;
1176        }
1177    },
1178
1179    /**
1180     * Checks whether the given node is an empty block node or not.
1181     * @param {ASTNode|null} node The node to check.
1182     * @returns {boolean} `true` if the node is an empty block.
1183     */
1184    isEmptyBlock(node) {
1185        return Boolean(node && node.type === "BlockStatement" && node.body.length === 0);
1186    },
1187
1188    /**
1189     * Checks whether the given node is an empty function node or not.
1190     * @param {ASTNode|null} node The node to check.
1191     * @returns {boolean} `true` if the node is an empty function.
1192     */
1193    isEmptyFunction(node) {
1194        return isFunction(node) && module.exports.isEmptyBlock(node.body);
1195    },
1196
1197    /**
1198     * Get directives from directive prologue of a Program or Function node.
1199     * @param {ASTNode} node The node to check.
1200     * @returns {ASTNode[]} The directives found in the directive prologue.
1201     */
1202    getDirectivePrologue(node) {
1203        const directives = [];
1204
1205        // Directive prologues only occur at the top of files or functions.
1206        if (
1207            node.type === "Program" ||
1208            node.type === "FunctionDeclaration" ||
1209            node.type === "FunctionExpression" ||
1210
1211            /*
1212             * Do not check arrow functions with implicit return.
1213             * `() => "use strict";` returns the string `"use strict"`.
1214             */
1215            (node.type === "ArrowFunctionExpression" && node.body.type === "BlockStatement")
1216        ) {
1217            const statements = node.type === "Program" ? node.body : node.body.body;
1218
1219            for (const statement of statements) {
1220                if (
1221                    statement.type === "ExpressionStatement" &&
1222                    statement.expression.type === "Literal"
1223                ) {
1224                    directives.push(statement);
1225                } else {
1226                    break;
1227                }
1228            }
1229        }
1230
1231        return directives;
1232    },
1233
1234
1235    /**
1236     * Determines whether this node is a decimal integer literal. If a node is a decimal integer literal, a dot added
1237     * after the node will be parsed as a decimal point, rather than a property-access dot.
1238     * @param {ASTNode} node The node to check.
1239     * @returns {boolean} `true` if this node is a decimal integer.
1240     * @example
1241     *
1242     * 0         // true
1243     * 5         // true
1244     * 50        // true
1245     * 5_000     // true
1246     * 1_234_56  // true
1247     * 08        // true
1248     * 0192      // true
1249     * 5.        // false
1250     * .5        // false
1251     * 5.0       // false
1252     * 5.00_00   // false
1253     * 05        // false
1254     * 0x5       // false
1255     * 0b101     // false
1256     * 0b11_01   // false
1257     * 0o5       // false
1258     * 5e0       // false
1259     * 5e1_000   // false
1260     * 5n        // false
1261     * 1_000n    // false
1262     * '5'       // false
1263     */
1264    isDecimalInteger(node) {
1265        return node.type === "Literal" && typeof node.value === "number" &&
1266            DECIMAL_INTEGER_PATTERN.test(node.raw);
1267    },
1268
1269    /**
1270     * Determines whether this token is a decimal integer numeric token.
1271     * This is similar to isDecimalInteger(), but for tokens.
1272     * @param {Token} token The token to check.
1273     * @returns {boolean} `true` if this token is a decimal integer.
1274     */
1275    isDecimalIntegerNumericToken(token) {
1276        return token.type === "Numeric" && DECIMAL_INTEGER_PATTERN.test(token.value);
1277    },
1278
1279    /**
1280     * Gets the name and kind of the given function node.
1281     *
1282     * - `function foo() {}`  .................... `function 'foo'`
1283     * - `(function foo() {})`  .................. `function 'foo'`
1284     * - `(function() {})`  ...................... `function`
1285     * - `function* foo() {}`  ................... `generator function 'foo'`
1286     * - `(function* foo() {})`  ................. `generator function 'foo'`
1287     * - `(function*() {})`  ..................... `generator function`
1288     * - `() => {}`  ............................. `arrow function`
1289     * - `async () => {}`  ....................... `async arrow function`
1290     * - `({ foo: function foo() {} })`  ......... `method 'foo'`
1291     * - `({ foo: function() {} })`  ............. `method 'foo'`
1292     * - `({ ['foo']: function() {} })`  ......... `method 'foo'`
1293     * - `({ [foo]: function() {} })`  ........... `method`
1294     * - `({ foo() {} })`  ....................... `method 'foo'`
1295     * - `({ foo: function* foo() {} })`  ........ `generator method 'foo'`
1296     * - `({ foo: function*() {} })`  ............ `generator method 'foo'`
1297     * - `({ ['foo']: function*() {} })`  ........ `generator method 'foo'`
1298     * - `({ [foo]: function*() {} })`  .......... `generator method`
1299     * - `({ *foo() {} })`  ...................... `generator method 'foo'`
1300     * - `({ foo: async function foo() {} })`  ... `async method 'foo'`
1301     * - `({ foo: async function() {} })`  ....... `async method 'foo'`
1302     * - `({ ['foo']: async function() {} })`  ... `async method 'foo'`
1303     * - `({ [foo]: async function() {} })`  ..... `async method`
1304     * - `({ async foo() {} })`  ................. `async method 'foo'`
1305     * - `({ get foo() {} })`  ................... `getter 'foo'`
1306     * - `({ set foo(a) {} })`  .................. `setter 'foo'`
1307     * - `class A { constructor() {} }`  ......... `constructor`
1308     * - `class A { foo() {} }`  ................. `method 'foo'`
1309     * - `class A { *foo() {} }`  ................ `generator method 'foo'`
1310     * - `class A { async foo() {} }`  ........... `async method 'foo'`
1311     * - `class A { ['foo']() {} }`  ............. `method 'foo'`
1312     * - `class A { *['foo']() {} }`  ............ `generator method 'foo'`
1313     * - `class A { async ['foo']() {} }`  ....... `async method 'foo'`
1314     * - `class A { [foo]() {} }`  ............... `method`
1315     * - `class A { *[foo]() {} }`  .............. `generator method`
1316     * - `class A { async [foo]() {} }`  ......... `async method`
1317     * - `class A { get foo() {} }`  ............. `getter 'foo'`
1318     * - `class A { set foo(a) {} }`  ............ `setter 'foo'`
1319     * - `class A { static foo() {} }`  .......... `static method 'foo'`
1320     * - `class A { static *foo() {} }`  ......... `static generator method 'foo'`
1321     * - `class A { static async foo() {} }`  .... `static async method 'foo'`
1322     * - `class A { static get foo() {} }`  ...... `static getter 'foo'`
1323     * - `class A { static set foo(a) {} }`  ..... `static setter 'foo'`
1324     * @param {ASTNode} node The function node to get.
1325     * @returns {string} The name and kind of the function node.
1326     */
1327    getFunctionNameWithKind(node) {
1328        const parent = node.parent;
1329        const tokens = [];
1330
1331        if (parent.type === "MethodDefinition" && parent.static) {
1332            tokens.push("static");
1333        }
1334        if (node.async) {
1335            tokens.push("async");
1336        }
1337        if (node.generator) {
1338            tokens.push("generator");
1339        }
1340
1341        if (node.type === "ArrowFunctionExpression") {
1342            tokens.push("arrow", "function");
1343        } else if (parent.type === "Property" || parent.type === "MethodDefinition") {
1344            if (parent.kind === "constructor") {
1345                return "constructor";
1346            }
1347            if (parent.kind === "get") {
1348                tokens.push("getter");
1349            } else if (parent.kind === "set") {
1350                tokens.push("setter");
1351            } else {
1352                tokens.push("method");
1353            }
1354        } else {
1355            tokens.push("function");
1356        }
1357
1358        if (node.id) {
1359            tokens.push(`'${node.id.name}'`);
1360        } else {
1361            const name = getStaticPropertyName(parent);
1362
1363            if (name !== null) {
1364                tokens.push(`'${name}'`);
1365            }
1366        }
1367
1368        return tokens.join(" ");
1369    },
1370
1371    /**
1372     * Gets the location of the given function node for reporting.
1373     *
1374     * - `function foo() {}`
1375     *    ^^^^^^^^^^^^
1376     * - `(function foo() {})`
1377     *     ^^^^^^^^^^^^
1378     * - `(function() {})`
1379     *     ^^^^^^^^
1380     * - `function* foo() {}`
1381     *    ^^^^^^^^^^^^^
1382     * - `(function* foo() {})`
1383     *     ^^^^^^^^^^^^^
1384     * - `(function*() {})`
1385     *     ^^^^^^^^^
1386     * - `() => {}`
1387     *       ^^
1388     * - `async () => {}`
1389     *             ^^
1390     * - `({ foo: function foo() {} })`
1391     *       ^^^^^^^^^^^^^^^^^
1392     * - `({ foo: function() {} })`
1393     *       ^^^^^^^^^^^^^
1394     * - `({ ['foo']: function() {} })`
1395     *       ^^^^^^^^^^^^^^^^^
1396     * - `({ [foo]: function() {} })`
1397     *       ^^^^^^^^^^^^^^^
1398     * - `({ foo() {} })`
1399     *       ^^^
1400     * - `({ foo: function* foo() {} })`
1401     *       ^^^^^^^^^^^^^^^^^^
1402     * - `({ foo: function*() {} })`
1403     *       ^^^^^^^^^^^^^^
1404     * - `({ ['foo']: function*() {} })`
1405     *       ^^^^^^^^^^^^^^^^^^
1406     * - `({ [foo]: function*() {} })`
1407     *       ^^^^^^^^^^^^^^^^
1408     * - `({ *foo() {} })`
1409     *       ^^^^
1410     * - `({ foo: async function foo() {} })`
1411     *       ^^^^^^^^^^^^^^^^^^^^^^^
1412     * - `({ foo: async function() {} })`
1413     *       ^^^^^^^^^^^^^^^^^^^
1414     * - `({ ['foo']: async function() {} })`
1415     *       ^^^^^^^^^^^^^^^^^^^^^^^
1416     * - `({ [foo]: async function() {} })`
1417     *       ^^^^^^^^^^^^^^^^^^^^^
1418     * - `({ async foo() {} })`
1419     *       ^^^^^^^^^
1420     * - `({ get foo() {} })`
1421     *       ^^^^^^^
1422     * - `({ set foo(a) {} })`
1423     *       ^^^^^^^
1424     * - `class A { constructor() {} }`
1425     *              ^^^^^^^^^^^
1426     * - `class A { foo() {} }`
1427     *              ^^^
1428     * - `class A { *foo() {} }`
1429     *              ^^^^
1430     * - `class A { async foo() {} }`
1431     *              ^^^^^^^^^
1432     * - `class A { ['foo']() {} }`
1433     *              ^^^^^^^
1434     * - `class A { *['foo']() {} }`
1435     *              ^^^^^^^^
1436     * - `class A { async ['foo']() {} }`
1437     *              ^^^^^^^^^^^^^
1438     * - `class A { [foo]() {} }`
1439     *              ^^^^^
1440     * - `class A { *[foo]() {} }`
1441     *              ^^^^^^
1442     * - `class A { async [foo]() {} }`
1443     *              ^^^^^^^^^^^
1444     * - `class A { get foo() {} }`
1445     *              ^^^^^^^
1446     * - `class A { set foo(a) {} }`
1447     *              ^^^^^^^
1448     * - `class A { static foo() {} }`
1449     *              ^^^^^^^^^^
1450     * - `class A { static *foo() {} }`
1451     *              ^^^^^^^^^^^
1452     * - `class A { static async foo() {} }`
1453     *              ^^^^^^^^^^^^^^^^
1454     * - `class A { static get foo() {} }`
1455     *              ^^^^^^^^^^^^^^
1456     * - `class A { static set foo(a) {} }`
1457     *              ^^^^^^^^^^^^^^
1458     * @param {ASTNode} node The function node to get.
1459     * @param {SourceCode} sourceCode The source code object to get tokens.
1460     * @returns {string} The location of the function node for reporting.
1461     */
1462    getFunctionHeadLoc(node, sourceCode) {
1463        const parent = node.parent;
1464        let start = null;
1465        let end = null;
1466
1467        if (node.type === "ArrowFunctionExpression") {
1468            const arrowToken = sourceCode.getTokenBefore(node.body, isArrowToken);
1469
1470            start = arrowToken.loc.start;
1471            end = arrowToken.loc.end;
1472        } else if (parent.type === "Property" || parent.type === "MethodDefinition") {
1473            start = parent.loc.start;
1474            end = getOpeningParenOfParams(node, sourceCode).loc.start;
1475        } else {
1476            start = node.loc.start;
1477            end = getOpeningParenOfParams(node, sourceCode).loc.start;
1478        }
1479
1480        return {
1481            start: Object.assign({}, start),
1482            end: Object.assign({}, end)
1483        };
1484    },
1485
1486    /**
1487     * Gets next location when the result is not out of bound, otherwise returns null.
1488     *
1489     * Assumptions:
1490     *
1491     * - The given location represents a valid location in the given source code.
1492     * - Columns are 0-based.
1493     * - Lines are 1-based.
1494     * - Column immediately after the last character in a line (not incl. linebreaks) is considered to be a valid location.
1495     * - If the source code ends with a linebreak, `sourceCode.lines` array will have an extra element (empty string) at the end.
1496     *   The start (column 0) of that extra line is considered to be a valid location.
1497     *
1498     * Examples of successive locations (line, column):
1499     *
1500     * code: foo
1501     * locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> null
1502     *
1503     * code: foo<LF>
1504     * locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> (2, 0) -> null
1505     *
1506     * code: foo<CR><LF>
1507     * locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> (2, 0) -> null
1508     *
1509     * code: a<LF>b
1510     * locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> null
1511     *
1512     * code: a<LF>b<LF>
1513     * locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> (3, 0) -> null
1514     *
1515     * code: a<CR><LF>b<CR><LF>
1516     * locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> (3, 0) -> null
1517     *
1518     * code: a<LF><LF>
1519     * locations: (1, 0) -> (1, 1) -> (2, 0) -> (3, 0) -> null
1520     *
1521     * code: <LF>
1522     * locations: (1, 0) -> (2, 0) -> null
1523     *
1524     * code:
1525     * locations: (1, 0) -> null
1526     * @param {SourceCode} sourceCode The sourceCode
1527     * @param {{line: number, column: number}} location The location
1528     * @returns {{line: number, column: number} | null} Next location
1529     */
1530    getNextLocation(sourceCode, { line, column }) {
1531        if (column < sourceCode.lines[line - 1].length) {
1532            return {
1533                line,
1534                column: column + 1
1535            };
1536        }
1537
1538        if (line < sourceCode.lines.length) {
1539            return {
1540                line: line + 1,
1541                column: 0
1542            };
1543        }
1544
1545        return null;
1546    },
1547
1548    /**
1549     * Gets the parenthesized text of a node. This is similar to sourceCode.getText(node), but it also includes any parentheses
1550     * surrounding the node.
1551     * @param {SourceCode} sourceCode The source code object
1552     * @param {ASTNode} node An expression node
1553     * @returns {string} The text representing the node, with all surrounding parentheses included
1554     */
1555    getParenthesisedText(sourceCode, node) {
1556        let leftToken = sourceCode.getFirstToken(node);
1557        let rightToken = sourceCode.getLastToken(node);
1558
1559        while (
1560            sourceCode.getTokenBefore(leftToken) &&
1561            sourceCode.getTokenBefore(leftToken).type === "Punctuator" &&
1562            sourceCode.getTokenBefore(leftToken).value === "(" &&
1563            sourceCode.getTokenAfter(rightToken) &&
1564            sourceCode.getTokenAfter(rightToken).type === "Punctuator" &&
1565            sourceCode.getTokenAfter(rightToken).value === ")"
1566        ) {
1567            leftToken = sourceCode.getTokenBefore(leftToken);
1568            rightToken = sourceCode.getTokenAfter(rightToken);
1569        }
1570
1571        return sourceCode.getText().slice(leftToken.range[0], rightToken.range[1]);
1572    },
1573
1574    /*
1575     * Determine if a node has a possiblity to be an Error object
1576     * @param  {ASTNode} node  ASTNode to check
1577     * @returns {boolean} True if there is a chance it contains an Error obj
1578     */
1579    couldBeError(node) {
1580        switch (node.type) {
1581            case "Identifier":
1582            case "CallExpression":
1583            case "NewExpression":
1584            case "MemberExpression":
1585            case "TaggedTemplateExpression":
1586            case "YieldExpression":
1587            case "AwaitExpression":
1588            case "ChainExpression":
1589                return true; // possibly an error object.
1590
1591            case "AssignmentExpression":
1592                if (["=", "&&="].includes(node.operator)) {
1593                    return module.exports.couldBeError(node.right);
1594                }
1595
1596                if (["||=", "??="].includes(node.operator)) {
1597                    return module.exports.couldBeError(node.left) || module.exports.couldBeError(node.right);
1598                }
1599
1600                /**
1601                 * All other assignment operators are mathematical assignment operators (arithmetic or bitwise).
1602                 * An assignment expression with a mathematical operator can either evaluate to a primitive value,
1603                 * or throw, depending on the operands. Thus, it cannot evaluate to an `Error` object.
1604                 */
1605                return false;
1606
1607            case "SequenceExpression": {
1608                const exprs = node.expressions;
1609
1610                return exprs.length !== 0 && module.exports.couldBeError(exprs[exprs.length - 1]);
1611            }
1612
1613            case "LogicalExpression":
1614                return module.exports.couldBeError(node.left) || module.exports.couldBeError(node.right);
1615
1616            case "ConditionalExpression":
1617                return module.exports.couldBeError(node.consequent) || module.exports.couldBeError(node.alternate);
1618
1619            default:
1620                return false;
1621        }
1622    },
1623
1624    /**
1625     * Check if a given node is a numeric literal or not.
1626     * @param {ASTNode} node The node to check.
1627     * @returns {boolean} `true` if the node is a number or bigint literal.
1628     */
1629    isNumericLiteral(node) {
1630        return (
1631            node.type === "Literal" &&
1632            (typeof node.value === "number" || Boolean(node.bigint))
1633        );
1634    },
1635
1636    /**
1637     * Determines whether two tokens can safely be placed next to each other without merging into a single token
1638     * @param {Token|string} leftValue The left token. If this is a string, it will be tokenized and the last token will be used.
1639     * @param {Token|string} rightValue The right token. If this is a string, it will be tokenized and the first token will be used.
1640     * @returns {boolean} If the tokens cannot be safely placed next to each other, returns `false`. If the tokens can be placed
1641     * next to each other, behavior is undefined (although it should return `true` in most cases).
1642     */
1643    canTokensBeAdjacent(leftValue, rightValue) {
1644        const espreeOptions = {
1645            ecmaVersion: espree.latestEcmaVersion,
1646            comment: true,
1647            range: true
1648        };
1649
1650        let leftToken;
1651
1652        if (typeof leftValue === "string") {
1653            let tokens;
1654
1655            try {
1656                tokens = espree.tokenize(leftValue, espreeOptions);
1657            } catch {
1658                return false;
1659            }
1660
1661            const comments = tokens.comments;
1662
1663            leftToken = tokens[tokens.length - 1];
1664            if (comments.length) {
1665                const lastComment = comments[comments.length - 1];
1666
1667                if (lastComment.range[0] > leftToken.range[0]) {
1668                    leftToken = lastComment;
1669                }
1670            }
1671        } else {
1672            leftToken = leftValue;
1673        }
1674
1675        if (leftToken.type === "Shebang") {
1676            return false;
1677        }
1678
1679        let rightToken;
1680
1681        if (typeof rightValue === "string") {
1682            let tokens;
1683
1684            try {
1685                tokens = espree.tokenize(rightValue, espreeOptions);
1686            } catch {
1687                return false;
1688            }
1689
1690            const comments = tokens.comments;
1691
1692            rightToken = tokens[0];
1693            if (comments.length) {
1694                const firstComment = comments[0];
1695
1696                if (firstComment.range[0] < rightToken.range[0]) {
1697                    rightToken = firstComment;
1698                }
1699            }
1700        } else {
1701            rightToken = rightValue;
1702        }
1703
1704        if (leftToken.type === "Punctuator" || rightToken.type === "Punctuator") {
1705            if (leftToken.type === "Punctuator" && rightToken.type === "Punctuator") {
1706                const PLUS_TOKENS = new Set(["+", "++"]);
1707                const MINUS_TOKENS = new Set(["-", "--"]);
1708
1709                return !(
1710                    PLUS_TOKENS.has(leftToken.value) && PLUS_TOKENS.has(rightToken.value) ||
1711                    MINUS_TOKENS.has(leftToken.value) && MINUS_TOKENS.has(rightToken.value)
1712                );
1713            }
1714            if (leftToken.type === "Punctuator" && leftToken.value === "/") {
1715                return !["Block", "Line", "RegularExpression"].includes(rightToken.type);
1716            }
1717            return true;
1718        }
1719
1720        if (
1721            leftToken.type === "String" || rightToken.type === "String" ||
1722            leftToken.type === "Template" || rightToken.type === "Template"
1723        ) {
1724            return true;
1725        }
1726
1727        if (leftToken.type !== "Numeric" && rightToken.type === "Numeric" && rightToken.value.startsWith(".")) {
1728            return true;
1729        }
1730
1731        if (leftToken.type === "Block" || rightToken.type === "Block" || rightToken.type === "Line") {
1732            return true;
1733        }
1734
1735        return false;
1736    },
1737
1738    /**
1739     * Get the `loc` object of a given name in a `/*globals` directive comment.
1740     * @param {SourceCode} sourceCode The source code to convert index to loc.
1741     * @param {Comment} comment The `/*globals` directive comment which include the name.
1742     * @param {string} name The name to find.
1743     * @returns {SourceLocation} The `loc` object.
1744     */
1745    getNameLocationInGlobalDirectiveComment(sourceCode, comment, name) {
1746        const namePattern = new RegExp(`[\\s,]${lodash.escapeRegExp(name)}(?:$|[\\s,:])`, "gu");
1747
1748        // To ignore the first text "global".
1749        namePattern.lastIndex = comment.value.indexOf("global") + 6;
1750
1751        // Search a given variable name.
1752        const match = namePattern.exec(comment.value);
1753
1754        // Convert the index to loc.
1755        const start = sourceCode.getLocFromIndex(
1756            comment.range[0] +
1757            "/*".length +
1758            (match ? match.index + 1 : 0)
1759        );
1760        const end = {
1761            line: start.line,
1762            column: start.column + (match ? name.length : 1)
1763        };
1764
1765        return { start, end };
1766    },
1767
1768    /**
1769     * Determines whether the given raw string contains an octal escape sequence.
1770     *
1771     * "\1", "\2" ... "\7"
1772     * "\00", "\01" ... "\09"
1773     *
1774     * "\0", when not followed by a digit, is not an octal escape sequence.
1775     * @param {string} rawString A string in its raw representation.
1776     * @returns {boolean} `true` if the string contains at least one octal escape sequence.
1777     */
1778    hasOctalEscapeSequence(rawString) {
1779        return OCTAL_ESCAPE_PATTERN.test(rawString);
1780    },
1781
1782    isLogicalExpression,
1783    isCoalesceExpression,
1784    isMixedLogicalAndCoalesceExpressions,
1785    isNullLiteral,
1786    getStaticStringValue,
1787    getStaticPropertyName,
1788    skipChainExpression,
1789    isSpecificId,
1790    isSpecificMemberAccess,
1791    equalLiteralValue,
1792    isSameReference,
1793    isLogicalAssignmentOperator
1794};
1795