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.
- package/README.md +34 -239
- package/dist/bin/concurrently.js +37 -22
- package/dist/bin/read-package.d.ts +6 -0
- package/dist/bin/read-package.js +47 -0
- package/dist/src/command-parser/expand-arguments.d.ts +1 -0
- package/dist/src/command-parser/expand-arguments.js +1 -0
- package/dist/src/command-parser/expand-npm-shortcut.d.ts +1 -1
- package/dist/src/command-parser/expand-npm-shortcut.js +4 -3
- package/dist/src/command-parser/expand-npm-wildcard.js +4 -2
- package/dist/src/command-parser/strip-quotes.d.ts +1 -0
- package/dist/src/command.d.ts +46 -5
- package/dist/src/command.js +91 -16
- package/dist/src/completion-listener.d.ts +4 -1
- package/dist/src/completion-listener.js +27 -6
- package/dist/src/concurrently.d.ts +16 -4
- package/dist/src/concurrently.js +15 -14
- package/dist/src/date-format.d.ts +19 -0
- package/dist/src/date-format.js +318 -0
- package/dist/src/defaults.d.ts +1 -1
- package/dist/src/defaults.js +1 -1
- package/dist/src/flow-control/flow-controller.d.ts +1 -1
- package/dist/src/flow-control/input-handler.js +4 -0
- package/dist/src/flow-control/kill-on-signal.d.ts +4 -1
- package/dist/src/flow-control/kill-on-signal.js +8 -1
- package/dist/src/flow-control/kill-others.d.ts +4 -1
- package/dist/src/flow-control/kill-others.js +7 -1
- package/dist/src/flow-control/log-error.js +1 -0
- package/dist/src/flow-control/log-exit.js +1 -0
- package/dist/src/flow-control/log-output.js +1 -0
- package/dist/src/flow-control/log-timings.d.ts +1 -1
- package/dist/src/flow-control/log-timings.js +6 -4
- package/dist/src/flow-control/logger-padding.d.ts +13 -0
- package/dist/src/flow-control/logger-padding.js +35 -0
- package/dist/src/flow-control/restart-process.d.ts +3 -2
- package/dist/src/flow-control/restart-process.js +14 -2
- package/dist/src/flow-control/teardown.d.ts +21 -0
- package/dist/src/flow-control/teardown.js +72 -0
- package/dist/src/index.d.ts +18 -8
- package/dist/src/index.js +28 -7
- package/dist/src/logger.d.ts +25 -10
- package/dist/src/logger.js +78 -39
- package/dist/src/output-writer.js +6 -2
- package/dist/src/prefix-color-selector.js +1 -0
- package/dist/src/{get-spawn-opts.d.ts → spawn.d.ts} +20 -5
- package/dist/src/spawn.js +49 -0
- package/docs/README.md +13 -0
- package/docs/cli/configuration.md +11 -0
- package/docs/cli/input-handling.md +40 -0
- package/docs/cli/output-control.md +35 -0
- package/docs/cli/passthrough-arguments.md +80 -0
- package/docs/cli/prefixing.md +147 -0
- package/docs/cli/restarting.md +38 -0
- package/docs/cli/shortcuts.md +72 -0
- package/docs/demo.gif +0 -0
- package/index.d.mts +7 -0
- package/index.d.ts +11 -0
- package/index.js +6 -1
- package/index.mjs +2 -2
- package/package.json +37 -29
- package/dist/bin/epilogue.d.ts +0 -1
- package/dist/bin/epilogue.js +0 -90
- package/dist/src/get-spawn-opts.js +0 -18
package/dist/src/command.d.ts
CHANGED
|
@@ -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
|
-
|
|
100
|
-
|
|
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 {};
|
package/dist/src/command.js
CHANGED
|
@@ -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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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.
|
|
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.
|
|
71
|
-
|
|
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
|
|
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
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
|
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
|
|
96
|
+
* Defaults to a function that spawns using either `cmd.exe` or `/bin/sh`.
|
|
85
97
|
*/
|
|
86
98
|
spawn: SpawnCommand;
|
|
87
99
|
/**
|
package/dist/src/concurrently.js
CHANGED
|
@@ -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:
|
|
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,
|
|
56
|
-
|
|
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
|
+
}
|