UNPKG

50.5 kBJavaScriptView Raw
1"use strict";
2// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3// See LICENSE in the project root for license information.
4var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5 if (k2 === undefined) k2 = k;
6 var desc = Object.getOwnPropertyDescriptor(m, k);
7 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8 desc = { enumerable: true, get: function() { return m[k]; } };
9 }
10 Object.defineProperty(o, k2, desc);
11}) : (function(o, m, k, k2) {
12 if (k2 === undefined) k2 = k;
13 o[k2] = m[k];
14}));
15var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16 Object.defineProperty(o, "default", { enumerable: true, value: v });
17}) : function(o, v) {
18 o["default"] = v;
19});
20var __importStar = (this && this.__importStar) || function (mod) {
21 if (mod && mod.__esModule) return mod;
22 var result = {};
23 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
24 __setModuleDefault(result, mod);
25 return result;
26};
27Object.defineProperty(exports, "__esModule", { value: true });
28exports.MarkdownDocumenter = void 0;
29const path = __importStar(require("path"));
30const node_core_library_1 = require("@rushstack/node-core-library");
31const tsdoc_1 = require("@microsoft/tsdoc");
32const api_extractor_model_1 = require("@microsoft/api-extractor-model");
33const CustomDocNodeKind_1 = require("../nodes/CustomDocNodeKind");
34const DocHeading_1 = require("../nodes/DocHeading");
35const DocTable_1 = require("../nodes/DocTable");
36const DocEmphasisSpan_1 = require("../nodes/DocEmphasisSpan");
37const DocTableRow_1 = require("../nodes/DocTableRow");
38const DocTableCell_1 = require("../nodes/DocTableCell");
39const DocNoteBox_1 = require("../nodes/DocNoteBox");
40const Utilities_1 = require("../utils/Utilities");
41const CustomMarkdownEmitter_1 = require("../markdown/CustomMarkdownEmitter");
42const PluginLoader_1 = require("../plugin/PluginLoader");
43const MarkdownDocumenterFeature_1 = require("../plugin/MarkdownDocumenterFeature");
44const MarkdownDocumenterAccessor_1 = require("../plugin/MarkdownDocumenterAccessor");
45/**
46 * Renders API documentation in the Markdown file format.
47 * For more info: https://en.wikipedia.org/wiki/Markdown
48 */
49class MarkdownDocumenter {
50 constructor(options) {
51 this._apiModel = options.apiModel;
52 this._documenterConfig = options.documenterConfig;
53 this._outputFolder = options.outputFolder;
54 this._tsdocConfiguration = CustomDocNodeKind_1.CustomDocNodes.configuration;
55 this._markdownEmitter = new CustomMarkdownEmitter_1.CustomMarkdownEmitter(this._apiModel);
56 this._pluginLoader = new PluginLoader_1.PluginLoader();
57 }
58 generateFiles() {
59 if (this._documenterConfig) {
60 this._pluginLoader.load(this._documenterConfig, () => {
61 return new MarkdownDocumenterFeature_1.MarkdownDocumenterFeatureContext({
62 apiModel: this._apiModel,
63 outputFolder: this._outputFolder,
64 documenter: new MarkdownDocumenterAccessor_1.MarkdownDocumenterAccessor({
65 getLinkForApiItem: (apiItem) => {
66 return this._getLinkFilenameForApiItem(apiItem);
67 }
68 })
69 });
70 });
71 }
72 console.log();
73 this._deleteOldOutputFiles();
74 this._writeApiItemPage(this._apiModel);
75 if (this._pluginLoader.markdownDocumenterFeature) {
76 this._pluginLoader.markdownDocumenterFeature.onFinished({});
77 }
78 }
79 _writeApiItemPage(apiItem) {
80 const configuration = this._tsdocConfiguration;
81 const output = new tsdoc_1.DocSection({ configuration });
82 this._writeBreadcrumb(output, apiItem);
83 const scopedName = apiItem.getScopedNameWithinPackage();
84 switch (apiItem.kind) {
85 case api_extractor_model_1.ApiItemKind.Class:
86 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `${scopedName} class` }));
87 break;
88 case api_extractor_model_1.ApiItemKind.Enum:
89 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `${scopedName} enum` }));
90 break;
91 case api_extractor_model_1.ApiItemKind.Interface:
92 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `${scopedName} interface` }));
93 break;
94 case api_extractor_model_1.ApiItemKind.Constructor:
95 case api_extractor_model_1.ApiItemKind.ConstructSignature:
96 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: scopedName }));
97 break;
98 case api_extractor_model_1.ApiItemKind.Method:
99 case api_extractor_model_1.ApiItemKind.MethodSignature:
100 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `${scopedName} method` }));
101 break;
102 case api_extractor_model_1.ApiItemKind.Function:
103 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `${scopedName} function` }));
104 break;
105 case api_extractor_model_1.ApiItemKind.Model:
106 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `API Reference` }));
107 break;
108 case api_extractor_model_1.ApiItemKind.Namespace:
109 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `${scopedName} namespace` }));
110 break;
111 case api_extractor_model_1.ApiItemKind.Package:
112 console.log(`Writing ${apiItem.displayName} package`);
113 const unscopedPackageName = node_core_library_1.PackageName.getUnscopedName(apiItem.displayName);
114 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `${unscopedPackageName} package` }));
115 break;
116 case api_extractor_model_1.ApiItemKind.Property:
117 case api_extractor_model_1.ApiItemKind.PropertySignature:
118 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `${scopedName} property` }));
119 break;
120 case api_extractor_model_1.ApiItemKind.TypeAlias:
121 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `${scopedName} type` }));
122 break;
123 case api_extractor_model_1.ApiItemKind.Variable:
124 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: `${scopedName} variable` }));
125 break;
126 default:
127 throw new Error('Unsupported API item kind: ' + apiItem.kind);
128 }
129 if (api_extractor_model_1.ApiReleaseTagMixin.isBaseClassOf(apiItem)) {
130 if (apiItem.releaseTag === api_extractor_model_1.ReleaseTag.Alpha) {
131 this._writeAlphaWarning(output);
132 }
133 else if (apiItem.releaseTag === api_extractor_model_1.ReleaseTag.Beta) {
134 this._writeBetaWarning(output);
135 }
136 }
137 const decoratorBlocks = [];
138 if (apiItem instanceof api_extractor_model_1.ApiDocumentedItem) {
139 const tsdocComment = apiItem.tsdocComment;
140 if (tsdocComment) {
141 decoratorBlocks.push(...tsdocComment.customBlocks.filter((block) => block.blockTag.tagNameWithUpperCase === tsdoc_1.StandardTags.decorator.tagNameWithUpperCase));
142 if (tsdocComment.deprecatedBlock) {
143 output.appendNode(new DocNoteBox_1.DocNoteBox({ configuration }, [
144 new tsdoc_1.DocParagraph({ configuration }, [
145 new tsdoc_1.DocPlainText({
146 configuration,
147 text: 'Warning: This API is now obsolete. '
148 })
149 ]),
150 ...tsdocComment.deprecatedBlock.content.nodes
151 ]));
152 }
153 this._appendSection(output, tsdocComment.summarySection);
154 }
155 }
156 if (apiItem instanceof api_extractor_model_1.ApiDeclaredItem) {
157 if (apiItem.excerpt.text.length > 0) {
158 output.appendNode(new tsdoc_1.DocParagraph({ configuration }, [
159 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, bold: true }, [
160 new tsdoc_1.DocPlainText({ configuration, text: 'Signature:' })
161 ])
162 ]));
163 output.appendNode(new tsdoc_1.DocFencedCode({
164 configuration,
165 code: apiItem.getExcerptWithModifiers(),
166 language: 'typescript'
167 }));
168 }
169 this._writeHeritageTypes(output, apiItem);
170 }
171 if (decoratorBlocks.length > 0) {
172 output.appendNode(new tsdoc_1.DocParagraph({ configuration }, [
173 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, bold: true }, [
174 new tsdoc_1.DocPlainText({ configuration, text: 'Decorators:' })
175 ])
176 ]));
177 for (const decoratorBlock of decoratorBlocks) {
178 output.appendNodes(decoratorBlock.content.nodes);
179 }
180 }
181 let appendRemarks = true;
182 switch (apiItem.kind) {
183 case api_extractor_model_1.ApiItemKind.Class:
184 case api_extractor_model_1.ApiItemKind.Interface:
185 case api_extractor_model_1.ApiItemKind.Namespace:
186 case api_extractor_model_1.ApiItemKind.Package:
187 this._writeRemarksSection(output, apiItem);
188 appendRemarks = false;
189 break;
190 }
191 switch (apiItem.kind) {
192 case api_extractor_model_1.ApiItemKind.Class:
193 this._writeClassTables(output, apiItem);
194 break;
195 case api_extractor_model_1.ApiItemKind.Enum:
196 this._writeEnumTables(output, apiItem);
197 break;
198 case api_extractor_model_1.ApiItemKind.Interface:
199 this._writeInterfaceTables(output, apiItem);
200 break;
201 case api_extractor_model_1.ApiItemKind.Constructor:
202 case api_extractor_model_1.ApiItemKind.ConstructSignature:
203 case api_extractor_model_1.ApiItemKind.Method:
204 case api_extractor_model_1.ApiItemKind.MethodSignature:
205 case api_extractor_model_1.ApiItemKind.Function:
206 this._writeParameterTables(output, apiItem);
207 this._writeThrowsSection(output, apiItem);
208 break;
209 case api_extractor_model_1.ApiItemKind.Namespace:
210 this._writePackageOrNamespaceTables(output, apiItem);
211 break;
212 case api_extractor_model_1.ApiItemKind.Model:
213 this._writeModelTable(output, apiItem);
214 break;
215 case api_extractor_model_1.ApiItemKind.Package:
216 this._writePackageOrNamespaceTables(output, apiItem);
217 break;
218 case api_extractor_model_1.ApiItemKind.Property:
219 case api_extractor_model_1.ApiItemKind.PropertySignature:
220 break;
221 case api_extractor_model_1.ApiItemKind.TypeAlias:
222 break;
223 case api_extractor_model_1.ApiItemKind.Variable:
224 break;
225 default:
226 throw new Error('Unsupported API item kind: ' + apiItem.kind);
227 }
228 if (appendRemarks) {
229 this._writeRemarksSection(output, apiItem);
230 }
231 const filename = path.join(this._outputFolder, this._getFilenameForApiItem(apiItem));
232 const stringBuilder = new tsdoc_1.StringBuilder();
233 stringBuilder.append('<!-- Do not edit this file. It is automatically generated by API Documenter. -->\n\n');
234 this._markdownEmitter.emit(stringBuilder, output, {
235 contextApiItem: apiItem,
236 onGetFilenameForApiItem: (apiItemForFilename) => {
237 return this._getLinkFilenameForApiItem(apiItemForFilename);
238 }
239 });
240 let pageContent = stringBuilder.toString();
241 if (this._pluginLoader.markdownDocumenterFeature) {
242 // Allow the plugin to customize the pageContent
243 const eventArgs = {
244 apiItem: apiItem,
245 outputFilename: filename,
246 pageContent: pageContent
247 };
248 this._pluginLoader.markdownDocumenterFeature.onBeforeWritePage(eventArgs);
249 pageContent = eventArgs.pageContent;
250 }
251 node_core_library_1.FileSystem.writeFile(filename, pageContent, {
252 convertLineEndings: this._documenterConfig ? this._documenterConfig.newlineKind : node_core_library_1.NewlineKind.CrLf
253 });
254 }
255 _writeHeritageTypes(output, apiItem) {
256 const configuration = this._tsdocConfiguration;
257 if (apiItem instanceof api_extractor_model_1.ApiClass) {
258 if (apiItem.extendsType) {
259 const extendsParagraph = new tsdoc_1.DocParagraph({ configuration }, [
260 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, bold: true }, [
261 new tsdoc_1.DocPlainText({ configuration, text: 'Extends: ' })
262 ])
263 ]);
264 this._appendExcerptWithHyperlinks(extendsParagraph, apiItem.extendsType.excerpt);
265 output.appendNode(extendsParagraph);
266 }
267 if (apiItem.implementsTypes.length > 0) {
268 const implementsParagraph = new tsdoc_1.DocParagraph({ configuration }, [
269 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, bold: true }, [
270 new tsdoc_1.DocPlainText({ configuration, text: 'Implements: ' })
271 ])
272 ]);
273 let needsComma = false;
274 for (const implementsType of apiItem.implementsTypes) {
275 if (needsComma) {
276 implementsParagraph.appendNode(new tsdoc_1.DocPlainText({ configuration, text: ', ' }));
277 }
278 this._appendExcerptWithHyperlinks(implementsParagraph, implementsType.excerpt);
279 needsComma = true;
280 }
281 output.appendNode(implementsParagraph);
282 }
283 }
284 if (apiItem instanceof api_extractor_model_1.ApiInterface) {
285 if (apiItem.extendsTypes.length > 0) {
286 const extendsParagraph = new tsdoc_1.DocParagraph({ configuration }, [
287 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, bold: true }, [
288 new tsdoc_1.DocPlainText({ configuration, text: 'Extends: ' })
289 ])
290 ]);
291 let needsComma = false;
292 for (const extendsType of apiItem.extendsTypes) {
293 if (needsComma) {
294 extendsParagraph.appendNode(new tsdoc_1.DocPlainText({ configuration, text: ', ' }));
295 }
296 this._appendExcerptWithHyperlinks(extendsParagraph, extendsType.excerpt);
297 needsComma = true;
298 }
299 output.appendNode(extendsParagraph);
300 }
301 }
302 if (apiItem instanceof api_extractor_model_1.ApiTypeAlias) {
303 const refs = apiItem.excerptTokens.filter((token) => token.kind === api_extractor_model_1.ExcerptTokenKind.Reference &&
304 token.canonicalReference &&
305 this._apiModel.resolveDeclarationReference(token.canonicalReference, undefined).resolvedApiItem);
306 if (refs.length > 0) {
307 const referencesParagraph = new tsdoc_1.DocParagraph({ configuration }, [
308 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, bold: true }, [
309 new tsdoc_1.DocPlainText({ configuration, text: 'References: ' })
310 ])
311 ]);
312 let needsComma = false;
313 const visited = new Set();
314 for (const ref of refs) {
315 if (visited.has(ref.text)) {
316 continue;
317 }
318 visited.add(ref.text);
319 if (needsComma) {
320 referencesParagraph.appendNode(new tsdoc_1.DocPlainText({ configuration, text: ', ' }));
321 }
322 this._appendExcerptTokenWithHyperlinks(referencesParagraph, ref);
323 needsComma = true;
324 }
325 output.appendNode(referencesParagraph);
326 }
327 }
328 }
329 _writeRemarksSection(output, apiItem) {
330 const configuration = this._tsdocConfiguration;
331 if (apiItem instanceof api_extractor_model_1.ApiDocumentedItem) {
332 const tsdocComment = apiItem.tsdocComment;
333 if (tsdocComment) {
334 // Write the @remarks block
335 if (tsdocComment.remarksBlock) {
336 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Remarks' }));
337 this._appendSection(output, tsdocComment.remarksBlock.content);
338 }
339 // Write the @example blocks
340 const exampleBlocks = tsdocComment.customBlocks.filter((x) => x.blockTag.tagNameWithUpperCase === tsdoc_1.StandardTags.example.tagNameWithUpperCase);
341 let exampleNumber = 1;
342 for (const exampleBlock of exampleBlocks) {
343 const heading = exampleBlocks.length > 1 ? `Example ${exampleNumber}` : 'Example';
344 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: heading }));
345 this._appendSection(output, exampleBlock.content);
346 ++exampleNumber;
347 }
348 }
349 }
350 }
351 _writeThrowsSection(output, apiItem) {
352 const configuration = this._tsdocConfiguration;
353 if (apiItem instanceof api_extractor_model_1.ApiDocumentedItem) {
354 const tsdocComment = apiItem.tsdocComment;
355 if (tsdocComment) {
356 // Write the @throws blocks
357 const throwsBlocks = tsdocComment.customBlocks.filter((x) => x.blockTag.tagNameWithUpperCase === tsdoc_1.StandardTags.throws.tagNameWithUpperCase);
358 if (throwsBlocks.length > 0) {
359 const heading = 'Exceptions';
360 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: heading }));
361 for (const throwsBlock of throwsBlocks) {
362 this._appendSection(output, throwsBlock.content);
363 }
364 }
365 }
366 }
367 }
368 /**
369 * GENERATE PAGE: MODEL
370 */
371 _writeModelTable(output, apiModel) {
372 const configuration = this._tsdocConfiguration;
373 const packagesTable = new DocTable_1.DocTable({
374 configuration,
375 headerTitles: ['Package', 'Description']
376 });
377 for (const apiMember of apiModel.members) {
378 const row = new DocTableRow_1.DocTableRow({ configuration }, [
379 this._createTitleCell(apiMember),
380 this._createDescriptionCell(apiMember)
381 ]);
382 switch (apiMember.kind) {
383 case api_extractor_model_1.ApiItemKind.Package:
384 packagesTable.addRow(row);
385 this._writeApiItemPage(apiMember);
386 break;
387 }
388 }
389 if (packagesTable.rows.length > 0) {
390 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Packages' }));
391 output.appendNode(packagesTable);
392 }
393 }
394 /**
395 * GENERATE PAGE: PACKAGE or NAMESPACE
396 */
397 _writePackageOrNamespaceTables(output, apiContainer) {
398 const configuration = this._tsdocConfiguration;
399 const abstractClassesTable = new DocTable_1.DocTable({
400 configuration,
401 headerTitles: ['Abstract Class', 'Description']
402 });
403 const classesTable = new DocTable_1.DocTable({
404 configuration,
405 headerTitles: ['Class', 'Description']
406 });
407 const enumerationsTable = new DocTable_1.DocTable({
408 configuration,
409 headerTitles: ['Enumeration', 'Description']
410 });
411 const functionsTable = new DocTable_1.DocTable({
412 configuration,
413 headerTitles: ['Function', 'Description']
414 });
415 const interfacesTable = new DocTable_1.DocTable({
416 configuration,
417 headerTitles: ['Interface', 'Description']
418 });
419 const namespacesTable = new DocTable_1.DocTable({
420 configuration,
421 headerTitles: ['Namespace', 'Description']
422 });
423 const variablesTable = new DocTable_1.DocTable({
424 configuration,
425 headerTitles: ['Variable', 'Description']
426 });
427 const typeAliasesTable = new DocTable_1.DocTable({
428 configuration,
429 headerTitles: ['Type Alias', 'Description']
430 });
431 const apiMembers = apiContainer.kind === api_extractor_model_1.ApiItemKind.Package
432 ? apiContainer.entryPoints[0].members
433 : apiContainer.members;
434 for (const apiMember of apiMembers) {
435 const row = new DocTableRow_1.DocTableRow({ configuration }, [
436 this._createTitleCell(apiMember),
437 this._createDescriptionCell(apiMember)
438 ]);
439 switch (apiMember.kind) {
440 case api_extractor_model_1.ApiItemKind.Class:
441 if (api_extractor_model_1.ApiAbstractMixin.isBaseClassOf(apiMember) && apiMember.isAbstract) {
442 abstractClassesTable.addRow(row);
443 }
444 else {
445 classesTable.addRow(row);
446 }
447 this._writeApiItemPage(apiMember);
448 break;
449 case api_extractor_model_1.ApiItemKind.Enum:
450 enumerationsTable.addRow(row);
451 this._writeApiItemPage(apiMember);
452 break;
453 case api_extractor_model_1.ApiItemKind.Interface:
454 interfacesTable.addRow(row);
455 this._writeApiItemPage(apiMember);
456 break;
457 case api_extractor_model_1.ApiItemKind.Namespace:
458 namespacesTable.addRow(row);
459 this._writeApiItemPage(apiMember);
460 break;
461 case api_extractor_model_1.ApiItemKind.Function:
462 functionsTable.addRow(row);
463 this._writeApiItemPage(apiMember);
464 break;
465 case api_extractor_model_1.ApiItemKind.TypeAlias:
466 typeAliasesTable.addRow(row);
467 this._writeApiItemPage(apiMember);
468 break;
469 case api_extractor_model_1.ApiItemKind.Variable:
470 variablesTable.addRow(row);
471 this._writeApiItemPage(apiMember);
472 break;
473 }
474 }
475 if (classesTable.rows.length > 0) {
476 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Classes' }));
477 output.appendNode(classesTable);
478 }
479 if (abstractClassesTable.rows.length > 0) {
480 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Abstract Classes' }));
481 output.appendNode(abstractClassesTable);
482 }
483 if (enumerationsTable.rows.length > 0) {
484 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Enumerations' }));
485 output.appendNode(enumerationsTable);
486 }
487 if (functionsTable.rows.length > 0) {
488 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Functions' }));
489 output.appendNode(functionsTable);
490 }
491 if (interfacesTable.rows.length > 0) {
492 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Interfaces' }));
493 output.appendNode(interfacesTable);
494 }
495 if (namespacesTable.rows.length > 0) {
496 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Namespaces' }));
497 output.appendNode(namespacesTable);
498 }
499 if (variablesTable.rows.length > 0) {
500 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Variables' }));
501 output.appendNode(variablesTable);
502 }
503 if (typeAliasesTable.rows.length > 0) {
504 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Type Aliases' }));
505 output.appendNode(typeAliasesTable);
506 }
507 }
508 /**
509 * GENERATE PAGE: CLASS
510 */
511 _writeClassTables(output, apiClass) {
512 const configuration = this._tsdocConfiguration;
513 const eventsTable = new DocTable_1.DocTable({
514 configuration,
515 headerTitles: ['Property', 'Modifiers', 'Type', 'Description']
516 });
517 const constructorsTable = new DocTable_1.DocTable({
518 configuration,
519 headerTitles: ['Constructor', 'Modifiers', 'Description']
520 });
521 const propertiesTable = new DocTable_1.DocTable({
522 configuration,
523 headerTitles: ['Property', 'Modifiers', 'Type', 'Description']
524 });
525 const methodsTable = new DocTable_1.DocTable({
526 configuration,
527 headerTitles: ['Method', 'Modifiers', 'Description']
528 });
529 const apiMembers = this._getMembersAndWriteIncompleteWarning(apiClass, output);
530 for (const apiMember of apiMembers) {
531 const isInherited = apiMember.parent !== apiClass;
532 switch (apiMember.kind) {
533 case api_extractor_model_1.ApiItemKind.Constructor: {
534 constructorsTable.addRow(new DocTableRow_1.DocTableRow({ configuration }, [
535 this._createTitleCell(apiMember),
536 this._createModifiersCell(apiMember),
537 this._createDescriptionCell(apiMember, isInherited)
538 ]));
539 this._writeApiItemPage(apiMember);
540 break;
541 }
542 case api_extractor_model_1.ApiItemKind.Method: {
543 methodsTable.addRow(new DocTableRow_1.DocTableRow({ configuration }, [
544 this._createTitleCell(apiMember),
545 this._createModifiersCell(apiMember),
546 this._createDescriptionCell(apiMember, isInherited)
547 ]));
548 this._writeApiItemPage(apiMember);
549 break;
550 }
551 case api_extractor_model_1.ApiItemKind.Property: {
552 if (apiMember.isEventProperty) {
553 eventsTable.addRow(new DocTableRow_1.DocTableRow({ configuration }, [
554 this._createTitleCell(apiMember),
555 this._createModifiersCell(apiMember),
556 this._createPropertyTypeCell(apiMember),
557 this._createDescriptionCell(apiMember, isInherited)
558 ]));
559 }
560 else {
561 propertiesTable.addRow(new DocTableRow_1.DocTableRow({ configuration }, [
562 this._createTitleCell(apiMember),
563 this._createModifiersCell(apiMember),
564 this._createPropertyTypeCell(apiMember),
565 this._createDescriptionCell(apiMember, isInherited)
566 ]));
567 }
568 this._writeApiItemPage(apiMember);
569 break;
570 }
571 }
572 }
573 if (eventsTable.rows.length > 0) {
574 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Events' }));
575 output.appendNode(eventsTable);
576 }
577 if (constructorsTable.rows.length > 0) {
578 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Constructors' }));
579 output.appendNode(constructorsTable);
580 }
581 if (propertiesTable.rows.length > 0) {
582 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Properties' }));
583 output.appendNode(propertiesTable);
584 }
585 if (methodsTable.rows.length > 0) {
586 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Methods' }));
587 output.appendNode(methodsTable);
588 }
589 }
590 /**
591 * GENERATE PAGE: ENUM
592 */
593 _writeEnumTables(output, apiEnum) {
594 const configuration = this._tsdocConfiguration;
595 const enumMembersTable = new DocTable_1.DocTable({
596 configuration,
597 headerTitles: ['Member', 'Value', 'Description']
598 });
599 for (const apiEnumMember of apiEnum.members) {
600 enumMembersTable.addRow(new DocTableRow_1.DocTableRow({ configuration }, [
601 new DocTableCell_1.DocTableCell({ configuration }, [
602 new tsdoc_1.DocParagraph({ configuration }, [
603 new tsdoc_1.DocPlainText({ configuration, text: Utilities_1.Utilities.getConciseSignature(apiEnumMember) })
604 ])
605 ]),
606 this._createInitializerCell(apiEnumMember),
607 this._createDescriptionCell(apiEnumMember)
608 ]));
609 }
610 if (enumMembersTable.rows.length > 0) {
611 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Enumeration Members' }));
612 output.appendNode(enumMembersTable);
613 }
614 }
615 /**
616 * GENERATE PAGE: INTERFACE
617 */
618 _writeInterfaceTables(output, apiInterface) {
619 const configuration = this._tsdocConfiguration;
620 const eventsTable = new DocTable_1.DocTable({
621 configuration,
622 headerTitles: ['Property', 'Modifiers', 'Type', 'Description']
623 });
624 const propertiesTable = new DocTable_1.DocTable({
625 configuration,
626 headerTitles: ['Property', 'Modifiers', 'Type', 'Description']
627 });
628 const methodsTable = new DocTable_1.DocTable({
629 configuration,
630 headerTitles: ['Method', 'Description']
631 });
632 const apiMembers = this._getMembersAndWriteIncompleteWarning(apiInterface, output);
633 for (const apiMember of apiMembers) {
634 const isInherited = apiMember.parent !== apiInterface;
635 switch (apiMember.kind) {
636 case api_extractor_model_1.ApiItemKind.ConstructSignature:
637 case api_extractor_model_1.ApiItemKind.MethodSignature: {
638 methodsTable.addRow(new DocTableRow_1.DocTableRow({ configuration }, [
639 this._createTitleCell(apiMember),
640 this._createDescriptionCell(apiMember, isInherited)
641 ]));
642 this._writeApiItemPage(apiMember);
643 break;
644 }
645 case api_extractor_model_1.ApiItemKind.PropertySignature: {
646 if (apiMember.isEventProperty) {
647 eventsTable.addRow(new DocTableRow_1.DocTableRow({ configuration }, [
648 this._createTitleCell(apiMember),
649 this._createModifiersCell(apiMember),
650 this._createPropertyTypeCell(apiMember),
651 this._createDescriptionCell(apiMember, isInherited)
652 ]));
653 }
654 else {
655 propertiesTable.addRow(new DocTableRow_1.DocTableRow({ configuration }, [
656 this._createTitleCell(apiMember),
657 this._createModifiersCell(apiMember),
658 this._createPropertyTypeCell(apiMember),
659 this._createDescriptionCell(apiMember, isInherited)
660 ]));
661 }
662 this._writeApiItemPage(apiMember);
663 break;
664 }
665 }
666 }
667 if (eventsTable.rows.length > 0) {
668 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Events' }));
669 output.appendNode(eventsTable);
670 }
671 if (propertiesTable.rows.length > 0) {
672 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Properties' }));
673 output.appendNode(propertiesTable);
674 }
675 if (methodsTable.rows.length > 0) {
676 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Methods' }));
677 output.appendNode(methodsTable);
678 }
679 }
680 /**
681 * GENERATE PAGE: FUNCTION-LIKE
682 */
683 _writeParameterTables(output, apiParameterListMixin) {
684 const configuration = this._tsdocConfiguration;
685 const parametersTable = new DocTable_1.DocTable({
686 configuration,
687 headerTitles: ['Parameter', 'Type', 'Description']
688 });
689 for (const apiParameter of apiParameterListMixin.parameters) {
690 const parameterDescription = new tsdoc_1.DocSection({ configuration });
691 if (apiParameter.isOptional) {
692 parameterDescription.appendNodesInParagraph([
693 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, italic: true }, [
694 new tsdoc_1.DocPlainText({ configuration, text: '(Optional)' })
695 ]),
696 new tsdoc_1.DocPlainText({ configuration, text: ' ' })
697 ]);
698 }
699 if (apiParameter.tsdocParamBlock) {
700 this._appendAndMergeSection(parameterDescription, apiParameter.tsdocParamBlock.content);
701 }
702 parametersTable.addRow(new DocTableRow_1.DocTableRow({ configuration }, [
703 new DocTableCell_1.DocTableCell({ configuration }, [
704 new tsdoc_1.DocParagraph({ configuration }, [
705 new tsdoc_1.DocPlainText({ configuration, text: apiParameter.name })
706 ])
707 ]),
708 new DocTableCell_1.DocTableCell({ configuration }, [
709 this._createParagraphForTypeExcerpt(apiParameter.parameterTypeExcerpt)
710 ]),
711 new DocTableCell_1.DocTableCell({ configuration }, parameterDescription.nodes)
712 ]));
713 }
714 if (parametersTable.rows.length > 0) {
715 output.appendNode(new DocHeading_1.DocHeading({ configuration, title: 'Parameters' }));
716 output.appendNode(parametersTable);
717 }
718 if (api_extractor_model_1.ApiReturnTypeMixin.isBaseClassOf(apiParameterListMixin)) {
719 const returnTypeExcerpt = apiParameterListMixin.returnTypeExcerpt;
720 output.appendNode(new tsdoc_1.DocParagraph({ configuration }, [
721 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, bold: true }, [
722 new tsdoc_1.DocPlainText({ configuration, text: 'Returns:' })
723 ])
724 ]));
725 output.appendNode(this._createParagraphForTypeExcerpt(returnTypeExcerpt));
726 if (apiParameterListMixin instanceof api_extractor_model_1.ApiDocumentedItem) {
727 if (apiParameterListMixin.tsdocComment && apiParameterListMixin.tsdocComment.returnsBlock) {
728 this._appendSection(output, apiParameterListMixin.tsdocComment.returnsBlock.content);
729 }
730 }
731 }
732 }
733 _createParagraphForTypeExcerpt(excerpt) {
734 const configuration = this._tsdocConfiguration;
735 const paragraph = new tsdoc_1.DocParagraph({ configuration });
736 if (!excerpt.text.trim()) {
737 paragraph.appendNode(new tsdoc_1.DocPlainText({ configuration, text: '(not declared)' }));
738 }
739 else {
740 this._appendExcerptWithHyperlinks(paragraph, excerpt);
741 }
742 return paragraph;
743 }
744 _appendExcerptWithHyperlinks(docNodeContainer, excerpt) {
745 for (const token of excerpt.spannedTokens) {
746 this._appendExcerptTokenWithHyperlinks(docNodeContainer, token);
747 }
748 }
749 _appendExcerptTokenWithHyperlinks(docNodeContainer, token) {
750 const configuration = this._tsdocConfiguration;
751 // Markdown doesn't provide a standardized syntax for hyperlinks inside code spans, so we will render
752 // the type expression as DocPlainText. Instead of creating multiple DocParagraphs, we can simply
753 // discard any newlines and let the renderer do normal word-wrapping.
754 const unwrappedTokenText = token.text.replace(/[\r\n]+/g, ' ');
755 // If it's hyperlinkable, then append a DocLinkTag
756 if (token.kind === api_extractor_model_1.ExcerptTokenKind.Reference && token.canonicalReference) {
757 const apiItemResult = this._apiModel.resolveDeclarationReference(token.canonicalReference, undefined);
758 if (apiItemResult.resolvedApiItem) {
759 docNodeContainer.appendNode(new tsdoc_1.DocLinkTag({
760 configuration,
761 tagName: '@link',
762 linkText: unwrappedTokenText,
763 urlDestination: this._getLinkFilenameForApiItem(apiItemResult.resolvedApiItem)
764 }));
765 return;
766 }
767 }
768 // Otherwise append non-hyperlinked text
769 docNodeContainer.appendNode(new tsdoc_1.DocPlainText({ configuration, text: unwrappedTokenText }));
770 }
771 _createTitleCell(apiItem) {
772 const configuration = this._tsdocConfiguration;
773 let linkText = Utilities_1.Utilities.getConciseSignature(apiItem);
774 if (api_extractor_model_1.ApiOptionalMixin.isBaseClassOf(apiItem) && apiItem.isOptional) {
775 linkText += '?';
776 }
777 return new DocTableCell_1.DocTableCell({ configuration }, [
778 new tsdoc_1.DocParagraph({ configuration }, [
779 new tsdoc_1.DocLinkTag({
780 configuration,
781 tagName: '@link',
782 linkText: linkText,
783 urlDestination: this._getLinkFilenameForApiItem(apiItem)
784 })
785 ])
786 ]);
787 }
788 /**
789 * This generates a DocTableCell for an ApiItem including the summary section and "(BETA)" annotation.
790 *
791 * @remarks
792 * We mostly assume that the input is an ApiDocumentedItem, but it's easier to perform this as a runtime
793 * check than to have each caller perform a type cast.
794 */
795 _createDescriptionCell(apiItem, isInherited = false) {
796 const configuration = this._tsdocConfiguration;
797 const section = new tsdoc_1.DocSection({ configuration });
798 if (api_extractor_model_1.ApiReleaseTagMixin.isBaseClassOf(apiItem)) {
799 if (apiItem.releaseTag === api_extractor_model_1.ReleaseTag.Alpha || apiItem.releaseTag === api_extractor_model_1.ReleaseTag.Beta) {
800 section.appendNodesInParagraph([
801 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, bold: true, italic: true }, [
802 new tsdoc_1.DocPlainText({
803 configuration,
804 text: `(${apiItem.releaseTag === api_extractor_model_1.ReleaseTag.Alpha ? 'ALPHA' : 'BETA'})`
805 })
806 ]),
807 new tsdoc_1.DocPlainText({ configuration, text: ' ' })
808 ]);
809 }
810 }
811 if (api_extractor_model_1.ApiOptionalMixin.isBaseClassOf(apiItem) && apiItem.isOptional) {
812 section.appendNodesInParagraph([
813 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, italic: true }, [
814 new tsdoc_1.DocPlainText({ configuration, text: '(Optional)' })
815 ]),
816 new tsdoc_1.DocPlainText({ configuration, text: ' ' })
817 ]);
818 }
819 if (apiItem instanceof api_extractor_model_1.ApiDocumentedItem) {
820 if (apiItem.tsdocComment !== undefined) {
821 this._appendAndMergeSection(section, apiItem.tsdocComment.summarySection);
822 }
823 }
824 if (isInherited && apiItem.parent) {
825 section.appendNode(new tsdoc_1.DocParagraph({ configuration }, [
826 new tsdoc_1.DocPlainText({ configuration, text: '(Inherited from ' }),
827 new tsdoc_1.DocLinkTag({
828 configuration,
829 tagName: '@link',
830 linkText: apiItem.parent.displayName,
831 urlDestination: this._getLinkFilenameForApiItem(apiItem.parent)
832 }),
833 new tsdoc_1.DocPlainText({ configuration, text: ')' })
834 ]));
835 }
836 return new DocTableCell_1.DocTableCell({ configuration }, section.nodes);
837 }
838 _createModifiersCell(apiItem) {
839 const configuration = this._tsdocConfiguration;
840 const section = new tsdoc_1.DocSection({ configuration });
841 // Output modifiers in syntactically correct order: first access modifier (here: `protected`), then
842 // `static` or `abstract` (no member can be both, so the order between the two of them does not matter),
843 // last `readonly`. If `override` was supported, it would go directly before `readonly`.
844 if (api_extractor_model_1.ApiProtectedMixin.isBaseClassOf(apiItem)) {
845 if (apiItem.isProtected) {
846 section.appendNode(new tsdoc_1.DocParagraph({ configuration }, [new tsdoc_1.DocCodeSpan({ configuration, code: 'protected' })]));
847 }
848 }
849 if (api_extractor_model_1.ApiStaticMixin.isBaseClassOf(apiItem)) {
850 if (apiItem.isStatic) {
851 section.appendNode(new tsdoc_1.DocParagraph({ configuration }, [new tsdoc_1.DocCodeSpan({ configuration, code: 'static' })]));
852 }
853 }
854 if (api_extractor_model_1.ApiAbstractMixin.isBaseClassOf(apiItem)) {
855 if (apiItem.isAbstract) {
856 section.appendNode(new tsdoc_1.DocParagraph({ configuration }, [new tsdoc_1.DocCodeSpan({ configuration, code: 'abstract' })]));
857 }
858 }
859 if (api_extractor_model_1.ApiReadonlyMixin.isBaseClassOf(apiItem)) {
860 if (apiItem.isReadonly) {
861 section.appendNode(new tsdoc_1.DocParagraph({ configuration }, [new tsdoc_1.DocCodeSpan({ configuration, code: 'readonly' })]));
862 }
863 }
864 return new DocTableCell_1.DocTableCell({ configuration }, section.nodes);
865 }
866 _createPropertyTypeCell(apiItem) {
867 const configuration = this._tsdocConfiguration;
868 const section = new tsdoc_1.DocSection({ configuration });
869 if (apiItem instanceof api_extractor_model_1.ApiPropertyItem) {
870 section.appendNode(this._createParagraphForTypeExcerpt(apiItem.propertyTypeExcerpt));
871 }
872 return new DocTableCell_1.DocTableCell({ configuration }, section.nodes);
873 }
874 _createInitializerCell(apiItem) {
875 const configuration = this._tsdocConfiguration;
876 const section = new tsdoc_1.DocSection({ configuration });
877 if (api_extractor_model_1.ApiInitializerMixin.isBaseClassOf(apiItem)) {
878 if (apiItem.initializerExcerpt) {
879 section.appendNodeInParagraph(new tsdoc_1.DocCodeSpan({ configuration, code: apiItem.initializerExcerpt.text }));
880 }
881 }
882 return new DocTableCell_1.DocTableCell({ configuration }, section.nodes);
883 }
884 _writeBreadcrumb(output, apiItem) {
885 const configuration = this._tsdocConfiguration;
886 output.appendNodeInParagraph(new tsdoc_1.DocLinkTag({
887 configuration,
888 tagName: '@link',
889 linkText: 'Home',
890 urlDestination: this._getLinkFilenameForApiItem(this._apiModel)
891 }));
892 for (const hierarchyItem of apiItem.getHierarchy()) {
893 switch (hierarchyItem.kind) {
894 case api_extractor_model_1.ApiItemKind.Model:
895 case api_extractor_model_1.ApiItemKind.EntryPoint:
896 // We don't show the model as part of the breadcrumb because it is the root-level container.
897 // We don't show the entry point because today API Extractor doesn't support multiple entry points;
898 // this may change in the future.
899 break;
900 default:
901 output.appendNodesInParagraph([
902 new tsdoc_1.DocPlainText({
903 configuration,
904 text: ' > '
905 }),
906 new tsdoc_1.DocLinkTag({
907 configuration,
908 tagName: '@link',
909 linkText: hierarchyItem.displayName,
910 urlDestination: this._getLinkFilenameForApiItem(hierarchyItem)
911 })
912 ]);
913 }
914 }
915 }
916 _writeAlphaWarning(output) {
917 const configuration = this._tsdocConfiguration;
918 const betaWarning = 'This API is provided as an alpha preview for developers and may change' +
919 ' based on feedback that we receive. Do not use this API in a production environment.';
920 output.appendNode(new DocNoteBox_1.DocNoteBox({ configuration }, [
921 new tsdoc_1.DocParagraph({ configuration }, [new tsdoc_1.DocPlainText({ configuration, text: betaWarning })])
922 ]));
923 }
924 _writeBetaWarning(output) {
925 const configuration = this._tsdocConfiguration;
926 const betaWarning = 'This API is provided as a beta preview for developers and may change' +
927 ' based on feedback that we receive. Do not use this API in a production environment.';
928 output.appendNode(new DocNoteBox_1.DocNoteBox({ configuration }, [
929 new tsdoc_1.DocParagraph({ configuration }, [new tsdoc_1.DocPlainText({ configuration, text: betaWarning })])
930 ]));
931 }
932 _appendSection(output, docSection) {
933 for (const node of docSection.nodes) {
934 output.appendNode(node);
935 }
936 }
937 _appendAndMergeSection(output, docSection) {
938 let firstNode = true;
939 for (const node of docSection.nodes) {
940 if (firstNode) {
941 if (node.kind === tsdoc_1.DocNodeKind.Paragraph) {
942 output.appendNodesInParagraph(node.getChildNodes());
943 firstNode = false;
944 continue;
945 }
946 }
947 firstNode = false;
948 output.appendNode(node);
949 }
950 }
951 _getMembersAndWriteIncompleteWarning(apiClassOrInterface, output) {
952 var _a;
953 const configuration = this._tsdocConfiguration;
954 const showInheritedMembers = !!((_a = this._documenterConfig) === null || _a === void 0 ? void 0 : _a.configFile.showInheritedMembers);
955 if (!showInheritedMembers) {
956 return apiClassOrInterface.members;
957 }
958 const result = apiClassOrInterface.findMembersWithInheritance();
959 // If the result is potentially incomplete, write a short warning communicating this.
960 if (result.maybeIncompleteResult) {
961 output.appendNode(new tsdoc_1.DocParagraph({ configuration }, [
962 new DocEmphasisSpan_1.DocEmphasisSpan({ configuration, italic: true }, [
963 new tsdoc_1.DocPlainText({
964 configuration,
965 text: '(Some inherited members may not be shown because they are not represented in the documentation.)'
966 })
967 ])
968 ]));
969 }
970 // Log the messages for diagnostic purposes.
971 for (const message of result.messages) {
972 console.log(`Diagnostic message for findMembersWithInheritance: ${message.text}`);
973 }
974 return result.items;
975 }
976 _getFilenameForApiItem(apiItem) {
977 if (apiItem.kind === api_extractor_model_1.ApiItemKind.Model) {
978 return 'index.md';
979 }
980 let baseName = '';
981 for (const hierarchyItem of apiItem.getHierarchy()) {
982 // For overloaded methods, add a suffix such as "MyClass.myMethod_2".
983 let qualifiedName = Utilities_1.Utilities.getSafeFilenameForName(hierarchyItem.displayName);
984 if (api_extractor_model_1.ApiParameterListMixin.isBaseClassOf(hierarchyItem)) {
985 if (hierarchyItem.overloadIndex > 1) {
986 // Subtract one for compatibility with earlier releases of API Documenter.
987 // (This will get revamped when we fix GitHub issue #1308)
988 qualifiedName += `_${hierarchyItem.overloadIndex - 1}`;
989 }
990 }
991 switch (hierarchyItem.kind) {
992 case api_extractor_model_1.ApiItemKind.Model:
993 case api_extractor_model_1.ApiItemKind.EntryPoint:
994 case api_extractor_model_1.ApiItemKind.EnumMember:
995 break;
996 case api_extractor_model_1.ApiItemKind.Package:
997 baseName = Utilities_1.Utilities.getSafeFilenameForName(node_core_library_1.PackageName.getUnscopedName(hierarchyItem.displayName));
998 break;
999 default:
1000 baseName += '.' + qualifiedName;
1001 }
1002 }
1003 return baseName + '.md';
1004 }
1005 _getLinkFilenameForApiItem(apiItem) {
1006 return './' + this._getFilenameForApiItem(apiItem);
1007 }
1008 _deleteOldOutputFiles() {
1009 console.log('Deleting old output from ' + this._outputFolder);
1010 node_core_library_1.FileSystem.ensureEmptyFolder(this._outputFolder);
1011 }
1012}
1013exports.MarkdownDocumenter = MarkdownDocumenter;
1014//# sourceMappingURL=MarkdownDocumenter.js.map
\No newline at end of file