2
2
3
3
const {
4
4
ArrayIsArray,
5
+ ArrayPrototypeJoin,
6
+ ArrayPrototypeShift,
5
7
JSONParse,
6
8
JSONStringify,
7
9
ObjectFreeze,
8
10
ObjectGetOwnPropertyNames,
9
11
ObjectPrototypeHasOwnProperty,
12
+ RegExp,
10
13
SafeMap,
11
14
SafeSet,
12
15
StringPrototypeEndsWith,
13
16
StringPrototypeIncludes,
14
17
StringPrototypeIndexOf,
18
+ StringPrototypeReplace,
15
19
StringPrototypeSlice,
20
+ StringPrototypeSplit,
16
21
StringPrototypeStartsWith,
17
22
StringPrototypeSubstr,
18
23
} = primordials ;
@@ -29,8 +34,8 @@ const {
29
34
Stats,
30
35
} = require ( 'fs' ) ;
31
36
const { getOptionValue } = require ( 'internal/options' ) ;
32
- const { sep } = require ( 'path' ) ;
33
-
37
+ const { sep, relative } = require ( 'path' ) ;
38
+ const { Module : CJSModule } = require ( 'internal/modules/cjs/loader' ) ;
34
39
const preserveSymlinks = getOptionValue ( '--preserve-symlinks' ) ;
35
40
const preserveSymlinksMain = getOptionValue ( '--preserve-symlinks-main' ) ;
36
41
const typeFlag = getOptionValue ( '--input-type' ) ;
@@ -611,9 +616,11 @@ function packageResolve(specifier, base, conditions) {
611
616
throw new ERR_MODULE_NOT_FOUND ( packageName , fileURLToPath ( base ) ) ;
612
617
}
613
618
614
- function shouldBeTreatedAsRelativeOrAbsolutePath ( specifier ) {
615
- if ( specifier === '' ) return false ;
616
- if ( specifier [ 0 ] === '/' ) return true ;
619
+ function isBareSpecifier ( specifier ) {
620
+ return specifier [ 0 ] && specifier [ 0 ] !== '/' && specifier [ 0 ] !== '.' ;
621
+ }
622
+
623
+ function isRelativeSpecifier ( specifier ) {
617
624
if ( specifier [ 0 ] === '.' ) {
618
625
if ( specifier . length === 1 || specifier [ 1 ] === '/' ) return true ;
619
626
if ( specifier [ 1 ] === '.' ) {
@@ -623,6 +630,12 @@ function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
623
630
return false ;
624
631
}
625
632
633
+ function shouldBeTreatedAsRelativeOrAbsolutePath ( specifier ) {
634
+ if ( specifier === '' ) return false ;
635
+ if ( specifier [ 0 ] === '/' ) return true ;
636
+ return isRelativeSpecifier ( specifier ) ;
637
+ }
638
+
626
639
/**
627
640
* @param {string } specifier
628
641
* @param {URL } base
@@ -645,6 +658,51 @@ function moduleResolve(specifier, base, conditions) {
645
658
return finalizeResolution ( resolved , base ) ;
646
659
}
647
660
661
+ /**
662
+ * Try to resolve an import as a CommonJS module
663
+ * @param {string } specifier
664
+ * @param {string } parentURL
665
+ * @returns {boolean|string }
666
+ */
667
+ function resolveAsCommonJS ( specifier , parentURL ) {
668
+ try {
669
+ const parent = fileURLToPath ( parentURL ) ;
670
+ const tmpModule = new CJSModule ( parent , null ) ;
671
+ tmpModule . paths = CJSModule . _nodeModulePaths ( parent ) ;
672
+
673
+ let found = CJSModule . _resolveFilename ( specifier , tmpModule , false ) ;
674
+
675
+ // If it is a relative specifier return the relative path
676
+ // to the parent
677
+ if ( isRelativeSpecifier ( specifier ) ) {
678
+ found = relative ( parent , found ) ;
679
+ // Add '.separator if the path does not start with '..separator'
680
+ // This should be a safe assumption because when loading
681
+ // esm modules there should be always a file specified so
682
+ // there should not be a specifier like '..' or '.'
683
+ if ( ! StringPrototypeStartsWith ( found , `..${ sep } ` ) ) {
684
+ found = `.${ sep } ${ found } ` ;
685
+ }
686
+ } else if ( isBareSpecifier ( specifier ) ) {
687
+ // If it is a bare specifier return the relative path within the
688
+ // module
689
+ const pkg = StringPrototypeSplit ( specifier , '/' ) [ 0 ] ;
690
+ const index = StringPrototypeIndexOf ( found , pkg ) ;
691
+ if ( index !== - 1 ) {
692
+ found = StringPrototypeSlice ( found , index ) ;
693
+ }
694
+ }
695
+ // Normalize the path separator to give a valid suggestion
696
+ // on Windows
697
+ if ( process . platform === 'win32' ) {
698
+ found = StringPrototypeReplace ( found , new RegExp ( `\\${ sep } ` , 'g' ) , '/' ) ;
699
+ }
700
+ return found ;
701
+ } catch {
702
+ return false ;
703
+ }
704
+ }
705
+
648
706
function defaultResolve ( specifier , context = { } , defaultResolveUnused ) {
649
707
let { parentURL, conditions } = context ;
650
708
let parsed ;
@@ -685,7 +743,27 @@ function defaultResolve(specifier, context = {}, defaultResolveUnused) {
685
743
}
686
744
687
745
conditions = getConditionsSet ( conditions ) ;
688
- let url = moduleResolve ( specifier , parentURL , conditions ) ;
746
+ let url ;
747
+ try {
748
+ url = moduleResolve ( specifier , parentURL , conditions ) ;
749
+ } catch ( error ) {
750
+ // Try to give the user a hint of what would have been the
751
+ // resolved CommonJS module
752
+ if ( error . code === 'ERR_MODULE_NOT_FOUND' ) {
753
+ const found = resolveAsCommonJS ( specifier , parentURL ) ;
754
+ if ( found ) {
755
+ // Modify the stack and message string to include the hint
756
+ const lines = StringPrototypeSplit ( error . stack , '\n' ) ;
757
+ const hint = `Did you mean to import ${ found } ?` ;
758
+ error . stack =
759
+ ArrayPrototypeShift ( lines ) + '\n' +
760
+ hint + '\n' +
761
+ ArrayPrototypeJoin ( lines , '\n' ) ;
762
+ error . message += `\n${ hint } ` ;
763
+ }
764
+ }
765
+ throw error ;
766
+ }
689
767
690
768
if ( isMain ? ! preserveSymlinksMain : ! preserveSymlinks ) {
691
769
const urlPath = fileURLToPath ( url ) ;
0 commit comments