@@ -112,6 +112,7 @@ let prevCwd: string
112
112
113
113
let mappersCachedOptions : InternalResolverOptions
114
114
let mappers : Array < {
115
+ path : string
115
116
files : Set < string >
116
117
mapperFn : NonNullable < ReturnType < typeof createPathsMatcher > >
117
118
} > = [ ]
@@ -311,35 +312,50 @@ function getMappedPaths(
311
312
paths = [ resolved ]
312
313
}
313
314
} else {
314
- paths = [
315
- ...new Set (
316
- mappers
317
- . filter ( ( { files } ) => files . has ( file ) )
318
- . map ( ( { mapperFn } ) =>
319
- mapperFn ( source ) . map ( item => [
320
- ...extensions . map ( ext => `${ item } ${ ext } ` ) ,
321
- ...originalExtensions . map ( ext => `${ item } /index${ ext } ` ) ,
322
- ] ) ,
323
- )
324
- . flat ( 2 )
325
- . map ( toNativePathSeparator ) ,
326
- ) ,
327
- ] . filter ( mappedPath => {
328
- try {
329
- const stat = fs . statSync ( mappedPath , { throwIfNoEntry : false } )
330
- if ( stat === undefined ) return false
331
- if ( stat . isFile ( ) ) return true
332
-
333
- // Maybe this is a module dir?
334
- if ( stat . isDirectory ( ) ) {
335
- return isModule ( mappedPath )
315
+ // Filter mapper functions associated with file
316
+ let mapperFns : Array < NonNullable < ReturnType < typeof createPathsMatcher > > > =
317
+ mappers
318
+ . filter ( ( { files } ) => files . has ( file ) )
319
+ . map ( ( { mapperFn } ) => mapperFn )
320
+ if ( mapperFns . length === 0 ) {
321
+ // If empty, try all mapper functions, starting with the nearest one
322
+ mapperFns = mappers
323
+ . map ( mapper => ( {
324
+ mapperFn : mapper . mapperFn ,
325
+ counter : equalChars ( path . dirname ( file ) , path . dirname ( mapper . path ) ) ,
326
+ } ) )
327
+ . sort (
328
+ ( a , b ) =>
329
+ // Sort in descending order where the nearest one has the longest counter
330
+ b . counter - a . counter ,
331
+ )
332
+ . map ( ( { mapperFn } ) => mapperFn )
333
+ }
334
+ paths = mapperFns
335
+ . map ( mapperFn =>
336
+ mapperFn ( source ) . map ( item => [
337
+ ...extensions . map ( ext => `${ item } ${ ext } ` ) ,
338
+ ...originalExtensions . map ( ext => `${ item } /index${ ext } ` ) ,
339
+ ] ) ,
340
+ )
341
+ . flat ( 2 )
342
+ . map ( toNativePathSeparator )
343
+ . filter ( mappedPath => {
344
+ try {
345
+ const stat = fs . statSync ( mappedPath , { throwIfNoEntry : false } )
346
+ if ( stat === undefined ) return false
347
+ if ( stat . isFile ( ) ) return true
348
+
349
+ // Maybe this is a module dir?
350
+ if ( stat . isDirectory ( ) ) {
351
+ return isModule ( mappedPath )
352
+ }
353
+ } catch {
354
+ return false
336
355
}
337
- } catch {
338
- return false
339
- }
340
356
341
- return false
342
- } )
357
+ return false
358
+ } )
343
359
}
344
360
345
361
if ( retry && paths . length === 0 ) {
@@ -487,6 +503,7 @@ function initMappers(options: InternalResolverOptions) {
487
503
}
488
504
489
505
return {
506
+ path : toNativePathSeparator ( tsconfigResult . path ) ,
490
507
files : new Set ( files . map ( toNativePathSeparator ) ) ,
491
508
mapperFn,
492
509
}
@@ -551,3 +568,23 @@ function toNativePathSeparator(p: string) {
551
568
function isDefined < T > ( value : T | null | undefined ) : value is T {
552
569
return value !== null && value !== undefined
553
570
}
571
+
572
+ /**
573
+ * Counts how many characters in strings `a` and `b` are exactly the same and in the same position.
574
+ *
575
+ * @param {string } a First string
576
+ * @param {string } b Second string
577
+ * @returns Number of matching characters
578
+ */
579
+ function equalChars ( a : string , b : string ) : number {
580
+ if ( a . length === 0 || b . length === 0 ) {
581
+ return 0
582
+ }
583
+
584
+ let i = 0
585
+ const length = Math . min ( a . length , b . length )
586
+ while ( i < length && a . charAt ( i ) === b . charAt ( i ) ) {
587
+ i += 1
588
+ }
589
+ return i
590
+ }
0 commit comments