ZenStack CLI plugin that generates Markdown documentation from ZModel schemas. Pure function: AST in, Markdown files out. No template engines, no runtime dependencies beyond @zenstackhq/language and @zenstackhq/sdk.
Entry point: src/index.ts exports a CliPlugin. The orchestrator is src/generator.ts. Each entity type has a dedicated renderer in src/renderers/.
This project uses Conventional Commits with Release Please for automated versioning. Commit message format matters — it determines version bumps and changelog entries.
<type>[optional scope]: <description>
| Type | Version bump | Changelog |
|---|---|---|
feat |
minor | visible |
fix |
patch | visible |
perf |
patch | visible |
docs |
none | hidden |
test |
none | hidden |
refactor |
none | hidden |
chore |
none | hidden |
ci |
none | hidden |
Append ! after the type: feat!: rename diagramFormat option. This bumps major (or minor while pre-1.0).
- Features:
feature/<short-description> - Fixes:
fix/<short-description> - Docs:
docs/<short-description> - Chores:
chore/<short-description>
- Never force-push to
main. - Never amend commits that have been pushed.
- Always create a branch and PR for changes — do not commit directly to
main. - PR titles should follow the same conventional commit format (GitHub uses the PR title as the merge commit message).
- Strict mode with
noUncheckedIndexedAccess— every indexed access needs a null check or!assertion. - No
any— write type guards instead of type assertions. - Use
functiondeclarations, not arrow-function expressions (thefunc-stylelint rule is disabled for this reason). - Filenames are kebab-case.
- Use
import typefor type-only imports. - ESM only (
"type": "module"in package.json).
Uses eslint-config-canonical with project-specific overrides in eslint.config.js. Run pnpm run lint before committing. Key overrides:
!= nullchecks are allowed (idiomatic null/undefined coalescing).consoleusage is allowed (CLI plugin).- Non-null assertions (
!) are allowed after guarded regex matches and array lookups. perfectionist/sort-modulesis enforced — exported functions must come before non-exported ones, and functions should be in alphabetical order.
Prettier is integrated via eslint-config-canonical. Do not add a separate prettier config — it runs through ESLint.
- Framework: vitest
- Run:
pnpm test - Tests call the public
generate()function through helpers intest/utils.ts, then assert on the generated Markdown output. - Use Red-Green TDD: write a failing test first, then implement.
- Update snapshots with
pnpm test -- --update.
| Function | Purpose |
|---|---|
generateFromSchema(schema, options?) |
Parse inline ZModel, generate docs to temp dir |
readDoc(tmpDir, ...segments) |
Read a generated doc file |
findFieldLine(doc, fieldName) |
Find a field's table row |
findBrokenLinks(outputDir) |
Verify all relative links resolve |
pnpm run typecheck # tsc --noEmit
pnpm run lint # eslint
pnpm test # vitest run
pnpm run build # tsc --noEmit && tsup-nodeAlways run typecheck, lint, and test before pushing. CI runs all three on Node 20 and 22.
Every renderer follows the same pattern: accept AST node(s) and options, build a string[] where each element is one line, join with '\n', return the full page. Conditional sections are omitted by not pushing lines.
src/extractors.ts contains pure functions for pulling data from the ZModel AST. Keep extraction separate from rendering.
Mermaid blocks in rendered markdown are post-processed by src/renderers/diagram-processor.ts. It supports three modes via diagramFormat (mermaid, svg, both) and two embed modes via diagramEmbed (file, inline). SVG rendering uses beautiful-mermaid.
- Add the option to
PluginOptionsinsrc/types.ts - Parse it in
resolvePluginOptions()insrc/generator.ts - If it controls rendering, add it to
RenderOptionsandresolveRenderOptions()insrc/extractors.ts - Update
README.mdconfiguration table - Add tests
- Write a failing test
- Add rendering logic to the renderer in
src/renderers/ - If needed, add extraction logic in
src/extractors.ts - If toggleable, add a boolean to
RenderOptions
@zenstackhq/languageand@zenstackhq/sdkare peer dependencies — the consuming project provides them.beautiful-mermaidis the only runtime dependency (SVG rendering).- Use
pnpmas the package manager.