From 5001ca28580612977631573e721533f38be3cf4b Mon Sep 17 00:00:00 2001 From: JounQin Date: Thu, 26 Jun 2025 13:55:08 +0800 Subject: [PATCH 1/4] fix: should not use `context.physicalFilename` as fallback instead of main source close #397 close #398 --- src/utils/resolve.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/resolve.ts b/src/utils/resolve.ts index ee10c7c5..e5d5ee39 100644 --- a/src/utils/resolve.ts +++ b/src/utils/resolve.ts @@ -306,7 +306,7 @@ function fullResolve( const sourceFiles = context.physicalFilename === sourceFile ? [sourceFile] - : [context.physicalFilename, sourceFile] + : [sourceFile, context.physicalFilename] for (const sourceFile of sourceFiles) { for (const { From f82cb466585e9fd72cf3ef0e4d53c1c0b52ca2f4 Mon Sep 17 00:00:00 2001 From: JounQin Date: Thu, 26 Jun 2025 13:56:31 +0800 Subject: [PATCH 2/4] Create itchy-poets-rush.md Signed-off-by: JounQin --- .changeset/itchy-poets-rush.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/itchy-poets-rush.md diff --git a/.changeset/itchy-poets-rush.md b/.changeset/itchy-poets-rush.md new file mode 100644 index 00000000..d41c8791 --- /dev/null +++ b/.changeset/itchy-poets-rush.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-import-x": patch +--- + +fix: should only use `context.physicalFilename` as fallback instead of main source From 44744b717b3891f67c72fca18b7ff79d06e42df3 Mon Sep 17 00:00:00 2001 From: JounQin Date: Thu, 26 Jun 2025 22:38:36 +0800 Subject: [PATCH 3/4] test: add a failing case --- src/utils/resolve.ts | 4 ++-- test/fixtures/config-helper.js | 0 test/utils/resolve.spec.ts | 16 ++++++++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/config-helper.js diff --git a/src/utils/resolve.ts b/src/utils/resolve.ts index e5d5ee39..4a6a64f1 100644 --- a/src/utils/resolve.ts +++ b/src/utils/resolve.ts @@ -306,7 +306,7 @@ function fullResolve( const sourceFiles = context.physicalFilename === sourceFile ? [sourceFile] - : [sourceFile, context.physicalFilename] + : [context.physicalFilename, sourceFile] for (const sourceFile of sourceFiles) { for (const { @@ -355,7 +355,7 @@ function fullResolve( } // else, counts - fileExistsCache.set(cacheKey, resolved.path as string | null) + fileExistsCache.set(cacheKey, resolved.path) return resolved } } diff --git a/test/fixtures/config-helper.js b/test/fixtures/config-helper.js new file mode 100644 index 00000000..e69de29b diff --git a/test/utils/resolve.spec.ts b/test/utils/resolve.spec.ts index ae0c08ed..a033b788 100644 --- a/test/utils/resolve.spec.ts +++ b/test/utils/resolve.spec.ts @@ -6,17 +6,19 @@ import { setTimeout } from 'node:timers/promises' import { jest } from '@jest/globals' import type { TSESLint } from '@typescript-eslint/utils' -import { testContext, testFilePath } from '../utils.js' +import { TEST_FILENAME, testContext, testFilePath } from '../utils.js' -import { importXResolverCompat } from 'eslint-plugin-import-x' +import { cjsRequire, importXResolverCompat } from 'eslint-plugin-import-x' import type { CjsRequire, NewResolver, NormalizedCacheSettings, + RuleContext, } from 'eslint-plugin-import-x' import { CASE_SENSITIVE_FS, fileExistsWithCaseSync, + relative, resolve, } from 'eslint-plugin-import-x/utils' @@ -830,5 +832,15 @@ describe('resolve', () => { }), ).toBe(testFilePath('./bar.tsx')) }) + + it('sourceFile should take higher priority than context.physicalFilename', () => { + const sourceFile = cjsRequire.resolve('typescript-eslint') + expect( + relative('./config-helper', sourceFile, {}, { + physicalFilename: TEST_FILENAME, + settings: {}, + } as RuleContext), + ).toBe(path.resolve(sourceFile, '../config-helper.js')) + }) }) }) From 5f684d2c6888d7ed274bb59f0cf90c70e0853922 Mon Sep 17 00:00:00 2001 From: JounQin Date: Thu, 26 Jun 2025 22:48:33 +0800 Subject: [PATCH 4/4] chore: then fix it --- src/utils/import-type.ts | 2 +- src/utils/resolve.ts | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/utils/import-type.ts b/src/utils/import-type.ts index 3698d9f1..256158e0 100644 --- a/src/utils/import-type.ts +++ b/src/utils/import-type.ts @@ -283,7 +283,7 @@ function isInternalPath( * @param name The name of the module to check * @returns `true` if the name is an external looking name, otherwise `false` */ -function isExternalLookingName(name: string) { +export function isExternalLookingName(name: string) { return isModule(name) || isScoped(name) } diff --git a/src/utils/resolve.ts b/src/utils/resolve.ts index 4a6a64f1..87edc078 100644 --- a/src/utils/resolve.ts +++ b/src/utils/resolve.ts @@ -19,6 +19,7 @@ import type { import { arraify } from './arraify.js' import { makeContextCacheKey } from './export-map.js' +import { isExternalLookingName } from './import-type.js' import { LEGACY_NODE_RESOLVERS, normalizeConfigResolvers, @@ -304,9 +305,11 @@ function fullResolve( } // backward compatibility const sourceFiles = - context.physicalFilename === sourceFile + context.physicalFilename === sourceFile || + // only try to fallback for external packages + !isExternalLookingName(modulePath) ? [sourceFile] - : [context.physicalFilename, sourceFile] + : [sourceFile, context.physicalFilename] for (const sourceFile of sourceFiles) { for (const {