Skip to content

Generate the README API reference from JSDoc - #4224

Open
amanmahajan7 wants to merge 24 commits into
mainfrom
typedoc-readme-api
Open

amanmahajan7 wants to merge 24 commits into
mainfrom
typedoc-readme-api

Conversation

@amanmahajan7

@amanmahajan7 amanmahajan7 commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Generate the README API reference from JSDoc

The README's API reference and the JSDoc comments documented the same API twice, and they had drifted apart (see below). This PR makes the JSDoc comments the single source: the API reference section of the README is generated from them, and CI fails if it is out of date. Editor hovers now also show the full docs, including examples, defaults, and performance notes.

Approach

  • Verbatim migration. The README text of each export moved into its JSDoc comment verbatim. Only the README's structural labels became tags:
    • **Default:** → @defaultValue
    • **Example:** → @example
    • **See also:** → @see
    • **Returns:** → @returns
    • generics → @typeParam
    • links to README anchors → {@linkcode}
  • Generator. vp run docs runs vp pack, then scripts/generateApiDocs.ts, then vp fmt README.md. The script parses the declarations and JSDoc comments of the built lib/index.d.ts with the TypeScript 7 API (typescript/sync), which ships with the typescript@beta the repo already uses, and writes the API reference between <!-- api:start --> and <!-- api:end -->.
    • Because it reads the emitted .d.ts, the signatures are exactly what users of the package see, e.g. hooks show their real return types.
    • There's no doc tool and no second TypeScript install.
  • Hand-written sections. The intro, installation, getting started, styling, and "Generics" sections stay hand-written.
  • Layout. src/index.ts sets the layout of the API reference: the exports are listed in their order, under the section of the comment above them (// Components, // Hooks, // Render Functions, // Context, // Other, // Types). The exports are reordered to match the previous README, and the set of exports is unchanged.
  • CI. vp run ci runs vp run docs in place of vp pack, followed by git diff --exit-code README.md.
  • Checks. Generation fails, rather than silently dropping content, on:
    • an export without a section, or an unknown section;
    • a link that doesn't match a heading, e.g. a misspelled {@link Column.widht}, including links in comments shown inside code blocks;
    • a tag the README doesn't render, e.g. @deprecated;
    • a heading inside a JSDoc comment, which would shift the anchors;
    • a type under Components that isn't a component's props;
    • an interface shown with a heading per member that extends an undocumented type, whose members would be lost.

The generated README

It keeps the layout of the previous README:

  • sections at ###, items at ####, props at #####;
  • the **Default:**, **Example:**, and **See also:** labels.

Types are shown as copyable declarations, with their comments, in tsx code blocks:

  • Props with headings. DataGridProps, TreeDataGridProps, and Column, whose props have examples, lists, or @see tags, keep a heading per prop, with the prop's signature in a code block.
  • Merged internal interfaces. Public interfaces that extend undocumented internal interfaces show those members merged in. For example, RenderRowProps lists every prop, plus extends Omit<React.ComponentProps<'div'>, 'children'>, Pick<DataGridProps<R, SR>, …>, instead of linking to BaseRenderRowProps → BaseRenderCellProps.
  • Internal types. Documented internal types that the API references (Maybe, Position, GroupRow, CellEvent, …) are listed at the end of Types, marked "(internal)", as before.

Notable differences from the previous README

  • No text was lost. A comparison against the current main README found:
    • no missing prose;
    • all 51 example code blocks unchanged;
    • all 29 member comments of the previous type code blocks present.
  • Headings only contain the name. For example, ##### rowKeyGetter? instead of `###### `rowKeyGetter?: Maybe<(row: R) => K>, followed by the signature in a code block.
    • Anchors no longer change when a signature changes.
    • Names used more than once get numbered anchors (e.g. the ColumnWidths type is #columnwidths-1), which can shift when headings with the same name are added or removed.
    • Links to the previous anchors from outside the README, e.g. #rowkeygetter-mayberow-r--k, will break.
  • Stable links from hand-written sections. The links from the styling sections to API members use the member as their title, e.g. [width](#width 'Column.width'), and vp run docs keeps their anchor up to date.
  • Emoji. The :warning: and :bulb: shortcodes are now ⚠️ and 💡, so they also render in editor hovers.
  • Absolute link. The "See more examples" link of onCellKeyDown is an absolute GitHub URL, as relative paths can't be resolved from a JSDoc comment.
  • // comments in types. Comments that aren't JSDoc, like // Always set, … in CalculatedColumn, are dropped by the .d.ts build, so they aren't shown. The type's description covers it.
  • Newly documented. Every member of every exported type is listed. ColumnFrozen and TreeDataGridProps now have a section.
  • Size: 2,267 lines before, 2,657 after.

Drift this fixes

Compared on main, member by member:

  • Defaults only in the README: Column.frozen, resizable, sortable, draggable, sortDescendingFirst.
  • Different descriptions in the JSDoc and the README: rows, onActivePositionChange, direction, Column.width, and Column.frozen. The README's wording was kept.
  • Only in the README: the performance warnings of columns, rows, the summary rows, rowKeyGetter, rowHeight, rowClass, rowGrouper, and groupIdGetter. Also behavior notes, e.g. "rowKeyGetter is required for row selection to work".
  • No JSDoc at all:
    • TreeDataGrid and TreeDataGridProps;
    • DataGridProps' ref, className, style, role, the aria-* props, and the data-* props;
    • Column.colSpan;
    • the components, hooks, render functions, DataGridRenderersContext, SelectColumn, and SELECT_COLUMN_KEY.

Source changes

There are no public API changes.

  • div props. DataGridProps declares the div props it accepts (className, style, role, aria-*, onScroll) with React's types instead of Pick-ing them, so they can carry JSDoc. They are type-identical to before.
  • Type parameter names. TRow and TSummaryRow are renamed to R and SR, like the other types. Type parameter names are not part of the public API.
  • src/index.ts. It lists its exports explicitly, under section comments, in README order.

JSDoc linting

  • Plugin. Oxlint's jsdoc plugin is enabled.
  • Allowed tags. check-tag-names allows TSDoc's defaultValue and typeParam. No custom tags are used.
  • Defaults. @defaultValue is preferred over @default.
  • Disabled rules. The require-*-type rules are off, since TypeScript provides the types.
  • No JSDoc formatting. Oxfmt's jsdoc formatting is not enabled. It corrupts fenced code blocks in @example tags (oxc-project/oxc#21549).

Other changes

  • Dev dependencies: github-slugger, which computes GitHub's heading anchors to resolve the links.
  • tsconfig.node.json: includes scripts/.
  • AGENTS.md: documents the workflow:
    • edit the JSDoc, run vp run docs, and never edit the generated section by hand;
    • src/index.ts sets the sections and order of the API reference;
    • use member titles for links from the hand-written sections.

Testing

  • Typecheck, vp check, the Markdown lint, vp pack, and vp build pass, and vp run docs is idempotent.
  • All 131 in-README links resolve to the right heading, checked with github-slugger.
  • Each generation check was tested by editing the declarations and confirming that generation fails.
  • The README renders correctly on GitHub.

🤖 Generated with Claude Code

Make the JSDoc comments the single source of the API documentation:
the README's API reference is generated from them, so the docs no longer
have to be kept in sync by hand.

- Move the API reference text of the README into the JSDoc comments of
  the exports, keeping the README's wording
- Add `vp run docs`, which generates the API reference with TypeDoc and
  typedoc-plugin-markdown between the `api:start` and `api:end` markers
  of the README
- `vp run ci` fails if the generated README is out of date
- TypeDoc does not support TypeScript 7 yet, so it runs with
  `@typescript/typescript6` while the `typescript` package stays on
  TypeScript 7

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@amanmahajan7 amanmahajan7 self-assigned this Oct 22, 2026
amanmahajan7 and others added 5 commits October 22, 2026 10:17
Enable oxlint's `jsdoc` plugin, now that JSDoc comments are the source
of the README's API reference. TypeDoc's tags are allowed by
`jsdoc/check-tag-names`, and `@defaultValue` is preferred over
`@default`. The rules that require types in comments are disabled, as
TypeScript provides them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reduce the repetition of the generated API reference:

- Remove the type parameter and parameter sections, which repeat the
  signatures and the "Generics" section
- List the properties of interfaces in a table, unless a property has
  more than a short description
- Only show the return type of functions with a `@returns` description
- Remove the "Inherited from" and "Overrides" sections
- Don't copy the comments of the members that `CalculatedColumn`
  redeclares

Make the generator stricter:

- Links from the hand-written README sections use the member they link
  to as link title, e.g. "Column.width", to keep their anchor up to date
- Fail on links and anchors that don't match a heading
- Use `github-slugger` for the heading anchors
- Detect code fences by their character and length

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use the same type parameter names as the other types, which simplifies
the "Generics" section of the README. Type parameter names are not part
of the public API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Members that come from a public type through an internal type, like the
cell event handlers that `RenderCellProps` inherits from
`BaseRenderCellProps`, which picks them from `DataGridProps`, repeated
the docs of the public type. Remove them like the members inherited
directly from public types, and remove the properties sections left
empty, like the one of `RenderSortStatusProps`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TypeDoc names destructured parameters `__namedParameters`, which showed
in the signatures of the components and render functions that
destructure their props, e.g. `SelectCheckbox`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Oct 22, 2026 •

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.13%. Comparing base (81f2df3) to head (906cb34).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4224   +/-   ##
=======================================
  Coverage   99.13%   99.13%           
=======================================
  Files          46       46           
  Lines        2207     2207           
  Branches      977      977           
=======================================
  Hits         2188     2188           
  Misses         19       19           
Files with missing lines Coverage Δ
src/Cell.tsx 100.00% <ø> (ø)
src/Columns.tsx 100.00% <ø> (ø)
src/DataGrid.tsx 99.08% <ø> (ø)
src/DataGridRenderersContext.ts 100.00% <ø> (ø)
src/Row.tsx 100.00% <ø> (ø)
src/TreeDataGrid.tsx 98.66% <100.00%> (ø)
src/cellRenderers/SelectCheckbox.tsx 100.00% <ø> (ø)
src/cellRenderers/renderCheckbox.tsx 100.00% <ø> (ø)
src/cellRenderers/renderToggleGroup.tsx 100.00% <ø> (ø)
src/cellRenderers/renderValue.tsx 100.00% <ø> (ø)
... and 5 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Title components like the previous README, e.g. `<DataGrid />`
  instead of `DataGrid()`, and show their props instead of a function
  signature
- List the components with a props interface first, each followed by
  its props interface, then the other components

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/DataGrid.tsx
} from './style/core';
import SummaryRow from './SummaryRow';

/**

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This file has become quite big. We can create a separate interface file if needed

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I was thinking of moving a bunch of types into types.ts so we can manage all of them together/have better type inheritance & maintenance.

Comment thread README.md
- `SR`: Summary row type
- `K`: Row key type

<!-- api:start -->

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Can create a separate API.md file if needed

Install TypeScript 6 as `typescript` and TypeScript 7 as
`@typescript/native`, the setup recommended for tools that need the
TypeScript API, which TypeScript 7 doesn't provide yet.

TypeScript 6's package also provides a `tsc` binary, which npm linked
instead of TypeScript 7's, so `vp run typecheck` used TypeScript 6. With
this setup, `tsc` is TypeScript 7, and TypeDoc no longer needs a resolve
hook, a peer dependency override, or `skipLibCheck`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@nstepien nstepien left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not sure I like the approach.
Now we have a huge script we have to maintain, and we have to compromise on how typescript is installed.

Are there alternative tools to generate JSDocs?

The new output is honestly much less user-friendly, it's more confusing to read, you can't just copy/paste it for example:

Image

Before:

Image

Another example:

Image Image

This is just hard to read:

Image

Let me read TypeScript with syntax highlighting, not... this 🥺🙏
What do you think?

We can keep some of the generated JSDocs though.

Comment thread src/DataGrid.tsx Outdated
Comment on lines +205 to +207
* :bulb: While optional, setting this prop is recommended for optimal performance, as the returned value is used to set the `key` prop on the row elements.
*
* :warning: **Performance:** Define this function outside your component or memoize it with `useCallback` to prevent unnecessary re-renders.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

:bulb: and :warning: are GH-flavored markdown stuff, what do these look like in vscode?

@amanmahajan7 amanmahajan7 Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The :warning: and :bulb: shortcodes are now ⚠️ and 💡, so they also render in editor hovers.

@amanmahajan7

Copy link
Copy Markdown
Collaborator Author

Now we have a huge script we have to maintain

Had to add the script otherwise Typedoc defaults are not the best

and we have to compromise on how typescript is installed.

Don't think this should be an issue. Looks like TS7 support is on the way TypeStrong/typedoc#3098 (comment)

The new output is honestly much less user-friendly, it's more confusing to read,

I agree, I wasn't a big fan either

Are there alternative tools to generate JSDocs?

I have an idea in mind. I will give it a try

I do think it is better to have single source of truth. Claude found the following items

Drift between the README and the JSDoc before this PR

Compared on main (f2f8880), member by member.

Defaults only in the README (the editor showed no default):

  • Column.frozen, resizable, sortable, draggable, sortDescendingFirst: false

Same prop, different descriptions:

  • rows: "An array of rows, which can be of any type" (JSDoc) vs "An array of rows. The row data can be of any type." (README)
  • onActivePositionChange: "Function called whenever the active position is changed" (JSDoc) vs "Callback triggered when the active position changes." (README)
  • direction: "Text direction of the grid ('ltr' or 'rtl')" (JSDoc) vs "This property sets the text direction of the grid. It defaults to 'ltr' (left-to-right)." (README), plus the list of effects of 'rtl', only in the README
  • Column.width: the JSDoc didn't say it accepts any CSS grid column value ('25%', 'max-content', 'minmax(100px, max-content)'); only the README did
  • Column.frozen: the JSDoc only said "true is an alias for 'start'"; what 'start'/'end' pin to in LTR and RTL was only in the README
  • editorOptions.displayCellContent: "By default, the cell content is not rendered when the edit cell is open." was only in the JSDoc

Behavior documented only in the README (missing from editor hovers):

  • selectedRows: "rowKeyGetter is required for row selection to work"
  • sortColumns: "Sorting is controlled: the grid does not reorder rows for you"
  • onCellPaste / onFill: return the updated row, and the grid calls onRowsChange with it
  • columnWidths / onColumnWidthsChange: an internal state is used when not provided
  • the performance warnings of columns, rows, topSummaryRows/bottomSummaryRows, rowKeyGetter, rowHeight, rowClass, rowGrouper, and groupIdGetter

No JSDoc at all (only documented in the README):

  • DataGridProps: ref, className, style, role, aria-label, aria-labelledby, aria-description, aria-describedby, aria-rowcount, data-testid, data-cy
  • Column.colSpan
  • TreeDataGrid and all of TreeDataGridProps: groupBy, rowGrouper, expandedGroupIds, onExpandedGroupIdsChange, groupIdGetter, rowHeight
  • the components, hooks, render functions, DataGridRenderersContext, SelectColumn, and SELECT_COLUMN_KEY

No README section:

  • ColumnFrozen and TreeDataGridProps, both exported

amanmahajan7 and others added 5 commits October 22, 2026 16:23
Replace TypeDoc and `typedoc-plugin-markdown` with a smaller generator
that parses the declarations and JSDoc comments of `lib/index.d.ts`,
which `vp pack` bundles with TypeScript 7, using `oxc-parser`:

- Only TypeScript 7 is needed again, as the generator doesn't rely on
  the TypeScript API
- Types are shown as copyable declarations with their comments, like
  the previous README, instead of tables
- The layout and labels follow the previous README

Also replace the `:warning:` and `:bulb:` emoji shortcodes with emoji,
as editors don't render shortcodes in hovers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- List the items in the order they are exported from `src/index.ts`,
  which now exports them by name, in the order of the previous README
- Title the items and members with their signatures, which keeps most
  of the previous anchors, and nest the props interfaces under their
  components
- Show the documented internal types with the other types, and the
  undocumented ones in the code block of the types that reference them
- Declare the `div` props of `DataGridProps` with React's types
- Move the "Generics" section back to the end of the API reference

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Title the items and members with their name, and show their signature
  in a code block, so their anchors don't change with their types
- Show `DataGridRenderersContext` like the other constants
- Only show the helper types directly referenced by a type

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reference

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gs, and headings in JSDoc

Also describe the props of SelectCheckbox under Props again, and run `vp run docs` in place of `vp pack` in the ci task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@amanmahajan7

Copy link
Copy Markdown
Collaborator Author

@nstepien wdyt about the new approach (desc updated). It does not use typedoc anymore. We still need the script but hopefully we do not need to change it often. Output is closed to before with some changes (mentioned in the PR).

@amanmahajan7

Copy link
Copy Markdown
Collaborator Author

another idea, I can just use ts7 beta api

amanmahajan7 and others added 5 commits October 22, 2026 19:31
…arser

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	README.md
#	src/types.ts
…group` tags

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… cases

Render `@see Foo` as a link, check the links in the comments of code blocks,
catch setext headings in JSDoc, fail on interfaces with a heading per member that
extend undocumented types, and only show object types as nested options through
`Maybe<…>` and unions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	README.md
#	src/types.ts
@amanmahajan7
amanmahajan7 requested a review from nstepien October 23, 2026 15:10

This branch has not been deployed

No deployments
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.

3 participants