CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-zx

A tool for writing better scripts by bridging JavaScript and shell commands with cross-platform wrappers around child_process

Overview
Eval results
Files

utilities.mddocs/

Utility Functions

General-purpose utilities for common scripting tasks including retry logic, error handling, string processing, and vendor library access.

Capabilities

Retry and Resilience

Implement retry logic with various backoff strategies for handling transient failures.

/**
 * Retry a function with exponential backoff
 * @param count - Number of retry attempts
 * @param callback - Function to retry
 * @returns Promise resolving to callback result
 */
function retry<T>(count: number, callback: () => T): Promise<T>;

/**
 * Retry a function with custom backoff strategy
 * @param count - Number of retry attempts  
 * @param duration - Fixed delay or generator for dynamic delays
 * @param callback - Function to retry
 * @returns Promise resolving to callback result
 */
function retry<T>(
  count: number,
  duration: Duration | Generator<number>,
  callback: () => T
): Promise<T>;

/**
 * Generate exponential backoff delays
 * @param max - Maximum delay (default: '60s')
 * @param delay - Initial delay (default: '100ms')
 * @returns Generator yielding delay values in milliseconds
 */
function expBackoff(
  max?: Duration,
  delay?: Duration
): Generator<number, void, unknown>;

Usage Examples:

import { retry, expBackoff, $, echo, fetch } from "zx";

// Simple retry
const result = await retry(3, async () => {
  const response = await fetch('https://unreliable-api.example.com/data');
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return response.json();
});

// Retry with fixed delay
const fileContent = await retry(5, '2s', async () => {
  return await $`cat /proc/meminfo`;
});

// Retry with exponential backoff
const backoffGen = expBackoff('30s', '500ms');
const stableResult = await retry(10, backoffGen, async () => {
  const healthCheck = await $`curl -f https://service.example.com/health`;
  return healthCheck.stdout;
});

// Custom retry with logging
const deployment = await retry(3, '5s', async () => {
  try {
    echo('Attempting deployment...');
    await $`kubectl apply -f deployment.yaml`;
    await $`kubectl rollout status deployment/myapp`;
    echo('Deployment successful');
    return 'success';
  } catch (error) {
    echo`Deployment failed: ${error.message}`;
    throw error;
  }
});

// Complex backoff strategy
function* customBackoff() {
  const delays = [1000, 2000, 5000, 10000, 30000]; // Custom delays
  for (const delay of delays) {
    yield delay;
  }
  while (true) {
    yield 30000; // Max delay for remaining attempts
  }
}

const criticalOperation = await retry(20, customBackoff(), async () => {
  return await $`important-operation`;
});

String Processing

Utilities for processing and formatting strings in shell contexts.

/**
 * Quote shell arguments to prevent injection
 * @param arg - String to quote for shell safety
 * @returns Properly quoted string
 */
function quote(arg: string): string;

/**
 * Quote arguments for PowerShell
 * @param arg - String to quote for PowerShell safety  
 * @returns Properly quoted string for PowerShell
 */
function quotePowerShell(arg: string): string;

Usage Examples:

import { quote, quotePowerShell, $, echo } from "zx";

// Safe shell argument quoting
const userInput = "file with spaces & special chars";
const quoted = quote(userInput);
echo`Quoted: ${quoted}`;

// Use in commands
const filename = "my file.txt";
await $`cat ${quote(filename)}`; // Safer than direct interpolation

// PowerShell quoting
const psArg = "C:\\Program Files\\My App\\data.txt";
const psQuoted = quotePowerShell(psArg);
echo`PowerShell quoted: ${psQuoted}`;

// Platform-specific quoting
const path = "/path/with spaces/file.txt";
const safePath = process.platform === 'win32' 
  ? quotePowerShell(path) 
  : quote(path);

await $`ls ${safePath}`;

Error Handling

Error classes and utilities for better error reporting.

/**
 * Enhanced error class for command failures
 */
class Fail extends Error {
  constructor(message?: string);
  
  /** Format exit error message */
  static formatExitMessage(code: number, signal: string, stderr: string): string;
  
  /** Format general error message */
  static formatErrorMessage(error: Error): string;
  
  /** Format detailed error information */
  static formatErrorDetails(error: Error): string;
  
  /** Get exit code information */
  static getExitCodeInfo(code: number): string;
}

Usage Examples:

import { Fail, $, echo } from "zx";

// Custom error handling
function validateInput(input) {
  if (!input || input.trim().length === 0) {
    throw new Fail('Input cannot be empty');
  }
  return input.trim();
}

try {
  const userInput = validateInput('');
} catch (error) {
  if (error instanceof Fail) {
    echo`Validation error: ${error.message}`;
  }
}

// Process error formatting
try {
  await $`exit 1`;
} catch (error) {
  echo('Exit message:', Fail.formatExitMessage(1, null, 'Command failed'));
  echo('Error details:', Fail.formatErrorDetails(error));
}

Logging System

Structured logging with different output modes and filtering.

/**
 * Logging function with structured output
 * @param entry - Log entry object or message
 */
function log(entry: LogEntry | any): void;

interface LogEntry {
  /** Log entry type/category */
  kind: string;
  /** Whether to show verbose output */
  verbose?: boolean;
  /** Error message */
  error?: string;
  /** Additional metadata */
  [key: string]: any;
}

Usage Examples:

import { log, $ } from "zx";

// Structured logging
log({
  kind: 'deployment',
  status: 'started',
  environment: 'production',
  verbose: true
});

// Error logging
log({
  kind: 'error',
  message: 'Database connection failed',
  error: 'Connection timeout',
  retries: 3
});

// Simple message logging
log('Starting backup process...');

// Conditional verbose logging
log({
  kind: 'debug',
  message: 'Processing file batch',
  count: 150,
  verbose: $.verbose
});

Vendor Library Access

Access to commonly used libraries bundled with zx.

/**
 * Command line argument parser
 */
declare const minimist: typeof import('minimist') & {
  (args: string[], opts?: minimist.Opts): minimist.ParsedArgs;
};

/**
 * Environment variable loader with dotenv config functionality
 */
declare const dotenv: {
  config(options?: { path?: string }): { parsed?: Record<string, string> };
};

/**
 * Enhanced file system operations (fs-extra)
 */
declare const fs: typeof import('fs-extra');

/**
 * YAML parser and serializer
 */
declare const YAML: {
  parse(text: string): any;
  stringify(object: any): string;
};

/**
 * File globbing and pattern matching (globby)
 */
declare const glob: {
  (patterns: string | readonly string[], options?: GlobbyOptions): Promise<string[]>;
  sync: (patterns: string | readonly string[], options?: GlobbyOptions) => string[];
  globby: typeof glob;
  convertPathToPattern: (path: string) => string;
  isDynamicPattern: (pattern: string) => boolean;
};

/**
 * Terminal string styling (chalk)
 */
declare const chalk: ChalkInstance;

/**
 * Find executable in PATH
 */
declare const which: {
  (cmd: string): Promise<string>;
  sync: (cmd: string) => string;
};

/**
 * Process information utilities
 */
declare const ps: {
  findAll(): Promise<Array<{ pid: number; name: string; cmd: string }>>;
};

Usage Examples:

import { 
  minimist, dotenv, fs, YAML, glob, chalk, which, ps, echo 
} from "zx";

// Command line parsing
const args = minimist(process.argv.slice(2), {
  boolean: ['verbose', 'dry-run'],
  string: ['env', 'config'],
  default: { env: 'development' }
});
echo`Environment: ${args.env}`;

// Environment variables
dotenv.config({ path: '.env.local' });
echo`Database URL: ${process.env.DATABASE_URL}`;

// File system operations
await fs.ensureDir('build/assets');
const packageInfo = await fs.readJson('package.json');
echo`Project: ${packageInfo.name}`;

// YAML processing
const config = YAML.parse(await fs.readFile('config.yaml', 'utf8'));
echo`Config loaded: ${config.app.name}`;

// File globbing
const jsFiles = await glob('src/**/*.js');
echo`Found ${jsFiles.length} JavaScript files`;

// Terminal styling
echo(chalk.green('✓ Success'), chalk.blue('Deployment completed'));
echo(chalk.red.bold('Error:'), chalk.yellow('Configuration missing'));

// Executable discovery
const dockerPath = await which('docker');
if (dockerPath) {
  echo`Docker found at: ${dockerPath}`;
} else {
  echo(chalk.red('Docker not found in PATH'));
}

// Process information
const processes = await ps.findAll();
const nodeProcesses = processes.filter(p => p.name.includes('node'));
echo`Found ${nodeProcesses.length} Node.js processes`;

Version Information

Access package version information and dependency versions.

/**
 * ZX package version string
 */
declare const VERSION: string;

/**
 * Alias for VERSION
 */
declare const version: string;

/**
 * Version information for zx and bundled dependencies
 */
declare const versions: Record<string, string>;

Usage Examples:

import { VERSION, version, versions, echo } from "zx";

echo`Running ZX version: ${VERSION}`;
echo`Version (alias): ${version}`;

// Version comparison
const [major, minor, patch] = VERSION.split('.').map(n => parseInt(n));
if (major >= 8) {
  echo('Using modern ZX features');
}

// Dependency versions
echo`Bundled dependencies:`;
for (const [dep, ver] of Object.entries(versions)) {
  echo`  ${dep}: ${ver}`;
}

// Check specific dependency version
echo`Using chalk version: ${versions.chalk}`;
echo`Using minimist version: ${versions.minimist}`;

Argument Parsing Utilities

Enhanced argument parsing with additional processing options.

/**
 * Global parsed arguments (automatically populated)
 */
declare const argv: minimist.ParsedArgs;

/**
 * Update global argv with new arguments
 * @param args - Arguments to parse
 * @param opts - Parsing options
 */
function updateArgv(args?: string[], opts?: ArgvOpts): void;

interface ArgvOpts extends minimist.Opts {
  /** Convert kebab-case to camelCase */
  camelCase?: boolean;
  /** Parse 'true'/'false' strings to booleans */
  parseBoolean?: boolean;
}

Usage Examples:

import { argv, updateArgv, echo } from "zx";

// Access global arguments
echo`Script arguments:`, argv;

if (argv.help || argv.h) {
  echo('Usage: script.mjs [options]');
  echo('Options:');
  echo('  --env, -e     Environment (default: development)');
  echo('  --verbose, -v Enable verbose logging');
  echo('  --help, -h    Show this help');
  process.exit(0);
}

// Update arguments dynamically
updateArgv(['--database-url', 'postgres://localhost/mydb'], {
  camelCase: true
});

echo`Database URL: ${argv.databaseUrl}`;

// Boolean parsing
updateArgv(['--enable-cache', 'true', '--debug', 'false'], {
  parseBoolean: true
});

echo`Cache enabled: ${argv.enableCache}`; // true (boolean)
echo`Debug mode: ${argv.debug}`;          // false (boolean)

Types

/**
 * Duration specification as string or number
 */
type Duration = string | number;

/**
 * Log entry structure
 */
interface LogEntry {
  kind: string;
  verbose?: boolean;
  error?: string;
  [key: string]: any;
}

/**
 * Parsed command line arguments
 */
interface ParsedArgs {
  _: string[];
  [key: string]: any;
}

/**
 * Argument parsing options
 */
interface ArgvOpts extends minimist.Opts {
  camelCase?: boolean;
  parseBoolean?: boolean;
}

Install with Tessl CLI

npx tessl i tessl/npm-zx

docs

cli.md

file-system.md

index.md

network-operations.md

process-management.md

shell-execution.md

user-interaction.md

utilities.md

tile.json