import * as path from "path" ; import { InternalError } from "../error" ; import { trace , tracef } from "../utils" ; import { ChainableHost } from "./hosts" ; import * as ts from "./tsmod" ; const tsmod = ts . tsmod ; const debugModuleResolution = false ; const dtsRegex = /\.d\.ts$/ ; export class ModuleResolver extends ChainableHost { private cache : Map < string , ts . ResolvedModuleFull | null > ; constructor ( private compilerOptions , chainHost ? , id ? ) { super ( ( chainHost && chainHost . cwd ) || "/" ) ; if ( chainHost ) this . setSource ( chainHost ) ; this . cache = new Map < string , ts . ResolvedModuleFull | null > ( ) ; if ( id ) this . _id = id ; } @ tracef ( debugModuleResolution ) resolveModuleNames ( moduleNames , containingFile , reusedNames ? ) { const resolved = [ ] ; for ( const modName of moduleNames ) { resolved . push ( this . resolveModuleName ( modName , containingFile , false ) as ts . ResolvedModuleFull ) ; } return resolved ; } param modName param containingFile param runnable @ tracef ( debugModuleResolution ) resolveModuleName ( modName , containingFile , runnable ) { trace ( debugModuleResolution , `Trying to resolve ${ modName }` ) ; const fn = this . realFilename ( containingFile ) ; if ( ! fn ) throw new Error ( `Unable to get real filename for ${ containingFile }` ) ; containingFile = fn ; const cacheKey = `${ modName }\0${ containingFile }\0${ runnable }` ; let mod = this . cache . get ( cacheKey ) ; if ( mod !== undefined ) return mod === null ? undefined : mod ; const r = tsmod ( ) . resolveModuleName ( modName , containingFile , this . compilerOptions , this ) ; if ( r ) { mod = r . resolvedModule ; if ( runnable ) { const resolved = mod && mod . resolvedFileName ; if ( resolved && resolved . match ( dtsRegex ) ) { trace ( debugModuleResolution , `Initially resolved to ${ resolved }, but rejecting .d.ts ` + `file because runnable=true` ) ; mod = resolveJS ( modName , containingFile , this ) ; } } } if ( mod ) { trace ( debugModuleResolution , `Resolved to ${ mod . resolvedFileName }` ) ; this . cache . set ( cacheKey , mod ) ; return mod ; } trace ( debugModuleResolution , `FAILED to resolve ${ modName }` ) ; this . cache . set ( cacheKey , null ) ; return undefined ; } param s trace ( s ) { trace ( debugModuleResolution , s ) ; } } function resolveJS ( modName , containingFile , host ) { const tsResolve = ( tsmod ( ) as any ) . resolveJSModule || ( tsmod ( ) as any ) . resolveJavaScriptModule ; if ( ! tsResolve ) { throw new InternalError ( `Unable to locate the Javascript resolver ` + `function from the TypeScript library` ) ; } const jsFile = tsResolve ( modName , path . dirname ( containingFile ) , host ) ; if ( ! jsFile ) { trace ( debugModuleResolution , `JavaScript file resolution failed` ) ; return null ; } let ext ; switch ( path . extname ( jsFile ) ) { case tsmod ( ) . Extension . Js : ext = tsmod ( ) . Extension . Js ; break ; case tsmod ( ) . Extension . Jsx : ext = tsmod ( ) . Extension . Jsx ; break ; default : throw new Error ( `Module file extension ` + `'${ path . extname ( jsFile ) }' not understood` ) ; } return { resolvedFileName : jsFile , isExternalLibraryImport : true , extension : ext , } ; }