@@ -4,14 +4,20 @@ const path = require('path');
4
4
const resolve = require ( 'resolve' ) ;
5
5
const tsconfigPaths = require ( 'tsconfig-paths' ) ;
6
6
const debug = require ( 'debug' ) ;
7
+ const globSync = require ( 'glob' ) . sync ;
8
+ const isGlob = require ( 'is-glob' ) ;
7
9
8
10
const log = debug ( 'eslint-import-resolver-typescript' ) ;
9
11
12
+ const extensions = [ '.ts' , '.tsx' , '.d.ts' ] . concat (
13
+ Object . keys ( require . extensions ) ,
14
+ ) ;
15
+
10
16
/**
11
17
* @param {string } source the module to resolve; i.e './some-module'
12
18
* @param {string } file the importing file's full path; i.e. '/usr/local/bin/file.js'
13
19
*/
14
- function resolveFile ( source , file , config ) {
20
+ function resolveFile ( source , file , options = { } ) {
15
21
log ( 'looking for:' , source ) ;
16
22
17
23
// don't worry about core node modules
@@ -24,36 +30,16 @@ function resolveFile(source, file, config) {
24
30
} ;
25
31
}
26
32
27
- let foundTsPath = null ;
28
- const extensions = [ '.ts' , '.tsx' , '.d.ts' ] . concat (
29
- Object . keys ( require . extensions ) ,
30
- ) ;
31
-
32
- // setup tsconfig-paths
33
- const searchStart = config . directory || process . cwd ( ) ;
34
- const configLoaderResult = tsconfigPaths . loadConfig ( searchStart ) ;
35
- if ( configLoaderResult . resultType === 'success' ) {
36
- const matchPath = tsconfigPaths . createMatchPath (
37
- configLoaderResult . absoluteBaseUrl ,
38
- configLoaderResult . paths ,
39
- ) ;
40
-
41
- // look for files based on setup tsconfig "paths"
42
- foundTsPath = matchPath ( source , undefined , undefined , extensions ) ;
43
-
44
- if ( foundTsPath ) {
45
- log ( 'matched ts path:' , foundTsPath ) ;
46
- }
47
- } else {
48
- log ( 'failed to init tsconfig-paths:' , configLoaderResult . message ) ;
49
- // this can happen if the user has problems with their tsconfig
50
- // or if it's valid, but they don't have baseUrl set
33
+ initMappers ( options ) ;
34
+ const mappedPath = getMappedPath ( source , file ) ;
35
+ if ( mappedPath ) {
36
+ log ( 'matched ts path:' , mappedPath ) ;
51
37
}
52
38
53
- // note that even if we match via tsconfig-paths , we still need to do a final resolve
39
+ // note that even if we map the path , we still need to do a final resolve
54
40
let foundNodePath ;
55
41
try {
56
- foundNodePath = resolve . sync ( foundTsPath || source , {
42
+ foundNodePath = resolve . sync ( mappedPath || source , {
57
43
extensions,
58
44
basedir : path . dirname ( path . resolve ( file ) ) ,
59
45
packageFilter,
@@ -66,15 +52,15 @@ function resolveFile(source, file, config) {
66
52
// if path is neither absolute nor relative
67
53
if (
68
54
( / \. j s x ? $ / . test ( foundNodePath ) ||
69
- ( config . alwaysTryTypes && ! foundNodePath ) ) &&
55
+ ( options . alwaysTryTypes && ! foundNodePath ) ) &&
70
56
! / ^ @ t y p e s [ / \\ ] / . test ( source ) &&
71
57
! path . isAbsolute ( source ) &&
72
58
source [ 0 ] !== '.'
73
59
) {
74
60
const definitelyTyped = resolveFile (
75
61
'@types' + path . sep + mangleScopedPackage ( source ) ,
76
62
file ,
77
- config ,
63
+ options ,
78
64
) ;
79
65
if ( definitelyTyped . found ) {
80
66
return definitelyTyped ;
@@ -104,6 +90,74 @@ function packageFilter(pkg) {
104
90
}
105
91
106
92
/**
93
+ * @param {string } source the module to resolve; i.e './some-module'
94
+ * @param {string } file the importing file's full path; i.e. '/usr/local/bin/file.js'
95
+ * @returns The mapped path of the module or undefined
96
+ */
97
+ function getMappedPath ( source , file ) {
98
+ const paths = mappers
99
+ . map ( mapper => mapper ( source , file ) )
100
+ . filter ( path => ! ! path ) ;
101
+
102
+ if ( paths . length > 1 ) {
103
+ log ( 'found multiple matching ts paths:' , paths ) ;
104
+ }
105
+
106
+ return paths [ 0 ] ;
107
+ }
108
+
109
+ let mappers ;
110
+ function initMappers ( options ) {
111
+ if ( mappers ) {
112
+ return ;
113
+ }
114
+
115
+ const isArrayOfStrings = array =>
116
+ Array . isArray ( array ) && array . every ( o => typeof o === 'string' ) ;
117
+
118
+ const configPaths =
119
+ typeof options . directory === 'string'
120
+ ? [ options . directory ]
121
+ : isArrayOfStrings ( options . directory )
122
+ ? options . directory
123
+ : [ process . cwd ( ) ] ;
124
+
125
+ mappers = configPaths
126
+ // turn glob patterns into paths
127
+ . reduce (
128
+ ( paths , path ) => paths . concat ( isGlob ( path ) ? globSync ( path ) : path ) ,
129
+ [ ] ,
130
+ )
131
+
132
+ . map ( path => tsconfigPaths . loadConfig ( path ) )
133
+ . filter ( configLoaderResult => {
134
+ const success = configLoaderResult . resultType === 'success' ;
135
+ if ( ! success ) {
136
+ // this can happen if the user has problems with their tsconfig
137
+ // or if it's valid, but they don't have baseUrl set
138
+ log ( 'failed to init tsconfig-paths:' , configLoaderResult . message ) ;
139
+ }
140
+ return success ;
141
+ } )
142
+ . map ( configLoaderResult => {
143
+ const matchPath = tsconfigPaths . createMatchPath (
144
+ configLoaderResult . absoluteBaseUrl ,
145
+ configLoaderResult . paths ,
146
+ ) ;
147
+
148
+ return ( source , file ) => {
149
+ // exclude files that are not part of the config base url
150
+ if ( ! file . includes ( configLoaderResult . absoluteBaseUrl ) ) {
151
+ return undefined ;
152
+ }
153
+
154
+ // look for files based on setup tsconfig "paths"
155
+ return matchPath ( source , undefined , undefined , extensions ) ;
156
+ } ;
157
+ } ) ;
158
+ }
159
+
160
+ /*
107
161
* For a scoped package, we must look in `@types/foo__bar` instead of `@types/@foo/bar`.
108
162
*
109
163
* @param {string } moduleName
0 commit comments