diff --git a/tools/node_modules/eslint/README.md b/tools/node_modules/eslint/README.md index 0cde09fc602b17..65c57271956185 100644 --- a/tools/node_modules/eslint/README.md +++ b/tools/node_modules/eslint/README.md @@ -39,7 +39,7 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J ## Installation and Usage -Prerequisites: [Node.js](https://nodejs.org/) (`^8.10.0`, `^10.13.0`, or `>=11.10.1`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.) +Prerequisites: [Node.js](https://nodejs.org/) (`^10.12.0`, or `>=12.0.0`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.) You can install ESLint using npm: @@ -264,7 +264,7 @@ The following companies, organizations, and individuals support ESLint's ongoing

Gold Sponsors

Shopify Salesforce Badoo Airbnb Facebook Open Source

Silver Sponsors

AMP Project

Bronze Sponsors

-

UI UX Design Agencies Top Web Design Agencies Bugsnag Stability Monitoring Crosswordsolver Codacy Mixpanel VPS Server Free Icons by Icons8 EduBirdie clay Discord ThemeIsle TekHattan Marfeel Fire Stick Tricks JSHeroes

+

Free Icons by Icons8 BonusFinder Deutschland EduBirdie Bugsnag Stability Monitoring Crosswordsolver Codacy Mixpanel VPS Server Top Web Design Agencies UI UX Design Agencies clay Discord ThemeIsle TekHattan Marfeel Fire Stick Tricks JSHeroes

## Technology Sponsors diff --git a/tools/node_modules/eslint/conf/default-cli-options.js b/tools/node_modules/eslint/conf/default-cli-options.js index 0f7b377fb362ec..e09a829d17cee2 100644 --- a/tools/node_modules/eslint/conf/default-cli-options.js +++ b/tools/node_modules/eslint/conf/default-cli-options.js @@ -12,7 +12,7 @@ module.exports = { useEslintrc: true, envs: [], globals: [], - extensions: [".js"], + extensions: null, ignore: true, ignorePath: void 0, cache: false, diff --git a/tools/node_modules/eslint/lib/cli-engine/cascading-config-array-factory.js b/tools/node_modules/eslint/lib/cli-engine/cascading-config-array-factory.js index 52703a873bb67e..f91dea4c448276 100644 --- a/tools/node_modules/eslint/lib/cli-engine/cascading-config-array-factory.js +++ b/tools/node_modules/eslint/lib/cli-engine/cascading-config-array-factory.js @@ -26,6 +26,7 @@ const os = require("os"); const path = require("path"); const { validateConfigArray } = require("../shared/config-validator"); +const { emitDeprecationWarning } = require("../shared/deprecation-warnings"); const { ConfigArrayFactory } = require("./config-array-factory"); const { ConfigArray, ConfigDependency, IgnorePattern } = require("./config-array"); const loadRules = require("./load-rules"); @@ -105,6 +106,7 @@ function createBaseConfigArray({ */ if (rulePaths && rulePaths.length > 0) { baseConfigArray.push({ + type: "config", name: "--rulesdir", filePath: "", plugins: { @@ -290,10 +292,11 @@ class CascadingConfigArrayFactory { /** * Load and normalize config files from the ancestor directories. * @param {string} directoryPath The path to a leaf directory. + * @param {boolean} configsExistInSubdirs `true` if configurations exist in subdirectories. * @returns {ConfigArray} The loaded config. * @private */ - _loadConfigInAncestors(directoryPath) { + _loadConfigInAncestors(directoryPath, configsExistInSubdirs = false) { const { baseConfigArray, configArrayFactory, @@ -320,6 +323,16 @@ class CascadingConfigArrayFactory { // Consider this is root. if (directoryPath === homePath && cwd !== homePath) { debug("Stop traversing because of considered root."); + if (configsExistInSubdirs) { + const filePath = ConfigArrayFactory.getPathToConfigFileInDirectory(directoryPath); + + if (filePath) { + emitDeprecationWarning( + filePath, + "ESLINT_PERSONAL_CONFIG_SUPPRESS" + ); + } + } return this._cacheConfig(directoryPath, baseConfigArray); } @@ -344,7 +357,10 @@ class CascadingConfigArrayFactory { // Load from the ancestors and merge it. const parentPath = path.dirname(directoryPath); const parentConfigArray = parentPath && parentPath !== directoryPath - ? this._loadConfigInAncestors(parentPath) + ? this._loadConfigInAncestors( + parentPath, + configsExistInSubdirs || configArray.length > 0 + ) : baseConfigArray; if (configArray.length > 0) { @@ -400,12 +416,29 @@ class CascadingConfigArrayFactory { configArray.every(c => !c.filePath) && cliConfigArray.every(c => !c.filePath) // `--config` option can be a file. ) { - debug("Loading the config file of the home directory."); + const homePath = os.homedir(); + + debug("Loading the config file of the home directory:", homePath); - finalConfigArray = configArrayFactory.loadInDirectory( - os.homedir(), - { name: "PersonalConfig", parent: finalConfigArray } + const personalConfigArray = configArrayFactory.loadInDirectory( + homePath, + { name: "PersonalConfig" } ); + + if ( + personalConfigArray.length > 0 && + !directoryPath.startsWith(homePath) + ) { + const lastElement = + personalConfigArray[personalConfigArray.length - 1]; + + emitDeprecationWarning( + lastElement.filePath, + "ESLINT_PERSONAL_CONFIG_LOAD" + ); + } + + finalConfigArray = finalConfigArray.concat(personalConfigArray); } // Apply CLI options. diff --git a/tools/node_modules/eslint/lib/cli-engine/cli-engine.js b/tools/node_modules/eslint/lib/cli-engine/cli-engine.js index 22336a91de2909..6a0352399b7738 100644 --- a/tools/node_modules/eslint/lib/cli-engine/cli-engine.js +++ b/tools/node_modules/eslint/lib/cli-engine/cli-engine.js @@ -57,7 +57,7 @@ const validFixTypes = new Set(["problem", "suggestion", "layout"]); * @property {string} configFile The configuration file to use. * @property {string} cwd The value to use for the current working directory. * @property {string[]} envs An array of environments to load. - * @property {string[]} extensions An array of file extensions to check. + * @property {string[]|null} extensions An array of file extensions to check. * @property {boolean|Function} fix Execute in autofix mode. If a function, should return a boolean. * @property {string[]} fixTypes Array of rule types to apply fixes for. * @property {string[]} globals An array of global variables to declare. @@ -201,7 +201,7 @@ function calculateStatsPerRun(results) { * @param {boolean} config.fix If `true` then it does fix. * @param {boolean} config.allowInlineConfig If `true` then it uses directive comments. * @param {boolean} config.reportUnusedDisableDirectives If `true` then it reports unused `eslint-disable` comments. - * @param {RegExp} config.extensionRegExp The `RegExp` object that tests if a file path has the allowed file extensions. + * @param {FileEnumerator} config.fileEnumerator The file enumerator to check if a path is a target or not. * @param {Linter} config.linter The linter instance to verify. * @returns {LintResult} The result of linting. * @private @@ -214,7 +214,7 @@ function verifyText({ fix, allowInlineConfig, reportUnusedDisableDirectives, - extensionRegExp, + fileEnumerator, linter }) { const filePath = providedFilePath || ""; @@ -238,13 +238,11 @@ function verifyText({ /** * Check if the linter should adopt a given code block or not. - * Currently, the linter adopts code blocks if the name matches `--ext` option. - * In the future, `overrides` in the configuration would affect the adoption (https://github.com/eslint/rfcs/pull/20). * @param {string} blockFilename The virtual filename of a code block. * @returns {boolean} `true` if the linter should adopt the code block. */ filterCodeBlock(blockFilename) { - return extensionRegExp.test(blockFilename); + return fileEnumerator.isTargetPath(blockFilename); } } ); @@ -704,7 +702,7 @@ class CLIEngine { return patterns.filter(Boolean); } - const extensions = options.extensions.map(ext => ext.replace(/^\./u, "")); + const extensions = (options.extensions || [".js"]).map(ext => ext.replace(/^\./u, "")); const dirSuffix = `/**/*.{${extensions.join(",")}}`; return patterns.filter(Boolean).map(pathname => { @@ -803,7 +801,7 @@ class CLIEngine { fix, allowInlineConfig, reportUnusedDisableDirectives, - extensionRegExp: fileEnumerator.extensionRegExp, + fileEnumerator, linter }); @@ -891,7 +889,7 @@ class CLIEngine { fix, allowInlineConfig, reportUnusedDisableDirectives, - extensionRegExp: fileEnumerator.extensionRegExp, + fileEnumerator, linter })); } 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 76c4ccd70212cd..997a7e15318dfd 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 @@ -436,6 +436,29 @@ class ConfigArrayFactory { ); } + /** + * Check if a config file on a given directory exists or not. + * @param {string} directoryPath The path to a directory. + * @returns {string | null} The path to the found config file. If not found then null. + */ + static getPathToConfigFileInDirectory(directoryPath) { + for (const filename of configFilenames) { + const filePath = path.join(directoryPath, filename); + + if (fs.existsSync(filePath)) { + if (filename === "package.json") { + try { + loadPackageJSONConfigFile(filePath); + return filePath; + } catch (error) { /* ignore */ } + } else { + return filePath; + } + } + } + return null; + } + /** * Load `.eslintignore` file. * @param {string} filePath The path to a `.eslintignore` file to load. @@ -542,7 +565,7 @@ class ConfigArrayFactory { */ *_normalizeESLintIgnoreData(ignorePatterns, filePath, name) { const elements = this._normalizeObjectConfigData( - { ignorePatterns }, + { type: "ignore", ignorePatterns }, filePath, name ); @@ -644,6 +667,7 @@ class ConfigArrayFactory { root, rules, settings, + type = "config", overrides: overrideList = [] }, filePath, @@ -675,6 +699,7 @@ class ConfigArrayFactory { yield { // Debug information. + type, name, filePath, @@ -1024,6 +1049,7 @@ class ConfigArrayFactory { if (processorId.startsWith(".")) { yield* this._normalizeObjectConfigData( { + type: "implicit-processor", files: [`*${processorId}`], processor: `${pluginId}/${processorId}` }, 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 4fae8deaca1b69..02f73b43e65438 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 @@ -454,6 +454,25 @@ class ConfigArray extends Array { return cache.get(cacheKey); } + + /** + * Check if a given path is an additional lint target. + * @param {string} filePath The absolute path to the target file. + * @returns {boolean} `true` if the file is an additional lint target. + */ + isAdditionalTargetPath(filePath) { + for (const { criteria, type } of this) { + if ( + type === "config" && + criteria && + !criteria.endsWithWildcard && + criteria.test(filePath) + ) { + return true; + } + } + return false; + } } const exportObject = { diff --git a/tools/node_modules/eslint/lib/cli-engine/config-array/override-tester.js b/tools/node_modules/eslint/lib/cli-engine/config-array/override-tester.js index 67c8a6ed8a0cbb..e7ba1202f1cb08 100644 --- a/tools/node_modules/eslint/lib/cli-engine/config-array/override-tester.js +++ b/tools/node_modules/eslint/lib/cli-engine/config-array/override-tester.js @@ -96,14 +96,22 @@ class OverrideTester { static create(files, excludedFiles, basePath) { const includePatterns = normalizePatterns(files); const excludePatterns = normalizePatterns(excludedFiles); - const allPatterns = includePatterns.concat(excludePatterns); + let endsWithWildcard = false; - if (allPatterns.length === 0) { + if (includePatterns.length === 0) { return null; } // Rejects absolute paths or relative paths to parents. - for (const pattern of allPatterns) { + for (const pattern of includePatterns) { + if (path.isAbsolute(pattern) || pattern.includes("..")) { + throw new Error(`Invalid override pattern (expected relative path not containing '..'): ${pattern}`); + } + if (pattern.endsWith("*")) { + endsWithWildcard = true; + } + } + for (const pattern of excludePatterns) { if (path.isAbsolute(pattern) || pattern.includes("..")) { throw new Error(`Invalid override pattern (expected relative path not containing '..'): ${pattern}`); } @@ -112,7 +120,11 @@ class OverrideTester { const includes = toMatcher(includePatterns); const excludes = toMatcher(excludePatterns); - return new OverrideTester([{ includes, excludes }], basePath); + return new OverrideTester( + [{ includes, excludes }], + basePath, + endsWithWildcard + ); } /** @@ -125,28 +137,44 @@ class OverrideTester { */ static and(a, b) { if (!b) { - return a && new OverrideTester(a.patterns, a.basePath); + return a && new OverrideTester( + a.patterns, + a.basePath, + a.endsWithWildcard + ); } if (!a) { - return new OverrideTester(b.patterns, b.basePath); + return new OverrideTester( + b.patterns, + b.basePath, + b.endsWithWildcard + ); } assert.strictEqual(a.basePath, b.basePath); - return new OverrideTester(a.patterns.concat(b.patterns), a.basePath); + return new OverrideTester( + a.patterns.concat(b.patterns), + a.basePath, + a.endsWithWildcard || b.endsWithWildcard + ); } /** * Initialize this instance. * @param {Pattern[]} patterns The matchers. * @param {string} basePath The base path. + * @param {boolean} endsWithWildcard If `true` then a pattern ends with `*`. */ - constructor(patterns, basePath) { + constructor(patterns, basePath, endsWithWildcard = false) { /** @type {Pattern[]} */ this.patterns = patterns; /** @type {string} */ this.basePath = basePath; + + /** @type {boolean} */ + this.endsWithWildcard = endsWithWildcard; } /** diff --git a/tools/node_modules/eslint/lib/cli-engine/file-enumerator.js b/tools/node_modules/eslint/lib/cli-engine/file-enumerator.js index c67e01aef9b1c8..16e5182ad8a450 100644 --- a/tools/node_modules/eslint/lib/cli-engine/file-enumerator.js +++ b/tools/node_modules/eslint/lib/cli-engine/file-enumerator.js @@ -88,7 +88,7 @@ const IGNORED = 2; * @typedef {Object} FileEnumeratorInternalSlots * @property {CascadingConfigArrayFactory} configArrayFactory The factory for config arrays. * @property {string} cwd The base directory to start lookup. - * @property {RegExp} extensionRegExp The RegExp to test if a string ends with specific file extensions. + * @property {RegExp|null} extensionRegExp The RegExp to test if a string ends with specific file extensions. * @property {boolean} globInputPaths Set to false to skip glob resolution of input file paths to lint (default: true). If false, each input file paths is assumed to be a non-glob path to an existing file. * @property {boolean} ignoreFlag The flag to check ignored files. * @property {(filePath:string, dot:boolean) => boolean} defaultIgnores The default predicate function to ignore files. @@ -127,12 +127,12 @@ function statSafeSync(filePath) { /** * Get filenames in a given path to a directory. * @param {string} directoryPath The path to target directory. - * @returns {string[]} The filenames. + * @returns {import("fs").Dirent[]} The filenames. * @private */ function readdirSafeSync(directoryPath) { try { - return fs.readdirSync(directoryPath); + return fs.readdirSync(directoryPath, { withFileTypes: true }); } catch (error) { /* istanbul ignore next */ if (error.code !== "ENOENT") { @@ -142,6 +142,27 @@ function readdirSafeSync(directoryPath) { } } +/** + * Create a `RegExp` object to detect extensions. + * @param {string[] | null} extensions The extensions to create. + * @returns {RegExp | null} The created `RegExp` object or null. + */ +function createExtensionRegExp(extensions) { + if (extensions) { + const normalizedExts = extensions.map(ext => escapeRegExp( + ext.startsWith(".") + ? ext.slice(1) + : ext + )); + + return new RegExp( + `.\\.(?:${normalizedExts.join("|")})$`, + "u" + ); + } + return null; +} + /** * The error type when no files match a glob. */ @@ -188,7 +209,7 @@ class FileEnumerator { constructor({ cwd = process.cwd(), configArrayFactory = new CascadingConfigArrayFactory({ cwd }), - extensions = [".js"], + extensions = null, globInputPaths = true, errorOnUnmatchedPattern = true, ignore = true @@ -197,17 +218,7 @@ class FileEnumerator { configArrayFactory, cwd, defaultIgnores: IgnorePattern.createDefaultIgnore(cwd), - extensionRegExp: new RegExp( - `.\\.(?:${extensions - .map(ext => escapeRegExp( - ext.startsWith(".") - ? ext.slice(1) - : ext - )) - .join("|") - })$`, - "u" - ), + extensionRegExp: createExtensionRegExp(extensions), globInputPaths, errorOnUnmatchedPattern, ignoreFlag: ignore @@ -215,11 +226,36 @@ class FileEnumerator { } /** - * The `RegExp` object that tests if a file path has the allowed file extensions. - * @type {RegExp} + * Check if a given file is target or not. + * @param {string} filePath The path to a candidate file. + * @param {ConfigArray} [providedConfig] Optional. The configuration for the file. + * @returns {boolean} `true` if the file is a target. */ - get extensionRegExp() { - return internalSlotsMap.get(this).extensionRegExp; + isTargetPath(filePath, providedConfig) { + const { + configArrayFactory, + extensionRegExp + } = internalSlotsMap.get(this); + + // If `--ext` option is present, use it. + if (extensionRegExp) { + return extensionRegExp.test(filePath); + } + + // `.js` file is target by default. + if (filePath.endsWith(".js")) { + return true; + } + + // use `overrides[].files` to check additional targets. + const config = + providedConfig || + configArrayFactory.getConfigArrayForFile( + filePath, + { ignoreNotFoundError: true } + ); + + return config.isAdditionalTargetPath(filePath); } /** @@ -380,18 +416,17 @@ class FileEnumerator { */ *_iterateFilesRecursive(directoryPath, options) { debug(`Enter the directory: ${directoryPath}`); - const { configArrayFactory, extensionRegExp } = internalSlotsMap.get(this); + const { configArrayFactory } = internalSlotsMap.get(this); /** @type {ConfigArray|null} */ let config = null; // Enumerate the files of this directory. - for (const filename of readdirSafeSync(directoryPath)) { - const filePath = path.join(directoryPath, filename); - const stat = statSafeSync(filePath); // TODO: Use `withFileTypes` in the future. + for (const entry of readdirSafeSync(directoryPath)) { + const filePath = path.join(directoryPath, entry.name); // Check if the file is matched. - if (stat && stat.isFile()) { + if (entry.isFile()) { if (!config) { config = configArrayFactory.getConfigArrayForFile( filePath, @@ -404,29 +439,30 @@ class FileEnumerator { { ignoreNotFoundError: true } ); } - const ignored = this._isIgnoredFile(filePath, { ...options, config }); - const flag = ignored ? IGNORED_SILENTLY : NONE; const matched = options.selector // Started with a glob pattern; choose by the pattern. ? options.selector.match(filePath) // Started with a directory path; choose by file extensions. - : extensionRegExp.test(filePath); + : this.isTargetPath(filePath, config); if (matched) { - debug(`Yield: ${filename}${ignored ? " but ignored" : ""}`); + const ignored = this._isIgnoredFile(filePath, { ...options, config }); + const flag = ignored ? IGNORED_SILENTLY : NONE; + + debug(`Yield: ${entry.name}${ignored ? " but ignored" : ""}`); yield { config: configArrayFactory.getConfigArrayForFile(filePath), filePath, flag }; } else { - debug(`Didn't match: ${filename}`); + debug(`Didn't match: ${entry.name}`); } // Dive into the sub directory. - } else if (options.recursive && stat && stat.isDirectory()) { + } else if (options.recursive && entry.isDirectory()) { if (!config) { config = configArrayFactory.getConfigArrayForFile( filePath, diff --git a/tools/node_modules/eslint/lib/cli-engine/formatters/junit.js b/tools/node_modules/eslint/lib/cli-engine/formatters/junit.js index c32425883f7cac..a994b4b1980eea 100644 --- a/tools/node_modules/eslint/lib/cli-engine/formatters/junit.js +++ b/tools/node_modules/eslint/lib/cli-engine/formatters/junit.js @@ -32,7 +32,7 @@ function getMessageType(message) { * @private */ function pathWithoutExt(filePath) { - return path.posix.join(path.posix.dirname(filePath), path.basename(filePath, path.extname(filePath))); + return path.join(path.dirname(filePath), path.basename(filePath, path.extname(filePath))); } //------------------------------------------------------------------------------ diff --git a/tools/node_modules/eslint/lib/cli.js b/tools/node_modules/eslint/lib/cli.js index 944b4b79353b3d..815ce68c22fe2e 100644 --- a/tools/node_modules/eslint/lib/cli.js +++ b/tools/node_modules/eslint/lib/cli.js @@ -17,7 +17,6 @@ const fs = require("fs"), path = require("path"), - mkdirp = require("mkdirp"), { CLIEngine } = require("./cli-engine"), options = require("./options"), log = require("./shared/logging"), @@ -115,7 +114,7 @@ function printResults(engine, results, format, outputFile) { } try { - mkdirp.sync(path.dirname(filePath)); + fs.mkdirSync(path.dirname(filePath), { recursive: true }); fs.writeFileSync(filePath, output); } catch (ex) { log.error("There was a problem writing the output file:\n%s", ex); diff --git a/tools/node_modules/eslint/lib/linter/linter.js b/tools/node_modules/eslint/lib/linter/linter.js index 6d88cb5aa1245f..76d35b49eefb55 100644 --- a/tools/node_modules/eslint/lib/linter/linter.js +++ b/tools/node_modules/eslint/lib/linter/linter.js @@ -267,6 +267,15 @@ function createDisableDirectives(options) { return result; } +/** + * Remove the ignored part from a given directive comment and trim it. + * @param {string} value The comment text to strip. + * @returns {string} The stripped text. + */ +function stripDirectiveComment(value) { + return value.split(/\s-{2,}\s/u)[0].trim(); +} + /** * Parses comments in file to extract file-specific config of rules, globals * and environments and merges them with global config; also code blocks @@ -286,7 +295,7 @@ function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) { const disableDirectives = []; ast.comments.filter(token => token.type !== "Shebang").forEach(comment => { - const trimmedCommentText = comment.value.trim(); + const trimmedCommentText = stripDirectiveComment(comment.value); const match = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(trimmedCommentText); if (!match) { @@ -444,8 +453,11 @@ function findEslintEnv(text) { eslintEnvPattern.lastIndex = 0; - while ((match = eslintEnvPattern.exec(text))) { - retv = Object.assign(retv || {}, commentParser.parseListConfig(match[1])); + while ((match = eslintEnvPattern.exec(text)) !== null) { + retv = Object.assign( + retv || {}, + commentParser.parseListConfig(stripDirectiveComment(match[1])) + ); } return retv; diff --git a/tools/node_modules/eslint/lib/rule-tester/rule-tester.js b/tools/node_modules/eslint/lib/rule-tester/rule-tester.js index 44e01dadf09b5d..2ac26534fcc0ea 100644 --- a/tools/node_modules/eslint/lib/rule-tester/rule-tester.js +++ b/tools/node_modules/eslint/lib/rule-tester/rule-tester.js @@ -50,6 +50,52 @@ const const ajv = require("../shared/ajv")({ strictDefaults: true }); + +//------------------------------------------------------------------------------ +// Typedefs +//------------------------------------------------------------------------------ + +/** + * A test case that is expected to pass lint. + * @typedef {Object} ValidTestCase + * @property {string} code Code for the test case. + * @property {any[]} [options] Options for the test case. + * @property {{ [name: string]: any }} [settings] Settings for the test case. + * @property {string} [filename] The fake filename for the test case. Useful for rules that make assertion about filenames. + * @property {string} [parser] The absolute path for the parser. + * @property {{ [name: string]: any }} [parserOptions] Options for the parser. + * @property {{ [name: string]: "readonly" | "writable" | "off" }} [globals] The additional global variables. + * @property {{ [name: string]: boolean }} [env] Environments for the test case. + */ + +/** + * A test case that is expected to fail lint. + * @typedef {Object} InvalidTestCase + * @property {string} code Code for the test case. + * @property {number | Array} errors Expected errors. + * @property {string | null} [output] The expected code after autofixes are applied. If set to `null`, the test runner will assert that no autofix is suggested. + * @property {any[]} [options] Options for the test case. + * @property {{ [name: string]: any }} [settings] Settings for the test case. + * @property {string} [filename] The fake filename for the test case. Useful for rules that make assertion about filenames. + * @property {string} [parser] The absolute path for the parser. + * @property {{ [name: string]: any }} [parserOptions] Options for the parser. + * @property {{ [name: string]: "readonly" | "writable" | "off" }} [globals] The additional global variables. + * @property {{ [name: string]: boolean }} [env] Environments for the test case. + */ + +/** + * A description of a reported error used in a rule tester test. + * @typedef {Object} TestCaseError + * @property {string | RegExp} [message] Message. + * @property {string} [messageId] Message ID. + * @property {string} [type] The type of the reported AST node. + * @property {{ [name: string]: string }} [data] The data used to fill the message template. + * @property {number} [line] The 1-based line number of the reported start location. + * @property {number} [column] The 1-based column number of the reported start location. + * @property {number} [endLine] The 1-based line number of the reported end location. + * @property {number} [endColumn] The 1-based column number of the reported end location. + */ + //------------------------------------------------------------------------------ // Private Members //------------------------------------------------------------------------------ @@ -128,7 +174,7 @@ function freezeDeeply(x) { */ function sanitize(text) { return text.replace( - /[\u0000-\u0009|\u000b-\u001a]/gu, // eslint-disable-line no-control-regex + /[\u0000-\u0009\u000b-\u001a]/gu, // eslint-disable-line no-control-regex c => `\\u${c.codePointAt(0).toString(16).padStart(4, "0")}` ); } @@ -273,7 +319,10 @@ class RuleTester { * Adds a new rule test to execute. * @param {string} ruleName The name of the rule to run. * @param {Function} rule The rule to test. - * @param {Object} test The collection of tests to run. + * @param {{ + * valid: (ValidTestCase | string)[], + * invalid: InvalidTestCase[] + * }} test The collection of tests to run. * @returns {void} */ run(ruleName, rule, test) { diff --git a/tools/node_modules/eslint/lib/rules/array-callback-return.js b/tools/node_modules/eslint/lib/rules/array-callback-return.js index d632a3f30c28a3..6e425dcdcb89da 100644 --- a/tools/node_modules/eslint/lib/rules/array-callback-return.js +++ b/tools/node_modules/eslint/lib/rules/array-callback-return.js @@ -18,7 +18,7 @@ const astUtils = require("./utils/ast-utils"); //------------------------------------------------------------------------------ const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/u; -const TARGET_METHODS = /^(?:every|filter|find(?:Index)?|map|reduce(?:Right)?|some|sort)$/u; +const TARGET_METHODS = /^(?:every|filter|find(?:Index)?|flatMap|map|reduce(?:Right)?|some|sort)$/u; /** * Checks a given code path segment is reachable. diff --git a/tools/node_modules/eslint/lib/rules/array-element-newline.js b/tools/node_modules/eslint/lib/rules/array-element-newline.js index 1da67667bee849..b7a967865b92a1 100644 --- a/tools/node_modules/eslint/lib/rules/array-element-newline.js +++ b/tools/node_modules/eslint/lib/rules/array-element-newline.js @@ -24,28 +24,52 @@ module.exports = { fixable: "whitespace", - schema: [ - { - oneOf: [ - { - enum: ["always", "never", "consistent"] - }, - { - type: "object", - properties: { - multiline: { - type: "boolean" + schema: { + definitions: { + basicConfig: { + oneOf: [ + { + enum: ["always", "never", "consistent"] + }, + { + type: "object", + properties: { + multiline: { + type: "boolean" + }, + minItems: { + type: ["integer", "null"], + minimum: 0 + } }, - minItems: { - type: ["integer", "null"], - minimum: 0 - } + additionalProperties: false + } + ] + } + }, + items: [ + { + oneOf: [ + { + $ref: "#/definitions/basicConfig" }, - additionalProperties: false - } - ] - } - ], + { + type: "object", + properties: { + ArrayExpression: { + $ref: "#/definitions/basicConfig" + }, + ArrayPattern: { + $ref: "#/definitions/basicConfig" + } + }, + additionalProperties: false, + minProperties: 1 + } + ] + } + ] + }, messages: { unexpectedLineBreak: "There should be no linebreak here.", @@ -93,6 +117,20 @@ module.exports = { * @returns {{ArrayExpression: {multiline: boolean, minItems: number}, ArrayPattern: {multiline: boolean, minItems: number}}} Normalized option object. */ function normalizeOptions(options) { + if (options && (options.ArrayExpression || options.ArrayPattern)) { + let expressionOptions, patternOptions; + + if (options.ArrayExpression) { + expressionOptions = normalizeOptionValue(options.ArrayExpression); + } + + if (options.ArrayPattern) { + patternOptions = normalizeOptionValue(options.ArrayPattern); + } + + return { ArrayExpression: expressionOptions, ArrayPattern: patternOptions }; + } + const value = normalizeOptionValue(options); return { ArrayExpression: value, ArrayPattern: value }; @@ -177,6 +215,10 @@ module.exports = { const normalizedOptions = normalizeOptions(context.options[0]); const options = normalizedOptions[node.type]; + if (!options) { + return; + } + let elementBreak = false; /* diff --git a/tools/node_modules/eslint/lib/rules/computed-property-spacing.js b/tools/node_modules/eslint/lib/rules/computed-property-spacing.js index a0bd7f48ced66b..48bea6a6fdc8f4 100644 --- a/tools/node_modules/eslint/lib/rules/computed-property-spacing.js +++ b/tools/node_modules/eslint/lib/rules/computed-property-spacing.js @@ -67,7 +67,7 @@ module.exports = { function reportNoBeginningSpace(node, token, tokenAfter) { context.report({ node, - loc: token.loc.start, + loc: { start: token.loc.end, end: tokenAfter.loc.start }, messageId: "unexpectedSpaceAfter", data: { tokenValue: token.value @@ -88,7 +88,7 @@ module.exports = { function reportNoEndingSpace(node, token, tokenBefore) { context.report({ node, - loc: token.loc.start, + loc: { start: tokenBefore.loc.end, end: token.loc.start }, messageId: "unexpectedSpaceBefore", data: { tokenValue: token.value @@ -108,7 +108,7 @@ module.exports = { function reportRequiredBeginningSpace(node, token) { context.report({ node, - loc: token.loc.start, + loc: token.loc, messageId: "missingSpaceAfter", data: { tokenValue: token.value @@ -128,7 +128,7 @@ module.exports = { function reportRequiredEndingSpace(node, token) { context.report({ node, - loc: token.loc.start, + loc: token.loc, messageId: "missingSpaceBefore", data: { tokenValue: token.value diff --git a/tools/node_modules/eslint/lib/rules/default-case-last.js b/tools/node_modules/eslint/lib/rules/default-case-last.js new file mode 100644 index 00000000000000..80c5d6bda73958 --- /dev/null +++ b/tools/node_modules/eslint/lib/rules/default-case-last.js @@ -0,0 +1,44 @@ +/** + * @fileoverview Rule to enforce default clauses in switch statements to be last + * @author Milos Djermanovic + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: "suggestion", + + docs: { + description: "enforce default clauses in switch statements to be last", + category: "Best Practices", + recommended: false, + url: "https://eslint.org/docs/rules/default-case-last" + }, + + schema: [], + + messages: { + notLast: "Default clause should be the last clause." + } + }, + + create(context) { + return { + SwitchStatement(node) { + const cases = node.cases, + indexOfDefault = cases.findIndex(c => c.test === null); + + if (indexOfDefault !== -1 && indexOfDefault !== cases.length - 1) { + const defaultClause = cases[indexOfDefault]; + + context.report({ node: defaultClause, messageId: "notLast" }); + } + } + }; + } +}; diff --git a/tools/node_modules/eslint/lib/rules/id-blacklist.js b/tools/node_modules/eslint/lib/rules/id-blacklist.js index 53be62e68a3626..e5dcdc63091568 100644 --- a/tools/node_modules/eslint/lib/rules/id-blacklist.js +++ b/tools/node_modules/eslint/lib/rules/id-blacklist.js @@ -61,9 +61,12 @@ module.exports = { * @returns {boolean} whether an error should be reported or not */ function shouldReport(effectiveParent, name) { - return effectiveParent.type !== "CallExpression" && + return ( + effectiveParent.type !== "CallExpression" && effectiveParent.type !== "NewExpression" && - isInvalid(name); + effectiveParent.parent.type !== "ObjectPattern" && + isInvalid(name) + ); } /** @@ -98,11 +101,11 @@ module.exports = { report(node); } - // Report AssignmentExpressions only if they are the left side of the assignment + // Report AssignmentExpressions only if they are the left side of the assignment } else if (effectiveParent.type === "AssignmentExpression" && (effectiveParent.right.type !== "MemberExpression" || - effectiveParent.left.type === "MemberExpression" && - effectiveParent.left.property.name === node.name)) { + effectiveParent.left.type === "MemberExpression" && + effectiveParent.left.property.name === node.name)) { if (isInvalid(name)) { report(node); } @@ -115,7 +118,7 @@ module.exports = { report(node); } - // Report anything that is a match and not a CallExpression + // Report anything that is a match and not a CallExpression } else if (shouldReport(effectiveParent, name)) { report(node); } diff --git a/tools/node_modules/eslint/lib/rules/indent.js b/tools/node_modules/eslint/lib/rules/indent.js index 694cf7d9e6ed4f..d576fde0382461 100644 --- a/tools/node_modules/eslint/lib/rules/indent.js +++ b/tools/node_modules/eslint/lib/rules/indent.js @@ -540,8 +540,15 @@ module.exports = { ] }, outerIIFEBody: { - type: "integer", - minimum: 0 + oneOf: [ + { + type: "integer", + minimum: 0 + }, + { + enum: ["off"] + } + ] }, MemberExpression: { oneOf: [ @@ -590,6 +597,10 @@ module.exports = { type: "boolean", default: false }, + offsetTernaryExpressions: { + type: "boolean", + default: false + }, ignoredNodes: { type: "array", items: { @@ -922,7 +933,11 @@ module.exports = { parameterParens.add(openingParen); parameterParens.add(closingParen); - offsets.setDesiredOffset(openingParen, sourceCode.getTokenBefore(openingParen), 0); + + const offsetAfterToken = node.callee.type === "TaggedTemplateExpression" ? sourceCode.getFirstToken(node.callee.quasi) : openingParen; + const offsetToken = sourceCode.getTokenBefore(offsetAfterToken); + + offsets.setDesiredOffset(openingParen, offsetToken, 0); addElementListIndent(node.arguments, openingParen, closingParen, options.CallExpression.arguments); } @@ -1088,7 +1103,6 @@ module.exports = { }, "BlockStatement, ClassBody"(node) { - let blockIndentLevel; if (node.parent && isOuterIIFE(node.parent)) { @@ -1108,6 +1122,7 @@ module.exports = { if (!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)) { offsets.setDesiredOffset(sourceCode.getFirstToken(node), sourceCode.getFirstToken(node.parent), 0); } + addElementListIndent(node.body, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), blockIndentLevel); }, @@ -1142,7 +1157,8 @@ module.exports = { offsets.setDesiredOffset(questionMarkToken, firstToken, 1); offsets.setDesiredOffset(colonToken, firstToken, 1); - offsets.setDesiredOffset(firstConsequentToken, firstToken, 1); + offsets.setDesiredOffset(firstConsequentToken, firstToken, + options.offsetTernaryExpressions ? 2 : 1); /* * The alternate and the consequent should usually have the same indentation. @@ -1167,7 +1183,9 @@ module.exports = { * If `baz` were aligned with `bar` rather than being offset by 1 from `foo`, `baz` would end up * having no expected indentation. */ - offsets.setDesiredOffset(firstAlternateToken, firstToken, 1); + offsets.setDesiredOffset(firstAlternateToken, firstToken, + firstAlternateToken.type === "Punctuator" && + options.offsetTernaryExpressions ? 2 : 1); } } }, diff --git a/tools/node_modules/eslint/lib/rules/index.js b/tools/node_modules/eslint/lib/rules/index.js index d3fbe412080360..7f563eb2ebfb96 100644 --- a/tools/node_modules/eslint/lib/rules/index.js +++ b/tools/node_modules/eslint/lib/rules/index.js @@ -37,6 +37,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({ "constructor-super": () => require("./constructor-super"), curly: () => require("./curly"), "default-case": () => require("./default-case"), + "default-case-last": () => require("./default-case-last"), "default-param-last": () => require("./default-param-last"), "dot-location": () => require("./dot-location"), "dot-notation": () => require("./dot-notation"), @@ -178,6 +179,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({ "no-prototype-builtins": () => require("./no-prototype-builtins"), "no-redeclare": () => require("./no-redeclare"), "no-regex-spaces": () => require("./no-regex-spaces"), + "no-restricted-exports": () => require("./no-restricted-exports"), "no-restricted-globals": () => require("./no-restricted-globals"), "no-restricted-imports": () => require("./no-restricted-imports"), "no-restricted-modules": () => require("./no-restricted-modules"), @@ -215,6 +217,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({ "no-unused-labels": () => require("./no-unused-labels"), "no-unused-vars": () => require("./no-unused-vars"), "no-use-before-define": () => require("./no-use-before-define"), + "no-useless-backreference": () => require("./no-useless-backreference"), "no-useless-call": () => require("./no-useless-call"), "no-useless-catch": () => require("./no-useless-catch"), "no-useless-computed-key": () => require("./no-useless-computed-key"), diff --git a/tools/node_modules/eslint/lib/rules/key-spacing.js b/tools/node_modules/eslint/lib/rules/key-spacing.js index 6d1b9121c78c5f..c405043794c7d1 100644 --- a/tools/node_modules/eslint/lib/rules/key-spacing.js +++ b/tools/node_modules/eslint/lib/rules/key-spacing.js @@ -414,8 +414,7 @@ module.exports = { if (property.computed) { return sourceCode.getText().slice(key.range[0], key.range[1]); } - - return property.key.name || property.key.value; + return astUtils.getStaticPropertyName(property); } /** diff --git a/tools/node_modules/eslint/lib/rules/max-len.js b/tools/node_modules/eslint/lib/rules/max-len.js index b29099ed4c4f09..82229c3be4894a 100644 --- a/tools/node_modules/eslint/lib/rules/max-len.js +++ b/tools/node_modules/eslint/lib/rules/max-len.js @@ -183,6 +183,21 @@ module.exports = { (end.line > lineNumber || (end.line === lineNumber && end.column === line.length)); } + /** + * Check if a node is a JSXEmptyExpression contained in a single line JSXExpressionContainer. + * @param {ASTNode} node A node to check. + * @returns {boolean} True if the node is a JSXEmptyExpression contained in a single line JSXExpressionContainer. + */ + function isJSXEmptyExpressionInSingleLineContainer(node) { + if (!node || !node.parent || node.type !== "JSXEmptyExpression" || node.parent.type !== "JSXExpressionContainer") { + return false; + } + + const parent = node.parent; + + return parent.loc.start.line === parent.loc.end.line; + } + /** * Gets the line after the comment and any remaining trailing whitespace is * stripped. @@ -252,6 +267,33 @@ module.exports = { return acc; } + /** + * Returns an array of all comments in the source code. + * If the element in the array is a JSXEmptyExpression contained with a single line JSXExpressionContainer, + * the element is changed with JSXExpressionContainer node. + * @returns {ASTNode[]} An array of comment nodes + */ + function getAllComments() { + const comments = []; + + sourceCode.getAllComments() + .forEach(commentNode => { + const containingNode = sourceCode.getNodeByRangeIndex(commentNode.range[0]); + + if (isJSXEmptyExpressionInSingleLineContainer(containingNode)) { + + // push a unique node only + if (comments[comments.length - 1] !== containingNode.parent) { + comments.push(containingNode.parent); + } + } else { + comments.push(commentNode); + } + }); + + return comments; + } + /** * Check the program for max length * @param {ASTNode} node Node to examine @@ -264,7 +306,7 @@ module.exports = { const lines = sourceCode.lines, // list of comments to ignore - comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? sourceCode.getAllComments() : []; + comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? getAllComments() : []; // we iterate over comments in parallel with the lines let commentsIndex = 0; diff --git a/tools/node_modules/eslint/lib/rules/max-lines-per-function.js b/tools/node_modules/eslint/lib/rules/max-lines-per-function.js index 0cfc1f8da9e65e..03539fae470078 100644 --- a/tools/node_modules/eslint/lib/rules/max-lines-per-function.js +++ b/tools/node_modules/eslint/lib/rules/max-lines-per-function.js @@ -54,9 +54,6 @@ const OPTIONS_OR_INTEGER_SCHEMA = { function getCommentLineNumbers(comments) { const map = new Map(); - if (!comments) { - return map; - } comments.forEach(comment => { for (let i = comment.loc.start.line; i <= comment.loc.end.line; i++) { map.set(i, comment); diff --git a/tools/node_modules/eslint/lib/rules/new-cap.js b/tools/node_modules/eslint/lib/rules/new-cap.js index cee979310ea7cc..7cce968c5aed0e 100644 --- a/tools/node_modules/eslint/lib/rules/new-cap.js +++ b/tools/node_modules/eslint/lib/rules/new-cap.js @@ -9,6 +9,8 @@ // Requirements //------------------------------------------------------------------------------ +const astUtils = require("./utils/ast-utils"); + //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ @@ -160,13 +162,7 @@ module.exports = { let name = ""; if (node.callee.type === "MemberExpression") { - const property = node.callee.property; - - if (property.type === "Literal" && (typeof property.value === "string")) { - name = property.value; - } else if (property.type === "Identifier" && !node.callee.computed) { - name = property.name; - } + name = astUtils.getStaticPropertyName(node.callee) || ""; } else { name = node.callee.name; } diff --git a/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js b/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js index 6041e9e371ce5e..55639746b27590 100644 --- a/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js +++ b/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js @@ -5,6 +5,8 @@ "use strict"; +const astUtils = require("./utils/ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -53,21 +55,6 @@ module.exports = { return stateMap[key][isStatic ? "static" : "nonStatic"]; } - /** - * Gets the name text of a given node. - * @param {ASTNode} node A node to get the name. - * @returns {string} The name text of the node. - */ - function getName(node) { - switch (node.type) { - case "Identifier": return node.name; - case "Literal": return String(node.value); - - /* istanbul ignore next: syntax error */ - default: return ""; - } - } - return { // Initializes the stack of state of member declarations. @@ -91,7 +78,7 @@ module.exports = { return; } - const name = getName(node.key); + const name = astUtils.getStaticPropertyName(node) || ""; const state = getState(name, node.static); let isDuplicate = false; 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 f96e572bfeef54..e70353576bb950 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-parens.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-parens.js @@ -169,6 +169,28 @@ module.exports = { return ruleApplies(node) && isParenthesisedTwice(node); } + /** + * Determines if a node that is expected to be parenthesised is surrounded by + * (potentially) invalid extra parentheses with considering precedence level of the node. + * If the preference level of the node is not higher or equal to precedence lower limit, it also checks + * whether the node is surrounded by parentheses twice or not. + * @param {ASTNode} node The node to be checked. + * @param {number} precedenceLowerLimit The lower limit of precedence. + * @returns {boolean} True if the node is has an unexpected extra pair of parentheses. + * @private + */ + function hasExcessParensWithPrecedence(node, precedenceLowerLimit) { + if (ruleApplies(node) && isParenthesised(node)) { + if ( + precedence(node) >= precedenceLowerLimit || + isParenthesisedTwice(node) + ) { + return true; + } + } + return false; + } + /** * Determines if a node test expression is allowed to have a parenthesised assignment * @param {ASTNode} node The node to be checked. @@ -320,6 +342,17 @@ module.exports = { return node.type === "CallExpression" && node.callee.type === "FunctionExpression"; } + /** + * Determines if the given node can be the assignment target in destructuring or the LHS of an assignment. + * This is to avoid an autofix that could change behavior because parsers mistakenly allow invalid syntax, + * such as `(a = b) = c` and `[(a = b) = c] = []`. Ideally, this function shouldn't be necessary. + * @param {ASTNode} [node] The node to check + * @returns {boolean} `true` if the given node can be a valid assignment target + */ + function canBeAssignmentTarget(node) { + return node && (node.type === "Identifier" || node.type === "MemberExpression"); + } + /** * Report the node * @param {ASTNode} node node to evaluate @@ -370,17 +403,13 @@ module.exports = { } /** - * Evaluate Unary update + * Evaluate a argument of the node. * @param {ASTNode} node node to evaluate * @returns {void} * @private */ - function checkUnaryUpdate(node) { - if (node.type === "UnaryExpression" && node.argument.type === "BinaryExpression" && node.argument.operator === "**") { - return; - } - - if (hasExcessParens(node.argument) && precedence(node.argument) >= precedence(node)) { + function checkArgumentWithPrecedence(node) { + if (hasExcessParensWithPrecedence(node.argument, precedence(node))) { report(node.argument); } } @@ -411,25 +440,24 @@ module.exports = { function checkCallNew(node) { const callee = node.callee; - if (hasExcessParens(callee) && precedence(callee) >= precedence(node)) { + if (hasExcessParensWithPrecedence(callee, precedence(node))) { const hasNewParensException = callee.type === "NewExpression" && !isNewExpressionWithParens(callee); if ( hasDoubleExcessParens(callee) || !isIIFE(node) && !hasNewParensException && !( - /* - * Allow extra parens around a new expression if - * there are intervening parentheses. - */ - (callee.type === "MemberExpression" && doesMemberExpressionContainCallExpression(callee)) + // Allow extra parens around a new expression if they are intervening parentheses. + node.type === "NewExpression" && + callee.type === "MemberExpression" && + doesMemberExpressionContainCallExpression(callee) ) ) { report(node.callee); } } node.arguments - .filter(arg => hasExcessParens(arg) && precedence(arg) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) + .filter(arg => hasExcessParensWithPrecedence(arg, PRECEDENCE_OF_ASSIGNMENT_EXPR)) .forEach(report); } @@ -444,15 +472,26 @@ module.exports = { const leftPrecedence = precedence(node.left); const rightPrecedence = precedence(node.right); const isExponentiation = node.operator === "**"; - const shouldSkipLeft = (NESTED_BINARY && (node.left.type === "BinaryExpression" || node.left.type === "LogicalExpression")) || - node.left.type === "UnaryExpression" && isExponentiation; + const shouldSkipLeft = NESTED_BINARY && (node.left.type === "BinaryExpression" || node.left.type === "LogicalExpression"); const shouldSkipRight = NESTED_BINARY && (node.right.type === "BinaryExpression" || node.right.type === "LogicalExpression"); - if (!shouldSkipLeft && hasExcessParens(node.left) && (leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation))) { - report(node.left); + if (!shouldSkipLeft && hasExcessParens(node.left)) { + if ( + !(node.left.type === "UnaryExpression" && isExponentiation) && + (leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation)) || + isParenthesisedTwice(node.left) + ) { + report(node.left); + } } - if (!shouldSkipRight && hasExcessParens(node.right) && (rightPrecedence > prec || (rightPrecedence === prec && isExponentiation))) { - report(node.right); + + if (!shouldSkipRight && hasExcessParens(node.right)) { + if ( + (rightPrecedence > prec || (rightPrecedence === prec && isExponentiation)) || + isParenthesisedTwice(node.right) + ) { + report(node.right); + } } } @@ -485,11 +524,7 @@ module.exports = { * @returns {void} */ function checkSpreadOperator(node) { - const hasExtraParens = precedence(node.argument) >= PRECEDENCE_OF_ASSIGNMENT_EXPR - ? hasExcessParens(node.argument) - : hasDoubleExcessParens(node.argument); - - if (hasExtraParens) { + if (hasExcessParensWithPrecedence(node.argument, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(node.argument); } } @@ -651,7 +686,13 @@ module.exports = { return { ArrayExpression(node) { node.elements - .filter(e => e && hasExcessParens(e) && precedence(e) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) + .filter(e => e && hasExcessParensWithPrecedence(e, PRECEDENCE_OF_ASSIGNMENT_EXPR)) + .forEach(report); + }, + + ArrayPattern(node) { + node.elements + .filter(e => canBeAssignmentTarget(e) && hasExcessParens(e)) .forEach(report); }, @@ -674,18 +715,18 @@ module.exports = { if (astUtils.isOpeningParenToken(tokenBeforeFirst) && astUtils.isOpeningBraceToken(firstBodyToken)) { tokensToIgnore.add(firstBodyToken); } - if (hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + if (hasExcessParensWithPrecedence(node.body, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(node.body); } } }, AssignmentExpression(node) { - if (isReturnAssignException(node)) { - return; + if (canBeAssignmentTarget(node.left) && hasExcessParens(node.left)) { + report(node.left); } - if (hasExcessParens(node.right) && precedence(node.right) >= precedence(node)) { + if (!isReturnAssignException(node) && hasExcessParensWithPrecedence(node.right, precedence(node))) { report(node.right); } }, @@ -702,8 +743,8 @@ module.exports = { ClassBody(node) { node.body - .filter(member => member.type === "MethodDefinition" && member.computed && - member.key && hasExcessParens(member.key) && precedence(member.key) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) + .filter(member => member.type === "MethodDefinition" && member.computed && member.key) + .filter(member => hasExcessParensWithPrecedence(member.key, PRECEDENCE_OF_ASSIGNMENT_EXPR)) .forEach(member => report(member.key)); }, @@ -711,16 +752,18 @@ module.exports = { if (isReturnAssignException(node)) { return; } - - if (hasExcessParens(node.test) && precedence(node.test) >= precedence({ type: "LogicalExpression", operator: "||" })) { + if ( + !isCondAssignException(node) && + hasExcessParensWithPrecedence(node.test, precedence({ type: "LogicalExpression", operator: "||" })) + ) { report(node.test); } - if (hasExcessParens(node.consequent) && precedence(node.consequent) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + if (hasExcessParensWithPrecedence(node.consequent, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(node.consequent); } - if (hasExcessParens(node.alternate) && precedence(node.alternate) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + if (hasExcessParensWithPrecedence(node.alternate, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(node.alternate); } }, @@ -757,9 +800,19 @@ module.exports = { tokensToIgnore.add(firstLeftToken); } } - if (!(node.type === "ForOfStatement" && node.right.type === "SequenceExpression") && hasExcessParens(node.right)) { + + if (node.type === "ForOfStatement") { + const hasExtraParens = node.right.type === "SequenceExpression" + ? hasDoubleExcessParens(node.right) + : hasExcessParens(node.right); + + if (hasExtraParens) { + report(node.right); + } + } else if (hasExcessParens(node.right)) { report(node.right); } + if (hasExcessParens(node.left)) { report(node.left); } @@ -910,11 +963,17 @@ module.exports = { NewExpression: checkCallNew, ObjectExpression(node) { + node.properties + .filter(property => property.value && hasExcessParensWithPrecedence(property.value, PRECEDENCE_OF_ASSIGNMENT_EXPR)) + .forEach(property => report(property.value)); + }, + + ObjectPattern(node) { node.properties .filter(property => { const value = property.value; - return value && hasExcessParens(value) && precedence(value) >= PRECEDENCE_OF_ASSIGNMENT_EXPR; + return canBeAssignmentTarget(value) && hasExcessParens(value); }).forEach(property => report(property.value)); }, @@ -922,12 +981,20 @@ module.exports = { if (node.computed) { const { key } = node; - if (key && hasExcessParens(key) && precedence(key) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + if (key && hasExcessParensWithPrecedence(key, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(key); } } }, + RestElement(node) { + const argument = node.argument; + + if (canBeAssignmentTarget(argument) && hasExcessParens(argument)) { + report(argument); + } + }, + ReturnStatement(node) { const returnToken = sourceCode.getFirstToken(node); @@ -945,8 +1012,10 @@ module.exports = { }, SequenceExpression(node) { + const precedenceOfNode = precedence(node); + node.expressions - .filter(e => hasExcessParens(e) && precedence(e) >= precedence(node)) + .filter(e => hasExcessParensWithPrecedence(e, precedenceOfNode)) .forEach(report); }, @@ -970,16 +1039,17 @@ module.exports = { } }, - UnaryExpression: checkUnaryUpdate, - UpdateExpression: checkUnaryUpdate, - AwaitExpression: checkUnaryUpdate, + UnaryExpression: checkArgumentWithPrecedence, + UpdateExpression: checkArgumentWithPrecedence, + AwaitExpression: checkArgumentWithPrecedence, VariableDeclarator(node) { - if (node.init && hasExcessParens(node.init) && - precedence(node.init) >= PRECEDENCE_OF_ASSIGNMENT_EXPR && + if ( + node.init && hasExcessParensWithPrecedence(node.init, PRECEDENCE_OF_ASSIGNMENT_EXPR) && - // RegExp literal is allowed to have parens (#1589) - !(node.init.type === "Literal" && node.init.regex)) { + // RegExp literal is allowed to have parens (#1589) + !(node.init.type === "Literal" && node.init.regex) + ) { report(node.init); } }, @@ -1022,9 +1092,13 @@ module.exports = { }, AssignmentPattern(node) { - const { right } = node; + const { left, right } = node; + + if (canBeAssignmentTarget(left) && hasExcessParens(left)) { + report(left); + } - if (right && hasExcessParens(right) && precedence(right) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + if (right && hasExcessParensWithPrecedence(right, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(right); } } diff --git a/tools/node_modules/eslint/lib/rules/no-func-assign.js b/tools/node_modules/eslint/lib/rules/no-func-assign.js index 66756e62bef5b2..33d0ad9ecd1433 100644 --- a/tools/node_modules/eslint/lib/rules/no-func-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-func-assign.js @@ -22,7 +22,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-func-assign" }, - schema: [] + schema: [], + + messages: { + isAFunction: "'{{name}}' is a function." + } }, create(context) { @@ -34,7 +38,13 @@ module.exports = { */ function checkReference(references) { astUtils.getModifyingReferences(references).forEach(reference => { - context.report({ node: reference.identifier, message: "'{{name}}' is a function.", data: { name: reference.identifier.name } }); + context.report({ + node: reference.identifier, + messageId: "isAFunction", + data: { + name: reference.identifier.name + } + }); }); } diff --git a/tools/node_modules/eslint/lib/rules/no-global-assign.js b/tools/node_modules/eslint/lib/rules/no-global-assign.js index 4ab0c706446256..ea854c4aa8cd9b 100644 --- a/tools/node_modules/eslint/lib/rules/no-global-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-global-assign.js @@ -32,7 +32,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + globalShouldNotBeModified: "Read-only global '{{name}}' should not be modified." + } }, create(context) { @@ -60,8 +64,10 @@ module.exports = { ) { context.report({ node: identifier, - message: "Read-only global '{{name}}' should not be modified.", - data: identifier + messageId: "globalShouldNotBeModified", + data: { + name: identifier.name + } }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js b/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js index c80f9813020be5..6d5ee61e96bd5b 100644 --- a/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js +++ b/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js @@ -187,7 +187,11 @@ module.exports = { } }, additionalProperties: false - }] + }], + + messages: { + useRecommendation: "use `{{recommendation}}` instead." + } }, create(context) { @@ -204,7 +208,7 @@ module.exports = { function report(node, recommendation, shouldFix) { context.report({ node, - message: "use `{{recommendation}}` instead.", + messageId: "useRecommendation", data: { recommendation }, diff --git a/tools/node_modules/eslint/lib/rules/no-implied-eval.js b/tools/node_modules/eslint/lib/rules/no-implied-eval.js index e0764d8223db0a..46bb5d4f76e5f7 100644 --- a/tools/node_modules/eslint/lib/rules/no-implied-eval.js +++ b/tools/node_modules/eslint/lib/rules/no-implied-eval.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-implied-eval" }, - schema: [] + schema: [], + + messages: { + impliedEval: "Implied eval. Consider passing a function instead of a string." + } }, create(context) { @@ -107,7 +111,10 @@ module.exports = { // remove the entire substack, to avoid duplicate reports const substack = impliedEvalAncestorsStack.pop(); - context.report({ node: substack[0], message: "Implied eval. Consider passing a function instead of a string." }); + context.report({ + node: substack[0], + messageId: "impliedEval" + }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-inline-comments.js b/tools/node_modules/eslint/lib/rules/no-inline-comments.js index bd226ecc35fde1..41b0f1e664c776 100644 --- a/tools/node_modules/eslint/lib/rules/no-inline-comments.js +++ b/tools/node_modules/eslint/lib/rules/no-inline-comments.js @@ -21,7 +21,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-inline-comments" }, - schema: [] + schema: [], + + messages: { + unexpectedInlineComment: "Unexpected comment inline with code." + } }, create(context) { @@ -64,7 +68,10 @@ module.exports = { return; } - context.report({ node, message: "Unexpected comment inline with code." }); + context.report({ + node, + messageId: "unexpectedInlineComment" + }); } //-------------------------------------------------------------------------- diff --git a/tools/node_modules/eslint/lib/rules/no-inner-declarations.js b/tools/node_modules/eslint/lib/rules/no-inner-declarations.js index 60508d3e864eda..e1c29e0a3b4f3f 100644 --- a/tools/node_modules/eslint/lib/rules/no-inner-declarations.js +++ b/tools/node_modules/eslint/lib/rules/no-inner-declarations.js @@ -24,7 +24,11 @@ module.exports = { { enum: ["functions", "both"] } - ] + ], + + messages: { + moveDeclToRoot: "Move {{type}} declaration to {{body}} root." + } }, create(context) { @@ -68,7 +72,7 @@ module.exports = { if (!valid) { context.report({ node, - message: "Move {{type}} declaration to {{body}} root.", + messageId: "moveDeclToRoot", data: { type: (node.type === "FunctionDeclaration" ? "function" : "variable"), body: (body.type === "Program" ? "program" : "function body") diff --git a/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js b/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js index 852efbbb935b90..4ede995891bbca 100644 --- a/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js +++ b/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js @@ -40,6 +40,8 @@ module.exports = { }, additionalProperties: false }] + + // no messages, because the error text comes directly from the regexpp module }, create(context) { diff --git a/tools/node_modules/eslint/lib/rules/no-invalid-this.js b/tools/node_modules/eslint/lib/rules/no-invalid-this.js index 5398fc3b5f842c..a79c586d719852 100644 --- a/tools/node_modules/eslint/lib/rules/no-invalid-this.js +++ b/tools/node_modules/eslint/lib/rules/no-invalid-this.js @@ -37,7 +37,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedThis: "Unexpected 'this'." + } }, create(context) { @@ -130,7 +134,10 @@ module.exports = { const current = stack.getCurrent(); if (current && !current.valid) { - context.report({ node, message: "Unexpected 'this'." }); + context.report({ + node, + messageId: "unexpectedThis" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js b/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js index f339fa6c8f34c9..fa72c3ee72fcdc 100644 --- a/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js +++ b/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js @@ -59,7 +59,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + noIrregularWhitespace: "Irregular whitespace not allowed." + } }, create(context) { @@ -161,7 +165,11 @@ module.exports = { column: match.index }; - errors.push({ node, message: "Irregular whitespace not allowed.", loc: location }); + errors.push({ + node, + messageId: "noIrregularWhitespace", + loc: location + }); } }); } @@ -186,7 +194,11 @@ module.exports = { column: sourceLines[lineIndex].length }; - errors.push({ node, message: "Irregular whitespace not allowed.", loc: location }); + errors.push({ + node, + messageId: "noIrregularWhitespace", + loc: location + }); lastLineIndex = lineIndex; } } diff --git a/tools/node_modules/eslint/lib/rules/no-iterator.js b/tools/node_modules/eslint/lib/rules/no-iterator.js index 82319a3fb1dfb6..0b01d3533d9db1 100644 --- a/tools/node_modules/eslint/lib/rules/no-iterator.js +++ b/tools/node_modules/eslint/lib/rules/no-iterator.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-iterator" }, - schema: [] + schema: [], + + messages: { + noIterator: "Reserved name '__iterator__'." + } }, create(context) { @@ -32,7 +36,10 @@ module.exports = { if (node.property && (node.property.type === "Identifier" && node.property.name === "__iterator__" && !node.computed) || (node.property.type === "Literal" && node.property.value === "__iterator__")) { - context.report({ node, message: "Reserved name '__iterator__'." }); + context.report({ + node, + messageId: "noIterator" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-label-var.js b/tools/node_modules/eslint/lib/rules/no-label-var.js index a9fd042a390225..570db03285cf97 100644 --- a/tools/node_modules/eslint/lib/rules/no-label-var.js +++ b/tools/node_modules/eslint/lib/rules/no-label-var.js @@ -26,7 +26,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-label-var" }, - schema: [] + schema: [], + + messages: { + identifierClashWithLabel: "Found identifier with same name as label." + } }, create(context) { @@ -62,7 +66,10 @@ module.exports = { * with the innermost scope. */ if (findIdentifier(scope, node.label.name)) { - context.report({ node, message: "Found identifier with same name as label." }); + context.report({ + node, + messageId: "identifierClashWithLabel" + }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-labels.js b/tools/node_modules/eslint/lib/rules/no-labels.js index 52f4b0f5168b71..85760d80dbedd7 100644 --- a/tools/node_modules/eslint/lib/rules/no-labels.js +++ b/tools/node_modules/eslint/lib/rules/no-labels.js @@ -40,7 +40,13 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedLabel: "Unexpected labeled statement.", + unexpectedLabelInBreak: "Unexpected label in break statement.", + unexpectedLabelInContinue: "Unexpected label in continue statement." + } }, create(context) { @@ -113,7 +119,7 @@ module.exports = { if (!isAllowed(scopeInfo.kind)) { context.report({ node, - message: "Unexpected labeled statement." + messageId: "unexpectedLabel" }); } @@ -124,7 +130,7 @@ module.exports = { if (node.label && !isAllowed(getKind(node.label.name))) { context.report({ node, - message: "Unexpected label in break statement." + messageId: "unexpectedLabelInBreak" }); } }, @@ -133,7 +139,7 @@ module.exports = { if (node.label && !isAllowed(getKind(node.label.name))) { context.report({ node, - message: "Unexpected label in continue statement." + messageId: "unexpectedLabelInContinue" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-lone-blocks.js b/tools/node_modules/eslint/lib/rules/no-lone-blocks.js index 37561b0f9a3055..d7069887b8e460 100644 --- a/tools/node_modules/eslint/lib/rules/no-lone-blocks.js +++ b/tools/node_modules/eslint/lib/rules/no-lone-blocks.js @@ -20,7 +20,12 @@ module.exports = { url: "https://eslint.org/docs/rules/no-lone-blocks" }, - schema: [] + schema: [], + + messages: { + redundantBlock: "Block is redundant.", + redundantNestedBlock: "Nested block is redundant." + } }, create(context) { @@ -35,9 +40,12 @@ module.exports = { * @returns {void} */ function report(node) { - const message = node.parent.type === "BlockStatement" ? "Nested block is redundant." : "Block is redundant."; + const messageId = node.parent.type === "BlockStatement" ? "redundantNestedBlock" : "redundantBlock"; - context.report({ node, message }); + context.report({ + node, + messageId + }); } /** diff --git a/tools/node_modules/eslint/lib/rules/no-lonely-if.js b/tools/node_modules/eslint/lib/rules/no-lonely-if.js index b62d176a264210..53f9445f835ec5 100644 --- a/tools/node_modules/eslint/lib/rules/no-lonely-if.js +++ b/tools/node_modules/eslint/lib/rules/no-lonely-if.js @@ -20,7 +20,11 @@ module.exports = { }, schema: [], - fixable: "code" + fixable: "code", + + messages: { + unexpectedLonelyIf: "Unexpected if as the only statement in an else block." + } }, create(context) { @@ -38,7 +42,7 @@ module.exports = { parent === grandparent.alternate) { context.report({ node, - message: "Unexpected if as the only statement in an else block.", + messageId: "unexpectedLonelyIf", fix(fixer) { const openingElseCurly = sourceCode.getFirstToken(parent); const closingElseCurly = sourceCode.getLastToken(parent); diff --git a/tools/node_modules/eslint/lib/rules/no-magic-numbers.js b/tools/node_modules/eslint/lib/rules/no-magic-numbers.js index 0909e3166d952e..4bf24996cb8f20 100644 --- a/tools/node_modules/eslint/lib/rules/no-magic-numbers.js +++ b/tools/node_modules/eslint/lib/rules/no-magic-numbers.js @@ -5,10 +5,24 @@ "use strict"; +const { isNumericLiteral } = require("./utils/ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ +/** + * Convert the value to bigint if it's a string. Otherwise return the value as-is. + * @param {bigint|number|string} x The value to normalize. + * @returns {bigint|number} The normalized value. + */ +function normalizeIgnoreValue(x) { + if (typeof x === "string") { + return BigInt(x.slice(0, -1)); + } + return x; +} + module.exports = { meta: { type: "suggestion", @@ -34,7 +48,10 @@ module.exports = { ignore: { type: "array", items: { - type: "number" + anyOf: [ + { type: "number" }, + { type: "string", pattern: "^[+-]?(?:0|[1-9][0-9]*)n$" } + ] }, uniqueItems: true }, @@ -56,18 +73,9 @@ module.exports = { const config = context.options[0] || {}, detectObjects = !!config.detectObjects, enforceConst = !!config.enforceConst, - ignore = config.ignore || [], + ignore = (config.ignore || []).map(normalizeIgnoreValue), ignoreArrayIndexes = !!config.ignoreArrayIndexes; - /** - * Returns whether the node is number literal - * @param {Node} node the node literal being evaluated - * @returns {boolean} true if the node is a number literal - */ - function isNumber(node) { - return typeof node.value === "number"; - } - /** * Returns whether the number should be ignored * @param {number} num the number @@ -113,7 +121,7 @@ module.exports = { Literal(node) { const okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"]; - if (!isNumber(node)) { + if (!isNumericLiteral(node)) { return; } 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 80fac79affdb0e..37e8906e827a4c 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-operators.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-operators.js @@ -112,7 +112,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedMixedOperator: "Unexpected mix of '{{leftOperator}}' and '{{rightOperator}}'." + } }, create(context) { @@ -188,8 +192,6 @@ module.exports = { const parent = 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 || "?:" @@ -198,13 +200,13 @@ module.exports = { context.report({ node: left, loc: getOperatorToken(left).loc, - message, + messageId: "unexpectedMixedOperator", data }); context.report({ node: right, loc: getOperatorToken(right).loc, - message, + messageId: "unexpectedMixedOperator", data }); } diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-requires.js b/tools/node_modules/eslint/lib/rules/no-mixed-requires.js index fda8a11d9e2e74..8e988e32c24f84 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-requires.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-requires.js @@ -40,7 +40,12 @@ module.exports = { } ] } - ] + ], + + messages: { + noMixRequire: "Do not mix 'require' and other declarations.", + noMixCoreModuleFileComputed: "Do not mix core, module, file and computed requires." + } }, create(context) { @@ -211,9 +216,15 @@ module.exports = { VariableDeclaration(node) { if (isMixed(node.declarations)) { - context.report({ node, message: "Do not mix 'require' and other declarations." }); + context.report({ + node, + messageId: "noMixRequire" + }); } else if (grouping && !isGrouped(node.declarations)) { - context.report({ node, message: "Do not mix core, module, file and computed requires." }); + context.report({ + node, + messageId: "noMixCoreModuleFileComputed" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js b/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js index 7b1e2c4a2a760c..16c2bd4122e851 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js @@ -23,14 +23,17 @@ module.exports = { { enum: ["smart-tabs", true, false] } - ] + ], + + messages: { + mixedSpacesAndTabs: "Mixed spaces and tabs." + } }, create(context) { const sourceCode = context.getSourceCode(); let smartTabs; - const ignoredLocs = []; switch (context.options[0]) { case true: // Support old syntax, maybe add deprecation warning here @@ -41,47 +44,23 @@ module.exports = { smartTabs = false; } - /** - * Determines if a given line and column are before a location. - * @param {Location} loc The location object from an AST node. - * @param {int} line The line to check. - * @param {int} column The column to check. - * @returns {boolean} True if the line and column are before the location, false if not. - * @private - */ - function beforeLoc(loc, line, column) { - if (line < loc.start.line) { - return true; - } - return line === loc.start.line && column < loc.start.column; - } - - /** - * Determines if a given line and column are after a location. - * @param {Location} loc The location object from an AST node. - * @param {int} line The line to check. - * @param {int} column The column to check. - * @returns {boolean} True if the line and column are after the location, false if not. - * @private - */ - function afterLoc(loc, line, column) { - if (line > loc.end.line) { - return true; - } - return line === loc.end.line && column > loc.end.column; - } - //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { - TemplateElement(node) { - ignoredLocs.push(node.loc); - }, - "Program:exit"(node) { + const lines = sourceCode.lines, + comments = sourceCode.getAllComments(), + ignoredCommentLines = new Set(); + + // Add all lines except the first ones. + comments.forEach(comment => { + for (let i = comment.loc.start.line + 1; i <= comment.loc.end.line; i++) { + ignoredCommentLines.add(i); + } + }); /* * At least one space followed by a tab @@ -89,24 +68,6 @@ module.exports = { * characters begin. */ let regex = /^(?=[\t ]*(\t | \t))/u; - const lines = sourceCode.lines, - comments = sourceCode.getAllComments(); - - comments.forEach(comment => { - ignoredLocs.push(comment.loc); - }); - - ignoredLocs.sort((first, second) => { - if (beforeLoc(first, second.start.line, second.start.column)) { - return 1; - } - - if (beforeLoc(second, first.start.line, second.start.column)) { - return -1; - } - - return 0; - }); if (smartTabs) { @@ -122,25 +83,23 @@ module.exports = { if (match) { const lineNumber = i + 1, - column = match.index + 1; - - for (let j = 0; j < ignoredLocs.length; j++) { - if (beforeLoc(ignoredLocs[j], lineNumber, column)) { - continue; + column = match.index + 1, + loc = { line: lineNumber, column }; + + if (!ignoredCommentLines.has(lineNumber)) { + const containingNode = sourceCode.getNodeByRangeIndex(sourceCode.getIndexFromLoc(loc)); + + if (!(containingNode && ["Literal", "TemplateElement"].includes(containingNode.type))) { + context.report({ + node, + loc, + messageId: "mixedSpacesAndTabs" + }); } - if (afterLoc(ignoredLocs[j], lineNumber, column)) { - continue; - } - - return; } - - context.report({ node, loc: { line: lineNumber, column }, message: "Mixed spaces and tabs." }); } }); } - }; - } }; diff --git a/tools/node_modules/eslint/lib/rules/no-multi-assign.js b/tools/node_modules/eslint/lib/rules/no-multi-assign.js index 8524a1a571ef9e..ab6430c19ef070 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-assign.js @@ -21,7 +21,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-multi-assign" }, - schema: [] + schema: [], + + messages: { + unexpectedChain: "Unexpected chained assignment." + } }, create(context) { @@ -35,7 +39,7 @@ module.exports = { if (["AssignmentExpression", "VariableDeclarator"].indexOf(node.parent.type) !== -1) { context.report({ node, - message: "Unexpected chained assignment." + messageId: "unexpectedChain" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-multi-spaces.js b/tools/node_modules/eslint/lib/rules/no-multi-spaces.js index 403d04da9dd9ec..d43ed736337945 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-spaces.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-spaces.js @@ -44,7 +44,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + multipleSpaces: "Multiple spaces found before '{{displayValue}}'." + } }, create(context) { @@ -122,7 +126,7 @@ module.exports = { context.report({ node: rightToken, loc: { start: leftToken.loc.end, end: rightToken.loc.start }, - message: "Multiple spaces found before '{{displayValue}}'.", + messageId: "multipleSpaces", data: { displayValue }, fix: fixer => fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], " ") }); diff --git a/tools/node_modules/eslint/lib/rules/no-multi-str.js b/tools/node_modules/eslint/lib/rules/no-multi-str.js index f6832f3341777f..7cf1ae367942fe 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-str.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-str.js @@ -26,7 +26,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-multi-str" }, - schema: [] + schema: [], + + messages: { + multilineString: "Multiline support is limited to browsers supporting ES5 only." + } }, create(context) { @@ -49,7 +53,10 @@ module.exports = { Literal(node) { if (astUtils.LINEBREAK_MATCHER.test(node.raw) && !isJSXElement(node.parent)) { - context.report({ node, message: "Multiline support is limited to browsers supporting ES5 only." }); + context.report({ + node, + messageId: "multilineString" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js b/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js index 41e6be3a289584..9cccef3088a56e 100644 --- a/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js +++ b/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js @@ -42,7 +42,13 @@ module.exports = { required: ["max"], additionalProperties: false } - ] + ], + + messages: { + blankBeginningOfFile: "Too many blank lines at the beginning of file. Max of {{max}} allowed.", + blankEndOfFile: "Too many blank lines at the end of file. Max of {{max}} allowed.", + consecutiveBlank: "More than {{max}} blank {{pluralizedLines}} not allowed." + } }, create(context) { @@ -94,25 +100,31 @@ module.exports = { // Given two line numbers of non-empty lines, report the lines between if the difference is too large. .reduce((lastLineNumber, lineNumber) => { - let message, maxAllowed; + let messageId, maxAllowed; if (lastLineNumber === 0) { - message = "Too many blank lines at the beginning of file. Max of {{max}} allowed."; + messageId = "blankBeginningOfFile"; maxAllowed = maxBOF; } else if (lineNumber === allLines.length + 1) { - message = "Too many blank lines at the end of file. Max of {{max}} allowed."; + messageId = "blankEndOfFile"; maxAllowed = maxEOF; } else { - message = "More than {{max}} blank {{pluralizedLines}} not allowed."; + messageId = "consecutiveBlank"; maxAllowed = max; } if (lineNumber - lastLineNumber - 1 > maxAllowed) { context.report({ node, - loc: { start: { line: lastLineNumber + maxAllowed + 1, column: 0 }, end: { line: lineNumber, column: 0 } }, - message, - data: { max: maxAllowed, pluralizedLines: maxAllowed === 1 ? "line" : "lines" }, + loc: { + start: { line: lastLineNumber + maxAllowed + 1, column: 0 }, + end: { line: lineNumber, column: 0 } + }, + messageId, + data: { + max: maxAllowed, + pluralizedLines: maxAllowed === 1 ? "line" : "lines" + }, fix(fixer) { const rangeStart = sourceCode.getIndexFromLoc({ line: lastLineNumber + 1, column: 0 }); diff --git a/tools/node_modules/eslint/lib/rules/no-negated-condition.js b/tools/node_modules/eslint/lib/rules/no-negated-condition.js index e55a8287487de3..8a9eba881df04c 100644 --- a/tools/node_modules/eslint/lib/rules/no-negated-condition.js +++ b/tools/node_modules/eslint/lib/rules/no-negated-condition.js @@ -19,7 +19,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-negated-condition" }, - schema: [] + schema: [], + + messages: { + unexpectedNegated: "Unexpected negated condition." + } }, create(context) { @@ -72,12 +76,18 @@ module.exports = { } if (isNegatedIf(node)) { - context.report({ node, message: "Unexpected negated condition." }); + context.report({ + node, + messageId: "unexpectedNegated" + }); } }, ConditionalExpression(node) { if (isNegatedIf(node)) { - context.report({ node, message: "Unexpected negated condition." }); + context.report({ + node, + messageId: "unexpectedNegated" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-nested-ternary.js b/tools/node_modules/eslint/lib/rules/no-nested-ternary.js index 87a11e87962a8f..383bb238887d2a 100644 --- a/tools/node_modules/eslint/lib/rules/no-nested-ternary.js +++ b/tools/node_modules/eslint/lib/rules/no-nested-ternary.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-nested-ternary" }, - schema: [] + schema: [], + + messages: { + noNestedTernary: "Do not nest ternary expressions." + } }, create(context) { @@ -29,7 +33,10 @@ module.exports = { ConditionalExpression(node) { if (node.alternate.type === "ConditionalExpression" || node.consequent.type === "ConditionalExpression") { - context.report({ node, message: "Do not nest ternary expressions." }); + context.report({ + node, + messageId: "noNestedTernary" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-new-func.js b/tools/node_modules/eslint/lib/rules/no-new-func.js index 23e92f7bf3030c..d1360e9dee036d 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-func.js +++ b/tools/node_modules/eslint/lib/rules/no-new-func.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new-func" }, - schema: [] + schema: [], + + messages: { + noFunctionConstructor: "The Function constructor is eval." + } }, create(context) { @@ -36,7 +40,10 @@ module.exports = { * @private */ function report(node) { - context.report({ node, message: "The Function constructor is eval." }); + context.report({ + node, + messageId: "noFunctionConstructor" + }); } return { diff --git a/tools/node_modules/eslint/lib/rules/no-new-object.js b/tools/node_modules/eslint/lib/rules/no-new-object.js index f5cc28664f4e1c..f3e99c9bd13502 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-object.js +++ b/tools/node_modules/eslint/lib/rules/no-new-object.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new-object" }, - schema: [] + schema: [], + + messages: { + preferLiteral: "The object literal notation {} is preferrable." + } }, create(context) { @@ -29,7 +33,10 @@ module.exports = { NewExpression(node) { if (node.callee.name === "Object") { - context.report({ node, message: "The object literal notation {} is preferrable." }); + context.report({ + node, + messageId: "preferLiteral" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-new-require.js b/tools/node_modules/eslint/lib/rules/no-new-require.js index 1eae0659430fbd..df12a424e3527e 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-require.js +++ b/tools/node_modules/eslint/lib/rules/no-new-require.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new-require" }, - schema: [] + schema: [], + + messages: { + noNewRequire: "Unexpected use of new with require." + } }, create(context) { @@ -29,7 +33,10 @@ module.exports = { NewExpression(node) { if (node.callee.type === "Identifier" && node.callee.name === "require") { - context.report({ node, message: "Unexpected use of new with require." }); + context.report({ + node, + messageId: "noNewRequire" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-new-symbol.js b/tools/node_modules/eslint/lib/rules/no-new-symbol.js index ccf757ed6a0cee..cb7e4f0fc88d69 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-symbol.js +++ b/tools/node_modules/eslint/lib/rules/no-new-symbol.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new-symbol" }, - schema: [] + schema: [], + + messages: { + noNewSymbol: "`Symbol` cannot be called as a constructor." + } }, create(context) { @@ -35,7 +39,10 @@ module.exports = { const node = ref.identifier; if (node.parent && node.parent.type === "NewExpression") { - context.report({ node, message: "`Symbol` cannot be called as a constructor." }); + context.report({ + node, + messageId: "noNewSymbol" + }); } }); } diff --git a/tools/node_modules/eslint/lib/rules/no-new-wrappers.js b/tools/node_modules/eslint/lib/rules/no-new-wrappers.js index ae2aeec0341243..0a2861fa5f7799 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-wrappers.js +++ b/tools/node_modules/eslint/lib/rules/no-new-wrappers.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new-wrappers" }, - schema: [] + schema: [], + + messages: { + noConstructor: "Do not use {{fn}} as a constructor." + } }, create(context) { @@ -31,7 +35,11 @@ module.exports = { const wrapperObjects = ["String", "Number", "Boolean", "Math", "JSON"]; if (wrapperObjects.indexOf(node.callee.name) > -1) { - context.report({ node, message: "Do not use {{fn}} as a constructor.", data: { fn: node.callee.name } }); + context.report({ + node, + messageId: "noConstructor", + data: { fn: node.callee.name } + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-new.js b/tools/node_modules/eslint/lib/rules/no-new.js index 2e0702597eade3..aa8a4e26876609 100644 --- a/tools/node_modules/eslint/lib/rules/no-new.js +++ b/tools/node_modules/eslint/lib/rules/no-new.js @@ -21,14 +21,21 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new" }, - schema: [] + schema: [], + + messages: { + noNewStatement: "Do not use 'new' for side effects." + } }, create(context) { return { "ExpressionStatement > NewExpression"(node) { - context.report({ node: node.parent, message: "Do not use 'new' for side effects." }); + context.report({ + node: node.parent, + messageId: "noNewStatement" + }); } }; diff --git a/tools/node_modules/eslint/lib/rules/no-octal.js b/tools/node_modules/eslint/lib/rules/no-octal.js index 5ee69f0309ee03..e9940befafa889 100644 --- a/tools/node_modules/eslint/lib/rules/no-octal.js +++ b/tools/node_modules/eslint/lib/rules/no-octal.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-octal" }, - schema: [] + schema: [], + + messages: { + noOcatal: "Octal literals should not be used." + } }, create(context) { @@ -29,7 +33,10 @@ module.exports = { Literal(node) { if (typeof node.value === "number" && /^0[0-9]/u.test(node.raw)) { - context.report({ node, message: "Octal literals should not be used." }); + context.report({ + node, + messageId: "noOcatal" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-param-reassign.js b/tools/node_modules/eslint/lib/rules/no-param-reassign.js index d65eb34762aaf2..6874af44f389b7 100644 --- a/tools/node_modules/eslint/lib/rules/no-param-reassign.js +++ b/tools/node_modules/eslint/lib/rules/no-param-reassign.js @@ -58,7 +58,12 @@ module.exports = { } ] } - ] + ], + + messages: { + assignmentToFunctionParam: "Assignment to function parameter '{{name}}'.", + assignmentToFunctionParamProp: "Assignment to property of function parameter '{{name}}'." + } }, create(context) { @@ -177,9 +182,17 @@ module.exports = { (index === 0 || references[index - 1].identifier !== identifier) ) { if (reference.isWrite()) { - context.report({ node: identifier, message: "Assignment to function parameter '{{name}}'.", data: { name: identifier.name } }); + context.report({ + node: identifier, + messageId: "assignmentToFunctionParam", + data: { name: identifier.name } + }); } else if (props && isModifyingProp(reference) && !isIgnoredPropertyAssignment(identifier.name)) { - context.report({ node: identifier, message: "Assignment to property of function parameter '{{name}}'.", data: { name: identifier.name } }); + context.report({ + node: identifier, + messageId: "assignmentToFunctionParamProp", + data: { name: identifier.name } + }); } } } diff --git a/tools/node_modules/eslint/lib/rules/no-path-concat.js b/tools/node_modules/eslint/lib/rules/no-path-concat.js index abe0d5247db719..9fa8b852fe8358 100644 --- a/tools/node_modules/eslint/lib/rules/no-path-concat.js +++ b/tools/node_modules/eslint/lib/rules/no-path-concat.js @@ -19,7 +19,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-path-concat" }, - schema: [] + schema: [], + + messages: { + usePathFunctions: "Use path.join() or path.resolve() instead of + to create paths." + } }, create(context) { @@ -42,7 +46,10 @@ module.exports = { (right.type === "Identifier" && MATCHER.test(right.name))) ) { - context.report({ node, message: "Use path.join() or path.resolve() instead of + to create paths." }); + context.report({ + node, + messageId: "usePathFunctions" + }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-plusplus.js b/tools/node_modules/eslint/lib/rules/no-plusplus.js index 1d122dcd31f086..f55303863d25ca 100644 --- a/tools/node_modules/eslint/lib/rules/no-plusplus.js +++ b/tools/node_modules/eslint/lib/rules/no-plusplus.js @@ -32,7 +32,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedUnaryOp: "Unary operator '{{operator}}' used." + } }, create(context) { @@ -52,7 +56,7 @@ module.exports = { } context.report({ node, - message: "Unary operator '{{operator}}' used.", + messageId: "unexpectedUnaryOp", data: { operator: node.operator } diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-exports.js b/tools/node_modules/eslint/lib/rules/no-restricted-exports.js new file mode 100644 index 00000000000000..5b5c7d9bffb99c --- /dev/null +++ b/tools/node_modules/eslint/lib/rules/no-restricted-exports.js @@ -0,0 +1,84 @@ +/** + * @fileoverview Rule to disallow specified names in exports + * @author Milos Djermanovic + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: "suggestion", + + docs: { + description: "disallow specified names in exports", + category: "ECMAScript 6", + recommended: false, + url: "https://eslint.org/docs/rules/no-restricted-exports" + }, + + schema: [{ + type: "object", + properties: { + restrictedNamedExports: { + type: "array", + items: { + type: "string" + }, + uniqueItems: true + } + }, + additionalProperties: false + }], + + messages: { + restrictedNamed: "'{{name}}' is restricted from being used as an exported name." + } + }, + + create(context) { + + const restrictedNames = new Set(context.options[0] && context.options[0].restrictedNamedExports); + + /** + * Checks and reports given exported identifier. + * @param {ASTNode} node exported `Identifer` node to check. + * @returns {void} + */ + function checkExportedName(node) { + const name = node.name; + + if (restrictedNames.has(name)) { + context.report({ + node, + messageId: "restrictedNamed", + data: { name } + }); + } + } + + return { + ExportNamedDeclaration(node) { + const declaration = node.declaration; + + if (declaration) { + if (declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") { + checkExportedName(declaration.id); + } else if (declaration.type === "VariableDeclaration") { + context.getDeclaredVariables(declaration) + .map(v => v.defs.find(d => d.parent === declaration)) + .map(d => d.name) // Identifier nodes + .forEach(checkExportedName); + } + } else { + node.specifiers + .map(s => s.exported) + .forEach(checkExportedName); + } + } + }; + } +}; diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-globals.js b/tools/node_modules/eslint/lib/rules/no-restricted-globals.js index 1a2629a8ec95e8..2c932a7307c0b2 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-globals.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-globals.js @@ -4,13 +4,6 @@ */ "use strict"; -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - -const DEFAULT_MESSAGE_TEMPLATE = "Unexpected use of '{{name}}'.", - CUSTOM_MESSAGE_TEMPLATE = "Unexpected use of '{{name}}'. {{customMessage}}"; - //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -46,6 +39,12 @@ module.exports = { }, uniqueItems: true, minItems: 0 + }, + + messages: { + defaultMessage: "Unexpected use of '{{name}}'.", + // eslint-disable-next-line eslint-plugin/report-message-format + customMessage: "Unexpected use of '{{name}}'. {{customMessage}}" } }, @@ -75,13 +74,13 @@ module.exports = { function reportReference(reference) { const name = reference.identifier.name, customMessage = restrictedGlobalMessages[name], - message = customMessage - ? CUSTOM_MESSAGE_TEMPLATE - : DEFAULT_MESSAGE_TEMPLATE; + messageId = customMessage + ? "customMessage" + : "defaultMessage"; context.report({ node: reference.identifier, - message, + messageId, data: { name, customMessage diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-imports.js b/tools/node_modules/eslint/lib/rules/no-restricted-imports.js index ec0696f99a2de0..c205dad8bdb79d 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-imports.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-imports.js @@ -64,7 +64,11 @@ module.exports = { everything: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted.", // eslint-disable-next-line eslint-plugin/report-message-format - everythingWithCustomMessage: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted. {{customMessage}}" + everythingWithCustomMessage: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted. {{customMessage}}", + + importName: "'{{importName}}' import from '{{importSource}}' is restricted.", + // eslint-disable-next-line eslint-plugin/report-message-format + importNameWithCustomMessage: "'{{importName}}' import from '{{importSource}}' is restricted. {{customMessage}}" }, schema: { @@ -87,6 +91,7 @@ module.exports = { }, create(context) { + const sourceCode = context.getSourceCode(); const options = Array.isArray(context.options) ? context.options : []; const isPathAndPatternsObject = typeof options[0] === "object" && @@ -95,6 +100,11 @@ module.exports = { const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || []; const restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || []; + // if no imports are restricted we don"t need to check + if (Object.keys(restrictedPaths).length === 0 && restrictedPatterns.length === 0) { + return {}; + } + const restrictedPathMessages = restrictedPaths.reduce((memo, importSource) => { if (typeof importSource === "string") { memo[importSource] = { message: null }; @@ -107,40 +117,68 @@ module.exports = { return memo; }, {}); - // if no imports are restricted we don"t need to check - if (Object.keys(restrictedPaths).length === 0 && restrictedPatterns.length === 0) { - return {}; - } - const restrictedPatternsMatcher = ignore().add(restrictedPatterns); - /** - * Checks to see if "*" is being used to import everything. - * @param {Set.} importNames Set of import names that are being imported - * @returns {boolean} whether everything is imported or not - */ - function isEverythingImported(importNames) { - return importNames.has("*"); - } - /** * Report a restricted path. + * @param {string} importSource path of the import + * @param {Map} importNames Map of import names that are being imported * @param {node} node representing the restricted path reference * @returns {void} * @private */ - function reportPath(node) { - const importSource = node.source.value.trim(); - const customMessage = restrictedPathMessages[importSource] && restrictedPathMessages[importSource].message; + function checkRestrictedPathAndReport(importSource, importNames, node) { + if (!Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource)) { + return; + } - context.report({ - node, - messageId: customMessage ? "pathWithCustomMessage" : "path", - data: { - importSource, - customMessage + const customMessage = restrictedPathMessages[importSource].message; + const restrictedImportNames = restrictedPathMessages[importSource].importNames; + + if (restrictedImportNames) { + if (importNames.has("*")) { + const specifierData = importNames.get("*")[0]; + + context.report({ + node, + messageId: customMessage ? "everythingWithCustomMessage" : "everything", + loc: specifierData.loc, + data: { + importSource, + importNames: restrictedImportNames, + customMessage + } + }); } - }); + + restrictedImportNames.forEach(importName => { + if (importNames.has(importName)) { + const specifiers = importNames.get(importName); + + specifiers.forEach(specifier => { + context.report({ + node, + messageId: customMessage ? "importNameWithCustomMessage" : "importName", + loc: specifier.loc, + data: { + importSource, + customMessage, + importName + } + }); + }); + } + }); + } else { + context.report({ + node, + messageId: customMessage ? "pathWithCustomMessage" : "path", + data: { + importSource, + customMessage + } + }); + } } /** @@ -161,75 +199,6 @@ module.exports = { }); } - /** - * Report a restricted path specifically when using the '*' import. - * @param {string} importSource path of the import - * @param {node} node representing the restricted path reference - * @returns {void} - * @private - */ - function reportPathForEverythingImported(importSource, node) { - const importNames = restrictedPathMessages[importSource].importNames; - const customMessage = restrictedPathMessages[importSource] && restrictedPathMessages[importSource].message; - - context.report({ - node, - messageId: customMessage ? "everythingWithCustomMessage" : "everything", - data: { - importSource, - importNames, - customMessage - } - }); - } - - /** - * Check if the given importSource is restricted because '*' is being imported. - * @param {string} importSource path of the import - * @param {Set.} importNames Set of import names that are being imported - * @returns {boolean} whether the path is restricted - * @private - */ - function isRestrictedForEverythingImported(importSource, importNames) { - return Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource) && - restrictedPathMessages[importSource].importNames && - isEverythingImported(importNames); - } - - /** - * Check if the given importNames are restricted given a list of restrictedImportNames. - * @param {Set.} importNames Set of import names that are being imported - * @param {string[]} restrictedImportNames array of import names that are restricted for this import - * @returns {boolean} whether the objectName is restricted - * @private - */ - function isRestrictedObject(importNames, restrictedImportNames) { - return restrictedImportNames.some(restrictedObjectName => ( - importNames.has(restrictedObjectName) - )); - } - - /** - * Check if the given importSource is a restricted path. - * @param {string} importSource path of the import - * @param {Set.} importNames Set of import names that are being imported - * @returns {boolean} whether the variable is a restricted path or not - * @private - */ - function isRestrictedPath(importSource, importNames) { - let isRestricted = false; - - if (Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource)) { - if (restrictedPathMessages[importSource].importNames) { - isRestricted = isRestrictedObject(importNames, restrictedPathMessages[importSource].importNames); - } else { - isRestricted = true; - } - } - - return isRestricted; - } - /** * Check if the given importSource is restricted by a pattern. * @param {string} importSource path of the import @@ -248,26 +217,39 @@ module.exports = { */ function checkNode(node) { const importSource = node.source.value.trim(); - const importNames = node.specifiers ? node.specifiers.reduce((set, specifier) => { - if (specifier.type === "ImportDefaultSpecifier") { - set.add("default"); - } else if (specifier.type === "ImportNamespaceSpecifier") { - set.add("*"); - } else if (specifier.imported) { - set.add(specifier.imported.name); - } else if (specifier.local) { - set.add(specifier.local.name); - } - return set; - }, new Set()) : new Set(); + const importNames = new Map(); + + if (node.type === "ExportAllDeclaration") { + const starToken = sourceCode.getFirstToken(node, 1); + + importNames.set("*", [{ loc: starToken.loc }]); + } else if (node.specifiers) { + for (const specifier of node.specifiers) { + let name; + const specifierData = { loc: specifier.loc }; + + if (specifier.type === "ImportDefaultSpecifier") { + name = "default"; + } else if (specifier.type === "ImportNamespaceSpecifier") { + name = "*"; + } else if (specifier.imported) { + name = specifier.imported.name; + } else if (specifier.local) { + name = specifier.local.name; + } - if (isRestrictedForEverythingImported(importSource, importNames)) { - reportPathForEverythingImported(importSource, node); + if (name) { + if (importNames.has(name)) { + importNames.get(name).push(specifierData); + } else { + importNames.set(name, [specifierData]); + } + } + } } - if (isRestrictedPath(importSource, importNames)) { - reportPath(node); - } + checkRestrictedPathAndReport(importSource, importNames, node); + if (isRestrictedPattern(importSource)) { reportPathForPatterns(node); } diff --git a/tools/node_modules/eslint/lib/rules/no-shadow.js b/tools/node_modules/eslint/lib/rules/no-shadow.js index bad6cb5f3094cc..1be8590e47abcb 100644 --- a/tools/node_modules/eslint/lib/rules/no-shadow.js +++ b/tools/node_modules/eslint/lib/rules/no-shadow.js @@ -41,7 +41,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + noShadow: "'{{name}}' is already declared in the upper scope." + } }, create(context) { @@ -163,7 +167,7 @@ module.exports = { ) { context.report({ node: variable.identifiers[0], - message: "'{{name}}' is already declared in the upper scope.", + messageId: "noShadow", data: variable }); } diff --git a/tools/node_modules/eslint/lib/rules/no-use-before-define.js b/tools/node_modules/eslint/lib/rules/no-use-before-define.js index ed3540532f9095..c7300567ede0b7 100644 --- a/tools/node_modules/eslint/lib/rules/no-use-before-define.js +++ b/tools/node_modules/eslint/lib/rules/no-use-before-define.js @@ -157,7 +157,11 @@ module.exports = { } ] } - ] + ], + + messages: { + usedBeforeDefined: "'{{name}}' was used before it was defined." + } }, create(context) { @@ -212,7 +216,7 @@ module.exports = { // Reports. context.report({ node: reference.identifier, - message: "'{{name}}' was used before it was defined.", + messageId: "usedBeforeDefined", data: reference.identifier }); }); diff --git a/tools/node_modules/eslint/lib/rules/no-useless-backreference.js b/tools/node_modules/eslint/lib/rules/no-useless-backreference.js new file mode 100644 index 00000000000000..8a6fbe14daafe6 --- /dev/null +++ b/tools/node_modules/eslint/lib/rules/no-useless-backreference.js @@ -0,0 +1,193 @@ +/** + * @fileoverview Rule to disallow useless backreferences in regular expressions + * @author Milos Djermanovic + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require("eslint-utils"); +const { RegExpParser, visitRegExpAST } = require("regexpp"); +const lodash = require("lodash"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +const parser = new RegExpParser(); + +/** + * Finds the path from the given `regexpp` AST node to the root node. + * @param {regexpp.Node} node Node. + * @returns {regexpp.Node[]} Array that starts with the given node and ends with the root node. + */ +function getPathToRoot(node) { + const path = []; + let current = node; + + do { + path.push(current); + current = current.parent; + } while (current); + + return path; +} + +/** + * Determines whether the given `regexpp` AST node is a lookaround node. + * @param {regexpp.Node} node Node. + * @returns {boolean} `true` if it is a lookaround node. + */ +function isLookaround(node) { + return node.type === "Assertion" && + (node.kind === "lookahead" || node.kind === "lookbehind"); +} + +/** + * Determines whether the given `regexpp` AST node is a negative lookaround node. + * @param {regexpp.Node} node Node. + * @returns {boolean} `true` if it is a negative lookaround node. + */ +function isNegativeLookaround(node) { + return isLookaround(node) && node.negate; +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: "problem", + + docs: { + description: "disallow useless backreferences in regular expressions", + category: "Possible Errors", + recommended: false, + url: "https://eslint.org/docs/rules/no-useless-backreference" + }, + + schema: [], + + messages: { + nested: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' from within that group.", + forward: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which appears later in the pattern.", + backward: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which appears before in the same lookbehind.", + disjunctive: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which is in another alternative.", + intoNegativeLookaround: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which is in a negative lookaround." + } + }, + + create(context) { + + /** + * Checks and reports useless backreferences in the given regular expression. + * @param {ASTNode} node Node that represents regular expression. A regex literal or RegExp constructor call. + * @param {string} pattern Regular expression pattern. + * @param {string} flags Regular expression flags. + * @returns {void} + */ + function checkRegex(node, pattern, flags) { + let regExpAST; + + try { + regExpAST = parser.parsePattern(pattern, 0, pattern.length, flags.includes("u")); + } catch (e) { + + // Ignore regular expressions with syntax errors + return; + } + + visitRegExpAST(regExpAST, { + onBackreferenceEnter(bref) { + const group = bref.resolved, + brefPath = getPathToRoot(bref), + groupPath = getPathToRoot(group); + let messageId = null; + + if (brefPath.includes(group)) { + + // group is bref's ancestor => bref is nested ('nested reference') => group hasn't matched yet when bref starts to match. + messageId = "nested"; + } else { + + // Start from the root to find the lowest common ancestor. + let i = brefPath.length - 1, + j = groupPath.length - 1; + + do { + i--; + j--; + } while (brefPath[i] === groupPath[j]); + + const indexOfLowestCommonAncestor = j + 1, + groupCut = groupPath.slice(0, indexOfLowestCommonAncestor), + commonPath = groupPath.slice(indexOfLowestCommonAncestor), + lowestCommonLookaround = commonPath.find(isLookaround), + isMatchingBackward = lowestCommonLookaround && lowestCommonLookaround.kind === "lookbehind"; + + if (!isMatchingBackward && bref.end <= group.start) { + + // bref is left, group is right ('forward reference') => group hasn't matched yet when bref starts to match. + messageId = "forward"; + } else if (isMatchingBackward && group.end <= bref.start) { + + // the opposite of the previous when the regex is matching backward in a lookbehind context. + messageId = "backward"; + } else if (lodash.last(groupCut).type === "Alternative") { + + // group's and bref's ancestor nodes below the lowest common ancestor are sibling alternatives => they're disjunctive. + messageId = "disjunctive"; + } else if (groupCut.some(isNegativeLookaround)) { + + // group is in a negative lookaround which isn't bref's ancestor => group has already failed when bref starts to match. + messageId = "intoNegativeLookaround"; + } + } + + if (messageId) { + context.report({ + node, + messageId, + data: { + bref: bref.raw, + group: group.raw + } + }); + } + } + }); + } + + return { + "Literal[regex]"(node) { + const { pattern, flags } = node.regex; + + checkRegex(node, pattern, flags); + }, + Program() { + const scope = context.getScope(), + tracker = new ReferenceTracker(scope), + traceMap = { + RegExp: { + [CALL]: true, + [CONSTRUCT]: true + } + }; + + for (const { node } of tracker.iterateGlobalReferences(traceMap)) { + const [patternNode, flagsNode] = node.arguments, + pattern = getStringIfConstant(patternNode, scope), + flags = getStringIfConstant(flagsNode, scope); + + if (typeof pattern === "string") { + checkRegex(node, pattern, flags || ""); + } + } + } + }; + } +}; diff --git a/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js b/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js index b5e53174e42be7..0e0acbea7c381c 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js @@ -71,14 +71,11 @@ module.exports = { message: MESSAGE_UNNECESSARY_COMPUTED, data: { property: sourceCode.getText(key) }, fix(fixer) { - const leftSquareBracket = sourceCode.getFirstToken(node, astUtils.isOpeningBracketToken); - const rightSquareBracket = sourceCode.getFirstTokenBetween(node.key, node.value, astUtils.isClosingBracketToken); - const tokensBetween = sourceCode.getTokensBetween(leftSquareBracket, rightSquareBracket, 1); + const leftSquareBracket = sourceCode.getTokenBefore(key, astUtils.isOpeningBracketToken); + const rightSquareBracket = sourceCode.getTokenAfter(key, astUtils.isClosingBracketToken); - if (tokensBetween.slice(0, -1).some((token, index) => - sourceCode.getText().slice(token.range[1], tokensBetween[index + 1].range[0]).trim())) { - - // If there are comments between the brackets and the property name, don't do a fix. + // If there are comments between the brackets and the property name, don't do a fix. + if (sourceCode.commentsExistBetween(leftSquareBracket, rightSquareBracket)) { return null; } diff --git a/tools/node_modules/eslint/lib/rules/no-useless-constructor.js b/tools/node_modules/eslint/lib/rules/no-useless-constructor.js index 7cf033805f99d9..2920328c6f39c0 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-constructor.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-constructor.js @@ -143,7 +143,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-useless-constructor" }, - schema: [] + schema: [], + + messages: { + noUselessConstructor: "Useless constructor." + } }, create(context) { @@ -165,7 +169,7 @@ module.exports = { if (superClass ? isRedundantSuperCall(body, ctorParams) : (body.length === 0)) { context.report({ node, - message: "Useless constructor." + messageId: "noUselessConstructor" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-void.js b/tools/node_modules/eslint/lib/rules/no-void.js index d2b5d2f9631dff..99c83785552ab8 100644 --- a/tools/node_modules/eslint/lib/rules/no-void.js +++ b/tools/node_modules/eslint/lib/rules/no-void.js @@ -19,22 +19,46 @@ module.exports = { url: "https://eslint.org/docs/rules/no-void" }, - schema: [] + messages: { + noVoid: "Expected 'undefined' and instead saw 'void'." + }, + + schema: [ + { + type: "object", + properties: { + allowAsStatement: { + type: "boolean", + default: false + } + }, + additionalProperties: false + } + ] }, create(context) { + const allowAsStatement = + context.options[0] && context.options[0].allowAsStatement; //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { - UnaryExpression(node) { - if (node.operator === "void") { - context.report({ node, message: "Expected 'undefined' and instead saw 'void'." }); + 'UnaryExpression[operator="void"]'(node) { + if ( + allowAsStatement && + node.parent && + node.parent.type === "ExpressionStatement" + ) { + return; } + context.report({ + node, + messageId: "noVoid" + }); } }; - } }; diff --git a/tools/node_modules/eslint/lib/rules/prefer-object-spread.js b/tools/node_modules/eslint/lib/rules/prefer-object-spread.js index bbcd88bee3d071..00f5fb6d4c8991 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-object-spread.js +++ b/tools/node_modules/eslint/lib/rules/prefer-object-spread.js @@ -25,6 +25,36 @@ function hasArraySpread(node) { return node.arguments.some(arg => arg.type === "SpreadElement"); } +/** + * Determines whether the given node is an accessor property (getter/setter). + * @param {ASTNode} node Node to check. + * @returns {boolean} `true` if the node is a getter or a setter. + */ +function isAccessorProperty(node) { + return node.type === "Property" && + (node.kind === "get" || node.kind === "set"); +} + +/** + * Determines whether the given object expression node has accessor properties (getters/setters). + * @param {ASTNode} node `ObjectExpression` node to check. + * @returns {boolean} `true` if the node has at least one getter/setter. + */ +function hasAccessors(node) { + return node.properties.some(isAccessorProperty); +} + +/** + * Determines whether the given call expression node has object expression arguments with accessor properties (getters/setters). + * @param {ASTNode} node `CallExpression` node to check. + * @returns {boolean} `true` if the node has at least one argument that is an object expression with at least one getter/setter. + */ +function hasArgumentsWithAccessors(node) { + return node.arguments + .filter(arg => arg.type === "ObjectExpression") + .some(hasAccessors); +} + /** * Helper that checks if the node needs parentheses to be valid JS. * The default is to wrap the node in parentheses to avoid parsing errors. @@ -249,7 +279,11 @@ module.exports = { if ( node.arguments.length >= 1 && node.arguments[0].type === "ObjectExpression" && - !hasArraySpread(node) + !hasArraySpread(node) && + !( + node.arguments.length > 1 && + hasArgumentsWithAccessors(node) + ) ) { const messageId = node.arguments.length === 1 ? "useLiteralMessage" diff --git a/tools/node_modules/eslint/lib/rules/quote-props.js b/tools/node_modules/eslint/lib/rules/quote-props.js index ab09b8fa938e63..4cc53b988f634d 100644 --- a/tools/node_modules/eslint/lib/rules/quote-props.js +++ b/tools/node_modules/eslint/lib/rules/quote-props.js @@ -8,8 +8,9 @@ // Requirements //------------------------------------------------------------------------------ -const espree = require("espree"), - keywords = require("./utils/keywords"); +const espree = require("espree"); +const astUtils = require("./utils/ast-utils"); +const keywords = require("./utils/keywords"); //------------------------------------------------------------------------------ // Rule Definition @@ -177,7 +178,7 @@ module.exports = { data: { property: key.name }, fix: fixer => fixer.replaceText(key, getQuotedKey(key)) }); - } else if (NUMBERS && key.type === "Literal" && typeof key.value === "number") { + } else if (NUMBERS && key.type === "Literal" && astUtils.isNumericLiteral(key)) { context.report({ node, message: MESSAGE_NUMERIC, diff --git a/tools/node_modules/eslint/lib/rules/quotes.js b/tools/node_modules/eslint/lib/rules/quotes.js index f78d1129425633..d1f4443b9033c9 100644 --- a/tools/node_modules/eslint/lib/rules/quotes.js +++ b/tools/node_modules/eslint/lib/rules/quotes.js @@ -110,7 +110,11 @@ module.exports = { } ] } - ] + ], + + messages: { + wrongQuotes: "Strings must use {{description}}." + } }, create(context) { @@ -273,7 +277,7 @@ module.exports = { if (!isValid) { context.report({ node, - message: "Strings must use {{description}}.", + messageId: "wrongQuotes", data: { description: settings.description }, @@ -304,7 +308,7 @@ module.exports = { context.report({ node, - message: "Strings must use {{description}}.", + messageId: "wrongQuotes", data: { description: settings.description }, diff --git a/tools/node_modules/eslint/lib/rules/require-await.js b/tools/node_modules/eslint/lib/rules/require-await.js index 22c111b6dc852e..274e241cfc7d5b 100644 --- a/tools/node_modules/eslint/lib/rules/require-await.js +++ b/tools/node_modules/eslint/lib/rules/require-await.js @@ -39,7 +39,11 @@ module.exports = { url: "https://eslint.org/docs/rules/require-await" }, - schema: [] + schema: [], + + messages: { + missingAwait: "{{name}} has no 'await' expression." + } }, create(context) { @@ -68,7 +72,7 @@ module.exports = { context.report({ node, loc: astUtils.getFunctionHeadLoc(node, sourceCode), - message: "{{name}} has no 'await' expression.", + messageId: "missingAwait", data: { name: capitalizeFirstLetter( astUtils.getFunctionNameWithKind(node) diff --git a/tools/node_modules/eslint/lib/rules/semi.js b/tools/node_modules/eslint/lib/rules/semi.js index 22e299efe72e49..3491f4765c77a2 100644 --- a/tools/node_modules/eslint/lib/rules/semi.js +++ b/tools/node_modules/eslint/lib/rules/semi.js @@ -67,6 +67,11 @@ module.exports = { maxItems: 2 } ] + }, + + messages: { + missingSemi: "Missing semicolon.", + extraSemi: "Extra semicolon." } }, @@ -91,12 +96,12 @@ module.exports = { */ function report(node, missing) { const lastToken = sourceCode.getLastToken(node); - let message, + let messageId, fix, loc; if (!missing) { - message = "Missing semicolon."; + messageId = "missingSemi"; loc = { start: lastToken.loc.end, end: astUtils.getNextLocation(sourceCode, lastToken.loc.end) @@ -105,7 +110,7 @@ module.exports = { return fixer.insertTextAfter(lastToken, ";"); }; } else { - message = "Extra semicolon."; + messageId = "extraSemi"; loc = lastToken.loc; fix = function(fixer) { @@ -123,7 +128,7 @@ module.exports = { context.report({ node, loc, - message, + messageId, fix }); diff --git a/tools/node_modules/eslint/lib/rules/template-curly-spacing.js b/tools/node_modules/eslint/lib/rules/template-curly-spacing.js index 07da6a39b0e9bb..a16c0732df7b50 100644 --- a/tools/node_modules/eslint/lib/rules/template-curly-spacing.js +++ b/tools/node_modules/eslint/lib/rules/template-curly-spacing.js @@ -57,7 +57,7 @@ module.exports = { * @returns {void} */ function checkSpacingBefore(token) { - const prevToken = sourceCode.getTokenBefore(token); + const prevToken = sourceCode.getTokenBefore(token, { includeComments: true }); if (prevToken && CLOSE_PAREN.test(token.value) && @@ -86,7 +86,7 @@ module.exports = { * @returns {void} */ function checkSpacingAfter(token) { - const nextToken = sourceCode.getTokenAfter(token); + const nextToken = sourceCode.getTokenAfter(token, { includeComments: true }); if (nextToken && OPEN_PAREN.test(token.value) && 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 01c6b47b82eefc..e10544dd61e9ca 100644 --- a/tools/node_modules/eslint/lib/rules/utils/ast-utils.js +++ b/tools/node_modules/eslint/lib/rules/utils/ast-utils.js @@ -865,6 +865,47 @@ module.exports = { return isFunction(node) && module.exports.isEmptyBlock(node.body); }, + /** + * Returns the result of the string conversion applied to the evaluated value of the given expression node, + * if it can be determined statically. + * + * This function returns a `string` value for all `Literal` nodes and simple `TemplateLiteral` nodes only. + * In all other cases, this function returns `null`. + * @param {ASTNode} node Expression node. + * @returns {string|null} String value if it can be determined. Otherwise, `null`. + */ + getStaticStringValue(node) { + switch (node.type) { + case "Literal": + if (node.value === null) { + if (module.exports.isNullLiteral(node)) { + return String(node.value); // "null" + } + if (node.regex) { + return `/${node.regex.pattern}/${node.regex.flags}`; + } + if (node.bigint) { + return node.bigint; + } + + // Otherwise, this is an unknown literal. The function will return null. + + } else { + return String(node.value); + } + break; + case "TemplateLiteral": + if (node.expressions.length === 0 && node.quasis.length === 1) { + return node.quasis[0].value.cooked; + } + break; + + // no default + } + + return null; + }, + /** * Gets the property name of a given node. * The node can be a MemberExpression, a Property, or a MethodDefinition. @@ -911,23 +952,12 @@ module.exports = { // no default } - switch (prop && prop.type) { - case "Literal": - return String(prop.value); - - case "TemplateLiteral": - if (prop.expressions.length === 0 && prop.quasis.length === 1) { - return prop.quasis[0].value.cooked; - } - break; - - case "Identifier": - if (!node.computed) { - return prop.name; - } - break; + if (prop) { + if (prop.type === "Identifier" && !node.computed) { + return prop.name; + } - // no default + return module.exports.getStaticStringValue(prop); } return null; @@ -987,6 +1017,7 @@ module.exports = { * 0o5 // false * 5e0 // false * '5' // false + * 5n // false */ isDecimalInteger(node) { return node.type === "Literal" && typeof node.value === "number" && @@ -1306,6 +1337,18 @@ module.exports = { return node.type === "Literal" && node.value === null && !node.regex && !node.bigint; }, + /** + * Check if a given node is a numeric literal or not. + * @param {ASTNode} node The node to check. + * @returns {boolean} `true` if the node is a number or bigint literal. + */ + isNumericLiteral(node) { + return ( + node.type === "Literal" && + (typeof node.value === "number" || Boolean(node.bigint)) + ); + }, + /** * Determines whether two tokens can safely be placed next to each other without merging into a single token * @param {Token|string} leftValue The left token. If this is a string, it will be tokenized and the last token will be used. diff --git a/tools/node_modules/eslint/lib/rules/utils/unicode/is-combining-character.js b/tools/node_modules/eslint/lib/rules/utils/unicode/is-combining-character.js index 0fa40ee4ae8630..0498b99a21ed45 100644 --- a/tools/node_modules/eslint/lib/rules/utils/unicode/is-combining-character.js +++ b/tools/node_modules/eslint/lib/rules/utils/unicode/is-combining-character.js @@ -1,13 +1,13 @@ -// THIS FILE WAS GENERATED BY 'tools/update-unicode-utils.js' +/** + * @author Toru Nagashima + */ "use strict"; -const combiningChars = new Set([768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,1155,1156,1157,1158,1159,1160,1161,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1471,1473,1474,1476,1477,1479,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1648,1750,1751,1752,1753,1754,1755,1756,1759,1760,1761,1762,1763,1764,1767,1768,1770,1771,1772,1773,1809,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,2027,2028,2029,2030,2031,2032,2033,2034,2035,2070,2071,2072,2073,2075,2076,2077,2078,2079,2080,2081,2082,2083,2085,2086,2087,2089,2090,2091,2092,2093,2137,2138,2139,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2362,2363,2364,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2385,2386,2387,2388,2389,2390,2391,2402,2403,2433,2434,2435,2492,2494,2495,2496,2497,2498,2499,2500,2503,2504,2507,2508,2509,2519,2530,2531,2561,2562,2563,2620,2622,2623,2624,2625,2626,2631,2632,2635,2636,2637,2641,2672,2673,2677,2689,2690,2691,2748,2750,2751,2752,2753,2754,2755,2756,2757,2759,2760,2761,2763,2764,2765,2786,2787,2810,2811,2812,2813,2814,2815,2817,2818,2819,2876,2878,2879,2880,2881,2882,2883,2884,2887,2888,2891,2892,2893,2902,2903,2914,2915,2946,3006,3007,3008,3009,3010,3014,3015,3016,3018,3019,3020,3021,3031,3072,3073,3074,3075,3134,3135,3136,3137,3138,3139,3140,3142,3143,3144,3146,3147,3148,3149,3157,3158,3170,3171,3201,3202,3203,3260,3262,3263,3264,3265,3266,3267,3268,3270,3271,3272,3274,3275,3276,3277,3285,3286,3298,3299,3328,3329,3330,3331,3387,3388,3390,3391,3392,3393,3394,3395,3396,3398,3399,3400,3402,3403,3404,3405,3415,3426,3427,3458,3459,3530,3535,3536,3537,3538,3539,3540,3542,3544,3545,3546,3547,3548,3549,3550,3551,3570,3571,3633,3636,3637,3638,3639,3640,3641,3642,3655,3656,3657,3658,3659,3660,3661,3662,3761,3764,3765,3766,3767,3768,3769,3771,3772,3784,3785,3786,3787,3788,3789,3864,3865,3893,3895,3897,3902,3903,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3974,3975,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4038,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4182,4183,4184,4185,4190,4191,4192,4194,4195,4196,4199,4200,4201,4202,4203,4204,4205,4209,4210,4211,4212,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4239,4250,4251,4252,4253,4957,4958,4959,5906,5907,5908,5938,5939,5940,5970,5971,6002,6003,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6109,6155,6156,6157,6277,6278,6313,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,6679,6680,6681,6682,6683,6741,6742,6743,6744,6745,6746,6747,6748,6749,6750,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761,6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,6779,6780,6783,6832,6833,6834,6835,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,6912,6913,6914,6915,6916,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,7019,7020,7021,7022,7023,7024,7025,7026,7027,7040,7041,7042,7073,7074,7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,7154,7155,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213,7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7376,7377,7378,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400,7405,7410,7411,7412,7415,7416,7417,7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631,7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7675,7676,7677,7678,7679,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421,8422,8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,11503,11504,11505,11647,11744,11745,11746,11747,11748,11749,11750,11751,11752,11753,11754,11755,11756,11757,11758,11759,11760,11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,11774,11775,12330,12331,12332,12333,12334,12335,12441,12442,42607,42608,42609,42610,42612,42613,42614,42615,42616,42617,42618,42619,42620,42621,42654,42655,42736,42737,43010,43014,43019,43043,43044,43045,43046,43047,43136,43137,43188,43189,43190,43191,43192,43193,43194,43195,43196,43197,43198,43199,43200,43201,43202,43203,43204,43205,43232,43233,43234,43235,43236,43237,43238,43239,43240,43241,43242,43243,43244,43245,43246,43247,43248,43249,43302,43303,43304,43305,43306,43307,43308,43309,43335,43336,43337,43338,43339,43340,43341,43342,43343,43344,43345,43346,43347,43392,43393,43394,43395,43443,43444,43445,43446,43447,43448,43449,43450,43451,43452,43453,43454,43455,43456,43493,43561,43562,43563,43564,43565,43566,43567,43568,43569,43570,43571,43572,43573,43574,43587,43596,43597,43643,43644,43645,43696,43698,43699,43700,43703,43704,43710,43711,43713,43755,43756,43757,43758,43759,43765,43766,44003,44004,44005,44006,44007,44008,44009,44010,44012,44013,64286,65024,65025,65026,65027,65028,65029,65030,65031,65032,65033,65034,65035,65036,65037,65038,65039,65056,65057,65058,65059,65060,65061,65062,65063,65064,65065,65066,65067,65068,65069,65070,65071,66045,66272,66422,66423,66424,66425,66426,68097,68098,68099,68101,68102,68108,68109,68110,68111,68152,68153,68154,68159,68325,68326,69632,69633,69634,69688,69689,69690,69691,69692,69693,69694,69695,69696,69697,69698,69699,69700,69701,69702,69759,69760,69761,69762,69808,69809,69810,69811,69812,69813,69814,69815,69816,69817,69818,69888,69889,69890,69927,69928,69929,69930,69931,69932,69933,69934,69935,69936,69937,69938,69939,69940,70003,70016,70017,70018,70067,70068,70069,70070,70071,70072,70073,70074,70075,70076,70077,70078,70079,70080,70090,70091,70092,70188,70189,70190,70191,70192,70193,70194,70195,70196,70197,70198,70199,70206,70367,70368,70369,70370,70371,70372,70373,70374,70375,70376,70377,70378,70400,70401,70402,70403,70460,70462,70463,70464,70465,70466,70467,70468,70471,70472,70475,70476,70477,70487,70498,70499,70502,70503,70504,70505,70506,70507,70508,70512,70513,70514,70515,70516,70709,70710,70711,70712,70713,70714,70715,70716,70717,70718,70719,70720,70721,70722,70723,70724,70725,70726,70832,70833,70834,70835,70836,70837,70838,70839,70840,70841,70842,70843,70844,70845,70846,70847,70848,70849,70850,70851,71087,71088,71089,71090,71091,71092,71093,71096,71097,71098,71099,71100,71101,71102,71103,71104,71132,71133,71216,71217,71218,71219,71220,71221,71222,71223,71224,71225,71226,71227,71228,71229,71230,71231,71232,71339,71340,71341,71342,71343,71344,71345,71346,71347,71348,71349,71350,71351,71453,71454,71455,71456,71457,71458,71459,71460,71461,71462,71463,71464,71465,71466,71467,72193,72194,72195,72196,72197,72198,72199,72200,72201,72202,72243,72244,72245,72246,72247,72248,72249,72251,72252,72253,72254,72263,72273,72274,72275,72276,72277,72278,72279,72280,72281,72282,72283,72330,72331,72332,72333,72334,72335,72336,72337,72338,72339,72340,72341,72342,72343,72344,72345,72751,72752,72753,72754,72755,72756,72757,72758,72760,72761,72762,72763,72764,72765,72766,72767,72850,72851,72852,72853,72854,72855,72856,72857,72858,72859,72860,72861,72862,72863,72864,72865,72866,72867,72868,72869,72870,72871,72873,72874,72875,72876,72877,72878,72879,72880,72881,72882,72883,72884,72885,72886,73009,73010,73011,73012,73013,73014,73018,73020,73021,73023,73024,73025,73026,73027,73028,73029,73031,92912,92913,92914,92915,92916,92976,92977,92978,92979,92980,92981,92982,94033,94034,94035,94036,94037,94038,94039,94040,94041,94042,94043,94044,94045,94046,94047,94048,94049,94050,94051,94052,94053,94054,94055,94056,94057,94058,94059,94060,94061,94062,94063,94064,94065,94066,94067,94068,94069,94070,94071,94072,94073,94074,94075,94076,94077,94078,94095,94096,94097,94098,113821,113822,119141,119142,119143,119144,119145,119149,119150,119151,119152,119153,119154,119163,119164,119165,119166,119167,119168,119169,119170,119173,119174,119175,119176,119177,119178,119179,119210,119211,119212,119213,119362,119363,119364,121344,121345,121346,121347,121348,121349,121350,121351,121352,121353,121354,121355,121356,121357,121358,121359,121360,121361,121362,121363,121364,121365,121366,121367,121368,121369,121370,121371,121372,121373,121374,121375,121376,121377,121378,121379,121380,121381,121382,121383,121384,121385,121386,121387,121388,121389,121390,121391,121392,121393,121394,121395,121396,121397,121398,121403,121404,121405,121406,121407,121408,121409,121410,121411,121412,121413,121414,121415,121416,121417,121418,121419,121420,121421,121422,121423,121424,121425,121426,121427,121428,121429,121430,121431,121432,121433,121434,121435,121436,121437,121438,121439,121440,121441,121442,121443,121444,121445,121446,121447,121448,121449,121450,121451,121452,121461,121476,121499,121500,121501,121502,121503,121505,121506,121507,121508,121509,121510,121511,121512,121513,121514,121515,121516,121517,121518,121519,122880,122881,122882,122883,122884,122885,122886,122888,122889,122890,122891,122892,122893,122894,122895,122896,122897,122898,122899,122900,122901,122902,122903,122904,122907,122908,122909,122910,122911,122912,122913,122915,122916,122918,122919,122920,122921,122922,125136,125137,125138,125139,125140,125141,125142,125252,125253,125254,125255,125256,125257,125258,917760,917761,917762,917763,917764,917765,917766,917767,917768,917769,917770,917771,917772,917773,917774,917775,917776,917777,917778,917779,917780,917781,917782,917783,917784,917785,917786,917787,917788,917789,917790,917791,917792,917793,917794,917795,917796,917797,917798,917799,917800,917801,917802,917803,917804,917805,917806,917807,917808,917809,917810,917811,917812,917813,917814,917815,917816,917817,917818,917819,917820,917821,917822,917823,917824,917825,917826,917827,917828,917829,917830,917831,917832,917833,917834,917835,917836,917837,917838,917839,917840,917841,917842,917843,917844,917845,917846,917847,917848,917849,917850,917851,917852,917853,917854,917855,917856,917857,917858,917859,917860,917861,917862,917863,917864,917865,917866,917867,917868,917869,917870,917871,917872,917873,917874,917875,917876,917877,917878,917879,917880,917881,917882,917883,917884,917885,917886,917887,917888,917889,917890,917891,917892,917893,917894,917895,917896,917897,917898,917899,917900,917901,917902,917903,917904,917905,917906,917907,917908,917909,917910,917911,917912,917913,917914,917915,917916,917917,917918,917919,917920,917921,917922,917923,917924,917925,917926,917927,917928,917929,917930,917931,917932,917933,917934,917935,917936,917937,917938,917939,917940,917941,917942,917943,917944,917945,917946,917947,917948,917949,917950,917951,917952,917953,917954,917955,917956,917957,917958,917959,917960,917961,917962,917963,917964,917965,917966,917967,917968,917969,917970,917971,917972,917973,917974,917975,917976,917977,917978,917979,917980,917981,917982,917983,917984,917985,917986,917987,917988,917989,917990,917991,917992,917993,917994,917995,917996,917997,917998,917999]) - /** * Check whether a given character is a combining mark or not. - * @param {number} c The character code to check. - * @returns {boolean} `true` if the character belongs to the category, one of `Mc`, `Me`, and `Mn`. + * @param {number} codePoint The character code to check. + * @returns {boolean} `true` if the character belongs to the category, any of `Mc`, `Me`, and `Mn`. */ -module.exports = function isCombiningCharacter(c) { - return combiningChars.has(c); +module.exports = function isCombiningCharacter(codePoint) { + return /^[\p{Mc}\p{Me}\p{Mn}]$/u.test(String.fromCodePoint(codePoint)); }; diff --git a/tools/node_modules/eslint/lib/rules/yoda.js b/tools/node_modules/eslint/lib/rules/yoda.js index b00acf82c702b0..be5c59ce072269 100644 --- a/tools/node_modules/eslint/lib/rules/yoda.js +++ b/tools/node_modules/eslint/lib/rules/yoda.js @@ -53,8 +53,7 @@ function looksLikeLiteral(node) { return (node.type === "UnaryExpression" && node.operator === "-" && node.prefix && - node.argument.type === "Literal" && - typeof node.argument.value === "number"); + astUtils.isNumericLiteral(node.argument)); } /** diff --git a/tools/node_modules/eslint/lib/shared/config-validator.js b/tools/node_modules/eslint/lib/shared/config-validator.js index aca6e1fb274fdb..70eaf0a9670514 100644 --- a/tools/node_modules/eslint/lib/shared/config-validator.js +++ b/tools/node_modules/eslint/lib/shared/config-validator.js @@ -10,13 +10,12 @@ //------------------------------------------------------------------------------ const - path = require("path"), util = require("util"), - lodash = require("lodash"), configSchema = require("../../conf/config-schema"), BuiltInEnvironments = require("../../conf/environments"), BuiltInRules = require("../rules"), - ConfigOps = require("./config-ops"); + ConfigOps = require("./config-ops"), + { emitDeprecationWarning } = require("./deprecation-warnings"); const ajv = require("./ajv")(); const ruleValidators = new WeakMap(); @@ -26,11 +25,6 @@ const noop = Function.prototype; // Private //------------------------------------------------------------------------------ let validateSchema; - -// Defitions for deprecation warnings. -const deprecationWarningMessages = { - ESLINT_LEGACY_ECMAFEATURES: "The 'ecmaFeatures' config file property is deprecated, and has no effect." -}; const severityMap = { error: 2, warn: 1, @@ -254,25 +248,6 @@ function formatErrors(errors) { }).map(message => `\t- ${message}.\n`).join(""); } -/** - * Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted - * for each unique file path, but repeated invocations with the same file path have no effect. - * No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active. - * @param {string} source The name of the configuration source to report the warning for. - * @param {string} errorCode The warning message to show. - * @returns {void} - */ -const emitDeprecationWarning = lodash.memoize((source, errorCode) => { - const rel = path.relative(process.cwd(), source); - const message = deprecationWarningMessages[errorCode]; - - process.emitWarning( - `${message} (found in "${rel}")`, - "DeprecationWarning", - errorCode - ); -}); - /** * Validates the top level properties of the config object. * @param {Object} config The config object to validate. diff --git a/tools/node_modules/eslint/lib/shared/deprecation-warnings.js b/tools/node_modules/eslint/lib/shared/deprecation-warnings.js new file mode 100644 index 00000000000000..e1481a2e9aa0b8 --- /dev/null +++ b/tools/node_modules/eslint/lib/shared/deprecation-warnings.js @@ -0,0 +1,56 @@ +/** + * @fileoverview Provide the function that emits deprecation warnings. + * @author Toru Nagashima + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const path = require("path"); +const lodash = require("lodash"); + +//------------------------------------------------------------------------------ +// Private +//------------------------------------------------------------------------------ + +// Defitions for deprecation warnings. +const deprecationWarningMessages = { + ESLINT_LEGACY_ECMAFEATURES: + "The 'ecmaFeatures' config file property is deprecated and has no effect.", + ESLINT_PERSONAL_CONFIG_LOAD: + "'~/.eslintrc.*' config files have been deprecated. " + + "Please use a config file per project or the '--config' option.", + ESLINT_PERSONAL_CONFIG_SUPPRESS: + "'~/.eslintrc.*' config files have been deprecated. " + + "Please remove it or add 'root:true' to the config files in your " + + "projects in order to avoid loading '~/.eslintrc.*' accidentally." +}; + +/** + * Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted + * for each unique file path, but repeated invocations with the same file path have no effect. + * No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active. + * @param {string} source The name of the configuration source to report the warning for. + * @param {string} errorCode The warning message to show. + * @returns {void} + */ +const emitDeprecationWarning = lodash.memoize((source, errorCode) => { + const rel = path.relative(process.cwd(), source); + const message = deprecationWarningMessages[errorCode]; + + process.emitWarning( + `${message} (found in "${rel}")`, + "DeprecationWarning", + errorCode + ); +}, (...args) => JSON.stringify(args)); + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +module.exports = { + emitDeprecationWarning +}; diff --git a/tools/node_modules/eslint/lib/shared/relative-module-resolver.js b/tools/node_modules/eslint/lib/shared/relative-module-resolver.js index 5b25fa111214ed..fa6cca72361df5 100644 --- a/tools/node_modules/eslint/lib/shared/relative-module-resolver.js +++ b/tools/node_modules/eslint/lib/shared/relative-module-resolver.js @@ -6,35 +6,18 @@ "use strict"; const Module = require("module"); -const path = require("path"); -// Polyfill Node's `Module.createRequire` if not present. We only support the case where the argument is a filepath, not a URL. -const createRequire = ( - - // Added in v12.2.0 - Module.createRequire || - - // Added in v10.12.0, but deprecated in v12.2.0. - Module.createRequireFromPath || - - // Polyfill - This is not executed on the tests on node@>=10. - /* istanbul ignore next */ - (filename => { - const mod = new Module(filename, null); - - mod.filename = filename; - mod.paths = Module._nodeModulePaths(path.dirname(filename)); // eslint-disable-line no-underscore-dangle - mod._compile("module.exports = require;", filename); // eslint-disable-line no-underscore-dangle - return mod.exports; - }) -); +/* + * `Module.createRequire` is added in v12.2.0. It supports URL as well. + * We only support the case where the argument is a filepath, not a URL. + */ +const createRequire = Module.createRequire || Module.createRequireFromPath; module.exports = { /** * Resolves a Node module relative to another module * @param {string} moduleName The name of a Node module, or a path to a Node module. - * * @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be * a file rather than a directory, but the file need not actually exist. * @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath` @@ -43,6 +26,8 @@ module.exports = { try { return createRequire(relativeToPath).resolve(moduleName); } catch (error) { + + // This `if` block is for older Node.js than 12.0.0. We can remove this block in the future. if ( typeof error === "object" && error !== null && diff --git a/tools/node_modules/eslint/node_modules/@babel/code-frame/lib/index.js b/tools/node_modules/eslint/node_modules/@babel/code-frame/lib/index.js index 35176fbc0682ca..62945f7782a774 100644 --- a/tools/node_modules/eslint/node_modules/@babel/code-frame/lib/index.js +++ b/tools/node_modules/eslint/node_modules/@babel/code-frame/lib/index.js @@ -6,17 +6,11 @@ Object.defineProperty(exports, "__esModule", { exports.codeFrameColumns = codeFrameColumns; exports.default = _default; -function _highlight() { - const data = _interopRequireWildcard(require("@babel/highlight")); +var _highlight = _interopRequireWildcard(require("@babel/highlight")); - _highlight = function () { - return data; - }; - - return data; -} +function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } let deprecationWarningShown = false; @@ -35,7 +29,7 @@ function getMarkerLines(loc, source, opts) { column: 0, line: -1 }, loc.start); - const endLoc = Object.assign({}, startLoc, loc.end); + const endLoc = Object.assign({}, startLoc, {}, loc.end); const { linesAbove = 2, linesBelow = 3 @@ -94,8 +88,8 @@ function getMarkerLines(loc, source, opts) { } function codeFrameColumns(rawLines, loc, opts = {}) { - const highlighted = (opts.highlightCode || opts.forceColor) && (0, _highlight().shouldHighlight)(opts); - const chalk = (0, _highlight().getChalk)(opts); + const highlighted = (opts.highlightCode || opts.forceColor) && (0, _highlight.shouldHighlight)(opts); + const chalk = (0, _highlight.getChalk)(opts); const defs = getDefs(chalk); const maybeHighlight = (chalkFn, string) => { @@ -110,7 +104,7 @@ function codeFrameColumns(rawLines, loc, opts = {}) { } = getMarkerLines(loc, lines, opts); const hasColumns = loc.start && typeof loc.start.column === "number"; const numberMaxWidth = String(end).length; - const highlightedLines = highlighted ? (0, _highlight().default)(rawLines, opts) : rawLines; + const highlightedLines = highlighted ? (0, _highlight.default)(rawLines, opts) : rawLines; let frame = highlightedLines.split(NEWLINE).slice(start, end).map((line, index) => { const number = start + 1 + index; const paddedNumber = ` ${number}`.slice(-numberMaxWidth); diff --git a/tools/node_modules/eslint/node_modules/@babel/code-frame/package.json b/tools/node_modules/eslint/node_modules/@babel/code-frame/package.json index d619d9a8f53194..7508b5b1402c94 100644 --- a/tools/node_modules/eslint/node_modules/@babel/code-frame/package.json +++ b/tools/node_modules/eslint/node_modules/@babel/code-frame/package.json @@ -5,7 +5,7 @@ }, "bundleDependencies": false, "dependencies": { - "@babel/highlight": "^7.0.0" + "@babel/highlight": "^7.8.3" }, "deprecated": false, "description": "Generate errors that contain a code frame that point to source locations.", @@ -13,7 +13,7 @@ "chalk": "^2.0.0", "strip-ansi": "^4.0.0" }, - "gitHead": "0407f034f09381b95e9cabefbf6b176c76485a43", + "gitHead": "a7620bd266ae1345975767bbc7abf09034437017", "homepage": "https://babeljs.io/", "license": "MIT", "main": "lib/index.js", @@ -25,5 +25,5 @@ "type": "git", "url": "https://github.com/babel/babel/tree/master/packages/babel-code-frame" }, - "version": "7.5.5" + "version": "7.8.3" } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/@babel/highlight/lib/index.js b/tools/node_modules/eslint/node_modules/@babel/highlight/lib/index.js index 6ac5b4a350b8e6..bf275748784b50 100644 --- a/tools/node_modules/eslint/node_modules/@babel/highlight/lib/index.js +++ b/tools/node_modules/eslint/node_modules/@babel/highlight/lib/index.js @@ -7,39 +7,17 @@ exports.shouldHighlight = shouldHighlight; exports.getChalk = getChalk; exports.default = highlight; -function _jsTokens() { - const data = _interopRequireWildcard(require("js-tokens")); +var _jsTokens = _interopRequireWildcard(require("js-tokens")); - _jsTokens = function () { - return data; - }; - - return data; -} - -function _esutils() { - const data = _interopRequireDefault(require("esutils")); +var _esutils = _interopRequireDefault(require("esutils")); - _esutils = function () { - return data; - }; - - return data; -} - -function _chalk() { - const data = _interopRequireDefault(require("chalk")); - - _chalk = function () { - return data; - }; - - return data; -} +var _chalk = _interopRequireDefault(require("chalk")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } +function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function getDefs(chalk) { return { @@ -61,10 +39,10 @@ const BRACKET = /^[()[\]{}]$/; function getTokenType(match) { const [offset, text] = match.slice(-2); - const token = (0, _jsTokens().matchToToken)(match); + const token = (0, _jsTokens.matchToToken)(match); if (token.type === "name") { - if (_esutils().default.keyword.isReservedWordES6(token.value)) { + if (_esutils.default.keyword.isReservedWordES6(token.value)) { return "keyword"; } @@ -89,7 +67,7 @@ function getTokenType(match) { } function highlightTokens(defs, text) { - return text.replace(_jsTokens().default, function (...args) { + return text.replace(_jsTokens.default, function (...args) { const type = getTokenType(args); const colorize = defs[type]; @@ -102,14 +80,14 @@ function highlightTokens(defs, text) { } function shouldHighlight(options) { - return _chalk().default.supportsColor || options.forceColor; + return _chalk.default.supportsColor || options.forceColor; } function getChalk(options) { - let chalk = _chalk().default; + let chalk = _chalk.default; if (options.forceColor) { - chalk = new (_chalk().default.constructor)({ + chalk = new _chalk.default.constructor({ enabled: true, level: 1 }); diff --git a/tools/node_modules/eslint/node_modules/chalk/index.js b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/index.js similarity index 100% rename from tools/node_modules/eslint/node_modules/chalk/index.js rename to tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/index.js diff --git a/tools/node_modules/eslint/node_modules/chalk/index.js.flow b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/index.js.flow similarity index 100% rename from tools/node_modules/eslint/node_modules/chalk/index.js.flow rename to tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/index.js.flow diff --git a/tools/node_modules/eslint/node_modules/string-width/node_modules/strip-ansi/license b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/license similarity index 100% rename from tools/node_modules/eslint/node_modules/string-width/node_modules/strip-ansi/license rename to tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/license diff --git a/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/package.json b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/package.json new file mode 100644 index 00000000000000..270fecdc347d42 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/package.json @@ -0,0 +1,80 @@ +{ + "bugs": { + "url": "https://github.com/chalk/chalk/issues" + }, + "bundleDependencies": false, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "deprecated": false, + "description": "Terminal string styling done right", + "devDependencies": { + "ava": "*", + "coveralls": "^3.0.0", + "execa": "^0.9.0", + "flow-bin": "^0.68.0", + "import-fresh": "^2.0.0", + "matcha": "^0.7.0", + "nyc": "^11.0.2", + "resolve-from": "^4.0.0", + "typescript": "^2.5.3", + "xo": "*" + }, + "engines": { + "node": ">=4" + }, + "files": [ + "index.js", + "templates.js", + "types/index.d.ts", + "index.js.flow" + ], + "homepage": "https://github.com/chalk/chalk#readme", + "keywords": [ + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "str", + "ansi", + "style", + "styles", + "tty", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "log", + "logging", + "command-line", + "text" + ], + "license": "MIT", + "name": "chalk", + "repository": { + "type": "git", + "url": "git+https://github.com/chalk/chalk.git" + }, + "scripts": { + "bench": "matcha benchmark.js", + "coveralls": "nyc report --reporter=text-lcov | coveralls", + "test": "xo && tsc --project types && flow --max-warnings=0 && nyc ava" + }, + "types": "types/index.d.ts", + "version": "2.4.2", + "xo": { + "envs": [ + "node", + "mocha" + ], + "ignores": [ + "test/_flow.js" + ] + } +} \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/readme.md b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/readme.md new file mode 100644 index 00000000000000..d298e2c48d64a0 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/readme.md @@ -0,0 +1,314 @@ +

+
+
+ Chalk +
+
+
+

+ +> Terminal string styling done right + +[![Build Status](https://travis-ci.org/chalk/chalk.svg?branch=master)](https://travis-ci.org/chalk/chalk) [![Coverage Status](https://coveralls.io/repos/github/chalk/chalk/badge.svg?branch=master)](https://coveralls.io/github/chalk/chalk?branch=master) [![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo) [![Mentioned in Awesome Node.js](https://awesome.re/mentioned-badge.svg)](https://github.com/sindresorhus/awesome-nodejs) + +### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0) + + + + +## Highlights + +- Expressive API +- Highly performant +- Ability to nest styles +- [256/Truecolor color support](#256-and-truecolor-color-support) +- Auto-detects color support +- Doesn't extend `String.prototype` +- Clean and focused +- Actively maintained +- [Used by ~23,000 packages](https://www.npmjs.com/browse/depended/chalk) as of December 31, 2017 + + +## Install + +```console +$ npm install chalk +``` + + + + + + +## Usage + +```js +const chalk = require('chalk'); + +console.log(chalk.blue('Hello world!')); +``` + +Chalk comes with an easy to use composable API where you just chain and nest the styles you want. + +```js +const chalk = require('chalk'); +const log = console.log; + +// Combine styled and normal strings +log(chalk.blue('Hello') + ' World' + chalk.red('!')); + +// Compose multiple styles using the chainable API +log(chalk.blue.bgRed.bold('Hello world!')); + +// Pass in multiple arguments +log(chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz')); + +// Nest styles +log(chalk.red('Hello', chalk.underline.bgBlue('world') + '!')); + +// Nest styles of the same type even (color, underline, background) +log(chalk.green( + 'I am a green line ' + + chalk.blue.underline.bold('with a blue substring') + + ' that becomes green again!' +)); + +// ES2015 template literal +log(` +CPU: ${chalk.red('90%')} +RAM: ${chalk.green('40%')} +DISK: ${chalk.yellow('70%')} +`); + +// ES2015 tagged template literal +log(chalk` +CPU: {red ${cpu.totalPercent}%} +RAM: {green ${ram.used / ram.total * 100}%} +DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%} +`); + +// Use RGB colors in terminal emulators that support it. +log(chalk.keyword('orange')('Yay for orange colored text!')); +log(chalk.rgb(123, 45, 67).underline('Underlined reddish color')); +log(chalk.hex('#DEADED').bold('Bold gray!')); +``` + +Easily define your own themes: + +```js +const chalk = require('chalk'); + +const error = chalk.bold.red; +const warning = chalk.keyword('orange'); + +console.log(error('Error!')); +console.log(warning('Warning!')); +``` + +Take advantage of console.log [string substitution](https://nodejs.org/docs/latest/api/console.html#console_console_log_data_args): + +```js +const name = 'Sindre'; +console.log(chalk.green('Hello %s'), name); +//=> 'Hello Sindre' +``` + + +## API + +### chalk.`