npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@massivescale/tsp-api-docs

v1.0.0

Published

TypeSpec emitter for generating API reference documentation in Markdown for Azure DevOps Wiki, GitHub, and DocFx.

Readme

@massivescale/tsp-api-docs

npm version License: MIT CI

TypeSpec emitter for generating API reference documentation in Markdown.

Supports multiple output formats targeting Azure DevOps Wiki, GitHub, and DocFx.

Features

  • Emits Markdown docs with per-service overview pages, per-operation pages, and per-type pages (models, enums, unions, scalars). Type pages cover payload data only — response models and metadata-only models are documented on operation pages instead. See Which types get pages.
  • Three output formats: azure-devops (default), github, and docfx.
  • Automatically formats Markdown tables with aligned columns.
  • External Handlebars templates — override any built-in template with a custom .hbs file.
  • Optional root service index page.
  • Versioned API support via @typespec/versioning.
  • Optional api-name prefix for versioned file/folder slugs (e.g. my-api-v1-0/).
  • Configurable route-prefix with {version} token substitution for HTTP request lines (default: api/{version}).
  • Response headers documented per status code, and included in example responses.
  • Query, header, path, and cookie parameters documented by their HTTP wire names (e.g. $expand, If-Match).
  • Request body examples automatically omit read-only and immutable properties based on HTTP verb visibility.
  • Type names rendered exactly as defined — no CamelCase splitting in page titles.
  • Related-methods table on type pages lists only operations that directly address the type — return it (including through a response model such as EntityResponse<Widget>), accept it as a parameter or body (including through MergePatchUpdate<Widget>), or use a direct array/record/union of it. Operations that reference the type only through nested properties are excluded, except for one-level wrapper request models that are direct operation parameters (e.g. CreateWidgetRequest { widget: Widget }). Types decorated with @error are never treated as addressable entities and have no Methods section.
  • DocFx toc.yml output is YAML-safe — service and page titles containing colons or other special characters are properly quoted.

Requirements

  • Node.js 22 or later
  • @typespec/compiler ^1.15.0
  • @typespec/http ^1.15.0
  • @typespec/openapi ^1.15.0
  • @typespec/versioning >=0.85.0 <1.0.0

Install

npm install --save-dev @massivescale/tsp-api-docs

Peer dependencies must also be present in your project:

npm install --save-dev @typespec/compiler @typespec/http @typespec/openapi @typespec/versioning

Emitter Usage

Add the emitter to your TypeSpec config and set options as needed.

emit:
  - "@massivescale/tsp-api-docs"
options:
  "@massivescale/tsp-api-docs":
    emitter-output-dir: ./tsp-output
    format: azure-devops

Options

All options are set under the "@massivescale/tsp-api-docs" key in tspconfig.yaml:

options:
  "@massivescale/tsp-api-docs":
    format: azure-devops
    api-name: "My API"
    route-prefix: "api/{version}"

General options

| Option | Type | Default | Description | | ------------------------- | ------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | api-name | string | — | API name prefix for file/folder slugs. See API Name below. | | clean-output-dir | boolean | true | Before emitting, deletes the entire emitter-output-dir for azure-devops and github formats. For docfx, enumerates and removes only non-project files, preserving docfx.json. Do not point emitter-output-dir at a directory that contains unrelated files when this is true. Set to false to skip cleaning entirely. | | emit-project-files | boolean | true | When true, emits project/configuration files (e.g. docfx.json). Set to false to emit documentation files only. | | emit-relation-diagram | boolean | false | When true, emits a relation-diagram.md containing a Mermaid ER diagram of all types for each service. | | emitter-output-dir | string | ./tsp-output | Output directory for generated files. | | format | "azure-devops" | "github" | "docfx" | "azure-devops" | Output format. See Output Formats below. | | overwrite-project-files | boolean | false | When false, project files are only written if they do not already exist. Set to true to always overwrite them. | | page-title-prefix | string | — | Fallback title prefix used when the service has no explicit title. | | render-service-index | boolean | false | Emit a root index page listing all services. | | route-prefix | string | api/{version} | Prefix prepended to HTTP request paths. Supports {version} token substitution. See Route Prefix below. | | templates | TemplateOverrides | — | Per-template path overrides for custom Handlebars templates. See Custom Templates below. |

DocFx options

DocFx-specific options are nested under a docfx: key, which itself lives under "@massivescale/tsp-api-docs". These are only applied when format: docfx.

options:
  "@massivescale/tsp-api-docs":
    format: docfx
    docfx:
      app-name: "My API"
      app-title: "My API Reference"
      enable-pdf: true
      enable-pdf-toc-page: true
      theme:
        - default
        - modern

| Option | Type | Default | Description | | --------------------- | ---------- | ----------------------- | ------------------------------------------------------------------------------------------------ | | app-name | string | api-name or "API" | Application name in the site header. Sets globalMetadata._appName in docfx.json. | | app-title | string | api-name or "API" | Application title in the browser <title> tag. Sets globalMetadata._appTitle in docfx.json. | | emit-json | boolean | true | When false, suppresses docfx.json output while leaving documentation pages unaffected. | | enable-pdf | boolean | true | Sets globalMetadata.pdf in docfx.json, enabling PDF generation in the DocFx build. | | enable-pdf-toc-page | boolean | true | Sets globalMetadata.pdfTocPage in docfx.json, enabling a PDF table-of-contents page. | | theme | string[] | ["default", "modern"] | Template names applied to the build.template array in docfx.json. |

Which types get pages

A type page (and a row in the Types index) describes data: something a client sends or receives as an HTTP body. The emitter decides this by asking @typespec/http how each operation's request and response bodies resolve, rather than documenting every model in the namespace. This is the same rule @massivescale/tsp-aspnetcore-api uses to decide which models get a C# class, and it matches how @typespec/openapi3 builds schemas.

TypeSpec calls @statusCode, @header, @cookie, @query, and @path properties metadata. Two kinds of model describe HTTP details rather than data:

  • A metadata-only model has only metadata properties, e.g. model ETagHeader { @header("ETag") etag: string; }, model UpdatedResponse { ...NoContentResponse; ...ETagHeader; }, or a spread parameter model like model IfMatchHeader { @header("If-Match") ifMatch?: string; }. It never gets a type page. Its properties show up on the operation pages that use it, as request headers, response headers, or parameters.
  • A response model is used as an operation's return type and carries metadata. Only its body is data:
    • Explicit body. With an @body or @bodyRoot property (model EntityResponse<T> { ...OkResponse; ...ETagHeader; @body body: T; }, or @error model NotFoundError { ...NotFoundResponse; @body body: Error; }), the response model gets no type page. Its body type (T, Error) does. The response model's @doc still appears as that status code's description on the operation page.
    • Implicit body. If a response model mixes metadata with plain properties and has no @body, the plain properties form the body. The model gets a type page that lists only those plain properties.
model WidgetResult {
  @header("ETag") etag: string; // metadata: shown as a response header on the operation page
  name: string;                 // body: shown on the WidgetResult type page
}

@get read(): WidgetResult;

Metadata never appears in a type's property table, JSON representation, or relation diagram entry, wherever the model is used. Specifically, @header, @cookie, and @statusCode properties are left out, as are properties typed as a metadata-only or explicit-body response model. @path and @query properties stay, because on a returned resource (model Widget { @path id: string; ... }) they are ordinary body data.

Reachability

When the service has HTTP operations, a model, union, or scalar gets a page only if an operation reaches it:

  • a request body, a response body (as resolved above), or a parameter type;
  • transitively, a property type, base model, array/record element, union variant, or MergePatchUpdate<T> source of one of those;
  • every derived model of a reachable @discriminator base. A derived model that is itself a response model (e.g. model OddPet extends Pet { kind: "odd"; @body body: Toy; }) still gets no page.

Enums always get a page, whether or not an operation uses them. Templated models (EntityResponse<T>) never get their own page; their body types do.

If a base model is metadata-only, a derived model's "Base type" points at the nearest base that does have a page (or is omitted).

When the service has no HTTP operations (a models-only library), every named model, enum, union, and scalar in the namespace gets a page, except metadata-only models and explicit-body response models.

Operation pages

Each operation page documents the HTTP request and every response:

  • HTTP request — the verb and URI template, with the route prefix applied. Percent-encoded names are decoded so the line reads the way a client types it ({?$expand} rather than {?%24expand}).
  • Path parameters, Optional query parameters, Request headers, and Request cookies — one table each, using the wire name from @path, @query, @header, or @cookie (e.g. $expand, If-Match), not the TypeSpec property name. Empty path and cookie sections are omitted. Operations without HTTP metadata get a single Parameters table instead.
  • Request body — the body type, content types, and a JSON example.
  • Response — what the caller receives on success (the 2xx body types, or void), followed by one row per status code with its body type and description. Status codes show their standard reason phrase (e.g. 409 Conflict, 412 Precondition Failed).
  • Response headers — one table per status code that returns headers (name, type, required, summary).
  • Examples — from @opExample, or generated from the HTTP metadata. Example requests use wire names (?$expand=string), and example responses include response headers (ETag: string). When an @opExample return value is a response model, its @body value becomes the JSON body and its header values become the header lines.

Output Formats

azure-devops (default)

Generates structure compatible with Azure DevOps Wiki. Index pages sit beside the folder they describe — Azure DevOps Wiki associates a page with a folder when the page is at the same level as (not inside) the folder.

tsp-output/
  README.md                         # root index (render-service-index: true)
  <service-slug>.md                 # overview — beside the service folder
  <service-slug>/
    api.md                          # operations index — beside api/
    api/
      <Operation>.md
    resources.md                    # types index — beside resources/
    resources/
      <Type>.md

github

Generates structure compatible with GitHub rendering. Each folder's landing page is README.md, which GitHub renders automatically when browsing directories.

tsp-output/
  README.md                         # root index (render-service-index: true)
  <service-slug>/
    README.md                       # overview
    api/
      README.md                     # sub-folder index
      <Operation>.md
    resources/
      README.md                     # sub-folder index
      <Type>.md

docfx

Generates structure compatible with a DocFx project. Each service folder contains an index.md overview and a toc.yml table of contents for navigation. When render-service-index: true, a root toc.yml is also emitted. A docfx.json project configuration file is emitted at the output root by default (see DocFx Project Files).

tsp-output/
  docfx.json                        # project config (emit-project-files: true)
  index.md                          # root index (render-service-index: true)
  toc.yml                           # root TOC (render-service-index: true)
  <service-slug>/
    index.md                        # overview
    toc.yml                         # service TOC (Overview / API / Resources)
    relation-diagram.md             # Mermaid ER diagram (emit-relation-diagram: true)
    api/
      <Operation>.md
    resources/
      <Type>.md

DocFx Project Files

When format: docfx is used, the emitter writes a docfx.json configuration file at the output root. This file is only written if it does not already exist (controlled by overwrite-project-files). To skip it entirely, set emit-project-files: false or docfx: { emit-json: false }.

The following options populate fields in the generated docfx.json:

options:
  "@massivescale/tsp-api-docs":
    format: docfx
    docfx:
      app-name: "My API" # globalMetadata._appName
      app-title: "My API Docs" # globalMetadata._appTitle
      enable-pdf: true # globalMetadata.pdf
      enable-pdf-toc-page: true # globalMetadata.pdfTocPage
      theme:
        - default
        - my-custom-theme

Relation Diagram

When emit-relation-diagram: true, a relation-diagram.md file is emitted in each service folder. It contains a Mermaid erDiagram block that shows every type that has a page (see Which types get pages) and their relationships:

options:
  "@massivescale/tsp-api-docs":
    emit-relation-diagram: true

The code fence syntax is automatically selected per format — Azure DevOps Wiki uses :::mermaid / ::: while GitHub and DocFx use ```mermaid / ```.

The diagram includes:

  • Models as entities with their properties and types
  • Enums as entities with their members
  • Unions as entities with their named variants
  • Relationship lines between models that reference other service types

API Name

The api-name option provides a consistent prefix for file and folder slugs, which is useful when the TypeSpec service title differs from how you want the output organized.

options:
  "@massivescale/tsp-api-docs":
    api-name: "My Awesome API"

Non-versioned service — the slug is derived from api-name instead of the service title:

my-awesome-api.md
my-awesome-api/
  api/Get-Widget.md
  resources/Widget.md

Versioned service — the slug is <api-name> <version> slugified:

my-awesome-api-v1-0.md        # version 1.0 folder and overview
my-awesome-api-v2-0.md        # version 2.0 folder and overview

When render-service-index is also enabled, versioned entries are grouped under the api-name heading in the index.

The combined label (e.g. "My Awesome API v1.0") is also exposed to all templates as the {{apiName}} variable so custom templates can reference it.

Route Prefix

The route-prefix option controls the path prefix shown in HTTP request lines on operation pages. It supports a {version} token that is substituted with the actual API version value for versioned services.

The default value is api/{version}:

options:
  "@massivescale/tsp-api-docs":
    route-prefix: "api/{version}"

Non-versioned service — {version} resolves to an empty string, giving just api:

GET /api/widgets/{id}

Versioned service at v1.0 — {version} is substituted with 1.0:

GET /api/1.0/widgets/{id}

To use a custom prefix pattern:

options:
  "@massivescale/tsp-api-docs":
    route-prefix: "v{version}/rest"

To emit bare paths with no prefix, set route-prefix to an empty string:

options:
  "@massivescale/tsp-api-docs":
    route-prefix: ""

Custom Templates

Any of the built-in Handlebars templates can be replaced by specifying a path to a custom .hbs file. Paths are resolved relative to the directory where tsp compile is run.

options:
  "@massivescale/tsp-api-docs":
    templates:
      overview: ./my-templates/overview.md.hbs
      operation: ./my-templates/operation.md.hbs

Only the templates you list are overridden; all others continue to use the built-in defaults.

Available template keys

| Key | Built-in file | Renders | | ------------------ | ----------------------------------- | ----------------------------------------------------- | | overview | templates/overview.md.hbs | Service overview page | | operation | templates/operation.md.hbs | Individual operation reference page | | type | templates/type.md.hbs | Type page (models, unions, scalars) | | enum | templates/enum.md.hbs | Enum type page | | service-index | templates/service-index.md.hbs | Root service index | | operations-index | templates/operations-index.md.hbs | api/ sub-folder index | | types-index | templates/types-index.md.hbs | resources/ sub-folder index | | docfx-project | templates/docfx.json.hbs | DocFx docfx.json project config (docfx format only) |

Template variables

All templates receive the standard view model for their page type. The following variables are common across all page templates:

| Variable | Description | | -------------- | --------------------------------------------------------------------------------------------------- | | title | Page title (service label, operation name, or type name). | | summary | Doc summary from the TypeSpec @summary decorator, if present. | | versionLabel | The API version string (e.g. "v1.0"), present only on versioned services. | | apiName | The full api-name-prefixed label (e.g. "My Awesome API v1.0"). undefined when not configured. |

Refer to the built-in templates in templates/ for the full variable list for each page type.

The operation template also receives pathParameters, optionalQueryParameters, requestHeaders, and requestCookies (each a list of name/type/requiredLabel/summaryOrFallback, keyed by wire name), parameters (every TypeSpec parameter by TypeSpec name), and responses, where each response has statusCode, type, description, and headers. responseHeaders lists every response header across all status codes.

Contributing

git clone https://github.com/MassiveScale/tsp-api-docs.git
cd tsp-api-docs
npm install
npm test

Key source files: src/emitter.ts (core), src/lib.ts (option schema), src/templates.ts (template loader). Example TypeSpec projects are in examples/.

License

MIT