Comparing version 9.0.0 to 9.1.0
@@ -151,14 +151,2 @@ #!/usr/bin/env node | ||
// Call the config inspector if `--inspect-config` is present. | ||
if (process.argv.includes("--inspect-config")) { | ||
console.warn("You can also run this command directly using 'npx @eslint/config-inspector' in the same directory as your configuration file."); | ||
const spawn = require("cross-spawn"); | ||
spawn.sync("npx", ["@eslint/config-inspector"], { encoding: "utf8", stdio: "inherit" }); | ||
return; | ||
} | ||
// Otherwise, call the CLI. | ||
@@ -165,0 +153,0 @@ const cli = require("../lib/cli"); |
@@ -73,2 +73,3 @@ /** | ||
Int8Array: false, | ||
Intl: false, | ||
Map: false, | ||
@@ -75,0 +76,0 @@ Promise: false, |
@@ -22,3 +22,3 @@ /** | ||
{ LegacyESLint } = require("./eslint"), | ||
{ ESLint, shouldUseFlatConfig } = require("./eslint/eslint"), | ||
{ ESLint, shouldUseFlatConfig, locateConfigFileToUse } = require("./eslint/eslint"), | ||
createCLIOptions = require("./options"), | ||
@@ -341,2 +341,23 @@ log = require("./shared/logging"), | ||
/** | ||
* Calculates the command string for the --inspect-config operation. | ||
* @param {string} configFile The path to the config file to inspect. | ||
* @returns {Promise<string>} The command string to execute. | ||
*/ | ||
async calculateInspectConfigFlags(configFile) { | ||
// find the config file | ||
const { | ||
configFilePath, | ||
basePath, | ||
error | ||
} = await locateConfigFileToUse({ cwd: process.cwd(), configFile }); | ||
if (error) { | ||
throw error; | ||
} | ||
return ["--config", configFilePath, "--basePath", basePath]; | ||
}, | ||
/** | ||
* Executes the CLI based on an array of arguments that is passed in. | ||
@@ -430,2 +451,20 @@ * @param {string|Array|Object} args The arguments to process. | ||
if (options.inspectConfig) { | ||
log.info("You can also run this command directly using 'npx @eslint/config-inspector' in the same directory as your configuration file."); | ||
try { | ||
const flatOptions = await translateOptions(options, "flat"); | ||
const spawn = require("cross-spawn"); | ||
const flags = await cli.calculateInspectConfigFlags(flatOptions.overrideConfigFile); | ||
spawn.sync("npx", ["@eslint/config-inspector", ...flags], { encoding: "utf8", stdio: "inherit" }); | ||
} catch (error) { | ||
log.error(error); | ||
return 2; | ||
} | ||
return 0; | ||
} | ||
debug(`Running on ${useStdin ? "text" : "files"}`); | ||
@@ -432,0 +471,0 @@ |
@@ -21,2 +21,7 @@ /** | ||
/** | ||
* Fields that are considered metadata and not part of the config object. | ||
*/ | ||
const META_FIELDS = new Set(["name"]); | ||
const ruleValidator = new RuleValidator(); | ||
@@ -78,3 +83,49 @@ | ||
/** | ||
* Wraps a config error with details about where the error occurred. | ||
* @param {Error} error The original error. | ||
* @param {number} originalLength The original length of the config array. | ||
* @param {number} baseLength The length of the base config. | ||
* @returns {TypeError} The new error with details. | ||
*/ | ||
function wrapConfigErrorWithDetails(error, originalLength, baseLength) { | ||
let location = "user-defined"; | ||
let configIndex = error.index; | ||
/* | ||
* A config array is set up in this order: | ||
* 1. Base config | ||
* 2. Original configs | ||
* 3. User-defined configs | ||
* 4. CLI-defined configs | ||
* | ||
* So we need to adjust the index to account for the base config. | ||
* | ||
* - If the index is less than the base length, it's in the base config | ||
* (as specified by `baseConfig` argument to `FlatConfigArray` constructor). | ||
* - If the index is greater than the base length but less than the original | ||
* length + base length, it's in the original config. The original config | ||
* is passed to the `FlatConfigArray` constructor as the first argument. | ||
* - Otherwise, it's in the user-defined config, which is loaded from the | ||
* config file and merged with any command-line options. | ||
*/ | ||
if (error.index < baseLength) { | ||
location = "base"; | ||
} else if (error.index < originalLength + baseLength) { | ||
location = "original"; | ||
configIndex = error.index - baseLength; | ||
} else { | ||
configIndex = error.index - originalLength - baseLength; | ||
} | ||
return new TypeError( | ||
`${error.message.slice(0, -1)} at ${location} index ${configIndex}.`, | ||
{ cause: error } | ||
); | ||
} | ||
const originalBaseConfig = Symbol("originalBaseConfig"); | ||
const originalLength = Symbol("originalLength"); | ||
const baseLength = Symbol("baseLength"); | ||
@@ -106,2 +157,8 @@ //----------------------------------------------------------------------------- | ||
/** | ||
* The original length of the array before any modifications. | ||
* @type {number} | ||
*/ | ||
this[originalLength] = this.length; | ||
if (baseConfig[Symbol.iterator]) { | ||
@@ -114,2 +171,8 @@ this.unshift(...baseConfig); | ||
/** | ||
* The length of the array after applying the base config. | ||
* @type {number} | ||
*/ | ||
this[baseLength] = this.length - this[originalLength]; | ||
/** | ||
* The base config used to build the config array. | ||
@@ -131,2 +194,45 @@ * @type {Array<FlatConfig>} | ||
/** | ||
* Normalizes the array by calling the superclass method and catching/rethrowing | ||
* any ConfigError exceptions with additional details. | ||
* @param {any} [context] The context to use to normalize the array. | ||
* @returns {Promise<FlatConfigArray>} A promise that resolves when the array is normalized. | ||
*/ | ||
normalize(context) { | ||
return super.normalize(context) | ||
.catch(error => { | ||
if (error.name === "ConfigError") { | ||
throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]); | ||
} | ||
throw error; | ||
}); | ||
} | ||
/** | ||
* Normalizes the array by calling the superclass method and catching/rethrowing | ||
* any ConfigError exceptions with additional details. | ||
* @param {any} [context] The context to use to normalize the array. | ||
* @returns {FlatConfigArray} The current instance. | ||
* @throws {TypeError} If the config is invalid. | ||
*/ | ||
normalizeSync(context) { | ||
try { | ||
return super.normalizeSync(context); | ||
} catch (error) { | ||
if (error.name === "ConfigError") { | ||
throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]); | ||
} | ||
throw error; | ||
} | ||
} | ||
/* eslint-disable class-methods-use-this -- Desired as instance method */ | ||
@@ -143,5 +249,5 @@ /** | ||
/* | ||
* If `shouldIgnore` is false, we remove any ignore patterns specified | ||
* in the config so long as it's not a default config and it doesn't | ||
* have a `files` entry. | ||
* If a config object has `ignores` and no other non-meta fields, then it's an object | ||
* for global ignores. If `shouldIgnore` is false, that object shouldn't apply, | ||
* so we'll remove its `ignores`. | ||
*/ | ||
@@ -152,3 +258,3 @@ if ( | ||
config.ignores && | ||
!config.files | ||
Object.keys(config).filter(key => !META_FIELDS.has(key)).length === 1 | ||
) { | ||
@@ -155,0 +261,0 @@ /* eslint-disable-next-line no-unused-vars -- need to strip off other keys */ |
@@ -18,3 +18,2 @@ /** | ||
const minimatch = require("minimatch"); | ||
const util = require("util"); | ||
const fswalk = require("@nodelib/fs.walk"); | ||
@@ -28,3 +27,2 @@ const globParent = require("glob-parent"); | ||
const doFsWalk = util.promisify(fswalk.walk); | ||
const Minimatch = minimatch.Minimatch; | ||
@@ -285,52 +283,88 @@ const MINIMATCH_OPTIONS = { dot: true }; | ||
const filePaths = (await doFsWalk(basePath, { | ||
const filePaths = (await new Promise((resolve, reject) => { | ||
deepFilter(entry) { | ||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path)); | ||
const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true)); | ||
let promiseRejected = false; | ||
return matchesPattern && !configs.isDirectoryIgnored(entry.path); | ||
}, | ||
entryFilter(entry) { | ||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path)); | ||
/** | ||
* Wraps a boolean-returning filter function. The wrapped function will reject the promise if an error occurs. | ||
* @param {Function} filter A filter function to wrap. | ||
* @returns {Function} A function similar to the wrapped filter that rejects the promise if an error occurs. | ||
*/ | ||
function wrapFilter(filter) { | ||
return (...args) => { | ||
// entries may be directories or files so filter out directories | ||
if (entry.dirent.isDirectory()) { | ||
// No need to run the filter if an error has been thrown. | ||
if (!promiseRejected) { | ||
try { | ||
return filter(...args); | ||
} catch (error) { | ||
promiseRejected = true; | ||
reject(error); | ||
} | ||
} | ||
return false; | ||
} | ||
}; | ||
} | ||
/* | ||
* Optimization: We need to track when patterns are left unmatched | ||
* and so we use `unmatchedPatterns` to do that. There is a bit of | ||
* complexity here because the same file can be matched by more than | ||
* one pattern. So, when we start, we actually need to test every | ||
* pattern against every file. Once we know there are no remaining | ||
* unmatched patterns, then we can switch to just looking for the | ||
* first matching pattern for improved speed. | ||
*/ | ||
const matchesPattern = unmatchedPatterns.size > 0 | ||
? matchers.reduce((previousValue, matcher) => { | ||
const pathMatches = matcher.match(relativePath); | ||
fswalk.walk( | ||
basePath, | ||
{ | ||
deepFilter: wrapFilter(entry => { | ||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path)); | ||
const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true)); | ||
return matchesPattern && !configs.isDirectoryIgnored(entry.path); | ||
}), | ||
entryFilter: wrapFilter(entry => { | ||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path)); | ||
// entries may be directories or files so filter out directories | ||
if (entry.dirent.isDirectory()) { | ||
return false; | ||
} | ||
/* | ||
* We updated the unmatched patterns set only if the path | ||
* matches and the file isn't ignored. If the file is | ||
* ignored, that means there wasn't a match for the | ||
* pattern so it should not be removed. | ||
* | ||
* Performance note: isFileIgnored() aggressively caches | ||
* results so there is no performance penalty for calling | ||
* it twice with the same argument. | ||
* Optimization: We need to track when patterns are left unmatched | ||
* and so we use `unmatchedPatterns` to do that. There is a bit of | ||
* complexity here because the same file can be matched by more than | ||
* one pattern. So, when we start, we actually need to test every | ||
* pattern against every file. Once we know there are no remaining | ||
* unmatched patterns, then we can switch to just looking for the | ||
* first matching pattern for improved speed. | ||
*/ | ||
if (pathMatches && !configs.isFileIgnored(entry.path)) { | ||
unmatchedPatterns.delete(matcher.pattern); | ||
} | ||
const matchesPattern = unmatchedPatterns.size > 0 | ||
? matchers.reduce((previousValue, matcher) => { | ||
const pathMatches = matcher.match(relativePath); | ||
return pathMatches || previousValue; | ||
}, false) | ||
: matchers.some(matcher => matcher.match(relativePath)); | ||
/* | ||
* We updated the unmatched patterns set only if the path | ||
* matches and the file isn't ignored. If the file is | ||
* ignored, that means there wasn't a match for the | ||
* pattern so it should not be removed. | ||
* | ||
* Performance note: isFileIgnored() aggressively caches | ||
* results so there is no performance penalty for calling | ||
* it twice with the same argument. | ||
*/ | ||
if (pathMatches && !configs.isFileIgnored(entry.path)) { | ||
unmatchedPatterns.delete(matcher.pattern); | ||
} | ||
return matchesPattern && !configs.isFileIgnored(entry.path); | ||
} | ||
return pathMatches || previousValue; | ||
}, false) | ||
: matchers.some(matcher => matcher.match(relativePath)); | ||
return matchesPattern && !configs.isFileIgnored(entry.path); | ||
}) | ||
}, | ||
(error, entries) => { | ||
// If the promise is already rejected, calling `resolve` or `reject` will do nothing. | ||
if (error) { | ||
reject(error); | ||
} else { | ||
resolve(entries); | ||
} | ||
} | ||
); | ||
})).map(entry => entry.path); | ||
@@ -337,0 +371,0 @@ |
@@ -45,2 +45,3 @@ /** | ||
const LintResultCache = require("../cli-engine/lint-result-cache"); | ||
const { Retrier } = require("@humanwhocodes/retry"); | ||
@@ -855,2 +856,4 @@ /* | ||
const controller = new AbortController(); | ||
const retryCodes = new Set(["ENFILE", "EMFILE"]); | ||
const retrier = new Retrier(error => retryCodes.has(error.code)); | ||
@@ -924,3 +927,3 @@ debug(`${filePaths.length} files found in: ${Date.now() - startTime}ms`); | ||
return fs.readFile(filePath, { encoding: "utf8", signal: controller.signal }) | ||
return retrier.retry(() => fs.readFile(filePath, { encoding: "utf8", signal: controller.signal }) | ||
.then(text => { | ||
@@ -955,7 +958,7 @@ | ||
return result; | ||
}).catch(error => { | ||
})) | ||
.catch(error => { | ||
controller.abort(error); | ||
throw error; | ||
}); | ||
}) | ||
@@ -1221,3 +1224,4 @@ ); | ||
ESLint, | ||
shouldUseFlatConfig | ||
shouldUseFlatConfig, | ||
locateConfigFileToUse | ||
}; |
@@ -41,12 +41,12 @@ /** | ||
*/ | ||
function groupByParentComment(directives) { | ||
function groupByParentDirective(directives) { | ||
const groups = new Map(); | ||
for (const directive of directives) { | ||
const { unprocessedDirective: { parentComment } } = directive; | ||
const { unprocessedDirective: { parentDirective } } = directive; | ||
if (groups.has(parentComment)) { | ||
groups.get(parentComment).push(directive); | ||
if (groups.has(parentDirective)) { | ||
groups.get(parentDirective).push(directive); | ||
} else { | ||
groups.set(parentComment, [directive]); | ||
groups.set(parentDirective, [directive]); | ||
} | ||
@@ -61,15 +61,15 @@ } | ||
* @param {Directive[]} directives Unused directives to be removed. | ||
* @param {Token} commentToken The backing Comment token. | ||
* @param {Token} node The backing Comment token. | ||
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems. | ||
*/ | ||
function createIndividualDirectivesRemoval(directives, commentToken) { | ||
function createIndividualDirectivesRemoval(directives, node) { | ||
/* | ||
* `commentToken.value` starts right after `//` or `/*`. | ||
* `node.value` starts right after `//` or `/*`. | ||
* All calculated offsets will be relative to this index. | ||
*/ | ||
const commentValueStart = commentToken.range[0] + "//".length; | ||
const commentValueStart = node.range[0] + "//".length; | ||
// Find where the list of rules starts. `\S+` matches with the directive name (e.g. `eslint-disable-line`) | ||
const listStartOffset = /^\s*\S+\s+/u.exec(commentToken.value)[0].length; | ||
const listStartOffset = /^\s*\S+\s+/u.exec(node.value)[0].length; | ||
@@ -83,3 +83,3 @@ /* | ||
*/ | ||
const listText = commentToken.value | ||
const listText = node.value | ||
.slice(listStartOffset) // remove directive name and all whitespace before the list | ||
@@ -165,9 +165,9 @@ .split(/\s-{2,}\s/u)[0] // remove `-- comment`, if it exists | ||
/** | ||
* Creates a description of deleting an entire unused disable comment. | ||
* Creates a description of deleting an entire unused disable directive. | ||
* @param {Directive[]} directives Unused directives to be removed. | ||
* @param {Token} commentToken The backing Comment token. | ||
* @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output Problem. | ||
* @param {Token} node The backing Comment token. | ||
* @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output problem. | ||
*/ | ||
function createCommentRemoval(directives, commentToken) { | ||
const { range } = commentToken; | ||
function createDirectiveRemoval(directives, node) { | ||
const { range } = node; | ||
const ruleIds = directives.filter(directive => directive.ruleId).map(directive => `'${directive.ruleId}'`); | ||
@@ -193,8 +193,8 @@ | ||
function processUnusedDirectives(allDirectives) { | ||
const directiveGroups = groupByParentComment(allDirectives); | ||
const directiveGroups = groupByParentDirective(allDirectives); | ||
return directiveGroups.flatMap( | ||
directives => { | ||
const { parentComment } = directives[0].unprocessedDirective; | ||
const remainingRuleIds = new Set(parentComment.ruleIds); | ||
const { parentDirective } = directives[0].unprocessedDirective; | ||
const remainingRuleIds = new Set(parentDirective.ruleIds); | ||
@@ -206,4 +206,4 @@ for (const directive of directives) { | ||
return remainingRuleIds.size | ||
? createIndividualDirectivesRemoval(directives, parentComment.commentToken) | ||
: [createCommentRemoval(directives, parentComment.commentToken)]; | ||
? createIndividualDirectivesRemoval(directives, parentDirective.node) | ||
: [createDirectiveRemoval(directives, parentDirective.node)]; | ||
} | ||
@@ -381,3 +381,3 @@ ); | ||
.map(({ description, fix, unprocessedDirective }) => { | ||
const { parentComment, type, line, column } = unprocessedDirective; | ||
const { parentDirective, type, line, column } = unprocessedDirective; | ||
@@ -398,4 +398,4 @@ let message; | ||
message, | ||
line: type === "disable-next-line" ? parentComment.commentToken.loc.start.line : line, | ||
column: type === "disable-next-line" ? parentComment.commentToken.loc.start.column + 1 : column, | ||
line: type === "disable-next-line" ? parentDirective.node.loc.start.line : line, | ||
column: type === "disable-next-line" ? parentDirective.node.loc.start.column + 1 : column, | ||
severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2, | ||
@@ -402,0 +402,0 @@ nodeType: null, |
@@ -41,3 +41,3 @@ /** | ||
* @property {string} [ignorePath] Specify path of ignore file | ||
* @property {string[]} [ignorePattern] Pattern of files to ignore (in addition to those in .eslintignore) | ||
* @property {string[]} [ignorePattern] Patterns of files to ignore. In eslintrc mode, these are in addition to `.eslintignore` | ||
* @property {boolean} init Run config initialization wizard | ||
@@ -265,3 +265,3 @@ * @property {boolean} inlineConfig Prevent comments from changing config or rules | ||
type: "[String]", | ||
description: "Pattern of files to ignore (in addition to those in .eslintignore)", | ||
description: `Patterns of files to ignore${usingFlatConfig ? "" : " (in addition to those in .eslintignore)"}`, | ||
concatRepeatedArrays: [true, { | ||
@@ -268,0 +268,0 @@ oneValuePerFlag: true |
@@ -34,4 +34,3 @@ /** | ||
checkLoops: { | ||
type: "boolean", | ||
default: true | ||
enum: ["all", "allExceptWhileTrue", "none", true, false] | ||
} | ||
@@ -49,7 +48,13 @@ }, | ||
create(context) { | ||
const options = context.options[0] || {}, | ||
checkLoops = options.checkLoops !== false, | ||
loopSetStack = []; | ||
const options = context.options[0] || {}; | ||
let checkLoops = options.checkLoops ?? "allExceptWhileTrue"; | ||
const loopSetStack = []; | ||
const sourceCode = context.sourceCode; | ||
if (options.checkLoops === true) { | ||
checkLoops = "all"; | ||
} else if (options.checkLoops === false) { | ||
checkLoops = "none"; | ||
} | ||
let loopsInCurrentScope = new Set(); | ||
@@ -125,3 +130,3 @@ | ||
function checkLoop(node) { | ||
if (checkLoops) { | ||
if (checkLoops === "all" || checkLoops === "allExceptWhileTrue") { | ||
trackConstantConditionLoop(node); | ||
@@ -138,3 +143,9 @@ } | ||
IfStatement: reportIfConstant, | ||
WhileStatement: checkLoop, | ||
WhileStatement(node) { | ||
if (node.test.type === "Literal" && node.test.value === true && checkLoops === "allExceptWhileTrue") { | ||
return; | ||
} | ||
checkLoop(node); | ||
}, | ||
"WhileStatement:exit": checkConstantConditionLoopInSet, | ||
@@ -141,0 +152,0 @@ DoWhileStatement: checkLoop, |
@@ -9,8 +9,2 @@ /** | ||
//------------------------------------------------------------------------------ | ||
// Requirements | ||
//------------------------------------------------------------------------------ | ||
const Graphemer = require("graphemer").default; | ||
//------------------------------------------------------------------------------ | ||
// Helpers | ||
@@ -22,4 +16,4 @@ //------------------------------------------------------------------------------ | ||
/** @type {Graphemer | undefined} */ | ||
let splitter; | ||
/** @type {Intl.Segmenter | undefined} */ | ||
let segmenter; | ||
@@ -52,7 +46,11 @@ //------------------------------------------------------------------------------ | ||
if (!splitter) { | ||
splitter = new Graphemer(); | ||
segmenter ??= new Intl.Segmenter("en-US"); // en-US locale should be supported everywhere | ||
let graphemeCount = 0; | ||
// eslint-disable-next-line no-unused-vars -- for-of needs a variable | ||
for (const unused of segmenter.segment(value)) { | ||
graphemeCount++; | ||
} | ||
return splitter.countGraphemes(value); | ||
return graphemeCount; | ||
} | ||
@@ -59,0 +57,0 @@ |
@@ -376,2 +376,52 @@ /** | ||
/** | ||
* A class to represent a directive comment. | ||
*/ | ||
class Directive { | ||
/** | ||
* The type of directive. | ||
* @type {"disable"|"enable"|"disable-next-line"|"disable-line"} | ||
* @readonly | ||
*/ | ||
type; | ||
/** | ||
* The node representing the directive. | ||
* @type {ASTNode|Comment} | ||
* @readonly | ||
*/ | ||
node; | ||
/** | ||
* Everything after the "eslint-disable" portion of the directive, | ||
* but before the "--" that indicates the justification. | ||
* @type {string} | ||
* @readonly | ||
*/ | ||
value; | ||
/** | ||
* The justification for the directive. | ||
* @type {string} | ||
* @readonly | ||
*/ | ||
justification; | ||
/** | ||
* Creates a new instance. | ||
* @param {Object} options The options for the directive. | ||
* @param {"disable"|"enable"|"disable-next-line"|"disable-line"} options.type The type of directive. | ||
* @param {ASTNode|Comment} options.node The node representing the directive. | ||
* @param {string} options.value The value of the directive. | ||
* @param {string} options.justification The justification for the directive. | ||
*/ | ||
constructor({ type, node, value, justification }) { | ||
this.type = type; | ||
this.node = node; | ||
this.value = value; | ||
this.justification = justification; | ||
} | ||
} | ||
//------------------------------------------------------------------------------ | ||
@@ -926,2 +976,80 @@ // Public Interface | ||
/** | ||
* Returns an all directive nodes that enable or disable rules along with any problems | ||
* encountered while parsing the directives. | ||
* @returns {{problems:Array<Problem>,directives:Array<Directive>}} Information | ||
* that ESLint needs to further process the directives. | ||
*/ | ||
getDisableDirectives() { | ||
// check the cache first | ||
const cachedDirectives = this[caches].get("disableDirectives"); | ||
if (cachedDirectives) { | ||
return cachedDirectives; | ||
} | ||
const problems = []; | ||
const directives = []; | ||
this.getInlineConfigNodes().forEach(comment => { | ||
const { directivePart, justificationPart } = commentParser.extractDirectiveComment(comment.value); | ||
// Step 1: Extract the directive text | ||
const match = directivesPattern.exec(directivePart); | ||
if (!match) { | ||
return; | ||
} | ||
const directiveText = match[1]; | ||
// Step 2: Extract the directive value | ||
const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(directiveText); | ||
if (comment.type === "Line" && !lineCommentSupported) { | ||
return; | ||
} | ||
// Step 3: Validate the directive does not span multiple lines | ||
if (directiveText === "eslint-disable-line" && comment.loc.start.line !== comment.loc.end.line) { | ||
const message = `${directiveText} comment should not span multiple lines.`; | ||
problems.push({ | ||
ruleId: null, | ||
message, | ||
loc: comment.loc | ||
}); | ||
return; | ||
} | ||
// Step 4: Extract the directive value and create the Directive object | ||
const directiveValue = directivePart.slice(match.index + directiveText.length); | ||
switch (directiveText) { | ||
case "eslint-disable": | ||
case "eslint-enable": | ||
case "eslint-disable-next-line": | ||
case "eslint-disable-line": { | ||
const directiveType = directiveText.slice("eslint-".length); | ||
directives.push(new Directive({ | ||
type: directiveType, | ||
node: comment, | ||
value: directiveValue, | ||
justification: justificationPart | ||
})); | ||
} | ||
// no default | ||
} | ||
}); | ||
const result = { problems, directives }; | ||
this[caches].set("disableDirectives", result); | ||
return result; | ||
} | ||
/** | ||
* Applies language options sent in from the core. | ||
@@ -928,0 +1056,0 @@ * @param {Object} languageOptions The language options for this run. |
{ | ||
"name": "eslint", | ||
"version": "9.0.0", | ||
"version": "9.1.0", | ||
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>", | ||
@@ -36,3 +36,4 @@ "description": "An AST-based pattern checker for JavaScript.", | ||
"test:fuzz": "node Makefile.js fuzz", | ||
"test:performance": "node Makefile.js perf" | ||
"test:performance": "node Makefile.js perf", | ||
"test:emfile": "node tools/check-emfile-handling.js" | ||
}, | ||
@@ -72,5 +73,6 @@ "gitHooks": { | ||
"@eslint/eslintrc": "^3.0.2", | ||
"@eslint/js": "9.0.0", | ||
"@humanwhocodes/config-array": "^0.12.3", | ||
"@eslint/js": "9.1.1", | ||
"@humanwhocodes/config-array": "^0.13.0", | ||
"@humanwhocodes/module-importer": "^1.0.1", | ||
"@humanwhocodes/retry": "^0.2.3", | ||
"@nodelib/fs.walk": "^1.2.8", | ||
@@ -91,3 +93,2 @@ "ajv": "^6.12.4", | ||
"glob-parent": "^6.0.2", | ||
"graphemer": "^1.4.0", | ||
"ignore": "^5.2.0", | ||
@@ -126,3 +127,3 @@ "imurmurhash": "^0.1.4", | ||
"eslint-plugin-eslint-comments": "^3.2.0", | ||
"eslint-plugin-eslint-plugin": "^5.2.1", | ||
"eslint-plugin-eslint-plugin": "^6.0.0", | ||
"eslint-plugin-internal-rules": "file:tools/internal-rules", | ||
@@ -138,3 +139,3 @@ "eslint-plugin-jsdoc": "^46.9.0", | ||
"glob": "^10.0.0", | ||
"globals": "^14.0.0", | ||
"globals": "^15.0.0", | ||
"got": "^11.8.3", | ||
@@ -141,0 +142,0 @@ "gray-matter": "^4.0.3", |
@@ -62,3 +62,3 @@ [![npm version](https://img.shields.io/npm/v/eslint.svg)](https://www.npmjs.com/package/eslint) | ||
After running `npm init @eslint/config`, you'll have an `eslint.config.js` or `eslint.config.mjs` file in your directory. In it, you'll see some rules configured like this: | ||
After running `npm init @eslint/config`, you'll have an `eslint.config.js` (or `eslint.config.mjs`) file in your directory. In it, you'll see some rules configured like this: | ||
@@ -304,3 +304,3 @@ ```js | ||
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3> | ||
<p><a href="https://bitwarden.com"><img src="https://avatars.githubusercontent.com/u/15990069?v=4" alt="Bitwarden" height="96"></a> <a href="https://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a></p><h3>Silver Sponsors</h3> | ||
<p><a href="https://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a></p><h3>Silver Sponsors</h3> | ||
<p><a href="https://www.jetbrains.com/"><img src="https://images.opencollective.com/jetbrains/eb04ddc/logo.png" alt="JetBrains" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="64"></a> <a href="https://www.workleap.com"><img src="https://avatars.githubusercontent.com/u/53535748?u=d1e55d7661d724bf2281c1bfd33cb8f99fe2465f&v=4" alt="Workleap" height="64"></a></p><h3>Bronze Sponsors</h3> | ||
@@ -307,0 +307,0 @@ <p><a href="https://www.notion.so"><img src="https://images.opencollective.com/notion/bf3b117/logo.png" alt="notion" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://transloadit.com/"><img src="https://avatars.githubusercontent.com/u/125754?v=4" alt="Transloadit" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104?v=4" alt="Nx" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://usenextbase.com"><img src="https://avatars.githubusercontent.com/u/145838380?v=4" alt="Nextbase Starter Kit" height="32"></a></p> |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3034432
71399
+ Added@humanwhocodes/retry@^0.2.3
+ Added@eslint/js@9.1.1(transitive)
+ Added@humanwhocodes/config-array@0.13.0(transitive)
+ Added@humanwhocodes/retry@0.2.4(transitive)
- Removedgraphemer@^1.4.0
- Removed@eslint/js@9.0.0(transitive)
- Removed@humanwhocodes/config-array@0.12.3(transitive)
- Removedgraphemer@1.4.0(transitive)
Updated@eslint/js@9.1.1