Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d9857fd

Browse filesBrowse files
guybedfordcodebytere
authored andcommitted
module: custom --conditions flag option
PR-URL: #34637 Backport-PR-URL: #35385 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Geoffrey Booth <webmaster@geoffreybooth.com> Reviewed-By: Jan Krems <jan.krems@gmail.com>
1 parent 3ad146d commit d9857fd
Copy full SHA for d9857fd

File tree

Expand file treeCollapse file tree

10 files changed

+93
-38
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

10 files changed

+93
-38
lines changed
Open diff view settings
Collapse file

‎doc/api/cli.md‎

Copy file name to clipboardExpand all lines: doc/api/cli.md
+16Lines changed: 16 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,21 @@ $ node --completion-bash > node_bash_completion
8181
$ source node_bash_completion
8282
```
8383

84+
### `-u`, `--conditions=condition`
85+
<!-- YAML
86+
added: REPLACEME
87+
-->
88+
89+
> Stability: 1 - Experimental
90+
91+
Enable experimental support for custom conditional exports resolution
92+
conditions.
93+
94+
Any number of custom string condition names are permitted.
95+
96+
The default Node.js conditions of `"node"`, `"default"`, `"import"`, and
97+
`"require"` will always apply as defined.
98+
8499
### `--cpu-prof`
85100
<!-- YAML
86101
added: v12.0.0
@@ -1166,6 +1181,7 @@ node --require "./a.js" --require "./b.js"
11661181

11671182
Node.js options that are allowed are:
11681183
<!-- node-options-node start -->
1184+
* `--conditions`, `-u`
11691185
* `--diagnostic-dir`
11701186
* `--disable-proto`
11711187
* `--enable-fips`
Collapse file

‎doc/api/esm.md‎

Copy file name to clipboardExpand all lines: doc/api/esm.md
+15Lines changed: 15 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,21 @@ a nested conditional does not have any mapping it will continue checking
501501
the remaining conditions of the parent condition. In this way nested
502502
conditions behave analogously to nested JavaScript `if` statements.
503503

504+
#### Resolving user conditions
505+
506+
When running Node.js, custom user conditions can be added with the
507+
`--conditions` or `-u` flag:
508+
509+
```bash
510+
node --conditions=development main.js
511+
```
512+
513+
which would then resolve the `"development"` condition in package imports and
514+
exports, while resolving the existing `"node"`, `"default"`, `"import"`, and
515+
`"require"` conditions as appropriate.
516+
517+
Any number of custom conditions can be set with repeat flags.
518+
504519
#### Self-referencing a package using its name
505520

506521
Within a package, the values defined in the package’s
Collapse file

‎doc/node.1‎

Copy file name to clipboardExpand all lines: doc/node.1
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ Aborting instead of exiting causes a core file to be generated for analysis.
7878
.It Fl -completion-bash
7979
Print source-able bash completion script for Node.js.
8080
.
81+
.It Fl u , Fl -conditions Ar string
82+
Use custom conditional exports conditions
83+
.Ar string
84+
.
8185
.It Fl -cpu-prof
8286
Start the V8 CPU profiler on start up, and write the CPU profile to disk
8387
before exit. If
Collapse file

‎lib/internal/modules/cjs/loader.js‎

Copy file name to clipboardExpand all lines: lib/internal/modules/cjs/loader.js
+33-31Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ const manifest = getOptionValue('--experimental-policy') ?
8080
require('internal/process/policy').manifest :
8181
null;
8282
const { compileFunction } = internalBinding('contextify');
83+
const userConditions = getOptionValue('--conditions');
8384

8485
// Whether any user-provided CJS modules had been loaded (executed).
8586
// Used for internal assertions.
@@ -472,8 +473,12 @@ function applyExports(basePath, expansion) {
472473
if (typeof pkgExports === 'object') {
473474
if (ObjectPrototypeHasOwnProperty(pkgExports, mappingKey)) {
474475
const mapping = pkgExports[mappingKey];
475-
return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, '',
476-
mappingKey);
476+
const resolved = resolveExportsTarget(
477+
pathToFileURL(basePath + '/'), mapping, '', mappingKey);
478+
if (resolved === null || resolved === undefined)
479+
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
480+
basePath, mappingKey);
481+
return resolved;
477482
}
478483

479484
let dirMatch = '';
@@ -490,6 +495,9 @@ function applyExports(basePath, expansion) {
490495
const subpath = StringPrototypeSlice(mappingKey, dirMatch.length);
491496
const resolved = resolveExportsTarget(pathToFileURL(basePath + '/'),
492497
mapping, subpath, mappingKey);
498+
if (resolved === null || resolved === undefined)
499+
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
500+
basePath, mappingKey + subpath);
493501
// Extension searching for folder exports only
494502
const rc = stat(resolved);
495503
if (rc === 0) return resolved;
@@ -577,21 +585,29 @@ function resolveExportsTarget(baseUrl, target, subpath, mappingKey) {
577585
throw new ERR_INVALID_MODULE_SPECIFIER(mappingKey + subpath, reason);
578586
} else if (ArrayIsArray(target)) {
579587
if (target.length === 0)
580-
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
581-
baseUrl.pathname, mappingKey + subpath);
588+
return null;
582589
let lastException;
583590
for (const targetValue of target) {
591+
let resolved;
584592
try {
585-
return resolveExportsTarget(baseUrl, targetValue, subpath, mappingKey);
593+
resolved = resolveExportsTarget(baseUrl, targetValue, subpath,
594+
mappingKey);
586595
} catch (e) {
587596
lastException = e;
588-
if (e.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED' &&
589-
e.code !== 'ERR_INVALID_PACKAGE_TARGET')
597+
if (e.code !== 'ERR_INVALID_PACKAGE_TARGET')
590598
throw e;
591599
}
600+
if (resolved === undefined)
601+
continue;
602+
if (resolved === null) {
603+
lastException = null;
604+
continue;
605+
}
606+
return resolved;
592607
}
593608
// Throw last fallback error
594-
assert(lastException !== undefined);
609+
if (lastException === undefined || lastException === null)
610+
return lastException;
595611
throw lastException;
596612
} else if (typeof target === 'object' && target !== null) {
597613
const keys = ObjectKeys(target);
@@ -600,30 +616,17 @@ function resolveExportsTarget(baseUrl, target, subpath, mappingKey) {
600616
'contain numeric property keys.');
601617
}
602618
for (const p of keys) {
603-
switch (p) {
604-
case 'node':
605-
case 'require':
606-
try {
607-
return resolveExportsTarget(baseUrl, target[p], subpath,
608-
mappingKey);
609-
} catch (e) {
610-
if (e.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') throw e;
611-
}
612-
break;
613-
case 'default':
614-
try {
615-
return resolveExportsTarget(baseUrl, target.default, subpath,
616-
mappingKey);
617-
} catch (e) {
618-
if (e.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') throw e;
619-
}
619+
if (cjsConditions.has(p) || p === 'default') {
620+
const resolved = resolveExportsTarget(baseUrl, target[p], subpath,
621+
mappingKey);
622+
if (resolved === undefined)
623+
continue;
624+
return resolved;
620625
}
621626
}
622-
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
623-
baseUrl.pathname, mappingKey + subpath);
627+
return undefined;
624628
} else if (target === null) {
625-
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
626-
baseUrl.pathname, mappingKey + subpath);
629+
return null;
627630
}
628631
throw new ERR_INVALID_PACKAGE_TARGET(baseUrl.pathname, mappingKey, target);
629632
}
@@ -923,8 +926,7 @@ Module._load = function(request, parent, isMain) {
923926
return module.exports;
924927
};
925928

926-
// TODO: Use this set when resolving pkg#exports conditions.
927-
const cjsConditions = new SafeSet(['require', 'node']);
929+
const cjsConditions = new SafeSet(['require', 'node', ...userConditions]);
928930
Module._resolveFilename = function(request, parent, isMain, options) {
929931
if (NativeModule.canBeRequiredByUsers(request)) {
930932
return request;
Collapse file

‎lib/internal/modules/esm/resolve.js‎

Copy file name to clipboardExpand all lines: lib/internal/modules/esm/resolve.js
+4-6Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ const {
5151
const { Module: CJSModule } = require('internal/modules/cjs/loader');
5252

5353
const packageJsonReader = require('internal/modules/package_json_reader');
54-
const DEFAULT_CONDITIONS = ObjectFreeze(['node', 'import']);
54+
const userConditions = getOptionValue('--conditions');
55+
const DEFAULT_CONDITIONS = ObjectFreeze(['node', 'import', ...userConditions]);
5556
const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS);
5657

5758

@@ -359,12 +360,9 @@ function isArrayIndex(key) {
359360
function resolvePackageTarget(
360361
packageJSONUrl, target, subpath, packageSubpath, base, internal, conditions) {
361362
if (typeof target === 'string') {
362-
const resolved = resolvePackageTargetString(
363+
return finalizeResolution(resolvePackageTargetString(
363364
target, subpath, packageSubpath, packageJSONUrl, base, internal,
364-
conditions);
365-
if (resolved === null)
366-
return null;
367-
return finalizeResolution(resolved, base);
365+
conditions), base);
368366
} else if (ArrayIsArray(target)) {
369367
if (target.length === 0)
370368
return null;
Collapse file

‎src/node_options.cc‎

Copy file name to clipboardExpand all lines: src/node_options.cc
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,11 @@ DebugOptionsParser::DebugOptionsParser() {
283283
}
284284

285285
EnvironmentOptionsParser::EnvironmentOptionsParser() {
286+
AddOption("--conditions",
287+
"additional user conditions for conditional exports and imports",
288+
&EnvironmentOptions::conditions,
289+
kAllowedInEnvironment);
290+
AddAlias("-u", "--conditions");
286291
AddOption("--diagnostic-dir",
287292
"set dir for all output files"
288293
" (default: current working directory)",
Collapse file

‎src/node_options.h‎

Copy file name to clipboardExpand all lines: src/node_options.h
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class DebugOptions : public Options {
100100
class EnvironmentOptions : public Options {
101101
public:
102102
bool abort_on_uncaught_exception = false;
103+
std::vector<std::string> conditions;
103104
bool enable_source_maps = false;
104105
bool experimental_json_modules = false;
105106
bool experimental_modules = false;
Collapse file
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Flags: --conditions=custom-condition -u another
2+
import { mustCall } from '../common/index.mjs';
3+
import { strictEqual } from 'assert';
4+
import { requireFixture, importFixture } from '../fixtures/pkgexports.mjs';
5+
[requireFixture, importFixture].forEach((loadFixture) => {
6+
loadFixture('pkgexports/condition')
7+
.then(mustCall((actual) => {
8+
strictEqual(actual.default, 'from custom condition');
9+
}));
10+
});
Collapse file

‎test/fixtures/node_modules/pkgexports/custom-condition.js‎

Copy file name to clipboardExpand all lines: test/fixtures/node_modules/pkgexports/custom-condition.js
+1Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Collapse file

‎test/fixtures/node_modules/pkgexports/package.json‎

Copy file name to clipboardExpand all lines: test/fixtures/node_modules/pkgexports/package.json
+4-1Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.