UNPKG

@lunora/cli

Version:

The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands

65 lines (62 loc) 2.18 kB
import { spawn } from 'node:child_process'; const NEEDS_CMD_QUOTING = /[\s"%&<>^|]/u; const BACKSLASH_RUN_BEFORE_QUOTE = /(\\*)"/gu; const TRAILING_BACKSLASH_RUN = /(\\+)$/u; const spawnShellCompat = (command, args, platform = process.platform) => { if (platform !== "win32" || command === process.execPath) { return { args: [...args], command, shell: false }; } const quote = (value) => { if (value === "") { return `""`; } if (!NEEDS_CMD_QUOTING.test(value)) { return value; } const escaped = value.replaceAll(BACKSLASH_RUN_BEFORE_QUOTE, String.raw`$1$1\"`).replace(TRAILING_BACKSLASH_RUN, "$1$1"); return `"${escaped}"`; }; return { args: args.map((argument) => quote(argument)), command: quote(command), shell: true }; }; const defaultSpawner = (descriptor) => new Promise((resolve, reject) => { const hasInput = typeof descriptor.input === "string"; const wantCapture = descriptor.captureStdout === true; let stdout = "inherit"; if (wantCapture) { stdout = "pipe"; } else if (descriptor.stdoutToStderr) { stdout = 2; } const exec = spawnShellCompat(descriptor.command, descriptor.args); const child = spawn(exec.command, exec.args, { cwd: descriptor.cwd ?? process.cwd(), env: descriptor.env ? { ...process.env, ...descriptor.env } : process.env, shell: exec.shell, stdio: [hasInput ? "pipe" : "inherit", stdout, "inherit"] }); let captured = ""; if (wantCapture && child.stdout) { child.stdout.on("data", (chunk) => { captured += chunk.toString("utf8"); process.stdout.write(chunk); }); } child.on("error", (error) => { reject(error); }); child.on("exit", (code, signal) => { resolve({ code: code ?? (signal ? 1 : 0), stdout: wantCapture ? captured : void 0 }); }); if (hasInput && child.stdin) { child.stdin.end(descriptor.input); } }); const createRecordingSpawner = (exitCode = 0) => { const calls = []; const spawner = (descriptor) => { calls.push({ descriptor }); return Promise.resolve({ code: exitCode }); }; return { calls, spawner }; }; export { createRecordingSpawner, defaultSpawner, spawnShellCompat };