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