Skip to content

Commit

Permalink
esm: port loader code to JS
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
addaleax authored and targos committed Apr 28, 2020
1 parent 217e3df commit 7410e8d
Show file tree
Hide file tree
Showing 9 changed files with 657 additions and 1,020 deletions.
59 changes: 43 additions & 16 deletions lib/internal/errors.js
Expand Up @@ -1070,29 +1070,50 @@ E('ERR_INVALID_FILE_URL_PATH', 'File URL path %s', TypeError);
E('ERR_INVALID_HANDLE_TYPE', 'This handle type cannot be sent', TypeError);
E('ERR_INVALID_HTTP_TOKEN', '%s must be a valid HTTP token ["%s"]', TypeError);
E('ERR_INVALID_IP_ADDRESS', 'Invalid IP address: %s', TypeError);
E('ERR_INVALID_MODULE_SPECIFIER', (pkgPath, subpath) => {
assert(subpath !== '.');
return `Package subpath '${subpath}' is not a valid module request for the ` +
`"exports" resolution of ${pkgPath}${sep}package.json`;
E('ERR_INVALID_MODULE_SPECIFIER', (pkgPath, subpath, base = undefined) => {
if (subpath === undefined) {
return `Invalid package name '${pkgPath}' imported from ${base}`;
} else if (base === undefined) {
assert(subpath !== '.');
return `Package subpath '${subpath}' is not a valid module request for ` +
`the "exports" resolution of ${pkgPath}${sep}package.json`;
} else {
return `Package subpath '${subpath}' is not a valid module request for ` +
`the "exports" resolution of ${pkgPath} imported from ${base}`;
}
}, TypeError);
E('ERR_INVALID_OPT_VALUE', (name, value) =>
`The value "${String(value)}" is invalid for option "${name}"`,
TypeError,
RangeError);
E('ERR_INVALID_OPT_VALUE_ENCODING',
'The value "%s" is invalid for option "encoding"', TypeError);
E('ERR_INVALID_PACKAGE_CONFIG',
`Invalid package config %s${sep}package.json, %s`, Error);
E('ERR_INVALID_PACKAGE_TARGET', (pkgPath, key, subpath, target) => {
if (key === '.') {
return `Invalid "exports" main target ${JSONStringify(target)} defined ` +
E('ERR_INVALID_PACKAGE_CONFIG', (path, message, hasMessage = true) => {
if (hasMessage)
return `Invalid package config ${path}${sep}package.json, ${message}`;
else
return `Invalid JSON in ${path} imported from ${message}`;
}, Error);
E('ERR_INVALID_PACKAGE_TARGET',
(pkgPath, key, subpath, target, base = undefined) => {
if (key === null) {
if (subpath !== '') {
return `Invalid "exports" target ${JSONStringify(target)} defined ` +
`for '${subpath}' in the package config ${pkgPath} imported from ` +
base;
} else {
return `Invalid "exports" main target ${target} defined in the ` +
`package config ${pkgPath} imported from ${base}.`;
}
} else if (key === '.') {
return `Invalid "exports" main target ${JSONStringify(target)} defined ` +
`in the package config ${pkgPath}${sep}package.json`;
} else {
return `Invalid "exports" target ${JSONStringify(target)} defined for '${
StringPrototypeSlice(key, 0, -subpath.length || key.length)}' in the ` +
} else {
return `Invalid "exports" target ${JSONStringify(target)} defined for '${
StringPrototypeSlice(key, 0, -subpath.length || key.length)}' in the ` +
`package config ${pkgPath}${sep}package.json`;
}
}, Error);
}
}, Error);
E('ERR_INVALID_PERFORMANCE_MARK',
'The "%s" performance mark has not been set', Error);
E('ERR_INVALID_PROTOCOL',
Expand Down Expand Up @@ -1203,6 +1224,9 @@ E('ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK',
'The ES Module loader may not return a format of \'dynamic\' when no ' +
'dynamicInstantiate function was provided', Error);
E('ERR_MISSING_OPTION', '%s is required', TypeError);
E('ERR_MODULE_NOT_FOUND', (path, base, type = 'package') => {
return `Cannot find ${type} '${path}' imported from ${base}`;
}, Error);
E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times', Error);
E('ERR_NAPI_CONS_FUNCTION', 'Constructor must be a function', TypeError);
E('ERR_NAPI_INVALID_DATAVIEW_ARGS',
Expand Down Expand Up @@ -1237,12 +1261,15 @@ E('ERR_OUT_OF_RANGE',
msg += ` It must be ${range}. Received ${received}`;
return msg;
}, RangeError);
E('ERR_PACKAGE_PATH_NOT_EXPORTED', (pkgPath, subpath) => {
E('ERR_PACKAGE_PATH_NOT_EXPORTED', (pkgPath, subpath, base = undefined) => {
if (subpath === '.') {
return `No "exports" main resolved in ${pkgPath}${sep}package.json`;
} else {
} else if (base === undefined) {
return `Package subpath '${subpath}' is not defined by "exports" in ${
pkgPath}${sep}package.json`;
} else {
return `Package subpath '${subpath}' is not defined by "exports" in ${
pkgPath} imported from ${base}`;
}
}, Error);
E('ERR_REQUIRE_ESM',
Expand Down
15 changes: 5 additions & 10 deletions lib/internal/modules/esm/get_format.js
@@ -1,20 +1,16 @@
'use strict';

const { StringPrototypeStartsWith } = primordials;
const { extname } = require('path');
const { getOptionValue } = require('internal/options');

const experimentalJsonModules = getOptionValue('--experimental-json-modules');
const experimentalSpeciferResolution =
getOptionValue('--experimental-specifier-resolution');
const experimentalWasmModules = getOptionValue('--experimental-wasm-modules');
const { getPackageType } = internalBinding('module_wrap');
const { getPackageType } = require('internal/modules/esm/resolve');
const { URL, fileURLToPath } = require('internal/url');
const { ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes;

// const TYPE_NONE = 0;
// const TYPE_COMMONJS = 1;
const TYPE_MODULE = 2;

const extensionFormatMap = {
'__proto__': null,
'.cjs': 'commonjs',
Expand All @@ -37,8 +33,8 @@ if (experimentalWasmModules)
if (experimentalJsonModules)
extensionFormatMap['.json'] = legacyExtensionFormatMap['.json'] = 'json';

function defaultGetFormat(url, context, defaultGetFormat) {
if (url.startsWith('nodejs:')) {
function defaultGetFormat(url, context, defaultGetFormatUnused) {
if (StringPrototypeStartsWith(url, 'nodejs:')) {
return { format: 'builtin' };
}
const parsed = new URL(url);
Expand All @@ -55,8 +51,7 @@ function defaultGetFormat(url, context, defaultGetFormat) {
const ext = extname(parsed.pathname);
let format;
if (ext === '.js') {
format = getPackageType(parsed.href) === TYPE_MODULE ?
'module' : 'commonjs';
format = getPackageType(parsed.href) === 'module' ? 'module' : 'commonjs';
} else {
format = extensionFormatMap[ext];
}
Expand Down

0 comments on commit 7410e8d

Please sign in to comment.