@andyfischer/subprocess-wrapper
v0.2.0
Published
A helpful wrapper around Node.js child processes with line-based parsing, event listeners, and promise support.
Downloads
7
Readme
subprocess-wrapper
A helpful wrapper around Node.js child processes with line-based parsing, event listeners, and promise support.
Features
- Parses stdout and stderr as lines
- Event listeners for stdout/stderr output
- Output buffering with getters
- Promise-based process completion
- Error handling and process management
- Shell command convenience functions
Installation
npm install @andyfischer/subprocess-wrapperQuick Start
import { runShellCommand, startShellCommand, Subprocess } from '@andyfischer/subprocess-wrapper';
// Run a command and wait for completion
const result = await runShellCommand('ls -la');
console.log(result.stdout);
// Start a command with real-time output
const subprocess = startShellCommand('ping google.com', {
onStdout: (line) => console.log('OUT:', line),
onStderr: (line) => console.log('ERR:', line)
});API Reference
High-Level Functions
runShellCommand(command, options?)
Runs a shell command and returns a promise that resolves with the complete result.
Parameters:
command: string | string[]- Command to run (string will be split on spaces)options?: ShellCommandOptions- Configuration options
Returns: Promise<SubprocessResult>
Example:
const result = await runShellCommand('echo "Hello World"');
console.log(result.stdout); // ['Hello World']
console.log(result.exitCode); // 0
console.log(result.failed()); // falsestartShellCommand(command, options?)
Starts a shell command and returns a Subprocess instance for real-time interaction.
Parameters:
command: string | string[]- Command to runoptions?: ShellCommandOptions- Configuration options
Returns: Subprocess
Example:
const subprocess = startShellCommand('tail -f /var/log/system.log', {
onStdout: (line) => console.log('LOG:', line),
enableOutputBuffering: false
});
// Stop the process after 10 seconds
setTimeout(() => subprocess.kill(), 10000);Classes
Subprocess
Main class for managing a subprocess with event-driven output handling.
Constructor:
new Subprocess(options?: { enableOutputBuffering?: boolean })Methods:
start(command, options?)
Starts the subprocess.
command: string | string[]- Command to executeoptions?: SubprocessOptions- Node.js spawn options
Example:
const subprocess = new Subprocess();
subprocess.onStdout(line => console.log('Output:', line));
subprocess.start(['ls', '-la'], { cwd: '/tmp' });
await subprocess.waitForExit();onStdout(listener)
Adds a listener for stdout lines.
listener: (line: string) => void- Callback for each stdout line
Example:
subprocess.onStdout((line) => {
console.log('Received:', line);
});onStderr(listener)
Adds a listener for stderr lines.
listener: (line: string) => void- Callback for each stderr line
Example:
subprocess.onStderr((line) => {
console.error('Error output:', line);
});getStdout()
Returns all stdout lines as an array (requires enableOutputBuffering: true).
Returns: string[]
Example:
const subprocess = new Subprocess({ enableOutputBuffering: true });
subprocess.start('ls -la');
await subprocess.waitForExit();
const lines = subprocess.getStdout();
console.log('All output lines:', lines);getStderr()
Returns all stderr lines as an array (requires enableOutputBuffering: true).
Returns: string[]
waitForExit()
Returns a promise that resolves when the process exits.
Returns: Promise<void>
Example:
const subprocess = startShellCommand('sleep 5');
console.log('Process started...');
await subprocess.waitForExit();
console.log('Process completed!');kill()
Terminates the running process.
Example:
const subprocess = startShellCommand('ping google.com');
// Kill after 5 seconds
setTimeout(() => {
subprocess.kill();
console.log('Process terminated');
}, 5000);SubprocessResult
Result object returned by runShellCommand().
Properties:
exitCode: number- Process exit codestdout: string[]- Array of stdout linesstderr: string[]- Array of stderr linessubprocess: Subprocess- Reference to the subprocess instance
Methods:
failed()
Returns true if the process failed (non-zero exit code).
Returns: boolean
asError()
Converts the result to an Error object (only if failed).
Returns: Error
Example:
const result = await runShellCommand('cat nonexistent-file');
if (result.failed()) {
throw result.asError(); // Throws error with stderr message
}stdoutAsString()
Returns stdout as a single string with newlines.
Returns: string
stderrAsString()
Returns stderr as a single string with newlines.
Returns: string
Example:
const result = await runShellCommand('ls -la');
console.log(result.stdoutAsString()); // Multi-line string outputOptions
ShellCommandOptions
Configuration options for shell commands.
interface ShellCommandOptions {
cwd?: string; // Working directory
stdio?: 'pipe' | 'inherit' | 'ignore'; // Standard I/O configuration
env?: Record<string, string>; // Environment variables
shell?: boolean | string; // Shell to use
enableOutputBuffering?: boolean; // Buffer output for getStdout/getStderr
onStdout?: (line: string) => void; // Stdout line callback
onStderr?: (line: string) => void; // Stderr line callback
pipePrefix?: string | boolean; // Prefix for piped output to console
}Usage Examples
Basic Command Execution
import { runShellCommand } from '@andyfischer/subprocess-wrapper';
// Simple command
const result = await runShellCommand('echo "Hello"');
console.log(result.stdout[0]); // "Hello"
// Command with arguments
const result2 = await runShellCommand(['ls', '-la', '/tmp']);
console.log(result2.stdout);Real-time Output Processing
import { startShellCommand } from '@andyfischer/subprocess-wrapper';
const subprocess = startShellCommand('npm install', {
cwd: '/path/to/project',
onStdout: (line) => console.log('📦', line),
onStderr: (line) => console.error('❌', line)
});
await subprocess.waitForExit();
console.log('Installation complete!');Long-running Process Management
const logWatcher = startShellCommand('tail -f /var/log/app.log', {
enableOutputBuffering: false,
onStdout: (line) => {
if (line.includes('ERROR')) {
console.error('🚨 Error detected:', line);
}
}
});
// Stop watching after 1 minute
setTimeout(() => logWatcher.kill(), 60000);Error Handling
try {
const result = await runShellCommand('invalid-command');
if (result.failed()) {
console.error('Command failed:', result.asError().message);
console.error('Stderr:', result.stderrAsString());
}
} catch (error) {
console.error('Execution error:', error.message);
}Custom Environment and Working Directory
const result = await runShellCommand('node build.js', {
cwd: '/path/to/project',
env: {
...process.env,
NODE_ENV: 'production',
BUILD_TARGET: 'web'
}
});Collecting Output Arrays
const subprocess = new Subprocess({ enableOutputBuffering: true });
subprocess.start('find . -name "*.js"');
await subprocess.waitForExit();
const jsFiles = subprocess.getStdout();
console.log(`Found ${jsFiles.length} JavaScript files:`);
jsFiles.forEach(file => console.log(file));Advanced Usage
Multiple Listeners
const subprocess = startShellCommand('build-script.sh');
// Add multiple stdout listeners
subprocess.onStdout((line) => logToFile(line));
subprocess.onStdout((line) => updateProgressBar(line));
subprocess.onStdout((line) => checkForWarnings(line));Process Monitoring
const subprocess = startShellCommand('long-running-process');
subprocess.onStdout((line) => console.log('OUT:', line));
subprocess.onStderr((line) => console.log('ERR:', line));
const timeout = setTimeout(() => {
console.log('Process taking too long, killing...');
subprocess.kill();
}, 30000);
await subprocess.waitForExit();
clearTimeout(timeout);
console.log('Process completed with code:', subprocess.exitCode);