nstdlib-nightly
Version:
Node.js standard library converted to runtime-agnostic ES modules.
360 lines (330 loc) • 9.61 kB
JavaScript
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/main/print_help.js
import * as __hoisted_assert__ from "nstdlib/lib/assert";
import * as __hoisted_internal_console_global__ from "nstdlib/lib/internal/console/global";
import { types } from "nstdlib/stub/binding/options";
import {
prepareMainThreadExecution,
markBootstrapComplete,
} from "nstdlib/lib/internal/process/pre_execution";
import {
getCLIOptionsInfo,
getOptionValue,
} from "nstdlib/lib/internal/options";
import {
hasIntl,
hasSmallICU,
hasNodeOptions,
} from "nstdlib/stub/binding/config";
import * as __hoisted_path__ from "nstdlib/lib/path";
const hasCrypto = Boolean(process.versions.openssl);
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.
// eslint-disable-next-line node-core/avoid-prototype-pollution
const envVars = new Map(
Array.prototype.concat.call(
[
[
"FORCE_COLOR",
{
helpText:
"when set to 'true', 1, 2, 3, or an empty " +
"string causes NO_COLOR and NODE_DISABLE_COLORS to be ignored.",
},
],
["NO_COLOR", { helpText: "Alias for NODE_DISABLE_COLORS" }],
[
"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. Only read once during process startup.",
},
],
[
"NODE_NO_WARNINGS",
{ helpText: "set to 1 to silence process warnings" },
],
[
"NODE_PATH",
{
helpText:
`'${__hoisted_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_PENDING_PIPE_INSTANCES",
{
helpText:
"set the number of pending " + "pipe instance handles on Windows",
},
],
[
"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" },
],
[
"NODE_REPL_EXTERNAL_MODULE",
{
helpText:
"path to a Node.js module " +
"which will be loaded in place of the built-in REPL",
},
],
[
"NODE_SKIP_PLATFORM_CHECK",
{
helpText:
"set to 1 to skip " +
"the check for a supported platform during Node.js startup",
},
],
[
"NODE_TLS_REJECT_UNAUTHORIZED",
{ helpText: "set to 0 to disable TLS " + "certificate validation" },
],
[
"NODE_V8_COVERAGE",
{ helpText: "directory to output v8 coverage JSON " + "to" },
],
["TZ", { helpText: "specify the timezone configuration" }],
[
"UV_THREADPOOL_SIZE",
{
helpText:
"sets the number of threads used in " + "libuv's threadpool",
},
],
],
hasIntl
? [
[
"NODE_ICU_DATA",
{
helpText:
"data path for ICU (Intl object) data" + hasSmallICU
? ""
: " (will extend linked-in data)",
},
],
]
: [],
),
hasNodeOptions
? [
[
"NODE_OPTIONS",
{
helpText:
"set CLI options in the environment via a " +
"space-separated list",
},
],
]
: [],
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) {
return RegExp.prototype[Symbol.replace].call(
/^/gm,
text,
String.prototype.repeat.call(" ", depth),
);
}
function fold(text, width) {
return RegExp.prototype[Symbol.replace].call(
new RegExp(`([^\n]{0,${width}})( |$)`, "g"),
text,
(_, newLine, end) => newLine + (end === " " ? "\n" : ""),
);
}
function getArgDescription(type) {
switch (typeLookup[type]) {
case "kNoOp":
case "kV8Option":
case "kBoolean":
case undefined:
break;
case "kHostPort":
return "[host:]port";
case "kInteger":
case "kUInteger":
case "kString":
case "kStringList":
return "...";
default:
__hoisted_assert__.fail(`unknown option type ${type}`);
}
}
function format({ options, aliases = new Map(), firstColumn, secondColumn }) {
let text = "";
let maxFirstColumnUsed = 0;
const sortedOptions = Array.prototype.sort.call(
[...options.entries()],
({ 0: name1, 1: option1 }, { 0: name2, 1: option2 }) => {
if (option1.defaultIsTrue) {
name1 = `--no-${String.prototype.slice.call(name1, 2)}`;
}
if (option2.defaultIsTrue) {
name2 = `--no-${String.prototype.slice.call(name2, 2)}`;
}
return String.prototype.localeCompare.call(name1, name2);
},
);
for (const {
0: name,
1: { helpText, type, defaultIsTrue },
} of sortedOptions) {
if (!helpText) continue;
const value = getOptionValue(name);
let displayName = name;
if (defaultIsTrue) {
displayName = `--no-${String.prototype.slice.call(displayName, 2)}`;
}
const argDescription = getArgDescription(type);
if (argDescription) displayName += `=${argDescription}`;
for (const { 0: from, 1: 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 === !defaultIsTrue) {
// 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;
maxFirstColumnUsed = Math.max(maxFirstColumnUsed, displayName.length);
if (displayName.length >= firstColumn)
text += "\n" + String.prototype.repeat.call(" ", firstColumn);
else
text += String.prototype.repeat.call(
" ",
firstColumn - displayName.length,
);
text +=
String.prototype.trimStart.call(
indent(fold(displayHelpText, secondColumn), firstColumn),
) + "\n";
}
if (maxFirstColumnUsed < firstColumn - 4) {
// If we have more than 4 blank gap spaces, reduce first column width.
return format({
options,
aliases,
firstColumn: maxFirstColumnUsed + 2,
secondColumn,
});
}
return text;
}
function print(stream) {
const { options, aliases } = getCLIOptionsInfo();
const console = __hoisted_internal_console_global__;
// Use 75 % of the available width, and at least 70 characters.
const width = Math.max(70, (stream.columns || 0) * 0.75);
const firstColumn = Math.floor(width * 0.4);
const secondColumn = Math.floor(width * 0.57);
options.set("-", {
helpText:
"script read from stdin " +
"(default if no file name is provided, " +
"interactive mode if a tty)",
});
options.set("--", { helpText: "indicate the end of node options" });
let helpText =
"Usage: node [options] [ script.js ] [arguments]\n" +
" node inspect [options] [ script.js | host:port ] [arguments]\n\n" +
"Options:\n";
helpText += indent(
format({
options,
aliases,
firstColumn,
secondColumn,
}),
2,
);
helpText += "\nEnvironment variables:\n";
helpText += format({
options: envVars,
firstColumn,
secondColumn,
});
helpText += "\nDocumentation can be found at https://nodejs.org/";
console.log(helpText);
}
prepareMainThreadExecution();
markBootstrapComplete();
print(process.stdout);