jsdoc-scribe 1.0.1 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,110 +1,521 @@
1
- # jsdoc-scribe
2
-
3
- Pure, deterministic, **AST-based** JSDoc comment generator for JavaScript & TypeScript.
4
- **No AI / LLM is used anywhere** — every line of every comment is derived
5
- mechanically from the syntax tree (names, modifiers, type annotations,
6
- parameter lists, heritage clauses, enum members, etc). Same input always
7
- produces the same output.
8
-
9
- ## Install
10
-
11
- ```bash
12
- # run once without installing anything
13
- npx jsdoc-scribe . --write
14
-
15
- # or add it to your project
16
- npm install --save-dev jsdoc-scribe
17
-
18
- # or install it globally
19
- npm install -g jsdoc-scribe
20
- ```
21
-
22
- Once installed, the command is **`gen-comments`**.
23
-
24
- ## Usage
25
-
26
- ```bash
27
- gen-comments <path> [path2 ...] [options]
28
- ```
29
-
30
- `<path>` can be a single file **or a directory** — directories are scanned
31
- recursively for `.js` / `.jsx` / `.ts` / `.tsx` files. `node_modules`, `.git`,
32
- `dist`, `build`, `out`, `coverage`, `.next`, `.turbo`, `.cache`, and any other
33
- dotfolder are skipped automatically.
34
-
35
- | Flag | Description |
36
- |---|---|
37
- | `--write`, `-w` | Edit files **in place**. Without this flag, output goes to a sibling `<name>.commented.<ext>` file next to each original, so you can review a diff before committing to it. |
38
- | `--force`, `-f` | Re-insert comment blocks even on nodes that already have a leading `/** */`. Off by default, to stay idempotent. |
39
- | `--help`, `-h` | Show usage. |
40
- | `--version`, `-v` | Show the installed version. |
41
-
42
- ```bash
43
- gen-comments src/utils.ts # preview only -> utils.commented.ts
44
- gen-comments . # scan whole project, preview only
45
- gen-comments . --write # scan whole project, edit in place
46
- gen-comments src --write --force # also re-document already-commented files
47
- ```
48
-
49
- If you run `--write` outside a git repo, the CLI prints a one-line warning
50
- (not a blocker) recommending you commit first so you have something to diff
51
- or revert against.
52
-
53
- ## The algorithm
54
-
55
- 1. **Parse** each file into a `ts.SourceFile` AST using the TypeScript
56
- compiler's parser (`typescript` npm package). That parser is syntax-only —
57
- it never type-checks — and it's a superset parser for JavaScript, which is
58
- why this works on plain `.js`/`.jsx` just as well as `.ts`/`.tsx`.
59
- 2. **Walk** the AST recursively. Tracked node kinds:
60
- - `FunctionDeclaration` (top-level or nested)
61
- - `ClassDeclaration` + its `constructor` / methods / properties / get-set
62
- - `VariableStatement` (`const`/`let`/`var`, including arrow/function inits)
63
- - `PropertyAssignment` with a function/arrow value inside an object literal
64
- - `InterfaceDeclaration`, `TypeAliasDeclaration`, `EnumDeclaration`
65
- 3. **Skip** any node that already has a leading `/** ... */` block — unless
66
- `--force` is passed. This keeps the tool idempotent: running it twice
67
- never duplicates comments.
68
- 4. **Build** the comment block from pure syntax only:
69
- - An explicit type annotation is always used as-is.
70
- - With no annotation, it falls back to a syntactic guess: literal kind for
71
- variables (`'x'` → `string`, `[1,2]` → `Array`, …), and for function
72
- return types, a scan for a top-level `return <value>;` (so a function
73
- that clearly returns something is never mislabeled `void` just because
74
- it lacks a type annotation).
75
- - Modifiers (`async`, `static`, `private`, `readonly`, `abstract`,
76
- `export`, generator `*`) are read directly off the AST node.
77
- 5. **Insert** the comment as plain text at the exact byte offset where the
78
- node's own line indentation begins. All edits are collected first, then
79
- applied bottom-to-top so earlier offsets never shift — the rest of the
80
- file is never re-printed or reformatted, only insertions happen.
81
- 6. **Write** the result — to `<file>.commented.<ext>` by default, or back to
82
- the original file with `--write`.
83
-
84
- ## Using it as a library
85
-
86
- ```js
87
- const { processFile, collectFiles } = require('jsdoc-scribe');
88
-
89
- // process one file, return number of comment blocks added
90
- processFile('src/utils.ts', { write: true });
91
-
92
- // recursively find every matching source file under a directory
93
- const files = collectFiles('src');
94
- ```
95
-
96
- ## Known scope / limitations (by design)
97
-
98
- - Inline anonymous callbacks passed directly as call arguments
99
- (`arr.map(x => x * 2)`) are **not** commented — inserting a multi-line block
100
- there would mangle the call expression. Anything with its own declaration
101
- (function decl, class member, variable, named object property) is covered.
102
- - Type/return inference is 100% syntactic. It is never "smart" about what
103
- your code *means* — only what it *looks like* structurally.
104
- - Multi-declarator statements (`const a = 1, b = 2;`) get one combined block
105
- rather than a per-declarator function-style doc.
106
- - `.d.ts` files are skipped (no implementation to document).
107
-
108
- ## License
109
-
110
- MIT
1
+ # jsdoc-scribe
2
+
3
+ [![npm version](https://img.shields.io/npm/v/jsdoc-scribe.svg)](https://www.npmjs.com/package/jsdoc-scribe)
4
+ [![npm downloads](https://img.shields.io/npm/dm/jsdoc-scribe.svg)](https://www.npmjs.com/package/jsdoc-scribe)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
6
+ [![Node.js](https://img.shields.io/node/v/jsdoc-scribe.svg)](https://nodejs.org)
7
+
8
+ > Pure, deterministic, **AST-based** JSDoc comment generator and multi-page documentation site builder for JavaScript & TypeScript.
9
+ > **No AI. No LLM. No surprises.** Same input always produces the same output.
10
+
11
+ ---
12
+
13
+ ## What it does
14
+
15
+ `jsdoc-scribe` ships two independent CLI tools:
16
+
17
+ | Tool | What it does |
18
+ |---|---|
19
+ | `gen-comments` | Inserts `/** */` JSDoc blocks into your source files by reading the AST — no AI, no guessing |
20
+ | `gen-docs` | Generates a multi-page HTML documentation site from your already-documented source |
21
+
22
+ ---
23
+
24
+ ## Table of contents
25
+
26
+ - [Install](#install)
27
+ - [gen-comments Add JSDoc to source files](#gen-comments--add-jsdoc-to-source-files)
28
+ - [Before / after example](#before--after-example)
29
+ - [CLI flags](#cli-flags)
30
+ - [How the algorithm works](#how-the-algorithm-works)
31
+ - [gen-docs Build a documentation site](#gen-docs--build-a-documentation-site)
32
+ - [Quick start](#quick-start)
33
+ - [CLI flags](#cli-flags-1)
34
+ - [Config file](#config-file)
35
+ - [Themes](#themes)
36
+ - [Source links](#source-links)
37
+ - [Ignore patterns](#ignore-patterns)
38
+ - [Watch mode](#watch-mode)
39
+ - [Programmatic API](#programmatic-api)
40
+ - [GitHub Actions auto-deploy docs](#github-actions--auto-deploy-docs)
41
+ - [Known limitations](#known-limitations)
42
+ - [License](#license)
43
+
44
+ ---
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ # run once without installing
50
+ npx jsdoc-scribe . --write
51
+
52
+ # add to your project
53
+ npm install --save-dev jsdoc-scribe
54
+
55
+ # or install globally
56
+ npm install -g jsdoc-scribe
57
+ ```
58
+
59
+ ---
60
+
61
+ ## gen-comments Add JSDoc to source files
62
+
63
+ `gen-comments` walks your source tree, parses every `.js` / `.jsx` / `.ts` / `.tsx` file with the TypeScript compiler's AST parser, and inserts `/** */` blocks for every undocumented function, class, method, interface, enum, type alias, and variable.
64
+
65
+ ### Before / after example
66
+
67
+ **Before** a plain TypeScript file with no documentation:
68
+
69
+ ```ts
70
+ // src/auth.ts
71
+
72
+ export async function login(username: string, password: string): Promise<User> {
73
+ const user = await db.findByUsername(username);
74
+ if (!user || !verify(password, user.passwordHash)) {
75
+ throw new AuthError("Invalid credentials");
76
+ }
77
+ return user;
78
+ }
79
+
80
+ export class TokenService {
81
+ private readonly secret: string;
82
+
83
+ constructor(secret: string) {
84
+ this.secret = secret;
85
+ }
86
+
87
+ sign(payload: Record<string, unknown>, expiresIn = "1h"): string {
88
+ return jwt.sign(payload, this.secret, { expiresIn });
89
+ }
90
+
91
+ verify(token: string): Record<string, unknown> | null {
92
+ try {
93
+ return jwt.verify(token, this.secret) as Record<string, unknown>;
94
+ } catch {
95
+ return null;
96
+ }
97
+ }
98
+ }
99
+
100
+ export type AuthRole = "admin" | "editor" | "viewer";
101
+
102
+ export enum Permission {
103
+ Read = "read",
104
+ Write = "write",
105
+ Delete = "delete",
106
+ }
107
+ ```
108
+
109
+ **After** — run `gen-comments src/auth.ts --write`:
110
+
111
+ ```ts
112
+ // src/auth.ts
113
+
114
+ /**
115
+ * @async
116
+ * @param {string} username
117
+ * @param {string} password
118
+ * @returns {Promise<User>}
119
+ */
120
+ export async function login(username: string, password: string): Promise<User> {
121
+ const user = await db.findByUsername(username);
122
+ if (!user || !verify(password, user.passwordHash)) {
123
+ throw new AuthError("Invalid credentials");
124
+ }
125
+ return user;
126
+ }
127
+
128
+ /**
129
+ * @class TokenService
130
+ */
131
+ export class TokenService {
132
+ /** @type {string} */
133
+ private readonly secret: string;
134
+
135
+ /**
136
+ * @constructor
137
+ * @param {string} secret
138
+ */
139
+ constructor(secret: string) {
140
+ this.secret = secret;
141
+ }
142
+
143
+ /**
144
+ * @param {Record<string, unknown>} payload
145
+ * @param {string} [expiresIn]
146
+ * @returns {string}
147
+ */
148
+ sign(payload: Record<string, unknown>, expiresIn = "1h"): string {
149
+ return jwt.sign(payload, this.secret, { expiresIn });
150
+ }
151
+
152
+ /**
153
+ * @param {string} token
154
+ * @returns {Record<string, unknown> | null}
155
+ */
156
+ verify(token: string): Record<string, unknown> | null {
157
+ try {
158
+ return jwt.verify(token, this.secret) as Record<string, unknown>;
159
+ } catch {
160
+ return null;
161
+ }
162
+ }
163
+ }
164
+
165
+ /**
166
+ * @typedef {"admin" | "editor" | "viewer"} AuthRole
167
+ */
168
+ export type AuthRole = "admin" | "editor" | "viewer";
169
+
170
+ /**
171
+ * @enum {string}
172
+ */
173
+ export enum Permission {
174
+ Read = "read",
175
+ Write = "write",
176
+ Delete = "delete",
177
+ }
178
+ ```
179
+
180
+ > The tool is **idempotent** — running it a second time adds zero blocks.
181
+ > Nodes that already have a `/** */` block are never touched unless you pass `--force`.
182
+
183
+ ### CLI flags
184
+
185
+ ```bash
186
+ gen-comments <path> [path2 ...] [options]
187
+ ```
188
+
189
+ `<path>` can be a file or directory. Directories are recursively scanned. `node_modules`, `dist`, `build`, `.git`, and all dotfolders are skipped automatically.
190
+
191
+ | Flag | Short | Description |
192
+ |---|---|---|
193
+ | `--write` | `-w` | Edit files **in place**. Without this flag, output goes to a sibling `<name>.out.<ext>` file so you can review the diff first. |
194
+ | `--force` | `-f` | Re-insert blocks even on nodes that already have `/** */`. Useful for regenerating stale docs. |
195
+ | `--help` | `-h` | Show usage. |
196
+ | `--version` | `-v` | Show installed version. |
197
+
198
+ ```bash
199
+ gen-comments src/utils.ts # preview → writes utils.out.ts
200
+ gen-comments . # scan whole project, preview only
201
+ gen-comments . --write # scan and edit in place
202
+ gen-comments src --write --force # also re-document already-commented files
203
+ ```
204
+
205
+ > **Tip:** Commit your changes before running `--write`. The CLI reminds you if you're outside a git repo.
206
+
207
+ ### How the algorithm works
208
+
209
+ 1. **Parse** — uses `typescript` (the npm package) purely as a syntax parser. Works on `.js`/`.jsx` as well as `.ts`/`.tsx`. No type-checking, no compilation.
210
+ 2. **Walk** — visits `FunctionDeclaration`, `ClassDeclaration` (+ constructor / methods / properties / accessors), `VariableStatement` (including arrow functions and const objects), `InterfaceDeclaration`, `TypeAliasDeclaration`, `EnumDeclaration`.
211
+ 3. **Skip** — any node with an existing leading `/** */` block is left untouched (unless `--force`).
212
+ 4. **Build** — the comment block is built purely from syntax:
213
+ - Explicit type annotations are used verbatim.
214
+ - Without annotations, the tool infers from syntax: literal kind for variables (`'x'` → `string`, `[1,2]` → `Array`), and for function returns it scans for a top-level `return <value>` statement.
215
+ - Modifiers (`async`, `static`, `private`, `readonly`, `abstract`, `export`, generator `*`) are read from the AST.
216
+ 5. **Insert** — edits are collected and applied bottom-to-top so no byte offset shifts, and the rest of the file is never reprinted.
217
+
218
+ ---
219
+
220
+ ## gen-docs — Build a documentation site
221
+
222
+ `gen-docs` reads your source files (or an entire directory), extracts the public API using the same AST engine, and outputs a multi-page HTML documentation site with search, themes, source links, and cross-references.
223
+
224
+ ### Quick start
225
+
226
+ ```bash
227
+ # Generate docs for an entire directory
228
+ gen-docs src --out docs --title "My Project"
229
+
230
+ # Open docs/index.html in your browser
231
+ ```
232
+
233
+ The output is a self-contained static site — no server required. Output structure:
234
+
235
+ ```
236
+ docs/
237
+ index.html # project index (module cards)
238
+ search-index.js # shared search index (fetched once)
239
+ assets/
240
+ style.css # shared CSS — cached after first page load
241
+ app.js # shared JS (search, theme toggle, copy)
242
+ modules/
243
+ api.html
244
+ utils.html
245
+ ...
246
+ ```
247
+
248
+ ### CLI flags
249
+
250
+ ```bash
251
+ gen-docs <path> [path2 ...] [options]
252
+ ```
253
+
254
+ | Flag | Short | Description |
255
+ |---|---|---|
256
+ | `--out <dir>` | `-o` | Output directory (default: `docs`). |
257
+ | `--title <name>` | `-t` | Site title shown in the header and `<title>` tag. |
258
+ | `--theme <name>` | `-T` | Visual theme: `default`, `minimal`, or `dark` (default: `default`). |
259
+ | `--json` | `-j` | Also write a `docs.json` machine-readable export. |
260
+ | `--readme` | `-r` | Also write a `README.md` with markdown tables of every module. |
261
+ | `--source-url <url>` | `-s` | GitHub base URL for per-card source links (e.g. `https://github.com/org/repo/blob/main`). |
262
+ | `--ignore <glob>` | `-I` | Glob pattern to exclude files. Repeatable. |
263
+ | `--config <file>` | `-c` | Path to a `.jsdoc-scribe.json` config file. |
264
+ | `--watch` | `-W` | Rebuild on file changes (150 ms debounce). |
265
+ | `--help` | `-h` | Show usage. |
266
+ | `--version` | `-v` | Show installed version. |
267
+
268
+ ```bash
269
+ gen-docs src --out docs --title "My API"
270
+ gen-docs src --theme dark --source-url https://github.com/org/repo/blob/main
271
+ gen-docs src --json --readme --out _site
272
+ gen-docs src --ignore "**/internal/**" --ignore "**/*.test.ts"
273
+ gen-docs src --watch
274
+ ```
275
+
276
+ ### Config file
277
+
278
+ Create `.jsdoc-scribe.json` in your project root to avoid repeating flags:
279
+
280
+ ```json
281
+ {
282
+ "out": "docs",
283
+ "title": "My Project",
284
+ "theme": "default",
285
+ "json": true,
286
+ "readme": false,
287
+ "sourceUrl": "https://github.com/org/repo/blob/main",
288
+ "ignore": [
289
+ "**/internal/**",
290
+ "**/*.test.ts",
291
+ "**/*.spec.ts"
292
+ ]
293
+ }
294
+ ```
295
+
296
+ CLI flags always override config file values. Use `--config path/to/other.json` to point to a custom config path.
297
+
298
+ ### Themes
299
+
300
+ | Theme | Description |
301
+ |---|---|
302
+ | `default` | Blue-accented light sidebar, light/dark toggle stored in `localStorage`. |
303
+ | `minimal` | Clean light-only layout, no toggle. |
304
+ | `dark` | Forced dark mode, no toggle. |
305
+
306
+ ```bash
307
+ gen-docs src --theme minimal
308
+ gen-docs src --theme dark
309
+ ```
310
+
311
+ ### Source links
312
+
313
+ Pass a GitHub blob base URL and every documented symbol card gets a clickable "line N" link straight to the source:
314
+
315
+ ```bash
316
+ gen-docs src \
317
+ --source-url https://github.com/org/repo/blob/main \
318
+ --out docs
319
+ ```
320
+
321
+ Each card then shows `line 42 ↗` linking to `https://github.com/org/repo/blob/main/src/utils.ts#L42`.
322
+
323
+ ### Ignore patterns
324
+
325
+ ```bash
326
+ # Exclude test files and an entire folder
327
+ gen-docs src \
328
+ --ignore "**/*.test.ts" \
329
+ --ignore "**/*.spec.ts" \
330
+ --ignore "**/internal/**"
331
+ ```
332
+
333
+ Patterns support `**/` prefix and `*` wildcard. You can also specify them in `.jsdoc-scribe.json`.
334
+
335
+ ### Watch mode
336
+
337
+ ```bash
338
+ gen-docs src --out docs --watch
339
+ ```
340
+
341
+ The site rebuilds whenever any matching source file changes. Useful during active development — just refresh the browser.
342
+
343
+ ---
344
+
345
+ ## Programmatic API
346
+
347
+ ```js
348
+ const {
349
+ collectFiles,
350
+ extractModule,
351
+ extractModules,
352
+ buildSite,
353
+ generateSite,
354
+ moduleLabel,
355
+ moduleHtmlPath,
356
+ DEFAULT_EXTENSIONS,
357
+ DEFAULT_IGNORE_DIRS,
358
+ } = require('jsdoc-scribe/docs');
359
+ ```
360
+
361
+ ### One-shot generation
362
+
363
+ ```js
364
+ const { generateSite } = require('jsdoc-scribe/docs');
365
+ const fs = require('fs'), path = require('path');
366
+
367
+ const pages = generateSite(['src'], {
368
+ projectName: 'My Project',
369
+ version: '1.0.0',
370
+ });
371
+
372
+ // pages = [{ path: 'index.html', html }, { path: 'assets/style.css', html }, ...]
373
+ for (const p of pages) {
374
+ const dest = path.join('docs', p.path);
375
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
376
+ fs.writeFileSync(dest, p.html, 'utf8');
377
+ }
378
+ ```
379
+
380
+ ### Step-by-step
381
+
382
+ ```js
383
+ const { collectFiles, extractModules, buildSite } = require('jsdoc-scribe/docs');
384
+ const fs = require('fs');
385
+ const path = require('path');
386
+
387
+ // 1. Collect source files
388
+ const files = collectFiles(['src'], {
389
+ extensions: ['.ts', '.tsx'],
390
+ ignore: ['**/*.test.ts'],
391
+ });
392
+
393
+ // 2. Extract the API model
394
+ const modules = extractModules(files);
395
+
396
+ // 3. Inspect the model
397
+ modules.forEach(mod => {
398
+ console.log(mod.filePath, {
399
+ functions: mod.functions.length,
400
+ classes: mod.classes.length,
401
+ description: mod.description,
402
+ });
403
+ });
404
+
405
+ // 4. Build the HTML site
406
+ const pages = buildSite(modules, {
407
+ title: 'My Project',
408
+ theme: 'dark',
409
+ sourceUrl: 'https://github.com/org/repo/blob/main',
410
+ });
411
+
412
+ // 5. Write all files
413
+ // pages = [{ path, html }] and includes HTML pages + shared assets:
414
+ // assets/style.css, assets/app.js, search-index.js
415
+ // Always use mkdirSync so assets/ and modules/ are created automatically.
416
+ const outDir = 'docs';
417
+ for (const p of pages) {
418
+ const dest = path.join(outDir, p.path);
419
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
420
+ fs.writeFileSync(dest, p.html, 'utf8');
421
+ }
422
+ ```
423
+
424
+ ### Extracted module shape
425
+
426
+ Each module object returned by `extractModule(filePath)` has this structure:
427
+
428
+ ```ts
429
+ {
430
+ filePath: string;
431
+ description: string | null; // top-of-file @module description
432
+ since: string | null; // @since from top-of-file block
433
+ functions: Array<{
434
+ name: string;
435
+ params: Array<{ name: string; type: string; optional: boolean }>;
436
+ returnType: string;
437
+ isAsync: boolean;
438
+ isExported: boolean;
439
+ line: number; // 1-based line number
440
+ description: string | null;
441
+ jsdocParams: Array<{ name: string; type: string; description: string }>;
442
+ returns: { type: string; description: string } | null;
443
+ throws: Array<{ type: string; description: string }>;
444
+ since: string | null;
445
+ deprecated: string | null;
446
+ }>;
447
+ classes: Array<{ name: string; methods: [...]; properties: [...]; ... }>;
448
+ interfaces: Array<{ ... }>;
449
+ typeAliases: Array<{ ... }>;
450
+ enums: Array<{ ... }>;
451
+ variables: Array<{ ... }>;
452
+ }
453
+ ```
454
+
455
+ ---
456
+
457
+ ## GitHub Actions — auto-deploy docs
458
+
459
+ Add this workflow to automatically publish your docs to GitHub Pages on every push to `main`:
460
+
461
+ ```yaml
462
+ # .github/workflows/docs.yml
463
+ name: Deploy docs
464
+
465
+ on:
466
+ push:
467
+ branches: [main]
468
+
469
+ permissions:
470
+ contents: read
471
+ pages: write
472
+ id-token: write
473
+
474
+ jobs:
475
+ deploy:
476
+ runs-on: ubuntu-latest
477
+ environment:
478
+ name: github-pages
479
+ url: ${{ steps.deployment.outputs.page_url }}
480
+ steps:
481
+ - uses: actions/checkout@v4
482
+
483
+ - uses: actions/setup-node@v4
484
+ with:
485
+ node-version: 20
486
+
487
+ - run: npm ci
488
+
489
+ - name: Generate docs
490
+ run: |
491
+ npx gen-docs src \
492
+ --out _site \
493
+ --title "${{ github.event.repository.name }}" \
494
+ --source-url "https://github.com/${{ github.repository }}/blob/main" \
495
+ --json
496
+
497
+ - uses: actions/upload-pages-artifact@v3
498
+ with:
499
+ path: _site
500
+
501
+ - id: deployment
502
+ uses: actions/deploy-pages@v4
503
+ ```
504
+
505
+ Enable GitHub Pages in your repo settings (Settings → Pages → Source: GitHub Actions) and your docs will be live at `https://<org>.github.io/<repo>` after every push.
506
+
507
+ ---
508
+
509
+ ## Known limitations
510
+
511
+ - **Inline anonymous callbacks** passed directly as call arguments (`arr.map(x => x * 2)`) are not documented — inserting a multi-line block there would mangle the expression. Named declarations (functions, class members, variables, object properties) are all covered.
512
+ - **Type inference is 100% syntactic.** The tool reads what your code *looks like*, not what it *means*. It never evaluates, imports, or type-checks.
513
+ - **Multi-declarator statements** (`const a = 1, b = 2;`) get one combined block rather than per-declarator docs.
514
+ - **`.d.ts` files** are skipped — no implementation to document.
515
+ - **`gen-docs` does not serve** — the output is a static site. Use any static file server (`npx serve docs`) or deploy to GitHub Pages, Netlify, Vercel, etc.
516
+
517
+ ---
518
+
519
+ ## License
520
+
521
+ MIT © [Chintan](https://github.com/imchintoo)