From ef21a138287a4e84f5e53624b236b6f9c78ee4c1 Mon Sep 17 00:00:00 2001 From: Daijiro Wachi Date: Sun, 14 Jun 2026 02:34:41 +0900 Subject: [PATCH] cli: fix env vars missing from `node --help` The `envVars` table in print_help.js was built with a malformed expression that silently dropped entries from the help output: 1. The closing parenthesis of `ArrayPrototypeConcat()` was placed after the `hasIntl` argument, so the `hasNodeOptions` and `hasCrypto` lists were passed as extra arguments to `new SafeMap()`, which ignores everything after the first. As a result NODE_OPTIONS, OPENSSL_CONF, SSL_CERT_DIR and SSL_CERT_FILE never appeared. 2. The NODE_ICU_DATA helpText used `'...' + hasSmallICU ? '' : '...'`, which parses as `('...' + hasSmallICU) ? '' : '...'` and is always the empty string. Since format() skips entries with falsy helpText, the NODE_ICU_DATA entry was dropped as well. The existing test only checked for the bare `NODE_ICU_DATA` and `OPENSSL_CONF` substrings, which also occur in the `--icu-data-dir` and `--openssl-config` descriptions, so the missing entries went unnoticed. The added test parses the "Environment variables:" section and asserts each entry appears at the start of a line. Signed-off-by: Daijiro Wachi --- lib/internal/main/print_help.js | 8 ++--- test/parallel/test-cli-node-print-help.js | 41 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/lib/internal/main/print_help.js b/lib/internal/main/print_help.js index 62269956be9faf..d99f23f42520ec 100644 --- a/lib/internal/main/print_help.js +++ b/lib/internal/main/print_help.js @@ -72,17 +72,17 @@ const envVars = new SafeMap(ArrayPrototypeConcat([ 'libuv\'s threadpool' }], ], hasIntl ? [ ['NODE_ICU_DATA', { helpText: 'data path for ICU (Intl object) data' + - hasSmallICU ? '' : ' (will extend linked-in data)' }], -] : []), (hasNodeOptions ? [ + (hasSmallICU ? '' : ' (will extend linked-in data)') }], +] : [], hasNodeOptions ? [ ['NODE_OPTIONS', { helpText: 'set CLI options in the environment via a ' + 'space-separated list' }], -] : []), hasCrypto ? [ +] : [], hasCrypto ? [ ['OPENSSL_CONF', { helpText: 'load OpenSSL configuration from file' }], ['SSL_CERT_DIR', { helpText: 'sets OpenSSL\'s directory of trusted ' + 'certificates when used in conjunction with --use-openssl-ca' }], ['SSL_CERT_FILE', { helpText: 'sets OpenSSL\'s trusted certificate file ' + 'when used in conjunction with --use-openssl-ca' }], -] : []); +] : [])); function indent(text, depth) { diff --git a/test/parallel/test-cli-node-print-help.js b/test/parallel/test-cli-node-print-help.js index f42129eb133026..478ddea73929c9 100644 --- a/test/parallel/test-cli-node-print-help.js +++ b/test/parallel/test-cli-node-print-help.js @@ -36,6 +36,47 @@ function validateNodePrintHelp() { ]; cliHelpOptions.forEach(testForSubstring); + + validateEnvVarSection(); +} + +// Verify that the "Environment variables:" section lists the expected +// entries. Each entry is printed at the start of its own line, so matching +// against the start of a line avoids false positives from names that also +// appear inside an option's description (e.g. `--icu-data-dir` mentions +// "overrides NODE_ICU_DATA" and `--openssl-config` mentions +// "overrides OPENSSL_CONF"). These checks guard against malformed +// construction of the environment-variable list that would silently drop +// entries from the help output. +function validateEnvVarSection() { + const { internalBinding } = require('internal/test/binding'); + const { hasNodeOptions } = internalBinding('config'); + + const start = stdOut.indexOf('Environment variables:'); + assert.ok(start !== -1, 'Missing "Environment variables:" section'); + const end = stdOut.indexOf('Documentation can be found', start); + const envSection = stdOut.slice(start, end === -1 ? undefined : end); + + const expectedEnvVars = [ + { name: 'FORCE_COLOR', present: true }, + { name: 'NODE_PATH', present: true }, + { name: 'NODE_ICU_DATA', present: common.hasIntl }, + { name: 'NODE_OPTIONS', present: hasNodeOptions }, + { name: 'OPENSSL_CONF', present: common.hasCrypto }, + { name: 'SSL_CERT_DIR', present: common.hasCrypto }, + { name: 'SSL_CERT_FILE', present: common.hasCrypto }, + ]; + + for (const { name, present } of expectedEnvVars) { + const re = new RegExp(`^${name}\\b`, 'm'); + if (present) { + assert.match(envSection, re, + `Missing environment variable ${name} in:\n${envSection}`); + } else { + assert.doesNotMatch(envSection, re, + `Unexpected environment variable ${name} in:\n${envSection}`); + } + } } function testForSubstring(options) {