UNPKG

4.98 kBTypeScriptView Raw
1/// <reference types="node" />
2/// <reference types="node" />
3/// <reference types="node" />
4/// <reference types="node" />
5import { ChildProcess as BaseChildProcess, MessageOptions, SendHandle, SpawnOptions } from 'child_process';
6import * as Rx from 'rxjs';
7import { EventEmitter, Writable } from 'stream';
8/**
9 * Identifier for a command; if string, it's the command's name, if number, it's the index.
10 */
11export type CommandIdentifier = string | number;
12export interface CommandInfo {
13 /**
14 * Command's name.
15 */
16 name: string;
17 /**
18 * Which command line the command has.
19 */
20 command: string;
21 /**
22 * Which environment variables should the spawned process have.
23 */
24 env?: Record<string, unknown>;
25 /**
26 * The current working directory of the process when spawned.
27 */
28 cwd?: string;
29 /**
30 * Color to use on prefix of the command.
31 */
32 prefixColor?: string;
33 /**
34 * Whether sending of messages to/from this command (also known as "inter-process communication")
35 * should be enabled, and using which file descriptor number.
36 *
37 * If set, must be > 2.
38 */
39 ipc?: number;
40 /**
41 * Output command in raw format.
42 */
43 raw?: boolean;
44}
45export interface CloseEvent {
46 command: CommandInfo;
47 /**
48 * The command's index among all commands ran.
49 */
50 index: number;
51 /**
52 * Whether the command exited because it was killed.
53 */
54 killed: boolean;
55 /**
56 * The exit code or signal for the command.
57 */
58 exitCode: string | number;
59 timings: {
60 startDate: Date;
61 endDate: Date;
62 durationSeconds: number;
63 };
64}
65export interface TimerEvent {
66 startDate: Date;
67 endDate?: Date;
68}
69export interface MessageEvent {
70 message: object;
71 handle?: SendHandle;
72}
73interface OutgoingMessageEvent extends MessageEvent {
74 options?: MessageOptions;
75 onSent(error?: unknown): void;
76}
77/**
78 * Subtype of NodeJS's child_process including only what's actually needed for a command to work.
79 */
80export type ChildProcess = EventEmitter & Pick<BaseChildProcess, 'pid' | 'stdin' | 'stdout' | 'stderr' | 'send'>;
81/**
82 * Interface for a function that must kill the process with `pid`, optionally sending `signal` to it.
83 */
84export type KillProcess = (pid: number, signal?: string) => void;
85/**
86 * Interface for a function that spawns a command and returns its child process instance.
87 */
88export type SpawnCommand = (command: string, options: SpawnOptions) => ChildProcess;
89/**
90 * The state of a command.
91 *
92 * - `stopped`: command was never started
93 * - `started`: command is currently running
94 * - `errored`: command failed spawning
95 * - `exited`: command is not running anymore, e.g. it received a close event
96 */
97type CommandState = 'stopped' | 'started' | 'errored' | 'exited';
98export declare class Command implements CommandInfo {
99 private readonly killProcess;
100 private readonly spawn;
101 private readonly spawnOpts;
102 readonly index: number;
103 /** @inheritdoc */
104 readonly name: string;
105 /** @inheritdoc */
106 readonly command: string;
107 /** @inheritdoc */
108 readonly prefixColor?: string;
109 /** @inheritdoc */
110 readonly env: Record<string, unknown>;
111 /** @inheritdoc */
112 readonly cwd?: string;
113 /** @inheritdoc */
114 readonly ipc?: number;
115 readonly close: Rx.Subject<CloseEvent>;
116 readonly error: Rx.Subject<unknown>;
117 readonly stdout: Rx.Subject<Buffer>;
118 readonly stderr: Rx.Subject<Buffer>;
119 readonly timer: Rx.Subject<TimerEvent>;
120 readonly messages: {
121 incoming: Rx.Subject<MessageEvent>;
122 outgoing: Rx.ReplaySubject<OutgoingMessageEvent>;
123 };
124 process?: ChildProcess;
125 private subscriptions;
126 stdin?: Writable;
127 pid?: number;
128 killed: boolean;
129 exited: boolean;
130 state: CommandState;
131 constructor({ index, name, command, prefixColor, env, cwd, ipc }: CommandInfo & {
132 index: number;
133 }, spawnOpts: SpawnOptions, spawn: SpawnCommand, killProcess: KillProcess);
134 /**
135 * Starts this command, piping output, error and close events onto the corresponding observables.
136 */
137 start(): void;
138 private maybeSetupIPC;
139 /**
140 * Sends a message to the underlying process once it starts.
141 *
142 * @throws If the command doesn't have an IPC channel enabled
143 * @returns Promise that resolves when the message is sent,
144 * or rejects if it fails to deliver the message.
145 */
146 send(message: object, handle?: SendHandle, options?: MessageOptions): Promise<void>;
147 /**
148 * Kills this command, optionally specifying a signal to send to it.
149 */
150 kill(code?: string): void;
151 private cleanUp;
152 /**
153 * Detects whether a command can be killed.
154 *
155 * Also works as a type guard on the input `command`.
156 */
157 static canKill(command: Command): command is Command & {
158 pid: number;
159 process: ChildProcess;
160 };
161}
162export {};