Skip to content

Commit

Permalink
module: subpath folder mappings EOL
Browse files Browse the repository at this point in the history
PR-URL: #40121
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
guybedford committed Sep 22, 2021
1 parent 0991dfc commit 36e2ffe
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 237 deletions.
10 changes: 6 additions & 4 deletions doc/api/deprecations.md
Expand Up @@ -2707,6 +2707,9 @@ Use `fs.rm(path, { recursive: true, force: true })`,
### DEP0148: Folder mappings in `"exports"` (trailing `"/"`)
<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/40121
description: End-of-Life.
- version: v16.0.0
pr-url: https://github.com/nodejs/node/pull/37215
description: Runtime deprecation.
Expand All @@ -2720,9 +2723,9 @@ changes:

Type: Runtime

Using a trailing `"/"` to define
[subpath folder mappings][] in the [subpath exports][] or
[subpath imports][] fields is deprecated. Use [subpath patterns][] instead.
Using a trailing `"/"` to define subpath folder mappings in the
[subpath exports][] or [subpath imports][] fields is deprecated. Use
[subpath patterns][] instead.

### DEP0149: `http.IncomingMessage#connection`
<!-- YAML
Expand Down Expand Up @@ -2965,6 +2968,5 @@ for package `"exports"` and `"imports"` pattern resolutions.
[legacy `urlObject`]: url.md#legacy-urlobject
[static methods of `crypto.Certificate()`]: crypto.md#class-certificate
[subpath exports]: packages.md#subpath-exports
[subpath folder mappings]: packages.md#subpath-folder-mappings
[subpath imports]: packages.md#subpath-imports
[subpath patterns]: packages.md#subpath-patterns
82 changes: 31 additions & 51 deletions doc/api/esm.md
Expand Up @@ -1068,9 +1068,8 @@ The resolver can throw the following errors:
> 1. Set _resolved_ to the URL resolution of _specifier_ relative to
> _parentURL_.
> 1. Otherwise, if _specifier_ starts with _"#"_, then
> 1. Set _resolved_ to the destructured value of the result of
> **PACKAGE_IMPORTS_RESOLVE**(_specifier_, _parentURL_,
> _defaultConditions_).
> 1. Set _resolved_ to the result of **PACKAGE_IMPORTS_RESOLVE**(_specifier_,
> _parentURL_, _defaultConditions_).
> 1. Otherwise,
> 1. Note: _specifier_ is now a bare specifier.
> 1. Set _resolved_ the result of
Expand Down Expand Up @@ -1103,7 +1102,7 @@ The resolver can throw the following errors:
> 1. If _packageName_ starts with _"."_ or contains _"\\"_ or _"%"_, then
> 1. Throw an _Invalid Module Specifier_ error.
> 1. Let _packageSubpath_ be _"."_ concatenated with the substring of
> _packageSpecifier_ from the position at the length of _packageName_.
> _packageSpecifier_ from the position at the length of _packageName_.
> 1. Let _selfUrl_ be the result of
> **PACKAGE_SELF_RESOLVE**(_packageName_, _packageSubpath_, _parentURL_).
> 1. If _selfUrl_ is not **undefined**, return _selfUrl_.
Expand All @@ -1121,11 +1120,10 @@ The resolver can throw the following errors:
> 1. If _pjson_ is not **null** and _pjson_._exports_ is not **null** or
> **undefined**, then
> 1. Let _exports_ be _pjson.exports_.
> 1. Return the _resolved_ destructured value of the result of
> **PACKAGE_EXPORTS_RESOLVE**(_packageURL_, _packageSubpath_,
> _pjson.exports_, _defaultConditions_).
> 1. Return the result of **PACKAGE_EXPORTS_RESOLVE**(_packageURL_,
> _packageSubpath_, _pjson.exports_, _defaultConditions_).
> 1. Otherwise, if _packageSubpath_ is equal to _"."_, then
> 1. Return the result applying the legacy **LOAD_AS_DIRECTORY**
> 1. Return the result of applying the legacy **LOAD_AS_DIRECTORY**
> CommonJS resolver to _packageURL_, throwing a _Module Not Found_
> error for no resolution.
> 1. Otherwise,
Expand All @@ -1142,13 +1140,14 @@ The resolver can throw the following errors:
> **undefined**, then
> 1. Return **undefined**.
> 1. If _pjson.name_ is equal to _packageName_, then
> 1. Return the _resolved_ destructured value of the result of
> **PACKAGE_EXPORTS_RESOLVE**(_packageURL_, _subpath_, _pjson.exports_,
> _defaultConditions_).
> 1. Return the result of **PACKAGE_EXPORTS_RESOLVE**(_packageURL_,
> _subpath_, _pjson.exports_, _defaultConditions_).
> 1. Otherwise, return **undefined**.

**PACKAGE_EXPORTS_RESOLVE**(_packageURL_, _subpath_, _exports_, _conditions_)

> 1. If _subpath_ ends in _"/"_, then
> 1. Throw an _Invalid Module Specifier_ error.
> 1. If _exports_ is an Object with both a key starting with _"."_ and a key not
> starting with _"."_, throw an _Invalid Package Configuration_ error.
> 1. If _subpath_ is equal to _"."_, then
Expand All @@ -1162,53 +1161,45 @@ The resolver can throw the following errors:
> 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**(
> _packageURL_, _mainExport_, _""_, **false**, **false**,
> _conditions_).
> 1. If _resolved_ is not **null** or **undefined**, then
> 1. Return _resolved_.
> 1. If _resolved_ is not **null** or **undefined**, return _resolved_.
> 1. Otherwise, if _exports_ is an Object and all keys of _exports_ start with
> _"."_, then
> 1. Let _matchKey_ be the string _"./"_ concatenated with _subpath_.
> 1. Let _resolvedMatch_ be result of **PACKAGE_IMPORTS_EXPORTS_RESOLVE**(
> 1. Let _resolved_ be the result of **PACKAGE_IMPORTS_EXPORTS_RESOLVE**(
> _matchKey_, _exports_, _packageURL_, **false**, _conditions_).
> 1. If _resolvedMatch_._resolve_ is not **null** or **undefined**, then
> 1. Return _resolvedMatch_.
> 1. If _resolved_ is not **null** or **undefined**, return _resolved_.
> 1. Throw a _Package Path Not Exported_ error.

**PACKAGE_IMPORTS_RESOLVE**(_specifier_, _parentURL_, _conditions_)

> 1. Assert: _specifier_ begins with _"#"_.
> 1. If _specifier_ is exactly equal to _"#"_ or starts with _"#/"_, then
> 1. If _specifier_ is exactly equal to _"#"_, starts with _"#/"_, or ends in
> _"/"_, then
> 1. Throw an _Invalid Module Specifier_ error.
> 1. Let _packageURL_ be the result of **READ_PACKAGE_SCOPE**(_parentURL_).
> 1. If _packageURL_ is not **null**, then
> 1. Let _pjson_ be the result of **READ_PACKAGE_JSON**(_packageURL_).
> 1. If _pjson.imports_ is a non-null Object, then
> 1. Let _resolvedMatch_ be the result of
> **PACKAGE_IMPORTS_EXPORTS_RESOLVE**(_specifier_, _pjson.imports_,
> _packageURL_, **true**, _conditions_).
> 1. If _resolvedMatch_._resolve_ is not **null** or **undefined**, then
> 1. Return _resolvedMatch_.
> 1. Let _resolved_ be the result of **PACKAGE_IMPORTS_EXPORTS_RESOLVE**(
> _specifier_, _pjson.imports_, _packageURL_, **true**, _conditions_).
> 1. If _resolved_ is not **null** or **undefined**, return _resolved_.
> 1. Throw a _Package Import Not Defined_ error.

**PACKAGE_IMPORTS_EXPORTS_RESOLVE**(_matchKey_, _matchObj_, _packageURL_,
_isImports_, _conditions_)

> 1. If _matchKey_ is a key of _matchObj_ and does not end in _"/"_ or contain
> _"*"_, then
> 1. Assert: _matchKey_ does not end in _"/"_.
> 1. If _matchKey_ is a key of _matchObj_ and does not contain _"*"_, then
> 1. Let _target_ be the value of _matchObj_\[_matchKey_\].
> 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**(
> _packageURL_, _target_, _""_, **false**, _isImports_, _conditions_).
> 1. Return the object _{ resolved, exact: **true** }_.
> 1. Let _expansionKeys_ be the list of keys of _matchObj_ either ending in
> _"/"_ or containing only a single _"*"_, sorted by the sorting function
> **PATTERN_KEY_COMPARE** which orders in descending order of specificity.
> 1. Return the result of **PACKAGE_TARGET_RESOLVE**(_packageURL_, _target_,
> _""_, **false**, _isImports_, _conditions_).
> 1. Let _expansionKeys_ be the list of keys of _matchObj_ containing only a
> single _"*"_, sorted by the sorting function **PATTERN_KEY_COMPARE** which
> orders in descending order of specificity.
> 1. For each key _expansionKey_ in _expansionKeys_, do
> 1. Let _patternBase_ be **null**.
> 1. If _expansionKey_ contains _"*"_, set _patternBase_ to the substring of
> _expansionKey_ up to but excluding the first _"*"_ character.
> 1. If _patternBase_ is not **null** and _matchKey_ starts with but is not
> equal to _patternBase_, then
> 1. If _matchKey_ ends with _"/"_, throw an _Invalid Module Specifier_
> error.
> 1. Let _patternBase_ be the substring of _expansionKey_ up to but excluding
> the first _"*"_ character.
> 1. If _matchKey_ starts with but is not equal to _patternBase_, then
> 1. Let _patternTrailer_ be the substring of _expansionKey_ from the
> index after the first _"*"_ character.
> 1. If _patternTrailer_ has zero length, or if _matchKey_ ends with
Expand All @@ -1218,20 +1209,9 @@ _isImports_, _conditions_)
> 1. Let _subpath_ be the substring of _matchKey_ starting at the
> index of the length of _patternBase_ up to the length of
> _matchKey_ minus the length of _patternTrailer_.
> 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**(
> _packageURL_, _target_, _subpath_, **true**, _isImports_,
> _conditions_).
> 1. Return the object _{ resolved, exact: **true** }_.
> 1. Otherwise if _patternBase_ is **null** and _matchKey_ starts with
> _expansionKey_, then
> 1. Let _target_ be the value of _matchObj_\[_expansionKey_\].
> 1. Let _subpath_ be the substring of _matchKey_ starting at the
> index of the length of _expansionKey_.
> 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**(
> _packageURL_, _target_, _subpath_, **false**, _isImports_,
> _conditions_).
> 1. Return the object _{ resolved, exact: **false** }_.
> 1. Return the object _{ resolved: **null**, exact: **true** }_.
> 1. Return the result of **PACKAGE_TARGET_RESOLVE**(_packageURL_,
> _target_, _subpath_, **true**, _isImports_, _conditions_).
> 1. Return **null**.

**PATTERN_KEY_COMPARE**(_keyA_, _keyB_)

Expand Down
45 changes: 0 additions & 45 deletions doc/api/packages.md
Expand Up @@ -422,50 +422,6 @@ import featureX from 'es-module-package/features/x';
// Loads ./node_modules/es-module-package/src/features/x.js
```

### Subpath folder mappings
<!-- YAML
changes:
- version: v16.0.0
pr-url: https://github.com/nodejs/node/pull/37215
description: Runtime deprecation.
- version: v15.1.0
pr-url: https://github.com/nodejs/node/pull/35747
description: Runtime deprecation for self-referencing imports.
- version:
- v14.13.0
- v12.20.0
pr-url: https://github.com/nodejs/node/pull/34718
description: Documentation-only deprecation.
-->

> Stability: 0 - Deprecated: Use subpath patterns instead.
Before subpath patterns were supported, a trailing `"/"` suffix was used to
support folder mappings:

```json
{
"exports": {
"./features/": "./features/"
}
}
```

_This feature will be removed in a future release._

Instead, use direct [subpath patterns][]:

```json
{
"exports": {
"./features/*": "./features/*.js"
}
}
```

The benefit of patterns over folder exports is that packages can always be
imported by consumers without subpath file extensions being necessary.

### Exports sugar
<!-- YAML
added: v12.11.0
Expand Down Expand Up @@ -1270,7 +1226,6 @@ This field defines [subpath imports][] for the current package.
[self-reference]: #self-referencing-a-package-using-its-name
[subpath exports]: #subpath-exports
[subpath imports]: #subpath-imports
[subpath patterns]: #subpath-patterns
[supported package managers]: corepack.md#supported-package-managers
[the dual CommonJS/ES module packages section]: #dual-commonjses-module-packages
[the full specifier path]: esm.md#mandatory-file-extensions
16 changes: 5 additions & 11 deletions lib/internal/modules/cjs/loader.js
Expand Up @@ -457,7 +457,7 @@ function trySelf(parentPath, request) {
try {
return finalizeEsmResolution(packageExportsResolve(
pathToFileURL(pkgPath + '/package.json'), expansion, pkg,
pathToFileURL(parentPath), cjsConditions), request, parentPath, pkgPath);
pathToFileURL(parentPath), cjsConditions), parentPath, pkgPath);
} catch (e) {
if (e.code === 'ERR_MODULE_NOT_FOUND')
throw createEsmNotFoundErr(request, pkgPath + '/package.json');
Expand All @@ -481,7 +481,7 @@ function resolveExports(nmPath, request) {
try {
return finalizeEsmResolution(packageExportsResolve(
pathToFileURL(pkgPath + '/package.json'), '.' + expansion, pkg, null,
cjsConditions), request, null, pkgPath);
cjsConditions), null, pkgPath);
} catch (e) {
if (e.code === 'ERR_MODULE_NOT_FOUND')
throw createEsmNotFoundErr(request, pkgPath + '/package.json');
Expand Down Expand Up @@ -894,7 +894,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
try {
return finalizeEsmResolution(
packageImportsResolve(request, pathToFileURL(parent.filename),
cjsConditions), request, parent.filename,
cjsConditions), parent.filename,
pkg.path);
} catch (e) {
if (e.code === 'ERR_MODULE_NOT_FOUND')
Expand Down Expand Up @@ -936,18 +936,12 @@ Module._resolveFilename = function(request, parent, isMain, options) {
throw err;
};

function finalizeEsmResolution(match, request, parentPath, pkgPath) {
const { resolved, exact } = match;
function finalizeEsmResolution(resolved, parentPath, pkgPath) {
if (RegExpPrototypeTest(encodedSepRegEx, resolved))
throw new ERR_INVALID_MODULE_SPECIFIER(
resolved, 'must not include encoded "/" or "\\" characters', parentPath);
const filename = fileURLToPath(resolved);
let actual = tryFile(filename);
if (!exact && !actual) {
const exts = ObjectKeys(Module._extensions);
actual = tryExtensions(filename, exts, false) ||
tryPackage(filename, exts, false, request);
}
const actual = tryFile(filename);
if (actual)
return actual;
const err = createEsmNotFoundErr(filename,
Expand Down

0 comments on commit 36e2ffe

Please sign in to comment.