Skip to content

draft: src: support namespace options in configuration schema generation #58073

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft
132 changes: 132 additions & 0 deletions doc/node-config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,138 @@
}
},
"type": "object"
},
"test_runner": {
"type": "object",
"additionalProperties": false,
"properties": {
"experimental-test-coverage": {
"type": "boolean"
},
"experimental-test-module-mocks": {
"type": "boolean"
},
"test-concurrency": {
"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-force-exit": {
"type": "boolean"
},
"test-global-setup": {
"type": "string"
},
"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"
}
]
},
"test-timeout": {
"type": "number"
},
"test-udp-no-try-send": {
"type": "boolean"
},
"test-update-snapshots": {
"type": "boolean"
}
}
}
},
"type": "object"
Expand Down
71 changes: 57 additions & 14 deletions lib/internal/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {
getCLIOptionsInfo,
getEmbedderOptions: getEmbedderOptionsFromBinding,
getEnvOptionsInputType,
getNamespaceOptionsInputType,
} = internalBinding('options');

let warnOnAllowUnauthorized = true;
Expand All @@ -38,7 +39,22 @@ function getEmbedderOptions() {
}

function generateConfigJsonSchema() {
const map = getEnvOptionsInputType();
const envOptionsMap = getEnvOptionsInputType();
const namespaceOptionsMap = getNamespaceOptionsInputType();

function createPropertyForType(key, type) {
if (type === 'array') {
return {
__proto__: null,
oneOf: [
{ __proto__: null, type: 'string' },
{ __proto__: null, items: { __proto__: null, type: 'string', minItems: 1 }, type: 'array' },
],
};
}

return { __proto__: null, type };
}

const schema = {
__proto__: null,
Expand All @@ -60,31 +76,58 @@ function generateConfigJsonSchema() {
type: 'object',
};

const nodeOptions = schema.properties.nodeOptions.properties;
// Get the root properties object for adding namespaces
const rootProperties = schema.properties;
const nodeOptions = rootProperties.nodeOptions.properties;

for (const { 0: key, 1: type } of map) {
// Add env options to nodeOptions (backward compatibility)
for (const { 0: key, 1: type } of envOptionsMap) {
const keyWithoutPrefix = StringPrototypeReplace(key, '--', '');
if (type === 'array') {
nodeOptions[keyWithoutPrefix] = {
__proto__: null,
oneOf: [
{ __proto__: null, type: 'string' },
{ __proto__: null, items: { __proto__: null, type: 'string', minItems: 1 }, type: 'array' },
],
};
} else {
nodeOptions[keyWithoutPrefix] = { __proto__: null, type };
nodeOptions[keyWithoutPrefix] = createPropertyForType(key, type);
}

// Add namespace properties at the root level
for (const { 0: namespace, 1: optionsMap } of namespaceOptionsMap) {
// Create namespace object at the root level
rootProperties[namespace] = {
__proto__: null,
type: 'object',
additionalProperties: false,
properties: { __proto__: null },
};

const namespaceProperties = rootProperties[namespace].properties;

// Add all options for this namespace
for (const { 0: optionName, 1: optionType } of optionsMap) {
const keyWithoutPrefix = StringPrototypeReplace(optionName, '--', '');
namespaceProperties[keyWithoutPrefix] = createPropertyForType(optionName, optionType);
}

// Sort the namespace properties alphabetically
const sortedNamespaceKeys = ArrayPrototypeSort(ObjectKeys(namespaceProperties));
const sortedNamespaceProperties = ObjectFromEntries(
ArrayPrototypeMap(sortedNamespaceKeys, (key) => [key, namespaceProperties[key]]),
);
rootProperties[namespace].properties = sortedNamespaceProperties;
}

// Sort the proerties by key alphabetically.
// Sort the top-level properties by key alphabetically
const sortedKeys = ArrayPrototypeSort(ObjectKeys(nodeOptions));
const sortedProperties = ObjectFromEntries(
ArrayPrototypeMap(sortedKeys, (key) => [key, nodeOptions[key]]),
);

schema.properties.nodeOptions.properties = sortedProperties;

// Also sort the root level properties
const sortedRootKeys = ArrayPrototypeSort(ObjectKeys(rootProperties));
const sortedRootProperties = ObjectFromEntries(
ArrayPrototypeMap(sortedRootKeys, (key) => [key, rootProperties[key]]),
);

schema.properties = sortedRootProperties;

return schema;
}

Expand Down
8 changes: 7 additions & 1 deletion lib/internal/test_runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,13 @@ let debug = require('internal/util/debuglog').debuglog('test_runner', (fn) => {
});

const kIsolatedProcessName = Symbol('kIsolatedProcessName');
const kFilterArgs = ['--test', '--experimental-test-coverage', '--watch'];
const kFilterArgs = [
'--test',
'--experimental-test-coverage',
'--watch',
'--experimental-default-config-file',
'-experimental-config-file',
];
const kFilterArgValues = ['--test-reporter', '--test-reporter-destination'];
const kDiagnosticsFilterArgs = ['tests', 'suites', 'pass', 'fail', 'cancelled', 'skipped', 'todo', 'duration_ms'];

Expand Down
14 changes: 13 additions & 1 deletion src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,19 @@ static ExitCode InitializeNodeWithArgsInternal(
#endif

if (!(flags & ProcessInitializationFlags::kDisableCLIOptions)) {
const ExitCode exit_code =
// Parse the options coming from the config file.
// This is done before parsing the command line options
// as the cli flags are expected to override the config file ones.
std::vector<std::string> extra_argv =
per_process::config_reader.AssignNodeNonEnvOptions();
// [0] is expected to be the program name, fill it in from the real argv.
extra_argv.insert(extra_argv.begin(), argv->at(0));
// Parse the extra argv coming from the config file
ExitCode exit_code = ProcessGlobalArgsInternal(
&extra_argv, nullptr, errors, kDisallowedInEnvvar);
if (exit_code != ExitCode::kNoFailure) return exit_code;
// Parse options coming from the command line.
exit_code =
ProcessGlobalArgsInternal(argv, exec_argv, errors, kDisallowedInEnvvar);
if (exit_code != ExitCode::kNoFailure) return exit_code;
}
Expand Down
Loading