Skip to content

Commit 7319bad

Browse files
fix(typescript-eslint): handle file:// urls in stack trace when inferring tsconfigRootDir (#11464)
1 parent 88b063e commit 7319bad

File tree

3 files changed

+34
-2
lines changed

3 files changed

+34
-2
lines changed

.cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"\\(#.+?\\)"
4747
],
4848
"words": [
49+
"AFAICT",
4950
"Airbnb",
5051
"Airbnb's",
5152
"allowdefaultproject",

packages/typescript-eslint/src/getTSConfigRootDirFromStack.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from 'node:path';
2+
import { fileURLToPath } from 'node:url';
23

34
/**
45
* Infers the `tsconfigRootDir` from the current call stack, using the V8 API.
@@ -26,11 +27,18 @@ export function getTSConfigRootDirFromStack(): string | undefined {
2627
}
2728

2829
for (const callSite of getStack()) {
29-
const stackFrameFilePath = callSite.getFileName();
30-
if (!stackFrameFilePath) {
30+
const stackFrameFilePathOrUrl = callSite.getFileName();
31+
if (!stackFrameFilePathOrUrl) {
3132
continue;
3233
}
3334

35+
// ESM seem to return a file URL, so we'll convert it to a file path.
36+
// AFAICT this isn't documented in the v8 API docs, but it seems to be the case.
37+
// See https://github.com/typescript-eslint/typescript-eslint/issues/11429
38+
const stackFrameFilePath = stackFrameFilePathOrUrl.startsWith('file://')
39+
? fileURLToPath(stackFrameFilePathOrUrl)
40+
: stackFrameFilePathOrUrl;
41+
3442
const parsedPath = path.parse(stackFrameFilePath);
3543
if (/^eslint\.config\.(c|m)?(j|t)s$/.test(parsedPath.base)) {
3644
return parsedPath.dir;

packages/typescript-eslint/tests/getTsconfigRootDirFromStack.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,34 @@ import * as normalFolder from './path-test-fixtures/tsconfigRootDirInference-nor
33
import * as notEslintConfig from './path-test-fixtures/tsconfigRootDirInference-not-eslint-config/not-an-eslint.config.cjs';
44
import * as folderThatHasASpace from './path-test-fixtures/tsconfigRootDirInference-space/folder that has a space/eslint.config.cjs';
55

6+
const isWindows = process.platform === 'win32';
7+
68
describe(getTSConfigRootDirFromStack, () => {
79
it('does stack analysis right for normal folder', () => {
810
expect(normalFolder.get()).toBe(normalFolder.dirname());
911
});
1012

13+
it('does stack analysis right for a file that gives a file:// URL as its name', () => {
14+
vi.spyOn(Error, 'captureStackTrace').mockImplementationOnce(
15+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
16+
(target: any, _constructorOpt) => {
17+
target.stack = [
18+
{
19+
getFileName() {
20+
return !isWindows
21+
? 'file:///a/b/eslint.config.mts'
22+
: 'file:///F:/a/b/eslint.config.mts';
23+
},
24+
},
25+
];
26+
},
27+
);
28+
29+
const inferredTsconfigRootDir = getTSConfigRootDirFromStack();
30+
31+
expect(inferredTsconfigRootDir).toBe(!isWindows ? '/a/b' : 'F:\\a\\b');
32+
});
33+
1134
it('does stack analysis right for folder that has a space', () => {
1235
expect(folderThatHasASpace.get()).toBe(folderThatHasASpace.dirname());
1336
});

0 commit comments

Comments
 (0)