concurrently 9.1.2 → 9.2.1

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 (52) hide show
  1. package/README.md +8 -8
  2. package/dist/bin/concurrently.js +29 -12
  3. package/dist/bin/read-package.js +18 -9
  4. package/dist/src/assert.d.ts +5 -0
  5. package/dist/src/assert.js +15 -0
  6. package/dist/src/command-parser/expand-arguments.d.ts +5 -5
  7. package/dist/src/command-parser/expand-arguments.js +14 -12
  8. package/dist/src/command-parser/expand-wildcard.js +7 -6
  9. package/dist/src/command-parser/strip-quotes.d.ts +5 -5
  10. package/dist/src/command.d.ts +10 -6
  11. package/dist/src/command.js +41 -13
  12. package/dist/src/completion-listener.d.ts +0 -1
  13. package/dist/src/completion-listener.js +21 -8
  14. package/dist/src/concurrently.d.ts +0 -6
  15. package/dist/src/concurrently.js +15 -13
  16. package/dist/src/date-format.js +4 -1
  17. package/dist/src/flow-control/input-handler.d.ts +0 -1
  18. package/dist/src/flow-control/input-handler.js +18 -8
  19. package/dist/src/flow-control/kill-on-signal.d.ts +0 -2
  20. package/dist/src/flow-control/kill-others.d.ts +4 -2
  21. package/dist/src/flow-control/kill-others.js +19 -6
  22. package/dist/src/flow-control/log-timings.js +20 -16
  23. package/dist/src/flow-control/output-error-handler.d.ts +18 -0
  24. package/dist/src/flow-control/output-error-handler.js +27 -0
  25. package/dist/src/flow-control/restart-process.js +18 -8
  26. package/dist/src/flow-control/teardown.js +17 -7
  27. package/dist/src/index.d.ts +14 -3
  28. package/dist/src/index.js +12 -9
  29. package/dist/src/jsonc.d.ts +2 -2
  30. package/dist/src/logger.js +30 -15
  31. package/dist/src/observables.d.ts +8 -0
  32. package/dist/src/observables.js +23 -0
  33. package/dist/src/output-writer.d.ts +4 -1
  34. package/dist/src/output-writer.js +33 -8
  35. package/dist/src/prefix-color-selector.js +1 -1
  36. package/dist/src/spawn.d.ts +6 -12
  37. package/dist/src/spawn.js +3 -3
  38. package/dist/src/utils.d.ts +10 -0
  39. package/dist/src/utils.js +16 -0
  40. package/dist/tsconfig.tsbuildinfo +1 -0
  41. package/docs/README.md +2 -0
  42. package/docs/cli/input-handling.md +5 -5
  43. package/docs/cli/output-control.md +3 -3
  44. package/docs/cli/passthrough-arguments.md +8 -8
  45. package/docs/cli/prefixing.md +10 -10
  46. package/docs/cli/restarting.md +3 -3
  47. package/docs/cli/shortcuts.md +9 -9
  48. package/docs/cli/success.md +73 -0
  49. package/docs/cli/terminating.md +52 -0
  50. package/index.js +1 -1
  51. package/index.mjs +0 -1
  52. package/package.json +30 -35
package/README.md CHANGED
@@ -61,7 +61,7 @@ The tool is written in Node.js, but you can use it to run **any** commands.
61
61
  Remember to surround separate commands with quotes:
62
62
 
63
63
  ```bash
64
- concurrently "command1 arg" "command2 arg"
64
+ concurrently 'command1 arg' 'command2 arg'
65
65
  ```
66
66
 
67
67
  Otherwise **concurrently** would try to run 4 separate commands:
@@ -70,7 +70,7 @@ Otherwise **concurrently** would try to run 4 separate commands:
70
70
  In package.json, escape quotes:
71
71
 
72
72
  ```bash
73
- "start": "concurrently \"command1 arg\" \"command2 arg\""
73
+ "start": "concurrently 'command1 arg' 'command2 arg'"
74
74
  ```
75
75
 
76
76
  You can always check concurrently's flag list by running `concurrently --help`.
@@ -88,7 +88,7 @@ Check out documentation and other usage examples in the [`docs` directory](./doc
88
88
  with the shape `{ command, name, prefixColor, env, cwd, ipc }`.
89
89
 
90
90
  - `options` (optional): an object containing any of the below:
91
- - `cwd`: the working directory to be used by all commands. Can be overriden per command.
91
+ - `cwd`: the working directory to be used by all commands. Can be overridden per command.
92
92
  Default: `process.cwd()`.
93
93
  - `defaultInputTarget`: the default input target when reading from `inputStream`.
94
94
  Default: `0`.
@@ -96,8 +96,8 @@ Check out documentation and other usage examples in the [`docs` directory](./doc
96
96
  - `inputStream`: a [`Readable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_readable_streams)
97
97
  to read the input from. Should only be used in the rare instance you would like to stream anything other than `process.stdin`. Overrides `handleInput`.
98
98
  - `pauseInputStreamOnFinish`: by default, pauses the input stream (`process.stdin` when `handleInput` is enabled, or `inputStream` if provided) when all of the processes have finished. If you need to read from the input stream after `concurrently` has finished, set this to `false`. ([#252](https://github.com/kimmobrunfeldt/concurrently/issues/252)).
99
- - `killOthers`: an array of exitting conditions that will cause a process to kill others.
100
- Can contain any of `success` or `failure`.
99
+ - `killOthersOn`: once the first command exits with one of these statuses, kill other commands.
100
+ Can be an array containing the strings `success` (status code zero) and/or `failure` (non-zero exit status).
101
101
  - `maxProcesses`: how many processes should run at once.
102
102
  - `outputStream`: a [`Writable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_writable_streams)
103
103
  to write logs to. Default: `process.stdout`.
@@ -109,14 +109,14 @@ Check out documentation and other usage examples in the [`docs` directory](./doc
109
109
  Prefix colors specified per-command take precedence over this list.
110
110
  - `prefixLength`: how many characters to show when prefixing with `command`. Default: `10`
111
111
  - `raw`: whether raw mode should be used, meaning strictly process output will
112
- be logged, without any prefixes, coloring or extra stuff. Can be overriden per command.
112
+ be logged, without any prefixes, coloring or extra stuff. Can be overridden per command.
113
113
  - `successCondition`: the condition to consider the run was successful.
114
114
  If `first`, only the first process to exit will make up the success of the run; if `last`, the last process that exits will determine whether the run succeeds.
115
115
  Anything else means all processes should exit successfully.
116
116
  - `restartTries`: how many attempts to restart a process that dies will be made. Default: `0`.
117
117
  - `restartDelay`: how many milliseconds to wait between process restarts. Default: `0`.
118
118
  - `timestampFormat`: a [Unicode format](https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table)
119
- to use when prefixing with `time`. Default: `yyyy-MM-dd HH:mm:ss.ZZZ`
119
+ to use when prefixing with `time`. Default: `yyyy-MM-dd HH:mm:ss.SSS`
120
120
  - `additionalArguments`: list of additional arguments passed that will get replaced in each command. If not defined, no argument replacing will happen.
121
121
 
122
122
  > **Returns:** an object in the shape `{ result, commands }`.
@@ -172,8 +172,8 @@ It has the following properties:
172
172
  - `stderr`: an RxJS observable to the command's `stderr`.
173
173
  - `error`: an RxJS observable to the command's error events (e.g. when it fails to spawn).
174
174
  - `timer`: an RxJS observable to the command's timing events (e.g. starting, stopping).
175
+ - `stateChange`: an RxJS observable for changes to the command's `state` property.
175
176
  - `messages`: an object with the following properties:
176
-
177
177
  - `incoming`: an RxJS observable for the IPC messages received from the underlying process.
178
178
  - `outgoing`: an RxJS observable for the IPC messages sent to the underlying process.
179
179
 
@@ -16,22 +16,33 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
16
16
  }) : function(o, v) {
17
17
  o["default"] = v;
18
18
  });
19
- var __importStar = (this && this.__importStar) || function (mod) {
20
- if (mod && mod.__esModule) return mod;
21
- var result = {};
22
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
- __setModuleDefault(result, mod);
24
- return result;
25
- };
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
26
36
  var __importDefault = (this && this.__importDefault) || function (mod) {
27
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
28
38
  };
29
39
  Object.defineProperty(exports, "__esModule", { value: true });
30
- const lodash_1 = __importDefault(require("lodash"));
31
40
  const yargs_1 = __importDefault(require("yargs"));
32
41
  const helpers_1 = require("yargs/helpers");
42
+ const assert_1 = require("../src/assert");
33
43
  const defaults = __importStar(require("../src/defaults"));
34
44
  const index_1 = require("../src/index");
45
+ const utils_1 = require("../src/utils");
35
46
  const read_package_1 = require("./read-package");
36
47
  const version = String((0, read_package_1.readPackage)().version);
37
48
  const epilogue = `For documentation and more examples, visit:\nhttps://github.com/open-cli-tools/concurrently/tree/v${version}/docs`;
@@ -128,7 +139,7 @@ const program = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
128
139
  // Kill others
129
140
  'kill-others': {
130
141
  alias: 'k',
131
- describe: 'Kill other processes if one exits or dies.',
142
+ describe: 'Kill other processes once the first exits.',
132
143
  type: 'boolean',
133
144
  },
134
145
  'kill-others-on-fail': {
@@ -141,6 +152,10 @@ const program = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
141
152
  type: 'string',
142
153
  default: defaults.killSignal,
143
154
  },
155
+ 'kill-timeout': {
156
+ describe: 'How many milliseconds to wait before forcing process terminating.',
157
+ type: 'number',
158
+ },
144
159
  // Prefix
145
160
  prefix: {
146
161
  alias: 'p',
@@ -209,13 +224,14 @@ const program = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
209
224
  .group(['m', 'n', 'name-separator', 's', 'r', 'no-color', 'hide', 'g', 'timings', 'P', 'teardown'], 'General')
210
225
  .group(['p', 'c', 'l', 't', 'pad-prefix'], 'Prefix styling')
211
226
  .group(['i', 'default-input-target'], 'Input handling')
212
- .group(['k', 'kill-others-on-fail', 'kill-signal'], 'Killing other processes')
227
+ .group(['k', 'kill-others-on-fail', 'kill-signal', 'kill-timeout'], 'Killing other processes')
213
228
  .group(['restart-tries', 'restart-after'], 'Restarting')
214
229
  .epilogue(epilogue);
215
230
  const args = program.parseSync();
231
+ (0, assert_1.assertDeprecated)(args.nameSeparator === defaults.nameSeparator, 'name-separator', 'Use commas as name separators instead.');
216
232
  // Get names of commands by the specified separator
217
233
  const names = (args.names || '').split(args.nameSeparator);
218
- const additionalArguments = lodash_1.default.castArray(args['--'] ?? []).map(String);
234
+ const additionalArguments = (0, utils_1.castArray)(args['--'] ?? []).map(String);
219
235
  const commands = args.passthroughArguments ? args._ : args._.concat(additionalArguments);
220
236
  if (!commands.length) {
221
237
  program.showHelp();
@@ -227,12 +243,13 @@ if (!commands.length) {
227
243
  })), {
228
244
  handleInput: args.handleInput,
229
245
  defaultInputTarget: args.defaultInputTarget,
230
- killOthers: args.killOthers
246
+ killOthersOn: args.killOthers
231
247
  ? ['success', 'failure']
232
248
  : args.killOthersOnFail
233
249
  ? ['failure']
234
250
  : [],
235
251
  killSignal: args.killSignal,
252
+ killTimeout: args.killTimeout,
236
253
  maxProcesses: args.maxProcesses,
237
254
  raw: args.raw,
238
255
  hide: args.hide.split(','),
@@ -15,15 +15,25 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
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
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.readPackage = void 0;
36
+ exports.readPackage = readPackage;
27
37
  const fs = __importStar(require("fs"));
28
38
  const path = __importStar(require("path"));
29
39
  /**
@@ -44,4 +54,3 @@ function readPackage() {
44
54
  } while (oldDir !== dir);
45
55
  throw new Error('package.json not found');
46
56
  }
47
- exports.readPackage = readPackage;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Asserts that some condition is true, and if not, prints a warning about it being deprecated.
3
+ * The message is printed only once.
4
+ */
5
+ export declare function assertDeprecated(check: boolean, name: string, message: string): void;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertDeprecated = assertDeprecated;
4
+ const deprecations = new Set();
5
+ /**
6
+ * Asserts that some condition is true, and if not, prints a warning about it being deprecated.
7
+ * The message is printed only once.
8
+ */
9
+ function assertDeprecated(check, name, message) {
10
+ if (!check && !deprecations.has(name)) {
11
+ // eslint-disable-next-line no-console
12
+ console.warn(`[concurrently] ${name} is deprecated. ${message}`);
13
+ deprecations.add(name);
14
+ }
15
+ }
@@ -9,10 +9,10 @@ export declare class ExpandArguments implements CommandParser {
9
9
  parse(commandInfo: CommandInfo): {
10
10
  command: string;
11
11
  name: string;
12
- env?: Record<string, unknown> | undefined;
13
- cwd?: string | undefined;
14
- prefixColor?: string | undefined;
15
- ipc?: number | undefined;
16
- raw?: boolean | undefined;
12
+ env?: Record<string, unknown>;
13
+ cwd?: string;
14
+ prefixColor?: string;
15
+ ipc?: number;
16
+ raw?: boolean;
17
17
  };
18
18
  }
@@ -16,18 +16,20 @@ class ExpandArguments {
16
16
  if (match.startsWith('\\')) {
17
17
  return match.slice(1);
18
18
  }
19
- // Replace numeric placeholder if value exists in additional arguments.
20
- if (!isNaN(placeholderTarget) &&
21
- placeholderTarget <= this.additionalArguments.length) {
22
- return (0, shell_quote_1.quote)([this.additionalArguments[placeholderTarget - 1]]);
23
- }
24
- // Replace all arguments placeholder.
25
- if (placeholderTarget === '@') {
26
- return (0, shell_quote_1.quote)(this.additionalArguments);
27
- }
28
- // Replace combined arguments placeholder.
29
- if (placeholderTarget === '*') {
30
- return (0, shell_quote_1.quote)([this.additionalArguments.join(' ')]);
19
+ if (this.additionalArguments.length > 0) {
20
+ // Replace numeric placeholder if value exists in additional arguments.
21
+ if (!isNaN(placeholderTarget) &&
22
+ placeholderTarget <= this.additionalArguments.length) {
23
+ return (0, shell_quote_1.quote)([this.additionalArguments[placeholderTarget - 1]]);
24
+ }
25
+ // Replace all arguments placeholder.
26
+ if (placeholderTarget === '@') {
27
+ return (0, shell_quote_1.quote)(this.additionalArguments);
28
+ }
29
+ // Replace combined arguments placeholder.
30
+ if (placeholderTarget === '*') {
31
+ return (0, shell_quote_1.quote)([this.additionalArguments.join(' ')]);
32
+ }
31
33
  }
32
34
  // Replace placeholder with empty string
33
35
  // if value doesn't exist in additional arguments.
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ExpandWildcard = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
- const lodash_1 = __importDefault(require("lodash"));
9
8
  const jsonc_1 = __importDefault(require("../jsonc"));
9
+ const utils_1 = require("../utils");
10
10
  // Matches a negative filter surrounded by '(!' and ')'.
11
11
  const OMISSION = /\(!([^)]+)\)/;
12
12
  /**
@@ -28,7 +28,7 @@ class ExpandWildcard {
28
28
  }
29
29
  return jsonc_1.default.parse(json);
30
30
  }
31
- catch (e) {
31
+ catch {
32
32
  return {};
33
33
  }
34
34
  }
@@ -37,7 +37,7 @@ class ExpandWildcard {
37
37
  const json = fs_1.default.readFileSync('package.json', { encoding: 'utf-8' });
38
38
  return JSON.parse(json);
39
39
  }
40
- catch (e) {
40
+ catch {
41
41
  return {};
42
42
  }
43
43
  }
@@ -79,8 +79,8 @@ class ExpandWildcard {
79
79
  }
80
80
  const [, omission] = OMISSION.exec(scriptGlob) || [];
81
81
  const scriptGlobSansOmission = scriptGlob.replace(OMISSION, '');
82
- const preWildcard = lodash_1.default.escapeRegExp(scriptGlobSansOmission.slice(0, wildcardPosition));
83
- const postWildcard = lodash_1.default.escapeRegExp(scriptGlobSansOmission.slice(wildcardPosition + 1));
82
+ const preWildcard = (0, utils_1.escapeRegExp)(scriptGlobSansOmission.slice(0, wildcardPosition));
83
+ const postWildcard = (0, utils_1.escapeRegExp)(scriptGlobSansOmission.slice(wildcardPosition + 1));
84
84
  const wildcardRegex = new RegExp(`^${preWildcard}(.*?)${postWildcard}$`);
85
85
  // If 'commandInfo.name' doesn't match 'scriptGlob', this means a custom name
86
86
  // has been specified and thus becomes the prefix (as described in the README).
@@ -90,7 +90,8 @@ class ExpandWildcard {
90
90
  if (omission && RegExp(omission).test(script)) {
91
91
  return;
92
92
  }
93
- const [, match] = wildcardRegex.exec(script) || [];
93
+ const result = wildcardRegex.exec(script);
94
+ const match = result?.[1];
94
95
  if (match !== undefined) {
95
96
  return {
96
97
  ...commandInfo,
@@ -7,10 +7,10 @@ export declare class StripQuotes implements CommandParser {
7
7
  parse(commandInfo: CommandInfo): {
8
8
  command: string;
9
9
  name: string;
10
- env?: Record<string, unknown> | undefined;
11
- cwd?: string | undefined;
12
- prefixColor?: string | undefined;
13
- ipc?: number | undefined;
14
- raw?: boolean | undefined;
10
+ env?: Record<string, unknown>;
11
+ cwd?: string;
12
+ prefixColor?: string;
13
+ ipc?: number;
14
+ raw?: boolean;
15
15
  };
16
16
  }
@@ -1,7 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
- /// <reference types="node" />
4
- /// <reference types="node" />
5
1
  import { ChildProcess as BaseChildProcess, MessageOptions, SendHandle, SpawnOptions } from 'child_process';
6
2
  import * as Rx from 'rxjs';
7
3
  import { EventEmitter, Writable } from 'stream';
@@ -114,9 +110,16 @@ export declare class Command implements CommandInfo {
114
110
  readonly ipc?: number;
115
111
  readonly close: Rx.Subject<CloseEvent>;
116
112
  readonly error: Rx.Subject<unknown>;
117
- readonly stdout: Rx.Subject<Buffer>;
118
- readonly stderr: Rx.Subject<Buffer>;
113
+ readonly stdout: Rx.Subject<Buffer<ArrayBufferLike>>;
114
+ readonly stderr: Rx.Subject<Buffer<ArrayBufferLike>>;
119
115
  readonly timer: Rx.Subject<TimerEvent>;
116
+ /**
117
+ * A stream of changes to the `#state` property.
118
+ *
119
+ * Note that the command never goes back to the `stopped` state, therefore it's not a value
120
+ * that's emitted by this stream.
121
+ */
122
+ readonly stateChange: Rx.Subject<"started" | "errored" | "exited">;
120
123
  readonly messages: {
121
124
  incoming: Rx.Subject<MessageEvent>;
122
125
  outgoing: Rx.ReplaySubject<OutgoingMessageEvent>;
@@ -135,6 +138,7 @@ export declare class Command implements CommandInfo {
135
138
  * Starts this command, piping output, error and close events onto the corresponding observables.
136
139
  */
137
140
  start(): void;
141
+ private changeState;
138
142
  private maybeSetupIPC;
139
143
  /**
140
144
  * Sends a message to the underlying process once it starts.
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
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
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
36
  exports.Command = void 0;
27
37
  const Rx = __importStar(require("rxjs"));
@@ -47,6 +57,13 @@ class Command {
47
57
  stdout = new Rx.Subject();
48
58
  stderr = new Rx.Subject();
49
59
  timer = new Rx.Subject();
60
+ /**
61
+ * A stream of changes to the `#state` property.
62
+ *
63
+ * Note that the command never goes back to the `stopped` state, therefore it's not a value
64
+ * that's emitted by this stream.
65
+ */
66
+ stateChange = new Rx.Subject();
50
67
  messages = {
51
68
  incoming: new Rx.Subject(),
52
69
  outgoing: new Rx.ReplaySubject(),
@@ -76,7 +93,7 @@ class Command {
76
93
  */
77
94
  start() {
78
95
  const child = this.spawn(this.command, this.spawnOpts);
79
- this.state = 'started';
96
+ this.changeState('started');
80
97
  this.process = child;
81
98
  this.pid = child.pid;
82
99
  const startDate = new Date(Date.now());
@@ -88,7 +105,7 @@ class Command {
88
105
  const endDate = new Date(Date.now());
89
106
  this.timer.next({ startDate, endDate });
90
107
  this.error.next(event);
91
- this.state = 'errored';
108
+ this.changeState('errored');
92
109
  });
93
110
  Rx.fromEvent(child, 'close')
94
111
  .pipe(Rx.map((event) => event))
@@ -96,7 +113,7 @@ class Command {
96
113
  this.cleanUp();
97
114
  // Don't override error event
98
115
  if (this.state !== 'errored') {
99
- this.state = 'exited';
116
+ this.changeState('exited');
100
117
  }
101
118
  const endDate = new Date(Date.now());
102
119
  this.timer.next({ startDate, endDate });
@@ -113,12 +130,18 @@ class Command {
113
130
  },
114
131
  });
115
132
  });
116
- child.stdout &&
133
+ if (child.stdout) {
117
134
  pipeTo(Rx.fromEvent(child.stdout, 'data').pipe(Rx.map((event) => event)), this.stdout);
118
- child.stderr &&
135
+ }
136
+ if (child.stderr) {
119
137
  pipeTo(Rx.fromEvent(child.stderr, 'data').pipe(Rx.map((event) => event)), this.stderr);
138
+ }
120
139
  this.stdin = child.stdin || undefined;
121
140
  }
141
+ changeState(state) {
142
+ this.state = state;
143
+ this.stateChange.next(state);
144
+ }
122
145
  maybeSetupIPC(child) {
123
146
  if (!this.ipc) {
124
147
  return [];
@@ -155,7 +178,12 @@ class Command {
155
178
  handle,
156
179
  options,
157
180
  onSent(error) {
158
- error ? reject(error) : resolve();
181
+ if (error) {
182
+ reject(error);
183
+ }
184
+ else {
185
+ resolve();
186
+ }
159
187
  },
160
188
  });
161
189
  });
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import * as Rx from 'rxjs';
3
2
  import { CloseEvent, Command } from './command';
4
3
  /**
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
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
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
36
  exports.CompletionListener = void 0;
27
37
  const Rx = __importStar(require("rxjs"));
@@ -61,7 +71,7 @@ class CompletionListener {
61
71
  // All commands except the specified ones must exit successfully
62
72
  return events.every((event) => targetCommandsEvents.includes(event) || event.exitCode === 0);
63
73
  }
64
- // Only the specified commands must exit succesfully
74
+ // Only the specified commands must exit successfully
65
75
  return (targetCommandsEvents.length > 0 &&
66
76
  targetCommandsEvents.every((event) => event.exitCode === 0));
67
77
  }
@@ -73,6 +83,9 @@ class CompletionListener {
73
83
  * Commands that didn't spawn are filtered out.
74
84
  */
75
85
  listen(commands, abortSignal) {
86
+ if (!commands.length) {
87
+ return Promise.resolve([]);
88
+ }
76
89
  const abort = abortSignal &&
77
90
  Rx.fromEvent(abortSignal, 'abort', { once: true }).pipe(
78
91
  // The abort signal must happen before commands are killed, otherwise new commands
@@ -1,5 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
1
  import { Writable } from 'stream';
4
2
  import { CloseEvent, Command, CommandIdentifier, CommandInfo, KillProcess, SpawnCommand } from './command';
5
3
  import { SuccessCondition } from './completion-listener';
@@ -101,10 +99,6 @@ export type ConcurrentlyOptions = {
101
99
  * Defaults to the `tree-kill` module.
102
100
  */
103
101
  kill: KillProcess;
104
- /**
105
- * Signal to send to killed processes.
106
- */
107
- killSignal?: string;
108
102
  /**
109
103
  * List of additional arguments passed that will get replaced in each command.
110
104
  * If not defined, no argument replacing will happen.
@@ -3,10 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.concurrently = void 0;
6
+ exports.concurrently = concurrently;
7
7
  const assert_1 = __importDefault(require("assert"));
8
- const lodash_1 = __importDefault(require("lodash"));
9
- const os_1 = require("os");
8
+ const os_1 = __importDefault(require("os"));
9
+ const rxjs_1 = require("rxjs");
10
10
  const tree_kill_1 = __importDefault(require("tree-kill"));
11
11
  const command_1 = require("./command");
12
12
  const expand_arguments_1 = require("./command-parser/expand-arguments");
@@ -17,6 +17,7 @@ const completion_listener_1 = require("./completion-listener");
17
17
  const output_writer_1 = require("./output-writer");
18
18
  const prefix_color_selector_1 = require("./prefix-color-selector");
19
19
  const spawn_1 = require("./spawn");
20
+ const utils_1 = require("./utils");
20
21
  const defaults = {
21
22
  spawn: spawn_1.spawn,
22
23
  kill: tree_kill_1.default,
@@ -33,7 +34,7 @@ const defaults = {
33
34
  function concurrently(baseCommands, baseOptions) {
34
35
  assert_1.default.ok(Array.isArray(baseCommands), '[concurrently] commands should be an array');
35
36
  assert_1.default.notStrictEqual(baseCommands.length, 0, '[concurrently] no commands provided');
36
- const options = lodash_1.default.defaults(baseOptions, defaults);
37
+ const options = { ...defaults, ...baseOptions };
37
38
  const prefixColorSelector = new prefix_color_selector_1.PrefixColorSelector(options.prefixColors || []);
38
39
  const commandParsers = [
39
40
  new strip_quotes_1.StripQuotes(),
@@ -44,7 +45,7 @@ function concurrently(baseCommands, baseOptions) {
44
45
  commandParsers.push(new expand_arguments_1.ExpandArguments(options.additionalArguments));
45
46
  }
46
47
  const hide = (options.hide || []).map(String);
47
- let commands = (0, lodash_1.default)(baseCommands)
48
+ let commands = baseCommands
48
49
  .map(mapToCommandInfo)
49
50
  .flatMap((command) => parseCommand(command, commandParsers))
50
51
  .map((command, index) => {
@@ -55,17 +56,16 @@ function concurrently(baseCommands, baseOptions) {
55
56
  ...command,
56
57
  }, (0, spawn_1.getSpawnOpts)({
57
58
  ipc: command.ipc,
58
- stdio: hidden ? 'hidden' : command.raw ?? options.raw ? 'raw' : 'normal',
59
+ stdio: hidden ? 'hidden' : (command.raw ?? options.raw) ? 'raw' : 'normal',
59
60
  env: command.env,
60
61
  cwd: command.cwd || options.cwd,
61
62
  }), options.spawn, options.kill);
62
- })
63
- .value();
63
+ });
64
64
  const handleResult = options.controllers.reduce(({ commands: prevCommands, onFinishCallbacks }, controller) => {
65
65
  const { commands, onFinish } = controller.handle(prevCommands);
66
66
  return {
67
67
  commands,
68
- onFinishCallbacks: lodash_1.default.concat(onFinishCallbacks, onFinish ? [onFinish] : []),
68
+ onFinishCallbacks: onFinishCallbacks.concat(onFinish ? [onFinish] : []),
69
69
  };
70
70
  }, { commands, onFinishCallbacks: [] });
71
71
  commands = handleResult.commands;
@@ -75,11 +75,14 @@ function concurrently(baseCommands, baseOptions) {
75
75
  group: !!options.group,
76
76
  commands,
77
77
  });
78
- options.logger.output.subscribe(({ command, text }) => outputWriter.write(command, text));
78
+ options.logger.output
79
+ // Stop trying to write after there's been an error.
80
+ .pipe((0, rxjs_1.takeUntil)(outputWriter.error))
81
+ .subscribe(({ command, text }) => outputWriter.write(command, text));
79
82
  }
80
83
  const commandsLeft = commands.slice();
81
84
  const maxProcesses = Math.max(1, (typeof options.maxProcesses === 'string' && options.maxProcesses.endsWith('%')
82
- ? Math.round(((0, os_1.cpus)().length * Number(options.maxProcesses.slice(0, -1))) / 100)
85
+ ? Math.round((os_1.default.cpus().length * Number(options.maxProcesses.slice(0, -1))) / 100)
83
86
  : Number(options.maxProcesses)) || commandsLeft.length);
84
87
  for (let i = 0; i < maxProcesses; i++) {
85
88
  maybeRunMore(commandsLeft, options.abortSignal);
@@ -92,7 +95,6 @@ function concurrently(baseCommands, baseOptions) {
92
95
  commands,
93
96
  };
94
97
  }
95
- exports.concurrently = concurrently;
96
98
  function mapToCommandInfo(command) {
97
99
  if (typeof command === 'string') {
98
100
  return mapToCommandInfo({ command });
@@ -117,7 +119,7 @@ function mapToCommandInfo(command) {
117
119
  };
118
120
  }
119
121
  function parseCommand(command, parsers) {
120
- return parsers.reduce((commands, parser) => lodash_1.default.flatMap(commands, (command) => parser.parse(command)), lodash_1.default.castArray(command));
122
+ return parsers.reduce((commands, parser) => commands.flatMap((command) => parser.parse(command)), (0, utils_1.castArray)(command));
121
123
  }
122
124
  function maybeRunMore(commandsLeft, abortSignal) {
123
125
  const command = commandsLeft.shift();