Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

module: subpath folder mappings EOL #40121

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2706,6 +2706,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 @@ -2719,9 +2722,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 @@ -2964,6 +2967,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
Original file line number Diff line number Diff line change
Expand Up @@ -1066,9 +1066,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 @@ -1101,7 +1100,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 @@ -1119,11 +1118,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 @@ -1140,13 +1138,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 @@ -1160,53 +1159,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 @@ -1216,20 +1207,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
Original file line number Diff line number Diff line change
Expand Up @@ -420,50 +420,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 @@ -1268,7 +1224,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
Original file line number Diff line number Diff line change
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
Loading