| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 7a02e4f commit 612f60c
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -25,11 +25,16 @@ const { | |||
| 25 | 25 | } = require('internal/process/pre_execution'); | |
| 26 | 26 | ||
| 27 | 27 | const { getCLIOptionsInfo, getOptionValue } = require('internal/options'); | |
| 28 | + const { styleText } = require('util'); | ||
| 28 | 29 | ||
| 29 | 30 | const typeLookup = []; | |
| 30 | 31 | for (const key of ObjectKeys(types)) | |
| 31 | 32 | typeLookup[types[key]] = key; | |
| 32 | 33 | ||
| 34 | + function style(format, text) { | ||
| 35 | + return styleText(format, text, { stream: process.stdout }); | ||
| 36 | + } | ||
| 37 | + | ||
| 33 | 38 | // Environment variables are parsed ad-hoc throughout the code base, | |
| 34 | 39 | // so we gather the documentation here. | |
| 35 | 40 | const { hasIntl, hasSmallICU, hasNodeOptions } = internalBinding('config'); | |
@@ -117,7 +122,7 @@ function getArgDescription(type) { | |||
| 117 | 122 | } | |
| 118 | 123 | ||
| 119 | 124 | function format( | |
| 120 | - { options, aliases = new SafeMap(), firstColumn, secondColumn }, | ||
| 125 | + { options, aliases = new SafeMap(), firstColumn, secondColumn, nameStyle = [] }, | ||
| 121 | 126 | ) { | |
| 122 | 127 | let text = ''; | |
| 123 | 128 | let maxFirstColumnUsed = 0; | |
@@ -176,7 +181,7 @@ function format( | |||
| 176 | 181 | displayHelpText += ' (currently set)'; | |
| 177 | 182 | } | |
| 178 | 183 | ||
| 179 | - text += displayName; | ||
| 184 | + text += style(nameStyle, displayName); | ||
| 180 | 185 | maxFirstColumnUsed = MathMax(maxFirstColumnUsed, displayName.length); | |
| 181 | 186 | if (displayName.length >= firstColumn) | |
| 182 | 187 | text += '\n' + StringPrototypeRepeat(' ', firstColumn); | |
@@ -194,6 +199,7 @@ function format( | |||
| 194 | 199 | aliases, | |
| 195 | 200 | firstColumn: maxFirstColumnUsed + 2, | |
| 196 | 201 | secondColumn, | |
| 202 | + nameStyle, | ||
| 197 | 203 | }); | |
| 198 | 204 | } | |
| 199 | 205 | ||
@@ -214,20 +220,29 @@ function print(stream) { | |||
| 214 | 220 | 'interactive mode if a tty)' }); | |
| 215 | 221 | options.set('--', { helpText: 'indicate the end of node options' }); | |
| 216 | 222 | let helpText = ( | |
| 217 | - 'Usage: node [options] [ script.js ] [arguments]\n' + | ||
| 218 | - ' node inspect [options] [ script.js | host:port ] [arguments]\n\n' + | ||
| 219 | - 'Options:\n'); | ||
| 223 | + style('bold', | ||
| 224 | + 'Usage: node [options] [ script.js ] [arguments]\n' + | ||
| 225 | + ' node inspect [options] [ script.js | host:port ] [arguments]') + | ||
| 226 | + '\n\n' + style('bold', 'Options:') + '\n'); | ||
| 220 | 227 | helpText += (indent(format({ | |
| 221 | - options, aliases, firstColumn, secondColumn, | ||
| 228 | + options, aliases, firstColumn, secondColumn, nameStyle: ['bold', 'green'], | ||
| 222 | 229 | }), 2)); | |
| 223 | 230 | ||
| 224 | - helpText += ('\nEnvironment variables:\n'); | ||
| 231 | + helpText += ('\n' + style('bold', 'Environment variables:') + '\n'); | ||
| 225 | 232 | ||
| 226 | 233 | helpText += (format({ | |
| 227 | - options: envVars, firstColumn, secondColumn, | ||
| 234 | + options: envVars, firstColumn, secondColumn, nameStyle: ['bold', 'magenta'], | ||
| 228 | 235 | })); | |
| 229 | 236 | ||
| 230 | - helpText += ('\nDocumentation can be found at https://nodejs.org/'); | ||
| 237 | + helpText += ('\nDocumentation can be found at ' + | ||
| 238 | + style(['blue', 'underline'], 'https://nodejs.org/')); | ||
| 239 | + | ||
| 240 | + helpText = RegExpPrototypeSymbolReplace( | ||
| 241 | + / \(currently set\)/g, | ||
| 242 | + helpText, | ||
| 243 | + style('dim', ' (currently set)'), | ||
| 244 | + ); | ||
| 245 | + | ||
| 231 | 246 | console.log(helpText); | |
| 232 | 247 | } | |
| 233 | 248 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,64 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../common'); | ||
| 4 | + const assert = require('assert'); | ||
| 5 | + const { execFile } = require('child_process'); | ||
| 6 | + | ||
| 7 | + // eslint-disable-next-line no-control-regex | ||
| 8 | + const ANSI_SGR_REGEX = new RegExp('\x1b\\[[0-9;]*m', 'g'); | ||
| 9 | + | ||
| 10 | + function stripAnsi(text) { | ||
| 11 | + return text.replace(ANSI_SGR_REGEX, ''); | ||
| 12 | + } | ||
| 13 | + | ||
| 14 | + // Test: FORCE_COLOR=1 produces styled output | ||
| 15 | + { | ||
| 16 | + const env = { ...process.env, FORCE_COLOR: '1' }; | ||
| 17 | + execFile(process.execPath, ['--help'], { env }, | ||
| 18 | + common.mustSucceed((stdout) => { | ||
| 19 | + assert.ok(stdout.includes('\x1b[1m'), 'bold for headers should be present'); | ||
| 20 | + assert.ok(stdout.includes('\x1b[32m'), 'green for option names should be present'); | ||
| 21 | + assert.ok(stdout.includes('\x1b[35m'), 'magenta for env var names should be present'); | ||
| 22 | + assert.ok(stdout.includes('\x1b[34m'), 'blue for URL should be present'); | ||
| 23 | + assert.ok(stdout.includes('\x1b[4m'), 'underline for URL should be present'); | ||
| 24 | + })); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + // Test: NO_COLOR=1 produces plain output | ||
| 28 | + { | ||
| 29 | + const env = { ...process.env, NO_COLOR: '1' }; | ||
| 30 | + delete env.FORCE_COLOR; | ||
| 31 | + execFile(process.execPath, ['--help'], { env }, | ||
| 32 | + common.mustSucceed((stdout) => { | ||
| 33 | + assert.ok(stripAnsi(stdout) === stdout, | ||
| 34 | + 'no ANSI escape sequences should be present with NO_COLOR=1'); | ||
| 35 | + })); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + // Test: piped (non-TTY, no FORCE_COLOR) produces plain output | ||
| 39 | + { | ||
| 40 | + const env = { ...process.env }; | ||
| 41 | + delete env.FORCE_COLOR; | ||
| 42 | + delete env.NO_COLOR; | ||
| 43 | + delete env.NODE_DISABLE_COLORS; | ||
| 44 | + execFile(process.execPath, ['--help'], { env }, | ||
| 45 | + common.mustSucceed((stdout) => { | ||
| 46 | + assert.ok(stripAnsi(stdout) === stdout, | ||
| 47 | + 'no ANSI escape sequences should be present when piped (non-TTY)'); | ||
| 48 | + })); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + // Test: alignment preservation - stripped styled output matches plain output | ||
| 52 | + { | ||
| 53 | + const envStyled = { ...process.env, FORCE_COLOR: '1' }; | ||
| 54 | + const envPlain = { ...process.env, NO_COLOR: '1' }; | ||
| 55 | + delete envPlain.FORCE_COLOR; | ||
| 56 | + execFile(process.execPath, ['--help'], { env: envStyled }, | ||
| 57 | + common.mustSucceed((styledStdout) => { | ||
| 58 | + execFile(process.execPath, ['--help'], { env: envPlain }, | ||
| 59 | + common.mustSucceed((plainStdout) => { | ||
| 60 | + assert.ok(stripAnsi(styledStdout) === plainStdout, | ||
| 61 | + 'stripped styled output should match plain output (alignment preservation)'); | ||
| 62 | + })); | ||
| 63 | + })); | ||
| 64 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments