1- import { ModulePatcher , TBabelCore , TBabelJest , TTypeScript , TsJestImporter } from '../types'
1+ import { ModulePatcher , TBabelCore , TBabelJest , TTypeScript } from '../types'
22
33import * as hacks from './hacks'
44import { rootLogger } from './logger'
@@ -26,7 +26,7 @@ const passThru = (action: () => void) => (input: any) => {
2626/**
2727 * @internal
2828 */
29- export class Importer implements TsJestImporter {
29+ export class Importer {
3030 @Memoize ( )
3131 static get instance ( ) {
3232 logger . debug ( 'creating Importer singleton' )
@@ -70,22 +70,51 @@ export class Importer implements TsJestImporter {
7070 }
7171
7272 @Memoize ( ( ...args : string [ ] ) => args . join ( ':' ) )
73- tryThese ( moduleName : string , ...fallbacks : string [ ] ) : any {
73+ tryThese ( moduleName : string , ...fallbacks : string [ ] ) {
7474 let name : string
75- let loaded : any
75+ let loaded : RequireResult < true > | undefined
7676 const tries = [ moduleName , ...fallbacks ]
7777 // tslint:disable-next-line:no-conditional-assignment
7878 while ( ( name = tries . shift ( ) as string ) !== undefined ) {
79- try {
80- loaded = requireModule ( name )
81- logger . debug ( 'loaded module' , name )
79+ const req = requireWrapper ( name )
80+
81+ // remove exports from what we're going to log
82+ const contextReq : any = { ...req }
83+ delete contextReq . exports
84+
85+ if ( req . exists ) {
86+ // module exists
87+ loaded = req as RequireResult < true >
88+ if ( loaded . error ) {
89+ // require-ing it failed
90+ logger . error ( { requireResult : contextReq } , `failed loading module '${ name } '` , loaded . error . message )
91+ } else {
92+ // it has been loaded, let's patch it
93+ logger . debug ( { requireResult : contextReq } , 'loaded module' , name )
94+ loaded . exports = this . _patch ( name , loaded . exports )
95+ }
8296 break
83- } catch ( err ) {
84- logger . debug ( 'fail loading module' , name )
97+ } else {
98+ // module does not exists in the path
99+ logger . debug ( { requireResult : contextReq } , `module '${ name } ' not found` )
100+ continue
85101 }
86102 }
87103
88- return loaded && this . _patch ( name , loaded )
104+ // return the loaded one, could be one that has been loaded, or one which has failed during load
105+ // but not one which does not exists
106+ return loaded
107+ }
108+
109+ tryTheseOr < T > ( moduleNames : [ string , ...string [ ] ] | string , missingResult : T , allowLoadError ?: boolean ) : T
110+ tryTheseOr < T > ( moduleNames : [ string , ...string [ ] ] | string , missingResult ?: T , allowLoadError ?: boolean ) : T | undefined
111+ tryTheseOr < T > ( moduleNames : [ string , ...string [ ] ] | string , missingResult ?: T , allowLoadError = false ) : T | undefined {
112+ const args : [ string , ...string [ ] ] = Array . isArray ( moduleNames ) ? moduleNames : [ moduleNames ]
113+ const result = this . tryThese ( ...args )
114+ if ( ! result ) return missingResult
115+ if ( ! result . error ) return result . exports as T
116+ if ( allowLoadError ) return missingResult
117+ throw result . error
89118 }
90119
91120 @Memoize ( name => name )
@@ -105,8 +134,10 @@ export class Importer implements TsJestImporter {
105134 // try to load any of the alternative after trying main one
106135 const res = this . tryThese ( moduleName , ...alternatives )
107136 // if we could load one, return it
108- if ( res ) {
109- return res
137+ if ( res && res . exists ) {
138+ if ( ! res . error ) return res . exports
139+ // it could not load because of a failure while importing, but it exists
140+ throw new Error ( interpolate ( Errors . LoadingModuleFailed , { module : res . given , error : res . error . message } ) )
110141 }
111142
112143 // if it couldn't load, build a nice error message so the user can fix it by himself
@@ -136,11 +167,43 @@ export class Importer implements TsJestImporter {
136167 */
137168export const importer = Importer . instance
138169
170+ /**
171+ * @internal
172+ */
173+ export interface RequireResult < E = boolean > {
174+ exists : E
175+ given : string
176+ path ?: string
177+ exports ?: any
178+ error ?: Error
179+ }
180+
181+ function requireWrapper ( moduleName : string ) : RequireResult {
182+ let path : string
183+ let exists = false
184+ try {
185+ path = resolveModule ( moduleName )
186+ exists = true
187+ } catch ( error ) {
188+ return { error, exists, given : moduleName }
189+ }
190+ const result : RequireResult = { exists, path, given : moduleName }
191+ try {
192+ result . exports = requireModule ( moduleName )
193+ } catch ( error ) {
194+ result . error = error
195+ }
196+ return result
197+ }
198+
139199let requireModule = ( mod : string ) => require ( mod )
200+ let resolveModule = ( mod : string ) => require . resolve ( mod )
201+
140202/**
141203 * @internal
142204 */
143205// so that we can test easier
144- export function __requireModule ( localRequire : typeof requireModule ) {
206+ export function __requireModule ( localRequire : typeof requireModule , localResolve : typeof resolveModule ) {
145207 requireModule = localRequire
208+ resolveModule = localResolve
146209}
0 commit comments