@@ -4,10 +4,30 @@ import { DEFAULT_EXTENSIONS, DTS_EXTENSIONS } from '../constants.ts';
44import { sanitizeSpecifier } from '../util/modules.ts' ;
55import { timerify } from '../util/Performance.ts' ;
66import { dirname , extname , isAbsolute , isInNodeModules , join } from '../util/path.ts' ;
7- import { _createSyncModuleResolver , _resolveModuleSync , convertPathsToAlias } from '../util/resolve.ts' ;
7+ import { _createSyncModuleResolver , _resolveModuleSync } from '../util/resolve.ts' ;
88import type { ToSourceFilePath } from '../util/to-source-path.ts' ;
99import type { ResolveModule , ResolvedModule } from './visitors/helpers.ts' ;
1010
11+ interface PathMapping {
12+ prefix : string ;
13+ wildcard : boolean ;
14+ values : string [ ] ;
15+ }
16+
17+ function compilePathMappings ( paths : Record < string , string [ ] > | undefined ) : PathMapping [ ] | undefined {
18+ if ( ! paths ) return undefined ;
19+ const mappings : PathMapping [ ] = [ ] ;
20+ for ( const key in paths ) {
21+ const starIdx = key . indexOf ( '*' ) ;
22+ if ( starIdx >= 0 ) {
23+ mappings . push ( { prefix : key . slice ( 0 , starIdx ) , wildcard : true , values : paths [ key ] } ) ;
24+ } else {
25+ mappings . push ( { prefix : key , wildcard : false , values : paths [ key ] } ) ;
26+ }
27+ }
28+ return mappings . length > 0 ? mappings : undefined ;
29+ }
30+
1131export function createCustomModuleResolver (
1232 compilerOptions : { paths ?: Record < string , string [ ] > ; rootDirs ?: string [ ] } ,
1333 customCompilerExtensions : string [ ] ,
@@ -16,9 +36,8 @@ export function createCustomModuleResolver(
1636 const customCompilerExtensionsSet = new Set ( customCompilerExtensions ) ;
1737 const hasCustomExts = customCompilerExtensionsSet . size > 0 ;
1838 const extensions = [ ...DEFAULT_EXTENSIONS , ...customCompilerExtensions , ...DTS_EXTENSIONS ] ;
19- const alias = convertPathsToAlias ( compilerOptions . paths as Record < string , string [ ] > ) ;
2039 const resolveSync = hasCustomExts ? _createSyncModuleResolver ( extensions ) : _resolveModuleSync ;
21- const resolveWithAlias = alias ? _createSyncModuleResolver ( extensions , alias ) : undefined ;
40+ const pathMappings = compilePathMappings ( compilerOptions . paths as Record < string , string [ ] > ) ;
2241 const rootDirs = compilerOptions . rootDirs ;
2342
2443 function toSourcePath ( resolvedFileName : string ) : string {
@@ -37,38 +56,47 @@ export function createCustomModuleResolver(
3756 }
3857
3958 function resolveModuleName ( name : string , containingFile : string ) : ResolvedModule | undefined {
40- const sanitizedSpecifier = sanitizeSpecifier ( name ) ;
59+ const specifier = sanitizeSpecifier ( name ) ;
4160
42- if ( isBuiltin ( sanitizedSpecifier ) ) return undefined ;
61+ if ( isBuiltin ( specifier ) ) return undefined ;
4362
44- const resolvedFileName = resolveSync ( sanitizedSpecifier , containingFile ) ;
63+ const resolvedFileName = resolveSync ( specifier , containingFile ) ;
4564 if ( resolvedFileName ) return toResult ( resolvedFileName ) ;
4665
47- if ( resolveWithAlias ) {
48- const aliasResolved = resolveWithAlias ( sanitizedSpecifier , containingFile ) ;
49- if ( aliasResolved ) return toResult ( aliasResolved ) ;
50- }
51-
52- const candidate = isAbsolute ( sanitizedSpecifier )
53- ? sanitizedSpecifier
54- : join ( dirname ( containingFile ) , sanitizedSpecifier ) ;
55- if ( existsSync ( candidate ) ) {
56- return { resolvedFileName : candidate , isExternalLibraryImport : false } ;
66+ // Fallback for knip.json#paths not in tsconfig.json#compilerOptions.paths
67+ if ( pathMappings ) {
68+ for ( const { prefix, wildcard, values } of pathMappings ) {
69+ if ( wildcard ? specifier . startsWith ( prefix ) : specifier === prefix ) {
70+ const captured = wildcard ? specifier . slice ( prefix . length ) : '' ;
71+ for ( const value of values ) {
72+ const starIdx = value . indexOf ( '*' ) ;
73+ const mapped = starIdx >= 0 ? value . slice ( 0 , starIdx ) + captured + value . slice ( starIdx + 1 ) : value ;
74+ const resolved = resolveSync ( mapped , containingFile ) ;
75+ if ( resolved ) return toResult ( resolved ) ;
76+ }
77+ }
78+ }
5779 }
5880
59- if ( rootDirs && ! isAbsolute ( sanitizedSpecifier ) ) {
81+ // Fallback for https://github.com/oxc-project/oxc-resolver/issues/1075
82+ if ( rootDirs && ! isAbsolute ( specifier ) ) {
6083 const containingDir = dirname ( containingFile ) ;
6184 for ( const srcRoot of rootDirs ) {
6285 if ( ! containingDir . startsWith ( srcRoot ) ) continue ;
6386 const relPath = containingDir . slice ( srcRoot . length ) ;
6487 for ( const targetRoot of rootDirs ) {
6588 if ( targetRoot === srcRoot ) continue ;
66- const mapped = join ( targetRoot , relPath , sanitizedSpecifier ) ;
89+ const mapped = join ( targetRoot , relPath , specifier ) ;
6790 const resolved = resolveSync ( mapped , containingFile ) ;
6891 if ( resolved ) return toResult ( resolved ) ;
6992 }
7093 }
7194 }
95+
96+ const candidate = isAbsolute ( specifier ) ? specifier : join ( dirname ( containingFile ) , specifier ) ;
97+ if ( existsSync ( candidate ) ) {
98+ return { resolvedFileName : candidate , isExternalLibraryImport : false } ;
99+ }
72100 }
73101
74102 return timerify ( resolveModuleName ) ;
0 commit comments