@@ -91,6 +91,19 @@ type Options<TModule, TPackage> = {|
91
91
+ sourceExts : Array < string > ,
92
92
| } ;
93
93
94
+ /**
95
+ * This is a way to describe what files we tried to look for when resolving
96
+ * a module name as file. This is mainly used for error reporting, so that
97
+ * we can explain why we cannot resolve a module.
98
+ */
99
+ type FileCandidates =
100
+ // We only tried to resolve a specific asset.
101
+ | { | + type : 'asset ', + name : string | }
102
+ // We attempted to resolve a name as being a source file (ex. JavaScript,
103
+ // JSON...), in which case there can be several variants we tried, for
104
+ // example `foo.ios.js`, `foo.js`, etc.
105
+ | { | + type : 'sources ', + fileNames : $ReadOnlyArray < string > | } ;
106
+
94
107
/**
95
108
* It may not be a great pattern to leverage exception just for "trying" things
96
109
* out, notably for performance. We should consider replacing these functions
@@ -433,7 +446,12 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
433
446
path . relative ( packageName , realModuleName ) ,
434
447
) ;
435
448
return tryResolveSync (
436
- ( ) => this . _loadAsFile ( potentialModulePath , fromModule , toModuleName ) ,
449
+ ( ) =>
450
+ this . _loadAsFileOrThrow (
451
+ potentialModulePath ,
452
+ fromModule ,
453
+ toModuleName ,
454
+ ) ,
437
455
( ) => this . _loadAsDir ( potentialModulePath , fromModule , toModuleName ) ,
438
456
) ;
439
457
}
@@ -463,15 +481,15 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
463
481
potentialModulePath ,
464
482
) ;
465
483
if ( realModuleName === false ) {
466
- return this . _loadAsFile (
484
+ return this . _loadAsFileOrThrow (
467
485
ResolutionRequest . EMPTY_MODULE ,
468
486
fromModule ,
469
487
toModuleName ,
470
488
) ;
471
489
}
472
490
473
491
return tryResolveSync (
474
- ( ) => this . _loadAsFile ( realModuleName , fromModule , toModuleName ) ,
492
+ ( ) => this . _loadAsFileOrThrow ( realModuleName , fromModule , toModuleName ) ,
475
493
( ) => this . _loadAsDir ( realModuleName , fromModule , toModuleName ) ,
476
494
) ;
477
495
}
@@ -483,7 +501,7 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
483
501
const realModuleName = this . _redirectRequire ( fromModule , toModuleName ) ;
484
502
// exclude
485
503
if ( realModuleName === false ) {
486
- return this . _loadAsFile (
504
+ return this . _loadAsFileOrThrow (
487
505
ResolutionRequest . EMPTY_MODULE ,
488
506
fromModule ,
489
507
toModuleName ,
@@ -567,7 +585,7 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
567
585
) : ?TModule {
568
586
try {
569
587
return tryResolveSync (
570
- ( ) => this . _loadAsFile ( searchPath , fromModule , toModuleName ) ,
588
+ ( ) => this . _loadAsFileOrThrow ( searchPath , fromModule , toModuleName ) ,
571
589
( ) => this . _loadAsDir ( searchPath , fromModule , toModuleName ) ,
572
590
) ;
573
591
} catch ( error ) {
@@ -578,53 +596,74 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
578
596
}
579
597
}
580
598
581
- _loadAsFile (
582
- basepath : string ,
599
+ /**
600
+ * Eventually we'd like to remove all the exception being throw in the middle
601
+ * of the resolution algorithm, instead keeping track of tentatives in a
602
+ * specific data structure, and building a proper error at the top-level.
603
+ * This function is meant to be a temporary proxy for _loadAsFile until
604
+ * the callsites switch to that tracking structure.
605
+ */
606
+ _loadAsFileOrThrow (
607
+ basePath : string ,
583
608
fromModule : TModule ,
584
609
toModule : string ,
585
610
) : TModule {
586
- if ( this . _options . helpers . isAssetFile ( basepath ) ) {
587
- return this . _loadAsAssetFile ( basepath , fromModule , toModule ) ;
611
+ const dirPath = path . dirname ( basePath ) ;
612
+ const fileNameHint = path . basename ( basePath ) ;
613
+ const candidates = [ ] ;
614
+ const result = this . _loadAsFile ( dirPath , fileNameHint , candidates ) ;
615
+ if ( result != null ) {
616
+ return result ;
617
+ }
618
+ const [ candidate ] = candidates ;
619
+ invariant ( candidate != null , 'missing file candidate' ) ;
620
+ if ( candidate . type === 'asset' ) {
621
+ const msg =
622
+ `Directory \`${ dirPath } ' doesn't contain asset ` +
623
+ `\`${ candidate . name } '` ;
624
+ throw new UnableToResolveError ( fromModule , toModule , msg ) ;
625
+ }
626
+ invariant ( candidate . type === 'sources' , 'invalid candidate type' ) ;
627
+ const msg =
628
+ `Could not resolve the base path \`${ basePath } ' into a module. The ` +
629
+ `folder \`${ dirPath } ' was searched for one of these files: ` +
630
+ candidate . fileNames . map ( filePath => `\`${ filePath } '` ) . join ( ', ' ) +
631
+ '.' ;
632
+ throw new UnableToResolveError ( fromModule , toModule , msg ) ;
633
+ }
634
+
635
+ _loadAsFile (
636
+ dirPath : string ,
637
+ fileNameHint : string ,
638
+ candidates : Array < FileCandidates > ,
639
+ ) : ?TModule {
640
+ if ( this . _options . helpers . isAssetFile ( fileNameHint ) ) {
641
+ const result = this . _loadAsAssetFile ( dirPath , fileNameHint ) ;
642
+ if ( result != null ) {
643
+ return result ;
644
+ }
645
+ candidates . push ( { type : 'asset' , name : fileNameHint } ) ;
646
+ return null ;
588
647
}
589
- const dirPath = path . dirname ( basepath ) ;
590
648
const doesFileExist = this . _doesFileExist ;
591
649
const resolver = new FileNameResolver ( { doesFileExist, dirPath} ) ;
592
- const fileNamePrefix = path . basename ( basepath ) ;
593
- const fileName = this . _tryToResolveAllFileNames ( resolver , fileNamePrefix ) ;
650
+ const fileName = this . _tryToResolveAllFileNames ( resolver , fileNameHint ) ;
594
651
if ( fileName != null ) {
595
652
return this . _options. moduleCache . getModule ( path . join ( dirPath , fileName ) ) ;
596
653
}
597
- throw new UnableToResolveError (
598
- fromModule ,
599
- toModule ,
600
- `Could not resolve the base path \`${ basepath } ' into a module. The ` +
601
- `folder \`${ dirPath } ' was searched for one of these files: ` +
602
- resolver
603
- . getTentativeFileNames ( )
604
- . map ( filePath => `\`${ filePath } '` )
605
- . join ( ', ' ) +
606
- '.' ,
607
- ) ;
654
+ const fileNames = resolver . getTentativeFileNames ( ) ;
655
+ candidates . push ( { type : 'sources' , fileNames} ) ;
656
+ return null ;
608
657
}
609
658
610
- _loadAsAssetFile (
611
- potentialModulePath : string ,
612
- fromModule : TModule ,
613
- toModule : string ,
614
- ) : TModule {
615
- const dirPath = path . dirname ( potentialModulePath ) ;
616
- const baseName = path . basename ( potentialModulePath ) ;
617
- const assetNames = this . _options . resolveAsset ( dirPath , baseName ) ;
659
+ _loadAsAssetFile ( dirPath : string , fileNameHint : string ) : ?TModule {
660
+ const assetNames = this . _options . resolveAsset ( dirPath , fileNameHint ) ;
618
661
const assetName = getArrayLowestItem ( assetNames ) ;
619
662
if ( assetName != null ) {
620
663
const assetPath = path . join ( dirPath , assetName ) ;
621
664
return this . _options . moduleCache . getAssetModule ( assetPath ) ;
622
665
}
623
- throw new UnableToResolveError (
624
- fromModule ,
625
- toModule ,
626
- `Directory \`${ dirPath } ' doesn't contain asset \`${ baseName } '` ,
627
- ) ;
666
+ return null ;
628
667
}
629
668
630
669
/**
@@ -692,12 +731,12 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
692
731
. getPackage ( packageJsonPath )
693
732
. getMain ( ) ;
694
733
return tryResolveSync (
695
- ( ) => this . _loadAsFile ( main , fromModule , toModule ) ,
734
+ ( ) => this . _loadAsFileOrThrow ( main , fromModule , toModule ) ,
696
735
( ) => this . _loadAsDir ( main , fromModule , toModule ) ,
697
736
) ;
698
737
}
699
738
700
- return this . _loadAsFile (
739
+ return this . _loadAsFileOrThrow (
701
740
path . join ( potentialDirPath , 'index ') ,
702
741
fromModule ,
703
742
toModule ,
0 commit comments