Skip to content
Open
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
13 changes: 10 additions & 3 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,7 @@ added:

Enable experimental import support for `.node` addons.

### `--experimental-config-file=config`
### `--experimental-config-file=path`, `--experimental-config-file`

<!-- YAML
added:
Expand All @@ -1056,6 +1056,12 @@ added:
> Stability: 1.0 - Early development

If present, Node.js will look for a configuration file at the specified path.
If the path is not specified, Node.js will look for a `node.config.json` file
in the current working directory.
To specify a custom path, use the `--experimental-config-file=path` form.
The space-separated `--experimental-config-file path` form is not supported.
The alias `--experimental-default-config-file` is equivalent to
`--experimental-config-file` without an argument.
Node.js will read the configuration file and apply the settings. The
configuration file should be a JSON file with the following structure. `vX.Y.Z`
in the `$schema` must be replaced with the version of Node.js you are using.
Expand Down Expand Up @@ -1162,9 +1168,10 @@ added:

> Stability: 1.0 - Early development

If the `--experimental-default-config-file` flag is present, Node.js will look for a
This flag is an alias for `--experimental-config-file` without an argument.
If present, Node.js will look for a
`node.config.json` file in the current working directory and load it as a
as configuration file.
configuration file.

### `--experimental-eventsource`

Expand Down
2 changes: 1 addition & 1 deletion doc/api/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -4531,7 +4531,7 @@ test.describe('my suite', (suite) => {
[`suite()`]: #suitename-options-fn
[`test()`]: #testname-options-fn
[code coverage]: #collecting-code-coverage
[configuration files]: cli.md#--experimental-config-fileconfig
[configuration files]: cli.md#--experimental-config-filepath---experimental-config-file
[describe options]: #describename-options-fn
[it options]: #testname-options-fn
[module customization hooks]: module.md#customization-hooks
Expand Down
11 changes: 8 additions & 3 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -623,8 +623,12 @@ It is possible to run code containing inline types unless the
.It Fl -experimental-addon-modules
Enable experimental import support for \fB.node\fR addons.
.
.It Fl -experimental-config-file Ns = Ns Ar config
.It Fl -experimental-config-file= Ns Ar config , Fl -experimental-config-file , Fl -experimental-default-config-file
If present, Node.js will look for a configuration file at the specified path.
If the path is not specified, Node.js will look for a \fBnode.config.json\fR file
in the current working directory.
To specify a custom path, use the \fB--experimental-config-file=\fR\fBpath\fR form.
The space-separated \fB--experimental-config-file path\fR form is not supported.
Node.js will read the configuration file and apply the settings. The
configuration file should be a JSON file with the following structure. \fBvX.Y.Z\fR
in the \fB$schema\fR must be replaced with the version of Node.js you are using.
Expand Down Expand Up @@ -710,9 +714,10 @@ Node.js will not sanitize or perform validation on the user-provided configurati
so \fBNEVER\fR use untrusted configuration files.
.
.It Fl -experimental-default-config-file
If the \fB--experimental-default-config-file\fR flag is present, Node.js will look for a
This flag is an alias for \fB--experimental-config-file\fR without an argument.
If present, Node.js will look for a
\fBnode.config.json\fR file in the current working directory and load it as a
as configuration file.
configuration file.
.
.It Fl -experimental-eventsource
Enable exposition of EventSource Web API on the global scope.
Expand Down
8 changes: 2 additions & 6 deletions lib/internal/main/watch_mode.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';
const {
ArrayPrototypeForEach,
ArrayPrototypeIncludes,
ArrayPrototypeJoin,
ArrayPrototypeMap,
ArrayPrototypePush,
Expand Down Expand Up @@ -67,11 +66,8 @@ for (let i = 0; i < process.execArgv.length; i++) {
}
continue;
}
if (StringPrototypeStartsWith(arg, '--experimental-config-file')) {
if (!ArrayPrototypeIncludes(arg, '=')) {
// Skip the flag and the next argument (the config file path)
i++;
}
if (arg === '--experimental-config-file' ||
StringPrototypeStartsWith(arg, '--experimental-config-file=')) {
continue;
}
if (arg === '--experimental-default-config-file') {
Expand Down
3 changes: 1 addition & 2 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,7 @@ function setupSQLite() {
}

function initializeConfigFileSupport() {
if (getOptionValue('--experimental-default-config-file') ||
getOptionValue('--experimental-config-file')) {
if (getOptionValue('--experimental-config-file')) {
emitExperimentalWarning('--experimental-config-file');
}
}
Expand Down
6 changes: 5 additions & 1 deletion lib/internal/test_runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,11 @@ function createTestFileList(patterns, cwd) {

function filterExecArgv(arg, i, arr) {
return !ArrayPrototypeIncludes(kFilterArgs, arg) &&
!ArrayPrototypeSome(kFilterArgValues, (p) => arg === p || (i > 0 && arr[i - 1] === p) || StringPrototypeStartsWith(arg, `${p}=`));
!ArrayPrototypeSome(kFilterArgValues, (p) => {
return arg === p ||
StringPrototypeStartsWith(arg, `${p}=`) ||
(p !== '--experimental-config-file' && i > 0 && arr[i - 1] === p);
});
}

function getRunArgs(path, { forceExit,
Expand Down
14 changes: 10 additions & 4 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -900,15 +900,21 @@ static ExitCode InitializeNodeWithArgsInternal(
}

std::string node_options_from_config;
if (auto path = per_process::config_reader.GetDataFromArgs(*argv)) {
switch (per_process::config_reader.ParseConfig(*path)) {
auto config_path = per_process::config_reader.GetDataFromArgs(argv);
if (per_process::config_reader.HasInvalidDefaultConfigFileArgument()) {
errors->push_back("--experimental-default-config-file does not take an "
"argument");
return ExitCode::kInvalidCommandLineArgument;
}
if (config_path) {
switch (per_process::config_reader.ParseConfig(*config_path)) {
case ParseResult::Valid:
break;
case ParseResult::InvalidContent:
errors->push_back(std::string(*path) + ": invalid content");
errors->push_back(std::string(*config_path) + ": invalid content");
break;
case ParseResult::FileError:
errors->push_back(std::string(*path) + ": not found");
errors->push_back(std::string(*config_path) + ": not found");
break;
default:
UNREACHABLE();
Expand Down
64 changes: 39 additions & 25 deletions src/node_config_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,53 @@
#include "debug_utils-inl.h"
#include "simdjson.h"

#include <string>

namespace node {

constexpr std::string_view kConfigFileFlag = "--experimental-config-file";
constexpr std::string_view kDefaultConfigFileFlag =
"--experimental-default-config-file";
constexpr std::string_view kDefaultConfigFileName = "node.config.json";

inline bool HasEqualsPrefix(std::string_view arg, std::string_view flag) {
return arg.size() > flag.size() && arg.starts_with(flag) &&
arg[flag.size()] == '=';
}

std::optional<std::string_view> ConfigReader::GetDataFromArgs(
const std::vector<std::string>& args) {
constexpr std::string_view flag_path = "--experimental-config-file";
constexpr std::string_view default_file =
"--experimental-default-config-file";

bool has_default_config_file = false;

for (auto it = args.begin(); it != args.end(); ++it) {
if (*it == flag_path) {
// Case: "--experimental-config-file foo"
if (auto next = std::next(it); next != args.end()) {
return *next;
std::vector<std::string>* args) {
std::optional<std::string_view> result;
invalid_default_config_file_argument_ = false;

for (size_t i = 0; i < args->size(); ++i) {
std::string& arg = (*args)[i];

if (arg == kConfigFileFlag) {
// --experimental-config-file
arg = std::string(kConfigFileFlag) + "=" +
std::string(kDefaultConfigFileName);
result = kDefaultConfigFileName;
} else if (HasEqualsPrefix(arg, kConfigFileFlag)) {
// --experimental-config-file=path
std::string_view path =
std::string_view(arg).substr(kConfigFileFlag.size() + 1);
if (!path.empty()) {
result = path;
}
} else if (it->starts_with(flag_path)) {
// Case: "--experimental-config-file=foo"
if (it->size() > flag_path.size() && (*it)[flag_path.size()] == '=') {
return std::string_view(*it).substr(flag_path.size() + 1);
}
} else if (*it == default_file || it->starts_with(default_file)) {
has_default_config_file = true;
} else if (arg == kDefaultConfigFileFlag) {
// --experimental-default-config-file
arg = std::string(kConfigFileFlag) + "=" +
std::string(kDefaultConfigFileName);
result = kDefaultConfigFileName;
} else if (HasEqualsPrefix(arg, kDefaultConfigFileFlag)) {
invalid_default_config_file_argument_ = true;
}
}

if (has_default_config_file) {
return "node.config.json";
}
return result;
}

return std::nullopt;
bool ConfigReader::HasInvalidDefaultConfigFileArgument() const {
return invalid_default_config_file_argument_;
}

ParseResult ConfigReader::ProcessOptionValue(
Expand Down
4 changes: 3 additions & 1 deletion src/node_config_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class ConfigReader {
ParseResult ParseConfig(const std::string_view& config_path);

std::optional<std::string_view> GetDataFromArgs(
const std::vector<std::string>& args);
std::vector<std::string>* args);
bool HasInvalidDefaultConfigFileArgument() const;

std::string GetNodeOptions();
const std::vector<std::string>& GetNamespaceFlags() const;
Expand All @@ -53,6 +54,7 @@ class ConfigReader {

std::vector<std::string> node_options_;
std::vector<std::string> namespace_options_;
bool invalid_default_config_file_argument_ = false;

// Cache for fast lookup of environment options
std::unordered_map<std::string, options_parser::OptionMappingDetails>
Expand Down
9 changes: 4 additions & 5 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -900,11 +900,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
&EnvironmentOptions::optional_env_file);
Implies("--env-file-if-exists", "[has_env_file_string]");
AddOption("--experimental-config-file",
"set config file from supplied file",
&EnvironmentOptions::experimental_config_file_path);
AddOption("--experimental-default-config-file",
"set config file from default config file",
&EnvironmentOptions::experimental_default_config_file);
"set config file path",
&EnvironmentOptions::experimental_config_file_path,
kDisallowedInEnvvar);
AddAlias("--experimental-default-config-file", "--experimental-config-file");
AddOption("--test",
"launch test runner on startup",
&EnvironmentOptions::test_runner,
Expand Down
1 change: 0 additions & 1 deletion src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ class EnvironmentOptions : public Options {
bool report_exclude_env = false;
bool report_exclude_network = false;
std::string experimental_config_file_path;
bool experimental_default_config_file = false;

inline DebugOptions* get_debug_options() { return &debug_options_; }
inline const DebugOptions& debug_options() const { return debug_options_; }
Expand Down
1 change: 1 addition & 0 deletions test/parallel/test-cli-node-options-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,6 @@ for (const [, envVar, config] of nodeOptionsCC.matchAll(addOptionRE)) {

// add alias handling
manPagesOptions.delete('-trace-events-enabled');
manPagesOptions.delete('-experimental-default-config-file');

assert.strictEqual(manPagesOptions.size, 0, `Man page options not documented: ${[...manPagesOptions]}`);
6 changes: 2 additions & 4 deletions test/parallel/test-cli-options-as-flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ describe('getOptionsAsFlagsFromBinding', () => {
const result = await spawnPromisified(process.execPath, [
'--no-warnings',
'--expose-internals',
'--experimental-config-file',
configFile,
`--experimental-config-file=${configFile}`,
fixtureFile,
]);

Expand All @@ -75,8 +74,7 @@ describe('getOptionsAsFlagsFromBinding', () => {
'--no-warnings',
'--expose-internals',
'--stack-trace-limit=512',
'--experimental-config-file',
configFile,
`--experimental-config-file=${configFile}`,
fixtureFile,
]);

Expand Down
Loading
Loading