mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
module: custom --conditions flag option
PR-URL: https://github.com/nodejs/node/pull/34637 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Geoffrey Booth <webmaster@geoffreybooth.com> Reviewed-By: Jan Krems <jan.krems@gmail.com>
This commit is contained in:
1 parent
420da0ccd1
commit
77a515c31a
10 files changed
+93
-38
No files matched your search
@@ -76,6 +76,21 @@ $ node --completion-bash > node_bash_completion
|
||||
$ source node_bash_completion
|
||||
```
|
||||
|
||||
### `-u`, `--conditions=condition`
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
> Stability: 1 - Experimental
|
||||
|
||||
Enable experimental support for custom conditional exports resolution
|
||||
conditions.
|
||||
|
||||
Any number of custom string condition names are permitted.
|
||||
|
||||
The default Node.js conditions of `"node"`, `"default"`, `"import"`, and
|
||||
`"require"` will always apply as defined.
|
||||
|
||||
### `--cpu-prof`
|
||||
<!-- YAML
|
||||
added: v12.0.0
|
||||
@@ -1232,6 +1247,7 @@ node --require "./a.js" --require "./b.js"
|
||||
|
||||
Node.js options that are allowed are:
|
||||
<!-- node-options-node start -->
|
||||
* `--conditions`, `-u`
|
||||
* `--diagnostic-dir`
|
||||
* `--disable-proto`
|
||||
* `--enable-fips`
|
||||
|
||||
@@ -501,6 +501,21 @@ a nested conditional does not have any mapping it will continue checking
|
||||
the remaining conditions of the parent condition. In this way nested
|
||||
conditions behave analogously to nested JavaScript `if` statements.
|
||||
|
||||
#### Resolving user conditions
|
||||
|
||||
When running Node.js, custom user conditions can be added with the
|
||||
`--conditions` or `-u` flag:
|
||||
|
||||
```bash
|
||||
node --conditions=development main.js
|
||||
```
|
||||
|
||||
which would then resolve the `"development"` condition in package imports and
|
||||
exports, while resolving the existing `"node"`, `"default"`, `"import"`, and
|
||||
`"require"` conditions as appropriate.
|
||||
|
||||
Any number of custom conditions can be set with repeat flags.
|
||||
|
||||
#### Self-referencing a package using its name
|
||||
|
||||
Within a package, the values defined in the package’s
|
||||
|
||||
@@ -78,6 +78,10 @@ Aborting instead of exiting causes a core file to be generated for analysis.
|
||||
.It Fl -completion-bash
|
||||
Print source-able bash completion script for Node.js.
|
||||
.
|
||||
.It Fl u , Fl -conditions Ar string
|
||||
Use custom conditional exports conditions
|
||||
.Ar string
|
||||
.
|
||||
.It Fl -cpu-prof
|
||||
Start the V8 CPU profiler on start up, and write the CPU profile to disk
|
||||
before exit. If
|
||||
|
||||
@@ -85,6 +85,7 @@ const manifest = getOptionValue('--experimental-policy') ?
|
||||
require('internal/process/policy').manifest :
|
||||
null;
|
||||
const { compileFunction } = internalBinding('contextify');
|
||||
const userConditions = getOptionValue('--conditions');
|
||||
|
||||
// Whether any user-provided CJS modules had been loaded (executed).
|
||||
// Used for internal assertions.
|
||||
@@ -491,8 +492,12 @@ function applyExports(basePath, expansion) {
|
||||
if (typeof pkgExports === 'object') {
|
||||
if (ObjectPrototypeHasOwnProperty(pkgExports, mappingKey)) {
|
||||
const mapping = pkgExports[mappingKey];
|
||||
return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, '',
|
||||
mappingKey);
|
||||
const resolved = resolveExportsTarget(
|
||||
pathToFileURL(basePath + '/'), mapping, '', mappingKey);
|
||||
if (resolved === null || resolved === undefined)
|
||||
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
|
||||
basePath, mappingKey);
|
||||
return resolved;
|
||||
}
|
||||
|
||||
let dirMatch = '';
|
||||
@@ -509,6 +514,9 @@ function applyExports(basePath, expansion) {
|
||||
const subpath = StringPrototypeSlice(mappingKey, dirMatch.length);
|
||||
const resolved = resolveExportsTarget(pathToFileURL(basePath + '/'),
|
||||
mapping, subpath, mappingKey);
|
||||
if (resolved === null || resolved === undefined)
|
||||
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
|
||||
basePath, mappingKey + subpath);
|
||||
// Extension searching for folder exports only
|
||||
const rc = stat(resolved);
|
||||
if (rc === 0) return resolved;
|
||||
@@ -596,21 +604,29 @@ function resolveExportsTarget(baseUrl, target, subpath, mappingKey) {
|
||||
throw new ERR_INVALID_MODULE_SPECIFIER(mappingKey + subpath, reason);
|
||||
} else if (ArrayIsArray(target)) {
|
||||
if (target.length === 0)
|
||||
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
|
||||
baseUrl.pathname, mappingKey + subpath);
|
||||
return null;
|
||||
let lastException;
|
||||
for (const targetValue of target) {
|
||||
let resolved;
|
||||
try {
|
||||
return resolveExportsTarget(baseUrl, targetValue, subpath, mappingKey);
|
||||
resolved = resolveExportsTarget(baseUrl, targetValue, subpath,
|
||||
mappingKey);
|
||||
} catch (e) {
|
||||
lastException = e;
|
||||
if (e.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED' &&
|
||||
e.code !== 'ERR_INVALID_PACKAGE_TARGET')
|
||||
if (e.code !== 'ERR_INVALID_PACKAGE_TARGET')
|
||||
throw e;
|
||||
}
|
||||
if (resolved === undefined)
|
||||
continue;
|
||||
if (resolved === null) {
|
||||
lastException = null;
|
||||
continue;
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
// Throw last fallback error
|
||||
assert(lastException !== undefined);
|
||||
if (lastException === undefined || lastException === null)
|
||||
return lastException;
|
||||
throw lastException;
|
||||
} else if (typeof target === 'object' && target !== null) {
|
||||
const keys = ObjectKeys(target);
|
||||
@@ -619,30 +635,17 @@ function resolveExportsTarget(baseUrl, target, subpath, mappingKey) {
|
||||
'contain numeric property keys.');
|
||||
}
|
||||
for (const p of keys) {
|
||||
switch (p) {
|
||||
case 'node':
|
||||
case 'require':
|
||||
try {
|
||||
return resolveExportsTarget(baseUrl, target[p], subpath,
|
||||
mappingKey);
|
||||
} catch (e) {
|
||||
if (e.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') throw e;
|
||||
}
|
||||
break;
|
||||
case 'default':
|
||||
try {
|
||||
return resolveExportsTarget(baseUrl, target.default, subpath,
|
||||
mappingKey);
|
||||
} catch (e) {
|
||||
if (e.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') throw e;
|
||||
}
|
||||
if (cjsConditions.has(p) || p === 'default') {
|
||||
const resolved = resolveExportsTarget(baseUrl, target[p], subpath,
|
||||
mappingKey);
|
||||
if (resolved === undefined)
|
||||
continue;
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
|
||||
baseUrl.pathname, mappingKey + subpath);
|
||||
return undefined;
|
||||
} else if (target === null) {
|
||||
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
|
||||
baseUrl.pathname, mappingKey + subpath);
|
||||
return null;
|
||||
}
|
||||
throw new ERR_INVALID_PACKAGE_TARGET(baseUrl.pathname, mappingKey, target);
|
||||
}
|
||||
@@ -999,8 +1002,7 @@ Module._load = function(request, parent, isMain) {
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
// TODO: Use this set when resolving pkg#exports conditions.
|
||||
const cjsConditions = new SafeSet(['require', 'node']);
|
||||
const cjsConditions = new SafeSet(['require', 'node', ...userConditions]);
|
||||
Module._resolveFilename = function(request, parent, isMain, options) {
|
||||
if (NativeModule.canBeRequiredByUsers(request)) {
|
||||
return request;
|
||||
|
||||
@@ -51,7 +51,8 @@ const {
|
||||
const { Module: CJSModule } = require('internal/modules/cjs/loader');
|
||||
|
||||
const packageJsonReader = require('internal/modules/package_json_reader');
|
||||
const DEFAULT_CONDITIONS = ObjectFreeze(['node', 'import']);
|
||||
const userConditions = getOptionValue('--conditions');
|
||||
const DEFAULT_CONDITIONS = ObjectFreeze(['node', 'import', ...userConditions]);
|
||||
const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS);
|
||||
|
||||
|
||||
@@ -359,12 +360,9 @@ function isArrayIndex(key) {
|
||||
function resolvePackageTarget(
|
||||
packageJSONUrl, target, subpath, packageSubpath, base, internal, conditions) {
|
||||
if (typeof target === 'string') {
|
||||
const resolved = resolvePackageTargetString(
|
||||
return finalizeResolution(resolvePackageTargetString(
|
||||
target, subpath, packageSubpath, packageJSONUrl, base, internal,
|
||||
conditions);
|
||||
if (resolved === null)
|
||||
return null;
|
||||
return finalizeResolution(resolved, base);
|
||||
conditions), base);
|
||||
} else if (ArrayIsArray(target)) {
|
||||
if (target.length === 0)
|
||||
return null;
|
||||
|
||||
@@ -281,6 +281,11 @@ DebugOptionsParser::DebugOptionsParser() {
|
||||
}
|
||||
|
||||
EnvironmentOptionsParser::EnvironmentOptionsParser() {
|
||||
AddOption("--conditions",
|
||||
"additional user conditions for conditional exports and imports",
|
||||
&EnvironmentOptions::conditions,
|
||||
kAllowedInEnvironment);
|
||||
AddAlias("-u", "--conditions");
|
||||
AddOption("--diagnostic-dir",
|
||||
"set dir for all output files"
|
||||
" (default: current working directory)",
|
||||
|
||||
@@ -100,6 +100,7 @@ class DebugOptions : public Options {
|
||||
class EnvironmentOptions : public Options {
|
||||
public:
|
||||
bool abort_on_uncaught_exception = false;
|
||||
std::vector<std::string> conditions;
|
||||
bool enable_source_maps = false;
|
||||
bool experimental_json_modules = false;
|
||||
bool experimental_modules = false;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Flags: --conditions=custom-condition -u another
|
||||
import { mustCall } from '../common/index.mjs';
|
||||
import { strictEqual } from 'assert';
|
||||
import { requireFixture, importFixture } from '../fixtures/pkgexports.mjs';
|
||||
[requireFixture, importFixture].forEach((loadFixture) => {
|
||||
loadFixture('pkgexports/condition')
|
||||
.then(mustCall((actual) => {
|
||||
strictEqual(actual.default, 'from custom condition');
|
||||
}));
|
||||
});
|
||||
+1
@@ -0,0 +1 @@
|
||||
module.exports = 'from custom condition';
|
||||
+4
-1
@@ -21,7 +21,10 @@
|
||||
"./nofallback2": [null, {}, "builtin:x"],
|
||||
"./nodemodules": "./node_modules/internalpkg/x.js",
|
||||
"./condition": [{
|
||||
"custom-condition": "./custom-condition.mjs",
|
||||
"custom-condition": {
|
||||
"import": "./custom-condition.mjs",
|
||||
"require": "./custom-condition.js"
|
||||
},
|
||||
"import": "///overridden",
|
||||
"require": {
|
||||
"require": {
|
||||
|
||||
Reference in new issue
Block a user