concurrently 9.2.1 → 10.0.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 (149) hide show
  1. package/README.md +25 -14
  2. package/dist/bin/{concurrently.js → index.js} +23 -62
  3. package/dist/bin/index.spec.d.ts +1 -0
  4. package/dist/bin/index.spec.js +368 -0
  5. package/dist/bin/normalize-cli-command.d.ts +1 -0
  6. package/dist/bin/normalize-cli-command.js +15 -0
  7. package/dist/bin/normalize-cli-command.spec.d.ts +1 -0
  8. package/dist/bin/normalize-cli-command.spec.js +36 -0
  9. package/dist/bin/read-package-json.d.ts +4 -0
  10. package/dist/bin/read-package-json.js +17 -0
  11. package/dist/lib/__fixtures__/create-mock-instance.d.ts +2 -0
  12. package/dist/lib/__fixtures__/create-mock-instance.js +5 -0
  13. package/dist/lib/__fixtures__/fake-command.d.ts +6 -0
  14. package/dist/lib/__fixtures__/fake-command.js +37 -0
  15. package/dist/lib/assert.d.ts +10 -0
  16. package/dist/lib/assert.js +24 -0
  17. package/dist/lib/assert.spec.d.ts +1 -0
  18. package/dist/lib/assert.spec.js +41 -0
  19. package/dist/{src → lib}/command-parser/expand-arguments.d.ts +2 -2
  20. package/dist/{src → lib}/command-parser/expand-arguments.js +7 -12
  21. package/dist/lib/command-parser/expand-arguments.spec.d.ts +1 -0
  22. package/dist/lib/command-parser/expand-arguments.spec.js +57 -0
  23. package/dist/{src → lib}/command-parser/expand-shortcut.d.ts +2 -2
  24. package/dist/{src → lib}/command-parser/expand-shortcut.js +1 -5
  25. package/dist/lib/command-parser/expand-shortcut.spec.d.ts +1 -0
  26. package/dist/lib/command-parser/expand-shortcut.spec.js +36 -0
  27. package/dist/{src → lib}/command-parser/expand-wildcard.d.ts +2 -2
  28. package/dist/{src → lib}/command-parser/expand-wildcard.js +21 -28
  29. package/dist/lib/command-parser/expand-wildcard.spec.d.ts +1 -0
  30. package/dist/lib/command-parser/expand-wildcard.spec.js +288 -0
  31. package/dist/{src → lib}/command.d.ts +5 -4
  32. package/dist/{src → lib}/command.js +3 -39
  33. package/dist/lib/command.spec.d.ts +1 -0
  34. package/dist/lib/command.spec.js +369 -0
  35. package/dist/{src → lib}/completion-listener.d.ts +2 -2
  36. package/dist/{src → lib}/completion-listener.js +9 -46
  37. package/dist/lib/completion-listener.spec.d.ts +1 -0
  38. package/dist/lib/completion-listener.spec.js +229 -0
  39. package/dist/{src → lib}/concurrently.d.ts +10 -10
  40. package/dist/{src → lib}/concurrently.js +29 -40
  41. package/dist/lib/concurrently.spec.d.ts +1 -0
  42. package/dist/lib/concurrently.spec.js +320 -0
  43. package/dist/{src → lib}/date-format.d.ts +2 -2
  44. package/dist/{src → lib}/date-format.js +97 -76
  45. package/dist/lib/date-format.spec.d.ts +1 -0
  46. package/dist/lib/date-format.spec.js +480 -0
  47. package/dist/{src → lib}/defaults.d.ts +2 -6
  48. package/dist/{src → lib}/defaults.js +16 -23
  49. package/dist/{src → lib}/flow-control/input-handler.d.ts +4 -4
  50. package/dist/{src → lib}/flow-control/input-handler.js +8 -44
  51. package/dist/lib/flow-control/input-handler.spec.d.ts +1 -0
  52. package/dist/lib/flow-control/input-handler.spec.js +116 -0
  53. package/dist/{src → lib}/flow-control/kill-on-signal.d.ts +3 -3
  54. package/dist/{src → lib}/flow-control/kill-on-signal.js +3 -7
  55. package/dist/lib/flow-control/kill-on-signal.spec.d.ts +1 -0
  56. package/dist/lib/flow-control/kill-on-signal.spec.js +63 -0
  57. package/dist/{src → lib}/flow-control/kill-others.d.ts +3 -3
  58. package/dist/{src → lib}/flow-control/kill-others.js +8 -12
  59. package/dist/lib/flow-control/kill-others.spec.d.ts +1 -0
  60. package/dist/lib/flow-control/kill-others.spec.js +98 -0
  61. package/dist/{src → lib}/flow-control/log-error.d.ts +3 -3
  62. package/dist/{src → lib}/flow-control/log-error.js +1 -5
  63. package/dist/lib/flow-control/log-error.spec.d.ts +1 -0
  64. package/dist/lib/flow-control/log-error.spec.js +33 -0
  65. package/dist/{src → lib}/flow-control/log-exit.d.ts +3 -3
  66. package/dist/{src → lib}/flow-control/log-exit.js +1 -5
  67. package/dist/lib/flow-control/log-exit.spec.d.ts +1 -0
  68. package/dist/lib/flow-control/log-exit.spec.js +24 -0
  69. package/dist/{src → lib}/flow-control/log-output.d.ts +3 -3
  70. package/dist/{src → lib}/flow-control/log-output.js +1 -5
  71. package/dist/lib/flow-control/log-output.spec.d.ts +1 -0
  72. package/dist/lib/flow-control/log-output.spec.js +33 -0
  73. package/dist/{src → lib}/flow-control/log-timings.d.ts +3 -3
  74. package/dist/{src → lib}/flow-control/log-timings.js +8 -45
  75. package/dist/lib/flow-control/log-timings.spec.d.ts +1 -0
  76. package/dist/lib/flow-control/log-timings.spec.js +89 -0
  77. package/dist/{src → lib}/flow-control/logger-padding.d.ts +3 -3
  78. package/dist/{src → lib}/flow-control/logger-padding.js +7 -7
  79. package/dist/lib/flow-control/logger-padding.spec.d.ts +1 -0
  80. package/dist/lib/flow-control/logger-padding.spec.js +60 -0
  81. package/dist/{src → lib}/flow-control/output-error-handler.d.ts +4 -4
  82. package/dist/{src → lib}/flow-control/output-error-handler.js +3 -7
  83. package/dist/lib/flow-control/output-error-handler.spec.d.ts +1 -0
  84. package/dist/lib/flow-control/output-error-handler.spec.js +41 -0
  85. package/dist/{src → lib}/flow-control/restart-process.d.ts +4 -4
  86. package/dist/lib/flow-control/restart-process.js +61 -0
  87. package/dist/lib/flow-control/restart-process.spec.d.ts +1 -0
  88. package/dist/lib/flow-control/restart-process.spec.js +127 -0
  89. package/dist/{src → lib}/flow-control/teardown.d.ts +4 -5
  90. package/dist/lib/flow-control/teardown.js +45 -0
  91. package/dist/lib/flow-control/teardown.spec.d.ts +1 -0
  92. package/dist/lib/flow-control/teardown.spec.js +93 -0
  93. package/dist/{src → lib}/index.d.ts +21 -19
  94. package/dist/lib/index.js +98 -0
  95. package/dist/{src → lib}/jsonc.js +3 -8
  96. package/dist/lib/jsonc.spec.d.ts +1 -0
  97. package/dist/lib/jsonc.spec.js +73 -0
  98. package/dist/{src → lib}/logger.d.ts +3 -2
  99. package/dist/{src → lib}/logger.js +109 -65
  100. package/dist/lib/logger.spec.d.ts +1 -0
  101. package/dist/lib/logger.spec.js +507 -0
  102. package/dist/{src → lib}/observables.d.ts +1 -1
  103. package/dist/{src → lib}/observables.js +3 -6
  104. package/dist/lib/observables.spec.d.ts +1 -0
  105. package/dist/lib/observables.spec.js +29 -0
  106. package/dist/{src → lib}/output-writer.d.ts +3 -3
  107. package/dist/{src → lib}/output-writer.js +4 -41
  108. package/dist/lib/output-writer.spec.d.ts +1 -0
  109. package/dist/lib/output-writer.spec.js +96 -0
  110. package/dist/lib/prefix-color-selector.d.ts +21 -0
  111. package/dist/{src → lib}/prefix-color-selector.js +14 -31
  112. package/dist/lib/prefix-color-selector.spec.d.ts +1 -0
  113. package/dist/lib/prefix-color-selector.spec.js +159 -0
  114. package/dist/{src → lib}/spawn.d.ts +14 -5
  115. package/dist/lib/spawn.js +105 -0
  116. package/dist/lib/spawn.spec.d.ts +1 -0
  117. package/dist/lib/spawn.spec.js +100 -0
  118. package/dist/lib/utils.d.ts +25 -0
  119. package/dist/lib/utils.js +52 -0
  120. package/dist/lib/utils.spec.d.ts +1 -0
  121. package/dist/lib/utils.spec.js +58 -0
  122. package/dist/tsconfig.tsbuildinfo +1 -1
  123. package/docs/README.md +6 -0
  124. package/docs/cli/prefixing.md +44 -4
  125. package/docs/shell-resolution.md +48 -0
  126. package/package.json +59 -75
  127. package/dist/bin/read-package.d.ts +0 -6
  128. package/dist/bin/read-package.js +0 -56
  129. package/dist/src/assert.d.ts +0 -5
  130. package/dist/src/assert.js +0 -15
  131. package/dist/src/command-parser/command-parser.d.ts +0 -19
  132. package/dist/src/command-parser/command-parser.js +0 -2
  133. package/dist/src/command-parser/strip-quotes.d.ts +0 -16
  134. package/dist/src/command-parser/strip-quotes.js +0 -17
  135. package/dist/src/flow-control/flow-controller.d.ts +0 -13
  136. package/dist/src/flow-control/flow-controller.js +0 -2
  137. package/dist/src/flow-control/restart-process.js +0 -98
  138. package/dist/src/flow-control/teardown.js +0 -82
  139. package/dist/src/index.js +0 -96
  140. package/dist/src/prefix-color-selector.d.ts +0 -11
  141. package/dist/src/spawn.js +0 -49
  142. package/dist/src/utils.d.ts +0 -10
  143. package/dist/src/utils.js +0 -16
  144. package/index.d.mts +0 -7
  145. package/index.d.ts +0 -11
  146. package/index.js +0 -14
  147. package/index.mjs +0 -9
  148. /package/dist/bin/{concurrently.d.ts → index.d.ts} +0 -0
  149. /package/dist/{src → lib}/jsonc.d.ts +0 -0
@@ -0,0 +1,369 @@
1
+ import { Buffer } from 'node:buffer';
2
+ import { EventEmitter } from 'node:events';
3
+ import { Readable, Writable } from 'node:stream';
4
+ import { subscribeSpyTo } from '@hirez_io/observer-spy';
5
+ import Rx from 'rxjs';
6
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
7
+ import { Command, } from './command.js';
8
+ let process;
9
+ let sendMessage;
10
+ let spawn;
11
+ let killProcess;
12
+ const IPC_FD = 3;
13
+ beforeEach(() => {
14
+ sendMessage = vi.fn();
15
+ process = new (class extends EventEmitter {
16
+ pid = 1;
17
+ send = sendMessage;
18
+ stdout = new Readable({
19
+ read() {
20
+ // do nothing
21
+ },
22
+ });
23
+ stderr = new Readable({
24
+ read() {
25
+ // do nothing
26
+ },
27
+ });
28
+ stdin = new Writable({
29
+ write() {
30
+ // do nothing
31
+ },
32
+ });
33
+ })();
34
+ spawn = vi.fn().mockReturnValue(process);
35
+ killProcess = vi.fn();
36
+ });
37
+ const createCommand = (overrides, spawnOpts = {}) => {
38
+ const command = new Command({ index: 0, name: '', command: 'echo foo', ...overrides }, spawnOpts, spawn, killProcess);
39
+ let error;
40
+ let close;
41
+ const timer = subscribeSpyTo(command.timer);
42
+ const finished = subscribeSpyTo(new Rx.Observable((observer) => {
43
+ // First event in both subjects means command has finished
44
+ command.error.subscribe({
45
+ next: (value) => {
46
+ error = value;
47
+ observer.complete();
48
+ },
49
+ });
50
+ command.close.subscribe({
51
+ next: (value) => {
52
+ close = value;
53
+ observer.complete();
54
+ },
55
+ });
56
+ }));
57
+ const values = async () => {
58
+ await finished.onComplete();
59
+ return { error, close, timer: timer.getValues() };
60
+ };
61
+ return { command, values };
62
+ };
63
+ it('has stopped state by default', () => {
64
+ const { command } = createCommand();
65
+ expect(command.state).toBe('stopped');
66
+ });
67
+ describe('#start()', () => {
68
+ it('spawns process with given command and options', () => {
69
+ const { command } = createCommand({}, { detached: true });
70
+ command.start();
71
+ expect(spawn).toHaveBeenCalledExactlyOnceWith(command.command, { detached: true });
72
+ });
73
+ it('sets stdin, process and PID', () => {
74
+ const { command } = createCommand();
75
+ command.start();
76
+ expect(command.process).toBe(process);
77
+ expect(command.pid).toBe(process.pid);
78
+ expect(command.stdin).toBe(process.stdin);
79
+ });
80
+ it('handles process with no stdin', () => {
81
+ process.stdin = null;
82
+ const { command } = createCommand();
83
+ command.start();
84
+ expect(command.stdin).toBe(undefined);
85
+ });
86
+ it('changes state to started', () => {
87
+ const { command } = createCommand();
88
+ const spy = subscribeSpyTo(command.stateChange);
89
+ command.start();
90
+ expect(command.state).toBe('started');
91
+ expect(spy.getFirstValue()).toBe('started');
92
+ });
93
+ describe('on errors', () => {
94
+ it('changes state to errored', () => {
95
+ const { command } = createCommand();
96
+ command.start();
97
+ const spy = subscribeSpyTo(command.stateChange);
98
+ process.emit('error', 'foo');
99
+ expect(command.state).toBe('errored');
100
+ expect(spy.getFirstValue()).toBe('errored');
101
+ });
102
+ it('shares to the error stream', async () => {
103
+ const { command, values } = createCommand();
104
+ command.start();
105
+ process.emit('error', 'foo');
106
+ const { error } = await values();
107
+ expect(error).toBe('foo');
108
+ expect(command.process).toBeUndefined();
109
+ });
110
+ it('shares start and error timing events to the timing stream', async () => {
111
+ const { command, values } = createCommand();
112
+ const startDate = new Date();
113
+ const endDate = new Date(startDate.getTime() + 1000);
114
+ vi.spyOn(Date, 'now')
115
+ .mockReturnValueOnce(startDate.getTime())
116
+ .mockReturnValueOnce(endDate.getTime());
117
+ command.start();
118
+ process.emit('error', 0, null);
119
+ const { timer } = await values();
120
+ expect(timer[0]).toEqual({ startDate, endDate: undefined });
121
+ expect(timer[1]).toEqual({ startDate, endDate });
122
+ });
123
+ });
124
+ describe('on close', () => {
125
+ it('changes state to exited', () => {
126
+ const { command } = createCommand();
127
+ command.start();
128
+ const spy = subscribeSpyTo(command.stateChange);
129
+ process.emit('close', 0, null);
130
+ expect(command.state).toBe('exited');
131
+ expect(spy.getFirstValue()).toBe('exited');
132
+ });
133
+ it('does not change state if there was an error', () => {
134
+ const { command } = createCommand();
135
+ command.start();
136
+ process.emit('error', 'foo');
137
+ const spy = subscribeSpyTo(command.stateChange);
138
+ process.emit('close', 0, null);
139
+ expect(command.state).toBe('errored');
140
+ expect(spy.getValuesLength()).toBe(0);
141
+ });
142
+ it('shares start and close timing events to the timing stream', async () => {
143
+ const { command, values } = createCommand();
144
+ const startDate = new Date();
145
+ const endDate = new Date(startDate.getTime() + 1000);
146
+ vi.spyOn(Date, 'now')
147
+ .mockReturnValueOnce(startDate.getTime())
148
+ .mockReturnValueOnce(endDate.getTime());
149
+ command.start();
150
+ process.emit('close', 0, null);
151
+ const { timer } = await values();
152
+ expect(timer[0]).toEqual({ startDate, endDate: undefined });
153
+ expect(timer[1]).toEqual({ startDate, endDate });
154
+ });
155
+ it('shares to the close stream with exit code', async () => {
156
+ const { command, values } = createCommand();
157
+ command.start();
158
+ process.emit('close', 0, null);
159
+ const { close } = await values();
160
+ expect(close).toMatchObject({ exitCode: 0, killed: false });
161
+ expect(command.process).toBeUndefined();
162
+ });
163
+ it('shares to the close stream with signal', async () => {
164
+ const { command, values } = createCommand();
165
+ command.start();
166
+ process.emit('close', null, 'SIGKILL');
167
+ const { close } = await values();
168
+ expect(close).toMatchObject({ exitCode: 'SIGKILL', killed: false });
169
+ });
170
+ it('shares to the close stream with timing information', async () => {
171
+ const { command, values } = createCommand();
172
+ const startDate = new Date();
173
+ const endDate = new Date(startDate.getTime() + 1000);
174
+ vi.spyOn(Date, 'now')
175
+ .mockReturnValueOnce(startDate.getTime())
176
+ .mockReturnValueOnce(endDate.getTime());
177
+ vi.spyOn(globalThis.process, 'hrtime')
178
+ .mockReturnValueOnce([0, 0])
179
+ .mockReturnValueOnce([1, 1e8]);
180
+ command.start();
181
+ process.emit('close', null, 'SIGKILL');
182
+ const { close } = await values();
183
+ expect(close.timings).toStrictEqual({
184
+ startDate,
185
+ endDate,
186
+ durationSeconds: 1.1,
187
+ });
188
+ });
189
+ it('shares to the close stream with command info', async () => {
190
+ const commandInfo = {
191
+ command: 'cmd',
192
+ name: 'name',
193
+ prefixColor: 'green',
194
+ env: { VAR: 'yes' },
195
+ };
196
+ const { command, values } = createCommand(commandInfo);
197
+ command.start();
198
+ process.emit('close', 0, null);
199
+ const { close } = await values();
200
+ expect(close.command).toEqual(expect.objectContaining(commandInfo));
201
+ expect(close.killed).toBe(false);
202
+ });
203
+ });
204
+ it('shares stdout to the stdout stream', async () => {
205
+ const { command } = createCommand();
206
+ const stdout = Rx.firstValueFrom(command.stdout);
207
+ command.start();
208
+ process.stdout?.emit('data', Buffer.from('hello'));
209
+ expect((await stdout).toString()).toBe('hello');
210
+ });
211
+ it('shares stderr to the stdout stream', async () => {
212
+ const { command } = createCommand();
213
+ const stderr = Rx.firstValueFrom(command.stderr);
214
+ command.start();
215
+ process.stderr?.emit('data', Buffer.from('dang'));
216
+ expect((await stderr).toString()).toBe('dang');
217
+ });
218
+ describe('on incoming messages', () => {
219
+ it('does not share to the incoming messages stream, if IPC is disabled', () => {
220
+ const { command } = createCommand();
221
+ const spy = subscribeSpyTo(command.messages.incoming);
222
+ command.start();
223
+ process.emit('message', {});
224
+ expect(spy.getValuesLength()).toBe(0);
225
+ });
226
+ it('shares to the incoming messages stream, if IPC is enabled', () => {
227
+ const { command } = createCommand({ ipc: IPC_FD });
228
+ const spy = subscribeSpyTo(command.messages.incoming);
229
+ command.start();
230
+ const message1 = {};
231
+ process.emit('message', message1, undefined);
232
+ const message2 = {};
233
+ const handle = {};
234
+ process.emit('message', message2, handle);
235
+ expect(spy.getValuesLength()).toBe(2);
236
+ expect(spy.getValueAt(0)).toEqual({ message: message1, handle: undefined });
237
+ expect(spy.getValueAt(1)).toEqual({ message: message2, handle });
238
+ });
239
+ });
240
+ describe('on outgoing messages', () => {
241
+ it('calls onSent with an error if the process does not have IPC enabled', () => {
242
+ const { command } = createCommand({ ipc: IPC_FD });
243
+ command.start();
244
+ Object.assign(process, {
245
+ // The TS types don't assume `send` can be undefined,
246
+ // despite the Node docs saying so
247
+ send: undefined,
248
+ });
249
+ const onSent = vi.fn();
250
+ command.messages.outgoing.next({ message: {}, onSent });
251
+ expect(onSent).toHaveBeenCalledWith(expect.any(Error));
252
+ });
253
+ it('sends the message to the process', () => {
254
+ const { command } = createCommand({ ipc: IPC_FD });
255
+ command.start();
256
+ const message1 = {};
257
+ command.messages.outgoing.next({ message: message1, onSent() { } });
258
+ const message2 = {};
259
+ const handle = {};
260
+ command.messages.outgoing.next({ message: message2, handle, onSent() { } });
261
+ const message3 = {};
262
+ const options = {};
263
+ command.messages.outgoing.next({ message: message3, options, onSent() { } });
264
+ expect(process.send).toHaveBeenCalledTimes(3);
265
+ expect(process.send).toHaveBeenNthCalledWith(1, message1, undefined, undefined, expect.any(Function));
266
+ expect(process.send).toHaveBeenNthCalledWith(2, message2, handle, undefined, expect.any(Function));
267
+ expect(process.send).toHaveBeenNthCalledWith(3, message3, undefined, options, expect.any(Function));
268
+ });
269
+ it('sends the message to the process, if it starts late', () => {
270
+ const { command } = createCommand({ ipc: IPC_FD });
271
+ command.messages.outgoing.next({ message: {}, onSent() { } });
272
+ expect(process.send).not.toHaveBeenCalled();
273
+ command.start();
274
+ expect(process.send).toHaveBeenCalled();
275
+ });
276
+ it('calls onSent with the result of sending the message', () => {
277
+ const { command } = createCommand({ ipc: IPC_FD });
278
+ command.start();
279
+ const onSent = vi.fn();
280
+ command.messages.outgoing.next({ message: {}, onSent });
281
+ expect(onSent).not.toHaveBeenCalled();
282
+ sendMessage.mock.calls[0][3]();
283
+ expect(onSent).toHaveBeenCalledWith(undefined);
284
+ const error = new Error('test');
285
+ sendMessage.mock.calls[0][3](error);
286
+ expect(onSent).toHaveBeenCalledWith(error);
287
+ });
288
+ });
289
+ });
290
+ describe('#send()', () => {
291
+ it('throws if IPC is not set up', () => {
292
+ const { command } = createCommand();
293
+ const fn = () => command.send({});
294
+ expect(fn).toThrow();
295
+ });
296
+ it('pushes the message on the outgoing messages stream', () => {
297
+ const { command } = createCommand({ ipc: IPC_FD });
298
+ const spy = subscribeSpyTo(command.messages.outgoing);
299
+ const message1 = { foo: true };
300
+ command.send(message1);
301
+ const message2 = { bar: 123 };
302
+ const handle = {};
303
+ command.send(message2, handle);
304
+ const message3 = { baz: 'yes' };
305
+ const options = {};
306
+ command.send(message3, undefined, options);
307
+ expect(spy.getValuesLength()).toBe(3);
308
+ expect(spy.getValueAt(0)).toMatchObject({
309
+ message: message1,
310
+ handle: undefined,
311
+ options: undefined,
312
+ });
313
+ expect(spy.getValueAt(1)).toMatchObject({ message: message2, handle, options: undefined });
314
+ expect(spy.getValueAt(2)).toMatchObject({ message: message3, handle: undefined, options });
315
+ });
316
+ it('resolves when onSent callback is called with no arguments', async () => {
317
+ const { command } = createCommand({ ipc: IPC_FD });
318
+ const spy = subscribeSpyTo(command.messages.outgoing);
319
+ const promise = command.send({});
320
+ spy.getFirstValue().onSent();
321
+ await expect(promise).resolves.toBeUndefined();
322
+ });
323
+ it('rejects when onSent callback is called with an argument', async () => {
324
+ const { command } = createCommand({ ipc: IPC_FD });
325
+ const spy = subscribeSpyTo(command.messages.outgoing);
326
+ const promise = command.send({});
327
+ spy.getFirstValue().onSent('foo');
328
+ await expect(promise).rejects.toBe('foo');
329
+ });
330
+ });
331
+ describe('#kill()', () => {
332
+ let createdCommand;
333
+ beforeEach(() => {
334
+ createdCommand = createCommand();
335
+ });
336
+ it('kills process', () => {
337
+ createdCommand.command.start();
338
+ createdCommand.command.kill();
339
+ expect(killProcess).toHaveBeenCalledExactlyOnceWith(createdCommand.command.pid, undefined);
340
+ });
341
+ it('kills process with some signal', () => {
342
+ createdCommand.command.start();
343
+ createdCommand.command.kill('SIGKILL');
344
+ expect(killProcess).toHaveBeenCalledExactlyOnceWith(createdCommand.command.pid, 'SIGKILL');
345
+ });
346
+ it('does not try to kill inexistent process', () => {
347
+ createdCommand.command.start();
348
+ process.emit('error');
349
+ createdCommand.command.kill();
350
+ expect(killProcess).not.toHaveBeenCalled();
351
+ });
352
+ it('marks the command as killed', async () => {
353
+ createdCommand.command.start();
354
+ createdCommand.command.kill();
355
+ process.emit('close', 1, null);
356
+ const { close } = await createdCommand.values();
357
+ expect(close).toMatchObject({ exitCode: 1, killed: true });
358
+ });
359
+ });
360
+ describe('.canKill()', () => {
361
+ it('returns whether command has both PID and process', () => {
362
+ const { command } = createCommand();
363
+ expect(Command.canKill(command)).toBe(false);
364
+ command.pid = 1;
365
+ expect(Command.canKill(command)).toBe(false);
366
+ command.process = process;
367
+ expect(Command.canKill(command)).toBe(true);
368
+ });
369
+ });
@@ -1,5 +1,5 @@
1
- import * as Rx from 'rxjs';
2
- import { CloseEvent, Command } from './command';
1
+ import Rx from 'rxjs';
2
+ import { CloseEvent, Command } from './command.js';
3
3
  /**
4
4
  * Defines which command(s) in a list must exit successfully (with an exit code of `0`):
5
5
  *
@@ -1,45 +1,9 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.CompletionListener = void 0;
37
- const Rx = __importStar(require("rxjs"));
38
- const operators_1 = require("rxjs/operators");
1
+ import Rx from 'rxjs';
2
+ import { delay, filter, map, share, switchMap, take } from 'rxjs/operators';
39
3
  /**
40
4
  * Provides logic to determine whether lists of commands ran successfully.
41
5
  */
42
- class CompletionListener {
6
+ export class CompletionListener {
43
7
  successCondition;
44
8
  scheduler;
45
9
  constructor({ successCondition = 'all', scheduler, }) {
@@ -91,24 +55,23 @@ class CompletionListener {
91
55
  // The abort signal must happen before commands are killed, otherwise new commands
92
56
  // might spawn. Because of this, it's not be possible to capture the close events
93
57
  // without an immediate delay
94
- (0, operators_1.delay)(0, this.scheduler), (0, operators_1.map)(() => undefined),
58
+ delay(0, this.scheduler), map(() => undefined),
95
59
  // #502 - node might warn of too many active listeners on this object if it isn't shared,
96
60
  // as each command subscribes to abort event over and over
97
- (0, operators_1.share)());
61
+ share());
98
62
  const closeStreams = commands.map((command) => abort
99
63
  ? // Commands that have been started must close.
100
- Rx.race(command.close, abort.pipe((0, operators_1.filter)(() => command.state === 'stopped')))
64
+ Rx.race(command.close, abort.pipe(filter(() => command.state === 'stopped')))
101
65
  : command.close);
102
- return Rx.lastValueFrom(Rx.combineLatest(closeStreams).pipe((0, operators_1.filter)(() => commands.every((command) => command.state !== 'started')), (0, operators_1.map)((events) => events
66
+ return Rx.lastValueFrom(Rx.combineLatest(closeStreams).pipe(filter(() => commands.every((command) => command.state !== 'started')), map((events) => events
103
67
  // Filter out aborts, since they cannot be sorted and are considered success condition anyways
104
68
  .filter((event) => event != null)
105
69
  // Sort according to exit time
106
- .sort((first, second) => first.timings.endDate.getTime() - second.timings.endDate.getTime())), (0, operators_1.switchMap)((events) => this.isSuccess(events)
70
+ .sort((first, second) => first.timings.endDate.getTime() - second.timings.endDate.getTime())), switchMap((events) => this.isSuccess(events)
107
71
  ? this.emitWithScheduler(Rx.of(events))
108
- : this.emitWithScheduler(Rx.throwError(() => events))), (0, operators_1.take)(1)));
72
+ : this.emitWithScheduler(Rx.throwError(() => events))), take(1)));
109
73
  }
110
74
  emitWithScheduler(input) {
111
75
  return this.scheduler ? input.pipe(Rx.observeOn(this.scheduler)) : input;
112
76
  }
113
77
  }
114
- exports.CompletionListener = CompletionListener;
@@ -0,0 +1 @@
1
+ export {};