doc-kit reads GitHub Flavored Markdown, plus a handful of conventions that turn a page into an API reference: headings written as signatures, typed parameter lists, version history and stability. This page covers what most documents use. The Markdown specification is the full contract.
Documenting a TypeScript or JavaScript project?
@doc-kit/typedoc writes this Markdown for you,
from your source code and its JSDoc comments. See
Documenting TypeScript.
# Kittens The `kittens` module adopts, feeds and pets kittens.
Start every file with one level-one heading. Its text is the page's title: it
names the browser tab and, unless you configure the sidebar yourself, the
page's link in the sidebar. The website skips a file that has headings but no
level-one heading. The first paragraph is the page's description, which
llms.txt lists next to the link.
The output file follows the source path, not the title: with docs/**/*.md as
input, docs/kittens.md becomes kittens.html.
Everything GitHub Markdown does still works. On top of it:
- Text in curly braces is a type annotation:
{string}renders as code that links to the type's documentation. Put literal braces in a code span. - Headings written like signatures, such as
`kittens.adopt(name)`, are API entries. - A list under an entry whose items start with a name and a type is a typed list.
- HTML comments carry metadata:
<!-- YAMLblocks record history, and<!--key=value-->comments set page metadata. - A blockquote that starts with
Stability:is a stability indicator. - Two or more code blocks in a row become tabs.
- Links to
.mdfiles point to the generated pages.
Each heading below the title, down to #####, starts an entry, and deeper
headings start entries nested inside it. An entry has up to six parts, in this
order: a heading, its history, its stability, its typed list, prose, and code
samples. All but the heading come before the next heading, whatever its level.
Every part after the heading is optional, and most entries use only a few:
## `kittens.adopt(name[, options])` <!-- YAML added: v1.0.0 --> - `name` {string} The kitten's name. - `options` {Object} - `color` {string} Coat color. **Default:** `'tabby'`. - Returns: {Promise} Fulfills with the adopted kitten. Adopts a kitten, once the paperwork is done. ```js const kitten = await kittens.adopt('Mittens'); ```
The heading makes this a method and gives its signature, the comment records when it was added, and the list becomes its parameters and return value. The website renders a signature, a parameter table and a version history; the JSON output keeps each part as data.
doc-kit reads an entry's kind from its heading, with no annotation needed:
| Heading | Kind |
|---|---|
## Class: `kittens.Kitten` | Class |
### `new kittens.Kitten(name)` | Constructor |
### Static method: `Kitten.from(json)` | Static method |
### `kitten.pet([times])` | Method |
### `kitten.name` | Property |
### Event: `'purr'` | Event |
- Parentheses make a method, and their absence a property. A method needs only
a name, as in
`adopt(name)`, but a property needs an owner:`kitten.name`or`kitten[key]`. - The
Class:,Static method:andEvent:prefixes mark those kinds, andnewmarks a constructor. - The code span must be the whole heading, after any prefix:
### `kitten.pet()` againis a plain section. - Optional parameters go in square brackets, nested when one only makes sense
after another:
`kitten.groom(brush[, side[, strokes]])`. A rest parameter is written[...names]. Leave types and defaults out of the heading; they belong in the typed list. - Anything else, like
## Synopsis, is a plain section. Write those headings in plain words, without backticks.
Entries nest by heading level, so put a class's constructor, methods, properties and events one level below the class.
Under the heading, and after any history or stability, a typed list describes what the entry takes and returns. Each item is a name in a code span, a type in curly braces, and a description:
### `kitten.feed(food[, options])` - `food` {string|string[]} What to serve. - `options` {Object} - `portion` {number} Grams per serving. **Default:** `50`. - `signal` {AbortSignal} Cancels the meal. - Returns: {Promise<boolean>} Fulfills with `true` once the bowl is empty.
- Nested lists describe the properties of an object, to any depth.
**Default:**followed by the value in a code span records a default and makes the parameter optional. Square brackets in the heading make it optional too.- Three prefixes stand in for the name:
Returns:for a return value,Type:for a property's type, andExtends:for a class's parent class.
The same list works for the other kinds. An event's list describes the arguments its listeners receive:
## Class: `kittens.Kitten` - Extends: {EventTarget} ### `kitten.name` - Type: {string} ### Event: `'purr'` - `volume` {number} How loud, from 1 to 10.
doc-kit recognizes a typed list by its first item, which must start with a name and a type, a bare type, or one of the prefixes. A list whose first item has a name but no type stays a plain list, and plain bullets after the typed items stay prose.
On the website, a typed list becomes a table, under the signature for methods and constructors. In JSON, each item's name, type, description, default and whether it's optional become fields.
Curly braces hold a TypeScript type, in a typed list or anywhere in prose. doc-kit renders it as code and links each type name in it to its documentation:
- `food` {string|string[]} What to serve. `kittens.adopt()` returns a {Promise} that fulfills with a {kittens.Kitten}.
Anything valid on the right of a TypeScript type X = works, including
unions, arrays and generics such as {Promise<boolean>}. doc-kit looks each
name up in order, and the first match wins:
- Your type map. Its names are case-sensitive and may contain spaces.
- JavaScript primitives and keywords, such as
string,number,nullandany, linked to MDN. - JavaScript's built-in objects and the Web APIs documented on MDN, such as
Promise,Map,AbortSignalandURL. - Dotted names, which link into your own docs: the part before the first dot
names the page.
{kittens.Kitten}links to theClass:heading on thekittenspage (a capitalized last part means a class), and{kittens.breeds}to thekittens.breedsproperty.
Steps 2 and 3 ignore case. A name that nothing matches stays plain text inside the code, which is fine. If the braces don't hold a valid type, doc-kit logs a warning and renders the text as plain code.
For your own types, and other projects' types, write a JSON file that maps names to URLs:
{ "Litter": "https://example.com/docs/litter", "Adoption options": "kittens.html#kittensadoptname-options" }
Then point metadata.typeMap at it, or pass it to the CLI's
--type-map option:
export default { metadata: { typeMap: './type-map.json', }, };
typeMap takes a URL, or a path read from the directory you run doc-kit in.
A relative URL in the map is relative to the output root, and doc-kit adjusts
it for each page.
An HTML comment that starts with YAML, right after an entry's heading,
records the entry's history:
### `kittens.adopt(name[, options])` <!-- YAML added: v1.0.0 changes: - version: v2.0.0 pr-url: https://github.com/you/kittens/pull/42 description: The `color` option accepts any CSS color. deprecated: v3.0.0 -->
| Field | What it records |
|---|---|
added | The version the entry first shipped in. |
deprecated | The version that deprecated it. |
removed | The version that removed it. |
changes | Notable changes, each with a version, a pr-url and a description (Markdown). |
A version is a string such as v1.0.0. Use a list of versions for a change
that was backported to older release lines. The website shows the history next
to the heading, and JSON keeps it as data.
A blockquote that starts with Stability:, a level and a label marks an
entry's stage in its lifecycle. The website renders it as a colored box, like
this one:
Place it after the history comment, if there is one, and before the typed list. The text after the level is yours: explain, link to an alternative, or continue on more lines.
### `kittens.adopt(name[, options])` <!-- YAML added: v1.0.0 --> > Stability: 1 - Experimental. The adoption fee may change. - `name` {string} The kitten's name.
| Level | Meaning |
|---|---|
| 0 | Deprecated: may emit warnings, and compatibility isn't guaranteed. |
| 1 | Experimental: outside semantic versioning, and may change in any release. |
| 2 | Stable: compatibility is a priority. |
| 3 | Legacy: still covered by semantic versioning, but no longer maintained. |
Level 1 takes sub-levels that say how close an API is to stable: 1.0 (early
development), 1.1 (active development) and 1.2 (release candidate). On the
title, a stability indicator applies to the whole page.
Fence code samples with a language, so the website can highlight them. Two or
more code blocks in a row become one block with a tab each. A tab is labelled
by its block's displayName, or by its language when it has none (cjs and
mjs read as CJS and ESM):
```bash displayName="npm" npm install kittens ``` ```bash displayName="pnpm" pnpm add kittens ```
That renders as:
npm install kittens
pnpm add kittens
To keep blocks apart, put a sentence between them. The JSON output lists each
entry's code samples, with their language and displayName.
GitHub's alert syntax renders as a callout, like the tip at the top of this page:
> [!WARNING] > Kittens adopted before eight weeks of age need extra care.
The five kinds are NOTE, TIP, IMPORTANT, WARNING and CAUTION.
Link to other pages by their source file, with a relative path. doc-kit
rewrites the .md extension to the output's .html:
See [`kittens.adopt()`][] for the details, or the [care guide](care.md). [`kittens.adopt()`]: kittens.md#kittensadoptname-options
Anchors are heading slugs, made much as GitHub makes them:
## `kittens.adopt(name[, options])` becomes #kittensadoptname-options,
and ## Class: `kittens.Kitten` becomes #class-kittenskitten. When in
doubt, copy the link from the heading on the rendered page.
Reference-style links, with their definitions at the end of the file, keep
long pages readable. A system call written like open(2) in plain text (not
in a code span) links to its Linux manual page.
One-line comments right after the title set metadata for the whole page:
# Kittens <!--introduced_in=v1.0.0--> <!--source_link=lib/kittens.js--> <!--llm_description=Adopt, feed and pet kittens.-->
| Directive | What it does |
|---|---|
introduced_in | The version the module first shipped in, shown with the page's history. |
source_link | Links the page to the file that implements it, in your repository on GitHub. |
llm_description | Describes the page in llms.txt, in place of its first paragraph. |
type | What the page documents: module (the default), misc or global. |
name | The module's name in JSON output, when it isn't the file name. |
A frontmatter block at the top of the file does the same job with YAML keys:
any of the directives above or the history fields, plus title, which
replaces the heading's text in the browser tab, and mdx, described in
MDX pages.
--- title: Adopting kittens introduced_in: v1.0.0 --- # Kittens
Guides need nothing special: headings that don't look like an API stay plain
sections. Still, doc-kit treats every page as documenting a module unless its
type directive says otherwise:
# Caring for your kitten <!--type=misc-->
misc marks a guide or another conceptual page: JSON output records the
page's type as misc, with no module name. global marks a page of
globals, which need no import, and JSON gives its entries a global scope.
The directive doesn't change how headings are classified: on a misc page,
## `kitten.pet()` is still a method. When a heading looks like an API
but isn't an entry, write it in plain words, or override its kind in its YAML
comment so that it becomes a plain section:
### `kitten.whiskers` <!-- YAML type: misc -->
When a page needs components, such as a landing page or a live demo, write it
in MDX: name the file .mdx, or set mdx: true in a Markdown file's
frontmatter (mdx: false turns an .mdx file back into Markdown).
--- title: Kittens --- # Kittens Everything about adopting, feeding and petting kittens. <DocumentationIndex />
<DocumentationIndex /> is built in: it lists every page with its stability
and description. Components you register yourself work too; see
Customizing the site.
In MDX, curly braces are JavaScript expressions, not types, so typed lists
stay plain lists and type names don't link. HTML comments aren't valid MDX
either, so set page metadata in frontmatter, write comments as {/* ... */},
and keep entries that need history in Markdown pages. Headings and stability
indicators work as they do in Markdown.
- The Markdown specification is the full contract for the format, edge cases included.
- Documenting TypeScript generates these pages from your source code.
- Customizing the site covers navigation, the theme and components.