Skip to content

Commit e3cc7e4

Browse files
mrginglymusJounQin
andauthored
fix: strip querystrings and hash fragments when checking for file existence (#479)
Co-authored-by: JounQin <admin@1stg.me> Signed-off-by: JounQin <admin@1stg.me>
1 parent 9a07009 commit e3cc7e4

4 files changed

Lines changed: 46 additions & 6 deletions

File tree

.changeset/khaki-lemons-divide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-import-x": patch
3+
---
4+
5+
fix: strip querystrings and hash fragments when checking for file existence

src/utils/resolve.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,11 @@ export function fileExistsWithCaseSync(
7171
if (filepath === null) {
7272
return true
7373
}
74+
7475
if (filepath.toLowerCase() === process.cwd().toLowerCase() && !strict) {
7576
return true
7677
}
78+
7779
const parsedPath = path.parse(filepath)
7880
const dir = parsedPath.dir
7981

@@ -88,15 +90,36 @@ export function fileExistsWithCaseSync(
8890
} else {
8991
try {
9092
const filenames = fs.readdirSync(dir)
91-
result = filenames.includes(parsedPath.base)
92-
? fileExistsWithCaseSync(dir, cacheSettings, strict, false)
93-
: !leaf &&
93+
if (filenames.includes(parsedPath.base)) {
94+
result = fileExistsWithCaseSync(dir, cacheSettings, strict, false)
95+
} else {
96+
const baseLowerCase = parsedPath.base.toLowerCase()
97+
const hasCaseInsensitiveMatch = filenames.some(
98+
p => p.toLowerCase() === baseLowerCase,
99+
)
100+
101+
const isMissing = !hasCaseInsensitiveMatch
102+
103+
if (isMissing && leaf) {
104+
const queryIndex = filepath.lastIndexOf('?')
105+
const hashIndex = filepath.lastIndexOf('#')
106+
const index = Math.max(queryIndex, hashIndex)
107+
108+
result =
109+
index > 0
110+
? fileExistsWithCaseSync(
111+
filepath.slice(0, index),
112+
cacheSettings,
113+
strict,
114+
)
115+
: false
116+
} else {
94117
// We tolerate case-insensitive matches if there are no case-insensitive matches.
95118
// It'll fail anyway on the leaf node if the file truly doesn't exist (if it doesn't
96119
// fail it's that we're probably working with a virtual in-memory filesystem).
97-
!filenames.some(
98-
p => p.toLowerCase() === parsedPath.base.toLowerCase(),
99-
)
120+
result = isMissing && !leaf
121+
}
122+
}
100123
} catch (error) {
101124
if (isDirectoryAccessError(error)) {
102125
result = true

test/rules/no-unresolved.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ function runResolverTests(resolver: 'node' | 'webpack') {
4848
}),
4949

5050
tValid({ code: 'import foo from "./bar";' }),
51+
tValid({ code: 'import foo from "./bar?qs";' }),
52+
...(resolver === 'node'
53+
? [tValid({ code: 'import foo from "./bar#hash";' })]
54+
: []),
55+
tValid({ code: 'import foo from "./bar?qs#hash";' }),
5156
tValid({ code: "import bar from './bar.js';" }),
5257
tValid({ code: "import {someThing} from './test-module';" }),
5358
tValid({ code: "import fs from 'fs';" }),

test/utils/resolve.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,13 @@ describe('resolve', () => {
477477
expect(fileExistsWithCaseSync(file, cacheSettings)).toBe(false)
478478
})
479479

480+
it.each(['?qs', '#hash', '?qs#hash'])(
481+
'falls back from %s when detecting case mismatch',
482+
suffix => {
483+
expect(fileExistsWithCaseSync(file + suffix, cacheSettings)).toBe(false)
484+
},
485+
)
486+
480487
it('detecting case does not include parent folder path (issue #720)', () => {
481488
const f = path.resolve(
482489
process.cwd().toUpperCase(),

0 commit comments

Comments
 (0)