@zokugun/exec-lite 0.0.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +306 -34
  3. package/lib/cjs/create-command.cjs +19 -0
  4. package/lib/cjs/create-command.d.cts +3 -0
  5. package/lib/cjs/exec-process.cjs +241 -0
  6. package/lib/cjs/exec-process.d.cts +41 -0
  7. package/lib/cjs/exec.cjs +9 -0
  8. package/lib/cjs/exec.d.cts +3 -0
  9. package/lib/cjs/index.cjs +9 -0
  10. package/lib/cjs/index.d.cts +4 -0
  11. package/lib/cjs/types.cjs +2 -0
  12. package/lib/cjs/types.d.cts +70 -0
  13. package/lib/cjs/utils/combineSignals.cjs +19 -0
  14. package/lib/cjs/utils/combineSignals.d.cts +1 -0
  15. package/lib/cjs/utils/command/detectShebang.cjs +36 -0
  16. package/lib/cjs/utils/command/detectShebang.d.cts +1 -0
  17. package/lib/cjs/utils/command/normalizeCommand.cjs +59 -0
  18. package/lib/cjs/utils/command/normalizeCommand.d.cts +6 -0
  19. package/lib/cjs/utils/command/resolveCommand.cjs +43 -0
  20. package/lib/cjs/utils/command/resolveCommand.d.cts +2 -0
  21. package/lib/cjs/utils/env/addNodeBinToPath.cjs +24 -0
  22. package/lib/cjs/utils/env/addNodeBinToPath.d.cts +2 -0
  23. package/lib/cjs/utils/env/computeEnv.cjs +17 -0
  24. package/lib/cjs/utils/env/computeEnv.d.cts +2 -0
  25. package/lib/cjs/utils/env/getPathFromEnv.cjs +22 -0
  26. package/lib/cjs/utils/env/getPathFromEnv.d.cts +2 -0
  27. package/lib/cjs/utils/env/types.cjs +2 -0
  28. package/lib/cjs/utils/env/types.d.cts +5 -0
  29. package/lib/cjs/utils/normalizeOptions.cjs +31 -0
  30. package/lib/cjs/utils/normalizeOptions.d.cts +2 -0
  31. package/lib/cjs/utils/stream/combineStreams.cjs +25 -0
  32. package/lib/cjs/utils/stream/combineStreams.d.cts +2 -0
  33. package/lib/cjs/utils/stream/readStream.cjs +16 -0
  34. package/lib/cjs/utils/stream/readStream.d.cts +5 -0
  35. package/lib/esm/create-command.d.mts +3 -0
  36. package/lib/esm/create-command.mjs +17 -0
  37. package/lib/esm/exec-process.d.mts +41 -0
  38. package/lib/esm/exec-process.mjs +235 -0
  39. package/lib/esm/exec.d.mts +3 -0
  40. package/lib/esm/exec.mjs +7 -0
  41. package/lib/esm/index.d.mts +4 -0
  42. package/lib/esm/index.mjs +3 -0
  43. package/lib/esm/types.d.mts +70 -0
  44. package/lib/esm/types.mjs +1 -0
  45. package/lib/esm/utils/combineSignals.d.mts +1 -0
  46. package/lib/esm/utils/combineSignals.mjs +16 -0
  47. package/lib/esm/utils/command/detectShebang.d.mts +1 -0
  48. package/lib/esm/utils/command/detectShebang.mjs +30 -0
  49. package/lib/esm/utils/command/normalizeCommand.d.mts +6 -0
  50. package/lib/esm/utils/command/normalizeCommand.mjs +53 -0
  51. package/lib/esm/utils/command/resolveCommand.d.mts +2 -0
  52. package/lib/esm/utils/command/resolveCommand.mjs +37 -0
  53. package/lib/esm/utils/env/addNodeBinToPath.d.mts +2 -0
  54. package/lib/esm/utils/env/addNodeBinToPath.mjs +18 -0
  55. package/lib/esm/utils/env/computeEnv.d.mts +2 -0
  56. package/lib/esm/utils/env/computeEnv.mjs +14 -0
  57. package/lib/esm/utils/env/getPathFromEnv.d.mts +2 -0
  58. package/lib/esm/utils/env/getPathFromEnv.mjs +19 -0
  59. package/lib/esm/utils/env/types.d.mts +5 -0
  60. package/lib/esm/utils/env/types.mjs +1 -0
  61. package/lib/esm/utils/normalizeOptions.d.mts +2 -0
  62. package/lib/esm/utils/normalizeOptions.mjs +25 -0
  63. package/lib/esm/utils/stream/combineStreams.d.mts +2 -0
  64. package/lib/esm/utils/stream/combineStreams.mjs +22 -0
  65. package/lib/esm/utils/stream/readStream.d.mts +5 -0
  66. package/lib/esm/utils/stream/readStream.mjs +13 -0
  67. package/package.json +145 -3
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exec = exec;
4
+ const exec_process_js_1 = require("./exec-process.cjs");
5
+ function exec(command, args, options) {
6
+ const subprocess = new exec_process_js_1.ExecProcess(command, args, options);
7
+ subprocess.spawn();
8
+ return subprocess;
9
+ }
@@ -0,0 +1,3 @@
1
+ import type { Options, ResultMode, Subprocess } from './types.cjs';
2
+ declare function exec<M extends ResultMode = 'result'>(command: string, args?: readonly string[] | null, options?: Partial<Options<M>>): Subprocess<M>;
3
+ export { type Options, type ResultMode, type Subprocess, exec, };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exec = exports.ExecProcess = exports.createCommand = void 0;
4
+ var create_command_js_1 = require("./create-command.cjs");
5
+ Object.defineProperty(exports, "createCommand", { enumerable: true, get: function () { return create_command_js_1.createCommand; } });
6
+ var exec_process_js_1 = require("./exec-process.cjs");
7
+ Object.defineProperty(exports, "ExecProcess", { enumerable: true, get: function () { return exec_process_js_1.ExecProcess; } });
8
+ var exec_js_1 = require("./exec.cjs");
9
+ Object.defineProperty(exports, "exec", { enumerable: true, get: function () { return exec_js_1.exec; } });
@@ -0,0 +1,4 @@
1
+ export type { Command, ExecFailure, ExecResult, ExecSuccess, KillSignal, Options, ResultMode, StdinOption, StdioOption, Subprocess, } from './types.cjs';
2
+ export { createCommand } from './create-command.cjs';
3
+ export { ExecProcess } from './exec-process.cjs';
4
+ export { exec } from './exec.cjs';
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,70 @@
1
+ import type { ChildProcess, SpawnOptions as ProcessSpawnOptions } from 'node:child_process';
2
+ import type { Result } from '@zokugun/xtry';
3
+ export type Command<M extends ResultMode = 'result'> = {
4
+ (args?: readonly string[] | null, options?: Partial<Options<M>>): Subprocess<M>;
5
+ toCwdFirst(): (cwd: string, ...args: string[]) => Subprocess<M>;
6
+ toFlatArgs(): (...args: string[]) => Subprocess<M>;
7
+ withOptions(options: Partial<Options<M>>): Command<M>;
8
+ };
9
+ export type ExecFailure = {
10
+ args: readonly string[];
11
+ canceled: boolean;
12
+ cwd?: string;
13
+ command: string;
14
+ durationMs: number;
15
+ error?: Error;
16
+ exitCode?: number;
17
+ merged?: string;
18
+ pipedFrom?: ExecResult;
19
+ signalCode?: string;
20
+ stderr?: string;
21
+ stdout?: string;
22
+ };
23
+ export type ResultMode = 'merged' | 'result';
24
+ export type ExecResult<M extends ResultMode = 'result'> = M extends 'merged' ? string : Result<ExecSuccess, ExecFailure>;
25
+ export type ExecSuccess = {
26
+ args: readonly string[];
27
+ command: string;
28
+ cwd: string;
29
+ durationMs: number;
30
+ error?: undefined;
31
+ exitCode: number;
32
+ merged: string;
33
+ pipedFrom?: ExecResult;
34
+ stderr: string;
35
+ stdout: string;
36
+ };
37
+ export type KillSignal = Parameters<ChildProcess['kill']>[0];
38
+ export type Options<M extends ResultMode = ResultMode> = Omit<ProcessSpawnOptions, 'cwd' | 'env' | 'stdio'> & Readonly<Partial<{
39
+ cwd?: string;
40
+ env: Readonly<Partial<Record<string, string>>>;
41
+ localDir: string;
42
+ preferLocal: boolean;
43
+ resultMode: M;
44
+ signal: AbortSignal;
45
+ stderr: StdioOption;
46
+ stdin: ExecResult | StdinOption | Subprocess<ResultMode>;
47
+ stdio: readonly [StdinOption, ...readonly StdioOption[]] | SpawnOptions['stdio'];
48
+ stdout: StdioOption;
49
+ }>>;
50
+ export type SpawnOptions = {
51
+ cwd: string;
52
+ } & Omit<ProcessSpawnOptions, 'cwd'>;
53
+ export type StdinOption = StdioOption | {
54
+ readonly string?: string;
55
+ };
56
+ export type StdioOption = Readonly<Exclude<SpawnOptions['stdio'], undefined>[number]>;
57
+ export type Subprocess<M extends ResultMode = 'result'> = AsyncIterable<string> & PromiseLike<ExecResult<M>> & {
58
+ get aborted(): boolean;
59
+ get error(): Error | undefined;
60
+ get exitCode(): number | undefined;
61
+ get failed(): boolean;
62
+ kill: (signal?: KillSignal) => boolean;
63
+ get killed(): boolean;
64
+ get pid(): number | undefined;
65
+ pipe: <N extends ResultMode = 'result'>(command: string, args?: readonly string[], options?: Partial<Options> & {
66
+ resultMode?: N;
67
+ }) => Subprocess<N>;
68
+ get process(): ChildProcess | undefined;
69
+ get signalCode(): string | undefined;
70
+ };
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.combineSignals = combineSignals;
4
+ function combineSignals(signals) {
5
+ const controller = new AbortController();
6
+ for (const signal of signals) {
7
+ if (signal.aborted) {
8
+ controller.abort();
9
+ return signal;
10
+ }
11
+ const onAbort = () => {
12
+ controller.abort(signal.reason);
13
+ };
14
+ signal.addEventListener('abort', onAbort, {
15
+ signal: controller.signal,
16
+ });
17
+ }
18
+ return controller.signal;
19
+ }
@@ -0,0 +1 @@
1
+ export declare function combineSignals(signals: AbortSignal[]): AbortSignal;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.detectShebang = detectShebang;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = require("node:path");
9
+ const SHEBANG_REGEX = /^#!\s*(.+)/;
10
+ const SIZE = 150;
11
+ function detectShebang(file) {
12
+ const buffer = Buffer.alloc(SIZE);
13
+ let fd = null;
14
+ try {
15
+ fd = node_fs_1.default.openSync(file, 'r');
16
+ node_fs_1.default.readSync(fd, buffer, 0, SIZE, 0);
17
+ }
18
+ catch {
19
+ // do nothing, we'll just assume it's not a shebang
20
+ }
21
+ finally {
22
+ if (fd !== null) {
23
+ node_fs_1.default.closeSync(fd);
24
+ }
25
+ }
26
+ const match = SHEBANG_REGEX.exec(buffer.toString());
27
+ if (match === null) {
28
+ return null;
29
+ }
30
+ const line = match[1].trim();
31
+ const separatorIndex = line.indexOf(' ');
32
+ const path = separatorIndex !== -1 ? line.slice(0, separatorIndex) : line;
33
+ const argument = separatorIndex !== -1 ? line.slice(separatorIndex + 1) : '';
34
+ const binary = (0, node_path_1.basename)(path);
35
+ return binary === 'env' ? argument || null : binary;
36
+ }
@@ -0,0 +1 @@
1
+ export declare function detectShebang(file: string): string | null;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.normalizeCommand = normalizeCommand;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const detectShebang_js_1 = require("./detectShebang.cjs");
9
+ const resolveCommand_js_1 = require("./resolveCommand.cjs");
10
+ const IS_BATCH_FILE_REGEX = /\.(?:bat|cmd)$/i;
11
+ const IS_EXECUTABLE_REGEX = /\.(?:com|exe)$/i;
12
+ const IS_WINDOWS = process.platform === 'win32';
13
+ const META_CHARS_REGEX = /([ !"%&()*,;<>?[\]^`|])/g;
14
+ function normalizeCommand(command, args, options) {
15
+ if (['node', 'node.exe'].includes(command.toLowerCase())) {
16
+ command = process.execPath;
17
+ args = [...process.execArgv.filter((flag) => !flag.startsWith('--inspect')), ...args];
18
+ }
19
+ if (options.shell === true || !IS_WINDOWS) {
20
+ return {
21
+ command,
22
+ args,
23
+ options,
24
+ };
25
+ }
26
+ let file = (0, resolveCommand_js_1.resolveCommand)(command, options);
27
+ if (file !== null) {
28
+ const shebang = (0, detectShebang_js_1.detectShebang)(file);
29
+ if (shebang !== null) {
30
+ args = [file, ...args];
31
+ command = shebang;
32
+ file = (0, resolveCommand_js_1.resolveCommand)(command, options);
33
+ }
34
+ }
35
+ if (file !== null && IS_EXECUTABLE_REGEX.test(file)) {
36
+ return {
37
+ command,
38
+ args,
39
+ options,
40
+ };
41
+ }
42
+ const needsDoubleEscape = file !== null && IS_BATCH_FILE_REGEX.test(file);
43
+ const normalizedCommand = node_path_1.default.normalize(command).replace(META_CHARS_REGEX, '^$1');
44
+ const normalizedArgs = [];
45
+ for (let arg of args) {
46
+ arg = arg.replace(/(?=(\\+?))\1(?:"|$)/g, '$1$1\\"');
47
+ arg = `"${arg}"`;
48
+ arg = arg.replace(META_CHARS_REGEX, '^$1');
49
+ if (needsDoubleEscape) {
50
+ arg = arg.replace(META_CHARS_REGEX, '^$1');
51
+ }
52
+ normalizedArgs.push(arg);
53
+ }
54
+ return {
55
+ command: options.env?.comspec ?? 'cmd.exe',
56
+ args: ['/d', '/s', '/c', `"${[normalizedCommand, ...normalizedArgs].join(' ')}"`],
57
+ options: { ...options, windowsVerbatimArguments: true },
58
+ };
59
+ }
@@ -0,0 +1,6 @@
1
+ import type { SpawnOptions } from '../../types.cjs';
2
+ export declare function normalizeCommand(command: string, args: readonly string[], options: SpawnOptions): {
3
+ args: readonly string[];
4
+ command: string;
5
+ options: SpawnOptions;
6
+ };
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveCommand = resolveCommand;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const getPathFromEnv_js_1 = require("../env/getPathFromEnv.cjs");
10
+ const CACHE = Object.create(null);
11
+ const DEFAULT_PATH_EXT = ['.EXE', '.CMD', '.BAT', '.COM'];
12
+ function resolveCommand(command, options) {
13
+ const cwd = options.cwd ?? process.cwd();
14
+ const env = options.env ?? process.env;
15
+ const pathEnv = (0, getPathFromEnv_js_1.getPathFromEnv)(env).value;
16
+ const key = `${command}%%%%${pathEnv}`;
17
+ if (CACHE[key] !== undefined) {
18
+ return CACHE[key];
19
+ }
20
+ const parts = command.includes('/') || command.includes('\\') ? [''] : [cwd, ...pathEnv.split(node_path_1.default.delimiter)];
21
+ let pathExt = env.PATHEXT ? env.PATHEXT.split(node_path_1.default.delimiter) : DEFAULT_PATH_EXT;
22
+ if (command.includes('.') && pathExt[0] !== '') {
23
+ pathExt = ['', ...pathExt];
24
+ }
25
+ for (const part of parts) {
26
+ const unquoted = part.startsWith('"') && part.endsWith('"') && part.length > 1 ? part.slice(1, -1) : part;
27
+ const dest = node_path_1.default.resolve(cwd, unquoted, command);
28
+ for (const ext of [...pathExt, '']) {
29
+ const destWithExt = dest + ext;
30
+ try {
31
+ if (node_fs_1.default.statSync(destWithExt).isFile()) {
32
+ CACHE[key] = destWithExt;
33
+ return destWithExt;
34
+ }
35
+ }
36
+ catch {
37
+ // do nothing, it didn't exist
38
+ }
39
+ }
40
+ }
41
+ CACHE[key] = null;
42
+ return null;
43
+ }
@@ -0,0 +1,2 @@
1
+ import type { SpawnOptions } from '../../types.cjs';
2
+ export declare function resolveCommand(command: string, options: SpawnOptions): string | null;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.addNodeBinToPath = addNodeBinToPath;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ function addNodeBinToPath(cwd, { value, key }) {
9
+ const parts = value.split(node_path_1.default.delimiter);
10
+ const nodeBinPaths = [];
11
+ let currentPath = cwd;
12
+ let lastPath;
13
+ do {
14
+ nodeBinPaths.push(node_path_1.default.resolve(currentPath, 'node_modules', '.bin'));
15
+ lastPath = currentPath;
16
+ currentPath = node_path_1.default.dirname(currentPath);
17
+ } while (currentPath !== lastPath);
18
+ nodeBinPaths.push(node_path_1.default.dirname(process.execPath));
19
+ const newValue = nodeBinPaths.concat(parts).join(node_path_1.default.delimiter);
20
+ return {
21
+ key,
22
+ value: newValue,
23
+ };
24
+ }
@@ -0,0 +1,2 @@
1
+ import type { EnvPathInfo } from './types.cjs';
2
+ export declare function addNodeBinToPath(cwd: string, { value, key }: EnvPathInfo): EnvPathInfo;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeEnv = computeEnv;
4
+ const addNodeBinToPath_js_1 = require("./addNodeBinToPath.cjs");
5
+ const getPathFromEnv_js_1 = require("./getPathFromEnv.cjs");
6
+ function computeEnv(env, preferLocal, localDir) {
7
+ const computedEnv = {
8
+ ...process.env,
9
+ ...env,
10
+ };
11
+ if (!preferLocal) {
12
+ return computedEnv;
13
+ }
14
+ const pathEnvInfo = (0, addNodeBinToPath_js_1.addNodeBinToPath)(localDir, (0, getPathFromEnv_js_1.getPathFromEnv)(computedEnv));
15
+ computedEnv[pathEnvInfo.key] = pathEnvInfo.value;
16
+ return computedEnv;
17
+ }
@@ -0,0 +1,2 @@
1
+ import type { EnvLike } from './types.cjs';
2
+ export declare function computeEnv(env: Readonly<EnvLike> | undefined, preferLocal: boolean, localDir: string): Readonly<EnvLike>;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPathFromEnv = getPathFromEnv;
4
+ function getPathFromEnv(env) {
5
+ for (const key in env) {
6
+ if (key.toLowerCase() !== 'path') {
7
+ continue;
8
+ }
9
+ const value = env[key];
10
+ if (!value) {
11
+ return {
12
+ key: 'PATH',
13
+ value: '',
14
+ };
15
+ }
16
+ return { key, value };
17
+ }
18
+ return {
19
+ key: 'PATH',
20
+ value: '',
21
+ };
22
+ }
@@ -0,0 +1,2 @@
1
+ import type { EnvLike, EnvPathInfo } from './types.cjs';
2
+ export declare function getPathFromEnv(env: EnvLike): EnvPathInfo;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ export type EnvLike = (typeof process)['env'];
2
+ export type EnvPathInfo = {
3
+ key: string;
4
+ value: string;
5
+ };
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.normalizeOptions = normalizeOptions;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const computeEnv_js_1 = require("./env/computeEnv.cjs");
9
+ const combineSignals_js_1 = require("./combineSignals.cjs");
10
+ function normalizeOptions(options) {
11
+ const { cwd, env, preferLocal, resultMode: _resultMode, signal, stderr, stdin, stdio: stdioOption, stdout, ...restOptions } = options;
12
+ const spawnOptions = restOptions;
13
+ spawnOptions.cwd = node_path_1.default.resolve(cwd ?? process.cwd());
14
+ spawnOptions.env = (0, computeEnv_js_1.computeEnv)(env, preferLocal ?? false, options.localDir ?? spawnOptions.cwd);
15
+ const signals = [];
16
+ if (options.timeout !== undefined) {
17
+ signals.push(AbortSignal.timeout(options.timeout));
18
+ }
19
+ if (signal !== undefined) {
20
+ signals.push(signal);
21
+ }
22
+ if (signals.length > 0) {
23
+ spawnOptions.signal = (0, combineSignals_js_1.combineSignals)(signals);
24
+ }
25
+ const stdio = stdioOption ?? [undefined, stdout, stderr];
26
+ if (Array.isArray(stdio) && !(typeof stdin === 'string' || (typeof stdin === 'object' && stdin !== null && 'process' in stdin))) {
27
+ stdio[0] = 'pipe';
28
+ }
29
+ spawnOptions.stdio = stdio;
30
+ return spawnOptions;
31
+ }
@@ -0,0 +1,2 @@
1
+ import type { Options, SpawnOptions } from '../types.cjs';
2
+ export declare function normalizeOptions(options: Options): SpawnOptions;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.combineStreams = combineStreams;
4
+ const node_stream_1 = require("node:stream");
5
+ const promises_1 = require("node:stream/promises");
6
+ function combineStreams(streams) {
7
+ let streamCount = streams.length;
8
+ const combined = new node_stream_1.PassThrough();
9
+ if (streamCount === 0) {
10
+ combined.end();
11
+ return combined;
12
+ }
13
+ const maybeEmitEnd = () => {
14
+ streamCount -= 1;
15
+ if (streamCount === 0) {
16
+ combined.end();
17
+ }
18
+ };
19
+ for (const stream of streams) {
20
+ (0, promises_1.pipeline)(stream, combined, { end: false })
21
+ .then(maybeEmitEnd)
22
+ .catch(maybeEmitEnd);
23
+ }
24
+ return combined;
25
+ }
@@ -0,0 +1,2 @@
1
+ import type { Readable } from 'node:stream';
2
+ export declare function combineStreams(streams: Readable[]): Readable;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readStream = readStream;
4
+ async function readStream(stream, context) {
5
+ let output = '';
6
+ try {
7
+ for await (const chunk of stream) {
8
+ output += String(chunk);
9
+ context.merged += String(chunk);
10
+ }
11
+ }
12
+ catch {
13
+ // suppress errors, child process probably failed to spawn
14
+ }
15
+ return output;
16
+ }
@@ -0,0 +1,5 @@
1
+ import type { Readable } from 'node:stream';
2
+ export type StreamContext = {
3
+ merged: string;
4
+ };
5
+ export declare function readStream(stream: Readable, context: StreamContext): Promise<string>;
@@ -0,0 +1,3 @@
1
+ import type { Command, Options, ResultMode, Subprocess } from './types.mjs';
2
+ declare function createCommand<M extends ResultMode = 'result'>(command: string, args?: readonly string[] | null, options?: Partial<Options<M>>): Command<M>;
3
+ export { type Command, type Options, type ResultMode, type Subprocess, createCommand, };
@@ -0,0 +1,17 @@
1
+ import { exec } from './exec.mjs';
2
+ function createCommand(command, args = [], options = {}) {
3
+ const create = (options) => {
4
+ const run = ((runArgs, runOptions) => {
5
+ return exec(command, [...(args ?? []), ...(runArgs ?? [])], {
6
+ ...options,
7
+ ...runOptions,
8
+ });
9
+ });
10
+ run.withOptions = (overrides) => create({ ...options, ...overrides });
11
+ run.toCwdFirst = () => ((cwd, ...runArgs) => run(runArgs, { cwd }));
12
+ run.toFlatArgs = () => ((...runArgs) => run(runArgs));
13
+ return run;
14
+ };
15
+ return create(options);
16
+ }
17
+ export { createCommand, };
@@ -0,0 +1,41 @@
1
+ import type { ChildProcess } from 'node:child_process';
2
+ import type { Readable } from 'node:stream';
3
+ import type { ExecFailure, ExecResult, ExecSuccess, KillSignal, Options, ResultMode, Subprocess } from './types.mjs';
4
+ declare class ExecProcess implements Subprocess<ResultMode> {
5
+ protected _aborted: boolean;
6
+ protected _args: readonly string[];
7
+ protected _command: string;
8
+ protected _cwd: string | undefined;
9
+ protected _failed: boolean;
10
+ protected _options: Partial<Options>;
11
+ protected _process?: ChildProcess;
12
+ protected _processClosed: Promise<void>;
13
+ protected _resolveClose?: () => void;
14
+ protected _signal?: AbortSignal;
15
+ protected _start?: bigint;
16
+ protected _streamErr?: Readable;
17
+ protected _streamOut?: Readable;
18
+ protected _thrownError?: Error;
19
+ constructor(command: string, args?: readonly string[] | null, options?: Partial<Options>);
20
+ get aborted(): boolean;
21
+ get error(): Error | undefined;
22
+ get exitCode(): number | undefined;
23
+ get failed(): boolean;
24
+ get killed(): boolean;
25
+ get pid(): number | undefined;
26
+ get process(): ChildProcess | undefined;
27
+ get signalCode(): string | undefined;
28
+ kill(signal?: KillSignal): boolean;
29
+ pipe<N extends ResultMode = 'result'>(command: string, args?: readonly string[], options?: Partial<Options> & {
30
+ resultMode?: N;
31
+ }): Subprocess<N>;
32
+ spawn(): void;
33
+ [Symbol.asyncIterator](): AsyncIterator<string>;
34
+ then<TResult1 = ExecResult<ResultMode>, TResult2 = never>(onfulfilled?: ((value: ExecResult<ResultMode>) => PromiseLike<TResult1> | TResult1) | null, onrejected?: ((reason: unknown) => PromiseLike<TResult2> | TResult2) | null): Promise<TResult1 | TResult2>;
35
+ protected onClose(): void;
36
+ protected onError(error: Error): void;
37
+ protected reset(): void;
38
+ protected toFailure(error: Error): ExecResult<ResultMode>;
39
+ protected toResult(): Promise<ExecResult<ResultMode>>;
40
+ }
41
+ export { type ExecFailure, type ExecResult, type ExecSuccess, type KillSignal, type Options, type ResultMode, type Subprocess, ExecProcess, };