voluptasmollitia
Version:
Monorepo for the Firebase JavaScript SDK
1,095 lines (972 loc) • 33.8 kB
text/typescript
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
import {
FileSystem,
NewlineKind,
PackageName
} from '@rushstack/node-core-library';
import {
DocSection,
TSDocConfiguration,
StringBuilder,
DocNode,
DocComment,
DocParagraph,
DocPlainText,
DocNodeContainer,
DocLinkTag,
DocFencedCode
} from '@microsoft/tsdoc';
import {
ApiModel,
ApiItem,
ApiItemKind,
ApiReleaseTagMixin,
ReleaseTag,
ApiDocumentedItem,
ApiDeclaredItem,
ApiClass,
ApiPropertyItem,
ApiEnum,
ApiInterface,
ApiParameterListMixin,
ApiReturnTypeMixin,
Excerpt,
ExcerptTokenKind,
IResolveDeclarationReferenceResult,
ApiPackage,
ApiEntryPoint,
ApiNamespace
} from 'api-extractor-model-me';
import { CustomDocNodes } from '../nodes/CustomDocNodeKind';
import { CustomMarkdownEmitter } from '../markdown/CustomMarkdownEmitter';
import { PluginLoader } from '../plugin/PluginLoader';
import {
IMarkdownDocumenterFeatureOnBeforeWritePageArgs,
MarkdownDocumenterFeatureContext
} from '../plugin/MarkdownDocumenterFeature';
import { DocumenterConfig } from './DocumenterConfig';
import { MarkdownDocumenterAccessor } from '../plugin/MarkdownDocumenterAccessor';
import {
getLinkForApiItem,
getFilenameForApiItem,
createBetaWarning,
createRemarksSection,
createTitleCell,
createModifiersCell,
createDescriptionCell,
createEnumTables,
createThrowsSection,
createEntryPointTitleCell,
createExampleSection
} from './MarkdownDocumenterHelpers';
import * as path from 'path';
import { DocHeading } from '../nodes/DocHeading';
import { DocNoteBox } from '../nodes/DocNoteBox';
import { DocTable } from '../nodes/DocTable';
import { DocTableRow } from '../nodes/DocTableRow';
import { DocTableCell } from '../nodes/DocTableCell';
import { DocEmphasisSpan } from '../nodes/DocEmphasisSpan';
export interface IMarkdownDocumenterOptions {
apiModel: ApiModel;
documenterConfig: DocumenterConfig | undefined;
outputFolder: string;
addFileNameSuffix: boolean;
}
/**
* Renders API documentation in the Markdown file format.
* For more info: https://en.wikipedia.org/wiki/Markdown
*/
export class MarkdownDocumenter {
private readonly _apiModel: ApiModel;
private readonly _documenterConfig: DocumenterConfig | undefined;
private readonly _tsdocConfiguration: TSDocConfiguration;
private readonly _markdownEmitter: CustomMarkdownEmitter;
private readonly _outputFolder: string;
private readonly _pluginLoader: PluginLoader;
private readonly _addFileNameSuffix: boolean;
public constructor(options: IMarkdownDocumenterOptions) {
this._apiModel = options.apiModel;
this._documenterConfig = options.documenterConfig;
this._outputFolder = options.outputFolder;
this._addFileNameSuffix = options.addFileNameSuffix;
this._tsdocConfiguration = CustomDocNodes.configuration;
this._markdownEmitter = new CustomMarkdownEmitter(this._apiModel);
this._pluginLoader = new PluginLoader();
}
public generateFiles(): void {
if (this._documenterConfig) {
this._pluginLoader.load(this._documenterConfig, () => {
return new MarkdownDocumenterFeatureContext({
apiModel: this._apiModel,
outputFolder: this._outputFolder,
documenter: new MarkdownDocumenterAccessor({
getLinkForApiItem: (apiItem: ApiItem) => {
return getLinkForApiItem(apiItem, this._addFileNameSuffix);
}
})
});
});
}
this._deleteOldOutputFiles();
this._writeApiItemPage(this._apiModel);
if (this._pluginLoader.markdownDocumenterFeature) {
this._pluginLoader.markdownDocumenterFeature.onFinished({});
}
}
_writeApiItemPage(apiItem: ApiItem): void {
const output: DocSection = new DocSection({
configuration: this._tsdocConfiguration
});
const nodes = this._createCompleteOutputForApiItem(apiItem);
/**
* Remove the heading of the page from md output. (the first item is always a DocHeading)
* Later we will add the heading to the devsite header {% block title %}
*/
const headingNode: DocHeading = nodes[0] as DocHeading;
const pageWithoutHeading = nodes.slice(1);
output.appendNodes(pageWithoutHeading);
// write to file
const filename: string = path.join(
this._outputFolder,
getFilenameForApiItem(apiItem, this._addFileNameSuffix)
);
const stringBuilder: StringBuilder = new StringBuilder();
// devsite headers
stringBuilder.append(
'{% extends "_internal/templates/reference.html" %}\n'
);
stringBuilder.append(
`{% block title %}${headingNode.title}{% endblock title %}\n`
);
stringBuilder.append('{% block body %}\n');
this._markdownEmitter.emit(stringBuilder, output, {
contextApiItem: apiItem,
onGetFilenameForApiItem: (apiItemForFilename: ApiItem) => {
return getLinkForApiItem(apiItemForFilename, this._addFileNameSuffix);
}
});
stringBuilder.append('{% endblock body %}\n');
let pageContent: string = stringBuilder.toString();
if (this._pluginLoader.markdownDocumenterFeature) {
// Allow the plugin to customize the pageContent
const eventArgs: IMarkdownDocumenterFeatureOnBeforeWritePageArgs = {
apiItem: apiItem,
outputFilename: filename,
pageContent: pageContent
};
this._pluginLoader.markdownDocumenterFeature.onBeforeWritePage(eventArgs);
pageContent = eventArgs.pageContent;
}
FileSystem.writeFile(filename, pageContent, {
convertLineEndings: NewlineKind.Lf
});
}
_createCompleteOutputForApiItem(apiItem: ApiItem): DocNode[] {
const configuration = this._tsdocConfiguration;
const output: DocNode[] = [];
const scopedName: string = apiItem.getScopedNameWithinPackage();
switch (apiItem.kind) {
case ApiItemKind.Class:
output.push(
new DocHeading({ configuration, title: `${scopedName} class` })
);
break;
case ApiItemKind.Enum:
output.push(new DocHeading({ configuration, title: `${scopedName}` }));
break;
case ApiItemKind.Interface:
output.push(
new DocHeading({ configuration, title: `${scopedName} interface` })
);
break;
case ApiItemKind.Constructor:
case ApiItemKind.ConstructSignature:
output.push(new DocHeading({ configuration, title: scopedName }));
break;
case ApiItemKind.Method:
case ApiItemKind.MethodSignature:
output.push(new DocHeading({ configuration, title: `${scopedName}` }));
break;
case ApiItemKind.Function:
output.push(new DocHeading({ configuration, title: `${scopedName}` }));
break;
case ApiItemKind.Model:
output.push(new DocHeading({ configuration, title: `API Reference` }));
break;
case ApiItemKind.Namespace:
output.push(
new DocHeading({ configuration, title: `${scopedName} namespace` })
);
break;
case ApiItemKind.Package:
const unscopedPackageName: string = PackageName.getUnscopedName(
apiItem.displayName
);
output.push(
new DocHeading({
configuration,
title: `${unscopedPackageName} package`
})
);
break;
case ApiItemKind.EntryPoint:
const packageName: string = apiItem.parent!.displayName;
output.push(
new DocHeading({
configuration,
title: `${packageName}${
apiItem.displayName && '/' + apiItem.displayName
}`
})
);
break;
case ApiItemKind.Property:
case ApiItemKind.PropertySignature:
output.push(new DocHeading({ configuration, title: `${scopedName}` }));
break;
case ApiItemKind.TypeAlias:
output.push(new DocHeading({ configuration, title: `${scopedName}` }));
break;
case ApiItemKind.Variable:
output.push(new DocHeading({ configuration, title: `${scopedName}` }));
break;
default:
throw new Error('Unsupported API item kind:1 ' + apiItem.kind);
}
if (ApiReleaseTagMixin.isBaseClassOf(apiItem)) {
if (apiItem.releaseTag === ReleaseTag.Beta) {
output.push(createBetaWarning(configuration));
}
}
if (apiItem instanceof ApiDocumentedItem) {
const tsdocComment: DocComment | undefined = apiItem.tsdocComment;
if (tsdocComment) {
if (tsdocComment.deprecatedBlock) {
output.push(
new DocNoteBox({ configuration }, [
new DocParagraph({ configuration }, [
new DocPlainText({
configuration,
text: 'Warning: This API is now obsolete. '
})
]),
...tsdocComment.deprecatedBlock.content.nodes
])
);
}
output.push(...tsdocComment.summarySection.nodes);
}
}
// render remark sections
output.push(...createRemarksSection(apiItem, configuration));
if (apiItem instanceof ApiDeclaredItem) {
output.push(...this._createSignatureSection(apiItem));
}
switch (apiItem.kind) {
case ApiItemKind.Class:
output.push(...this._createClassTables(apiItem as ApiClass));
break;
case ApiItemKind.Enum:
output.push(...createEnumTables(apiItem as ApiEnum, configuration));
break;
case ApiItemKind.Interface:
output.push(...this._createInterfaceTables(apiItem as ApiInterface));
break;
case ApiItemKind.Constructor:
case ApiItemKind.ConstructSignature:
case ApiItemKind.Method:
case ApiItemKind.MethodSignature:
case ApiItemKind.Function:
output.push(
...this._createParameterTables(apiItem as ApiParameterListMixin)
);
output.push(...createThrowsSection(apiItem, configuration));
break;
case ApiItemKind.Namespace:
output.push(
...this._createEntryPointOrNamespace(apiItem as ApiNamespace)
);
break;
case ApiItemKind.Model:
output.push(...this._createModelTable(apiItem as ApiModel));
break;
case ApiItemKind.Package:
output.push(...this._createPackage(apiItem as ApiPackage));
break;
case ApiItemKind.EntryPoint:
output.push(
...this._createEntryPointOrNamespace(apiItem as ApiEntryPoint)
);
break;
case ApiItemKind.Property:
case ApiItemKind.PropertySignature:
break;
case ApiItemKind.TypeAlias:
break;
case ApiItemKind.Variable:
break;
default:
throw new Error('Unsupported API item kind:2 ' + apiItem.kind);
}
output.push(...createExampleSection(apiItem, configuration));
return output;
}
/**
* GENERATE PAGE: CLASS
*
* TODO: generate member references in the same page
*/
private _createClassTables(apiClass: ApiClass): DocNode[] {
const configuration = this._tsdocConfiguration;
const output: DocNode[] = [];
const eventsTable: DocTable = new DocTable({
configuration,
headerTitles: ['Property', 'Modifiers', 'Type', 'Description']
});
const constructorsTable: DocTable = new DocTable({
configuration,
headerTitles: ['Constructor', 'Modifiers', 'Description']
});
const propertiesTable: DocTable = new DocTable({
configuration,
headerTitles: ['Property', 'Modifiers', 'Type', 'Description']
});
const methodsTable: DocTable = new DocTable({
configuration,
headerTitles: ['Method', 'Modifiers', 'Description']
});
const constructorsDefinitions: DocNode[] = [];
const methodsDefinitions: DocNode[] = [];
const propertiesDefinitions: DocNode[] = [];
const eventsDefinitions: DocNode[] = [];
for (const apiMember of apiClass.members) {
switch (apiMember.kind) {
case ApiItemKind.Constructor: {
constructorsTable.addRow(
new DocTableRow({ configuration }, [
createTitleCell(
apiMember,
configuration,
this._addFileNameSuffix
),
createModifiersCell(apiMember, configuration),
createDescriptionCell(apiMember, configuration)
])
);
constructorsDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
break;
}
case ApiItemKind.Method: {
methodsTable.addRow(
new DocTableRow({ configuration }, [
createTitleCell(
apiMember,
configuration,
this._addFileNameSuffix
),
createModifiersCell(apiMember, configuration),
createDescriptionCell(apiMember, configuration)
])
);
methodsDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
break;
}
case ApiItemKind.Property: {
if ((apiMember as ApiPropertyItem).isEventProperty) {
eventsTable.addRow(
new DocTableRow({ configuration }, [
createTitleCell(
apiMember,
configuration,
this._addFileNameSuffix
),
createModifiersCell(apiMember, configuration),
this._createPropertyTypeCell(apiMember),
createDescriptionCell(apiMember, configuration)
])
);
eventsDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
} else {
propertiesTable.addRow(
new DocTableRow({ configuration }, [
createTitleCell(
apiMember,
configuration,
this._addFileNameSuffix
),
createModifiersCell(apiMember, configuration),
this._createPropertyTypeCell(apiMember),
createDescriptionCell(apiMember, configuration)
])
);
propertiesDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
}
break;
}
}
}
if (eventsTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Events' }));
output.push(eventsTable);
}
if (constructorsTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Constructors' }));
output.push(constructorsTable);
}
if (propertiesTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Properties' }));
output.push(propertiesTable);
}
if (methodsTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Methods' }));
output.push(methodsTable);
}
output.push(...eventsDefinitions);
output.push(...constructorsDefinitions);
output.push(...propertiesDefinitions);
output.push(...methodsDefinitions);
return output;
}
/**
* GENERATE PAGE: INTERFACE
*/
private _createInterfaceTables(apiClass: ApiInterface): DocNode[] {
const configuration = this._tsdocConfiguration;
const output: DocNode[] = [];
const eventsTable: DocTable = new DocTable({
configuration,
headerTitles: ['Property', 'Type', 'Description']
});
const propertiesTable: DocTable = new DocTable({
configuration,
headerTitles: ['Property', 'Type', 'Description']
});
const methodsTable: DocTable = new DocTable({
configuration,
headerTitles: ['Method', 'Description']
});
const methodsDefinitions: DocNode[] = [];
const propertiesDefinitions: DocNode[] = [];
const eventsDefinitions: DocNode[] = [];
for (const apiMember of apiClass.members) {
switch (apiMember.kind) {
case ApiItemKind.ConstructSignature:
case ApiItemKind.MethodSignature: {
methodsTable.addRow(
new DocTableRow({ configuration }, [
createTitleCell(
apiMember,
configuration,
this._addFileNameSuffix
),
createDescriptionCell(apiMember, configuration)
])
);
methodsDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
break;
}
case ApiItemKind.PropertySignature: {
if ((apiMember as ApiPropertyItem).isEventProperty) {
eventsTable.addRow(
new DocTableRow({ configuration }, [
createTitleCell(
apiMember,
configuration,
this._addFileNameSuffix
),
this._createPropertyTypeCell(apiMember),
createDescriptionCell(apiMember, configuration)
])
);
eventsDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
} else {
propertiesTable.addRow(
new DocTableRow({ configuration }, [
createTitleCell(
apiMember,
configuration,
this._addFileNameSuffix
),
this._createPropertyTypeCell(apiMember),
createDescriptionCell(apiMember, configuration)
])
);
propertiesDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
}
break;
}
}
}
if (eventsTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Events' }));
output.push(eventsTable);
}
if (propertiesTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Properties' }));
output.push(propertiesTable);
}
if (methodsTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Methods' }));
output.push(methodsTable);
}
output.push(...eventsDefinitions);
output.push(...propertiesDefinitions);
output.push(...methodsDefinitions);
return output;
}
/**
* GENERATE PAGE: FUNCTION-LIKE
*/
private _createParameterTables(
apiParameterListMixin: ApiParameterListMixin
): DocNode[] {
const configuration = this._tsdocConfiguration;
const output: DocNode[] = [];
const parametersTable: DocTable = new DocTable({
configuration,
headerTitles: ['Parameter', 'Type', 'Description']
});
for (const apiParameter of apiParameterListMixin.parameters) {
const parameterDescription: DocSection = new DocSection({
configuration
});
if (apiParameter.tsdocParamBlock) {
parameterDescription.appendNodes(
apiParameter.tsdocParamBlock.content.nodes
);
}
parametersTable.addRow(
new DocTableRow({ configuration }, [
new DocTableCell({ configuration }, [
new DocParagraph({ configuration }, [
new DocPlainText({ configuration, text: apiParameter.name })
])
]),
new DocTableCell({ configuration }, [
this._createParagraphForTypeExcerpt(
apiParameter.parameterTypeExcerpt
)
]),
new DocTableCell({ configuration }, parameterDescription.nodes)
])
);
}
if (parametersTable.rows.length > 0) {
output.push(
new DocHeading({ configuration, title: 'Parameters', level: 2 })
);
output.push(parametersTable);
}
if (ApiReturnTypeMixin.isBaseClassOf(apiParameterListMixin)) {
const returnTypeExcerpt: Excerpt =
apiParameterListMixin.returnTypeExcerpt;
output.push(
new DocParagraph({ configuration }, [
new DocEmphasisSpan({ configuration, bold: true }, [
new DocPlainText({ configuration, text: 'Returns:' })
])
])
);
output.push(this._createParagraphForTypeExcerpt(returnTypeExcerpt));
if (apiParameterListMixin instanceof ApiDocumentedItem) {
if (
apiParameterListMixin.tsdocComment &&
apiParameterListMixin.tsdocComment.returnsBlock
) {
output.push(
...apiParameterListMixin.tsdocComment.returnsBlock.content.nodes
);
}
}
}
return output;
}
private _createParagraphForTypeExcerpt(excerpt: Excerpt): DocParagraph {
const configuration = this._tsdocConfiguration;
const paragraph: DocParagraph = new DocParagraph({ configuration });
if (!excerpt.text.trim()) {
paragraph.appendNode(
new DocPlainText({ configuration, text: '(not declared)' })
);
} else {
this._appendExcerptWithHyperlinks(paragraph, excerpt);
}
return paragraph;
}
private _appendExcerptWithHyperlinks(
docNodeContainer: DocNodeContainer,
excerpt: Excerpt
): void {
const configuration = this._tsdocConfiguration;
for (const token of excerpt.spannedTokens) {
// Markdown doesn't provide a standardized syntax for hyperlinks inside code spans, so we will render
// the type expression as DocPlainText. Instead of creating multiple DocParagraphs, we can simply
// discard any newlines and let the renderer do normal word-wrapping.
const unwrappedTokenText: string = token.text.replace(/[\r\n]+/g, ' ');
// If it's hyperlinkable, then append a DocLinkTag
if (
token.kind === ExcerptTokenKind.Reference &&
token.canonicalReference
) {
const apiItemResult: IResolveDeclarationReferenceResult = this._apiModel.resolveDeclarationReference(
token.canonicalReference,
undefined
);
if (apiItemResult.resolvedApiItem) {
docNodeContainer.appendNode(
new DocLinkTag({
configuration,
tagName: '@link',
linkText: unwrappedTokenText,
urlDestination: getLinkForApiItem(
apiItemResult.resolvedApiItem,
this._addFileNameSuffix
)
})
);
continue;
}
}
// Otherwise append non-hyperlinked text
docNodeContainer.appendNode(
new DocPlainText({ configuration, text: unwrappedTokenText })
);
}
}
/**
* GENERATE PAGE: MODEL
*/
private _createModelTable(apiModel: ApiModel): DocNode[] {
const configuration = this._tsdocConfiguration;
const output: DocNode[] = [];
const packagesTable: DocTable = new DocTable({
configuration,
headerTitles: ['Package', 'Description']
});
for (const apiMember of apiModel.members) {
const row: DocTableRow = new DocTableRow({ configuration }, [
createTitleCell(apiMember, configuration, this._addFileNameSuffix),
createDescriptionCell(apiMember, configuration)
]);
switch (apiMember.kind) {
case ApiItemKind.Package:
packagesTable.addRow(row);
this._writeApiItemPage(apiMember);
break;
}
}
if (packagesTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Packages' }));
output.push(packagesTable);
}
return output;
}
/**´
* Generate a table of entry points if there are more than one entry points.
* Otherwise, generate the entry point directly in the package page.
*/
private _createPackage(apiContainer: ApiPackage): DocNode[] {
const configuration = this._tsdocConfiguration;
const output: DocNode[] = [];
// If a package has a single entry point, generate entry point page in the package page directly
if (apiContainer.entryPoints.length === 1) {
return this._createEntryPointOrNamespace(
apiContainer.members[0] as ApiEntryPoint
);
}
const entryPointsTable: DocTable = new DocTable({
configuration,
headerTitles: ['Entry Point', 'Description']
});
for (const entryPoint of apiContainer.entryPoints) {
const row: DocTableRow = new DocTableRow({ configuration }, [
createEntryPointTitleCell(
entryPoint,
configuration,
this._addFileNameSuffix
),
createDescriptionCell(entryPoint, configuration)
]);
entryPointsTable.addRow(row);
}
output.push(entryPointsTable);
// write entry point pages
for (const entryPoint of apiContainer.entryPoints) {
this._writeApiItemPage(entryPoint);
}
return output;
}
/**
* GENERATE PAGE: ENTRYPOINT or NAMESPACE
*/
private _createEntryPointOrNamespace(
apiContainer: ApiEntryPoint | ApiNamespace
): DocNode[] {
const configuration = this._tsdocConfiguration;
const output: DocNode[] = [];
const classesTable: DocTable = new DocTable({
configuration,
headerTitles: ['Class', 'Description']
});
const enumerationsTable: DocTable = new DocTable({
configuration,
headerTitles: ['Enumeration', 'Description']
});
const functionsTable: DocTable = new DocTable({
configuration,
headerTitles: ['Function', 'Description']
});
const interfacesTable: DocTable = new DocTable({
configuration,
headerTitles: ['Interface', 'Description']
});
const namespacesTable: DocTable = new DocTable({
configuration,
headerTitles: ['Namespace', 'Description']
});
const variablesTable: DocTable = new DocTable({
configuration,
headerTitles: ['Variable', 'Description']
});
const typeAliasesTable: DocTable = new DocTable({
configuration,
headerTitles: ['Type Alias', 'Description']
});
const functionsDefinitions: DocNode[] = [];
const variablesDefinitions: DocNode[] = [];
const typeAliasDefinitions: DocNode[] = [];
const enumsDefinitions: DocNode[] = [];
const apiMembers: ReadonlyArray<ApiItem> =
apiContainer.kind === ApiItemKind.EntryPoint
? (apiContainer as ApiEntryPoint).members
: (apiContainer as ApiNamespace).members;
for (const apiMember of apiMembers) {
const row: DocTableRow = new DocTableRow({ configuration }, [
createTitleCell(apiMember, configuration, this._addFileNameSuffix),
createDescriptionCell(apiMember, configuration)
]);
switch (apiMember.kind) {
case ApiItemKind.Class:
classesTable.addRow(row);
this._writeApiItemPage(apiMember);
break;
case ApiItemKind.Enum:
enumerationsTable.addRow(row);
enumsDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
break;
case ApiItemKind.Interface:
interfacesTable.addRow(row);
this._writeApiItemPage(apiMember);
break;
case ApiItemKind.Namespace:
namespacesTable.addRow(row);
this._writeApiItemPage(apiMember);
break;
case ApiItemKind.Function:
functionsTable.addRow(row);
functionsDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
break;
case ApiItemKind.TypeAlias:
typeAliasesTable.addRow(row);
typeAliasDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
break;
case ApiItemKind.Variable:
variablesTable.addRow(row);
variablesDefinitions.push(
...this._createCompleteOutputForApiItem(apiMember)
);
break;
}
}
if (classesTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Classes' }));
output.push(classesTable);
}
if (enumerationsTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Enumerations' }));
output.push(enumerationsTable);
}
if (functionsTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Functions' }));
output.push(functionsTable);
}
if (interfacesTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Interfaces' }));
output.push(interfacesTable);
}
if (namespacesTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Namespaces' }));
output.push(namespacesTable);
}
if (variablesTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Variables' }));
output.push(variablesTable);
}
if (typeAliasesTable.rows.length > 0) {
output.push(new DocHeading({ configuration, title: 'Type Aliases' }));
output.push(typeAliasesTable);
}
if (functionsDefinitions.length > 0) {
output.push(...functionsDefinitions);
}
if (variablesDefinitions.length > 0) {
output.push(...variablesDefinitions);
}
if (typeAliasDefinitions.length > 0) {
output.push(...typeAliasDefinitions);
}
if (enumsDefinitions.length > 0) {
output.push(...enumsDefinitions);
}
return output;
}
private _createPropertyTypeCell(apiItem: ApiItem): DocTableCell {
const section: DocSection = new DocSection({
configuration: this._tsdocConfiguration
});
if (apiItem instanceof ApiPropertyItem) {
section.appendNode(
this._createParagraphForTypeExcerpt(apiItem.propertyTypeExcerpt)
);
}
return new DocTableCell(
{ configuration: this._tsdocConfiguration },
section.nodes
);
}
private _createSignatureSection(apiItem: ApiDeclaredItem): DocNode[] {
const configuration = this._tsdocConfiguration;
const nodes: DocNode[] = [];
if (apiItem.excerpt.text.length > 0) {
nodes.push(
new DocParagraph({ configuration }, [
new DocEmphasisSpan({ configuration, bold: true }, [
new DocPlainText({ configuration, text: 'Signature:' })
])
])
);
nodes.push(
new DocFencedCode({
configuration,
code: apiItem.getExcerptWithModifiers(),
language: 'typescript'
})
);
}
nodes.push(...this._writeHeritageTypes(apiItem));
return nodes;
}
private _writeHeritageTypes(apiItem: ApiDeclaredItem): DocNode[] {
const configuration = this._tsdocConfiguration;
const nodes: DocNode[] = [];
if (apiItem instanceof ApiClass) {
if (apiItem.extendsType) {
const extendsParagraph: DocParagraph = new DocParagraph(
{ configuration },
[
new DocEmphasisSpan({ configuration, bold: true }, [
new DocPlainText({ configuration, text: 'Extends: ' })
])
]
);
this._appendExcerptWithHyperlinks(
extendsParagraph,
apiItem.extendsType.excerpt
);
nodes.push(extendsParagraph);
}
if (apiItem.implementsTypes.length > 0) {
const implementsParagraph: DocParagraph = new DocParagraph(
{ configuration },
[
new DocEmphasisSpan({ configuration, bold: true }, [
new DocPlainText({ configuration, text: 'Implements: ' })
])
]
);
let needsComma: boolean = false;
for (const implementsType of apiItem.implementsTypes) {
if (needsComma) {
implementsParagraph.appendNode(
new DocPlainText({ configuration, text: ', ' })
);
}
this._appendExcerptWithHyperlinks(
implementsParagraph,
implementsType.excerpt
);
needsComma = true;
}
nodes.push(implementsParagraph);
}
}
if (apiItem instanceof ApiInterface) {
if (apiItem.extendsTypes.length > 0) {
const extendsParagraph: DocParagraph = new DocParagraph(
{ configuration },
[
new DocEmphasisSpan({ configuration, bold: true }, [
new DocPlainText({ configuration, text: 'Extends: ' })
])
]
);
let needsComma: boolean = false;
for (const extendsType of apiItem.extendsTypes) {
if (needsComma) {
extendsParagraph.appendNode(
new DocPlainText({ configuration, text: ', ' })
);
}
this._appendExcerptWithHyperlinks(
extendsParagraph,
extendsType.excerpt
);
needsComma = true;
}
nodes.push(extendsParagraph);
}
}
return nodes;
}
private _deleteOldOutputFiles(): void {
console.log('Deleting old output from ' + this._outputFolder);
FileSystem.ensureEmptyFolder(this._outputFolder);
}
}