concurrently 7.2.2 → 7.3.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 +82 -67
- package/dist/bin/concurrently.js +11 -9
- package/dist/bin/epilogue.js +16 -15
- package/dist/src/command-parser/expand-arguments.d.ts +5 -1
- package/dist/src/command-parser/expand-arguments.js +3 -5
- package/dist/src/command-parser/expand-npm-shortcut.js +3 -3
- package/dist/src/command-parser/expand-npm-wildcard.js +11 -31
- package/dist/src/command-parser/strip-quotes.d.ts +5 -1
- package/dist/src/command-parser/strip-quotes.js +2 -3
- package/dist/src/command.d.ts +5 -2
- package/dist/src/command.js +1 -2
- package/dist/src/completion-listener.d.ts +2 -2
- package/dist/src/completion-listener.js +7 -11
- package/dist/src/concurrently.js +13 -10
- package/dist/src/flow-control/input-handler.d.ts +1 -1
- package/dist/src/flow-control/input-handler.js +3 -4
- package/dist/src/flow-control/kill-on-signal.js +1 -2
- package/dist/src/flow-control/kill-others.d.ts +1 -1
- package/dist/src/flow-control/kill-others.js +2 -4
- package/dist/src/flow-control/log-error.js +1 -2
- package/dist/src/flow-control/log-exit.js +0 -1
- package/dist/src/flow-control/log-output.js +0 -1
- package/dist/src/flow-control/log-timings.d.ts +3 -3
- package/dist/src/flow-control/log-timings.js +7 -11
- package/dist/src/flow-control/restart-process.d.ts +1 -1
- package/dist/src/flow-control/restart-process.js +4 -3
- package/dist/src/get-spawn-opts.d.ts +4 -1
- package/dist/src/get-spawn-opts.js +9 -2
- package/dist/src/logger.d.ts +2 -2
- package/dist/src/logger.js +8 -9
- package/dist/src/output-writer.d.ts +1 -1
- package/dist/src/output-writer.js +2 -4
- package/index.js +1 -0
- package/package.json +25 -23
package/README.md
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
#
|
|
1
|
+
# concurrently
|
|
2
2
|
|
|
3
|
-
[](https://github.com/open-cli-tools/concurrently/releases)
|
|
4
|
+
[](https://github.com/open-cli-tools/concurrently/blob/main/LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/concurrently)
|
|
6
|
+
[](https://github.com/open-cli-tools/concurrently/actions/workflows/ci.yml)
|
|
7
|
+
[](https://coveralls.io/github/open-cli-tools/concurrently?branch=main)
|
|
7
8
|
|
|
8
9
|
Run multiple commands concurrently.
|
|
9
10
|
Like `npm run watch-js & npm run watch-less` but better.
|
|
10
11
|
|
|
11
|
-

|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
**Table of Contents**
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
- [Concurrently](#concurrently)
|
|
16
|
+
- [concurrently](#concurrently)
|
|
15
17
|
- [Why](#why)
|
|
16
18
|
- [Install](#install)
|
|
17
19
|
- [Usage](#usage)
|
|
@@ -34,10 +36,10 @@ tired of opening terminals and made **concurrently**.
|
|
|
34
36
|
|
|
35
37
|
**Features:**
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
- Cross platform (including Windows)
|
|
40
|
+
- Output is easy to follow with prefixes
|
|
41
|
+
- With `--kill-others` switch, all commands are killed if one dies
|
|
42
|
+
- Spawns commands with [spawn-command](https://github.com/mmalecki/spawn-command)
|
|
41
43
|
|
|
42
44
|
## Install
|
|
43
45
|
|
|
@@ -56,6 +58,7 @@ npm install concurrently --save
|
|
|
56
58
|
## Usage
|
|
57
59
|
|
|
58
60
|
Remember to surround separate commands with quotes:
|
|
61
|
+
|
|
59
62
|
```bash
|
|
60
63
|
concurrently "command1 arg" "command2 arg"
|
|
61
64
|
```
|
|
@@ -81,17 +84,17 @@ concurrently -n watch-js,watch-css,watch-node "npm run watch-js" "npm run watch-
|
|
|
81
84
|
NPM shortened commands also support wildcards. Given the following scripts in
|
|
82
85
|
package.json:
|
|
83
86
|
|
|
84
|
-
```
|
|
87
|
+
```jsonc
|
|
85
88
|
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
// ...
|
|
89
|
-
"watch-js": "...",
|
|
90
|
-
"watch-css": "...",
|
|
91
|
-
"watch-node": "...",
|
|
92
|
-
// ...
|
|
93
|
-
},
|
|
89
|
+
//...
|
|
90
|
+
"scripts": {
|
|
94
91
|
// ...
|
|
92
|
+
"watch-js": "...",
|
|
93
|
+
"watch-css": "...",
|
|
94
|
+
"watch-node": "..."
|
|
95
|
+
// ...
|
|
96
|
+
}
|
|
97
|
+
// ...
|
|
95
98
|
}
|
|
96
99
|
```
|
|
97
100
|
|
|
@@ -110,19 +113,21 @@ concurrently -n w:js,w:css,w:node "npm run watch-js" "npm run watch-css" "npm ru
|
|
|
110
113
|
```
|
|
111
114
|
|
|
112
115
|
Exclusion is also supported. Given the following scripts in package.json:
|
|
113
|
-
|
|
116
|
+
|
|
117
|
+
```jsonc
|
|
114
118
|
{
|
|
119
|
+
// ...
|
|
120
|
+
"scripts": {
|
|
121
|
+
"lint:js": "...",
|
|
122
|
+
"lint:ts": "...",
|
|
123
|
+
"lint:fix:js": "...",
|
|
124
|
+
"lint:fix:ts": "..."
|
|
115
125
|
// ...
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"lint:ts": "...",
|
|
119
|
-
"lint:fix:js": "...",
|
|
120
|
-
"lint:fix:ts": "...",
|
|
121
|
-
// ...
|
|
122
|
-
}
|
|
123
|
-
// ...
|
|
126
|
+
}
|
|
127
|
+
// ...
|
|
124
128
|
}
|
|
125
129
|
```
|
|
130
|
+
|
|
126
131
|
```bash
|
|
127
132
|
# Running only lint:js and lint:ts
|
|
128
133
|
# with lint:fix:js and lint:fix:ts excluded
|
|
@@ -291,7 +296,8 @@ For more details, visit https://github.com/open-cli-tools/concurrently
|
|
|
291
296
|
```
|
|
292
297
|
|
|
293
298
|
## API
|
|
294
|
-
|
|
299
|
+
|
|
300
|
+
**concurrently** can be used programmatically by using the API documented below:
|
|
295
301
|
|
|
296
302
|
### `concurrently(commands[, options])`
|
|
297
303
|
|
|
@@ -299,38 +305,39 @@ concurrently can be used programmatically by using the API documented below:
|
|
|
299
305
|
with the shape `{ command, name, prefixColor, env, cwd }`.
|
|
300
306
|
|
|
301
307
|
- `options` (optional): an object containing any of the below:
|
|
302
|
-
|
|
308
|
+
- `cwd`: the working directory to be used by all commands. Can be overriden per command.
|
|
303
309
|
Default: `process.cwd()`.
|
|
304
|
-
|
|
310
|
+
- `defaultInputTarget`: the default input target when reading from `inputStream`.
|
|
305
311
|
Default: `0`.
|
|
306
|
-
|
|
307
|
-
|
|
312
|
+
- `handleInput`: when `true`, reads input from `process.stdin`.
|
|
313
|
+
- `inputStream`: a [`Readable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_readable_streams)
|
|
308
314
|
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`.
|
|
309
|
-
|
|
310
|
-
|
|
315
|
+
- `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)).
|
|
316
|
+
- `killOthers`: an array of exitting conditions that will cause a process to kill others.
|
|
311
317
|
Can contain any of `success` or `failure`.
|
|
312
|
-
|
|
313
|
-
|
|
318
|
+
- `maxProcesses`: how many processes should run at once.
|
|
319
|
+
- `outputStream`: a [`Writable` stream](https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_writable_streams)
|
|
314
320
|
to write logs to. Default: `process.stdout`.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
- `prefix`: the prefix type to use when logging processes output.
|
|
322
|
+
Possible values: `index`, `pid`, `time`, `command`, `name`, `none`, or a template (eg `[{time} process: {pid}]`).
|
|
323
|
+
Default: the name of the process, or its index if no name is set.
|
|
324
|
+
- `prefixColors`: a list of colors as supported by [chalk](https://www.npmjs.com/package/chalk).
|
|
325
|
+
If concurrently would run more commands than there are colors, the last color is repeated.
|
|
326
|
+
Prefix colors specified per-command take precedence over this list.
|
|
327
|
+
- `prefixLength`: how many characters to show when prefixing with `command`. Default: `10`
|
|
328
|
+
- `raw`: whether raw mode should be used, meaning strictly process output will
|
|
323
329
|
be logged, without any prefixes, colouring or extra stuff.
|
|
324
|
-
|
|
330
|
+
- `successCondition`: the condition to consider the run was successful.
|
|
325
331
|
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.
|
|
326
332
|
Anything else means all processes should exit successfully.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
333
|
+
- `restartTries`: how many attempts to restart a process that dies will be made. Default: `0`.
|
|
334
|
+
- `restartDelay`: how many milliseconds to wait between process restarts. Default: `0`.
|
|
335
|
+
- `timestampFormat`: a [date-fns format](https://date-fns.org/v2.0.1/docs/format)
|
|
330
336
|
to use when prefixing with `time`. Default: `yyyy-MM-dd HH:mm:ss.ZZZ`
|
|
331
|
-
|
|
337
|
+
- `additionalArguments`: list of additional arguments passed that will get replaced in each command. If not defined, no argument replacing will happen.
|
|
332
338
|
|
|
333
339
|
> **Returns:** an object in the shape `{ result, commands }`.
|
|
340
|
+
>
|
|
334
341
|
> - `result`: a `Promise` that resolves if the run was successful (according to `successCondition` option),
|
|
335
342
|
> or rejects, containing an array of [`CloseEvent`](#CloseEvent), in the order that the commands terminated.
|
|
336
343
|
> - `commands`: an array of all spawned [`Command`s](#Command).
|
|
@@ -339,21 +346,29 @@ Example:
|
|
|
339
346
|
|
|
340
347
|
```js
|
|
341
348
|
const concurrently = require('concurrently');
|
|
342
|
-
const { result } = concurrently(
|
|
349
|
+
const { result } = concurrently(
|
|
350
|
+
[
|
|
343
351
|
'npm:watch-*',
|
|
344
352
|
{ command: 'nodemon', name: 'server' },
|
|
345
353
|
{ command: 'deploy', name: 'deploy', env: { PUBLIC_KEY: '...' } },
|
|
346
|
-
{
|
|
347
|
-
|
|
354
|
+
{
|
|
355
|
+
command: 'watch',
|
|
356
|
+
name: 'watch',
|
|
357
|
+
cwd: path.resolve(__dirname, 'scripts/watchers'),
|
|
358
|
+
},
|
|
359
|
+
],
|
|
360
|
+
{
|
|
348
361
|
prefix: 'name',
|
|
349
362
|
killOthers: ['failure', 'success'],
|
|
350
363
|
restartTries: 3,
|
|
351
364
|
cwd: path.resolve(__dirname, 'scripts'),
|
|
352
|
-
}
|
|
365
|
+
}
|
|
366
|
+
);
|
|
353
367
|
result.then(success, failure);
|
|
354
368
|
```
|
|
355
369
|
|
|
356
370
|
### `Command`
|
|
371
|
+
|
|
357
372
|
An object that contains all information about a spawned command, and ways to interact with it.<br>
|
|
358
373
|
It has the following properties:
|
|
359
374
|
|
|
@@ -376,6 +391,7 @@ It has the following properties:
|
|
|
376
391
|
- `kill([signal])`: kills the command, optionally specifying a signal (e.g. `SIGTERM`, `SIGKILL`, etc).
|
|
377
392
|
|
|
378
393
|
### `CloseEvent`
|
|
394
|
+
|
|
379
395
|
An object with information about a command's closing event.<br>
|
|
380
396
|
It contains the following properties:
|
|
381
397
|
|
|
@@ -387,19 +403,18 @@ It contains the following properties:
|
|
|
387
403
|
|
|
388
404
|
## FAQ
|
|
389
405
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
From [Node child_process documentation](http://nodejs.org/api/child_process.html#child_process_event_exit), `exit` event:
|
|
406
|
+
- Process exited with code _null_?
|
|
393
407
|
|
|
394
|
-
|
|
395
|
-
> terminated normally, code is the final exit code of the process,
|
|
396
|
-
> otherwise null. If the process terminated due to receipt of a signal,
|
|
397
|
-
> signal is the string name of the signal, otherwise null.
|
|
408
|
+
From [Node child_process documentation](http://nodejs.org/api/child_process.html#child_process_event_exit), `exit` event:
|
|
398
409
|
|
|
410
|
+
> This event is emitted after the child process ends. If the process
|
|
411
|
+
> terminated normally, code is the final exit code of the process,
|
|
412
|
+
> otherwise null. If the process terminated due to receipt of a signal,
|
|
413
|
+
> signal is the string name of the signal, otherwise null.
|
|
399
414
|
|
|
400
|
-
|
|
401
|
-
|
|
415
|
+
So _null_ means the process didn't terminate normally. This will make **concurrently**
|
|
416
|
+
to return non-zero exit code too.
|
|
402
417
|
|
|
403
|
-
|
|
418
|
+
- Does this work with the npm-replacements [yarn](https://github.com/yarnpkg/yarn) or [pnpm](https://pnpm.js.org/)?
|
|
404
419
|
|
|
405
|
-
|
|
420
|
+
Yes! In all examples above, you may replace "`npm`" with "`yarn`" or "`pnpm`".
|
package/dist/bin/concurrently.js
CHANGED
|
@@ -35,7 +35,7 @@ const epilogue_1 = require("./epilogue");
|
|
|
35
35
|
// Clean-up arguments (yargs expects only the arguments after the program name)
|
|
36
36
|
const cleanArgs = (0, helpers_1.hideBin)(process.argv);
|
|
37
37
|
// Find argument separator (double dash)
|
|
38
|
-
const argsSepIdx = cleanArgs.findIndex(
|
|
38
|
+
const argsSepIdx = cleanArgs.findIndex(arg => arg === '--');
|
|
39
39
|
// Arguments before separator
|
|
40
40
|
const argsBeforeSep = argsSepIdx >= 0 ? cleanArgs.slice(0, argsSepIdx) : cleanArgs;
|
|
41
41
|
// Arguments after separator
|
|
@@ -57,7 +57,7 @@ const args = (0, yargs_1.default)(argsBeforeSep)
|
|
|
57
57
|
'New processes only spawn after all restart tries of a process.',
|
|
58
58
|
type: 'number',
|
|
59
59
|
},
|
|
60
|
-
|
|
60
|
+
names: {
|
|
61
61
|
alias: 'n',
|
|
62
62
|
describe: 'List of custom names to be used in prefix template.\n' +
|
|
63
63
|
'Example names: "main,browser,server"',
|
|
@@ -68,7 +68,7 @@ const args = (0, yargs_1.default)(argsBeforeSep)
|
|
|
68
68
|
'concurrently -n "styles|scripts|server" --name-separator "|"',
|
|
69
69
|
default: defaults.nameSeparator,
|
|
70
70
|
},
|
|
71
|
-
|
|
71
|
+
success: {
|
|
72
72
|
alias: 's',
|
|
73
73
|
describe: 'Which command(s) must exit with code 0 in order for concurrently exit with ' +
|
|
74
74
|
'code 0 too. Options are:\n' +
|
|
@@ -81,7 +81,7 @@ const args = (0, yargs_1.default)(argsBeforeSep)
|
|
|
81
81
|
'name or index.\n',
|
|
82
82
|
default: defaults.success,
|
|
83
83
|
},
|
|
84
|
-
|
|
84
|
+
raw: {
|
|
85
85
|
alias: 'r',
|
|
86
86
|
describe: 'Output only raw output of processes, disables prettifying ' +
|
|
87
87
|
'and concurrently coloring.',
|
|
@@ -93,18 +93,18 @@ const args = (0, yargs_1.default)(argsBeforeSep)
|
|
|
93
93
|
describe: 'Disables colors from logging',
|
|
94
94
|
type: 'boolean',
|
|
95
95
|
},
|
|
96
|
-
|
|
96
|
+
hide: {
|
|
97
97
|
describe: 'Comma-separated list of processes to hide the output.\n' +
|
|
98
98
|
'The processes can be identified by their name or index.',
|
|
99
99
|
default: defaults.hide,
|
|
100
100
|
type: 'string',
|
|
101
101
|
},
|
|
102
|
-
|
|
102
|
+
group: {
|
|
103
103
|
alias: 'g',
|
|
104
104
|
describe: 'Order the output as if the commands were run sequentially.',
|
|
105
105
|
type: 'boolean',
|
|
106
106
|
},
|
|
107
|
-
|
|
107
|
+
timings: {
|
|
108
108
|
describe: 'Show timing information for all processes.',
|
|
109
109
|
type: 'boolean',
|
|
110
110
|
default: defaults.timings,
|
|
@@ -127,7 +127,7 @@ const args = (0, yargs_1.default)(argsBeforeSep)
|
|
|
127
127
|
type: 'boolean',
|
|
128
128
|
},
|
|
129
129
|
// Prefix
|
|
130
|
-
|
|
130
|
+
prefix: {
|
|
131
131
|
alias: 'p',
|
|
132
132
|
describe: 'Prefix used in logging for each process.\n' +
|
|
133
133
|
'Possible values: index, pid, time, command, name, none, or a template. ' +
|
|
@@ -205,7 +205,9 @@ const commands = args.passthroughArguments ? args._ : [...args._, ...argsAfterSe
|
|
|
205
205
|
defaultInputTarget: args.defaultInputTarget,
|
|
206
206
|
killOthers: args.killOthers
|
|
207
207
|
? ['success', 'failure']
|
|
208
|
-
:
|
|
208
|
+
: args.killOthersOnFail
|
|
209
|
+
? ['failure']
|
|
210
|
+
: [],
|
|
209
211
|
maxProcesses: args.maxProcesses,
|
|
210
212
|
raw: args.raw,
|
|
211
213
|
hide: args.hide.split(','),
|
package/dist/bin/epilogue.js
CHANGED
|
@@ -33,17 +33,11 @@ const examples = [
|
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
description: 'Send input to specific child identified by index',
|
|
36
|
-
example: [
|
|
37
|
-
'$ $0 --handle-input "npm run watch-js" nodemon',
|
|
38
|
-
'1:rs',
|
|
39
|
-
].join('\n'),
|
|
36
|
+
example: ['$ $0 --handle-input "npm run watch-js" nodemon', '1:rs'].join('\n'),
|
|
40
37
|
},
|
|
41
38
|
{
|
|
42
39
|
description: 'Send input to specific child identified by name',
|
|
43
|
-
example: [
|
|
44
|
-
'$ $0 --handle-input -n js,srv "npm run watch-js" nodemon',
|
|
45
|
-
'srv:rs',
|
|
46
|
-
].join('\n'),
|
|
40
|
+
example: ['$ $0 --handle-input -n js,srv "npm run watch-js" nodemon', 'srv:rs'].join('\n'),
|
|
47
41
|
},
|
|
48
42
|
{
|
|
49
43
|
description: 'Shortened NPM run commands',
|
|
@@ -58,24 +52,31 @@ const examples = [
|
|
|
58
52
|
example: '$ $0 "npm:*(!fix)"',
|
|
59
53
|
},
|
|
60
54
|
{
|
|
61
|
-
description:
|
|
55
|
+
description: "Passthrough some additional arguments via '{<number>}' placeholder",
|
|
62
56
|
example: '$ $0 -P "echo {1}" -- foo',
|
|
63
57
|
},
|
|
64
58
|
{
|
|
65
|
-
description:
|
|
59
|
+
description: "Passthrough all additional arguments via '{@}' placeholder",
|
|
66
60
|
example: '$ $0 -P "npm:dev-* -- {@}" -- --watch --noEmit',
|
|
67
61
|
},
|
|
68
62
|
{
|
|
69
|
-
description:
|
|
63
|
+
description: "Passthrough all additional arguments combined via '{*}' placeholder",
|
|
70
64
|
example: '$ $0 -P "npm:dev-* -- {*}" -- --watch --noEmit',
|
|
71
65
|
},
|
|
72
66
|
];
|
|
67
|
+
const examplesString = examples
|
|
68
|
+
.map(({ example, description }) => [
|
|
69
|
+
` - ${description}`,
|
|
70
|
+
example
|
|
71
|
+
.split('\n')
|
|
72
|
+
.map(line => ` ${line}`)
|
|
73
|
+
.join('\n'),
|
|
74
|
+
].join('\n\n'))
|
|
75
|
+
.join('\n\n');
|
|
73
76
|
exports.epilogue = `
|
|
74
77
|
Examples:
|
|
75
|
-
${examples.map(({ example, description }) => `
|
|
76
|
-
- ${description}
|
|
77
78
|
|
|
78
|
-
${
|
|
79
|
-
|
|
79
|
+
${examplesString}
|
|
80
|
+
|
|
80
81
|
For more details, visit https://github.com/open-cli-tools/concurrently
|
|
81
82
|
`;
|
|
@@ -6,7 +6,11 @@ import { CommandParser } from './command-parser';
|
|
|
6
6
|
export declare class ExpandArguments implements CommandParser {
|
|
7
7
|
private readonly additionalArguments;
|
|
8
8
|
constructor(additionalArguments: string[]);
|
|
9
|
-
parse(commandInfo: CommandInfo):
|
|
9
|
+
parse(commandInfo: CommandInfo): {
|
|
10
10
|
command: string;
|
|
11
|
+
name: string;
|
|
12
|
+
env?: Record<string, unknown>;
|
|
13
|
+
cwd?: string;
|
|
14
|
+
prefixColor?: string;
|
|
11
15
|
};
|
|
12
16
|
}
|
|
@@ -10,10 +10,10 @@ class ExpandArguments {
|
|
|
10
10
|
this.additionalArguments = additionalArguments;
|
|
11
11
|
}
|
|
12
12
|
parse(commandInfo) {
|
|
13
|
-
const command = commandInfo.command.replace(/\\?\{([
|
|
13
|
+
const command = commandInfo.command.replace(/\\?\{([@*]|[1-9][0-9]*)\}/g, (match, placeholderTarget) => {
|
|
14
14
|
// Don't replace the placeholder if it is escaped by a backslash.
|
|
15
15
|
if (match.startsWith('\\')) {
|
|
16
|
-
return match.
|
|
16
|
+
return match.slice(1);
|
|
17
17
|
}
|
|
18
18
|
// Replace numeric placeholder if value exists in additional arguments.
|
|
19
19
|
if (!isNaN(placeholderTarget) &&
|
|
@@ -32,9 +32,7 @@ class ExpandArguments {
|
|
|
32
32
|
// if value doesn't exist in additional arguments.
|
|
33
33
|
return '';
|
|
34
34
|
});
|
|
35
|
-
return
|
|
36
|
-
command,
|
|
37
|
-
});
|
|
35
|
+
return { ...commandInfo, command };
|
|
38
36
|
}
|
|
39
37
|
}
|
|
40
38
|
exports.ExpandArguments = ExpandArguments;
|
|
@@ -10,11 +10,11 @@ class ExpandNpmShortcut {
|
|
|
10
10
|
if (!cmdName) {
|
|
11
11
|
return commandInfo;
|
|
12
12
|
}
|
|
13
|
-
return
|
|
13
|
+
return {
|
|
14
|
+
...commandInfo,
|
|
14
15
|
name: commandInfo.name || cmdName,
|
|
15
16
|
command: `${npmCmd} run ${cmdName}${args}`,
|
|
16
|
-
}
|
|
17
|
+
};
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
exports.ExpandNpmShortcut = ExpandNpmShortcut;
|
|
20
|
-
;
|
|
@@ -1,32 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
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 (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;
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
4
|
};
|
|
25
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
6
|
exports.ExpandNpmWildcard = void 0;
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const OMISSION = /\(!([
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
9
|
+
const OMISSION = /\(!([^)]+)\)/;
|
|
30
10
|
/**
|
|
31
11
|
* Finds wildcards in npm/yarn/pnpm run commands and replaces them with all matching scripts in the
|
|
32
12
|
* `package.json` file of the current directory.
|
|
@@ -37,7 +17,7 @@ class ExpandNpmWildcard {
|
|
|
37
17
|
}
|
|
38
18
|
static readPackage() {
|
|
39
19
|
try {
|
|
40
|
-
const json =
|
|
20
|
+
const json = fs_1.default.readFileSync('package.json', { encoding: 'utf-8' });
|
|
41
21
|
return JSON.parse(json);
|
|
42
22
|
}
|
|
43
23
|
catch (e) {
|
|
@@ -57,8 +37,8 @@ class ExpandNpmWildcard {
|
|
|
57
37
|
}
|
|
58
38
|
const omissionRegex = cmdName.match(OMISSION);
|
|
59
39
|
const cmdNameSansOmission = cmdName.replace(OMISSION, '');
|
|
60
|
-
const preWildcard =
|
|
61
|
-
const postWildcard =
|
|
40
|
+
const preWildcard = lodash_1.default.escapeRegExp(cmdNameSansOmission.slice(0, wildcardPosition));
|
|
41
|
+
const postWildcard = lodash_1.default.escapeRegExp(cmdNameSansOmission.slice(wildcardPosition + 1));
|
|
62
42
|
const wildcardRegex = new RegExp(`^${preWildcard}(.*?)${postWildcard}$`);
|
|
63
43
|
const currentName = commandInfo.name || '';
|
|
64
44
|
return this.scripts
|
|
@@ -71,16 +51,16 @@ class ExpandNpmWildcard {
|
|
|
71
51
|
}
|
|
72
52
|
}
|
|
73
53
|
if (match) {
|
|
74
|
-
return
|
|
54
|
+
return {
|
|
55
|
+
...commandInfo,
|
|
75
56
|
command: `${npmCmd} run ${script}${args}`,
|
|
76
57
|
// Will use an empty command name if command has no name and the wildcard match is empty,
|
|
77
58
|
// e.g. if `npm:watch-*` matches `npm run watch-`.
|
|
78
59
|
name: currentName + match[1],
|
|
79
|
-
}
|
|
60
|
+
};
|
|
80
61
|
}
|
|
81
62
|
})
|
|
82
63
|
.filter((commandInfo) => !!commandInfo);
|
|
83
64
|
}
|
|
84
65
|
}
|
|
85
66
|
exports.ExpandNpmWildcard = ExpandNpmWildcard;
|
|
86
|
-
;
|
|
@@ -4,7 +4,11 @@ import { CommandParser } from './command-parser';
|
|
|
4
4
|
* Strips quotes around commands so that they can run on the current shell.
|
|
5
5
|
*/
|
|
6
6
|
export declare class StripQuotes implements CommandParser {
|
|
7
|
-
parse(commandInfo: CommandInfo):
|
|
7
|
+
parse(commandInfo: CommandInfo): {
|
|
8
8
|
command: string;
|
|
9
|
+
name: string;
|
|
10
|
+
env?: Record<string, unknown>;
|
|
11
|
+
cwd?: string;
|
|
12
|
+
prefixColor?: string;
|
|
9
13
|
};
|
|
10
14
|
}
|
|
@@ -9,10 +9,9 @@ class StripQuotes {
|
|
|
9
9
|
let { command } = commandInfo;
|
|
10
10
|
// Removes the quotes surrounding a command.
|
|
11
11
|
if (/^"(.+?)"$/.test(command) || /^'(.+?)'$/.test(command)) {
|
|
12
|
-
command = command.
|
|
12
|
+
command = command.slice(1, command.length - 1);
|
|
13
13
|
}
|
|
14
|
-
return
|
|
14
|
+
return { ...commandInfo, command };
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
exports.StripQuotes = StripQuotes;
|
|
18
|
-
;
|
package/dist/src/command.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
/// <reference types="node" />
|
|
2
5
|
import { ChildProcess as BaseChildProcess, SpawnOptions } from 'child_process';
|
|
3
6
|
import * as Rx from 'rxjs';
|
|
4
7
|
import { EventEmitter, Writable } from 'stream';
|
|
@@ -18,7 +21,7 @@ export interface CommandInfo {
|
|
|
18
21
|
/**
|
|
19
22
|
* Which environment variables should the spawned process have.
|
|
20
23
|
*/
|
|
21
|
-
env?: Record<string,
|
|
24
|
+
env?: Record<string, unknown>;
|
|
22
25
|
/**
|
|
23
26
|
* The current working directory of the process when spawned.
|
|
24
27
|
*/
|
|
@@ -76,7 +79,7 @@ export declare class Command implements CommandInfo {
|
|
|
76
79
|
/** @inheritdoc */
|
|
77
80
|
readonly prefixColor: string;
|
|
78
81
|
/** @inheritdoc */
|
|
79
|
-
readonly env: Record<string,
|
|
82
|
+
readonly env: Record<string, unknown>;
|
|
80
83
|
/** @inheritdoc */
|
|
81
84
|
readonly cwd?: string;
|
|
82
85
|
readonly close: Rx.Subject<CloseEvent>;
|
package/dist/src/command.js
CHANGED
|
@@ -77,7 +77,7 @@ class Command {
|
|
|
77
77
|
timings: {
|
|
78
78
|
startDate,
|
|
79
79
|
endDate,
|
|
80
|
-
durationSeconds: durationSeconds +
|
|
80
|
+
durationSeconds: durationSeconds + durationNanoSeconds / 1e9,
|
|
81
81
|
},
|
|
82
82
|
});
|
|
83
83
|
});
|
|
@@ -96,7 +96,6 @@ class Command {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
exports.Command = Command;
|
|
99
|
-
;
|
|
100
99
|
/**
|
|
101
100
|
* Pipes all events emitted by `stream` into `subject`.
|
|
102
101
|
*/
|
|
@@ -12,11 +12,11 @@ import { CloseEvent, Command } from './command';
|
|
|
12
12
|
export declare type SuccessCondition = 'first' | 'last' | 'all' | `command-${string | number}` | `!command-${string | number}`;
|
|
13
13
|
/**
|
|
14
14
|
* Provides logic to determine whether lists of commands ran successfully.
|
|
15
|
-
*/
|
|
15
|
+
*/
|
|
16
16
|
export declare class CompletionListener {
|
|
17
17
|
private readonly successCondition;
|
|
18
18
|
private readonly scheduler?;
|
|
19
|
-
constructor({ successCondition, scheduler }: {
|
|
19
|
+
constructor({ successCondition, scheduler, }: {
|
|
20
20
|
/**
|
|
21
21
|
* How this instance will define that a list of commands ran successfully.
|
|
22
22
|
* Defaults to `all`.
|
|
@@ -28,9 +28,9 @@ const Rx = __importStar(require("rxjs"));
|
|
|
28
28
|
const operators_1 = require("rxjs/operators");
|
|
29
29
|
/**
|
|
30
30
|
* Provides logic to determine whether lists of commands ran successfully.
|
|
31
|
-
*/
|
|
31
|
+
*/
|
|
32
32
|
class CompletionListener {
|
|
33
|
-
constructor({ successCondition = 'all', scheduler }) {
|
|
33
|
+
constructor({ successCondition = 'all', scheduler, }) {
|
|
34
34
|
this.successCondition = successCondition;
|
|
35
35
|
this.scheduler = scheduler;
|
|
36
36
|
}
|
|
@@ -50,16 +50,14 @@ class CompletionListener {
|
|
|
50
50
|
// Note that a command's `name` is not necessarily unique,
|
|
51
51
|
// in which case all of them must meet the success condition.
|
|
52
52
|
const nameOrIndex = commandSyntaxMatch[1];
|
|
53
|
-
const targetCommandsEvents = events.filter(({ command, index }) =>
|
|
54
|
-
|| index === Number(nameOrIndex)));
|
|
53
|
+
const targetCommandsEvents = events.filter(({ command, index }) => command.name === nameOrIndex || index === Number(nameOrIndex));
|
|
55
54
|
if (this.successCondition.startsWith('!')) {
|
|
56
55
|
// All commands except the specified ones must exit succesfully
|
|
57
|
-
return events.every(
|
|
58
|
-
|| event.exitCode === 0));
|
|
56
|
+
return events.every(event => targetCommandsEvents.includes(event) || event.exitCode === 0);
|
|
59
57
|
}
|
|
60
58
|
// Only the specified commands must exit succesfully
|
|
61
|
-
return targetCommandsEvents.length > 0
|
|
62
|
-
|
|
59
|
+
return (targetCommandsEvents.length > 0 &&
|
|
60
|
+
targetCommandsEvents.every(event => event.exitCode === 0));
|
|
63
61
|
}
|
|
64
62
|
/**
|
|
65
63
|
* Given a list of commands, wait for all of them to exit and then evaluate their exit codes.
|
|
@@ -68,11 +66,9 @@ class CompletionListener {
|
|
|
68
66
|
*/
|
|
69
67
|
listen(commands) {
|
|
70
68
|
const closeStreams = commands.map(command => command.close);
|
|
71
|
-
return Rx.lastValueFrom(Rx.merge(...closeStreams)
|
|
72
|
-
.pipe((0, operators_1.bufferCount)(closeStreams.length), (0, operators_1.switchMap)(exitInfos => this.isSuccess(exitInfos)
|
|
69
|
+
return Rx.lastValueFrom(Rx.merge(...closeStreams).pipe((0, operators_1.bufferCount)(closeStreams.length), (0, operators_1.switchMap)(exitInfos => this.isSuccess(exitInfos)
|
|
73
70
|
? Rx.of(exitInfos, this.scheduler)
|
|
74
71
|
: Rx.throwError(exitInfos, this.scheduler)), (0, operators_1.take)(1)));
|
|
75
72
|
}
|
|
76
73
|
}
|
|
77
74
|
exports.CompletionListener = CompletionListener;
|
|
78
|
-
;
|
package/dist/src/concurrently.js
CHANGED
|
@@ -47,11 +47,12 @@ function concurrently(baseCommands, baseOptions) {
|
|
|
47
47
|
.flatMap(command => parseCommand(command, commandParsers))
|
|
48
48
|
.map((command, index) => {
|
|
49
49
|
// Use documented behaviour of repeating last color when specifying more commands than colors
|
|
50
|
-
lastColor = options.prefixColors && options.prefixColors[index] || lastColor;
|
|
51
|
-
return new command_1.Command(
|
|
50
|
+
lastColor = (options.prefixColors && options.prefixColors[index]) || lastColor;
|
|
51
|
+
return new command_1.Command({
|
|
52
52
|
index,
|
|
53
53
|
prefixColor: lastColor,
|
|
54
|
-
|
|
54
|
+
...command,
|
|
55
|
+
}, (0, get_spawn_opts_1.getSpawnOpts)({
|
|
55
56
|
raw: options.raw,
|
|
56
57
|
env: command.env,
|
|
57
58
|
cwd: command.cwd || options.cwd,
|
|
@@ -66,7 +67,7 @@ function concurrently(baseCommands, baseOptions) {
|
|
|
66
67
|
};
|
|
67
68
|
}, { commands, onFinishCallbacks: [] });
|
|
68
69
|
commands = handleResult.commands;
|
|
69
|
-
if (options.logger) {
|
|
70
|
+
if (options.logger && options.outputStream) {
|
|
70
71
|
const outputWriter = new output_writer_1.OutputWriter({
|
|
71
72
|
outputStream: options.outputStream,
|
|
72
73
|
group: options.group,
|
|
@@ -82,7 +83,7 @@ function concurrently(baseCommands, baseOptions) {
|
|
|
82
83
|
const result = new completion_listener_1.CompletionListener({ successCondition: options.successCondition })
|
|
83
84
|
.listen(commands)
|
|
84
85
|
.finally(() => {
|
|
85
|
-
handleResult.onFinishCallbacks.forEach(
|
|
86
|
+
handleResult.onFinishCallbacks.forEach(onFinish => onFinish());
|
|
86
87
|
});
|
|
87
88
|
return {
|
|
88
89
|
result,
|
|
@@ -90,7 +91,6 @@ function concurrently(baseCommands, baseOptions) {
|
|
|
90
91
|
};
|
|
91
92
|
}
|
|
92
93
|
exports.concurrently = concurrently;
|
|
93
|
-
;
|
|
94
94
|
function mapToCommandInfo(command) {
|
|
95
95
|
if (typeof command === 'string') {
|
|
96
96
|
return {
|
|
@@ -100,14 +100,17 @@ function mapToCommandInfo(command) {
|
|
|
100
100
|
cwd: '',
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
|
-
return
|
|
103
|
+
return {
|
|
104
104
|
command: command.command,
|
|
105
105
|
name: command.name || '',
|
|
106
106
|
env: command.env || {},
|
|
107
107
|
cwd: command.cwd || '',
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
...(command.prefixColor
|
|
109
|
+
? {
|
|
110
|
+
prefixColor: command.prefixColor,
|
|
111
|
+
}
|
|
112
|
+
: {}),
|
|
113
|
+
};
|
|
111
114
|
}
|
|
112
115
|
function parseCommand(command, parsers) {
|
|
113
116
|
return parsers.reduce((commands, parser) => lodash_1.default.flatMap(commands, command => parser.parse(command)), lodash_1.default.castArray(command));
|
|
@@ -17,7 +17,7 @@ export declare class InputHandler implements FlowController {
|
|
|
17
17
|
private readonly defaultInputTarget;
|
|
18
18
|
private readonly inputStream;
|
|
19
19
|
private readonly pauseInputStreamOnFinish;
|
|
20
|
-
constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger }: {
|
|
20
|
+
constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger, }: {
|
|
21
21
|
inputStream: Readable;
|
|
22
22
|
logger: Logger;
|
|
23
23
|
defaultInputTarget?: CommandIdentifier;
|
|
@@ -37,7 +37,7 @@ const defaults = __importStar(require("../defaults"));
|
|
|
37
37
|
* If the input doesn't start with a command identifier, it is then always sent to the default target.
|
|
38
38
|
*/
|
|
39
39
|
class InputHandler {
|
|
40
|
-
constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger }) {
|
|
40
|
+
constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger, }) {
|
|
41
41
|
this.logger = logger;
|
|
42
42
|
this.defaultInputTarget = defaultInputTarget || defaults.defaultInputTarget;
|
|
43
43
|
this.inputStream = inputStream;
|
|
@@ -53,8 +53,8 @@ class InputHandler {
|
|
|
53
53
|
const dataParts = data.split(/:(.+)/);
|
|
54
54
|
const targetId = dataParts.length > 1 ? dataParts[0] : this.defaultInputTarget;
|
|
55
55
|
const input = dataParts[1] || data;
|
|
56
|
-
const command = commands.find(command =>
|
|
57
|
-
command.index.toString() === targetId.toString())
|
|
56
|
+
const command = commands.find(command => command.name === targetId ||
|
|
57
|
+
command.index.toString() === targetId.toString());
|
|
58
58
|
if (command && command.stdin) {
|
|
59
59
|
command.stdin.write(input);
|
|
60
60
|
}
|
|
@@ -74,4 +74,3 @@ class InputHandler {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
exports.InputHandler = InputHandler;
|
|
77
|
-
;
|
|
@@ -22,7 +22,7 @@ class KillOnSignal {
|
|
|
22
22
|
commands: commands.map(command => {
|
|
23
23
|
const closeStream = command.close.pipe((0, operators_1.map)(exitInfo => {
|
|
24
24
|
const exitCode = caughtSignal === 'SIGINT' ? 0 : exitInfo.exitCode;
|
|
25
|
-
return
|
|
25
|
+
return { ...exitInfo, exitCode };
|
|
26
26
|
}));
|
|
27
27
|
return new Proxy(command, {
|
|
28
28
|
get(target, prop) {
|
|
@@ -34,4 +34,3 @@ class KillOnSignal {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
exports.KillOnSignal = KillOnSignal;
|
|
37
|
-
;
|
|
@@ -8,7 +8,7 @@ export declare type ProcessCloseCondition = 'failure' | 'success';
|
|
|
8
8
|
export declare class KillOthers implements FlowController {
|
|
9
9
|
private readonly logger;
|
|
10
10
|
private readonly conditions;
|
|
11
|
-
constructor({ logger, conditions }: {
|
|
11
|
+
constructor({ logger, conditions, }: {
|
|
12
12
|
logger: Logger;
|
|
13
13
|
conditions: ProcessCloseCondition | ProcessCloseCondition[];
|
|
14
14
|
});
|
|
@@ -10,13 +10,12 @@ const operators_1 = require("rxjs/operators");
|
|
|
10
10
|
* Sends a SIGTERM signal to all commands when one of the exits with a matching condition.
|
|
11
11
|
*/
|
|
12
12
|
class KillOthers {
|
|
13
|
-
constructor({ logger, conditions }) {
|
|
13
|
+
constructor({ logger, conditions, }) {
|
|
14
14
|
this.logger = logger;
|
|
15
15
|
this.conditions = lodash_1.default.castArray(conditions);
|
|
16
16
|
}
|
|
17
17
|
handle(commands) {
|
|
18
|
-
const conditions = this.conditions.filter(condition =>
|
|
19
|
-
condition === 'success'));
|
|
18
|
+
const conditions = this.conditions.filter(condition => condition === 'failure' || condition === 'success');
|
|
20
19
|
if (!conditions.length) {
|
|
21
20
|
return { commands };
|
|
22
21
|
}
|
|
@@ -32,4 +31,3 @@ class KillOthers {
|
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
33
|
exports.KillOthers = KillOthers;
|
|
35
|
-
;
|
|
@@ -11,11 +11,10 @@ class LogError {
|
|
|
11
11
|
handle(commands) {
|
|
12
12
|
commands.forEach(command => command.error.subscribe(event => {
|
|
13
13
|
this.logger.logCommandEvent(`Error occurred when executing command: ${command.command}`, command);
|
|
14
|
-
const errorText = String(event instanceof Error ?
|
|
14
|
+
const errorText = String(event instanceof Error ? event.stack || event : event);
|
|
15
15
|
this.logger.logCommandEvent(errorText, command);
|
|
16
16
|
}));
|
|
17
17
|
return { commands };
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
exports.LogError = LogError;
|
|
21
|
-
;
|
|
@@ -12,14 +12,14 @@ interface TimingInfo {
|
|
|
12
12
|
* Logs timing information about commands as they start/stop and then a summary when all commands finish.
|
|
13
13
|
*/
|
|
14
14
|
export declare class LogTimings implements FlowController {
|
|
15
|
-
static mapCloseEventToTimingInfo({ command, timings, killed, exitCode }: CloseEvent): TimingInfo;
|
|
15
|
+
static mapCloseEventToTimingInfo({ command, timings, killed, exitCode, }: CloseEvent): TimingInfo;
|
|
16
16
|
private readonly logger?;
|
|
17
17
|
private readonly timestampFormat;
|
|
18
|
-
constructor({ logger, timestampFormat }: {
|
|
18
|
+
constructor({ logger, timestampFormat, }: {
|
|
19
19
|
logger?: Logger;
|
|
20
20
|
timestampFormat?: string;
|
|
21
21
|
});
|
|
22
|
-
printExitInfoTimingTable
|
|
22
|
+
private printExitInfoTimingTable;
|
|
23
23
|
handle(commands: Command[]): {
|
|
24
24
|
commands: Command[];
|
|
25
25
|
};
|
|
@@ -36,11 +36,11 @@ const defaults = __importStar(require("../defaults"));
|
|
|
36
36
|
* Logs timing information about commands as they start/stop and then a summary when all commands finish.
|
|
37
37
|
*/
|
|
38
38
|
class LogTimings {
|
|
39
|
-
constructor({ logger, timestampFormat = defaults.timestampFormat }) {
|
|
39
|
+
constructor({ logger, timestampFormat = defaults.timestampFormat, }) {
|
|
40
40
|
this.logger = logger;
|
|
41
41
|
this.timestampFormat = timestampFormat;
|
|
42
42
|
}
|
|
43
|
-
static mapCloseEventToTimingInfo({ command, timings, killed, exitCode }) {
|
|
43
|
+
static mapCloseEventToTimingInfo({ command, timings, killed, exitCode, }) {
|
|
44
44
|
const readableDurationMs = (timings.endDate.getTime() - timings.startDate.getTime()).toLocaleString();
|
|
45
45
|
return {
|
|
46
46
|
name: command.name,
|
|
@@ -51,17 +51,15 @@ class LogTimings {
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
printExitInfoTimingTable(exitInfos) {
|
|
54
|
-
var _a, _b;
|
|
55
54
|
const exitInfoTable = (0, lodash_1.default)(exitInfos)
|
|
56
55
|
.sortBy(({ timings }) => timings.durationSeconds)
|
|
57
56
|
.reverse()
|
|
58
57
|
.map(LogTimings.mapCloseEventToTimingInfo)
|
|
59
58
|
.value();
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
this.logger.logGlobalEvent('Timings:');
|
|
60
|
+
this.logger.logTable(exitInfoTable);
|
|
62
61
|
return exitInfos;
|
|
63
62
|
}
|
|
64
|
-
;
|
|
65
63
|
handle(commands) {
|
|
66
64
|
if (!this.logger) {
|
|
67
65
|
return { commands };
|
|
@@ -69,24 +67,22 @@ class LogTimings {
|
|
|
69
67
|
// individual process timings
|
|
70
68
|
commands.forEach(command => {
|
|
71
69
|
command.timer.subscribe(({ startDate, endDate }) => {
|
|
72
|
-
var _a, _b;
|
|
73
70
|
if (!endDate) {
|
|
74
71
|
const formattedStartDate = (0, format_1.default)(startDate, this.timestampFormat);
|
|
75
|
-
|
|
72
|
+
this.logger.logCommandEvent(`${command.command} started at ${formattedStartDate}`, command);
|
|
76
73
|
}
|
|
77
74
|
else {
|
|
78
75
|
const durationMs = endDate.getTime() - startDate.getTime();
|
|
79
76
|
const formattedEndDate = (0, format_1.default)(endDate, this.timestampFormat);
|
|
80
|
-
|
|
77
|
+
this.logger.logCommandEvent(`${command.command} stopped at ${formattedEndDate} after ${durationMs.toLocaleString()}ms`, command);
|
|
81
78
|
}
|
|
82
79
|
});
|
|
83
80
|
});
|
|
84
81
|
// overall summary timings
|
|
85
82
|
const closeStreams = commands.map(command => command.close);
|
|
86
83
|
const allProcessesClosed = Rx.merge(...closeStreams).pipe((0, operators_1.bufferCount)(closeStreams.length), (0, operators_1.take)(1));
|
|
87
|
-
allProcessesClosed.subscribe(
|
|
84
|
+
allProcessesClosed.subscribe(exitInfos => this.printExitInfoTimingTable(exitInfos));
|
|
88
85
|
return { commands };
|
|
89
86
|
}
|
|
90
87
|
}
|
|
91
88
|
exports.LogTimings = LogTimings;
|
|
92
|
-
;
|
|
@@ -10,7 +10,7 @@ export declare class RestartProcess implements FlowController {
|
|
|
10
10
|
private readonly scheduler?;
|
|
11
11
|
readonly delay: number;
|
|
12
12
|
readonly tries: number;
|
|
13
|
-
constructor({ delay, tries, logger, scheduler }: {
|
|
13
|
+
constructor({ delay, tries, logger, scheduler, }: {
|
|
14
14
|
delay?: number;
|
|
15
15
|
tries?: number;
|
|
16
16
|
logger: Logger;
|
|
@@ -31,7 +31,7 @@ const defaults = __importStar(require("../defaults"));
|
|
|
31
31
|
* Restarts commands that fail up to a defined number of times.
|
|
32
32
|
*/
|
|
33
33
|
class RestartProcess {
|
|
34
|
-
constructor({ delay, tries, logger, scheduler }) {
|
|
34
|
+
constructor({ delay, tries, logger, scheduler, }) {
|
|
35
35
|
this.logger = logger;
|
|
36
36
|
this.delay = delay != null ? +delay : defaults.restartDelay;
|
|
37
37
|
this.tries = tries != null ? +tries : defaults.restartTries;
|
|
@@ -42,7 +42,9 @@ class RestartProcess {
|
|
|
42
42
|
if (this.tries === 0) {
|
|
43
43
|
return { commands };
|
|
44
44
|
}
|
|
45
|
-
commands
|
|
45
|
+
commands
|
|
46
|
+
.map(command => command.close.pipe((0, operators_1.take)(this.tries), (0, operators_1.takeWhile)(({ exitCode }) => exitCode !== 0)))
|
|
47
|
+
.map((failure, index) => Rx.merge(
|
|
46
48
|
// Delay the emission (so that the restarts happen on time),
|
|
47
49
|
// explicitly telling the subscriber that a restart is needed
|
|
48
50
|
failure.pipe((0, operators_1.delay)(this.delay, this.scheduler), (0, operators_1.mapTo)(true)),
|
|
@@ -72,4 +74,3 @@ class RestartProcess {
|
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
exports.RestartProcess = RestartProcess;
|
|
75
|
-
;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
/// <reference types="node" />
|
|
2
5
|
import { SpawnOptions } from 'child_process';
|
|
3
6
|
import supportsColor from 'supports-color';
|
|
4
7
|
export declare const getSpawnOpts: ({ colorSupport, cwd, process, raw, env, }: {
|
|
@@ -26,5 +29,5 @@ export declare const getSpawnOpts: ({ colorSupport, cwd, process, raw, env, }: {
|
|
|
26
29
|
/**
|
|
27
30
|
* Map of custom environment variables to include in the spawn options.
|
|
28
31
|
*/
|
|
29
|
-
env?: Record<string,
|
|
32
|
+
env?: Record<string, unknown>;
|
|
30
33
|
}) => SpawnOptions;
|
|
@@ -5,7 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getSpawnOpts = void 0;
|
|
7
7
|
const supports_color_1 = __importDefault(require("supports-color"));
|
|
8
|
-
const getSpawnOpts = ({ colorSupport = supports_color_1.default.stdout, cwd, process = global.process, raw = false, env = {}, }) =>
|
|
8
|
+
const getSpawnOpts = ({ colorSupport = supports_color_1.default.stdout, cwd, process = global.process, raw = false, env = {}, }) => ({
|
|
9
9
|
cwd: cwd || process.cwd(),
|
|
10
|
-
|
|
10
|
+
...(raw && { stdio: 'inherit' }),
|
|
11
|
+
...(/^win/.test(process.platform) && { detached: false }),
|
|
12
|
+
env: {
|
|
13
|
+
...(colorSupport ? { FORCE_COLOR: colorSupport.level.toString() } : {}),
|
|
14
|
+
...process.env,
|
|
15
|
+
...env,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
11
18
|
exports.getSpawnOpts = getSpawnOpts;
|
package/dist/src/logger.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare class Logger {
|
|
|
19
19
|
command: Command | undefined;
|
|
20
20
|
text: string;
|
|
21
21
|
}>;
|
|
22
|
-
constructor({ hide, prefixFormat, prefixLength, raw, timestampFormat }: {
|
|
22
|
+
constructor({ hide, prefixFormat, prefixLength, raw, timestampFormat, }: {
|
|
23
23
|
/**
|
|
24
24
|
* Which command(s) should have their output hidden.
|
|
25
25
|
*/
|
|
@@ -66,7 +66,7 @@ export declare class Logger {
|
|
|
66
66
|
*
|
|
67
67
|
* Each row is a single input item, and they are presented in the input order.
|
|
68
68
|
*/
|
|
69
|
-
logTable(tableContents:
|
|
69
|
+
logTable(tableContents: unknown[]): void;
|
|
70
70
|
log(prefix: string, text: string, command?: Command): void;
|
|
71
71
|
emit(command: Command | undefined, text: string): void;
|
|
72
72
|
}
|
package/dist/src/logger.js
CHANGED
|
@@ -33,7 +33,7 @@ const format_1 = __importDefault(require("date-fns/format"));
|
|
|
33
33
|
const Rx = __importStar(require("rxjs"));
|
|
34
34
|
const defaults = __importStar(require("./defaults"));
|
|
35
35
|
class Logger {
|
|
36
|
-
constructor({ hide, prefixFormat, prefixLength, raw = false, timestampFormat }) {
|
|
36
|
+
constructor({ hide, prefixFormat, prefixLength, raw = false, timestampFormat, }) {
|
|
37
37
|
/**
|
|
38
38
|
* Observable that emits when there's been output logged.
|
|
39
39
|
* If `command` is is `undefined`, then the log is for a global event.
|
|
@@ -42,7 +42,9 @@ class Logger {
|
|
|
42
42
|
// To avoid empty strings from hiding the output of commands that don't have a name,
|
|
43
43
|
// keep in the list of commands to hide only strings with some length.
|
|
44
44
|
// This might happen through the CLI when no `--hide` argument is specified, for example.
|
|
45
|
-
this.hide = lodash_1.default.castArray(hide)
|
|
45
|
+
this.hide = lodash_1.default.castArray(hide)
|
|
46
|
+
.filter(name => name || name === 0)
|
|
47
|
+
.map(String);
|
|
46
48
|
this.raw = raw;
|
|
47
49
|
this.prefixFormat = prefixFormat;
|
|
48
50
|
this.prefixLength = prefixLength || defaults.prefixLength;
|
|
@@ -56,8 +58,8 @@ class Logger {
|
|
|
56
58
|
const prefixLength = this.prefixLength - ellipsis.length;
|
|
57
59
|
const endLength = Math.floor(prefixLength / 2);
|
|
58
60
|
const beginningLength = prefixLength - endLength;
|
|
59
|
-
const beginnning = text.
|
|
60
|
-
const end = text.
|
|
61
|
+
const beginnning = text.slice(0, beginningLength);
|
|
62
|
+
const end = text.slice(text.length - endLength, text.length);
|
|
61
63
|
return beginnning + ellipsis + end;
|
|
62
64
|
}
|
|
63
65
|
getPrefixesFor(command) {
|
|
@@ -137,7 +139,7 @@ class Logger {
|
|
|
137
139
|
const headers = {};
|
|
138
140
|
const contentRows = tableContents.map(row => {
|
|
139
141
|
const rowContents = [];
|
|
140
|
-
Object.keys(row).forEach(
|
|
142
|
+
Object.keys(row).forEach(col => {
|
|
141
143
|
if (!headers[col]) {
|
|
142
144
|
headers[col] = {
|
|
143
145
|
index: nextColIndex++,
|
|
@@ -153,9 +155,7 @@ class Logger {
|
|
|
153
155
|
});
|
|
154
156
|
return rowContents;
|
|
155
157
|
});
|
|
156
|
-
const headersFormatted = Object
|
|
157
|
-
.keys(headers)
|
|
158
|
-
.map(header => header.padEnd(headers[header].length, ' '));
|
|
158
|
+
const headersFormatted = Object.keys(headers).map(header => header.padEnd(headers[header].length, ' '));
|
|
159
159
|
if (!headersFormatted.length) {
|
|
160
160
|
// No columns exist.
|
|
161
161
|
return;
|
|
@@ -200,4 +200,3 @@ class Logger {
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
exports.Logger = Logger;
|
|
203
|
-
;
|
|
@@ -9,7 +9,7 @@ export declare class OutputWriter {
|
|
|
9
9
|
private readonly group;
|
|
10
10
|
readonly buffers: string[][];
|
|
11
11
|
activeCommandIndex: number;
|
|
12
|
-
constructor({ outputStream, group, commands }: {
|
|
12
|
+
constructor({ outputStream, group, commands, }: {
|
|
13
13
|
outputStream: Writable;
|
|
14
14
|
group: boolean;
|
|
15
15
|
commands: Command[];
|
|
@@ -29,14 +29,13 @@ const Rx = __importStar(require("rxjs"));
|
|
|
29
29
|
* Class responsible for actually writing output onto a writable stream.
|
|
30
30
|
*/
|
|
31
31
|
class OutputWriter {
|
|
32
|
-
constructor({ outputStream, group, commands }) {
|
|
32
|
+
constructor({ outputStream, group, commands, }) {
|
|
33
33
|
this.activeCommandIndex = 0;
|
|
34
34
|
this.outputStream = outputStream;
|
|
35
35
|
this.group = group;
|
|
36
36
|
this.buffers = commands.map(() => []);
|
|
37
37
|
if (this.group) {
|
|
38
|
-
Rx.merge(...commands.map(c => c.close))
|
|
39
|
-
.subscribe(command => {
|
|
38
|
+
Rx.merge(...commands.map(c => c.close)).subscribe(command => {
|
|
40
39
|
if (command.index !== this.activeCommandIndex) {
|
|
41
40
|
return;
|
|
42
41
|
}
|
|
@@ -70,4 +69,3 @@ class OutputWriter {
|
|
|
70
69
|
}
|
|
71
70
|
}
|
|
72
71
|
exports.OutputWriter = OutputWriter;
|
|
73
|
-
;
|
package/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// While in local development, make sure you've run `npm run build` first.
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
5
6
|
const concurrently = require('./dist/src/index.js');
|
|
6
7
|
module.exports = exports = concurrently.default;
|
|
7
8
|
Object.assign(exports, concurrently);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "concurrently",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.0",
|
|
4
4
|
"description": "Run commands concurrently",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -12,16 +12,22 @@
|
|
|
12
12
|
"node": "^12.20.0 || ^14.13.0 || >=16.0.0"
|
|
13
13
|
},
|
|
14
14
|
"exports": {
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
".": {
|
|
16
|
+
"import": "./index.mjs",
|
|
17
|
+
"require": "./index.js",
|
|
18
|
+
"default": "./index.js",
|
|
19
|
+
"types": "./dist/src/index.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./package.json": "./package.json"
|
|
19
22
|
},
|
|
20
23
|
"scripts": {
|
|
21
24
|
"build": "tsc --build",
|
|
22
25
|
"postbuild": "chmod +x dist/bin/concurrently.js",
|
|
23
26
|
"clean": "tsc --build --clean",
|
|
27
|
+
"format": "prettier --ignore-path .gitignore --check '**/{!(package-lock).json,*.y?(a)ml,*.md}'",
|
|
28
|
+
"format:fix": "npm run format -- --write",
|
|
24
29
|
"lint": "eslint . --ext js,ts --ignore-path .gitignore",
|
|
30
|
+
"lint:fix": "npm run lint -- --fix",
|
|
25
31
|
"prepublishOnly": "npm run build",
|
|
26
32
|
"report-coverage": "cat coverage/lcov.info | coveralls",
|
|
27
33
|
"test": "jest"
|
|
@@ -52,6 +58,9 @@
|
|
|
52
58
|
"yargs": "^17.3.1"
|
|
53
59
|
},
|
|
54
60
|
"devDependencies": {
|
|
61
|
+
"@swc-node/register": "^1.5.1",
|
|
62
|
+
"@swc/core": "^1.2.204",
|
|
63
|
+
"@swc/jest": "^0.2.21",
|
|
55
64
|
"@types/jest": "^27.0.3",
|
|
56
65
|
"@types/lodash": "^4.14.178",
|
|
57
66
|
"@types/node": "^17.0.0",
|
|
@@ -62,10 +71,13 @@
|
|
|
62
71
|
"@typescript-eslint/parser": "^5.8.1",
|
|
63
72
|
"coveralls-next": "^4.1.2",
|
|
64
73
|
"eslint": "^8.15.0",
|
|
74
|
+
"eslint-config-prettier": "^8.5.0",
|
|
75
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
65
76
|
"jest": "^27.5.1",
|
|
66
77
|
"jest-create-mock-instance": "^2.0.0",
|
|
67
|
-
"
|
|
68
|
-
"
|
|
78
|
+
"lint-staged": "^12.4.1",
|
|
79
|
+
"prettier": "^2.6.2",
|
|
80
|
+
"simple-git-hooks": "^2.7.0",
|
|
69
81
|
"typescript": "^4.5.4"
|
|
70
82
|
},
|
|
71
83
|
"files": [
|
|
@@ -76,21 +88,11 @@
|
|
|
76
88
|
"!**/*.spec.js",
|
|
77
89
|
"!**/*.spec.d.ts"
|
|
78
90
|
],
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
],
|
|
86
|
-
"coveragePathIgnorePatterns": [
|
|
87
|
-
"/fixtures/",
|
|
88
|
-
"/node_modules/"
|
|
89
|
-
],
|
|
90
|
-
"testEnvironment": "node",
|
|
91
|
-
"testPathIgnorePatterns": [
|
|
92
|
-
"/node_modules/",
|
|
93
|
-
"/dist"
|
|
94
|
-
]
|
|
91
|
+
"simple-git-hooks": {
|
|
92
|
+
"pre-commit": "npx lint-staged"
|
|
93
|
+
},
|
|
94
|
+
"lint-staged": {
|
|
95
|
+
"*.{js,ts}": "eslint --fix",
|
|
96
|
+
"{!(package-lock).json,*.y?(a)ml,*.md}": "prettier --write"
|
|
95
97
|
}
|
|
96
98
|
}
|