mirror of
https://github.com/nodejs/node.git
synced 2026-10-14 10:26:26 -04:00
src: namespace config file flags
PR-URL: https://github.com/nodejs/node/pull/57170 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it>
This commit is contained in:
1 parent
992036ec32
commit
56773ba50d
20 files changed
+757
-690
No files matched your search
+10
-8
@@ -928,17 +928,19 @@ with the following structure:
|
||||
```json
|
||||
{
|
||||
"$schema": "https://nodejs.org/dist/REPLACEME/docs/node_config_json_schema.json",
|
||||
"experimental-transform-types": true,
|
||||
"import": [
|
||||
"amaro/transform"
|
||||
],
|
||||
"disable-warning": "ExperimentalWarning",
|
||||
"watch-path": "src",
|
||||
"watch-preserve-output": true
|
||||
"nodeOptions": {
|
||||
"experimental-transform-types": true,
|
||||
"import": [
|
||||
"amaro/transform"
|
||||
],
|
||||
"disable-warning": "ExperimentalWarning",
|
||||
"watch-path": "src",
|
||||
"watch-preserve-output": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Only flags that are allowed in [`NODE_OPTIONS`][] are supported.
|
||||
In the `nodeOptions` field, only flags that are allowed in [`NODE_OPTIONS`][] are supported.
|
||||
No-op flags are not supported.
|
||||
Not all V8 flags are currently supported.
|
||||
|
||||
|
||||
+547
-541
File diff suppressed because it is too large.
Load diff
+14
-6
@@ -45,33 +45,41 @@ function generateConfigJsonSchema() {
|
||||
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
nodeOptions: {
|
||||
__proto__: null,
|
||||
additionalProperties: false,
|
||||
properties: { __proto__: null },
|
||||
type: 'object',
|
||||
},
|
||||
__proto__: null,
|
||||
},
|
||||
type: 'object',
|
||||
};
|
||||
|
||||
const nodeOptions = schema.properties.nodeOptions.properties;
|
||||
|
||||
for (const { 0: key, 1: type } of map) {
|
||||
const keyWithoutPrefix = StringPrototypeReplace(key, '--', '');
|
||||
if (type === 'array') {
|
||||
schema.properties[keyWithoutPrefix] = {
|
||||
nodeOptions[keyWithoutPrefix] = {
|
||||
__proto__: null,
|
||||
oneOf: [
|
||||
{ __proto__: null, type: 'string' },
|
||||
{ __proto__: null, type: 'array', items: { __proto__: null, type: 'string', minItems: 1 } },
|
||||
{ __proto__: null, items: { __proto__: null, type: 'string', minItems: 1 }, type: 'array' },
|
||||
],
|
||||
};
|
||||
} else {
|
||||
schema.properties[keyWithoutPrefix] = { __proto__: null, type };
|
||||
nodeOptions[keyWithoutPrefix] = { __proto__: null, type };
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the proerties by key alphabetically.
|
||||
const sortedKeys = ArrayPrototypeSort(ObjectKeys(schema.properties));
|
||||
const sortedKeys = ArrayPrototypeSort(ObjectKeys(nodeOptions));
|
||||
const sortedProperties = ObjectFromEntries(
|
||||
ArrayPrototypeMap(sortedKeys, (key) => [key, schema.properties[key]]),
|
||||
ArrayPrototypeMap(sortedKeys, (key) => [key, nodeOptions[key]]),
|
||||
);
|
||||
|
||||
schema.properties = sortedProperties;
|
||||
schema.properties.nodeOptions.properties = sortedProperties;
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
+133
-114
@@ -27,6 +27,123 @@ std::optional<std::string_view> ConfigReader::GetDataFromArgs(
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ParseResult ConfigReader::ParseNodeOptions(
|
||||
simdjson::ondemand::object* node_options_object) {
|
||||
auto env_options_map = options_parser::MapEnvOptionsFlagInputType();
|
||||
simdjson::ondemand::value ondemand_value;
|
||||
std::string_view key;
|
||||
|
||||
for (auto field : *node_options_object) {
|
||||
if (field.unescaped_key().get(key) || field.value().get(ondemand_value)) {
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
|
||||
// The key needs to match the CLI option
|
||||
std::string prefix = "--";
|
||||
auto it = env_options_map.find(prefix.append(key));
|
||||
if (it != env_options_map.end()) {
|
||||
switch (it->second) {
|
||||
case options_parser::OptionType::kBoolean: {
|
||||
bool result;
|
||||
if (ondemand_value.get_bool().get(result)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
node_options_.push_back(it->first + "=" +
|
||||
(result ? "true" : "false"));
|
||||
break;
|
||||
}
|
||||
// String array can allow both string and array types
|
||||
case options_parser::OptionType::kStringList: {
|
||||
simdjson::ondemand::json_type field_type;
|
||||
if (ondemand_value.type().get(field_type)) {
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
switch (field_type) {
|
||||
case simdjson::ondemand::json_type::array: {
|
||||
std::vector<std::string> result;
|
||||
simdjson::ondemand::array raw_imports;
|
||||
if (ondemand_value.get_array().get(raw_imports)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
for (auto raw_import : raw_imports) {
|
||||
std::string_view import;
|
||||
if (raw_import.get_string(import)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
node_options_.push_back(it->first + "=" + std::string(import));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case simdjson::ondemand::json_type::string: {
|
||||
std::string result;
|
||||
if (ondemand_value.get_string(result)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
node_options_.push_back(it->first + "=" + result);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case options_parser::OptionType::kString: {
|
||||
std::string result;
|
||||
if (ondemand_value.get_string(result)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
node_options_.push_back(it->first + "=" + result);
|
||||
break;
|
||||
}
|
||||
case options_parser::OptionType::kInteger: {
|
||||
int64_t result;
|
||||
if (ondemand_value.get_int64().get(result)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
node_options_.push_back(it->first + "=" + std::to_string(result));
|
||||
break;
|
||||
}
|
||||
case options_parser::OptionType::kHostPort:
|
||||
case options_parser::OptionType::kUInteger: {
|
||||
uint64_t result;
|
||||
if (ondemand_value.get_uint64().get(result)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
node_options_.push_back(it->first + "=" + std::to_string(result));
|
||||
break;
|
||||
}
|
||||
case options_parser::OptionType::kNoOp: {
|
||||
FPrintF(stderr,
|
||||
"No-op flag %s is currently not supported\n",
|
||||
it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
break;
|
||||
}
|
||||
case options_parser::OptionType::kV8Option: {
|
||||
FPrintF(stderr,
|
||||
"V8 flag %s is currently not supported\n",
|
||||
it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
FPrintF(stderr, "Unknown or not allowed option %s\n", key.data());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
}
|
||||
return ParseResult::Valid;
|
||||
}
|
||||
|
||||
ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) {
|
||||
std::string file_content;
|
||||
// Read the configuration file
|
||||
@@ -59,137 +176,39 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) {
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
|
||||
auto env_options_map = options_parser::MapEnvOptionsFlagInputType();
|
||||
simdjson::ondemand::value ondemand_value;
|
||||
std::string_view key;
|
||||
|
||||
for (auto field : main_object) {
|
||||
if (field.unescaped_key().get(key) || field.value().get(ondemand_value)) {
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
|
||||
// The key needs to match the CLI option
|
||||
std::string prefix = "--";
|
||||
auto it = env_options_map.find(prefix.append(key));
|
||||
if (it != env_options_map.end()) {
|
||||
switch (it->second) {
|
||||
case options_parser::OptionType::kBoolean: {
|
||||
bool result;
|
||||
if (ondemand_value.get_bool().get(result)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
flags_.push_back(it->first + "=" + (result ? "true" : "false"));
|
||||
break;
|
||||
}
|
||||
// String array can allow both string and array types
|
||||
case options_parser::OptionType::kStringList: {
|
||||
simdjson::ondemand::json_type field_type;
|
||||
if (ondemand_value.type().get(field_type)) {
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
switch (field_type) {
|
||||
case simdjson::ondemand::json_type::array: {
|
||||
std::vector<std::string> result;
|
||||
simdjson::ondemand::array raw_imports;
|
||||
if (ondemand_value.get_array().get(raw_imports)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
for (auto raw_import : raw_imports) {
|
||||
std::string_view import;
|
||||
if (raw_import.get_string(import)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
flags_.push_back(it->first + "=" + std::string(import));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case simdjson::ondemand::json_type::string: {
|
||||
std::string result;
|
||||
if (ondemand_value.get_string(result)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
flags_.push_back(it->first + "=" + result);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case options_parser::OptionType::kString: {
|
||||
std::string result;
|
||||
if (ondemand_value.get_string(result)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
flags_.push_back(it->first + "=" + result);
|
||||
break;
|
||||
}
|
||||
case options_parser::OptionType::kInteger: {
|
||||
int64_t result;
|
||||
if (ondemand_value.get_int64().get(result)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
flags_.push_back(it->first + "=" + std::to_string(result));
|
||||
break;
|
||||
}
|
||||
case options_parser::OptionType::kHostPort:
|
||||
case options_parser::OptionType::kUInteger: {
|
||||
uint64_t result;
|
||||
if (ondemand_value.get_uint64().get(result)) {
|
||||
FPrintF(stderr, "Invalid value for %s\n", it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
flags_.push_back(it->first + "=" + std::to_string(result));
|
||||
break;
|
||||
}
|
||||
case options_parser::OptionType::kNoOp: {
|
||||
FPrintF(stderr,
|
||||
"No-op flag %s is currently not supported\n",
|
||||
it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
break;
|
||||
}
|
||||
case options_parser::OptionType::kV8Option: {
|
||||
FPrintF(stderr,
|
||||
"V8 flag %s is currently not supported\n",
|
||||
it->first.c_str());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
FPrintF(stderr, "Unknown or not allowed option %s\n", key.data());
|
||||
simdjson::ondemand::object node_options_object;
|
||||
// If "nodeOptions" is an object, parse it
|
||||
if (auto node_options_error =
|
||||
main_object["nodeOptions"].get_object().get(node_options_object)) {
|
||||
if (node_options_error != simdjson::error_code::NO_SUCH_FIELD) {
|
||||
FPrintF(stderr,
|
||||
"\"nodeOptions\" value unexpected for %s\n\n",
|
||||
config_path.data());
|
||||
return ParseResult::InvalidContent;
|
||||
}
|
||||
} else {
|
||||
return ParseNodeOptions(&node_options_object);
|
||||
}
|
||||
|
||||
return ParseResult::Valid;
|
||||
}
|
||||
|
||||
std::string ConfigReader::AssignNodeOptions() {
|
||||
if (flags_.empty()) {
|
||||
if (node_options_.empty()) {
|
||||
return "";
|
||||
} else {
|
||||
DCHECK_GT(flags_.size(), 0);
|
||||
DCHECK_GT(node_options_.size(), 0);
|
||||
std::string acc;
|
||||
acc.reserve(flags_.size() * 2);
|
||||
for (size_t i = 0; i < flags_.size(); ++i) {
|
||||
acc.reserve(node_options_.size() * 2);
|
||||
for (size_t i = 0; i < node_options_.size(); ++i) {
|
||||
// The space is necessary at the beginning of the string
|
||||
acc += " " + flags_[i];
|
||||
acc += " " + node_options_[i];
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ConfigReader::GetFlagsSize() {
|
||||
return flags_.size();
|
||||
return node_options_.size();
|
||||
}
|
||||
} // namespace node
|
||||
@@ -33,7 +33,9 @@ class ConfigReader {
|
||||
size_t GetFlagsSize();
|
||||
|
||||
private:
|
||||
std::vector<std::string> flags_;
|
||||
ParseResult ParseNodeOptions(simdjson::ondemand::object* node_options_object);
|
||||
|
||||
std::vector<std::string> node_options_;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
||||
Vendored
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"inspect-port": 65535
|
||||
"nodeOptions": {
|
||||
"inspect-port": 65535
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"import": "./test/fixtures/printA.js"
|
||||
"nodeOptions":{
|
||||
"import": "./test/fixtures/printA.js"
|
||||
}
|
||||
}
|
||||
Vendored
+7
-5
@@ -1,7 +1,9 @@
|
||||
{
|
||||
"import": [
|
||||
"./test/fixtures/printA.js",
|
||||
"./test/fixtures/printB.js",
|
||||
"./test/fixtures/printC.js"
|
||||
]
|
||||
"nodeOptions": {
|
||||
"import": [
|
||||
"./test/fixtures/printA.js",
|
||||
"./test/fixtures/printB.js",
|
||||
"./test/fixtures/printC.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
+5
-1
@@ -1,3 +1,7 @@
|
||||
{
|
||||
"import": [1]
|
||||
"nodeOptions": {
|
||||
"import": [
|
||||
1
|
||||
]
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"max-http-header-size": -1
|
||||
"nodeOptions": {
|
||||
"max-http-header-size": -1
|
||||
}
|
||||
}
|
||||
Vendored
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"http-parser": true
|
||||
"nodeOptions": {
|
||||
"http-parser": true
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"--test": true
|
||||
"nodeOptions": {
|
||||
"test": true
|
||||
}
|
||||
}
|
||||
Vendored
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"max-http-header-size": 4294967295
|
||||
"nodeOptions": {
|
||||
"max-http-header-size": 4294967295
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"experimental-transform-types": true,
|
||||
"experimental-transform-types": false
|
||||
"nodeOptions": {
|
||||
"experimental-transform-types": true,
|
||||
"experimental-transform-types": false
|
||||
}
|
||||
}
|
||||
Vendored
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"import": "./test/fixtures/printA.js --experimental-transform-types"
|
||||
"nodeOptions": {
|
||||
"import": "./test/fixtures/printA.js --experimental-transform-types"
|
||||
}
|
||||
}
|
||||
Vendored
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"test-reporter": "dot"
|
||||
"nodeOptions": {
|
||||
"test-reporter": "dot"
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"experimental-transform-types": true
|
||||
"nodeOptions": {
|
||||
"experimental-transform-types": true
|
||||
}
|
||||
}
|
||||
Vendored
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"some-unknown-flag": true
|
||||
"nodeOptions": {
|
||||
"some-unknown-flag": true
|
||||
}
|
||||
}
|
||||
Vendored
+3
-1
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"abort-on-uncaught-exception": true
|
||||
"nodeOptions": {
|
||||
"abort-on-uncaught-exception": true
|
||||
}
|
||||
}
|
||||
@@ -162,7 +162,7 @@ test('should throw at flag not available in NODE_OPTIONS', async () => {
|
||||
fixtures.path('rc/not-node-options-flag.json'),
|
||||
'-p', '"Hello, World!"',
|
||||
]);
|
||||
match(result.stderr, /Unknown or not allowed option --test/);
|
||||
match(result.stderr, /Unknown or not allowed option test/);
|
||||
strictEqual(result.stdout, '');
|
||||
strictEqual(result.code, 9);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user