3
3
const {
4
4
ArrayIsArray,
5
5
ArrayPrototypeJoin,
6
- ArrayPrototypeShift ,
6
+ ArrayPrototypeMap ,
7
7
JSONStringify,
8
8
ObjectGetOwnPropertyNames,
9
9
ObjectPrototypeHasOwnProperty,
10
- RegExp,
11
10
RegExpPrototypeExec,
12
11
RegExpPrototypeSymbolReplace,
13
12
SafeMap,
@@ -21,6 +20,7 @@ const {
21
20
StringPrototypeSlice,
22
21
StringPrototypeSplit,
23
22
StringPrototypeStartsWith,
23
+ encodeURIComponent,
24
24
} = primordials ;
25
25
const internalFS = require ( 'internal/fs/utils' ) ;
26
26
const { BuiltinModule } = require ( 'internal/bootstrap/realm' ) ;
@@ -30,7 +30,7 @@ const { getOptionValue } = require('internal/options');
30
30
const policy = getOptionValue ( '--experimental-policy' ) ?
31
31
require ( 'internal/process/policy' ) :
32
32
null ;
33
- const { sep, relative, toNamespacedPath, resolve } = require ( 'path' ) ;
33
+ const { sep, posix : { relative : relativePosixPath } , toNamespacedPath, resolve } = require ( 'path' ) ;
34
34
const preserveSymlinks = getOptionValue ( '--preserve-symlinks' ) ;
35
35
const preserveSymlinksMain = getOptionValue ( '--preserve-symlinks-main' ) ;
36
36
const experimentalNetworkImports =
@@ -921,6 +921,7 @@ function moduleResolve(specifier, base, conditions, preserveSymlinks) {
921
921
* Try to resolve an import as a CommonJS module.
922
922
* @param {string } specifier - The specifier to resolve.
923
923
* @param {string } parentURL - The base URL.
924
+ * @returns {string | Buffer | false }
924
925
*/
925
926
function resolveAsCommonJS ( specifier , parentURL ) {
926
927
try {
@@ -933,29 +934,38 @@ function resolveAsCommonJS(specifier, parentURL) {
933
934
// If it is a relative specifier return the relative path
934
935
// to the parent
935
936
if ( isRelativeSpecifier ( specifier ) ) {
936
- found = relative ( parent , found ) ;
937
- // Add '.separator if the path does not start with '..separator'
937
+ const foundURL = pathToFileURL ( found ) . pathname ;
938
+ found = relativePosixPath (
939
+ StringPrototypeSlice ( parentURL , 'file://' . length , StringPrototypeLastIndexOf ( parentURL , '/' ) ) ,
940
+ foundURL ) ;
941
+
942
+ // Add './' if the path does not start with '../'
938
943
// This should be a safe assumption because when loading
939
944
// esm modules there should be always a file specified so
940
945
// there should not be a specifier like '..' or '.'
941
- if ( ! StringPrototypeStartsWith ( found , `.. ${ sep } ` ) ) {
942
- found = `.${ sep } ${ found } ` ;
946
+ if ( ! StringPrototypeStartsWith ( found , '../' ) ) {
947
+ found = `./ ${ found } ` ;
943
948
}
944
949
} else if ( isBareSpecifier ( specifier ) ) {
945
950
// If it is a bare specifier return the relative path within the
946
951
// module
947
- const pkg = StringPrototypeSplit ( specifier , '/' ) [ 0 ] ;
948
- const index = StringPrototypeIndexOf ( found , pkg ) ;
952
+ const i = StringPrototypeIndexOf ( specifier , '/' ) ;
953
+ const pkg = i === - 1 ? specifier : StringPrototypeSlice ( specifier , 0 , i ) ;
954
+ const needle = `${ sep } node_modules${ sep } ${ pkg } ${ sep } ` ;
955
+ const index = StringPrototypeLastIndexOf ( found , needle ) ;
949
956
if ( index !== - 1 ) {
950
- found = StringPrototypeSlice ( found , index ) ;
957
+ found = pkg + '/' + ArrayPrototypeJoin (
958
+ ArrayPrototypeMap (
959
+ StringPrototypeSplit ( StringPrototypeSlice ( found , index + needle . length ) , sep ) ,
960
+ // Escape URL-special characters to avoid generating a incorrect suggestion
961
+ encodeURIComponent ,
962
+ ) ,
963
+ '/' ,
964
+ ) ;
965
+ } else {
966
+ found = `${ pathToFileURL ( found ) } ` ;
951
967
}
952
968
}
953
- // Normalize the path separator to give a valid suggestion
954
- // on Windows
955
- if ( process . platform === 'win32' ) {
956
- found = RegExpPrototypeSymbolReplace ( new RegExp ( `\\${ sep } ` , 'g' ) ,
957
- found , '/' ) ;
958
- }
959
969
return found ;
960
970
} catch {
961
971
return false ;
@@ -1163,14 +1173,14 @@ function defaultResolve(specifier, context = {}) {
1163
1173
*/
1164
1174
function decorateErrorWithCommonJSHints ( error , specifier , parentURL ) {
1165
1175
const found = resolveAsCommonJS ( specifier , parentURL ) ;
1166
- if ( found ) {
1176
+ if ( found && found !== specifier ) { // Don't suggest the same input the user provided.
1167
1177
// Modify the stack and message string to include the hint
1168
- const lines = StringPrototypeSplit ( error . stack , '\n' ) ;
1169
- const hint = `Did you mean to import ${ found } ?` ;
1178
+ const endOfFirstLine = StringPrototypeIndexOf ( error . stack , '\n' ) ;
1179
+ const hint = `Did you mean to import ${ JSONStringify ( found ) } ?` ;
1170
1180
error . stack =
1171
- ArrayPrototypeShift ( lines ) + '\n' +
1172
- hint + '\n' +
1173
- ArrayPrototypeJoin ( lines , '\n' ) ;
1181
+ StringPrototypeSlice ( error . stack , 0 , endOfFirstLine ) + '\n' +
1182
+ hint +
1183
+ StringPrototypeSlice ( error . stack , endOfFirstLine ) ;
1174
1184
error . message += `\n${ hint } ` ;
1175
1185
}
1176
1186
}
0 commit comments