@amritk/generate-markdown
v0.4.1
Published
Generate markdown documentation from JSON Schemas.
Maintainers
Readme
@amritk/generate-markdown
Generate markdown documentation from JSON Schemas.
Overview
@amritk/generate-markdown renders a configuration reference table from a config.schema.json file and writes the result to README.md. It exists so the documentation for a CLI's flags can be regenerated from the schema itself, keeping the two in sync.
For every property it reads the standard JSON Schema keywords:
type— shown in the Type columndescription— the first paragraph fills the full-width detail rowdefault— shown (quoted/JSON-encoded) in the Default columnenum— listed as Allowed: values in the detail rowexamples— listed as Examples: values in the detail rowrequired— the parent'srequiredarray drives the Required column
Schemas built from references work too. $ref pointers are resolved against the
document's $defs (any #/… JSON pointer, in fact) before rendering, recursive
definitions are detected and collapsed so generation always terminates, and
sibling keywords on a $ref node — typically description — override the
referenced definition. When a property describes its type through enum,
const, or anyOf/oneOf/allOf rather than a plain type, the Type
column shows an inferred label (e.g. string or number | string).
…plus two non-standard keywords for richer output:
x-cli-flag— the matching CLI flag (e.g.--schema <path>), shown in the CLI Flag columnx-icon— an emoji shown next to the property name
Columns and icons are only rendered when the schema actually uses them. The
CLI Flag, Required, and Default columns are each dropped entirely
when no property anywhere in the schema fills them, and a property with no
x-icon simply shows no icon. There are no — placeholders: a cell with
nothing to say is left empty. The check spans the whole schema (including
nested objects), so every table keeps the same set of columns.
Object properties with their own properties are linked to a nested detail table rendered below the main one.
Installation
npm install @amritk/generate-markdown
# or
pnpm add @amritk/generate-markdown
# or
yarn add @amritk/generate-markdown
# or
bun add @amritk/generate-markdownUsage
import { generateMarkdown } from '@amritk/generate-markdown'
await generateMarkdown()
// Reads ./config.schema.json from process.cwd()
// Writes ./README.mdIf README.md already exists and contains the marker comments below, only the content between them is replaced — everything else in the file is preserved:
<!-- config-table-start -->
<!-- config-table-end -->Without markers (or without an existing README) the file is overwritten with just the table.
Examples
Each example below shows an input config.schema.json and the markdown generateMarkdown() produces from it.
Defaults of every type
Defaults are rendered in the Default column. Strings are quoted; numbers and booleans are printed bare; objects and arrays are JSON-encoded. None of these properties use a CLI flag or are required, so those columns are dropped — only Property, Type, and Default remain.
{
"title": "Defaults",
"properties": {
"outDir": { "type": "string", "default": "./generated", "x-icon": "📁", "description": "Output directory." },
"port": { "type": "number", "default": 8080, "x-icon": "🔌", "description": "Port to listen on." },
"minify": { "type": "boolean", "default": false, "x-icon": "🗜️", "description": "Minify the output." },
"include": { "type": "array", "default": ["**/*.ts"], "x-icon": "📥", "description": "Glob patterns to include." },
"env": { "type": "object", "default": { "NODE_ENV": "production" }, "x-icon": "🌱", "description": "Environment variables." }
}
}Generated markdown:
Enums and examples
enum becomes an Allowed: line and examples becomes an Examples: line, both appended to the property's detail row beneath the description.
{
"title": "Input",
"required": ["input"],
"properties": {
"input": {
"type": "string",
"enum": ["json", "zod", "typebox"],
"default": "json",
"x-cli-flag": "--input <format>",
"x-icon": "🔌",
"description": "Source format of the schema.",
"examples": ["json", "zod"]
}
}
}Generated markdown:
Required properties and CLI flags
A property name appears in the Required column (✅) when it is listed in the object's required array. x-cli-flag fills the CLI Flag column, and x-icon sits next to the name. Neither property sets a default, so the Default column is dropped; the outFile row, which isn't required, leaves the Required cell empty rather than printing a placeholder.
{
"title": "RequiredFlags",
"required": ["schema"],
"properties": {
"schema": { "type": "string", "x-cli-flag": "--schema <path>", "x-icon": "📄", "description": "Path to the schema to process.", "examples": ["./schema.json"] },
"outFile": { "type": "string", "x-cli-flag": "--out-file <file>", "x-icon": "📄", "description": "Write everything to a single file." }
}
}Generated markdown:
Nested objects
An object property that declares its own properties is linked to a detail table rendered below the main one. The nested table uses the object's own required array, so required markers are scoped to each level.
{
"title": "Nested",
"properties": {
"server": {
"type": "object",
"x-icon": "🖥️",
"description": "HTTP server settings.",
"required": ["host"],
"properties": {
"host": { "type": "string", "x-icon": "🌐", "description": "Hostname to bind." },
"port": { "type": "number", "x-icon": "🔌", "default": 3000, "description": "Port to listen on." }
}
}
}
}Generated markdown:
server
References and definitions
$ref pointers are inlined from $defs before rendering, so a schema assembled
from reusable definitions produces the same tables as an inline one. Sibling
keywords on a $ref (here x-icon and description) override the definition,
and a property whose type comes from enum (logLevel) gets an inferred Type.
{
"title": "Refs",
"required": ["server"],
"properties": {
"server": { "$ref": "#/$defs/server", "x-icon": "🖥️", "description": "HTTP server settings." },
"logLevel": { "$ref": "#/$defs/logLevel", "x-icon": "🔊" }
},
"$defs": {
"server": {
"type": "object",
"required": ["host"],
"properties": {
"host": { "type": "string", "x-icon": "🌐", "description": "Hostname to bind." },
"port": { "type": "number", "x-icon": "🔌", "default": 3000, "description": "Port to listen on." }
}
},
"logLevel": {
"enum": ["debug", "info", "warn", "error"],
"default": "info",
"description": "Minimum log level to emit."
}
}
}Generated markdown:
server
API
generateMarkdown(): Promise<void>
No arguments. Reads from ${cwd}/config.schema.json and writes to ${cwd}/README.md.
Related packages
@amritk/mjst— uses this package to keep its README's flag table in sync withconfig.schema.json@amritk/generate-parsers— sibling generator for TypeScript parsers and types@amritk/generate-validators— sibling generator for predicate validators
