concurrently 9.2.0 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -15
- package/dist/bin/{concurrently.js → index.js} +23 -52
- package/dist/bin/index.spec.d.ts +1 -0
- package/dist/bin/index.spec.js +368 -0
- package/dist/bin/normalize-cli-command.d.ts +1 -0
- package/dist/bin/normalize-cli-command.js +15 -0
- package/dist/bin/normalize-cli-command.spec.d.ts +1 -0
- package/dist/bin/normalize-cli-command.spec.js +36 -0
- package/dist/bin/read-package-json.d.ts +4 -0
- package/dist/bin/read-package-json.js +17 -0
- package/dist/lib/__fixtures__/create-mock-instance.d.ts +2 -0
- package/dist/lib/__fixtures__/create-mock-instance.js +5 -0
- package/dist/lib/__fixtures__/fake-command.d.ts +6 -0
- package/dist/lib/__fixtures__/fake-command.js +37 -0
- package/dist/lib/assert.d.ts +10 -0
- package/dist/lib/assert.js +24 -0
- package/dist/lib/assert.spec.d.ts +1 -0
- package/dist/lib/assert.spec.js +41 -0
- package/dist/{src → lib}/command-parser/expand-arguments.d.ts +7 -7
- package/dist/lib/command-parser/expand-arguments.js +36 -0
- package/dist/lib/command-parser/expand-arguments.spec.d.ts +1 -0
- package/dist/lib/command-parser/expand-arguments.spec.js +57 -0
- package/dist/{src → lib}/command-parser/expand-shortcut.d.ts +2 -2
- package/dist/{src → lib}/command-parser/expand-shortcut.js +1 -5
- package/dist/lib/command-parser/expand-shortcut.spec.d.ts +1 -0
- package/dist/lib/command-parser/expand-shortcut.spec.js +36 -0
- package/dist/{src → lib}/command-parser/expand-wildcard.d.ts +2 -2
- package/dist/{src → lib}/command-parser/expand-wildcard.js +25 -31
- package/dist/lib/command-parser/expand-wildcard.spec.d.ts +1 -0
- package/dist/lib/command-parser/expand-wildcard.spec.js +288 -0
- package/dist/{src → lib}/command.d.ts +7 -10
- package/dist/{src → lib}/command.js +13 -32
- package/dist/lib/command.spec.d.ts +1 -0
- package/dist/lib/command.spec.js +369 -0
- package/dist/{src → lib}/completion-listener.d.ts +2 -3
- package/dist/{src → lib}/completion-listener.js +9 -36
- package/dist/lib/completion-listener.spec.d.ts +1 -0
- package/dist/lib/completion-listener.spec.js +229 -0
- package/dist/{src → lib}/concurrently.d.ts +10 -12
- package/dist/{src → lib}/concurrently.js +34 -47
- package/dist/lib/concurrently.spec.d.ts +1 -0
- package/dist/lib/concurrently.spec.js +320 -0
- package/dist/{src → lib}/date-format.d.ts +2 -2
- package/dist/{src → lib}/date-format.js +101 -77
- package/dist/lib/date-format.spec.d.ts +1 -0
- package/dist/lib/date-format.spec.js +480 -0
- package/dist/{src → lib}/defaults.d.ts +2 -6
- package/dist/{src → lib}/defaults.js +16 -23
- package/dist/{src → lib}/flow-control/input-handler.d.ts +4 -5
- package/dist/{src → lib}/flow-control/input-handler.js +8 -34
- package/dist/lib/flow-control/input-handler.spec.d.ts +1 -0
- package/dist/lib/flow-control/input-handler.spec.js +116 -0
- package/dist/{src → lib}/flow-control/kill-on-signal.d.ts +3 -5
- package/dist/{src → lib}/flow-control/kill-on-signal.js +3 -7
- package/dist/lib/flow-control/kill-on-signal.spec.d.ts +1 -0
- package/dist/lib/flow-control/kill-on-signal.spec.js +63 -0
- package/dist/{src → lib}/flow-control/kill-others.d.ts +3 -4
- package/dist/{src → lib}/flow-control/kill-others.js +8 -15
- package/dist/lib/flow-control/kill-others.spec.d.ts +1 -0
- package/dist/lib/flow-control/kill-others.spec.js +98 -0
- package/dist/{src → lib}/flow-control/log-error.d.ts +3 -3
- package/dist/{src → lib}/flow-control/log-error.js +1 -5
- package/dist/lib/flow-control/log-error.spec.d.ts +1 -0
- package/dist/lib/flow-control/log-error.spec.js +33 -0
- package/dist/{src → lib}/flow-control/log-exit.d.ts +3 -3
- package/dist/{src → lib}/flow-control/log-exit.js +1 -5
- package/dist/lib/flow-control/log-exit.spec.d.ts +1 -0
- package/dist/lib/flow-control/log-exit.spec.js +24 -0
- package/dist/{src → lib}/flow-control/log-output.d.ts +3 -3
- package/dist/{src → lib}/flow-control/log-output.js +1 -5
- package/dist/lib/flow-control/log-output.spec.d.ts +1 -0
- package/dist/lib/flow-control/log-output.spec.js +33 -0
- package/dist/{src → lib}/flow-control/log-timings.d.ts +3 -3
- package/dist/{src → lib}/flow-control/log-timings.js +11 -44
- package/dist/lib/flow-control/log-timings.spec.d.ts +1 -0
- package/dist/lib/flow-control/log-timings.spec.js +89 -0
- package/dist/{src → lib}/flow-control/logger-padding.d.ts +3 -3
- package/dist/{src → lib}/flow-control/logger-padding.js +7 -7
- package/dist/lib/flow-control/logger-padding.spec.d.ts +1 -0
- package/dist/lib/flow-control/logger-padding.spec.js +60 -0
- package/dist/{src → lib}/flow-control/output-error-handler.d.ts +4 -6
- package/dist/{src → lib}/flow-control/output-error-handler.js +3 -7
- package/dist/lib/flow-control/output-error-handler.spec.d.ts +1 -0
- package/dist/lib/flow-control/output-error-handler.spec.js +41 -0
- package/dist/{src → lib}/flow-control/restart-process.d.ts +4 -4
- package/dist/{src → lib}/flow-control/restart-process.js +10 -37
- package/dist/lib/flow-control/restart-process.spec.d.ts +1 -0
- package/dist/lib/flow-control/restart-process.spec.js +127 -0
- package/dist/{src → lib}/flow-control/teardown.d.ts +4 -5
- package/dist/{src → lib}/flow-control/teardown.js +6 -33
- package/dist/lib/flow-control/teardown.spec.d.ts +1 -0
- package/dist/lib/flow-control/teardown.spec.js +93 -0
- package/dist/{src → lib}/index.d.ts +21 -20
- package/dist/lib/index.js +98 -0
- package/dist/lib/jsonc.d.ts +8 -0
- package/dist/{src → lib}/jsonc.js +3 -8
- package/dist/lib/jsonc.spec.d.ts +1 -0
- package/dist/lib/jsonc.spec.js +73 -0
- package/dist/{src → lib}/logger.d.ts +3 -2
- package/dist/{src → lib}/logger.js +112 -53
- package/dist/lib/logger.spec.d.ts +1 -0
- package/dist/lib/logger.spec.js +507 -0
- package/dist/{src → lib}/observables.d.ts +1 -2
- package/dist/{src → lib}/observables.js +3 -7
- package/dist/lib/observables.spec.d.ts +1 -0
- package/dist/lib/observables.spec.js +29 -0
- package/dist/{src → lib}/output-writer.d.ts +3 -4
- package/dist/{src → lib}/output-writer.js +4 -31
- package/dist/lib/output-writer.spec.d.ts +1 -0
- package/dist/lib/output-writer.spec.js +96 -0
- package/dist/lib/prefix-color-selector.d.ts +21 -0
- package/dist/{src → lib}/prefix-color-selector.js +14 -31
- package/dist/lib/prefix-color-selector.spec.d.ts +1 -0
- package/dist/lib/prefix-color-selector.spec.js +159 -0
- package/dist/{src → lib}/spawn.d.ts +19 -16
- package/dist/lib/spawn.js +105 -0
- package/dist/lib/spawn.spec.d.ts +1 -0
- package/dist/lib/spawn.spec.js +100 -0
- package/dist/lib/utils.d.ts +25 -0
- package/dist/lib/utils.js +52 -0
- package/dist/lib/utils.spec.d.ts +1 -0
- package/dist/lib/utils.spec.js +58 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/README.md +6 -0
- package/docs/cli/passthrough-arguments.md +8 -8
- package/docs/cli/prefixing.md +44 -4
- package/docs/cli/shortcuts.md +2 -2
- package/docs/shell-resolution.md +48 -0
- package/package.json +64 -85
- package/dist/bin/read-package.d.ts +0 -6
- package/dist/bin/read-package.js +0 -47
- package/dist/src/assert.d.ts +0 -5
- package/dist/src/assert.js +0 -16
- package/dist/src/command-parser/command-parser.d.ts +0 -19
- package/dist/src/command-parser/command-parser.js +0 -2
- package/dist/src/command-parser/expand-arguments.js +0 -39
- package/dist/src/command-parser/strip-quotes.d.ts +0 -16
- package/dist/src/command-parser/strip-quotes.js +0 -17
- package/dist/src/flow-control/flow-controller.d.ts +0 -13
- package/dist/src/flow-control/flow-controller.js +0 -2
- package/dist/src/index.js +0 -99
- package/dist/src/jsonc.d.ts +0 -8
- package/dist/src/prefix-color-selector.d.ts +0 -11
- package/dist/src/spawn.js +0 -49
- package/index.d.mts +0 -7
- package/index.d.ts +0 -11
- package/index.js +0 -14
- package/index.mjs +0 -10
- /package/dist/bin/{concurrently.d.ts → index.d.ts} +0 -0
|
@@ -1,38 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.Teardown = void 0;
|
|
27
|
-
const Rx = __importStar(require("rxjs"));
|
|
28
|
-
const spawn_1 = require("../spawn");
|
|
29
|
-
class Teardown {
|
|
1
|
+
import Rx from 'rxjs';
|
|
2
|
+
import { getSpawnOpts } from '../spawn.js';
|
|
3
|
+
export class Teardown {
|
|
30
4
|
logger;
|
|
31
5
|
spawn;
|
|
32
6
|
teardown;
|
|
33
7
|
constructor({ logger, spawn, commands, }) {
|
|
34
8
|
this.logger = logger;
|
|
35
|
-
this.spawn = spawn
|
|
9
|
+
this.spawn = spawn;
|
|
36
10
|
this.teardown = commands;
|
|
37
11
|
}
|
|
38
12
|
handle(commands) {
|
|
@@ -43,7 +17,7 @@ class Teardown {
|
|
|
43
17
|
}
|
|
44
18
|
for (const command of teardown) {
|
|
45
19
|
logger.logGlobalEvent(`Running teardown command "${command}"`);
|
|
46
|
-
const child = spawn(command,
|
|
20
|
+
const child = spawn(command, getSpawnOpts({ stdio: 'raw' }));
|
|
47
21
|
const error = Rx.fromEvent(child, 'error');
|
|
48
22
|
const close = Rx.fromEvent(child, 'close');
|
|
49
23
|
try {
|
|
@@ -62,11 +36,10 @@ class Teardown {
|
|
|
62
36
|
const errorText = String(error instanceof Error ? error.stack || error : error);
|
|
63
37
|
logger.logGlobalEvent(`Teardown command "${command}" errored:`);
|
|
64
38
|
logger.logGlobalEvent(errorText);
|
|
65
|
-
return Promise.reject();
|
|
39
|
+
return Promise.reject(error);
|
|
66
40
|
}
|
|
67
41
|
}
|
|
68
42
|
};
|
|
69
43
|
return { commands, onFinish };
|
|
70
44
|
}
|
|
71
45
|
}
|
|
72
|
-
exports.Teardown = Teardown;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { createMockInstance } from '../__fixtures__/create-mock-instance.js';
|
|
3
|
+
import { createFakeProcess, FakeCommand } from '../__fixtures__/fake-command.js';
|
|
4
|
+
import { Logger } from '../logger.js';
|
|
5
|
+
import { getSpawnOpts } from '../spawn.js';
|
|
6
|
+
import { Teardown } from './teardown.js';
|
|
7
|
+
let spawn;
|
|
8
|
+
const logger = createMockInstance(Logger);
|
|
9
|
+
const commands = [new FakeCommand()];
|
|
10
|
+
const teardown = 'cowsay bye';
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
spawn = vi.fn(() => createFakeProcess(1));
|
|
13
|
+
});
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
const create = (teardown) => new Teardown({
|
|
18
|
+
spawn,
|
|
19
|
+
logger,
|
|
20
|
+
commands: teardown,
|
|
21
|
+
});
|
|
22
|
+
it('returns commands unchanged', () => {
|
|
23
|
+
const { commands: actual } = create([]).handle(commands);
|
|
24
|
+
expect(actual).toBe(commands);
|
|
25
|
+
});
|
|
26
|
+
describe('onFinish callback', () => {
|
|
27
|
+
it('does not spawn nothing if there are no teardown commands', () => {
|
|
28
|
+
create([]).handle(commands).onFinish();
|
|
29
|
+
expect(spawn).not.toHaveBeenCalled();
|
|
30
|
+
});
|
|
31
|
+
it('runs teardown command', () => {
|
|
32
|
+
create([teardown]).handle(commands).onFinish();
|
|
33
|
+
expect(spawn).toHaveBeenCalledWith(teardown, getSpawnOpts({ stdio: 'raw' }));
|
|
34
|
+
});
|
|
35
|
+
it('waits for teardown command to close', async () => {
|
|
36
|
+
const child = createFakeProcess(1);
|
|
37
|
+
spawn.mockReturnValue(child);
|
|
38
|
+
const result = create([teardown]).handle(commands).onFinish();
|
|
39
|
+
child.emit('close', 1, null);
|
|
40
|
+
await expect(result).resolves.toBeUndefined();
|
|
41
|
+
});
|
|
42
|
+
it('rejects if teardown command errors (string)', async () => {
|
|
43
|
+
const child = createFakeProcess(1);
|
|
44
|
+
spawn.mockReturnValue(child);
|
|
45
|
+
const result = create([teardown]).handle(commands).onFinish();
|
|
46
|
+
const error = 'fail';
|
|
47
|
+
child.emit('error', error);
|
|
48
|
+
await expect(result).rejects.toBe(error);
|
|
49
|
+
expect(logger.logGlobalEvent).toHaveBeenLastCalledWith('fail');
|
|
50
|
+
});
|
|
51
|
+
it('rejects if teardown command errors (error)', async () => {
|
|
52
|
+
const child = createFakeProcess(1);
|
|
53
|
+
spawn.mockReturnValue(child);
|
|
54
|
+
const result = create([teardown]).handle(commands).onFinish();
|
|
55
|
+
const error = new Error('fail');
|
|
56
|
+
child.emit('error', error);
|
|
57
|
+
await expect(result).rejects.toBe(error);
|
|
58
|
+
expect(logger.logGlobalEvent).toHaveBeenLastCalledWith(expect.stringMatching(/Error: fail/));
|
|
59
|
+
});
|
|
60
|
+
it('rejects if teardown command errors (error, no stack)', async () => {
|
|
61
|
+
const child = createFakeProcess(1);
|
|
62
|
+
spawn.mockReturnValue(child);
|
|
63
|
+
const result = create([teardown]).handle(commands).onFinish();
|
|
64
|
+
const error = new Error('fail');
|
|
65
|
+
delete error.stack;
|
|
66
|
+
child.emit('error', error);
|
|
67
|
+
await expect(result).rejects.toBe(error);
|
|
68
|
+
expect(logger.logGlobalEvent).toHaveBeenLastCalledWith('Error: fail');
|
|
69
|
+
});
|
|
70
|
+
it('runs multiple teardown commands in sequence', async () => {
|
|
71
|
+
const child1 = createFakeProcess(1);
|
|
72
|
+
const child2 = createFakeProcess(2);
|
|
73
|
+
spawn.mockReturnValueOnce(child1).mockReturnValueOnce(child2);
|
|
74
|
+
const result = create(['foo', 'bar']).handle(commands).onFinish();
|
|
75
|
+
expect(spawn).toHaveBeenCalledTimes(1);
|
|
76
|
+
expect(spawn).toHaveBeenLastCalledWith('foo', getSpawnOpts({ stdio: 'raw' }));
|
|
77
|
+
child1.emit('close', 1, null);
|
|
78
|
+
await new Promise((resolve) => setTimeout(resolve));
|
|
79
|
+
expect(spawn).toHaveBeenCalledTimes(2);
|
|
80
|
+
expect(spawn).toHaveBeenLastCalledWith('bar', getSpawnOpts({ stdio: 'raw' }));
|
|
81
|
+
child2.emit('close', 0, null);
|
|
82
|
+
await expect(result).resolves.toBeUndefined();
|
|
83
|
+
});
|
|
84
|
+
it('stops running teardown commands on SIGINT', async () => {
|
|
85
|
+
const child = createFakeProcess(1);
|
|
86
|
+
spawn.mockReturnValue(child);
|
|
87
|
+
const result = create(['foo', 'bar']).handle(commands).onFinish();
|
|
88
|
+
child.emit('close', null, 'SIGINT');
|
|
89
|
+
await result;
|
|
90
|
+
expect(spawn).toHaveBeenCalledTimes(1);
|
|
91
|
+
expect(spawn).toHaveBeenLastCalledWith('foo', expect.anything());
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
export type ConcurrentlyOptions = Omit<BaseConcurrentlyOptions, 'abortSignal' | 'hide'> & {
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
import { CloseEvent, Command, CommandIdentifier, TimerEvent } from './command.js';
|
|
3
|
+
import { concurrently as createConcurrently, ConcurrentlyCommandInput, ConcurrentlyOptions as BaseConcurrentlyOptions, ConcurrentlyResult } from './concurrently.js';
|
|
4
|
+
import type { FlowController } from './flow-control/flow-controller.js';
|
|
5
|
+
import { InputHandler } from './flow-control/input-handler.js';
|
|
6
|
+
import { KillOnSignal } from './flow-control/kill-on-signal.js';
|
|
7
|
+
import { KillOthers, ProcessCloseCondition } from './flow-control/kill-others.js';
|
|
8
|
+
import { LogError } from './flow-control/log-error.js';
|
|
9
|
+
import { LogExit } from './flow-control/log-exit.js';
|
|
10
|
+
import { LogOutput } from './flow-control/log-output.js';
|
|
11
|
+
import { LogTimings } from './flow-control/log-timings.js';
|
|
12
|
+
import { RestartDelay, RestartProcess } from './flow-control/restart-process.js';
|
|
13
|
+
import { Logger } from './logger.js';
|
|
14
|
+
export type ConcurrentlyOptions = Omit<BaseConcurrentlyOptions, 'abortSignal' | 'hide' | 'spawn'> & {
|
|
16
15
|
/**
|
|
17
16
|
* Which command(s) should have their output hidden.
|
|
18
17
|
*/
|
|
@@ -55,11 +54,6 @@ export type ConcurrentlyOptions = Omit<BaseConcurrentlyOptions, 'abortSignal' |
|
|
|
55
54
|
* @see RestartProcess
|
|
56
55
|
*/
|
|
57
56
|
restartTries?: number;
|
|
58
|
-
/**
|
|
59
|
-
* @deprecated Use `killOthersOn` instead.
|
|
60
|
-
* @see KillOthers
|
|
61
|
-
*/
|
|
62
|
-
killOthers?: ProcessCloseCondition | ProcessCloseCondition[];
|
|
63
57
|
/**
|
|
64
58
|
* Once the first command exits with one of these statuses, kill other commands.
|
|
65
59
|
* @see KillOthers
|
|
@@ -89,8 +83,15 @@ export type ConcurrentlyOptions = Omit<BaseConcurrentlyOptions, 'abortSignal' |
|
|
|
89
83
|
* If not defined, no argument replacing will happen.
|
|
90
84
|
*/
|
|
91
85
|
additionalArguments?: string[];
|
|
86
|
+
/**
|
|
87
|
+
* Shell executable used to run command strings.
|
|
88
|
+
* When unset, uses the `npm_config_script_shell` env variable if present. Otherwise, falls back
|
|
89
|
+
* to `cmd.exe` on Windows, and `/bin/sh` elsewhere.
|
|
90
|
+
*/
|
|
91
|
+
shell?: string;
|
|
92
92
|
};
|
|
93
93
|
export declare function concurrently(commands: ConcurrentlyCommandInput[], options?: Partial<ConcurrentlyOptions>): ConcurrentlyResult;
|
|
94
|
+
export default concurrently;
|
|
94
95
|
export { ConcurrentlyCommandInput, ConcurrentlyResult, createConcurrently, Logger };
|
|
95
96
|
export { CloseEvent, Command, CommandIdentifier, TimerEvent };
|
|
96
97
|
export { FlowController, InputHandler, KillOnSignal, KillOthers, LogError, LogExit, LogOutput, LogTimings, RestartProcess, };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import { assertNotRuntime } from './assert.js';
|
|
3
|
+
import { Command } from './command.js';
|
|
4
|
+
import { concurrently as createConcurrently, } from './concurrently.js';
|
|
5
|
+
import { InputHandler } from './flow-control/input-handler.js';
|
|
6
|
+
import { KillOnSignal } from './flow-control/kill-on-signal.js';
|
|
7
|
+
import { KillOthers } from './flow-control/kill-others.js';
|
|
8
|
+
import { LogError } from './flow-control/log-error.js';
|
|
9
|
+
import { LogExit } from './flow-control/log-exit.js';
|
|
10
|
+
import { LogOutput } from './flow-control/log-output.js';
|
|
11
|
+
import { LogTimings } from './flow-control/log-timings.js';
|
|
12
|
+
import { LoggerPadding } from './flow-control/logger-padding.js';
|
|
13
|
+
import { OutputErrorHandler } from './flow-control/output-error-handler.js';
|
|
14
|
+
import { RestartProcess } from './flow-control/restart-process.js';
|
|
15
|
+
import { Teardown } from './flow-control/teardown.js';
|
|
16
|
+
import { Logger } from './logger.js';
|
|
17
|
+
import { createSpawn } from './spawn.js';
|
|
18
|
+
import { castArray } from './utils.js';
|
|
19
|
+
export function concurrently(commands, options = {}) {
|
|
20
|
+
assertNotRuntime(
|
|
21
|
+
// When run via /snap/bin/node, process.execPath maps to the actual snap path, but it also sets
|
|
22
|
+
// several SNAP_* env variables. If the snap is run directly via e.g. /snap/node/current/bin/node,
|
|
23
|
+
// the issues don't happen and no env variables are set.
|
|
24
|
+
!String(process.env.SNAP).startsWith('/snap'), 'Snap', 'Snap confinement can interfere with spawning child processes. See issue #584');
|
|
25
|
+
// To avoid empty strings from hiding the output of commands that don't have a name,
|
|
26
|
+
// keep in the list of commands to hide only strings with some length.
|
|
27
|
+
// This might happen through the CLI when no `--hide` argument is specified, for example.
|
|
28
|
+
const hide = castArray(options.hide).filter((id) => id || id === 0);
|
|
29
|
+
const logger = options.logger ||
|
|
30
|
+
new Logger({
|
|
31
|
+
hide,
|
|
32
|
+
prefixFormat: options.prefix,
|
|
33
|
+
commandLength: options.prefixLength,
|
|
34
|
+
raw: options.raw,
|
|
35
|
+
timestampFormat: options.timestampFormat,
|
|
36
|
+
});
|
|
37
|
+
if (options.prefixColors === false) {
|
|
38
|
+
logger.toggleColors(false);
|
|
39
|
+
}
|
|
40
|
+
const abortController = new AbortController();
|
|
41
|
+
const outputStream = options.outputStream || process.stdout;
|
|
42
|
+
const spawn = createSpawn(options.shell);
|
|
43
|
+
return createConcurrently(commands, {
|
|
44
|
+
maxProcesses: options.maxProcesses,
|
|
45
|
+
raw: options.raw,
|
|
46
|
+
successCondition: options.successCondition,
|
|
47
|
+
cwd: options.cwd,
|
|
48
|
+
spawn,
|
|
49
|
+
hide,
|
|
50
|
+
logger,
|
|
51
|
+
outputStream,
|
|
52
|
+
group: options.group,
|
|
53
|
+
abortSignal: abortController.signal,
|
|
54
|
+
controllers: [
|
|
55
|
+
// LoggerPadding needs to run before any other controllers that might output something
|
|
56
|
+
...(options.padPrefix ? [new LoggerPadding({ logger })] : []),
|
|
57
|
+
new LogError({ logger }),
|
|
58
|
+
new LogOutput({ logger }),
|
|
59
|
+
new LogExit({ logger }),
|
|
60
|
+
new InputHandler({
|
|
61
|
+
logger,
|
|
62
|
+
defaultInputTarget: options.defaultInputTarget,
|
|
63
|
+
inputStream: options.inputStream || (options.handleInput ? process.stdin : undefined),
|
|
64
|
+
pauseInputStreamOnFinish: options.pauseInputStreamOnFinish,
|
|
65
|
+
}),
|
|
66
|
+
new KillOnSignal({ process, abortController }),
|
|
67
|
+
new RestartProcess({
|
|
68
|
+
logger,
|
|
69
|
+
delay: options.restartDelay,
|
|
70
|
+
tries: options.restartTries,
|
|
71
|
+
}),
|
|
72
|
+
new KillOthers({
|
|
73
|
+
logger,
|
|
74
|
+
conditions: options.killOthersOn || [],
|
|
75
|
+
timeoutMs: options.killTimeout,
|
|
76
|
+
killSignal: options.killSignal,
|
|
77
|
+
abortController,
|
|
78
|
+
}),
|
|
79
|
+
new OutputErrorHandler({ abortController, outputStream }),
|
|
80
|
+
new LogTimings({
|
|
81
|
+
logger: options.timings ? logger : undefined,
|
|
82
|
+
timestampFormat: options.timestampFormat,
|
|
83
|
+
}),
|
|
84
|
+
new Teardown({ logger, spawn, commands: options.teardown || [] }),
|
|
85
|
+
],
|
|
86
|
+
prefixColors: options.prefixColors || [],
|
|
87
|
+
additionalArguments: options.additionalArguments,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
// Export all flow controllers, types, and the main concurrently function,
|
|
91
|
+
// so that 3rd-parties can use them however they want
|
|
92
|
+
// Main
|
|
93
|
+
export default concurrently;
|
|
94
|
+
export { createConcurrently, Logger };
|
|
95
|
+
// Command specific
|
|
96
|
+
export { Command };
|
|
97
|
+
// Flow controllers
|
|
98
|
+
export { InputHandler, KillOnSignal, KillOthers, LogError, LogExit, LogOutput, LogTimings, RestartProcess, };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare const JSONC: {
|
|
2
|
+
parse: (text: string) => any;
|
|
3
|
+
stringify: {
|
|
4
|
+
(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
|
|
5
|
+
(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
export default JSONC;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/*
|
|
3
2
|
ORIGINAL https://www.npmjs.com/package/tiny-jsonc
|
|
4
3
|
BY Fabio Spampinato
|
|
@@ -6,11 +5,8 @@ MIT license
|
|
|
6
5
|
|
|
7
6
|
Copied due to the dependency not being compatible with CommonJS
|
|
8
7
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const stringOrCommentRe = /("(?:\\?[^])*?")|(\/\/.*)|(\/\*[^]*?\*\/)/g;
|
|
12
|
-
const stringOrTrailingCommaRe = /("(?:\\?[^])*?")|(,\s*)(?=]|})/g;
|
|
13
|
-
/* MAIN */
|
|
8
|
+
const stringOrCommentRe = /("(?:\\?[\s\S])*?")|(\/\/.*)|(\/\*[\s\S]*?\*\/)/g;
|
|
9
|
+
const stringOrTrailingCommaRe = /("(?:\\?[\s\S])*?")|(,\s*)(?=\]|\})/g;
|
|
14
10
|
const JSONC = {
|
|
15
11
|
parse: (text) => {
|
|
16
12
|
text = String(text); // To be extra safe
|
|
@@ -25,5 +21,4 @@ const JSONC = {
|
|
|
25
21
|
},
|
|
26
22
|
stringify: JSON.stringify,
|
|
27
23
|
};
|
|
28
|
-
|
|
29
|
-
exports.default = JSONC;
|
|
24
|
+
export default JSONC;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/*
|
|
2
|
+
ORIGINAL https://www.npmjs.com/package/tiny-jsonc
|
|
3
|
+
BY Fabio Spampinato
|
|
4
|
+
MIT license
|
|
5
|
+
|
|
6
|
+
Copied due to the dependency not being compatible with CommonJS
|
|
7
|
+
*/
|
|
8
|
+
import { expect, it } from 'vitest';
|
|
9
|
+
import JSONC from './jsonc.js';
|
|
10
|
+
const fixtures = {
|
|
11
|
+
errors: {
|
|
12
|
+
comment: '// asd',
|
|
13
|
+
empty: '',
|
|
14
|
+
prefix: 'invalid 123',
|
|
15
|
+
suffix: '123 invalid',
|
|
16
|
+
multiLineString: `
|
|
17
|
+
{
|
|
18
|
+
"foo": "/*
|
|
19
|
+
*/"
|
|
20
|
+
}
|
|
21
|
+
`,
|
|
22
|
+
},
|
|
23
|
+
parse: {
|
|
24
|
+
input: `
|
|
25
|
+
// Example // Yes
|
|
26
|
+
/* EXAMPLE */ /* YES */
|
|
27
|
+
{
|
|
28
|
+
"one": {},
|
|
29
|
+
"two" :{},
|
|
30
|
+
"three": {
|
|
31
|
+
"one": null,
|
|
32
|
+
"two" :true,
|
|
33
|
+
"three": false,
|
|
34
|
+
"four": "asd\\n\\u0022\\"",
|
|
35
|
+
"five": -123.123e10,
|
|
36
|
+
"six": [ 123, true, [],],
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
// Example // Yes
|
|
40
|
+
/* EXAMPLE */ /* YES */
|
|
41
|
+
`,
|
|
42
|
+
output: {
|
|
43
|
+
one: {},
|
|
44
|
+
two: {},
|
|
45
|
+
three: {
|
|
46
|
+
one: null,
|
|
47
|
+
two: true,
|
|
48
|
+
three: false,
|
|
49
|
+
four: 'asd\n\u0022"',
|
|
50
|
+
five: -123.123e10,
|
|
51
|
+
six: [123, true, []],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
it('supports strings with comments and trailing commas', () => {
|
|
57
|
+
const { input, output } = fixtures.parse;
|
|
58
|
+
expect(JSONC.parse(input)).toEqual(output);
|
|
59
|
+
});
|
|
60
|
+
it('throws on invalid input', () => {
|
|
61
|
+
const { prefix, suffix } = fixtures.errors;
|
|
62
|
+
expect(() => JSONC.parse(prefix)).toThrow(SyntaxError);
|
|
63
|
+
expect(() => JSONC.parse(suffix)).toThrow(SyntaxError);
|
|
64
|
+
});
|
|
65
|
+
it('throws on insufficient input', () => {
|
|
66
|
+
const { comment, empty } = fixtures.errors;
|
|
67
|
+
expect(() => JSONC.parse(comment)).toThrow(SyntaxError);
|
|
68
|
+
expect(() => JSONC.parse(empty)).toThrow(SyntaxError);
|
|
69
|
+
});
|
|
70
|
+
it('throws on multi-line strings', () => {
|
|
71
|
+
const { multiLineString } = fixtures.errors;
|
|
72
|
+
expect(() => JSONC.parse(multiLineString)).toThrow(SyntaxError);
|
|
73
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Command, CommandIdentifier } from './command';
|
|
1
|
+
import Rx from 'rxjs';
|
|
2
|
+
import { Command, CommandIdentifier } from './command.js';
|
|
3
|
+
export declare const COLOR_MARKER_RE: RegExp;
|
|
3
4
|
export declare class Logger {
|
|
4
5
|
private readonly hide;
|
|
5
6
|
private readonly raw;
|
|
@@ -1,40 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
import chalk, { Chalk } from 'chalk';
|
|
2
|
+
import Rx from 'rxjs';
|
|
3
|
+
import { DateFormatter } from './date-format.js';
|
|
4
|
+
import * as defaults from './defaults.js';
|
|
5
|
+
import { escapeRegExp, splitOutsideParens } from './utils.js';
|
|
6
|
+
const defaultChalk = chalk;
|
|
7
|
+
const noColorChalk = new Chalk({ level: 0 });
|
|
8
|
+
const HEX_PATTERN = /^#[0-9A-Fa-f]{3,6}$/;
|
|
9
|
+
const COLOR_OPEN = '{color}';
|
|
10
|
+
const COLOR_CLOSE = '{/color}';
|
|
11
|
+
export const COLOR_MARKER_RE = /\{\/?color\}/g;
|
|
12
|
+
/**
|
|
13
|
+
* Applies a single color segment to a chalk instance.
|
|
14
|
+
* Handles: function calls (hex, bgHex, rgb, bgRgb, ansi256, bgAnsi256, etc.),
|
|
15
|
+
* shorthands (#HEX, bg#HEX), and named colors/modifiers.
|
|
16
|
+
*/
|
|
17
|
+
function applySegment(color, segment) {
|
|
18
|
+
// Function call: name(args) - handles chalk color functions
|
|
19
|
+
const fnMatch = segment.match(/^(\w+)\((.+)\)$/);
|
|
20
|
+
if (fnMatch) {
|
|
21
|
+
const [, fnName, argsStr] = fnMatch;
|
|
22
|
+
const args = argsStr.split(',').map((a) => {
|
|
23
|
+
const t = a.trim();
|
|
24
|
+
return /^\d+$/.test(t) ? parseInt(t, 10) : t;
|
|
25
|
+
});
|
|
26
|
+
// Explicit function calls for known chalk color functions
|
|
27
|
+
switch (fnName) {
|
|
28
|
+
case 'rgb':
|
|
29
|
+
return color.rgb(args[0], args[1], args[2]);
|
|
30
|
+
case 'bgRgb':
|
|
31
|
+
return color.bgRgb(args[0], args[1], args[2]);
|
|
32
|
+
case 'hex':
|
|
33
|
+
if (!HEX_PATTERN.test(args[0]))
|
|
34
|
+
return undefined;
|
|
35
|
+
return color.hex(args[0]);
|
|
36
|
+
case 'bgHex':
|
|
37
|
+
if (!HEX_PATTERN.test(args[0]))
|
|
38
|
+
return undefined;
|
|
39
|
+
return color.bgHex(args[0]);
|
|
40
|
+
case 'ansi256':
|
|
41
|
+
return color.ansi256(args[0]);
|
|
42
|
+
case 'bgAnsi256':
|
|
43
|
+
return color.bgAnsi256(args[0]);
|
|
44
|
+
default:
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Shorthands
|
|
49
|
+
if (segment.startsWith('bg#'))
|
|
50
|
+
return color.bgHex(segment.slice(2));
|
|
51
|
+
if (segment.startsWith('#'))
|
|
52
|
+
return color.hex(segment);
|
|
53
|
+
// Property: black, bold, dim, etc.
|
|
54
|
+
return color[segment] ?? undefined;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Applies a color string to chalk, supporting chained colors and modifiers.
|
|
58
|
+
* Returns undefined if any segment is invalid (triggers fallback to default).
|
|
59
|
+
*/
|
|
60
|
+
function applyColor(chalkInstance, colorString) {
|
|
61
|
+
const segments = splitOutsideParens(colorString, '.');
|
|
62
|
+
if (segments.length === 0)
|
|
63
|
+
return undefined;
|
|
64
|
+
let color = chalkInstance;
|
|
65
|
+
for (const segment of segments) {
|
|
66
|
+
const next = applySegment(color, segment);
|
|
67
|
+
if (!next)
|
|
68
|
+
return undefined;
|
|
69
|
+
color = next;
|
|
70
|
+
}
|
|
71
|
+
return color;
|
|
72
|
+
}
|
|
73
|
+
export class Logger {
|
|
38
74
|
hide;
|
|
39
75
|
raw;
|
|
40
76
|
prefixFormat;
|
|
@@ -61,7 +97,7 @@ class Logger {
|
|
|
61
97
|
this.raw = raw;
|
|
62
98
|
this.prefixFormat = prefixFormat;
|
|
63
99
|
this.commandLength = commandLength || defaults.prefixLength;
|
|
64
|
-
this.dateFormatter = new
|
|
100
|
+
this.dateFormatter = new DateFormatter(timestampFormat || defaults.timestampFormat);
|
|
65
101
|
}
|
|
66
102
|
/**
|
|
67
103
|
* Toggles colors on/off globally.
|
|
@@ -101,8 +137,8 @@ class Logger {
|
|
|
101
137
|
if (Object.keys(prefixes).includes(prefix)) {
|
|
102
138
|
return { type: 'default', value: prefixes[prefix] };
|
|
103
139
|
}
|
|
104
|
-
const value =
|
|
105
|
-
const keyRegex = new RegExp(
|
|
140
|
+
const value = Object.entries(prefixes).reduce((prev, [key, val]) => {
|
|
141
|
+
const keyRegex = new RegExp(escapeRegExp(`{${key}}`), 'g');
|
|
106
142
|
return prev.replace(keyRegex, String(val));
|
|
107
143
|
}, prefix);
|
|
108
144
|
return { type: 'template', value };
|
|
@@ -112,23 +148,47 @@ class Logger {
|
|
|
112
148
|
if (!content) {
|
|
113
149
|
return '';
|
|
114
150
|
}
|
|
151
|
+
const visibleLength = content.value.replace(COLOR_MARKER_RE, '').length;
|
|
152
|
+
const padding = ' '.repeat(Math.max(0, this.prefixLength - visibleLength));
|
|
115
153
|
return content.type === 'template'
|
|
116
|
-
? content.value
|
|
117
|
-
: `[${content.value
|
|
154
|
+
? content.value + padding
|
|
155
|
+
: `[${content.value}${padding}]`;
|
|
118
156
|
}
|
|
119
157
|
setPrefixLength(length) {
|
|
120
158
|
this.prefixLength = length;
|
|
121
159
|
}
|
|
122
160
|
colorText(command, text) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
161
|
+
const prefixColor = command.prefixColor ?? '';
|
|
162
|
+
const defaultColor = applyColor(this.chalk, defaults.prefixColors) ?? this.chalk.reset;
|
|
163
|
+
const color = applyColor(this.chalk, prefixColor) ?? defaultColor;
|
|
164
|
+
// Segment the text around `{color}` / `{/color}` markers and only apply `color`
|
|
165
|
+
// inside opened regions. If either marker is missing, it's implicitly added to
|
|
166
|
+
// the start or end respectively — so a marker-free input stays fully colored,
|
|
167
|
+
// preserving backward compatibility.
|
|
168
|
+
let normalized = text;
|
|
169
|
+
if (!normalized.includes(COLOR_OPEN))
|
|
170
|
+
normalized = COLOR_OPEN + normalized;
|
|
171
|
+
if (!normalized.includes(COLOR_CLOSE))
|
|
172
|
+
normalized = normalized + COLOR_CLOSE;
|
|
173
|
+
let output = '';
|
|
174
|
+
let rest = normalized;
|
|
175
|
+
let inColorRegion = false;
|
|
176
|
+
while (rest.length > 0) {
|
|
177
|
+
const marker = inColorRegion ? COLOR_CLOSE : COLOR_OPEN;
|
|
178
|
+
const idx = rest.indexOf(marker);
|
|
179
|
+
if (idx === -1) {
|
|
180
|
+
// Tail after the last closing marker: normalization guarantees a
|
|
181
|
+
// `{/color}` exists, so once opened a region always finds its close —
|
|
182
|
+
// reaching here implies `inColorRegion` is false and the tail is plain.
|
|
183
|
+
output += rest;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
const segment = rest.slice(0, idx);
|
|
187
|
+
output += inColorRegion ? color(segment) : segment;
|
|
188
|
+
rest = rest.slice(idx + marker.length);
|
|
189
|
+
inColorRegion = !inColorRegion;
|
|
130
190
|
}
|
|
131
|
-
return
|
|
191
|
+
return output;
|
|
132
192
|
}
|
|
133
193
|
/**
|
|
134
194
|
* Logs an event for a command (e.g. start, stop).
|
|
@@ -146,7 +206,7 @@ class Logger {
|
|
|
146
206
|
if (this.lastWrite?.command === command && this.lastWrite.char !== '\n') {
|
|
147
207
|
prefix = '\n';
|
|
148
208
|
}
|
|
149
|
-
this.logCommandText(prefix
|
|
209
|
+
this.logCommandText(`${prefix}${this.chalk.reset(text)}\n`, command);
|
|
150
210
|
}
|
|
151
211
|
logCommandText(text, command) {
|
|
152
212
|
if (this.hide.includes(String(command.index)) || this.hide.includes(command.name)) {
|
|
@@ -164,7 +224,7 @@ class Logger {
|
|
|
164
224
|
if (this.raw) {
|
|
165
225
|
return;
|
|
166
226
|
}
|
|
167
|
-
this.log(this.chalk.reset('-->')
|
|
227
|
+
this.log(`${this.chalk.reset('-->')} `, `${this.chalk.reset(text)}\n`);
|
|
168
228
|
}
|
|
169
229
|
/**
|
|
170
230
|
* Logs a table from an input object array, like `console.table`.
|
|
@@ -238,4 +298,3 @@ class Logger {
|
|
|
238
298
|
this.output.next({ command, text });
|
|
239
299
|
}
|
|
240
300
|
}
|
|
241
|
-
exports.Logger = Logger;
|