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 6929649

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

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
@@ -76,6 +76,21 @@ $ node --completion-bash > node_bash_completion
7676
$ source node_bash_completion
7777
```
7878

79+
### `-u`, `--conditions=condition`
80+
<!-- YAML
81+
added: REPLACEME
82+
-->
83+
84+
> Stability: 1 - Experimental
85+
86+
Enable experimental support for custom conditional exports resolution
87+
conditions.
88+
89+
Any number of custom string condition names are permitted.
90+
91+
The default Node.js conditions of `"node"`, `"default"`, `"import"`, and
92+
`"require"` will always apply as defined.
93+
7994
### `--cpu-prof`
8095
<!-- YAML
8196
added: v12.0.0
@@ -1199,6 +1214,7 @@ node --require "./a.js" --require "./b.js"
11991214

12001215
Node.js options that are allowed are:
12011216
<!-- node-options-node start -->
1217+
* `--conditions`, `-u`
12021218
* `--diagnostic-dir`
12031219
* `--disable-proto`
12041220
* `--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
@@ -84,6 +84,7 @@ const manifest = getOptionValue('--experimental-policy') ?
8484
require('internal/process/policy').manifest :
8585
null;
8686
const { compileFunction } = internalBinding('contextify');
87+
const userConditions = getOptionValue('--conditions');
8788

8889
// Whether any user-provided CJS modules had been loaded (executed).
8990
// Used for internal assertions.
@@ -477,8 +478,12 @@ function applyExports(basePath, expansion) {
477478
if (typeof pkgExports === 'object') {
478479
if (ObjectPrototypeHasOwnProperty(pkgExports, mappingKey)) {
479480
const mapping = pkgExports[mappingKey];
480-
return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, '',
481-
mappingKey);
481+
const resolved = resolveExportsTarget(
482+
pathToFileURL(basePath + '/'), mapping, '', mappingKey);
483+
if (resolved === null || resolved === undefined)
484+
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
485+
basePath, mappingKey);
486+
return resolved;
482487
}
483488

484489
let dirMatch = '';
@@ -495,6 +500,9 @@ function applyExports(basePath, expansion) {
495500
const subpath = StringPrototypeSlice(mappingKey, dirMatch.length);
496501
const resolved = resolveExportsTarget(pathToFileURL(basePath + '/'),
497502
mapping, subpath, mappingKey);
503+
if (resolved === null || resolved === undefined)
504+
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
505+
basePath, mappingKey + subpath);
498506
// Extension searching for folder exports only
499507
const rc = stat(resolved);
500508
if (rc === 0) return resolved;
@@ -582,21 +590,29 @@ function resolveExportsTarget(baseUrl, target, subpath, mappingKey) {
582590
throw new ERR_INVALID_MODULE_SPECIFIER(mappingKey + subpath, reason);
583591
} else if (ArrayIsArray(target)) {
584592
if (target.length === 0)
585-
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
586-
baseUrl.pathname, mappingKey + subpath);
593+
return null;
587594
let lastException;
588595
for (const targetValue of target) {
596+
let resolved;
589597
try {
590-
return resolveExportsTarget(baseUrl, targetValue, subpath, mappingKey);
598+
resolved = resolveExportsTarget(baseUrl, targetValue, subpath,
599+
mappingKey);
591600
} catch (e) {
592601
lastException = e;
593-
if (e.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED' &&
594-
e.code !== 'ERR_INVALID_PACKAGE_TARGET')
602+
if (e.code !== 'ERR_INVALID_PACKAGE_TARGET')
595603
throw e;
596604
}
605+
if (resolved === undefined)
606+
continue;
607+
if (resolved === null) {
608+
lastException = null;
609+
continue;
610+
}
611+
return resolved;
597612
}
598613
// Throw last fallback error
599-
assert(lastException !== undefined);
614+
if (lastException === undefined || lastException === null)
615+
return lastException;
600616
throw lastException;
601617
} else if (typeof target === 'object' && target !== null) {
602618
const keys = ObjectKeys(target);
@@ -605,30 +621,17 @@ function resolveExportsTarget(baseUrl, target, subpath, mappingKey) {
605621
'contain numeric property keys.');
606622
}
607623
for (const p of keys) {
608-
switch (p) {
609-
case 'node':
610-
case 'require':
611-
try {
612-
return resolveExportsTarget(baseUrl, target[p], subpath,
613-
mappingKey);
614-
} catch (e) {
615-
if (e.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') throw e;
616-
}
617-
break;
618-
case 'default':
619-
try {
620-
return resolveExportsTarget(baseUrl, target.default, subpath,
621-
mappingKey);
622-
} catch (e) {
623-
if (e.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') throw e;
624-
}
624+
if (cjsConditions.has(p) || p === 'default') {
625+
const resolved = resolveExportsTarget(baseUrl, target[p], subpath,
626+
mappingKey);
627+
if (resolved === undefined)
628+
continue;
629+
return resolved;
625630
}
626631
}
627-
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
628-
baseUrl.pathname, mappingKey + subpath);
632+
return undefined;
629633
} else if (target === null) {
630-
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
631-
baseUrl.pathname, mappingKey + subpath);
634+
return null;
632635
}
633636
throw new ERR_INVALID_PACKAGE_TARGET(baseUrl.pathname, mappingKey, target);
634637
}
@@ -985,8 +988,7 @@ Module._load = function(request, parent, isMain) {
985988
return module.exports;
986989
};
987990

988-
// TODO: Use this set when resolving pkg#exports conditions.
989-
const cjsConditions = new SafeSet(['require', 'node']);
991+
const cjsConditions = new SafeSet(['require', 'node', ...userConditions]);
990992
Module._resolveFilename = function(request, parent, isMain, options) {
991993
if (NativeModule.canBeRequiredByUsers(request)) {
992994
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
@@ -281,6 +281,11 @@ DebugOptionsParser::DebugOptionsParser() {
281281
}
282282

283283
EnvironmentOptionsParser::EnvironmentOptionsParser() {
284+
AddOption("--conditions",
285+
"additional user conditions for conditional exports and imports",
286+
&EnvironmentOptions::conditions,
287+
kAllowedInEnvironment);
288+
AddAlias("-u", "--conditions");
284289
AddOption("--diagnostic-dir",
285290
"set dir for all output files"
286291
" (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.