Skip to content

Commit cf25a01

Browse files
authored
fix(extensions): don't require extension for package subpaths resolving to .d.ts (#498)
1 parent b543300 commit cf25a01

8 files changed

Lines changed: 52 additions & 5 deletions

File tree

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(extensions): don't require an extension for package subpaths that resolve to a `.d.ts` (e.g. `vitest/config`)

‎src/rules/extensions.ts‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -329,15 +329,12 @@ export default createRule<Options, MessageId>({
329329
}
330330

331331
const resolvedPath = resolve(importPath, context)
332+
const resolvedToDts = !!resolvedPath && dtsRe.test(resolvedPath)
332333

333334
// get extension from resolved path, or source value if unresolved.
334335
// for .d.ts/.d.mts/.d.cts, use the import path extension instead.
335336
const extension = path
336-
.extname(
337-
resolvedPath && dtsRe.test(resolvedPath)
338-
? importPath
339-
: resolvedPath || importPath,
340-
)
337+
.extname(resolvedToDts ? importPath : resolvedPath || importPath)
341338
.slice(1)
342339

343340
// determine if this is a module
@@ -349,6 +346,13 @@ export default createRule<Options, MessageId>({
349346
) || isScoped(importPath)
350347

351348
if (!extension || !importPath.endsWith(`.${extension}`)) {
349+
// A package subpath that resolves to a type declaration
350+
// (.d.ts/.d.mts/.d.cts) has no runtime extension to enforce — the
351+
// entry point is governed by the package's "exports" map
352+
// (e.g. `vitest/config`, `eslint/config`).
353+
if (resolvedToDts && !extension && isPackage) {
354+
return
355+
}
352356
// ignore type-only imports and exports
353357
if (
354358
!props.checkTypeImports &&

‎test/fixtures/node_modules/dts-subpath-package/config.d.ts‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/node_modules/dts-subpath-package/config.js‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/node_modules/dts-subpath-package/index.d.ts‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/node_modules/dts-subpath-package/index.js‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/node_modules/dts-subpath-package/package.json‎

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/rules/extensions.spec.ts‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,24 @@ describe('TypeScript', () => {
12821282
options: ['always'],
12831283
}),
12841284

1285+
// an extensionless package subpath that resolves to a `.d.ts` declaration
1286+
// (via the TypeScript resolver's types-first conditions) has no runtime
1287+
// extension to enforce (e.g. `vitest/config`) — #468 regression
1288+
tValid({
1289+
code: 'import { defineConfig } from "dts-subpath-package/config";',
1290+
options: ['always'],
1291+
settings: {
1292+
'import-x/resolver': { typescript: { alwaysTryTypes: true } },
1293+
},
1294+
}),
1295+
tValid({
1296+
code: 'import { defineConfig } from "dts-subpath-package/config";',
1297+
options: ['always', { ts: 'never' }],
1298+
settings: {
1299+
'import-x/resolver': { typescript: { alwaysTryTypes: true } },
1300+
},
1301+
}),
1302+
12851303
// pathGroupOverrides: no patterns match good bespoke specifiers
12861304
tValid({
12871305
code: `

0 commit comments

Comments
 (0)