diff options
author | cjihrig <cjihrig@gmail.com> | 2019-08-25 23:54:42 -0400 |
---|---|---|
committer | cjihrig <cjihrig@gmail.com> | 2019-08-28 10:17:26 -0400 |
commit | 403dacf9ce205d591b27c937141feb8321774c0b (patch) | |
tree | 2630ef172432a6b7f52a9be3debc9f8ef2822cd7 /tools/node_modules/eslint/lib | |
parent | 0259aadc5a2330dfa8b444e67114d0c0cbc9aae1 (diff) | |
download | android-node-v8-403dacf9ce205d591b27c937141feb8321774c0b.tar.gz android-node-v8-403dacf9ce205d591b27c937141feb8321774c0b.tar.bz2 android-node-v8-403dacf9ce205d591b27c937141feb8321774c0b.zip |
tools: update ESLint to 6.2.2
Update ESLint to 6.2.2
PR-URL: https://github.com/nodejs/node/pull/29320
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: Roman Reiss <me@silverwind.io>
Diffstat (limited to 'tools/node_modules/eslint/lib')
29 files changed, 686 insertions, 171 deletions
diff --git a/tools/node_modules/eslint/lib/cli-engine/config-array-factory.js b/tools/node_modules/eslint/lib/cli-engine/config-array-factory.js index 95430c358d..0b2ed07b6a 100644 --- a/tools/node_modules/eslint/lib/cli-engine/config-array-factory.js +++ b/tools/node_modules/eslint/lib/cli-engine/config-array-factory.js @@ -526,6 +526,7 @@ class ConfigArrayFactory { env, extends: extend, globals, + noInlineConfig, parser: parserName, parserOptions, plugins: pluginList, @@ -567,6 +568,7 @@ class ConfigArrayFactory { criteria: null, env, globals, + noInlineConfig, parser, parserOptions, plugins, diff --git a/tools/node_modules/eslint/lib/cli-engine/config-array/config-array.js b/tools/node_modules/eslint/lib/cli-engine/config-array/config-array.js index 5c7aaa3340..0859868d82 100644 --- a/tools/node_modules/eslint/lib/cli-engine/config-array/config-array.js +++ b/tools/node_modules/eslint/lib/cli-engine/config-array/config-array.js @@ -54,6 +54,7 @@ const { ExtractedConfig } = require("./extracted-config"); * @property {InstanceType<OverrideTester>|null} criteria The tester for the `files` and `excludedFiles` of this config element. * @property {Record<string, boolean>|undefined} env The environment settings. * @property {Record<string, GlobalConf>|undefined} globals The global variable settings. + * @property {boolean|undefined} noInlineConfig The flag that disables directive comments. * @property {DependentParser|undefined} parser The parser loader. * @property {Object|undefined} parserOptions The parser options. * @property {Record<string, DependentPlugin>|undefined} plugins The plugin loaders. @@ -250,6 +251,12 @@ function createConfig(instance, indices) { config.processor = element.processor; } + // Adopt the noInlineConfig which was found at first. + if (config.noInlineConfig === void 0 && element.noInlineConfig !== void 0) { + config.noInlineConfig = element.noInlineConfig; + config.configNameOfNoInlineConfig = element.name; + } + // Merge others. mergeWithoutOverwrite(config.env, element.env); mergeWithoutOverwrite(config.globals, element.globals); diff --git a/tools/node_modules/eslint/lib/cli-engine/config-array/extracted-config.js b/tools/node_modules/eslint/lib/cli-engine/config-array/extracted-config.js index 377cc0fa91..53208c16e4 100644 --- a/tools/node_modules/eslint/lib/cli-engine/config-array/extracted-config.js +++ b/tools/node_modules/eslint/lib/cli-engine/config-array/extracted-config.js @@ -30,6 +30,12 @@ class ExtractedConfig { constructor() { /** + * The config name what `noInlineConfig` setting came from. + * @type {string} + */ + this.configNameOfNoInlineConfig = ""; + + /** * Environments. * @type {Record<string, boolean>} */ @@ -42,6 +48,12 @@ class ExtractedConfig { this.globals = {}; /** + * The flag that disables directive comments. + * @type {boolean|undefined} + */ + this.noInlineConfig = void 0; + + /** * Parser definition. * @type {DependentParser|null} */ @@ -84,7 +96,10 @@ class ExtractedConfig { */ toCompatibleObjectAsConfigFileContent() { const { - processor: _ignore, // eslint-disable-line no-unused-vars + /* eslint-disable no-unused-vars */ + configNameOfNoInlineConfig: _ignore1, + processor: _ignore2, + /* eslint-enable no-unused-vars */ ...config } = this; diff --git a/tools/node_modules/eslint/lib/init/npm-utils.js b/tools/node_modules/eslint/lib/init/npm-utils.js index 26e78406fd..3a680aae92 100644 --- a/tools/node_modules/eslint/lib/init/npm-utils.js +++ b/tools/node_modules/eslint/lib/init/npm-utils.js @@ -135,7 +135,7 @@ function check(packages, opt) { * Check whether node modules are included in the dependencies of a project's * package.json. * - * Convienience wrapper around check(). + * Convenience wrapper around check(). * * @param {string[]} packages Array of node modules to check. * @param {string} rootDir The directory contianing a package.json @@ -150,7 +150,7 @@ function checkDeps(packages, rootDir) { * Check whether node modules are included in the devDependencies of a project's * package.json. * - * Convienience wrapper around check(). + * Convenience wrapper around check(). * * @param {string[]} packages Array of node modules to check. * @returns {Object} An object whose keys are the module names diff --git a/tools/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js b/tools/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js index c1f4a60045..821477aef9 100644 --- a/tools/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js +++ b/tools/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js @@ -526,6 +526,7 @@ function processCodePathToExit(analyzer, node) { break; case "CallExpression": + case "ImportExpression": case "MemberExpression": case "NewExpression": state.makeFirstThrowablePathInTryBlock(); diff --git a/tools/node_modules/eslint/lib/linter/linter.js b/tools/node_modules/eslint/lib/linter/linter.js index a49d850859..d367cef6cb 100644 --- a/tools/node_modules/eslint/lib/linter/linter.js +++ b/tools/node_modules/eslint/lib/linter/linter.js @@ -198,14 +198,20 @@ function createMissingRuleMessage(ruleId) { /** * creates a linting problem * @param {Object} options to create linting error - * @param {string} options.ruleId the ruleId to report - * @param {Object} options.loc the loc to report - * @param {string} options.message the error message to report - * @returns {Problem} created problem, returns a missing-rule problem if only provided ruleId. + * @param {string} [options.ruleId] the ruleId to report + * @param {Object} [options.loc] the loc to report + * @param {string} [options.message] the error message to report + * @param {string} [options.severity] the error message to report + * @returns {LintMessage} created problem, returns a missing-rule problem if only provided ruleId. * @private */ function createLintingProblem(options) { - const { ruleId, loc = DEFAULT_ERROR_LOC, message = createMissingRuleMessage(options.ruleId) } = options; + const { + ruleId = null, + loc = DEFAULT_ERROR_LOC, + message = createMissingRuleMessage(options.ruleId), + severity = 2 + } = options; return { ruleId, @@ -214,7 +220,7 @@ function createLintingProblem(options) { column: loc.start.column + 1, endLine: loc.end.line, endColumn: loc.end.column + 1, - severity: 2, + severity, nodeType: null }; } @@ -257,10 +263,11 @@ function createDisableDirectives(options) { * @param {string} filename The file being checked. * @param {ASTNode} ast The top node of the AST. * @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules + * @param {string|null} warnInlineConfig If a string then it should warn directive comments as disabled. The string value is the config name what the setting came from. * @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, problems: Problem[], disableDirectives: DisableDirective[]}} * A collection of the directive comments that were found, along with any problems that occurred when parsing */ -function getDirectiveComments(filename, ast, ruleMapper) { +function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) { const configuredRules = {}; const enabledGlobals = Object.create(null); const exportedVariables = {}; @@ -269,16 +276,29 @@ function getDirectiveComments(filename, ast, ruleMapper) { ast.comments.filter(token => token.type !== "Shebang").forEach(comment => { const trimmedCommentText = comment.value.trim(); - const match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/u.exec(trimmedCommentText); + const match = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(trimmedCommentText); if (!match) { return; } + const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(match[1]); + + if (warnInlineConfig && (lineCommentSupported || comment.type === "Block")) { + const kind = comment.type === "Block" ? `/*${match[1]}*/` : `//${match[1]}`; + + problems.push(createLintingProblem({ + ruleId: null, + message: `'${kind}' has no effect because you have 'noInlineConfig' setting in ${warnInlineConfig}.`, + loc: comment.loc, + severity: 1 + })); + return; + } const directiveValue = trimmedCommentText.slice(match.index + match[1].length); let directiveType = ""; - if (/^eslint-disable-(next-)?line$/u.test(match[1])) { + if (lineCommentSupported) { if (comment.loc.start.line === comment.loc.end.line) { directiveType = match[1].slice("eslint-".length); } else { @@ -441,16 +461,27 @@ function normalizeFilename(filename) { return index === -1 ? filename : parts.slice(index).join(path.sep); } +// eslint-disable-next-line valid-jsdoc /** * Normalizes the possible options for `linter.verify` and `linter.verifyAndFix` to a * consistent shape. * @param {VerifyOptions} providedOptions Options - * @returns {Required<VerifyOptions>} Normalized options + * @param {ConfigData} config Config. + * @returns {Required<VerifyOptions> & { warnInlineConfig: string|null }} Normalized options */ -function normalizeVerifyOptions(providedOptions) { +function normalizeVerifyOptions(providedOptions, config) { + const disableInlineConfig = config.noInlineConfig === true; + const ignoreInlineConfig = providedOptions.allowInlineConfig === false; + const configNameOfNoInlineConfig = config.configNameOfNoInlineConfig + ? ` (${config.configNameOfNoInlineConfig})` + : ""; + return { filename: normalizeFilename(providedOptions.filename || "<input>"), - allowInlineConfig: providedOptions.allowInlineConfig !== false, + allowInlineConfig: !ignoreInlineConfig, + warnInlineConfig: disableInlineConfig && !ignoreInlineConfig + ? `your config${configNameOfNoInlineConfig}` + : null, reportUnusedDisableDirectives: Boolean(providedOptions.reportUnusedDisableDirectives), disableFixes: Boolean(providedOptions.disableFixes) }; @@ -984,7 +1015,7 @@ class Linter { _verifyWithoutProcessors(textOrSourceCode, providedConfig, providedOptions) { const slots = internalSlotsMap.get(this); const config = providedConfig || {}; - const options = normalizeVerifyOptions(providedOptions); + const options = normalizeVerifyOptions(providedOptions, config); let text; // evaluate arguments @@ -1019,7 +1050,9 @@ class Linter { } // search and apply "eslint-env *". - const envInFile = findEslintEnv(text); + const envInFile = options.allowInlineConfig && !options.warnInlineConfig + ? findEslintEnv(text) + : {}; const resolvedEnvConfig = Object.assign({ builtin: true }, config.env, envInFile); const enabledEnvs = Object.keys(resolvedEnvConfig) .filter(envName => resolvedEnvConfig[envName]) @@ -1062,7 +1095,7 @@ class Linter { const sourceCode = slots.lastSourceCode; const commentDirectives = options.allowInlineConfig - ? getDirectiveComments(options.filename, sourceCode.ast, ruleId => getRule(slots, ruleId)) + ? getDirectiveComments(options.filename, sourceCode.ast, ruleId => getRule(slots, ruleId), options.warnInlineConfig) : { configuredRules: {}, enabledGlobals: {}, exportedVariables: {}, problems: [], disableDirectives: [] }; // augment global scope with declared global variables diff --git a/tools/node_modules/eslint/lib/rules/accessor-pairs.js b/tools/node_modules/eslint/lib/rules/accessor-pairs.js index aca2318486..9c78bdc70e 100644 --- a/tools/node_modules/eslint/lib/rules/accessor-pairs.js +++ b/tools/node_modules/eslint/lib/rules/accessor-pairs.js @@ -6,10 +6,87 @@ "use strict"; //------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const astUtils = require("./utils/ast-utils"); + +//------------------------------------------------------------------------------ +// Typedefs +//------------------------------------------------------------------------------ + +/** + * Property name if it can be computed statically, otherwise the list of the tokens of the key node. + * @typedef {string|Token[]} Key + */ + +/** + * Accessor nodes with the same key. + * @typedef {Object} AccessorData + * @property {Key} key Accessor's key + * @property {ASTNode[]} getters List of getter nodes. + * @property {ASTNode[]} setters List of setter nodes. + */ + +//------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ /** + * Checks whether or not the given lists represent the equal tokens in the same order. + * Tokens are compared by their properties, not by instance. + * @param {Token[]} left First list of tokens. + * @param {Token[]} right Second list of tokens. + * @returns {boolean} `true` if the lists have same tokens. + */ +function areEqualTokenLists(left, right) { + if (left.length !== right.length) { + return false; + } + + for (let i = 0; i < left.length; i++) { + const leftToken = left[i], + rightToken = right[i]; + + if (leftToken.type !== rightToken.type || leftToken.value !== rightToken.value) { + return false; + } + } + + return true; +} + +/** + * Checks whether or not the given keys are equal. + * @param {Key} left First key. + * @param {Key} right Second key. + * @returns {boolean} `true` if the keys are equal. + */ +function areEqualKeys(left, right) { + if (typeof left === "string" && typeof right === "string") { + + // Statically computed names. + return left === right; + } + if (Array.isArray(left) && Array.isArray(right)) { + + // Token lists. + return areEqualTokenLists(left, right); + } + + return false; +} + +/** + * Checks whether or not a given node is of an accessor kind ('get' or 'set'). + * @param {ASTNode} node - A node to check. + * @returns {boolean} `true` if the node is of an accessor kind. + */ +function isAccessorKind(node) { + return node.kind === "get" || node.kind === "set"; +} + +/** * Checks whether or not a given node is an `Identifier` node which was named a given name. * @param {ASTNode} node - A node to check. * @param {string} name - An expected name of the node. @@ -97,69 +174,152 @@ module.exports = { }], messages: { - getter: "Getter is not present.", - setter: "Setter is not present." + missingGetterInPropertyDescriptor: "Getter is not present in property descriptor.", + missingSetterInPropertyDescriptor: "Setter is not present in property descriptor.", + missingGetterInObjectLiteral: "Getter is not present for {{ name }}.", + missingSetterInObjectLiteral: "Setter is not present for {{ name }}." } }, create(context) { const config = context.options[0] || {}; const checkGetWithoutSet = config.getWithoutSet === true; const checkSetWithoutGet = config.setWithoutGet !== false; + const sourceCode = context.getSourceCode(); /** - * Checks a object expression to see if it has setter and getter both present or none. - * @param {ASTNode} node The node to check. + * Reports the given node. + * @param {ASTNode} node The node to report. + * @param {string} messageKind "missingGetter" or "missingSetter". * @returns {void} * @private */ - function checkLonelySetGet(node) { - let isSetPresent = false; - let isGetPresent = false; - const isDescriptor = isPropertyDescriptor(node); + function report(node, messageKind) { + if (node.type === "Property") { + context.report({ + node, + messageId: `${messageKind}InObjectLiteral`, + loc: astUtils.getFunctionHeadLoc(node.value, sourceCode), + data: { name: astUtils.getFunctionNameWithKind(node.value) } + }); + } else { + context.report({ + node, + messageId: `${messageKind}InPropertyDescriptor` + }); + } + } - for (let i = 0, end = node.properties.length; i < end; i++) { - const property = node.properties[i]; + /** + * Reports each of the nodes in the given list using the same messageId. + * @param {ASTNode[]} nodes Nodes to report. + * @param {string} messageKind "missingGetter" or "missingSetter". + * @returns {void} + * @private + */ + function reportList(nodes, messageKind) { + for (const node of nodes) { + report(node, messageKind); + } + } - let propToCheck = ""; + /** + * Creates a new `AccessorData` object for the given getter or setter node. + * @param {ASTNode} node A getter or setter node. + * @returns {AccessorData} New `AccessorData` object that contains the given node. + * @private + */ + function createAccessorData(node) { + const name = astUtils.getStaticPropertyName(node); + const key = (name !== null) ? name : sourceCode.getTokens(node.key); - if (property.kind === "init") { - if (isDescriptor && !property.computed) { - propToCheck = property.key.name; - } - } else { - propToCheck = property.kind; - } + return { + key, + getters: node.kind === "get" ? [node] : [], + setters: node.kind === "set" ? [node] : [] + }; + } - switch (propToCheck) { - case "set": - isSetPresent = true; - break; + /** + * Merges the given `AccessorData` object into the given accessors list. + * @param {AccessorData[]} accessors The list to merge into. + * @param {AccessorData} accessorData The object to merge. + * @returns {AccessorData[]} The same instance with the merged object. + * @private + */ + function mergeAccessorData(accessors, accessorData) { + const equalKeyElement = accessors.find(a => areEqualKeys(a.key, accessorData.key)); - case "get": - isGetPresent = true; - break; + if (equalKeyElement) { + equalKeyElement.getters.push(...accessorData.getters); + equalKeyElement.setters.push(...accessorData.setters); + } else { + accessors.push(accessorData); + } - default: + return accessors; + } - // Do nothing - } + /** + * Checks accessor pairs in the given list of nodes. + * @param {ASTNode[]} nodes The list to check. + * @returns {void} + * @private + */ + function checkList(nodes) { + const accessors = nodes + .filter(isAccessorKind) + .map(createAccessorData) + .reduce(mergeAccessorData, []); - if (isSetPresent && isGetPresent) { - break; + for (const { getters, setters } of accessors) { + if (checkSetWithoutGet && setters.length && !getters.length) { + reportList(setters, "missingGetter"); + } + if (checkGetWithoutSet && getters.length && !setters.length) { + reportList(getters, "missingSetter"); } } + } - if (checkSetWithoutGet && isSetPresent && !isGetPresent) { - context.report({ node, messageId: "getter" }); - } else if (checkGetWithoutSet && isGetPresent && !isSetPresent) { - context.report({ node, messageId: "setter" }); + /** + * Checks accessor pairs in an object literal. + * @param {ASTNode} node `ObjectExpression` node to check. + * @returns {void} + * @private + */ + function checkObjectLiteral(node) { + checkList(node.properties.filter(p => p.type === "Property")); + } + + /** + * Checks accessor pairs in a property descriptor. + * @param {ASTNode} node Property descriptor `ObjectExpression` node to check. + * @returns {void} + * @private + */ + function checkPropertyDescriptor(node) { + const namesToCheck = node.properties + .filter(p => p.type === "Property" && p.kind === "init" && !p.computed) + .map(({ key }) => key.name); + + const hasGetter = namesToCheck.includes("get"); + const hasSetter = namesToCheck.includes("set"); + + if (checkSetWithoutGet && hasSetter && !hasGetter) { + report(node, "missingGetter"); + } + if (checkGetWithoutSet && hasGetter && !hasSetter) { + report(node, "missingSetter"); } } return { ObjectExpression(node) { if (checkSetWithoutGet || checkGetWithoutSet) { - checkLonelySetGet(node); + checkObjectLiteral(node); + if (isPropertyDescriptor(node)) { + checkPropertyDescriptor(node); + } } } }; diff --git a/tools/node_modules/eslint/lib/rules/class-methods-use-this.js b/tools/node_modules/eslint/lib/rules/class-methods-use-this.js index 0eb1da87f4..4bf17090ab 100644 --- a/tools/node_modules/eslint/lib/rules/class-methods-use-this.js +++ b/tools/node_modules/eslint/lib/rules/class-methods-use-this.js @@ -6,6 +6,12 @@ "use strict"; //------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const astUtils = require("./utils/ast-utils"); + +//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -34,7 +40,7 @@ module.exports = { }], messages: { - missingThis: "Expected 'this' to be used by class method '{{name}}'." + missingThis: "Expected 'this' to be used by class {{name}}." } }, create(context) { @@ -70,7 +76,8 @@ module.exports = { * @private */ function isIncludedInstanceMethod(node) { - return isInstanceMethod(node) && !exceptMethods.has(node.key.name); + return isInstanceMethod(node) && + (node.computed || !exceptMethods.has(node.key.name)); } /** @@ -89,7 +96,7 @@ module.exports = { node, messageId: "missingThis", data: { - name: node.parent.key.name + name: astUtils.getFunctionNameWithKind(node) } }); } diff --git a/tools/node_modules/eslint/lib/rules/dot-notation.js b/tools/node_modules/eslint/lib/rules/dot-notation.js index 61184ddcd1..2e8fff8b90 100644 --- a/tools/node_modules/eslint/lib/rules/dot-notation.js +++ b/tools/node_modules/eslint/lib/rules/dot-notation.js @@ -9,13 +9,16 @@ //------------------------------------------------------------------------------ const astUtils = require("./utils/ast-utils"); +const keywords = require("./utils/keywords"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/u; -const keywords = require("./utils/keywords"); + +// `null` literal must be handled separately. +const literalTypesToCheck = new Set(["string", "boolean"]); module.exports = { meta: { @@ -115,7 +118,8 @@ module.exports = { MemberExpression(node) { if ( node.computed && - node.property.type === "Literal" + node.property.type === "Literal" && + (literalTypesToCheck.has(typeof node.property.value) || astUtils.isNullLiteral(node.property)) ) { checkComputedProperty(node, node.property.value); } diff --git a/tools/node_modules/eslint/lib/rules/func-call-spacing.js b/tools/node_modules/eslint/lib/rules/func-call-spacing.js index f9c8e78057..e2edd4282d 100644 --- a/tools/node_modules/eslint/lib/rules/func-call-spacing.js +++ b/tools/node_modules/eslint/lib/rules/func-call-spacing.js @@ -78,21 +78,13 @@ module.exports = { /** * Check if open space is present in a function name * @param {ASTNode} node node to evaluate + * @param {Token} leftToken The last token of the callee. This may be the closing parenthesis that encloses the callee. + * @param {Token} rightToken Tha first token of the arguments. this is the opening parenthesis that encloses the arguments. * @returns {void} * @private */ - function checkSpacing(node) { - const lastToken = sourceCode.getLastToken(node); - const lastCalleeToken = sourceCode.getLastToken(node.callee); - const parenToken = sourceCode.getFirstTokenBetween(lastCalleeToken, lastToken, astUtils.isOpeningParenToken); - const prevToken = parenToken && sourceCode.getTokenBefore(parenToken); - - // Parens in NewExpression are optional - if (!(parenToken && parenToken.range[1] < node.range[1])) { - return; - } - - const textBetweenTokens = text.slice(prevToken.range[1], parenToken.range[0]).replace(/\/\*.*?\*\//gu, ""); + function checkSpacing(node, leftToken, rightToken) { + const textBetweenTokens = text.slice(leftToken.range[1], rightToken.range[0]).replace(/\/\*.*?\*\//gu, ""); const hasWhitespace = /\s/u.test(textBetweenTokens); const hasNewline = hasWhitespace && astUtils.LINEBREAK_MATCHER.test(textBetweenTokens); @@ -123,7 +115,7 @@ module.exports = { if (never && hasWhitespace) { context.report({ node, - loc: lastCalleeToken.loc.start, + loc: leftToken.loc.start, messageId: "unexpected", fix(fixer) { @@ -132,7 +124,7 @@ module.exports = { * https://github.com/eslint/eslint/issues/7787 */ if (!hasNewline) { - return fixer.removeRange([prevToken.range[1], parenToken.range[0]]); + return fixer.removeRange([leftToken.range[1], rightToken.range[0]]); } return null; @@ -141,27 +133,45 @@ module.exports = { } else if (!never && !hasWhitespace) { context.report({ node, - loc: lastCalleeToken.loc.start, + loc: leftToken.loc.start, messageId: "missing", fix(fixer) { - return fixer.insertTextBefore(parenToken, " "); + return fixer.insertTextBefore(rightToken, " "); } }); } else if (!never && !allowNewlines && hasNewline) { context.report({ node, - loc: lastCalleeToken.loc.start, + loc: leftToken.loc.start, messageId: "unexpected", fix(fixer) { - return fixer.replaceTextRange([prevToken.range[1], parenToken.range[0]], " "); + return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], " "); } }); } } return { - CallExpression: checkSpacing, - NewExpression: checkSpacing + "CallExpression, NewExpression"(node) { + const lastToken = sourceCode.getLastToken(node); + const lastCalleeToken = sourceCode.getLastToken(node.callee); + const parenToken = sourceCode.getFirstTokenBetween(lastCalleeToken, lastToken, astUtils.isOpeningParenToken); + const prevToken = parenToken && sourceCode.getTokenBefore(parenToken); + + // Parens in NewExpression are optional + if (!(parenToken && parenToken.range[1] < node.range[1])) { + return; + } + + checkSpacing(node, prevToken, parenToken); + }, + + ImportExpression(node) { + const leftToken = sourceCode.getFirstToken(node); + const rightToken = sourceCode.getTokenAfter(leftToken); + + checkSpacing(node, leftToken, rightToken); + } }; } diff --git a/tools/node_modules/eslint/lib/rules/func-names.js b/tools/node_modules/eslint/lib/rules/func-names.js index 01beb9e2ed..ff3a1f4b5b 100644 --- a/tools/node_modules/eslint/lib/rules/func-names.js +++ b/tools/node_modules/eslint/lib/rules/func-names.js @@ -69,6 +69,8 @@ module.exports = { create(context) { + const sourceCode = context.getSourceCode(); + /** * Returns the config option for the given node. * @param {ASTNode} node - A node to get the config for. @@ -130,6 +132,7 @@ module.exports = { context.report({ node, messageId: "unnamed", + loc: astUtils.getFunctionHeadLoc(node, sourceCode), data: { name: astUtils.getFunctionNameWithKind(node) } }); } @@ -143,6 +146,7 @@ module.exports = { context.report({ node, messageId: "named", + loc: astUtils.getFunctionHeadLoc(node, sourceCode), data: { name: astUtils.getFunctionNameWithKind(node) } }); } diff --git a/tools/node_modules/eslint/lib/rules/function-call-argument-newline.js b/tools/node_modules/eslint/lib/rules/function-call-argument-newline.js new file mode 100644 index 0000000000..8bf31f7c71 --- /dev/null +++ b/tools/node_modules/eslint/lib/rules/function-call-argument-newline.js @@ -0,0 +1,120 @@ +/** + * @fileoverview Rule to enforce line breaks between arguments of a function call + * @author Alexey Gonchar <https://github.com/finico> + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: "layout", + + docs: { + description: "enforce line breaks between arguments of a function call", + category: "Stylistic Issues", + recommended: false, + url: "https://eslint.org/docs/rules/function-call-argument-newline" + }, + + fixable: "whitespace", + + schema: [ + { + enum: ["always", "never", "consistent"] + } + ], + + messages: { + unexpectedLineBreak: "There should be no line break here.", + missingLineBreak: "There should be a line break after this argument." + } + }, + + create(context) { + const sourceCode = context.getSourceCode(); + + const checkers = { + unexpected: { + messageId: "unexpectedLineBreak", + check: (prevToken, currentToken) => prevToken.loc.start.line !== currentToken.loc.start.line, + createFix: (token, tokenBefore) => fixer => + fixer.replaceTextRange([tokenBefore.range[1], token.range[0]], " ") + }, + missing: { + messageId: "missingLineBreak", + check: (prevToken, currentToken) => prevToken.loc.start.line === currentToken.loc.start.line, + createFix: (token, tokenBefore) => fixer => + fixer.replaceTextRange([tokenBefore.range[1], token.range[0]], "\n") + } + }; + + /** + * Check all arguments for line breaks in the CallExpression + * @param {CallExpression} node node to evaluate + * @param {{ messageId: string, check: Function }} checker selected checker + * @returns {void} + * @private + */ + function checkArguments(node, checker) { + for (let i = 1; i < node.arguments.length; i++) { + const prevArgToken = sourceCode.getFirstToken(node.arguments[i - 1]); + const currentArgToken = sourceCode.getFirstToken(node.arguments[i]); + + if (checker.check(prevArgToken, currentArgToken)) { + const tokenBefore = sourceCode.getTokenBefore( + currentArgToken, + { includeComments: true } + ); + + context.report({ + node, + loc: { + start: tokenBefore.loc.end, + end: currentArgToken.loc.start + }, + messageId: checker.messageId, + fix: checker.createFix(currentArgToken, tokenBefore) + }); + } + } + } + + /** + * Check if open space is present in a function name + * @param {CallExpression} node node to evaluate + * @returns {void} + * @private + */ + function check(node) { + if (node.arguments.length < 2) { + return; + } + + const option = context.options[0] || "always"; + + if (option === "never") { + checkArguments(node, checkers.unexpected); + } else if (option === "always") { + checkArguments(node, checkers.missing); + } else if (option === "consistent") { + const firstArgToken = sourceCode.getFirstToken(node.arguments[0]); + const secondArgToken = sourceCode.getFirstToken(node.arguments[1]); + + if (firstArgToken.loc.start.line === secondArgToken.loc.start.line) { + checkArguments(node, checkers.unexpected); + } else { + checkArguments(node, checkers.missing); + } + } + } + + return { + CallExpression: check, + NewExpression: check + }; + } +}; diff --git a/tools/node_modules/eslint/lib/rules/function-paren-newline.js b/tools/node_modules/eslint/lib/rules/function-paren-newline.js index 0a0b57a372..c9f09fdefa 100644 --- a/tools/node_modules/eslint/lib/rules/function-paren-newline.js +++ b/tools/node_modules/eslint/lib/rules/function-paren-newline.js @@ -232,25 +232,15 @@ module.exports = { }; } - default: - throw new TypeError(`unexpected node with type ${node.type}`); - } - } - - /** - * Validates the parentheses for a node - * @param {ASTNode} node The node with parens - * @returns {void} - */ - function validateNode(node) { - const parens = getParenTokens(node); - - if (parens) { - validateParens(parens, astUtils.isFunction(node) ? node.params : node.arguments); + case "ImportExpression": { + const leftParen = sourceCode.getFirstToken(node, 1); + const rightParen = sourceCode.getLastToken(node); - if (multilineArgumentsOption) { - validateArguments(parens, astUtils.isFunction(node) ? node.params : node.arguments); + return { leftParen, rightParen }; } + + default: + throw new TypeError(`unexpected node with type ${node.type}`); } } @@ -259,11 +249,33 @@ module.exports = { //---------------------------------------------------------------------- return { - ArrowFunctionExpression: validateNode, - CallExpression: validateNode, - FunctionDeclaration: validateNode, - FunctionExpression: validateNode, - NewExpression: validateNode + [[ + "ArrowFunctionExpression", + "CallExpression", + "FunctionDeclaration", + "FunctionExpression", + "ImportExpression", + "NewExpression" + ]](node) { + const parens = getParenTokens(node); + let params; + + if (node.type === "ImportExpression") { + params = [node.source]; + } else if (astUtils.isFunction(node)) { + params = node.params; + } else { + params = node.arguments; + } + + if (parens) { + validateParens(parens, params); + + if (multilineArgumentsOption) { + validateArguments(parens, params); + } + } + } }; } }; diff --git a/tools/node_modules/eslint/lib/rules/indent.js b/tools/node_modules/eslint/lib/rules/indent.js index 345c69e81c..79b1063137 100644 --- a/tools/node_modules/eslint/lib/rules/indent.js +++ b/tools/node_modules/eslint/lib/rules/indent.js @@ -99,7 +99,8 @@ const KNOWN_NODES = new Set([ "ImportDeclaration", "ImportSpecifier", "ImportDefaultSpecifier", - "ImportNamespaceSpecifier" + "ImportNamespaceSpecifier", + "ImportExpression" ]); /* @@ -1109,7 +1110,6 @@ module.exports = { CallExpression: addFunctionCallIndent, - "ClassDeclaration[superClass], ClassExpression[superClass]"(node) { const classToken = sourceCode.getFirstToken(node); const extendsToken = sourceCode.getTokenBefore(node.superClass, astUtils.isNotOpeningParenToken); @@ -1236,6 +1236,17 @@ module.exports = { } }, + ImportExpression(node) { + const openingParen = sourceCode.getFirstToken(node, 1); + const closingParen = sourceCode.getLastToken(node); + + parameterParens.add(openingParen); + parameterParens.add(closingParen); + offsets.setDesiredOffset(openingParen, sourceCode.getTokenBefore(openingParen), 0); + + addElementListIndent([node.source], openingParen, closingParen, options.CallExpression.arguments); + }, + "MemberExpression, JSXMemberExpression, MetaProperty"(node) { const object = node.type === "MetaProperty" ? node.meta : node.object; const firstNonObjectToken = sourceCode.getFirstTokenBetween(object, node.property, astUtils.isNotClosingParenToken); diff --git a/tools/node_modules/eslint/lib/rules/index.js b/tools/node_modules/eslint/lib/rules/index.js index 45045904bb..c42ae41d6c 100644 --- a/tools/node_modules/eslint/lib/rules/index.js +++ b/tools/node_modules/eslint/lib/rules/index.js @@ -46,6 +46,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({ "func-name-matching": () => require("./func-name-matching"), "func-names": () => require("./func-names"), "func-style": () => require("./func-style"), + "function-call-argument-newline": () => require("./function-call-argument-newline"), "function-paren-newline": () => require("./function-paren-newline"), "generator-star-spacing": () => require("./generator-star-spacing"), "getter-return": () => require("./getter-return"), diff --git a/tools/node_modules/eslint/lib/rules/new-cap.js b/tools/node_modules/eslint/lib/rules/new-cap.js index dcae238d9b..cee979310e 100644 --- a/tools/node_modules/eslint/lib/rules/new-cap.js +++ b/tools/node_modules/eslint/lib/rules/new-cap.js @@ -23,7 +23,8 @@ const CAPS_ALLOWED = [ "Object", "RegExp", "String", - "Symbol" + "Symbol", + "BigInt" ]; /** diff --git a/tools/node_modules/eslint/lib/rules/no-dupe-keys.js b/tools/node_modules/eslint/lib/rules/no-dupe-keys.js index d0751b4a2d..1b7f69cfac 100644 --- a/tools/node_modules/eslint/lib/rules/no-dupe-keys.js +++ b/tools/node_modules/eslint/lib/rules/no-dupe-keys.js @@ -120,7 +120,7 @@ module.exports = { } // Skip if the name is not static. - if (!name) { + if (name === null) { return; } diff --git a/tools/node_modules/eslint/lib/rules/no-duplicate-case.js b/tools/node_modules/eslint/lib/rules/no-duplicate-case.js index 93c8548f91..c8a0fa9da3 100644 --- a/tools/node_modules/eslint/lib/rules/no-duplicate-case.js +++ b/tools/node_modules/eslint/lib/rules/no-duplicate-case.js @@ -33,17 +33,19 @@ module.exports = { return { SwitchStatement(node) { - const mapping = {}; + const previousKeys = new Set(); - node.cases.forEach(switchCase => { - const key = sourceCode.getText(switchCase.test); + for (const switchCase of node.cases) { + if (switchCase.test) { + const key = sourceCode.getText(switchCase.test); - if (mapping[key]) { - context.report({ node: switchCase, messageId: "unexpected" }); - } else { - mapping[key] = switchCase; + if (previousKeys.has(key)) { + context.report({ node: switchCase, messageId: "unexpected" }); + } else { + previousKeys.add(key); + } } - }); + } } }; } diff --git a/tools/node_modules/eslint/lib/rules/no-extra-bind.js b/tools/node_modules/eslint/lib/rules/no-extra-bind.js index 5380cf217f..cc0b1f8437 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-bind.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-bind.js @@ -98,6 +98,7 @@ module.exports = { grandparent.type === "CallExpression" && grandparent.callee === parent && grandparent.arguments.length === 1 && + grandparent.arguments[0].type !== "SpreadElement" && parent.type === "MemberExpression" && parent.object === node && astUtils.getStaticPropertyName(parent) === "bind" diff --git a/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js b/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js index 8dd526477d..9ae9b5be61 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js @@ -50,8 +50,8 @@ module.exports = { /** * Check if a node is in a context where its value would be coerced to a boolean at runtime. * - * @param {Object} node The node - * @param {Object} parent Its parent + * @param {ASTNode} node The node + * @param {ASTNode} parent Its parent * @returns {boolean} If it is in a boolean context */ function isInBooleanContext(node, parent) { @@ -65,6 +65,15 @@ module.exports = { ); } + /** + * Check if a node has comments inside. + * + * @param {ASTNode} node The node to check. + * @returns {boolean} `true` if it has comments inside. + */ + function hasCommentsInside(node) { + return Boolean(sourceCode.getCommentsInside(node).length); + } return { UnaryExpression(node) { @@ -89,7 +98,12 @@ module.exports = { context.report({ node, messageId: "unexpectedNegation", - fix: fixer => fixer.replaceText(parent, sourceCode.getText(node.argument)) + fix: fixer => { + if (hasCommentsInside(parent)) { + return null; + } + return fixer.replaceText(parent, sourceCode.getText(node.argument)); + } }); } }, @@ -106,10 +120,35 @@ module.exports = { messageId: "unexpectedCall", fix: fixer => { if (!node.arguments.length) { - return fixer.replaceText(parent, "true"); + if (parent.type === "UnaryExpression" && parent.operator === "!") { + + // !Boolean() -> true + + if (hasCommentsInside(parent)) { + return null; + } + + const replacement = "true"; + let prefix = ""; + const tokenBefore = sourceCode.getTokenBefore(parent); + + if (tokenBefore && tokenBefore.range[1] === parent.range[0] && + !astUtils.canTokensBeAdjacent(tokenBefore, replacement)) { + prefix = " "; + } + + return fixer.replaceText(parent, prefix + replacement); + } + + // Boolean() -> false + if (hasCommentsInside(node)) { + return null; + } + return fixer.replaceText(node, "false"); } - if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement") { + if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement" || + hasCommentsInside(node)) { return null; } diff --git a/tools/node_modules/eslint/lib/rules/no-extra-parens.js b/tools/node_modules/eslint/lib/rules/no-extra-parens.js index 6c3198b5f0..aa455c6a25 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-parens.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-parens.js @@ -8,6 +8,7 @@ // Rule Definition //------------------------------------------------------------------------------ +const { isParenthesized: isParenthesizedRaw } = require("eslint-utils"); const astUtils = require("./utils/ast-utils.js"); module.exports = { @@ -68,7 +69,6 @@ module.exports = { const sourceCode = context.getSourceCode(); const tokensToIgnore = new WeakSet(); - const isParenthesised = astUtils.isParenthesised.bind(astUtils, sourceCode); const precedence = astUtils.getPrecedence; const ALL_NODES = context.options[0] !== "functions"; const EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === false; @@ -119,18 +119,23 @@ module.exports = { } /** + * Determines if a node is surrounded by parentheses. + * @param {ASTNode} node - The node to be checked. + * @returns {boolean} True if the node is parenthesised. + * @private + */ + function isParenthesised(node) { + return isParenthesizedRaw(1, node, sourceCode); + } + + /** * Determines if a node is surrounded by parentheses twice. * @param {ASTNode} node - The node to be checked. * @returns {boolean} True if the node is doubly parenthesised. * @private */ function isParenthesisedTwice(node) { - const previousToken = sourceCode.getTokenBefore(node, 1), - nextToken = sourceCode.getTokenAfter(node, 1); - - return isParenthesised(node) && previousToken && nextToken && - astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] && - astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1]; + return isParenthesizedRaw(2, node, sourceCode); } /** @@ -406,15 +411,9 @@ module.exports = { report(node.callee); } } - if (node.arguments.length === 1) { - if (hasDoubleExcessParens(node.arguments[0]) && precedence(node.arguments[0]) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { - report(node.arguments[0]); - } - } else { - node.arguments - .filter(arg => hasExcessParens(arg) && precedence(arg) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) - .forEach(report); - } + node.arguments + .filter(arg => hasExcessParens(arg) && precedence(arg) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) + .forEach(report); } /** @@ -686,6 +685,13 @@ module.exports = { CallExpression: checkCallNew, + ClassBody(node) { + node.body + .filter(member => member.type === "MethodDefinition" && member.computed && + member.key && hasExcessParens(member.key) && precedence(member.key) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) + .forEach(member => report(member.key)); + }, + ConditionalExpression(node) { if (isReturnAssignException(node)) { return; @@ -705,7 +711,7 @@ module.exports = { }, DoWhileStatement(node) { - if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) { + if (hasExcessParens(node.test) && !isCondAssignException(node)) { report(node.test); } }, @@ -830,11 +836,23 @@ module.exports = { }, IfStatement(node) { - if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) { + if (hasExcessParens(node.test) && !isCondAssignException(node)) { report(node.test); } }, + ImportExpression(node) { + const { source } = node; + + if (source.type === "SequenceExpression") { + if (hasDoubleExcessParens(source)) { + report(source); + } + } else if (hasExcessParens(source)) { + report(source); + } + }, + LogicalExpression: checkBinaryLogical, MemberExpression(node) { @@ -917,7 +935,7 @@ module.exports = { }, SwitchStatement(node) { - if (hasDoubleExcessParens(node.discriminant)) { + if (hasExcessParens(node.discriminant)) { report(node.discriminant); } }, @@ -945,13 +963,13 @@ module.exports = { }, WhileStatement(node) { - if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) { + if (hasExcessParens(node.test) && !isCondAssignException(node)) { report(node.test); } }, WithStatement(node) { - if (hasDoubleExcessParens(node.object)) { + if (hasExcessParens(node.object)) { report(node.object); } }, @@ -973,7 +991,21 @@ module.exports = { SpreadElement: checkSpreadOperator, SpreadProperty: checkSpreadOperator, - ExperimentalSpreadProperty: checkSpreadOperator + ExperimentalSpreadProperty: checkSpreadOperator, + + TemplateLiteral(node) { + node.expressions + .filter(e => e && hasExcessParens(e)) + .forEach(report); + }, + + AssignmentPattern(node) { + const { right } = node; + + if (right && hasExcessParens(right) && precedence(right) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + report(right); + } + } }; } diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-operators.js b/tools/node_modules/eslint/lib/rules/no-mixed-operators.js index 21e1d95c68..8d1c7a6af4 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-operators.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-operators.js @@ -20,12 +20,14 @@ const BITWISE_OPERATORS = ["&", "|", "^", "~", "<<", ">>", ">>>"]; const COMPARISON_OPERATORS = ["==", "!=", "===", "!==", ">", ">=", "<", "<="]; const LOGICAL_OPERATORS = ["&&", "||"]; const RELATIONAL_OPERATORS = ["in", "instanceof"]; +const TERNARY_OPERATOR = ["?:"]; const ALL_OPERATORS = [].concat( ARITHMETIC_OPERATORS, BITWISE_OPERATORS, COMPARISON_OPERATORS, LOGICAL_OPERATORS, - RELATIONAL_OPERATORS + RELATIONAL_OPERATORS, + TERNARY_OPERATOR ); const DEFAULT_GROUPS = [ ARITHMETIC_OPERATORS, @@ -34,7 +36,7 @@ const DEFAULT_GROUPS = [ LOGICAL_OPERATORS, RELATIONAL_OPERATORS ]; -const TARGET_NODE_TYPE = /^(?:Binary|Logical)Expression$/u; +const TARGET_NODE_TYPE = /^(?:Binary|Logical|Conditional)Expression$/u; /** * Normalizes options. @@ -65,6 +67,18 @@ function includesBothInAGroup(groups, left, right) { return groups.some(group => group.indexOf(left) !== -1 && group.indexOf(right) !== -1); } +/** + * Checks whether the given node is a conditional expression and returns the test node else the left node. + * + * @param {ASTNode} node - A node which can be a BinaryExpression or a LogicalExpression node. + * This parent node can be BinaryExpression, LogicalExpression + * , or a ConditionalExpression node + * @returns {ASTNode} node the appropriate node(left or test). + */ +function getChildNode(node) { + return node.type === "ConditionalExpression" ? node.test : node.left; +} + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -121,7 +135,7 @@ module.exports = { const b = node.parent; return ( - !includesBothInAGroup(options.groups, a.operator, b.operator) || + !includesBothInAGroup(options.groups, a.operator, b.type === "ConditionalExpression" ? "?:" : b.operator) || ( options.allowSamePrecedence && astUtils.getPrecedence(a) === astUtils.getPrecedence(b) @@ -139,6 +153,7 @@ module.exports = { * @returns {boolean} `true` if the node was mixed. */ function isMixedWithParent(node) { + return ( node.operator !== node.parent.operator && !astUtils.isParenthesised(sourceCode, node) @@ -146,6 +161,18 @@ module.exports = { } /** + * Checks whether the operator of a given node is mixed with a + * conditional expression. + * + * @param {ASTNode} node - A node to check. This is a conditional + * expression node + * @returns {boolean} `true` if the node was mixed. + */ + function isMixedWithConditionalParent(node) { + return !astUtils.isParenthesised(sourceCode, node) && !astUtils.isParenthesised(sourceCode, node.test); + } + + /** * Gets the operator token of a given node. * * @param {ASTNode} node - A node to check. This is a BinaryExpression @@ -153,7 +180,7 @@ module.exports = { * @returns {Token} The operator token of the node. */ function getOperatorToken(node) { - return sourceCode.getTokenAfter(node.left, astUtils.isNotClosingParenToken); + return sourceCode.getTokenAfter(getChildNode(node), astUtils.isNotClosingParenToken); } /** @@ -167,13 +194,13 @@ module.exports = { */ function reportBothOperators(node) { const parent = node.parent; - const left = (parent.left === node) ? node : parent; - const right = (parent.left !== node) ? node : parent; + const left = (getChildNode(parent) === node) ? node : parent; + const right = (getChildNode(parent) !== node) ? node : parent; const message = "Unexpected mix of '{{leftOperator}}' and '{{rightOperator}}'."; const data = { - leftOperator: left.operator, - rightOperator: right.operator + leftOperator: left.operator || "?:", + rightOperator: right.operator || "?:" }; context.report({ @@ -198,17 +225,25 @@ module.exports = { * @returns {void} */ function check(node) { - if (TARGET_NODE_TYPE.test(node.parent.type) && - isMixedWithParent(node) && - !shouldIgnore(node) - ) { - reportBothOperators(node); + if (TARGET_NODE_TYPE.test(node.parent.type)) { + if (node.parent.type === "ConditionalExpression" && !shouldIgnore(node) && isMixedWithConditionalParent(node.parent)) { + reportBothOperators(node); + } else { + if (TARGET_NODE_TYPE.test(node.parent.type) && + isMixedWithParent(node) && + !shouldIgnore(node) + ) { + reportBothOperators(node); + } + } } + } return { BinaryExpression: check, LogicalExpression: check + }; } }; diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js b/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js index 74eea14789..41aa9fa390 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js @@ -21,7 +21,7 @@ module.exports = { schema: { type: "array", - items: [{ + items: { oneOf: [ { type: "string" @@ -36,7 +36,7 @@ module.exports = { additionalProperties: false } ] - }], + }, uniqueItems: true, minItems: 0 } diff --git a/tools/node_modules/eslint/lib/rules/no-unused-vars.js b/tools/node_modules/eslint/lib/rules/no-unused-vars.js index 48df3aa3cc..8094de57c7 100644 --- a/tools/node_modules/eslint/lib/rules/no-unused-vars.js +++ b/tools/node_modules/eslint/lib/rules/no-unused-vars.js @@ -507,7 +507,7 @@ module.exports = { const childScopes = scope.childScopes; let i, l; - if (scope.type !== "TDZ" && (scope.type !== "global" || config.vars === "all")) { + if (scope.type !== "global" || config.vars === "all") { for (i = 0, l = variables.length; i < l; ++i) { const variable = variables[i]; diff --git a/tools/node_modules/eslint/lib/rules/prefer-template.js b/tools/node_modules/eslint/lib/rules/prefer-template.js index f73ac34f83..a2507d452c 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-template.js +++ b/tools/node_modules/eslint/lib/rules/prefer-template.js @@ -52,16 +52,7 @@ function isOctalEscapeSequence(node) { return false; } - const match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-7]{1,3})/u); - - if (match) { - - // \0 is actually not considered an octal - if (match[2] !== "0" || typeof match[3] !== "undefined") { - return true; - } - } - return false; + return astUtils.hasOctalEscapeSequence(node.raw); } /** diff --git a/tools/node_modules/eslint/lib/rules/sort-keys.js b/tools/node_modules/eslint/lib/rules/sort-keys.js index beda42f1e3..c314d4a636 100644 --- a/tools/node_modules/eslint/lib/rules/sort-keys.js +++ b/tools/node_modules/eslint/lib/rules/sort-keys.js @@ -29,7 +29,13 @@ const astUtils = require("./utils/ast-utils"), * @private */ function getPropertyName(node) { - return astUtils.getStaticPropertyName(node) || node.key.name || null; + const staticName = astUtils.getStaticPropertyName(node); + + if (staticName !== null) { + return staticName; + } + + return node.key.name || null; } /** @@ -151,9 +157,11 @@ module.exports = { const numKeys = stack.numKeys; const thisName = getPropertyName(node); - stack.prevName = thisName || prevName; + if (thisName !== null) { + stack.prevName = thisName; + } - if (!prevName || !thisName || numKeys < minKeys) { + if (prevName === null || thisName === null || numKeys < minKeys) { return; } diff --git a/tools/node_modules/eslint/lib/rules/utils/ast-utils.js b/tools/node_modules/eslint/lib/rules/utils/ast-utils.js index 78ae7bc015..f0b926e329 100644 --- a/tools/node_modules/eslint/lib/rules/utils/ast-utils.js +++ b/tools/node_modules/eslint/lib/rules/utils/ast-utils.js @@ -38,6 +38,7 @@ const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]); const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]); const DECIMAL_INTEGER_PATTERN = /^(0|[1-9]\d*)$/u; +const OCTAL_ESCAPE_PATTERN = /^(?:[^\\]|\\[^0-7]|\\0(?![0-9]))*\\(?:[1-7]|0[0-9])/u; /** * Checks reference if is non initializer and writable. @@ -847,6 +848,7 @@ module.exports = { return 17; case "CallExpression": + case "ImportExpression": return 18; case "NewExpression": @@ -1101,7 +1103,7 @@ module.exports = { } else { const name = module.exports.getStaticPropertyName(parent); - if (name) { + if (name !== null) { tokens.push(`'${name}'`); } } @@ -1301,7 +1303,7 @@ module.exports = { * set `node.value` to a unicode regex. To make sure a literal is actually `null`, check * `node.regex` instead. Also see: https://github.com/eslint/eslint/issues/8020 */ - return node.type === "Literal" && node.value === null && !node.regex; + return node.type === "Literal" && node.value === null && !node.regex && !node.bigint; }, /** @@ -1373,5 +1375,20 @@ module.exports = { "/*".length + (match ? match.index + 1 : 0) ); + }, + + /** + * Determines whether the given raw string contains an octal escape sequence. + * + * "\1", "\2" ... "\7" + * "\00", "\01" ... "\09" + * + * "\0", when not followed by a digit, is not an octal escape sequence. + * + * @param {string} rawString A string in its raw representation. + * @returns {boolean} `true` if the string contains at least one octal escape sequence. + */ + hasOctalEscapeSequence(rawString) { + return OCTAL_ESCAPE_PATTERN.test(rawString); } }; diff --git a/tools/node_modules/eslint/lib/rules/yoda.js b/tools/node_modules/eslint/lib/rules/yoda.js index 43783c193b..89c4a8afd1 100644 --- a/tools/node_modules/eslint/lib/rules/yoda.js +++ b/tools/node_modules/eslint/lib/rules/yoda.js @@ -119,7 +119,7 @@ function same(a, b) { const nameA = astUtils.getStaticPropertyName(a); // x.y = x["y"] - if (nameA) { + if (nameA !== null) { return ( same(a.object, b.object) && nameA === astUtils.getStaticPropertyName(b) diff --git a/tools/node_modules/eslint/lib/shared/types.js b/tools/node_modules/eslint/lib/shared/types.js index d835779994..8a889d21db 100644 --- a/tools/node_modules/eslint/lib/shared/types.js +++ b/tools/node_modules/eslint/lib/shared/types.js @@ -30,6 +30,7 @@ module.exports = {}; * @property {Record<string, boolean>} [env] The environment settings. * @property {string | string[]} [extends] The path to other config files or the package name of shareable configs. * @property {Record<string, GlobalConf>} [globals] The global variable settings. + * @property {boolean} [noInlineConfig] The flag that disables directive comments. * @property {OverrideConfigData[]} [overrides] The override settings per kind of files. * @property {string} [parser] The path to a parser or the package name of a parser. * @property {ParserOptions} [parserOptions] The parser options. @@ -47,6 +48,7 @@ module.exports = {}; * @property {string | string[]} [extends] The path to other config files or the package name of shareable configs. * @property {string | string[]} files The glob pattarns for target files. * @property {Record<string, GlobalConf>} [globals] The global variable settings. + * @property {boolean} [noInlineConfig] The flag that disables directive comments. * @property {OverrideConfigData[]} [overrides] The override settings per kind of files. * @property {string} [parser] The path to a parser or the package name of a parser. * @property {ParserOptions} [parserOptions] The parser options. |