diff --git a/doc/api/cli.md b/doc/api/cli.md index 37ce213570b25b..0e6ca372337651 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -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. diff --git a/doc/node_config_json_schema.json b/doc/node_config_json_schema.json index f76fbef3c7c3fd..8430a086d285a4 100644 --- a/doc/node_config_json_schema.json +++ b/doc/node_config_json_schema.json @@ -2,576 +2,582 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { - "addons": { - "type": "boolean" - }, - "allow-addons": { - "type": "boolean" - }, - "allow-child-process": { - "type": "boolean" - }, - "allow-fs-read": { - "oneOf": [ - { + "nodeOptions": { + "additionalProperties": false, + "properties": { + "addons": { + "type": "boolean" + }, + "allow-addons": { + "type": "boolean" + }, + "allow-child-process": { + "type": "boolean" + }, + "allow-fs-read": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "allow-fs-write": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "allow-wasi": { + "type": "boolean" + }, + "allow-worker": { + "type": "boolean" + }, + "async-context-frame": { + "type": "boolean" + }, + "conditions": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "cpu-prof": { + "type": "boolean" + }, + "cpu-prof-dir": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "allow-fs-write": { - "oneOf": [ - { + "cpu-prof-interval": { + "type": "number" + }, + "cpu-prof-name": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "allow-wasi": { - "type": "boolean" - }, - "allow-worker": { - "type": "boolean" - }, - "async-context-frame": { - "type": "boolean" - }, - "conditions": { - "oneOf": [ - { + "debug-arraybuffer-allocations": { + "type": "boolean" + }, + "deprecation": { + "type": "boolean" + }, + "diagnostic-dir": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "cpu-prof": { - "type": "boolean" - }, - "cpu-prof-dir": { - "type": "string" - }, - "cpu-prof-interval": { - "type": "number" - }, - "cpu-prof-name": { - "type": "string" - }, - "debug-arraybuffer-allocations": { - "type": "boolean" - }, - "deprecation": { - "type": "boolean" - }, - "diagnostic-dir": { - "type": "string" - }, - "disable-proto": { - "type": "string" - }, - "disable-sigusr1": { - "type": "boolean" - }, - "disable-warning": { - "oneOf": [ - { + "disable-proto": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "disable-wasm-trap-handler": { - "type": "boolean" - }, - "dns-result-order": { - "type": "string" - }, - "enable-fips": { - "type": "boolean" - }, - "enable-source-maps": { - "type": "boolean" - }, - "entry-url": { - "type": "boolean" - }, - "experimental-addon-modules": { - "type": "boolean" - }, - "experimental-detect-module": { - "type": "boolean" - }, - "experimental-eventsource": { - "type": "boolean" - }, - "experimental-global-navigator": { - "type": "boolean" - }, - "experimental-import-meta-resolve": { - "type": "boolean" - }, - "experimental-loader": { - "oneOf": [ - { + "disable-sigusr1": { + "type": "boolean" + }, + "disable-warning": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "disable-wasm-trap-handler": { + "type": "boolean" + }, + "dns-result-order": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "experimental-print-required-tla": { - "type": "boolean" - }, - "experimental-repl-await": { - "type": "boolean" - }, - "experimental-require-module": { - "type": "boolean" - }, - "experimental-shadow-realm": { - "type": "boolean" - }, - "experimental-sqlite": { - "type": "boolean" - }, - "experimental-strip-types": { - "type": "boolean" - }, - "experimental-transform-types": { - "type": "boolean" - }, - "experimental-vm-modules": { - "type": "boolean" - }, - "experimental-wasm-modules": { - "type": "boolean" - }, - "experimental-websocket": { - "type": "boolean" - }, - "experimental-webstorage": { - "type": "boolean" - }, - "extra-info-on-fatal-exception": { - "type": "boolean" - }, - "force-async-hooks-checks": { - "type": "boolean" - }, - "force-context-aware": { - "type": "boolean" - }, - "force-fips": { - "type": "boolean" - }, - "force-node-api-uncaught-exceptions-policy": { - "type": "boolean" - }, - "frozen-intrinsics": { - "type": "boolean" - }, - "global-search-paths": { - "type": "boolean" - }, - "heap-prof": { - "type": "boolean" - }, - "heap-prof-dir": { - "type": "string" - }, - "heap-prof-interval": { - "type": "number" - }, - "heap-prof-name": { - "type": "string" - }, - "heapsnapshot-near-heap-limit": { - "type": "number" - }, - "heapsnapshot-signal": { - "type": "string" - }, - "icu-data-dir": { - "type": "string" - }, - "import": { - "oneOf": [ - { + "enable-fips": { + "type": "boolean" + }, + "enable-source-maps": { + "type": "boolean" + }, + "entry-url": { + "type": "boolean" + }, + "experimental-addon-modules": { + "type": "boolean" + }, + "experimental-detect-module": { + "type": "boolean" + }, + "experimental-eventsource": { + "type": "boolean" + }, + "experimental-global-navigator": { + "type": "boolean" + }, + "experimental-import-meta-resolve": { + "type": "boolean" + }, + "experimental-loader": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "experimental-print-required-tla": { + "type": "boolean" + }, + "experimental-repl-await": { + "type": "boolean" + }, + "experimental-require-module": { + "type": "boolean" + }, + "experimental-shadow-realm": { + "type": "boolean" + }, + "experimental-sqlite": { + "type": "boolean" + }, + "experimental-strip-types": { + "type": "boolean" + }, + "experimental-transform-types": { + "type": "boolean" + }, + "experimental-vm-modules": { + "type": "boolean" + }, + "experimental-wasm-modules": { + "type": "boolean" + }, + "experimental-websocket": { + "type": "boolean" + }, + "experimental-webstorage": { + "type": "boolean" + }, + "extra-info-on-fatal-exception": { + "type": "boolean" + }, + "force-async-hooks-checks": { + "type": "boolean" + }, + "force-context-aware": { + "type": "boolean" + }, + "force-fips": { + "type": "boolean" + }, + "force-node-api-uncaught-exceptions-policy": { + "type": "boolean" + }, + "frozen-intrinsics": { + "type": "boolean" + }, + "global-search-paths": { + "type": "boolean" + }, + "heap-prof": { + "type": "boolean" + }, + "heap-prof-dir": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "input-type": { - "type": "string" - }, - "insecure-http-parser": { - "type": "boolean" - }, - "inspect": { - "type": "boolean" - }, - "inspect-brk": { - "type": "boolean" - }, - "inspect-port": { - "type": "number" - }, - "inspect-publish-uid": { - "type": "string" - }, - "inspect-wait": { - "type": "boolean" - }, - "localstorage-file": { - "type": "string" - }, - "max-http-header-size": { - "type": "number" - }, - "network-family-autoselection": { - "type": "boolean" - }, - "network-family-autoselection-attempt-timeout": { - "type": "number" - }, - "node-snapshot": { - "type": "boolean" - }, - "openssl-config": { - "type": "string" - }, - "openssl-legacy-provider": { - "type": "boolean" - }, - "openssl-shared-config": { - "type": "boolean" - }, - "pending-deprecation": { - "type": "boolean" - }, - "permission": { - "type": "boolean" - }, - "preserve-symlinks": { - "type": "boolean" - }, - "preserve-symlinks-main": { - "type": "boolean" - }, - "redirect-warnings": { - "type": "string" - }, - "report-compact": { - "type": "boolean" - }, - "report-dir": { - "type": "string" - }, - "report-exclude-env": { - "type": "boolean" - }, - "report-exclude-network": { - "type": "boolean" - }, - "report-filename": { - "type": "string" - }, - "report-on-fatalerror": { - "type": "boolean" - }, - "report-on-signal": { - "type": "boolean" - }, - "report-signal": { - "type": "string" - }, - "report-uncaught-exception": { - "type": "boolean" - }, - "require": { - "oneOf": [ - { + "heap-prof-interval": { + "type": "number" + }, + "heap-prof-name": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "secure-heap": { - "type": "number" - }, - "secure-heap-min": { - "type": "number" - }, - "snapshot-blob": { - "type": "string" - }, - "stack-trace-limit": { - "type": "number" - }, - "test-coverage-branches": { - "type": "number" - }, - "test-coverage-exclude": { - "oneOf": [ - { + "heapsnapshot-near-heap-limit": { + "type": "number" + }, + "heapsnapshot-signal": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "test-coverage-functions": { - "type": "number" - }, - "test-coverage-include": { - "oneOf": [ - { + "icu-data-dir": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "test-coverage-lines": { - "type": "number" - }, - "test-isolation": { - "type": "string" - }, - "test-name-pattern": { - "oneOf": [ - { + "import": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "input-type": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "test-only": { - "type": "boolean" - }, - "test-reporter": { - "oneOf": [ - { + "insecure-http-parser": { + "type": "boolean" + }, + "inspect": { + "type": "boolean" + }, + "inspect-brk": { + "type": "boolean" + }, + "inspect-port": { + "type": "number" + }, + "inspect-publish-uid": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "test-reporter-destination": { - "oneOf": [ - { + "inspect-wait": { + "type": "boolean" + }, + "localstorage-file": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "test-shard": { - "type": "string" - }, - "test-skip-pattern": { - "oneOf": [ - { + "max-http-header-size": { + "type": "number" + }, + "network-family-autoselection": { + "type": "boolean" + }, + "network-family-autoselection-attempt-timeout": { + "type": "number" + }, + "node-snapshot": { + "type": "boolean" + }, + "openssl-config": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } - } - ] - }, - "throw-deprecation": { - "type": "boolean" - }, - "title": { - "type": "string" - }, - "tls-cipher-list": { - "type": "string" - }, - "tls-keylog": { - "type": "string" - }, - "tls-max-v1.2": { - "type": "boolean" - }, - "tls-max-v1.3": { - "type": "boolean" - }, - "tls-min-v1.0": { - "type": "boolean" - }, - "tls-min-v1.1": { - "type": "boolean" - }, - "tls-min-v1.2": { - "type": "boolean" - }, - "tls-min-v1.3": { - "type": "boolean" - }, - "trace-deprecation": { - "type": "boolean" - }, - "trace-env": { - "type": "boolean" - }, - "trace-env-js-stack": { - "type": "boolean" - }, - "trace-env-native-stack": { - "type": "boolean" - }, - "trace-event-categories": { - "type": "string" - }, - "trace-event-file-pattern": { - "type": "string" - }, - "trace-exit": { - "type": "boolean" - }, - "trace-promises": { - "type": "boolean" - }, - "trace-require-module": { - "type": "string" - }, - "trace-sigint": { - "type": "boolean" - }, - "trace-sync-io": { - "type": "boolean" - }, - "trace-tls": { - "type": "boolean" - }, - "trace-uncaught": { - "type": "boolean" - }, - "trace-warnings": { - "type": "boolean" - }, - "track-heap-objects": { - "type": "boolean" - }, - "unhandled-rejections": { - "type": "string" - }, - "use-bundled-ca": { - "type": "boolean" - }, - "use-largepages": { - "type": "string" - }, - "use-openssl-ca": { - "type": "boolean" - }, - "use-system-ca": { - "type": "boolean" - }, - "v8-pool-size": { - "type": "number" - }, - "verify-base-objects": { - "type": "boolean" - }, - "warnings": { - "type": "boolean" - }, - "watch": { - "type": "boolean" - }, - "watch-path": { - "oneOf": [ - { + "openssl-legacy-provider": { + "type": "boolean" + }, + "openssl-shared-config": { + "type": "boolean" + }, + "pending-deprecation": { + "type": "boolean" + }, + "permission": { + "type": "boolean" + }, + "preserve-symlinks": { + "type": "boolean" + }, + "preserve-symlinks-main": { + "type": "boolean" + }, + "redirect-warnings": { "type": "string" }, - { - "type": "array", - "items": { - "type": "string", - "minItems": 1 - } + "report-compact": { + "type": "boolean" + }, + "report-dir": { + "type": "string" + }, + "report-exclude-env": { + "type": "boolean" + }, + "report-exclude-network": { + "type": "boolean" + }, + "report-filename": { + "type": "string" + }, + "report-on-fatalerror": { + "type": "boolean" + }, + "report-on-signal": { + "type": "boolean" + }, + "report-signal": { + "type": "string" + }, + "report-uncaught-exception": { + "type": "boolean" + }, + "require": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "secure-heap": { + "type": "number" + }, + "secure-heap-min": { + "type": "number" + }, + "snapshot-blob": { + "type": "string" + }, + "stack-trace-limit": { + "type": "number" + }, + "test-coverage-branches": { + "type": "number" + }, + "test-coverage-exclude": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-coverage-functions": { + "type": "number" + }, + "test-coverage-include": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-coverage-lines": { + "type": "number" + }, + "test-isolation": { + "type": "string" + }, + "test-name-pattern": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-only": { + "type": "boolean" + }, + "test-reporter": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-reporter-destination": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "test-shard": { + "type": "string" + }, + "test-skip-pattern": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "throw-deprecation": { + "type": "boolean" + }, + "title": { + "type": "string" + }, + "tls-cipher-list": { + "type": "string" + }, + "tls-keylog": { + "type": "string" + }, + "tls-max-v1.2": { + "type": "boolean" + }, + "tls-max-v1.3": { + "type": "boolean" + }, + "tls-min-v1.0": { + "type": "boolean" + }, + "tls-min-v1.1": { + "type": "boolean" + }, + "tls-min-v1.2": { + "type": "boolean" + }, + "tls-min-v1.3": { + "type": "boolean" + }, + "trace-deprecation": { + "type": "boolean" + }, + "trace-env": { + "type": "boolean" + }, + "trace-env-js-stack": { + "type": "boolean" + }, + "trace-env-native-stack": { + "type": "boolean" + }, + "trace-event-categories": { + "type": "string" + }, + "trace-event-file-pattern": { + "type": "string" + }, + "trace-exit": { + "type": "boolean" + }, + "trace-promises": { + "type": "boolean" + }, + "trace-require-module": { + "type": "string" + }, + "trace-sigint": { + "type": "boolean" + }, + "trace-sync-io": { + "type": "boolean" + }, + "trace-tls": { + "type": "boolean" + }, + "trace-uncaught": { + "type": "boolean" + }, + "trace-warnings": { + "type": "boolean" + }, + "track-heap-objects": { + "type": "boolean" + }, + "unhandled-rejections": { + "type": "string" + }, + "use-bundled-ca": { + "type": "boolean" + }, + "use-largepages": { + "type": "string" + }, + "use-openssl-ca": { + "type": "boolean" + }, + "use-system-ca": { + "type": "boolean" + }, + "v8-pool-size": { + "type": "number" + }, + "verify-base-objects": { + "type": "boolean" + }, + "warnings": { + "type": "boolean" + }, + "watch": { + "type": "boolean" + }, + "watch-path": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string", + "minItems": 1 + }, + "type": "array" + } + ] + }, + "watch-preserve-output": { + "type": "boolean" + }, + "zero-fill-buffers": { + "type": "boolean" } - ] - }, - "watch-preserve-output": { - "type": "boolean" - }, - "zero-fill-buffers": { - "type": "boolean" + }, + "type": "object" } }, "type": "object" diff --git a/lib/internal/options.js b/lib/internal/options.js index f23b75c0a8f3a2..e9f9d57e95e326 100644 --- a/lib/internal/options.js +++ b/lib/internal/options.js @@ -45,33 +45,42 @@ 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; } diff --git a/src/node_config_file.cc b/src/node_config_file.cc index 700c3e458dad23..7fe79ee8d34c6d 100644 --- a/src/node_config_file.cc +++ b/src/node_config_file.cc @@ -27,43 +27,13 @@ std::optional ConfigReader::GetDataFromArgs( return std::nullopt; } -ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { - std::string file_content; - // Read the configuration file - int r = ReadFileSync(&file_content, config_path.data()); - if (r != 0) { - const char* err = uv_strerror(r); - FPrintF( - stderr, "Cannot read configuration from %s: %s\n", config_path, err); - return ParseResult::FileError; - } - - // Parse the configuration file - simdjson::ondemand::parser json_parser; - simdjson::ondemand::document document; - if (json_parser.iterate(file_content).get(document)) { - FPrintF(stderr, "Can't parse %s\n", config_path.data()); - return ParseResult::InvalidContent; - } - - simdjson::ondemand::object main_object; - // If document is not an object, throw an error. - if (auto root_error = document.get_object().get(main_object)) { - if (root_error == simdjson::error_code::INCORRECT_TYPE) { - FPrintF(stderr, - "Root value unexpected not an object for %s\n\n", - config_path.data()); - } else { - FPrintF(stderr, "Can't parse %s\n", config_path.data()); - } - return ParseResult::InvalidContent; - } - +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 : main_object) { + for (auto field : *node_options_object) { if (field.unescaped_key().get(key) || field.value().get(ondemand_value)) { return ParseResult::InvalidContent; } @@ -79,7 +49,8 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); return ParseResult::InvalidContent; } - flags_.push_back(it->first + "=" + (result ? "true" : "false")); + node_options_.push_back(it->first + "=" + + (result ? "true" : "false")); break; } // String array can allow both string and array types @@ -102,7 +73,7 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); return ParseResult::InvalidContent; } - flags_.push_back(it->first + "=" + std::string(import)); + node_options_.push_back(it->first + "=" + std::string(import)); } break; } @@ -112,7 +83,7 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); return ParseResult::InvalidContent; } - flags_.push_back(it->first + "=" + result); + node_options_.push_back(it->first + "=" + result); break; } default: @@ -127,7 +98,7 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); return ParseResult::InvalidContent; } - flags_.push_back(it->first + "=" + result); + node_options_.push_back(it->first + "=" + result); break; } case options_parser::OptionType::kInteger: { @@ -136,7 +107,7 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); return ParseResult::InvalidContent; } - flags_.push_back(it->first + "=" + std::to_string(result)); + node_options_.push_back(it->first + "=" + std::to_string(result)); break; } case options_parser::OptionType::kHostPort: @@ -146,7 +117,7 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { FPrintF(stderr, "Invalid value for %s\n", it->first.c_str()); return ParseResult::InvalidContent; } - flags_.push_back(it->first + "=" + std::to_string(result)); + node_options_.push_back(it->first + "=" + std::to_string(result)); break; } case options_parser::OptionType::kNoOp: { @@ -170,26 +141,77 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { return ParseResult::InvalidContent; } } + return ParseResult::Valid; +} + +ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) { + std::string file_content; + // Read the configuration file + int r = ReadFileSync(&file_content, config_path.data()); + if (r != 0) { + const char* err = uv_strerror(r); + FPrintF( + stderr, "Cannot read configuration from %s: %s\n", config_path, err); + return ParseResult::FileError; + } + + // Parse the configuration file + simdjson::ondemand::parser json_parser; + simdjson::ondemand::document document; + if (json_parser.iterate(file_content).get(document)) { + FPrintF(stderr, "Can't parse %s\n", config_path.data()); + return ParseResult::InvalidContent; + } + + simdjson::ondemand::object main_object; + // If document is not an object, throw an error. + if (auto root_error = document.get_object().get(main_object)) { + if (root_error == simdjson::error_code::INCORRECT_TYPE) { + FPrintF(stderr, + "Root value unexpected not an object for %s\n\n", + config_path.data()); + } else { + FPrintF(stderr, "Can't parse %s\n", config_path.data()); + } + return ParseResult::InvalidContent; + } + + 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 { + auto result = ParseNodeOptions(&node_options_object); + if (result != ParseResult::Valid) { + return result; + } + } 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 diff --git a/src/node_config_file.h b/src/node_config_file.h index 938f3647d8eb8e..04b4721a411088 100644 --- a/src/node_config_file.h +++ b/src/node_config_file.h @@ -33,7 +33,9 @@ class ConfigReader { size_t GetFlagsSize(); private: - std::vector flags_; + ParseResult ParseNodeOptions(simdjson::ondemand::object* node_options_object); + + std::vector node_options_; }; } // namespace node diff --git a/test/fixtures/rc/host-port.json b/test/fixtures/rc/host-port.json index d9ee9a3662387d..48fb16edae64d6 100644 --- a/test/fixtures/rc/host-port.json +++ b/test/fixtures/rc/host-port.json @@ -1,3 +1,5 @@ { - "inspect-port": 65535 + "nodeOptions": { + "inspect-port": 65535 + } } diff --git a/test/fixtures/rc/import-as-string.json b/test/fixtures/rc/import-as-string.json index e719e1bc9d9a8a..b1e1feb96a9aef 100644 --- a/test/fixtures/rc/import-as-string.json +++ b/test/fixtures/rc/import-as-string.json @@ -1,3 +1,5 @@ { - "import": "./test/fixtures/printA.js" + "nodeOptions":{ + "import": "./test/fixtures/printA.js" + } } diff --git a/test/fixtures/rc/import.json b/test/fixtures/rc/import.json index d169f8a9100395..c0f74ed62b4eec 100644 --- a/test/fixtures/rc/import.json +++ b/test/fixtures/rc/import.json @@ -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" + ] + } } diff --git a/test/fixtures/rc/invalid-import.json b/test/fixtures/rc/invalid-import.json index bc6a4a2757e166..8d6a1a0777e6b9 100644 --- a/test/fixtures/rc/invalid-import.json +++ b/test/fixtures/rc/invalid-import.json @@ -1,3 +1,7 @@ { - "import": [1] + "nodeOptions": { + "import": [ + 1 + ] + } } diff --git a/test/fixtures/rc/negative-numeric.json b/test/fixtures/rc/negative-numeric.json index a1303cb8251331..f0b6d5736985a4 100644 --- a/test/fixtures/rc/negative-numeric.json +++ b/test/fixtures/rc/negative-numeric.json @@ -1,3 +1,5 @@ { - "max-http-header-size": -1 + "nodeOptions": { + "max-http-header-size": -1 + } } diff --git a/test/fixtures/rc/no-op.json b/test/fixtures/rc/no-op.json index 8901009333cac3..a8e0a191ca7cb5 100644 --- a/test/fixtures/rc/no-op.json +++ b/test/fixtures/rc/no-op.json @@ -1,3 +1,5 @@ { - "http-parser": true + "nodeOptions": { + "http-parser": true + } } diff --git a/test/fixtures/rc/not-node-options-flag.json b/test/fixtures/rc/not-node-options-flag.json index 446d3207b135f0..c35ff6064ea39c 100644 --- a/test/fixtures/rc/not-node-options-flag.json +++ b/test/fixtures/rc/not-node-options-flag.json @@ -1,3 +1,5 @@ { - "--test": true + "nodeOptions": { + "test": true + } } diff --git a/test/fixtures/rc/numeric.json b/test/fixtures/rc/numeric.json index d22bf4eec303e8..c9d5d6241f85ed 100644 --- a/test/fixtures/rc/numeric.json +++ b/test/fixtures/rc/numeric.json @@ -1,3 +1,5 @@ { - "max-http-header-size": 4294967295 + "nodeOptions": { + "max-http-header-size": 4294967295 + } } diff --git a/test/fixtures/rc/override-property.json b/test/fixtures/rc/override-property.json index 17e3ac7738d76f..9e76f24fcd30bc 100644 --- a/test/fixtures/rc/override-property.json +++ b/test/fixtures/rc/override-property.json @@ -1,4 +1,6 @@ { - "experimental-transform-types": true, - "experimental-transform-types": false + "nodeOptions": { + "experimental-transform-types": true, + "experimental-transform-types": false + } } diff --git a/test/fixtures/rc/sneaky-flag.json b/test/fixtures/rc/sneaky-flag.json index 20a5d966f01868..0b2342539eaff2 100644 --- a/test/fixtures/rc/sneaky-flag.json +++ b/test/fixtures/rc/sneaky-flag.json @@ -1,3 +1,5 @@ { - "import": "./test/fixtures/printA.js --experimental-transform-types" + "nodeOptions": { + "import": "./test/fixtures/printA.js --experimental-transform-types" + } } diff --git a/test/fixtures/rc/string.json b/test/fixtures/rc/string.json index e1b4d4ebc001aa..54dd0964b31a82 100644 --- a/test/fixtures/rc/string.json +++ b/test/fixtures/rc/string.json @@ -1,3 +1,5 @@ { - "test-reporter": "dot" + "nodeOptions": { + "test-reporter": "dot" + } } diff --git a/test/fixtures/rc/transform-types.json b/test/fixtures/rc/transform-types.json index aae5a83d651f71..ea5a9f9f16ff1f 100644 --- a/test/fixtures/rc/transform-types.json +++ b/test/fixtures/rc/transform-types.json @@ -1,3 +1,5 @@ { - "experimental-transform-types": true + "nodeOptions": { + "experimental-transform-types": true + } } diff --git a/test/fixtures/rc/unknown-flag.json b/test/fixtures/rc/unknown-flag.json index 1e284d7f9cbb0c..31087baa00f4f0 100644 --- a/test/fixtures/rc/unknown-flag.json +++ b/test/fixtures/rc/unknown-flag.json @@ -1,3 +1,5 @@ { - "some-unknown-flag": true + "nodeOptions": { + "some-unknown-flag": true + } } diff --git a/test/fixtures/rc/v8-flag.json b/test/fixtures/rc/v8-flag.json index b38a41d9325a49..5f740953063002 100644 --- a/test/fixtures/rc/v8-flag.json +++ b/test/fixtures/rc/v8-flag.json @@ -1,3 +1,5 @@ { - "abort-on-uncaught-exception": true + "nodeOptions": { + "abort-on-uncaught-exception": true + } } diff --git a/test/parallel/test-config-file.js b/test/parallel/test-config-file.js index 6cd24adbc7943a..49960e262ba42a 100644 --- a/test/parallel/test-config-file.js +++ b/test/parallel/test-config-file.js @@ -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); });