Writing and publishing documentation
Introduction · Tutorial · API overview
DI Bag's documentation starts with ordinary Markdown. The README introduces the library, the tutorial teaches its APIs, and the server guide shows how to use those APIs in applications. TypeDoc generates the exact API reference from the two public TypeScript entry points. VitePress publishes these pages as a searchable website at dany-fedorov.github.io/di-bag.
Work locally
Use the repository's Node version, then install both development and documentation dependencies from their lockfiles:
npm ci
npm ci --prefix tools/docs
npm run docs:generate
npm run docs:devOpen the local URL printed by VitePress with the /di-bag/ path. Edit the original Markdown files; the development command stages changes automatically. After editing API comments, run npm run docs:generate again to update the reference.
To verify and preview the production build:
npm run docs:check
npm run docs:build
npm run docs:previewChoose the right source
| What needs changing | Edit |
|---|---|
| First impression, installation, quickstart | README.md |
| Concepts and examples for each API | tutorial.md |
| Tradeoffs and comparisons with other libraries | comparison.md |
| Node HTTP, Express, Fastify, Bun, and Deno applications | server-integration.md |
| API navigation and type inventories | api-reference.md |
| A signature's explanation, parameters, return value, or failure behavior | The public declaration's comment in src, then regenerate |
| A call's line and example in the API card | That call's JSDoc summary, @throws, and @example in src, then regenerate |
| The card's "one way per task" table | api-card-tasks.json, then regenerate |
| A rule a coding agent must follow, the per-module check, the fast check | AGENTS.md |
| The recommended module layout | examples-modularity.md; copy the block byte for byte into AGENTS.md |
| How to do one agent task | recipes.md |
A compile-time message family or a DI_BAG_* code: when, cause, fix | errors.md; add the section in the change that adds the code |
| Site navigation and appearance | VitePress configuration and theme |
| The list of guides and contributor documents | Documentation map |
Keep docs/reference/ generated. Its Markdown is committed so it can be reviewed in pull requests and read directly on GitHub. Edit source comments instead of patching generated pages. Use import type for type-only API exports; the reference must never suggest that Bag, Builder, or Provider are public runtime constructors.
Write examples with enough context to reproduce them. State whether a snippet continues an earlier example. Keep acquisition, cancellation, and cleanup rules close to the code they explain. Link to the tutorial for a learning path and to the generated reference for exact overloads and generic constraints.
Keep comparison claims specific and link to the other library's official docs or source. Distinguish a typed lookup from checks across the dependency graph, a Promise-valued service from automatically awaited dependencies, and feature availability from stability or performance. Explain when an alternative is a good fit. Record version-sensitive scope and review dates in the comparison guide.
How generation is checked
npm run docs:generate uses TypeDoc, its Markdown plugin, and its VitePress theme. It reads only src/index.ts and src/node.ts. The rendering extension prints declarations with TypeScript so constructor constraints, grouping, readonly fields, and const type parameters retain their meaning. TypeDoc supplies the prose, navigation, and source links.
Generation requires comments on exported declarations and checks generated public exports and callable overloads against the TypeScript compiler's view, parses every generated TypeScript block, validates documentation links, and rejects internal compiler witness fields in the public output.
Generation also writes docs/agent/api-card.md from the JSDoc of the runtime surface (DiBag facade members, Builder and Bag methods, the error classes) and the task table in tools/docs/api-card-tasks.json. Each call gets its first summary sentence, the DI_BAG_* codes named in its @throws, and its @example. Generation fails when a runtime call has no @example, a task names an unknown call, or the card exceeds 400 lines. Never edit the card by hand.
npm run docs:check runs the tooling tests, generates a fresh temporary reference, and compares it with the committed files. Added, changed, and removed pages all count as drift. It then checks the agent documentation:
- Snippets. Every
tsblock inAGENTS.mdanddocs/agent/*.md, and every@exampleinsrc/, is type-checked in one strict program against declarations emitted fromsrc/into a temporarynode_modules/di-bag, sodi-baganddi-bag/noderesolve as in a consumer project. No prior build is needed. Leading comment lines are markers:// src/features/x/module.tsmakes the block that file, so blocks on one page can import each other;// continues: <heading-id>prepends the last block under that heading on the same page;// expect-error: <text>requires a diagnostic containing the text. An@examplewithout imports getsimport { DiBag } from 'di-bag';. - Size budgets.
AGENTS.mdat most 150 lines, each recipe section under 60 lines, anddocs/agent/api-card.mdat most 400 lines. - Layout identity. The
textblock inAGENTS.mdequals the one under "Recommended module layout" in the modularity guide. - Errors page. The
DI_BAG_*codes insrc/and the code sections ofdocs/agent/errors.mdare the same set; every heading there has an explicit{#id}, a code section's id is the code lower-cased with_replaced by-, and the six compile-time family sections exist. - Message URLs. Every
https://dany-fedorov.github.io/di-bag/...URL insrc/names an existing page and heading.docs:buildchecks them again against the rendered HTML.
It also stages the site and checks that linked repository files exist. npm run docs:build checks website page links while building the production artifact, then verifies rendered anchors and asset paths under the Pages base. Run both before pushing documentation changes.
The pinned tools and their independent lockfile live in tools/docs. TypeDoc uses classic TypeScript 6.0.3 because its compiler API is required for documentation generation. The library's separate native compiler checks remain part of development verification.
Website and package boundaries
The site command stages the README, Markdown in docs/guides/ and docs/agent/ (published at /agent/), and generated reference pages into the ignored tools/docs/site/ directory. The site description is read from package.json. It rewrites relative links for the hosted routes; links to examples, source files, and other repository material lead back to GitHub. Nothing else is copied into the site.
The production output is tools/docs/site/.vitepress/dist/. Keep the configured /di-bag/ base when serving it as a GitHub Pages project site. Local search indexes the built Markdown and needs no external search account. Generated pages offer links to their source declarations; handwritten pages offer an edit link.
Documentation dependencies stay in the private tools package. The published library archive contains the manifest, README, license, dist/, AGENTS.md, and docs/agent/, so agents read the rules and recipes in node_modules/di-bag; it does not contain the website or its dependencies.
Publish through GitHub Pages
The documentation workflow checks generation and builds the site on pull requests and pushes to main. Only a successful main build deploys its artifact to the github-pages environment. A manual run on main can also rebuild and deploy the site.
The repository's Pages source must be GitHub Actions. The deployment job uses GitHub's short-lived Pages and identity-token permissions; no publishing token belongs in this repository. To publish an update, regenerate changed API pages, run the checks above, commit the sources and generated Markdown, and push. Inspect the Documentation workflow's deployment result before claiming the public site is updated.