Skip to content

feat(chalk-to-util.styleText): handle migration #198

@AugustinMauroy

Description

@AugustinMauroy

Description

This issue tracks the migration from the chalk package to Node.js's built-in util.styleText API. The goal is to reduce external dependencies by leveraging Node.js's native terminal styling capabilities.

Migration Scope

Compatible Features:

  • Basic colors (red, green, blue, yellow, etc.)
  • Bright colors (redBright, greenBright, etc.)
  • Background colors (bgRed, bgGreen, etc.)
  • Text modifiers (bold, dim, italic, underline, strikethrough, etc.)
  • Style chaining via array syntax
  • Environment variable support (NO_COLOR, NODE_DISABLE_COLORS, FORCE_COLOR)

Non-Compatible Features:

  • Custom RGB colors (chalk.rgb(), chalk.hex())
  • 256-color palette (chalk.ansi256())
  • Template literal syntax (chalk...``)
  • Advanced modifiers with limited terminal support (overline, blink, etc.)

Benefits

  1. Zero Dependencies: Eliminates need for external chalk package
  2. Better Performance: No additional bundle size or installation overhead
  3. Native Support: Uses Node.js built-in APIs
  4. Environment Awareness: Automatic respect for color-related environment variables

Examples

Suite of examples that demonstrate how the codemod will work. These can also serve as the base test suite.

Case 1: Basic Color Usage

Before:

import chalk from 'chalk';

console.log(chalk.red('Error message'));
console.log(chalk.green('Success message'));
console.log(chalk.blue('Info message'));

After:

import { styleText } from 'node:util';

console.log(styleText('red', 'Error message'));
console.log(styleText('green', 'Success message'));
console.log(styleText('blue', 'Info message'));

Case 2: Chained Styles

Before:

import chalk from 'chalk';

console.log(chalk.red.bold('Error: Operation failed'));
console.log(chalk.green.underline('Success: All tests passed'));
console.log(chalk.yellow.bgBlack('Warning: Deprecated API usage'));

After:

import { styleText } from 'node:util';

console.log(styleText(['red', 'bold'], 'Error: Operation failed'));
console.log(styleText(['green', 'underline'], 'Success: All tests passed'));
console.log(styleText(['yellow', 'bgBlack'], 'Warning: Deprecated API usage'));

Case 3: Background Colors

Before:

import chalk from 'chalk';

console.log(chalk.bgRed.white('Error on red background'));
console.log(chalk.bgGreen.black('Success on green background'));
console.log(chalk.bgBlue.whiteBright('Info on blue background'));

After:

import { styleText } from 'node:util';

console.log(styleText(['bgRed', 'white'], 'Error on red background'));
console.log(styleText(['bgGreen', 'black'], 'Success on green background'));
console.log(styleText(['bgBlue', 'whiteBright'], 'Info on blue background'));

Case 4: Multiple Modifiers

Before:

import chalk from 'chalk';

console.log(chalk.bold.italic.underline('Important announcement'));
console.log(chalk.dim.strikethrough('Deprecated feature'));
console.log(chalk.inverse('Inverted colors'));

After:

import { styleText } from 'node:util';

console.log(styleText(['bold', 'italic', 'underline'], 'Important announcement'));
console.log(styleText(['dim', 'strikethrough'], 'Deprecated feature'));
console.log(styleText('inverse', 'Inverted colors'));

Case 5: Mixed Import and Usage

Before:

import chalk from 'chalk';
import { otherFunction } from './utils';

function logError(message) {
  console.log(chalk.red.bold(`ERROR: ${message}`));
}

function logSuccess(message) {
  console.log(chalk.green(`SUCCESS: ${message}`));
}

logError('Something went wrong');
logSuccess('Operation completed');

After:

import { styleText } from 'node:util';
import { otherFunction } from './utils';

function logError(message) {
  console.log(styleText(['red', 'bold'], `ERROR: ${message}`));
}

function logSuccess(message) {
  console.log(styleText('green', `SUCCESS: ${message}`));
}

logError('Something went wrong');
logSuccess('Operation completed');

Case 6: CommonJS Require

Before:

const chalk = require('chalk');

const error = chalk.red('Error');
const warning = chalk.yellow('Warning');
const info = chalk.blue('Info');

console.log(error, warning, info);

After:

const { styleText } = require('node:util');

const error = styleText('red', 'Error');
const warning = styleText('yellow', 'Warning');
const info = styleText('blue', 'Info');

console.log(error, warning, info);

Case 7: Complex Chaining with Variables

Before:

import chalk from 'chalk';

const level = 'error';
const styles = level === 'error' ? chalk.red.bold : chalk.yellow;

console.log(styles('This is a message'));

After:

import { styleText } from 'node:util';

const level = 'error';
const styles = level === 'error' ? (text) => styleText(['red', 'bold'], text) : (text) => styleText('yellow', text);

console.log(styles('This is a message'));

Case 8: Advanced Modifiers (Limited Support)

Before:

import chalk from 'chalk';

// These have limited terminal support
console.log(chalk.overline('Overlined text'));
console.log(chalk.blink('Blinking text'));
console.log(chalk.doubleunderline('Double underlined'));
console.log(chalk.framed('Framed text'));

After:

import { styleText } from 'node:util';

// These have limited terminal support - may not work in all environments
console.log(styleText('overlined', 'Overlined text'));
console.log(styleText('blink', 'Blinking text'));
console.log(styleText('doubleunderline', 'Double underlined'));
console.log(styleText('framed', 'Framed text'));

Additional note

If the codemod detect un-migratable apis we should warn it and advice the user to take a manual look at the code.

https://github.com/nodejs/userland-migrations/blob/main/utils/src/ast-grep/package-json.ts may need to be extended to support dependency removal

REFS

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Status

    🏗 In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions