All files run.ts

100% Statements 14/14
100% Branches 4/4
100% Functions 1/1
100% Lines 13/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58                                                                        12x 12x         4x 3x 3x 3x   8x 2x 2x   6x 6x 2x   6x    
/**
 * 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;
}
 
/**
 * 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);
  for (const w of plan.warnings) {
    deps.stderr(`${w}\n`);
  }
  return deps.exec('npx', ['wrangler', ...plan.wranglerArgs], plan.env);
}