in-parallel-lit 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.cjs CHANGED
@@ -1,413 +1,438 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6
- const node_module = require("node:module");
7
- const sade = require("sade");
8
- const node_stream = require("node:stream");
9
- const node_string_decoder = require("node:string_decoder");
10
- const crossSpawn = require("cross-spawn");
11
- const os = require("node:os");
12
- var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
13
- const signals = {
14
- SIGABRT: 6,
15
- SIGALRM: 14,
16
- SIGBUS: 10,
17
- SIGCHLD: 20,
18
- SIGCONT: 19,
19
- SIGFPE: 8,
20
- SIGHUP: 1,
21
- SIGILL: 4,
22
- SIGINT: 2,
23
- SIGKILL: 9,
24
- SIGPIPE: 13,
25
- SIGQUIT: 3,
26
- SIGSEGV: 11,
27
- SIGSTOP: 17,
28
- SIGTERM: 15,
29
- SIGTRAP: 5,
30
- SIGTSTP: 18,
31
- SIGTTIN: 21,
32
- SIGTTOU: 22,
33
- SIGUSR1: 30,
34
- SIGUSR2: 31
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
35
18
  };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let node_module = require("node:module");
25
+ let sade = require("sade");
26
+ sade = __toESM(sade);
27
+ let node_stream = require("node:stream");
28
+ let node_string_decoder = require("node:string_decoder");
29
+ let cross_spawn = require("cross-spawn");
30
+ let node_os = require("node:os");
31
+ node_os = __toESM(node_os);
32
+ //#region src/lib/get-signal-num.ts
33
+ var signals = {
34
+ SIGABRT: 6,
35
+ SIGALRM: 14,
36
+ SIGBUS: 10,
37
+ SIGCHLD: 20,
38
+ SIGCONT: 19,
39
+ SIGFPE: 8,
40
+ SIGHUP: 1,
41
+ SIGILL: 4,
42
+ SIGINT: 2,
43
+ SIGKILL: 9,
44
+ SIGPIPE: 13,
45
+ SIGQUIT: 3,
46
+ SIGSEGV: 11,
47
+ SIGSTOP: 17,
48
+ SIGTERM: 15,
49
+ SIGTRAP: 5,
50
+ SIGTSTP: 18,
51
+ SIGTTIN: 21,
52
+ SIGTTOU: 22,
53
+ SIGUSR1: 30,
54
+ SIGUSR2: 31
55
+ };
56
+ /**
57
+ * Converts a signal name to a number.
58
+ */
36
59
  function getSignalNumber(signal) {
37
- return signals[signal] || 0;
60
+ return signals[signal] || 0;
38
61
  }
62
+ //#endregion
63
+ //#region src/lib/get-stream-kind.ts
64
+ /**
65
+ * Converts a given stream to an option for `child_process.spawn`.
66
+ */
39
67
  function getStreamKind(stream, std) {
40
- if (stream == null) return "ignore";
41
- if (stream !== std || !std.isTTY) return "pipe";
42
- return stream;
43
- }
44
- class InParallelError extends Error {
45
- constructor(causeResult, allResults) {
46
- super(`"${causeResult.name}" exited with ${causeResult.code}.`);
47
- __publicField(this, "code");
48
- __publicField(this, "results");
49
- this.name = causeResult.name;
50
- this.code = causeResult.code;
51
- this.results = allResults;
52
- }
68
+ if (stream == null) return "ignore";
69
+ if (stream !== std || !std.isTTY) return "pipe";
70
+ return stream;
53
71
  }
54
- const noop = () => {
72
+ //#endregion
73
+ //#region src/lib/in-parallel-error.ts
74
+ var InParallelError = class extends Error {
75
+ code;
76
+ results;
77
+ constructor(causeResult, allResults) {
78
+ super(`"${causeResult.name}" exited with ${causeResult.code}.`);
79
+ this.name = causeResult.name;
80
+ this.code = causeResult.code;
81
+ this.results = allResults;
82
+ }
55
83
  };
56
- class MemoryWritable extends node_stream.Writable {
57
- constructor(data = null) {
58
- super();
59
- __publicField(this, "queue", []);
60
- __publicField(this, "data");
61
- this.data = Array.isArray(data) ? data : [data];
62
- this.queue = [];
63
- for (let chunk of this.data) {
64
- if (chunk == null) continue;
65
- if (!(chunk instanceof Buffer)) {
66
- chunk = Buffer.from(chunk);
67
- }
68
- this.queue.push(chunk);
69
- }
70
- }
71
- _write(chunk, enc, cb = noop) {
72
- let decoder = null;
73
- try {
74
- decoder = enc && enc !== "buffer" ? new node_string_decoder.StringDecoder(enc) : null;
75
- } catch (err) {
76
- return cb(err);
77
- }
78
- let decodedChunk = decoder != null ? decoder.write(chunk) : chunk;
79
- this.queue.push(
80
- Buffer.isBuffer(decodedChunk) ? decodedChunk : Buffer.from(decodedChunk)
81
- );
82
- cb();
83
- }
84
- _getQueueSize() {
85
- let size = 0;
86
- for (let i = 0; i < this.queue.length; i++) {
87
- size += this.queue[i].length;
88
- }
89
- return size;
90
- }
91
- toString() {
92
- let str = "";
93
- for (const chunk of this.queue) {
94
- str += chunk.toString();
95
- }
96
- return str;
97
- }
98
- toBuffer() {
99
- const buffer = Buffer.alloc(this._getQueueSize());
100
- let currentOffset = 0;
101
- for (const chunk of this.queue) {
102
- chunk.copy(buffer, currentOffset);
103
- currentOffset += chunk.length;
104
- }
105
- return buffer;
106
- }
107
- }
84
+ //#endregion
85
+ //#region src/lib/memory-writable.ts
86
+ var noop = () => {};
87
+ var MemoryWritable = class extends node_stream.Writable {
88
+ queue = [];
89
+ data;
90
+ constructor(data = null) {
91
+ super();
92
+ this.data = Array.isArray(data) ? data : [data];
93
+ this.queue = [];
94
+ for (let chunk of this.data) {
95
+ if (chunk == null) continue;
96
+ if (!(chunk instanceof Buffer)) chunk = Buffer.from(chunk);
97
+ this.queue.push(chunk);
98
+ }
99
+ }
100
+ _write(chunk, enc, cb = noop) {
101
+ let decoder = null;
102
+ try {
103
+ decoder = enc && enc !== "buffer" ? new node_string_decoder.StringDecoder(enc) : null;
104
+ } catch (err) {
105
+ return cb(err);
106
+ }
107
+ let decodedChunk = decoder != null ? decoder.write(chunk) : chunk;
108
+ this.queue.push(Buffer.isBuffer(decodedChunk) ? decodedChunk : Buffer.from(decodedChunk));
109
+ cb();
110
+ }
111
+ _getQueueSize() {
112
+ let size = 0;
113
+ for (let i = 0; i < this.queue.length; i++) size += this.queue[i].length;
114
+ return size;
115
+ }
116
+ toString() {
117
+ let str = "";
118
+ for (const chunk of this.queue) str += chunk.toString();
119
+ return str;
120
+ }
121
+ toBuffer() {
122
+ const buffer = Buffer.alloc(this._getQueueSize());
123
+ let currentOffset = 0;
124
+ for (const chunk of this.queue) {
125
+ chunk.copy(buffer, currentOffset);
126
+ currentOffset += chunk.length;
127
+ }
128
+ return buffer;
129
+ }
130
+ };
131
+ //#endregion
132
+ //#region src/lib/remove-from-arr.ts
133
+ /**
134
+ * removeFromArr removes an `item` from `arr`.
135
+ */
108
136
  function removeFromArr(arr, item) {
109
- const index = arr.indexOf(item);
110
- if (index !== -1) {
111
- arr.splice(index, 1);
112
- }
137
+ const index = arr.indexOf(item);
138
+ if (index !== -1) arr.splice(index, 1);
113
139
  }
140
+ //#endregion
141
+ //#region src/lib/kill-pids.ts
142
+ /**
143
+ * Wrap crossSpawn in a Promise
144
+ */
114
145
  function crossSpawnPromise(cmd, args = [], options = {}) {
115
- return new Promise((resolve, reject) => {
116
- let stdout = "";
117
- let stderr = "";
118
- const ch = crossSpawn.spawn(cmd, args, options);
119
- if (ch.stdout === null || ch.stderr === null) {
120
- return reject("stdout/stderr is null");
121
- }
122
- ch.stdout.on("data", (d) => {
123
- stdout += d.toString();
124
- });
125
- ch.stderr.on("data", (d) => {
126
- stderr += d.toString();
127
- });
128
- ch.on("error", (err) => reject(err));
129
- ch.on("close", (code) => {
130
- if (stderr) return reject(stderr);
131
- if (code !== 0) return reject(`${cmd} exited with code ${code}`);
132
- return resolve(stdout);
133
- });
134
- });
146
+ return new Promise((resolve, reject) => {
147
+ let stdout = "";
148
+ let stderr = "";
149
+ const ch = (0, cross_spawn.spawn)(cmd, args, options);
150
+ if (ch.stdout === null || ch.stderr === null) return reject("stdout/stderr is null");
151
+ ch.stdout.on("data", (d) => {
152
+ stdout += d.toString();
153
+ });
154
+ ch.stderr.on("data", (d) => {
155
+ stderr += d.toString();
156
+ });
157
+ ch.on("error", (err) => reject(err));
158
+ ch.on("close", (code) => {
159
+ if (stderr) return reject(stderr);
160
+ if (code !== 0) return reject(`${cmd} exited with code ${code}`);
161
+ return resolve(stdout);
162
+ });
163
+ });
135
164
  }
165
+ /**
166
+ * Kills a process by ID and all its subprocesses.
167
+ */
136
168
  async function killPids(pid, platform = process.platform) {
137
- if (platform === "win32") {
138
- crossSpawn.spawn("taskkill", ["/F", "/T", "/PID", String(pid)]);
139
- return;
140
- }
141
- try {
142
- let stdout = await crossSpawnPromise("ps", ["-A", "-o", "ppid,pid"]);
143
- let stdoutRows = stdout.split(os.EOL);
144
- let pidExists = false;
145
- const pidTree = {};
146
- for (let i = 1; i < stdoutRows.length; i++) {
147
- stdoutRows[i] = stdoutRows[i].trim();
148
- if (!stdoutRows[i]) continue;
149
- let stdoutTuple = stdoutRows[i].split(/\s+/);
150
- let stdoutPpid = parseInt(stdoutTuple[0], 10);
151
- let stdoutPid = parseInt(stdoutTuple[1], 10);
152
- if (!pidExists && stdoutPid === pid || !pidExists && stdoutPpid === pid) {
153
- pidExists = true;
154
- }
155
- if (pidTree[stdoutPpid]) {
156
- pidTree[stdoutPpid].push(stdoutPid);
157
- } else {
158
- pidTree[stdoutPpid] = [stdoutPid];
159
- }
160
- }
161
- if (!pidExists) return;
162
- let idx = 0;
163
- const pids = [pid];
164
- while (idx < pids.length) {
165
- let curpid = pids[idx++];
166
- if (!pidTree[curpid]) continue;
167
- for (let j = 0; j < pidTree[curpid].length; j++) {
168
- pids.push(pidTree[curpid][j]);
169
- }
170
- delete pidTree[curpid];
171
- }
172
- for (const pid2 of pids) {
173
- process.kill(pid2);
174
- }
175
- } catch (err) {
176
- }
169
+ if (platform === "win32") {
170
+ (0, cross_spawn.spawn)("taskkill", [
171
+ "/F",
172
+ "/T",
173
+ "/PID",
174
+ String(pid)
175
+ ]);
176
+ return;
177
+ }
178
+ try {
179
+ const stdoutRows = (await crossSpawnPromise("ps", [
180
+ "-A",
181
+ "-o",
182
+ "ppid,pid"
183
+ ])).split(node_os.default.EOL);
184
+ let pidExists = false;
185
+ const pidTree = {};
186
+ for (let i = 1; i < stdoutRows.length; i++) {
187
+ stdoutRows[i] = stdoutRows[i].trim();
188
+ if (!stdoutRows[i]) continue;
189
+ const stdoutTuple = stdoutRows[i].split(/\s+/);
190
+ const stdoutPpid = parseInt(stdoutTuple[0], 10);
191
+ const stdoutPid = parseInt(stdoutTuple[1], 10);
192
+ if (!pidExists && stdoutPid === pid || !pidExists && stdoutPpid === pid) pidExists = true;
193
+ if (pidTree[stdoutPpid]) pidTree[stdoutPpid].push(stdoutPid);
194
+ else pidTree[stdoutPpid] = [stdoutPid];
195
+ }
196
+ if (!pidExists) return;
197
+ let idx = 0;
198
+ const pids = [pid];
199
+ while (idx < pids.length) {
200
+ const curpid = pids[idx++];
201
+ if (!pidTree[curpid]) continue;
202
+ for (let j = 0; j < pidTree[curpid].length; j++) pids.push(pidTree[curpid][j]);
203
+ delete pidTree[curpid];
204
+ }
205
+ for (const pid of pids) process.kill(pid);
206
+ } catch {}
177
207
  }
208
+ //#endregion
209
+ //#region src/lib/spawn.ts
210
+ /**
211
+ * Launches a new process with the given command.
212
+ * This is almost same as `child_process.spawn`, but it adds a `kill` method
213
+ * that kills the instance process and its sub processes.
214
+ */
178
215
  function spawn(command, args, options) {
179
- const child = crossSpawn.spawn(command, args, options);
180
- child.kill = function kill() {
181
- killPids(this.pid);
182
- return true;
183
- };
184
- return child;
216
+ const child = (0, cross_spawn.spawn)(command, args, options);
217
+ child.kill = function kill() {
218
+ killPids(this.pid);
219
+ return true;
220
+ };
221
+ return child;
185
222
  }
186
- let FORCE_COLOR;
187
- let NODE_DISABLE_COLORS;
188
- let NO_COLOR;
189
- let TERM;
190
- let isTTY = true;
191
- let enabled;
223
+ //#endregion
224
+ //#region src/lib/prefix-transform.ts
225
+ var ALL_BR = /\n/g;
226
+ var PrefixTransform = class extends node_stream.Transform {
227
+ prefix;
228
+ lastPrefix;
229
+ lastIsLinebreak;
230
+ constructor(prefix) {
231
+ super();
232
+ this.prefix = prefix;
233
+ this.lastPrefix = null;
234
+ this.lastIsLinebreak = true;
235
+ }
236
+ _transform(chunk, _enc, cb) {
237
+ const prefixed = `${this.lastIsLinebreak ? this.prefix : this.lastPrefix !== this.prefix ? "\n" : ""}${chunk}`.replace(ALL_BR, `\n${this.prefix}`);
238
+ const index = prefixed.indexOf(this.prefix, Math.max(0, prefixed.length - this.prefix.length));
239
+ this.lastPrefix = this.prefix;
240
+ this.lastIsLinebreak = index !== -1;
241
+ cb(null, index !== -1 ? prefixed.slice(0, index) : prefixed);
242
+ }
243
+ };
244
+ //#endregion
245
+ //#region src/lib/select-color.ts
246
+ var FORCE_COLOR;
247
+ var NODE_DISABLE_COLORS;
248
+ var NO_COLOR;
249
+ var TERM;
250
+ var isTTY = true;
251
+ var enabled;
252
+ /**
253
+ * Check if color support is enabled.
254
+ */
192
255
  function checkColorSupport() {
193
- if (enabled != null) return;
194
- ({ FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM } = process.env);
195
- isTTY = process.stdout && process.stdout.isTTY;
196
- enabled = !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== "dumb" && (FORCE_COLOR != null && FORCE_COLOR !== "0" || isTTY);
256
+ if (enabled != null) return;
257
+ ({FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM} = process.env);
258
+ isTTY = process.stdout?.isTTY;
259
+ enabled = !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== "dumb" && (FORCE_COLOR != null && FORCE_COLOR !== "0" || isTTY);
197
260
  }
261
+ /**
262
+ * Returns functions that wrap a given string with color char codes.
263
+ */
198
264
  function createColor(x, y) {
199
- const rgx = new RegExp(`\\x1b\\[${y}m`, "g");
200
- const open = `\x1B[${x}m`;
201
- const close = `\x1B[${y}m`;
202
- return function(txt) {
203
- checkColorSupport();
204
- if (!enabled) return txt;
205
- return open + (~("" + txt).indexOf(close) ? txt.replace(rgx, close + open) : txt) + close;
206
- };
265
+ const rgx = new RegExp(`\\x1b\\[${y}m`, "g");
266
+ const open = `\x1b[${x}m`;
267
+ const close = `\x1b[${y}m`;
268
+ return function(txt) {
269
+ checkColorSupport();
270
+ if (!enabled) return txt;
271
+ return open + (~`${txt}`.indexOf(close) ? txt.replace(rgx, close + open) : txt) + close;
272
+ };
207
273
  }
208
- const colors = [
209
- createColor(36, 39),
210
- // cyan
211
- createColor(32, 39),
212
- // green
213
- createColor(35, 39),
214
- // magenta
215
- createColor(33, 39),
216
- // yellow
217
- createColor(31, 39)
218
- // red
274
+ var colors = [
275
+ createColor(36, 39),
276
+ createColor(32, 39),
277
+ createColor(35, 39),
278
+ createColor(33, 39),
279
+ createColor(31, 39)
219
280
  ];
220
- let colorIndex = 0;
221
- const taskNamesToColors = /* @__PURE__ */ new Map();
281
+ var colorIndex = 0;
282
+ var taskNamesToColors = /* @__PURE__ */ new Map();
283
+ /**
284
+ * Select a color from given task name.
285
+ */
222
286
  function selectColor(taskName) {
223
- let color = taskNamesToColors.get(taskName);
224
- if (color == null) {
225
- color = colors[colorIndex];
226
- colorIndex = (colorIndex + 1) % colors.length;
227
- taskNamesToColors.set(taskName, color);
228
- }
229
- return color;
230
- }
231
- const ALL_BR = /\n/g;
232
- class PrefixTransform extends node_stream.Transform {
233
- constructor(prefix) {
234
- super();
235
- __publicField(this, "prefix");
236
- __publicField(this, "lastPrefix");
237
- __publicField(this, "lastIsLinebreak");
238
- this.prefix = prefix;
239
- this.lastPrefix = null;
240
- this.lastIsLinebreak = true;
241
- }
242
- _transform(chunk, _enc, cb) {
243
- const firstPrefix = this.lastIsLinebreak ? this.prefix : this.lastPrefix !== this.prefix ? "\n" : "";
244
- const prefixed = `${firstPrefix}${chunk}`.replace(
245
- ALL_BR,
246
- `
247
- ${this.prefix}`
248
- );
249
- const index = prefixed.indexOf(
250
- this.prefix,
251
- Math.max(0, prefixed.length - this.prefix.length)
252
- );
253
- this.lastPrefix = this.prefix;
254
- this.lastIsLinebreak = index !== -1;
255
- cb(null, index !== -1 ? prefixed.slice(0, index) : prefixed);
256
- }
287
+ let color = taskNamesToColors.get(taskName);
288
+ if (color == null) {
289
+ color = colors[colorIndex];
290
+ colorIndex = (colorIndex + 1) % colors.length;
291
+ taskNamesToColors.set(taskName, color);
292
+ }
293
+ return color;
257
294
  }
295
+ //#endregion
296
+ //#region src/lib/wrap-stream-with-label.ts
297
+ /**
298
+ * Wraps stdout/stderr with a transform stream to add the task name as prefix.
299
+ */
258
300
  function wrapStreamWithLabel(source, label) {
259
- if (source == null) return source;
260
- const color = source.isTTY ? selectColor(label) : (x) => x;
261
- const prefix = color(`[${label}] `);
262
- const target = new PrefixTransform(prefix);
263
- target.pipe(source);
264
- return target;
301
+ if (source == null) return source;
302
+ const target = new PrefixTransform((source.isTTY ? selectColor(label) : (x) => x)(`[${label}] `));
303
+ target.pipe(source);
304
+ return target;
265
305
  }
306
+ //#endregion
307
+ //#region src/index.ts
308
+ /**
309
+ * prog represents the main program logic.
310
+ */
266
311
  function prog(opts, proc) {
267
- const { _: tasks, ...options } = opts;
268
- const customTaskNames = options.names != null ? options.names.split(",").map((n) => n.trim()) : [];
269
- return new Promise((resolve, reject) => {
270
- let results = [];
271
- let queue = [];
272
- let promises = [];
273
- let error = null;
274
- let aborted = false;
275
- if (tasks.length === 0) return done();
276
- for (let i = 0; i < tasks.length; i++) {
277
- results.push({ name: tasks[i], code: void 0 });
278
- queue.push({ name: tasks[i], index: i });
279
- }
280
- function done() {
281
- if (error == null) return resolve(results);
282
- return reject(error);
283
- }
284
- function abort() {
285
- if (aborted) return;
286
- aborted = true;
287
- if (promises.length === 0) return done();
288
- for (const p of promises) {
289
- p.abort();
290
- }
291
- return Promise.all(promises).then(done, reject);
292
- }
293
- function next() {
294
- if (aborted) return;
295
- if (queue.length === 0) {
296
- if (promises.length === 0) return done();
297
- return;
298
- }
299
- const task = queue.shift();
300
- if (task == null) return;
301
- const originalOutputStream = proc.stdout;
302
- const optionsClone = {
303
- stdout: proc.stdout,
304
- stderr: proc.stderr,
305
- stdin: proc.stdin,
306
- customName: customTaskNames[task.index]
307
- };
308
- const writer = new MemoryWritable();
309
- if (options["aggregate-output"]) {
310
- optionsClone.stdout = writer;
311
- }
312
- const promise = runTask(task.name, optionsClone);
313
- promises.push(promise);
314
- promise.then(
315
- (result) => {
316
- removeFromArr(promises, promise);
317
- if (aborted) return;
318
- if (options["aggregate-output"]) {
319
- originalOutputStream.write(writer.toString());
320
- }
321
- if (result.code === null && result.signal !== null) {
322
- result.code = 128 + getSignalNumber(result.signal);
323
- }
324
- results[task.index].code = result.code;
325
- if (result.code) {
326
- error = new InParallelError(result, results);
327
- if (!options["continue-on-error"]) {
328
- return abort();
329
- }
330
- }
331
- next();
332
- },
333
- (err) => {
334
- removeFromArr(promises, promise);
335
- if (!options["continue-on-error"]) {
336
- error = err;
337
- return abort();
338
- }
339
- next();
340
- }
341
- );
342
- }
343
- let end = tasks.length;
344
- if (typeof options["max-parallel"] === "number" && options["max-parallel"] > 0) {
345
- end = Math.min(tasks.length, options["max-parallel"]);
346
- }
347
- for (let i = 0; i < end; ++i) {
348
- next();
349
- }
350
- });
312
+ const { _: tasks, ...options } = opts;
313
+ const customTaskNames = options.names != null ? options.names.split(",").map((n) => n.trim()) : [];
314
+ return new Promise((resolve, reject) => {
315
+ let results = [];
316
+ let queue = [];
317
+ let promises = [];
318
+ let error = null;
319
+ let aborted = false;
320
+ if (tasks.length === 0) return done();
321
+ for (let i = 0; i < tasks.length; i++) {
322
+ results.push({
323
+ name: tasks[i],
324
+ code: void 0
325
+ });
326
+ queue.push({
327
+ name: tasks[i],
328
+ index: i
329
+ });
330
+ }
331
+ function done() {
332
+ if (error == null) return resolve(results);
333
+ return reject(error);
334
+ }
335
+ function abort() {
336
+ if (aborted) return;
337
+ aborted = true;
338
+ if (promises.length === 0) return done();
339
+ for (const p of promises) p.abort();
340
+ return Promise.all(promises).then(done, reject);
341
+ }
342
+ function next() {
343
+ if (aborted) return;
344
+ if (queue.length === 0) {
345
+ if (promises.length === 0) return done();
346
+ return;
347
+ }
348
+ const task = queue.shift();
349
+ if (task == null) return;
350
+ const originalOutputStream = proc.stdout;
351
+ const optionsClone = {
352
+ stdout: proc.stdout,
353
+ stderr: proc.stderr,
354
+ stdin: proc.stdin,
355
+ customName: customTaskNames[task.index]
356
+ };
357
+ const writer = new MemoryWritable();
358
+ if (options["aggregate-output"]) optionsClone.stdout = writer;
359
+ const promise = runTask(task.name, optionsClone);
360
+ promises.push(promise);
361
+ promise.then((result) => {
362
+ removeFromArr(promises, promise);
363
+ if (aborted) return;
364
+ if (options["aggregate-output"]) originalOutputStream.write(writer.toString());
365
+ if (result.code === null && result.signal !== null) result.code = 128 + getSignalNumber(result.signal);
366
+ results[task.index].code = result.code;
367
+ if (result.code) {
368
+ error = new InParallelError(result, results);
369
+ if (!options["continue-on-error"]) return abort();
370
+ }
371
+ next();
372
+ }, (err) => {
373
+ removeFromArr(promises, promise);
374
+ if (!options["continue-on-error"]) {
375
+ error = err;
376
+ return abort();
377
+ }
378
+ next();
379
+ });
380
+ }
381
+ let end = tasks.length;
382
+ if (typeof options["max-parallel"] === "number" && options["max-parallel"] > 0) end = Math.min(tasks.length, options["max-parallel"]);
383
+ for (let i = 0; i < end; ++i) next();
384
+ });
351
385
  }
386
+ /**
387
+ * runTask executes a single task as a child process.
388
+ */
352
389
  function runTask(name, opts) {
353
- let proc = null;
354
- const task = new Promise((resolve, reject) => {
355
- const stdin = opts.stdin;
356
- const stdout = wrapStreamWithLabel(opts.stdout, opts.customName || name);
357
- const stderr = wrapStreamWithLabel(opts.stderr, opts.customName || name);
358
- const stdinKind = getStreamKind(stdin, process.stdin);
359
- const stdoutKind = getStreamKind(stdout, process.stdout);
360
- const stderrKind = getStreamKind(stderr, process.stderr);
361
- const [spawnName, ...spawnArgs] = name.split(" ");
362
- proc = spawn(spawnName, spawnArgs, {
363
- stdio: [stdinKind, stdoutKind, stderrKind]
364
- });
365
- if (proc == null) return reject("Failed to spawn process");
366
- if (stdinKind === "pipe") {
367
- stdin.pipe(proc.stdin);
368
- }
369
- if (stdoutKind === "pipe") {
370
- proc.stdout.pipe(stdout, { end: false });
371
- }
372
- if (stderrKind === "pipe") {
373
- proc.stderr.pipe(stderr, { end: false });
374
- }
375
- proc.on("error", (err) => {
376
- proc = null;
377
- return reject(err);
378
- });
379
- proc.on("close", (code, signal) => {
380
- proc = null;
381
- return resolve({ name, code, signal });
382
- });
383
- });
384
- task.abort = () => {
385
- if (proc == null) return;
386
- proc.kill();
387
- proc = null;
388
- };
389
- return task;
390
+ let proc = null;
391
+ const task = new Promise((resolve, reject) => {
392
+ const stdin = opts.stdin;
393
+ const stdout = wrapStreamWithLabel(opts.stdout, opts.customName || name);
394
+ const stderr = wrapStreamWithLabel(opts.stderr, opts.customName || name);
395
+ const stdinKind = getStreamKind(stdin, process.stdin);
396
+ const stdoutKind = getStreamKind(stdout, process.stdout);
397
+ const stderrKind = getStreamKind(stderr, process.stderr);
398
+ const [spawnName, ...spawnArgs] = name.split(" ");
399
+ proc = spawn(spawnName, spawnArgs, { stdio: [
400
+ stdinKind,
401
+ stdoutKind,
402
+ stderrKind
403
+ ] });
404
+ if (proc == null) return reject("Failed to spawn process");
405
+ if (stdinKind === "pipe") stdin.pipe(proc.stdin);
406
+ if (stdoutKind === "pipe") proc.stdout.pipe(stdout, { end: false });
407
+ if (stderrKind === "pipe") proc.stderr.pipe(stderr, { end: false });
408
+ proc.on("error", (err) => {
409
+ proc = null;
410
+ return reject(err);
411
+ });
412
+ proc.on("close", (code, signal) => {
413
+ proc = null;
414
+ return resolve({
415
+ name,
416
+ code,
417
+ signal
418
+ });
419
+ });
420
+ });
421
+ task.abort = () => {
422
+ if (proc == null) return;
423
+ proc.kill();
424
+ proc = null;
425
+ };
426
+ return task;
390
427
  }
428
+ //#endregion
429
+ //#region src/bin.ts
391
430
  async function run(argv) {
392
- const require$1 = node_module.createRequire(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.src || new URL("bin.cjs", document.baseURI).href);
393
- const packageJson = require$1("../package.json");
394
- process.stdout.setMaxListeners(0);
395
- process.stderr.setMaxListeners(0);
396
- process.stdin.setMaxListeners(0);
397
- sade("in-parallel", true).version(packageJson.version).describe(packageJson.description).option(
398
- `-n, --names`,
399
- `List of custom names to be used in prefix template.`
400
- ).example(`-n "first,second" "ping google.com" "ping 172.0.0.1"`).option(
401
- `-c, --continue-on-error`,
402
- `Set the flag to continue executing other/subsequent tasks even if a task threw an error. 'in-parallel' itself will exit with non-zero code if one or more tasks threw error(s).`
403
- ).option(
404
- `--max-parallel`,
405
- `Set the maximum number of parallelism. Default is unlimited.`,
406
- 0
407
- ).option(
408
- `--aggregate-output`,
409
- `Avoid interleaving output by delaying printing of each command's output until it has finished.`,
410
- false
411
- ).action((opts) => prog(opts, process)).parse(argv);
431
+ const packageJson = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href)("../package.json");
432
+ process.stdout.setMaxListeners(0);
433
+ process.stderr.setMaxListeners(0);
434
+ process.stdin.setMaxListeners(0);
435
+ (0, sade.default)("in-parallel", true).version(packageJson.version).describe(packageJson.description).option(`-n, --names`, `List of custom names to be used in prefix template.`).example(`-n "first,second" "ping google.com" "ping 172.0.0.1"`).option(`-c, --continue-on-error`, `Set the flag to continue executing other/subsequent tasks even if a task threw an error. 'in-parallel' itself will exit with non-zero code if one or more tasks threw error(s).`).option(`--max-parallel`, `Set the maximum number of parallelism. Default is unlimited.`, 0).option(`--aggregate-output`, `Avoid interleaving output by delaying printing of each command's output until it has finished.`, false).action((opts) => prog(opts, process)).parse(argv);
412
436
  }
413
437
  run(process.argv);
438
+ //#endregion