first commit
This commit is contained in:
96
docs/devtools/tooling/electrobun/src/generator/generator.md
Normal file
96
docs/devtools/tooling/electrobun/src/generator/generator.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Generator — `generator.ts`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Owns the two-call surface that scaffolds an Electrobun project on disk.
|
||||
`collectFiles(options, overrides?)` is pure — it returns the
|
||||
`GeneratedFile[]` list for a given `ProjectOptions` without touching the
|
||||
filesystem. `generate(options, deps?)` writes the file list through the
|
||||
`FsAdapter` seam, snapshots the `.suaveplan-electrobun.json` config, and
|
||||
optionally runs the icon pipeline when `options.iconSource` is set.
|
||||
|
||||
The generator is the only place that knows the canonical file order: the
|
||||
nine core files come first (`electrobun.config.ts`, `package.json`,
|
||||
`tsconfig.json`, the main-process Bun entry, three mainview files, the
|
||||
shared types module, the README), then one file per selected feature in
|
||||
the `FEATURE_ORDER` (`i18n`, `networking`, `api`, `api-schemas`,
|
||||
`storage`, `auth`, `form-builder`, `r3f`). Input order does not matter
|
||||
— the iterator walks `FEATURE_ORDER` and includes the feature only when
|
||||
it is present in the input set.
|
||||
|
||||
The `overrides` argument lets tests substitute a faulty renderer to
|
||||
exercise the `ELECTROBUN.TEMPLATE_RENDER_FAILED` wrapper without forcing
|
||||
the production renderer table to throw. Production callers never set
|
||||
overrides.
|
||||
|
||||
## Features
|
||||
|
||||
- Deterministic file ordering across runs.
|
||||
- Zod-validated input via `ProjectOptionsSchema`.
|
||||
- Wraps every renderer throw as `ELECTROBUN.TEMPLATE_RENDER_FAILED`.
|
||||
- Optional icon pipeline gated by `options.iconSource`.
|
||||
- OTel: `recordProject(featuresCount)` increment +
|
||||
`recordGenerateDuration(ms, featuresCount)` observation per call.
|
||||
- `CollectOverrides` seam for test-only renderer substitution.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { generate } from "@suaveplan/electrobun/generator";
|
||||
|
||||
const report = await generate({
|
||||
name: "my-app",
|
||||
identifier: "com.example.my-app",
|
||||
description: "demo",
|
||||
version: "0.1.0",
|
||||
outputDir: "/tmp/my-app",
|
||||
features: ["i18n", "api"],
|
||||
networkingComplexity: "basic",
|
||||
r3fModules: [],
|
||||
});
|
||||
console.log(`Wrote ${report.filesCreated.length} files in ${report.durationMs}ms`);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { collectFiles } from "@suaveplan/electrobun/generator";
|
||||
import type { FsAdapter } from "@suaveplan/electrobun/types";
|
||||
import { writeFiles } from "@suaveplan/electrobun/fs";
|
||||
|
||||
const fs: FsAdapter = /* in-memory adapter */;
|
||||
const files = collectFiles(opts);
|
||||
await writeFiles(opts.outputDir, files, fs);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `collectFiles(options: ProjectOptions, overrides?: CollectOverrides):
|
||||
GeneratedFile[]`.
|
||||
- `generate(options: ProjectOptions, deps?: GenerateDeps):
|
||||
Promise<GenerateReport>`.
|
||||
- `GenerateDeps = { fs?, renderer?, fileExists?, now?, overrides? }`.
|
||||
- `CollectOverrides = { renderProjectFile?, renderFeatureFile? }` — the
|
||||
test seam.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`collectFiles` validates with Zod first, then iterates the file list.
|
||||
Each renderer is wrapped in a try/catch that converts native errors into
|
||||
`ElectrobunError(ELECTROBUN.TEMPLATE_RENDER_FAILED)` carrying the
|
||||
faulty path (or feature name) in `details`. The wrap is essential
|
||||
because a renderer failure surfaces as a string-typed crash at the call
|
||||
site that consumed `collectFiles`; the typed code lets the caller branch
|
||||
on "template bug" vs "Zod bug" vs "fs bug" without parsing messages.
|
||||
|
||||
The icon-pipeline integration is gated by a truthy
|
||||
`parsed.iconSource` rather than `!= undefined`, so an empty-string
|
||||
`iconSource` (a common prompt default) skips icon generation entirely.
|
||||
This matches the upstream behaviour: the prompt layer collapses an
|
||||
empty answer to `undefined` before passing it down, but the generator
|
||||
defends against the empty-string case too in case a config file
|
||||
materialises one.
|
||||
Reference in New Issue
Block a user