cli: generate --help text in JS
Instead of having a custom, static, hand-written string that is being printed to stdout when `--help` is present, generate it in JS when requested. PR-URL: https://github.com/nodejs/node/pull/22490 Reviewed-By: Michaël Zasso <targos@protonmail.com>
This commit is contained in:
parent
e812be4a55
commit
c8880ea276
@ -105,6 +105,11 @@
|
||||
NativeModule.require('internal/inspector_async_hook').setup();
|
||||
}
|
||||
|
||||
if (internalBinding('options').getOptions('--help')) {
|
||||
NativeModule.require('internal/print_help').print(process.stdout);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMainThread) {
|
||||
mainThreadSetup.setupChildProcessIpcChannel();
|
||||
}
|
||||
|
151
lib/internal/print_help.js
Normal file
151
lib/internal/print_help.js
Normal file
@ -0,0 +1,151 @@
|
||||
'use strict';
|
||||
const { internalBinding } = require('internal/bootstrap/loaders');
|
||||
const { getOptions, types } = internalBinding('options');
|
||||
|
||||
const typeLookup = [];
|
||||
for (const key of Object.keys(types))
|
||||
typeLookup[types[key]] = key;
|
||||
|
||||
// Environment variables are parsed ad-hoc throughout the code base,
|
||||
// so we gather the documentation here.
|
||||
const { hasIntl, hasSmallICU, hasNodeOptions } = process.binding('config');
|
||||
const envVars = new Map([
|
||||
['NODE_DEBUG', { helpText: "','-separated list of core modules that " +
|
||||
'should print debug information' }],
|
||||
['NODE_DEBUG_NATIVE', { helpText: "','-separated list of C++ core debug " +
|
||||
'categories that should print debug output' }],
|
||||
['NODE_DISABLE_COLORS', { helpText: 'set to 1 to disable colors in ' +
|
||||
'the REPL' }],
|
||||
['NODE_EXTRA_CA_CERTS', { helpText: 'path to additional CA certificates ' +
|
||||
'file' }],
|
||||
['NODE_NO_WARNINGS', { helpText: 'set to 1 to silence process warnings' }],
|
||||
['NODE_PATH', { helpText: `'${require('path').delimiter}'-separated list ` +
|
||||
'of directories prefixed to the module search path' }],
|
||||
['NODE_PENDING_DEPRECATION', { helpText: 'set to 1 to emit pending ' +
|
||||
'deprecation warnings' }],
|
||||
['NODE_PRESERVE_SYMLINKS', { helpText: 'set to 1 to preserve symbolic ' +
|
||||
'links when resolving and caching modules' }],
|
||||
['NODE_REDIRECT_WARNINGS', { helpText: 'write warnings to path instead ' +
|
||||
'of stderr' }],
|
||||
['NODE_REPL_HISTORY', { helpText: 'path to the persistent REPL ' +
|
||||
'history file' }],
|
||||
['OPENSSL_CONF', { helpText: 'load OpenSSL configuration from file' }]
|
||||
].concat(hasIntl ? [
|
||||
['NODE_ICU_DATA', { helpText: 'data path for ICU (Intl object) data' +
|
||||
hasSmallICU ? '' : ' (will extend linked-in data)' }]
|
||||
] : []).concat(hasNodeOptions ? [
|
||||
['NODE_OPTIONS', { helpText: 'set CLI options in the environment via a ' +
|
||||
'space-separated list' }]
|
||||
] : []));
|
||||
|
||||
|
||||
function indent(text, depth) {
|
||||
return text.replace(/^/gm, ' '.repeat(depth));
|
||||
}
|
||||
|
||||
function fold(text, width) {
|
||||
return text.replace(new RegExp(`([^\n]{0,${width}})( |$)`, 'g'),
|
||||
(_, newLine, end) => newLine + (end === ' ' ? '\n' : ''));
|
||||
}
|
||||
|
||||
function getArgDescription(type) {
|
||||
switch (typeLookup[type]) {
|
||||
case 'kNoOp':
|
||||
case 'kV8Option':
|
||||
case 'kBoolean':
|
||||
break;
|
||||
case 'kHostPort':
|
||||
return '[host:]port';
|
||||
case 'kInteger':
|
||||
case 'kString':
|
||||
case 'kStringList':
|
||||
return '...';
|
||||
case undefined:
|
||||
break;
|
||||
default:
|
||||
require('assert').fail(`unknown option type ${type}`);
|
||||
}
|
||||
}
|
||||
|
||||
function format({ options, aliases = new Map(), firstColumn, secondColumn }) {
|
||||
let text = '';
|
||||
|
||||
for (const [
|
||||
name, { helpText, type, value }
|
||||
] of [...options.entries()].sort()) {
|
||||
if (!helpText) continue;
|
||||
|
||||
let displayName = name;
|
||||
const argDescription = getArgDescription(type);
|
||||
if (argDescription)
|
||||
displayName += `=${argDescription}`;
|
||||
|
||||
for (const [ from, to ] of aliases) {
|
||||
// For cases like e.g. `-e, --eval`.
|
||||
if (to[0] === name && to.length === 1) {
|
||||
displayName = `${from}, ${displayName}`;
|
||||
}
|
||||
|
||||
// For cases like `--inspect-brk[=[host:]port]`.
|
||||
const targetInfo = options.get(to[0]);
|
||||
const targetArgDescription =
|
||||
targetInfo ? getArgDescription(targetInfo.type) : '...';
|
||||
if (from === `${name}=`) {
|
||||
displayName += `[=${targetArgDescription}]`;
|
||||
} else if (from === `${name} <arg>`) {
|
||||
displayName += ` [${targetArgDescription}]`;
|
||||
}
|
||||
}
|
||||
|
||||
let displayHelpText = helpText;
|
||||
if (value === true) {
|
||||
// Mark boolean options we currently have enabled.
|
||||
// In particular, it indicates whether --use-openssl-ca
|
||||
// or --use-bundled-ca is the (current) default.
|
||||
displayHelpText += ' (currently set)';
|
||||
}
|
||||
|
||||
text += displayName;
|
||||
if (displayName.length >= firstColumn)
|
||||
text += '\n' + ' '.repeat(firstColumn);
|
||||
else
|
||||
text += ' '.repeat(firstColumn - displayName.length);
|
||||
|
||||
text += indent(fold(displayHelpText, secondColumn),
|
||||
firstColumn).trimLeft() + '\n';
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
function print(stream) {
|
||||
const { options, aliases } = getOptions();
|
||||
|
||||
// TODO(addaleax): Allow a bit of expansion depending on `stream.columns`
|
||||
// if it is set.
|
||||
const firstColumn = 28;
|
||||
const secondColumn = 40;
|
||||
|
||||
options.set('-', { helpText: 'script read from stdin (default; ' +
|
||||
'interactive mode if a tty)' });
|
||||
options.set('--', { helpText: 'indicate the end of node options' });
|
||||
stream.write(
|
||||
'Usage: node [options] [ -e script | script.js | - ] [arguments]\n' +
|
||||
' node inspect script.js [arguments]\n\n' +
|
||||
'Options:\n');
|
||||
stream.write(indent(format({
|
||||
options, aliases, firstColumn, secondColumn
|
||||
}), 2));
|
||||
|
||||
stream.write('\nEnvironment variables:\n');
|
||||
|
||||
stream.write(format({
|
||||
options: envVars, firstColumn, secondColumn
|
||||
}));
|
||||
|
||||
stream.write('\nDocumentation can be found at https://nodejs.org/\n');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
print
|
||||
};
|
1
node.gyp
1
node.gyp
@ -132,6 +132,7 @@
|
||||
'lib/internal/modules/esm/translators.js',
|
||||
'lib/internal/safe_globals.js',
|
||||
'lib/internal/net.js',
|
||||
'lib/internal/print_help.js',
|
||||
'lib/internal/priority_queue.js',
|
||||
'lib/internal/process/esm_loader.js',
|
||||
'lib/internal/process/main_thread_only.js',
|
||||
|
154
src/node.cc
154
src/node.cc
@ -2348,155 +2348,6 @@ void LoadEnvironment(Environment* env) {
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintHelp() {
|
||||
printf("Usage: node [options] [ -e script | script.js | - ] [arguments]\n"
|
||||
" node inspect script.js [arguments]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" - script read from stdin (default; \n"
|
||||
" interactive mode if a tty)\n"
|
||||
" -- indicate the end of node options\n"
|
||||
" --abort-on-uncaught-exception\n"
|
||||
" aborting instead of exiting causes a\n"
|
||||
" core file to be generated for analysis\n"
|
||||
#if HAVE_OPENSSL && NODE_FIPS_MODE
|
||||
" --enable-fips enable FIPS crypto at startup\n"
|
||||
#endif // NODE_FIPS_MODE && NODE_FIPS_MODE
|
||||
" --experimental-modules experimental ES Module support\n"
|
||||
" and caching modules\n"
|
||||
" --experimental-repl-await experimental await keyword support\n"
|
||||
" in REPL\n"
|
||||
" --experimental-vm-modules experimental ES Module support\n"
|
||||
" in vm module\n"
|
||||
" --experimental-worker experimental threaded Worker support\n"
|
||||
#if HAVE_OPENSSL && NODE_FIPS_MODE
|
||||
" --force-fips force FIPS crypto (cannot be disabled)\n"
|
||||
#endif // HAVE_OPENSSL && NODE_FIPS_MODE
|
||||
#if defined(NODE_HAVE_I18N_SUPPORT)
|
||||
" --icu-data-dir=dir set ICU data load path to dir\n"
|
||||
" (overrides NODE_ICU_DATA)\n"
|
||||
#if !defined(NODE_HAVE_SMALL_ICU)
|
||||
" note: linked-in ICU data is present\n"
|
||||
#endif
|
||||
#endif // defined(NODE_HAVE_I18N_SUPPORT)
|
||||
#if HAVE_INSPECTOR
|
||||
" --inspect-brk[=[host:]port]\n"
|
||||
" activate inspector on host:port\n"
|
||||
" and break at start of user script\n"
|
||||
" --inspect-port=[host:]port\n"
|
||||
" set host:port for inspector\n"
|
||||
" --inspect[=[host:]port] activate inspector on host:port\n"
|
||||
" (default: 127.0.0.1:9229)\n"
|
||||
#endif // HAVE_INSPECTOR
|
||||
" --loader=file (with --experimental-modules) use the \n"
|
||||
" specified file as a custom loader\n"
|
||||
" for ECMAScript Modules \n"
|
||||
" --napi-modules load N-API modules (no-op - option\n"
|
||||
" kept for compatibility)\n"
|
||||
" --no-deprecation silence deprecation warnings\n"
|
||||
" --no-force-async-hooks-checks\n"
|
||||
" disable checks for async_hooks\n"
|
||||
" --no-warnings silence all process warnings\n"
|
||||
#if HAVE_OPENSSL
|
||||
" --openssl-config=file load OpenSSL configuration from the\n"
|
||||
" specified file (overrides\n"
|
||||
" OPENSSL_CONF)\n"
|
||||
#endif // HAVE_OPENSSL
|
||||
" --pending-deprecation emit pending deprecation warnings\n"
|
||||
" --preserve-symlinks preserve symbolic links when resolving\n"
|
||||
" --preserve-symlinks-main preserve symbolic links when resolving\n"
|
||||
" the main module\n"
|
||||
" --prof generate V8 profiler output\n"
|
||||
" --prof-process process V8 profiler output generated\n"
|
||||
" using --prof\n"
|
||||
" --redirect-warnings=file\n"
|
||||
" write warnings to file instead of\n"
|
||||
" stderr\n"
|
||||
" --throw-deprecation throw an exception on deprecations\n"
|
||||
" --title=title the process title to use on start up\n"
|
||||
#if HAVE_OPENSSL
|
||||
" --tls-cipher-list=val use an alternative default TLS cipher "
|
||||
"list\n"
|
||||
#endif // HAVE_OPENSSL
|
||||
" --trace-deprecation show stack traces on deprecations\n"
|
||||
" --trace-event-categories comma separated list of trace event\n"
|
||||
" categories to record\n"
|
||||
" --trace-event-file-pattern Template string specifying the\n"
|
||||
" filepath for the trace-events data, it\n"
|
||||
" supports ${rotation} and ${pid}\n"
|
||||
" log-rotation id. %%2$u is the pid.\n"
|
||||
" --trace-events-enabled track trace events\n"
|
||||
" --trace-sync-io show stack trace when use of sync IO\n"
|
||||
" is detected after the first tick\n"
|
||||
" --trace-warnings show stack traces on process warnings\n"
|
||||
" --track-heap-objects track heap object allocations for heap "
|
||||
"snapshots\n"
|
||||
#if HAVE_OPENSSL
|
||||
" --use-bundled-ca use bundled CA store"
|
||||
#if !defined(NODE_OPENSSL_CERT_STORE)
|
||||
" (default)"
|
||||
#endif
|
||||
"\n"
|
||||
" --use-openssl-ca use OpenSSL's default CA store"
|
||||
#if defined(NODE_OPENSSL_CERT_STORE)
|
||||
" (default)"
|
||||
#endif
|
||||
#endif // HAVE_OPENSSL
|
||||
"\n"
|
||||
" --v8-options print v8 command line options\n"
|
||||
" --v8-pool-size=num set v8's thread pool size\n"
|
||||
" --zero-fill-buffers automatically zero-fill all newly "
|
||||
"allocated\n"
|
||||
" Buffer and SlowBuffer instances\n"
|
||||
" -c, --check syntax check script without executing\n"
|
||||
" -e, --eval script evaluate script\n"
|
||||
" -h, --help print node command line options\n"
|
||||
" -i, --interactive always enter the REPL even if stdin\n"
|
||||
" does not appear to be a terminal\n"
|
||||
" -p, --print evaluate script and print result\n"
|
||||
" -r, --require module to preload (option can be "
|
||||
"repeated)\n"
|
||||
" -v, --version print Node.js version\n"
|
||||
"\n"
|
||||
"Environment variables:\n"
|
||||
"NODE_DEBUG ','-separated list of core modules\n"
|
||||
" that should print debug information\n"
|
||||
"NODE_DEBUG_NATIVE ','-separated list of C++ core debug\n"
|
||||
" categories that should print debug\n"
|
||||
" output\n"
|
||||
"NODE_DISABLE_COLORS set to 1 to disable colors in the REPL\n"
|
||||
"NODE_EXTRA_CA_CERTS path to additional CA certificates\n"
|
||||
" file\n"
|
||||
#if defined(NODE_HAVE_I18N_SUPPORT)
|
||||
"NODE_ICU_DATA data path for ICU (Intl object) data\n"
|
||||
#if !defined(NODE_HAVE_SMALL_ICU)
|
||||
" (will extend linked-in data)\n"
|
||||
#endif
|
||||
#endif // defined(NODE_HAVE_I18N_SUPPORT)
|
||||
"NODE_NO_WARNINGS set to 1 to silence process warnings\n"
|
||||
#if !defined(NODE_WITHOUT_NODE_OPTIONS)
|
||||
"NODE_OPTIONS set CLI options in the environment\n"
|
||||
" via a space-separated list\n"
|
||||
#endif // !defined(NODE_WITHOUT_NODE_OPTIONS)
|
||||
#ifdef _WIN32
|
||||
"NODE_PATH ';'-separated list of directories\n"
|
||||
#else
|
||||
"NODE_PATH ':'-separated list of directories\n"
|
||||
#endif
|
||||
" prefixed to the module search path\n"
|
||||
"NODE_PENDING_DEPRECATION set to 1 to emit pending deprecation\n"
|
||||
" warnings\n"
|
||||
"NODE_PRESERVE_SYMLINKS set to 1 to preserve symbolic links\n"
|
||||
" when resolving and caching modules\n"
|
||||
"NODE_REDIRECT_WARNINGS write warnings to path instead of\n"
|
||||
" stderr\n"
|
||||
"NODE_REPL_HISTORY path to the persistent REPL history\n"
|
||||
" file\n"
|
||||
"OPENSSL_CONF load OpenSSL configuration from file\n"
|
||||
"\n"
|
||||
"Documentation can be found at https://nodejs.org/\n");
|
||||
}
|
||||
|
||||
|
||||
static void StartInspector(Environment* env, const char* path,
|
||||
std::shared_ptr<DebugOptions> debug_options) {
|
||||
@ -2772,11 +2623,6 @@ void ProcessArgv(std::vector<std::string>* args,
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (per_process_opts->print_help) {
|
||||
PrintHelp();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (per_process_opts->print_v8_help) {
|
||||
V8::SetFlagsFromString("--help", 6);
|
||||
exit(0);
|
||||
|
@ -73,6 +73,10 @@ static void Initialize(Local<Object> target,
|
||||
READONLY_BOOLEAN_PROPERTY("hasTracing");
|
||||
#endif
|
||||
|
||||
#if !defined(NODE_WITHOUT_NODE_OPTIONS)
|
||||
READONLY_BOOLEAN_PROPERTY("hasNodeOptions");
|
||||
#endif
|
||||
|
||||
// TODO(addaleax): This seems to be an unused, private API. Remove it?
|
||||
READONLY_STRING_PROPERTY(target, "icuDataDir",
|
||||
per_process_opts->icu_data_dir);
|
||||
|
@ -251,11 +251,19 @@ PerProcessOptionsParser::PerProcessOptionsParser() {
|
||||
&PerProcessOptions::tls_cipher_list,
|
||||
kAllowedInEnvironment);
|
||||
AddOption("--use-openssl-ca",
|
||||
"use OpenSSL's default CA store",
|
||||
"use OpenSSL's default CA store"
|
||||
#if defined(NODE_OPENSSL_CERT_STORE)
|
||||
" (default)"
|
||||
#endif
|
||||
,
|
||||
&PerProcessOptions::use_openssl_ca,
|
||||
kAllowedInEnvironment);
|
||||
AddOption("--use-bundled-ca",
|
||||
"use bundled CA store",
|
||||
"use bundled CA store"
|
||||
#if !defined(NODE_OPENSSL_CERT_STORE)
|
||||
" (default)"
|
||||
#endif
|
||||
,
|
||||
&PerProcessOptions::use_bundled_ca,
|
||||
kAllowedInEnvironment);
|
||||
// Similar to [has_eval_string] above, except that the separation between
|
||||
|
@ -11,4 +11,4 @@ const list = process.moduleLoadList.slice();
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
assert(list.length <= 73, list);
|
||||
assert(list.length <= 74, list);
|
||||
|
@ -27,12 +27,12 @@ function validateNodePrintHelp() {
|
||||
|
||||
const cliHelpOptions = [
|
||||
{ compileConstant: HAVE_OPENSSL,
|
||||
flags: [ '--openssl-config=file', '--tls-cipher-list=val',
|
||||
flags: [ '--openssl-config=...', '--tls-cipher-list=...',
|
||||
'--use-bundled-ca', '--use-openssl-ca' ] },
|
||||
{ compileConstant: NODE_FIPS_MODE,
|
||||
flags: [ '--enable-fips', '--force-fips' ] },
|
||||
{ compileConstant: NODE_HAVE_I18N_SUPPORT,
|
||||
flags: [ '--icu-data-dir=dir', 'NODE_ICU_DATA' ] },
|
||||
flags: [ '--icu-data-dir=...', 'NODE_ICU_DATA' ] },
|
||||
{ compileConstant: HAVE_INSPECTOR,
|
||||
flags: [ '--inspect-brk[=[host:]port]', '--inspect-port=[host:]port',
|
||||
'--inspect[=[host:]port]' ] },
|
||||
|
Loading…
x
Reference in New Issue
Block a user