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 =
@@ -912,6 +912,7 @@ function moduleResolve(specifier, base, conditions, preserveSymlinks) {
912
912
* Try to resolve an import as a CommonJS module.
913
913
* @param {string } specifier - The specifier to resolve.
914
914
* @param {string } parentURL - The base URL.
915
+ * @returns {string | Buffer | false }
915
916
*/
916
917
function resolveAsCommonJS ( specifier , parentURL ) {
917
918
try {
@@ -924,29 +925,38 @@ function resolveAsCommonJS(specifier, parentURL) {
924
925
// If it is a relative specifier return the relative path
925
926
// to the parent
926
927
if ( isRelativeSpecifier ( specifier ) ) {
927
- found = relative ( parent , found ) ;
928
- // Add '.separator if the path does not start with '..separator'
928
+ const foundURL = pathToFileURL ( found ) . pathname ;
929
+ found = relativePosixPath (
930
+ StringPrototypeSlice ( parentURL , 'file://' . length , StringPrototypeLastIndexOf ( parentURL , '/' ) ) ,
931
+ foundURL ) ;
932
+
933
+ // Add './' if the path does not start with '../'
929
934
// This should be a safe assumption because when loading
930
935
// esm modules there should be always a file specified so
931
936
// there should not be a specifier like '..' or '.'
932
- if ( ! StringPrototypeStartsWith ( found , `.. ${ sep } ` ) ) {
933
- found = `.${ sep } ${ found } ` ;
937
+ if ( ! StringPrototypeStartsWith ( found , '../' ) ) {
938
+ found = `./ ${ found } ` ;
934
939
}
935
940
} else if ( isBareSpecifier ( specifier ) ) {
936
941
// If it is a bare specifier return the relative path within the
937
942
// module
938
- const pkg = StringPrototypeSplit ( specifier , '/' ) [ 0 ] ;
939
- const index = StringPrototypeIndexOf ( found , pkg ) ;
943
+ const i = StringPrototypeIndexOf ( specifier , '/' ) ;
944
+ const pkg = i === - 1 ? specifier : StringPrototypeSlice ( specifier , 0 , i ) ;
945
+ const needle = `${ sep } node_modules${ sep } ${ pkg } ${ sep } ` ;
946
+ const index = StringPrototypeLastIndexOf ( found , needle ) ;
940
947
if ( index !== - 1 ) {
941
- found = StringPrototypeSlice ( found , index ) ;
948
+ found = pkg + '/' + ArrayPrototypeJoin (
949
+ ArrayPrototypeMap (
950
+ StringPrototypeSplit ( StringPrototypeSlice ( found , index + needle . length ) , sep ) ,
951
+ // Escape URL-special characters to avoid generating a incorrect suggestion
952
+ encodeURIComponent ,
953
+ ) ,
954
+ '/' ,
955
+ ) ;
956
+ } else {
957
+ found = `${ pathToFileURL ( found ) } ` ;
942
958
}
943
959
}
944
- // Normalize the path separator to give a valid suggestion
945
- // on Windows
946
- if ( process . platform === 'win32' ) {
947
- found = RegExpPrototypeSymbolReplace ( new RegExp ( `\\${ sep } ` , 'g' ) ,
948
- found , '/' ) ;
949
- }
950
960
return found ;
951
961
} catch {
952
962
return false ;
@@ -1154,14 +1164,14 @@ function defaultResolve(specifier, context = {}) {
1154
1164
*/
1155
1165
function decorateErrorWithCommonJSHints ( error , specifier , parentURL ) {
1156
1166
const found = resolveAsCommonJS ( specifier , parentURL ) ;
1157
- if ( found ) {
1167
+ if ( found && found !== specifier ) { // Don't suggest the same input the user provided.
1158
1168
// Modify the stack and message string to include the hint
1159
- const lines = StringPrototypeSplit ( error . stack , '\n' ) ;
1160
- const hint = `Did you mean to import ${ found } ?` ;
1169
+ const endOfFirstLine = StringPrototypeIndexOf ( error . stack , '\n' ) ;
1170
+ const hint = `Did you mean to import ${ JSONStringify ( found ) } ?` ;
1161
1171
error . stack =
1162
- ArrayPrototypeShift ( lines ) + '\n' +
1163
- hint + '\n' +
1164
- ArrayPrototypeJoin ( lines , '\n' ) ;
1172
+ StringPrototypeSlice ( error . stack , 0 , endOfFirstLine ) + '\n' +
1173
+ hint +
1174
+ StringPrototypeSlice ( error . stack , endOfFirstLine ) ;
1165
1175
error . message += `\n${ hint } ` ;
1166
1176
}
1167
1177
}
0 commit comments