Skip to content

feat: Add API docs renderer - #205

Merged
milesj merged 10 commits into
masterfrom
api-docs
Sep 11, 2026
Merged

milesj merged 10 commits into
masterfrom
api-docs

Conversation

@milesj

@milesj milesj commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds ApiDocsRenderer, behind a new renderer_api_docs feature, which renders a markdown API documentation page per type from a SchemaGenerator. It works like the JSON schema renderer: the last type added is the page rendered, and every other type in the generator is a link target.

A page has frontmatter, the type's description, an ## Index table, then a section per property or variant with tags, its comment, and a table of type information (type, default, values, constraints, aliases, env var). Types referenced from the page are linked inline and listed under ## References. Structs render properties, unit enums and unions render variants, headed by the variant name.

Options

  • render_tags, render_description, render_link, render_anchor: functions that own how tags, descriptions, type links, and index fragments are rendered, for sites with their own components or heading ids.
  • frontmatter: a map of extra key: value entries.
  • enum_format: render a unit enum's variants as one table instead of sections.
  • include_index, index_page, exclude_aliases, mark_struct_fields_required.
  • ApiDocsRenderer::generate_all writes a page for every type into a directory plus an index page listing them.

Changes outside the renderer

  • UnionType.variants_names (new, optional). A union derived from an enum records each variant's name by position, so a variant can be labeled. A variant's Schema.name could not carry this: the generator treats any named schema as a standalone reference, so List(Vec<String>) would have become a top-level List definition in JSON schema and TypeScript output. Mirrors how EnumType::from_schemas moves names out of variant schemas. Hand-built unions carry None, and serialization skips it.
  • SchemaGenerator::add moves a re-added type to the end. Without this, adding a type that an earlier type had nested left the old root in place, so a per-type loop silently rendered the wrong page. This reorders two TypeScript snapshots where a fixture re-adds a nested type; content is unchanged.

Reviewer notes

  • Composite types render as a single code span with a separate References row, because a markdown link cannot sit inside a code span. Bare references link directly.
  • Nullable and flattened fields are not tagged Required, unlike the JSON schema renderer's required list, since serde accepts a missing Option and a flattened field has no key.
  • Tags in the enum table mode are plain labels, not routed through render_tags, as its block output cannot sit in a table cell.
  • Every named type in the generator gets a page, including aliased scalars, since every named type is a link target.

Book page at book/src/schema/generator/api-docs.md fills the existing "API documentation" placeholder in the summary. Changelog has an Unreleased entry.

Test plan

  • cargo test --workspace
  • cargo clippy --workspace --all-targets clean
  • cargo build -p schematic --no-default-features --features renderer_api_docs
  • cargo test -p schematic_types on its own
  • Regenerated core and partialize snapshots read, not just accepted
  • Tried against a real config crate via [patch.crates-io]

🤖 Generated with Claude Code

@milesj
milesj merged commit 0c2aed8 into master Sep 11, 2026
6 checks passed
@milesj
milesj deleted the api-docs branch September 11, 2026 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant