Skip to content

Commit 03a28dd

Browse files
committed
module: package "exports" error refinements
PR-URL: nodejs#31625 Reviewed-By: Jan Krems <[email protected]>
1 parent d577190 commit 03a28dd

File tree

10 files changed

+333
-218
lines changed

10 files changed

+333
-218
lines changed

doc/api/errors.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,6 +1301,12 @@ An invalid HTTP token was supplied.
13011301

13021302
An IP address is not valid.
13031303

1304+
<a id="ERR_INVALID_MODULE_SPECIFIER"></a>
1305+
### `ERR_INVALID_MODULE_SPECIFIER`
1306+
1307+
The imported module string is an invalid URL, package name, or package subpath
1308+
specifier.
1309+
13041310
<a id="ERR_INVALID_OPT_VALUE"></a>
13051311
### `ERR_INVALID_OPT_VALUE`
13061312

@@ -1316,6 +1322,12 @@ An invalid or unknown file encoding was passed.
13161322

13171323
An invalid `package.json` file was found which failed parsing.
13181324

1325+
<a id="ERR_INVALID_PACKAGE_TARGET"></a>
1326+
### `ERR_INVALID_PACKAGE_TARGET`
1327+
1328+
The `package.json` [exports][] field contains an invalid target mapping value
1329+
for the attempted module resolution.
1330+
13191331
<a id="ERR_INVALID_PERFORMANCE_MARK"></a>
13201332
### `ERR_INVALID_PERFORMANCE_MARK`
13211333

@@ -1616,6 +1628,13 @@ A non-context-aware native addon was loaded in a process that disallows them.
16161628

16171629
A given value is out of the accepted range.
16181630

1631+
<a id="ERR_PACKAGE_PATH_NOT_EXPORTED"></a>
1632+
### `ERR_PACKAGE_PATH_NOT_EXPORTED`
1633+
1634+
The `package.json` [exports][] field does not export the requested subpath.
1635+
Because exports are encapsulated, private internal modules that are not exported
1636+
cannot be imported through the package resolution, unless using an absolute URL.
1637+
16191638
<a id="ERR_REQUIRE_ESM"></a>
16201639
### `ERR_REQUIRE_ESM`
16211640

@@ -2457,6 +2476,7 @@ such as `process.stdout.on('data')`.
24572476
[crypto digest algorithm]: crypto.html#crypto_crypto_gethashes
24582477
[domains]: domain.html
24592478
[event emitter-based]: events.html#events_class_eventemitter
2479+
[exports]: esm.html#esm_package_exports
24602480
[file descriptors]: https://en.wikipedia.org/wiki/File_descriptor
24612481
[policy]: policy.html
24622482
[stream-based]: stream.html

doc/api/esm.md

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,6 +1424,17 @@ of these top-level routines unless stated otherwise.
14241424
_defaultEnv_ is the conditional environment name priority array,
14251425
`["node", "import"]`.
14261426
1427+
The resolver can throw the following errors:
1428+
* _Invalid Module Specifier_: Module specifier is an invalid URL, package name
1429+
or package subpath specifier.
1430+
* _Invalid Package Configuration_: package.json configuration is invalid or
1431+
contains an invalid configuration.
1432+
* _Invalid Package Target_: Package exports define a target module within the
1433+
package that is an invalid type or string target.
1434+
* _Package Path Not Exported_: Package exports do not define or permit a target
1435+
subpath in the package for the given module.
1436+
* _Module Not Found_: The package or module requested does not exist.
1437+
14271438
<details>
14281439
<summary>Resolver algorithm specification</summary>
14291440
@@ -1434,7 +1445,7 @@ _defaultEnv_ is the conditional environment name priority array,
14341445
> 1. Set _resolvedURL_ to the result of parsing and reserializing
14351446
> _specifier_ as a URL.
14361447
> 1. Otherwise, if _specifier_ starts with _"/"_, then
1437-
> 1. Throw an _Invalid Specifier_ error.
1448+
> 1. Throw an _Invalid Module Specifier_ error.
14381449
> 1. Otherwise, if _specifier_ starts with _"./"_ or _"../"_, then
14391450
> 1. Set _resolvedURL_ to the URL resolution of _specifier_ relative to
14401451
> _parentURL_.
@@ -1444,8 +1455,9 @@ _defaultEnv_ is the conditional environment name priority array,
14441455
> **PACKAGE_RESOLVE**(_specifier_, _parentURL_).
14451456
> 1. If _resolvedURL_ contains any percent encodings of _"/"_ or _"\\"_ (_"%2f"_
14461457
> and _"%5C"_ respectively), then
1447-
> 1. Throw an _Invalid Specifier_ error.
1448-
> 1. If the file at _resolvedURL_ does not exist, then
1458+
> 1. Throw an _Invalid Module Specifier_ error.
1459+
> 1. If _resolvedURL_ does not end with a trailing _"/"_ and the file at
1460+
> _resolvedURL_ does not exist, then
14491461
> 1. Throw a _Module Not Found_ error.
14501462
> 1. Set _resolvedURL_ to the real path of _resolvedURL_.
14511463
> 1. Let _format_ be the result of **ESM_FORMAT**(_resolvedURL_).
@@ -1456,22 +1468,22 @@ _defaultEnv_ is the conditional environment name priority array,
14561468
> 1. Let _packageName_ be *undefined*.
14571469
> 1. Let _packageSubpath_ be *undefined*.
14581470
> 1. If _packageSpecifier_ is an empty string, then
1459-
> 1. Throw an _Invalid Specifier_ error.
1471+
> 1. Throw an _Invalid Module Specifier_ error.
14601472
> 1. Otherwise,
14611473
> 1. If _packageSpecifier_ does not contain a _"/"_ separator, then
1462-
> 1. Throw an _Invalid Specifier_ error.
1474+
> 1. Throw an _Invalid Module Specifier_ error.
14631475
> 1. Set _packageName_ to the substring of _packageSpecifier_
14641476
> until the second _"/"_ separator or the end of the string.
14651477
> 1. If _packageName_ starts with _"."_ or contains _"\\"_ or _"%"_, then
1466-
> 1. Throw an _Invalid Specifier_ error.
1478+
> 1. Throw an _Invalid Module Specifier_ error.
14671479
> 1. Let _packageSubpath_ be _undefined_.
14681480
> 1. If the length of _packageSpecifier_ is greater than the length of
14691481
> _packageName_, then
14701482
> 1. Set _packageSubpath_ to _"."_ concatenated with the substring of
14711483
> _packageSpecifier_ from the position at the length of _packageName_.
14721484
> 1. If _packageSubpath_ contains any _"."_ or _".."_ segments or percent
14731485
> encoded strings for _"/"_ or _"\\"_, then
1474-
> 1. Throw an _Invalid Specifier_ error.
1486+
> 1. Throw an _Invalid Module Specifier_ error.
14751487
> 1. Set _selfUrl_ to the result of
14761488
> **SELF_REFERENCE_RESOLVE**(_packageName_, _packageSubpath_, _parentURL_).
14771489
> 1. If _selfUrl_ isn't empty, return _selfUrl_.
@@ -1524,7 +1536,7 @@ _defaultEnv_ is the conditional environment name priority array,
15241536
> 1. Throw a _Module Not Found_ error.
15251537
> 1. If _pjson.exports_ is not **null** or **undefined**, then
15261538
> 1. If _exports_ is an Object with both a key starting with _"."_ and a key
1527-
> not starting with _"."_, throw an "Invalid Package Configuration" error.
1539+
> not starting with _"."_, throw an _Invalid Package Configuration_ error.
15281540
> 1. If _pjson.exports_ is a String or Array, or an Object containing no
15291541
> keys starting with _"."_, then
15301542
> 1. Return **PACKAGE_EXPORTS_TARGET_RESOLVE**(_packageURL_,
@@ -1533,6 +1545,7 @@ _defaultEnv_ is the conditional environment name priority array,
15331545
> 1. Let _mainExport_ be the _"."_ property in _pjson.exports_.
15341546
> 1. Return **PACKAGE_EXPORTS_TARGET_RESOLVE**(_packageURL_,
15351547
> _mainExport_, _""_).
1548+
> 1. Throw a _Package Path Not Exported_ error.
15361549
> 1. If _pjson.main_ is a String, then
15371550
> 1. Let _resolvedMain_ be the URL resolution of _packageURL_, "/", and
15381551
> _pjson.main_.
@@ -1547,7 +1560,7 @@ _defaultEnv_ is the conditional environment name priority array,
15471560
15481561
**PACKAGE_EXPORTS_RESOLVE**(_packageURL_, _packagePath_, _exports_)
15491562
> 1. If _exports_ is an Object with both a key starting with _"."_ and a key not
1550-
> starting with _"."_, throw an "Invalid Package Configuration" error.
1563+
> starting with _"."_, throw an _Invalid Package Configuration_ error.
15511564
> 1. If _exports_ is an Object and all keys of _exports_ start with _"."_, then
15521565
> 1. Set _packagePath_ to _"./"_ concatenated with _packagePath_.
15531566
> 1. If _packagePath_ is a key of _exports_, then
@@ -1563,43 +1576,44 @@ _defaultEnv_ is the conditional environment name priority array,
15631576
> of the length of _directory_.
15641577
> 1. Return **PACKAGE_EXPORTS_TARGET_RESOLVE**(_packageURL_, _target_,
15651578
> _subpath_, _defaultEnv_).
1566-
> 1. Throw a _Module Not Found_ error.
1579+
> 1. Throw a _Package Path Not Exported_ error.
15671580
15681581
**PACKAGE_EXPORTS_TARGET_RESOLVE**(_packageURL_, _target_, _subpath_, _env_)
15691582
1570-
> 1. If _target_ is a String, then
1571-
> 1. If _target_ does not start with _"./"_, throw a _Module Not Found_
1572-
> error.
1573-
> 1. If _subpath_ has non-zero length and _target_ does not end with _"/"_,
1574-
> throw a _Module Not Found_ error.
1575-
> 1. If _target_ or _subpath_ contain any _"node_modules"_ segments including
1576-
> _"node_modules"_ percent-encoding, throw a _Module Not Found_ error.
1583+
> 1.If _target_ is a String, then
1584+
> 1. If _target_ does not start with _"./"_ or contains any _"node_modules"_
1585+
> segments including _"node_modules"_ percent-encoding, throw an
1586+
> _Invalid Package Target_ error.
15771587
> 1. Let _resolvedTarget_ be the URL resolution of the concatenation of
15781588
> _packageURL_ and _target_.
1579-
> 1. If _resolvedTarget_ is contained in _packageURL_, then
1580-
> 1. Let _resolved_ be the URL resolution of the concatenation of
1581-
> _subpath_ and _resolvedTarget_.
1582-
> 1. If _resolved_ is contained in _resolvedTarget_, then
1583-
> 1. Return _resolved_.
1589+
> 1. If _resolvedTarget_ is not contained in _packageURL_, throw an
1590+
> _Invalid Package Target_ error.
1591+
> 1. If _subpath_ has non-zero length and _target_ does not end with _"/"_,
1592+
> throw an _Invalid Module Specifier_ error.
1593+
> 1. Let _resolved_ be the URL resolution of the concatenation of
1594+
> _subpath_ and _resolvedTarget_.
1595+
> 1. If _resolved_ is not contained in _resolvedTarget_, throw an
1596+
> _Invalid Module Specifier_ error.
1597+
> 1. Return _resolved_.
15841598
> 1. Otherwise, if _target_ is a non-null Object, then
15851599
> 1. If _exports_ contains any index property keys, as defined in ECMA-262
15861600
> [6.1.7 Array Index][], throw an _Invalid Package Configuration_ error.
15871601
> 1. For each property _p_ of _target_, in object insertion order as,
15881602
> 1. If _env_ contains an entry for _p_, then
15891603
> 1. Let _targetValue_ be the value of the _p_ property in _target_.
1590-
> 1. Let _resolved_ be the result of **PACKAGE_EXPORTS_TARGET_RESOLVE**
1591-
> (_packageURL_, _targetValue_, _subpath_, _env_).
1592-
> 1. Assert: _resolved_ is a String.
1593-
> 1. Return _resolved_.
1604+
> 1. Return the result of **PACKAGE_EXPORTS_TARGET_RESOLVE**(
1605+
> _packageURL_, _targetValue_, _subpath_, _env_), continuing the
1606+
> loop on any _Package Path Not Exported_ error.
1607+
> 1. Throw a _Package Path Not Exported_ error.
15941608
> 1. Otherwise, if _target_ is an Array, then
1609+
> 1. If _target.length is zero, throw an _Invalid Package Target_ error.
15951610
> 1. For each item _targetValue_ in _target_, do
15961611
> 1. If _targetValue_ is an Array, continue the loop.
1597-
> 1. Let _resolved_ be the result of
1598-
> **PACKAGE_EXPORTS_TARGET_RESOLVE**(_packageURL_, _targetValue_,
1599-
> _subpath_, _env_), continuing the loop on abrupt completion.
1600-
> 1. Assert: _resolved_ is a String.
1601-
> 1. Return _resolved_.
1602-
> 1. Throw a _Module Not Found_ error.
1612+
> 1. Return the result of **PACKAGE_EXPORTS_TARGET_RESOLVE**(_packageURL_,
1613+
> _targetValue_, _subpath_, _env_), continuing the loop on any
1614+
> _Package Path Not Exported_ or _Invalid Package Target_ error.
1615+
> 1. Throw the last fallback resolution error.
1616+
> 1. Otherwise throw an _Invalid Package Target_ error.
16031617
16041618
**ESM_FORMAT**(_url_)
16051619

lib/internal/errors.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,20 @@
1313
const {
1414
ArrayIsArray,
1515
Error,
16+
JSONStringify,
1617
Map,
1718
MathAbs,
1819
NumberIsInteger,
1920
ObjectDefineProperty,
2021
ObjectKeys,
22+
StringPrototypeSlice,
2123
Symbol,
2224
SymbolFor,
2325
WeakMap,
2426
} = primordials;
2527

28+
const sep = process.platform === 'win32' ? '\\' : '/';
29+
2630
const messages = new Map();
2731
const codes = {};
2832

@@ -1065,14 +1069,29 @@ E('ERR_INVALID_FILE_URL_PATH', 'File URL path %s', TypeError);
10651069
E('ERR_INVALID_HANDLE_TYPE', 'This handle type cannot be sent', TypeError);
10661070
E('ERR_INVALID_HTTP_TOKEN', '%s must be a valid HTTP token ["%s"]', TypeError);
10671071
E('ERR_INVALID_IP_ADDRESS', 'Invalid IP address: %s', TypeError);
1072+
E('ERR_INVALID_MODULE_SPECIFIER', (pkgPath, subpath) => {
1073+
assert(subpath !== '.');
1074+
return `Package subpath '${subpath}' is not a valid module request for the ` +
1075+
`"exports" resolution of ${pkgPath}${sep}package.json`;
1076+
}, TypeError);
10681077
E('ERR_INVALID_OPT_VALUE', (name, value) =>
10691078
`The value "${String(value)}" is invalid for option "${name}"`,
10701079
TypeError,
10711080
RangeError);
10721081
E('ERR_INVALID_OPT_VALUE_ENCODING',
10731082
'The value "%s" is invalid for option "encoding"', TypeError);
10741083
E('ERR_INVALID_PACKAGE_CONFIG',
1075-
'Invalid package config for \'%s\', %s', Error);
1084+
`Invalid package config %s${sep}package.json, %s`, Error);
1085+
E('ERR_INVALID_PACKAGE_TARGET', (pkgPath, key, subpath, target) => {
1086+
if (key === '.') {
1087+
return `Invalid "exports" main target ${JSONStringify(target)} defined ` +
1088+
`in the package config ${pkgPath}${sep}package.json`;
1089+
} else {
1090+
return `Invalid "exports" target ${JSONStringify(target)} defined for '${
1091+
StringPrototypeSlice(key, 0, -subpath.length || key.length)}' in the ` +
1092+
`package config ${pkgPath}${sep}package.json`;
1093+
}
1094+
}, Error);
10761095
E('ERR_INVALID_PERFORMANCE_MARK',
10771096
'The "%s" performance mark has not been set', Error);
10781097
E('ERR_INVALID_PROTOCOL',
@@ -1216,6 +1235,14 @@ E('ERR_OUT_OF_RANGE',
12161235
msg += ` It must be ${range}. Received ${received}`;
12171236
return msg;
12181237
}, RangeError);
1238+
E('ERR_PACKAGE_PATH_NOT_EXPORTED', (pkgPath, subpath) => {
1239+
if (subpath === '.') {
1240+
return `No "exports" main resolved in ${pkgPath}${sep}package.json`;
1241+
} else {
1242+
return `Package subpath '${subpath}' is not defined by "exports" in ${
1243+
pkgPath}${sep}package.json`;
1244+
}
1245+
}, Error);
12191246
E('ERR_REQUIRE_ESM',
12201247
(filename, parentPath = null, packageJsonPath = null) => {
12211248
let msg = `Must use import to load ES Module: ${filename}`;

0 commit comments

Comments
 (0)