@@ -3,9 +3,15 @@ import path from 'node:path'
3
3
import { fileURLToPath } from 'node:url'
4
4
5
5
import debug from 'debug'
6
+ import {
7
+ FileSystem ,
8
+ ResolveOptions ,
9
+ Resolver ,
10
+ ResolverFactory ,
11
+ } from 'enhanced-resolve'
6
12
import { createPathsMatcher , getTsconfig } from 'get-tsconfig'
13
+ import isCore from 'is-core-module'
7
14
import isGlob from 'is-glob'
8
- import { isCore , type PackageJSON , sync , SyncOpts } from 'resolve'
9
15
import { createSyncFn } from 'synckit'
10
16
11
17
const IMPORTER_NAME = 'eslint-import-resolver-typescript'
@@ -21,15 +27,37 @@ const globSync = createSyncFn<typeof import('globby').globby>(
21
27
path . resolve ( _dirname , 'worker.mjs' ) ,
22
28
)
23
29
30
+ /**
31
+ * .mts, .cts, .d.mts, .d.cts, .mjs, .cjs are not included because .cjs and .mjs must be used explicitly.
32
+ */
33
+ const defaultExtensions = [
34
+ '.ts' ,
35
+ '.tsx' ,
36
+ '.d.ts' ,
37
+ '.js' ,
38
+ '.jsx' ,
39
+ '.json' ,
40
+ '.node' ,
41
+ ]
42
+
43
+ const defaultMainFields = [ 'types' , 'typings' , 'module' , 'jsnext:main' , 'main' ]
44
+
24
45
export const interfaceVersion = 2
25
46
26
- export type TsResolverOptions = SyncOpts & {
47
+ export interface TsResolverOptions
48
+ extends Omit < ResolveOptions , 'fileSystem' | 'useSyncFileSystemCalls' > {
27
49
alwaysTryTypes ?: boolean
28
50
project ?: string [ ] | string
29
51
extensions ?: string [ ]
30
52
packageFilter ?: ( pkg : Record < string , string > ) => Record < string , string >
31
53
}
32
54
55
+ const fileSystem = fs as FileSystem
56
+
57
+ let mappersBuildForOptions : TsResolverOptions
58
+ let mappers : Array < ( ( specifier : string ) => string [ ] ) | null > | undefined
59
+ let resolver : Resolver
60
+
33
61
/**
34
62
* @param {string } source the module to resolve; i.e './some-module'
35
63
* @param {string } file the importing file's full path; i.e. '/usr/local/bin/file.js'
@@ -38,12 +66,20 @@ export type TsResolverOptions = SyncOpts & {
38
66
export function resolve (
39
67
source : string ,
40
68
file : string ,
41
- options : TsResolverOptions | null ,
69
+ options ? : TsResolverOptions | null ,
42
70
) : {
43
71
found : boolean
44
72
path ?: string | null
45
73
} {
46
- options = options ?? { }
74
+ const opts : ResolveOptions & TsResolverOptions = {
75
+ ...options ,
76
+ extensions : options ?. extensions ?? defaultExtensions ,
77
+ mainFields : options ?. mainFields ?? defaultMainFields ,
78
+ fileSystem,
79
+ useSyncFileSystemCalls : true ,
80
+ }
81
+
82
+ resolver = ResolverFactory . createResolver ( opts )
47
83
48
84
log ( 'looking for:' , source )
49
85
@@ -59,7 +95,7 @@ export function resolve(
59
95
}
60
96
}
61
97
62
- initMappers ( options )
98
+ initMappers ( opts )
63
99
64
100
const mappedPath = getMappedPath ( source , file , true )
65
101
if ( mappedPath ) {
@@ -69,11 +105,9 @@ export function resolve(
69
105
// note that even if we map the path, we still need to do a final resolve
70
106
let foundNodePath : string | null | undefined
71
107
try {
72
- foundNodePath = tsResolve ( mappedPath ?? source , {
73
- ...options ,
74
- basedir : path . dirname ( path . resolve ( file ) ) ,
75
- packageFilter : options . packageFilter ?? packageFilterDefault ,
76
- } )
108
+ foundNodePath =
109
+ tsResolve ( mappedPath ?? source , path . dirname ( path . resolve ( file ) ) , opts ) ||
110
+ null
77
111
} catch {
78
112
foundNodePath = null
79
113
}
@@ -82,7 +116,7 @@ export function resolve(
82
116
// if path is neither absolute nor relative
83
117
if (
84
118
( / \. j s x ? $ / . test ( foundNodePath ! ) ||
85
- ( options . alwaysTryTypes && ! foundNodePath ) ) &&
119
+ ( opts . alwaysTryTypes && ! foundNodePath ) ) &&
86
120
! / ^ @ t y p e s [ / \\ ] / . test ( source ) &&
87
121
! path . isAbsolute ( source ) &&
88
122
! source . startsWith ( '.' )
@@ -113,12 +147,6 @@ export function resolve(
113
147
}
114
148
}
115
149
116
- function packageFilterDefault ( pkg : PackageJSON ) {
117
- pkg . main =
118
- pkg . types || pkg . typings || pkg . module || pkg [ 'jsnext:main' ] || pkg . main
119
- return pkg
120
- }
121
-
122
150
function resolveExtension ( id : string ) {
123
151
const idWithoutJsExt = removeJsExtension ( id )
124
152
@@ -149,16 +177,21 @@ function resolveExtension(id: string) {
149
177
* Like `sync` from `resolve` package, but considers that the module id
150
178
* could have a .js or .jsx extension.
151
179
*/
152
- function tsResolve ( id : string , opts : SyncOpts ) : string {
180
+ function tsResolve (
181
+ source : string ,
182
+ base : string ,
183
+ options : ResolveOptions ,
184
+ ) : string | false {
153
185
try {
154
- return sync ( id , opts )
186
+ return resolver . resolveSync ( { } , base , source )
155
187
} catch ( error ) {
156
- const resolved = resolveExtension ( id )
188
+ const resolved = resolveExtension ( source )
157
189
if ( resolved ) {
158
- return sync ( resolved . path , {
159
- ...opts ,
160
- extensions : resolved . extensions ?? opts . extensions ,
190
+ const resolver = ResolverFactory . createResolver ( {
191
+ ...options ,
192
+ extensions : resolved . extensions ?? options . extensions ,
161
193
} )
194
+ return resolver . resolveSync ( { } , base , resolved . path )
162
195
}
163
196
throw error
164
197
}
@@ -178,9 +211,6 @@ function removeJsExtension(id: string) {
178
211
return id . replace ( / \. ( [ c m ] j s | j s x ? ) $ / , '' )
179
212
}
180
213
181
- let mappersBuildForOptions : TsResolverOptions
182
- let mappers : Array < ( ( specifier : string ) => string [ ] ) | null > | undefined
183
-
184
214
const JS_EXT_PATTERN = / \. ( [ c m ] j s | j s x ? ) $ /
185
215
const RELATIVE_PATH_PATTERN = / ^ \. { 1 , 2 } ( \/ .* ) ? $ /
186
216
0 commit comments