Skip to content

Commit 9a07009

Browse files
authored
fix: make extensions rule check Node.js subpath imports (#484)
1 parent 3e13121 commit 9a07009

5 files changed

Lines changed: 74 additions & 2 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"eslint-plugin-import-x": patch
3+
---
4+
5+
Make the `extensions` rule check Node.js subpath imports (specifiers starting with `#`, e.g. `#utils/helper`). Previously `parsePath` treated a leading `#` as a URL hash fragment, so the rule skipped extension validation for these imports.
6+
7+
Note: single-segment subpath imports without a slash (e.g. `#dep`) are still skipped by the existing external-root-module classification; fixing that is deferred to avoid expanding scope.

‎src/utils/parse-path.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ export interface ParsedPath {
77
export const parsePath = (path: string): ParsedPath => {
88
const hashIndex = path.indexOf('#')
99
const queryIndex = path.indexOf('?')
10-
const hasHash = hashIndex !== -1
10+
// A `#` at index 0 is the sigil for a Node.js subpath import (e.g.
11+
// `#utils/helper`), not a URL hash fragment, so it must stay in `pathname`.
12+
const hasHash = hashIndex > 0
1113
const hash = hasHash ? path.slice(hashIndex) : ''
1214
const hasQuery = queryIndex !== -1 && (!hasHash || queryIndex < hashIndex)
1315
const query = hasQuery

‎test/rules/extensions.spec.ts‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,19 @@ ruleTester.run('extensions', rule, {
7676
tValid({ code: 'import thing from "./fake-file.js"', options: ['always'] }),
7777
tValid({ code: 'import thing from "non-package"', options: ['never'] }),
7878

79+
// Node.js subpath imports (#437)
80+
tValid({
81+
code: 'import { helper } from "#utils/helper.js"',
82+
options: ['always'],
83+
}),
84+
tValid({
85+
code: 'import { helper } from "#utils/helper"',
86+
options: ['never'],
87+
}),
88+
// single-segment subpath imports (e.g. `#dep`) are skipped by the
89+
// existing external-root-module classification; deferred (see #437)
90+
tValid({ code: 'import dep from "#dep"', options: ['always'] }),
91+
7992
tValid({
8093
code: `
8194
import foo from './foo.js'
@@ -659,6 +672,20 @@ ruleTester.run('extensions', rule, {
659672
],
660673
}),
661674

675+
// Node.js subpath imports (#437)
676+
tInvalid({
677+
code: 'import { helper } from "#utils/helper"',
678+
options: ['always'],
679+
errors: [
680+
{
681+
messageId: 'missing',
682+
data: { importPath: '#utils/helper' },
683+
line: 1,
684+
column: 24,
685+
},
686+
],
687+
}),
688+
662689
tInvalid({
663690
code: 'import thing from "@name/pkg/test.js"',
664691
options: ['never'],

‎test/utils/__snapshots__/parse-path.spec.ts.snap‎

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,36 @@
1-
// Jest Snapshot v1, https://goo.gl/fbAQLP
1+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2+
3+
exports[`parse-path should parse and stringify path expectedly: #utils/helper 1`] = `
4+
{
5+
"hash": "",
6+
"pathname": "#utils/helper",
7+
"query": "",
8+
}
9+
`;
10+
11+
exports[`parse-path should parse and stringify path expectedly: #utils/helper.js 1`] = `
12+
{
13+
"hash": "",
14+
"pathname": "#utils/helper.js",
15+
"query": "",
16+
}
17+
`;
18+
19+
exports[`parse-path should parse and stringify path expectedly: #utils/helper.js?query 1`] = `
20+
{
21+
"hash": "",
22+
"pathname": "#utils/helper.js",
23+
"query": "?query",
24+
}
25+
`;
26+
27+
exports[`parse-path should parse and stringify path expectedly: #utils/helper?query 1`] = `
28+
{
29+
"hash": "",
30+
"pathname": "#utils/helper",
31+
"query": "?query",
32+
}
33+
`;
234

335
exports[`parse-path should parse and stringify path expectedly: foo 1`] = `
436
{

‎test/utils/parse-path.spec.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ describe('parse-path', () => {
88
'foo#hash',
99
'foo?query#hash',
1010
'foo#hash?query',
11+
'#utils/helper',
12+
'#utils/helper.js',
13+
'#utils/helper?query',
14+
'#utils/helper.js?query',
1115
]
1216

1317
for (const input of cases) {

0 commit comments

Comments
 (0)