-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(deps): update dependency eslint to v8.57.1 #1220
Conversation
[puLL-Merge] - eslint/[email protected] Diffdiff --git .github/workflows/ci.yml .github/workflows/ci.yml
index c1a59660fbf2..2d31eb961c56 100644
--- .github/workflows/ci.yml
+++ .github/workflows/ci.yml
@@ -1,9 +1,9 @@
name: CI
on:
push:
- branches: [main, v8.x]
+ branches: [main, v8.x-dev]
pull_request:
- branches: [main, v8.x]
+ branches: [main, v8.x-dev]
permissions:
contents: read
diff --git CHANGELOG.md CHANGELOG.md
index 63a93f4a53a8..97ab6f3013da 100644
--- CHANGELOG.md
+++ CHANGELOG.md
@@ -1,3 +1,23 @@
+v8.57.1 - September 16, 2024
+
+* [`140ec45`](https://github.com/eslint/eslint/commit/140ec4569fda5a974b6964242b0b2991828a5567) chore: upgrade @eslint/[email protected] (#18913) (Milos Djermanovic)
+* [`bcdfc04`](https://github.com/eslint/eslint/commit/bcdfc04a69c53dbf1fc3d38603fe0a796bf2274d) chore: package.json update for @eslint/js release (Jenkins)
+* [`3f6ce8d`](https://github.com/eslint/eslint/commit/3f6ce8d6b74aba0d645448e898f271825eeb9630) chore: pin [email protected] (#18910) (Milos Djermanovic)
+* [`a19072f`](https://github.com/eslint/eslint/commit/a19072f9f17ea8266bc66193e5f8a4bf1368835d) fix: add logic to handle fixTypes in the lintText() method (#18900) (Francesco Trotta)
+* [`04c7188`](https://github.com/eslint/eslint/commit/04c718865b75a95ebfc4d429b8c9fad773228624) fix: Don't lint same file multiple times (#18899) (Francesco Trotta)
+* [`87ec3c4`](https://github.com/eslint/eslint/commit/87ec3c49dd23ab8892bc19aae711292d03a73483) fix: do not throw when defining a global named `__defineSetter__` (#18898) (Francesco Trotta)
+* [`60a1267`](https://github.com/eslint/eslint/commit/60a12676878c3fe0623c3b93e7565f003daac5f0) fix: Provide helpful error message for nullish configs (#18889) (Milos Djermanovic)
+* [`35d366a`](https://github.com/eslint/eslint/commit/35d366aed6e8ab0cfa8f9c9bac4656e3784c11f6) build: Support updates to previous major versions (#18870) (Milos Djermanovic)
+* [`a0dea8e`](https://github.com/eslint/eslint/commit/a0dea8ee01cc4c1b65927562afd3a46418573a02) fix: allow `name` in global ignores, fix `--no-ignore` for non-global (#18875) (Milos Djermanovic)
+* [`3836bb4`](https://github.com/eslint/eslint/commit/3836bb48d3f12058ec36c2edf2ca1b50eb1c923b) fix: do not crash on error in `fs.walk` filter (#18886) (Milos Djermanovic)
+* [`2dec349`](https://github.com/eslint/eslint/commit/2dec349199df4cba1554172ad38163cc09ad0a52) fix: skip processor code blocks that match only universal patterns (#18880) (Milos Djermanovic)
+* [`6a5add4`](https://github.com/eslint/eslint/commit/6a5add41e80941c7253b56b02815ac316e583006) docs: v8.x Add EOL banner (#18744) (Amaresh S M)
+* [`b034575`](https://github.com/eslint/eslint/commit/b034575978e3bb57e2edca0d2dc547c7a3abc928) docs: v8.x add version support page to the dropdown (#18731) (Amaresh S M)
+* [`760ef7d`](https://github.com/eslint/eslint/commit/760ef7d9dbd7b615ccbdc20f02cbc05dbabbada8) docs: v8.x add version support page in the side navbar (#18740) (Amaresh S M)
+* [`428b7ea`](https://github.com/eslint/eslint/commit/428b7ea0a9c086b7d8afa0adb629b09d7347d41d) docs: Add Powered by Algolia label to the search (#18658) (Amaresh S M)
+* [`9f07549`](https://github.com/eslint/eslint/commit/9f0754979527d05cd0abb2ea7ab1c3563fb4a361) chore: ignore `/docs/v8.x` in link checker (#18660) (Milos Djermanovic)
+* [`c68c07f`](https://github.com/eslint/eslint/commit/c68c07ff44c180952e93c6f2c860079db6291b29) docs: version selectors synchronization (#18265) (Milos Djermanovic)
+
v8.57.0 - February 23, 2024
* [`1813aec`](https://github.com/eslint/eslint/commit/1813aecc4660582b0678cf32ba466eb9674266c4) chore: upgrade @eslint/[email protected] (#18143) (Milos Djermanovic)
diff --git Makefile.js Makefile.js
index 5e5352895bc8..8bf5e1c7fc4f 100644
--- Makefile.js
+++ Makefile.js
@@ -51,6 +51,8 @@ const OPEN_SOURCE_LICENSES = [
/MIT/u, /BSD/u, /Apache/u, /ISC/u, /WTF/u, /Public Domain/u, /LGPL/u, /Python/u
];
+const MAIN_GIT_BRANCH = "main";
+
//------------------------------------------------------------------------------
// Data
//------------------------------------------------------------------------------
@@ -78,6 +80,8 @@ const NODE = "node ", // intentional extra space
TEST_FILES = "\"tests/{bin,conf,lib,tools}/**/*.js\"",
PERF_ESLINTRC = path.join(PERF_TMP_DIR, "eslint.config.js"),
PERF_MULTIFILES_TARGET_DIR = path.join(PERF_TMP_DIR, "eslint"),
+ CHANGELOG_FILE = "./CHANGELOG.md",
+ VERSIONS_FILE = "./docs/src/_data/versions.json",
/*
* glob arguments with Windows separator `\` don't work:
@@ -125,6 +129,14 @@ function execSilent(cmd) {
return exec(cmd, { silent: true }).stdout;
}
+/**
+ * Gets name of the currently checked out Git branch.
+ * @returns {string} Name of the currently checked out Git branch.
+ */
+function getCurrentGitBranch() {
+ return execSilent("git branch --show-current").trim();
+}
+
/**
* Generates a release blog post for eslint.org
* @param {Object} releaseInfo The release metadata.
@@ -274,10 +286,14 @@ function publishSite() {
/**
* Updates the changelog, bumps the version number in package.json, creates a local git commit and tag,
* and generates the site in an adjacent `website` folder.
+ * @param {Object} options Release options.
+ * @param {string} options.packageTag Tag that should be added to the package submitted to the npm registry.
* @returns {void}
*/
-function generateRelease() {
- ReleaseOps.generateRelease();
+function generateRelease({ packageTag }) {
+ echo(`Current Git branch: ${getCurrentGitBranch()}`);
+
+ ReleaseOps.generateRelease(/* prereleaseId = */ void 0, packageTag);
const releaseInfo = JSON.parse(cat(".eslint-release-info.json"));
echo("Generating site");
@@ -343,19 +359,33 @@ function generatePrerelease(prereleaseId) {
function publishRelease() {
ReleaseOps.publishRelease();
const releaseInfo = JSON.parse(cat(".eslint-release-info.json"));
- const isPreRelease = /[a-z]/u.test(releaseInfo.version);
- /*
- * for a pre-release, push to the "next" branch to trigger docs deploy
- * for a release, push to the "latest" branch to trigger docs deploy
- */
- if (isPreRelease) {
- exec("git push origin HEAD:next -f");
- } else {
- exec("git push origin HEAD:latest -f");
- }
+ const docsSiteBranch = releaseInfo.packageTag === "maintenance"
+ ? `v${semver.major(releaseInfo.version)}.x`
+ : releaseInfo.packageTag; // "latest" or "next"
+
+ echo(`Updating docs site branch: ${docsSiteBranch}`);
+ exec(`git push origin HEAD:${docsSiteBranch} -f`);
publishSite();
+
+ // Update changelog and list of versions on the main branch
+ if (getCurrentGitBranch() !== MAIN_GIT_BRANCH) {
+ echo(`Updating changelog and versions on branch: ${MAIN_GIT_BRANCH}`);
+
+ exec(`git checkout ${MAIN_GIT_BRANCH} --force`);
+
+ fs.writeFileSync(CHANGELOG_FILE, `${releaseInfo.markdownChangelog}${cat(CHANGELOG_FILE)}`);
+
+ const versions = JSON.parse(cat(VERSIONS_FILE));
+
+ versions.items.find(({ branch }) => branch === docsSiteBranch).version = releaseInfo.version;
+ fs.writeFileSync(VERSIONS_FILE, `${JSON.stringify(versions, null, 4)}\n`);
+
+ exec(`git add ${CHANGELOG_FILE} ${VERSIONS_FILE}`);
+ exec(`git commit -m "chore: updates for v${releaseInfo.version} release"`);
+ exec("git push origin HEAD");
+ }
}
/**
@@ -1105,6 +1135,6 @@ target.perf = function() {
});
};
-target.generateRelease = generateRelease;
+target.generateRelease = ([packageTag]) => generateRelease({ packageTag });
target.generatePrerelease = ([prereleaseType]) => generatePrerelease(prereleaseType);
target.publishRelease = publishRelease;
diff --git docs/.eleventy.js docs/.eleventy.js
index 9debf1c0d6f5..4370ea227282 100644
--- docs/.eleventy.js
+++ docs/.eleventy.js
@@ -43,6 +43,8 @@ module.exports = function(eleventyConfig) {
pathPrefix = "/docs/latest/";
} else if (process.env.BRANCH === "next") {
pathPrefix = "/docs/next/";
+ } else if (process.env.BRANCH && /^v\d+\.x$/u.test(process.env.BRANCH)) {
+ pathPrefix = `/docs/${process.env.BRANCH}/`; // `/docs/v8.x/`, `/docs/v9.x/`, `/docs/v10.x/` ...
}
//------------------------------------------------------------------------------
diff --git docs/package.json docs/package.json
index f513acf8f5e3..40a00e5c116d 100644
--- docs/package.json
+++ docs/package.json
@@ -1,7 +1,7 @@
{
"name": "docs-eslint",
"private": true,
- "version": "8.57.0",
+ "version": "8.57.1",
"description": "",
"main": "index.js",
"keywords": [],
diff --git a/docs/src/_data/eslintVersions.js b/docs/src/_data/eslintVersions.js
new file mode 100644
index 000000000000..2fc2b981828b
diff --git a/docs/src/use/version-suppport.md b/docs/src/use/version-suppport.md
new file mode 100644
index 000000000000..483d05330498
diff --git lib/config/flat-config-array.js lib/config/flat-config-array.js
index 689dc429f502..99d1dee6752e 100644
--- lib/config/flat-config-array.js
+++ lib/config/flat-config-array.js
@@ -19,6 +19,11 @@ const jsPlugin = require("@eslint/js");
// Helpers
//-----------------------------------------------------------------------------
+/**
+ * Fields that are considered metadata and not part of the config object.
+ */
+const META_FIELDS = new Set(["name"]);
+
const ruleValidator = new RuleValidator();
/**
@@ -75,7 +80,53 @@ function getObjectId(object) {
return name;
}
+/**
+ * Wraps a config error with details about where the error occurred.
+ * @param {Error} error The original error.
+ * @param {number} originalLength The original length of the config array.
+ * @param {number} baseLength The length of the base config.
+ * @returns {TypeError} The new error with details.
+ */
+function wrapConfigErrorWithDetails(error, originalLength, baseLength) {
+
+ let location = "user-defined";
+ let configIndex = error.index;
+
+ /*
+ * A config array is set up in this order:
+ * 1. Base config
+ * 2. Original configs
+ * 3. User-defined configs
+ * 4. CLI-defined configs
+ *
+ * So we need to adjust the index to account for the base config.
+ *
+ * - If the index is less than the base length, it's in the base config
+ * (as specified by `baseConfig` argument to `FlatConfigArray` constructor).
+ * - If the index is greater than the base length but less than the original
+ * length + base length, it's in the original config. The original config
+ * is passed to the `FlatConfigArray` constructor as the first argument.
+ * - Otherwise, it's in the user-defined config, which is loaded from the
+ * config file and merged with any command-line options.
+ */
+ if (error.index < baseLength) {
+ location = "base";
+ } else if (error.index < originalLength + baseLength) {
+ location = "original";
+ configIndex = error.index - baseLength;
+ } else {
+ configIndex = error.index - originalLength - baseLength;
+ }
+
+ return new TypeError(
+ `${error.message.slice(0, -1)} at ${location} index ${configIndex}.`,
+ { cause: error }
+ );
+}
+
const originalBaseConfig = Symbol("originalBaseConfig");
+const originalLength = Symbol("originalLength");
+const baseLength = Symbol("baseLength");
//-----------------------------------------------------------------------------
// Exports
@@ -102,12 +153,24 @@ class FlatConfigArray extends ConfigArray {
schema: flatConfigSchema
});
+ /**
+ * The original length of the array before any modifications.
+ * @type {number}
+ */
+ this[originalLength] = this.length;
+
if (baseConfig[Symbol.iterator]) {
this.unshift(...baseConfig);
} else {
this.unshift(baseConfig);
}
+ /**
+ * The length of the array after applying the base config.
+ * @type {number}
+ */
+ this[baseLength] = this.length - this[originalLength];
+
/**
* The base config used to build the config array.
* @type {Array<FlatConfig>}
@@ -125,6 +188,49 @@ class FlatConfigArray extends ConfigArray {
Object.defineProperty(this, "shouldIgnore", { writable: false });
}
+ /**
+ * Normalizes the array by calling the superclass method and catching/rethrowing
+ * any ConfigError exceptions with additional details.
+ * @param {any} [context] The context to use to normalize the array.
+ * @returns {Promise<FlatConfigArray>} A promise that resolves when the array is normalized.
+ */
+ normalize(context) {
+ return super.normalize(context)
+ .catch(error => {
+ if (error.name === "ConfigError") {
+ throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]);
+ }
+
+ throw error;
+
+ });
+ }
+
+ /**
+ * Normalizes the array by calling the superclass method and catching/rethrowing
+ * any ConfigError exceptions with additional details.
+ * @param {any} [context] The context to use to normalize the array.
+ * @returns {FlatConfigArray} The current instance.
+ * @throws {TypeError} If the config is invalid.
+ */
+ normalizeSync(context) {
+
+ try {
+
+ return super.normalizeSync(context);
+
+ } catch (error) {
+
+ if (error.name === "ConfigError") {
+ throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]);
+ }
+
+ throw error;
+
+ }
+
+ }
+
/* eslint-disable class-methods-use-this -- Desired as instance method */
/**
* Replaces a config with another config to allow us to put strings
@@ -155,15 +261,15 @@ class FlatConfigArray extends ConfigArray {
}
/*
- * If `shouldIgnore` is false, we remove any ignore patterns specified
- * in the config so long as it's not a default config and it doesn't
- * have a `files` entry.
+ * If a config object has `ignores` and no other non-meta fields, then it's an object
+ * for global ignores. If `shouldIgnore` is false, that object shouldn't apply,
+ * so we'll remove its `ignores`.
*/
if (
!this.shouldIgnore &&
!this[originalBaseConfig].includes(config) &&
config.ignores &&
- !config.files
+ Object.keys(config).filter(key => !META_FIELDS.has(key)).length === 1
) {
/* eslint-disable-next-line no-unused-vars -- need to strip off other keys */
const { ignores, ...otherKeys } = config;
diff --git lib/eslint/eslint-helpers.js lib/eslint/eslint-helpers.js
index 685826ac69cf..3c65d11bf52e 100644
--- lib/eslint/eslint-helpers.js
+++ lib/eslint/eslint-helpers.js
@@ -15,7 +15,6 @@ const fsp = fs.promises;
const isGlob = require("is-glob");
const hash = require("../cli-engine/hash");
const minimatch = require("minimatch");
-const util = require("util");
const fswalk = require("@nodelib/fs.walk");
const globParent = require("glob-parent");
const isPathInside = require("is-path-inside");
@@ -24,7 +23,6 @@ const isPathInside = require("is-path-inside");
// Fixup references
//-----------------------------------------------------------------------------
-const doFsWalk = util.promisify(fswalk.walk);
const Minimatch = minimatch.Minimatch;
const MINIMATCH_OPTIONS = { dot: true };
@@ -270,56 +268,92 @@ async function globSearch({
*/
const unmatchedPatterns = new Set([...relativeToPatterns.keys()]);
- const filePaths = (await doFsWalk(basePath, {
+ const filePaths = (await new Promise((resolve, reject) => {
- deepFilter(entry) {
- const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
- const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true));
-
- return matchesPattern && !configs.isDirectoryIgnored(entry.path);
- },
- entryFilter(entry) {
- const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
+ let promiseRejected = false;
- // entries may be directories or files so filter out directories
- if (entry.dirent.isDirectory()) {
+ /**
+ * Wraps a boolean-returning filter function. The wrapped function will reject the promise if an error occurs.
+ * @param {Function} filter A filter function to wrap.
+ * @returns {Function} A function similar to the wrapped filter that rejects the promise if an error occurs.
+ */
+ function wrapFilter(filter) {
+ return (...args) => {
+
+ // No need to run the filter if an error has been thrown.
+ if (!promiseRejected) {
+ try {
+ return filter(...args);
+ } catch (error) {
+ promiseRejected = true;
+ reject(error);
+ }
+ }
return false;
- }
+ };
+ }
- /*
- * Optimization: We need to track when patterns are left unmatched
- * and so we use `unmatchedPatterns` to do that. There is a bit of
- * complexity here because the same file can be matched by more than
- * one pattern. So, when we start, we actually need to test every
- * pattern against every file. Once we know there are no remaining
- * unmatched patterns, then we can switch to just looking for the
- * first matching pattern for improved speed.
- */
- const matchesPattern = unmatchedPatterns.size > 0
- ? matchers.reduce((previousValue, matcher) => {
- const pathMatches = matcher.match(relativePath);
+ fswalk.walk(
+ basePath,
+ {
+ deepFilter: wrapFilter(entry => {
+ const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
+ const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true));
+
+ return matchesPattern && !configs.isDirectoryIgnored(entry.path);
+ }),
+ entryFilter: wrapFilter(entry => {
+ const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
+
+ // entries may be directories or files so filter out directories
+ if (entry.dirent.isDirectory()) {
+ return false;
+ }
/*
- * We updated the unmatched patterns set only if the path
- * matches and the file isn't ignored. If the file is
- * ignored, that means there wasn't a match for the
- * pattern so it should not be removed.
- *
- * Performance note: isFileIgnored() aggressively caches
- * results so there is no performance penalty for calling
- * it twice with the same argument.
+ * Optimization: We need to track when patterns are left unmatched
+ * and so we use `unmatchedPatterns` to do that. There is a bit of
+ * complexity here because the same file can be matched by more than
+ * one pattern. So, when we start, we actually need to test every
+ * pattern against every file. Once we know there are no remaining
+ * unmatched patterns, then we can switch to just looking for the
+ * first matching pattern for improved speed.
*/
- if (pathMatches && !configs.isFileIgnored(entry.path)) {
- unmatchedPatterns.delete(matcher.pattern);
- }
-
- return pathMatches || previousValue;
- }, false)
- : matchers.some(matcher => matcher.match(relativePath));
-
- return matchesPattern && !configs.isFileIgnored(entry.path);
- }
-
+ const matchesPattern = unmatchedPatterns.size > 0
+ ? matchers.reduce((previousValue, matcher) => {
+ const pathMatches = matcher.match(relativePath);
+
+ /*
+ * We updated the unmatched patterns set only if the path
+ * matches and the file isn't ignored. If the file is
+ * ignored, that means there wasn't a match for the
+ * pattern so it should not be removed.
+ *
+ * Performance note: isFileIgnored() aggressively caches
+ * results so there is no performance penalty for calling
+ * it twice with the same argument.
+ */
+ if (pathMatches && !configs.isFileIgnored(entry.path)) {
+ unmatchedPatterns.delete(matcher.pattern);
+ }
+
+ return pathMatches || previousValue;
+ }, false)
+ : matchers.some(matcher => matcher.match(relativePath));
+
+ return matchesPattern && !configs.isFileIgnored(entry.path);
+ })
+ },
+ (error, entries) => {
+
+ // If the promise is already rejected, calling `resolve` or `reject` will do nothing.
+ if (error) {
+ reject(error);
+ } else {
+ resolve(entries);
+ }
+ }
+ );
})).map(entry => entry.path);
// now check to see if we have any unmatched patterns
@@ -450,7 +484,7 @@ async function globMultiSearch({ searches, configs, errorOnUnmatchedPattern }) {
}
- return [...new Set(filePaths)];
+ return filePaths;
}
@@ -499,10 +533,7 @@ async function findFiles({
// files are added directly to the list
if (stat.isFile()) {
- results.push({
- filePath,
- ignored: configs.isFileIgnored(filePath)
- });
+ results.push(filePath);
}
// directories need extensions attached
@@ -560,11 +591,10 @@ async function findFiles({
});
return [
- ...results,
- ...globbyResults.map(filePath => ({
- filePath: path.resolve(filePath),
- ignored: false
- }))
+ ...new Set([
+ ...results,
+ ...globbyResults.map(filePath => path.resolve(filePath))
+ ])
];
}
diff --git lib/eslint/flat-eslint.js lib/eslint/flat-eslint.js
index ca961aafb649..e4e19a832dea 100644
--- lib/eslint/flat-eslint.js
+++ lib/eslint/flat-eslint.js
@@ -489,7 +489,7 @@ function verifyText({
* @returns {boolean} `true` if the linter should adopt the code block.
*/
filterCodeBlock(blockFilename) {
- return configs.isExplicitMatch(blockFilename);
+ return configs.getConfig(blockFilename) !== void 0;
}
}
);
@@ -541,6 +541,23 @@ function createExtraneousResultsError() {
return new TypeError("Results object was not created from this ESLint instance.");
}
+/**
+ * Creates a fixer function based on the provided fix, fixTypesSet, and config.
+ * @param {Function|boolean} fix The original fix option.
+ * @param {Set<string>} fixTypesSet A set of fix types to filter messages for fixing.
+ * @param {FlatConfig} config The config for the file that generated the message.
+ * @returns {Function|boolean} The fixer function or the original fix value.
+ */
+function getFixerForFixTypes(fix, fixTypesSet, config) {
+ if (!fix || !fixTypesSet) {
+ return fix;
+ }
+
+ const originalFix = (typeof fix === "function") ? fix : () => true;
+
+ return message => shouldMessageBeFixed(message, config, fixTypesSet) && originalFix(message);
+}
+
//-----------------------------------------------------------------------------
// Main API
//-----------------------------------------------------------------------------
@@ -790,13 +807,15 @@ class FlatESLint {
*/
const results = await Promise.all(
- filePaths.map(({ filePath, ignored }) => {
+ filePaths.map(filePath => {
+
+ const config = configs.getConfig(filePath);
/*
- * If a filename was entered that matches an ignore
- * pattern, then notify the user.
+ * If a filename was entered that cannot be matched
+ * to a config, then notify the user.
*/
- if (ignored) {
+ if (!config) {
if (warnIgnored) {
return createIgnoreResult(filePath, cwd);
}
@@ -804,17 +823,6 @@ class FlatESLint {
return void 0;
}
- const config = configs.getConfig(filePath);
-
- /*
- * Sometimes a file found through a glob pattern will
- * be ignored. In this case, `config` will be undefined
- * and we just silently ignore the file.
- */
- if (!config) {
- return void 0;
- }
-
// Skip if there is cached result.
if (lintResultCache) {
const cachedResult =
@@ -836,16 +844,7 @@ class FlatESLint {
// set up fixer for fixTypes if necessary
- let fixer = fix;
-
- if (fix && fixTypesSet) {
-
- // save original value of options.fix in case it's a function
- const originalFix = (typeof fix === "function")
- ? fix : () => true;
-
- fixer = message => shouldMessageBeFixed(message, config, fixTypesSet) && originalFix(message);
- }
+ const fixer = getFixerForFixTypes(fix, fixTypesSet, config);
return fs.readFile(filePath, "utf8")
.then(text => {
@@ -942,11 +941,16 @@ class FlatESLint {
allowInlineConfig,
cwd,
fix,
+ fixTypes,
warnIgnored: constructorWarnIgnored
} = eslintOptions;
const results = [];
const startTime = Date.now();
+ const fixTypesSet = fixTypes ? new Set(fixTypes) : null;
const resolvedFilename = path.resolve(cwd, filePath || "__placeholder__.js");
+ const config = configs.getConfig(resolvedFilename);
+
+ const fixer = getFixerForFixTypes(fix, fixTypesSet, config);
// Clear the last used config arrays.
if (resolvedFilename && await this.isPathIgnored(resolvedFilename)) {
@@ -963,7 +967,7 @@ class FlatESLint {
filePath: resolvedFilename.endsWith("__placeholder__.js") ? "<text>" : resolvedFilename,
configs,
cwd,
- fix,
+ fix: fixer,
allowInlineConfig,
linter
}));
diff --git lib/linter/linter.js lib/linter/linter.js
index f74d0ecd13f2..d25f85403f6a 100644
--- lib/linter/linter.js
+++ lib/linter/linter.js
@@ -733,7 +733,7 @@ function createLanguageOptions({ globals: configuredGlobals, parser, parserOptio
*/
function resolveGlobals(providedGlobals, enabledEnvironments) {
return Object.assign(
- {},
+ Object.create(null),
...enabledEnvironments.filter(env => env.globals).map(env => env.globals),
providedGlobals
);
diff --git lib/source-code/source-code.js lib/source-code/source-code.js
index 236f6b5c6cc1..e3c6e978162d 100644
--- lib/source-code/source-code.js
+++ lib/source-code/source-code.js
@@ -934,7 +934,7 @@ class SourceCode extends TokenStore {
* https://github.com/eslint/eslint/issues/16302
*/
const configGlobals = Object.assign(
- {},
+ Object.create(null), // https://github.com/eslint/eslint/issues/18363
getGlobalsForEcmaVersion(languageOptions.ecmaVersion),
languageOptions.sourceType === "commonjs" ? globals.commonjs : void 0,
languageOptions.globals
diff --git package.json package.json
index a51b58b2444f..8517c3170393 100644
--- package.json
+++ package.json
@@ -1,6 +1,6 @@
{
"name": "eslint",
- "version": "8.57.0",
+ "version": "8.57.1",
"author": "Nicholas C. Zakas <[email protected]>",
"description": "An AST-based pattern checker for JavaScript.",
"bin": {
@@ -24,7 +24,8 @@
"lint:fix:docs:js": "node Makefile.js lintDocsJS -- fix",
"release:generate:alpha": "node Makefile.js generatePrerelease -- alpha",
"release:generate:beta": "node Makefile.js generatePrerelease -- beta",
- "release:generate:latest": "node Makefile.js generateRelease",
+ "release:generate:latest": "node Makefile.js generateRelease -- latest",
+ "release:generate:maintenance": "node Makefile.js generateRelease -- maintenance",
"release:generate:rc": "node Makefile.js generatePrerelease -- rc",
"release:publish": "node Makefile.js publishRelease",
"test": "node Makefile.js test",
@@ -65,8 +66,8 @@
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.57.0",
- "@humanwhocodes/config-array": "^0.11.14",
+ "@eslint/js": "8.57.1",
+ "@humanwhocodes/config-array": "^0.13.0",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0",
@@ -104,6 +105,7 @@
"devDependencies": {
"@babel/core": "^7.4.3",
"@babel/preset-env": "^7.4.3",
+ "@sinonjs/fake-timers": "11.2.2",
"@wdio/browser-runner": "^8.14.6",
"@wdio/cli": "^8.14.6",
"@wdio/concise-reporter": "^8.14.0",
@@ -124,7 +126,7 @@
"eslint-plugin-jsdoc": "^46.2.5",
"eslint-plugin-n": "^16.6.0",
"eslint-plugin-unicorn": "^49.0.0",
- "eslint-release": "^3.2.0",
+ "eslint-release": "^3.3.0",
"eslump": "^3.0.0",
"esprima": "^4.0.1",
"fast-glob": "^3.2.11",
@@ -159,7 +161,7 @@
"semver": "^7.5.3",
"shelljs": "^0.8.2",
"sinon": "^11.0.0",
- "vite-plugin-commonjs": "^0.10.0",
+ "vite-plugin-commonjs": "0.10.1",
"webdriverio": "^8.14.6",
"webpack": "^5.23.0",
"webpack-cli": "^4.5.0",
diff --git packages/js/package.json packages/js/package.json
index 8f6776fa06d0..e9ec6a2860a3 100644
--- packages/js/package.json
+++ packages/js/package.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/js",
- "version": "8.57.0",
+ "version": "8.57.1",
"description": "ESLint JavaScript language implementation",
"main": "./src/index.js",
"scripts": {},
diff --git a/tests/fixtures/eslint.config-with-ignores3.js b/tests/fixtures/eslint.config-with-ignores3.js
new file mode 100644
index 000000000000..ed82eee5cd58
--- /dev/null
+++ tests/fixtures/eslint.config-with-ignores3.js
@@ -0,0 +1,9 @@
+const eslintConfig = require("./eslint.config.js");
+
+module.exports = [
+ eslintConfig,
+ {
+ name: "Global ignores",
+ ignores: ["**/*.json", "**/*.js"]
+ }
+];
diff --git tests/lib/config/flat-config-array.js tests/lib/config/flat-config-array.js
index c38f099a3188..1184f4ff0d41 100644
--- tests/lib/config/flat-config-array.js
+++ tests/lib/config/flat-config-array.js
@@ -120,9 +120,8 @@ async function assertMergedResult(values, result) {
async function assertInvalidConfig(values, message) {
const configs = createFlatConfigArray(values);
- await configs.normalize();
-
assert.throws(() => {
+ configs.normalizeSync();
configs.getConfig("foo.js");
}, message);
}
@@ -650,6 +649,161 @@ describe("FlatConfigArray", () => {
});
});
+ describe("Config array elements", () => {
+ it("should error on a 'foo' string config", async () => {
+
+ await assertInvalidConfig(["foo"], "Config (unnamed): Unexpected non-object config at original index 0.");
+ });
+
+ it("should throw an error when undefined original config is normalized", () => {
+
+ const configs = new FlatConfigArray([void 0]);
+
+ assert.throws(() => {
+ configs.normalizeSync();
+ }, "Config (unnamed): Unexpected undefined config at original index 0.");
+
+ });
+
+ it("should throw an error when undefined original config is normalized asynchronously", async () => {
+
+ const configs = new FlatConfigArray([void 0]);
+
+ try {
+ await configs.normalize();
+ assert.fail("Error not thrown");
+ } catch (error) {
+ assert.strictEqual(error.message, "Config (unnamed): Unexpected undefined config at original index 0.");
+ }
+
+ });
+
+ it("should throw an error when null original config is normalized", () => {
+
+ const configs = new FlatConfigArray([null]);
+
+ assert.throws(() => {
+ configs.normalizeSync();
+ }, "Config (unnamed): Unexpected null config at original index 0.");
+
+ });
+
+ it("should throw an error when null original config is normalized asynchronously", async () => {
+
+ const configs = new FlatConfigArray([null]);
+
+ try {
+ await configs.normalize();
+ assert.fail("Error not thrown");
+ } catch (error) {
+ assert.strictEqual(error.message, "Config (unnamed): Unexpected null config at original index 0.");
+ }
+
+ });
+
+ it("should throw an error when undefined base config is normalized", () => {
+
+ const configs = new FlatConfigArray([], { baseConfig: [void 0] });
+
+ assert.throws(() => {
+ configs.normalizeSync();
+ }, "Config (unnamed): Unexpected undefined config at base index 0.");
+
+ });
+
+ it("should throw an error when undefined base config is normalized asynchronously", async () => {
+
+ const configs = new FlatConfigArray([], { baseConfig: [void 0] });
+
+ try {
+ await configs.normalize();
+ assert.fail("Error not thrown");
+ } catch (error) {
+ assert.strictEqual(error.message, "Config (unnamed): Unexpected undefined config at base index 0.");
+ }
+
+ });
+
+ it("should throw an error when null base config is normalized", () => {
+
+ const configs = new FlatConfigArray([], { baseConfig: [null] });
+
+ assert.throws(() => {
+ configs.normalizeSync();
+ }, "Config (unnamed): Unexpected null config at base index 0.");
+
+ });
+
+ it("should throw an error when null base config is normalized asynchronously", async () => {
+
+ const configs = new FlatConfigArray([], { baseConfig: [null] });
+
+ try {
+ await configs.normalize();
+ assert.fail("Error not thrown");
+ } catch (error) {
+ assert.strictEqual(error.message, "Config (unnamed): Unexpected null config at base index 0.");
+ }
+
+ });
+
+ it("should throw an error when undefined user-defined config is normalized", () => {
+
+ const configs = new FlatConfigArray([]);
+
+ configs.push(void 0);
+
+ assert.throws(() => {
+ configs.normalizeSync();
+ }, "Config (unnamed): Unexpected undefined config at user-defined index 0.");
+
+ });
+
+ it("should throw an error when undefined user-defined config is normalized asynchronously", async () => {
+
+ const configs = new FlatConfigArray([]);
+
+ configs.push(void 0);
+
+ try {
+ await configs.normalize();
+ assert.fail("Error not thrown");
+ } catch (error) {
+ assert.strictEqual(error.message, "Config (unnamed): Unexpected undefined config at user-defined index 0.");
+ }
+
+ });
+
+ it("should throw an error when null user-defined config is normalized", () => {
+
+ const configs = new FlatConfigArray([]);
+
+ configs.push(null);
+
+ assert.throws(() => {
+ configs.normalizeSync();
+ }, "Config (unnamed): Unexpected null config at user-defined index 0.");
+
+ });
+
+ it("should throw an error when null user-defined config is normalized asynchronously", async () => {
+
+ const configs = new FlatConfigArray([]);
+
+ configs.push(null);
+
+ try {
+ await configs.normalize();
+ assert.fail("Error not thrown");
+ } catch (error) {
+ assert.strictEqual(error.message, "Config (unnamed): Unexpected null config at user-defined index 0.");
+ }
+
+ });
+
+
+ });
+
describe("Config Properties", () => {
describe("settings", () => {
diff --git tests/lib/eslint/flat-eslint.js tests/lib/eslint/flat-eslint.js
index 9bfdff3e305c..b06753bc763c 100644
--- tests/lib/eslint/flat-eslint.js
+++ tests/lib/eslint/flat-eslint.js
@@ -66,6 +66,12 @@ describe("FlatESLint", () => {
}
};
const examplePreprocessorName = "eslint-plugin-processor";
+ const patternProcessor = require("../../fixtures/processors/pattern-processor");
+ const exampleMarkdownPlugin = {
+ processors: {
+ markdown: patternProcessor.defineProcessor(/\`\`\`(\w+)\n(.+?)\n```(?:\n|$)/gsu)
+ }
+ };
const originalDir = process.cwd();
const fixtureDir = path.resolve(fs.realpathSync(os.tmpdir()), "eslint/fixtures");
@@ -1031,6 +1037,56 @@ describe("FlatESLint", () => {
await assert.rejects(async () => await eslint.lintFiles(["lib/cli.js"]), /Expected object with parse\(\) or parseForESLint\(\) method/u);
});
+ describe("Overlapping searches", () => {
+ it("should not lint the same file multiple times when the file path was passed multiple times", async () => {
+ const cwd = getFixturePath();
+
+ eslint = new FlatESLint({
+ cwd,
+ overrideConfigFile: true
+ });
+
+ const results = await eslint.lintFiles(["files/foo.js", "files/../files/foo.js", "files/foo.js"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].filePath, path.resolve(cwd, "files/foo.js"));
+ assert.strictEqual(results[0].messages.length, 0);
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ });
+
+ it("should not lint the same file multiple times when the file path and a pattern that matches the file were passed", async () => {
+ const cwd = getFixturePath();
+
+ eslint = new FlatESLint({
+ cwd,
+ overrideConfigFile: true
+ });
+
+ const results = await eslint.lintFiles(["files/foo.js", "files/foo*"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].filePath, path.resolve(cwd, "files/foo.js"));
+ assert.strictEqual(results[0].messages.length, 0);
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ });
+
+ it("should not lint the same file multiple times when multiple patterns that match the file were passed", async () => {
+ const cwd = getFixturePath();
+
+ eslint = new FlatESLint({
+ cwd,
+ overrideConfigFile: true
+ });
+
+ const results = await eslint.lintFiles(["files/f*.js", "files/foo*"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].filePath, path.resolve(cwd, "files/foo.js"));
+ assert.strictEqual(results[0].messages.length, 0);
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ });
+ });
+
it("should report zero messages when given a directory with a .js2 file", async () => {
eslint = new FlatESLint({
cwd: path.join(fixtureDir, ".."),
@@ -1543,6 +1599,16 @@ describe("FlatESLint", () => {
}, /All files matched by 'tests\/fixtures\/cli-engine\/' are ignored\./u);
});
+ it("should throw an error when all given files are ignored by a config object that has `name`", async () => {
+ eslint = new FlatESLint({
+ overrideConfigFile: getFixturePath("eslint.config-with-ignores3.js")
+ });
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["tests/fixtures/cli-engine/"]);
+ }, /All files matched by 'tests\/fixtures\/cli-engine\/' are ignored\./u);
+ });
+
it("should throw an error when all given files are ignored even with a `./` prefix", async () => {
eslint = new FlatESLint({
overrideConfigFile: getFixturePath("eslint.config_with_ignores.js")
@@ -1676,6 +1742,29 @@ describe("FlatESLint", () => {
assert.strictEqual(results[0].suppressedMessages.length, 0);
});
+ it("should return two messages when given a file in excluded files list by a config object that has `name` while ignore is off", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath(),
+ ignore: false,
+ overrideConfigFile: getFixturePath("eslint.config-with-ignores3.js"),
+ overrideConfig: {
+ rules: {
+ "no-undef": 2
+ }
+ }
+ });
+ const filePath = fs.realpathSync(getFixturePath("undef.js"));
+ const results = await eslint.lintFiles([filePath]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].filePath, filePath);
+ assert.strictEqual(results[0].messages[0].ruleId, "no-undef");
+ assert.strictEqual(results[0].messages[0].severity, 2);
+ assert.strictEqual(results[0].messages[1].ruleId, "no-undef");
+ assert.strictEqual(results[0].messages[1].severity, 2);
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ });
+
// https://github.com/eslint/eslint/issues/16300
it("should process ignore patterns relative to basePath not cwd", async () => {
eslint = new FlatESLint({
@@ -3590,6 +3679,178 @@ describe("FlatESLint", () => {
assert(!Object.prototype.hasOwnProperty.call(results[0], "output"));
});
});
+
+ describe("matching and ignoring code blocks", () => {
+ const pluginConfig = {
+ files: ["**/*.md"],
+ plugins: {
+ markdown: exampleMarkdownPlugin
+ },
+ processor: "markdown/markdown"
+ };
+ const text = unIndent`
+ \`\`\`js
+ foo_js
+ \`\`\`
+
+ \`\`\`ts
+ foo_ts
+ \`\`\`
+
+ \`\`\`cjs
+ foo_cjs
+ \`\`\`
+
+ \`\`\`mjs
+ foo_mjs
+ \`\`\`
+ `;
+
+ it("should by default lint only .js, .mjs, and .cjs virtual files", async () => {
+ eslint = new FlatESLint({
+ overrideConfigFile: true,
+ overrideConfig: [
+ pluginConfig,
+ {
+ rules: {
+ "no-undef": 2
+ }
+ }
+ ]
+ });
+ const [result] = await eslint.lintText(text, { filePath: "foo.md" });
+
+ assert.strictEqual(result.messages.length, 3);
+ assert.strictEqual(result.messages[0].ruleId, "no-undef");
+ assert.match(result.messages[0].message, /foo_js/u);
+ assert.strictEqual(result.messages[0].line, 2);
+ assert.strictEqual(result.messages[1].ruleId, "no-undef");
+ assert.match(result.messages[1].message, /foo_cjs/u);
+ assert.strictEqual(result.messages[1].line, 10);
+ assert.strictEqual(result.messages[2].ruleId, "no-undef");
+ assert.match(result.messages[2].message, /foo_mjs/u);
+ assert.strictEqual(result.messages[2].line, 14);
+ });
+
+ it("should lint additional virtual files that match non-universal patterns", async () => {
+ eslint = new FlatESLint({
+ overrideConfigFile: true,
+ overrideConfig: [
+ pluginConfig,
+ {
+ rules: {
+ "no-undef": 2
+ }
+ },
+ {
+ files: ["**/*.ts"]
+ }
+ ]
+ });
+ const [result] = await eslint.lintText(text, { filePath: "foo.md" });
+
+ assert.strictEqual(result.messages.length, 4);
+ assert.strictEqual(result.messages[0].ruleId, "no-undef");
+ assert.match(result.messages[0].message, /foo_js/u);
+ assert.strictEqual(result.messages[0].line, 2);
+ assert.strictEqual(result.messages[1].ruleId, "no-undef");
+ assert.match(result.messages[1].message, /foo_ts/u);
+ assert.strictEqual(result.messages[1].line, 6);
+ assert.strictEqual(result.messages[2].ruleId, "no-undef");
+ assert.match(result.messages[2].message, /foo_cjs/u);
+ assert.strictEqual(result.messages[2].line, 10);
+ assert.strictEqual(result.messages[3].ruleId, "no-undef");
+ assert.match(result.messages[3].message, /foo_mjs/u);
+ assert.strictEqual(result.messages[3].line, 14);
+ });
+
+ // https://github.com/eslint/eslint/issues/18493
+ it("should silently skip virtual files that match only universal patterns", async () => {
+ eslint = new FlatESLint({
+ overrideConfigFile: true,
+ overrideConfig: [
+ pluginConfig,
+ {
+ files: ["**/*"],
+ rules: {
+ "no-undef": 2
+ }
+ }
+ ]
+ });
+ const [result] = await eslint.lintText(text, { filePath: "foo.md" });
+
+ assert.strictEqual(result.messages.length, 3);
+ assert.strictEqual(result.messages[0].ruleId, "no-undef");
+ assert.match(result.messages[0].message, /foo_js/u);
+ assert.strictEqual(result.messages[0].line, 2);
+ assert.strictEqual(result.messages[1].ruleId, "no-undef");
+ assert.match(result.messages[1].message, /foo_cjs/u);
+ assert.strictEqual(result.messages[1].line, 10);
+ assert.strictEqual(result.messages[2].ruleId, "no-undef");
+ assert.match(result.messages[2].message, /foo_mjs/u);
+ assert.strictEqual(result.messages[2].line, 14);
+ });
+
+ it("should silently skip virtual files that are ignored by global ignores", async () => {
+ eslint = new FlatESLint({
+ overrideConfigFile: true,
+ overrideConfig: [
+ pluginConfig,
+ {
+ rules: {
+ "no-undef": 2
+ }
+ },
+ {
+ ignores: ["**/*.cjs"]
+ }
+ ]
+ });
+ const [result] = await eslint.lintText(text, { filePath: "foo.md" });
+
+ assert.strictEqual(result.messages.length, 2);
+ assert.strictEqual(result.messages[0].ruleId, "no-undef");
+ assert.match(result.messages[0].message, /foo_js/u);
+ assert.strictEqual(result.messages[0].line, 2);
+ assert.strictEqual(result.messages[1].ruleId, "no-undef");
+ assert.match(result.messages[1].message, /foo_mjs/u);
+ assert.strictEqual(result.messages[1].line, 14);
+ });
+
+ // https://github.com/eslint/eslint/issues/15949
+ it("should silently skip virtual files that are ignored by global ignores even if they match non-universal patterns", async () => {
+ eslint = new FlatESLint({
+ overrideConfigFile: true,
+ overrideConfig: [
+ pluginConfig,
+ {
+ rules: {
+ "no-undef": 2
+ }
+ },
+ {
+ files: ["**/*.ts"]
+ },
+ {
+ ignores: ["**/*.md/*.ts"]
+ }
+ ]
+ });
+ const [result] = await eslint.lintText(text, { filePath: "foo.md" });
+
+ assert.strictEqual(result.messages.length, 3);
+ assert.strictEqual(result.messages[0].ruleId, "no-undef");
+ assert.match(result.messages[0].message, /foo_js/u);
+ assert.strictEqual(result.messages[0].line, 2);
+ assert.strictEqual(result.messages[1].ruleId, "no-undef");
+ assert.match(result.messages[1].message, /foo_cjs/u);
+ assert.strictEqual(result.messages[1].line, 10);
+ assert.strictEqual(result.messages[2].ruleId, "no-undef");
+ assert.match(result.messages[2].message, /foo_mjs/u);
+ assert.strictEqual(result.messages[2].line, 14);
+ });
+ });
});
describe("Patterns which match no file should throw errors.", () => {
@@ -4363,82 +4624,182 @@ describe("FlatESLint", () => {
});
});
+ describe("Error while globbing", () => {
+
+ it("should throw an error with a glob pattern if an invalid config was provided", async () => {
+
+ const cwd = getFixturePath("files");
+
+ eslint = new FlatESLint({
+ cwd,
+ overrideConfig: [{ invalid: "foobar" }]
+ });
+
+ await assert.rejects(eslint.lintFiles("*.js"));
+ });
+ it("should throw an error with a glob pattern if an error occurs traversing a directory", async () => {
+
+ const fsWalk = require("@nodelib/fs.walk");
+ const error = new Error("Boom!");
+
+ sinon
+ .stub(fsWalk, "walk")
+ .value(sinon.stub().yieldsRight(error)); // call the callback passed to `fs.walk` with an error
+
+ const cwd = getFixturePath("files");
+
+ eslint = new FlatESLint({
+ cwd,
+ overrideConfigFile: true
+ });
+
+ await assert.rejects(eslint.lintFiles("*.js"), error);
+ });
+
+ });
});
describe("Fix Types", () => {
let eslint;
- it("should throw an error when an invalid fix type is specified", () => {
- assert.throws(() => {
+ describe("fixTypes values validation", () => {
+ it("should throw an error when an invalid fix type is specified", () => {
+ assert.throws(() => {
+ eslint = new FlatESLint({
+ cwd: path.join(fixtureDir, ".."),
+ overrideConfigFile: true,
+ fix: true,
+ fixTypes: ["layou"]
+ });
+ }, /'fixTypes' must be an array of any of "directive", "problem", "suggestion", and "layout"\./iu);
+ });
+ });
+
+ describe("with lintFiles", () => {
+ it("should not fix any rules when fixTypes is used without fix", async () => {
+ eslint = new FlatESLint({
+ cwd: path.join(fixtureDir, ".."),
+ overrideConfigFile: true,
+ fix: false,
+ fixTypes: ["layout"]
+ });
+ const inputPath = getFixturePath("fix-types/fix-only-semi.js");
+ const results = await eslint.lintFiles([inputPath]);
+
+ assert.strictEqual(results[0].output, void 0);
+ });
+
+ it("should not fix non-style rules when fixTypes has only 'layout'", async () => {
eslint = new FlatESLint({
cwd: path.join(fixtureDir, ".."),
overrideConfigFile: true,
fix: true,
- fixTypes: ["layou"]
+ fixTypes: ["layout"]
});
- }, /'fixTypes' must be an array of any of "directive", "problem", "suggestion", and "layout"\./iu);
- });
+ const inputPath = getFixturePath("fix-types/fix-only-semi.js");
+ const outputPath = getFixturePath("fix-types/fix-only-semi.expected.js");
+ const results = await eslint.lintFiles([inputPath]);
+ const expectedOutput = fs.readFileSync(outputPath, "utf8");
- it("should not fix any rules when fixTypes is used without fix", async () => {
- eslint = new FlatESLint({
- cwd: path.join(fixtureDir, ".."),
- overrideConfigFile: true,
- fix: false,
- fixTypes: ["layout"]
+ assert.strictEqual(results[0].output, expectedOutput);
});
- const inputPath = getFixturePath("fix-types/fix-only-semi.js");
- const results = await eslint.lintFiles([inputPath]);
- assert.strictEqual(results[0].output, void 0);
- });
+ it("should not fix style or problem rules when fixTypes has only 'suggestion'", async () => {
+ eslint = new FlatESLint({
+ cwd: path.join(fixtureDir, ".."),
+ overrideConfigFile: true,
+ fix: true,
+ fixTypes: ["suggestion"]
+ });
+ const inputPath = getFixturePath("fix-types/fix-only-prefer-arrow-callback.js");
+ const outputPath = getFixturePath("fix-types/fix-only-prefer-arrow-callback.expected.js");
+ const results = await eslint.lintFiles([inputPath]);
+ const expectedOutput = fs.readFileSync(outputPath, "utf8");
- it("should not fix non-style rules when fixTypes has only 'layout'", async () => {
- eslint = new FlatESLint({
- cwd: path.join(fixtureDir, ".."),
- overrideConfigFile: true,
- fix: true,
- fixTypes: ["layout"]
+ assert.strictEqual(results[0].output, expectedOutput);
});
- const inputPath = getFixturePath("fix-types/fix-only-semi.js");
- const outputPath = getFixturePath("fix-types/fix-only-semi.expected.js");
- const results = await eslint.lintFiles([inputPath]);
- const expectedOutput = fs.readFileSync(outputPath, "utf8");
- assert.strictEqual(results[0].output, expectedOutput);
+ it("should fix both style and problem rules when fixTypes has 'suggestion' and 'layout'", async () => {
+ eslint = new FlatESLint({
+ cwd: path.join(fixtureDir, ".."),
+ overrideConfigFile: true,
+ fix: true,
+ fixTypes: ["suggestion", "layout"]
+ });
+ const inputPath = getFixturePath("fix-types/fix-both-semi-and-prefer-arrow-callback.js");
+ const outputPath = getFixturePath("fix-types/fix-both-semi-and-prefer-arrow-callback.expected.js");
+ const results = await eslint.lintFiles([inputPath]);
+ const expectedOutput = fs.readFileSync(outputPath, "utf8");
+
+ assert.strictEqual(results[0].output, expectedOutput);
+ });
});
- it("should not fix style or problem rules when fixTypes has only 'suggestion'", async () => {
- eslint = new FlatESLint({
- cwd: path.join(fixtureDir, ".."),
- overrideConfigFile: true,
- fix: true,
- fixTypes: ["suggestion"]
+ describe("with lintText", () => {
+ it("should not fix any rules when fixTypes is used without fix", async () => {
+ eslint = new FlatESLint({
+ cwd: path.join(fixtureDir, ".."),
+ overrideConfigFile: true,
+ fix: false,
+ fixTypes: ["layout"]
+ });
+ const inputPath = getFixturePath("fix-types/fix-only-semi.js");
+ const content = fs.readFileSync(inputPath, "utf8");
+ const results = await eslint.lintText(content, { filePath: inputPath });
+
+ assert.strictEqual(results[0].output, void 0);
});
- const inputPath = getFixturePath("fix-types/fix-only-prefer-arrow-callback.js");
- const outputPath = getFixturePath("fix-types/fix-only-prefer-arrow-callback.expected.js");
- const results = await eslint.lintFiles([inputPath]);
- const expectedOutput = fs.readFileSync(outputPath, "utf8");
- assert.strictEqual(results[0].output, expectedOutput);
- });
+ it("should not fix non-style rules when fixTypes has only 'layout'", async () => {
+ eslint = new FlatESLint({
+ cwd: path.join(fixtureDir, ".."),
+ overrideConfigFile: true,
+ fix: true,
+ fixTypes: ["layout"]
+ });
+ const inputPath = getFixturePath("fix-types/fix-only-semi.js");
+ const outputPath = getFixturePath("fix-types/fix-only-semi.expected.js");
+ const content = fs.readFileSync(inputPath, "utf8");
+ const results = await eslint.lintText(content, { filePath: inputPath });
+ const expectedOutput = fs.readFileSync(outputPath, "utf8");
- it("should fix both style and problem rules when fixTypes has 'suggestion' and 'layout'", async () => {
- eslint = new FlatESLint({
- cwd: path.join(fixtureDir, ".."),
- overrideConfigFile: true,
- fix: true,
- fixTypes: ["suggestion", "layout"]
+ assert.strictEqual(results[0].output, expectedOutput);
});
- const inputPath = getFixturePath("fix-types/fix-both-semi-and-prefer-arrow-callback.js");
- const outputPath = getFixturePath("fix-types/fix-both-semi-and-prefer-arrow-callback.expected.js");
- const results = await eslint.lintFiles([inputPath]);
- const expectedOutput = fs.readFileSync(outputPath, "utf8");
- assert.strictEqual(results[0].output, expectedOutput);
- });
+ it("should not fix style or problem rules when fixTypes has only 'suggestion'", async () => {
+ eslint = new FlatESLint({
+ cwd: path.join(fixtureDir, ".."),
+ overrideConfigFile: true,
+ fix: true,
+ fixTypes: ["suggestion"]
+ });
+ const inputPath = getFixturePath("fix-types/fix-only-prefer-arrow-callback.js");
+ const outputPath = getFixturePath("fix-types/fix-only-prefer-arrow-callback.expected.js");
+ const content = fs.readFileSync(inputPath, "utf8");
+ const results = await eslint.lintText(content, { filePath: inputPath });
+ const expectedOutput = fs.readFileSync(outputPath, "utf8");
+ assert.strictEqual(results[0].output, expectedOutput);
+ });
+
+ it("should fix both style and problem rules when fixTypes has 'suggestion' and 'layout'", async () => {
+ eslint = new FlatESLint({
+ cwd: path.join(fixtureDir, ".."),
+ overrideConfigFile: true,
+ fix: true,
+ fixTypes: ["suggestion", "layout"]
+ });
+ const inputPath = getFixturePath("fix-types/fix-both-semi-and-prefer-arrow-callback.js");
+ const outputPath = getFixturePath("fix-types/fix-both-semi-and-prefer-arrow-callback.expected.js");
+ const content = fs.readFileSync(inputPath, "utf8");
+ const results = await eslint.lintText(content, { filePath: inputPath });
+ const expectedOutput = fs.readFileSync(outputPath, "utf8");
+
+ assert.strictEqual(results[0].output, expectedOutput);
+ });
+ });
});
describe("isPathIgnored", () => {
@@ -5513,6 +5874,30 @@ describe("FlatESLint", () => {
assert.strictEqual(warnResult.messages[0].ruleId, "no-unused-vars");
assert.strictEqual(warnResult.messages[0].severity, 1);
});
+
+ // https://github.com/eslint/eslint/issues/18261
+ it("should apply to all files except for 'error.js' even with `ignore: false` option", async () => {
+ const engine = new FlatESLint({
+ cwd,
+ ignore: false
+ });
+
+ const results = await engine.lintFiles("{error,warn}.js");
+
+ assert.strictEqual(results.length, 2);
+
+ const [errorResult, warnResult] = results;
+
+ assert.strictEqual(errorResult.filePath, path.join(getPath(), "error.js"));
+ assert.strictEqual(errorResult.messages.length, 1);
+ assert.strictEqual(errorResult.messages[0].ruleId, "no-unused-vars");
+ assert.strictEqual(errorResult.messages[0].severity, 2);
+
+ assert.strictEqual(warnResult.filePath, path.join(getPath(), "warn.js"));
+ assert.strictEqual(warnResult.messages.length, 1);
+ assert.strictEqual(warnResult.messages[0].ruleId, "no-unused-vars");
+ assert.strictEqual(warnResult.messages[0].severity, 1);
+ });
});
describe("config with ignores: ['**/*.json']", () => {
diff --git tests/lib/linter/linter.js tests/lib/linter/linter.js
index dec2aabb67d5..98cc63a74e71 100644
--- tests/lib/linter/linter.js
+++ tests/lib/linter/linter.js
@@ -12510,6 +12510,48 @@ describe("Linter with FlatConfigArray", () => {
describe("when eval,uating code containing /*global */ and /*globals */ blocks", () => {
+ /**
+ * Asserts the global variables in the provided code using the specified language options and data.
+ * @param {string} code The code to verify.
+ * @param {Object} languageOptions The language options to use.
+ * @param {Object} [data={}] Additional data for the assertion.
+ * @returns {void}
+ */
+ function assertGlobalVariable(code, languageOptions, data = {}) {
+ let spy;
+
+ const config = {
+ plugins: {
+ test: {
+ rules: {
+ checker: {
+ create(context) {
+ spy = sinon.spy(node => {
+ const scope = context.sourceCode.getScope(node);
+ const g = getVariable(scope, data.name);
+
+ assert.strictEqual(g.name, data.name);
+ assert.strictEqual(g.writeable, data.writeable);
+ });
+
+ return { Program: spy };
+ }
+ }
+ }
+ }
+ },
+ rules: { "test/checker": "error" }
+ };
+
+ if (languageOptions !== void 0) {
+ config.languageOptions = languageOptions;
+ }
+
+ linter.verify(code, config);
+ assert(spy && spy.calledOnce);
+
+ }
+
it("variables should be available in global scope", () => {
const code = `
/*global a b:true c:false d:readable e:writeable Math:off */
@@ -12570,6 +12612,15 @@ describe("Linter with FlatConfigArray", () => {
linter.verify(code, config);
assert(spy && spy.calledOnce);
});
+
+ // https://github.com/eslint/eslint/issues/18363
+ it("not throw when defining a global named __defineSetter__", () => {
+ assertGlobalVariable("/*global __defineSetter__ */", {}, { name: "__defineSetter__", writeable: false });
+ assertGlobalVariable("/*global __defineSetter__ */", void 0, { name: "__defineSetter__", writeable: false });
+ assertGlobalVariable("/*global __defineSetter__ */", { globals: { __defineSetter__: "off" } }, { name: "__defineSetter__", writeable: false });
+ assertGlobalVariable("/*global __defineSetter__ */", { globals: { __defineSetter__: "writeable" } }, { name: "__defineSetter__", writeable: false });
+ assertGlobalVariable("/*global __defineSetter__:writeable */", {}, { name: "__defineSetter__", writeable: true });
+ });
});
describe("when evaluating code containing a /*global */ block with sloppy whitespace", () => {
Here's my review of the pull request: DescriptionThis PR includes several changes and bug fixes for the ESLint project. The main changes include updating the CI workflow, modifying the release process, fixing issues with global variable handling, improving error messages for invalid configurations, and enhancing the behavior of file ignore patterns. Possible Issues
Security HotspotsNo significant security issues were identified in this PR. ChangesChanges
sequenceDiagram
participant CI as CI Workflow
participant Make as Makefile.js
participant ESLint as FlatESLint
participant Config as FlatConfigArray
participant Linter as Linter
CI->>Make: Trigger release process
Make->>ESLint: Generate release
ESLint->>Config: Normalize configurations
Config-->>ESLint: Return normalized config
ESLint->>Linter: Lint files
Linter-->>ESLint: Return lint results
ESLint-->>Make: Return release data
Make->>CI: Publish release
|
ffcfe12
to
76063f1
Compare
This PR contains the following updates:
8.57.0
->8.57.1
Release Notes
eslint/eslint (eslint)
v8.57.1
Compare Source
Configuration
📅 Schedule: Branch creation - "* 0-4 * * 3" (UTC), Automerge - At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.