Skip to content

Add generated API documentation site POC#209

Open
rafael81 wants to merge 2 commits into
piotrwitek:masterfrom
rafael81:docs/api-site-poc
Open

Add generated API documentation site POC#209
rafael81 wants to merge 2 commits into
piotrwitek:masterfrom
rafael81:docs/api-site-poc

Conversation

@rafael81
Copy link
Copy Markdown

@rafael81 rafael81 commented May 12, 2026

Summary

Fixes #30.

This adds a working proof-of-concept for generated API docs that follows the direction discussed in the issue:

  • parses the public exports from src/index.ts with the existing TypeScript compiler dependency
  • reads JSDoc descriptions, tags, examples, aliases, and declaration snippets from the source files
  • generates markdown subpages per source module under docs/api/
  • serves the markdown with a small Docsify shell and built-in search
  • adds npm run docs:api so docs can be refreshed after API/JSDoc changes

I avoided Typedoc here because the issue discussion called out its UX/search/export-name problems. This POC keeps the generated output markdown-based and handles public re-export names such as Required while still noting their source declaration when aliased.

Validation

  • npm run docs:api
  • npm run ci-check
  • git diff --check
  • served docs/ locally and verified the Docsify sidebar/search flow with DeepReadonly
  • push hook also ran prettier:fix, lint, tsc, and test:update

Transparency

This PR was prepared with AI assistance. I reviewed the generated code and docs locally, ran the validation above, and kept the change limited to the documentation POC for the funded IssueHunt issue.


IssueHunt Summary

Referenced issues

This pull request has been submitted to:


Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an automated documentation generation system for the utility-types library. It adds a new script, scripts/generate-api-docs.js, which leverages the TypeScript compiler API to extract type definitions, JSDoc comments, and examples into Markdown files for a Docsify-powered documentation site. Feedback includes addressing a potential crash in the generation script when the entry point is missing, improving the robustness of function snippet extraction, and correcting minor syntax and content errors in the generated documentation files.

Comment thread scripts/generate-api-docs.js Outdated
Comment on lines +185 to +186
var index = program.getSourceFile(path.join(srcDir, 'index.ts'));
var moduleSymbol = checker.getSymbolAtLocation(index);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

If src/index.ts is missing or cannot be read by the TypeScript program, program.getSourceFile will return undefined. This will cause the script to crash with a TypeError when calling checker.getSymbolAtLocation(index) on the following line. A defensive check should be added.

  var indexFile = path.join(srcDir, 'index.ts');
  var index = program.getSourceFile(indexFile);
  if (!index) {
    throw new Error('Could not find entry point: ' + indexFile);
  }
  var moduleSymbol = checker.getSymbolAtLocation(index);

Comment thread docs/api/aliases-and-guards.md Outdated

## `Nullish`

Type representing [nullish values][https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing] in TypeScript: `null | undefined`
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The markdown link syntax for the TypeScript handbook is incorrect. It uses square brackets for both parts [text][url], which is not standard for inline links.

Suggested change
Type representing [nullish values][https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing] in TypeScript: `null | undefined`
Type representing [nullish values](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing) in TypeScript: `null | undefined`

Comment thread docs/api/mapped-types.md Outdated

```ts
// Expect: "string | null"
SymmetricDifference<string | null | undefined>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The example for NonUndefined incorrectly uses SymmetricDifference. This likely stems from a copy-paste error in the source JSDoc in src/mapped-types.ts.

Suggested change
SymmetricDifference<string | null | undefined>;
NonUndefined<string | null | undefined>;

Comment thread docs/api/utility-types.md Outdated
type DefaultProps = { age: number };

// Expect: { name: string; visible: boolean; }
type RequiredProps = Diff<Props, DefaultProps>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The example for $Diff incorrectly uses the Diff type instead of $Diff. This should be corrected in the source JSDoc in src/utility-types.ts to ensure the documentation accurately reflects the utility being described.

Suggested change
type RequiredProps = Diff<Props, DefaultProps>;
type RequiredProps = $Diff<Props, DefaultProps>;

Comment on lines +129 to +136
function getDeclarationSnippet(declaration, publicName, checker) {
if (ts.isVariableDeclaration(declaration)) {
var type = checker.typeToString(checker.getTypeAtLocation(declaration.name));
return 'export const ' + publicName + ': ' + type + ';';
}

return trimImplementation(declaration.getText(declaration.getSourceFile()));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The current implementation of getDeclarationSnippet relies on a fragile trimImplementation function that only handles arrow functions with a specific block format (=> {). It fails to trim the body of regular function declarations (like getReturnOfExpression), causing implementation details to leak into the documentation. Using the TypeScript compiler API to identify the function body is more robust.

function getDeclarationSnippet(declaration, publicName, checker) {
  if (ts.isVariableDeclaration(declaration)) {
    var type = checker.typeToString(checker.getTypeAtLocation(declaration.name));
    return 'export const ' + publicName + ': ' + type + ';';
  }

  var sourceFile = declaration.getSourceFile();
  var text = declaration.getText(sourceFile);
  var stripped = stripJsDoc(text).trim();

  if (ts.isFunctionDeclaration(declaration) && declaration.body) {
    var bodyStart = declaration.body.getStart(sourceFile);
    var nodeStart = declaration.getStart(sourceFile);
    return stripped.slice(0, bodyStart - nodeStart).trim() + ';';
  }

  var arrowIndex = stripped.indexOf('=> {');
  if (arrowIndex !== -1) {
    return stripped.slice(0, arrowIndex + 2).trim() + ' ...';
  }

  return stripped;
}

@rafael81
Copy link
Copy Markdown
Author

Addressed the Gemini review feedback in 13ddb05:

  • Added explicit failures when the docs entry point or module symbol cannot be loaded.
  • Updated function declaration snippet generation to emit signatures without leaking implementation bodies.
  • Fixed the generated nullish link, NonUndefined example, and $Diff example at their source JSDoc comments and regenerated the API docs.

Validation:

  • npm run docs:api
  • npm run ci-check
  • git diff --check

This follow-up was prepared with AI assistance and manually reviewed before pushing.

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.

Add a web page with API documentation that will be automatically generated from the recent source code changes

1 participant