@@ -112,6 +112,7 @@ let prevCwd: string
112112
113113let mappersCachedOptions : InternalResolverOptions
114114let mappers : Array < {
115+ path : string
115116 files : Set < string >
116117 mapperFn : NonNullable < ReturnType < typeof createPathsMatcher > >
117118} > = [ ]
@@ -311,35 +312,50 @@ function getMappedPaths(
311312 paths = [ resolved ]
312313 }
313314 } 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
336355 }
337- } catch {
338- return false
339- }
340356
341- return false
342- } )
357+ return false
358+ } )
343359 }
344360
345361 if ( retry && paths . length === 0 ) {
@@ -487,6 +503,7 @@ function initMappers(options: InternalResolverOptions) {
487503 }
488504
489505 return {
506+ path : toNativePathSeparator ( tsconfigResult . path ) ,
490507 files : new Set ( files . map ( toNativePathSeparator ) ) ,
491508 mapperFn,
492509 }
@@ -551,3 +568,23 @@ function toNativePathSeparator(p: string) {
551568function isDefined < T > ( value : T | null | undefined ) : value is T {
552569 return value !== null && value !== undefined
553570}
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