Socket
Socket
Sign inDemoInstall

concurrently

Package Overview
Dependencies
Maintainers
2
Versions
60
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

concurrently - npm Package Compare versions

Comparing version 7.5.0 to 7.6.0

5

dist/bin/concurrently.js

@@ -57,4 +57,5 @@ #!/usr/bin/env node

describe: 'How many processes should run at once.\n' +
'New processes only spawn after all restart tries of a process.',
type: 'number',
'New processes only spawn after all restart tries of a process.\n' +
'Exact number or a percent of CPUs available (for example "50%")',
type: 'string',
},

@@ -61,0 +62,0 @@ names: {

6

dist/src/command-parser/expand-arguments.d.ts

@@ -12,6 +12,6 @@ import { CommandInfo } from '../command';

name: string;
env?: Record<string, unknown>;
cwd?: string;
prefixColor?: string;
env?: Record<string, unknown> | undefined;
cwd?: string | undefined;
prefixColor?: string | undefined;
};
}

@@ -15,5 +15,2 @@ "use strict";

class ExpandNpmWildcard {
constructor(readPackage = ExpandNpmWildcard.readPackage) {
this.readPackage = readPackage;
}
static readPackage() {

@@ -28,2 +25,5 @@ try {

}
constructor(readPackage = ExpandNpmWildcard.readPackage) {
this.readPackage = readPackage;
}
parse(commandInfo) {

@@ -45,3 +45,5 @@ const [, npmCmd, cmdName, args] = commandInfo.command.match(/(npm|yarn|pnpm) run (\S+)([^&]*)/) || [];

const wildcardRegex = new RegExp(`^${preWildcard}(.*?)${postWildcard}$`);
const currentName = commandInfo.name || '';
// If 'commandInfo.name' doesn't match 'cmdName', this means a custom name
// has been specified and thus becomes the prefix (as described in the README).
const prefix = commandInfo.name !== cmdName ? commandInfo.name : '';
return this.scripts

@@ -60,5 +62,5 @@ .map((script) => {

command: `${npmCmd} run ${script}${args}`,
// Will use an empty command name if command has no name and the wildcard match is empty,
// e.g. if `npm:watch-*` matches `npm run watch-`.
name: currentName + match[1],
// Will use an empty command name if no prefix has been specified and
// the wildcard match is empty, e.g. if `npm:watch-*` matches `npm run watch-`.
name: prefix + match[1],
};

@@ -65,0 +67,0 @@ }

@@ -10,6 +10,6 @@ import { CommandInfo } from '../command';

name: string;
env?: Record<string, unknown>;
cwd?: string;
prefixColor?: string;
env?: Record<string, unknown> | undefined;
cwd?: string | undefined;
prefixColor?: string | undefined;
};
}

@@ -11,3 +11,3 @@ /// <reference types="node" />

*/
export declare type CommandIdentifier = string | number;
export type CommandIdentifier = string | number;
export interface CommandInfo {

@@ -62,11 +62,11 @@ /**

*/
export declare type ChildProcess = EventEmitter & Pick<BaseChildProcess, 'pid' | 'stdin' | 'stdout' | 'stderr'>;
export type ChildProcess = EventEmitter & Pick<BaseChildProcess, 'pid' | 'stdin' | 'stdout' | 'stderr'>;
/**
* Interface for a function that must kill the process with `pid`, optionally sending `signal` to it.
*/
export declare type KillProcess = (pid: number, signal?: string) => void;
export type KillProcess = (pid: number, signal?: string) => void;
/**
* Interface for a function that spawns a command and returns its child process instance.
*/
export declare type SpawnCommand = (command: string, options: SpawnOptions) => ChildProcess;
export type SpawnCommand = (command: string, options: SpawnOptions) => ChildProcess;
export declare class Command implements CommandInfo {

@@ -82,3 +82,3 @@ private readonly killProcess;

/** @inheritdoc */
readonly prefixColor: string;
readonly prefixColor?: string;
/** @inheritdoc */

@@ -98,2 +98,3 @@ readonly env: Record<string, unknown>;

exited: boolean;
/** @deprecated */
get killable(): boolean;

@@ -111,2 +112,11 @@ constructor({ index, name, command, prefixColor, env, cwd }: CommandInfo & {

kill(code?: string): void;
/**
* Detects whether a command can be killed.
*
* Also works as a type guard on the input `command`.
*/
static canKill(command: Command): command is Command & {
pid: number;
process: ChildProcess;
};
}

@@ -29,2 +29,6 @@ "use strict";

class Command {
/** @deprecated */
get killable() {
return Command.canKill(this);
}
constructor({ index, name, command, prefixColor, env, cwd }, spawnOpts, spawn, killProcess) {

@@ -42,3 +46,3 @@ this.close = new Rx.Subject();

this.prefixColor = prefixColor;
this.env = env;
this.env = env || {};
this.cwd = cwd;

@@ -49,5 +53,2 @@ this.killProcess = killProcess;

}
get killable() {
return !!this.process;
}
/**

@@ -78,3 +79,3 @@ * Starts this command, piping output, error and close events onto the corresponding observables.

index: this.index,
exitCode: exitCode === null ? signal : exitCode,
exitCode: exitCode !== null && exitCode !== void 0 ? exitCode : String(signal),
killed: this.killed,

@@ -90,3 +91,3 @@ timings: {

child.stderr && pipeTo(Rx.fromEvent(child.stderr, 'data'), this.stderr);
this.stdin = child.stdin;
this.stdin = child.stdin || undefined;
}

@@ -97,3 +98,3 @@ /**

kill(code) {
if (this.killable) {
if (Command.canKill(this)) {
this.killed = true;

@@ -103,2 +104,10 @@ this.killProcess(this.pid, code);

}
/**
* Detects whether a command can be killed.
*
* Also works as a type guard on the input `command`.
*/
static canKill(command) {
return !!command.pid && !!command.process;
}
}

@@ -105,0 +114,0 @@ exports.Command = Command;

@@ -12,3 +12,3 @@ import * as Rx from 'rxjs';

*/
export declare type SuccessCondition = 'first' | 'last' | 'all' | `command-${string | number}` | `!command-${string | number}`;
export type SuccessCondition = 'first' | 'last' | 'all' | `command-${string | number}` | `!command-${string | number}`;
/**

@@ -40,2 +40,3 @@ * Provides logic to determine whether lists of commands ran successfully.

listen(commands: Command[]): Promise<CloseEvent[]>;
private emitWithScheduler;
}

@@ -70,6 +70,9 @@ "use strict";

return Rx.lastValueFrom(Rx.merge(...closeStreams).pipe((0, operators_1.bufferCount)(closeStreams.length), (0, operators_1.switchMap)((exitInfos) => this.isSuccess(exitInfos)
? Rx.of(exitInfos, this.scheduler)
: Rx.throwError(exitInfos, this.scheduler)), (0, operators_1.take)(1)));
? this.emitWithScheduler(Rx.of(exitInfos))
: this.emitWithScheduler(Rx.throwError(exitInfos))), (0, operators_1.take)(1)));
}
emitWithScheduler(input) {
return this.scheduler ? input.pipe(Rx.observeOn(this.scheduler)) : input;
}
}
exports.CompletionListener = CompletionListener;

@@ -12,4 +12,6 @@ /// <reference types="node" />

*/
export declare type ConcurrentlyCommandInput = string | Partial<CommandInfo>;
export declare type ConcurrentlyResult = {
export type ConcurrentlyCommandInput = string | ({
command: string;
} & Partial<CommandInfo>);
export type ConcurrentlyResult = {
/**

@@ -27,3 +29,3 @@ * All commands created and ran by concurrently.

};
export declare type ConcurrentlyOptions = {
export type ConcurrentlyOptions = {
logger?: Logger;

@@ -44,2 +46,3 @@ /**

* Maximum number of commands to run at once.
* Exact number or a percent of CPUs available (for example "50%").
*

@@ -49,3 +52,3 @@ * If undefined, then all processes will start in parallel.

*/
maxProcesses?: number;
maxProcesses?: number | string;
/**

@@ -52,0 +55,0 @@ * Whether commands should be spawned in raw mode.

@@ -9,2 +9,3 @@ "use strict";

const lodash_1 = __importDefault(require("lodash"));
const os_1 = require("os");
const spawn_command_1 = __importDefault(require("spawn-command"));

@@ -73,3 +74,3 @@ const tree_kill_1 = __importDefault(require("tree-kill"));

outputStream: options.outputStream,
group: options.group,
group: !!options.group,
commands,

@@ -80,3 +81,5 @@ });

const commandsLeft = commands.slice();
const maxProcesses = Math.max(1, Number(options.maxProcesses) || commandsLeft.length);
const maxProcesses = Math.max(1, (typeof options.maxProcesses === 'string' && options.maxProcesses.endsWith('%')
? Math.round(((0, os_1.cpus)().length * Number(options.maxProcesses.slice(0, -1))) / 100)
: Number(options.maxProcesses)) || commandsLeft.length);
for (let i = 0; i < maxProcesses; i++) {

@@ -98,9 +101,5 @@ maybeRunMore(commandsLeft);

if (typeof command === 'string') {
return {
command,
name: '',
env: {},
cwd: '',
};
return mapToCommandInfo({ command });
}
assert_1.default.ok(command.command, '[concurrently] command cannot be empty');
return {

@@ -107,0 +106,0 @@ command: command.command,

@@ -18,6 +18,6 @@ /// <reference types="node" />

private readonly defaultInputTarget;
private readonly inputStream;
private readonly inputStream?;
private readonly pauseInputStreamOnFinish;
constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger, }: {
inputStream: Readable;
inputStream?: Readable;
logger: Logger;

@@ -24,0 +24,0 @@ defaultInputTarget?: CommandIdentifier;

@@ -47,7 +47,8 @@ "use strict";

handle(commands) {
if (!this.inputStream) {
const { inputStream } = this;
if (!inputStream) {
return { commands };
}
Rx.fromEvent(this.inputStream, 'data')
.pipe((0, operators_1.map)((data) => data.toString()))
Rx.fromEvent(inputStream, 'data')
.pipe((0, operators_1.map)((data) => String(data)))
.subscribe((data) => {

@@ -71,3 +72,3 @@ const dataParts = data.split(/:(.+)/);

// https://github.com/kimmobrunfeldt/concurrently/issues/252
this.inputStream.pause();
inputStream.pause();
}

@@ -74,0 +75,0 @@ },

import { Command } from '../command';
import { Logger } from '../logger';
import { FlowController } from './flow-controller';
export declare type ProcessCloseCondition = 'failure' | 'success';
export type ProcessCloseCondition = 'failure' | 'success';
/**
* Sends a SIGTERM signal to all commands when one of the exits with a matching condition.
* Sends a SIGTERM signal to all commands when one of the commands exits with a matching condition.
*/

@@ -8,0 +8,0 @@ export declare class KillOthers implements FlowController {

@@ -9,4 +9,5 @@ "use strict";

const operators_1 = require("rxjs/operators");
const command_1 = require("../command");
/**
* Sends a SIGTERM signal to all commands when one of the exits with a matching condition.
* Sends a SIGTERM signal to all commands when one of the commands exits with a matching condition.
*/

@@ -25,3 +26,3 @@ class KillOthers {

closeStates.forEach((closeState) => closeState.subscribe(() => {
const killableCommands = commands.filter((command) => command.killable);
const killableCommands = commands.filter((command) => command_1.Command.canKill(command));
if (killableCommands.length) {

@@ -28,0 +29,0 @@ this.logger.logGlobalEvent('Sending SIGTERM to other processes..');

@@ -30,2 +30,3 @@ "use strict";

exports.LogTimings = void 0;
const assert = __importStar(require("assert"));
const format_1 = __importDefault(require("date-fns/format"));

@@ -40,6 +41,2 @@ const lodash_1 = __importDefault(require("lodash"));

class LogTimings {
constructor({ logger, timestampFormat = defaults.timestampFormat, }) {
this.logger = logger;
this.timestampFormat = timestampFormat;
}
static mapCloseEventToTimingInfo({ command, timings, killed, exitCode, }) {

@@ -55,3 +52,8 @@ const readableDurationMs = (timings.endDate.getTime() - timings.startDate.getTime()).toLocaleString();

}
constructor({ logger, timestampFormat = defaults.timestampFormat, }) {
this.logger = logger;
this.timestampFormat = timestampFormat;
}
printExitInfoTimingTable(exitInfos) {
assert.ok(this.logger);
const exitInfoTable = (0, lodash_1.default)(exitInfos)

@@ -67,3 +69,4 @@ .sortBy(({ timings }) => timings.durationSeconds)

handle(commands) {
if (!this.logger) {
const { logger } = this;
if (!logger) {
return { commands };

@@ -76,3 +79,3 @@ }

const formattedStartDate = (0, format_1.default)(startDate, this.timestampFormat);
this.logger.logCommandEvent(`${command.command} started at ${formattedStartDate}`, command);
logger.logCommandEvent(`${command.command} started at ${formattedStartDate}`, command);
}

@@ -82,3 +85,3 @@ else {

const formattedEndDate = (0, format_1.default)(endDate, this.timestampFormat);
this.logger.logCommandEvent(`${command.command} stopped at ${formattedEndDate} after ${durationMs.toLocaleString()}ms`, command);
logger.logCommandEvent(`${command.command} stopped at ${formattedEndDate} after ${durationMs.toLocaleString()}ms`, command);
}

@@ -85,0 +88,0 @@ });

@@ -14,7 +14,7 @@ /// <reference types="node" />

*/
colorSupport?: Pick<supportsColor.supportsColor.Level, 'level'> | false;
colorSupport?: false | Pick<supportsColor.supportsColor.Level, "level"> | undefined;
/**
* The NodeJS process.
*/
process?: Pick<NodeJS.Process, 'cwd' | 'platform' | 'env'>;
process?: Pick<NodeJS.Process, "cwd" | "env" | "platform"> | undefined;
/**

@@ -24,3 +24,3 @@ * A custom working directory to spawn processes in.

*/
cwd?: string;
cwd?: string | undefined;
/**

@@ -30,7 +30,7 @@ * Whether to customize the options for spawning processes in raw mode.

*/
raw?: boolean;
raw?: boolean | undefined;
/**
* Map of custom environment variables to include in the spawn options.
*/
env?: Record<string, unknown>;
env?: Record<string, unknown> | undefined;
}) => SpawnOptions;

@@ -15,3 +15,3 @@ /// <reference types="node" />

import { Logger } from './logger';
export declare type ConcurrentlyOptions = BaseConcurrentlyOptions & {
export type ConcurrentlyOptions = BaseConcurrentlyOptions & {
/**

@@ -18,0 +18,0 @@ * Which command(s) should have their output hidden.

@@ -49,3 +49,3 @@ "use strict";

defaultInputTarget: options.defaultInputTarget,
inputStream: options.inputStream || (options.handleInput && process.stdin),
inputStream: options.inputStream || (options.handleInput ? process.stdin : undefined),
pauseInputStreamOnFinish: options.pauseInputStreamOnFinish,

@@ -61,6 +61,6 @@ }),

logger,
conditions: options.killOthers,
conditions: options.killOthers || [],
}),
new log_timings_1.LogTimings({
logger: options.timings ? logger : null,
logger: options.timings ? logger : undefined,
timestampFormat: options.timestampFormat,

@@ -67,0 +67,0 @@ }),

@@ -89,2 +89,3 @@ "use strict";

colorText(command, text) {
var _a;
let color;

@@ -96,3 +97,3 @@ if (command.prefixColor && command.prefixColor.startsWith('#')) {

const defaultColor = lodash_1.default.get(chalk_1.default, defaults.prefixColors, chalk_1.default.reset);
color = lodash_1.default.get(chalk_1.default, command.prefixColor, defaultColor);
color = lodash_1.default.get(chalk_1.default, (_a = command.prefixColor) !== null && _a !== void 0 ? _a : '', defaultColor);
}

@@ -99,0 +100,0 @@ return color(text);

@@ -28,3 +28,3 @@ "use strict";

}
currentColor = nextAutoColors.shift();
currentColor = String(nextAutoColors.shift());
}

@@ -31,0 +31,0 @@ yield currentColor; // Auto color

{
"name": "concurrently",
"version": "7.5.0",
"version": "7.6.0",
"description": "Run commands concurrently",

@@ -28,5 +28,5 @@ "main": "index.js",

"clean": "tsc --build --clean",
"format": "prettier --ignore-path .gitignore --check '**/{!(package-lock).json,*.y?(a)ml,*.md}'",
"format": "prettier --check '**/*.{json,y?(a)ml,md}'",
"format:fix": "npm run format -- --write",
"lint": "eslint . --ext mjs,js,ts --ignore-path .gitignore",
"lint": "eslint --ignore-path .gitignore --ext mjs,js,ts .",
"lint:fix": "npm run lint -- --fix",

@@ -90,3 +90,3 @@ "prepublishOnly": "npm run build",

"string-argv": "^0.3.1",
"typescript": "~4.8.3"
"typescript": "~4.9.3"
},

@@ -106,4 +106,4 @@ "files": [

"*.m?{js,ts}": "eslint --fix",
"{!(package-lock).json,*.{y?(a)ml,md}}": "prettier --write"
"*.{json,y?(a)ml,md}": "prettier --write"
}
}

@@ -6,3 +6,3 @@ # concurrently

[![Weekly Downloads on NPM](https://img.shields.io/npm/dw/concurrently?label=Downloads&logo=npm)](https://www.npmjs.com/package/concurrently)
[![CI Status](https://img.shields.io/github/workflow/status/open-cli-tools/concurrently/CI?label=CI&logo=github)](https://github.com/open-cli-tools/concurrently/actions/workflows/ci.yml)
[![CI Status](https://img.shields.io/github/workflow/status/open-cli-tools/concurrently/Test?label=CI&logo=github)](https://github.com/open-cli-tools/concurrently/actions/workflows/test.yml)
[![Coverage Status](https://img.shields.io/coveralls/github/open-cli-tools/concurrently/main?label=Coverage&logo=coveralls)](https://coveralls.io/github/open-cli-tools/concurrently?branch=main)

@@ -19,3 +19,3 @@

- [Why](#why)
- [Install](#install)
- [Installation](#installation)
- [Usage](#usage)

@@ -46,16 +46,13 @@ - [API](#api)

## Install
## Installation
The tool is written in Node.js, but you can use it to run **any** commands.
**concurrently** can be installed in the global scope (if you'd like to have it available and use it on the whole system) or locally for a specific package (for example if you'd like to use it in the `scripts` section of your package):
```bash
npm install -g concurrently
```
| | npm | Yarn | pnpm |
| ----------- | ----------------------- | ------------------------------ | -------------------------- |
| **Global** | `npm i -g concurrently` | `yarn global add concurrently` | `pnpm add -g concurrently` |
| **Local**\* | `npm i concurrently -D` | `yarn add concurrently -D` | `pnpm add -D concurrently` |
or if you are using it from npm scripts:
<sub>\* It's recommended to add **concurrently** as `devDependencies` as it's usually used for developing purposes. Please change this flag if this doesn't apply in your case.</sub>
```bash
npm install concurrently --save
```
## Usage

@@ -66,2 +63,4 @@

The tool is written in Node.js, but you can use it to run **any** commands.
Remember to surround separate commands with quotes:

@@ -153,4 +152,5 @@

-m, --max-processes How many processes should run at once.
Exact number or a percent of CPUs available (for example "50%").
New processes only spawn after all restart tries
of a process. [number]
of a process. [string]
-n, --names List of custom names to be used in prefix

@@ -157,0 +157,0 @@ template.

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc