Comparing version 8.50.0 to 8.51.0
@@ -96,2 +96,10 @@ #!/usr/bin/env node | ||
/** | ||
* Tracks error messages that are shown to the user so we only ever show the | ||
* same message once. | ||
* @type {Set<string>} | ||
*/ | ||
const displayedErrors = new Set(); | ||
/** | ||
* Catch and report unexpected error. | ||
@@ -105,5 +113,3 @@ * @param {any} error The thrown error object. | ||
const { version } = require("../package.json"); | ||
const message = getErrorMessage(error); | ||
console.error(` | ||
const message = ` | ||
Oops! Something went wrong! :( | ||
@@ -113,3 +119,8 @@ | ||
${message}`); | ||
${getErrorMessage(error)}`; | ||
if (!displayedErrors.has(message)) { | ||
console.error(message); | ||
displayedErrors.add(message); | ||
} | ||
} | ||
@@ -116,0 +127,0 @@ |
@@ -94,3 +94,4 @@ /** | ||
rule, | ||
rulesdir | ||
rulesdir, | ||
warnIgnored | ||
}, configType) { | ||
@@ -186,2 +187,3 @@ | ||
options.ignorePatterns = ignorePattern; | ||
options.warnIgnored = warnIgnored; | ||
} else { | ||
@@ -390,3 +392,5 @@ options.resolvePluginsRelativeTo = resolvePluginsRelativeTo; | ||
filePath: options.stdinFilename, | ||
warnIgnored: true | ||
// flatConfig respects CLI flag and constructor warnIgnored, eslintrc forces true for backwards compatibility | ||
warnIgnored: usingFlatConfig ? void 0 : true | ||
}); | ||
@@ -393,0 +397,0 @@ } else { |
@@ -182,5 +182,3 @@ /** | ||
function assertIsRuleSeverity(ruleId, value) { | ||
const severity = typeof value === "string" | ||
? ruleSeverities.get(value.toLowerCase()) | ||
: ruleSeverities.get(value); | ||
const severity = ruleSeverities.get(value); | ||
@@ -187,0 +185,0 @@ if (typeof severity === "undefined") { |
@@ -597,5 +597,5 @@ /** | ||
if (isInNodeModules) { | ||
message = "File ignored by default because it is located under the node_modules directory. Use ignore pattern \"!**/node_modules/\" to override."; | ||
message = "File ignored by default because it is located under the node_modules directory. Use ignore pattern \"!**/node_modules/\" to disable file ignore settings or use \"--no-warn-ignored\" to suppress this warning."; | ||
} else { | ||
message = "File ignored because of a matching ignore pattern. Use \"--no-ignore\" to override."; | ||
message = "File ignored because of a matching ignore pattern. Use \"--no-ignore\" to disable file ignore settings or use \"--no-warn-ignored\" to suppress this warning."; | ||
} | ||
@@ -680,2 +680,3 @@ | ||
reportUnusedDisableDirectives = null, // ← should be null by default because if it's a string then it overrides the 'reportUnusedDisableDirectives' setting in config files. And we cannot use `overrideConfig.reportUnusedDisableDirectives` instead because we cannot configure the `error` severity with that. | ||
warnIgnored = true, | ||
...unknownOptions | ||
@@ -786,2 +787,5 @@ }) { | ||
} | ||
if (typeof warnIgnored !== "boolean") { | ||
errors.push("'warnIgnored' must be a boolean."); | ||
} | ||
if (errors.length > 0) { | ||
@@ -808,3 +812,4 @@ throw new ESLintInvalidOptionsError(errors); | ||
ignorePatterns, | ||
reportUnusedDisableDirectives | ||
reportUnusedDisableDirectives, | ||
warnIgnored | ||
}; | ||
@@ -811,0 +816,0 @@ } |
@@ -87,2 +87,3 @@ /** | ||
* @property {"error" | "warn" | "off"} [reportUnusedDisableDirectives] the severity to report unused eslint-disable directives. | ||
* @property {boolean} warnIgnored Show warnings when the file list includes ignored files | ||
*/ | ||
@@ -753,3 +754,4 @@ | ||
globInputPaths, | ||
errorOnUnmatchedPattern | ||
errorOnUnmatchedPattern, | ||
warnIgnored | ||
} = eslintOptions; | ||
@@ -800,3 +802,7 @@ const startTime = Date.now(); | ||
if (ignored) { | ||
return createIgnoreResult(filePath, cwd); | ||
if (warnIgnored) { | ||
return createIgnoreResult(filePath, cwd); | ||
} | ||
return void 0; | ||
} | ||
@@ -914,3 +920,3 @@ | ||
filePath, | ||
warnIgnored = false, | ||
warnIgnored, | ||
...unknownOptions | ||
@@ -929,3 +935,3 @@ } = options || {}; | ||
if (typeof warnIgnored !== "boolean") { | ||
if (typeof warnIgnored !== "boolean" && typeof warnIgnored !== "undefined") { | ||
throw new Error("'options.warnIgnored' must be a boolean or undefined"); | ||
@@ -945,3 +951,4 @@ } | ||
fix, | ||
reportUnusedDisableDirectives | ||
reportUnusedDisableDirectives, | ||
warnIgnored: constructorWarnIgnored | ||
} = eslintOptions; | ||
@@ -954,3 +961,5 @@ const results = []; | ||
if (resolvedFilename && await this.isPathIgnored(resolvedFilename)) { | ||
if (warnIgnored) { | ||
const shouldWarnIgnored = typeof warnIgnored === "boolean" ? warnIgnored : constructorWarnIgnored; | ||
if (shouldWarnIgnored) { | ||
results.push(createIgnoreResult(resolvedFilename, cwd)); | ||
@@ -957,0 +966,0 @@ } |
@@ -90,3 +90,3 @@ /** | ||
const regex = new RegExp(String.raw`(?:^|\s*,\s*)${escapeRegExp(ruleId)}(?:\s*,\s*|$)`, "u"); | ||
const regex = new RegExp(String.raw`(?:^|\s*,\s*)(?<quote>['"]?)${escapeRegExp(ruleId)}\k<quote>(?:\s*,\s*|$)`, "u"); | ||
const match = regex.exec(listText); | ||
@@ -93,0 +93,0 @@ const matchedText = match[0]; |
@@ -83,3 +83,5 @@ /** | ||
/** | ||
* The initial code path segment. | ||
* The initial code path segment. This is the segment that is at the head | ||
* of the code path. | ||
* This is a passthrough to the underlying `CodePathState`. | ||
* @type {CodePathSegment} | ||
@@ -92,4 +94,6 @@ */ | ||
/** | ||
* Final code path segments. | ||
* This array is a mix of `returnedSegments` and `thrownSegments`. | ||
* Final code path segments. These are the terminal (tail) segments in the | ||
* code path, which is the combination of `returnedSegments` and `thrownSegments`. | ||
* All segments in this array are reachable. | ||
* This is a passthrough to the underlying `CodePathState`. | ||
* @type {CodePathSegment[]} | ||
@@ -102,5 +106,10 @@ */ | ||
/** | ||
* Final code path segments which is with `return` statements. | ||
* This array contains the last path segment if it's reachable. | ||
* Since the reachable last path returns `undefined`. | ||
* Final code path segments that represent normal completion of the code path. | ||
* For functions, this means both explicit `return` statements and implicit returns, | ||
* such as the last reachable segment in a function that does not have an | ||
* explicit `return` as this implicitly returns `undefined`. For scripts, | ||
* modules, class field initializers, and class static blocks, this means | ||
* all lines of code have been executed. | ||
* These segments are also present in `finalSegments`. | ||
* This is a passthrough to the underlying `CodePathState`. | ||
* @type {CodePathSegment[]} | ||
@@ -113,3 +122,5 @@ */ | ||
/** | ||
* Final code path segments which is with `throw` statements. | ||
* Final code path segments that represent `throw` statements. | ||
* This is a passthrough to the underlying `CodePathState`. | ||
* These segments are also present in `finalSegments`. | ||
* @type {CodePathSegment[]} | ||
@@ -122,3 +133,8 @@ */ | ||
/** | ||
* Current code path segments. | ||
* Tracks the traversal of the code path through each segment. This array | ||
* starts empty and segments are added or removed as the code path is | ||
* traversed. This array always ends up empty at the end of a code path | ||
* traversal. The `CodePathState` uses this to track its progress through | ||
* the code path. | ||
* This is a passthrough to the underlying `CodePathState`. | ||
* @type {CodePathSegment[]} | ||
@@ -134,3 +150,3 @@ * @deprecated | ||
* | ||
* codePath.traverseSegments(function(segment, controller) { | ||
* codePath.traverseSegments((segment, controller) => { | ||
* // do something. | ||
@@ -141,36 +157,60 @@ * }); | ||
* | ||
* The `controller` object has two methods. | ||
* The `controller` argument has two methods: | ||
* | ||
* - `controller.skip()` - Skip the following segments in this branch. | ||
* - `controller.break()` - Skip all following segments. | ||
* @param {Object} [options] Omittable. | ||
* @param {CodePathSegment} [options.first] The first segment to traverse. | ||
* @param {CodePathSegment} [options.last] The last segment to traverse. | ||
* - `skip()` - skips the following segments in this branch | ||
* - `break()` - skips all following segments in the traversal | ||
* | ||
* A note on the parameters: the `options` argument is optional. This means | ||
* the first argument might be an options object or the callback function. | ||
* @param {Object} [optionsOrCallback] Optional first and last segments to traverse. | ||
* @param {CodePathSegment} [optionsOrCallback.first] The first segment to traverse. | ||
* @param {CodePathSegment} [optionsOrCallback.last] The last segment to traverse. | ||
* @param {Function} callback A callback function. | ||
* @returns {void} | ||
*/ | ||
traverseSegments(options, callback) { | ||
traverseSegments(optionsOrCallback, callback) { | ||
// normalize the arguments into a callback and options | ||
let resolvedOptions; | ||
let resolvedCallback; | ||
if (typeof options === "function") { | ||
resolvedCallback = options; | ||
if (typeof optionsOrCallback === "function") { | ||
resolvedCallback = optionsOrCallback; | ||
resolvedOptions = {}; | ||
} else { | ||
resolvedOptions = options || {}; | ||
resolvedOptions = optionsOrCallback || {}; | ||
resolvedCallback = callback; | ||
} | ||
// determine where to start traversing from based on the options | ||
const startSegment = resolvedOptions.first || this.internal.initialSegment; | ||
const lastSegment = resolvedOptions.last; | ||
let item = null; | ||
// set up initial location information | ||
let record = null; | ||
let index = 0; | ||
let end = 0; | ||
let segment = null; | ||
const visited = Object.create(null); | ||
// segments that have already been visited during traversal | ||
const visited = new Set(); | ||
// tracks the traversal steps | ||
const stack = [[startSegment, 0]]; | ||
// tracks the last skipped segment during traversal | ||
let skippedSegment = null; | ||
// indicates if we exited early from the traversal | ||
let broken = false; | ||
/** | ||
* Maintains traversal state. | ||
*/ | ||
const controller = { | ||
/** | ||
* Skip the following segments in this branch. | ||
* @returns {void} | ||
*/ | ||
skip() { | ||
@@ -183,2 +223,8 @@ if (stack.length <= 1) { | ||
}, | ||
/** | ||
* Stop traversal completely - do not traverse to any | ||
* other segments. | ||
* @returns {void} | ||
*/ | ||
break() { | ||
@@ -190,3 +236,3 @@ broken = true; | ||
/** | ||
* Checks a given previous segment has been visited. | ||
* Checks if a given previous segment has been visited. | ||
* @param {CodePathSegment} prevSegment A previous segment to check. | ||
@@ -197,3 +243,3 @@ * @returns {boolean} `true` if the segment has been visited. | ||
return ( | ||
visited[prevSegment.id] || | ||
visited.has(prevSegment) || | ||
segment.isLoopedPrevSegment(prevSegment) | ||
@@ -203,11 +249,25 @@ ); | ||
// the traversal | ||
while (stack.length > 0) { | ||
item = stack[stack.length - 1]; | ||
segment = item[0]; | ||
index = item[1]; | ||
/* | ||
* This isn't a pure stack. We use the top record all the time | ||
* but don't always pop it off. The record is popped only if | ||
* one of the following is true: | ||
* | ||
* 1) We have already visited the segment. | ||
* 2) We have not visited *all* of the previous segments. | ||
* 3) We have traversed past the available next segments. | ||
* | ||
* Otherwise, we just read the value and sometimes modify the | ||
* record as we traverse. | ||
*/ | ||
record = stack[stack.length - 1]; | ||
segment = record[0]; | ||
index = record[1]; | ||
if (index === 0) { | ||
// Skip if this segment has been visited already. | ||
if (visited[segment.id]) { | ||
if (visited.has(segment)) { | ||
stack.pop(); | ||
@@ -226,14 +286,25 @@ continue; | ||
// Reset the flag of skipping if all branches have been skipped. | ||
// Reset the skipping flag if all branches have been skipped. | ||
if (skippedSegment && segment.prevSegments.includes(skippedSegment)) { | ||
skippedSegment = null; | ||
} | ||
visited[segment.id] = true; | ||
visited.add(segment); | ||
// Call the callback when the first time. | ||
/* | ||
* If the most recent segment hasn't been skipped, then we call | ||
* the callback, passing in the segment and the controller. | ||
*/ | ||
if (!skippedSegment) { | ||
resolvedCallback.call(this, segment, controller); | ||
// exit if we're at the last segment | ||
if (segment === lastSegment) { | ||
controller.skip(); | ||
} | ||
/* | ||
* If the previous statement was executed, or if the callback | ||
* called a method on the controller, we might need to exit the | ||
* loop, so check for that and break accordingly. | ||
*/ | ||
if (broken) { | ||
@@ -248,8 +319,31 @@ break; | ||
if (index < end) { | ||
item[1] += 1; | ||
/* | ||
* If we haven't yet visited all of the next segments, update | ||
* the current top record on the stack to the next index to visit | ||
* and then push a record for the current segment on top. | ||
* | ||
* Setting the current top record's index lets us know how many | ||
* times we've been here and ensures that the segment won't be | ||
* reprocessed (because we only process segments with an index | ||
* of 0). | ||
*/ | ||
record[1] += 1; | ||
stack.push([segment.nextSegments[index], 0]); | ||
} else if (index === end) { | ||
item[0] = segment.nextSegments[index]; | ||
item[1] = 0; | ||
/* | ||
* If we are at the last next segment, then reset the top record | ||
* in the stack to next segment and set its index to 0 so it will | ||
* be processed next. | ||
*/ | ||
record[0] = segment.nextSegments[index]; | ||
record[1] = 0; | ||
} else { | ||
/* | ||
* If index > end, that means we have no more segments that need | ||
* processing. So, we pop that record off of the stack in order to | ||
* continue traversing at the next level up. | ||
*/ | ||
stack.pop(); | ||
@@ -256,0 +350,0 @@ } |
@@ -24,4 +24,4 @@ /** | ||
/** | ||
* Gets whether or not a given segment is reachable. | ||
* @param {CodePathSegment} segment A segment to get. | ||
* Determines whether or not a given segment is reachable. | ||
* @param {CodePathSegment} segment The segment to check. | ||
* @returns {boolean} `true` if the segment is reachable. | ||
@@ -34,22 +34,53 @@ */ | ||
/** | ||
* Creates new segments from the specific range of `context.segmentsList`. | ||
* Creates a new segment for each fork in the given context and appends it | ||
* to the end of the specified range of segments. Ultimately, this ends up calling | ||
* `new CodePathSegment()` for each of the forks using the `create` argument | ||
* as a wrapper around special behavior. | ||
* | ||
* The `startIndex` and `endIndex` arguments specify a range of segments in | ||
* `context` that should become `allPrevSegments` for the newly created | ||
* `CodePathSegment` objects. | ||
* | ||
* When `context.segmentsList` is `[[a, b], [c, d], [e, f]]`, `begin` is `0`, and | ||
* `end` is `-1`, this creates `[g, h]`. This `g` is from `a`, `c`, and `e`. | ||
* This `h` is from `b`, `d`, and `f`. | ||
* @param {ForkContext} context An instance. | ||
* @param {number} begin The first index of the previous segments. | ||
* @param {number} end The last index of the previous segments. | ||
* @param {Function} create A factory function of new segments. | ||
* @returns {CodePathSegment[]} New segments. | ||
* `end` is `-1`, this creates two new segments, `[g, h]`. This `g` is appended to | ||
* the end of the path from `a`, `c`, and `e`. This `h` is appended to the end of | ||
* `b`, `d`, and `f`. | ||
* @param {ForkContext} context An instance from which the previous segments | ||
* will be obtained. | ||
* @param {number} startIndex The index of the first segment in the context | ||
* that should be specified as previous segments for the newly created segments. | ||
* @param {number} endIndex The index of the last segment in the context | ||
* that should be specified as previous segments for the newly created segments. | ||
* @param {Function} create A function that creates new `CodePathSegment` | ||
* instances in a particular way. See the `CodePathSegment.new*` methods. | ||
* @returns {Array<CodePathSegment>} An array of the newly-created segments. | ||
*/ | ||
function makeSegments(context, begin, end, create) { | ||
function createSegments(context, startIndex, endIndex, create) { | ||
/** @type {Array<Array<CodePathSegment>>} */ | ||
const list = context.segmentsList; | ||
const normalizedBegin = begin >= 0 ? begin : list.length + begin; | ||
const normalizedEnd = end >= 0 ? end : list.length + end; | ||
/* | ||
* Both `startIndex` and `endIndex` work the same way: if the number is zero | ||
* or more, then the number is used as-is. If the number is negative, | ||
* then that number is added to the length of the segments list to | ||
* determine the index to use. That means -1 for either argument | ||
* is the last element, -2 is the second to last, and so on. | ||
* | ||
* So if `startIndex` is 0, `endIndex` is -1, and `list.length` is 3, the | ||
* effective `startIndex` is 0 and the effective `endIndex` is 2, so this function | ||
* will include items at indices 0, 1, and 2. | ||
* | ||
* Therefore, if `startIndex` is -1 and `endIndex` is -1, that means we'll only | ||
* be using the last segment in `list`. | ||
*/ | ||
const normalizedBegin = startIndex >= 0 ? startIndex : list.length + startIndex; | ||
const normalizedEnd = endIndex >= 0 ? endIndex : list.length + endIndex; | ||
/** @type {Array<CodePathSegment>} */ | ||
const segments = []; | ||
for (let i = 0; i < context.count; ++i) { | ||
// this is passed into `new CodePathSegment` to add to code path. | ||
const allPrevSegments = []; | ||
@@ -61,2 +92,3 @@ | ||
// note: `create` is just a wrapper that augments `new CodePathSegment`. | ||
segments.push(create(context.idGenerator.next(), allPrevSegments)); | ||
@@ -69,9 +101,8 @@ } | ||
/** | ||
* `segments` becomes doubly in a `finally` block. Then if a code path exits by a | ||
* control statement (such as `break`, `continue`) from the `finally` block, the | ||
* destination's segments may be half of the source segments. In that case, this | ||
* merges segments. | ||
* @param {ForkContext} context An instance. | ||
* @param {CodePathSegment[]} segments Segments to merge. | ||
* @returns {CodePathSegment[]} The merged segments. | ||
* Inside of a `finally` block we end up with two parallel paths. If the code path | ||
* exits by a control statement (such as `break` or `continue`) from the `finally` | ||
* block, then we need to merge the remaining parallel paths back into one. | ||
* @param {ForkContext} context The fork context to work on. | ||
* @param {Array<CodePathSegment>} segments Segments to merge. | ||
* @returns {Array<CodePathSegment>} The merged segments. | ||
*/ | ||
@@ -81,6 +112,29 @@ function mergeExtraSegments(context, segments) { | ||
/* | ||
* We need to ensure that the array returned from this function contains no more | ||
* than the number of segments that the context allows. `context.count` indicates | ||
* how many items should be in the returned array to ensure that the new segment | ||
* entries will line up with the already existing segment entries. | ||
*/ | ||
while (currentSegments.length > context.count) { | ||
const merged = []; | ||
for (let i = 0, length = currentSegments.length / 2 | 0; i < length; ++i) { | ||
/* | ||
* Because `context.count` is a factor of 2 inside of a `finally` block, | ||
* we can divide the segment count by 2 to merge the paths together. | ||
* This loops through each segment in the list and creates a new `CodePathSegment` | ||
* that has the segment and the segment two slots away as previous segments. | ||
* | ||
* If `currentSegments` is [a,b,c,d], this will create new segments e and f, such | ||
* that: | ||
* | ||
* When `i` is 0: | ||
* a->e | ||
* c->e | ||
* | ||
* When `i` is 1: | ||
* b->f | ||
* d->f | ||
*/ | ||
for (let i = 0, length = Math.floor(currentSegments.length / 2); i < length; ++i) { | ||
merged.push(CodePathSegment.newNext( | ||
@@ -91,4 +145,11 @@ context.idGenerator.next(), | ||
} | ||
/* | ||
* Go through the loop condition one more time to see if we have the | ||
* number of segments for the context. If not, we'll keep merging paths | ||
* of the merged segments until we get there. | ||
*/ | ||
currentSegments = merged; | ||
} | ||
return currentSegments; | ||
@@ -102,3 +163,3 @@ } | ||
/** | ||
* A class to manage forking. | ||
* Manages the forking of code paths. | ||
*/ | ||
@@ -108,10 +169,40 @@ class ForkContext { | ||
/** | ||
* Creates a new instance. | ||
* @param {IdGenerator} idGenerator An identifier generator for segments. | ||
* @param {ForkContext|null} upper An upper fork context. | ||
* @param {number} count A number of parallel segments. | ||
* @param {ForkContext|null} upper The preceding fork context. | ||
* @param {number} count The number of parallel segments in each element | ||
* of `segmentsList`. | ||
*/ | ||
constructor(idGenerator, upper, count) { | ||
/** | ||
* The ID generator that will generate segment IDs for any new | ||
* segments that are created. | ||
* @type {IdGenerator} | ||
*/ | ||
this.idGenerator = idGenerator; | ||
/** | ||
* The preceding fork context. | ||
* @type {ForkContext|null} | ||
*/ | ||
this.upper = upper; | ||
/** | ||
* The number of elements in each element of `segmentsList`. In most | ||
* cases, this is 1 but can be 2 when there is a `finally` present, | ||
* which forks the code path outside of normal flow. In the case of nested | ||
* `finally` blocks, this can be a multiple of 2. | ||
* @type {number} | ||
*/ | ||
this.count = count; | ||
/** | ||
* The segments within this context. Each element in this array has | ||
* `count` elements that represent one step in each fork. For example, | ||
* when `segmentsList` is `[[a, b], [c, d], [e, f]]`, there is one path | ||
* a->c->e and one path b->d->f, and `count` is 2 because each element | ||
* is an array with two elements. | ||
* @type {Array<Array<CodePathSegment>>} | ||
*/ | ||
this.segmentsList = []; | ||
@@ -121,4 +212,4 @@ } | ||
/** | ||
* The head segments. | ||
* @type {CodePathSegment[]} | ||
* The segments that begin this fork context. | ||
* @type {Array<CodePathSegment>} | ||
*/ | ||
@@ -132,3 +223,3 @@ get head() { | ||
/** | ||
* A flag which shows empty. | ||
* Indicates if the context contains no segments. | ||
* @type {boolean} | ||
@@ -141,3 +232,3 @@ */ | ||
/** | ||
* A flag which shows reachable. | ||
* Indicates if there are any segments that are reachable. | ||
* @type {boolean} | ||
@@ -152,38 +243,49 @@ */ | ||
/** | ||
* Creates new segments from this context. | ||
* @param {number} begin The first index of previous segments. | ||
* @param {number} end The last index of previous segments. | ||
* @returns {CodePathSegment[]} New segments. | ||
* Creates new segments in this context and appends them to the end of the | ||
* already existing `CodePathSegment`s specified by `startIndex` and | ||
* `endIndex`. | ||
* @param {number} startIndex The index of the first segment in the context | ||
* that should be specified as previous segments for the newly created segments. | ||
* @param {number} endIndex The index of the last segment in the context | ||
* that should be specified as previous segments for the newly created segments. | ||
* @returns {Array<CodePathSegment>} An array of the newly created segments. | ||
*/ | ||
makeNext(begin, end) { | ||
return makeSegments(this, begin, end, CodePathSegment.newNext); | ||
makeNext(startIndex, endIndex) { | ||
return createSegments(this, startIndex, endIndex, CodePathSegment.newNext); | ||
} | ||
/** | ||
* Creates new segments from this context. | ||
* The new segments is always unreachable. | ||
* @param {number} begin The first index of previous segments. | ||
* @param {number} end The last index of previous segments. | ||
* @returns {CodePathSegment[]} New segments. | ||
* Creates new unreachable segments in this context and appends them to the end of the | ||
* already existing `CodePathSegment`s specified by `startIndex` and | ||
* `endIndex`. | ||
* @param {number} startIndex The index of the first segment in the context | ||
* that should be specified as previous segments for the newly created segments. | ||
* @param {number} endIndex The index of the last segment in the context | ||
* that should be specified as previous segments for the newly created segments. | ||
* @returns {Array<CodePathSegment>} An array of the newly created segments. | ||
*/ | ||
makeUnreachable(begin, end) { | ||
return makeSegments(this, begin, end, CodePathSegment.newUnreachable); | ||
makeUnreachable(startIndex, endIndex) { | ||
return createSegments(this, startIndex, endIndex, CodePathSegment.newUnreachable); | ||
} | ||
/** | ||
* Creates new segments from this context. | ||
* The new segments don't have connections for previous segments. | ||
* But these inherit the reachable flag from this context. | ||
* @param {number} begin The first index of previous segments. | ||
* @param {number} end The last index of previous segments. | ||
* @returns {CodePathSegment[]} New segments. | ||
* Creates new segments in this context and does not append them to the end | ||
* of the already existing `CodePathSegment`s specified by `startIndex` and | ||
* `endIndex`. The `startIndex` and `endIndex` are only used to determine if | ||
* the new segments should be reachable. If any of the segments in this range | ||
* are reachable then the new segments are also reachable; otherwise, the new | ||
* segments are unreachable. | ||
* @param {number} startIndex The index of the first segment in the context | ||
* that should be considered for reachability. | ||
* @param {number} endIndex The index of the last segment in the context | ||
* that should be considered for reachability. | ||
* @returns {Array<CodePathSegment>} An array of the newly created segments. | ||
*/ | ||
makeDisconnected(begin, end) { | ||
return makeSegments(this, begin, end, CodePathSegment.newDisconnected); | ||
makeDisconnected(startIndex, endIndex) { | ||
return createSegments(this, startIndex, endIndex, CodePathSegment.newDisconnected); | ||
} | ||
/** | ||
* Adds segments into this context. | ||
* The added segments become the head. | ||
* @param {CodePathSegment[]} segments Segments to add. | ||
* Adds segments to the head of this context. | ||
* @param {Array<CodePathSegment>} segments The segments to add. | ||
* @returns {void} | ||
@@ -193,3 +295,2 @@ */ | ||
assert(segments.length >= this.count, `${segments.length} >= ${this.count}`); | ||
this.segmentsList.push(mergeExtraSegments(this, segments)); | ||
@@ -199,11 +300,13 @@ } | ||
/** | ||
* Replaces the head segments with given segments. | ||
* Replaces the head segments with the given segments. | ||
* The current head segments are removed. | ||
* @param {CodePathSegment[]} segments Segments to add. | ||
* @param {Array<CodePathSegment>} replacementHeadSegments The new head segments. | ||
* @returns {void} | ||
*/ | ||
replaceHead(segments) { | ||
assert(segments.length >= this.count, `${segments.length} >= ${this.count}`); | ||
this.segmentsList.splice(-1, 1, mergeExtraSegments(this, segments)); | ||
replaceHead(replacementHeadSegments) { | ||
assert( | ||
replacementHeadSegments.length >= this.count, | ||
`${replacementHeadSegments.length} >= ${this.count}` | ||
); | ||
this.segmentsList.splice(-1, 1, mergeExtraSegments(this, replacementHeadSegments)); | ||
} | ||
@@ -213,13 +316,8 @@ | ||
* Adds all segments of a given fork context into this context. | ||
* @param {ForkContext} context A fork context to add. | ||
* @param {ForkContext} otherForkContext The fork context to add from. | ||
* @returns {void} | ||
*/ | ||
addAll(context) { | ||
assert(context.count === this.count); | ||
const source = context.segmentsList; | ||
for (let i = 0; i < source.length; ++i) { | ||
this.segmentsList.push(source[i]); | ||
} | ||
addAll(otherForkContext) { | ||
assert(otherForkContext.count === this.count); | ||
this.segmentsList.push(...otherForkContext.segmentsList); | ||
} | ||
@@ -236,3 +334,4 @@ | ||
/** | ||
* Creates the root fork context. | ||
* Creates a new root context, meaning that there are no parent | ||
* fork contexts. | ||
* @param {IdGenerator} idGenerator An identifier generator for segments. | ||
@@ -252,10 +351,12 @@ * @returns {ForkContext} New fork context. | ||
* @param {ForkContext} parentContext The parent fork context. | ||
* @param {boolean} forkLeavingPath A flag which shows inside of `finally` block. | ||
* @param {boolean} shouldForkLeavingPath Indicates that we are inside of | ||
* a `finally` block and should therefore fork the path that leaves | ||
* `finally`. | ||
* @returns {ForkContext} New fork context. | ||
*/ | ||
static newEmpty(parentContext, forkLeavingPath) { | ||
static newEmpty(parentContext, shouldForkLeavingPath) { | ||
return new ForkContext( | ||
parentContext.idGenerator, | ||
parentContext, | ||
(forkLeavingPath ? 2 : 1) * parentContext.count | ||
(shouldForkLeavingPath ? 2 : 1) * parentContext.count | ||
); | ||
@@ -262,0 +363,0 @@ } |
@@ -142,3 +142,3 @@ /** | ||
string.split(",").forEach(name => { | ||
const trimmedName = name.trim(); | ||
const trimmedName = name.trim().replace(/^(?<quote>['"]?)(?<ruleId>.*)\k<quote>$/us, "$<ruleId>"); | ||
@@ -145,0 +145,0 @@ if (trimmedName) { |
@@ -58,2 +58,3 @@ /** | ||
* @property {boolean} [version] Output the version number | ||
* @property {boolean} warnIgnored Show warnings when the file list includes ignored files | ||
* @property {string[]} _ Positional filenames or patterns | ||
@@ -143,2 +144,13 @@ */ | ||
let warnIgnoredFlag; | ||
if (usingFlatConfig) { | ||
warnIgnoredFlag = { | ||
option: "warn-ignored", | ||
type: "Boolean", | ||
default: "true", | ||
description: "Suppress warnings when the file list includes ignored files" | ||
}; | ||
} | ||
return optionator({ | ||
@@ -354,2 +366,3 @@ prepend: "eslint [options] file.js [file.js] [dir]", | ||
}, | ||
warnIgnoredFlag, | ||
{ | ||
@@ -356,0 +369,0 @@ option: "debug", |
@@ -153,2 +153,27 @@ /** | ||
/** | ||
* Gets the leftmost operand of a consecutive logical expression. | ||
* @param {SourceCode} sourceCode The ESLint source code object | ||
* @param {LogicalExpression} node LogicalExpression | ||
* @returns {Expression} Leftmost operand | ||
*/ | ||
function getLeftmostOperand(sourceCode, node) { | ||
let left = node.left; | ||
while (left.type === "LogicalExpression" && left.operator === node.operator) { | ||
if (astUtils.isParenthesised(sourceCode, left)) { | ||
/* | ||
* It should have associativity, | ||
* but ignore it if use parentheses to make the evaluation order clear. | ||
*/ | ||
return left; | ||
} | ||
left = left.left; | ||
} | ||
return left; | ||
} | ||
//------------------------------------------------------------------------------ | ||
@@ -322,3 +347,6 @@ // Rule Definition | ||
"AssignmentExpression[operator='='][right.type='LogicalExpression']"(assignment) { | ||
if (!astUtils.isSameReference(assignment.left, assignment.right.left)) { | ||
const leftOperand = getLeftmostOperand(sourceCode, assignment.right); | ||
if (!astUtils.isSameReference(assignment.left, leftOperand) | ||
) { | ||
return; | ||
@@ -347,6 +375,6 @@ } | ||
// -> foo ||= bar | ||
const logicalOperatorToken = getOperatorToken(assignment.right); | ||
const logicalOperatorToken = getOperatorToken(leftOperand.parent); | ||
const firstRightOperandToken = sourceCode.getTokenAfter(logicalOperatorToken); | ||
yield ruleFixer.removeRange([assignment.right.range[0], firstRightOperandToken.range[0]]); | ||
yield ruleFixer.removeRange([leftOperand.parent.range[0], firstRightOperandToken.range[0]]); | ||
} | ||
@@ -353,0 +381,0 @@ }; |
{ | ||
"name": "eslint", | ||
"version": "8.50.0", | ||
"version": "8.51.0", | ||
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>", | ||
@@ -66,3 +66,3 @@ "description": "An AST-based pattern checker for JavaScript.", | ||
"@eslint/eslintrc": "^2.1.2", | ||
"@eslint/js": "8.50.0", | ||
"@eslint/js": "8.51.0", | ||
"@humanwhocodes/config-array": "^0.11.11", | ||
@@ -69,0 +69,0 @@ "@humanwhocodes/module-importer": "^1.0.1", |
@@ -291,4 +291,4 @@ [![npm version](https://img.shields.io/npm/v/eslint.svg)](https://www.npmjs.com/package/eslint) | ||
<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://sentry.io"><img src="https://avatars.githubusercontent.com/u/1396951?v=4" alt="Sentry" 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://opensource.siemens.com"><img src="https://avatars.githubusercontent.com/u/624020?v=4" alt="Siemens" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="64"></a></p><h3>Bronze Sponsors</h3> | ||
<p><a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" 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://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://quickbookstoolhub.com"><img src="https://avatars.githubusercontent.com/u/95090305?u=e5bc398ef775c9ed19f955c675cdc1fb6abf01df&v=4" alt="QuickBooks Tool hub" height="32"></a></p> | ||
<p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://opensource.siemens.com"><img src="https://avatars.githubusercontent.com/u/624020?v=4" alt="Siemens" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="64"></a></p><h3>Bronze Sponsors</h3> | ||
<p><a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" 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://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://quickbookstoolhub.com"><img src="https://avatars.githubusercontent.com/u/95090305?u=e5bc398ef775c9ed19f955c675cdc1fb6abf01df&v=4" alt="QuickBooks Tool hub" height="32"></a></p> | ||
<!--sponsorsend--> | ||
@@ -295,0 +295,0 @@ |
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
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
3003538
70814
0
4
6
0
30
+ Added@eslint/js@8.51.0(transitive)
- Removed@eslint/js@8.50.0(transitive)
Updated@eslint/js@8.51.0