printable-shell-command 1.2.0 → 2.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/README.md
CHANGED
|
@@ -50,8 +50,8 @@ const command = new PrintableShellCommand(/* … */);
|
|
|
50
50
|
const child_process = spawn(...command.toCommandWithFlatArgs()); // Note the `...`
|
|
51
51
|
|
|
52
52
|
// or directly
|
|
53
|
-
await command.
|
|
54
|
-
await command.
|
|
53
|
+
await command.spawn().success;
|
|
54
|
+
await command.spawnInherit().success;
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
### Spawn a process in `bun`
|
|
@@ -64,8 +64,8 @@ const command = new PrintableShellCommand(/* … */);
|
|
|
64
64
|
await spawn(command.toFlatCommand()).exited;
|
|
65
65
|
|
|
66
66
|
// or directly
|
|
67
|
-
await command.spawnBun().success;
|
|
68
|
-
await command.spawnBunInherit().success;
|
|
67
|
+
await command.bun.spawnBun().success;
|
|
68
|
+
await command.bun.spawnBunInherit().success;
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
## Protections
|
|
@@ -103,50 +103,50 @@ export declare class PrintableShellCommand {
|
|
|
103
103
|
/**
|
|
104
104
|
* The returned child process includes a `.success` `Promise` field, per https://github.com/oven-sh/bun/issues/8313
|
|
105
105
|
*/
|
|
106
|
-
|
|
106
|
+
spawn<Stdin extends NodeStdioNull | NodeStdioPipe, Stdout extends NodeStdioNull | NodeStdioPipe, Stderr extends NodeStdioNull | NodeStdioPipe>(options?: NodeSpawnOptions | NodeSpawnOptionsWithoutStdio | NodeSpawnOptionsWithStdioTuple<Stdin, Stdout, Stderr>): // TODO: figure out how to return `ChildProcessByStdio<…>` without duplicating fragile boilerplate.
|
|
107
107
|
NodeChildProcess & {
|
|
108
108
|
success: Promise<void>;
|
|
109
109
|
};
|
|
110
110
|
/** A wrapper for `.spawnNode(…)` that sets stdio to `"inherit"` (common for
|
|
111
111
|
* invoking commands from scripts whose output and interaction should be
|
|
112
112
|
* surfaced to the user). */
|
|
113
|
-
|
|
113
|
+
spawnInherit(options?: Omit<NodeSpawnOptions, "stdio">): NodeChildProcess & {
|
|
114
114
|
success: Promise<void>;
|
|
115
115
|
};
|
|
116
|
+
stdout(options?: Omit<NodeSpawnOptions, "stdio">): Response;
|
|
116
117
|
/** Equivalent to:
|
|
117
118
|
*
|
|
118
119
|
* ```
|
|
119
|
-
* await this.print().
|
|
120
|
+
* await this.print().spawnInherit(…).success;
|
|
120
121
|
* ```
|
|
121
122
|
*/
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
shellOut(options?: Omit<NodeSpawnOptions, "stdio">): Promise<void>;
|
|
124
|
+
bun: {
|
|
125
|
+
/** Equivalent to:
|
|
126
|
+
*
|
|
127
|
+
* ```
|
|
128
|
+
* await this.print().bun.spawnBunInherit(…).success;
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
spawnBun: <const In extends BunSpawnOptions.Writable = "ignore", const Out extends BunSpawnOptions.Readable = "pipe", const Err extends BunSpawnOptions.Readable = "inherit">(options?: Omit<BunSpawnOptions.OptionsObject<In, Out, Err>, "cmd">) => BunSubprocess<In, Out, Err> & {
|
|
132
|
+
success: Promise<void>;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* A wrapper for `.spawnBunInherit(…)` that sets stdio to `"inherit"` (common
|
|
136
|
+
* for invoking commands from scripts whose output and interaction should be
|
|
137
|
+
* surfaced to the user).
|
|
138
|
+
*/
|
|
139
|
+
spawnBunInherit: (options?: Omit<Omit<BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">, "cmd">, "stdio">) => BunSubprocess<"inherit", "inherit", "inherit"> & {
|
|
140
|
+
success: Promise<void>;
|
|
141
|
+
};
|
|
142
|
+
/** Equivalent to:
|
|
143
|
+
*
|
|
144
|
+
* ```
|
|
145
|
+
* new Response(this.bun.spawnBun(…).stdout);
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
spawnBunStdout: (options?: Omit<Omit<BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">, "cmd">, "stdio">) => Response;
|
|
149
|
+
shellOutBun: (options?: Omit<Omit<BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">, "cmd">, "stdio">) => Promise<void>;
|
|
128
150
|
};
|
|
129
|
-
/**
|
|
130
|
-
* A wrapper for `.spawnBunInherit(…)` that sets stdio to `"inherit"` (common
|
|
131
|
-
* for invoking commands from scripts whose output and interaction should be
|
|
132
|
-
* surfaced to the user).
|
|
133
|
-
*/
|
|
134
|
-
spawnBunInherit(options?: Omit<Omit<BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">, "cmd">, "stdio">): BunSubprocess<"inherit", "inherit", "inherit"> & {
|
|
135
|
-
success: Promise<void>;
|
|
136
|
-
};
|
|
137
|
-
/** Equivalent to:
|
|
138
|
-
*
|
|
139
|
-
* ```
|
|
140
|
-
* new Response(this.spawnBun(…).stdout);
|
|
141
|
-
* ```
|
|
142
|
-
*/
|
|
143
|
-
spawnBunStdout(options?: Omit<Omit<BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">, "cmd">, "stdio">): Response;
|
|
144
|
-
/** Equivalent to:
|
|
145
|
-
*
|
|
146
|
-
* ```
|
|
147
|
-
* await this.print().spawnBunInherit(…).success;
|
|
148
|
-
* ```
|
|
149
|
-
*/
|
|
150
|
-
shellOutBun(options?: Omit<Omit<BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">, "cmd">, "stdio">): Promise<void>;
|
|
151
151
|
}
|
|
152
152
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
+
import { Readable } from "node:stream";
|
|
2
3
|
import { styleText } from "node:util";
|
|
3
4
|
var DEFAULT_MAIN_INDENTATION = "";
|
|
4
5
|
var DEFAULT_ARG_INDENTATION = " ";
|
|
@@ -193,7 +194,7 @@ var PrintableShellCommand = class {
|
|
|
193
194
|
return "";
|
|
194
195
|
}
|
|
195
196
|
if (options.skipLineWrapBeforeFirstArg ?? false) {
|
|
196
|
-
return
|
|
197
|
+
return INLINE_SEPARATOR;
|
|
197
198
|
}
|
|
198
199
|
return this.#intraEntrySeparator(options);
|
|
199
200
|
}
|
|
@@ -223,7 +224,7 @@ var PrintableShellCommand = class {
|
|
|
223
224
|
/**
|
|
224
225
|
* The returned child process includes a `.success` `Promise` field, per https://github.com/oven-sh/bun/issues/8313
|
|
225
226
|
*/
|
|
226
|
-
|
|
227
|
+
spawn(options) {
|
|
227
228
|
const { spawn } = process.getBuiltinModule("node:child_process");
|
|
228
229
|
const subprocess = spawn(...this.forNode(), options);
|
|
229
230
|
Object.defineProperty(subprocess, "success", {
|
|
@@ -248,25 +249,35 @@ var PrintableShellCommand = class {
|
|
|
248
249
|
/** A wrapper for `.spawnNode(…)` that sets stdio to `"inherit"` (common for
|
|
249
250
|
* invoking commands from scripts whose output and interaction should be
|
|
250
251
|
* surfaced to the user). */
|
|
251
|
-
|
|
252
|
+
spawnInherit(options) {
|
|
252
253
|
if (options && "stdio" in options) {
|
|
253
254
|
throw new Error("Unexpected `stdio` field.");
|
|
254
255
|
}
|
|
255
|
-
return this.
|
|
256
|
+
return this.spawn({ ...options, stdio: "inherit" });
|
|
257
|
+
}
|
|
258
|
+
stdout(options) {
|
|
259
|
+
if (options && "stdio" in options) {
|
|
260
|
+
throw new Error("Unexpected `stdio` field.");
|
|
261
|
+
}
|
|
262
|
+
const subprocess = this.spawn({
|
|
263
|
+
...options,
|
|
264
|
+
stdio: ["ignore", "pipe", "inherit"]
|
|
265
|
+
});
|
|
266
|
+
return new Response(Readable.toWeb(subprocess.stdout));
|
|
256
267
|
}
|
|
257
268
|
/** Equivalent to:
|
|
258
269
|
*
|
|
259
270
|
* ```
|
|
260
|
-
* await this.print().
|
|
271
|
+
* await this.print().spawnInherit(…).success;
|
|
261
272
|
* ```
|
|
262
273
|
*/
|
|
263
|
-
async
|
|
264
|
-
await this.print().
|
|
274
|
+
async shellOut(options) {
|
|
275
|
+
await this.print().spawnInherit(options).success;
|
|
265
276
|
}
|
|
266
277
|
/**
|
|
267
278
|
* The returned subprocess includes a `.success` `Promise` field, per https://github.com/oven-sh/bun/issues/8313
|
|
268
279
|
*/
|
|
269
|
-
spawnBun(options) {
|
|
280
|
+
#spawnBun(options) {
|
|
270
281
|
if (options && "cmd" in options) {
|
|
271
282
|
throw new Error("Unexpected `cmd` field.");
|
|
272
283
|
}
|
|
@@ -295,38 +306,44 @@ var PrintableShellCommand = class {
|
|
|
295
306
|
});
|
|
296
307
|
return subprocess;
|
|
297
308
|
}
|
|
298
|
-
|
|
299
|
-
* A wrapper for `.spawnBunInherit(…)` that sets stdio to `"inherit"` (common
|
|
300
|
-
* for invoking commands from scripts whose output and interaction should be
|
|
301
|
-
* surfaced to the user).
|
|
302
|
-
*/
|
|
303
|
-
spawnBunInherit(options) {
|
|
309
|
+
#spawnBunInherit(options) {
|
|
304
310
|
if (options && "stdio" in options) {
|
|
305
311
|
throw new Error("Unexpected `stdio` field.");
|
|
306
312
|
}
|
|
307
|
-
return this.spawnBun({
|
|
313
|
+
return this.bun.spawnBun({
|
|
308
314
|
...options,
|
|
309
315
|
stdio: ["inherit", "inherit", "inherit"]
|
|
310
316
|
});
|
|
311
317
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
* ```
|
|
315
|
-
* new Response(this.spawnBun(…).stdout);
|
|
316
|
-
* ```
|
|
317
|
-
*/
|
|
318
|
-
spawnBunStdout(options) {
|
|
319
|
-
return new Response(this.spawnBun(options).stdout);
|
|
318
|
+
#spawnBunStdout(options) {
|
|
319
|
+
return new Response(this.bun.spawnBun(options).stdout);
|
|
320
320
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
* ```
|
|
324
|
-
* await this.print().spawnBunInherit(…).success;
|
|
325
|
-
* ```
|
|
326
|
-
*/
|
|
327
|
-
async shellOutBun(options) {
|
|
328
|
-
await this.print().spawnBunInherit(options).success;
|
|
321
|
+
async #shellOutBun(options) {
|
|
322
|
+
await this.print().bun.spawnBunInherit(options).success;
|
|
329
323
|
}
|
|
324
|
+
bun = {
|
|
325
|
+
/** Equivalent to:
|
|
326
|
+
*
|
|
327
|
+
* ```
|
|
328
|
+
* await this.print().bun.spawnBunInherit(…).success;
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
spawnBun: this.#spawnBun.bind(this),
|
|
332
|
+
/**
|
|
333
|
+
* A wrapper for `.spawnBunInherit(…)` that sets stdio to `"inherit"` (common
|
|
334
|
+
* for invoking commands from scripts whose output and interaction should be
|
|
335
|
+
* surfaced to the user).
|
|
336
|
+
*/
|
|
337
|
+
spawnBunInherit: this.#spawnBunInherit.bind(this),
|
|
338
|
+
/** Equivalent to:
|
|
339
|
+
*
|
|
340
|
+
* ```
|
|
341
|
+
* new Response(this.bun.spawnBun(…).stdout);
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
spawnBunStdout: this.#spawnBunStdout.bind(this),
|
|
345
|
+
shellOutBun: this.#shellOutBun.bind(this)
|
|
346
|
+
};
|
|
330
347
|
};
|
|
331
348
|
export {
|
|
332
349
|
PrintableShellCommand
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n ChildProcess as NodeChildProcess,\n SpawnOptions as NodeSpawnOptions,\n SpawnOptionsWithoutStdio as NodeSpawnOptionsWithoutStdio,\n SpawnOptionsWithStdioTuple as NodeSpawnOptionsWithStdioTuple,\n StdioNull as NodeStdioNull,\n StdioPipe as NodeStdioPipe,\n} from \"node:child_process\";\nimport { styleText } from \"node:util\";\nimport type {\n SpawnOptions as BunSpawnOptions,\n Subprocess as BunSubprocess,\n} from \"bun\";\n\nconst DEFAULT_MAIN_INDENTATION = \"\";\nconst DEFAULT_ARG_INDENTATION = \" \";\nconst DEFAULT_ARGUMENT_LINE_WRAPPING = \"by-entry\";\n\nconst INLINE_SEPARATOR = \" \";\nconst LINE_WRAP_LINE_END = \" \\\\\\n\";\n\n// biome-ignore lint/suspicious/noExplicitAny: This is the correct type nere.\nfunction isString(s: any): s is string {\n return typeof s === \"string\";\n}\n// biome-ignore lint/suspicious/noExplicitAny: This is the correct type nere.\nfunction isStringArray(entries: any[]): entries is string[] {\n for (const entry of entries) {\n if (!isString(entry)) {\n return false;\n }\n }\n return true;\n}\n\n// TODO: allow `.toString()`ables?\ntype SingleArgument = string;\ntype FlagArgumentGroup = string[];\ntype ArgsEntry = SingleArgument | FlagArgumentGroup;\ntype Args = ArgsEntry[];\n\nexport interface PrintOptions {\n /** Defaults to \"\" */\n mainIndentation?: string;\n /** Defaults to \" \" */\n argIndentation?: string;\n /**\n * - `\"auto\"`: Quote only arguments that need it for safety. This tries to be\n * portable and safe across shells, but true safety and portability is hard\n * to guarantee.\n * - `\"extra-safe\"`: Quote all arguments, even ones that don't need it. This is\n * more likely to be safe under all circumstances.\n */\n quoting?: \"auto\" | \"extra-safe\";\n /** Line wrapping to use between arguments. Defaults to `\"by-entry\"`. */\n argumentLineWrapping?:\n | \"by-entry\"\n | \"nested-by-entry\"\n | \"by-argument\"\n | \"inline\";\n /** Include the first arg (or first arg group) on the same line as the command, regardless of the `argumentLineWrapping` setting. */\n skipLineWrapBeforeFirstArg?: true | false;\n /**\n * Style text using `node`'s [`styleText(\u2026)`](https://nodejs.org/api/util.html#utilstyletextformat-text-options)\n *\n * Example usage:\n *\n * ```\n * new PrintableShellCommand(\"echo\", [\"hi\"]).print({\n * styleTextFormat: [\"gray\", \"bold\"],\n * });\n * */\n styleTextFormat?: Parameters<typeof styleText>[0];\n}\n\n// https://mywiki.wooledge.org/BashGuide/SpecialCharacters\nconst SPECIAL_SHELL_CHARACTERS = new Set([\n \" \",\n '\"',\n \"'\",\n \"`\",\n \"|\",\n \"$\",\n \"*\",\n \"?\",\n \">\",\n \"<\",\n \"(\",\n \")\",\n \"[\",\n \"]\",\n \"{\",\n \"}\",\n \"&\",\n \"\\\\\",\n \";\",\n \"#\",\n]);\n\n// https://mywiki.wooledge.org/BashGuide/SpecialCharacters\nconst SPECIAL_SHELL_CHARACTERS_FOR_MAIN_COMMAND =\n // biome-ignore lint/suspicious/noExplicitAny: Workaround to make this package easier to use in a project that otherwise only uses ES2022.)\n (SPECIAL_SHELL_CHARACTERS as unknown as any).union(new Set([\"=\"]));\n\nexport class PrintableShellCommand {\n #commandName: string;\n constructor(\n commandName: string,\n private args: Args = [],\n ) {\n if (!isString(commandName)) {\n // biome-ignore lint/suspicious/noExplicitAny: We want to print this, no matter what it is.\n throw new Error(\"Command name is not a string:\", commandName as any);\n }\n this.#commandName = commandName;\n if (typeof args === \"undefined\") {\n return;\n }\n if (!Array.isArray(args)) {\n throw new Error(\"Command arguments are not an array\");\n }\n for (let i = 0; i < args.length; i++) {\n const argEntry = args[i];\n if (typeof argEntry === \"string\") {\n continue;\n }\n if (Array.isArray(argEntry) && isStringArray(argEntry)) {\n continue;\n }\n throw new Error(`Invalid arg entry at index: ${i}`);\n }\n }\n\n get commandName(): string {\n return this.#commandName;\n }\n\n /** For use with `bun`.\n *\n * Usage example:\n *\n * ```\n * import { PrintableShellCommand } from \"printable-shell-command\";\n * import { spawn } from \"bun\";\n *\n * const command = new PrintableShellCommand( \u2026 );\n * await spawn(command.toFlatCommand()).exited;\n * ```\n */\n public toFlatCommand(): string[] {\n return [this.commandName, ...this.args.flat()];\n }\n\n /**\n * Convenient alias for `toFlatCommand()`.\n *\n * Usage example:\n *\n * ```\n * import { PrintableShellCommand } from \"printable-shell-command\";\n * import { spawn } from \"bun\";\n *\n * const command = new PrintableShellCommand( \u2026 );\n * await spawn(command.forBun()).exited;\n * ```\n *\n * */\n public forBun(): string[] {\n return this.toFlatCommand();\n }\n\n /**\n * For use with `node:child_process`\n *\n * Usage example:\n *\n * ```\n * import { PrintableShellCommand } from \"printable-shell-command\";\n * import { spawn } from \"node:child_process\";\n *\n * const command = new PrintableShellCommand( \u2026 );\n * const child_process = spawn(...command.toCommandWithFlatArgs()); // Note the `...`\n * ```\n *\n */\n public toCommandWithFlatArgs(): [string, string[]] {\n return [this.commandName, this.args.flat()];\n }\n\n /**\n * For use with `node:child_process`\n *\n * Usage example:\n *\n * ```\n * import { PrintableShellCommand } from \"printable-shell-command\";\n * import { spawn } from \"node:child_process\";\n *\n * const command = new PrintableShellCommand( \u2026 );\n * const child_process = spawn(...command.forNode()); // Note the `...`\n * ```\n *\n * Convenient alias for `toCommandWithFlatArgs()`.\n */\n public forNode(): [string, string[]] {\n return this.toCommandWithFlatArgs();\n }\n\n #escapeArg(\n arg: string,\n isMainCommand: boolean,\n options: PrintOptions,\n ): string {\n const argCharacters = new Set(arg);\n const specialShellCharacters = isMainCommand\n ? SPECIAL_SHELL_CHARACTERS_FOR_MAIN_COMMAND\n : SPECIAL_SHELL_CHARACTERS;\n if (\n options?.quoting === \"extra-safe\" ||\n // biome-ignore lint/suspicious/noExplicitAny: Workaround to make this package easier to use in a project that otherwise only uses ES2022.)\n (argCharacters as unknown as any).intersection(specialShellCharacters)\n .size > 0\n ) {\n // Use single quote to reduce the need to escape (and therefore reduce the chance for bugs/security issues).\n const escaped = arg.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"'\", \"\\\\'\");\n return `'${escaped}'`;\n }\n return arg;\n }\n\n #mainIndentation(options: PrintOptions): string {\n return options?.mainIndentation ?? DEFAULT_MAIN_INDENTATION;\n }\n\n #argIndentation(options: PrintOptions): string {\n return (\n this.#mainIndentation(options) +\n (options?.argIndentation ?? DEFAULT_ARG_INDENTATION)\n );\n }\n\n #lineWrapSeparator(options: PrintOptions): string {\n return LINE_WRAP_LINE_END + this.#argIndentation(options);\n }\n\n #argPairSeparator(options: PrintOptions): string {\n switch (options?.argumentLineWrapping ?? DEFAULT_ARGUMENT_LINE_WRAPPING) {\n case \"by-entry\": {\n return INLINE_SEPARATOR;\n }\n case \"nested-by-entry\": {\n return this.#lineWrapSeparator(options) + this.#argIndentation(options);\n }\n case \"by-argument\": {\n return this.#lineWrapSeparator(options);\n }\n case \"inline\": {\n return INLINE_SEPARATOR;\n }\n default:\n throw new Error(\"Invalid argument line wrapping argument.\");\n }\n }\n\n #intraEntrySeparator(options: PrintOptions): string {\n switch (options?.argumentLineWrapping ?? DEFAULT_ARGUMENT_LINE_WRAPPING) {\n case \"by-entry\":\n case \"nested-by-entry\":\n case \"by-argument\": {\n return LINE_WRAP_LINE_END + this.#argIndentation(options);\n }\n case \"inline\": {\n return INLINE_SEPARATOR;\n }\n default:\n throw new Error(\"Invalid argument line wrapping argument.\");\n }\n }\n\n #separatorAfterCommand(\n options: PrintOptions,\n numFollowingEntries: number,\n ): string {\n if (numFollowingEntries === 0) {\n return \"\";\n }\n if (options.skipLineWrapBeforeFirstArg ?? false) {\n return \" \";\n }\n return this.#intraEntrySeparator(options);\n }\n\n public getPrintableCommand(options?: PrintOptions): string {\n // TODO: Why in the world does TypeScript not give the `options` arg the type of `PrintOptions | undefined`???\n options ??= {};\n const serializedEntries: string[] = [];\n\n for (let i = 0; i < this.args.length; i++) {\n const argsEntry = this.args[i];\n\n if (isString(argsEntry)) {\n serializedEntries.push(this.#escapeArg(argsEntry, false, options));\n } else {\n serializedEntries.push(\n argsEntry\n .map((part) => this.#escapeArg(part, false, options))\n .join(this.#argPairSeparator(options)),\n );\n }\n }\n\n let text =\n this.#mainIndentation(options) +\n this.#escapeArg(this.commandName, true, options) +\n this.#separatorAfterCommand(options, serializedEntries.length) +\n serializedEntries.join(this.#intraEntrySeparator(options));\n if (options?.styleTextFormat) {\n text = styleText(options.styleTextFormat, text);\n }\n return text;\n }\n\n public print(options?: PrintOptions): PrintableShellCommand {\n console.log(this.getPrintableCommand(options));\n return this;\n }\n\n /**\n * The returned child process includes a `.success` `Promise` field, per https://github.com/oven-sh/bun/issues/8313\n */\n public spawnNode<\n Stdin extends NodeStdioNull | NodeStdioPipe,\n Stdout extends NodeStdioNull | NodeStdioPipe,\n Stderr extends NodeStdioNull | NodeStdioPipe,\n >(\n options?:\n | NodeSpawnOptions\n | NodeSpawnOptionsWithoutStdio\n | NodeSpawnOptionsWithStdioTuple<Stdin, Stdout, Stderr>,\n ): // TODO: figure out how to return `ChildProcessByStdio<\u2026>` without duplicating fragile boilerplate.\n NodeChildProcess & { success: Promise<void> } {\n const { spawn } = process.getBuiltinModule(\"node:child_process\");\n // @ts-ignore: The TypeScript checker has trouble reconciling the optional (i.e. potentially `undefined`) `options` with the third argument.\n const subprocess = spawn(...this.forNode(), options) as NodeChildProcess & {\n success: Promise<void>;\n };\n Object.defineProperty(subprocess, \"success\", {\n get() {\n return new Promise<void>((resolve, reject) =>\n this.addListener(\n \"exit\",\n (exitCode: number /* we only use the first arg */) => {\n if (exitCode === 0) {\n resolve();\n } else {\n reject(`Command failed with non-zero exit code: ${exitCode}`);\n }\n },\n ),\n );\n },\n enumerable: false,\n });\n return subprocess;\n }\n\n /** A wrapper for `.spawnNode(\u2026)` that sets stdio to `\"inherit\"` (common for\n * invoking commands from scripts whose output and interaction should be\n * surfaced to the user). */\n public spawnNodeInherit(\n options?: Omit<NodeSpawnOptions, \"stdio\">,\n ): NodeChildProcess & { success: Promise<void> } {\n if (options && \"stdio\" in options) {\n throw new Error(\"Unexpected `stdio` field.\");\n }\n return this.spawnNode({ ...options, stdio: \"inherit\" });\n }\n\n /** Equivalent to:\n *\n * ```\n * await this.print().spawnNodeInherit(\u2026).success;\n * ```\n */\n public async shellOutNode(\n options?: Omit<NodeSpawnOptions, \"stdio\">,\n ): Promise<void> {\n await this.print().spawnNodeInherit(options).success;\n }\n\n /**\n * The returned subprocess includes a `.success` `Promise` field, per https://github.com/oven-sh/bun/issues/8313\n */\n public spawnBun<\n const In extends BunSpawnOptions.Writable = \"ignore\",\n const Out extends BunSpawnOptions.Readable = \"pipe\",\n const Err extends BunSpawnOptions.Readable = \"inherit\",\n >(\n options?: Omit<BunSpawnOptions.OptionsObject<In, Out, Err>, \"cmd\">,\n ): BunSubprocess<In, Out, Err> & { success: Promise<void> } {\n if (options && \"cmd\" in options) {\n throw new Error(\"Unexpected `cmd` field.\");\n }\n const { spawn } = process.getBuiltinModule(\"bun\") as typeof import(\"bun\");\n const subprocess = spawn({\n ...options,\n cmd: this.forBun(),\n }) as BunSubprocess<In, Out, Err> & { success: Promise<void> };\n Object.defineProperty(subprocess, \"success\", {\n get() {\n return new Promise<void>((resolve, reject) =>\n this.exited\n .then((exitCode: number) => {\n if (exitCode === 0) {\n resolve();\n } else {\n reject(\n new Error(\n `Command failed with non-zero exit code: ${exitCode}`,\n ),\n );\n }\n })\n .catch(reject),\n );\n },\n enumerable: false,\n });\n return subprocess;\n }\n\n /**\n * A wrapper for `.spawnBunInherit(\u2026)` that sets stdio to `\"inherit\"` (common\n * for invoking commands from scripts whose output and interaction should be\n * surfaced to the user).\n */\n public spawnBunInherit(\n options?: Omit<\n Omit<\n BunSpawnOptions.OptionsObject<\"inherit\", \"inherit\", \"inherit\">,\n \"cmd\"\n >,\n \"stdio\"\n >,\n ): BunSubprocess<\"inherit\", \"inherit\", \"inherit\"> & {\n success: Promise<void>;\n } {\n if (options && \"stdio\" in options) {\n throw new Error(\"Unexpected `stdio` field.\");\n }\n return this.spawnBun({\n ...options,\n stdio: [\"inherit\", \"inherit\", \"inherit\"],\n });\n }\n\n /** Equivalent to:\n *\n * ```\n * new Response(this.spawnBun(\u2026).stdout);\n * ```\n */\n public spawnBunStdout(\n options?: Omit<\n Omit<\n BunSpawnOptions.OptionsObject<\"inherit\", \"inherit\", \"inherit\">,\n \"cmd\"\n >,\n \"stdio\"\n >,\n ): Response {\n // biome-ignore lint/suspicious/noExplicitAny: Avoid breaking the lib check when used without `@types/bun`.\n return new Response((this.spawnBun(options) as any).stdout);\n }\n\n /** Equivalent to:\n *\n * ```\n * await this.print().spawnBunInherit(\u2026).success;\n * ```\n */\n public async shellOutBun(\n options?: Omit<\n Omit<\n BunSpawnOptions.OptionsObject<\"inherit\", \"inherit\", \"inherit\">,\n \"cmd\"\n >,\n \"stdio\"\n >,\n ): Promise<void> {\n await this.print().spawnBunInherit(options).success;\n }\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type {\n ChildProcess as NodeChildProcess,\n SpawnOptions as NodeSpawnOptions,\n SpawnOptionsWithoutStdio as NodeSpawnOptionsWithoutStdio,\n SpawnOptionsWithStdioTuple as NodeSpawnOptionsWithStdioTuple,\n StdioNull as NodeStdioNull,\n StdioPipe as NodeStdioPipe,\n} from \"node:child_process\";\nimport { Readable } from \"node:stream\";\nimport { styleText } from \"node:util\";\nimport type {\n SpawnOptions as BunSpawnOptions,\n Subprocess as BunSubprocess,\n} from \"bun\";\n\nconst DEFAULT_MAIN_INDENTATION = \"\";\nconst DEFAULT_ARG_INDENTATION = \" \";\nconst DEFAULT_ARGUMENT_LINE_WRAPPING = \"by-entry\";\n\nconst INLINE_SEPARATOR = \" \";\nconst LINE_WRAP_LINE_END = \" \\\\\\n\";\n\n// biome-ignore lint/suspicious/noExplicitAny: This is the correct type nere.\nfunction isString(s: any): s is string {\n return typeof s === \"string\";\n}\n// biome-ignore lint/suspicious/noExplicitAny: This is the correct type nere.\nfunction isStringArray(entries: any[]): entries is string[] {\n for (const entry of entries) {\n if (!isString(entry)) {\n return false;\n }\n }\n return true;\n}\n\n// TODO: allow `.toString()`ables?\ntype SingleArgument = string;\ntype FlagArgumentGroup = string[];\ntype ArgsEntry = SingleArgument | FlagArgumentGroup;\ntype Args = ArgsEntry[];\n\nexport interface PrintOptions {\n /** Defaults to \"\" */\n mainIndentation?: string;\n /** Defaults to \" \" */\n argIndentation?: string;\n /**\n * - `\"auto\"`: Quote only arguments that need it for safety. This tries to be\n * portable and safe across shells, but true safety and portability is hard\n * to guarantee.\n * - `\"extra-safe\"`: Quote all arguments, even ones that don't need it. This is\n * more likely to be safe under all circumstances.\n */\n quoting?: \"auto\" | \"extra-safe\";\n /** Line wrapping to use between arguments. Defaults to `\"by-entry\"`. */\n argumentLineWrapping?:\n | \"by-entry\"\n | \"nested-by-entry\"\n | \"by-argument\"\n | \"inline\";\n /** Include the first arg (or first arg group) on the same line as the command, regardless of the `argumentLineWrapping` setting. */\n skipLineWrapBeforeFirstArg?: true | false;\n /**\n * Style text using `node`'s [`styleText(\u2026)`](https://nodejs.org/api/util.html#utilstyletextformat-text-options)\n *\n * Example usage:\n *\n * ```\n * new PrintableShellCommand(\"echo\", [\"hi\"]).print({\n * styleTextFormat: [\"gray\", \"bold\"],\n * });\n * */\n styleTextFormat?: Parameters<typeof styleText>[0];\n}\n\n// https://mywiki.wooledge.org/BashGuide/SpecialCharacters\nconst SPECIAL_SHELL_CHARACTERS = new Set([\n \" \",\n '\"',\n \"'\",\n \"`\",\n \"|\",\n \"$\",\n \"*\",\n \"?\",\n \">\",\n \"<\",\n \"(\",\n \")\",\n \"[\",\n \"]\",\n \"{\",\n \"}\",\n \"&\",\n \"\\\\\",\n \";\",\n \"#\",\n]);\n\n// https://mywiki.wooledge.org/BashGuide/SpecialCharacters\nconst SPECIAL_SHELL_CHARACTERS_FOR_MAIN_COMMAND =\n // biome-ignore lint/suspicious/noExplicitAny: Workaround to make this package easier to use in a project that otherwise only uses ES2022.)\n (SPECIAL_SHELL_CHARACTERS as unknown as any).union(new Set([\"=\"]));\n\nexport class PrintableShellCommand {\n #commandName: string;\n constructor(\n commandName: string,\n private args: Args = [],\n ) {\n if (!isString(commandName)) {\n // biome-ignore lint/suspicious/noExplicitAny: We want to print this, no matter what it is.\n throw new Error(\"Command name is not a string:\", commandName as any);\n }\n this.#commandName = commandName;\n if (typeof args === \"undefined\") {\n return;\n }\n if (!Array.isArray(args)) {\n throw new Error(\"Command arguments are not an array\");\n }\n for (let i = 0; i < args.length; i++) {\n const argEntry = args[i];\n if (typeof argEntry === \"string\") {\n continue;\n }\n if (Array.isArray(argEntry) && isStringArray(argEntry)) {\n continue;\n }\n throw new Error(`Invalid arg entry at index: ${i}`);\n }\n }\n\n get commandName(): string {\n return this.#commandName;\n }\n\n /** For use with `bun`.\n *\n * Usage example:\n *\n * ```\n * import { PrintableShellCommand } from \"printable-shell-command\";\n * import { spawn } from \"bun\";\n *\n * const command = new PrintableShellCommand( \u2026 );\n * await spawn(command.toFlatCommand()).exited;\n * ```\n */\n public toFlatCommand(): string[] {\n return [this.commandName, ...this.args.flat()];\n }\n\n /**\n * Convenient alias for `toFlatCommand()`.\n *\n * Usage example:\n *\n * ```\n * import { PrintableShellCommand } from \"printable-shell-command\";\n * import { spawn } from \"bun\";\n *\n * const command = new PrintableShellCommand( \u2026 );\n * await spawn(command.forBun()).exited;\n * ```\n *\n * */\n public forBun(): string[] {\n return this.toFlatCommand();\n }\n\n /**\n * For use with `node:child_process`\n *\n * Usage example:\n *\n * ```\n * import { PrintableShellCommand } from \"printable-shell-command\";\n * import { spawn } from \"node:child_process\";\n *\n * const command = new PrintableShellCommand( \u2026 );\n * const child_process = spawn(...command.toCommandWithFlatArgs()); // Note the `...`\n * ```\n *\n */\n public toCommandWithFlatArgs(): [string, string[]] {\n return [this.commandName, this.args.flat()];\n }\n\n /**\n * For use with `node:child_process`\n *\n * Usage example:\n *\n * ```\n * import { PrintableShellCommand } from \"printable-shell-command\";\n * import { spawn } from \"node:child_process\";\n *\n * const command = new PrintableShellCommand( \u2026 );\n * const child_process = spawn(...command.forNode()); // Note the `...`\n * ```\n *\n * Convenient alias for `toCommandWithFlatArgs()`.\n */\n public forNode(): [string, string[]] {\n return this.toCommandWithFlatArgs();\n }\n\n #escapeArg(\n arg: string,\n isMainCommand: boolean,\n options: PrintOptions,\n ): string {\n const argCharacters = new Set(arg);\n const specialShellCharacters = isMainCommand\n ? SPECIAL_SHELL_CHARACTERS_FOR_MAIN_COMMAND\n : SPECIAL_SHELL_CHARACTERS;\n if (\n options?.quoting === \"extra-safe\" ||\n // biome-ignore lint/suspicious/noExplicitAny: Workaround to make this package easier to use in a project that otherwise only uses ES2022.)\n (argCharacters as unknown as any).intersection(specialShellCharacters)\n .size > 0\n ) {\n // Use single quote to reduce the need to escape (and therefore reduce the chance for bugs/security issues).\n const escaped = arg.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"'\", \"\\\\'\");\n return `'${escaped}'`;\n }\n return arg;\n }\n\n #mainIndentation(options: PrintOptions): string {\n return options?.mainIndentation ?? DEFAULT_MAIN_INDENTATION;\n }\n\n #argIndentation(options: PrintOptions): string {\n return (\n this.#mainIndentation(options) +\n (options?.argIndentation ?? DEFAULT_ARG_INDENTATION)\n );\n }\n\n #lineWrapSeparator(options: PrintOptions): string {\n return LINE_WRAP_LINE_END + this.#argIndentation(options);\n }\n\n #argPairSeparator(options: PrintOptions): string {\n switch (options?.argumentLineWrapping ?? DEFAULT_ARGUMENT_LINE_WRAPPING) {\n case \"by-entry\": {\n return INLINE_SEPARATOR;\n }\n case \"nested-by-entry\": {\n return this.#lineWrapSeparator(options) + this.#argIndentation(options);\n }\n case \"by-argument\": {\n return this.#lineWrapSeparator(options);\n }\n case \"inline\": {\n return INLINE_SEPARATOR;\n }\n default:\n throw new Error(\"Invalid argument line wrapping argument.\");\n }\n }\n\n #intraEntrySeparator(options: PrintOptions): string {\n switch (options?.argumentLineWrapping ?? DEFAULT_ARGUMENT_LINE_WRAPPING) {\n case \"by-entry\":\n case \"nested-by-entry\":\n case \"by-argument\": {\n return LINE_WRAP_LINE_END + this.#argIndentation(options);\n }\n case \"inline\": {\n return INLINE_SEPARATOR;\n }\n default:\n throw new Error(\"Invalid argument line wrapping argument.\");\n }\n }\n\n #separatorAfterCommand(\n options: PrintOptions,\n numFollowingEntries: number,\n ): string {\n if (numFollowingEntries === 0) {\n return \"\";\n }\n if (options.skipLineWrapBeforeFirstArg ?? false) {\n return INLINE_SEPARATOR;\n }\n return this.#intraEntrySeparator(options);\n }\n\n public getPrintableCommand(options?: PrintOptions): string {\n // TODO: Why in the world does TypeScript not give the `options` arg the type of `PrintOptions | undefined`???\n options ??= {};\n const serializedEntries: string[] = [];\n\n for (let i = 0; i < this.args.length; i++) {\n const argsEntry = this.args[i];\n\n if (isString(argsEntry)) {\n serializedEntries.push(this.#escapeArg(argsEntry, false, options));\n } else {\n serializedEntries.push(\n argsEntry\n .map((part) => this.#escapeArg(part, false, options))\n .join(this.#argPairSeparator(options)),\n );\n }\n }\n\n let text =\n this.#mainIndentation(options) +\n this.#escapeArg(this.commandName, true, options) +\n this.#separatorAfterCommand(options, serializedEntries.length) +\n serializedEntries.join(this.#intraEntrySeparator(options));\n if (options?.styleTextFormat) {\n text = styleText(options.styleTextFormat, text);\n }\n return text;\n }\n\n public print(options?: PrintOptions): PrintableShellCommand {\n console.log(this.getPrintableCommand(options));\n return this;\n }\n\n /**\n * The returned child process includes a `.success` `Promise` field, per https://github.com/oven-sh/bun/issues/8313\n */\n public spawn<\n Stdin extends NodeStdioNull | NodeStdioPipe,\n Stdout extends NodeStdioNull | NodeStdioPipe,\n Stderr extends NodeStdioNull | NodeStdioPipe,\n >(\n options?:\n | NodeSpawnOptions\n | NodeSpawnOptionsWithoutStdio\n | NodeSpawnOptionsWithStdioTuple<Stdin, Stdout, Stderr>,\n ): // TODO: figure out how to return `ChildProcessByStdio<\u2026>` without duplicating fragile boilerplate.\n NodeChildProcess & { success: Promise<void> } {\n const { spawn } = process.getBuiltinModule(\"node:child_process\");\n // biome-ignore lint/suspicious/noTsIgnore: We don't want linting to depend on *broken* type checking.\n // @ts-ignore: The TypeScript checker has trouble reconciling the optional (i.e. potentially `undefined`) `options` with the third argument.\n const subprocess = spawn(...this.forNode(), options) as NodeChildProcess & {\n success: Promise<void>;\n };\n Object.defineProperty(subprocess, \"success\", {\n get() {\n return new Promise<void>((resolve, reject) =>\n this.addListener(\n \"exit\",\n (exitCode: number /* we only use the first arg */) => {\n if (exitCode === 0) {\n resolve();\n } else {\n reject(`Command failed with non-zero exit code: ${exitCode}`);\n }\n },\n ),\n );\n },\n enumerable: false,\n });\n return subprocess;\n }\n\n /** A wrapper for `.spawnNode(\u2026)` that sets stdio to `\"inherit\"` (common for\n * invoking commands from scripts whose output and interaction should be\n * surfaced to the user). */\n public spawnInherit(\n options?: Omit<NodeSpawnOptions, \"stdio\">,\n ): NodeChildProcess & { success: Promise<void> } {\n if (options && \"stdio\" in options) {\n throw new Error(\"Unexpected `stdio` field.\");\n }\n return this.spawn({ ...options, stdio: \"inherit\" });\n }\n\n public stdout(options?: Omit<NodeSpawnOptions, \"stdio\">): Response {\n if (options && \"stdio\" in options) {\n throw new Error(\"Unexpected `stdio` field.\");\n }\n const subprocess = this.spawn({\n ...options,\n stdio: [\"ignore\", \"pipe\", \"inherit\"],\n });\n\n // biome-ignore lint/style/noNonNullAssertion: dude\n return new Response(Readable.toWeb(subprocess.stdout!));\n }\n\n /** Equivalent to:\n *\n * ```\n * await this.print().spawnInherit(\u2026).success;\n * ```\n */\n public async shellOut(\n options?: Omit<NodeSpawnOptions, \"stdio\">,\n ): Promise<void> {\n await this.print().spawnInherit(options).success;\n }\n\n /**\n * The returned subprocess includes a `.success` `Promise` field, per https://github.com/oven-sh/bun/issues/8313\n */\n #spawnBun<\n const In extends BunSpawnOptions.Writable = \"ignore\",\n const Out extends BunSpawnOptions.Readable = \"pipe\",\n const Err extends BunSpawnOptions.Readable = \"inherit\",\n >(\n options?: Omit<BunSpawnOptions.OptionsObject<In, Out, Err>, \"cmd\">,\n ): BunSubprocess<In, Out, Err> & { success: Promise<void> } {\n if (options && \"cmd\" in options) {\n throw new Error(\"Unexpected `cmd` field.\");\n }\n const { spawn } = process.getBuiltinModule(\"bun\") as typeof import(\"bun\");\n const subprocess = spawn({\n ...options,\n cmd: this.forBun(),\n }) as BunSubprocess<In, Out, Err> & { success: Promise<void> };\n Object.defineProperty(subprocess, \"success\", {\n get() {\n return new Promise<void>((resolve, reject) =>\n this.exited\n .then((exitCode: number) => {\n if (exitCode === 0) {\n resolve();\n } else {\n reject(\n new Error(\n `Command failed with non-zero exit code: ${exitCode}`,\n ),\n );\n }\n })\n .catch(reject),\n );\n },\n enumerable: false,\n });\n return subprocess;\n }\n\n #spawnBunInherit(\n options?: Omit<\n Omit<\n BunSpawnOptions.OptionsObject<\"inherit\", \"inherit\", \"inherit\">,\n \"cmd\"\n >,\n \"stdio\"\n >,\n ): BunSubprocess<\"inherit\", \"inherit\", \"inherit\"> & {\n success: Promise<void>;\n } {\n if (options && \"stdio\" in options) {\n throw new Error(\"Unexpected `stdio` field.\");\n }\n return this.bun.spawnBun({\n ...options,\n stdio: [\"inherit\", \"inherit\", \"inherit\"],\n });\n }\n\n #spawnBunStdout(\n options?: Omit<\n Omit<\n BunSpawnOptions.OptionsObject<\"inherit\", \"inherit\", \"inherit\">,\n \"cmd\"\n >,\n \"stdio\"\n >,\n ): Response {\n // biome-ignore lint/suspicious/noExplicitAny: Avoid breaking the lib check when used without `@types/bun`.\n return new Response((this.bun.spawnBun(options) as any).stdout);\n }\n\n async #shellOutBun(\n options?: Omit<\n Omit<\n BunSpawnOptions.OptionsObject<\"inherit\", \"inherit\", \"inherit\">,\n \"cmd\"\n >,\n \"stdio\"\n >,\n ): Promise<void> {\n await this.print().bun.spawnBunInherit(options).success;\n }\n\n bun = {\n /** Equivalent to:\n *\n * ```\n * await this.print().bun.spawnBunInherit(\u2026).success;\n * ```\n */\n spawnBun: this.#spawnBun.bind(this),\n /**\n * A wrapper for `.spawnBunInherit(\u2026)` that sets stdio to `\"inherit\"` (common\n * for invoking commands from scripts whose output and interaction should be\n * surfaced to the user).\n */\n spawnBunInherit: this.#spawnBunInherit.bind(this),\n /** Equivalent to:\n *\n * ```\n * new Response(this.bun.spawnBun(\u2026).stdout);\n * ```\n */\n spawnBunStdout: this.#spawnBunStdout.bind(this),\n shellOutBun: this.#shellOutBun.bind(this),\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "printable-shell-command",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"main": "./src/index.ts",
|
|
5
5
|
"devDependencies": {
|
|
6
6
|
"@biomejs/biome": "^2.1.4",
|
|
7
7
|
"@cubing/dev-config": "^0.3.6",
|
|
8
8
|
"@types/bun": "^1.2.20",
|
|
9
9
|
"@types/node": "^24.2.0",
|
|
10
|
-
"esbuild": "^0.25.5"
|
|
10
|
+
"esbuild": "^0.25.5",
|
|
11
|
+
"typescript": "^5.9.3"
|
|
11
12
|
},
|
|
12
13
|
"optionalDependencies": {
|
|
13
14
|
"@types/bun": "^1.2.20",
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
StdioNull as NodeStdioNull,
|
|
7
7
|
StdioPipe as NodeStdioPipe,
|
|
8
8
|
} from "node:child_process";
|
|
9
|
+
import { Readable } from "node:stream";
|
|
9
10
|
import { styleText } from "node:util";
|
|
10
11
|
import type {
|
|
11
12
|
SpawnOptions as BunSpawnOptions,
|
|
@@ -285,7 +286,7 @@ export class PrintableShellCommand {
|
|
|
285
286
|
return "";
|
|
286
287
|
}
|
|
287
288
|
if (options.skipLineWrapBeforeFirstArg ?? false) {
|
|
288
|
-
return
|
|
289
|
+
return INLINE_SEPARATOR;
|
|
289
290
|
}
|
|
290
291
|
return this.#intraEntrySeparator(options);
|
|
291
292
|
}
|
|
@@ -328,7 +329,7 @@ export class PrintableShellCommand {
|
|
|
328
329
|
/**
|
|
329
330
|
* The returned child process includes a `.success` `Promise` field, per https://github.com/oven-sh/bun/issues/8313
|
|
330
331
|
*/
|
|
331
|
-
public
|
|
332
|
+
public spawn<
|
|
332
333
|
Stdin extends NodeStdioNull | NodeStdioPipe,
|
|
333
334
|
Stdout extends NodeStdioNull | NodeStdioPipe,
|
|
334
335
|
Stderr extends NodeStdioNull | NodeStdioPipe,
|
|
@@ -340,6 +341,7 @@ export class PrintableShellCommand {
|
|
|
340
341
|
): // TODO: figure out how to return `ChildProcessByStdio<…>` without duplicating fragile boilerplate.
|
|
341
342
|
NodeChildProcess & { success: Promise<void> } {
|
|
342
343
|
const { spawn } = process.getBuiltinModule("node:child_process");
|
|
344
|
+
// biome-ignore lint/suspicious/noTsIgnore: We don't want linting to depend on *broken* type checking.
|
|
343
345
|
// @ts-ignore: The TypeScript checker has trouble reconciling the optional (i.e. potentially `undefined`) `options` with the third argument.
|
|
344
346
|
const subprocess = spawn(...this.forNode(), options) as NodeChildProcess & {
|
|
345
347
|
success: Promise<void>;
|
|
@@ -367,31 +369,44 @@ export class PrintableShellCommand {
|
|
|
367
369
|
/** A wrapper for `.spawnNode(…)` that sets stdio to `"inherit"` (common for
|
|
368
370
|
* invoking commands from scripts whose output and interaction should be
|
|
369
371
|
* surfaced to the user). */
|
|
370
|
-
public
|
|
372
|
+
public spawnInherit(
|
|
371
373
|
options?: Omit<NodeSpawnOptions, "stdio">,
|
|
372
374
|
): NodeChildProcess & { success: Promise<void> } {
|
|
373
375
|
if (options && "stdio" in options) {
|
|
374
376
|
throw new Error("Unexpected `stdio` field.");
|
|
375
377
|
}
|
|
376
|
-
return this.
|
|
378
|
+
return this.spawn({ ...options, stdio: "inherit" });
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
public stdout(options?: Omit<NodeSpawnOptions, "stdio">): Response {
|
|
382
|
+
if (options && "stdio" in options) {
|
|
383
|
+
throw new Error("Unexpected `stdio` field.");
|
|
384
|
+
}
|
|
385
|
+
const subprocess = this.spawn({
|
|
386
|
+
...options,
|
|
387
|
+
stdio: ["ignore", "pipe", "inherit"],
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// biome-ignore lint/style/noNonNullAssertion: dude
|
|
391
|
+
return new Response(Readable.toWeb(subprocess.stdout!));
|
|
377
392
|
}
|
|
378
393
|
|
|
379
394
|
/** Equivalent to:
|
|
380
395
|
*
|
|
381
396
|
* ```
|
|
382
|
-
* await this.print().
|
|
397
|
+
* await this.print().spawnInherit(…).success;
|
|
383
398
|
* ```
|
|
384
399
|
*/
|
|
385
|
-
public async
|
|
400
|
+
public async shellOut(
|
|
386
401
|
options?: Omit<NodeSpawnOptions, "stdio">,
|
|
387
402
|
): Promise<void> {
|
|
388
|
-
await this.print().
|
|
403
|
+
await this.print().spawnInherit(options).success;
|
|
389
404
|
}
|
|
390
405
|
|
|
391
406
|
/**
|
|
392
407
|
* The returned subprocess includes a `.success` `Promise` field, per https://github.com/oven-sh/bun/issues/8313
|
|
393
408
|
*/
|
|
394
|
-
|
|
409
|
+
#spawnBun<
|
|
395
410
|
const In extends BunSpawnOptions.Writable = "ignore",
|
|
396
411
|
const Out extends BunSpawnOptions.Readable = "pipe",
|
|
397
412
|
const Err extends BunSpawnOptions.Readable = "inherit",
|
|
@@ -429,12 +444,7 @@ export class PrintableShellCommand {
|
|
|
429
444
|
return subprocess;
|
|
430
445
|
}
|
|
431
446
|
|
|
432
|
-
|
|
433
|
-
* A wrapper for `.spawnBunInherit(…)` that sets stdio to `"inherit"` (common
|
|
434
|
-
* for invoking commands from scripts whose output and interaction should be
|
|
435
|
-
* surfaced to the user).
|
|
436
|
-
*/
|
|
437
|
-
public spawnBunInherit(
|
|
447
|
+
#spawnBunInherit(
|
|
438
448
|
options?: Omit<
|
|
439
449
|
Omit<
|
|
440
450
|
BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">,
|
|
@@ -448,19 +458,13 @@ export class PrintableShellCommand {
|
|
|
448
458
|
if (options && "stdio" in options) {
|
|
449
459
|
throw new Error("Unexpected `stdio` field.");
|
|
450
460
|
}
|
|
451
|
-
return this.spawnBun({
|
|
461
|
+
return this.bun.spawnBun({
|
|
452
462
|
...options,
|
|
453
463
|
stdio: ["inherit", "inherit", "inherit"],
|
|
454
464
|
});
|
|
455
465
|
}
|
|
456
466
|
|
|
457
|
-
|
|
458
|
-
*
|
|
459
|
-
* ```
|
|
460
|
-
* new Response(this.spawnBun(…).stdout);
|
|
461
|
-
* ```
|
|
462
|
-
*/
|
|
463
|
-
public spawnBunStdout(
|
|
467
|
+
#spawnBunStdout(
|
|
464
468
|
options?: Omit<
|
|
465
469
|
Omit<
|
|
466
470
|
BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">,
|
|
@@ -470,16 +474,10 @@ export class PrintableShellCommand {
|
|
|
470
474
|
>,
|
|
471
475
|
): Response {
|
|
472
476
|
// biome-ignore lint/suspicious/noExplicitAny: Avoid breaking the lib check when used without `@types/bun`.
|
|
473
|
-
return new Response((this.spawnBun(options) as any).stdout);
|
|
477
|
+
return new Response((this.bun.spawnBun(options) as any).stdout);
|
|
474
478
|
}
|
|
475
479
|
|
|
476
|
-
|
|
477
|
-
*
|
|
478
|
-
* ```
|
|
479
|
-
* await this.print().spawnBunInherit(…).success;
|
|
480
|
-
* ```
|
|
481
|
-
*/
|
|
482
|
-
public async shellOutBun(
|
|
480
|
+
async #shellOutBun(
|
|
483
481
|
options?: Omit<
|
|
484
482
|
Omit<
|
|
485
483
|
BunSpawnOptions.OptionsObject<"inherit", "inherit", "inherit">,
|
|
@@ -488,6 +486,30 @@ export class PrintableShellCommand {
|
|
|
488
486
|
"stdio"
|
|
489
487
|
>,
|
|
490
488
|
): Promise<void> {
|
|
491
|
-
await this.print().spawnBunInherit(options).success;
|
|
489
|
+
await this.print().bun.spawnBunInherit(options).success;
|
|
492
490
|
}
|
|
491
|
+
|
|
492
|
+
bun = {
|
|
493
|
+
/** Equivalent to:
|
|
494
|
+
*
|
|
495
|
+
* ```
|
|
496
|
+
* await this.print().bun.spawnBunInherit(…).success;
|
|
497
|
+
* ```
|
|
498
|
+
*/
|
|
499
|
+
spawnBun: this.#spawnBun.bind(this),
|
|
500
|
+
/**
|
|
501
|
+
* A wrapper for `.spawnBunInherit(…)` that sets stdio to `"inherit"` (common
|
|
502
|
+
* for invoking commands from scripts whose output and interaction should be
|
|
503
|
+
* surfaced to the user).
|
|
504
|
+
*/
|
|
505
|
+
spawnBunInherit: this.#spawnBunInherit.bind(this),
|
|
506
|
+
/** Equivalent to:
|
|
507
|
+
*
|
|
508
|
+
* ```
|
|
509
|
+
* new Response(this.bun.spawnBun(…).stdout);
|
|
510
|
+
* ```
|
|
511
|
+
*/
|
|
512
|
+
spawnBunStdout: this.#spawnBunStdout.bind(this),
|
|
513
|
+
shellOutBun: this.#shellOutBun.bind(this),
|
|
514
|
+
};
|
|
493
515
|
}
|