concurrently 8.2.2 → 9.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 (62) hide show
  1. package/README.md +34 -239
  2. package/dist/bin/concurrently.js +37 -22
  3. package/dist/bin/read-package.d.ts +6 -0
  4. package/dist/bin/read-package.js +47 -0
  5. package/dist/src/command-parser/expand-arguments.d.ts +1 -0
  6. package/dist/src/command-parser/expand-arguments.js +1 -0
  7. package/dist/src/command-parser/expand-npm-shortcut.d.ts +1 -1
  8. package/dist/src/command-parser/expand-npm-shortcut.js +4 -3
  9. package/dist/src/command-parser/expand-npm-wildcard.js +4 -2
  10. package/dist/src/command-parser/strip-quotes.d.ts +1 -0
  11. package/dist/src/command.d.ts +46 -5
  12. package/dist/src/command.js +91 -16
  13. package/dist/src/completion-listener.d.ts +4 -1
  14. package/dist/src/completion-listener.js +27 -6
  15. package/dist/src/concurrently.d.ts +16 -4
  16. package/dist/src/concurrently.js +15 -14
  17. package/dist/src/date-format.d.ts +19 -0
  18. package/dist/src/date-format.js +318 -0
  19. package/dist/src/defaults.d.ts +1 -1
  20. package/dist/src/defaults.js +1 -1
  21. package/dist/src/flow-control/flow-controller.d.ts +1 -1
  22. package/dist/src/flow-control/input-handler.js +4 -0
  23. package/dist/src/flow-control/kill-on-signal.d.ts +4 -1
  24. package/dist/src/flow-control/kill-on-signal.js +8 -1
  25. package/dist/src/flow-control/kill-others.d.ts +4 -1
  26. package/dist/src/flow-control/kill-others.js +7 -1
  27. package/dist/src/flow-control/log-error.js +1 -0
  28. package/dist/src/flow-control/log-exit.js +1 -0
  29. package/dist/src/flow-control/log-output.js +1 -0
  30. package/dist/src/flow-control/log-timings.d.ts +1 -1
  31. package/dist/src/flow-control/log-timings.js +6 -4
  32. package/dist/src/flow-control/logger-padding.d.ts +13 -0
  33. package/dist/src/flow-control/logger-padding.js +35 -0
  34. package/dist/src/flow-control/restart-process.d.ts +3 -2
  35. package/dist/src/flow-control/restart-process.js +14 -2
  36. package/dist/src/flow-control/teardown.d.ts +21 -0
  37. package/dist/src/flow-control/teardown.js +72 -0
  38. package/dist/src/index.d.ts +18 -8
  39. package/dist/src/index.js +28 -7
  40. package/dist/src/logger.d.ts +25 -10
  41. package/dist/src/logger.js +78 -39
  42. package/dist/src/output-writer.js +6 -2
  43. package/dist/src/prefix-color-selector.js +1 -0
  44. package/dist/src/{get-spawn-opts.d.ts → spawn.d.ts} +20 -5
  45. package/dist/src/spawn.js +49 -0
  46. package/docs/README.md +13 -0
  47. package/docs/cli/configuration.md +11 -0
  48. package/docs/cli/input-handling.md +40 -0
  49. package/docs/cli/output-control.md +35 -0
  50. package/docs/cli/passthrough-arguments.md +80 -0
  51. package/docs/cli/prefixing.md +147 -0
  52. package/docs/cli/restarting.md +38 -0
  53. package/docs/cli/shortcuts.md +72 -0
  54. package/docs/demo.gif +0 -0
  55. package/index.d.mts +7 -0
  56. package/index.d.ts +11 -0
  57. package/index.js +6 -1
  58. package/index.mjs +2 -2
  59. package/package.json +37 -29
  60. package/dist/bin/epilogue.d.ts +0 -1
  61. package/dist/bin/epilogue.js +0 -90
  62. package/dist/src/get-spawn-opts.js +0 -18
@@ -2,7 +2,7 @@
2
2
  /// <reference types="node" />
3
3
  /// <reference types="node" />
4
4
  /// <reference types="node" />
5
- import { ChildProcess as BaseChildProcess, SpawnOptions } from 'child_process';
5
+ import { ChildProcess as BaseChildProcess, MessageOptions, SendHandle, SpawnOptions } from 'child_process';
6
6
  import * as Rx from 'rxjs';
7
7
  import { EventEmitter, Writable } from 'stream';
8
8
  /**
@@ -30,6 +30,13 @@ export interface CommandInfo {
30
30
  * Color to use on prefix of the command.
31
31
  */
32
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;
33
40
  /**
34
41
  * Output command in raw format.
35
42
  */
@@ -59,10 +66,18 @@ export interface TimerEvent {
59
66
  startDate: Date;
60
67
  endDate?: Date;
61
68
  }
69
+ export interface MessageEvent {
70
+ message: object;
71
+ handle?: SendHandle;
72
+ }
73
+ interface OutgoingMessageEvent extends MessageEvent {
74
+ options?: MessageOptions;
75
+ onSent(error?: unknown): void;
76
+ }
62
77
  /**
63
78
  * Subtype of NodeJS's child_process including only what's actually needed for a command to work.
64
79
  */
65
- export type ChildProcess = EventEmitter & Pick<BaseChildProcess, 'pid' | 'stdin' | 'stdout' | 'stderr'>;
80
+ export type ChildProcess = EventEmitter & Pick<BaseChildProcess, 'pid' | 'stdin' | 'stdout' | 'stderr' | 'send'>;
66
81
  /**
67
82
  * Interface for a function that must kill the process with `pid`, optionally sending `signal` to it.
68
83
  */
@@ -71,6 +86,15 @@ export type KillProcess = (pid: number, signal?: string) => void;
71
86
  * Interface for a function that spawns a command and returns its child process instance.
72
87
  */
73
88
  export 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
+ */
97
+ type CommandState = 'stopped' | 'started' | 'errored' | 'exited';
74
98
  export declare class Command implements CommandInfo {
75
99
  private readonly killProcess;
76
100
  private readonly spawn;
@@ -86,29 +110,45 @@ export declare class Command implements CommandInfo {
86
110
  readonly env: Record<string, unknown>;
87
111
  /** @inheritdoc */
88
112
  readonly cwd?: string;
113
+ /** @inheritdoc */
114
+ readonly ipc?: number;
89
115
  readonly close: Rx.Subject<CloseEvent>;
90
116
  readonly error: Rx.Subject<unknown>;
91
117
  readonly stdout: Rx.Subject<Buffer>;
92
118
  readonly stderr: Rx.Subject<Buffer>;
93
119
  readonly timer: Rx.Subject<TimerEvent>;
120
+ readonly messages: {
121
+ incoming: Rx.Subject<MessageEvent>;
122
+ outgoing: Rx.ReplaySubject<OutgoingMessageEvent>;
123
+ };
94
124
  process?: ChildProcess;
125
+ private subscriptions;
95
126
  stdin?: Writable;
96
127
  pid?: number;
97
128
  killed: boolean;
98
129
  exited: boolean;
99
- /** @deprecated */
100
- get killable(): boolean;
101
- constructor({ index, name, command, prefixColor, env, cwd }: CommandInfo & {
130
+ state: CommandState;
131
+ constructor({ index, name, command, prefixColor, env, cwd, ipc }: CommandInfo & {
102
132
  index: number;
103
133
  }, spawnOpts: SpawnOptions, spawn: SpawnCommand, killProcess: KillProcess);
104
134
  /**
105
135
  * Starts this command, piping output, error and close events onto the corresponding observables.
106
136
  */
107
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>;
108
147
  /**
109
148
  * Kills this command, optionally specifying a signal to send to it.
110
149
  */
111
150
  kill(code?: string): void;
151
+ private cleanUp;
112
152
  /**
113
153
  * Detects whether a command can be killed.
114
154
  *
@@ -119,3 +159,4 @@ export declare class Command implements CommandInfo {
119
159
  process: ChildProcess;
120
160
  };
121
161
  }
162
+ export {};
@@ -26,24 +26,47 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.Command = void 0;
27
27
  const Rx = __importStar(require("rxjs"));
28
28
  class Command {
29
- /** @deprecated */
30
- get killable() {
31
- return Command.canKill(this);
32
- }
33
- constructor({ index, name, command, prefixColor, env, cwd }, spawnOpts, spawn, killProcess) {
34
- this.close = new Rx.Subject();
35
- this.error = new Rx.Subject();
36
- this.stdout = new Rx.Subject();
37
- this.stderr = new Rx.Subject();
38
- this.timer = new Rx.Subject();
39
- this.killed = false;
40
- this.exited = false;
29
+ killProcess;
30
+ spawn;
31
+ spawnOpts;
32
+ index;
33
+ /** @inheritdoc */
34
+ name;
35
+ /** @inheritdoc */
36
+ command;
37
+ /** @inheritdoc */
38
+ prefixColor;
39
+ /** @inheritdoc */
40
+ env;
41
+ /** @inheritdoc */
42
+ cwd;
43
+ /** @inheritdoc */
44
+ ipc;
45
+ close = new Rx.Subject();
46
+ error = new Rx.Subject();
47
+ stdout = new Rx.Subject();
48
+ stderr = new Rx.Subject();
49
+ timer = new Rx.Subject();
50
+ messages = {
51
+ incoming: new Rx.Subject(),
52
+ outgoing: new Rx.ReplaySubject(),
53
+ };
54
+ process;
55
+ // TODO: Should exit/error/stdio subscriptions be added here?
56
+ subscriptions = [];
57
+ stdin;
58
+ pid;
59
+ killed = false;
60
+ exited = false;
61
+ state = 'stopped';
62
+ constructor({ index, name, command, prefixColor, env, cwd, ipc }, spawnOpts, spawn, killProcess) {
41
63
  this.index = index;
42
64
  this.name = name;
43
65
  this.command = command;
44
66
  this.prefixColor = prefixColor;
45
67
  this.env = env || {};
46
68
  this.cwd = cwd;
69
+ this.ipc = ipc;
47
70
  this.killProcess = killProcess;
48
71
  this.spawn = spawn;
49
72
  this.spawnOpts = spawnOpts;
@@ -53,22 +76,28 @@ class Command {
53
76
  */
54
77
  start() {
55
78
  const child = this.spawn(this.command, this.spawnOpts);
79
+ this.state = 'started';
56
80
  this.process = child;
57
81
  this.pid = child.pid;
58
82
  const startDate = new Date(Date.now());
59
83
  const highResStartTime = process.hrtime();
60
84
  this.timer.next({ startDate });
85
+ this.subscriptions = [...this.maybeSetupIPC(child)];
61
86
  Rx.fromEvent(child, 'error').subscribe((event) => {
62
- this.process = undefined;
87
+ this.cleanUp();
63
88
  const endDate = new Date(Date.now());
64
89
  this.timer.next({ startDate, endDate });
65
90
  this.error.next(event);
91
+ this.state = 'errored';
66
92
  });
67
93
  Rx.fromEvent(child, 'close')
68
94
  .pipe(Rx.map((event) => event))
69
95
  .subscribe(([exitCode, signal]) => {
70
- this.process = undefined;
71
- this.exited = true;
96
+ this.cleanUp();
97
+ // Don't override error event
98
+ if (this.state !== 'errored') {
99
+ this.state = 'exited';
100
+ }
72
101
  const endDate = new Date(Date.now());
73
102
  this.timer.next({ startDate, endDate });
74
103
  const [durationSeconds, durationNanoSeconds] = process.hrtime(highResStartTime);
@@ -90,6 +119,47 @@ class Command {
90
119
  pipeTo(Rx.fromEvent(child.stderr, 'data').pipe(Rx.map((event) => event)), this.stderr);
91
120
  this.stdin = child.stdin || undefined;
92
121
  }
122
+ maybeSetupIPC(child) {
123
+ if (!this.ipc) {
124
+ return [];
125
+ }
126
+ return [
127
+ pipeTo(Rx.fromEvent(child, 'message').pipe(Rx.map((event) => {
128
+ const [message, handle] = event;
129
+ return { message, handle };
130
+ })), this.messages.incoming),
131
+ this.messages.outgoing.subscribe((message) => {
132
+ if (!child.send) {
133
+ return message.onSent(new Error('Command does not have an IPC channel'));
134
+ }
135
+ child.send(message.message, message.handle, message.options, (error) => {
136
+ message.onSent(error);
137
+ });
138
+ }),
139
+ ];
140
+ }
141
+ /**
142
+ * Sends a message to the underlying process once it starts.
143
+ *
144
+ * @throws If the command doesn't have an IPC channel enabled
145
+ * @returns Promise that resolves when the message is sent,
146
+ * or rejects if it fails to deliver the message.
147
+ */
148
+ send(message, handle, options) {
149
+ if (this.ipc == null) {
150
+ throw new Error('Command IPC is disabled');
151
+ }
152
+ return new Promise((resolve, reject) => {
153
+ this.messages.outgoing.next({
154
+ message,
155
+ handle,
156
+ options,
157
+ onSent(error) {
158
+ error ? reject(error) : resolve();
159
+ },
160
+ });
161
+ });
162
+ }
93
163
  /**
94
164
  * Kills this command, optionally specifying a signal to send to it.
95
165
  */
@@ -99,6 +169,11 @@ class Command {
99
169
  this.killProcess(this.pid, code);
100
170
  }
101
171
  }
172
+ cleanUp() {
173
+ this.subscriptions?.forEach((sub) => sub.unsubscribe());
174
+ this.messages.outgoing = new Rx.ReplaySubject();
175
+ this.process = undefined;
176
+ }
102
177
  /**
103
178
  * Detects whether a command can be killed.
104
179
  *
@@ -113,5 +188,5 @@ exports.Command = Command;
113
188
  * Pipes all events emitted by `stream` into `subject`.
114
189
  */
115
190
  function pipeTo(stream, subject) {
116
- stream.subscribe((event) => subject.next(event));
191
+ return stream.subscribe((event) => subject.next(event));
117
192
  }
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import * as Rx from 'rxjs';
2
3
  import { CloseEvent, Command } from './command';
3
4
  /**
@@ -34,7 +35,9 @@ export declare class CompletionListener {
34
35
  * Given a list of commands, wait for all of them to exit and then evaluate their exit codes.
35
36
  *
36
37
  * @returns A Promise that resolves if the success condition is met, or rejects otherwise.
38
+ * In either case, the value is a list of close events for commands that spawned.
39
+ * Commands that didn't spawn are filtered out.
37
40
  */
38
- listen(commands: Command[]): Promise<CloseEvent[]>;
41
+ listen(commands: Command[], abortSignal?: AbortSignal): Promise<CloseEvent[]>;
39
42
  private emitWithScheduler;
40
43
  }
@@ -30,11 +30,17 @@ const operators_1 = require("rxjs/operators");
30
30
  * Provides logic to determine whether lists of commands ran successfully.
31
31
  */
32
32
  class CompletionListener {
33
+ successCondition;
34
+ scheduler;
33
35
  constructor({ successCondition = 'all', scheduler, }) {
34
36
  this.successCondition = successCondition;
35
37
  this.scheduler = scheduler;
36
38
  }
37
39
  isSuccess(events) {
40
+ if (!events.length) {
41
+ // When every command was aborted, consider a success.
42
+ return true;
43
+ }
38
44
  if (this.successCondition === 'first') {
39
45
  return events[0].exitCode === 0;
40
46
  }
@@ -52,7 +58,7 @@ class CompletionListener {
52
58
  const nameOrIndex = commandSyntaxMatch[1];
53
59
  const targetCommandsEvents = events.filter(({ command, index }) => command.name === nameOrIndex || index === Number(nameOrIndex));
54
60
  if (this.successCondition.startsWith('!')) {
55
- // All commands except the specified ones must exit succesfully
61
+ // All commands except the specified ones must exit successfully
56
62
  return events.every((event) => targetCommandsEvents.includes(event) || event.exitCode === 0);
57
63
  }
58
64
  // Only the specified commands must exit succesfully
@@ -63,12 +69,27 @@ class CompletionListener {
63
69
  * Given a list of commands, wait for all of them to exit and then evaluate their exit codes.
64
70
  *
65
71
  * @returns A Promise that resolves if the success condition is met, or rejects otherwise.
72
+ * In either case, the value is a list of close events for commands that spawned.
73
+ * Commands that didn't spawn are filtered out.
66
74
  */
67
- listen(commands) {
68
- const closeStreams = commands.map((command) => command.close);
69
- return Rx.lastValueFrom(Rx.merge(...closeStreams).pipe((0, operators_1.bufferCount)(closeStreams.length), (0, operators_1.switchMap)((exitInfos) => this.isSuccess(exitInfos)
70
- ? this.emitWithScheduler(Rx.of(exitInfos))
71
- : this.emitWithScheduler(Rx.throwError(() => exitInfos))), (0, operators_1.take)(1)));
75
+ listen(commands, abortSignal) {
76
+ const abort = abortSignal &&
77
+ Rx.fromEvent(abortSignal, 'abort', { once: true }).pipe(
78
+ // The abort signal must happen before commands are killed, otherwise new commands
79
+ // might spawn. Because of this, it's not be possible to capture the close events
80
+ // without an immediate delay
81
+ (0, operators_1.delay)(0, this.scheduler), (0, operators_1.map)(() => undefined));
82
+ const closeStreams = commands.map((command) => abort
83
+ ? // Commands that have been started must close.
84
+ Rx.race(command.close, abort.pipe((0, operators_1.filter)(() => command.state === 'stopped')))
85
+ : command.close);
86
+ return Rx.lastValueFrom(Rx.combineLatest(closeStreams).pipe((0, operators_1.filter)(() => commands.every((command) => command.state !== 'started')), (0, operators_1.map)((events) => events
87
+ // Filter out aborts, since they cannot be sorted and are considered success condition anyways
88
+ .filter((event) => event != null)
89
+ // Sort according to exit time
90
+ .sort((first, second) => first.timings.endDate.getTime() - second.timings.endDate.getTime())), (0, operators_1.switchMap)((events) => this.isSuccess(events)
91
+ ? this.emitWithScheduler(Rx.of(events))
92
+ : this.emitWithScheduler(Rx.throwError(() => events))), (0, operators_1.take)(1)));
72
93
  }
73
94
  emitWithScheduler(input) {
74
95
  return this.scheduler ? input.pipe(Rx.observeOn(this.scheduler)) : input;
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { Writable } from 'stream';
3
- import { CloseEvent, Command, CommandInfo, KillProcess, SpawnCommand } from './command';
4
+ import { CloseEvent, Command, CommandIdentifier, CommandInfo, KillProcess, SpawnCommand } from './command';
4
5
  import { SuccessCondition } from './completion-listener';
5
6
  import { FlowController } from './flow-control/flow-controller';
6
7
  import { Logger } from './logger';
@@ -21,7 +22,8 @@ export type ConcurrentlyResult = {
21
22
  * A promise that resolves when concurrently ran successfully according to the specified
22
23
  * success condition, or reject otherwise.
23
24
  *
24
- * Both the resolved and rejected value is the list of all command's close events.
25
+ * Both the resolved and rejected value is a list of all the close events for commands that
26
+ * spawned; commands that didn't spawn are filtered out.
25
27
  */
26
28
  result: Promise<CloseEvent[]>;
27
29
  };
@@ -49,9 +51,11 @@ export type ConcurrentlyOptions = {
49
51
  * Available background colors:
50
52
  * - `bgBlack`, `bgRed`, `bgGreen`, `bgYellow`, `bgBlue`, `bgMagenta`, `bgCyan`, `bgWhite`
51
53
  *
54
+ * Set to `false` to disable colors.
55
+ *
52
56
  * @see {@link https://www.npmjs.com/package/chalk} for more information.
53
57
  */
54
- prefixColors?: string | string[];
58
+ prefixColors?: string | string[] | false;
55
59
  /**
56
60
  * Maximum number of commands to run at once.
57
61
  * Exact number or a percent of CPUs available (for example "50%").
@@ -65,6 +69,10 @@ export type ConcurrentlyOptions = {
65
69
  * Defaults to false.
66
70
  */
67
71
  raw?: boolean;
72
+ /**
73
+ * Which commands should have their output hidden.
74
+ */
75
+ hide?: CommandIdentifier[];
68
76
  /**
69
77
  * The current working directory of commands which didn't specify one.
70
78
  * Defaults to `process.cwd()`.
@@ -74,6 +82,10 @@ export type ConcurrentlyOptions = {
74
82
  * @see CompletionListener
75
83
  */
76
84
  successCondition?: SuccessCondition;
85
+ /**
86
+ * A signal to stop spawning further processes.
87
+ */
88
+ abortSignal?: AbortSignal;
77
89
  /**
78
90
  * Which flow controllers should be applied on commands spawned by concurrently.
79
91
  * Defaults to an empty array.
@@ -81,7 +93,7 @@ export type ConcurrentlyOptions = {
81
93
  controllers: FlowController[];
82
94
  /**
83
95
  * A function that will spawn commands.
84
- * Defaults to the `spawn-command` module.
96
+ * Defaults to a function that spawns using either `cmd.exe` or `/bin/sh`.
85
97
  */
86
98
  spawn: SpawnCommand;
87
99
  /**
@@ -7,7 +7,6 @@ exports.concurrently = void 0;
7
7
  const assert_1 = __importDefault(require("assert"));
8
8
  const lodash_1 = __importDefault(require("lodash"));
9
9
  const os_1 = require("os");
10
- const spawn_command_1 = __importDefault(require("spawn-command"));
11
10
  const tree_kill_1 = __importDefault(require("tree-kill"));
12
11
  const command_1 = require("./command");
13
12
  const expand_arguments_1 = require("./command-parser/expand-arguments");
@@ -15,11 +14,11 @@ const expand_npm_shortcut_1 = require("./command-parser/expand-npm-shortcut");
15
14
  const expand_npm_wildcard_1 = require("./command-parser/expand-npm-wildcard");
16
15
  const strip_quotes_1 = require("./command-parser/strip-quotes");
17
16
  const completion_listener_1 = require("./completion-listener");
18
- const get_spawn_opts_1 = require("./get-spawn-opts");
19
17
  const output_writer_1 = require("./output-writer");
20
18
  const prefix_color_selector_1 = require("./prefix-color-selector");
19
+ const spawn_1 = require("./spawn");
21
20
  const defaults = {
22
- spawn: spawn_command_1.default,
21
+ spawn: spawn_1.spawn,
23
22
  kill: tree_kill_1.default,
24
23
  raw: false,
25
24
  controllers: [],
@@ -35,7 +34,7 @@ function concurrently(baseCommands, baseOptions) {
35
34
  assert_1.default.ok(Array.isArray(baseCommands), '[concurrently] commands should be an array');
36
35
  assert_1.default.notStrictEqual(baseCommands.length, 0, '[concurrently] no commands provided');
37
36
  const options = lodash_1.default.defaults(baseOptions, defaults);
38
- const prefixColorSelector = new prefix_color_selector_1.PrefixColorSelector(options.prefixColors);
37
+ const prefixColorSelector = new prefix_color_selector_1.PrefixColorSelector(options.prefixColors || []);
39
38
  const commandParsers = [
40
39
  new strip_quotes_1.StripQuotes(),
41
40
  new expand_npm_shortcut_1.ExpandNpmShortcut(),
@@ -44,16 +43,19 @@ function concurrently(baseCommands, baseOptions) {
44
43
  if (options.additionalArguments) {
45
44
  commandParsers.push(new expand_arguments_1.ExpandArguments(options.additionalArguments));
46
45
  }
46
+ const hide = (options.hide || []).map(String);
47
47
  let commands = (0, lodash_1.default)(baseCommands)
48
48
  .map(mapToCommandInfo)
49
49
  .flatMap((command) => parseCommand(command, commandParsers))
50
50
  .map((command, index) => {
51
+ const hidden = hide.includes(command.name) || hide.includes(String(index));
51
52
  return new command_1.Command({
52
53
  index,
53
54
  prefixColor: prefixColorSelector.getNextColor(),
54
55
  ...command,
55
- }, (0, get_spawn_opts_1.getSpawnOpts)({
56
- raw: command.raw ?? options.raw,
56
+ }, (0, spawn_1.getSpawnOpts)({
57
+ ipc: command.ipc,
58
+ stdio: hidden ? 'hidden' : command.raw ?? options.raw ? 'raw' : 'normal',
57
59
  env: command.env,
58
60
  cwd: command.cwd || options.cwd,
59
61
  }), options.spawn, options.kill);
@@ -80,13 +82,11 @@ function concurrently(baseCommands, baseOptions) {
80
82
  ? Math.round(((0, os_1.cpus)().length * Number(options.maxProcesses.slice(0, -1))) / 100)
81
83
  : Number(options.maxProcesses)) || commandsLeft.length);
82
84
  for (let i = 0; i < maxProcesses; i++) {
83
- maybeRunMore(commandsLeft);
85
+ maybeRunMore(commandsLeft, options.abortSignal);
84
86
  }
85
87
  const result = new completion_listener_1.CompletionListener({ successCondition: options.successCondition })
86
- .listen(commands)
87
- .finally(() => {
88
- handleResult.onFinishCallbacks.forEach((onFinish) => onFinish());
89
- });
88
+ .listen(commands, options.abortSignal)
89
+ .finally(() => Promise.all(handleResult.onFinishCallbacks.map((onFinish) => onFinish())));
90
90
  return {
91
91
  result,
92
92
  commands,
@@ -103,6 +103,7 @@ function mapToCommandInfo(command) {
103
103
  name: command.name || '',
104
104
  env: command.env || {},
105
105
  cwd: command.cwd || '',
106
+ ipc: command.ipc,
106
107
  ...(command.prefixColor
107
108
  ? {
108
109
  prefixColor: command.prefixColor,
@@ -118,13 +119,13 @@ function mapToCommandInfo(command) {
118
119
  function parseCommand(command, parsers) {
119
120
  return parsers.reduce((commands, parser) => lodash_1.default.flatMap(commands, (command) => parser.parse(command)), lodash_1.default.castArray(command));
120
121
  }
121
- function maybeRunMore(commandsLeft) {
122
+ function maybeRunMore(commandsLeft, abortSignal) {
122
123
  const command = commandsLeft.shift();
123
- if (!command) {
124
+ if (!command || abortSignal?.aborted) {
124
125
  return;
125
126
  }
126
127
  command.start();
127
128
  command.close.subscribe(() => {
128
- maybeRunMore(commandsLeft);
129
+ maybeRunMore(commandsLeft, abortSignal);
129
130
  });
130
131
  }
@@ -0,0 +1,19 @@
1
+ export type FormatterOptions = {
2
+ locale?: string;
3
+ calendar?: string;
4
+ };
5
+ /**
6
+ * Unicode-compliant date/time formatter.
7
+ *
8
+ * @see https://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
9
+ */
10
+ export declare class DateFormatter {
11
+ private readonly options;
12
+ private static tokenRegex;
13
+ private readonly parts;
14
+ constructor(pattern: string, options?: FormatterOptions);
15
+ private compileLiteral;
16
+ private compileOther;
17
+ private compileToken;
18
+ format(date: Date): string;
19
+ }