Skip to content
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

fix: throw error for first unmatched pattern #16533

Merged
merged 2 commits into from Nov 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 23 additions & 29 deletions lib/eslint/eslint-helpers.js
Expand Up @@ -76,7 +76,7 @@ class UnmatchedSearchPatternsError extends Error {
constructor({ basePath, unmatchedPatterns, patterns, rawPatterns }) {
super(`No files matching '${rawPatterns}' in '${basePath}' were found.`);
this.basePath = basePath;
this.patternsToCheck = unmatchedPatterns;
this.unmatchedPatterns = unmatchedPatterns;
this.patterns = patterns;
this.rawPatterns = rawPatterns;
}
Expand Down Expand Up @@ -337,49 +337,43 @@ async function globSearch({
}

/**
* Checks to see if there are any ignored results for a given search. This
* happens either when there are unmatched patterns during a search or if
* a search returns no results.
* Throws an error for unmatched patterns. The error will only contain information about the first one.
* Checks to see if there are any ignored results for a given search.
* @param {Object} options The options for this function.
* @param {string} options.basePath The directory to search.
* @param {Array<string>} options.patterns An array of glob patterns
* that were used in the original search.
* @param {Array<string>} options.rawPatterns An array of glob patterns
* as the user inputted them. Used for errors.
* @param {Array<string>} options.patternsToCheck An array of glob patterns
* to use for this check.
* @returns {void}
* @throws {NoFilesFoundError} If there is a pattern that doesn't match
* any files and `errorOnUnmatchedPattern` is true.
* @throws {AllFilesIgnoredError} If there is a pattern that matches files
* when there are no ignores.
* @param {Array<string>} options.unmatchedPatterns A non-empty array of glob patterns
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we only need the first item, why pass the whole array?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about passing in just the first item, but in the end I decided that it might make more sense to just pass all the data from the search and let throwErrorForUnmatchedPatterns construct the error from that, so that all the logic about what needs to be checked further and what information will the error contain is in throwErrorForUnmatchedPatterns.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough.

* that were unmatched in the original search.
* @returns {void} Always throws an error.
* @throws {NoFilesFoundError} If the first unmatched pattern
* doesn't match any files even when there are no ignores.
* @throws {AllFilesIgnoredError} If the first unmatched pattern
* matches some files when there are no ignores.
*/
async function checkForIgnoredResults({
async function throwErrorForUnmatchedPatterns({
basePath,
patterns,
rawPatterns,
patternsToCheck = patterns
unmatchedPatterns
}) {

for (const pattern of patternsToCheck) {
const pattern = unmatchedPatterns[0];
const rawPattern = rawPatterns[patterns.indexOf(pattern)];

const patternHasMatch = await globMatch({
basePath,
pattern
});
const patternHasMatch = await globMatch({
basePath,
pattern
});

if (patternHasMatch) {
throw new AllFilesIgnoredError(
rawPatterns[patterns.indexOf(pattern)]
);
}
if (patternHasMatch) {
throw new AllFilesIgnoredError(rawPattern);
}

// if we get here there are truly no matches
throw new NoFilesFoundError(
rawPatterns[patterns.indexOf(patternsToCheck[0])],
true
);
throw new NoFilesFoundError(rawPattern, true);
}

/**
Expand Down Expand Up @@ -446,9 +440,9 @@ async function globMultiSearch({ searches, configs, errorOnUnmatchedPattern }) {

if (errorOnUnmatchedPattern) {

await checkForIgnoredResults({
await throwErrorForUnmatchedPatterns({
...currentSearch,
patternsToCheck: error.patternsToCheck
unmatchedPatterns: error.unmatchedPatterns
});

}
Expand Down
25 changes: 25 additions & 0 deletions tests/lib/eslint/flat-eslint.js
Expand Up @@ -848,6 +848,31 @@ describe("FlatESLint", () => {
}, /All files matched by 'subdir2\/\*\.js' are ignored/u);
});

it("should always throw an error for the first unmatched file pattern", async () => {
eslint = new FlatESLint({
cwd: getFixturePath("example-app2"),
overrideConfig: {
ignores: ["subdir1/*.js", "subdir2/*.js"]
}
});

await assert.rejects(async () => {
await eslint.lintFiles(["doesnotexist1/*.js", "doesnotexist2/*.js"]);
}, /No files matching 'doesnotexist1\/\*\.js' were found/u);

await assert.rejects(async () => {
await eslint.lintFiles(["doesnotexist1/*.js", "subdir1/*.js"]);
}, /No files matching 'doesnotexist1\/\*\.js' were found/u);

await assert.rejects(async () => {
await eslint.lintFiles(["subdir1/*.js", "doesnotexist1/*.js"]);
}, /All files matched by 'subdir1\/\*\.js' are ignored/u);

await assert.rejects(async () => {
await eslint.lintFiles(["subdir1/*.js", "subdir2/*.js"]);
}, /All files matched by 'subdir1\/\*\.js' are ignored/u);
});

it("should not throw an error for an ignored file pattern when errorOnUnmatchedPattern is false", async () => {
eslint = new FlatESLint({
cwd: getFixturePath("example-app2"),
Expand Down