diff --git a/doc/api/cli.md b/doc/api/cli.md index 5c2a5820bc21a0..44334792e1514f 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -3052,7 +3052,6 @@ one is included in the list below. * `--experimental-abortcontroller` * `--experimental-async-context-frame` * `--experimental-default-type` -* `--experimental-detect-module` * `--experimental-eventsource` * `--experimental-import-meta-resolve` * `--experimental-json-modules` @@ -3060,7 +3059,6 @@ one is included in the list below. * `--experimental-modules` * `--experimental-permission` * `--experimental-print-required-tla` -* `--experimental-require-module` * `--experimental-shadow-realm` * `--experimental-specifier-resolution` * `--experimental-sqlite` @@ -3093,8 +3091,10 @@ one is included in the list below. * `--network-family-autoselection-attempt-timeout` * `--no-addons` * `--no-deprecation` +* `--no-experimental-detect-module` * `--no-experimental-global-navigator` * `--no-experimental-repl-await` +* `--no-experimental-require-module` * `--no-experimental-websocket` * `--no-extra-info-on-fatal-exception` * `--no-force-async-hooks-checks` diff --git a/test/parallel/test-cli-node-options-docs.js b/test/parallel/test-cli-node-options-docs.js index ef82489d044171..2171c12b72fcca 100644 --- a/test/parallel/test-cli-node-options-docs.js +++ b/test/parallel/test-cli-node-options-docs.js @@ -1,129 +1,90 @@ 'use strict'; -const common = require('../common'); -if (process.config.variables.node_without_node_options) - common.skip('missing NODE_OPTIONS support'); - -// Test options specified by env variable. +const common = require('../common'); const assert = require('assert'); const fs = require('fs'); const path = require('path'); +const { test } = require('node:test'); -const rootDir = path.resolve(__dirname, '..', '..'); -const cliMd = path.join(rootDir, 'doc', 'api', 'cli.md'); -const cliText = fs.readFileSync(cliMd, { encoding: 'utf8' }); - -const internalApiMd = path.join(rootDir, 'doc', 'contributing', 'internal-api.md'); -const internalApiText = fs.readFileSync(internalApiMd, { encoding: 'utf8' }); +// Skip test if NODE_OPTIONS support is missing +if (process.config.variables.node_without_node_options) { + common.skip('missing NODE_OPTIONS support'); +} -const nodeOptionsCC = fs.readFileSync(path.resolve(rootDir, 'src', 'node_options.cc'), 'utf8'); +const rootDir = path.resolve(__dirname, '..', '..'); +const cliFilePath = path.join(rootDir, 'doc', 'api', 'cli.md'); +const internalApiFilePath = path.join(rootDir, 'doc', 'contributing', 'internal-api.md'); +const manPagePath = path.join(rootDir, 'doc', 'node.1'); +const nodeOptionsCCPath = path.join(rootDir, 'src', 'node_options.cc'); + +// Read files +const cliText = fs.readFileSync(cliFilePath, 'utf8'); +const internalApiText = fs.readFileSync(internalApiFilePath, 'utf8'); +const manPageText = fs.readFileSync(manPagePath, 'utf8'); +const nodeOptionsCC = fs.readFileSync(nodeOptionsCCPath, 'utf8'); + +// Regular Expressions const addOptionRE = /AddOption[\s\n\r]*\([\s\n\r]*"([^"]+)"(.*?)\);/gs; - const nodeOptionsText = cliText.match(/(.*)/s)[1]; const v8OptionsText = cliText.match(/(.*)/s)[1]; -const manPage = path.join(rootDir, 'doc', 'node.1'); -const manPageText = fs.readFileSync(manPage, { encoding: 'utf8' }); - -// Documented in /doc/api/deprecations.md -const deprecated = [ - '--debug', - '--debug-brk', -]; - - -const manPagesOptions = new Set(); +// Deprecated options +const deprecatedOptions = new Set(['--debug', '--debug-brk']); -for (const [, envVar] of manPageText.matchAll(/\.It Fl (-[a-zA-Z0-9._-]+)/g)) { - manPagesOptions.add(envVar); -} +// Helper Functions +const isOptionDocumentedInCli = (envVar) => new RegExp(`###.*\`${envVar}[[=\\s\\b\`]`).test(cliText); +const isOptionDocumentedInInternalApi = (envVar) => new RegExp(`####.*\`${envVar}[[=\\s\\b\`]`).test(internalApiText); +const isOptionDocumentedInV8 = (envVar) => new RegExp(`###.*\`${envVar}[[=\\s\\b\`]`).test(v8OptionsText); +const isOptionInNodeOptions = (envVar) => new RegExp(`\`${envVar}\``).test(nodeOptionsText); -for (const [, envVar, config] of nodeOptionsCC.matchAll(addOptionRE)) { - let hasTrueAsDefaultValue = false; - let isInNodeOption = false; +const validateOption = (envVar, config) => { + let hasTrueAsDefault = false; + let isInNodeOptions = false; let isV8Option = false; - let isNoOp = false; + const isNoOp = config.includes('NoOp{}'); - if (config.includes('NoOp{}')) { - isNoOp = true; - } + // Check option categories + if (config.includes('kAllowedInEnvvar')) isInNodeOptions = true; + if (config.includes('V8Option{}')) isV8Option = true; + if (/^\s*true\s*$/.test(config.split(',').pop())) hasTrueAsDefault = true; - if (config.includes('kAllowedInEnvvar')) { - isInNodeOption = true; - } - if (config.includes('kDisallowedInEnvvar')) { - isInNodeOption = false; + const manpageEntry = hasTrueAsDefault ? `-no${envVar.slice(1)}` : envVar.slice(1); + if (envVar.startsWith('[') || deprecatedOptions.has(envVar) || isNoOp) { + return; } - if (config.includes('V8Option{}')) { - isV8Option = true; + if (isOptionDocumentedInInternalApi(envVar)) { + return; } - if (/^\s*true\s*$/.test(config.split(',').pop())) { - hasTrueAsDefaultValue = true; + if (!isV8Option && !hasTrueAsDefault && !isOptionDocumentedInCli(envVar)) { + assert.fail(`Should have option ${envVar} documented`); } - if ( - envVar.startsWith('[') || - deprecated.includes(envVar) || - isNoOp - ) { - // assert(!manPagesOptions.has(envVar.slice(1)), `Option ${envVar} should not be documented`) - manPagesOptions.delete(envVar.slice(1)); - continue; + if (!hasTrueAsDefault && isOptionDocumentedInCli(`--no${envVar.slice(1)}`)) { + assert.fail(`Should not have option --no${envVar.slice(1)} documented`); } - // Internal API options are documented in /doc/contributing/internal-api.md - if (new RegExp(`####.*\`${envVar}[[=\\s\\b\`]`).test(internalApiText) === true) { - manPagesOptions.delete(envVar.slice(1)); - continue; + if (!isV8Option && hasTrueAsDefault && !isOptionDocumentedInCli(`--no${envVar.slice(1)}`)) { + assert.fail(`Should have option --no${envVar.slice(1)} documented`); } - // CLI options - if (!isV8Option && !hasTrueAsDefaultValue) { - if (new RegExp(`###.*\`${envVar}[[=\\s\\b\`]`).test(cliText) === false) { - assert(false, `Should have option ${envVar} documented`); - } else { - manPagesOptions.delete(envVar.slice(1)); - } + if (isInNodeOptions && !hasTrueAsDefault && !isOptionInNodeOptions(envVar)) { + assert.fail(`Should have option ${envVar} in NODE_OPTIONS documented`); } - if (!hasTrueAsDefaultValue && new RegExp(`###.*\`--no${envVar.slice(1)}[[=\\s\\b\`]`).test(cliText) === true) { - assert(false, `Should not have option --no${envVar.slice(1)} documented`); + if (isInNodeOptions && hasTrueAsDefault && !isOptionInNodeOptions(`--no${envVar.slice(1)}`)) { + assert.fail(`Should have option --no${envVar.slice(1)} in NODE_OPTIONS documented`); } - if (!isV8Option && hasTrueAsDefaultValue) { - if (new RegExp(`###.*\`--no${envVar.slice(1)}[[=\\s\\b\`]`).test(cliText) === false) { - assert(false, `Should have option --no${envVar.slice(1)} documented`); - } else { - manPagesOptions.delete(`-no${envVar.slice(1)}`); - } + if (isV8Option && !isOptionDocumentedInV8(envVar)) { + assert.fail(`Should have option ${envVar} in V8 options documented`); } - // NODE_OPTIONS - if (isInNodeOption && !hasTrueAsDefaultValue && new RegExp(`\`${envVar}\``).test(nodeOptionsText) === false) { - assert(false, `Should have option ${envVar} in NODE_OPTIONS documented`); - } - - if (isInNodeOption && hasTrueAsDefaultValue && new RegExp(`\`--no${envVar.slice(1)}\``).test(cliText) === false) { - assert(false, `Should have option --no${envVar.slice(1)} in NODE_OPTIONS documented`); - } + assert(manPageText.includes(manpageEntry), `Should have option ${envVar} in node.1`); +}; - if (!hasTrueAsDefaultValue && new RegExp(`\`--no${envVar.slice(1)}\``).test(cliText) === true) { - assert(false, `Should not have option --no${envVar.slice(1)} in NODE_OPTIONS documented`); - } - - // V8 options - if (isV8Option) { - if (new RegExp(`###.*\`${envVar}[[=\\s\\b\`]`).test(v8OptionsText) === false) { - assert(false, `Should have option ${envVar} in V8 options documented`); - } else { - manPagesOptions.delete(envVar.slice(1)); - } - } +// Parse node options from source file +for (const [, envVar, config] of nodeOptionsCC.matchAll(addOptionRE)) { + test(envVar, () => validateOption(envVar, config)); } - -// add alias handling -manPagesOptions.delete('-trace-events-enabled'); - -assert.strictEqual(manPagesOptions.size, 0, `Man page options not documented: ${[...manPagesOptions]}`);