UNPKG

ethercalc

Version:

Multi-User Spreadsheet Server — TypeScript rewrite (Cloudflare fullstack)

65 lines (62 loc) 2.56 kB
/** * Thin orchestrator for `bin/ethercalc`. Ties parse → map → spawn together * and keeps IO at the edge so the logic modules stay pure. * * `main()` is the single entry point; it takes its IO sinks as parameters * so tests can stub them. `bin/ethercalc` passes real `process.stdout`, * `process.stderr`, and a `spawnSync`-based exec. */ import { parseFlags, CliError } from './parse.ts'; import { buildLaunchPlan } from './map.ts'; import { HELP_TEXT } from './help.ts'; /** * Dependencies injected into `main()`. Explicit so tests can stub stdout/ * stderr/exec without touching the real process. `exec` returns the exit * code the caller should propagate; implementations that `exec`-replace * the current process never return, but the return type is kept so the * test stub can still report what-would-have-happened. */ export interface MainDeps { stdout: (s: string) => void; stderr: (s: string) => void; exec: (cmd: string, args: string[], env: Record<string, string>) => number; env?: Record<string, string | undefined>; } /** * Entry point. Returns the exit code the caller should exit with. * * Behavior: * - `--help` / `-h`: print help to stdout, return 0. * - Parse error: print to stderr, return 2 (conventional EX_USAGE). * - Otherwise: map to launch plan, forward warnings to stderr, * exec wrangler, and return its exit code. */ export function main(argv: readonly string[], deps: MainDeps): number { let flags; try { flags = parseFlags(argv); } catch (err) { // parseFlags only ever raises CliError by design — we catch only that // subtype and let any other synchronous error propagate (an // engineering bug should not be swallowed). if (!(err instanceof CliError)) throw err; deps.stderr(`${err.message}\n`); deps.stderr('Run `ethercalc --help` for usage.\n'); return 2; } if (flags.help === true) { deps.stdout(`${HELP_TEXT}\n`); return 0; } const plan = buildLaunchPlan(flags, deps.env); for (const w of plan.warnings) { deps.stderr(`${w}\n`); } // `bunx wrangler` (not `npx wrangler`) — bin/ethercalc already has a // `#!/usr/bin/env bun` shebang, so bun is a hard prerequisite. Using // bunx avoids needing nodejs+npm on top of bun, which matters for // self-hosting in a minimal container (e.g. Sandstorm grains bundle // only what the app touches at runtime; extra Node toolchain doubles // the package size). return deps.exec('bunx', ['wrangler', ...plan.wranglerArgs], plan.env); }