@@ -4,14 +4,20 @@ const path = require('path');
44const resolve = require ( 'resolve' ) ;
55const tsconfigPaths = require ( 'tsconfig-paths' ) ;
66const debug = require ( 'debug' ) ;
7+ const globSync = require ( 'glob' ) . sync ;
8+ const isGlob = require ( 'is-glob' ) ;
79
810const log = debug ( 'eslint-import-resolver-typescript' ) ;
911
12+ const extensions = [ '.ts' , '.tsx' , '.d.ts' ] . concat (
13+ Object . keys ( require . extensions ) ,
14+ ) ;
15+
1016/**
1117 * @param {string } source the module to resolve; i.e './some-module'
1218 * @param {string } file the importing file's full path; i.e. '/usr/local/bin/file.js'
1319 */
14- function resolveFile ( source , file , config ) {
20+ function resolveFile ( source , file , options = { } ) {
1521 log ( 'looking for:' , source ) ;
1622
1723 // don't worry about core node modules
@@ -24,36 +30,16 @@ function resolveFile(source, file, config) {
2430 } ;
2531 }
2632
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 ) ;
5137 }
5238
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
5440 let foundNodePath ;
5541 try {
56- foundNodePath = resolve . sync ( foundTsPath || source , {
42+ foundNodePath = resolve . sync ( mappedPath || source , {
5743 extensions,
5844 basedir : path . dirname ( path . resolve ( file ) ) ,
5945 packageFilter,
@@ -66,15 +52,15 @@ function resolveFile(source, file, config) {
6652 // if path is neither absolute nor relative
6753 if (
6854 ( / \. j s x ? $ / . test ( foundNodePath ) ||
69- ( config . alwaysTryTypes && ! foundNodePath ) ) &&
55+ ( options . alwaysTryTypes && ! foundNodePath ) ) &&
7056 ! / ^ @ t y p e s [ / \\ ] / . test ( source ) &&
7157 ! path . isAbsolute ( source ) &&
7258 source [ 0 ] !== '.'
7359 ) {
7460 const definitelyTyped = resolveFile (
7561 '@types' + path . sep + mangleScopedPackage ( source ) ,
7662 file ,
77- config ,
63+ options ,
7864 ) ;
7965 if ( definitelyTyped . found ) {
8066 return definitelyTyped ;
@@ -104,6 +90,74 @@ function packageFilter(pkg) {
10490}
10591
10692/**
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+ /*
107161 * For a scoped package, we must look in `@types/foo__bar` instead of `@types/@foo/bar`.
108162 *
109163 * @param {string } moduleName
0 commit comments