@fgv/typedoc-compact-theme 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/.rush/temp/chunked-rush-logs/typedoc-compact-theme.build.chunks.jsonl +1 -0
- package/.rush/temp/operation/build/all.log +1 -0
- package/.rush/temp/operation/build/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +28 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +1083 -0
- package/lib/index.js.map +1 -0
- package/package.json +29 -0
- package/rush-logs/typedoc-compact-theme.build.cache.log +1 -0
- package/rush-logs/typedoc-compact-theme.build.log +1 -0
- package/src/index.ts +1327 -0
- package/tsconfig.json +18 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,1083 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeDoc Compact Theme
|
|
3
|
+
*
|
|
4
|
+
* Renders API documentation in a compact HTML table format similar to api-documenter.
|
|
5
|
+
* Uses TypeDoc's project model directly, bypassing the theme partial system for
|
|
6
|
+
* complete control over output format.
|
|
7
|
+
*
|
|
8
|
+
* Properties table: Property | Modifiers | Type | Description (includes accessors)
|
|
9
|
+
* Methods table: Method | Modifiers | Description
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from 'fs';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import { Application, Converter, DeclarationReflection, ParameterType, ProjectReflection, ReflectionKind } from 'typedoc';
|
|
14
|
+
/**
|
|
15
|
+
* Renders a class or interface to markdown.
|
|
16
|
+
*/
|
|
17
|
+
class CompactMarkdownRenderer {
|
|
18
|
+
_outputDir;
|
|
19
|
+
_options;
|
|
20
|
+
_urlMap = new Map();
|
|
21
|
+
_currentFilePath = '';
|
|
22
|
+
constructor(outputDir, options) {
|
|
23
|
+
this._outputDir = outputDir;
|
|
24
|
+
this._options = options;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Render the entire project.
|
|
28
|
+
*/
|
|
29
|
+
renderProject(project) {
|
|
30
|
+
// Clear and recreate output directory to remove stale files
|
|
31
|
+
if (fs.existsSync(this._outputDir)) {
|
|
32
|
+
fs.rmSync(this._outputDir, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
fs.mkdirSync(this._outputDir, { recursive: true });
|
|
35
|
+
// First pass: build URL map for all types
|
|
36
|
+
this._buildUrlMap(project, '');
|
|
37
|
+
// Render index
|
|
38
|
+
this._renderIndex(project);
|
|
39
|
+
// Recursively render all declarations
|
|
40
|
+
this._renderChildren(project, '');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build URL map for all documented types.
|
|
44
|
+
*/
|
|
45
|
+
_buildUrlMap(parent, basePath) {
|
|
46
|
+
if (!(parent instanceof DeclarationReflection) && !(parent instanceof ProjectReflection)) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const children = parent.children ?? [];
|
|
50
|
+
for (const child of children) {
|
|
51
|
+
const name = child.name;
|
|
52
|
+
let subdir = '';
|
|
53
|
+
let shouldIndex = true;
|
|
54
|
+
if (child.kind === ReflectionKind.Class) {
|
|
55
|
+
subdir = 'classes';
|
|
56
|
+
}
|
|
57
|
+
else if (child.kind === ReflectionKind.Interface) {
|
|
58
|
+
subdir = 'interfaces';
|
|
59
|
+
}
|
|
60
|
+
else if (child.kind === ReflectionKind.Enum) {
|
|
61
|
+
subdir = 'enums';
|
|
62
|
+
}
|
|
63
|
+
else if (child.kind === ReflectionKind.TypeAlias) {
|
|
64
|
+
subdir = 'type-aliases';
|
|
65
|
+
}
|
|
66
|
+
else if (child.kind === ReflectionKind.Function) {
|
|
67
|
+
subdir = 'functions';
|
|
68
|
+
}
|
|
69
|
+
else if (child.kind === ReflectionKind.Variable) {
|
|
70
|
+
subdir = 'variables';
|
|
71
|
+
}
|
|
72
|
+
else if (child.kind === ReflectionKind.Namespace || child.kind === ReflectionKind.Module) {
|
|
73
|
+
// Recurse into namespaces
|
|
74
|
+
const nsPath = path.join(basePath, this._sanitizeName(child.name));
|
|
75
|
+
this._buildUrlMap(child, nsPath);
|
|
76
|
+
shouldIndex = false;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
shouldIndex = false;
|
|
80
|
+
}
|
|
81
|
+
if (shouldIndex && subdir) {
|
|
82
|
+
const url = path.join(basePath, subdir, `${this._sanitizeName(name)}.md`);
|
|
83
|
+
this._urlMap.set(name, { url, kind: child.kind });
|
|
84
|
+
// Also index with full path for namespaced types
|
|
85
|
+
if (basePath) {
|
|
86
|
+
const fullName = basePath.replace(/\//g, '.') + '.' + name;
|
|
87
|
+
this._urlMap.set(fullName, { url, kind: child.kind });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Recurse into children for nested types
|
|
91
|
+
this._buildUrlMap(child, basePath);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
_renderChildren(parent, basePath) {
|
|
95
|
+
if (!(parent instanceof DeclarationReflection) && !(parent instanceof ProjectReflection)) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const children = parent.children ?? [];
|
|
99
|
+
for (const child of children) {
|
|
100
|
+
if (child.kind === ReflectionKind.Class || child.kind === ReflectionKind.Interface) {
|
|
101
|
+
this._renderClassOrInterface(child, basePath);
|
|
102
|
+
}
|
|
103
|
+
else if (child.kind === ReflectionKind.Namespace || child.kind === ReflectionKind.Module) {
|
|
104
|
+
// Create subdirectory for namespace and render its index
|
|
105
|
+
const nsPath = path.join(basePath, this._sanitizeName(child.name));
|
|
106
|
+
this._renderNamespaceIndex(child, nsPath);
|
|
107
|
+
this._renderChildren(child, nsPath);
|
|
108
|
+
}
|
|
109
|
+
else if (child.kind === ReflectionKind.Enum) {
|
|
110
|
+
this._renderEnum(child, basePath);
|
|
111
|
+
}
|
|
112
|
+
else if (child.kind === ReflectionKind.TypeAlias) {
|
|
113
|
+
this._renderTypeAlias(child, basePath);
|
|
114
|
+
}
|
|
115
|
+
else if (child.kind === ReflectionKind.Function) {
|
|
116
|
+
this._renderFunction(child, basePath);
|
|
117
|
+
}
|
|
118
|
+
else if (child.kind === ReflectionKind.Variable) {
|
|
119
|
+
this._renderVariable(child, basePath);
|
|
120
|
+
}
|
|
121
|
+
// Recurse into children
|
|
122
|
+
this._renderChildren(child, basePath);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
_renderIndex(project) {
|
|
126
|
+
this._setCurrentFile('README.md');
|
|
127
|
+
const lines = [];
|
|
128
|
+
lines.push(`# ${project.name}`);
|
|
129
|
+
lines.push('');
|
|
130
|
+
if (project.comment?.summary) {
|
|
131
|
+
lines.push(this._getCommentText(project.comment.summary));
|
|
132
|
+
lines.push('');
|
|
133
|
+
}
|
|
134
|
+
// Find namespaces/modules first
|
|
135
|
+
const namespaces = this._findByKind(project, ReflectionKind.Namespace);
|
|
136
|
+
const modules = this._findByKind(project, ReflectionKind.Module);
|
|
137
|
+
const allNamespaces = [...namespaces, ...modules];
|
|
138
|
+
if (allNamespaces.length > 0) {
|
|
139
|
+
lines.push('## Namespaces');
|
|
140
|
+
lines.push('');
|
|
141
|
+
lines.push(this._renderIndexTable(allNamespaces, (n) => `./${this._sanitizeName(n.name)}/README.md`));
|
|
142
|
+
lines.push('');
|
|
143
|
+
}
|
|
144
|
+
// List all top-level exports
|
|
145
|
+
const classes = this._findByKind(project, ReflectionKind.Class);
|
|
146
|
+
const interfaces = this._findByKind(project, ReflectionKind.Interface);
|
|
147
|
+
const enums = this._findByKind(project, ReflectionKind.Enum);
|
|
148
|
+
const typeAliases = this._findByKind(project, ReflectionKind.TypeAlias);
|
|
149
|
+
const functions = this._findByKind(project, ReflectionKind.Function);
|
|
150
|
+
const variables = this._findByKind(project, ReflectionKind.Variable);
|
|
151
|
+
if (classes.length > 0) {
|
|
152
|
+
lines.push('## Classes');
|
|
153
|
+
lines.push('');
|
|
154
|
+
lines.push(this._renderIndexTable(classes, (c) => `./classes/${this._sanitizeName(c.name)}.md`));
|
|
155
|
+
lines.push('');
|
|
156
|
+
}
|
|
157
|
+
if (interfaces.length > 0) {
|
|
158
|
+
lines.push('## Interfaces');
|
|
159
|
+
lines.push('');
|
|
160
|
+
lines.push(this._renderIndexTable(interfaces, (i) => `./interfaces/${this._sanitizeName(i.name)}.md`));
|
|
161
|
+
lines.push('');
|
|
162
|
+
}
|
|
163
|
+
if (enums.length > 0) {
|
|
164
|
+
lines.push('## Enums');
|
|
165
|
+
lines.push('');
|
|
166
|
+
lines.push(this._renderIndexTable(enums, (e) => `./enums/${this._sanitizeName(e.name)}.md`));
|
|
167
|
+
lines.push('');
|
|
168
|
+
}
|
|
169
|
+
if (typeAliases.length > 0) {
|
|
170
|
+
lines.push('## Type Aliases');
|
|
171
|
+
lines.push('');
|
|
172
|
+
lines.push(this._renderIndexTable(typeAliases, (t) => `./type-aliases/${this._sanitizeName(t.name)}.md`));
|
|
173
|
+
lines.push('');
|
|
174
|
+
}
|
|
175
|
+
if (functions.length > 0) {
|
|
176
|
+
lines.push('## Functions');
|
|
177
|
+
lines.push('');
|
|
178
|
+
lines.push(this._renderIndexTable(functions, (f) => `./functions/${this._sanitizeName(f.name)}.md`));
|
|
179
|
+
lines.push('');
|
|
180
|
+
}
|
|
181
|
+
if (variables.length > 0) {
|
|
182
|
+
lines.push('## Variables');
|
|
183
|
+
lines.push('');
|
|
184
|
+
lines.push(this._renderIndexTable(variables, (v) => `./variables/${this._sanitizeName(v.name)}.md`));
|
|
185
|
+
lines.push('');
|
|
186
|
+
}
|
|
187
|
+
const indexPath = path.join(this._outputDir, 'README.md');
|
|
188
|
+
fs.writeFileSync(indexPath, lines.join('\n'));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Render an index table for a list of declarations.
|
|
192
|
+
*/
|
|
193
|
+
_renderIndexTable(items, urlFn) {
|
|
194
|
+
const lines = [];
|
|
195
|
+
lines.push('<table><thead><tr><th>');
|
|
196
|
+
lines.push('');
|
|
197
|
+
lines.push('Name');
|
|
198
|
+
lines.push('');
|
|
199
|
+
lines.push('</th><th>');
|
|
200
|
+
lines.push('');
|
|
201
|
+
lines.push('Description');
|
|
202
|
+
lines.push('');
|
|
203
|
+
lines.push('</th></tr></thead>');
|
|
204
|
+
lines.push('<tbody>');
|
|
205
|
+
for (const item of items) {
|
|
206
|
+
const url = urlFn(item);
|
|
207
|
+
const desc = this._getItemDescription(item);
|
|
208
|
+
lines.push('<tr><td>');
|
|
209
|
+
lines.push('');
|
|
210
|
+
lines.push(`[${item.name}](${url})`);
|
|
211
|
+
lines.push('');
|
|
212
|
+
lines.push('</td><td>');
|
|
213
|
+
lines.push('');
|
|
214
|
+
lines.push(desc);
|
|
215
|
+
lines.push('');
|
|
216
|
+
lines.push('</td></tr>');
|
|
217
|
+
}
|
|
218
|
+
lines.push('</tbody></table>');
|
|
219
|
+
return lines.join('\n');
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get description for an item (first line of comment or signature comment).
|
|
223
|
+
*/
|
|
224
|
+
_getItemDescription(item) {
|
|
225
|
+
// Try item's own comment
|
|
226
|
+
if (item.comment?.summary) {
|
|
227
|
+
return this._getFirstLine(this._getCommentText(item.comment.summary));
|
|
228
|
+
}
|
|
229
|
+
// For functions, try signature comment
|
|
230
|
+
const sig = item.signatures?.[0];
|
|
231
|
+
if (sig?.comment?.summary) {
|
|
232
|
+
return this._getFirstLine(this._getCommentText(sig.comment.summary));
|
|
233
|
+
}
|
|
234
|
+
// For accessors, try getter/setter comment
|
|
235
|
+
if (item.getSignature?.comment?.summary) {
|
|
236
|
+
return this._getFirstLine(this._getCommentText(item.getSignature.comment.summary));
|
|
237
|
+
}
|
|
238
|
+
return '';
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get the first line/sentence of a description.
|
|
242
|
+
*/
|
|
243
|
+
_getFirstLine(text) {
|
|
244
|
+
// Split on period followed by space or newline
|
|
245
|
+
const firstSentence = text.split(/\.\s|\.\n/)[0];
|
|
246
|
+
if (firstSentence && firstSentence !== text) {
|
|
247
|
+
return firstSentence + '.';
|
|
248
|
+
}
|
|
249
|
+
// If no period, take first line
|
|
250
|
+
const firstLine = text.split('\n')[0];
|
|
251
|
+
return firstLine.trim();
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Render an index page for a namespace/module.
|
|
255
|
+
*/
|
|
256
|
+
_renderNamespaceIndex(ns, nsPath) {
|
|
257
|
+
const filePath = path.join(nsPath, 'README.md');
|
|
258
|
+
this._setCurrentFile(filePath);
|
|
259
|
+
const lines = [];
|
|
260
|
+
const kindName = ns.kind === ReflectionKind.Namespace ? 'Namespace' : 'Module';
|
|
261
|
+
// Breadcrumb - nsPath includes this namespace, file is at nsPath/README.md
|
|
262
|
+
// We need to go up one level more than pathParts length to reach root
|
|
263
|
+
const pathParts = nsPath.split('/').filter((p) => p);
|
|
264
|
+
const depth = pathParts.length;
|
|
265
|
+
const homePrefix = '../'.repeat(depth);
|
|
266
|
+
const breadcrumbParts = [`[Home](${homePrefix}README.md)`];
|
|
267
|
+
// Add parent namespaces (all but the last one)
|
|
268
|
+
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
269
|
+
const levelsUp = depth - (i + 1);
|
|
270
|
+
const nsPrefix = '../'.repeat(levelsUp);
|
|
271
|
+
breadcrumbParts.push(`[${pathParts[i]}](${nsPrefix}README.md)`);
|
|
272
|
+
}
|
|
273
|
+
// Current namespace (not linked)
|
|
274
|
+
breadcrumbParts.push(ns.name);
|
|
275
|
+
lines.push(breadcrumbParts.join(' > '));
|
|
276
|
+
lines.push('');
|
|
277
|
+
lines.push(`# ${kindName}: ${ns.name}`);
|
|
278
|
+
lines.push('');
|
|
279
|
+
if (ns.comment?.summary) {
|
|
280
|
+
lines.push(this._getCommentText(ns.comment.summary));
|
|
281
|
+
lines.push('');
|
|
282
|
+
}
|
|
283
|
+
// Collect children by kind
|
|
284
|
+
const children = ns.children ?? [];
|
|
285
|
+
const childNamespaces = children.filter((c) => c.kind === ReflectionKind.Namespace || c.kind === ReflectionKind.Module);
|
|
286
|
+
const classes = children.filter((c) => c.kind === ReflectionKind.Class);
|
|
287
|
+
const interfaces = children.filter((c) => c.kind === ReflectionKind.Interface);
|
|
288
|
+
const enums = children.filter((c) => c.kind === ReflectionKind.Enum);
|
|
289
|
+
const typeAliases = children.filter((c) => c.kind === ReflectionKind.TypeAlias);
|
|
290
|
+
const functions = children.filter((c) => c.kind === ReflectionKind.Function);
|
|
291
|
+
const variables = children.filter((c) => c.kind === ReflectionKind.Variable);
|
|
292
|
+
if (childNamespaces.length > 0) {
|
|
293
|
+
lines.push('## Namespaces');
|
|
294
|
+
lines.push('');
|
|
295
|
+
lines.push(this._renderIndexTable(childNamespaces, (n) => `./${this._sanitizeName(n.name)}/README.md`));
|
|
296
|
+
lines.push('');
|
|
297
|
+
}
|
|
298
|
+
if (classes.length > 0) {
|
|
299
|
+
lines.push('## Classes');
|
|
300
|
+
lines.push('');
|
|
301
|
+
lines.push(this._renderIndexTable(classes, (c) => `./classes/${this._sanitizeName(c.name)}.md`));
|
|
302
|
+
lines.push('');
|
|
303
|
+
}
|
|
304
|
+
if (interfaces.length > 0) {
|
|
305
|
+
lines.push('## Interfaces');
|
|
306
|
+
lines.push('');
|
|
307
|
+
lines.push(this._renderIndexTable(interfaces, (i) => `./interfaces/${this._sanitizeName(i.name)}.md`));
|
|
308
|
+
lines.push('');
|
|
309
|
+
}
|
|
310
|
+
if (enums.length > 0) {
|
|
311
|
+
lines.push('## Enums');
|
|
312
|
+
lines.push('');
|
|
313
|
+
lines.push(this._renderIndexTable(enums, (e) => `./enums/${this._sanitizeName(e.name)}.md`));
|
|
314
|
+
lines.push('');
|
|
315
|
+
}
|
|
316
|
+
if (typeAliases.length > 0) {
|
|
317
|
+
lines.push('## Type Aliases');
|
|
318
|
+
lines.push('');
|
|
319
|
+
lines.push(this._renderIndexTable(typeAliases, (t) => `./type-aliases/${this._sanitizeName(t.name)}.md`));
|
|
320
|
+
lines.push('');
|
|
321
|
+
}
|
|
322
|
+
if (functions.length > 0) {
|
|
323
|
+
lines.push('## Functions');
|
|
324
|
+
lines.push('');
|
|
325
|
+
lines.push(this._renderIndexTable(functions, (f) => `./functions/${this._sanitizeName(f.name)}.md`));
|
|
326
|
+
lines.push('');
|
|
327
|
+
}
|
|
328
|
+
if (variables.length > 0) {
|
|
329
|
+
lines.push('## Variables');
|
|
330
|
+
lines.push('');
|
|
331
|
+
lines.push(this._renderIndexTable(variables, (v) => `./variables/${this._sanitizeName(v.name)}.md`));
|
|
332
|
+
lines.push('');
|
|
333
|
+
}
|
|
334
|
+
// Ensure directory exists
|
|
335
|
+
const outDir = path.join(this._outputDir, nsPath);
|
|
336
|
+
if (!fs.existsSync(outDir)) {
|
|
337
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
338
|
+
}
|
|
339
|
+
const outPath = path.join(this._outputDir, filePath);
|
|
340
|
+
fs.writeFileSync(outPath, lines.join('\n'));
|
|
341
|
+
}
|
|
342
|
+
_renderClassOrInterface(decl, basePath) {
|
|
343
|
+
const lines = [];
|
|
344
|
+
const kindName = decl.kind === ReflectionKind.Class ? 'Class' : 'Interface';
|
|
345
|
+
// Set current file for relative URL computation
|
|
346
|
+
const subdir = decl.kind === ReflectionKind.Class ? 'classes' : 'interfaces';
|
|
347
|
+
const filePath = path.join(basePath, subdir, `${this._sanitizeName(decl.name)}.md`);
|
|
348
|
+
this._setCurrentFile(filePath);
|
|
349
|
+
// Breadcrumb
|
|
350
|
+
lines.push(this._generateBreadcrumb(basePath, decl.name, subdir));
|
|
351
|
+
lines.push('');
|
|
352
|
+
// Header
|
|
353
|
+
lines.push(`# ${kindName}: ${decl.name}`);
|
|
354
|
+
lines.push('');
|
|
355
|
+
// Description
|
|
356
|
+
if (decl.comment?.summary) {
|
|
357
|
+
lines.push(this._getCommentText(decl.comment.summary));
|
|
358
|
+
lines.push('');
|
|
359
|
+
}
|
|
360
|
+
// Extends and Implements on single lines with links
|
|
361
|
+
if (decl.extendedTypes && decl.extendedTypes.length > 0) {
|
|
362
|
+
const extList = decl.extendedTypes.map((t) => this._linkTypeInline(t.toString())).join(', ');
|
|
363
|
+
lines.push(`**Extends:** ${extList}`);
|
|
364
|
+
lines.push('');
|
|
365
|
+
}
|
|
366
|
+
if (decl.implementedTypes && decl.implementedTypes.length > 0) {
|
|
367
|
+
const implList = decl.implementedTypes.map((t) => this._linkTypeInline(t.toString())).join(', ');
|
|
368
|
+
lines.push(`**Implements:** ${implList}`);
|
|
369
|
+
lines.push('');
|
|
370
|
+
}
|
|
371
|
+
// Collect members by category
|
|
372
|
+
const children = decl.children ?? [];
|
|
373
|
+
const constructors = children.filter((c) => c.kind === ReflectionKind.Constructor);
|
|
374
|
+
const properties = children.filter((c) => c.kind === ReflectionKind.Property);
|
|
375
|
+
const accessors = children.filter((c) => c.kind === ReflectionKind.Accessor);
|
|
376
|
+
const methods = children.filter((c) => c.kind === ReflectionKind.Method);
|
|
377
|
+
// Member detail pages base path
|
|
378
|
+
const memberBasePath = path.join(basePath, subdir);
|
|
379
|
+
// Render constructors
|
|
380
|
+
if (constructors.length > 0) {
|
|
381
|
+
lines.push('## Constructors');
|
|
382
|
+
lines.push('');
|
|
383
|
+
lines.push(this._renderConstructorsTable(constructors, decl.name, memberBasePath));
|
|
384
|
+
lines.push('');
|
|
385
|
+
}
|
|
386
|
+
// Render properties + accessors combined
|
|
387
|
+
const allProperties = [...properties, ...accessors];
|
|
388
|
+
if (allProperties.length > 0) {
|
|
389
|
+
lines.push('## Properties');
|
|
390
|
+
lines.push('');
|
|
391
|
+
lines.push(this._renderPropertiesTable(allProperties, decl.name, memberBasePath));
|
|
392
|
+
lines.push('');
|
|
393
|
+
// Render property detail pages (optionally skip inherited members)
|
|
394
|
+
for (const prop of allProperties) {
|
|
395
|
+
if (this._options.includeInheritedMemberPages || !prop.inheritedFrom) {
|
|
396
|
+
this._renderPropertyDetailPage(prop, decl, memberBasePath);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
// Render methods
|
|
401
|
+
if (methods.length > 0) {
|
|
402
|
+
lines.push('## Methods');
|
|
403
|
+
lines.push('');
|
|
404
|
+
lines.push(this._renderMethodsTable(methods, decl.name, memberBasePath));
|
|
405
|
+
lines.push('');
|
|
406
|
+
// Render method detail pages (optionally skip inherited members)
|
|
407
|
+
for (const method of methods) {
|
|
408
|
+
if (this._options.includeInheritedMemberPages || !method.inheritedFrom) {
|
|
409
|
+
this._renderMethodDetailPage(method, decl, memberBasePath);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
// Write file
|
|
414
|
+
const outDir = path.join(this._outputDir, basePath, subdir);
|
|
415
|
+
if (!fs.existsSync(outDir)) {
|
|
416
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
417
|
+
}
|
|
418
|
+
const outPath = path.join(outDir, `${this._sanitizeName(decl.name)}.md`);
|
|
419
|
+
fs.writeFileSync(outPath, lines.join('\n'));
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Render a detail page for a property or accessor.
|
|
423
|
+
*/
|
|
424
|
+
_renderPropertyDetailPage(prop, parent, basePath) {
|
|
425
|
+
const fileName = `${this._sanitizeName(parent.name)}.${this._sanitizeName(prop.name)}.md`;
|
|
426
|
+
const filePath = path.join(basePath, fileName);
|
|
427
|
+
this._setCurrentFile(filePath);
|
|
428
|
+
const lines = [];
|
|
429
|
+
const kindLabel = prop.kind === ReflectionKind.Accessor ? 'property' : 'property';
|
|
430
|
+
// Breadcrumb: extract namespace path from basePath (which is like "Namespace/classes")
|
|
431
|
+
const pathParts = basePath.split('/').filter((p) => p);
|
|
432
|
+
const subdir = pathParts.pop(); // Remove "classes" or "interfaces"
|
|
433
|
+
const namespacePath = pathParts.join('/');
|
|
434
|
+
// Generate breadcrumb with linked parent class
|
|
435
|
+
const breadcrumbParts = [];
|
|
436
|
+
const depth = pathParts.length + 1; // +1 for subdir
|
|
437
|
+
breadcrumbParts.push(`[Home](${'../'.repeat(depth)}README.md)`);
|
|
438
|
+
// Add namespace parts
|
|
439
|
+
for (let i = 0; i < pathParts.length; i++) {
|
|
440
|
+
const levelsUp = depth - (i + 1);
|
|
441
|
+
breadcrumbParts.push(`[${pathParts[i]}](${'../'.repeat(levelsUp)}README.md)`);
|
|
442
|
+
}
|
|
443
|
+
// Add linked parent class
|
|
444
|
+
breadcrumbParts.push(`[${parent.name}](./${this._sanitizeName(parent.name)}.md)`);
|
|
445
|
+
// Add current property (unlinked)
|
|
446
|
+
breadcrumbParts.push(prop.name);
|
|
447
|
+
lines.push(breadcrumbParts.join(' > '));
|
|
448
|
+
lines.push('');
|
|
449
|
+
// Header
|
|
450
|
+
lines.push(`## ${parent.name}.${prop.name} ${kindLabel}`);
|
|
451
|
+
lines.push('');
|
|
452
|
+
// Description
|
|
453
|
+
let description = '';
|
|
454
|
+
if (prop.kind === ReflectionKind.Accessor) {
|
|
455
|
+
const getter = prop.getSignature;
|
|
456
|
+
const setter = prop.setSignature;
|
|
457
|
+
if (getter?.comment?.summary) {
|
|
458
|
+
description = this._getCommentText(getter.comment.summary);
|
|
459
|
+
}
|
|
460
|
+
else if (setter?.comment?.summary) {
|
|
461
|
+
description = this._getCommentText(setter.comment.summary);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
else if (prop.comment?.summary) {
|
|
465
|
+
description = this._getCommentText(prop.comment.summary);
|
|
466
|
+
}
|
|
467
|
+
if (description) {
|
|
468
|
+
lines.push(description);
|
|
469
|
+
lines.push('');
|
|
470
|
+
}
|
|
471
|
+
// Signature
|
|
472
|
+
lines.push('**Signature:**');
|
|
473
|
+
lines.push('');
|
|
474
|
+
lines.push('```typescript');
|
|
475
|
+
lines.push(this._getPropertySignature(prop));
|
|
476
|
+
lines.push('```');
|
|
477
|
+
lines.push('');
|
|
478
|
+
// Write file
|
|
479
|
+
const outDir = path.join(this._outputDir, basePath);
|
|
480
|
+
if (!fs.existsSync(outDir)) {
|
|
481
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
482
|
+
}
|
|
483
|
+
const outPath = path.join(this._outputDir, filePath);
|
|
484
|
+
fs.writeFileSync(outPath, lines.join('\n'));
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Render a detail page for a method.
|
|
488
|
+
*/
|
|
489
|
+
_renderMethodDetailPage(method, parent, basePath) {
|
|
490
|
+
const fileName = `${this._sanitizeName(parent.name)}.${this._sanitizeName(method.name)}.md`;
|
|
491
|
+
const filePath = path.join(basePath, fileName);
|
|
492
|
+
this._setCurrentFile(filePath);
|
|
493
|
+
const lines = [];
|
|
494
|
+
// Breadcrumb: extract namespace path from basePath (which is like "Namespace/classes")
|
|
495
|
+
const pathParts = basePath.split('/').filter((p) => p);
|
|
496
|
+
pathParts.pop(); // Remove "classes" or "interfaces"
|
|
497
|
+
// Generate breadcrumb with linked parent class
|
|
498
|
+
const breadcrumbParts = [];
|
|
499
|
+
const depth = pathParts.length + 1; // +1 for subdir
|
|
500
|
+
breadcrumbParts.push(`[Home](${'../'.repeat(depth)}README.md)`);
|
|
501
|
+
// Add namespace parts
|
|
502
|
+
for (let i = 0; i < pathParts.length; i++) {
|
|
503
|
+
const levelsUp = depth - (i + 1);
|
|
504
|
+
breadcrumbParts.push(`[${pathParts[i]}](${'../'.repeat(levelsUp)}README.md)`);
|
|
505
|
+
}
|
|
506
|
+
// Add linked parent class
|
|
507
|
+
breadcrumbParts.push(`[${parent.name}](./${this._sanitizeName(parent.name)}.md)`);
|
|
508
|
+
// Add current method (unlinked)
|
|
509
|
+
breadcrumbParts.push(method.name);
|
|
510
|
+
lines.push(breadcrumbParts.join(' > '));
|
|
511
|
+
lines.push('');
|
|
512
|
+
// Header
|
|
513
|
+
lines.push(`## ${parent.name}.${method.name}() method`);
|
|
514
|
+
lines.push('');
|
|
515
|
+
// Description from signature
|
|
516
|
+
const sig = method.signatures?.[0];
|
|
517
|
+
if (sig?.comment?.summary) {
|
|
518
|
+
lines.push(this._getCommentText(sig.comment.summary));
|
|
519
|
+
lines.push('');
|
|
520
|
+
}
|
|
521
|
+
// Signature
|
|
522
|
+
lines.push('**Signature:**');
|
|
523
|
+
lines.push('');
|
|
524
|
+
lines.push('```typescript');
|
|
525
|
+
lines.push(this._getMethodSignature(method));
|
|
526
|
+
lines.push('```');
|
|
527
|
+
lines.push('');
|
|
528
|
+
// Parameters
|
|
529
|
+
if (sig?.parameters && sig.parameters.length > 0) {
|
|
530
|
+
lines.push('**Parameters:**');
|
|
531
|
+
lines.push('');
|
|
532
|
+
lines.push('<table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead>');
|
|
533
|
+
lines.push('<tbody>');
|
|
534
|
+
for (const param of sig.parameters) {
|
|
535
|
+
const paramType = param.type?.toString() ?? 'unknown';
|
|
536
|
+
const paramDesc = param.comment?.summary ? this._getCommentText(param.comment.summary) : '';
|
|
537
|
+
lines.push(`<tr><td>${param.name}</td><td>${this._escapeHtml(paramType)}</td><td>${paramDesc}</td></tr>`);
|
|
538
|
+
}
|
|
539
|
+
lines.push('</tbody></table>');
|
|
540
|
+
lines.push('');
|
|
541
|
+
}
|
|
542
|
+
// Returns
|
|
543
|
+
if (sig?.type) {
|
|
544
|
+
lines.push('**Returns:**');
|
|
545
|
+
lines.push('');
|
|
546
|
+
lines.push(`${this._linkType(sig.type.toString())}`);
|
|
547
|
+
if (sig.comment?.blockTags) {
|
|
548
|
+
const returnsTag = sig.comment.blockTags.find((t) => t.tag === '@returns');
|
|
549
|
+
if (returnsTag?.content) {
|
|
550
|
+
lines.push('');
|
|
551
|
+
lines.push(this._getCommentText(returnsTag.content));
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
lines.push('');
|
|
555
|
+
}
|
|
556
|
+
// Write file
|
|
557
|
+
const outDir = path.join(this._outputDir, basePath);
|
|
558
|
+
if (!fs.existsSync(outDir)) {
|
|
559
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
560
|
+
}
|
|
561
|
+
const outPath = path.join(this._outputDir, filePath);
|
|
562
|
+
fs.writeFileSync(outPath, lines.join('\n'));
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Get signature string for a property.
|
|
566
|
+
*/
|
|
567
|
+
_getPropertySignature(prop) {
|
|
568
|
+
const modifiers = [];
|
|
569
|
+
if (prop.flags?.isReadonly)
|
|
570
|
+
modifiers.push('readonly');
|
|
571
|
+
if (prop.flags?.isStatic)
|
|
572
|
+
modifiers.push('static');
|
|
573
|
+
let typeStr = '';
|
|
574
|
+
if (prop.kind === ReflectionKind.Accessor) {
|
|
575
|
+
const getter = prop.getSignature;
|
|
576
|
+
const setter = prop.setSignature;
|
|
577
|
+
if (getter?.type) {
|
|
578
|
+
typeStr = getter.type.toString();
|
|
579
|
+
}
|
|
580
|
+
else if (setter?.parameters?.[0]?.type) {
|
|
581
|
+
typeStr = setter.parameters[0].type.toString();
|
|
582
|
+
}
|
|
583
|
+
if (getter && !setter)
|
|
584
|
+
modifiers.push('readonly');
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
typeStr = prop.type?.toString() ?? 'unknown';
|
|
588
|
+
}
|
|
589
|
+
const modStr = modifiers.length > 0 ? modifiers.join(' ') + ' ' : '';
|
|
590
|
+
return `${modStr}${prop.name}: ${typeStr};`;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Get signature string for a method.
|
|
594
|
+
*/
|
|
595
|
+
_getMethodSignature(method) {
|
|
596
|
+
const sig = method.signatures?.[0];
|
|
597
|
+
if (!sig)
|
|
598
|
+
return `${method.name}(): unknown;`;
|
|
599
|
+
const modifiers = [];
|
|
600
|
+
if (method.flags?.isStatic)
|
|
601
|
+
modifiers.push('static');
|
|
602
|
+
const params = sig.parameters
|
|
603
|
+
?.map((p) => {
|
|
604
|
+
const optional = p.flags?.isOptional ? '?' : '';
|
|
605
|
+
return `${p.name}${optional}: ${p.type?.toString() ?? 'unknown'}`;
|
|
606
|
+
})
|
|
607
|
+
.join(', ') ?? '';
|
|
608
|
+
const returnType = sig.type?.toString() ?? 'void';
|
|
609
|
+
const modStr = modifiers.length > 0 ? modifiers.join(' ') + ' ' : '';
|
|
610
|
+
return `${modStr}${method.name}(${params}): ${returnType};`;
|
|
611
|
+
}
|
|
612
|
+
_renderEnum(decl, basePath) {
|
|
613
|
+
const lines = [];
|
|
614
|
+
// Breadcrumb
|
|
615
|
+
lines.push(this._generateBreadcrumb(basePath, decl.name, 'enums'));
|
|
616
|
+
lines.push('');
|
|
617
|
+
lines.push(`# Enum: ${decl.name}`);
|
|
618
|
+
lines.push('');
|
|
619
|
+
if (decl.comment?.summary) {
|
|
620
|
+
lines.push(this._getCommentText(decl.comment.summary));
|
|
621
|
+
lines.push('');
|
|
622
|
+
}
|
|
623
|
+
const members = decl.children ?? [];
|
|
624
|
+
if (members.length > 0) {
|
|
625
|
+
lines.push('## Members');
|
|
626
|
+
lines.push('');
|
|
627
|
+
lines.push('<table><thead><tr><th>');
|
|
628
|
+
lines.push('');
|
|
629
|
+
lines.push('Member');
|
|
630
|
+
lines.push('');
|
|
631
|
+
lines.push('</th><th>');
|
|
632
|
+
lines.push('');
|
|
633
|
+
lines.push('Value');
|
|
634
|
+
lines.push('');
|
|
635
|
+
lines.push('</th><th>');
|
|
636
|
+
lines.push('');
|
|
637
|
+
lines.push('Description');
|
|
638
|
+
lines.push('');
|
|
639
|
+
lines.push('</th></tr></thead>');
|
|
640
|
+
lines.push('<tbody>');
|
|
641
|
+
for (const member of members) {
|
|
642
|
+
const value = member.type?.toString() ?? '';
|
|
643
|
+
const desc = member.comment?.summary ? this._getCommentText(member.comment.summary) : '';
|
|
644
|
+
lines.push('<tr><td>');
|
|
645
|
+
lines.push('');
|
|
646
|
+
lines.push(`\`${member.name}\``);
|
|
647
|
+
lines.push('');
|
|
648
|
+
lines.push('</td><td>');
|
|
649
|
+
lines.push('');
|
|
650
|
+
lines.push(value);
|
|
651
|
+
lines.push('');
|
|
652
|
+
lines.push('</td><td>');
|
|
653
|
+
lines.push('');
|
|
654
|
+
lines.push(desc);
|
|
655
|
+
lines.push('');
|
|
656
|
+
lines.push('</td></tr>');
|
|
657
|
+
}
|
|
658
|
+
lines.push('</tbody></table>');
|
|
659
|
+
lines.push('');
|
|
660
|
+
}
|
|
661
|
+
const outDir = path.join(this._outputDir, basePath, 'enums');
|
|
662
|
+
if (!fs.existsSync(outDir)) {
|
|
663
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
664
|
+
}
|
|
665
|
+
const outPath = path.join(outDir, `${this._sanitizeName(decl.name)}.md`);
|
|
666
|
+
fs.writeFileSync(outPath, lines.join('\n'));
|
|
667
|
+
}
|
|
668
|
+
_renderTypeAlias(decl, basePath) {
|
|
669
|
+
const lines = [];
|
|
670
|
+
// Breadcrumb
|
|
671
|
+
lines.push(this._generateBreadcrumb(basePath, decl.name, 'type-aliases'));
|
|
672
|
+
lines.push('');
|
|
673
|
+
lines.push(`# Type Alias: ${decl.name}`);
|
|
674
|
+
lines.push('');
|
|
675
|
+
if (decl.comment?.summary) {
|
|
676
|
+
lines.push(this._getCommentText(decl.comment.summary));
|
|
677
|
+
lines.push('');
|
|
678
|
+
}
|
|
679
|
+
if (decl.type) {
|
|
680
|
+
lines.push('## Type');
|
|
681
|
+
lines.push('');
|
|
682
|
+
lines.push('```typescript');
|
|
683
|
+
lines.push(`type ${decl.name} = ${decl.type.toString()}`);
|
|
684
|
+
lines.push('```');
|
|
685
|
+
lines.push('');
|
|
686
|
+
}
|
|
687
|
+
const outDir = path.join(this._outputDir, basePath, 'type-aliases');
|
|
688
|
+
if (!fs.existsSync(outDir)) {
|
|
689
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
690
|
+
}
|
|
691
|
+
const outPath = path.join(outDir, `${this._sanitizeName(decl.name)}.md`);
|
|
692
|
+
fs.writeFileSync(outPath, lines.join('\n'));
|
|
693
|
+
}
|
|
694
|
+
_renderFunction(decl, basePath) {
|
|
695
|
+
const lines = [];
|
|
696
|
+
// Breadcrumb
|
|
697
|
+
lines.push(this._generateBreadcrumb(basePath, decl.name, 'functions'));
|
|
698
|
+
lines.push('');
|
|
699
|
+
lines.push(`# Function: ${decl.name}`);
|
|
700
|
+
lines.push('');
|
|
701
|
+
const sig = decl.signatures?.[0];
|
|
702
|
+
if (sig?.comment?.summary) {
|
|
703
|
+
lines.push(this._getCommentText(sig.comment.summary));
|
|
704
|
+
lines.push('');
|
|
705
|
+
}
|
|
706
|
+
if (sig) {
|
|
707
|
+
lines.push('## Signature');
|
|
708
|
+
lines.push('');
|
|
709
|
+
lines.push('```typescript');
|
|
710
|
+
lines.push(this._renderSignature(decl.name, sig));
|
|
711
|
+
lines.push('```');
|
|
712
|
+
lines.push('');
|
|
713
|
+
}
|
|
714
|
+
const outDir = path.join(this._outputDir, basePath, 'functions');
|
|
715
|
+
if (!fs.existsSync(outDir)) {
|
|
716
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
717
|
+
}
|
|
718
|
+
const outPath = path.join(outDir, `${this._sanitizeName(decl.name)}.md`);
|
|
719
|
+
fs.writeFileSync(outPath, lines.join('\n'));
|
|
720
|
+
}
|
|
721
|
+
_renderVariable(decl, basePath) {
|
|
722
|
+
const lines = [];
|
|
723
|
+
// Breadcrumb
|
|
724
|
+
lines.push(this._generateBreadcrumb(basePath, decl.name, 'variables'));
|
|
725
|
+
lines.push('');
|
|
726
|
+
lines.push(`# Variable: ${decl.name}`);
|
|
727
|
+
lines.push('');
|
|
728
|
+
if (decl.comment?.summary) {
|
|
729
|
+
lines.push(this._getCommentText(decl.comment.summary));
|
|
730
|
+
lines.push('');
|
|
731
|
+
}
|
|
732
|
+
if (decl.type) {
|
|
733
|
+
lines.push('## Type');
|
|
734
|
+
lines.push('');
|
|
735
|
+
lines.push(`\`${decl.type.toString()}\``);
|
|
736
|
+
lines.push('');
|
|
737
|
+
}
|
|
738
|
+
const outDir = path.join(this._outputDir, basePath, 'variables');
|
|
739
|
+
if (!fs.existsSync(outDir)) {
|
|
740
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
741
|
+
}
|
|
742
|
+
const outPath = path.join(outDir, `${this._sanitizeName(decl.name)}.md`);
|
|
743
|
+
fs.writeFileSync(outPath, lines.join('\n'));
|
|
744
|
+
}
|
|
745
|
+
_renderConstructorsTable(constructors, _parentName, _basePath) {
|
|
746
|
+
const lines = [];
|
|
747
|
+
lines.push('<table><thead><tr><th>');
|
|
748
|
+
lines.push('');
|
|
749
|
+
lines.push('Constructor');
|
|
750
|
+
lines.push('');
|
|
751
|
+
lines.push('</th><th>');
|
|
752
|
+
lines.push('');
|
|
753
|
+
lines.push('Modifiers');
|
|
754
|
+
lines.push('');
|
|
755
|
+
lines.push('</th><th>');
|
|
756
|
+
lines.push('');
|
|
757
|
+
lines.push('Description');
|
|
758
|
+
lines.push('');
|
|
759
|
+
lines.push('</th></tr></thead>');
|
|
760
|
+
lines.push('<tbody>');
|
|
761
|
+
for (const ctor of constructors) {
|
|
762
|
+
const sig = ctor.signatures?.[0];
|
|
763
|
+
const params = sig?.parameters?.map((p) => p.name).join(', ') ?? '';
|
|
764
|
+
const ctorSig = `constructor(${params})`;
|
|
765
|
+
const modifiers = [];
|
|
766
|
+
if (ctor.flags?.isProtected)
|
|
767
|
+
modifiers.push('protected');
|
|
768
|
+
if (ctor.flags?.isPrivate)
|
|
769
|
+
modifiers.push('private');
|
|
770
|
+
const desc = sig?.comment?.summary ? this._getCommentText(sig.comment.summary) : '';
|
|
771
|
+
lines.push('<tr><td>');
|
|
772
|
+
lines.push('');
|
|
773
|
+
lines.push(`\`${ctorSig}\``);
|
|
774
|
+
lines.push('');
|
|
775
|
+
lines.push('</td><td>');
|
|
776
|
+
lines.push('');
|
|
777
|
+
lines.push(modifiers.map((m) => `\`${m}\``).join(' '));
|
|
778
|
+
lines.push('');
|
|
779
|
+
lines.push('</td><td>');
|
|
780
|
+
lines.push('');
|
|
781
|
+
lines.push(desc);
|
|
782
|
+
lines.push('');
|
|
783
|
+
lines.push('</td></tr>');
|
|
784
|
+
}
|
|
785
|
+
lines.push('</tbody></table>');
|
|
786
|
+
return lines.join('\n');
|
|
787
|
+
}
|
|
788
|
+
_renderPropertiesTable(members, parentName, _basePath) {
|
|
789
|
+
const lines = [];
|
|
790
|
+
lines.push('<table><thead><tr><th>');
|
|
791
|
+
lines.push('');
|
|
792
|
+
lines.push('Property');
|
|
793
|
+
lines.push('');
|
|
794
|
+
lines.push('</th><th>');
|
|
795
|
+
lines.push('');
|
|
796
|
+
lines.push('Modifiers');
|
|
797
|
+
lines.push('');
|
|
798
|
+
lines.push('</th><th>');
|
|
799
|
+
lines.push('');
|
|
800
|
+
lines.push('Type');
|
|
801
|
+
lines.push('');
|
|
802
|
+
lines.push('</th><th>');
|
|
803
|
+
lines.push('');
|
|
804
|
+
lines.push('Description');
|
|
805
|
+
lines.push('');
|
|
806
|
+
lines.push('</th></tr></thead>');
|
|
807
|
+
lines.push('<tbody>');
|
|
808
|
+
for (const member of members) {
|
|
809
|
+
if (member.kind === ReflectionKind.Accessor) {
|
|
810
|
+
lines.push(this._renderAccessorRow(member, parentName));
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
lines.push(this._renderPropertyRow(member, parentName));
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
lines.push('</tbody></table>');
|
|
817
|
+
return lines.join('\n');
|
|
818
|
+
}
|
|
819
|
+
_renderPropertyRow(prop, parentName) {
|
|
820
|
+
const typeStr = prop.type?.toString() ?? '';
|
|
821
|
+
const modifiers = [];
|
|
822
|
+
if (prop.flags?.isReadonly)
|
|
823
|
+
modifiers.push('readonly');
|
|
824
|
+
if (prop.flags?.isProtected)
|
|
825
|
+
modifiers.push('protected');
|
|
826
|
+
if (prop.flags?.isPrivate)
|
|
827
|
+
modifiers.push('private');
|
|
828
|
+
if (prop.flags?.isStatic)
|
|
829
|
+
modifiers.push('static');
|
|
830
|
+
const desc = prop.comment?.summary ? this._getFirstLine(this._getCommentText(prop.comment.summary)) : '';
|
|
831
|
+
// For inherited members, link to the defining class's detail page (unless includeInheritedMemberPages is true)
|
|
832
|
+
const definingClass = !this._options.includeInheritedMemberPages && prop.inheritedFrom
|
|
833
|
+
? this._sanitizeName(prop.inheritedFrom.reflection?.parent?.name ?? parentName)
|
|
834
|
+
: parentName;
|
|
835
|
+
const detailUrl = `./${this._sanitizeName(definingClass)}.${this._sanitizeName(prop.name)}.md`;
|
|
836
|
+
return this._formatTableRow(prop.name, modifiers, typeStr, desc, detailUrl);
|
|
837
|
+
}
|
|
838
|
+
_renderAccessorRow(accessor, parentName) {
|
|
839
|
+
const getter = accessor.getSignature;
|
|
840
|
+
const setter = accessor.setSignature;
|
|
841
|
+
let typeStr = '';
|
|
842
|
+
if (getter?.type) {
|
|
843
|
+
typeStr = getter.type.toString();
|
|
844
|
+
}
|
|
845
|
+
else if (setter?.parameters?.[0]?.type) {
|
|
846
|
+
typeStr = setter.parameters[0].type.toString();
|
|
847
|
+
}
|
|
848
|
+
const modifiers = [];
|
|
849
|
+
if (getter && !setter)
|
|
850
|
+
modifiers.push('readonly');
|
|
851
|
+
if (accessor.flags?.isProtected)
|
|
852
|
+
modifiers.push('protected');
|
|
853
|
+
if (accessor.flags?.isPrivate)
|
|
854
|
+
modifiers.push('private');
|
|
855
|
+
if (accessor.flags?.isStatic)
|
|
856
|
+
modifiers.push('static');
|
|
857
|
+
let desc = '';
|
|
858
|
+
if (getter?.comment?.summary) {
|
|
859
|
+
desc = this._getFirstLine(this._getCommentText(getter.comment.summary));
|
|
860
|
+
}
|
|
861
|
+
else if (setter?.comment?.summary) {
|
|
862
|
+
desc = this._getFirstLine(this._getCommentText(setter.comment.summary));
|
|
863
|
+
}
|
|
864
|
+
// For inherited members, link to the defining class's detail page (unless includeInheritedMemberPages is true)
|
|
865
|
+
const definingClass = !this._options.includeInheritedMemberPages && accessor.inheritedFrom
|
|
866
|
+
? this._sanitizeName(accessor.inheritedFrom.reflection?.parent?.name ?? parentName)
|
|
867
|
+
: parentName;
|
|
868
|
+
const detailUrl = `./${this._sanitizeName(definingClass)}.${this._sanitizeName(accessor.name)}.md`;
|
|
869
|
+
return this._formatTableRow(accessor.name, modifiers, typeStr, desc, detailUrl);
|
|
870
|
+
}
|
|
871
|
+
_formatTableRow(name, modifiers, type, description, detailUrl) {
|
|
872
|
+
const linkedType = this._linkType(type);
|
|
873
|
+
const modifierStr = modifiers.map((m) => `\`${m}\``).join(' ');
|
|
874
|
+
// Create linked name if detail URL provided
|
|
875
|
+
const nameDisplay = detailUrl ? `[${name}](${detailUrl})` : `\`${name}\``;
|
|
876
|
+
const lines = [];
|
|
877
|
+
lines.push('<tr><td>');
|
|
878
|
+
lines.push('');
|
|
879
|
+
lines.push(nameDisplay);
|
|
880
|
+
lines.push('');
|
|
881
|
+
lines.push('</td><td>');
|
|
882
|
+
lines.push('');
|
|
883
|
+
lines.push(modifierStr);
|
|
884
|
+
lines.push('');
|
|
885
|
+
lines.push('</td><td>');
|
|
886
|
+
lines.push('');
|
|
887
|
+
lines.push(linkedType);
|
|
888
|
+
lines.push('');
|
|
889
|
+
lines.push('</td><td>');
|
|
890
|
+
lines.push('');
|
|
891
|
+
lines.push(description);
|
|
892
|
+
lines.push('');
|
|
893
|
+
lines.push('</td></tr>');
|
|
894
|
+
return lines.join('\n');
|
|
895
|
+
}
|
|
896
|
+
_renderMethodsTable(methods, parentName, _basePath) {
|
|
897
|
+
const lines = [];
|
|
898
|
+
lines.push('<table><thead><tr><th>');
|
|
899
|
+
lines.push('');
|
|
900
|
+
lines.push('Method');
|
|
901
|
+
lines.push('');
|
|
902
|
+
lines.push('</th><th>');
|
|
903
|
+
lines.push('');
|
|
904
|
+
lines.push('Modifiers');
|
|
905
|
+
lines.push('');
|
|
906
|
+
lines.push('</th><th>');
|
|
907
|
+
lines.push('');
|
|
908
|
+
lines.push('Description');
|
|
909
|
+
lines.push('');
|
|
910
|
+
lines.push('</th></tr></thead>');
|
|
911
|
+
lines.push('<tbody>');
|
|
912
|
+
for (const method of methods) {
|
|
913
|
+
const sig = method.signatures?.[0];
|
|
914
|
+
const params = sig?.parameters?.map((p) => p.name).join(', ') ?? '';
|
|
915
|
+
const methodSig = `${method.name}(${params})`;
|
|
916
|
+
const modifiers = [];
|
|
917
|
+
if (method.flags?.isProtected)
|
|
918
|
+
modifiers.push('protected');
|
|
919
|
+
if (method.flags?.isPrivate)
|
|
920
|
+
modifiers.push('private');
|
|
921
|
+
if (method.flags?.isStatic)
|
|
922
|
+
modifiers.push('static');
|
|
923
|
+
const desc = sig?.comment?.summary ? this._getFirstLine(this._getCommentText(sig.comment.summary)) : '';
|
|
924
|
+
// For inherited members, link to the defining class's detail page (unless includeInheritedMemberPages is true)
|
|
925
|
+
const definingClass = !this._options.includeInheritedMemberPages && method.inheritedFrom
|
|
926
|
+
? this._sanitizeName(method.inheritedFrom.reflection?.parent?.name ?? parentName)
|
|
927
|
+
: parentName;
|
|
928
|
+
const detailUrl = `./${this._sanitizeName(definingClass)}.${this._sanitizeName(method.name)}.md`;
|
|
929
|
+
lines.push('<tr><td>');
|
|
930
|
+
lines.push('');
|
|
931
|
+
lines.push(`[${methodSig}](${detailUrl})`);
|
|
932
|
+
lines.push('');
|
|
933
|
+
lines.push('</td><td>');
|
|
934
|
+
lines.push('');
|
|
935
|
+
lines.push(modifiers.map((m) => `\`${m}\``).join(' '));
|
|
936
|
+
lines.push('');
|
|
937
|
+
lines.push('</td><td>');
|
|
938
|
+
lines.push('');
|
|
939
|
+
lines.push(desc);
|
|
940
|
+
lines.push('');
|
|
941
|
+
lines.push('</td></tr>');
|
|
942
|
+
}
|
|
943
|
+
lines.push('</tbody></table>');
|
|
944
|
+
return lines.join('\n');
|
|
945
|
+
}
|
|
946
|
+
_renderSignature(name, sig) {
|
|
947
|
+
const params = sig.parameters?.map((p) => `${p.name}: ${p.type?.toString() ?? 'unknown'}`).join(', ') ?? '';
|
|
948
|
+
const returnType = sig.type?.toString() ?? 'void';
|
|
949
|
+
return `function ${name}(${params}): ${returnType}`;
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Find direct children of a specific kind (no recursion into namespaces).
|
|
953
|
+
*/
|
|
954
|
+
_findByKind(parent, kind) {
|
|
955
|
+
if (!(parent instanceof DeclarationReflection) && !(parent instanceof ProjectReflection)) {
|
|
956
|
+
return [];
|
|
957
|
+
}
|
|
958
|
+
return (parent.children ?? []).filter((child) => child.kind === kind);
|
|
959
|
+
}
|
|
960
|
+
_sanitizeName(name) {
|
|
961
|
+
return name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Generate breadcrumb navigation for a page.
|
|
965
|
+
* @param basePath - The namespace path (e.g., "LibraryRuntime/Indexers")
|
|
966
|
+
* @param currentName - The name of the current item
|
|
967
|
+
* @param subdir - The subdirectory within the namespace (e.g., "classes", "interfaces")
|
|
968
|
+
*/
|
|
969
|
+
_generateBreadcrumb(basePath, currentName, subdir) {
|
|
970
|
+
const parts = [];
|
|
971
|
+
// Calculate how many levels deep we are
|
|
972
|
+
const pathParts = basePath ? basePath.split('/').filter((p) => p) : [];
|
|
973
|
+
const subdirDepth = subdir ? 1 : 0;
|
|
974
|
+
const totalDepth = pathParts.length + subdirDepth;
|
|
975
|
+
// Home link - go up the appropriate number of directories
|
|
976
|
+
const homePrefix = totalDepth > 0 ? '../'.repeat(totalDepth) : './';
|
|
977
|
+
parts.push(`[Home](${homePrefix}README.md)`);
|
|
978
|
+
// Namespace path components
|
|
979
|
+
let accumulatedPath = '';
|
|
980
|
+
for (let i = 0; i < pathParts.length; i++) {
|
|
981
|
+
const nsName = pathParts[i];
|
|
982
|
+
accumulatedPath += (accumulatedPath ? '/' : '') + nsName;
|
|
983
|
+
// Calculate relative path from current location to this namespace
|
|
984
|
+
const levelsUp = totalDepth - (i + 1);
|
|
985
|
+
const nsPrefix = levelsUp > 0 ? '../'.repeat(levelsUp) : './';
|
|
986
|
+
parts.push(`[${nsName}](${nsPrefix}README.md)`);
|
|
987
|
+
}
|
|
988
|
+
// Current item (not linked)
|
|
989
|
+
parts.push(currentName);
|
|
990
|
+
return parts.join(' > ');
|
|
991
|
+
}
|
|
992
|
+
_escapeHtml(str) {
|
|
993
|
+
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
994
|
+
}
|
|
995
|
+
_getCommentText(summary) {
|
|
996
|
+
return summary.map((part) => part.text).join('');
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Compute relative path from current file to target file.
|
|
1000
|
+
*/
|
|
1001
|
+
_relativePath(from, to) {
|
|
1002
|
+
const fromDir = path.dirname(from);
|
|
1003
|
+
return path.relative(fromDir, to);
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Convert a type string to a linked version where possible (for HTML table cells).
|
|
1007
|
+
* Handles generic types like `Map<K, V>` by linking individual type names.
|
|
1008
|
+
*/
|
|
1009
|
+
_linkType(typeStr) {
|
|
1010
|
+
if (!typeStr)
|
|
1011
|
+
return '';
|
|
1012
|
+
// Parse type string and link known types
|
|
1013
|
+
// This regex matches type names (identifiers) that might be linkable
|
|
1014
|
+
const result = typeStr.replace(/\b([A-Z][a-zA-Z0-9_]*)\b/g, (match, typeName) => {
|
|
1015
|
+
const urlInfo = this._urlMap.get(typeName);
|
|
1016
|
+
if (urlInfo) {
|
|
1017
|
+
const relativePath = this._relativePath(this._currentFilePath, urlInfo.url);
|
|
1018
|
+
return `[${typeName}](${relativePath})`;
|
|
1019
|
+
}
|
|
1020
|
+
return match;
|
|
1021
|
+
});
|
|
1022
|
+
return this._escapeHtml(result);
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Convert a type string to a linked version for inline markdown (not in HTML tables).
|
|
1026
|
+
* Returns the type wrapped in backticks, with links if the type is documented.
|
|
1027
|
+
*/
|
|
1028
|
+
_linkTypeInline(typeStr) {
|
|
1029
|
+
if (!typeStr)
|
|
1030
|
+
return '';
|
|
1031
|
+
// Check if the whole type name (without generics) is linkable
|
|
1032
|
+
const baseType = typeStr.split('<')[0].trim();
|
|
1033
|
+
const urlInfo = this._urlMap.get(baseType);
|
|
1034
|
+
if (urlInfo) {
|
|
1035
|
+
const relativePath = this._relativePath(this._currentFilePath, urlInfo.url);
|
|
1036
|
+
return `[\`${typeStr}\`](${relativePath})`;
|
|
1037
|
+
}
|
|
1038
|
+
return `\`${typeStr}\``;
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Set the current file being rendered (for computing relative URLs).
|
|
1042
|
+
*/
|
|
1043
|
+
_setCurrentFile(filePath) {
|
|
1044
|
+
this._currentFilePath = filePath;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Plugin load function - entry point for TypeDoc.
|
|
1049
|
+
*/
|
|
1050
|
+
export function load(app) {
|
|
1051
|
+
// Declare custom option for inherited member pages
|
|
1052
|
+
app.options.addDeclaration({
|
|
1053
|
+
name: 'includeInheritedMemberPages',
|
|
1054
|
+
help: '[Compact Theme] Generate separate detail pages for inherited members instead of linking to parent class',
|
|
1055
|
+
type: ParameterType.Boolean,
|
|
1056
|
+
defaultValue: false
|
|
1057
|
+
});
|
|
1058
|
+
// Read options after bootstrap
|
|
1059
|
+
let outputDir;
|
|
1060
|
+
let includeInheritedMemberPages = false;
|
|
1061
|
+
app.on(Application.EVENT_BOOTSTRAP_END, () => {
|
|
1062
|
+
outputDir = app.options.getValue('out');
|
|
1063
|
+
includeInheritedMemberPages = app.options.getValue('includeInheritedMemberPages');
|
|
1064
|
+
});
|
|
1065
|
+
// Render our markdown after conversion completes, before the renderer runs
|
|
1066
|
+
app.converter.on(Converter.EVENT_RESOLVE_END, (context) => {
|
|
1067
|
+
if (!outputDir) {
|
|
1068
|
+
console.error('[compact-markdown] Output directory not set');
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
// Render using our custom format
|
|
1072
|
+
const options = {
|
|
1073
|
+
includeInheritedMemberPages
|
|
1074
|
+
};
|
|
1075
|
+
const renderer = new CompactMarkdownRenderer(outputDir, options);
|
|
1076
|
+
renderer.renderProject(context.project);
|
|
1077
|
+
console.log(`[compact-markdown] Generated markdown documentation at ${outputDir}`);
|
|
1078
|
+
// Exit before TypeDoc's HTML renderer runs
|
|
1079
|
+
// This is the simplest way to prevent default output without intermediate files
|
|
1080
|
+
process.exit(0);
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
//# sourceMappingURL=index.js.map
|