Stubs for undocumented exports
What scaffold generates for components, interfaces and functions, and how the marker makes the review a search.
After convert, what is left is code that nobody documented. This example follows a small module through scaffold, so you can see what a stub contains and what it does not.
Before
export interface HeroProps {
title: string;
href: string;
onSelect: (id: string) => void;
}
export default function Hero({ title, href }: HeroProps) {
return <a href={href}>{title}</a>;
}export interface Lead {
id: string;
email: string;
}
export function slugify(input: string): string {
return input.toLowerCase().replace(/\s+/g, "-");
}
export const isEmpty = (value: string) => value.length === 0;Preview
npx jsdoc-to-tsdoc scaffold --dry-runAfter scaffold
/**
* Hero props.
*
* @remarks TODO(tsdoc): verify this generated summary.
*/
export interface HeroProps {
title: string;
href: string;
onSelect: (id: string) => void;
}
/**
* Renders the hero.
*
* @remarks TODO(tsdoc): verify this generated summary.
*
* @param props - TODO(tsdoc): describe props.
* @returns TODO(tsdoc): describe the return value.
*/
export default function Hero({ title, href }: HeroProps) {
return <a href={href}>{title}</a>;
}/**
* Lead.
*
* @remarks TODO(tsdoc): verify this generated summary.
*/
export interface Lead {
id: string;
email: string;
}
/**
* Slugify.
*
* @remarks TODO(tsdoc): verify this generated summary.
*
* @param input - TODO(tsdoc): describe input.
* @returns TODO(tsdoc): describe the return value.
*/
export function slugify(input: string): string {
return input.toLowerCase().replace(/\s+/g, "-");
}
/**
* Reports whether empty.
*
* @remarks TODO(tsdoc): verify this generated summary.
*
* @param value - TODO(tsdoc): describe value.
* @returns TODO(tsdoc): describe the return value.
*/
export const isEmpty = (value: string) => value.length === 0;What to notice
- The signature drives the tags. Each parameter gets a
@param, and each non-voidfunction gets a@returns. The names come from the code, so they cannot drift from it. - The summary comes from the name.
Herobecomes “Renders the hero.” because it is a React component, andisEmptybecomes “Reports whether empty.” because a name that starts withisis a predicate.slugifybecomes “Slugify.”, which is correct and no help to a reader. - Everything is marked. That is the important part: the summaries are guesses, and
TODO(tsdoc)turns “review the generated comments” into a search you can finish.
grep -rn "TODO(tsdoc)" srcMembers
HeroProps has three properties and only one stub, for the interface itself. To document each property too:
npx jsdoc-to-tsdoc scaffold --membersexport interface HeroProps {
/**
* Title.
*
* @remarks TODO(tsdoc): verify this generated summary.
*/
title: string;
/**
* Href.
*
* @remarks TODO(tsdoc): verify this generated summary.
*/
href: string;
/**
* On select.
*
* @remarks TODO(tsdoc): verify this generated summary.
*
* @param id - TODO(tsdoc): describe id.
*/
onSelect: (id: string) => void;
}onSelect is callable, so it gets a @param for id. Its summary reads “On select.” and not a verb sentence, because on is not a recognised leading verb.
Then a person takes over
A useful habit is to replace the guessed sentence with what the code cannot say:
/**
* Turns free text into a URL-safe slug.
*
* @param input - Any string, including spaces and mixed case.
* @returns The lowercase slug, with runs of whitespace replaced by a single hyphen.
*/
export function slugify(input: string): string {
return input.toLowerCase().replace(/\s+/g, "-");
}See also
The scaffold page and the tutorial Fill in the generated stubs.