Initial Commit
This commit is contained in:
104
packages/devtools/tooling/electrobun/src/schemas/schemas.md
Normal file
104
packages/devtools/tooling/electrobun/src/schemas/schemas.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Schemas — `schemas.ts`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## 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
|
||||
|
||||
```ts
|
||||
import { ProjectOptionsSchema } from "@suaveplan/electrobun/schemas";
|
||||
|
||||
const parsed = ProjectOptionsSchema.safeParse(input);
|
||||
if (!parsed.success) {
|
||||
console.error(parsed.error.issues);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
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`.
|
||||
Reference in New Issue
Block a user