Skip to content

Commit 3e9012a

Browse files
addaleaxMylesBorins
authored andcommitted
esm: port loader code to JS
There is no reason for this to be in C++. Using JavaScript means that the code is more accessible to more developers, which is important for any Node.js feature. This also simplifies the code significantly in some areas. On the technical side, this potentially also enables making some of the file system operations that are involved asynchronous. PR-URL: #32201 Reviewed-By: Bradley Farias <bradley.meck@gmail.com> Reviewed-By: Guy Bedford <guybedford@gmail.com>
1 parent fa1fa31 commit 3e9012a

File tree

9 files changed

+657
-1020
lines changed

9 files changed

+657
-1020
lines changed

lib/internal/errors.js

+43-16
Original file line numberDiff line numberDiff line change
@@ -1074,29 +1074,50 @@ E('ERR_INVALID_FILE_URL_PATH', 'File URL path %s', TypeError);
10741074
E('ERR_INVALID_HANDLE_TYPE', 'This handle type cannot be sent', TypeError);
10751075
E('ERR_INVALID_HTTP_TOKEN', '%s must be a valid HTTP token ["%s"]', TypeError);
10761076
E('ERR_INVALID_IP_ADDRESS', 'Invalid IP address: %s', TypeError);
1077-
E('ERR_INVALID_MODULE_SPECIFIER', (pkgPath, subpath) => {
1078-
assert(subpath !== '.');
1079-
return `Package subpath '${subpath}' is not a valid module request for the ` +
1080-
`"exports" resolution of ${pkgPath}${sep}package.json`;
1077+
E('ERR_INVALID_MODULE_SPECIFIER', (pkgPath, subpath, base = undefined) => {
1078+
if (subpath === undefined) {
1079+
return `Invalid package name '${pkgPath}' imported from ${base}`;
1080+
} else if (base === undefined) {
1081+
assert(subpath !== '.');
1082+
return `Package subpath '${subpath}' is not a valid module request for ` +
1083+
`the "exports" resolution of ${pkgPath}${sep}package.json`;
1084+
} else {
1085+
return `Package subpath '${subpath}' is not a valid module request for ` +
1086+
`the "exports" resolution of ${pkgPath} imported from ${base}`;
1087+
}
10811088
}, TypeError);
10821089
E('ERR_INVALID_OPT_VALUE', (name, value) =>
10831090
`The value "${String(value)}" is invalid for option "${name}"`,
10841091
TypeError,
10851092
RangeError);
10861093
E('ERR_INVALID_OPT_VALUE_ENCODING',
10871094
'The value "%s" is invalid for option "encoding"', TypeError);
1088-
E('ERR_INVALID_PACKAGE_CONFIG',
1089-
`Invalid package config %s${sep}package.json, %s`, Error);
1090-
E('ERR_INVALID_PACKAGE_TARGET', (pkgPath, key, subpath, target) => {
1091-
if (key === '.') {
1092-
return `Invalid "exports" main target ${JSONStringify(target)} defined ` +
1095+
E('ERR_INVALID_PACKAGE_CONFIG', (path, message, hasMessage = true) => {
1096+
if (hasMessage)
1097+
return `Invalid package config ${path}${sep}package.json, ${message}`;
1098+
else
1099+
return `Invalid JSON in ${path} imported from ${message}`;
1100+
}, Error);
1101+
E('ERR_INVALID_PACKAGE_TARGET',
1102+
(pkgPath, key, subpath, target, base = undefined) => {
1103+
if (key === null) {
1104+
if (subpath !== '') {
1105+
return `Invalid "exports" target ${JSONStringify(target)} defined ` +
1106+
`for '${subpath}' in the package config ${pkgPath} imported from ` +
1107+
base;
1108+
} else {
1109+
return `Invalid "exports" main target ${target} defined in the ` +
1110+
`package config ${pkgPath} imported from ${base}.`;
1111+
}
1112+
} else if (key === '.') {
1113+
return `Invalid "exports" main target ${JSONStringify(target)} defined ` +
10931114
`in the package config ${pkgPath}${sep}package.json`;
1094-
} else {
1095-
return `Invalid "exports" target ${JSONStringify(target)} defined for '${
1096-
StringPrototypeSlice(key, 0, -subpath.length || key.length)}' in the ` +
1115+
} else {
1116+
return `Invalid "exports" target ${JSONStringify(target)} defined for '${
1117+
StringPrototypeSlice(key, 0, -subpath.length || key.length)}' in the ` +
10971118
`package config ${pkgPath}${sep}package.json`;
1098-
}
1099-
}, Error);
1119+
}
1120+
}, Error);
11001121
E('ERR_INVALID_PERFORMANCE_MARK',
11011122
'The "%s" performance mark has not been set', Error);
11021123
E('ERR_INVALID_PROTOCOL',
@@ -1207,6 +1228,9 @@ E('ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK',
12071228
'The ES Module loader may not return a format of \'dynamic\' when no ' +
12081229
'dynamicInstantiate function was provided', Error);
12091230
E('ERR_MISSING_OPTION', '%s is required', TypeError);
1231+
E('ERR_MODULE_NOT_FOUND', (path, base, type = 'package') => {
1232+
return `Cannot find ${type} '${path}' imported from ${base}`;
1233+
}, Error);
12101234
E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times', Error);
12111235
E('ERR_NAPI_CONS_FUNCTION', 'Constructor must be a function', TypeError);
12121236
E('ERR_NAPI_INVALID_DATAVIEW_ARGS',
@@ -1241,12 +1265,15 @@ E('ERR_OUT_OF_RANGE',
12411265
msg += ` It must be ${range}. Received ${received}`;
12421266
return msg;
12431267
}, RangeError);
1244-
E('ERR_PACKAGE_PATH_NOT_EXPORTED', (pkgPath, subpath) => {
1268+
E('ERR_PACKAGE_PATH_NOT_EXPORTED', (pkgPath, subpath, base = undefined) => {
12451269
if (subpath === '.') {
12461270
return `No "exports" main resolved in ${pkgPath}${sep}package.json`;
1247-
} else {
1271+
} else if (base === undefined) {
12481272
return `Package subpath '${subpath}' is not defined by "exports" in ${
12491273
pkgPath}${sep}package.json`;
1274+
} else {
1275+
return `Package subpath '${subpath}' is not defined by "exports" in ${
1276+
pkgPath} imported from ${base}`;
12501277
}
12511278
}, Error);
12521279
E('ERR_REQUIRE_ESM',

lib/internal/modules/esm/get_format.js

+5-10
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
'use strict';
2-
2+
const { StringPrototypeStartsWith } = primordials;
33
const { extname } = require('path');
44
const { getOptionValue } = require('internal/options');
55

66
const experimentalJsonModules = getOptionValue('--experimental-json-modules');
77
const experimentalSpeciferResolution =
88
getOptionValue('--experimental-specifier-resolution');
99
const experimentalWasmModules = getOptionValue('--experimental-wasm-modules');
10-
const { getPackageType } = internalBinding('module_wrap');
10+
const { getPackageType } = require('internal/modules/esm/resolve');
1111
const { URL, fileURLToPath } = require('internal/url');
1212
const { ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes;
1313

14-
// const TYPE_NONE = 0;
15-
// const TYPE_COMMONJS = 1;
16-
const TYPE_MODULE = 2;
17-
1814
const extensionFormatMap = {
1915
'__proto__': null,
2016
'.cjs': 'commonjs',
@@ -37,8 +33,8 @@ if (experimentalWasmModules)
3733
if (experimentalJsonModules)
3834
extensionFormatMap['.json'] = legacyExtensionFormatMap['.json'] = 'json';
3935

40-
function defaultGetFormat(url, context, defaultGetFormat) {
41-
if (url.startsWith('nodejs:')) {
36+
function defaultGetFormat(url, context, defaultGetFormatUnused) {
37+
if (StringPrototypeStartsWith(url, 'nodejs:')) {
4238
return { format: 'builtin' };
4339
}
4440
const parsed = new URL(url);
@@ -55,8 +51,7 @@ function defaultGetFormat(url, context, defaultGetFormat) {
5551
const ext = extname(parsed.pathname);
5652
let format;
5753
if (ext === '.js') {
58-
format = getPackageType(parsed.href) === TYPE_MODULE ?
59-
'module' : 'commonjs';
54+
format = getPackageType(parsed.href) === 'module' ? 'module' : 'commonjs';
6055
} else {
6156
format = extensionFormatMap[ext];
6257
}

0 commit comments

Comments
 (0)