1import { Resolution } from 'metro-resolver'; 2import path from 'path'; 3 4import { matchTsConfigPathAlias } from './matchTsConfigPathAlias'; 5 6type Paths = { [match: string]: string[] }; 7 8const debug = require('debug')('expo:metro:tsconfig-paths') as typeof console.log; 9 10const isAbsolute = process.platform === 'win32' ? path.win32.isAbsolute : path.posix.isAbsolute; 11 12export function resolveWithTsConfigPaths( 13 config: { paths: Paths; baseUrl: string }, 14 request: { 15 /** Import request */ 16 moduleName: string; 17 /** Originating file path */ 18 originModulePath: string; 19 }, 20 resolve: (moduleName: string) => Resolution | null 21): Resolution | null { 22 const aliases = Object.keys(config.paths); 23 24 if ( 25 // If no aliases are added bail out 26 !aliases.length || 27 // Library authors cannot utilize this feature in userspace. 28 /node_modules/.test(request.originModulePath) || 29 // Absolute paths are not supported 30 isAbsolute(request.moduleName) || 31 // Relative paths are not supported 32 /^\.\.?($|[\\/])/.test(request.moduleName) 33 ) { 34 return null; 35 } 36 37 const matched = matchTsConfigPathAlias(aliases, request.moduleName); 38 if (!matched) { 39 return null; 40 } 41 42 for (const alias of config.paths[matched.text]) { 43 const nextModuleName = matched.star ? alias.replace('*', matched.star) : alias; 44 45 if (/\.d\.ts$/.test(nextModuleName)) continue; 46 47 const possibleResult = path.join(config.baseUrl, nextModuleName); 48 49 const result = resolve(possibleResult); 50 if (result) { 51 debug(`${request.moduleName} -> ${possibleResult}`); 52 return result; 53 } 54 } 55 return null; 56} 57