printable-shell-command 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -47,7 +47,11 @@ import { PrintableShellCommand } from "printable-shell-command";
47
47
  import { spawn } from "node:child_process";
48
48
 
49
49
  const command = new PrintableShellCommand(/* … */);
50
- const child_process = spawn(...command.toCommandWithFlatArgs()); // Note the `...`
50
+ const child_process = spawn(...command.toCommandWithFlatAr()); // Note the `...`
51
+
52
+ // or directly
53
+ await command.spawnNode().success;
54
+ await command.spawnNodeInherit().success;
51
55
  ```
52
56
 
53
57
  ### Spawn a process in `bun`
@@ -58,6 +62,10 @@ import { spawn } from "bun";
58
62
 
59
63
  const command = new PrintableShellCommand(/* … */);
60
64
  await spawn(command.toFlatCommand()).exited;
65
+
66
+ // or directly
67
+ await command.spawnBun().success;
68
+ await command.spawnBunInherit().success;
61
69
  ```
62
70
 
63
71
  ## Protections
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "printable-shell-command",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "main": "./src/index.ts",
5
5
  "type": "module",
6
6
  "exports": {
package/src/index.ts CHANGED
@@ -273,8 +273,9 @@ export class PrintableShellCommand {
273
273
  return serializedEntries.join(this.#entrySeparator(options));
274
274
  }
275
275
 
276
- public print(options?: PrintOptions): void {
276
+ public print(options?: PrintOptions): PrintableShellCommand {
277
277
  console.log(this.getPrintableCommand(options));
278
+ return this;
278
279
  }
279
280
 
280
281
  public spawnNode<
@@ -282,14 +283,58 @@ export class PrintableShellCommand {
282
283
  Stdout extends NodeStdioNull | NodeStdioPipe,
283
284
  Stderr extends NodeStdioNull | NodeStdioPipe,
284
285
  >(
285
- options:
286
+ options?:
286
287
  | NodeSpawnOptions
287
288
  | NodeSpawnOptionsWithoutStdio
288
289
  | NodeSpawnOptionsWithStdioTuple<Stdin, Stdout, Stderr>,
289
290
  ): // TODO: figure out how to return `ChildProcessByStdio<…>` without duplicating fragile boilerplate.
290
- NodeChildProcess {
291
+ NodeChildProcess & { success: Promise<void> } {
291
292
  const { spawn } = process.getBuiltinModule("node:child_process");
292
- return spawn(...this.forNode(), options);
293
+ const subprocess = spawn(...this.forNode(), options) as NodeChildProcess & {
294
+ success: Promise<void>;
295
+ };
296
+ Object.defineProperty(subprocess, "success", {
297
+ get() {
298
+ return new Promise<void>((resolve, reject) =>
299
+ this.addListener(
300
+ "exit",
301
+ (exitCode: number /* we only use the first arg */) => {
302
+ if (exitCode === 0) {
303
+ resolve();
304
+ } else {
305
+ reject(`Command failed with non-zero exit code: ${exitCode}`);
306
+ }
307
+ },
308
+ ),
309
+ );
310
+ },
311
+ enumerable: false,
312
+ });
313
+ return subprocess;
314
+ }
315
+
316
+ // A wrapper for `.spawnNode(…)` that sets stdio to `"inherit"` (common for
317
+ // invoking commands from scripts whose output and interaction should be
318
+ // surfaced to the user).
319
+ public spawnNodeInherit(
320
+ options?: Omit<NodeSpawnOptions, "stdio">,
321
+ ): NodeChildProcess & { success: Promise<void> } {
322
+ if (options && "stdio" in options) {
323
+ throw new Error("Unexpected `stdio` field.");
324
+ }
325
+ return this.spawnNode({ ...options, stdio: "inherit" });
326
+ }
327
+
328
+ /** Equivalent to:
329
+ *
330
+ * ```
331
+ * await this.print().spawnNodeInherit().success;
332
+ * ```
333
+ */
334
+ public async shellOutNode(
335
+ options?: Omit<NodeSpawnOptions, "stdio">,
336
+ ): Promise<void> {
337
+ await this.print().spawnNodeInherit(options).success;
293
338
  }
294
339
 
295
340
  // The returned subprocess includes a `.success` `Promise` field, per https://github.com/oven-sh/bun/issues/8313
@@ -300,6 +345,9 @@ export class PrintableShellCommand {
300
345
  >(
301
346
  options?: Omit<BunSpawnOptions.OptionsObject<In, Out, Err>, "cmd">,
302
347
  ): BunSubprocess<In, Out, Err> & { success: Promise<void> } {
348
+ if (options && "cmd" in options) {
349
+ throw new Error("Unexpected `cmd` field.");
350
+ }
303
351
  const { spawn } = process.getBuiltinModule("bun") as typeof import("bun");
304
352
  const subprocess = spawn({
305
353
  ...options,
@@ -313,7 +361,11 @@ export class PrintableShellCommand {
313
361
  if (exitCode === 0) {
314
362
  resolve();
315
363
  } else {
316
- reject("Command failed.");
364
+ reject(
365
+ new Error(
366
+ `Command failed with non-zero exit code: ${exitCode}`,
367
+ ),
368
+ );
317
369
  }
318
370
  })
319
371
  .catch(reject),
@@ -323,4 +375,45 @@ export class PrintableShellCommand {
323
375
  });
324
376
  return subprocess;
325
377
  }
378
+
379
+ // A wrapper for `.spawnBunInherit(…)` that sets stdio to `"inherit"` (common for
380
+ // invoking commands from scripts whose output and interaction should be
381
+ // surfaced to the user).
382
+ public spawnBunInherit(
383
+ options?: Omit<
384
+ Omit<
385
+ BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">,
386
+ "cmd"
387
+ >,
388
+ "stdio"
389
+ >,
390
+ ): BunSubprocess<"inherit", "inherit", "inherit"> & {
391
+ success: Promise<void>;
392
+ } {
393
+ if (options && "stdio" in options) {
394
+ throw new Error("Unexpected `stdio` field.");
395
+ }
396
+ return this.spawnBun({
397
+ ...options,
398
+ stdio: ["inherit", "inherit", "inherit"],
399
+ });
400
+ }
401
+
402
+ /** Equivalent to:
403
+ *
404
+ * ```
405
+ * await this.print().spawnBunInherit().success;
406
+ * ```
407
+ */
408
+ public async shellOutBun(
409
+ options?: Omit<
410
+ Omit<
411
+ BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">,
412
+ "cmd"
413
+ >,
414
+ "stdio"
415
+ >,
416
+ ): Promise<void> {
417
+ await this.print().spawnBunInherit(options).success;
418
+ }
326
419
  }
@@ -1,4 +1,3 @@
1
- import { spawn } from "bun";
2
1
  import { PrintableShellCommand } from "../src";
3
2
 
4
3
  const command = new PrintableShellCommand("ffmpeg", [
@@ -8,5 +7,4 @@ const command = new PrintableShellCommand("ffmpeg", [
8
7
  "./test/My video (slow-mo).mov",
9
8
  ]);
10
9
 
11
- command.print();
12
- await spawn(command.toFlatCommand()).exited;
10
+ await command.shellOutBun();
@@ -1,4 +1,3 @@
1
- import { spawn } from "node:child_process";
2
1
  import { PrintableShellCommand } from "../src";
3
2
 
4
3
  const command = new PrintableShellCommand("ffmpeg", [
@@ -8,7 +7,4 @@ const command = new PrintableShellCommand("ffmpeg", [
8
7
  "./test/My video (slow-mo).mov",
9
8
  ]);
10
9
 
11
- command.print();
12
- await new Promise((resolve, reject) => {
13
- spawn(...command.toCommandWithFlatArgs()).addListener("exit", resolve);
14
- });
10
+ command.print().shellOutNode();