Skip to content

Commit 0d2882e

Browse files
authored
fix(core): use picocolors instead of chalk in the nx package (#34305)
1 parent 541498f commit 0d2882e

43 files changed

Lines changed: 330 additions & 333 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

e2e/utils/command-utils.ts

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
1-
import { output, PackageManager, ProjectConfiguration } from '@nx/devkit';
1+
import {
2+
output,
3+
PackageManager,
4+
ProjectConfiguration,
5+
TargetConfiguration,
6+
} from '@nx/devkit';
7+
import { ChildProcess, exec, execSync, ExecSyncOptions } from 'child_process';
8+
import { existsSync } from 'fs-extra';
9+
import * as isCI from 'is-ci';
10+
import { join } from 'node:path';
11+
import { stripVTControlCharacters } from 'node:util';
12+
import { gte } from 'semver';
213
import { packageInstall, tmpProjPath } from './create-project-utils';
14+
import {
15+
ensureCypressInstallation,
16+
ensurePlaywrightBrowsersInstallation,
17+
} from './ensure-browser-installation';
18+
import { fileExists, readJson, updateJson } from './file-utils';
319
import {
420
detectPackageManager,
521
getNpmMajorVersion,
@@ -9,18 +25,7 @@ import {
925
getYarnMajorVersion,
1026
isVerboseE2ERun,
1127
} from './get-env-info';
12-
import {
13-
ensureCypressInstallation,
14-
ensurePlaywrightBrowsersInstallation,
15-
} from './ensure-browser-installation';
16-
import { TargetConfiguration } from '@nx/devkit';
17-
import { ChildProcess, exec, execSync, ExecSyncOptions } from 'child_process';
18-
import { join } from 'path';
19-
import * as isCI from 'is-ci';
20-
import { fileExists, readJson, updateJson } from './file-utils';
21-
import { logError, stripConsoleColors } from './log-utils';
22-
import { existsSync } from 'fs-extra';
23-
import { gte } from 'semver';
28+
import { logError } from './log-utils';
2429

2530
export interface RunCmdOpts {
2631
silenceError?: boolean;
@@ -94,13 +99,13 @@ export function runCommand(
9499
});
95100
}
96101

97-
return r as string;
102+
return stripVTControlCharacters(r as string);
98103
} catch (e) {
99104
// this is intentional
100105
// npm ls fails if package is not found
101106
logError(`Original command: ${command}`, `${e.stdout}\n\n${e.stderr}`);
102107
if (!failOnError && (e.stdout || e.stderr)) {
103-
return e.stdout + e.stderr;
108+
return stripVTControlCharacters(e.stdout + e.stderr);
104109
}
105110
throw e;
106111
}
@@ -257,9 +262,9 @@ export function runCommandAsync(
257262
}
258263

259264
const outputs = {
260-
stdout: stripConsoleColors(stdout),
261-
stderr: stripConsoleColors(stderr),
262-
combinedOutput: stripConsoleColors(`${stdout}${stderr}`),
265+
stdout: stripVTControlCharacters(stdout),
266+
stderr: stripVTControlCharacters(stderr),
267+
combinedOutput: stripVTControlCharacters(`${stdout}${stderr}`),
263268
};
264269

265270
if (opts.verbose ?? isVerboseE2ERun()) {
@@ -317,7 +322,7 @@ export function runCommandUntil(
317322

318323
function checkCriteria(c) {
319324
output += c.toString();
320-
const strippedOutput = stripConsoleColors(output);
325+
const strippedOutput = stripVTControlCharacters(output);
321326
if (criteria(strippedOutput) && !complete) {
322327
complete = true;
323328
clearTimeout(timeoutId);
@@ -381,7 +386,7 @@ export function runNgAdd(
381386
encoding: 'utf-8',
382387
});
383388

384-
const r = stripConsoleColors(result);
389+
const r = stripVTControlCharacters(result);
385390

386391
if (opts.verbose ?? isVerboseE2ERun()) {
387392
output.log({
@@ -438,12 +443,12 @@ export function runCLI(
438443
});
439444
}
440445

441-
const r = stripConsoleColors(logs);
446+
const r = stripVTControlCharacters(logs);
442447

443448
return r;
444449
} catch (e) {
445450
if (opts.silenceError) {
446-
return stripConsoleColors(e.stdout + e.stderr);
451+
return stripVTControlCharacters(e.stdout + e.stderr);
447452
} else {
448453
logError(`Original command: ${command}`, `${e.stdout}\n\n${e.stderr}`);
449454
throw e;
@@ -479,12 +484,12 @@ export function runLernaCLI(
479484
color: 'green',
480485
});
481486
}
482-
const r = stripConsoleColors(logs);
487+
const r = stripVTControlCharacters(logs);
483488

484489
return r;
485490
} catch (e) {
486491
if (opts.silenceError) {
487-
return stripConsoleColors(e.stdout + e.stderr);
492+
return stripVTControlCharacters(e.stdout + e.stderr);
488493
} else {
489494
logError(`Original command: ${command}`, `${e.stdout}\n\n${e.stderr}`);
490495
throw e;

e2e/utils/log-utils.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,3 @@ export function logSuccess(title: string, body?: string) {
3333
)} ${chalk.bold.green(title)}`;
3434
return e2eConsoleLogger(message, body);
3535
}
36-
37-
/**
38-
* Remove log colors for fail proof string search
39-
* @param log
40-
* @returns
41-
*/
42-
export function stripConsoleColors(log: string): string {
43-
return log?.replace(
44-
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
45-
''
46-
);
47-
}

packages/devkit/src/generators/plugin-migrations/aggregate-log-util.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ describe(`aggregateLog utils`, () => {
2929
// ASSERT
3030
expect(logger.warn).toHaveBeenCalled();
3131
expect(spyLog).toMatchInlineSnapshot(`
32-
"[1mEncountered the following while migrating '@nx/vite:serve':[22m
33-
[1m[22m • Encountered 'proxyConfig' in project.json. You will need to copy the contents of this file to the 'server.proxy' property in your Vite config file.
32+
"[1mEncountered the following while migrating '@nx/vite:serve':
33+
[22m • Encountered 'proxyConfig' in project.json. You will need to copy the contents of this file to the 'server.proxy' property in your Vite config file.
3434
Affected Projects
3535
app
3636
myapp
@@ -71,16 +71,16 @@ describe(`aggregateLog utils`, () => {
7171
// ASSERT
7272
expect(logger.warn).toHaveBeenCalled();
7373
expect(spyLog).toMatchInlineSnapshot(`
74-
"[1mEncountered the following while migrating '@nx/vite:serve':[22m
75-
[1m[22m • Encountered 'proxyConfig' in project.json. You will need to copy the contents of this file to the 'server.proxy' property in your Vite config file.
74+
"[1mEncountered the following while migrating '@nx/vite:serve':
75+
[22m • Encountered 'proxyConfig' in project.json. You will need to copy the contents of this file to the 'server.proxy' property in your Vite config file.
7676
Affected Projects
7777
app
7878
shop-app
7979
• Encountered 'AnotherValue' in project.json. You will need to copy the contents of this file to the 'config.prop' property in your Vite config file.
8080
Affected Projects
8181
shop-app
82-
[1mEncountered the following while migrating '@nx/vite:build':[22m
83-
[1m[22m • Encountered 'proxyConfig' in project.json. You will need to copy the contents of this file to the 'server.proxy' property in your Vite config file.
82+
[1mEncountered the following while migrating '@nx/vite:build':
83+
[22m • Encountered 'proxyConfig' in project.json. You will need to copy the contents of this file to the 'server.proxy' property in your Vite config file.
8484
Affected Projects
8585
myapp
8686
"

packages/nx/.eslintrc.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
{
1414
"name": "fs-extra",
1515
"message": "Please use equivalent utilities from `node:fs` instead."
16+
},
17+
{
18+
"name": "chalk",
19+
"message": "Please use `picocolors` instead. For an orange color, import `orange` from `utils/output`."
1620
}
1721
],
1822
"patterns": [

packages/nx/bin/nx.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
findWorkspaceRoot,
44
WorkspaceTypeAndRoot,
55
} from '../src/utils/find-workspace-root';
6-
import * as chalk from 'chalk';
6+
import * as pc from 'picocolors';
77
import { loadRootEnvFiles } from '../src/utils/dotenv';
88
import { initLocal } from './init-local';
99
import { output } from '../src/utils/output';
@@ -119,10 +119,10 @@ function handleNoWorkspace(globalNxVersion?: string) {
119119
title: `The current directory isn't part of an Nx workspace.`,
120120
bodyLines: [
121121
`To create a workspace run:`,
122-
chalk.bold.white(`npx create-nx-workspace@latest <workspace name>`),
122+
pc.bold(pc.white(`npx create-nx-workspace@latest <workspace name>`)),
123123
'',
124124
`To add Nx to an existing workspace with a workspace-specific nx.json, run:`,
125-
chalk.bold.white(`npx nx@latest init`),
125+
pc.bold(pc.white(`npx nx@latest init`)),
126126
],
127127
});
128128

@@ -199,7 +199,7 @@ function handleMissingLocalInstallation(detectedWorkspaceRoot: string | null) {
199199
title: detectedWorkspaceRoot
200200
? `Could not find Nx modules at "${detectedWorkspaceRoot}".`
201201
: `Could not find Nx modules in this workspace.`,
202-
bodyLines: [`Have you run ${chalk.bold.white(`npm/yarn install`)}?`],
202+
bodyLines: [`Have you run ${pc.bold(pc.white(`npm/yarn install`))}?`],
203203
});
204204
process.exit(1);
205205
}

packages/nx/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"@yarnpkg/parsers": "3.0.2",
4343
"@zkochan/js-yaml": "catalog:",
4444
"axios": "^1.12.0",
45-
"chalk": "catalog:",
45+
"picocolors": "catalog:",
4646
"cli-cursor": "3.1.0",
4747
"cli-spinners": "2.6.1",
4848
"cliui": "^8.0.1",

packages/nx/src/adapter/ngcli-adapter.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { FileBuffer } from '@angular-devkit/core/src/virtual-fs/host/interface';
1818
import type { Architect, Target } from '@angular-devkit/architect';
1919
import type { NodeModulesBuilderInfo } from '@angular-devkit/architect/node/node-modules-architect-host';
2020

21-
import * as chalk from 'chalk';
21+
import * as pc from 'picocolors';
2222
import { Stats } from 'fs';
2323
import { dirname, extname, join, resolve } from 'path';
2424

@@ -396,17 +396,17 @@ async function createRecorder(
396396
);
397397
} else if (event.kind === 'update') {
398398
record.loggingQueue.push(
399-
tags.oneLine`${chalk.white('UPDATE')} ${eventPath}`
399+
tags.oneLine`${pc.white('UPDATE')} ${eventPath}`
400400
);
401401
} else if (event.kind === 'create') {
402402
record.loggingQueue.push(
403-
tags.oneLine`${chalk.green('CREATE')} ${eventPath}`
403+
tags.oneLine`${pc.green('CREATE')} ${eventPath}`
404404
);
405405
} else if (event.kind === 'delete') {
406-
record.loggingQueue.push(`${chalk.yellow('DELETE')} ${eventPath}`);
406+
record.loggingQueue.push(`${pc.yellow('DELETE')} ${eventPath}`);
407407
} else if (event.kind === 'rename') {
408408
record.loggingQueue.push(
409-
`${chalk.blue('RENAME')} ${eventPath} => ${event.to}`
409+
`${pc.blue('RENAME')} ${eventPath} => ${event.to}`
410410
);
411411
}
412412
};
@@ -1190,20 +1190,20 @@ let logger: logging.Logger;
11901190
export const getLogger = (isVerbose = false): logging.Logger => {
11911191
if (!logger) {
11921192
logger = createConsoleLogger(isVerbose, process.stdout, process.stderr, {
1193-
warn: (s) => chalk.bold(chalk.yellow(s)),
1193+
warn: (s) => pc.bold(pc.yellow(s)),
11941194
error: (s) => {
11951195
if (s.startsWith('NX ')) {
1196-
return `\n${NX_ERROR} ${chalk.bold(chalk.red(s.slice(3)))}\n`;
1196+
return `\n${NX_ERROR} ${pc.bold(pc.red(s.slice(3)))}\n`;
11971197
}
11981198

1199-
return chalk.bold(chalk.red(s));
1199+
return pc.bold(pc.red(s));
12001200
},
12011201
info: (s) => {
12021202
if (s.startsWith('NX ')) {
1203-
return `\n${NX_PREFIX} ${chalk.bold(s.slice(3))}\n`;
1203+
return `\n${NX_PREFIX} ${pc.bold(s.slice(3))}\n`;
12041204
}
12051205

1206-
return chalk.white(s);
1206+
return pc.white(s);
12071207
},
12081208
});
12091209
}

packages/nx/src/command-line/configure-ai-agents/configure-ai-agents.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
import { prompt } from 'enquirer';
2-
import { output } from '../../utils/output';
3-
import { ensurePackageHasProvenance } from '../../utils/provenance';
4-
import * as chalk from 'chalk';
5-
2+
import { existsSync, readFileSync } from 'node:fs';
3+
import { relative } from 'node:path';
4+
import * as pc from 'picocolors';
5+
import { claudeMcpJsonPath } from '../../ai/constants';
66
import {
77
Agent,
8-
agentDisplayMap,
9-
supportedAgents,
8+
AgentConfiguration,
109
configureAgents,
1110
getAgentConfigurations,
12-
AgentConfiguration,
11+
supportedAgents,
1312
} from '../../ai/utils';
14-
import { claudeMcpJsonPath } from '../../ai/constants';
1513
import { installPackageToTmp } from '../../devkit-internals';
14+
import { output } from '../../utils/output';
15+
import { ensurePackageHasProvenance } from '../../utils/provenance';
1616
import { workspaceRoot } from '../../utils/workspace-root';
1717
import { ConfigureAiAgentsOptions } from './command-object';
1818
import ora = require('ora');
19-
import { relative } from 'path';
20-
import { existsSync, readFileSync } from 'fs';
2119

2220
export async function configureAiAgentsHandler(
2321
args: ConfigureAiAgentsOptions,
@@ -88,7 +86,7 @@ export async function configureAiAgentsHandlerImpl(
8886
output.log({
8987
title,
9088
bodyLines: [
91-
chalk.dim(
89+
pc.dim(
9290
'To manually configure the Nx MCP in your editor, install Nx Console (https://nx.dev/getting-started/editor-setup)'
9391
),
9492
],
@@ -225,7 +223,7 @@ export async function configureAiAgentsHandlerImpl(
225223
required: true,
226224
footer: function () {
227225
const focused = this.focused as AgentPromptChoice;
228-
return chalk.dim(
226+
return pc.dim(
229227
` ${getAgentFooterDescription(focused.agentConfiguration)}`
230228
);
231229
},

packages/nx/src/command-line/generate/generate.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as chalk from 'chalk';
1+
import * as pc from 'picocolors';
22
import { prompt } from 'enquirer';
33
import { relative } from 'path';
44

@@ -38,11 +38,11 @@ export interface GenerateOptions {
3838
export function printChanges(fileChanges: FileChange[]) {
3939
fileChanges.forEach((f) => {
4040
if (f.type === 'CREATE') {
41-
console.log(`${chalk.green('CREATE')} ${f.path}`);
41+
console.log(`${pc.green('CREATE')} ${f.path}`);
4242
} else if (f.type === 'UPDATE') {
43-
console.log(`${chalk.white('UPDATE')} ${f.path}`);
43+
console.log(`${pc.white('UPDATE')} ${f.path}`);
4444
} else if (f.type === 'DELETE') {
45-
console.log(`${chalk.yellow('DELETE')} ${f.path}`);
45+
console.log(`${pc.yellow('DELETE')} ${f.path}`);
4646
}
4747
});
4848
}
@@ -117,7 +117,7 @@ async function promptForCollection(
117117
} else {
118118
choicesFromLocalPlugins.push({
119119
name: value,
120-
message: chalk.bold(value),
120+
message: pc.bold(value),
121121
value,
122122
});
123123
}

0 commit comments

Comments
 (0)