Files
skills/docs/devtools/tooling/electrobun/src/schemas/schemas.md
2026-05-29 08:20:56 +01:00

3.8 KiB

Schemas — schemas.ts

(no submodules)

Purpose

Owns the Zod schemas that gate every public boundary of @suaveplan/electrobun. Each interface in src/types/electrobun.types.ts has a matching schema here, and the parseOrThrow helper folds the parse + throw pattern into one call so every entry point reads the same way: validate, then operate on the inferred type. The schemas are the runtime contract — when a downstream library passes a stale ProjectOptions shape, the schema fails at the boundary rather than silently producing a broken project.

The schemas use Zod 4's enum / object / readonly-array helpers to keep the TypeScript inference cheap, and parseOrThrow always raises ElectrobunError(ELECTROBUN.INVALID_OPTIONS) so consumers can branch on error.code === "ELECTROBUN.INVALID_OPTIONS" regardless of which entry point validated.

Features

  • Enum schemas (FeatureModuleSchema, NetworkingComplexitySchema, R3fModuleSchema, BuildTargetSchema).
  • Composite schemas (ProjectOptionsSchema, ElectrobunConfigSchema, GenerateIconsOptionsSchema, DevCommandOptionsSchema, BuildCommandOptionsSchema, PackageCommandOptionsSchema, SignCommandOptionsSchema).
  • parseOrThrow(schema, value, context) — single helper that converts a Zod failure into an ElectrobunError carrying details.issues.

Usage: Basic

import { ProjectOptionsSchema } from "@suaveplan/electrobun/schemas";

const parsed = ProjectOptionsSchema.safeParse(input);
if (!parsed.success) {
    console.error(parsed.error.issues);
}

Usage: Advanced

import {
    ProjectOptionsSchema,
    parseOrThrow,
} from "@suaveplan/electrobun/schemas";
import { ElectrobunError } from "@suaveplan/electrobun/error-codes";

try {
    const validated = parseOrThrow(
        ProjectOptionsSchema,
        input,
        "ProjectOptions"
    );
    await generate(validated);
} catch (err) {
    if (err instanceof ElectrobunError) {
        process.stderr.write(`${err.code}: ${err.message}\n`);
        for (const issue of err.details["issues"] as Array<{
            path: ReadonlyArray<string>;
            message: string;
        }>) {
            process.stderr.write(`  - ${issue.path.join(".")}: ${issue.message}\n`);
        }
    }
}

API Reference

  • FeatureModuleSchema, NetworkingComplexitySchema, R3fModuleSchema, BuildTargetSchema — closed Zod enums.
  • ProjectOptionsSchema — full ProjectOptions shape; rejects empty name, identifier, version, outputDir.
  • ElectrobunConfigSchema — partial config; every field optional.
  • GenerateIconsOptionsSchema — { inputPath, outputDir }.
  • DevCommandOptionsSchema, BuildCommandOptionsSchema, PackageCommandOptionsSchema, SignCommandOptionsSchema — per-command option shapes.
  • parseOrThrow<T>(schema, value, context) — returns the parsed value or throws ElectrobunError(ELECTROBUN.INVALID_OPTIONS, "${context}: invalid options", { details: { context, issues } }).

Implementation Notes

z.array(...).readonly() produces a readonly-typed inference that matches the readonly-array fields on ProjectOptions, so the consumer gets a parsed object whose mutability matches the interface. This is important because the generator iterates the feature list and would otherwise need an explicit Array.from(...) to avoid a structural mismatch.

parseOrThrow uses safeParse rather than parse so the Zod issue list lands on details.issues. The thrown error carries the original cause slot empty — the Zod issues are the cause, surfaced as structured data rather than a child Error. Consumers who want to log a single line should format err.message; consumers who want to drive remediation should walk details.issues.