'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 assert = require('assert'); const fs = require('fs'); const path = require('path'); 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' }); const nodeOptionsCC = fs.readFileSync(path.resolve(rootDir, 'src', 'node_options.cc'), 'utf8'); 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(); for (const [, envVar] of manPageText.matchAll(/\.It Fl (-[a-zA-Z0-9._-]+)/g)) { manPagesOptions.add(envVar); } for (const [, envVar, config] of nodeOptionsCC.matchAll(addOptionRE)) { const hasTrueAsDefaultValue = /,\s*(?:true|HAVE_[A-Z_]+)\s*$/.test(config); const isInNodeOption = config.includes('kAllowedInEnvvar') && !config.includes('kDisallowedInEnvvar'); const isV8Option = config.includes('V8Option{}'); const isNoOp = config.includes('NoOp{}'); 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; } // Internal API options are documented in /doc/contributing/internal-api.md if (new RegExp(`####.*\`${RegExp.escape(envVar)}[[=\\s\\b\`]`).test(internalApiText)) { manPagesOptions.delete(envVar.slice(1)); continue; } // CLI options if (!isV8Option && !hasTrueAsDefaultValue) { if (!new RegExp(`###.*\`${RegExp.escape(envVar)}[[=\\s\\b\`]`).test(cliText)) { assert.fail(`Should have option ${envVar} documented`); } else { manPagesOptions.delete(envVar.slice(1)); } } if (!hasTrueAsDefaultValue && new RegExp(`###.*\`--no${RegExp.escape(envVar.slice(1))}[[=\\s\\b\`]`).test(cliText)) { assert.fail(`Should not have option --no${envVar.slice(1)} documented`); } if (!isV8Option && hasTrueAsDefaultValue) { if (!new RegExp(`###.*\`--no${RegExp.escape(envVar.slice(1))}[[=\\s\\b\`]`).test(cliText)) { assert.fail(`Should have option --no${envVar.slice(1)} documented`); } else { manPagesOptions.delete(`-no${envVar.slice(1)}`); } } // NODE_OPTIONS if (isInNodeOption && !hasTrueAsDefaultValue && !new RegExp(`\`${RegExp.escape(envVar)}\``).test(nodeOptionsText)) { assert.fail(`Should have option ${envVar} in NODE_OPTIONS documented`); } if (isInNodeOption && hasTrueAsDefaultValue && !new RegExp(`\`--no${RegExp.escape(envVar.slice(1))}\``).test(cliText)) { assert.fail(`Should have option --no${envVar.slice(1)} in NODE_OPTIONS documented`); } if (!hasTrueAsDefaultValue && new RegExp(`\`--no${RegExp.escape(envVar.slice(1))}\``).test(cliText)) { assert.fail(`Should not have option --no${envVar.slice(1)} in NODE_OPTIONS documented`); } // V8 options if (isV8Option) { if (!new RegExp(`###.*\`${RegExp.escape(envVar)}[[=\\s\\b\`]`).test(v8OptionsText)) { assert.fail(`Should have option ${envVar} in V8 options documented`); } else { manPagesOptions.delete(envVar.slice(1)); } } } { const sections = /^## (.+)$/mg; const cliOptionPattern = /^### (?:`-\w.*`, )?`([^`]+)`/mg; let match; let previousIndex = 0; do { const sectionTitle = match?.[1]; match = sections.exec(cliText); const filteredCLIText = cliText.slice(previousIndex, match?.index); const options = Array.from(filteredCLIText.matchAll(cliOptionPattern), (match) => match[1]); assert.deepStrictEqual(options, options.toSorted(), `doc/api/cli.md ${sectionTitle} subsections are not in alphabetical order`); previousIndex = match?.index; } while (match); } // add alias handling manPagesOptions.delete('-trace-events-enabled'); assert.strictEqual(manPagesOptions.size, 0, `Man page options not documented: ${[...manPagesOptions]}`);