Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
node-version: ${{ matrix.node }}

- name: Test
run: pnpm exec vitest --coverage
run: pnpm test:all --coverage

- name: Submit coverage
uses: coverallsapp/github-action@master
Expand Down
3 changes: 1 addition & 2 deletions bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import { assertDeprecated } from '../lib/assert.js';
import * as defaults from '../lib/defaults.js';
import { concurrently } from '../lib/index.js';
import { castArray } from '../lib/utils.js';
import { readPackageJson } from './read-package-json.js';
import { version } from '../package.json' with { type: 'json' };

const version = String(readPackageJson().version);
const epilogue = `For documentation and more examples, visit:\nhttps://github.com/open-cli-tools/concurrently/tree/v${version}/docs`;

// Clean-up arguments (yargs expects only the arguments after the program name)
Expand Down
17 changes: 0 additions & 17 deletions bin/read-package-json.ts

This file was deleted.

29 changes: 27 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,19 @@ export default defineConfig(
},
},
eslint.configs.recommended,
tseslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
files: ['**/*.js', '**/*.spec.ts', '**/__fixtures__/**/*', 'tests/**/*'],
extends: [tseslint.configs.disableTypeChecked],
},
{
rules: {
curly: 'error',
Expand All @@ -36,6 +48,19 @@ export default defineConfig(
varsIgnorePattern: '^_',
},
],
'@typescript-eslint/prefer-promise-reject-errors': 'off',
},
},
{
files: ['**/*.ts'],
ignores: ['**/*.spec.ts', '**/__fixtures__/**/*', 'tests/**/*'],
rules: {
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/no-import-type-side-effects': 'error',
'@typescript-eslint/consistent-type-exports': [
'error',
{ fixMixedExportsWithInlineTypeSpecifier: true },
],
},
},
{ files: ['**/__fixtures__/**/*.{js,ts}'], rules: { 'no-console': 'off' } },
Expand All @@ -49,7 +74,7 @@ export default defineConfig(
'simple-import-sort/exports': 'error',
'import/first': 'error',
'import/newline-after-import': 'error',
'import/no-duplicates': 'error',
'import/no-duplicates': ['error', { 'prefer-inline': true }],
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion lib/command-parser/command-parser.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommandInfo } from '../command.js';
import type { CommandInfo } from '../command.js';

/**
* A command parser encapsulates a specific logic for mapping `CommandInfo` objects
Expand Down
4 changes: 2 additions & 2 deletions lib/command-parser/expand-arguments.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { quote } from 'shell-quote';

import { CommandInfo } from '../command.js';
import { CommandParser } from './command-parser.js';
import type { CommandInfo } from '../command.js';
import type { CommandParser } from './command-parser.js';

/**
* Replace placeholders with additional arguments.
Expand Down
4 changes: 2 additions & 2 deletions lib/command-parser/expand-shortcut.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommandInfo } from '../command.js';
import { CommandParser } from './command-parser.js';
import type { CommandInfo } from '../command.js';
import type { CommandParser } from './command-parser.js';

/**
* Expands shortcuts according to the following table:
Expand Down
25 changes: 15 additions & 10 deletions lib/command-parser/expand-wildcard.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import fs from 'node:fs';

import { CommandInfo } from '../command.js';
import type { CommandInfo } from '../command.js';
import JSONC from '../jsonc.js';
import { escapeRegExp } from '../utils.js';
import { CommandParser } from './command-parser.js';
import { escapeRegExp, isObject } from '../utils.js';
import type { CommandParser } from './command-parser.js';

// Matches a negative filter surrounded by '(!' and ')'.
const OMISSION = /\(!([^)]+)\)/;
Expand All @@ -14,7 +14,7 @@ const OMISSION = /\(!([^)]+)\)/;
* configuration files of the current directory.
*/
export class ExpandWildcard implements CommandParser {
static readDeno() {
static readDeno(this: void): unknown {
try {
let json: string = '{}';

Expand All @@ -30,7 +30,7 @@ export class ExpandWildcard implements CommandParser {
}
}

static readPackage() {
static readPackage(this: void): unknown {
try {
const json = fs.readFileSync('package.json', { encoding: 'utf-8' });
return JSON.parse(json);
Expand All @@ -49,18 +49,23 @@ export class ExpandWildcard implements CommandParser {

private relevantScripts(command: string): string[] {
if (!this.packageScripts) {
this.packageScripts = Object.keys(this.readPackage().scripts || {});
const content = this.readPackage();
const scripts =
isObject(content) && isObject(content.scripts) ? Object.keys(content.scripts) : [];

this.packageScripts = scripts;
}

if (command === 'deno task') {
if (!this.denoTasks) {
const content = this.readDeno();
const tasks =
isObject(content) && isObject(content.tasks) ? Object.keys(content.tasks) : [];

// If Deno tries to run a task that doesn't exist,
// it can fall back to running a script with the same name.
// Therefore, the actual list of tasks is the union of the tasks and scripts.
this.denoTasks = [
...Object.keys(this.readDeno().tasks || {}),
...this.packageScripts,
];
this.denoTasks = [...tasks, ...this.packageScripts];
}

return this.denoTasks;
Expand Down
4 changes: 2 additions & 2 deletions lib/command-parser/strip-quotes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommandInfo } from '../command.js';
import { CommandParser } from './command-parser.js';
import type { CommandInfo } from '../command.js';
import type { CommandParser } from './command-parser.js';

/**
* Strips quotes around commands so that they can run on the current shell.
Expand Down
6 changes: 3 additions & 3 deletions lib/command.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Buffer } from 'node:buffer';
import {
import type { Buffer } from 'node:buffer';
import type {
ChildProcess as BaseChildProcess,
MessageOptions,
SendHandle,
SpawnOptions,
} from 'node:child_process';
import process from 'node:process';
import { EventEmitter, Writable } from 'node:stream';
import type { EventEmitter, Writable } from 'node:stream';

import Rx from 'rxjs';

Expand Down
2 changes: 1 addition & 1 deletion lib/completion-listener.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Rx from 'rxjs';
import { delay, filter, map, share, switchMap, take } from 'rxjs/operators';

import { CloseEvent, Command } from './command.js';
import type { CloseEvent, Command } from './command.js';

/**
* Defines which command(s) in a list must exit successfully (with an exit code of `0`):
Expand Down
3 changes: 1 addition & 2 deletions lib/concurrently.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { CpuInfo } from 'node:os';
import os from 'node:os';
import os, { type CpuInfo } from 'node:os';
import { Writable } from 'node:stream';

import { beforeEach, expect, it, Mock, MockedObject, vi } from 'vitest';
Expand Down
21 changes: 11 additions & 10 deletions lib/concurrently.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import assert from 'node:assert';
import os from 'node:os';
import { Writable } from 'node:stream';
import type { Writable } from 'node:stream';

import { takeUntil } from 'rxjs';
import treeKill from 'tree-kill';

import {
CloseEvent,
type CloseEvent,
Command,
CommandIdentifier,
CommandInfo,
KillProcess,
SpawnCommand,
type CommandIdentifier,
type CommandInfo,
type KillProcess,
type SpawnCommand,
} from './command.js';
import { CommandParser } from './command-parser/command-parser.js';
import type { CommandParser } from './command-parser/command-parser.js';
import { ExpandArguments } from './command-parser/expand-arguments.js';
import { ExpandShortcut } from './command-parser/expand-shortcut.js';
import { ExpandWildcard } from './command-parser/expand-wildcard.js';
import { StripQuotes } from './command-parser/strip-quotes.js';
import { CompletionListener, SuccessCondition } from './completion-listener.js';
import { FlowController } from './flow-control/flow-controller.js';
import { Logger } from './logger.js';
import { CompletionListener, type SuccessCondition } from './completion-listener.js';
import type { FlowController } from './flow-control/flow-controller.js';
import type { Logger } from './logger.js';
import { OutputWriter } from './output-writer.js';
import { PrefixColorSelector } from './prefix-color-selector.js';
import { getSpawnOpts, spawn } from './spawn.js';
Expand Down Expand Up @@ -243,6 +243,7 @@ export function concurrently(

const result = new CompletionListener({ successCondition: options.successCondition })
.listen(commands, options.abortSignal)
// eslint-disable-next-line @typescript-eslint/no-misused-promises, @typescript-eslint/await-thenable
.finally(() => Promise.all(handleResult.onFinishCallbacks.map((onFinish) => onFinish())));

return {
Expand Down
2 changes: 1 addition & 1 deletion lib/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// It's read by the flow controllers, the executable, etc.
// Refer to tests for the meaning of the different possible values.

import { SuccessCondition } from './completion-listener.js';
import type { SuccessCondition } from './completion-listener.js';

export const defaultInputTarget = 0;

Expand Down
2 changes: 1 addition & 1 deletion lib/flow-control/flow-controller.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Command } from '../command.js';
import type { Command } from '../command.js';

/**
* Interface for a class that controls and/or watches the behavior of commands.
Expand Down
8 changes: 4 additions & 4 deletions lib/flow-control/input-handler.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Readable } from 'node:stream';
import type { Readable } from 'node:stream';

import Rx from 'rxjs';
import { map } from 'rxjs/operators';

import { Command, CommandIdentifier } from '../command.js';
import type { Command, CommandIdentifier } from '../command.js';
import * as defaults from '../defaults.js';
import { Logger } from '../logger.js';
import { FlowController } from './flow-controller.js';
import type { Logger } from '../logger.js';
import type { FlowController } from './flow-controller.js';

/**
* Sends input from concurrently through to commands.
Expand Down
6 changes: 3 additions & 3 deletions lib/flow-control/kill-on-signal.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import EventEmitter from 'node:events';
import type EventEmitter from 'node:events';

import { map } from 'rxjs/operators';

import { Command } from '../command.js';
import { FlowController } from './flow-controller.js';
import type { Command } from '../command.js';
import type { FlowController } from './flow-controller.js';

const SIGNALS = ['SIGINT', 'SIGTERM', 'SIGHUP'] as const;

Expand Down
4 changes: 2 additions & 2 deletions lib/flow-control/kill-others.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { filter, map } from 'rxjs/operators';

import { Command } from '../command.js';
import { Logger } from '../logger.js';
import type { Logger } from '../logger.js';
import { castArray } from '../utils.js';
import { FlowController } from './flow-controller.js';
import type { FlowController } from './flow-controller.js';

export type ProcessCloseCondition = 'failure' | 'success';

Expand Down
6 changes: 3 additions & 3 deletions lib/flow-control/log-error.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Command } from '../command.js';
import { Logger } from '../logger.js';
import { FlowController } from './flow-controller.js';
import type { Command } from '../command.js';
import type { Logger } from '../logger.js';
import type { FlowController } from './flow-controller.js';

/**
* Logs when commands failed executing, e.g. due to the executable not existing in the system.
Expand Down
6 changes: 3 additions & 3 deletions lib/flow-control/log-exit.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Command } from '../command.js';
import { Logger } from '../logger.js';
import { FlowController } from './flow-controller.js';
import type { Command } from '../command.js';
import type { Logger } from '../logger.js';
import type { FlowController } from './flow-controller.js';

/**
* Logs the exit code/signal of commands.
Expand Down
6 changes: 3 additions & 3 deletions lib/flow-control/log-output.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Command } from '../command.js';
import { Logger } from '../logger.js';
import { FlowController } from './flow-controller.js';
import type { Command } from '../command.js';
import type { Logger } from '../logger.js';
import type { FlowController } from './flow-controller.js';

/**
* Logs the stdout and stderr output of commands.
Expand Down
16 changes: 7 additions & 9 deletions lib/flow-control/log-timings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import assert from 'node:assert';
import Rx from 'rxjs';
import { bufferCount, combineLatestWith, take } from 'rxjs/operators';

import { CloseEvent, Command } from '../command.js';
import type { CloseEvent, Command } from '../command.js';
import { DateFormatter } from '../date-format.js';
import * as defaults from '../defaults.js';
import { Logger } from '../logger.js';
import { FlowController } from './flow-controller.js';
import type { Logger } from '../logger.js';
import type { FlowController } from './flow-controller.js';

type TimingInfo = {
name: string;
Expand All @@ -21,12 +21,10 @@ type TimingInfo = {
* Logs timing information about commands as they start/stop and then a summary when all commands finish.
*/
export class LogTimings implements FlowController {
static mapCloseEventToTimingInfo({
command,
timings,
killed,
exitCode,
}: CloseEvent): TimingInfo {
static mapCloseEventToTimingInfo(
this: void,
{ command, timings, killed, exitCode }: CloseEvent,
): TimingInfo {
const readableDurationMs = (
timings.endDate.getTime() - timings.startDate.getTime()
).toLocaleString();
Expand Down
6 changes: 3 additions & 3 deletions lib/flow-control/logger-padding.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Command } from '../command.js';
import { Logger } from '../logger.js';
import { FlowController } from './flow-controller.js';
import type { Command } from '../command.js';
import type { Logger } from '../logger.js';
import type { FlowController } from './flow-controller.js';

export class LoggerPadding implements FlowController {
private readonly logger: Logger;
Expand Down
6 changes: 3 additions & 3 deletions lib/flow-control/output-error-handler.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Writable } from 'node:stream';
import type { Writable } from 'node:stream';

import { Command } from '../command.js';
import type { Command } from '../command.js';
import { fromSharedEvent } from '../observables.js';
import { FlowController } from './flow-controller.js';
import type { FlowController } from './flow-controller.js';

/**
* Kills processes and aborts further command spawning on output stream error (namely, SIGPIPE).
Expand Down
Loading