• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3/* eslint-disable no-restricted-globals */
4
5const { types } = internalBinding('options');
6const hasCrypto = Boolean(process.versions.openssl);
7
8const {
9  prepareMainThreadExecution
10} = require('internal/bootstrap/pre_execution');
11
12const typeLookup = [];
13for (const key of Object.keys(types))
14  typeLookup[types[key]] = key;
15
16// Environment variables are parsed ad-hoc throughout the code base,
17// so we gather the documentation here.
18const { hasIntl, hasSmallICU, hasNodeOptions } = internalBinding('config');
19const envVars = new Map([
20  ['NODE_DEBUG', { helpText: "','-separated list of core modules that " +
21    'should print debug information' }],
22  ['NODE_DEBUG_NATIVE', { helpText: "','-separated list of C++ core debug " +
23    'categories that should print debug output' }],
24  ['NODE_DISABLE_COLORS', { helpText: 'set to 1 to disable colors in ' +
25    'the REPL' }],
26  ['NODE_EXTRA_CA_CERTS', { helpText: 'path to additional CA certificates ' +
27    'file' }],
28  ['NODE_NO_WARNINGS', { helpText: 'set to 1 to silence process warnings' }],
29  ['NODE_PATH', { helpText: `'${require('path').delimiter}'-separated list ` +
30    'of directories prefixed to the module search path' }],
31  ['NODE_PENDING_DEPRECATION', { helpText: 'set to 1 to emit pending ' +
32    'deprecation warnings' }],
33  ['NODE_PENDING_PIPE_INSTANCES', { helpText: 'set the number of pending ' +
34    'pipe instance handles on Windows' }],
35  ['NODE_PRESERVE_SYMLINKS', { helpText: 'set to 1 to preserve symbolic ' +
36    'links when resolving and caching modules' }],
37  ['NODE_REDIRECT_WARNINGS', { helpText: 'write warnings to path instead ' +
38    'of stderr' }],
39  ['NODE_REPL_HISTORY', { helpText: 'path to the persistent REPL ' +
40    'history file' }],
41  ['NODE_TLS_REJECT_UNAUTHORIZED', { helpText: 'set to 0 to disable TLS ' +
42    'certificate validation' }],
43  ['NODE_V8_COVERAGE', { helpText: 'directory to output v8 coverage JSON ' +
44    'to' }],
45  ['UV_THREADPOOL_SIZE', { helpText: 'sets the number of threads used in ' +
46    'libuv\'s threadpool' }]
47].concat(hasIntl ? [
48  ['NODE_ICU_DATA', { helpText: 'data path for ICU (Intl object) data' +
49    hasSmallICU ? '' : ' (will extend linked-in data)' }]
50] : []).concat(hasNodeOptions ? [
51  ['NODE_OPTIONS', { helpText: 'set CLI options in the environment via a ' +
52    'space-separated list' }]
53] : []).concat(hasCrypto ? [
54  ['OPENSSL_CONF', { helpText: 'load OpenSSL configuration from file' }],
55  ['SSL_CERT_DIR', { helpText: 'sets OpenSSL\'s directory of trusted ' +
56    'certificates when used in conjunction with --use-openssl-ca' }],
57  ['SSL_CERT_FILE', { helpText: 'sets OpenSSL\'s trusted certificate file ' +
58    'when used in conjunction with --use-openssl-ca' }],
59] : []));
60
61
62function indent(text, depth) {
63  return text.replace(/^/gm, ' '.repeat(depth));
64}
65
66function fold(text, width) {
67  return text.replace(new RegExp(`([^\n]{0,${width}})( |$)`, 'g'),
68                      (_, newLine, end) => newLine + (end === ' ' ? '\n' : ''));
69}
70
71function getArgDescription(type) {
72  switch (typeLookup[type]) {
73    case 'kNoOp':
74    case 'kV8Option':
75    case 'kBoolean':
76    case undefined:
77      break;
78    case 'kHostPort':
79      return '[host:]port';
80    case 'kInteger':
81    case 'kUInteger':
82    case 'kString':
83    case 'kStringList':
84      return '...';
85    default:
86      require('assert').fail(`unknown option type ${type}`);
87  }
88}
89
90function format({ options, aliases = new Map(), firstColumn, secondColumn }) {
91  let text = '';
92  let maxFirstColumnUsed = 0;
93
94  for (const [
95    name, { helpText, type, value }
96  ] of [...options.entries()].sort()) {
97    if (!helpText) continue;
98
99    let displayName = name;
100    const argDescription = getArgDescription(type);
101    if (argDescription)
102      displayName += `=${argDescription}`;
103
104    for (const [ from, to ] of aliases) {
105      // For cases like e.g. `-e, --eval`.
106      if (to[0] === name && to.length === 1) {
107        displayName = `${from}, ${displayName}`;
108      }
109
110      // For cases like `--inspect-brk[=[host:]port]`.
111      const targetInfo = options.get(to[0]);
112      const targetArgDescription =
113        targetInfo ? getArgDescription(targetInfo.type) : '...';
114      if (from === `${name}=`) {
115        displayName += `[=${targetArgDescription}]`;
116      } else if (from === `${name} <arg>`) {
117        displayName += ` [${targetArgDescription}]`;
118      }
119    }
120
121    let displayHelpText = helpText;
122    if (value === true) {
123      // Mark boolean options we currently have enabled.
124      // In particular, it indicates whether --use-openssl-ca
125      // or --use-bundled-ca is the (current) default.
126      displayHelpText += ' (currently set)';
127    }
128
129    text += displayName;
130    maxFirstColumnUsed = Math.max(maxFirstColumnUsed, displayName.length);
131    if (displayName.length >= firstColumn)
132      text += '\n' + ' '.repeat(firstColumn);
133    else
134      text += ' '.repeat(firstColumn - displayName.length);
135
136    text += indent(fold(displayHelpText, secondColumn),
137                   firstColumn).trimLeft() + '\n';
138  }
139
140  if (maxFirstColumnUsed < firstColumn - 4) {
141    // If we have more than 4 blank gap spaces, reduce first column width.
142    return format({
143      options,
144      aliases,
145      firstColumn: maxFirstColumnUsed + 2,
146      secondColumn
147    });
148  }
149
150  return text;
151}
152
153function print(stream) {
154  const { options, aliases } = require('internal/options');
155
156  // Use 75 % of the available width, and at least 70 characters.
157  const width = Math.max(70, (stream.columns || 0) * 0.75);
158  const firstColumn = Math.floor(width * 0.4);
159  const secondColumn = Math.floor(width * 0.57);
160
161  options.set('-', { helpText: 'script read from stdin ' +
162                               '(default if no file name is provided, ' +
163                               'interactive mode if a tty)' });
164  options.set('--', { helpText: 'indicate the end of node options' });
165  stream.write(
166    'Usage: node [options] [ script.js ] [arguments]\n' +
167    '       node inspect [options] [ script.js | host:port ] [arguments]\n\n' +
168    'Options:\n');
169  stream.write(indent(format({
170    options, aliases, firstColumn, secondColumn
171  }), 2));
172
173  stream.write('\nEnvironment variables:\n');
174
175  stream.write(format({
176    options: envVars, firstColumn, secondColumn
177  }));
178
179  stream.write('\nDocumentation can be found at https://nodejs.org/\n');
180}
181
182prepareMainThreadExecution();
183
184markBootstrapComplete();
185
186print(process.stdout);
187