Skip to content

Commit 207809a

Browse files
committed
feat: implement import-x resolver interface v3
1 parent e6256b7 commit 207809a

File tree

20 files changed

+272
-19
lines changed

20 files changed

+272
-19
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
dist
22
lib
3+
tests
34
CHANGELOG.md
45
/shim.d.ts
56
/pnpm-lock.yml

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"eslint.useFlatConfig": false
3+
}

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"prepare": "simple-git-hooks",
5252
"release": "changeset publish",
5353
"test": "run-p 'test:*'",
54+
"test:importXResolverV3": "eslint --config=tests/importXResolverV3/eslint.config.js tests/importXResolverV3",
5455
"test:multipleEslintrcs": "eslint --ext ts,tsx tests/multipleEslintrcs",
5556
"test:multipleTsconfigs": "eslint --ext ts,tsx tests/multipleTsconfigs",
5657
"test:withJsExtension": "node tests/withJsExtension/test.js && eslint --ext ts,tsx tests/withJsExtension",
@@ -78,13 +79,14 @@
7879
"@nolyfill/is-core-module": "1.0.39",
7980
"debug": "^4.3.7",
8081
"enhanced-resolve": "^5.15.0",
81-
"eslint-module-utils": "^2.8.1",
8282
"fast-glob": "^3.3.2",
8383
"get-tsconfig": "^4.7.5",
8484
"is-bun-module": "^1.0.2",
85-
"is-glob": "^4.0.3"
85+
"is-glob": "^4.0.3",
86+
"stable-hash": "^0.0.4"
8687
},
8788
"devDependencies": {
89+
"@1stg/eslint-config": "7",
8890
"@1stg/lib-config": "^12.0.1",
8991
"@changesets/changelog-github": "^0.5.0",
9092
"@changesets/cli": "^2.27.10",
@@ -99,6 +101,7 @@
99101
"eslint": "^8.57.1",
100102
"eslint-import-resolver-typescript": "link:.",
101103
"eslint-plugin-import": "npm:eslint-plugin-i@^2.29.1",
104+
"eslint-plugin-import-x": "^4.5.0",
102105
"lint-staged": "^13.3.0",
103106
"npm-run-all2": "^5.0.2",
104107
"prettier": "^2.8.8",

shim.d.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/index.ts

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@ import isNodeCoreModule from '@nolyfill/is-core-module'
55
import debug from 'debug'
66
import type { FileSystem, ResolveOptions, Resolver } from 'enhanced-resolve'
77
import enhancedResolve from 'enhanced-resolve'
8-
import { hashObject } from 'eslint-module-utils/hash.js'
98
import fg from 'fast-glob'
109
import { createPathsMatcher, getTsconfig } from 'get-tsconfig'
1110
import type { TsConfigResult } from 'get-tsconfig'
1211
import type { Version } from 'is-bun-module'
1312
import { isBunModule } from 'is-bun-module'
1413
import isGlob from 'is-glob'
14+
import stableHashExports from 'stable-hash'
1515

1616
const { globSync } = fg
1717

18+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- esmodule interop
19+
const stableHash = stableHashExports.default || stableHashExports
20+
1821
const IMPORTER_NAME = 'eslint-import-resolver-typescript'
1922

2023
const log = debug(IMPORTER_NAME)
@@ -114,10 +117,7 @@ let mappersCachedOptions: InternalResolverOptions
114117
let mappers: Array<((specifier: string) => string[]) | null> | undefined
115118

116119
let resolverCachedOptions: InternalResolverOptions
117-
let resolver: Resolver | undefined
118-
119-
const digestHashObject = (value: object | null | undefined) =>
120-
hashObject(value ?? {}).digest('hex')
120+
let cachedResolver: Resolver | undefined
121121

122122
/**
123123
* @param source the module to resolve; i.e './some-module'
@@ -129,13 +129,14 @@ export function resolve(
129129
source: string,
130130
file: string,
131131
options?: TsResolverOptions | null,
132+
resolver: Resolver | null = null,
132133
): {
133134
found: boolean
134135
path?: string | null
135136
} {
136137
if (
137138
!cachedOptions ||
138-
previousOptionsHash !== (optionsHash = digestHashObject(options))
139+
previousOptionsHash !== (optionsHash = stableHash(options))
139140
) {
140141
previousOptionsHash = optionsHash
141142
cachedOptions = {
@@ -152,9 +153,13 @@ export function resolve(
152153
}
153154
}
154155

155-
if (!resolver || resolverCachedOptions !== cachedOptions) {
156-
resolver = enhancedResolve.ResolverFactory.createResolver(cachedOptions)
157-
resolverCachedOptions = cachedOptions
156+
if (!resolver) {
157+
if (!cachedResolver || resolverCachedOptions !== cachedOptions) {
158+
cachedResolver =
159+
enhancedResolve.ResolverFactory.createResolver(cachedOptions)
160+
resolverCachedOptions = cachedOptions
161+
}
162+
resolver = cachedResolver
158163
}
159164

160165
log('looking for:', source)
@@ -229,6 +234,28 @@ export function resolve(
229234
}
230235
}
231236

237+
export function createTypeScriptImportResolver(
238+
options?: TsResolverOptions | null,
239+
) {
240+
const resolver = enhancedResolve.ResolverFactory.createResolver({
241+
...options,
242+
conditionNames: options?.conditionNames ?? defaultConditionNames,
243+
extensions: options?.extensions ?? defaultExtensions,
244+
extensionAlias: options?.extensionAlias ?? defaultExtensionAlias,
245+
mainFields: options?.mainFields ?? defaultMainFields,
246+
fileSystem: new enhancedResolve.CachedInputFileSystem(fileSystem, 5 * 1000),
247+
useSyncFileSystemCalls: true,
248+
})
249+
250+
return {
251+
interfaceVersion: 3,
252+
name: IMPORTER_NAME,
253+
resolve(source: string, file: string) {
254+
return resolve(source, file, options, resolver)
255+
},
256+
}
257+
}
258+
232259
/** Remove any trailing querystring from module id. */
233260
function removeQuerystring(id: string) {
234261
const querystringIndex = id.lastIndexOf('?')
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const path = require('path')
2+
const { createTypeScriptImportResolver } = require('../../lib/index.cjs')
3+
4+
const globPattern = './packages/*/tsconfig.json'
5+
6+
// in normal cases this is not needed because the __dirname would be the root
7+
const absoluteGlobPath = path.join(__dirname, globPattern)
8+
9+
module.exports = {
10+
...require('eslint-plugin-import-x').flatConfigs.typescript,
11+
settings: {
12+
...require('eslint-plugin-import-x').flatConfigs.typescript.settings,
13+
'import-x/resolver-next': [
14+
createTypeScriptImportResolver({
15+
project: absoluteGlobPath,
16+
alwaysTryTypes: true,
17+
}),
18+
],
19+
},
20+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// import relative
2+
import './tsImportee'
3+
import './tsxImportee'
4+
import './subfolder/tsImportee'
5+
import './subfolder/tsxImportee'
6+
7+
// import using tsconfig.json path mapping
8+
import 'folder/tsImportee'
9+
import 'folder/tsxImportee'
10+
import 'folder/subfolder/tsImportee'
11+
import 'folder/subfolder/tsxImportee'
12+
13+
// import from node_module
14+
import 'typescript'
15+
import 'dummy.js'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'yes'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'React Component'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'yes'
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"compilerOptions": {
3+
"baseUrl": ".",
4+
"jsx": "react",
5+
"paths": {
6+
"folder/*": ["*"],
7+
"*": ["../../../../node_modules/*"]
8+
}
9+
},
10+
"files": ["index.ts", "tsImportee.ts", "tsxImportee.tsx"]
11+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'React Component'
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// import relative
2+
import './tsImportee'
3+
import './tsxImportee'
4+
import './subfolder/tsImportee'
5+
import './subfolder/tsxImportee'
6+
7+
// import using tsconfig.json path mapping
8+
import 'folder/tsImportee'
9+
import 'folder/tsxImportee'
10+
import 'folder/subfolder/tsImportee'
11+
import 'folder/subfolder/tsxImportee'
12+
13+
// import from node_module
14+
import 'typescript'
15+
import 'dummy.js'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'yes'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'React Component'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'yes'
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"compilerOptions": {
3+
"baseUrl": ".",
4+
"jsx": "react",
5+
"paths": {
6+
"folder/*": ["*"],
7+
"*": ["../../../../node_modules/*"]
8+
}
9+
},
10+
"files": ["index.ts", "tsImportee.ts", "tsxImportee.tsx"]
11+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'React Component'

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
"allowSyntheticDefaultImports": true,
77
"esModuleInterop": true
88
},
9-
"include": ["./src", "./shim.d.ts"]
9+
"include": ["./src"]
1010
}

0 commit comments

Comments
 (0)