feat(website): parse tsdoc comments (#8386)

This commit is contained in:
Suneet Tipirneni
2022-07-29 04:46:17 -04:00
committed by GitHub
parent 26556390a3
commit 33113614e0
13 changed files with 253 additions and 13 deletions

View File

@@ -1,11 +1,12 @@
import type { ApiEnum, ApiModel } from '@microsoft/api-extractor-model';
import { DocItem } from './DocItem';
import { genToken, resolveDocComment, TokenDocumentation } from '~/util/parse.server';
import { CommentNodeContainer } from './comment/CommentNodeContainer';
import { genToken, TokenDocumentation } from '~/util/parse.server';
export interface EnumMemberData {
name: string;
initializerTokens: TokenDocumentation[];
summary: string | null;
summary: ReturnType<DocItem['toJSON']>['summary'];
}
export class DocEnum extends DocItem<ApiEnum> {
@@ -17,7 +18,9 @@ export class DocEnum extends DocItem<ApiEnum> {
this.members = item.members.map((member) => ({
name: member.name,
initializerTokens: member.initializerExcerpt?.spannedTokens.map((token) => genToken(this.model, token)) ?? [],
summary: resolveDocComment(member),
summary: member.tsdocComment
? new CommentNodeContainer(member.tsdocComment.summarySection, model, member).toJSON()
: null,
}));
}

View File

@@ -1,6 +1,7 @@
import type { ApiModel, ApiDeclaredItem } from '@microsoft/api-extractor-model';
import { CommentNodeContainer } from './comment/CommentNodeContainer';
import type { ReferenceData } from '~/util/model.server';
import { resolveName, genReference, resolveDocComment, TokenDocumentation, genToken } from '~/util/parse.server';
import { resolveName, genReference, TokenDocumentation, genToken } from '~/util/parse.server';
export type DocItemConstructor<T = DocItem> = new (...args: any[]) => T;
@@ -8,11 +9,12 @@ export class DocItem<T extends ApiDeclaredItem = ApiDeclaredItem> {
public readonly item: T;
public readonly name: string;
public readonly referenceData: ReferenceData;
public readonly summary: string | null;
public readonly model: ApiModel;
public readonly excerpt: string;
public readonly excerptTokens: TokenDocumentation[] = [];
public readonly kind: string;
public readonly remarks: CommentNodeContainer | null;
public readonly summary: CommentNodeContainer | null;
public constructor(model: ApiModel, item: T) {
this.item = item;
@@ -20,19 +22,25 @@ export class DocItem<T extends ApiDeclaredItem = ApiDeclaredItem> {
this.model = model;
this.name = resolveName(item);
this.referenceData = genReference(item);
this.summary = resolveDocComment(item);
this.excerpt = item.excerpt.text;
this.excerptTokens = item.excerpt.spannedTokens.map((token) => genToken(model, token));
this.remarks = item.tsdocComment?.remarksBlock
? new CommentNodeContainer(item.tsdocComment.remarksBlock.content, model, item.parent)
: null;
this.summary = item.tsdocComment?.summarySection
? new CommentNodeContainer(item.tsdocComment.summarySection, model, item.parent)
: null;
}
public toJSON() {
return {
name: this.name,
referenceData: this.referenceData,
summary: this.summary,
summary: this.summary?.toJSON() ?? null,
excerpt: this.excerpt,
excerptTokens: this.excerptTokens,
kind: this.kind,
remarks: this.remarks?.toJSON() ?? null,
};
}
}

View File

@@ -0,0 +1,22 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocNode } from '@microsoft/tsdoc';
export class CommentNode<T extends DocNode = DocNode> {
public readonly node: T;
public readonly kind: string;
public readonly model: ApiModel;
public readonly parentItem: ApiItem | null;
public constructor(node: T, model: ApiModel, parentItem?: ApiItem) {
this.node = node;
this.kind = node.kind;
this.model = model;
this.parentItem = parentItem ?? null;
}
public toJSON() {
return {
kind: this.kind,
};
}
}

View File

@@ -0,0 +1,20 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocNodeContainer } from '@microsoft/tsdoc';
import { createCommentNode } from '.';
import { CommentNode } from './CommentNode';
export class CommentNodeContainer<T extends DocNodeContainer = DocNodeContainer> extends CommentNode<DocNodeContainer> {
public readonly nodes: CommentNode[];
public constructor(container: T, model: ApiModel, parentItem?: ApiItem) {
super(container, model, parentItem);
this.nodes = container.nodes.map((node) => createCommentNode(node, model, parentItem));
}
public override toJSON() {
return {
...super.toJSON(),
nodes: this.nodes.map((node) => node.toJSON()),
};
}
}

View File

@@ -0,0 +1,22 @@
import type { ApiModel, ApiItem } from '@microsoft/api-extractor-model';
import type { DocFencedCode } from '@microsoft/tsdoc';
import { CommentNode } from './CommentNode';
export class FencedCodeCommentNode extends CommentNode<DocFencedCode> {
public readonly code: string;
public readonly language: string;
public constructor(node: DocFencedCode, model: ApiModel, parentItem?: ApiItem) {
super(node, model, parentItem);
this.code = node.code;
this.language = node.language;
}
public override toJSON() {
return {
...super.toJSON(),
code: this.code,
language: this.language,
};
}
}

View File

@@ -0,0 +1,54 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocDeclarationReference, DocLinkTag } from '@microsoft/tsdoc';
import { CommentNode } from './CommentNode';
import { generatePath, resolveName } from '~/util/parse.server';
export function genToken(
model: ApiModel,
ref: DocDeclarationReference,
context: ApiItem | null,
): LinkTagCodeLink | null {
if (!context) {
return null;
}
const item = model.resolveDeclarationReference(ref, context).resolvedApiItem ?? null;
if (!item) {
return null;
}
return {
name: resolveName(item),
kind: item.kind,
path: generatePath(item.getHierarchy()),
};
}
export interface LinkTagCodeLink {
name: string;
kind: string;
path: string;
}
export class LinkTagCommentNode extends CommentNode<DocLinkTag> {
public readonly codeDestination: LinkTagCodeLink | null;
public readonly text: string | null;
public readonly urlDestination: string | null;
public constructor(node: DocLinkTag, model: ApiModel, parentItem?: ApiItem) {
super(node, model, parentItem);
this.codeDestination = node.codeDestination ? genToken(model, node.codeDestination, this.parentItem) : null;
this.text = node.linkText ?? null;
this.urlDestination = node.urlDestination ?? null;
}
public override toJSON() {
return {
...super.toJSON(),
text: this.text,
codeDestination: this.codeDestination,
urlDestination: this.urlDestination,
};
}
}

View File

@@ -0,0 +1,19 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocPlainText } from '@microsoft/tsdoc';
import { CommentNode } from './CommentNode';
export class PlainTextCommentNode extends CommentNode<DocPlainText> {
public readonly text: string;
public constructor(node: DocPlainText, model: ApiModel, parentItem?: ApiItem) {
super(node, model, parentItem);
this.text = node.text;
}
public override toJSON() {
return {
...super.toJSON(),
text: this.text,
};
}
}

View File

@@ -0,0 +1,22 @@
import type { ApiModel, ApiItem } from '@microsoft/api-extractor-model';
import type { DocNode, DocPlainText, DocLinkTag, DocParagraph, DocFencedCode } from '@microsoft/tsdoc';
import { CommentNode } from './CommentNode';
import { CommentNodeContainer } from './CommentNodeContainer';
import { FencedCodeCommentNode } from './FencedCodeCommentNode';
import { LinkTagCommentNode } from './LinkTagCommentNode';
import { PlainTextCommentNode } from './PlainTextCommentNode';
export function createCommentNode(node: DocNode, model: ApiModel, parentItem?: ApiItem): CommentNode {
switch (node.kind) {
case 'PlainText':
return new PlainTextCommentNode(node as DocPlainText, model, parentItem);
case 'LinkTag':
return new LinkTagCommentNode(node as DocLinkTag, model, parentItem);
case 'Paragraph':
return new CommentNodeContainer(node as DocParagraph, model, parentItem);
case 'FencedCode':
return new FencedCodeCommentNode(node as DocFencedCode, model, parentItem);
default:
return new CommentNode(node, model, parentItem);
}
}