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