127 lines
5.0 KiB
Markdown
127 lines
5.0 KiB
Markdown
# README-generation templates
|
|
|
|
This directory holds `@suaveplan/templates` engine templates for auto-generating
|
|
`README.md` files at three levels of the `packages/` tree.
|
|
|
|
| Template | Target path | Purpose |
|
|
|----------|-------------|---------|
|
|
| `package-readme.template.md` | `packages/<category>/<plugin>/<pkg>/README.md` | Stand-alone npm-package readme |
|
|
| `plugin-readme.template.md` | `packages/<category>/<plugin>/README.md` | Index of packages inside one plugin |
|
|
| `category-readme.template.md` | `packages/<category>/README.md` | Index of all packages in a category |
|
|
|
|
## How to render
|
|
|
|
Load the template file as a string, build a context object, and pass both to
|
|
`TemplateEngine` with the **loop-aware preset**:
|
|
|
|
```ts
|
|
import {
|
|
TemplateEngine,
|
|
fullPresetWithLoops,
|
|
} from "@suaveplan/templates";
|
|
import type { ParseState } from "@suaveplan/templates";
|
|
|
|
const engine = new TemplateEngine();
|
|
engine.usePreset(
|
|
fullPresetWithLoops(
|
|
(tpl, ctx, state) =>
|
|
(engine as unknown as { parseInternal: Function }).parseInternal(
|
|
tpl,
|
|
ctx,
|
|
state
|
|
)
|
|
)
|
|
);
|
|
|
|
const template = await Bun.file(
|
|
".claude/templates/package-readme.template.md"
|
|
).text();
|
|
|
|
const context = {
|
|
packageName: "@suaveplan/api-plugin-vault",
|
|
shortDescription: "Per-user vault HTTP plugin for `@suaveplan/api`.",
|
|
summary: "Per-user vault HTTP plugin...",
|
|
installCommand: "bun add @suaveplan/api-plugin-vault",
|
|
quickStartCode: `import { createVaultPlugin } from "@suaveplan/api-plugin-vault";`,
|
|
quickStartDescription: "After `registry.start()`, the vault plugin...",
|
|
features: [
|
|
"Persists `site` records under SurrealDB...",
|
|
"Enforces per-organization and per-site caps...",
|
|
],
|
|
modules: [
|
|
{ name: "error-codes/error-codes", path: "./src/error-codes/error-codes.md", description: "9 stable `VAULT_PLUGIN_*` codes." },
|
|
{ name: "plugin/plugin", path: "./src/plugin/plugin.md", description: "`createVaultPlugin` factory." },
|
|
],
|
|
otelInstruments: [
|
|
{ type: "Counter", name: "webhook_plugin.deliveries_total", labels: "{event,status,endpoint_id}" },
|
|
],
|
|
otelStatusValues: "`delivered`, `exhausted`, `not_found`",
|
|
license: "MIT",
|
|
};
|
|
|
|
const readme = engine.parse(template, context);
|
|
```
|
|
|
|
## Context shapes
|
|
|
|
### `package-readme.template.md`
|
|
|
|
| Key | Type | Required | Notes |
|
|
|-----|------|----------|-------|
|
|
| `packageName` | `string` | ✅ | Full scoped name, e.g. `@suaveplan/templates` |
|
|
| `shortDescription` | `string` | ✅ | ≤120 characters; appended to H1 |
|
|
| `summary` | `string` | ✅ | Multi-line paragraph(s) |
|
|
| `installCommand` | `string` | ✅ | Shell command, e.g. `bun add @suaveplan/templates` |
|
|
| `quickStartCode` | `string` | ✅ | Code inside the `ts` fence (no backticks) |
|
|
| `quickStartDescription` | `string` | ❌ | Paragraph after the quick-start block |
|
|
| `features` | `string[]` | ❌ | Renders the "What it does" section |
|
|
| `modules` | `{name,path,description}[]` | ✅ | Module index bullets |
|
|
| `otelInstruments` | `{type,name,labels?}[]` | ❌ | Renders the "OpenTelemetry" section |
|
|
| `otelStatusValues` | `string` | ❌ | Sentence fragment after the instrument list |
|
|
| `license` | `string` | ✅ | e.g. `MIT` |
|
|
|
|
### `plugin-readme.template.md`
|
|
|
|
| Key | Type | Required |
|
|
|-----|------|----------|
|
|
| `pluginName` | `string` | ✅ |
|
|
| `pluginDescription` | `string` | ✅ |
|
|
| `packages` | `{name,path,description}[]` | ✅ |
|
|
|
|
### `category-readme.template.md`
|
|
|
|
| Key | Type | Required |
|
|
|-----|------|----------|
|
|
| `categoryName` | `string` | ✅ |
|
|
| `categoryDescription` | `string` | ✅ |
|
|
| `packages` | `{name,path,description}[]` | ✅ |
|
|
|
|
## Brace-escaping caveat
|
|
|
|
The `@suaveplan/templates` engine scans the **entire** template (including text
|
|
inside code blocks) for `{identifier}` tokens. If a context string contains a
|
|
literal brace pair that looks like a variable — e.g. `GET /sites/{id}/public` —
|
|
the engine will try to resolve it and, when the identifier is absent from
|
|
context, replace it with an empty string.
|
|
|
|
When building context objects, avoid bare `{foo}` patterns. Safe work-arounds:
|
|
|
|
1. **Add a space** — `{ id }` does not match any plugin regex.
|
|
2. **Back-tick wrapping** — `` `{id}` `` is still scanned, but if the value is
|
|
not in context the engine replaces it with `""`. Only use this when the
|
|
loss of the braces is acceptable.
|
|
3. **Post-process** — after rendering, run a regex replace that restores any
|
|
sentinels you placed in the context strings (e.g. `«LBRACE»` → `{`).
|
|
|
|
Because the package-level readme is aimed at npm consumers with no knowledge of
|
|
the monorepo, the generated text should already avoid monorepo-specific tags
|
|
(`genesis`, migration phases, universal tiers, etc.). The AI generating the
|
|
context object is responsible for stripping that content before rendering.
|
|
|
|
## Conditional nesting
|
|
|
|
The `@suaveplan/templates` conditional plugin (`{if:…}…{/if}`) does not support
|
|
nesting. The package template keeps all conditionals at the top level so they
|
|
never wrap each other. Loop bodies may contain inner conditionals safely because
|
|
the loop plugin resolves them recursively before the outer conditional runs.
|