jsdoczoom 0.4.21 → 1.0.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/dist/cli.js +38 -13
- package/dist/drilldown.js +12 -9
- package/dist/index.js +1 -0
- package/dist/skill-text.js +18 -0
- package/dist/text-format.js +42 -0
- package/dist/type-declarations.js +113 -0
- package/package.json +1 -1
- package/types/index.d.ts +1 -0
- package/types/skill-text.d.ts +1 -1
- package/types/text-format.d.ts +6 -0
- package/types/types.d.ts +1 -0
package/dist/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import { JsdocError } from "./errors.js";
|
|
|
7
7
|
import { lint, lintFiles } from "./lint.js";
|
|
8
8
|
import { parseSelector } from "./selector.js";
|
|
9
9
|
import { RULE_EXPLANATIONS, SKILL_TEXT } from "./skill-text.js";
|
|
10
|
+
import { formatTextOutput } from "./text-format.js";
|
|
10
11
|
import { DEFAULT_CACHE_DIR, VALIDATION_STATUS_PRIORITY } from "./types.js";
|
|
11
12
|
import { validate, validateFiles } from "./validate.js";
|
|
12
13
|
|
|
@@ -30,7 +31,8 @@ Options:
|
|
|
30
31
|
-c, --check Run validation mode
|
|
31
32
|
-l, --lint Run lint mode (comprehensive JSDoc quality)
|
|
32
33
|
-s, --skill Print JSDoc writing guidelines
|
|
33
|
-
--
|
|
34
|
+
--json Output as JSON (default is plain text)
|
|
35
|
+
--pretty Format JSON output with 2-space indent (use with --json)
|
|
34
36
|
--limit N Max results shown (default 500)
|
|
35
37
|
--no-gitignore Include files ignored by .gitignore
|
|
36
38
|
--disable-cache Skip all cache operations
|
|
@@ -51,8 +53,12 @@ Stdin:
|
|
|
51
53
|
find . -name "*.ts" | jsdoczoom -c
|
|
52
54
|
|
|
53
55
|
Output:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
Plain text by default. Each item has a "# path@depth" header followed by
|
|
57
|
+
content. Use the header value as the next selector to drill deeper.
|
|
58
|
+
Use --json for machine-parseable JSON output.
|
|
59
|
+
|
|
60
|
+
Type declarations (@3) include source line annotations (// LN or // LN-LM)
|
|
61
|
+
so you can locate the implementation in the source file.
|
|
56
62
|
|
|
57
63
|
Barrel gating (glob mode):
|
|
58
64
|
A barrel's @summary and description reflect the cumulative functionality
|
|
@@ -70,15 +76,15 @@ Exit codes:
|
|
|
70
76
|
2 Validation or lint failures found
|
|
71
77
|
|
|
72
78
|
Workflow:
|
|
73
|
-
$ jsdoczoom src/**/*.ts
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
$ jsdoczoom src/utils@2 # use next_id from above
|
|
77
|
-
{ "items": [{ "next_id": "src/utils@3", "text": "..." }] }
|
|
79
|
+
$ jsdoczoom src/**/*.ts # list summaries
|
|
80
|
+
$ jsdoczoom src/utils@2 # drill into description
|
|
81
|
+
$ jsdoczoom src/utils@3 # see type declarations
|
|
78
82
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
Pipe examples:
|
|
84
|
+
$ jsdoczoom src/utils.ts@3 | grep "functionName" # find symbol + source line
|
|
85
|
+
$ jsdoczoom src/utils.ts@3 | grep "// L" # list all declarations with lines
|
|
86
|
+
$ jsdoczoom src/**/*.ts | grep "^#" # list all file headers
|
|
87
|
+
$ grep -rl "term" src/ --include="*.ts" | jsdoczoom # describe matching files
|
|
82
88
|
`;
|
|
83
89
|
/**
|
|
84
90
|
* Parse a flag that requires a value argument.
|
|
@@ -97,6 +103,7 @@ function parseArgs(args) {
|
|
|
97
103
|
checkMode: false,
|
|
98
104
|
lintMode: false,
|
|
99
105
|
skillMode: false,
|
|
106
|
+
json: false,
|
|
100
107
|
pretty: false,
|
|
101
108
|
limit: 500,
|
|
102
109
|
gitignore: true,
|
|
@@ -128,6 +135,10 @@ function parseArgs(args) {
|
|
|
128
135
|
parsed.skillMode = true;
|
|
129
136
|
continue;
|
|
130
137
|
}
|
|
138
|
+
if (arg === "--json") {
|
|
139
|
+
parsed.json = true;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
131
142
|
if (arg === "--pretty") {
|
|
132
143
|
parsed.pretty = true;
|
|
133
144
|
continue;
|
|
@@ -196,6 +207,7 @@ async function processStdin(
|
|
|
196
207
|
selectorArg,
|
|
197
208
|
checkMode,
|
|
198
209
|
lintMode,
|
|
210
|
+
json,
|
|
199
211
|
pretty,
|
|
200
212
|
limit,
|
|
201
213
|
cwd,
|
|
@@ -218,7 +230,7 @@ async function processStdin(
|
|
|
218
230
|
limit,
|
|
219
231
|
cacheConfig,
|
|
220
232
|
);
|
|
221
|
-
|
|
233
|
+
writeDrilldownResult(result, json, pretty);
|
|
222
234
|
}
|
|
223
235
|
}
|
|
224
236
|
/**
|
|
@@ -228,6 +240,7 @@ async function processSelector(
|
|
|
228
240
|
selectorArg,
|
|
229
241
|
checkMode,
|
|
230
242
|
lintMode,
|
|
243
|
+
json,
|
|
231
244
|
pretty,
|
|
232
245
|
limit,
|
|
233
246
|
gitignore,
|
|
@@ -251,7 +264,7 @@ async function processSelector(
|
|
|
251
264
|
limit,
|
|
252
265
|
cacheConfig,
|
|
253
266
|
);
|
|
254
|
-
|
|
267
|
+
writeDrilldownResult(result, json, pretty);
|
|
255
268
|
}
|
|
256
269
|
}
|
|
257
270
|
/**
|
|
@@ -352,6 +365,7 @@ export async function main(args, stdin) {
|
|
|
352
365
|
parsed.selectorArg,
|
|
353
366
|
parsed.checkMode,
|
|
354
367
|
parsed.lintMode,
|
|
368
|
+
parsed.json,
|
|
355
369
|
parsed.pretty,
|
|
356
370
|
parsed.limit,
|
|
357
371
|
cwd,
|
|
@@ -362,6 +376,7 @@ export async function main(args, stdin) {
|
|
|
362
376
|
parsed.selectorArg,
|
|
363
377
|
parsed.checkMode,
|
|
364
378
|
parsed.lintMode,
|
|
379
|
+
parsed.json,
|
|
365
380
|
parsed.pretty,
|
|
366
381
|
parsed.limit,
|
|
367
382
|
parsed.gitignore,
|
|
@@ -373,6 +388,16 @@ export async function main(args, stdin) {
|
|
|
373
388
|
writeError(error);
|
|
374
389
|
}
|
|
375
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* Write a drilldown result to stdout as text (default) or JSON.
|
|
393
|
+
*/
|
|
394
|
+
function writeDrilldownResult(result, json, pretty) {
|
|
395
|
+
if (json) {
|
|
396
|
+
writeResult(result, pretty);
|
|
397
|
+
} else {
|
|
398
|
+
void process.stdout.write(formatTextOutput(result));
|
|
399
|
+
}
|
|
400
|
+
}
|
|
376
401
|
/**
|
|
377
402
|
* Write a result to stdout as JSON.
|
|
378
403
|
*/
|
package/dist/drilldown.js
CHANGED
|
@@ -335,11 +335,12 @@ export async function drilldown(
|
|
|
335
335
|
const sorted = results.sort((a, b) =>
|
|
336
336
|
sortKey(a).localeCompare(sortKey(b)),
|
|
337
337
|
);
|
|
338
|
-
const
|
|
339
|
-
const
|
|
338
|
+
const count = sorted.length;
|
|
339
|
+
const isTruncated = count > limit;
|
|
340
340
|
return {
|
|
341
341
|
items: sorted.slice(0, limit),
|
|
342
|
-
truncated,
|
|
342
|
+
truncated: isTruncated,
|
|
343
|
+
...(isTruncated ? { total: count } : {}),
|
|
343
344
|
};
|
|
344
345
|
}
|
|
345
346
|
// Single file path — errors are fatal
|
|
@@ -394,11 +395,12 @@ export async function drilldown(
|
|
|
394
395
|
const results = await processGlobWithBarrels(files, depth, cwd, config);
|
|
395
396
|
// Sort alphabetically by key
|
|
396
397
|
const sorted = results.sort((a, b) => sortKey(a).localeCompare(sortKey(b)));
|
|
397
|
-
const
|
|
398
|
-
const
|
|
398
|
+
const count = sorted.length;
|
|
399
|
+
const isTruncated = count > limit;
|
|
399
400
|
return {
|
|
400
401
|
items: sorted.slice(0, limit),
|
|
401
|
-
truncated,
|
|
402
|
+
truncated: isTruncated,
|
|
403
|
+
...(isTruncated ? { total: count } : {}),
|
|
402
404
|
};
|
|
403
405
|
}
|
|
404
406
|
/**
|
|
@@ -432,10 +434,11 @@ export async function drilldownFiles(
|
|
|
432
434
|
});
|
|
433
435
|
const results = await collectSafeResults(tsFiles, d, cwd, config);
|
|
434
436
|
const sorted = results.sort((a, b) => sortKey(a).localeCompare(sortKey(b)));
|
|
435
|
-
const
|
|
436
|
-
const
|
|
437
|
+
const count = sorted.length;
|
|
438
|
+
const isTruncated = count > limit;
|
|
437
439
|
return {
|
|
438
440
|
items: sorted.slice(0, limit),
|
|
439
|
-
truncated,
|
|
441
|
+
truncated: isTruncated,
|
|
442
|
+
...(isTruncated ? { total: count } : {}),
|
|
440
443
|
};
|
|
441
444
|
}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export { discoverFiles } from "./file-discovery.js";
|
|
|
14
14
|
export { extractFileJsdoc, parseFileSummaries } from "./jsdoc-parser.js";
|
|
15
15
|
export { lint, lintFiles } from "./lint.js";
|
|
16
16
|
export { parseSelector } from "./selector.js";
|
|
17
|
+
export { formatTextOutput } from "./text-format.js";
|
|
17
18
|
export { generateTypeDeclarations } from "./type-declarations.js";
|
|
18
19
|
export { DEFAULT_CACHE_DIR, VALIDATION_STATUS_PRIORITY } from "./types.js";
|
|
19
20
|
export { validate, validateFiles } from "./validate.js";
|
package/dist/skill-text.js
CHANGED
|
@@ -368,6 +368,24 @@ function parse(input: string | Buffer): number {
|
|
|
368
368
|
}
|
|
369
369
|
\`\`\`
|
|
370
370
|
|
|
371
|
+
## Text output and piping
|
|
372
|
+
|
|
373
|
+
jsdoczoom outputs human-readable text by default. Each item has a \`# path\` header followed by content. This makes it composable with standard Unix tools:
|
|
374
|
+
|
|
375
|
+
\`\`\`sh
|
|
376
|
+
jsdoczoom src/utils.ts@3 | grep "functionName" # find symbol + source line
|
|
377
|
+
jsdoczoom src/utils.ts@3 | grep "// L" # list all declarations with lines
|
|
378
|
+
jsdoczoom src/**/*.ts | grep "^#" # list all file summaries
|
|
379
|
+
grep -rl "term" src/ --include="*.ts" | jsdoczoom # describe matching files
|
|
380
|
+
\`\`\`
|
|
381
|
+
|
|
382
|
+
Type declarations include source line annotations (\`// LN\` or \`// LN-LM\` for ranges), so you can locate implementations in the source file without a separate search step.
|
|
383
|
+
|
|
384
|
+
For machine-parseable output, use \`--json\`:
|
|
385
|
+
|
|
386
|
+
\`\`\`sh
|
|
387
|
+
jsdoczoom --json src/**/*.ts | jq '.items[].text'
|
|
388
|
+
\`\`\`
|
|
371
389
|
`;
|
|
372
390
|
/** Explanation text for each lint rule, used by --explain-rule */
|
|
373
391
|
export const RULE_EXPLANATIONS = {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats drilldown results as human-readable text for shell piping.
|
|
3
|
+
* Each item gets a `# id` header line followed by its content.
|
|
4
|
+
* Items are separated by blank lines.
|
|
5
|
+
*
|
|
6
|
+
* @summary Plain-text output formatter for drilldown results
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Format a single output entry as a text block (header + content).
|
|
10
|
+
*/
|
|
11
|
+
function formatEntry(entry) {
|
|
12
|
+
if ("error" in entry) {
|
|
13
|
+
return `# ${entry.id} [${entry.error.code}]\n${entry.error.message}`;
|
|
14
|
+
}
|
|
15
|
+
const text = entry.text.trimEnd();
|
|
16
|
+
if ("next_id" in entry) {
|
|
17
|
+
const lines = [`# ${entry.next_id}`];
|
|
18
|
+
const children = entry.children;
|
|
19
|
+
if (children) {
|
|
20
|
+
lines.push(`## children: ${children.join(", ")}`);
|
|
21
|
+
}
|
|
22
|
+
if (text) lines.push(text);
|
|
23
|
+
return lines.join("\n");
|
|
24
|
+
}
|
|
25
|
+
// Terminal item
|
|
26
|
+
if (!text) return `# ${entry.id}`;
|
|
27
|
+
return `# ${entry.id}\n${text}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Format a DrilldownResult as plain text for CLI output.
|
|
31
|
+
* Returns the formatted string with a trailing newline.
|
|
32
|
+
*/
|
|
33
|
+
export function formatTextOutput(result) {
|
|
34
|
+
const blocks = result.items.map(formatEntry);
|
|
35
|
+
let output = blocks.join("\n\n");
|
|
36
|
+
if (result.truncated && result.total !== undefined) {
|
|
37
|
+
output += `\n\n# truncated (showing ${result.items.length} of ${result.total})`;
|
|
38
|
+
} else if (result.truncated) {
|
|
39
|
+
output += "\n\n# truncated";
|
|
40
|
+
}
|
|
41
|
+
return `${output}\n`;
|
|
42
|
+
}
|
|
@@ -153,6 +153,116 @@ export function resetCache() {
|
|
|
153
153
|
compilerOptionsCache.clear();
|
|
154
154
|
serviceCache.clear();
|
|
155
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Build a map of exported symbol names to their source line ranges.
|
|
158
|
+
* Walks top-level statements looking for export modifiers.
|
|
159
|
+
*/
|
|
160
|
+
function buildSourceLineMap(filePath) {
|
|
161
|
+
const content = readFileSync(filePath, "utf-8");
|
|
162
|
+
const sourceFile = ts.createSourceFile(
|
|
163
|
+
filePath,
|
|
164
|
+
content,
|
|
165
|
+
ts.ScriptTarget.Latest,
|
|
166
|
+
true,
|
|
167
|
+
);
|
|
168
|
+
const map = new Map();
|
|
169
|
+
for (const statement of sourceFile.statements) {
|
|
170
|
+
// Only process exported declarations
|
|
171
|
+
const modifiers = ts.canHaveModifiers(statement)
|
|
172
|
+
? ts.getModifiers(statement)
|
|
173
|
+
: undefined;
|
|
174
|
+
const isExported = modifiers?.some(
|
|
175
|
+
(m) => m.kind === ts.SyntaxKind.ExportKeyword,
|
|
176
|
+
);
|
|
177
|
+
if (!isExported) continue;
|
|
178
|
+
const start =
|
|
179
|
+
sourceFile.getLineAndCharacterOfPosition(statement.getStart(sourceFile))
|
|
180
|
+
.line + 1;
|
|
181
|
+
const end =
|
|
182
|
+
sourceFile.getLineAndCharacterOfPosition(statement.getEnd()).line + 1;
|
|
183
|
+
const addName = (name) => map.set(name, { start, end });
|
|
184
|
+
if (ts.isTypeAliasDeclaration(statement)) {
|
|
185
|
+
addName(statement.name.text);
|
|
186
|
+
} else if (ts.isInterfaceDeclaration(statement)) {
|
|
187
|
+
addName(statement.name.text);
|
|
188
|
+
} else if (ts.isFunctionDeclaration(statement) && statement.name) {
|
|
189
|
+
addName(statement.name.text);
|
|
190
|
+
} else if (ts.isClassDeclaration(statement) && statement.name) {
|
|
191
|
+
addName(statement.name.text);
|
|
192
|
+
} else if (ts.isEnumDeclaration(statement)) {
|
|
193
|
+
addName(statement.name.text);
|
|
194
|
+
} else if (ts.isVariableStatement(statement)) {
|
|
195
|
+
for (const decl of statement.declarationList.declarations) {
|
|
196
|
+
if (ts.isIdentifier(decl.name)) {
|
|
197
|
+
addName(decl.name.text);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return map;
|
|
203
|
+
}
|
|
204
|
+
/** Regex matching the start of a top-level export declaration in .d.ts output. */
|
|
205
|
+
const DECL_PATTERN =
|
|
206
|
+
/^export\s+(?:default\s+)?(?:declare\s+)?(?:abstract\s+)?(?:type|interface|function|const|let|var|class|enum)\s+(\w+)/;
|
|
207
|
+
/**
|
|
208
|
+
* Format a source range as a GitHub-style line annotation.
|
|
209
|
+
*/
|
|
210
|
+
function formatLineRef(range) {
|
|
211
|
+
return range.start === range.end
|
|
212
|
+
? `// L${range.start}`
|
|
213
|
+
: `// L${range.start}-L${range.end}`;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Find the start of the JSDoc block above a declaration line.
|
|
217
|
+
* Returns the declaration line index itself if no JSDoc is found.
|
|
218
|
+
*/
|
|
219
|
+
function findChunkStart(lines, declLine) {
|
|
220
|
+
if (declLine === 0) return 0;
|
|
221
|
+
const prev = lines[declLine - 1]?.trimEnd();
|
|
222
|
+
if (prev === "*/" || prev?.endsWith("*/")) {
|
|
223
|
+
for (let j = declLine - 1; j >= 0; j--) {
|
|
224
|
+
if (lines[j].trimStart().startsWith("/**")) return j;
|
|
225
|
+
}
|
|
226
|
+
} else if (prev?.trimStart().startsWith("/**")) {
|
|
227
|
+
// Single-line JSDoc: /** comment */
|
|
228
|
+
return declLine - 1;
|
|
229
|
+
}
|
|
230
|
+
return declLine;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Annotate .d.ts text with source line references for each top-level declaration.
|
|
234
|
+
* Inserts GitHub-style `// LN` or `// LN-LM` on a separate line before each
|
|
235
|
+
* declaration chunk, with a blank line above for visual separation.
|
|
236
|
+
*/
|
|
237
|
+
function annotateWithSourceLines(dtsText, filePath) {
|
|
238
|
+
const lineMap = buildSourceLineMap(filePath);
|
|
239
|
+
if (lineMap.size === 0) return dtsText;
|
|
240
|
+
const lines = dtsText.split("\n");
|
|
241
|
+
// First pass: map chunk start lines to their annotations
|
|
242
|
+
const annotations = new Map();
|
|
243
|
+
for (let i = 0; i < lines.length; i++) {
|
|
244
|
+
const match = lines[i].match(DECL_PATTERN);
|
|
245
|
+
if (!match) continue;
|
|
246
|
+
const range = lineMap.get(match[1]);
|
|
247
|
+
if (!range) continue;
|
|
248
|
+
annotations.set(findChunkStart(lines, i), formatLineRef(range));
|
|
249
|
+
}
|
|
250
|
+
if (annotations.size === 0) return dtsText;
|
|
251
|
+
// Second pass: build output with annotations inserted
|
|
252
|
+
const result = [];
|
|
253
|
+
for (let i = 0; i < lines.length; i++) {
|
|
254
|
+
const annotation = annotations.get(i);
|
|
255
|
+
if (annotation) {
|
|
256
|
+
// Blank line separator before annotation (if there's content above)
|
|
257
|
+
if (result.length > 0 && result[result.length - 1]?.trim() !== "") {
|
|
258
|
+
result.push("");
|
|
259
|
+
}
|
|
260
|
+
result.push(annotation);
|
|
261
|
+
}
|
|
262
|
+
result.push(lines[i]);
|
|
263
|
+
}
|
|
264
|
+
return result.join("\n");
|
|
265
|
+
}
|
|
156
266
|
/**
|
|
157
267
|
* Generates TypeScript declaration output from a source file.
|
|
158
268
|
*
|
|
@@ -208,5 +318,8 @@ export function generateTypeDeclarations(filePath) {
|
|
|
208
318
|
if (withoutComments === "export {};") {
|
|
209
319
|
cleaned = "";
|
|
210
320
|
}
|
|
321
|
+
if (cleaned.length > 0) {
|
|
322
|
+
cleaned = annotateWithSourceLines(cleaned, filePath);
|
|
323
|
+
}
|
|
211
324
|
return cleaned;
|
|
212
325
|
}
|
package/package.json
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export { discoverFiles } from "./file-discovery.js";
|
|
|
14
14
|
export { extractFileJsdoc, parseFileSummaries } from "./jsdoc-parser.js";
|
|
15
15
|
export { lint, lintFiles } from "./lint.js";
|
|
16
16
|
export { parseSelector } from "./selector.js";
|
|
17
|
+
export { formatTextOutput } from "./text-format.js";
|
|
17
18
|
export { generateTypeDeclarations } from "./type-declarations.js";
|
|
18
19
|
export {
|
|
19
20
|
type CacheConfig,
|
package/types/skill-text.d.ts
CHANGED
|
@@ -11,6 +11,6 @@ import type { ValidationStatus } from "./types.js";
|
|
|
11
11
|
/** Markdown guidance text for each validation status category */
|
|
12
12
|
export declare const GUIDANCE: Record<ValidationStatus, string>;
|
|
13
13
|
export declare const SKILL_TEXT =
|
|
14
|
-
'# World-Class JSDoc Guidelines for TypeScript\n\nThese guidelines describe the *properties* of excellent inline JSDoc in TypeScript repositories. They are a target to aim for, not a checklist. Use judgment; clarity beats volume.\n\n## Core principle\n\nTypeScript projects already have explicit types. JSDoc should add **intent, behavior, and constraints** rather than repeat what the type system already expresses.\n\n## Would have (high-signal properties)\n\n- **Intent and constraints**: Explains the non-obvious decision, constraint, or tradeoff (e.g., why a particular algorithm is used, why a heuristic exists, or what the runtime environment forbids).\n- **Behavioral contract**: Clearly states what inputs are accepted, what outputs represent, and how boundary cases are treated.\n- **Domain vocabulary**: Uses project-specific terms consistently so readers can navigate the codebase by vocabulary.\n- **Examples that disambiguate**: Includes `@example` blocks when behavior is otherwise ambiguous (e.g., parsing rules, path formats, or object schemas). Examples are short and realistic.\n- **Runtime effects**: Calls out side effects, temporal dependency (polling vs. event-driven), filesystem reads/writes, or external service behavior when those matter.\n- **Edge-case prompts**: Captures "what happens if..." questions that a reviewer would ask, especially where external APIs or platform behavior has caveats.\n- **Consistency with existing style**: Matches the formatting conventions already established in the codebase (multi-line descriptions, bullet lists where helpful).\n- **Future-proof hints**: Notes invariants and assumptions that must hold if the code evolves.\n- **LLM-friendly structure**: Uses short, self-contained paragraphs written in clear International Business English. Avoids prescriptive headers (e.g., "Why:", "Constraint:") in favor of natural prose that states context, purpose, and caveats directly.\n\n## Would not have (low-signal or risky properties)\n\n- **Type restatements**: Repeating TypeScript types in prose (e.g., "@param options - The options object" when the type is already `Options`). Keep `@param`, `@returns`, and `@throws` tags\u2014just make the descriptions add meaning beyond the type.\n- **Obvious narration**: Comments that paraphrase the code or parameter name without additional insight.\n- **Incorrect authority**: Claims that are not enforced by code (e.g., "never throws" when it can, or "always" without guardrails).\n- **Redundant verbosity**: Long descriptions that could be expressed more directly, or boilerplate that hides the key idea.\n- **Unbounded examples**: Large blocks or full payloads when a minimal example would do.\n- **Out-of-date operational details**: References to tooling, CLI flags, or config knobs that are not enforced or checked.\n- **Implementation leakage**: Unnecessary internal steps or private details that are likely to change and add churn to docs.\n- **Non-ASCII decoration**: Fancy symbols or emojis that do not already exist in the file; keep ASCII unless needed.\n\n## Tag usage cues (not rules)\n\n### IntelliSense tags (always include)\n\nThese tags power IDE hover tooltips, autocomplete, and signature help. Always include them for public APIs, constructors, and functions:\n\n- **`@param`**: Include for every parameter. Describe the parameter\'s purpose, valid ranges, or constraints\u2014not just its type.\n- **`@returns`**: Include when the function returns a value. Describe what the return value represents, especially for edge cases.\n- **`@throws`**: Include when the function can throw. Describe the conditions that cause the error.\n- **`@template`**: Include for generic functions and types. Describe what the type parameter represents.\n\n### Cross-reference tags (use to aid navigation)\n\n- **`@see`**: Link to related functions, types, or external documentation.\n- **`{@link Symbol}`**: Inline reference within descriptions. Creates a clickable link to another symbol.\n\n### Structural tags (use when appropriate)\n\n- Use `@module` at the top of files that define a cohesive domain concept.\n- Use `@example` when parsing or formatting behavior could be misread, or when a type is complex.\n- Use `@deprecated` on exports that are retained for compatibility.\n- Prefer short description + bullets for concepts with multiple facets.\n\n---\n\n## Writing file-level @summary and description\n\nEvery TypeScript file should have a file-level JSDoc block before the first code statement. This block is what jsdoczoom reads for orientation and validation.\n\n### Structure\n\n```typescript\n/**\n * Description paragraph goes here. It explains the file\'s responsibilities,\n * invariants, trade-offs, and failure modes. This is the deepest level of\n * native documentation \u2014 enough for someone to understand why this file\n * exists and how it fits into the broader system.\n *\n * @summary Concise one-line overview for quick orientation when scanning a codebase.\n */\n```\n\n### The @summary tag\n\nThe `@summary` tag provides a one-line overview \u2014 the first thing someone sees when scanning with jsdoczoom at the shallowest depth.\n\n**Good summaries:**\n- State what the file *does* or *is responsible for*, not what it contains\n- Are self-contained \u2014 understandable without reading other files\n- Use domain vocabulary consistently with the rest of the codebase\n- Fit on a single line (joined if multi-line in source)\n\n**Examples:**\n- `@summary Barrel tree model for hierarchical gating in glob mode`\n- `@summary Resolve selector patterns to absolute file paths with gitignore filtering`\n- `@summary CLI entry point \u2014 argument parsing, mode dispatch, and exit code handling`\n\n**Avoid:**\n- `@summary This file contains utility functions` \u2014 says what it *contains*, not what it *does*\n- `@summary Helpers` \u2014 too vague, no domain context\n- `@summary The main module` \u2014 no information about purpose or scope\n\n### The description paragraph\n\nThe description is prose that appears before any `@` tags. It provides the deeper context that the summary cannot \u2014 responsibilities, invariants, trade-offs, and failure modes.\n\n**Good descriptions:**\n- Explain *why* this file exists and what problem it solves\n- State invariants and assumptions that callers or maintainers must know\n- Note trade-offs and design decisions (e.g., "uses priority-order fill to keep the limit algorithm simple")\n- Mention failure modes and edge cases relevant to the file as a whole\n- Are 1-4 sentences, not an essay\n\n**Examples:**\n```typescript\n/**\n * Walks .gitignore files from cwd to filesystem root, building an ignore\n * filter that glob results pass through. Direct-path lookups bypass the\n * filter since the user explicitly named the file. The ignore instance is\n * created per call \u2014 no caching \u2014 because cwd may differ between invocations.\n *\n * @summary Resolve selector patterns to absolute file paths with gitignore filtering\n */\n```\n\n```typescript\n/**\n * Each file is classified into exactly one status category: the first\n * failing check wins (syntax_error > missing_jsdoc > missing_summary >\n * missing_description). Valid files are omitted from output entirely.\n * The limit parameter caps the total number of invalid paths shown,\n * filled in priority order across groups.\n *\n * @summary Validate file-level JSDoc and group results by status category\n */\n```\n\n**Avoid:**\n- Restating the summary in longer words\n- Listing every function in the file\n- Implementation details that change frequently (line numbers, internal variable names)\n\n### Barrel files (index.ts / index.tsx)\n\nBarrel files represent their directory. Their `@summary` and description should describe the **cumulative functionality of the directory\'s children**, not the barrel file itself.\n\n- **`@summary`**: The collective purpose of the files in this directory\n- **Description**: The combined capabilities and responsibilities of child modules \u2014 what they do together, not their filenames or the re-export mechanism\n\n```typescript\n// packages/auth/src/index.ts\n/**\n * Provides session lifecycle management, token validation and refresh,\n * and middleware for route-level access control. OAuth2 provider\n * integration is handled here; cryptographic primitives are delegated\n * to the crypto package.\n *\n * @summary Authentication and authorization module\n */\n```\n\n**Avoid:**\n- `@summary Re-exports all functions and types` \u2014 describes the barrel mechanism, not what the children do\n- `@summary Exports for the auth module` \u2014 describes the mechanism, not the purpose\n- `@summary Public API barrel` \u2014 names the pattern rather than describing functionality\n- Listing child filenames or saying "This is the entry point"\n\n### Placement\n\nThe file-level JSDoc block must appear **before the first code statement** (imports are fine above it, but the block must precede any `export`, `const`, `function`, `class`, etc.). A common pattern is to place it immediately after imports:\n\n```typescript\nimport { resolve } from "node:path";\nimport { globSync } from "glob";\n\n/**\n * Description paragraph here.\n *\n * @summary One-line overview here\n */\n\nexport function discoverFiles(...) { ... }\n```\n\n### Common lint rules and examples\n\nThese rules are enforced in lint mode (`-l`). Understanding what passes and fails reduces trial-and-rerun cycles.\n\n#### `jsdoc/informative-docs` \u2014 descriptions must add meaning\n\nThis rule rejects descriptions that merely restate the parameter name, type, or containing symbol name. Descriptions must provide behavioral context.\n\n**Fails:**\n- `@param id - The id`\n- `@param options - The options object`\n- `@returns The result`\n- `@param name - The name string`\n\n**Passes:**\n- `@param id - Unique identifier used for cache lookup and deduplication`\n- `@param options - Controls retry behavior, timeout, and error handling strategy`\n- `@returns Parsed configuration with defaults applied for missing fields`\n- `@param name - Display name shown in the navigation sidebar`\n\n**Rule of thumb:** If removing the parameter name from the description leaves no useful information, the description is not informative enough.\n\n#### `jsdoc/check-tag-names` \u2014 allowed tags only\n\nThe lint configuration rejects non-standard JSDoc tags. Common tags to **avoid in JSDoc blocks**:\n- `@remarks` \u2014 move content to the description paragraph (prose before tags)\n- `@packageDocumentation` \u2014 use `@module` instead\n- `@concept`, `@constraint` \u2014 move content to the description paragraph\n\nFramework directives that look like tags (e.g., `@vitest-environment`) should use plain comments instead:\n```typescript\n// @vitest-environment node \u2190 correct (plain comment)\n/** @vitest-environment node */ \u2190 incorrect (treated as JSDoc tag)\n```\n\n#### `jsdoc/require-throws` \u2014 document throw conditions\n\nInclude `@throws` for any function that can throw, including catch-and-rethrow patterns:\n```typescript\n/**\n * @param path - File path to read\n * @returns Parsed configuration object\n * @throws {ConfigError} When the file is missing or contains invalid YAML\n */\n```\n\nIf a function catches errors and rethrows them (wrapped or unwrapped), it still needs `@throws`.\n\n### Nested object parameters\n\nWhen a function accepts an inline object parameter, document each property with a nested `@param` tag:\n\n```typescript\n/**\n * Create a new user account.\n *\n * @param data - Account creation payload\n * @param data.email - Email address used for login and notifications\n * @param data.displayName - Public-facing name shown in the UI\n * @param data.role - Initial permission level assigned to the account\n * @returns The created user record with generated ID\n */\nfunction createUser(data: { email: string; displayName: string; role: Role }): User {\n```\n\nFor React component props, use `props` (or `root0` if destructured) as the root:\n\n```typescript\n/**\n * @param props - Component properties\n * @param props.title - Page heading displayed at the top\n * @param props.onSubmit - Callback invoked when the form is submitted\n */\nfunction MyComponent(props: { title: string; onSubmit: () => void }) {\n```\n\n### Overload documentation\n\nWhen a function has TypeScript overload signatures, document **both** the overload declarations and the implementation signature:\n\n```typescript\n/**\n * Parse a value from a string representation.\n *\n * @param input - Raw string to parse\n * @returns Parsed numeric value\n */\nfunction parse(input: string): number;\n/**\n * Parse a value from a buffer.\n *\n * @param input - Binary buffer to parse\n * @returns Parsed numeric value\n */\nfunction parse(input: Buffer): number;\n/**\n * Parse a value from string or buffer input. String inputs are decoded\n * as UTF-8 before numeric parsing.\n *\n * @param input - String or buffer to parse\n * @returns Parsed numeric value\n * @throws {ParseError} When the input cannot be interpreted as a number\n */\nfunction parse(input: string | Buffer): number {\n // implementation\n}\n```\n\n';
|
|
14
|
+
'# World-Class JSDoc Guidelines for TypeScript\n\nThese guidelines describe the *properties* of excellent inline JSDoc in TypeScript repositories. They are a target to aim for, not a checklist. Use judgment; clarity beats volume.\n\n## Core principle\n\nTypeScript projects already have explicit types. JSDoc should add **intent, behavior, and constraints** rather than repeat what the type system already expresses.\n\n## Would have (high-signal properties)\n\n- **Intent and constraints**: Explains the non-obvious decision, constraint, or tradeoff (e.g., why a particular algorithm is used, why a heuristic exists, or what the runtime environment forbids).\n- **Behavioral contract**: Clearly states what inputs are accepted, what outputs represent, and how boundary cases are treated.\n- **Domain vocabulary**: Uses project-specific terms consistently so readers can navigate the codebase by vocabulary.\n- **Examples that disambiguate**: Includes `@example` blocks when behavior is otherwise ambiguous (e.g., parsing rules, path formats, or object schemas). Examples are short and realistic.\n- **Runtime effects**: Calls out side effects, temporal dependency (polling vs. event-driven), filesystem reads/writes, or external service behavior when those matter.\n- **Edge-case prompts**: Captures "what happens if..." questions that a reviewer would ask, especially where external APIs or platform behavior has caveats.\n- **Consistency with existing style**: Matches the formatting conventions already established in the codebase (multi-line descriptions, bullet lists where helpful).\n- **Future-proof hints**: Notes invariants and assumptions that must hold if the code evolves.\n- **LLM-friendly structure**: Uses short, self-contained paragraphs written in clear International Business English. Avoids prescriptive headers (e.g., "Why:", "Constraint:") in favor of natural prose that states context, purpose, and caveats directly.\n\n## Would not have (low-signal or risky properties)\n\n- **Type restatements**: Repeating TypeScript types in prose (e.g., "@param options - The options object" when the type is already `Options`). Keep `@param`, `@returns`, and `@throws` tags\u2014just make the descriptions add meaning beyond the type.\n- **Obvious narration**: Comments that paraphrase the code or parameter name without additional insight.\n- **Incorrect authority**: Claims that are not enforced by code (e.g., "never throws" when it can, or "always" without guardrails).\n- **Redundant verbosity**: Long descriptions that could be expressed more directly, or boilerplate that hides the key idea.\n- **Unbounded examples**: Large blocks or full payloads when a minimal example would do.\n- **Out-of-date operational details**: References to tooling, CLI flags, or config knobs that are not enforced or checked.\n- **Implementation leakage**: Unnecessary internal steps or private details that are likely to change and add churn to docs.\n- **Non-ASCII decoration**: Fancy symbols or emojis that do not already exist in the file; keep ASCII unless needed.\n\n## Tag usage cues (not rules)\n\n### IntelliSense tags (always include)\n\nThese tags power IDE hover tooltips, autocomplete, and signature help. Always include them for public APIs, constructors, and functions:\n\n- **`@param`**: Include for every parameter. Describe the parameter\'s purpose, valid ranges, or constraints\u2014not just its type.\n- **`@returns`**: Include when the function returns a value. Describe what the return value represents, especially for edge cases.\n- **`@throws`**: Include when the function can throw. Describe the conditions that cause the error.\n- **`@template`**: Include for generic functions and types. Describe what the type parameter represents.\n\n### Cross-reference tags (use to aid navigation)\n\n- **`@see`**: Link to related functions, types, or external documentation.\n- **`{@link Symbol}`**: Inline reference within descriptions. Creates a clickable link to another symbol.\n\n### Structural tags (use when appropriate)\n\n- Use `@module` at the top of files that define a cohesive domain concept.\n- Use `@example` when parsing or formatting behavior could be misread, or when a type is complex.\n- Use `@deprecated` on exports that are retained for compatibility.\n- Prefer short description + bullets for concepts with multiple facets.\n\n---\n\n## Writing file-level @summary and description\n\nEvery TypeScript file should have a file-level JSDoc block before the first code statement. This block is what jsdoczoom reads for orientation and validation.\n\n### Structure\n\n```typescript\n/**\n * Description paragraph goes here. It explains the file\'s responsibilities,\n * invariants, trade-offs, and failure modes. This is the deepest level of\n * native documentation \u2014 enough for someone to understand why this file\n * exists and how it fits into the broader system.\n *\n * @summary Concise one-line overview for quick orientation when scanning a codebase.\n */\n```\n\n### The @summary tag\n\nThe `@summary` tag provides a one-line overview \u2014 the first thing someone sees when scanning with jsdoczoom at the shallowest depth.\n\n**Good summaries:**\n- State what the file *does* or *is responsible for*, not what it contains\n- Are self-contained \u2014 understandable without reading other files\n- Use domain vocabulary consistently with the rest of the codebase\n- Fit on a single line (joined if multi-line in source)\n\n**Examples:**\n- `@summary Barrel tree model for hierarchical gating in glob mode`\n- `@summary Resolve selector patterns to absolute file paths with gitignore filtering`\n- `@summary CLI entry point \u2014 argument parsing, mode dispatch, and exit code handling`\n\n**Avoid:**\n- `@summary This file contains utility functions` \u2014 says what it *contains*, not what it *does*\n- `@summary Helpers` \u2014 too vague, no domain context\n- `@summary The main module` \u2014 no information about purpose or scope\n\n### The description paragraph\n\nThe description is prose that appears before any `@` tags. It provides the deeper context that the summary cannot \u2014 responsibilities, invariants, trade-offs, and failure modes.\n\n**Good descriptions:**\n- Explain *why* this file exists and what problem it solves\n- State invariants and assumptions that callers or maintainers must know\n- Note trade-offs and design decisions (e.g., "uses priority-order fill to keep the limit algorithm simple")\n- Mention failure modes and edge cases relevant to the file as a whole\n- Are 1-4 sentences, not an essay\n\n**Examples:**\n```typescript\n/**\n * Walks .gitignore files from cwd to filesystem root, building an ignore\n * filter that glob results pass through. Direct-path lookups bypass the\n * filter since the user explicitly named the file. The ignore instance is\n * created per call \u2014 no caching \u2014 because cwd may differ between invocations.\n *\n * @summary Resolve selector patterns to absolute file paths with gitignore filtering\n */\n```\n\n```typescript\n/**\n * Each file is classified into exactly one status category: the first\n * failing check wins (syntax_error > missing_jsdoc > missing_summary >\n * missing_description). Valid files are omitted from output entirely.\n * The limit parameter caps the total number of invalid paths shown,\n * filled in priority order across groups.\n *\n * @summary Validate file-level JSDoc and group results by status category\n */\n```\n\n**Avoid:**\n- Restating the summary in longer words\n- Listing every function in the file\n- Implementation details that change frequently (line numbers, internal variable names)\n\n### Barrel files (index.ts / index.tsx)\n\nBarrel files represent their directory. Their `@summary` and description should describe the **cumulative functionality of the directory\'s children**, not the barrel file itself.\n\n- **`@summary`**: The collective purpose of the files in this directory\n- **Description**: The combined capabilities and responsibilities of child modules \u2014 what they do together, not their filenames or the re-export mechanism\n\n```typescript\n// packages/auth/src/index.ts\n/**\n * Provides session lifecycle management, token validation and refresh,\n * and middleware for route-level access control. OAuth2 provider\n * integration is handled here; cryptographic primitives are delegated\n * to the crypto package.\n *\n * @summary Authentication and authorization module\n */\n```\n\n**Avoid:**\n- `@summary Re-exports all functions and types` \u2014 describes the barrel mechanism, not what the children do\n- `@summary Exports for the auth module` \u2014 describes the mechanism, not the purpose\n- `@summary Public API barrel` \u2014 names the pattern rather than describing functionality\n- Listing child filenames or saying "This is the entry point"\n\n### Placement\n\nThe file-level JSDoc block must appear **before the first code statement** (imports are fine above it, but the block must precede any `export`, `const`, `function`, `class`, etc.). A common pattern is to place it immediately after imports:\n\n```typescript\nimport { resolve } from "node:path";\nimport { globSync } from "glob";\n\n/**\n * Description paragraph here.\n *\n * @summary One-line overview here\n */\n\nexport function discoverFiles(...) { ... }\n```\n\n### Common lint rules and examples\n\nThese rules are enforced in lint mode (`-l`). Understanding what passes and fails reduces trial-and-rerun cycles.\n\n#### `jsdoc/informative-docs` \u2014 descriptions must add meaning\n\nThis rule rejects descriptions that merely restate the parameter name, type, or containing symbol name. Descriptions must provide behavioral context.\n\n**Fails:**\n- `@param id - The id`\n- `@param options - The options object`\n- `@returns The result`\n- `@param name - The name string`\n\n**Passes:**\n- `@param id - Unique identifier used for cache lookup and deduplication`\n- `@param options - Controls retry behavior, timeout, and error handling strategy`\n- `@returns Parsed configuration with defaults applied for missing fields`\n- `@param name - Display name shown in the navigation sidebar`\n\n**Rule of thumb:** If removing the parameter name from the description leaves no useful information, the description is not informative enough.\n\n#### `jsdoc/check-tag-names` \u2014 allowed tags only\n\nThe lint configuration rejects non-standard JSDoc tags. Common tags to **avoid in JSDoc blocks**:\n- `@remarks` \u2014 move content to the description paragraph (prose before tags)\n- `@packageDocumentation` \u2014 use `@module` instead\n- `@concept`, `@constraint` \u2014 move content to the description paragraph\n\nFramework directives that look like tags (e.g., `@vitest-environment`) should use plain comments instead:\n```typescript\n// @vitest-environment node \u2190 correct (plain comment)\n/** @vitest-environment node */ \u2190 incorrect (treated as JSDoc tag)\n```\n\n#### `jsdoc/require-throws` \u2014 document throw conditions\n\nInclude `@throws` for any function that can throw, including catch-and-rethrow patterns:\n```typescript\n/**\n * @param path - File path to read\n * @returns Parsed configuration object\n * @throws {ConfigError} When the file is missing or contains invalid YAML\n */\n```\n\nIf a function catches errors and rethrows them (wrapped or unwrapped), it still needs `@throws`.\n\n### Nested object parameters\n\nWhen a function accepts an inline object parameter, document each property with a nested `@param` tag:\n\n```typescript\n/**\n * Create a new user account.\n *\n * @param data - Account creation payload\n * @param data.email - Email address used for login and notifications\n * @param data.displayName - Public-facing name shown in the UI\n * @param data.role - Initial permission level assigned to the account\n * @returns The created user record with generated ID\n */\nfunction createUser(data: { email: string; displayName: string; role: Role }): User {\n```\n\nFor React component props, use `props` (or `root0` if destructured) as the root:\n\n```typescript\n/**\n * @param props - Component properties\n * @param props.title - Page heading displayed at the top\n * @param props.onSubmit - Callback invoked when the form is submitted\n */\nfunction MyComponent(props: { title: string; onSubmit: () => void }) {\n```\n\n### Overload documentation\n\nWhen a function has TypeScript overload signatures, document **both** the overload declarations and the implementation signature:\n\n```typescript\n/**\n * Parse a value from a string representation.\n *\n * @param input - Raw string to parse\n * @returns Parsed numeric value\n */\nfunction parse(input: string): number;\n/**\n * Parse a value from a buffer.\n *\n * @param input - Binary buffer to parse\n * @returns Parsed numeric value\n */\nfunction parse(input: Buffer): number;\n/**\n * Parse a value from string or buffer input. String inputs are decoded\n * as UTF-8 before numeric parsing.\n *\n * @param input - String or buffer to parse\n * @returns Parsed numeric value\n * @throws {ParseError} When the input cannot be interpreted as a number\n */\nfunction parse(input: string | Buffer): number {\n // implementation\n}\n```\n\n## Text output and piping\n\njsdoczoom outputs human-readable text by default. Each item has a `# path` header followed by content. This makes it composable with standard Unix tools:\n\n```sh\njsdoczoom src/utils.ts@3 | grep "functionName" # find symbol + source line\njsdoczoom src/utils.ts@3 | grep "// L" # list all declarations with lines\njsdoczoom src/**/*.ts | grep "^#" # list all file summaries\ngrep -rl "term" src/ --include="*.ts" | jsdoczoom # describe matching files\n```\n\nType declarations include source line annotations (`// LN` or `// LN-LM` for ranges), so you can locate implementations in the source file without a separate search step.\n\nFor machine-parseable output, use `--json`:\n\n```sh\njsdoczoom --json src/**/*.ts | jq \'.items[].text\'\n```\n';
|
|
15
15
|
/** Explanation text for each lint rule, used by --explain-rule */
|
|
16
16
|
export declare const RULE_EXPLANATIONS: Record<string, string>;
|
package/types/types.d.ts
CHANGED