0
# Content Emitters
1
2
Utilities for rendering DocNode trees back to TSDoc markup or extracting plain text content from parsed comments.
3
4
## Capabilities
5
6
### TSDocEmitter
7
8
Renders a DocNode tree back to TSDoc markup, preserving the original comment structure and formatting.
9
10
```typescript { .api }
11
/**
12
* Renders a DocNode tree back to TSDoc markup
13
*/
14
class TSDocEmitter {
15
constructor();
16
17
/** Render any DocNode back to TSDoc format */
18
renderDocNode(docNode: DocNode): string;
19
20
/** Render a complete DocComment back to TSDoc format */
21
renderDocComment(docComment: DocComment): string;
22
}
23
```
24
25
**Usage Examples:**
26
27
```typescript
28
import { TSDocParser, TSDocEmitter } from "@microsoft/tsdoc";
29
30
const parser = new TSDocParser();
31
const emitter = new TSDocEmitter();
32
33
// Parse a comment
34
const context = parser.parseString(`
35
/**
36
* Calculates the area.
37
* @param width - The width value
38
* @param height - The height value
39
* @returns The calculated area
40
* @beta
41
* @example
42
* \`\`\`typescript
43
* const area = calculateArea(10, 20);
44
* console.log(area); // 200
45
* \`\`\`
46
*/
47
`);
48
49
// Render back to TSDoc
50
const renderedComment = emitter.renderDocComment(context.docComment);
51
console.log(renderedComment);
52
53
// Render individual sections
54
const remarksSection = context.docComment.remarksBlock;
55
if (remarksSection) {
56
const renderedRemarks = emitter.renderDocNode(remarksSection);
57
console.log("Remarks:", renderedRemarks);
58
}
59
60
// Render parameter blocks
61
context.docComment.parameterBlocks.forEach(paramBlock => {
62
const renderedParam = emitter.renderDocNode(paramBlock);
63
console.log("Parameter:", renderedParam);
64
});
65
```
66
67
### PlainTextEmitter
68
69
Extracts plain text from a DocNode tree, removing all TSDoc markup and formatting.
70
71
```typescript { .api }
72
/**
73
* Extracts plain text from a DocNode tree, removing markup
74
*/
75
class PlainTextEmitter {
76
constructor();
77
78
/** Extract plain text from any DocNode */
79
renderDocNode(docNode: DocNode): string;
80
81
/** Extract plain text from a complete DocComment */
82
renderDocComment(docComment: DocComment): string;
83
}
84
```
85
86
**Usage Examples:**
87
88
```typescript
89
import { TSDocParser, PlainTextEmitter } from "@microsoft/tsdoc";
90
91
const parser = new TSDocParser();
92
const plainTextEmitter = new PlainTextEmitter();
93
94
// Parse a complex comment with markup
95
const context = parser.parseString(`
96
/**
97
* This method {@link MyClass.helper | helps} with calculations.
98
*
99
* It supports **bold** and \`inline code\` formatting.
100
*
101
* @param value - The input {@link InputType | value}
102
* @returns Processed result
103
*
104
* @example
105
* Here's how to use it:
106
* \`\`\`typescript
107
* const result = process(42);
108
* \`\`\`
109
*/
110
`);
111
112
// Extract plain text (removes all markup)
113
const plainText = plainTextEmitter.renderDocComment(context.docComment);
114
console.log("Plain text:", plainText);
115
// Output: "This method helps with calculations. It supports bold and inline code formatting."
116
117
// Extract plain text from specific sections
118
const summaryText = plainTextEmitter.renderDocNode(context.docComment.summarySection);
119
console.log("Summary:", summaryText);
120
121
// Extract parameter descriptions
122
context.docComment.parameterBlocks.forEach(paramBlock => {
123
const paramText = plainTextEmitter.renderDocNode(paramBlock.content);
124
console.log(`${paramBlock.parameterName}: ${paramText}`);
125
});
126
```
127
128
### StringBuilder
129
130
Utility class for efficiently building strings with append operations. Used internally by emitters but also available for custom rendering logic.
131
132
```typescript { .api }
133
/**
134
* Utility for efficiently building strings
135
*/
136
class StringBuilder implements IStringBuilder {
137
constructor();
138
139
/** Append text to the string being built */
140
append(text: string): void;
141
142
/** Get the final built string */
143
toString(): string;
144
}
145
146
/**
147
* Interface for string building operations
148
*/
149
interface IStringBuilder {
150
/** Append text to the string being built */
151
append(text: string): void;
152
153
/** Get the final built string */
154
toString(): string;
155
}
156
```
157
158
**Usage Examples:**
159
160
```typescript
161
import { StringBuilder } from "@microsoft/tsdoc";
162
163
// Basic string building
164
const builder = new StringBuilder();
165
builder.append("Hello");
166
builder.append(" ");
167
builder.append("world");
168
console.log(builder.toString()); // "Hello world"
169
170
// Building formatted output
171
function formatParameterList(paramBlocks: ReadonlyArray<DocParamBlock>): string {
172
const builder = new StringBuilder();
173
174
builder.append("Parameters:\n");
175
paramBlocks.forEach((param, index) => {
176
builder.append(` ${index + 1}. ${param.parameterName}\n`);
177
});
178
179
return builder.toString();
180
}
181
182
// Custom rendering with StringBuilder
183
function renderCustomSummary(docComment: DocComment): string {
184
const builder = new StringBuilder();
185
const plainEmitter = new PlainTextEmitter();
186
187
// Extract summary text
188
const summaryText = plainEmitter.renderDocNode(docComment.summarySection);
189
builder.append("Summary: ");
190
builder.append(summaryText);
191
192
// Add parameter count
193
if (docComment.parameterBlocks.length > 0) {
194
builder.append(`\nParameters: ${docComment.parameterBlocks.length}`);
195
}
196
197
// Add modifiers
198
const modifiers = docComment.modifierTagSet;
199
if (modifiers.isBeta) {
200
builder.append("\n[BETA API]");
201
}
202
if (modifiers.isDeprecated) {
203
builder.append("\n[DEPRECATED]");
204
}
205
206
return builder.toString();
207
}
208
```
209
210
## Advanced Emitter Usage
211
212
### Custom Rendering Logic
213
214
Create custom rendering by combining emitters with AST traversal:
215
216
```typescript
217
import {
218
TSDocParser,
219
TSDocEmitter,
220
PlainTextEmitter,
221
DocNode,
222
DocCodeSpan,
223
DocFencedCode,
224
DocLinkTag
225
} from "@microsoft/tsdoc";
226
227
class CustomMarkdownEmitter {
228
private tsdocEmitter = new TSDocEmitter();
229
private plainEmitter = new PlainTextEmitter();
230
231
renderAsMarkdown(docComment: DocComment): string {
232
const builder = new StringBuilder();
233
234
// Render summary as markdown
235
const summaryText = this.plainEmitter.renderDocNode(docComment.summarySection);
236
builder.append(`## Summary\n\n${summaryText}\n\n`);
237
238
// Render parameters
239
if (docComment.parameterBlocks.length > 0) {
240
builder.append("## Parameters\n\n");
241
docComment.parameterBlocks.forEach(param => {
242
const description = this.plainEmitter.renderDocNode(param.content);
243
builder.append(`- **${param.parameterName}**: ${description}\n`);
244
});
245
builder.append("\n");
246
}
247
248
// Render examples
249
if (docComment.exampleBlocks.length > 0) {
250
builder.append("## Examples\n\n");
251
docComment.exampleBlocks.forEach((example, index) => {
252
const exampleText = this.extractCodeBlocks(example.content);
253
builder.append(`### Example ${index + 1}\n\n${exampleText}\n\n`);
254
});
255
}
256
257
return builder.toString();
258
}
259
260
private extractCodeBlocks(section: DocSection): string {
261
// Custom logic to find and format code blocks
262
const builder = new StringBuilder();
263
264
const findCodeNodes = (node: DocNode): void => {
265
if (node instanceof DocFencedCode) {
266
builder.append(`\`\`\`${node.language}\n${node.code}\n\`\`\`\n`);
267
} else if (node instanceof DocCodeSpan) {
268
builder.append(`\`${node.code}\`\n`);
269
}
270
271
for (const child of node.getChildNodes()) {
272
if (child) {
273
findCodeNodes(child);
274
}
275
}
276
};
277
278
findCodeNodes(section);
279
return builder.toString();
280
}
281
}
282
283
// Usage
284
const parser = new TSDocParser();
285
const customEmitter = new CustomMarkdownEmitter();
286
287
const context = parser.parseString("/** ... */");
288
const markdown = customEmitter.renderAsMarkdown(context.docComment);
289
```
290
291
### Selective Content Extraction
292
293
Extract specific types of content from comments:
294
295
```typescript
296
class ContentExtractor {
297
private plainEmitter = new PlainTextEmitter();
298
299
/** Extract all code examples from a comment */
300
extractCodeExamples(docComment: DocComment): string[] {
301
const examples: string[] = [];
302
303
const extractFromNode = (node: DocNode): void => {
304
if (node instanceof DocFencedCode) {
305
examples.push(node.code);
306
}
307
308
for (const child of node.getChildNodes()) {
309
if (child) {
310
extractFromNode(child);
311
}
312
}
313
};
314
315
// Extract from example blocks
316
docComment.exampleBlocks.forEach(block => {
317
extractFromNode(block.content);
318
});
319
320
return examples;
321
}
322
323
/** Extract all @see references */
324
extractSeeReferences(docComment: DocComment): string[] {
325
return docComment.seeBlocks.map(block =>
326
this.plainEmitter.renderDocNode(block.content).trim()
327
);
328
}
329
330
/** Extract parameter information */
331
extractParameterInfo(docComment: DocComment): Array<{name: string, description: string}> {
332
return docComment.parameterBlocks.map(param => ({
333
name: param.parameterName,
334
description: this.plainEmitter.renderDocNode(param.content).trim()
335
}));
336
}
337
338
/** Get API stability information */
339
getStabilityInfo(docComment: DocComment): {
340
stability: 'stable' | 'beta' | 'alpha' | 'experimental' | 'deprecated';
341
isInternal: boolean;
342
} {
343
const modifiers = docComment.modifierTagSet;
344
345
let stability: 'stable' | 'beta' | 'alpha' | 'experimental' | 'deprecated' = 'stable';
346
347
if (modifiers.isAlpha) stability = 'alpha';
348
else if (modifiers.isBeta) stability = 'beta';
349
else if (modifiers.isExperimental) stability = 'experimental';
350
else if (docComment.deprecatedBlock) stability = 'deprecated';
351
352
return {
353
stability,
354
isInternal: modifiers.isInternal
355
};
356
}
357
}
358
```