Skip to content

Commit 52c1808

Browse files
authored
fix: key ESLint caches on the effective cwd (#1221)
1 parent dbe3669 commit 52c1808

4 files changed

Lines changed: 74 additions & 4 deletions

File tree

.changeset/eslint-cache-cwd.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"prettier-eslint": patch
3+
---
4+
5+
Include the effective `cwd` in the ESLint instance and config cache keys, so a `process.cwd()` change no longer returns an entry resolved for a different directory.

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ function getESLintApiOptions(eslintConfig: ESLintConfig): ESLintConfig {
345345
return {
346346
ignore: eslintConfig.ignore ?? true,
347347
allowInlineConfig: eslintConfig.allowInlineConfig ?? true,
348-
cwd: eslintConfig.cwd,
348+
cwd: eslintConfig.cwd ?? process.cwd(),
349349
baseConfig: eslintConfig.baseConfig,
350350
overrideConfig: eslintConfig.overrideConfig,
351351
overrideConfigFile: eslintConfig.overrideConfigFile,
@@ -358,8 +358,8 @@ async function getESLintConfig(
358358
eslintPath: string,
359359
eslintConfig: ESLintConfig,
360360
): Promise<ESLintConfig> {
361-
const configPath = filePath || process.cwd();
362361
const configOptions = getESLintApiOptions(eslintConfig);
362+
const configPath = filePath || configOptions.cwd;
363363
const cacheKey = hash({ filePath, eslintPath, configOptions });
364364
const cachedConfig = eslintConfigCache.get(cacheKey);
365365

src/utils.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,11 @@ export async function getESLint(
679679
eslintPath: string,
680680
eslintOptions: ESLintOptions,
681681
) {
682-
const cacheKey = hash({ eslintPath, eslintOptions });
682+
const options = {
683+
...eslintOptions,
684+
cwd: eslintOptions.cwd ?? process.cwd(),
685+
};
686+
const cacheKey = hash({ eslintPath, eslintOptions: options });
683687
const cachedESLint = eslintCache.get(cacheKey);
684688

685689
if (cachedESLint) {
@@ -691,7 +695,7 @@ export async function getESLint(
691695
'eslint',
692696
);
693697
try {
694-
const eslint = new ESLint(eslintOptions);
698+
const eslint = new ESLint(options);
695699
eslintCache.set(cacheKey, eslint);
696700
return eslint;
697701
} catch (error) {

test/index.spec.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,67 @@ test('caches eslint configs with equivalent options', async () => {
550550
expect(eslintMock.mock.calculateConfigForFile).toHaveBeenCalledTimes(1);
551551
});
552552

553+
test('does not reuse cached eslint instances across effective cwds', async () => {
554+
const eslintPath = path.join(__dirname, '../__mocks__/eslint.ts');
555+
const cwdSpy = vi.spyOn(process, 'cwd');
556+
557+
cwdSpy.mockReturnValue(path.join(__dirname, 'fixtures'));
558+
const eslint = await getESLint(eslintPath, { fix: true });
559+
560+
cwdSpy.mockReturnValue(path.join(__dirname, 'fixtures/paths'));
561+
const otherESLint = await getESLint(eslintPath, { fix: true });
562+
563+
cwdSpy.mockRestore();
564+
565+
expect(otherESLint).not.toBe(eslint);
566+
expect(eslintMock.ESLint).toHaveBeenCalledTimes(2);
567+
});
568+
569+
test('does not reuse cached eslint configs across effective cwds', async () => {
570+
const fixturePath = path.join(
571+
__dirname,
572+
'fixtures/effective-cwd-default-config.js',
573+
);
574+
const cwdSpy = vi.spyOn(process, 'cwd');
575+
576+
cwdSpy.mockReturnValue(path.resolve(__dirname, '..'));
577+
await format({ text: defaultInputText(), filePath: fixturePath });
578+
579+
cwdSpy.mockReturnValue(__dirname);
580+
await format({ text: defaultInputText(), filePath: fixturePath });
581+
582+
cwdSpy.mockRestore();
583+
584+
expect(eslintMock.mock.calculateConfigForFile).toHaveBeenCalledTimes(2);
585+
});
586+
587+
test('reuses cached eslint configs when an explicit cwd is given', async () => {
588+
const fixturePath = path.join(
589+
__dirname,
590+
'fixtures/explicit-cwd-default-config.js',
591+
);
592+
const eslintConfig = { cwd: path.resolve(__dirname, '..') };
593+
const cwdSpy = vi.spyOn(process, 'cwd');
594+
595+
cwdSpy.mockReturnValue(path.join(__dirname, 'fixtures'));
596+
await format({
597+
text: defaultInputText(),
598+
filePath: fixturePath,
599+
eslintConfig,
600+
});
601+
602+
cwdSpy.mockReturnValue(path.join(__dirname, 'fixtures/paths'));
603+
await format({
604+
text: defaultInputText(),
605+
filePath: fixturePath,
606+
eslintConfig: { ...eslintConfig },
607+
});
608+
609+
cwdSpy.mockRestore();
610+
611+
expect(eslintMock.mock.calculateConfigForFile).toHaveBeenCalledTimes(1);
612+
});
613+
553614
test('uses caller eslint config on config cache hit', async () => {
554615
const fixturePath = path.resolve(
555616
'./mock/cache-override-test-default-config.js',

0 commit comments

Comments
 (0)