diff options
author | Anna Henningsen <anna@addaleax.net> | 2018-08-23 22:07:13 +0200 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2018-09-01 00:13:23 +0200 |
commit | c8880ea27645aec31ef9dd5687c57747f338d67f (patch) | |
tree | 6c0bae2ba0dc4377a8d111e2890563860e3c6acb /lib | |
parent | e812be4a55915575fc1afce739848026a48b781e (diff) | |
download | android-node-v8-c8880ea27645aec31ef9dd5687c57747f338d67f.tar.gz android-node-v8-c8880ea27645aec31ef9dd5687c57747f338d67f.tar.bz2 android-node-v8-c8880ea27645aec31ef9dd5687c57747f338d67f.zip |
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>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/internal/bootstrap/node.js | 5 | ||||
-rw-r--r-- | lib/internal/print_help.js | 151 |
2 files changed, 156 insertions, 0 deletions
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 30b177c5a4..069c8bc997 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -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(); } diff --git a/lib/internal/print_help.js b/lib/internal/print_help.js new file mode 100644 index 0000000000..9d14671973 --- /dev/null +++ b/lib/internal/print_help.js @@ -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 +}; |