Skip to content

feat(typedoc): add a TypeDoc plugin writing doc-kit Markdown - #1125

Open
ovflowd wants to merge 3 commits into
mainfrom
feat/typedoc
Open

ovflowd wants to merge 3 commits into
mainfrom
feat/typedoc

Conversation

@ovflowd

@ovflowd ovflowd commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Description

This PR adds @doc-kit/typedoc, a TypeDoc plugin that writes the API reference of a TypeScript project as doc-kit Markdown, so TypeScript projects get doc-kit's signatures, typed lists, stability indices and source links straight from their sources.

It registers a doc-kit output (outputs: [{ name: 'doc-kit', path: 'docs/api' }]) that writes:

  • One page per export, with signatures in doc-kit's syntax (`build(options[, extra])` heading + typed list), {Type} annotations, > Stability: from @deprecated / @experimental, source_link, and @example / @see / @throws. Custom block tags render as **Tag:** content.
  • type-map.json for doc-kit's typeMap, and pages.json (every page with its kind, URL and @category) for sites to build their navigation from.

A few docKit* options cover what bigger APIs need. The main one is docKitMemberPages: members of chosen types (e.g. a bundler's options) get a page of their own, and the type's page, the types extending it and the parameters typed with it list them as linked one-liners instead of repeating their docs. The others handle event emitters (Event: entries from an event-map type), receivers (this.resolve() instead of pluginContext.resolve()), signatures taken from another type, import paths and legacy member anchors. They're all documented in the package's README.

Some notes:

  • It only writes files whose contents changed, so typedoc --watch works nicely with node --watch on doc-kit.
  • It checks TypeDoc's discriminants (reflection.variant, type.type) instead of instanceof, so it still works when the plugin resolves a different TypeDoc copy than the host (linked packages, strict package managers).

This is part of a proof of concept of migrating rolldown.rs from VitePress to doc-kit. There it replaces ~1,100 lines of Rolldown-specific TypeDoc → doc-kit conversion with this plugin and a small typedoc.config.mjs.

Validation

  • Unit tests for the Markdown helpers, and an end-to-end test running TypeDoc with the plugin over a fixture (functions, an options interface with member pages, an extending interface, a class with events, @deprecated, @experimental, @default, a custom tag) and snapshotting every generated file.
  • Generating Rolldown's whole API reference (230 pages) produces the same pages as the custom script it replaces, apart from two deliberate changes: custom tags render as plain text (**Kind:** async parallel), and member lists are titled "Properties".

Related Issues

Part of the Rolldown docs migration PoC: rolldown/rolldown#11072. It's the base of a stack: #1125 (TypeDoc plugin) → #1126 (Graphviz diagrams) → #1127 (llms-full), each targeting the one below, with this one targeting main. The changes don't depend on each other, the stack just keeps them reviewable one at a time while the Rolldown PoC builds from the top branch.

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run node --run test and all tests passed.
  • I have check code formatting with node --run format:check & node --run lint.
  • I've covered new added functionality with unit tests if necessary.

@vercel

vercel Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
api-docs-tooling Ready Ready Preview Oct 1, 2026 2:24pm UTC

Request Review

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Failed ❌

View logs ↗
03f0300 2026-10-01T14:25:18.190Z View logs ↗
  • Build: Failed ❌

View logs ↗
933f8f5 2026-10-01T13:26:51.469Z View logs ↗

@codecov

codecov Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.09683% with 194 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.50%. Comparing base (c5a3fe8) to head (03f0300).

Files with missing lines Patch % Lines
packages/typedoc/src/render/pages.mjs 87.46% 41 Missing ⚠️
packages/typedoc/src/render/members.mjs 89.47% 28 Missing and 2 partials ⚠️
packages/typedoc/src/render/comments.mjs 81.73% 19 Missing and 2 partials ⚠️
packages/typedoc/src/model/declarations.mjs 80.64% 17 Missing and 1 partial ⚠️
packages/typedoc/src/render/lists.mjs 92.41% 14 Missing and 2 partials ⚠️
packages/typedoc/src/model/pages.mjs 89.23% 14 Missing ⚠️
packages/typedoc/src/render/types.mjs 68.29% 11 Missing and 2 partials ⚠️
packages/typedoc/src/utils/files.mjs 79.24% 11 Missing ⚠️
packages/typedoc/src/utils/reflections.mjs 91.97% 6 Missing and 5 partials ⚠️
packages/typedoc/src/render/entries.mjs 95.72% 10 Missing ⚠️
... and 3 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1125      +/-   ##
==========================================
- Coverage   92.64%   92.50%   -0.14%     
==========================================
  Files         244      263      +19     
  Lines       23113    25292    +2179     
  Branches     2263     2502     +239     
==========================================
+ Hits        21412    23397    +1985     
- Misses       1692     1872     +180     
- Partials        9       23      +14     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

api-links Generator

Performance estimate (single CI run)

  • Generation time: 0.7% faster (1.43 s → 1.42 s)
  • Peak memory: 0.7% lower (423.48 MB → 420.36 MB)

json Generator

Performance estimate (single CI run)

  • Generation time: 9.7% faster (10.17 s → 9.18 s)
  • Peak memory: 8.2% higher (1.45 GB → 1.57 GB)

legacy-html Generator

Performance estimate (single CI run)

  • Generation time: 16.1% faster (28.34 s → 23.78 s)
  • Peak memory: 2.6% lower (2.45 GB → 2.39 GB)

legacy-json Generator

Performance estimate (single CI run)

  • Generation time: 14.3% slower (6.43 s → 7.35 s)
  • Peak memory: 0.1% higher (1.58 GB → 1.58 GB)

llms-txt Generator

Performance estimate (single CI run)

  • Generation time: 35.4% faster (6.83 s → 4.41 s)
  • Peak memory: 16.8% higher (1.56 GB → 1.82 GB)

orama-db Generator

Output size: 1 file changed · net -153.00 B

File size details
File Main PR Change
orama-db.json 9.55 MB 9.55 MB -153.00 B (-0.0%)

Performance estimate (single CI run)

  • Generation time: 47.1% slower (6.41 s → 9.43 s)
  • Peak memory: 7.8% lower (1.63 GB → 1.50 GB)

web Generator

Performance estimate (single CI run)

  • Generation time: 3.7% slower (51.81 s → 53.72 s)
  • Peak memory: 1.3% lower (3.25 GB → 3.20 GB)

@avivkeller
avivkeller self-requested a review October 1, 2026 13:37
@ovflowd
ovflowd marked this pull request as ready for review October 1, 2026 14:15
@ovflowd
ovflowd requested a review from a team as a code owner October 1, 2026 14:15
A TypeDoc plugin with a `doc-kit` output: one page per export, with doc-kit signatures, typed lists, stability indices and source links, plus a type map and a page list. Members of chosen types (a bundler's options, say) can have pages of their own, listed and linked wherever the type appears.

Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>

@avivkeller avivkeller left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a first pass, and I didn't look at all the files.

From trying to change webpack-doc-kit to use this library, note that:

  • collectDeclarations only reads the direct children of the project, or of its entry-point modules. webpack exports 28 nested namespaces (optimize, container, javascript, cli, util, sources, etc).
  • Enums and namespaces are not in PAGE_KINDS (Intentional?)
  • Accessors render as {unknown} type
  • Call signatures of interfaces are dropped.
  • signaturesOf ignores named function types.
  • StatsObject (webpack type) gives an invalid toutput ype
  • docKitMemberAnchors shouldn't exist, IMO, it should always be true, since things like {@link Compiler.run} break without it
  • Type-map URLs assume doc-kit's input root is the site root.
  • Source links are relative to the host's Git root. IMO it should be relative to a provided value

As an aside, export= isn't properly handled, but I'd argue that's an issue for a project using the poor syntax over a issue here.

"typedoc": "^0.28.0"
},
"devDependencies": {
"typedoc": "^0.28.20",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this version and the version in peerDependencies differenrt?

Comment on lines +17 to +20
"exports": {
".": "./src/index.mjs",
"./package.json": "./package.json"
},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed, or is main enough for this package?

Comment on lines +13 to +15
"test": "node --test \"src/**/*.test.mjs\"",
"test:update-snapshots": "node --test --test-update-snapshots \"src/**/*.test.mjs\""
},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"test": "node --test \"src/**/*.test.mjs\"",
"test:update-snapshots": "node --test --test-update-snapshots \"src/**/*.test.mjs\""
},
"test": "node --experimental-test-module-mocks --test \"src/**/*.test.mjs\"",
"test:update-snapshots": "node --test --experimental-test-module-mocks --test-update-snapshots \"src/**/*.test.mjs\""
},


The output directory receives:

- A page per exported function, class, interface, type alias and variable: `Function.build.md`, `Interface.BuildOptions.md`, …

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the format we want? [Type].[Name].md?

Not functions/build.md?


## Options

- `docKitBasePath` {string} The URL path the pages are served under. **Default:** the output directory's name (`/api`).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TypeDoc provides a basePath, how is this different? Can we use TypeDoc's?

* @param {string} file
* @param {string} contents
*/
export const writeIfChanged = async (file, contents) => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should always write, like we do in the other generators, why are we unique here?

* @param {string} directory
* @param {Map<string, string>} files The files about to be written
*/
export const removeStalePages = async (directory, files) => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this is out of our scope, our plugin shouldn't be managing the filesystem outside of what it needs to.

return ['', markdown];
}

const end = /\n\s*\n/.exec(markdown);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be constants

Comment on lines +4 to +20
/** The URL path the pages are served under (`/reference`) */
docKitBasePath: string;
/** The URL of the site (`https://rolldown.rs`) */
docKitSiteUrl: string;
/** Types whose members each have a page of their own (`InputOptions`) */
docKitMemberPages: string[];
/** The name members of a type are documented on, by type name */
docKitReceivers: Record<string, string>;
/** Event emitters, mapped to the type mapping their events to their arguments */
docKitEvents: Record<string, string>;
/** Types whose members take their signatures from another type's members */
docKitSignatureSources: Record<string, string>;
/** The import path of each entry point, by file */
docKitImportPaths: Record<string, string>;
/** Whether members get an anchor of their name alone */
docKitMemberAnchors: boolean;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • docKitImportPaths: TypeDoc's built-in @module tag
  • docKitEvents: class Watcher extends EventEmitter<WatcherEvents> carries the event map in extendedTypes[0].typeArguments.
  • docKitMemberAnchors: This seems redundant...
  • docKitSiteUrl: We don't need the URL, do we? Can't we just use /?

etc

these options feel confusing

Comment on lines +46 to +56
export interface PageEntry {
name: string;
/** The kind of the declaration (`Function`), or `Member` for a member page */
kind: string;
url: string;
category?: string;
/** The type a member page belongs to */
owner?: string;
/** Whether the page only refers to the member page documenting the type */
inlined?: boolean;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels almost "too large", is all this info needed?

@avivkeller

avivkeller commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

diff.patch

I didn't want to push directly to your branch (although I will if you give me the OK), but here's how I would resolve most of these concerns

This branch was successfully deployed

1 active deployment
Preview – api-docs-tooling — 03f03007 Deployed Oct 1, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants