diff options
| author | Pinapelz <yukais@pinapelz.com> | 2025-06-28 17:26:46 -0700 |
|---|---|---|
| committer | Pinapelz <yukais@pinapelz.com> | 2025-06-28 17:43:56 -0700 |
| commit | e4fa1e69e7ebfb627c7198fd1a9881e9327ec4d4 (patch) | |
| tree | 06284a538a6008eca75051399e47db4e5d50301c /node_modules/concurrently/dist | |
initial commit: scaffolding
Diffstat (limited to 'node_modules/concurrently/dist')
50 files changed, 2509 insertions, 0 deletions
diff --git a/node_modules/concurrently/dist/bin/concurrently.d.ts b/node_modules/concurrently/dist/bin/concurrently.d.ts new file mode 100644 index 0000000..b798801 --- /dev/null +++ b/node_modules/concurrently/dist/bin/concurrently.d.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env node +export {}; diff --git a/node_modules/concurrently/dist/bin/concurrently.js b/node_modules/concurrently/dist/bin/concurrently.js new file mode 100755 index 0000000..341410a --- /dev/null +++ b/node_modules/concurrently/dist/bin/concurrently.js @@ -0,0 +1,232 @@ +#!/usr/bin/env node +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const yargs_1 = __importDefault(require("yargs")); +const helpers_1 = require("yargs/helpers"); +const defaults = __importStar(require("../src/defaults")); +const index_1 = __importDefault(require("../src/index")); +const epilogue_1 = require("./epilogue"); +// Clean-up arguments (yargs expects only the arguments after the program name) +const cleanArgs = (0, helpers_1.hideBin)(process.argv); +// Find argument separator (double dash) +const argsSepIdx = cleanArgs.findIndex((arg) => arg === '--'); +// Arguments before separator +const argsBeforeSep = argsSepIdx >= 0 ? cleanArgs.slice(0, argsSepIdx) : cleanArgs; +// Arguments after separator +const argsAfterSep = argsSepIdx >= 0 ? cleanArgs.slice(argsSepIdx + 1) : []; +const args = (0, yargs_1.default)(argsBeforeSep) + .usage('$0 [options] <command ...>') + .help('h') + .alias('h', 'help') + .version() + .alias('version', 'v') + .alias('version', 'V') + // TODO: Add some tests for this. + .env('CONCURRENTLY') + .options({ + // General + 'max-processes': { + alias: 'm', + describe: 'How many processes should run at once.\n' + + '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', + }, + names: { + alias: 'n', + describe: 'List of custom names to be used in prefix template.\n' + + 'Example names: "main,browser,server"', + type: 'string', + }, + 'name-separator': { + describe: 'The character to split <names> on. Example usage:\n' + + '-n "styles|scripts|server" --name-separator "|"', + default: defaults.nameSeparator, + }, + success: { + alias: 's', + describe: 'Which command(s) must exit with code 0 in order for concurrently exit with ' + + 'code 0 too. Options are:\n' + + '- "first" for the first command to exit;\n' + + '- "last" for the last command to exit;\n' + + '- "all" for all commands;\n' + + // Note: not a typo. Multiple commands can have the same name. + '- "command-{name}"/"command-{index}" for the commands with that name or index;\n' + + '- "!command-{name}"/"!command-{index}" for all commands but the ones with that ' + + 'name or index.\n', + default: defaults.success, + }, + raw: { + alias: 'r', + describe: 'Output only raw output of processes, disables prettifying ' + + 'and concurrently coloring.', + type: 'boolean', + }, + // This one is provided for free. Chalk reads this itself and removes colors. + // https://www.npmjs.com/package/chalk#chalksupportscolor + 'no-color': { + describe: 'Disables colors from logging', + type: 'boolean', + }, + hide: { + describe: 'Comma-separated list of processes to hide the output.\n' + + 'The processes can be identified by their name or index.', + default: defaults.hide, + type: 'string', + }, + group: { + alias: 'g', + describe: 'Order the output as if the commands were run sequentially.', + type: 'boolean', + }, + timings: { + describe: 'Show timing information for all processes.', + type: 'boolean', + default: defaults.timings, + }, + 'passthrough-arguments': { + alias: 'P', + describe: 'Passthrough additional arguments to commands (accessible via placeholders) ' + + 'instead of treating them as commands.', + type: 'boolean', + default: defaults.passthroughArguments, + }, + // Kill others + 'kill-others': { + alias: 'k', + describe: 'Kill other processes if one exits or dies.', + type: 'boolean', + }, + 'kill-others-on-fail': { + describe: 'Kill other processes if one exits with non zero status code.', + type: 'boolean', + }, + 'kill-signal': { + alias: 'ks', + describe: 'Signal to send to other processes if one exits or dies. (SIGTERM/SIGKILL, defaults to SIGTERM)', + type: 'string', + default: defaults.killSignal, + }, + // Prefix + prefix: { + alias: 'p', + describe: 'Prefix used in logging for each process.\n' + + 'Possible values: index, pid, time, command, name, none, or a template. ' + + 'Example template: "{time}-{pid}"', + defaultDescription: 'index or name (when --names is set)', + type: 'string', + }, + 'prefix-colors': { + alias: 'c', + describe: 'Comma-separated list of chalk colors to use on prefixes. ' + + 'If there are more commands than colors, the last color will be repeated.\n' + + '- Available modifiers: reset, bold, dim, italic, underline, inverse, hidden, strikethrough\n' + + '- Available colors: black, red, green, yellow, blue, magenta, cyan, white, gray, \n' + + 'any hex values for colors (e.g. #23de43) or auto for an automatically picked color\n' + + '- Available background colors: bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite\n' + + 'See https://www.npmjs.com/package/chalk for more information.', + default: defaults.prefixColors, + type: 'string', + }, + 'prefix-length': { + alias: 'l', + describe: 'Limit how many characters of the command is displayed in prefix. ' + + 'The option can be used to shorten the prefix when it is set to "command"', + default: defaults.prefixLength, + type: 'number', + }, + 'timestamp-format': { + alias: 't', + describe: 'Specify the timestamp in moment/date-fns format.', + default: defaults.timestampFormat, + type: 'string', + }, + // Restarting + 'restart-tries': { + describe: 'How many times a process that died should restart.\n' + + 'Negative numbers will make the process restart forever.', + default: defaults.restartTries, + type: 'number', + }, + 'restart-after': { + describe: 'Delay time to respawn the process, in milliseconds.', + default: defaults.restartDelay, + type: 'number', + }, + // Input + 'handle-input': { + alias: 'i', + describe: 'Whether input should be forwarded to the child processes. ' + + 'See examples for more information.', + type: 'boolean', + }, + 'default-input-target': { + default: defaults.defaultInputTarget, + describe: 'Identifier for child process to which input on stdin ' + + 'should be sent if not specified at start of input.\n' + + 'Can be either the index or the name of the process.', + }, +}) + .group(['m', 'n', 'name-separator', 's', 'r', 'no-color', 'hide', 'g', 'timings', 'P'], 'General') + .group(['p', 'c', 'l', 't'], 'Prefix styling') + .group(['i', 'default-input-target'], 'Input handling') + .group(['k', 'kill-others-on-fail', 'kill-signal'], 'Killing other processes') + .group(['restart-tries', 'restart-after'], 'Restarting') + .epilogue(epilogue_1.epilogue) + .parseSync(); +// Get names of commands by the specified separator +const names = (args.names || '').split(args.nameSeparator); +// If "passthrough-arguments" is disabled, treat additional arguments as commands +const commands = args.passthroughArguments ? args._ : [...args._, ...argsAfterSep]; +(0, index_1.default)(commands.map((command, index) => ({ + command: String(command), + name: names[index], +})), { + handleInput: args.handleInput, + defaultInputTarget: args.defaultInputTarget, + killOthers: args.killOthers + ? ['success', 'failure'] + : args.killOthersOnFail + ? ['failure'] + : [], + killSignal: args.killSignal, + maxProcesses: args.maxProcesses, + raw: args.raw, + hide: args.hide.split(','), + group: args.group, + prefix: args.prefix, + prefixColors: args.prefixColors.split(','), + prefixLength: args.prefixLength, + restartDelay: args.restartAfter, + restartTries: args.restartTries, + successCondition: args.success, + timestampFormat: args.timestampFormat, + timings: args.timings, + additionalArguments: args.passthroughArguments ? argsAfterSep : undefined, +}).result.then(() => process.exit(0), () => process.exit(1)); diff --git a/node_modules/concurrently/dist/bin/epilogue.d.ts b/node_modules/concurrently/dist/bin/epilogue.d.ts new file mode 100644 index 0000000..0b58cf9 --- /dev/null +++ b/node_modules/concurrently/dist/bin/epilogue.d.ts @@ -0,0 +1 @@ +export declare const epilogue: string; diff --git a/node_modules/concurrently/dist/bin/epilogue.js b/node_modules/concurrently/dist/bin/epilogue.js new file mode 100644 index 0000000..3f2b7e3 --- /dev/null +++ b/node_modules/concurrently/dist/bin/epilogue.js @@ -0,0 +1,90 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.epilogue = void 0; +// Add new examples here. +// Always start with `$ $0` so that it a) symbolizes a command line; and b) $0 gets replaced by the binary name uniformly. +const examples = [ + { + description: 'Output nothing more than stdout+stderr of child processes', + example: '$ $0 --raw "npm run watch-less" "npm run watch-js"', + }, + { + description: 'Normal output but without colors e.g. when logging to file', + example: '$ $0 --no-color "grunt watch" "http-server" > log', + }, + { + description: 'Custom prefix', + example: '$ $0 --prefix "{time}-{pid}" "npm run watch" "http-server"', + }, + { + description: 'Custom names and colored prefixes', + example: '$ $0 --names "HTTP,WATCH" -c "bgBlue.bold,bgMagenta.bold" "http-server" "npm run watch"', + }, + { + description: 'Auto varying colored prefixes', + example: '$ $0 -c "auto" "npm run watch" "http-server"', + }, + { + description: 'Mixing auto and manual colored prefixes', + example: '$ $0 -c "red,auto" "npm run watch" "http-server" "echo hello"', + }, + { + description: 'Configuring via environment variables with CONCURRENTLY_ prefix', + example: '$ CONCURRENTLY_RAW=true CONCURRENTLY_KILL_OTHERS=true $0 "echo hello" "echo world"', + }, + { + description: 'Send input to default', + example: [ + '$ $0 --handle-input "nodemon" "npm run watch-js"', + 'rs # Sends rs command to nodemon process', + ].join('\n'), + }, + { + description: 'Send input to specific child identified by index', + example: ['$ $0 --handle-input "npm run watch-js" nodemon', '1:rs'].join('\n'), + }, + { + description: 'Send input to specific child identified by name', + example: ['$ $0 --handle-input -n js,srv "npm run watch-js" nodemon', 'srv:rs'].join('\n'), + }, + { + description: 'Shortened NPM run commands', + example: '$ $0 npm:watch-node npm:watch-js npm:watch-css', + }, + { + description: 'Shortened NPM run command with wildcard (make sure to wrap it in quotes!)', + example: '$ $0 "npm:watch-*"', + }, + { + description: 'Exclude patterns so that between "lint:js" and "lint:fix:js", only "lint:js" is ran', + example: '$ $0 "npm:*(!fix)"', + }, + { + description: "Passthrough some additional arguments via '{<number>}' placeholder", + example: '$ $0 -P "echo {1}" -- foo', + }, + { + description: "Passthrough all additional arguments via '{@}' placeholder", + example: '$ $0 -P "npm:dev-* -- {@}" -- --watch --noEmit', + }, + { + description: "Passthrough all additional arguments combined via '{*}' placeholder", + example: '$ $0 -P "npm:dev-* -- {*}" -- --watch --noEmit', + }, +]; +const examplesString = examples + .map(({ example, description }) => [ + ` - ${description}`, + example + .split('\n') + .map((line) => ` ${line}`) + .join('\n'), +].join('\n\n')) + .join('\n\n'); +exports.epilogue = ` +Examples: + +${examplesString} + +For more details, visit https://github.com/open-cli-tools/concurrently +`; diff --git a/node_modules/concurrently/dist/src/command-parser/command-parser.d.ts b/node_modules/concurrently/dist/src/command-parser/command-parser.d.ts new file mode 100644 index 0000000..37ab795 --- /dev/null +++ b/node_modules/concurrently/dist/src/command-parser/command-parser.d.ts @@ -0,0 +1,19 @@ +import { CommandInfo } from '../command'; +/** + * A command parser encapsulates a specific logic for mapping `CommandInfo` objects + * into another `CommandInfo`. + * + * A prime example is turning an abstract `npm:foo` into `npm run foo`, but it could also turn + * the prefix color of a command brighter, or maybe even prefixing each command with `time(1)`. + */ +export interface CommandParser { + /** + * Parses `commandInfo` and returns one or more `CommandInfo`s. + * + * Returning multiple `CommandInfo` is used when there are multiple possibilities of commands to + * run given the original input. + * An example of this is when the command contains a wildcard and it must be expanded into all + * viable options so that the consumer can decide which ones to run. + */ + parse(commandInfo: CommandInfo): CommandInfo | CommandInfo[]; +} diff --git a/node_modules/concurrently/dist/src/command-parser/command-parser.js b/node_modules/concurrently/dist/src/command-parser/command-parser.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/node_modules/concurrently/dist/src/command-parser/command-parser.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/concurrently/dist/src/command-parser/expand-arguments.d.ts b/node_modules/concurrently/dist/src/command-parser/expand-arguments.d.ts new file mode 100644 index 0000000..c88e731 --- /dev/null +++ b/node_modules/concurrently/dist/src/command-parser/expand-arguments.d.ts @@ -0,0 +1,17 @@ +import { CommandInfo } from '../command'; +import { CommandParser } from './command-parser'; +/** + * Replace placeholders with additional arguments. + */ +export declare class ExpandArguments implements CommandParser { + private readonly additionalArguments; + constructor(additionalArguments: string[]); + parse(commandInfo: CommandInfo): { + command: string; + name: string; + env?: Record<string, unknown> | undefined; + cwd?: string | undefined; + prefixColor?: string | undefined; + raw?: boolean | undefined; + }; +} diff --git a/node_modules/concurrently/dist/src/command-parser/expand-arguments.js b/node_modules/concurrently/dist/src/command-parser/expand-arguments.js new file mode 100644 index 0000000..42c087c --- /dev/null +++ b/node_modules/concurrently/dist/src/command-parser/expand-arguments.js @@ -0,0 +1,38 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ExpandArguments = void 0; +const shell_quote_1 = require("shell-quote"); +/** + * Replace placeholders with additional arguments. + */ +class ExpandArguments { + constructor(additionalArguments) { + this.additionalArguments = additionalArguments; + } + parse(commandInfo) { + const command = commandInfo.command.replace(/\\?\{([@*]|[1-9][0-9]*)\}/g, (match, placeholderTarget) => { + // Don't replace the placeholder if it is escaped by a backslash. + if (match.startsWith('\\')) { + return match.slice(1); + } + // Replace numeric placeholder if value exists in additional arguments. + if (!isNaN(placeholderTarget) && + placeholderTarget <= this.additionalArguments.length) { + return (0, shell_quote_1.quote)([this.additionalArguments[placeholderTarget - 1]]); + } + // Replace all arguments placeholder. + if (placeholderTarget === '@') { + return (0, shell_quote_1.quote)(this.additionalArguments); + } + // Replace combined arguments placeholder. + if (placeholderTarget === '*') { + return (0, shell_quote_1.quote)([this.additionalArguments.join(' ')]); + } + // Replace placeholder with empty string + // if value doesn't exist in additional arguments. + return ''; + }); + return { ...commandInfo, command }; + } +} +exports.ExpandArguments = ExpandArguments; diff --git a/node_modules/concurrently/dist/src/command-parser/expand-npm-shortcut.d.ts b/node_modules/concurrently/dist/src/command-parser/expand-npm-shortcut.d.ts new file mode 100644 index 0000000..636018a --- /dev/null +++ b/node_modules/concurrently/dist/src/command-parser/expand-npm-shortcut.d.ts @@ -0,0 +1,8 @@ +import { CommandInfo } from '../command'; +import { CommandParser } from './command-parser'; +/** + * Expands commands prefixed with `npm:`, `yarn:`, `pnpm:`, or `bun:` into the full version `npm run <command>` and so on. + */ +export declare class ExpandNpmShortcut implements CommandParser { + parse(commandInfo: CommandInfo): CommandInfo; +} diff --git a/node_modules/concurrently/dist/src/command-parser/expand-npm-shortcut.js b/node_modules/concurrently/dist/src/command-parser/expand-npm-shortcut.js new file mode 100644 index 0000000..9a62362 --- /dev/null +++ b/node_modules/concurrently/dist/src/command-parser/expand-npm-shortcut.js @@ -0,0 +1,20 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ExpandNpmShortcut = void 0; +/** + * Expands commands prefixed with `npm:`, `yarn:`, `pnpm:`, or `bun:` into the full version `npm run <command>` and so on. + */ +class ExpandNpmShortcut { + parse(commandInfo) { + const [, npmCmd, cmdName, args] = commandInfo.command.match(/^(npm|yarn|pnpm|bun):(\S+)(.*)/) || []; + if (!cmdName) { + return commandInfo; + } + return { + ...commandInfo, + name: commandInfo.name || cmdName, + command: `${npmCmd} run ${cmdName}${args}`, + }; + } +} +exports.ExpandNpmShortcut = ExpandNpmShortcut; diff --git a/node_modules/concurrently/dist/src/command-parser/expand-npm-wildcard.d.ts b/node_modules/concurrently/dist/src/command-parser/expand-npm-wildcard.d.ts new file mode 100644 index 0000000..cc5f413 --- /dev/null +++ b/node_modules/concurrently/dist/src/command-parser/expand-npm-wildcard.d.ts @@ -0,0 +1,13 @@ +import { CommandInfo } from '../command'; +import { CommandParser } from './command-parser'; +/** + * Finds wildcards in npm/yarn/pnpm/bun run commands and replaces them with all matching scripts in the + * `package.json` file of the current directory. + */ +export declare class ExpandNpmWildcard implements CommandParser { + private readonly readPackage; + static readPackage(): any; + private scripts?; + constructor(readPackage?: typeof ExpandNpmWildcard.readPackage); + parse(commandInfo: CommandInfo): CommandInfo | CommandInfo[]; +} diff --git a/node_modules/concurrently/dist/src/command-parser/expand-npm-wildcard.js b/node_modules/concurrently/dist/src/command-parser/expand-npm-wildcard.js new file mode 100644 index 0000000..0109207 --- /dev/null +++ b/node_modules/concurrently/dist/src/command-parser/expand-npm-wildcard.js @@ -0,0 +1,68 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ExpandNpmWildcard = void 0; +const fs_1 = __importDefault(require("fs")); +const lodash_1 = __importDefault(require("lodash")); +const OMISSION = /\(!([^)]+)\)/; +/** + * Finds wildcards in npm/yarn/pnpm/bun run commands and replaces them with all matching scripts in the + * `package.json` file of the current directory. + */ +class ExpandNpmWildcard { + static readPackage() { + try { + const json = fs_1.default.readFileSync('package.json', { encoding: 'utf-8' }); + return JSON.parse(json); + } + catch (e) { + return {}; + } + } + constructor(readPackage = ExpandNpmWildcard.readPackage) { + this.readPackage = readPackage; + } + parse(commandInfo) { + const [, npmCmd, cmdName, args] = commandInfo.command.match(/(npm|yarn|pnpm|bun) run (\S+)([^&]*)/) || []; + const wildcardPosition = (cmdName || '').indexOf('*'); + // If the regex didn't match an npm script, or it has no wildcard, + // then we have nothing to do here + if (!cmdName || wildcardPosition === -1) { + return commandInfo; + } + if (!this.scripts) { + this.scripts = Object.keys(this.readPackage().scripts || {}); + } + const omissionRegex = cmdName.match(OMISSION); + const cmdNameSansOmission = cmdName.replace(OMISSION, ''); + const preWildcard = lodash_1.default.escapeRegExp(cmdNameSansOmission.slice(0, wildcardPosition)); + const postWildcard = lodash_1.default.escapeRegExp(cmdNameSansOmission.slice(wildcardPosition + 1)); + const wildcardRegex = new RegExp(`^${preWildcard}(.*?)${postWildcard}$`); + // 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 + .map((script) => { + const match = script.match(wildcardRegex); + if (omissionRegex) { + const toOmit = script.match(new RegExp(omissionRegex[1])); + if (toOmit) { + return; + } + } + if (match) { + return { + ...commandInfo, + command: `${npmCmd} run ${script}${args}`, + // 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], + }; + } + }) + .filter((commandInfo) => !!commandInfo); + } +} +exports.ExpandNpmWildcard = ExpandNpmWildcard; diff --git a/node_modules/concurrently/dist/src/command-parser/strip-quotes.d.ts b/node_modules/concurrently/dist/src/command-parser/strip-quotes.d.ts new file mode 100644 index 0000000..1a21b79 --- /dev/null +++ b/node_modules/concurrently/dist/src/command-parser/strip-quotes.d.ts @@ -0,0 +1,15 @@ +import { CommandInfo } from '../command'; +import { CommandParser } from './command-parser'; +/** + * Strips quotes around commands so that they can run on the current shell. + */ +export declare class StripQuotes implements CommandParser { + parse(commandInfo: CommandInfo): { + command: string; + name: string; + env?: Record<string, unknown> | undefined; + cwd?: string | undefined; + prefixColor?: string | undefined; + raw?: boolean | undefined; + }; +} diff --git a/node_modules/concurrently/dist/src/command-parser/strip-quotes.js b/node_modules/concurrently/dist/src/command-parser/strip-quotes.js new file mode 100644 index 0000000..971a524 --- /dev/null +++ b/node_modules/concurrently/dist/src/command-parser/strip-quotes.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.StripQuotes = void 0; +/** + * Strips quotes around commands so that they can run on the current shell. + */ +class StripQuotes { + parse(commandInfo) { + let { command } = commandInfo; + // Removes the quotes surrounding a command. + if (/^"(.+?)"$/.test(command) || /^'(.+?)'$/.test(command)) { + command = command.slice(1, command.length - 1); + } + return { ...commandInfo, command }; + } +} +exports.StripQuotes = StripQuotes; diff --git a/node_modules/concurrently/dist/src/command.d.ts b/node_modules/concurrently/dist/src/command.d.ts new file mode 100644 index 0000000..84c6298 --- /dev/null +++ b/node_modules/concurrently/dist/src/command.d.ts @@ -0,0 +1,121 @@ +/// <reference types="node" /> +/// <reference types="node" /> +/// <reference types="node" /> +/// <reference types="node" /> +import { ChildProcess as BaseChildProcess, SpawnOptions } from 'child_process'; +import * as Rx from 'rxjs'; +import { EventEmitter, Writable } from 'stream'; +/** + * Identifier for a command; if string, it's the command's name, if number, it's the index. + */ +export type CommandIdentifier = string | number; +export interface CommandInfo { + /** + * Command's name. + */ + name: string; + /** + * Which command line the command has. + */ + command: string; + /** + * Which environment variables should the spawned process have. + */ + env?: Record<string, unknown>; + /** + * The current working directory of the process when spawned. + */ + cwd?: string; + /** + * Color to use on prefix of the command. + */ + prefixColor?: string; + /** + * Output command in raw format. + */ + raw?: boolean; +} +export interface CloseEvent { + command: CommandInfo; + /** + * The command's index among all commands ran. + */ + index: number; + /** + * Whether the command exited because it was killed. + */ + killed: boolean; + /** + * The exit code or signal for the command. + */ + exitCode: string | number; + timings: { + startDate: Date; + endDate: Date; + durationSeconds: number; + }; +} +export interface TimerEvent { + startDate: Date; + endDate?: Date; +} +/** + * Subtype of NodeJS's child_process including only what's actually needed for a command to work. + */ +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 type KillProcess = (pid: number, signal?: string) => void; +/** + * Interface for a function that spawns a command and returns its child process instance. + */ +export type SpawnCommand = (command: string, options: SpawnOptions) => ChildProcess; +export declare class Command implements CommandInfo { + private readonly killProcess; + private readonly spawn; + private readonly spawnOpts; + readonly index: number; + /** @inheritdoc */ + readonly name: string; + /** @inheritdoc */ + readonly command: string; + /** @inheritdoc */ + readonly prefixColor?: string; + /** @inheritdoc */ + readonly env: Record<string, unknown>; + /** @inheritdoc */ + readonly cwd?: string; + readonly close: Rx.Subject<CloseEvent>; + readonly error: Rx.Subject<unknown>; + readonly stdout: Rx.Subject<Buffer>; + readonly stderr: Rx.Subject<Buffer>; + readonly timer: Rx.Subject<TimerEvent>; + process?: ChildProcess; + stdin?: Writable; + pid?: number; + killed: boolean; + exited: boolean; + /** @deprecated */ + get killable(): boolean; + constructor({ index, name, command, prefixColor, env, cwd }: CommandInfo & { + index: number; + }, spawnOpts: SpawnOptions, spawn: SpawnCommand, killProcess: KillProcess); + /** + * Starts this command, piping output, error and close events onto the corresponding observables. + */ + start(): void; + /** + * Kills this command, optionally specifying a signal to send to it. + */ + 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; + }; +} diff --git a/node_modules/concurrently/dist/src/command.js b/node_modules/concurrently/dist/src/command.js new file mode 100644 index 0000000..e30bbb9 --- /dev/null +++ b/node_modules/concurrently/dist/src/command.js @@ -0,0 +1,117 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Command = void 0; +const Rx = __importStar(require("rxjs")); +class Command { + /** @deprecated */ + get killable() { + return Command.canKill(this); + } + constructor({ index, name, command, prefixColor, env, cwd }, spawnOpts, spawn, killProcess) { + this.close = new Rx.Subject(); + this.error = new Rx.Subject(); + this.stdout = new Rx.Subject(); + this.stderr = new Rx.Subject(); + this.timer = new Rx.Subject(); + this.killed = false; + this.exited = false; + this.index = index; + this.name = name; + this.command = command; + this.prefixColor = prefixColor; + this.env = env || {}; + this.cwd = cwd; + this.killProcess = killProcess; + this.spawn = spawn; + this.spawnOpts = spawnOpts; + } + /** + * Starts this command, piping output, error and close events onto the corresponding observables. + */ + start() { + const child = this.spawn(this.command, this.spawnOpts); + this.process = child; + this.pid = child.pid; + const startDate = new Date(Date.now()); + const highResStartTime = process.hrtime(); + this.timer.next({ startDate }); + Rx.fromEvent(child, 'error').subscribe((event) => { + this.process = undefined; + const endDate = new Date(Date.now()); + this.timer.next({ startDate, endDate }); + this.error.next(event); + }); + Rx.fromEvent(child, 'close') + .pipe(Rx.map((event) => event)) + .subscribe(([exitCode, signal]) => { + this.process = undefined; + this.exited = true; + const endDate = new Date(Date.now()); + this.timer.next({ startDate, endDate }); + const [durationSeconds, durationNanoSeconds] = process.hrtime(highResStartTime); + this.close.next({ + command: this, + index: this.index, + exitCode: exitCode ?? String(signal), + killed: this.killed, + timings: { + startDate, + endDate, + durationSeconds: durationSeconds + durationNanoSeconds / 1e9, + }, + }); + }); + child.stdout && + pipeTo(Rx.fromEvent(child.stdout, 'data').pipe(Rx.map((event) => event)), this.stdout); + child.stderr && + pipeTo(Rx.fromEvent(child.stderr, 'data').pipe(Rx.map((event) => event)), this.stderr); + this.stdin = child.stdin || undefined; + } + /** + * Kills this command, optionally specifying a signal to send to it. + */ + kill(code) { + if (Command.canKill(this)) { + this.killed = true; + 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; + } +} +exports.Command = Command; +/** + * Pipes all events emitted by `stream` into `subject`. + */ +function pipeTo(stream, subject) { + stream.subscribe((event) => subject.next(event)); +} diff --git a/node_modules/concurrently/dist/src/completion-listener.d.ts b/node_modules/concurrently/dist/src/completion-listener.d.ts new file mode 100644 index 0000000..fd1ad42 --- /dev/null +++ b/node_modules/concurrently/dist/src/completion-listener.d.ts @@ -0,0 +1,40 @@ +import * as Rx from 'rxjs'; +import { CloseEvent, Command } from './command'; +/** + * Defines which command(s) in a list must exit successfully (with an exit code of `0`): + * + * - `first`: only the first specified command; + * - `last`: only the last specified command; + * - `all`: all commands. + * - `command-{name|index}`: only the commands with the specified names or index. + * - `!command-{name|index}`: all commands but the ones with the specified names or index. + */ +export type SuccessCondition = 'first' | 'last' | 'all' | `command-${string | number}` | `!command-${string | number}`; +/** + * Provides logic to determine whether lists of commands ran successfully. + */ +export declare class CompletionListener { + private readonly successCondition; + private readonly scheduler?; + constructor({ successCondition, scheduler, }: { + /** + * How this instance will define that a list of commands ran successfully. + * Defaults to `all`. + * + * @see {SuccessCondition} + */ + successCondition?: SuccessCondition; + /** + * For testing only. + */ + scheduler?: Rx.SchedulerLike; + }); + private isSuccess; + /** + * Given a list of commands, wait for all of them to exit and then evaluate their exit codes. + * + * @returns A Promise that resolves if the success condition is met, or rejects otherwise. + */ + listen(commands: Command[]): Promise<CloseEvent[]>; + private emitWithScheduler; +} diff --git a/node_modules/concurrently/dist/src/completion-listener.js b/node_modules/concurrently/dist/src/completion-listener.js new file mode 100644 index 0000000..7844fde --- /dev/null +++ b/node_modules/concurrently/dist/src/completion-listener.js @@ -0,0 +1,77 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CompletionListener = void 0; +const Rx = __importStar(require("rxjs")); +const operators_1 = require("rxjs/operators"); +/** + * Provides logic to determine whether lists of commands ran successfully. + */ +class CompletionListener { + constructor({ successCondition = 'all', scheduler, }) { + this.successCondition = successCondition; + this.scheduler = scheduler; + } + isSuccess(events) { + if (this.successCondition === 'first') { + return events[0].exitCode === 0; + } + else if (this.successCondition === 'last') { + return events[events.length - 1].exitCode === 0; + } + const commandSyntaxMatch = this.successCondition.match(/^!?command-(.+)$/); + if (commandSyntaxMatch == null) { + // If not a `command-` syntax, then it's an 'all' condition or it's treated as such. + return events.every(({ exitCode }) => exitCode === 0); + } + // Check `command-` syntax condition. + // Note that a command's `name` is not necessarily unique, + // in which case all of them must meet the success condition. + const nameOrIndex = commandSyntaxMatch[1]; + const targetCommandsEvents = events.filter(({ command, index }) => command.name === nameOrIndex || index === Number(nameOrIndex)); + if (this.successCondition.startsWith('!')) { + // All commands except the specified ones must exit succesfully + return events.every((event) => targetCommandsEvents.includes(event) || event.exitCode === 0); + } + // Only the specified commands must exit succesfully + return (targetCommandsEvents.length > 0 && + targetCommandsEvents.every((event) => event.exitCode === 0)); + } + /** + * Given a list of commands, wait for all of them to exit and then evaluate their exit codes. + * + * @returns A Promise that resolves if the success condition is met, or rejects otherwise. + */ + listen(commands) { + const closeStreams = commands.map((command) => command.close); + return Rx.lastValueFrom(Rx.merge(...closeStreams).pipe((0, operators_1.bufferCount)(closeStreams.length), (0, operators_1.switchMap)((exitInfos) => this.isSuccess(exitInfos) + ? 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; diff --git a/node_modules/concurrently/dist/src/concurrently.d.ts b/node_modules/concurrently/dist/src/concurrently.d.ts new file mode 100644 index 0000000..7af8297 --- /dev/null +++ b/node_modules/concurrently/dist/src/concurrently.d.ts @@ -0,0 +1,110 @@ +/// <reference types="node" /> +import { Writable } from 'stream'; +import { CloseEvent, Command, CommandInfo, KillProcess, SpawnCommand } from './command'; +import { SuccessCondition } from './completion-listener'; +import { FlowController } from './flow-control/flow-controller'; +import { Logger } from './logger'; +/** + * A command that is to be passed into `concurrently()`. + * If value is a string, then that's the command's command line. + * Fine grained options can be defined by using the object format. + */ +export type ConcurrentlyCommandInput = string | ({ + command: string; +} & Partial<CommandInfo>); +export type ConcurrentlyResult = { + /** + * All commands created and ran by concurrently. + */ + commands: Command[]; + /** + * A promise that resolves when concurrently ran successfully according to the specified + * success condition, or reject otherwise. + * + * Both the resolved and rejected value is the list of all command's close events. + */ + result: Promise<CloseEvent[]>; +}; +export type ConcurrentlyOptions = { + logger?: Logger; + /** + * Which stream should the commands output be written to. + */ + outputStream?: Writable; + /** + * Whether the output should be ordered as if the commands were run sequentially. + */ + group?: boolean; + /** + * A comma-separated list of chalk colors or a string for available styles listed below to use on prefixes. + * If there are more commands than colors, the last color will be repeated. + * + * Available modifiers: + * - `reset`, `bold`, `dim`, `italic`, `underline`, `inverse`, `hidden`, `strikethrough` + * + * Available colors: + * - `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`, `gray`, + * any hex values for colors (e.g. `#23de43`) or `auto` for an automatically picked color + * + * Available background colors: + * - `bgBlack`, `bgRed`, `bgGreen`, `bgYellow`, `bgBlue`, `bgMagenta`, `bgCyan`, `bgWhite` + * + * @see {@link https://www.npmjs.com/package/chalk} for more information. + */ + prefixColors?: string | string[]; + /** + * Maximum number of commands to run at once. + * Exact number or a percent of CPUs available (for example "50%"). + * + * If undefined, then all processes will start in parallel. + * Setting this value to 1 will achieve sequential running. + */ + maxProcesses?: number | string; + /** + * Whether commands should be spawned in raw mode. + * Defaults to false. + */ + raw?: boolean; + /** + * The current working directory of commands which didn't specify one. + * Defaults to `process.cwd()`. + */ + cwd?: string; + /** + * @see CompletionListener + */ + successCondition?: SuccessCondition; + /** + * Which flow controllers should be applied on commands spawned by concurrently. + * Defaults to an empty array. + */ + controllers: FlowController[]; + /** + * A function that will spawn commands. + * Defaults to the `spawn-command` module. + */ + spawn: SpawnCommand; + /** + * A function that will kill processes. + * Defaults to the `tree-kill` module. + */ + kill: KillProcess; + /** + * Signal to send to killed processes. + */ + killSignal?: string; + /** + * List of additional arguments passed that will get replaced in each command. + * If not defined, no argument replacing will happen. + * + * @see ExpandArguments + */ + additionalArguments?: string[]; +}; +/** + * Core concurrently functionality -- spawns the given commands concurrently and + * returns the commands themselves + the result according to the specified success condition. + * + * @see CompletionListener + */ +export declare function concurrently(baseCommands: ConcurrentlyCommandInput[], baseOptions?: Partial<ConcurrentlyOptions>): ConcurrentlyResult; diff --git a/node_modules/concurrently/dist/src/concurrently.js b/node_modules/concurrently/dist/src/concurrently.js new file mode 100644 index 0000000..fe07fb7 --- /dev/null +++ b/node_modules/concurrently/dist/src/concurrently.js @@ -0,0 +1,130 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.concurrently = void 0; +const assert_1 = __importDefault(require("assert")); +const lodash_1 = __importDefault(require("lodash")); +const os_1 = require("os"); +const spawn_command_1 = __importDefault(require("spawn-command")); +const tree_kill_1 = __importDefault(require("tree-kill")); +const command_1 = require("./command"); +const expand_arguments_1 = require("./command-parser/expand-arguments"); +const expand_npm_shortcut_1 = require("./command-parser/expand-npm-shortcut"); +const expand_npm_wildcard_1 = require("./command-parser/expand-npm-wildcard"); +const strip_quotes_1 = require("./command-parser/strip-quotes"); +const completion_listener_1 = require("./completion-listener"); +const get_spawn_opts_1 = require("./get-spawn-opts"); +const output_writer_1 = require("./output-writer"); +const prefix_color_selector_1 = require("./prefix-color-selector"); +const defaults = { + spawn: spawn_command_1.default, + kill: tree_kill_1.default, + raw: false, + controllers: [], + cwd: undefined, +}; +/** + * Core concurrently functionality -- spawns the given commands concurrently and + * returns the commands themselves + the result according to the specified success condition. + * + * @see CompletionListener + */ +function concurrently(baseCommands, baseOptions) { + assert_1.default.ok(Array.isArray(baseCommands), '[concurrently] commands should be an array'); + assert_1.default.notStrictEqual(baseCommands.length, 0, '[concurrently] no commands provided'); + const options = lodash_1.default.defaults(baseOptions, defaults); + const prefixColorSelector = new prefix_color_selector_1.PrefixColorSelector(options.prefixColors); + const commandParsers = [ + new strip_quotes_1.StripQuotes(), + new expand_npm_shortcut_1.ExpandNpmShortcut(), + new expand_npm_wildcard_1.ExpandNpmWildcard(), + ]; + if (options.additionalArguments) { + commandParsers.push(new expand_arguments_1.ExpandArguments(options.additionalArguments)); + } + let commands = (0, lodash_1.default)(baseCommands) + .map(mapToCommandInfo) + .flatMap((command) => parseCommand(command, commandParsers)) + .map((command, index) => { + return new command_1.Command({ + index, + prefixColor: prefixColorSelector.getNextColor(), + ...command, + }, (0, get_spawn_opts_1.getSpawnOpts)({ + raw: command.raw ?? options.raw, + env: command.env, + cwd: command.cwd || options.cwd, + }), options.spawn, options.kill); + }) + .value(); + const handleResult = options.controllers.reduce(({ commands: prevCommands, onFinishCallbacks }, controller) => { + const { commands, onFinish } = controller.handle(prevCommands); + return { + commands, + onFinishCallbacks: lodash_1.default.concat(onFinishCallbacks, onFinish ? [onFinish] : []), + }; + }, { commands, onFinishCallbacks: [] }); + commands = handleResult.commands; + if (options.logger && options.outputStream) { + const outputWriter = new output_writer_1.OutputWriter({ + outputStream: options.outputStream, + group: !!options.group, + commands, + }); + options.logger.output.subscribe(({ command, text }) => outputWriter.write(command, text)); + } + const commandsLeft = commands.slice(); + 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++) { + maybeRunMore(commandsLeft); + } + const result = new completion_listener_1.CompletionListener({ successCondition: options.successCondition }) + .listen(commands) + .finally(() => { + handleResult.onFinishCallbacks.forEach((onFinish) => onFinish()); + }); + return { + result, + commands, + }; +} +exports.concurrently = concurrently; +function mapToCommandInfo(command) { + if (typeof command === 'string') { + return mapToCommandInfo({ command }); + } + assert_1.default.ok(command.command, '[concurrently] command cannot be empty'); + return { + command: command.command, + name: command.name || '', + env: command.env || {}, + cwd: command.cwd || '', + ...(command.prefixColor + ? { + prefixColor: command.prefixColor, + } + : {}), + ...(command.raw !== undefined + ? { + raw: command.raw, + } + : {}), + }; +} +function parseCommand(command, parsers) { + return parsers.reduce((commands, parser) => lodash_1.default.flatMap(commands, (command) => parser.parse(command)), lodash_1.default.castArray(command)); +} +function maybeRunMore(commandsLeft) { + const command = commandsLeft.shift(); + if (!command) { + return; + } + command.start(); + command.close.subscribe(() => { + maybeRunMore(commandsLeft); + }); +} diff --git a/node_modules/concurrently/dist/src/defaults.d.ts b/node_modules/concurrently/dist/src/defaults.d.ts new file mode 100644 index 0000000..b50a9fc --- /dev/null +++ b/node_modules/concurrently/dist/src/defaults.d.ts @@ -0,0 +1,68 @@ +import { SuccessCondition } from './completion-listener'; +export declare const defaultInputTarget = 0; +/** + * Whether process.stdin should be forwarded to child processes. + */ +export declare const handleInput = false; +/** + * How many processes to run at once. + */ +export declare const maxProcesses = 0; +/** + * Indices and names of commands whose output are not to be logged. + */ +export declare const hide = ""; +/** + * The character to split <names> on. + */ +export declare const nameSeparator = ","; +/** + * Which prefix style to use when logging processes output. + */ +export declare const prefix = ""; +/** + * Default prefix color. + * @see https://www.npmjs.com/package/chalk + */ +export declare const prefixColors = "reset"; +/** + * How many bytes we'll show on the command prefix. + */ +export declare const prefixLength = 10; +export declare const raw = false; +/** + * Number of attempts of restarting a process, if it exits with non-0 code. + */ +export declare const restartTries = 0; +/** + * How many milliseconds concurrently should wait before restarting a process. + */ +export declare const restartDelay = 0; +/** + * Condition of success for concurrently itself. + */ +export declare const success: SuccessCondition; +/** + * Date format used when logging date/time. + * @see https://date-fns.org/v2.0.1/docs/format + */ +export declare const timestampFormat = "yyyy-MM-dd HH:mm:ss.SSS"; +/** + * Current working dir passed as option to spawn command. + * Defaults to process.cwd() + */ +export declare const cwd: string | undefined; +/** + * Whether to show timing information for processes in console output. + */ +export declare const timings = false; +/** + * Passthrough additional arguments to commands (accessible via placeholders) instead of treating them as commands. + */ +export declare const passthroughArguments = false; +/** + * Signal to send to other processes if one exits or dies. + * + * Defaults to OS specific signal. (SIGTERM on Linux/MacOS) + */ +export declare const killSignal: string | undefined; diff --git a/node_modules/concurrently/dist/src/defaults.js b/node_modules/concurrently/dist/src/defaults.js new file mode 100644 index 0000000..3dcb9e4 --- /dev/null +++ b/node_modules/concurrently/dist/src/defaults.js @@ -0,0 +1,73 @@ +"use strict"; +// This file is meant to be a shared place for default configs. +// It's read by the flow controllers, the executable, etc. +// Refer to tests for the meaning of the different possible values. +Object.defineProperty(exports, "__esModule", { value: true }); +exports.killSignal = exports.passthroughArguments = exports.timings = exports.cwd = exports.timestampFormat = exports.success = exports.restartDelay = exports.restartTries = exports.raw = exports.prefixLength = exports.prefixColors = exports.prefix = exports.nameSeparator = exports.hide = exports.maxProcesses = exports.handleInput = exports.defaultInputTarget = void 0; +exports.defaultInputTarget = 0; +/** + * Whether process.stdin should be forwarded to child processes. + */ +exports.handleInput = false; +/** + * How many processes to run at once. + */ +exports.maxProcesses = 0; +/** + * Indices and names of commands whose output are not to be logged. + */ +exports.hide = ''; +/** + * The character to split <names> on. + */ +exports.nameSeparator = ','; +/** + * Which prefix style to use when logging processes output. + */ +exports.prefix = ''; +/** + * Default prefix color. + * @see https://www.npmjs.com/package/chalk + */ +exports.prefixColors = 'reset'; +/** + * How many bytes we'll show on the command prefix. + */ +exports.prefixLength = 10; +exports.raw = false; +/** + * Number of attempts of restarting a process, if it exits with non-0 code. + */ +exports.restartTries = 0; +/** + * How many milliseconds concurrently should wait before restarting a process. + */ +exports.restartDelay = 0; +/** + * Condition of success for concurrently itself. + */ +exports.success = 'all'; +/** + * Date format used when logging date/time. + * @see https://date-fns.org/v2.0.1/docs/format + */ +exports.timestampFormat = 'yyyy-MM-dd HH:mm:ss.SSS'; +/** + * Current working dir passed as option to spawn command. + * Defaults to process.cwd() + */ +exports.cwd = undefined; +/** + * Whether to show timing information for processes in console output. + */ +exports.timings = false; +/** + * Passthrough additional arguments to commands (accessible via placeholders) instead of treating them as commands. + */ +exports.passthroughArguments = false; +/** + * Signal to send to other processes if one exits or dies. + * + * Defaults to OS specific signal. (SIGTERM on Linux/MacOS) + */ +exports.killSignal = undefined; diff --git a/node_modules/concurrently/dist/src/flow-control/flow-controller.d.ts b/node_modules/concurrently/dist/src/flow-control/flow-controller.d.ts new file mode 100644 index 0000000..b518aad --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/flow-controller.d.ts @@ -0,0 +1,13 @@ +import { Command } from '../command'; +/** + * Interface for a class that controls and/or watches the behavior of commands. + * + * This may include logging their output, creating interactions between them, or changing when they + * actually finish. + */ +export interface FlowController { + handle(commands: Command[]): { + commands: Command[]; + onFinish?: () => void; + }; +} diff --git a/node_modules/concurrently/dist/src/flow-control/flow-controller.js b/node_modules/concurrently/dist/src/flow-control/flow-controller.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/flow-controller.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/concurrently/dist/src/flow-control/input-handler.d.ts b/node_modules/concurrently/dist/src/flow-control/input-handler.d.ts new file mode 100644 index 0000000..3a7ee5a --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/input-handler.d.ts @@ -0,0 +1,30 @@ +/// <reference types="node" /> +import { Readable } from 'stream'; +import { Command, CommandIdentifier } from '../command'; +import { Logger } from '../logger'; +import { FlowController } from './flow-controller'; +/** + * Sends input from concurrently through to commands. + * + * Input can start with a command identifier, in which case it will be sent to that specific command. + * For instance, `0:bla` will send `bla` to command at index `0`, and `server:stop` will send `stop` + * to command with name `server`. + * + * If the input doesn't start with a command identifier, it is then always sent to the default target. + */ +export declare class InputHandler implements FlowController { + private readonly logger; + private readonly defaultInputTarget; + private readonly inputStream?; + private readonly pauseInputStreamOnFinish; + constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger, }: { + inputStream?: Readable; + logger: Logger; + defaultInputTarget?: CommandIdentifier; + pauseInputStreamOnFinish?: boolean; + }); + handle(commands: Command[]): { + commands: Command[]; + onFinish?: () => void | undefined; + }; +} diff --git a/node_modules/concurrently/dist/src/flow-control/input-handler.js b/node_modules/concurrently/dist/src/flow-control/input-handler.js new file mode 100644 index 0000000..76c552f --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/input-handler.js @@ -0,0 +1,90 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.InputHandler = void 0; +const Rx = __importStar(require("rxjs")); +const operators_1 = require("rxjs/operators"); +const defaults = __importStar(require("../defaults")); +/** + * Sends input from concurrently through to commands. + * + * Input can start with a command identifier, in which case it will be sent to that specific command. + * For instance, `0:bla` will send `bla` to command at index `0`, and `server:stop` will send `stop` + * to command with name `server`. + * + * If the input doesn't start with a command identifier, it is then always sent to the default target. + */ +class InputHandler { + constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger, }) { + this.logger = logger; + this.defaultInputTarget = defaultInputTarget || defaults.defaultInputTarget; + this.inputStream = inputStream; + this.pauseInputStreamOnFinish = pauseInputStreamOnFinish !== false; + } + handle(commands) { + const { inputStream } = this; + if (!inputStream) { + return { commands }; + } + const commandsMap = new Map(); + for (const command of commands) { + commandsMap.set(command.index.toString(), command); + commandsMap.set(command.name, command); + } + Rx.fromEvent(inputStream, 'data') + .pipe((0, operators_1.map)((data) => String(data))) + .subscribe((data) => { + let command, input; + const dataParts = data.split(/:(.+)/s); + let target = dataParts[0]; + if (dataParts.length > 1 && (command = commandsMap.get(target))) { + input = dataParts[1]; + } + else { + // If `target` does not match a registered command, + // fallback to `defaultInputTarget` and forward the whole input data + target = this.defaultInputTarget.toString(); + command = commandsMap.get(target); + input = data; + } + if (command && command.stdin) { + command.stdin.write(input); + } + else { + this.logger.logGlobalEvent(`Unable to find command "${target}", or it has no stdin open\n`); + } + }); + return { + commands, + onFinish: () => { + if (this.pauseInputStreamOnFinish) { + // https://github.com/kimmobrunfeldt/concurrently/issues/252 + inputStream.pause(); + } + }, + }; + } +} +exports.InputHandler = InputHandler; diff --git a/node_modules/concurrently/dist/src/flow-control/kill-on-signal.d.ts b/node_modules/concurrently/dist/src/flow-control/kill-on-signal.d.ts new file mode 100644 index 0000000..d706694 --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/kill-on-signal.d.ts @@ -0,0 +1,17 @@ +/// <reference types="node" /> +import EventEmitter from 'events'; +import { Command } from '../command'; +import { FlowController } from './flow-controller'; +/** + * Watches the main concurrently process for signals and sends the same signal down to each spawned + * command. + */ +export declare class KillOnSignal implements FlowController { + private readonly process; + constructor({ process }: { + process: EventEmitter; + }); + handle(commands: Command[]): { + commands: Command[]; + }; +} diff --git a/node_modules/concurrently/dist/src/flow-control/kill-on-signal.js b/node_modules/concurrently/dist/src/flow-control/kill-on-signal.js new file mode 100644 index 0000000..716a9bf --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/kill-on-signal.js @@ -0,0 +1,36 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.KillOnSignal = void 0; +const operators_1 = require("rxjs/operators"); +/** + * Watches the main concurrently process for signals and sends the same signal down to each spawned + * command. + */ +class KillOnSignal { + constructor({ process }) { + this.process = process; + } + handle(commands) { + let caughtSignal; + ['SIGINT', 'SIGTERM', 'SIGHUP'].forEach((signal) => { + this.process.on(signal, () => { + caughtSignal = signal; + commands.forEach((command) => command.kill(signal)); + }); + }); + return { + commands: commands.map((command) => { + const closeStream = command.close.pipe((0, operators_1.map)((exitInfo) => { + const exitCode = caughtSignal === 'SIGINT' ? 0 : exitInfo.exitCode; + return { ...exitInfo, exitCode }; + })); + return new Proxy(command, { + get(target, prop) { + return prop === 'close' ? closeStream : target[prop]; + }, + }); + }), + }; + } +} +exports.KillOnSignal = KillOnSignal; diff --git a/node_modules/concurrently/dist/src/flow-control/kill-others.d.ts b/node_modules/concurrently/dist/src/flow-control/kill-others.d.ts new file mode 100644 index 0000000..f10b7bb --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/kill-others.d.ts @@ -0,0 +1,20 @@ +import { Command } from '../command'; +import { Logger } from '../logger'; +import { FlowController } from './flow-controller'; +export type ProcessCloseCondition = 'failure' | 'success'; +/** + * Sends a SIGTERM signal to all commands when one of the commands exits with a matching condition. + */ +export declare class KillOthers implements FlowController { + private readonly logger; + private readonly conditions; + private readonly killSignal; + constructor({ logger, conditions, killSignal, }: { + logger: Logger; + conditions: ProcessCloseCondition | ProcessCloseCondition[]; + killSignal: string | undefined; + }); + handle(commands: Command[]): { + commands: Command[]; + }; +} diff --git a/node_modules/concurrently/dist/src/flow-control/kill-others.js b/node_modules/concurrently/dist/src/flow-control/kill-others.js new file mode 100644 index 0000000..1751677 --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/kill-others.js @@ -0,0 +1,35 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.KillOthers = void 0; +const lodash_1 = __importDefault(require("lodash")); +const operators_1 = require("rxjs/operators"); +const command_1 = require("../command"); +/** + * Sends a SIGTERM signal to all commands when one of the commands exits with a matching condition. + */ +class KillOthers { + constructor({ logger, conditions, killSignal, }) { + this.logger = logger; + this.conditions = lodash_1.default.castArray(conditions); + this.killSignal = killSignal; + } + handle(commands) { + const conditions = this.conditions.filter((condition) => condition === 'failure' || condition === 'success'); + if (!conditions.length) { + return { commands }; + } + const closeStates = commands.map((command) => command.close.pipe((0, operators_1.map)(({ exitCode }) => exitCode === 0 ? 'success' : 'failure'), (0, operators_1.filter)((state) => conditions.includes(state)))); + closeStates.forEach((closeState) => closeState.subscribe(() => { + const killableCommands = commands.filter((command) => command_1.Command.canKill(command)); + if (killableCommands.length) { + this.logger.logGlobalEvent(`Sending ${this.killSignal || 'SIGTERM'} to other processes..`); + killableCommands.forEach((command) => command.kill(this.killSignal)); + } + })); + return { commands }; + } +} +exports.KillOthers = KillOthers; diff --git a/node_modules/concurrently/dist/src/flow-control/log-error.d.ts b/node_modules/concurrently/dist/src/flow-control/log-error.d.ts new file mode 100644 index 0000000..8eac6dd --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/log-error.d.ts @@ -0,0 +1,15 @@ +import { Command } from '../command'; +import { Logger } from '../logger'; +import { FlowController } from './flow-controller'; +/** + * Logs when commands failed executing, e.g. due to the executable not existing in the system. + */ +export declare class LogError implements FlowController { + private readonly logger; + constructor({ logger }: { + logger: Logger; + }); + handle(commands: Command[]): { + commands: Command[]; + }; +} diff --git a/node_modules/concurrently/dist/src/flow-control/log-error.js b/node_modules/concurrently/dist/src/flow-control/log-error.js new file mode 100644 index 0000000..8fc7210 --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/log-error.js @@ -0,0 +1,20 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LogError = void 0; +/** + * Logs when commands failed executing, e.g. due to the executable not existing in the system. + */ +class LogError { + constructor({ logger }) { + this.logger = logger; + } + handle(commands) { + commands.forEach((command) => command.error.subscribe((event) => { + this.logger.logCommandEvent(`Error occurred when executing command: ${command.command}`, command); + const errorText = String(event instanceof Error ? event.stack || event : event); + this.logger.logCommandEvent(errorText, command); + })); + return { commands }; + } +} +exports.LogError = LogError; diff --git a/node_modules/concurrently/dist/src/flow-control/log-exit.d.ts b/node_modules/concurrently/dist/src/flow-control/log-exit.d.ts new file mode 100644 index 0000000..47b8718 --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/log-exit.d.ts @@ -0,0 +1,15 @@ +import { Command } from '../command'; +import { Logger } from '../logger'; +import { FlowController } from './flow-controller'; +/** + * Logs the exit code/signal of commands. + */ +export declare class LogExit implements FlowController { + private readonly logger; + constructor({ logger }: { + logger: Logger; + }); + handle(commands: Command[]): { + commands: Command[]; + }; +} diff --git a/node_modules/concurrently/dist/src/flow-control/log-exit.js b/node_modules/concurrently/dist/src/flow-control/log-exit.js new file mode 100644 index 0000000..6fe396d --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/log-exit.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LogExit = void 0; +/** + * Logs the exit code/signal of commands. + */ +class LogExit { + constructor({ logger }) { + this.logger = logger; + } + handle(commands) { + commands.forEach((command) => command.close.subscribe(({ exitCode }) => { + this.logger.logCommandEvent(`${command.command} exited with code ${exitCode}`, command); + })); + return { commands }; + } +} +exports.LogExit = LogExit; diff --git a/node_modules/concurrently/dist/src/flow-control/log-output.d.ts b/node_modules/concurrently/dist/src/flow-control/log-output.d.ts new file mode 100644 index 0000000..6c916de --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/log-output.d.ts @@ -0,0 +1,15 @@ +import { Command } from '../command'; +import { Logger } from '../logger'; +import { FlowController } from './flow-controller'; +/** + * Logs the stdout and stderr output of commands. + */ +export declare class LogOutput implements FlowController { + private readonly logger; + constructor({ logger }: { + logger: Logger; + }); + handle(commands: Command[]): { + commands: Command[]; + }; +} diff --git a/node_modules/concurrently/dist/src/flow-control/log-output.js b/node_modules/concurrently/dist/src/flow-control/log-output.js new file mode 100644 index 0000000..486a25b --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/log-output.js @@ -0,0 +1,19 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LogOutput = void 0; +/** + * Logs the stdout and stderr output of commands. + */ +class LogOutput { + constructor({ logger }) { + this.logger = logger; + } + handle(commands) { + commands.forEach((command) => { + command.stdout.subscribe((text) => this.logger.logCommandText(text.toString(), command)); + command.stderr.subscribe((text) => this.logger.logCommandText(text.toString(), command)); + }); + return { commands }; + } +} +exports.LogOutput = LogOutput; diff --git a/node_modules/concurrently/dist/src/flow-control/log-timings.d.ts b/node_modules/concurrently/dist/src/flow-control/log-timings.d.ts new file mode 100644 index 0000000..a847707 --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/log-timings.d.ts @@ -0,0 +1,31 @@ +import { CloseEvent, Command } from '../command'; +import { Logger } from '../logger'; +import { FlowController } from './flow-controller'; +type TimingInfo = { + name: string; + duration: string; + 'exit code': string | number; + killed: boolean; + command: string; +}; +/** + * Logs timing information about commands as they start/stop and then a summary when all commands finish. + */ +export declare class LogTimings implements FlowController { + static mapCloseEventToTimingInfo({ command, timings, killed, exitCode, }: CloseEvent): TimingInfo; + private readonly logger?; + private readonly timestampFormat; + constructor({ logger, timestampFormat, }: { + logger?: Logger; + timestampFormat?: string; + }); + private printExitInfoTimingTable; + handle(commands: Command[]): { + commands: Command[]; + onFinish?: undefined; + } | { + commands: Command[]; + onFinish: () => void; + }; +} +export {}; diff --git a/node_modules/concurrently/dist/src/flow-control/log-timings.js b/node_modules/concurrently/dist/src/flow-control/log-timings.js new file mode 100644 index 0000000..9c8879d --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/log-timings.js @@ -0,0 +1,92 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LogTimings = void 0; +const assert = __importStar(require("assert")); +const format_1 = __importDefault(require("date-fns/format")); +const lodash_1 = __importDefault(require("lodash")); +const Rx = __importStar(require("rxjs")); +const operators_1 = require("rxjs/operators"); +const defaults = __importStar(require("../defaults")); +/** + * Logs timing information about commands as they start/stop and then a summary when all commands finish. + */ +class LogTimings { + static mapCloseEventToTimingInfo({ command, timings, killed, exitCode, }) { + const readableDurationMs = (timings.endDate.getTime() - timings.startDate.getTime()).toLocaleString(); + return { + name: command.name, + duration: readableDurationMs, + 'exit code': exitCode, + killed, + command: command.command, + }; + } + constructor({ logger, timestampFormat = defaults.timestampFormat, }) { + this.logger = logger; + this.timestampFormat = timestampFormat; + } + printExitInfoTimingTable(exitInfos) { + assert.ok(this.logger); + const exitInfoTable = (0, lodash_1.default)(exitInfos) + .sortBy(({ timings }) => timings.durationSeconds) + .reverse() + .map(LogTimings.mapCloseEventToTimingInfo) + .value(); + this.logger.logGlobalEvent('Timings:'); + this.logger.logTable(exitInfoTable); + return exitInfos; + } + handle(commands) { + const { logger } = this; + if (!logger) { + return { commands }; + } + // individual process timings + commands.forEach((command) => { + command.timer.subscribe(({ startDate, endDate }) => { + if (!endDate) { + const formattedStartDate = (0, format_1.default)(startDate, this.timestampFormat); + logger.logCommandEvent(`${command.command} started at ${formattedStartDate}`, command); + } + else { + const durationMs = endDate.getTime() - startDate.getTime(); + const formattedEndDate = (0, format_1.default)(endDate, this.timestampFormat); + logger.logCommandEvent(`${command.command} stopped at ${formattedEndDate} after ${durationMs.toLocaleString()}ms`, command); + } + }); + }); + // overall summary timings + const closeStreams = commands.map((command) => command.close); + const finished = new Rx.Subject(); + const allProcessesClosed = Rx.merge(...closeStreams).pipe((0, operators_1.bufferCount)(closeStreams.length), (0, operators_1.take)(1), (0, operators_1.combineLatestWith)(finished)); + allProcessesClosed.subscribe(([exitInfos]) => this.printExitInfoTimingTable(exitInfos)); + return { commands, onFinish: () => finished.next() }; + } +} +exports.LogTimings = LogTimings; diff --git a/node_modules/concurrently/dist/src/flow-control/restart-process.d.ts b/node_modules/concurrently/dist/src/flow-control/restart-process.d.ts new file mode 100644 index 0000000..735d8d5 --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/restart-process.d.ts @@ -0,0 +1,22 @@ +import * as Rx from 'rxjs'; +import { Command } from '../command'; +import { Logger } from '../logger'; +import { FlowController } from './flow-controller'; +/** + * Restarts commands that fail up to a defined number of times. + */ +export declare class RestartProcess implements FlowController { + private readonly logger; + private readonly scheduler?; + readonly delay: number; + readonly tries: number; + constructor({ delay, tries, logger, scheduler, }: { + delay?: number; + tries?: number; + logger: Logger; + scheduler?: Rx.SchedulerLike; + }); + handle(commands: Command[]): { + commands: Command[]; + }; +} diff --git a/node_modules/concurrently/dist/src/flow-control/restart-process.js b/node_modules/concurrently/dist/src/flow-control/restart-process.js new file mode 100644 index 0000000..79131ce --- /dev/null +++ b/node_modules/concurrently/dist/src/flow-control/restart-process.js @@ -0,0 +1,76 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RestartProcess = void 0; +const Rx = __importStar(require("rxjs")); +const operators_1 = require("rxjs/operators"); +const defaults = __importStar(require("../defaults")); +/** + * Restarts commands that fail up to a defined number of times. + */ +class RestartProcess { + constructor({ delay, tries, logger, scheduler, }) { + this.logger = logger; + this.delay = delay != null ? +delay : defaults.restartDelay; + this.tries = tries != null ? +tries : defaults.restartTries; + this.tries = this.tries < 0 ? Infinity : this.tries; + this.scheduler = scheduler; + } + handle(commands) { + if (this.tries === 0) { + return { commands }; + } + commands + .map((command) => command.close.pipe((0, operators_1.take)(this.tries), (0, operators_1.takeWhile)(({ exitCode }) => exitCode !== 0))) + .map((failure, index) => Rx.merge( + // Delay the emission (so that the restarts happen on time), + // explicitly telling the subscriber that a restart is needed + failure.pipe((0, operators_1.delay)(this.delay, this.scheduler), (0, operators_1.map)(() => true)), + // Skip the first N emissions (as these would be duplicates of the above), + // meaning it will be empty because of success, or failed all N times, + // and no more restarts should be attempted. + failure.pipe((0, operators_1.skip)(this.tries), (0, operators_1.map)(() => false), (0, operators_1.defaultIfEmpty)(false))).subscribe((restart) => { + const command = commands[index]; + if (restart) { + this.logger.logCommandEvent(`${command.command} restarted`, command); + command.start(); + } + })); + return { + commands: commands.map((command) => { + const closeStream = command.close.pipe((0, operators_1.filter)(({ exitCode }, emission) => { + // We let all success codes pass, and failures only after restarting won't happen again + return exitCode === 0 || emission >= this.tries; + })); + return new Proxy(command, { + get(target, prop) { + return prop === 'close' ? closeStream : target[prop]; + }, + }); + }), + }; + } +} +exports.RestartProcess = RestartProcess; diff --git a/node_modules/concurrently/dist/src/get-spawn-opts.d.ts b/node_modules/concurrently/dist/src/get-spawn-opts.d.ts new file mode 100644 index 0000000..7538de7 --- /dev/null +++ b/node_modules/concurrently/dist/src/get-spawn-opts.d.ts @@ -0,0 +1,34 @@ +/// <reference types="node" /> +/// <reference types="node" /> +/// <reference types="node" /> +/// <reference types="node" /> +/// <reference types="node" /> +import { SpawnOptions } from 'child_process'; +import supportsColor from 'supports-color'; +export declare const getSpawnOpts: ({ colorSupport, cwd, process, raw, env, }: { + /** + * What the color support of the spawned processes should be. + * If set to `false`, then no colors should be output. + * + * Defaults to whatever the terminal's stdout support is. + */ + colorSupport?: false | Pick<supportsColor.supportsColor.Level, "level"> | undefined; + /** + * The NodeJS process. + */ + process?: Pick<NodeJS.Process, "platform" | "cwd" | "env"> | undefined; + /** + * A custom working directory to spawn processes in. + * Defaults to `process.cwd()`. + */ + cwd?: string | undefined; + /** + * Whether to customize the options for spawning processes in raw mode. + * Defaults to false. + */ + raw?: boolean | undefined; + /** + * Map of custom environment variables to include in the spawn options. + */ + env?: Record<string, unknown> | undefined; +}) => SpawnOptions; diff --git a/node_modules/concurrently/dist/src/get-spawn-opts.js b/node_modules/concurrently/dist/src/get-spawn-opts.js new file mode 100644 index 0000000..9b48af5 --- /dev/null +++ b/node_modules/concurrently/dist/src/get-spawn-opts.js @@ -0,0 +1,18 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getSpawnOpts = void 0; +const supports_color_1 = __importDefault(require("supports-color")); +const getSpawnOpts = ({ colorSupport = supports_color_1.default.stdout, cwd, process = global.process, raw = false, env = {}, }) => ({ + cwd: cwd || process.cwd(), + ...(raw && { stdio: 'inherit' }), + ...(/^win/.test(process.platform) && { detached: false }), + env: { + ...(colorSupport ? { FORCE_COLOR: colorSupport.level.toString() } : {}), + ...process.env, + ...env, + }, +}); +exports.getSpawnOpts = getSpawnOpts; diff --git a/node_modules/concurrently/dist/src/index.d.ts b/node_modules/concurrently/dist/src/index.d.ts new file mode 100644 index 0000000..6f4e68b --- /dev/null +++ b/node_modules/concurrently/dist/src/index.d.ts @@ -0,0 +1,74 @@ +/// <reference types="node" /> +import { Readable } from 'stream'; +import { CloseEvent, Command, CommandIdentifier, TimerEvent } from './command'; +import { concurrently, ConcurrentlyCommandInput, ConcurrentlyOptions as BaseConcurrentlyOptions, ConcurrentlyResult } from './concurrently'; +import { FlowController } from './flow-control/flow-controller'; +import { InputHandler } from './flow-control/input-handler'; +import { KillOnSignal } from './flow-control/kill-on-signal'; +import { KillOthers, ProcessCloseCondition } from './flow-control/kill-others'; +import { LogError } from './flow-control/log-error'; +import { LogExit } from './flow-control/log-exit'; +import { LogOutput } from './flow-control/log-output'; +import { LogTimings } from './flow-control/log-timings'; +import { RestartProcess } from './flow-control/restart-process'; +import { Logger } from './logger'; +export type ConcurrentlyOptions = BaseConcurrentlyOptions & { + /** + * Which command(s) should have their output hidden. + */ + hide?: CommandIdentifier | CommandIdentifier[]; + /** + * The prefix format to use when logging a command's output. + * Defaults to the command's index. + */ + prefix?: string; + /** + * How many characters should a prefix have at most, used when the prefix format is `command`. + */ + prefixLength?: number; + /** + * Whether output should be formatted to include prefixes and whether "event" logs will be logged. + */ + raw?: boolean; + /** + * Date format used when logging date/time. + * @see https://date-fns.org/v2.0.1/docs/format + */ + timestampFormat?: string; + defaultInputTarget?: CommandIdentifier; + inputStream?: Readable; + handleInput?: boolean; + pauseInputStreamOnFinish?: boolean; + /** + * How much time in milliseconds to wait before restarting a command. + * + * @see RestartProcess + */ + restartDelay?: number; + /** + * How many times commands should be restarted when they exit with a failure. + * + * @see RestartProcess + */ + restartTries?: number; + /** + * Under which condition(s) should other commands be killed when the first one exits. + * + * @see KillOthers + */ + killOthers?: ProcessCloseCondition | ProcessCloseCondition[]; + /** + * Whether to output timing information for processes. + * + * @see LogTimings + */ + timings?: boolean; + /** + * List of additional arguments passed that will get replaced in each command. + * If not defined, no argument replacing will happen. + */ + additionalArguments?: string[]; +}; +declare const _default: (commands: ConcurrentlyCommandInput[], options?: Partial<ConcurrentlyOptions>) => ConcurrentlyResult; +export default _default; +export { CloseEvent, Command, CommandIdentifier, concurrently, ConcurrentlyCommandInput, ConcurrentlyResult, FlowController, InputHandler, KillOnSignal, KillOthers, LogError, LogExit, Logger, LogOutput, LogTimings, RestartProcess, TimerEvent, }; diff --git a/node_modules/concurrently/dist/src/index.js b/node_modules/concurrently/dist/src/index.js new file mode 100644 index 0000000..2d87891 --- /dev/null +++ b/node_modules/concurrently/dist/src/index.js @@ -0,0 +1,71 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RestartProcess = exports.LogTimings = exports.LogOutput = exports.Logger = exports.LogExit = exports.LogError = exports.KillOthers = exports.KillOnSignal = exports.InputHandler = exports.concurrently = exports.Command = void 0; +const command_1 = require("./command"); +Object.defineProperty(exports, "Command", { enumerable: true, get: function () { return command_1.Command; } }); +const concurrently_1 = require("./concurrently"); +Object.defineProperty(exports, "concurrently", { enumerable: true, get: function () { return concurrently_1.concurrently; } }); +const input_handler_1 = require("./flow-control/input-handler"); +Object.defineProperty(exports, "InputHandler", { enumerable: true, get: function () { return input_handler_1.InputHandler; } }); +const kill_on_signal_1 = require("./flow-control/kill-on-signal"); +Object.defineProperty(exports, "KillOnSignal", { enumerable: true, get: function () { return kill_on_signal_1.KillOnSignal; } }); +const kill_others_1 = require("./flow-control/kill-others"); +Object.defineProperty(exports, "KillOthers", { enumerable: true, get: function () { return kill_others_1.KillOthers; } }); +const log_error_1 = require("./flow-control/log-error"); +Object.defineProperty(exports, "LogError", { enumerable: true, get: function () { return log_error_1.LogError; } }); +const log_exit_1 = require("./flow-control/log-exit"); +Object.defineProperty(exports, "LogExit", { enumerable: true, get: function () { return log_exit_1.LogExit; } }); +const log_output_1 = require("./flow-control/log-output"); +Object.defineProperty(exports, "LogOutput", { enumerable: true, get: function () { return log_output_1.LogOutput; } }); +const log_timings_1 = require("./flow-control/log-timings"); +Object.defineProperty(exports, "LogTimings", { enumerable: true, get: function () { return log_timings_1.LogTimings; } }); +const restart_process_1 = require("./flow-control/restart-process"); +Object.defineProperty(exports, "RestartProcess", { enumerable: true, get: function () { return restart_process_1.RestartProcess; } }); +const logger_1 = require("./logger"); +Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return logger_1.Logger; } }); +exports.default = (commands, options = {}) => { + const logger = new logger_1.Logger({ + hide: options.hide, + prefixFormat: options.prefix, + prefixLength: options.prefixLength, + raw: options.raw, + timestampFormat: options.timestampFormat, + }); + return (0, concurrently_1.concurrently)(commands, { + maxProcesses: options.maxProcesses, + raw: options.raw, + successCondition: options.successCondition, + cwd: options.cwd, + logger, + outputStream: options.outputStream || process.stdout, + group: options.group, + controllers: [ + new log_error_1.LogError({ logger }), + new log_output_1.LogOutput({ logger }), + new log_exit_1.LogExit({ logger }), + new input_handler_1.InputHandler({ + logger, + defaultInputTarget: options.defaultInputTarget, + inputStream: options.inputStream || (options.handleInput ? process.stdin : undefined), + pauseInputStreamOnFinish: options.pauseInputStreamOnFinish, + }), + new kill_on_signal_1.KillOnSignal({ process }), + new restart_process_1.RestartProcess({ + logger, + delay: options.restartDelay, + tries: options.restartTries, + }), + new kill_others_1.KillOthers({ + logger, + conditions: options.killOthers || [], + killSignal: options.killSignal, + }), + new log_timings_1.LogTimings({ + logger: options.timings ? logger : undefined, + timestampFormat: options.timestampFormat, + }), + ], + prefixColors: options.prefixColors || [], + additionalArguments: options.additionalArguments, + }); +}; diff --git a/node_modules/concurrently/dist/src/logger.d.ts b/node_modules/concurrently/dist/src/logger.d.ts new file mode 100644 index 0000000..69b0d13 --- /dev/null +++ b/node_modules/concurrently/dist/src/logger.d.ts @@ -0,0 +1,72 @@ +import * as Rx from 'rxjs'; +import { Command, CommandIdentifier } from './command'; +export declare class Logger { + private readonly hide; + private readonly raw; + private readonly prefixFormat?; + private readonly prefixLength; + private readonly timestampFormat; + /** + * Last character emitted. + * If `undefined`, then nothing has been logged yet. + */ + private lastChar?; + /** + * Observable that emits when there's been output logged. + * If `command` is is `undefined`, then the log is for a global event. + */ + readonly output: Rx.Subject<{ + command: Command | undefined; + text: string; + }>; + constructor({ hide, prefixFormat, prefixLength, raw, timestampFormat, }: { + /** + * Which command(s) should have their output hidden. + */ + hide?: CommandIdentifier | CommandIdentifier[]; + /** + * Whether output should be formatted to include prefixes and whether "event" logs will be + * logged. + */ + raw?: boolean; + /** + * The prefix format to use when logging a command's output. + * Defaults to the command's index. + */ + prefixFormat?: string; + /** + * How many characters should a prefix have at most, used when the prefix format is `command`. + */ + prefixLength?: number; + /** + * Date format used when logging date/time. + * @see https://date-fns.org/v2.0.1/docs/format + */ + timestampFormat?: string; + }); + private shortenText; + private getPrefixesFor; + getPrefix(command: Command): string; + colorText(command: Command, text: string): string; + /** + * Logs an event for a command (e.g. start, stop). + * + * If raw mode is on, then nothing is logged. + */ + logCommandEvent(text: string, command: Command): void; + logCommandText(text: string, command: Command): void; + /** + * Logs a global event (e.g. sending signals to processes). + * + * If raw mode is on, then nothing is logged. + */ + logGlobalEvent(text: string): void; + /** + * Logs a table from an input object array, like `console.table`. + * + * Each row is a single input item, and they are presented in the input order. + */ + logTable(tableContents: Record<string, unknown>[]): void; + log(prefix: string, text: string, command?: Command): void; + emit(command: Command | undefined, text: string): void; +} diff --git a/node_modules/concurrently/dist/src/logger.js b/node_modules/concurrently/dist/src/logger.js new file mode 100644 index 0000000..5fb368c --- /dev/null +++ b/node_modules/concurrently/dist/src/logger.js @@ -0,0 +1,202 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Logger = void 0; +const chalk_1 = __importDefault(require("chalk")); +const format_1 = __importDefault(require("date-fns/format")); +const lodash_1 = __importDefault(require("lodash")); +const Rx = __importStar(require("rxjs")); +const defaults = __importStar(require("./defaults")); +class Logger { + constructor({ hide, prefixFormat, prefixLength, raw = false, timestampFormat, }) { + /** + * Observable that emits when there's been output logged. + * If `command` is is `undefined`, then the log is for a global event. + */ + this.output = new Rx.Subject(); + // To avoid empty strings from hiding the output of commands that don't have a name, + // keep in the list of commands to hide only strings with some length. + // This might happen through the CLI when no `--hide` argument is specified, for example. + this.hide = lodash_1.default.castArray(hide) + .filter((name) => name || name === 0) + .map(String); + this.raw = raw; + this.prefixFormat = prefixFormat; + this.prefixLength = prefixLength || defaults.prefixLength; + this.timestampFormat = timestampFormat || defaults.timestampFormat; + } + shortenText(text) { + if (!text || text.length <= this.prefixLength) { + return text; + } + const ellipsis = '..'; + const prefixLength = this.prefixLength - ellipsis.length; + const endLength = Math.floor(prefixLength / 2); + const beginningLength = prefixLength - endLength; + const beginnning = text.slice(0, beginningLength); + const end = text.slice(text.length - endLength, text.length); + return beginnning + ellipsis + end; + } + getPrefixesFor(command) { + return { + pid: String(command.pid), + index: String(command.index), + name: command.name, + command: this.shortenText(command.command), + time: (0, format_1.default)(Date.now(), this.timestampFormat), + }; + } + getPrefix(command) { + const prefix = this.prefixFormat || (command.name ? 'name' : 'index'); + if (prefix === 'none') { + return ''; + } + const prefixes = this.getPrefixesFor(command); + if (Object.keys(prefixes).includes(prefix)) { + return `[${prefixes[prefix]}]`; + } + return lodash_1.default.reduce(prefixes, (prev, val, key) => { + const keyRegex = new RegExp(lodash_1.default.escapeRegExp(`{${key}}`), 'g'); + return prev.replace(keyRegex, String(val)); + }, prefix); + } + colorText(command, text) { + let color; + if (command.prefixColor && command.prefixColor.startsWith('#')) { + color = chalk_1.default.hex(command.prefixColor); + } + else { + 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); + } + return color(text); + } + /** + * Logs an event for a command (e.g. start, stop). + * + * If raw mode is on, then nothing is logged. + */ + logCommandEvent(text, command) { + if (this.raw) { + return; + } + this.logCommandText(chalk_1.default.reset(text) + '\n', command); + } + logCommandText(text, command) { + if (this.hide.includes(String(command.index)) || this.hide.includes(command.name)) { + return; + } + const prefix = this.colorText(command, this.getPrefix(command)); + return this.log(prefix + (prefix ? ' ' : ''), text, command); + } + /** + * Logs a global event (e.g. sending signals to processes). + * + * If raw mode is on, then nothing is logged. + */ + logGlobalEvent(text) { + if (this.raw) { + return; + } + this.log(chalk_1.default.reset('-->') + ' ', chalk_1.default.reset(text) + '\n'); + } + /** + * Logs a table from an input object array, like `console.table`. + * + * Each row is a single input item, and they are presented in the input order. + */ + logTable(tableContents) { + // For now, can only print array tables with some content. + if (this.raw || !Array.isArray(tableContents) || !tableContents.length) { + return; + } + let nextColIndex = 0; + const headers = {}; + const contentRows = tableContents.map((row) => { + const rowContents = []; + Object.keys(row).forEach((col) => { + if (!headers[col]) { + headers[col] = { + index: nextColIndex++, + length: col.length, + }; + } + const colIndex = headers[col].index; + const formattedValue = String(row[col] == null ? '' : row[col]); + // Update the column length in case this rows value is longer than the previous length for the column. + headers[col].length = Math.max(formattedValue.length, headers[col].length); + rowContents[colIndex] = formattedValue; + return rowContents; + }); + return rowContents; + }); + const headersFormatted = Object.keys(headers).map((header) => header.padEnd(headers[header].length, ' ')); + if (!headersFormatted.length) { + // No columns exist. + return; + } + const borderRowFormatted = headersFormatted.map((header) => '─'.padEnd(header.length, '─')); + this.logGlobalEvent(`┌─${borderRowFormatted.join('─┬─')}─┐`); + this.logGlobalEvent(`│ ${headersFormatted.join(' │ ')} │`); + this.logGlobalEvent(`├─${borderRowFormatted.join('─┼─')}─┤`); + contentRows.forEach((contentRow) => { + const contentRowFormatted = headersFormatted.map((header, colIndex) => { + // If the table was expanded after this row was processed, it won't have this column. + // Use an empty string in this case. + const col = contentRow[colIndex] || ''; + return col.padEnd(header.length, ' '); + }); + this.logGlobalEvent(`│ ${contentRowFormatted.join(' │ ')} │`); + }); + this.logGlobalEvent(`└─${borderRowFormatted.join('─┴─')}─┘`); + } + log(prefix, text, command) { + if (this.raw) { + return this.emit(command, text); + } + // #70 - replace some ANSI code that would impact clearing lines + text = text.replace(/\u2026/g, '...'); + const lines = text.split('\n').map((line, index, lines) => { + // First line will write prefix only if we finished the last write with a LF. + // Last line won't write prefix because it should be empty. + if (index === 0 || index === lines.length - 1) { + return line; + } + return prefix + line; + }); + if (!this.lastChar || this.lastChar === '\n') { + this.emit(command, prefix); + } + this.lastChar = text[text.length - 1]; + this.emit(command, lines.join('\n')); + } + emit(command, text) { + this.output.next({ command, text }); + } +} +exports.Logger = Logger; diff --git a/node_modules/concurrently/dist/src/output-writer.d.ts b/node_modules/concurrently/dist/src/output-writer.d.ts new file mode 100644 index 0000000..67f835b --- /dev/null +++ b/node_modules/concurrently/dist/src/output-writer.d.ts @@ -0,0 +1,19 @@ +/// <reference types="node" /> +import { Writable } from 'stream'; +import { Command } from './command'; +/** + * Class responsible for actually writing output onto a writable stream. + */ +export declare class OutputWriter { + private readonly outputStream; + private readonly group; + readonly buffers: string[][]; + activeCommandIndex: number; + constructor({ outputStream, group, commands, }: { + outputStream: Writable; + group: boolean; + commands: Command[]; + }); + write(command: Command | undefined, text: string): void; + private flushBuffer; +} diff --git a/node_modules/concurrently/dist/src/output-writer.js b/node_modules/concurrently/dist/src/output-writer.js new file mode 100644 index 0000000..0795e82 --- /dev/null +++ b/node_modules/concurrently/dist/src/output-writer.js @@ -0,0 +1,71 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.OutputWriter = void 0; +const Rx = __importStar(require("rxjs")); +/** + * Class responsible for actually writing output onto a writable stream. + */ +class OutputWriter { + constructor({ outputStream, group, commands, }) { + this.activeCommandIndex = 0; + this.outputStream = outputStream; + this.group = group; + this.buffers = commands.map(() => []); + if (this.group) { + Rx.merge(...commands.map((c) => c.close)).subscribe((command) => { + if (command.index !== this.activeCommandIndex) { + return; + } + for (let i = command.index + 1; i < commands.length; i++) { + this.activeCommandIndex = i; + this.flushBuffer(i); + if (!commands[i].exited) { + break; + } + } + }); + } + } + write(command, text) { + if (this.group && command) { + if (command.index <= this.activeCommandIndex) { + this.outputStream.write(text); + } + else { + this.buffers[command.index].push(text); + } + } + else { + // "global" logs (command=null) are output out of order + this.outputStream.write(text); + } + } + flushBuffer(index) { + this.buffers[index].forEach((t) => this.outputStream.write(t)); + this.buffers[index] = []; + } +} +exports.OutputWriter = OutputWriter; diff --git a/node_modules/concurrently/dist/src/prefix-color-selector.d.ts b/node_modules/concurrently/dist/src/prefix-color-selector.d.ts new file mode 100644 index 0000000..8dcf7a0 --- /dev/null +++ b/node_modules/concurrently/dist/src/prefix-color-selector.d.ts @@ -0,0 +1,11 @@ +import chalk from 'chalk'; +export declare class PrefixColorSelector { + private colorGenerator; + constructor(customColors?: string | string[]); + /** A list of colors that are readable in a terminal. */ + static get ACCEPTABLE_CONSOLE_COLORS(): ("stderr" | keyof chalk.Chalk | "supportsColor" | "Level" | "Color" | "ForegroundColor" | "BackgroundColor" | "Modifiers")[]; + /** + * @returns The given custom colors then a set of acceptable console colors indefinitely. + */ + getNextColor(): string; +} diff --git a/node_modules/concurrently/dist/src/prefix-color-selector.js b/node_modules/concurrently/dist/src/prefix-color-selector.js new file mode 100644 index 0000000..c01b2ca --- /dev/null +++ b/node_modules/concurrently/dist/src/prefix-color-selector.js @@ -0,0 +1,93 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PrefixColorSelector = void 0; +function getConsoleColorsWithoutCustomColors(customColors) { + return PrefixColorSelector.ACCEPTABLE_CONSOLE_COLORS.filter( + // Consider the "Bright" variants of colors to be the same as the plain color to avoid similar colors + (color) => !customColors.includes(color.replace(/Bright$/, ''))); +} +/** + * Creates a generator that yields an infinite stream of colors. + */ +function* createColorGenerator(customColors) { + // Custom colors should be used as is, except for "auto" + const nextAutoColors = getConsoleColorsWithoutCustomColors(customColors); + let lastColor; + for (const customColor of customColors) { + let currentColor = customColor; + if (currentColor !== 'auto') { + yield currentColor; // Manual color + } + else { + // Find the first auto color that is not the same as the last color + while (currentColor === 'auto' || lastColor === currentColor) { + if (!nextAutoColors.length) { + // There could be more "auto" values than auto colors so this needs to be able to refill + nextAutoColors.push(...PrefixColorSelector.ACCEPTABLE_CONSOLE_COLORS); + } + currentColor = String(nextAutoColors.shift()); + } + yield currentColor; // Auto color + } + lastColor = currentColor; + } + const lastCustomColor = customColors[customColors.length - 1] || ''; + if (lastCustomColor !== 'auto') { + while (true) { + yield lastCustomColor; // If last custom color was not "auto" then return same color forever, to maintain existing behaviour + } + } + // Finish the initial set(s) of auto colors to avoid repetition + for (const color of nextAutoColors) { + yield color; + } + // Yield an infinite stream of acceptable console colors + // + // If the given custom colors use every ACCEPTABLE_CONSOLE_COLORS except one then there is a chance a color will be repeated, + // however its highly unlikely and low consequence so not worth the extra complexity to account for it + while (true) { + for (const color of PrefixColorSelector.ACCEPTABLE_CONSOLE_COLORS) { + yield color; // Repeat colors forever + } + } +} +class PrefixColorSelector { + constructor(customColors = []) { + const normalizedColors = typeof customColors === 'string' ? [customColors] : customColors; + this.colorGenerator = createColorGenerator(normalizedColors); + } + /** A list of colors that are readable in a terminal. */ + static get ACCEPTABLE_CONSOLE_COLORS() { + // Colors picked randomly, can be amended if required + return [ + // Prevent duplicates, in case the list becomes significantly large + ...new Set([ + // Text colors + 'cyan', + 'yellow', + 'greenBright', + 'blueBright', + 'magentaBright', + 'white', + 'grey', + 'red', + // Background colors + 'bgCyan', + 'bgYellow', + 'bgGreenBright', + 'bgBlueBright', + 'bgMagenta', + 'bgWhiteBright', + 'bgGrey', + 'bgRed', + ]), + ]; + } + /** + * @returns The given custom colors then a set of acceptable console colors indefinitely. + */ + getNextColor() { + return this.colorGenerator.next().value; + } +} +exports.PrefixColorSelector = PrefixColorSelector; |
