UNPKG

@j-o-r/sh

Version:

Execute shell commands on Linux-based systems from javascript

233 lines (160 loc) 7.15 kB
# @j-o-r/sh Module Documentation ## Overview **Name:** @j-o-r/sh **Version:** 1.1.26 **Description:** Execute shell commands on Linux-based systems from javascript. This module simplifies the execution of shell commands within JavaScript applications, providing utilities to handle shell scripts and manage their output efficiently. It is inspired by the zx library and supports features like command execution, retries, user input, and more. **Repository:** https://codeberg.org/duin/sh **License:** Apache License, Version 2.0 Key features include: - Execute shell commands synchronously or asynchronously. - Utilities for changing directory, sleeping, retrying commands with backoff. - Parsing command-line arguments. - User input prompts. - A minimal test framework. - Async operation tracking. ## Installation Notes The module is already installed in the current environment. For new installations, use: ```sh npm install @j-o-r/sh ``` Requires Node.js >= 20.0.0. ## API Usage Examples ### Basic Usage ```javascript import { SH } from '@j-o-r/sh'; const output = await SH`ls -la`.run(); console.log(output); ``` ### Advanced Usage ```javascript import { SH, cd, within, sleep, retry, expBackoff, userIn } from '@j-o-r/sh'; cd('/tmp'); // Change directory const res = await SH`echo "Hello World"`.run(); console.log(res); // Retry example try { const p = await retry(3, expBackoff(), () => SH`curl -s https://unreachable`.run()); console.log(p); } catch (e) { console.error('Retry failed:', e); } // User input const user = userIn('Enter your name: '); const name = await user.input; console.log('Hello,', name); // Within async context within(async () => { const results = await Promise.all([ SH`sleep 1; echo 1`.run(), SH`sleep 2; echo 2`.run(), sleep(2), SH`sleep 3; echo 3`.run() ]); console.log(results); }); ``` ### Test Framework Example ```javascript import { Test, assert, jsType } from '@j-o-r/sh'; const test = new Test(); test.add('Test type', () => { assert.strictEqual(jsType('string'), 'String'); }); const report = await test.run(); if (report.errors > 0) { process.exit(1); } ``` ### AsyncTracker Example ```javascript import { AsyncTracker } from '@j-o-r/sh'; const tracker = new AsyncTracker(); tracker.enable(); setTimeout(() => { tracker.report(true); // Verbose report }, 1000); ``` ## Full API Reference ### Main Exports - **SH**: `(pieces: TemplateStringsArray, ...args: unknown[]) => SHDispatch` - Template tag for creating shell commands. Returns SHDispatch. - Interpolation: Arrays elements trimmed/escaped; non-arrays String(value) as-is (no escape, careful with untrusted input). - **cd(dir: string)**: `void` - Changes the working directory. - **sleep(duration: string | number)**: `Promise<any>` - Pauses execution for duration (e.g., '5s', 5000 ms). - **retry(count: number, a: string | number | typeof expBackoff | Function, b?: Function)**: `Promise<any>` - Retries callback up to `count` times. `a` can be delay, backoff generator, or callback (then `b` is callback). - **readIn()**: `Promise<string>` - Reads stdin as UTF-8, empty if TTY. - **userIn(prompt: string)**: `{input: Promise<string | void>, abort: () => void}` - Prompts user for input. - **within(callback: Function)**: `Promise<any>` - Executes callback in a new execution context. - **expBackoff(max?: string, rand?: string)**: `Generator<number>` - Yields exponential backoff intervals with jitter (max default '60s', rand '100ms'). - **parseArgs(args?: string[])**: `ArgsObject` - Parses args: --key value, -k value; duplicates error; no =value or grouped shorts; _ for unnamed. - **jsType(any: any)**: `string` - Returns real JS type name (e.g., 'Array' for []). - **hasProp(o: any, p: string)**: `boolean` - Safely checks if `o` has own property `p` (handles null/undefined). - **assert**: `typeof import('node:assert')` - Node.js assert module. - **Test**: Class - Minimal sync/async test framework (see below). - **AsyncTracker**: Class - Tracks async operations using Node async_hooks (see below). ### SHDispatch Class `new SHDispatch(cmd: string, options: SHOptions, prefix?: string)` - **options(options?: SHOptions, prefix?: string)**: `SHDispatch` - Configures execution options, merges with defaults (resets each call). - **run(payload?: string)**: `Promise<string>` - Executes command asynchronously, returns stdout. Rejects on error/timeout/kill. - **runSync(payload?: string)**: `import('child_process').SpawnSyncReturns<any>` - Executes synchronously. - **kill(signal?: string)**: `Promise<number[]>` - Kills the process (and children if possible). **Defaults/Semantics:** - cwd: `process.cwd()` - env: `process.env` - shell: `'bash'` (use shell if string/true; no shell if false/undefined, uses /usr/bin/env -S) - stdio: `['inherit', 'pipe', 'pipe']` - timeout: `0` (no timeout) - Prefix (e.g., 'set -euo pipefail') applied only with shell. - Buffering: Up to 40MiB per stream, truncates with marker. - Payload: Writes to stdin (forces pipe). ### Test Class `new Test(quiet?: boolean)` - quiet: no auto-report. - **syncTimeout(timeout: number)**: `void` - Timeout for sync tests (default 50ms, for async in sync). - **add(description: string, callback: Function | AsyncFunction)**: `Test` - Adds sync or async test. Throws if conditions fail. - **run(execute?: number[])**: `Promise<Report>` - Runs all or specified tests (by index). - **unresolved()**: `void` - Checks/handles unresolved (internal?). - **reset()**: `void` - Clears tests. **Types:** - `AsyncFunction = () => Promise<any>` - `testDefinition = {description: string, callback: Function | AsyncFunction}` - `testReport = {description: string, duration: number, executed: boolean}` - `Report = {tests: number, duration: number, errors: number, executed: number}` ### AsyncTracker Class `new AsyncTracker()` - **enable(type?: SystemTypes)**: `void` - Starts tracking all or specific type. - **disable()**: `void` - Stops tracking. - **reset()**: `void` - Clears tracked items. - **report(verbose?: boolean)**: `number` - Logs unresolved, returns count. - **getUnresolved(type?: SystemTypes)**: `AsyncHookItem[]` - Gets unresolved items. - **getTypeDescription(type: SystemTypes)**: `string` - Description of type. - **addCustomType(type: string, description: string)**: `void` - Adds custom type desc. **Types:** - `AsyncHookItem = {key: number, type: string, triggerAsyncId: number, stack: string, resource: SystemTypes}` - `SystemTypes` = "PROMISE" | "TIMEOUT" | ... (full Node async resource types) ### Other Types - `ArgsObject = {[x: string]: string}` (with `_`: string[] for unnamed) - `SpawnSyncResponse = {status: number|null, signal: string|null, output: (string|Buffer|null)[], pid: number, stdout: string|Buffer|null, stderr: string|Buffer|null}` - `SHOptions` extends `SpawnOptions` & `{maxBuffer?: number, input?: string|Uint8Array|Buffer}` - `StdioOption = "pipe" | "ignore" | "inherit" | number` ## Dependencies **Runtime Dependencies:** None **Dev Dependencies:** - @types/node: ^22.10.10