or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-cross-spawn

Cross platform child_process#spawn and child_process#spawnSync

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/cross-spawn@7.0.x

To install, run

npx @tessl/cli install tessl/npm-cross-spawn@7.0.0

index.mddocs/

Cross-Spawn

Cross-spawn is a Node.js library that provides cross-platform solutions for child_process.spawn and child_process.spawnSync. It resolves Windows-specific issues including PATHEXT resolution, shebang support, proper command escaping, and ENOENT error handling while maintaining the same API as Node.js built-ins.

Package Information

  • Package Name: cross-spawn
  • Package Type: npm
  • Language: JavaScript (Node.js)
  • Installation: npm install cross-spawn

Core Imports

const spawn = require('cross-spawn');

ES6 modules:

import spawn from 'cross-spawn';

Named imports:

const { spawn, sync } = require('cross-spawn');
import { spawn, sync } from 'cross-spawn';

Basic Usage

const spawn = require('cross-spawn');

// Asynchronous spawn - returns ChildProcess
const child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });

child.on('close', (code) => {
  console.log(`Child process exited with code ${code}`);
});

// Synchronous spawn - returns SpawnSyncResult
const result = spawn.sync('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
console.log('Exit code:', result.status);

Architecture

Cross-spawn is built around several key components that work together to provide cross-platform process spawning:

  • Command Parser (lib/parse.js): Normalizes and parses spawn arguments, handles Windows-specific command resolution and escaping
  • Command Resolution (lib/util/resolveCommand.js): Locates executable files using PATH and PATHEXT, handles custom working directories
  • Shebang Support (lib/util/readShebang.js): Reads and processes shebang headers from executable files on Windows
  • Argument Escaping (lib/util/escape.js): Properly escapes commands and arguments for Windows cmd.exe execution
  • Error Handling (lib/enoent.js): Provides consistent ENOENT (command not found) error reporting across platforms
  • Main Interface (index.js): Exposes the public API while delegating to Node.js built-in child_process functions

The library works by intercepting spawn calls, analyzing the target platform, and applying necessary transformations before delegating to Node.js built-in functions.

Capabilities

Asynchronous Spawn

Cross-platform asynchronous process spawning with Windows compatibility fixes.

/**
 * Spawn a child process asynchronously with cross-platform compatibility
 * @param {string} command - Command to execute
 * @param {string[]} [args] - Array of arguments
 * @param {object} [options] - Spawn options (same as child_process.spawn)
 * @returns {ChildProcess} Child process instance
 */
function spawn(command, args, options);

The returned ChildProcess object is the same as Node.js child_process.spawn, providing all standard events (exit, close, error, etc.) and streams (stdin, stdout, stderr).

Usage Examples:

const spawn = require('cross-spawn');

// Basic command execution
const child = spawn('echo', ['Hello World']);

// Command with options
const child = spawn('npm', ['install'], {
  cwd: '/path/to/project',
  stdio: 'inherit'
});

// Handle events
child.on('close', (code, signal) => {
  console.log(`Process exited with code ${code} and signal ${signal}`);
});

child.on('error', (err) => {
  console.error('Failed to start process:', err);
});

Synchronous Spawn

Cross-platform synchronous process spawning with Windows compatibility fixes.

/**
 * Spawn a child process synchronously with cross-platform compatibility
 * @param {string} command - Command to execute  
 * @param {string[]} [args] - Array of arguments
 * @param {object} [options] - Spawn options (same as child_process.spawnSync)
 * @returns {SpawnSyncResult} Result object with status, stdout, stderr, etc.
 */
function sync(command, args, options);

Usage Examples:

const { sync } = require('cross-spawn');

// Basic synchronous execution
const result = sync('echo', ['Hello World'], { encoding: 'utf8' });
console.log('Output:', result.stdout);
console.log('Exit code:', result.status);

// Handle errors
const result = sync('nonexistent-command');
if (result.error) {
  console.error('Command failed:', result.error.message);
}

Cross-Platform Features

Cross-spawn automatically handles several platform-specific differences:

Windows-specific enhancements:

  • PATHEXT Resolution: Automatically finds .com, .exe, .bat, .cmd files based on Windows PATHEXT environment variable
  • Shebang Support: Executes files with #!/usr/bin/env shebangs on Windows (Unix behavior emulation)
  • Command Escaping: Properly escapes commands and arguments for cmd.exe using ^ character
  • Space Handling: Correctly handles commands and arguments containing spaces by using cmd.exe shell when necessary
  • Batch File Execution: Automatically detects and properly executes batch files and Windows scripts

Cross-platform consistency:

  • ENOENT Errors: Provides consistent "command not found" error handling - Windows typically returns exit code 1, Unix returns ENOENT error
  • Path Normalization: Converts forward slashes to backslashes on Windows while preserving Unix paths on other platforms
  • Environment Handling: Consistent environment variable processing across all platforms

Types

SpawnSyncResult

/**
 * Result object returned by sync() function
 */
interface SpawnSyncResult {
  /** Process ID of the spawned process */
  pid: number;
  /** Buffer containing stdout data (if stdio not redirected) */
  output: Buffer[];
  /** String containing stdout data (if encoding specified) */
  stdout: string | Buffer;
  /** String containing stderr data (if encoding specified) */
  stderr: string | Buffer;
  /** Exit status code (null if process was killed by signal) */
  status: number | null;
  /** Signal that terminated the process (null if exited normally) */
  signal: string | null;
  /** Error object if spawn failed */
  error?: Error;
}

Spawn Options

Cross-spawn accepts the same options as Node.js built-in spawn functions:

/**
 * Options for spawn and sync functions (extends Node.js spawn options)
 */
interface SpawnOptions {
  /** Current working directory of the child process */
  cwd?: string;
  /** Environment key-value pairs */
  env?: Record<string, string>;
  /** Array or string stdio configuration */
  stdio?: 'pipe' | 'ignore' | 'inherit' | Array<string | number | Stream | null | undefined>;
  /** Detach the child process */
  detached?: boolean;
  /** User identity to run as */
  uid?: number;
  /** Group identity to run as */
  gid?: number;
  /** Use shell to execute command (cross-spawn enhancements disabled) */
  shell?: boolean | string;
  /** Signal to use to kill the child process */
  killSignal?: string | number;
  /** Timeout for sync operations */
  timeout?: number;
  /** Max buffer size for stdout/stderr in sync operations */
  maxBuffer?: number;
  /** Encoding for sync string output */
  encoding?: string;
  /** Windows-specific: pass arguments verbatim */
  windowsVerbatimArguments?: boolean;
  /** Windows-specific: hide console window */
  windowsHide?: boolean;
}

Error Handling

Cross-spawn provides consistent error handling across platforms:

const spawn = require('cross-spawn');

// Async error handling
const child = spawn('nonexistent-command');
child.on('error', (err) => {
  if (err.code === 'ENOENT') {
    console.error('Command not found');
  }
});

// Sync error handling  
const result = spawn.sync('nonexistent-command');
if (result.error && result.error.code === 'ENOENT') {
  console.error('Command not found');
}

Common Error Codes

  • ENOENT: Command not found or file does not exist
  • EACCES: Permission denied
  • EMFILE: Too many open files
  • ENOMEM: Cannot allocate memory

Internal/Testing Exports

Cross-spawn exposes internal functions for testing and advanced use cases. These should not be used in production code.

/**
 * Internal argument parsing function (exposed for testing)
 * @param {string} command - Command to execute
 * @param {string[]} [args] - Array of arguments
 * @param {object} [options] - Spawn options
 * @returns {object} Parsed command object with normalized arguments
 */
function _parse(command, args, options);

/**
 * Internal ENOENT error handling utilities (exposed for testing)
 */
const _enoent = {
  /** Hook into child process to emit proper ENOENT errors */
  hookChildProcess: function(cp: ChildProcess, parsed: object): void,
  /** Verify if exit status indicates ENOENT for async spawn */
  verifyENOENT: function(status: number, parsed: object): Error | null,
  /** Verify if exit status indicates ENOENT for sync spawn */
  verifyENOENTSync: function(status: number, parsed: object): Error | null,
  /** Create properly formatted ENOENT error objects */
  notFoundError: function(original: object, syscall: string): Error
};

These exports can be accessed as:

const spawn = require('cross-spawn');
const parsed = spawn._parse('command', ['arg1', 'arg2']);
const enoentUtils = spawn._enoent;

Platform Considerations

Windows Enhancements

Cross-spawn provides several Windows-specific enhancements:

  • Automatic resolution of executable extensions (.com, .exe, .bat, .cmd)
  • Proper handling of batch files and Windows commands
  • Support for shebang headers (limited to #!/usr/bin/env <program> format)
  • Correct escaping of meta characters in commands and arguments

Shell Option Behavior

When using options.shell, cross-spawn's enhancements are disabled to match Node.js behavior:

// Cross-spawn enhancements active (recommended)
spawn('npm', ['install']);

// Cross-spawn enhancements disabled (matches Node.js behavior)
spawn('npm install', { shell: true });

Shebang Limitations

Shebang support on Windows is limited to the format #!/usr/bin/env <program> where <program> cannot contain arguments.

Migration from Node.js Built-ins

Cross-spawn is a drop-in replacement for Node.js built-in spawn functions:

// Replace this
const { spawn, spawnSync } = require('child_process');

// With this
const spawn = require('cross-spawn');
const spawnSync = spawn.sync; // or const { sync: spawnSync } = require('cross-spawn');

// All existing code works unchanged
const child = spawn('command', ['args'], options);
const result = spawnSync('command', ['args'], options);