diff options
Diffstat (limited to 'tools/node_modules/eslint/node_modules/eslint-utils/index.js')
-rw-r--r-- | tools/node_modules/eslint/node_modules/eslint-utils/index.js | 305 |
1 files changed, 295 insertions, 10 deletions
diff --git a/tools/node_modules/eslint/node_modules/eslint-utils/index.js b/tools/node_modules/eslint/node_modules/eslint-utils/index.js index a74dd9037a..d501e86d3f 100644 --- a/tools/node_modules/eslint/node_modules/eslint-utils/index.js +++ b/tools/node_modules/eslint/node_modules/eslint-utils/index.js @@ -3,6 +3,10 @@ Object.defineProperty(exports, '__esModule', { value: true }); +function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } + +var evk = _interopDefault(require('eslint-visitor-keys')); + /** * Get the innermost scope which contains a given location. * @param {Scope} initialScope The initial scope to search. @@ -742,12 +746,291 @@ function getFunctionNameWithKind(node) { return tokens.join(" ") } +const typeConversionBinaryOps = Object.freeze( + new Set([ + "==", + "!=", + "<", + "<=", + ">", + ">=", + "<<", + ">>", + ">>>", + "+", + "-", + "*", + "/", + "%", + "|", + "^", + "&", + "in", + ]) +); +const typeConversionUnaryOps = Object.freeze(new Set(["-", "+", "!", "~"])); +const visitor = Object.freeze( + Object.assign(Object.create(null), { + $visit(node, options, visitorKeys) { + const { type } = node; + + if (typeof this[type] === "function") { + return this[type](node, options, visitorKeys) + } + + return this.$visitChildren(node, options, visitorKeys) + }, + + $visitChildren(node, options, visitorKeys) { + const { type } = node; + + for (const key of visitorKeys[type] || evk.getKeys(node)) { + const value = node[key]; + + if (Array.isArray(value)) { + for (const element of value) { + if ( + element && + this.$visit(element, options, visitorKeys) + ) { + return true + } + } + } else if (value && this.$visit(value, options, visitorKeys)) { + return true + } + } + + return false + }, + + ArrowFunctionExpression() { + return false + }, + AssignmentExpression() { + return true + }, + AwaitExpression() { + return true + }, + BinaryExpression(node, options, visitorKeys) { + if ( + options.considerImplicitTypeConversion && + typeConversionBinaryOps.has(node.operator) && + (node.left.type !== "Literal" || node.right.type !== "Literal") + ) { + return true + } + return this.$visitChildren(node, options, visitorKeys) + }, + CallExpression() { + return true + }, + FunctionExpression() { + return false + }, + ImportExpression() { + return true + }, + MemberExpression(node, options, visitorKeys) { + if (options.considerGetters) { + return true + } + if ( + options.considerImplicitTypeConversion && + node.computed && + node.property.type !== "Literal" + ) { + return true + } + return this.$visitChildren(node, options, visitorKeys) + }, + MethodDefinition(node, options, visitorKeys) { + if ( + options.considerImplicitTypeConversion && + node.computed && + node.key.type !== "Literal" + ) { + return true + } + return this.$visitChildren(node, options, visitorKeys) + }, + NewExpression() { + return true + }, + Property(node, options, visitorKeys) { + if ( + options.considerImplicitTypeConversion && + node.computed && + node.key.type !== "Literal" + ) { + return true + } + return this.$visitChildren(node, options, visitorKeys) + }, + UnaryExpression(node, options, visitorKeys) { + if (node.operator === "delete") { + return true + } + if ( + options.considerImplicitTypeConversion && + typeConversionUnaryOps.has(node.operator) && + node.argument.type !== "Literal" + ) { + return true + } + return this.$visitChildren(node, options, visitorKeys) + }, + UpdateExpression() { + return true + }, + YieldExpression() { + return true + }, + }) +); + +/** + * Check whether a given node has any side effect or not. + * @param {Node} node The node to get. + * @param {SourceCode} sourceCode The source code object. + * @param {object} [options] The option object. + * @param {boolean} [options.considerGetters=false] If `true` then it considers member accesses as the node which has side effects. + * @param {boolean} [options.considerImplicitTypeConversion=false] If `true` then it considers implicit type conversion as the node which has side effects. + * @param {object} [options.visitorKeys=evk.KEYS] The keys to traverse nodes. Use `context.getSourceCode().visitorKeys`. + * @returns {boolean} `true` if the node has a certain side effect. + */ +function hasSideEffect( + node, + sourceCode, + { considerGetters = false, considerImplicitTypeConversion = false } = {} +) { + return visitor.$visit( + node, + { considerGetters, considerImplicitTypeConversion }, + sourceCode.visitorKeys || evk.KEYS + ) +} + +/** + * Get the left parenthesis of the parent node syntax if it exists. + * E.g., `if (a) {}` then the `(`. + * @param {Node} node The AST node to check. + * @param {SourceCode} sourceCode The source code object to get tokens. + * @returns {Token|null} The left parenthesis of the parent node syntax + */ +function getParentSyntaxParen(node, sourceCode) { + const parent = node.parent; + + switch (parent.type) { + case "CallExpression": + case "NewExpression": + if (parent.arguments.length === 1 && parent.arguments[0] === node) { + return sourceCode.getTokenAfter( + parent.callee, + isOpeningParenToken + ) + } + return null + + case "DoWhileStatement": + if (parent.test === node) { + return sourceCode.getTokenAfter( + parent.body, + isOpeningParenToken + ) + } + return null + + case "IfStatement": + case "WhileStatement": + if (parent.test === node) { + return sourceCode.getFirstToken(parent, 1) + } + return null + + case "ImportExpression": + if (parent.source === node) { + return sourceCode.getFirstToken(parent, 1) + } + return null + + case "SwitchStatement": + if (parent.discriminant === node) { + return sourceCode.getFirstToken(parent, 1) + } + return null + + case "WithStatement": + if (parent.object === node) { + return sourceCode.getFirstToken(parent, 1) + } + return null + + default: + return null + } +} + +/** + * Check whether a given node is parenthesized or not. + * @param {number} times The number of parantheses. + * @param {Node} node The AST node to check. + * @param {SourceCode} sourceCode The source code object to get tokens. + * @returns {boolean} `true` if the node is parenthesized the given times. + */ +/** + * Check whether a given node is parenthesized or not. + * @param {Node} node The AST node to check. + * @param {SourceCode} sourceCode The source code object to get tokens. + * @returns {boolean} `true` if the node is parenthesized. + */ +function isParenthesized( + timesOrNode, + nodeOrSourceCode, + optionalSourceCode +) { + let times, node, sourceCode, maybeLeftParen, maybeRightParen; + if (typeof timesOrNode === "number") { + times = timesOrNode | 0; + node = nodeOrSourceCode; + sourceCode = optionalSourceCode; + if (!(times >= 1)) { + throw new TypeError("'times' should be a positive integer.") + } + } else { + times = 1; + node = timesOrNode; + sourceCode = nodeOrSourceCode; + } + + if (node == null) { + return false + } + + maybeLeftParen = maybeRightParen = node; + do { + maybeLeftParen = sourceCode.getTokenBefore(maybeLeftParen); + maybeRightParen = sourceCode.getTokenAfter(maybeRightParen); + } while ( + maybeLeftParen != null && + maybeRightParen != null && + isOpeningParenToken(maybeLeftParen) && + isClosingParenToken(maybeRightParen) && + // Avoid false positive such as `if (a) {}` + maybeLeftParen !== getParentSyntaxParen(node, sourceCode) && + --times > 0 + ) + + return times === 0 +} + /** * @author Toru Nagashima <https://github.com/mysticatea> * See LICENSE file in root directory for full license. */ -const placeholder = /\$(?:[$&`']|[1-9][0-9]?)/g; +const placeholder = /\$(?:[$&`']|[1-9][0-9]?)/gu; /** @type {WeakMap<PatternMatcher, {pattern:RegExp,escaped:boolean}>} */ const internal = new WeakMap(); @@ -814,7 +1097,6 @@ function replaceS(matcher, str, replacement) { return chunks.join("") } -//eslint-disable-next-line valid-jsdoc /** * Replace a given string by a given matcher. * @param {PatternMatcher} matcher The pattern matcher. @@ -890,7 +1172,6 @@ class PatternMatcher { return !ret.done } - //eslint-disable-next-line valid-jsdoc /** * Replace a given string. * @param {string} str The string to be replaced. @@ -904,8 +1185,8 @@ class PatternMatcher { } } -const SENTINEL_TYPE = /^(?:.+?Statement|.+?Declaration|(?:Array|ArrowFunction|Assignment|Call|Class|Function|Member|New|Object)Expression|AssignmentPattern|Program|VariableDeclarator)$/; -const IMPORT_TYPE = /^(?:Import|Export(?:All|Default|Named))Declaration$/; +const SENTINEL_TYPE = /^(?:.+?Statement|.+?Declaration|(?:Array|ArrowFunction|Assignment|Call|Class|Function|Member|New|Object)Expression|AssignmentPattern|Program|VariableDeclarator)$/u; +const IMPORT_TYPE = /^(?:Import|Export(?:All|Default|Named))Declaration$/u; const has = Function.call.bind(Object.hasOwnProperty); const READ = Symbol("read"); @@ -1126,7 +1407,7 @@ class ReferenceTracker { * @param {object} traceMap The trace map. * @returns {IterableIterator<{node:Node,path:string[],type:symbol,info:any}>} The iterator to iterate references. */ - //eslint-disable-next-line complexity, require-jsdoc + //eslint-disable-next-line complexity *_iteratePropertyReferences(rootNode, path, traceMap) { let node = rootNode; while (!SENTINEL_TYPE.test(node.parent.type)) { @@ -1342,6 +1623,7 @@ var index = { getPropertyName, getStaticValue, getStringIfConstant, + hasSideEffect, isArrowToken, isClosingBraceToken, isClosingBracketToken, @@ -1363,16 +1645,20 @@ var index = { isOpeningBraceToken, isOpeningBracketToken, isOpeningParenToken, + isParenthesized, isSemicolonToken, PatternMatcher, READ, ReferenceTracker, }; -exports.default = index; exports.CALL = CALL; exports.CONSTRUCT = CONSTRUCT; exports.ESM = ESM; +exports.PatternMatcher = PatternMatcher; +exports.READ = READ; +exports.ReferenceTracker = ReferenceTracker; +exports.default = index; exports.findVariable = findVariable; exports.getFunctionHeadLocation = getFunctionHeadLocation; exports.getFunctionNameWithKind = getFunctionNameWithKind; @@ -1380,6 +1666,7 @@ exports.getInnermostScope = getInnermostScope; exports.getPropertyName = getPropertyName; exports.getStaticValue = getStaticValue; exports.getStringIfConstant = getStringIfConstant; +exports.hasSideEffect = hasSideEffect; exports.isArrowToken = isArrowToken; exports.isClosingBraceToken = isClosingBraceToken; exports.isClosingBracketToken = isClosingBracketToken; @@ -1401,8 +1688,6 @@ exports.isNotSemicolonToken = isNotSemicolonToken; exports.isOpeningBraceToken = isOpeningBraceToken; exports.isOpeningBracketToken = isOpeningBracketToken; exports.isOpeningParenToken = isOpeningParenToken; +exports.isParenthesized = isParenthesized; exports.isSemicolonToken = isSemicolonToken; -exports.PatternMatcher = PatternMatcher; -exports.READ = READ; -exports.ReferenceTracker = ReferenceTracker; //# sourceMappingURL=index.js.map |