mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-11 17:42:43 -04:00
fix(reporter): make WARN and error labels readable without color (#11460)
The `WARN` and `ERR_PNPM_*` labels in pnpm's output relied entirely on a colored background to stand out from the surrounding text. In terminals without color — `NO_COLOR` set, output piped, dumb terminals — the badge collapsed into bare `WARN` / `ERR_PNPM_FOO` and became hard to spot inside the message. This PR wraps each label in brackets (`[WARN]`, `[ERR_PNPM_FOO]`, `[ERROR]`). The bracket characters are painted in the same color as the badge background, so in a color-capable terminal they appear as plain padding inside the colored badge — the rendering matches what we had before. When ANSI is stripped the brackets reappear as ordinary text, giving the label a clear delimiter.
This commit is contained in:
6
.changeset/warn-error-output-colon.md
Normal file
6
.changeset/warn-error-output-colon.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/cli.default-reporter": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
The `WARN` and error code labels in pnpm's output now wrap in brackets (`[WARN]`, `[ERR_PNPM_FOO]`). Previously the labels relied entirely on a colored background to stand out, which meant they blended into the surrounding text in terminals without color (e.g. when `NO_COLOR` is set or output is piped). The brackets are painted in the same color as the badge background, so they appear as ordinary padding in color-capable terminals — only the no-color rendering changes.
|
||||
@@ -304,7 +304,7 @@ function formatGenericError (errorMessage: string, stack: object): ErrorInfo {
|
||||
}
|
||||
|
||||
function formatErrorSummary (message: string, code?: string): string {
|
||||
return `${chalk.bgRed.black(`\u2009${code ?? 'ERROR'}\u2009`)} ${chalk.red(message)}`
|
||||
return `${chalk.bgRed.red('[')}${chalk.bgRed.black(code ?? 'ERROR')}${chalk.bgRed.red(']')} ${chalk.red(message)}`
|
||||
}
|
||||
|
||||
function reportModifiedDependency (msg: { modified: string[] }): ErrorInfo {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import chalk from 'chalk'
|
||||
|
||||
export function formatWarn (message: string): string {
|
||||
// The \u2009 is the "thin space" unicode character
|
||||
// It is used instead of ' ' because chalk (as of version 2.1.0)
|
||||
// trims whitespace at the beginning
|
||||
return `${chalk.bgYellow.black('\u2009WARN\u2009')} ${message}`
|
||||
return `${chalk.bgYellow.yellow('[')}${chalk.bgYellow.black('WARN')}${chalk.bgYellow.yellow(']')} ${message}`
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import { map, skip, take } from 'rxjs/operators'
|
||||
|
||||
import { formatWarn } from '../src/reporterForClient/utils/formatWarn.js'
|
||||
|
||||
const formatErrorCode = (code: string) => chalk.bgRed.black(`\u2009${code}\u2009`)
|
||||
const formatErrorCode = (code: string) => chalk.bgRed.red('[') + chalk.bgRed.black(code) + chalk.bgRed.red(']')
|
||||
const formatError = (code: string, message: string) => {
|
||||
return `${formatErrorCode(code)} ${chalk.red(message)}`
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ interface Exception extends NodeJS.ErrnoException {
|
||||
stage?: string
|
||||
}
|
||||
|
||||
const formatErrorCode = (code: string) => chalk.bgRed.black(`\u2009${code}\u2009`)
|
||||
const formatErrorCode = (code: string) => chalk.bgRed.red('[') + chalk.bgRed.black(code) + chalk.bgRed.red(']')
|
||||
const formatError = (code: string, message: string) => {
|
||||
return `${formatErrorCode(code)} ${chalk.red(message)}`
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import chalk from 'chalk'
|
||||
|
||||
export function formatUnknownOptionsError (unknownOptions: Map<string, string[]>): string {
|
||||
let output = chalk.bgRed.black('\u2009ERROR\u2009')
|
||||
let output = chalk.bgRed.red('[') + chalk.bgRed.black('ERROR') + chalk.bgRed.red(']')
|
||||
const unknownOptionsArray = Array.from(unknownOptions.keys())
|
||||
if (unknownOptionsArray.length > 1) {
|
||||
return `${output} ${chalk.red(`Unknown options: ${unknownOptionsArray.map(unknownOption => `'${unknownOption}'`).join(', ')}`)}`
|
||||
|
||||
@@ -374,7 +374,7 @@ export async function main (inputArgv: string[]): Promise<void> {
|
||||
}
|
||||
|
||||
function printError (message: string, hint?: string): void {
|
||||
const ERROR = chalk.bgRed.black('\u2009ERROR\u2009')
|
||||
const ERROR = chalk.bgRed.red('[') + chalk.bgRed.black('ERROR') + chalk.bgRed.red(']')
|
||||
console.error(`${message.startsWith(ERROR) ? '' : ERROR + ' '}${chalk.red(message)}`)
|
||||
if (hint) {
|
||||
console.error(hint)
|
||||
|
||||
@@ -92,5 +92,5 @@ test('should print error summary when some packages fail with --no-bail', async
|
||||
const output = stdout.toString()
|
||||
expect(output).toContain('ERR_PNPM_RECURSIVE_FAIL')
|
||||
expect(output).toContain('Summary: 1 fails, 2 passes')
|
||||
expect(output).toContain('ERROR project-2@1.0.0 build: `exit 1`')
|
||||
expect(output).toContain('[ERROR] project-2@1.0.0 build: `exit 1`')
|
||||
})
|
||||
|
||||
@@ -8,17 +8,17 @@ test('formatUnknownOptionsError()', async () => {
|
||||
expect(
|
||||
stripAnsi(formatUnknownOptionsError(new Map([['foo', []]])))
|
||||
).toBe(
|
||||
"\u2009ERROR\u2009 Unknown option: 'foo'"
|
||||
"[ERROR] Unknown option: 'foo'"
|
||||
)
|
||||
expect(
|
||||
stripAnsi(formatUnknownOptionsError(new Map([['foo', ['foa', 'fob']]])))
|
||||
).toBe(
|
||||
`\u2009ERROR\u2009 Unknown option: 'foo'
|
||||
`[ERROR] Unknown option: 'foo'
|
||||
Did you mean 'foa', or 'fob'? Use "--config.unknown=value" to force an unknown option.`
|
||||
)
|
||||
expect(
|
||||
stripAnsi(formatUnknownOptionsError(new Map([['foo', []], ['bar', []]])))
|
||||
).toBe(
|
||||
"\u2009ERROR\u2009 Unknown options: 'foo', 'bar'"
|
||||
"[ERROR] Unknown options: 'foo', 'bar'"
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user