8000 fix: ignore files on a different drive on Windows (#19069) · eslint/eslint@68fa497 · GitHub
[go: up one dir, main page]

Skip to content

Commit 68fa497

Browse files
authored
fix: ignore files on a different drive on Windows (#19069)
* fix: update for eslint/rewrite#59 * revert unnecessary changes with `basePath` defaulting to `"/"` * update to `config-array` v0.19.x * add tests for `Linter` and `RuleTester` * add tests for `lintFile` on a different drive * remove unused fallback logic for relative paths * add a test for `isPathIgnored` on a different drive * add more tests for `lintFiles` * add a test for `lintText` * remove unused param from `Linter#verify` calls * added comments to `lintFiles` test hooks
1 parent 4f08332 commit 68fa497

File tree

8 files changed

+387
-89
lines changed

8 files changed

+387
-89
lines changed

lib/eslint/eslint-helpers.js

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,14 @@ function isGlobPattern(pattern) {
155155
* Used primarily to help with useful error messages.
156156
* @param {Object} options The options for the function.
157157
* @param {string} options.basePath The directory to search.
158-
* @param {string} options.pattern A glob pattern to match.
158+
* @param {string} options.pattern An absolute path glob pattern to match.
159159
* @returns {Promise<boolean>} True if there is a glob match, false if not.
160160
*/
161161
async function globMatch({ basePath, pattern }) {
162162

163163
let found = false;
164164
const { hfs } = await import("@humanfs/node");
165-
const patternToUse = path.isAbsolute(pattern)
166-
? normalizeToPosix(path.relative(basePath, pattern))
167-
: pattern;
165+
const patternToUse = normalizeToPosix(path.relative(basePath, pattern));
168166

169167
const matcher = new Minimatch(patternToUse, MINIMATCH_OPTIONS);
170168

@@ -202,7 +200,7 @@ async function globMatch({ basePath, pattern }) {
202200
* ESLint.
203201
* @param {Object} options The options for this function.
204202
* @param {string} options.basePath The directory to search.
205-
* @param {Array<string>} options.patterns An array of glob patterns
203+
* @param {Array<string>} options.patterns An array of absolute path glob patterns
206204
* to match.
207205
* @param {Array<string>} options.rawPatterns An array of glob patterns
208206
* as the user inputted them. Used for errors.
@@ -241,9 +239,7 @@ async function globSearch({
241239
*/
242240
const relativeToPatterns = new Map();
243241
const matchers = patterns.map((pattern, i) => {
244-
const patternToUse = path.isAbsolute(pattern)
245-
? normalizeToPosix(path.relative(basePath, pattern))
246-
: pattern;
242+
const patternToUse = normalizeToPosix(path.relative(basePath, pattern));
247243

248244
relativeToPatterns.set(patternToUse, patterns[i]);
249245

@@ -353,7 +349,7 @@ async function globSearch({
353349
* that were used in the original search.
354350
* @param {Array<string>} options.rawPatterns An array of glob patterns
355351
* as the user inputted them. Used for errors.
356-
* @param {Array<string>} options.unmatchedPatterns A non-empty array of glob patterns
352+
* @param {Array<string>} options.unmatchedPatterns A non-empty array of absolute path glob patterns
357353
* that were unmatched in the original search.
358354
* @returns {void} Always throws an error.
359355
* @throws {NoFilesFoundError} If the first unmatched pattern
@@ -388,7 +384,7 @@ async function throwErrorForUnmatchedPatterns({
388384
* Performs multiple glob searches in parallel.
389385
* @param {Object} options The options for this function.
390386
* @param {Map<string,GlobSearch>} options.searches
391-
* An array of glob patterns to match.
387+
* A map of absolute path glob patterns to match.
392388
* @param {ConfigLoader|LegacyConfigLoader} options.configLoader The config loader to use for
393389
* determining what to ignore.
394390
* @param {boolean} options.errorOnUnmatchedPattern Determines if an
@@ -597,7 +593,7 @@ async function findFiles({
597593
return [
598594
...new Set([
599595
...results,
600-
...globbyResults.map(filePath => path.resolve(filePath))
596+
...globbyResults
601597
])
602598
];
603599
}
@@ -618,7 +614,7 @@ function isErrorMessage(message) {
618614

619615
/**
620616
* Returns result with warning by ignore settings
621-
* @param {string} filePath File path of checked code
617+
* @param {string} filePath Absolute file path of checked code
622618
* @param {string} baseDir Absolute path of base directory
623619
* @param {"ignored"|"external"|"unconfigured"} configStatus A status that determines why the file is ignored
624620
* @returns {LintResult} Result with single warning
@@ -648,7 +644,7 @@ function createIgnoreResult(filePath, baseDir, configStatus) {
648644
}
649645

650646
return {
651-
filePath: path.resolve(filePath),
647+
filePath,
652648
messages: [
653649
{
654650
ruleId: null,

lib/rule-tester/rule-tester.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ class RuleTester {
653653
};
654654

655655
if (item.filename) {
656-
flatConfigArrayOptions.basePath = path.parse(item.filename).root;
656+
flatConfigArrayOptions.basePath = path.parse(item.filename).root || void 0;
657657
}
658658

659659
const configs = new FlatConfigArray(testerConfig, flatConfigArrayOptions);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
"dependencies": {
100100
"@eslint-community/eslint-utils": "^4.2.0",
101101
"@eslint-community/regexpp": "^4.12.1",
102-
"@eslint/config-array": "^0.18.0",
102+
"@eslint/config-array": "^0.19.0",
103103
"@eslint/core": "^0.7.0",
104104
"@eslint/eslintrc": "^3.1.0",
105105
"@eslint/js": "9.14.0",

tests/lib/eslint/eslint.js

Lines changed: 168 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ describe("ESLint", () => {
201201
});
202202

203203
// https://github.com/eslint/eslint/issues/2380
204-
it("should not modify baseConfig when format is specified", () => {
204+
it("should not modify baseConfig in the constructor", () => {
205205
const customBaseConfig = { root: true };
206206

207207
new ESLint({ baseConfig: customBaseConfig, flags }); // eslint-disable-line no-new -- Check for argument side effects
@@ -390,7 +390,7 @@ describe("ESLint", () => {
390390
assert.strictEqual(results[0].suppressedMessages.length, 0);
391391
});
392392

393-
it("should report the total and per file warnings when using local cwd .eslintrc", async () => {
393+
it("should report the total and per file warnings when not using a config file", async () => {
394394
eslint = new ESLint({
395395
flags,
396396
overrideConfig: {
@@ -524,6 +524,36 @@ describe("ESLint", () => {
524524
assert.strictEqual(results[0].suppressedMessages.length, 0);
525525
});
526526

527+
if (os.platform() === "win32") {
528+
it("should return a warning when given a filename on a different drive by --stdin-filename if warnIgnored is true on Windows", async () => {
529+
const currentRoot = path.resolve("\\");
530+
const otherRoot = currentRoot === "A:\\" ? "B:\\" : "A:\\";
531+
532+
eslint = new ESLint({
533+
flags,
534+
cwd: getFixturePath(),
535+
overrideConfigFile: true
536+
});
537+
538+
const filePath = `${otherRoot}file.js`;
539+
const options = { filePath, warnIgnored: true };
540+
const results = await eslint.lintText("var bar = foo;", options);
541+
542+
assert.strictEqual(results.length, 1);
543+
assert.strictEqual(results[0].filePath, filePath);
544+
assert.strictEqual(results[0].messages[0].severity, 1);
545+
assert.strictEqual(results[0].messages[0].message, "File ignored because outside of base path.");
546+
assert.strictEqual(results[0].messages[0].output, void 0);
547+
assert.strictEqual(results[0].errorCount, 0);
548+
assert.strictEqual(results[0].warningCount, 1);
549+
assert.strictEqual(results[0].fatalErrorCount, 0);
550+
assert.strictEqual(results[0].fixableErrorCount, 0);
551+
assert.strictEqual(results[0].fixableWarningCount, 0);
552+
assert.strictEqual(results[0].usedDeprecatedRules.length, 0);
553+
assert.strictEqual(results[0].suppressedMessages.length, 0);
554+
});
555+
}
556+
527557
it("should return a warning when given a filename by --stdin-filename in excluded files list if constructor warnIgnored is false, but lintText warnIgnored is true", async () => {
528558
eslint = new ESLint({
529559
flags,
@@ -2937,6 +2967,126 @@ describe("ESLint", () => {
29372967
assert.strictEqual(results[0].messages[0].message, "Program is disallowed.");
29382968
});
29392969

2970+
// https://github.com/eslint/eslint/issues/18575
2971+
describe("on Windows", () => {
2972+
if (os.platform() !== "win32") {
2973+
return;
2974+
}
2975+
2976+
let otherDriveLetter;
2977+
const exec = util.promisify(require("node:child_process").exec);
2978+
2979+
/*
2980+
* Map the fixture directory to a new virtual drive.
2981+
* Use the first drive letter available.
2982+
*/
2983+
before(async () => {
2984+
const substDir = getFixturePath();
2985+
2986+
for (const driveLetter of "ABCDEFGHIJKLMNOPQRSTUVWXYZ") {
2987+
try {
2988+
2989+
// More info on this command at https://en.wikipedia.org/wiki/SUBST
2990+
await exec(`subst ${driveLetter}: "${substDir}"`);
2991+
} catch {
2992+
continue;
2993+
}
2994+
otherDriveLetter = driveLetter;
2995+
break;
2996+
}
2997+
if (!otherDriveLetter) {
2998+
throw Error("Unable to assign a virtual drive letter.");
2999+
}
3000+
});
3001+
3002+
/*
3003+
* Delete the virtual drive.
3004+
*/
3005+
after(async () => {
3006+
if (otherDriveLetter) {
3007+
try {
3008+
await exec(`subst /D ${otherDriveLetter}:`);
3009+
} catch ({ message }) {
3010+
throw new Error(`Unable to unassign virtual drive letter ${otherDriveLetter}: - ${message}`);
3011+
}
3012+
}
3013+
});
3014+
3015+
it("should return a warning when an explicitly given file is on a different drive", async () => {
3016+
eslint = new ESLint({
3017+
flags,
3018+
overrideConfigFile: true,
3019+
cwd: getFixturePath()
3020+
});
3021+
const filePath = `${otherDriveLetter}:\\passing.js`;
3022+
const results = await eslint.lintFiles([filePath]);
3023+
3024+
assert.strictEqual(results.length, 1);
3025+
assert.strictEqual(results[0].filePath, filePath);
3026+
assert.strictEqual(results[0].messages[0].severity, 1);
3027+
assert.strictEqual(results[0].messages[0].message, "File ignored because outside of base path.");
3028+
assert.strictEqual(results[0].errorCount, 0);
3029+
assert.strictEqual(results[0].warningCount, 1);
3030+
assert.strictEqual(results[0].fatalErrorCount, 0);
3031+
assert.strictEqual(results[0].fixableErrorCount, 0);
3032+
assert.strictEqual(results[0].fixableWarningCount, 0);
3033+
assert.strictEqual(results[0].suppressedMessages.length, 0);
3034+
});
3035+
3036+
it("should not ignore an explicitly given file that is on the same drive as cwd", async () => {
3037+
eslint = new ESLint({
3038+
flags,
3039+
overrideConfigFile: true,
3040+
cwd: `${otherDriveLetter}:\\`
3041+
});
3042+
const filePath = `${otherDriveLetter}:\\passing.js`;
3043+
const results = await eslint.lintFiles([filePath]);
3044+
3045+
assert.strictEqual(results.length, 1);
3046+
assert.strictEqual(results[0].filePath, filePath);
3047+
assert.strictEqual(results[0].messages.length, 0);
3048+
assert.strictEqual(results[0].errorCount, 0);
3049+
assert.strictEqual(results[0].warningCount, 0);
3050+
assert.strictEqual(results[0].fatalErrorCount, 0);
3051+
assert.strictEqual(results[0].fixableErrorCount, 0);
3052+
assert.strictEqual(results[0].fixableWarningCount, 0);
3053+
assert.strictEqual(results[0].suppressedMessages.length, 0);
3054+
});
3055+
3056+
it("should not ignore a file on the same drive as cwd that matches a glob pattern", async () => {
3057+
eslint = new ESLint({
3058+
flags,
3059+
overrideConfigFile: true,
3060+
cwd: `${otherDriveLetter}:\\`
3061+
});
3062+
const pattern = `${otherDriveLetter}:\\pa*ng.*`;
3063+
const results = await eslint.lintFiles([pattern]);
3064+
3065+
assert.strictEqual(results.length, 1);
3066+
assert.strictEqual(results[0].filePath, `${otherDriveLetter}:\\passing.js`);
3067+
assert.strictEqual(results[0].messages.length, 0);
3068+
assert.strictEqual(results[0].errorCount, 0);
3069+
assert.strictEqual(results[0].warningCount, 0);
3070+
assert.strictEqual(results[0].fatalErrorCount, 0);
3071+
assert.strictEqual(results[0].fixableErrorCount, 0);
3072+
assert.strictEqual(results[0].fixableWarningCount, 0);
3073+
assert.strictEqual(results[0].suppressedMessages.length, 0);
3074+
});
3075+
3076+
it("should throw an error when a glob pattern matches only files on different drive", async () => {
3077+
eslint = new ESLint({
3078+
flags,
3079+
overrideConfigFile: true,
3080+
cwd: getFixturePath()
3081+
});
3082+
const pattern = `${otherDriveLetter}:\\pa**ng.*`;
3083+
3084+
await assert.rejects(
3085+
eslint.lintFiles([pattern]),
3086+
`All files matched by '${otherDriveLetter}:\\pa**ng.*' are ignored.`
3087+
);
3088+
});
3089+
});
29403090
});
29413091

29423092

@@ -6110,6 +6260,22 @@ describe("ESLint", () => {
61106260
assert(await engine.isPathIgnored("node_modules/foo.js"));
61116261
});
61126262

6263+
if (os.platform() === "win32") {
6264+
it("should return true for a file on a different drive on Windows", async () => {
6265+
const currentRoot = path.resolve("\\");
6266+
const otherRoot = currentRoot === "A:\\" ? "B:\\" : "A:\\";
6267+
const engine = new ESLint({
6268+
flags,
6269+
overrideConfigFile: true,
6270+
cwd: currentRoot
6271+
});
6272+
6273+
assert(!await engine.isPathIgnored(`${currentRoot}file.js`));
6274+
assert(await engine.isPathIgnored(`${otherRoot}file.js`));
6275+
assert(await engine.isPathIgnored("//SERVER//share//file.js"));
6276+
});
6277+
}
6278+
61136279
describe("about the default ignore patterns", () => {
61146280
it("should always apply default ignore patterns if ignore option is true", async () => {
61156281
const cwd = getFixturePath("ignored-paths");

tests/lib/languages/js/source-code/source-code.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2489,7 +2489,7 @@ describe("SourceCode", () => {
24892489
rules: { "test/checker": "error" }
24902490
};
24912491

2492-
flatLinter.verify(code, config, filename, true);
2492+
flatLinter.verify(code, config, filename);
24932493
assert(spy && spy.calledOnce, "Spy was not called.");
24942494
});
24952495

@@ -2925,7 +2925,7 @@ describe("SourceCode", () => {
29252925
}
29262926
});
29272927

2928-
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } }, filename, true);
2928+
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } }, filename);
29292929
assert(spy && spy.calledOnce);
29302930
});
29312931

0 commit comments

Comments
 (0)
0