Update Bot

This commit is contained in:
2026-03-15 11:58:43 +01:00
parent b67c111ffc
commit cd99275933
560 changed files with 23173 additions and 55113 deletions

16
node_modules/eslint/README.md generated vendored
View File

@@ -13,7 +13,7 @@
[Contribute to ESLint](https://eslint.org/docs/latest/contribute) |
[Report Bugs](https://eslint.org/docs/latest/contribute/report-bugs) |
[Code of Conduct](https://eslint.org/conduct) |
[X](https://x.com/geteslint) |
[Twitter](https://twitter.com/geteslint) |
[Discord](https://eslint.org/chat) |
[Mastodon](https://fosstodon.org/@eslint) |
[Bluesky](https://bsky.app/profile/eslint.org)
@@ -287,11 +287,6 @@ fnx
Josh Goldberg ✨
</a>
</td><td align="center" valign="top" width="11%">
<a href="https://github.com/SwetaTanwar">
<img src="https://github.com/SwetaTanwar.png?s=75" width="75" height="75" alt="Sweta Tanwar's Avatar"><br />
Sweta Tanwar
</a>
</td><td align="center" valign="top" width="11%">
<a href="https://github.com/Tanujkanti4441">
<img src="https://github.com/Tanujkanti4441.png?s=75" width="75" height="75" alt="Tanuj Kanti's Avatar"><br />
Tanuj Kanti
@@ -301,11 +296,6 @@ Tanuj Kanti
<img src="https://github.com/lumirlumir.png?s=75" width="75" height="75" alt="루밀LuMir's Avatar"><br />
루밀LuMir
</a>
</td><td align="center" valign="top" width="11%">
<a href="https://github.com/Pixel998">
<img src="https://github.com/Pixel998.png?s=75" width="75" height="75" alt="Pixel998's Avatar"><br />
Pixel998
</a>
</td></tr></tbody></table>
### Website Team
@@ -342,8 +332,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
<h3>Platinum Sponsors</h3>
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="128"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="128"></a></p><h3>Gold Sponsors</h3>
<p><a href="https://qlty.sh/"><img src="https://images.opencollective.com/qltysh/33d157d/logo.png" alt="Qlty Software" height="96"></a> <a href="https://trunk.io/"><img src="https://images.opencollective.com/trunkio/fb92d60/avatar.png" alt="trunk.io" height="96"></a> <a href="https://shopify.engineering/"><img src="https://avatars.githubusercontent.com/u/8085" alt="Shopify" height="96"></a></p><h3>Silver Sponsors</h3>
<p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/e6d15e1/logo.png" alt="Vite" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/2d6c3b6/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301" alt="American Express" height="64"></a> <a href="https://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3>
<p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" 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://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://opensource.mercedes-benz.com/"><img src="https://avatars.githubusercontent.com/u/34240465" alt="Mercedes-Benz Group" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p>
<p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/e6d15e1/logo.png" alt="Vite" 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" alt="American Express" height="64"></a> <a href="https://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3>
<p><a href="https://syntax.fm"><img src="https://github.com/syntaxfm.png" alt="Syntax" height="32"></a> <a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://sentry.io"><img src="https://github.com/getsentry.png" alt="Sentry" 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://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://opensource.mercedes-benz.com/"><img src="https://avatars.githubusercontent.com/u/34240465" alt="Mercedes-Benz Group" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p>
<h3>Technology Sponsors</h3>
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.
<p><a href="https://netlify.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/netlify-icon.svg" alt="Netlify" height="32"></a> <a href="https://algolia.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/algolia-icon.svg" alt="Algolia" height="32"></a> <a href="https://1password.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/1password-icon.svg" alt="1Password" height="32"></a></p>

View File

@@ -17,12 +17,6 @@ const hash = require("./hash");
const debug = require("debug")("eslint:lint-result-cache");
//------------------------------------------------------------------------------
// Typedefs
//------------------------------------------------------------------------------
/** @typedef {import("../types").Linter.Config} Config */
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
@@ -46,7 +40,7 @@ function isValidCacheStrategy(cacheStrategy) {
/**
* Calculates the hash of the config
* @param {Config} config The config.
* @param {ConfigArray} config The config.
* @returns {string} The hash of the config
*/
function hashOfConfigFor(config) {
@@ -102,13 +96,38 @@ class LintResultCache {
* cache. If the file is present and has not been changed, rebuild any
* missing result information.
* @param {string} filePath The file for which to retrieve lint results.
* @param {Config} config The config of the file.
* @param {ConfigArray} config The config of the file.
* @returns {Object|null} The rebuilt lint results, or null if the file is
* changed or not in the filesystem.
*/
getCachedLintResults(filePath, config) {
const cachedResults = this.getValidCachedLintResults(filePath, config);
/*
* Cached lint results are valid if and only if:
* 1. The file is present in the filesystem
* 2. The file has not changed since the time it was previously linted
* 3. The ESLint configuration has not changed since the time the file
* was previously linted
* If any of these are not true, we will not reuse the lint results.
*/
const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath);
const hashOfConfig = hashOfConfigFor(config);
const changed =
fileDescriptor.changed ||
fileDescriptor.meta.hashOfConfig !== hashOfConfig;
if (fileDescriptor.notFound) {
debug(`File not found on the file system: ${filePath}`);
return null;
}
if (changed) {
debug(`Cache entry not found or no longer valid: ${filePath}`);
return null;
}
const cachedResults = fileDescriptor.meta.results;
// Just in case, not sure if this can ever happen.
if (!cachedResults) {
return cachedResults;
}
@@ -132,43 +151,6 @@ class LintResultCache {
return results;
}
/**
* Retrieve cached lint results for a given file path, if present in the
* cache and still valid.
* @param {string} filePath The file for which to retrieve lint results.
* @param {Config} config The config of the file.
* @returns {Object|null} The cached lint results if present in the cache
* and still valid; null otherwise.
*/
getValidCachedLintResults(filePath, config) {
/*
* Cached lint results are valid if and only if:
* 1. The file is present in the filesystem
* 2. The file has not changed since the time it was previously linted
* 3. The ESLint configuration has not changed since the time the file
* was previously linted
* If any of these are not true, we will not reuse the lint results.
*/
const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath);
if (fileDescriptor.notFound) {
debug(`File not found on the file system: ${filePath}`);
return null;
}
const hashOfConfig = hashOfConfigFor(config);
const changed =
fileDescriptor.changed ||
fileDescriptor.meta.hashOfConfig !== hashOfConfig;
if (changed) {
debug(`Cache entry not found or no longer valid: ${filePath}`);
return null;
}
return fileDescriptor.meta.results;
}
/**
* Set the cached lint results for a given file path, after removing any
* information that will be both unnecessary and difficult to serialize.
@@ -176,7 +158,7 @@ class LintResultCache {
* applied), to prevent potentially incorrect results if fixes are not
* written to disk.
* @param {string} filePath The file for which to set lint results.
* @param {Config} config The config of the file.
* @param {ConfigArray} config The config of the file.
* @param {Object} result The lint result to be set for the file.
* @returns {void}
*/

View File

@@ -29,7 +29,6 @@ const createDebug = require("debug");
const Minimatch = minimatch.Minimatch;
const MINIMATCH_OPTIONS = { dot: true };
const hrtimeBigint = process.hrtime.bigint;
//-----------------------------------------------------------------------------
// Types
@@ -56,13 +55,13 @@ const hrtimeBigint = process.hrtime.bigint;
*/
//------------------------------------------------------------------------------
// Debug Helpers
// Internal Helpers
//------------------------------------------------------------------------------
// Add %t formatter to print bigint nanosecond times in milliseconds.
const hrtimeBigint = process.hrtime.bigint;
createDebug.formatters.t = timeDiff =>
`${(timeDiff + 500_000n) / 1_000_000n} ms`;
const debug = createDebug(
`eslint:eslint-helpers${isMainThread ? "" : `:thread-${threadId}`}`,
);
@@ -506,7 +505,7 @@ async function globMultiSearch({
* @param {boolean} args.globInputPaths true to interpret glob patterns,
* false to not interpret glob patterns.
* @param {string} args.cwd The current working directory to find from.
* @param {ConfigLoader|LegacyConfigLoader} args.configLoader The config loader for the current run.
* @param {ConfigLoader|LegacyConfigLoader} args.configLoader The config loeader for the current run.
* @param {boolean} args.errorOnUnmatchedPattern Determines if an unmatched pattern
* should throw an error.
* @returns {Promise<Array<string>>} The fully resolved file paths.
@@ -1438,8 +1437,6 @@ function createConfigLoader(
//-----------------------------------------------------------------------------
module.exports = {
createDebug,
findFiles,
isNonEmptyString,

View File

@@ -17,11 +17,8 @@ const { pathToFileURL } = require("node:url");
const { SHARE_ENV, Worker } = require("node:worker_threads");
const { version } = require("../../package.json");
const { defaultConfig } = require("../config/default-config");
const timing = require("../linter/timing");
const {
createDebug,
findFiles,
getCacheFile,
@@ -54,6 +51,11 @@ const {
} = require("../shared/naming.js");
const { resolve } = require("../shared/relative-module-resolver.js");
/*
* This is necessary to allow overwriting writeFile for testing purposes.
* We can just use fs/promises once we drop Node.js 12 support.
*/
//------------------------------------------------------------------------------
// Typedefs
//------------------------------------------------------------------------------
@@ -104,9 +106,7 @@ const { resolve } = require("../shared/relative-module-resolver.js");
// Helpers
//------------------------------------------------------------------------------
const hrtimeBigint = process.hrtime.bigint;
const debug = createDebug("eslint:eslint");
const debug = require("debug")("eslint:eslint");
const privateMembers = new WeakMap();
const removedFormatters = new Set([
"checkstyle",
@@ -279,155 +279,36 @@ function createExtraneousResultsError(cause) {
* Maximum number of files assumed to be best handled by one worker thread.
* This value is a heuristic estimation that can be adjusted if required.
*/
const AUTO_FILES_PER_WORKER = 50;
/**
* Calculates the number of worker threads to run for "auto" concurrency depending on the number of
* files that need to be processed.
*
* The number of worker threads is calculated as the number of files that need to be processed
* (`processableFileCount`) divided by the number of files assumed to be best handled by one worker
* thread (`AUTO_FILES_PER_WORKER`), rounded up to the next integer.
* Two adjustments are made to this calculation: first, the number of workers is capped at half the
* number of available CPU cores (`maxWorkers`); second, a value of 1 is converted to 0.
* The following table shows the relationship between the number of files to be processed and the
* number of workers:
*
* Files to be processed | Workers
* -------------------------------------------------------------------|-----------------
* 0 | 0
* 1, 2, …, AUTO_FILES_PER_WORKER | 0 (there's no 1)
* AUTO_FILES_PER_WORKER + 1, …, AUTO_FILES_PER_WORKER * 2 | 2
* AUTO_FILES_PER_WORKER * 2 + 1, …, AUTO_FILES_PER_WORKER * 3 | 3
* ⋯ | ⋯
* AUTO_FILES_PER_WORKER * (𝑛 - 1) + 1, …, AUTO_FILES_PER_WORKER * 𝑛 | 𝑛
* ⋯ | ⋯
* AUTO_FILES_PER_WORKER * (maxWorkers - 1) + 1, … | maxWorkers
*
* The number of files to be processed should be determined by the calling function.
* @param {number} processableFileCount The number of files that need to be processed.
* @param {number} maxWorkers The maximum number of workers to run.
* @returns {number} The number of worker threads to run.
*/
function getWorkerCountFor(processableFileCount, maxWorkers) {
let workerCount = Math.ceil(processableFileCount / AUTO_FILES_PER_WORKER);
if (workerCount > maxWorkers) {
workerCount = maxWorkers;
}
if (workerCount <= 1) {
workerCount = 0;
}
return workerCount;
}
/**
* Returns true if a file has no valid cached results or if it needs to be reprocessed because there are violations that may need fixing.
* This function will access the filesystem.
* @param {LintResultCache} lintResultCache The lint result cache.
* @param {boolean} fix The fix option.
* @param {string} filePath The file for which to retrieve lint results.
* @param {Config} config The config of the file.
* @returns {boolean} True if the file needs to be reprocessed.
*/
function needsReprocessing(lintResultCache, fix, filePath, config) {
const results = lintResultCache.getValidCachedLintResults(filePath, config);
// This reflects the reprocessing logic of the `lintFile` helper function.
return !results || (fix && results.messages && results.messages.length > 0);
}
/**
* Calculates the number of worker threads to run for "auto" concurrency.
*
* The number of worker threads depends on the number files that need to be processed.
* Typically, this includes all non-ignored files.
* In a cached run with "metadata" strategy, files with a valid cached result aren't counted.
* @param {ESLint} eslint ESLint instance.
* @param {string[]} filePaths File paths to lint.
* @param {number} maxWorkers The maximum number of workers to run.
* @returns {number} The number of worker threads to run for "auto" concurrency.
*/
function calculateAutoWorkerCount(eslint, filePaths, maxWorkers) {
const startTime = hrtimeBigint();
const {
configLoader,
lintResultCache,
options: { cacheStrategy, fix },
} = privateMembers.get(eslint);
/** True if cache is not used or if strategy is "content". */
const countAllMatched = !lintResultCache || cacheStrategy === "content";
let processableFileCount = 0;
let remainingFiles = filePaths.length;
/** The number of workers if none of the remaining files were to be counted. */
let lowWorkerCount = 0;
/*
* Rather than counting all files to be processed in advance, we stop iterating as soon as we reach
* a point where adding more files doesn't change the number of workers anymore.
*/
for (const filePath of filePaths) {
/** The number of workers if all of the remaining files were to be counted. */
const highWorkerCount = getWorkerCountFor(
processableFileCount + remainingFiles,
maxWorkers,
);
if (lowWorkerCount >= highWorkerCount) {
// The highest possible number of workers has been reached, so stop counting.
break;
}
remainingFiles--;
const configs = configLoader.getCachedConfigArrayForFile(filePath);
const config = configs.getConfig(filePath);
if (!config) {
// file is ignored
continue;
}
if (
countAllMatched ||
needsReprocessing(lintResultCache, fix, filePath, config)
) {
processableFileCount++;
lowWorkerCount = getWorkerCountFor(
processableFileCount,
maxWorkers,
);
}
}
debug(
"%d file(s) to process counted in %t",
processableFileCount,
hrtimeBigint() - startTime,
);
return lowWorkerCount;
}
const AUTO_FILES_PER_WORKER = 35;
/**
* Calculates the number of workers to run based on the concurrency setting and the number of files to lint.
* @param {ESLint} eslint The ESLint instance.
* @param {string[]} filePaths File paths to lint.
* @param {number | "auto" | "off"} concurrency The normalized concurrency setting.
* @param {number} fileCount The number of files to be linted.
* @param {{ availableParallelism: () => number }} [os] Node.js `os` module, or a mock for testing.
* @returns {number} The effective number of worker threads to be started. A value of zero disables multithread linting.
*/
function calculateWorkerCount(
eslint,
filePaths,
concurrency,
fileCount,
{ availableParallelism } = os,
) {
const { concurrency } = privateMembers.get(eslint).options;
let workerCount;
switch (concurrency) {
case "off":
return 0;
case "auto": {
const maxWorkers = availableParallelism() >> 1;
return calculateAutoWorkerCount(eslint, filePaths, maxWorkers);
}
default: {
const workerCount = Math.min(concurrency, filePaths.length);
return workerCount > 1 ? workerCount : 0;
workerCount = Math.min(
availableParallelism() >> 1,
Math.ceil(fileCount / AUTO_FILES_PER_WORKER),
);
break;
}
default:
workerCount = Math.min(concurrency, fileCount);
break;
}
return workerCount > 1 ? workerCount : 0;
}
// Used internally. Do not expose.
@@ -479,6 +360,7 @@ async function runWorkers(
},
};
const hrtimeBigint = process.hrtime.bigint;
let worstNetLintingRatio = 1;
/**
@@ -504,11 +386,6 @@ async function runWorkers(
worstNetLintingRatio,
netLintingRatio,
);
if (timing.enabled && indexedResults.timings) {
timing.mergeData(indexedResults.timings);
}
for (const result of indexedResults) {
const { index } = result;
delete result.index;
@@ -528,17 +405,7 @@ async function runWorkers(
for (let index = 0; index < workerCount; ++index) {
promises[index] = new Promise(workerExecutor);
}
try {
await Promise.all(promises);
} catch (error) {
/*
* If any worker fails, suppress timing display in the main thread
* to avoid printing partial or misleading timing output.
*/
timing.disableDisplay();
throw error;
}
await Promise.all(promises);
if (worstNetLintingRatio < LOW_NET_LINTING_RATIO) {
warnOnLowNetLintingRatio();
@@ -992,11 +859,16 @@ class ESLint {
debug(`Using file patterns: ${normalizedPatterns}`);
const { concurrency, cwd, globInputPaths, errorOnUnmatchedPattern } =
eslintOptions;
const {
cache,
concurrency,
cwd,
globInputPaths,
errorOnUnmatchedPattern,
} = eslintOptions;
// Delete cache file; should this be done here?
if (!lintResultCache && cacheFilePath) {
if (!cache && cacheFilePath) {
debug(`Deleting cache file at ${cacheFilePath}`);
try {
@@ -1010,7 +882,7 @@ class ESLint {
}
}
const startTime = hrtimeBigint();
const startTime = Date.now();
const filePaths = await findFiles({
patterns: normalizedPatterns,
cwd,
@@ -1019,9 +891,7 @@ class ESLint {
errorOnUnmatchedPattern,
});
debug(
"%d file(s) found in %t",
filePaths.length,
hrtimeBigint() - startTime,
`${filePaths.length} files found in: ${Date.now() - startTime}ms`,
);
/** @type {LintResult[]} */
@@ -1029,8 +899,8 @@ class ESLint {
// The value of `module.exports.calculateWorkerCount` can be overridden in tests.
const workerCount = module.exports.calculateWorkerCount(
this,
filePaths,
concurrency,
filePaths.length,
);
if (workerCount) {
debug(`Linting using ${workerCount} worker thread(s).`);
@@ -1129,7 +999,7 @@ class ESLint {
stats,
} = eslintOptions;
const results = [];
const startTime = hrtimeBigint();
const startTime = Date.now();
const fixTypesSet = fixTypes ? new Set(fixTypes) : null;
const resolvedFilename = path.resolve(
cwd,
@@ -1174,7 +1044,7 @@ class ESLint {
);
}
debug("Linting complete in %t", hrtimeBigint() - startTime);
debug(`Linting complete in: ${Date.now() - startTime}ms`);
return processLintReport(this, results);
}
@@ -1315,7 +1185,7 @@ class ESLint {
* @returns {Promise<string|undefined>} The path to the config file being used or
* `undefined` if no config file is being used.
*/
async findConfigFile(filePath) {
findConfigFile(filePath) {
const options = privateMembers.get(this).options;
/*

View File

@@ -17,9 +17,9 @@ require("node:module").enableCompileCache?.();
//------------------------------------------------------------------------------
const { parentPort, threadId, workerData } = require("node:worker_threads");
const createDebug = require("debug");
const {
createConfigLoader,
createDebug,
createDefaultConfigs,
createLinter,
createLintResultCache,
@@ -29,7 +29,6 @@ const {
processOptions,
} = require("./eslint-helpers");
const { WarningService } = require("../services/warning-service");
const timing = require("../linter/timing");
const depsLoadedTime = hrtimeBigint();
@@ -40,7 +39,7 @@ const depsLoadedTime = hrtimeBigint();
/** @typedef {import("../types").ESLint.LintResult} LintResult */
/** @typedef {import("../types").ESLint.Options} ESLintOptions */
/** @typedef {LintResult & { index?: number; }} IndexedLintResult */
/** @typedef {IndexedLintResult[] & { netLintingDuration: bigint; timings?: Record<string, number>; }} WorkerLintResults */
/** @typedef {IndexedLintResult[] & { netLintingDuration: bigint; }} WorkerLintResults */
/**
* @typedef {Object} WorkerData - Data passed to the worker thread.
* @property {ESLintOptions | string} eslintOptionsOrURL - The unprocessed ESLint options or the URL of the options module.
@@ -53,17 +52,13 @@ const depsLoadedTime = hrtimeBigint();
//------------------------------------------------------------------------------
const debug = createDebug(`eslint:worker:thread-${threadId}`);
createDebug.formatters.t = timeDiff =>
`${(timeDiff + 500_000n) / 1_000_000n} ms`;
//------------------------------------------------------------------------------
// Main
//------------------------------------------------------------------------------
/*
* Prevent timing module from printing profiling output from worker threads.
* The main thread is responsible for displaying any aggregated timings.
*/
timing.disableDisplay();
debug("Dependencies loaded in %t", depsLoadedTime - startTime);
(async () => {
@@ -165,9 +160,5 @@ debug("Dependencies loaded in %t", depsLoadedTime - startTime);
indexedResults.netLintingDuration =
lintingDuration - loadConfigTotalDuration - readFileCounter.duration;
if (timing.enabled) {
indexedResults.timings = timing.getData();
}
parentPort.postMessage(indexedResults);
})();

View File

@@ -1303,7 +1303,7 @@ class SourceCode extends TokenStore {
new VisitNodeStep({
target: node,
phase: 1,
args: [node],
args: [node, node.parent],
}),
);
},
@@ -1312,7 +1312,7 @@ class SourceCode extends TokenStore {
new VisitNodeStep({
target: node,
phase: 2,
args: [node],
args: [node, node.parent],
}),
);
},

View File

@@ -90,7 +90,7 @@ class ESQueryParsedSelector {
}
/**
* Compares this selector's specificity to another selector for sorting purposes.
* Compares this selector's specifity to another selector for sorting purposes.
* @param {ESQueryParsedSelector} otherSelector The selector to compare against
* @returns {number}
* a value less than 0 if this selector is less specific than otherSelector

View File

@@ -426,7 +426,7 @@ function validateSuggestions(suggest, messages) {
if (typeof suggestion.fix !== "function") {
throw new TypeError(
`context.report() called with a suggest option without a fix function. See: ${JSON.stringify(suggestion, null, 2)}`,
`context.report() called with a suggest option without a fix function. See: ${suggestion}`,
);
}
});

View File

@@ -1921,20 +1921,6 @@ class Linter {
});
}
} else {
if (config.language === jslang) {
for (const comment of sourceCode.getInlineConfigNodes()) {
const { label } = commentParser.parseDirective(
comment.value,
);
if (label === "eslint-env") {
slots.warningService.emitESLintEnvWarning(
options.filename,
comment.loc.start.line,
);
}
}
}
const inlineConfigResult = sourceCode.applyInlineConfig?.();
if (inlineConfigResult) {

View File

@@ -17,9 +17,8 @@ const vk = require("eslint-visitor-keys");
//-----------------------------------------------------------------------------
/**
* @import { Language, SourceCode } from "@eslint/core";
* @import { ESQueryOptions } from "esquery";
* @import { ESQueryParsedSelector } from "./esquery.js";
* @import { Language, SourceCode } from "@eslint/core";
* @import { SourceCodeVisitor } from "./source-code-visitor.js";
*/
@@ -48,10 +47,11 @@ class ESQueryHelper {
* Creates a new instance.
* @param {SourceCodeVisitor} visitor The visitor containing the functions to call.
* @param {ESQueryOptions} esqueryOptions `esquery` options for traversing custom nodes.
* @returns {NodeEventGenerator} new instance
*/
constructor(visitor, esqueryOptions) {
/**
* The visitor to use during traversal.
* The emitter to use during traversal.
* @type {SourceCodeVisitor}
*/
this.visitor = visitor;
@@ -288,10 +288,7 @@ class SourceCodeTraverser {
false,
)
.forEach(selector => {
visitor.callSync(
selector,
...(step.args ?? [step.target]),
);
visitor.callSync(selector, step.target);
});
currentAncestry.unshift(step.target);
} else {
@@ -303,10 +300,7 @@ class SourceCodeTraverser {
true,
)
.forEach(selector => {
visitor.callSync(
selector,
...(step.args ?? [step.target]),
);
visitor.callSync(selector, step.target);
});
}
} catch (err) {

View File

@@ -131,7 +131,6 @@ function display(data) {
/* c8 ignore next */
module.exports = (function () {
const data = Object.create(null);
let displayEnabled = true;
/**
* Time the run
@@ -159,42 +158,9 @@ module.exports = (function () {
};
}
/**
* Returns a shallow copy of the collected timings data.
* @returns {Record<string, number>} mapping of ruleId to total time in ms
*/
function getData() {
return { ...data };
}
/**
* Merges rule timing totals collected elsewhere into this process' totals.
* @param {Record<string, number>} dataToMerge mapping of ruleId to total time in ms
* @returns {void}
*/
function mergeData(dataToMerge) {
for (const [key, value] of Object.entries(dataToMerge)) {
if (typeof data[key] === "undefined") {
data[key] = 0;
}
data[key] += value;
}
}
/**
* Disables printing of timing data on process exit.
* Intended for worker threads or non-main contexts.
* @returns {void}
*/
function disableDisplay() {
displayEnabled = false;
}
if (enabled) {
process.on("exit", () => {
if (displayEnabled && Object.keys(data).length > 0) {
display(data);
}
display(data);
});
}
@@ -202,8 +168,5 @@ module.exports = (function () {
time,
enabled,
getListSize,
getData,
mergeData,
disableDisplay,
};
})();

View File

@@ -19,7 +19,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -18,7 +18,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -19,7 +19,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -35,7 +35,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -22,7 +22,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -19,7 +19,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -19,7 +19,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -16,7 +16,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -78,7 +78,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -18,7 +18,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -19,7 +19,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -68,7 +68,6 @@ module.exports = {
},
create(context) {
const sourceCode = context.sourceCode;
const option = context.options[0];
let threshold = THRESHOLD_DEFAULT;
let VARIANT = "classic";
@@ -172,21 +171,17 @@ module.exports = {
if (complexity > threshold) {
let name;
let loc = node.loc;
if (codePath.origin === "class-field-initializer") {
name = "class field initializer";
} else if (codePath.origin === "class-static-block") {
name = "class static block";
loc = sourceCode.getFirstToken(node).loc;
} else {
name = astUtils.getFunctionNameWithKind(node);
loc = astUtils.getFunctionHeadLoc(node, sourceCode);
}
context.report({
node,
loc,
messageId: "complex",
data: {
name: upperCaseFirst(name),

View File

@@ -18,7 +18,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -19,7 +19,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -16,7 +16,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -46,10 +46,7 @@ module.exports = {
*/
function report(node) {
context.report({
loc: {
start: node.loc.start,
end: sourceCode.getTokenBefore(node.body).loc.end,
},
node,
messageId: "incorrectDirection",
});
}

View File

@@ -23,7 +23,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:
@@ -105,7 +105,7 @@ module.exports = {
* Check if open space is present in a function name
* @param {ASTNode} node node to evaluate
* @param {Token} leftToken The last token of the callee. This may be the closing parenthesis that encloses the callee.
* @param {Token} rightToken The first token of the arguments. this is the opening parenthesis that encloses the arguments.
* @param {Token} rightToken Tha first token of the arguments. this is the opening parenthesis that encloses the arguments.
* @returns {void}
* @private
*/

View File

@@ -17,7 +17,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -22,7 +22,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -33,7 +33,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -60,7 +60,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -17,7 +17,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -101,7 +101,7 @@ module.exports = {
message: "The rule was renamed.",
url: "https://eslint.org/blog/2020/07/eslint-v7.5.0-released/#deprecating-id-blacklist",
deprecatedSince: "7.5.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
rule: {

View File

@@ -17,7 +17,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -35,7 +35,6 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "4.0.0",
availableUntil: "11.0.0",
replacedBy: [
{
message:

View File

@@ -512,7 +512,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -44,7 +44,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -151,7 +151,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -82,7 +82,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -18,7 +18,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "9.3.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -31,7 +31,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -60,7 +60,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -56,7 +56,7 @@ module.exports = {
message: "The rule was replaced with a more general rule.",
url: "https://eslint.org/blog/2017/06/eslint-v4.0.0-released/",
deprecatedSince: "4.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message: "The new rule moved to a plugin.",

View File

@@ -37,7 +37,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -71,7 +71,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -22,7 +22,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -18,7 +18,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "9.3.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -19,7 +19,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -27,7 +27,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -42,7 +42,7 @@ module.exports = {
message: "The rule was replaced with a more general rule.",
url: "https://eslint.org/blog/2017/06/eslint-v4.0.0-released/",
deprecatedSince: "4.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message: "The new rule moved to a plugin.",

View File

@@ -30,7 +30,7 @@ module.exports = {
message: "The rule was replaced with a more general rule.",
url: "https://eslint.org/blog/2017/06/eslint-v4.0.0-released/",
deprecatedSince: "4.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message: "The new rule moved to a plugin.",

View File

@@ -20,7 +20,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -16,7 +16,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -32,7 +32,7 @@ module.exports = {
message: "This rule was renamed.",
url: "https://eslint.org/blog/2018/07/eslint-v5.1.0-released/",
deprecatedSince: "5.1.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
rule: {

View File

@@ -33,7 +33,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -5,12 +5,6 @@
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
@@ -64,15 +58,10 @@ module.exports = {
// Checks and reports duplications.
const defs = variable.defs.filter(isParameter);
const loc = {
start: astUtils.getOpeningParenOfParams(node, sourceCode)
.loc.start,
end: sourceCode.getTokenBefore(node.body).loc.end,
};
if (defs.length >= 2) {
context.report({
loc,
node,
messageId: "unexpected",
data: { name: variable.name },
});

View File

@@ -106,7 +106,7 @@ module.exports = {
if (isDuplicate) {
context.report({
loc: node.key.loc,
node,
messageId: "unexpected",
data: { name },
});

View File

@@ -21,7 +21,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -24,7 +24,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -23,7 +23,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -5,212 +5,6 @@
"use strict";
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/** Class representing a number in scientific notation. */
class ScientificNotation {
/** @type {string} The digits of the coefficient. A decimal point is implied after the first digit. */
coefficient;
/** @type {number} The order of magnitude. */
magnitude;
constructor(coefficient, magnitude) {
this.coefficient = coefficient;
this.magnitude = magnitude;
}
/* c8 ignore start -- debug only */
toString() {
return `${this.coefficient[0]}${this.coefficient.length > 1 ? `.${this.coefficient.slice(1)}` : ""}e${this.magnitude}`;
}
/* c8 ignore stop */
}
/**
* 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";
}
/**
* Gets the source code of the given number literal. Removes `_` numeric separators from the result.
* @param {Node} node the number `Literal` node
* @returns {string} raw source code of the literal, without numeric separators
*/
function getRaw(node) {
return node.raw.replace(/_/gu, "");
}
/**
* Checks whether the number is base ten
* @param {ASTNode} node the node being evaluated
* @returns {boolean} true if the node is in base ten
*/
function isBaseTen(node) {
const prefixes = ["0x", "0X", "0b", "0B", "0o", "0O"];
return (
prefixes.every(prefix => !node.raw.startsWith(prefix)) &&
!/^0[0-7]+$/u.test(node.raw)
);
}
/**
* Checks that the user-intended non-base ten number equals the actual number after is has been converted to the Number type
* @param {Node} node the node being evaluated
* @returns {boolean} true if they do not match
*/
function notBaseTenLosesPrecision(node) {
const rawString = getRaw(node).toUpperCase();
let base;
if (rawString.startsWith("0B")) {
base = 2;
} else if (rawString.startsWith("0X")) {
base = 16;
} else {
base = 8;
}
return !rawString.endsWith(node.value.toString(base).toUpperCase());
}
/**
* Returns the number stripped of leading zeros
* @param {string} numberAsString the string representation of the number
* @returns {string} the stripped string
*/
function removeLeadingZeros(numberAsString) {
for (let i = 0; i < numberAsString.length; i++) {
if (numberAsString[i] !== "0") {
return numberAsString.slice(i);
}
}
return numberAsString;
}
/**
* Returns the number stripped of trailing zeros
* @param {string} numberAsString the string representation of the number
* @returns {string} the stripped string
*/
function removeTrailingZeros(numberAsString) {
for (let i = numberAsString.length - 1; i >= 0; i--) {
if (numberAsString[i] !== "0") {
return numberAsString.slice(0, i + 1);
}
}
return numberAsString;
}
/**
* Converts an integer to an object containing the integer's coefficient and order of magnitude
* @param {string} stringInteger the string representation of the integer being converted
* @returns {ScientificNotation} the object containing the integer's coefficient and order of magnitude
*/
function normalizeInteger(stringInteger) {
const trimmedInteger = removeLeadingZeros(stringInteger);
const significantDigits = removeTrailingZeros(trimmedInteger);
return new ScientificNotation(significantDigits, trimmedInteger.length - 1);
}
/**
* Converts a float to an object containing the float's coefficient and order of magnitude
* @param {string} stringFloat the string representation of the float being converted
* @returns {ScientificNotation} the object containing the float's coefficient and order of magnitude
*/
function normalizeFloat(stringFloat) {
const trimmedFloat = removeLeadingZeros(stringFloat);
const indexOfDecimalPoint = trimmedFloat.indexOf(".");
switch (indexOfDecimalPoint) {
case 0: {
const significantDigits = removeLeadingZeros(trimmedFloat.slice(1));
return new ScientificNotation(
significantDigits,
significantDigits.length - trimmedFloat.length,
);
}
case -1:
return new ScientificNotation(
trimmedFloat,
trimmedFloat.length - 1,
);
default:
return new ScientificNotation(
trimmedFloat.replace(".", ""),
indexOfDecimalPoint - 1,
);
}
}
/**
* Converts a base ten number to proper scientific notation
* @param {string} stringNumber the string representation of the base ten number to be converted
* @param {boolean} parseAsFloat if true, the coefficient will be always parsed as a float, regardless of whether a decimal point is present
* @returns {ScientificNotation} the object containing the number's coefficient and order of magnitude
*/
function convertNumberToScientificNotation(stringNumber, parseAsFloat) {
const splitNumber = stringNumber.split("e");
const originalCoefficient = splitNumber[0];
const normalizedNumber =
parseAsFloat || stringNumber.includes(".")
? normalizeFloat(originalCoefficient)
: normalizeInteger(originalCoefficient);
if (splitNumber.length > 1) {
normalizedNumber.magnitude += parseInt(splitNumber[1], 10);
}
return normalizedNumber;
}
/**
* Checks that the user-intended base ten number equals the actual number after is has been converted to the Number type
* @param {Node} node the node being evaluated
* @returns {boolean} true if they do not match
*/
function baseTenLosesPrecision(node) {
const rawNumber = getRaw(node).toLowerCase();
const normalizedRawNumber = convertNumberToScientificNotation(
rawNumber,
false,
);
const requestedPrecision = normalizedRawNumber.coefficient.length;
if (requestedPrecision > 100) {
return true;
}
const storedNumber = node.value.toPrecision(requestedPrecision);
const normalizedStoredNumber = convertNumberToScientificNotation(
storedNumber,
true,
);
return (
normalizedRawNumber.magnitude !== normalizedStoredNumber.magnitude ||
normalizedRawNumber.coefficient !== normalizedStoredNumber.coefficient
);
}
/**
* Checks that the user-intended number equals the actual number after is has been converted to the Number type
* @param {Node} node the node being evaluated
* @returns {boolean} true if they do not match
*/
function losesPrecision(node) {
return isBaseTen(node)
? baseTenLosesPrecision(node)
: notBaseTenLosesPrecision(node);
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
@@ -235,6 +29,217 @@ module.exports = {
},
create(context) {
/**
* 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";
}
/**
* Gets the source code of the given number literal. Removes `_` numeric separators from the result.
* @param {Node} node the number `Literal` node
* @returns {string} raw source code of the literal, without numeric separators
*/
function getRaw(node) {
return node.raw.replace(/_/gu, "");
}
/**
* Checks whether the number is base ten
* @param {ASTNode} node the node being evaluated
* @returns {boolean} true if the node is in base ten
*/
function isBaseTen(node) {
const prefixes = ["0x", "0X", "0b", "0B", "0o", "0O"];
return (
prefixes.every(prefix => !node.raw.startsWith(prefix)) &&
!/^0[0-7]+$/u.test(node.raw)
);
}
/**
* Checks that the user-intended non-base ten number equals the actual number after is has been converted to the Number type
* @param {Node} node the node being evaluated
* @returns {boolean} true if they do not match
*/
function notBaseTenLosesPrecision(node) {
const rawString = getRaw(node).toUpperCase();
let base;
if (rawString.startsWith("0B")) {
base = 2;
} else if (rawString.startsWith("0X")) {
base = 16;
} else {
base = 8;
}
return !rawString.endsWith(node.value.toString(base).toUpperCase());
}
/**
* Adds a decimal point to the numeric string at index 1
* @param {string} stringNumber the numeric string without any decimal point
* @returns {string} the numeric string with a decimal point in the proper place
*/
function addDecimalPointToNumber(stringNumber) {
return `${stringNumber[0]}.${stringNumber.slice(1)}`;
}
/**
* Returns the number stripped of leading zeros
* @param {string} numberAsString the string representation of the number
* @returns {string} the stripped string
*/
function removeLeadingZeros(numberAsString) {
for (let i = 0; i < numberAsString.length; i++) {
if (numberAsString[i] !== "0") {
return numberAsString.slice(i);
}
}
return numberAsString;
}
/**
* Returns the number stripped of trailing zeros
* @param {string} numberAsString the string representation of the number
* @returns {string} the stripped string
*/
function removeTrailingZeros(numberAsString) {
for (let i = numberAsString.length - 1; i >= 0; i--) {
if (numberAsString[i] !== "0") {
return numberAsString.slice(0, i + 1);
}
}
return numberAsString;
}
/**
* Converts an integer to an object containing the integer's coefficient and order of magnitude
* @param {string} stringInteger the string representation of the integer being converted
* @returns {Object} the object containing the integer's coefficient and order of magnitude
*/
function normalizeInteger(stringInteger) {
const significantDigits = removeTrailingZeros(
removeLeadingZeros(stringInteger),
);
return {
magnitude: stringInteger.startsWith("0")
? stringInteger.length - 2
: stringInteger.length - 1,
coefficient: addDecimalPointToNumber(significantDigits),
};
}
/**
*
* Converts a float to an object containing the floats's coefficient and order of magnitude
* @param {string} stringFloat the string representation of the float being converted
* @returns {Object} the object containing the integer's coefficient and order of magnitude
*/
function normalizeFloat(stringFloat) {
const trimmedFloat = removeLeadingZeros(stringFloat);
if (trimmedFloat.startsWith(".")) {
const decimalDigits = trimmedFloat.slice(1);
const significantDigits = removeLeadingZeros(decimalDigits);
return {
magnitude:
significantDigits.length - decimalDigits.length - 1,
coefficient: addDecimalPointToNumber(significantDigits),
};
}
return {
magnitude: trimmedFloat.indexOf(".") - 1,
coefficient: addDecimalPointToNumber(
trimmedFloat.replace(".", ""),
),
};
}
/**
* Converts a base ten number to proper scientific notation
* @param {string} stringNumber the string representation of the base ten number to be converted
* @returns {string} the number converted to scientific notation
*/
function convertNumberToScientificNotation(stringNumber) {
const splitNumber = stringNumber.replace("E", "e").split("e");
const originalCoefficient = splitNumber[0];
const normalizedNumber = stringNumber.includes(".")
? normalizeFloat(originalCoefficient)
: normalizeInteger(originalCoefficient);
const normalizedCoefficient = normalizedNumber.coefficient;
const magnitude =
splitNumber.length > 1
? parseInt(splitNumber[1], 10) + normalizedNumber.magnitude
: normalizedNumber.magnitude;
return `${normalizedCoefficient}e${magnitude}`;
}
/**
* Checks that the user-intended base ten number equals the actual number after is has been converted to the Number type
* @param {Node} node the node being evaluated
* @returns {boolean} true if they do not match
*/
function baseTenLosesPrecision(node) {
const rawNumber = getRaw(node).toLowerCase();
/*
* If trailing zeros equal the exponent, this is a valid representation
* like "9.00e2" where 00 = 2 (meaning 9.00 * 10^2 = 900)
* https://github.com/eslint/eslint/issues/19957
*/
if (rawNumber.includes(".") && rawNumber.includes("e")) {
const parts = rawNumber.split("e");
const coefficient = parts[0];
const exponent = parseInt(parts[1], 10);
// Count trailing zeros after decimal
const decimalParts = coefficient.split(".");
if (decimalParts.length === 2) {
const decimalPart = decimalParts[1];
const trailingZeros = decimalPart.match(/0*$/u)[0].length;
if (trailingZeros === exponent) {
return false;
}
}
}
const normalizedRawNumber =
convertNumberToScientificNotation(rawNumber);
const requestedPrecision = normalizedRawNumber
.split("e")[0]
.replace(".", "").length;
if (requestedPrecision > 100) {
return true;
}
const storedNumber = node.value.toPrecision(requestedPrecision);
const normalizedStoredNumber =
convertNumberToScientificNotation(storedNumber);
return normalizedRawNumber !== normalizedStoredNumber;
}
/**
* Checks that the user-intended number equals the actual number after is has been converted to the Number type
* @param {Node} node the node being evaluated
* @returns {boolean} true if they do not match
*/
function losesPrecision(node) {
return isBaseTen(node)
? baseTenLosesPrecision(node)
: notBaseTenLosesPrecision(node);
}
return {
Literal(node) {
if (node.value && isNumber(node) && losesPrecision(node)) {

View File

@@ -90,7 +90,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -17,7 +17,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -16,7 +16,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -19,7 +19,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -17,7 +17,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -26,7 +26,7 @@ module.exports = {
message: "Renamed rule.",
url: "https://eslint.org/blog/2016/08/eslint-v3.3.0-released/#deprecated-rules",
deprecatedSince: "3.3.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
rule: {

View File

@@ -26,7 +26,7 @@ module.exports = {
message: "Renamed rule.",
url: "https://eslint.org/blog/2016/08/eslint-v3.3.0-released/#deprecated-rules",
deprecatedSince: "3.3.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
rule: {

View File

@@ -32,7 +32,7 @@ module.exports = {
"The new rule flags more situations where object literal syntax can be used, and it does not report a problem when the `Object` constructor is invoked with an argument.",
url: "https://eslint.org/blog/2023/09/eslint-v8.50.0-released/",
deprecatedSince: "8.50.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
rule: {

View File

@@ -17,7 +17,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -25,7 +25,7 @@ module.exports = {
message: "The rule was replaced with a more general rule.",
url: "https://eslint.org/docs/latest/use/migrate-to-9.0.0#eslint-recommended",
deprecatedSince: "9.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
rule: {

View File

@@ -16,7 +16,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -16,7 +16,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -16,7 +16,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -41,11 +41,6 @@ const arrayOfStringsOrObjects = {
type: "string",
},
},
allowTypeImports: {
type: "boolean",
description:
"Whether to allow type-only imports for a path.",
},
},
additionalProperties: false,
required: ["name"],
@@ -110,11 +105,6 @@ const arrayOfStringsOrObjectPatterns = {
caseSensitive: {
type: "boolean",
},
allowTypeImports: {
type: "boolean",
description:
"Whether to allow type-only imports for a pattern.",
},
},
additionalProperties: false,
not: {
@@ -147,8 +137,6 @@ const arrayOfStringsOrObjectPatterns = {
module.exports = {
meta: {
type: "suggestion",
dialects: ["typescript", "javascript"],
language: "javascript",
docs: {
description: "Disallow specified modules when loaded by `import`",
@@ -273,7 +261,6 @@ module.exports = {
message: importSource.message,
importNames: importSource.importNames,
allowImportNames: importSource.allowImportNames,
allowTypeImports: importSource.allowTypeImports,
});
}
return memo;
@@ -304,7 +291,6 @@ module.exports = {
importNamePattern,
allowImportNames,
allowImportNamePattern,
allowTypeImports,
}) => ({
...(group
? {
@@ -327,7 +313,6 @@ module.exports = {
importNamePattern,
allowImportNames,
allowImportNamePattern,
allowTypeImports,
}),
);
@@ -339,48 +324,6 @@ module.exports = {
return {};
}
/**
* Check if the node is a type-only import
* @param {ASTNode} node The node to check
* @returns {boolean} Whether the node is a type-only import
*/
function isTypeOnlyImport(node) {
return (
node.importKind === "type" ||
(node.specifiers?.length > 0 &&
node.specifiers.every(
specifier => specifier.importKind === "type",
))
);
}
/**
* Check if a specifier is type-only
* @param {ASTNode} specifier The specifier to check
* @returns {boolean} Whether the specifier is type-only
*/
function isTypeOnlySpecifier(specifier) {
return (
specifier.importKind === "type" ||
specifier.exportKind === "type"
);
}
/**
* Check if the node is a type-only export
* @param {ASTNode} node The node to check
* @returns {boolean} Whether the node is a type-only export
*/
function isTypeOnlyExport(node) {
return (
node.exportKind === "type" ||
(node.specifiers?.length > 0 &&
node.specifiers.every(
specifier => specifier.exportKind === "type",
))
);
}
/**
* Report a restricted path.
* @param {string} importSource path of the import
@@ -401,28 +344,6 @@ module.exports = {
restrictedPathEntry.importNames;
const allowedImportNames =
restrictedPathEntry.allowImportNames;
const allowTypeImports =
restrictedPathEntry.allowTypeImports;
// Skip if this is a type-only import and it's allowed for this specific entry
if (
allowTypeImports &&
(node.type === "ImportDeclaration" ||
node.type === "TSImportEqualsDeclaration") &&
isTypeOnlyImport(node)
) {
return;
}
// Skip if this is a type-only export and it's allowed for this specific entry
if (
allowTypeImports &&
(node.type === "ExportNamedDeclaration" ||
node.type === "ExportAllDeclaration") &&
isTypeOnlyExport(node)
) {
return;
}
if (!restrictedImportNames && !allowedImportNames) {
context.report({
@@ -479,14 +400,6 @@ module.exports = {
restrictedImportNames.includes(importName)
) {
specifiers.forEach(specifier => {
// Skip if this is a type-only import specifier and type imports are allowed
if (
allowTypeImports &&
isTypeOnlySpecifier(specifier.specifier)
) {
return;
}
context.report({
node,
messageId: customMessage
@@ -507,14 +420,6 @@ module.exports = {
!allowedImportNames.includes(importName)
) {
specifiers.forEach(specifier => {
// Skip if this is a type-only import specifier and type imports are allowed
if (
allowTypeImports &&
isTypeOnlySpecifier(specifier.specifier)
) {
return;
}
context.report({
node,
loc: specifier.loc,
@@ -541,30 +446,11 @@ module.exports = {
* @param {Object} group contains an Ignore instance for paths, the customMessage to show on failure,
* and any restricted import names that have been specified in the config
* @param {Map<string,Object[]>} importNames Map of import names that are being imported
* @param {string} importSource the import source string
* @returns {void}
* @private
*/
function reportPathForPatterns(node, group, importNames, importSource) {
// Skip if this is a type-only import and it's allowed
if (
group.allowTypeImports &&
(node.type === "ImportDeclaration" ||
node.type === "TSImportEqualsDeclaration") &&
isTypeOnlyImport(node)
) {
return;
}
// Skip if this is a type-only export and it's allowed
if (
group.allowTypeImports &&
(node.type === "ExportNamedDeclaration" ||
node.type === "ExportAllDeclaration") &&
isTypeOnlyExport(node)
) {
return;
}
function reportPathForPatterns(node, group, importNames) {
const importSource = node.source.value.trim();
const customMessage = group.customMessage;
const restrictedImportNames = group.importNames;
@@ -667,14 +553,6 @@ module.exports = {
restrictedImportNamePattern.test(importName))
) {
specifiers.forEach(specifier => {
// Skip if this is a type-only import specifier and type imports are allowed
if (
group.allowTypeImports &&
isTypeOnlySpecifier(specifier.specifier)
) {
return;
}
context.report({
node,
messageId: customMessage
@@ -695,14 +573,6 @@ module.exports = {
!allowedImportNames.includes(importName)
) {
specifiers.forEach(specifier => {
// Skip if this is a type-only import specifier and type imports are allowed
if (
group.allowTypeImports &&
isTypeOnlySpecifier(specifier.specifier)
) {
return;
}
context.report({
node,
messageId: customMessage
@@ -722,14 +592,6 @@ module.exports = {
!allowedImportNamePattern.test(importName)
) {
specifiers.forEach(specifier => {
// Skip if this is a type-only import specifier and type imports are allowed
if (
group.allowTypeImports &&
isTypeOnlySpecifier(specifier.specifier)
) {
return;
}
context.report({
node,
messageId: customMessage
@@ -778,7 +640,7 @@ module.exports = {
} else if (node.specifiers) {
for (const specifier of node.specifiers) {
let name;
const specifierData = { loc: specifier.loc, specifier };
const specifierData = { loc: specifier.loc };
if (specifier.type === "ImportDefaultSpecifier") {
name = "default";
@@ -803,12 +665,7 @@ module.exports = {
checkRestrictedPathAndReport(importSource, importNames, node);
restrictedPatternGroups.forEach(group => {
if (isRestrictedPattern(importSource, group)) {
reportPathForPatterns(
node,
group,
importNames,
importSource,
);
reportPathForPatterns(node, group, importNames);
}
});
}
@@ -821,30 +678,6 @@ module.exports = {
}
},
ExportAllDeclaration: checkNode,
// Add support for TypeScript import equals declarations
TSImportEqualsDeclaration(node) {
if (node.moduleReference.type === "TSExternalModuleReference") {
const importSource = node.moduleReference.expression.value;
const importNames = new Map();
// Use existing logic with the actual node
checkRestrictedPathAndReport(
importSource,
importNames,
node,
);
restrictedPatternGroups.forEach(group => {
if (isRestrictedPattern(importSource, group)) {
reportPathForPatterns(
node,
group,
importNames,
importSource,
);
}
});
}
},
};
},
};

View File

@@ -52,7 +52,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -26,7 +26,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2016/08/eslint-v3.3.0-released/#deprecated-rules",
deprecatedSince: "3.3.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -17,7 +17,7 @@ module.exports = {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
availableUntil: null,
replacedBy: [
{
message:

View File

@@ -24,7 +24,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -30,7 +30,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -22,7 +22,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -18,7 +18,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -162,7 +162,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -18,7 +18,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -17,7 +17,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -19,86 +19,6 @@ const OPTIONS = {
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
const CTOR_PREFIX_REGEX = /[^_$0-9]/u;
const JSDOC_COMMENT_REGEX = /^\s*\*/u;
/**
* Determines if the first character of the name is a capital letter.
* @param {string} name The name of the node to evaluate.
* @returns {boolean} True if the first character of the property name is a capital letter, false if not.
* @private
*/
function isConstructor(name) {
const match = CTOR_PREFIX_REGEX.exec(name);
// Not a constructor if name has no characters apart from '_', '$' and digits e.g. '_', '$$', '_8'
if (!match) {
return false;
}
const firstChar = name.charAt(match.index);
return firstChar === firstChar.toUpperCase();
}
/**
* Determines if the property can have a shorthand form.
* @param {ASTNode} property Property AST node
* @returns {boolean} True if the property can have a shorthand form
* @private
*/
function canHaveShorthand(property) {
return (
property.kind !== "set" &&
property.kind !== "get" &&
property.type !== "SpreadElement" &&
property.type !== "SpreadProperty" &&
property.type !== "ExperimentalSpreadProperty"
);
}
/**
* Checks whether a node is a string literal.
* @param {ASTNode} node Any AST node.
* @returns {boolean} `true` if it is a string literal.
*/
function isStringLiteral(node) {
return node.type === "Literal" && typeof node.value === "string";
}
/**
* Determines if the property is a shorthand or not.
* @param {ASTNode} property Property AST node
* @returns {boolean} True if the property is considered shorthand, false if not.
* @private
*/
function isShorthand(property) {
// property.method is true when `{a(){}}`.
return property.shorthand || property.method;
}
/**
* Determines if the property's key and method or value are named equally.
* @param {ASTNode} property Property AST node
* @returns {boolean} True if the key and value are named equally, false if not.
* @private
*/
function isRedundant(property) {
const value = property.value;
if (value.type === "FunctionExpression") {
return !value.id; // Only anonymous should be shorthand method.
}
if (value.type === "Identifier") {
return astUtils.getStaticPropertyName(property) === value.name;
}
return false;
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
@@ -219,6 +139,86 @@ module.exports = {
const AVOID_EXPLICIT_RETURN_ARROWS = !!PARAMS.avoidExplicitReturnArrows;
const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
const CTOR_PREFIX_REGEX = /[^_$0-9]/u;
/**
* Determines if the first character of the name is a capital letter.
* @param {string} name The name of the node to evaluate.
* @returns {boolean} True if the first character of the property name is a capital letter, false if not.
* @private
*/
function isConstructor(name) {
const match = CTOR_PREFIX_REGEX.exec(name);
// Not a constructor if name has no characters apart from '_', '$' and digits e.g. '_', '$$', '_8'
if (!match) {
return false;
}
const firstChar = name.charAt(match.index);
return firstChar === firstChar.toUpperCase();
}
/**
* Determines if the property can have a shorthand form.
* @param {ASTNode} property Property AST node
* @returns {boolean} True if the property can have a shorthand form
* @private
*/
function canHaveShorthand(property) {
return (
property.kind !== "set" &&
property.kind !== "get" &&
property.type !== "SpreadElement" &&
property.type !== "SpreadProperty" &&
property.type !== "ExperimentalSpreadProperty"
);
}
/**
* Checks whether a node is a string literal.
* @param {ASTNode} node Any AST node.
* @returns {boolean} `true` if it is a string literal.
*/
function isStringLiteral(node) {
return node.type === "Literal" && typeof node.value === "string";
}
/**
* Determines if the property is a shorthand or not.
* @param {ASTNode} property Property AST node
* @returns {boolean} True if the property is considered shorthand, false if not.
* @private
*/
function isShorthand(property) {
// property.method is true when `{a(){}}`.
return property.shorthand || property.method;
}
/**
* Determines if the property's key and method or value are named equally.
* @param {ASTNode} property Property AST node
* @returns {boolean} True if the key and value are named equally, false if not.
* @private
*/
function isRedundant(property) {
const value = property.value;
if (value.type === "FunctionExpression") {
return !value.id; // Only anonymous should be shorthand method.
}
if (value.type === "Identifier") {
return astUtils.getStaticPropertyName(property) === value.name;
}
return false;
}
/**
* Ensures that an object's properties are consistently shorthand, or not shorthand at all.
* @param {ASTNode} node Property AST node
@@ -582,19 +582,6 @@ module.exports = {
node.key.name === node.value.name &&
APPLY_TO_PROPS
) {
// Skip if there are JSDoc comments inside the property (e.g., JSDoc type annotations)
const comments = sourceCode.getCommentsInside(node);
if (
comments.some(
comment =>
comment.type === "Block" &&
JSDOC_COMMENT_REGEX.test(comment.value) &&
comment.value.includes("@type"),
)
) {
return;
}
// {x: x} should be written as {x}
context.report({
node,
@@ -619,18 +606,6 @@ module.exports = {
return;
}
const comments = sourceCode.getCommentsInside(node);
if (
comments.some(
comment =>
comment.type === "Block" &&
comment.value.startsWith("*") &&
comment.value.includes("@type"),
)
) {
return;
}
// {"x": x} should be written as {x}
context.report({
node,

View File

@@ -16,7 +16,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -23,7 +23,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -23,7 +23,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -393,7 +393,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -82,7 +82,11 @@ function getErrorCause(throwStatement) {
}
const causeProperties = errorOptions.properties.filter(
prop => astUtils.getStaticPropertyName(prop) === "cause",
prop =>
prop.type === "Property" &&
prop.key.type === "Identifier" &&
prop.key.name === "cause" &&
!prop.computed, // It is hard to accurately identify the value of computed props
);
const causeProperty = causeProperties.at(-1);

View File

@@ -24,7 +24,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -101,7 +101,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -17,7 +17,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -19,7 +19,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -89,7 +89,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -23,7 +23,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -42,7 +42,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

View File

@@ -22,7 +22,7 @@ module.exports = {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
availableUntil: "10.0.0",
replacedBy: [
{
message:

Some files were not shown because too many files have changed in this diff Show More