From 7116647947e413da59fbf493ed5251ddcd710ce7 Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Tue, 16 Aug 2022 10:33:49 -0400 Subject: [PATCH] feat(website): render tsdoc examples (#8494) --- packages/website/src/DocModel/DocEnum.ts | 6 +- packages/website/src/DocModel/DocItem.ts | 19 ++- .../src/DocModel/comment/CommentBlock.ts | 18 +++ .../src/DocModel/comment/CommentBlockTag.ts | 13 ++ .../src/DocModel/comment/CommentCodeSpan.ts | 13 ++ .../src/DocModel/comment/CommentNode.ts | 46 ++++--- .../DocModel/comment/CommentNodeContainer.ts | 29 ++-- .../DocModel/comment/FencedCodeCommentNode.ts | 31 ++--- .../DocModel/comment/LinkTagCommentNode.ts | 38 +++--- .../DocModel/comment/PlainTextCommentNode.ts | 26 ++-- .../src/DocModel/comment/RootComment.ts | 20 +++ .../website/src/DocModel/comment/index.ts | 53 +++++--- .../website/src/components/CodeListing.tsx | 8 +- packages/website/src/components/Comment.tsx | 85 ------------ .../website/src/components/DocContainer.tsx | 6 +- .../website/src/components/MethodItem.tsx | 5 +- .../website/src/components/PropertyList.tsx | 8 +- .../website/src/components/model/Class.tsx | 1 + .../src/components/tsdoc/BlockComment.tsx | 40 ++++++ .../website/src/components/tsdoc/TSDoc.tsx | 124 ++++++++++++++++++ packages/ws/src/utils/utils.ts | 1 + packages/ws/src/ws/WebSocketManager.ts | 1 + 22 files changed, 382 insertions(+), 209 deletions(-) create mode 100644 packages/website/src/DocModel/comment/CommentBlock.ts create mode 100644 packages/website/src/DocModel/comment/CommentBlockTag.ts create mode 100644 packages/website/src/DocModel/comment/CommentCodeSpan.ts create mode 100644 packages/website/src/DocModel/comment/RootComment.ts delete mode 100644 packages/website/src/components/Comment.tsx create mode 100644 packages/website/src/components/tsdoc/BlockComment.tsx create mode 100644 packages/website/src/components/tsdoc/TSDoc.tsx diff --git a/packages/website/src/DocModel/DocEnum.ts b/packages/website/src/DocModel/DocEnum.ts index 6b6e649a7..c2b7fcb69 100644 --- a/packages/website/src/DocModel/DocEnum.ts +++ b/packages/website/src/DocModel/DocEnum.ts @@ -1,6 +1,6 @@ import type { ApiEnum, ApiModel } from '@microsoft/api-extractor-model'; import { DocItem } from './DocItem'; -import { CommentNodeContainer } from './comment/CommentNodeContainer'; +import { nodeContainer } from './comment/CommentNodeContainer'; import { genToken, TokenDocumentation } from '~/util/parse.server'; export interface EnumMemberData { @@ -18,9 +18,7 @@ export class DocEnum extends DocItem { this.members = item.members.map((member) => ({ name: member.name, initializerTokens: member.initializerExcerpt?.spannedTokens.map((token) => genToken(this.model, token)) ?? [], - summary: member.tsdocComment - ? new CommentNodeContainer(member.tsdocComment.summarySection, model, member).toJSON() - : null, + summary: member.tsdocComment ? nodeContainer(member.tsdocComment.summarySection, model, member) : null, })); } diff --git a/packages/website/src/DocModel/DocItem.ts b/packages/website/src/DocModel/DocItem.ts index 062f3c2c2..e11a337e0 100644 --- a/packages/website/src/DocModel/DocItem.ts +++ b/packages/website/src/DocModel/DocItem.ts @@ -1,5 +1,7 @@ import type { ApiModel, ApiDeclaredItem } from '@microsoft/api-extractor-model'; -import { CommentNodeContainer } from './comment/CommentNodeContainer'; +import { createCommentNode } from './comment'; +import type { AnyDocNodeJSON } from './comment/CommentNode'; +import type { DocNodeContainerJSON } from './comment/CommentNodeContainer'; import type { ReferenceData } from '~/util/model.server'; import { resolveName, genReference, TokenDocumentation, genToken } from '~/util/parse.server'; @@ -13,9 +15,10 @@ export class DocItem { public readonly excerpt: string; public readonly excerptTokens: TokenDocumentation[] = []; public readonly kind: string; - public readonly remarks: CommentNodeContainer | null; - public readonly summary: CommentNodeContainer | null; + public readonly remarks: DocNodeContainerJSON | null; + public readonly summary: DocNodeContainerJSON | null; public readonly containerKey: string; + public readonly comment: AnyDocNodeJSON | null; public constructor(model: ApiModel, item: T) { this.item = item; @@ -26,12 +29,13 @@ export class DocItem { 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) + ? (createCommentNode(item.tsdocComment.remarksBlock, model, item.parent) as DocNodeContainerJSON) : null; this.summary = item.tsdocComment?.summarySection - ? new CommentNodeContainer(item.tsdocComment.summarySection, model, item.parent) + ? (createCommentNode(item.tsdocComment.summarySection, model, item.parent) as DocNodeContainerJSON) : null; this.containerKey = item.containerKey; + this.comment = item.tsdocComment ? createCommentNode(item.tsdocComment, model, item.parent) : null; } public get path() { @@ -54,13 +58,14 @@ export class DocItem { return { name: this.name, referenceData: this.referenceData, - summary: this.summary?.toJSON() ?? null, + summary: this.summary, excerpt: this.excerpt, excerptTokens: this.excerptTokens, kind: this.kind, - remarks: this.remarks?.toJSON() ?? null, + remarks: this.remarks, path: this.path, containerKey: this.containerKey, + comment: this.comment, }; } } diff --git a/packages/website/src/DocModel/comment/CommentBlock.ts b/packages/website/src/DocModel/comment/CommentBlock.ts new file mode 100644 index 000000000..8d7f88db3 --- /dev/null +++ b/packages/website/src/DocModel/comment/CommentBlock.ts @@ -0,0 +1,18 @@ +import type { ApiModel, ApiItem } from '@microsoft/api-extractor-model'; +import type { DocBlock } from '@microsoft/tsdoc'; +import { createCommentNode } from '.'; +import { blockTag, DocBlockTagJSON } from './CommentBlockTag'; +import { AnyDocNodeJSON, DocNodeJSON, node } from './CommentNode'; + +export interface DocBlockJSON extends DocNodeJSON { + content: AnyDocNodeJSON[]; + tag: DocBlockTagJSON; +} + +export function block(block: DocBlock, model: ApiModel, parentItem?: ApiItem) { + return { + ...node(block), + content: block.content.nodes.map((node) => createCommentNode(node, model, parentItem)), + tag: blockTag(block.blockTag), + }; +} diff --git a/packages/website/src/DocModel/comment/CommentBlockTag.ts b/packages/website/src/DocModel/comment/CommentBlockTag.ts new file mode 100644 index 000000000..608188316 --- /dev/null +++ b/packages/website/src/DocModel/comment/CommentBlockTag.ts @@ -0,0 +1,13 @@ +import type { DocBlockTag } from '@microsoft/tsdoc'; +import { type DocNodeJSON, node } from './CommentNode'; + +export interface DocBlockTagJSON extends DocNodeJSON { + tagName: string; +} + +export function blockTag(blockTag: DocBlockTag): DocBlockTagJSON { + return { + ...node(blockTag), + tagName: blockTag.tagName, + }; +} diff --git a/packages/website/src/DocModel/comment/CommentCodeSpan.ts b/packages/website/src/DocModel/comment/CommentCodeSpan.ts new file mode 100644 index 000000000..450656318 --- /dev/null +++ b/packages/website/src/DocModel/comment/CommentCodeSpan.ts @@ -0,0 +1,13 @@ +import type { DocCodeSpan } from '@microsoft/tsdoc'; +import { DocNodeJSON, node } from './CommentNode'; + +export interface DocCodeSpanJSON extends DocNodeJSON { + code: string; +} + +export function codeSpan(codeSpan: DocCodeSpan): DocCodeSpanJSON { + return { + ...node(codeSpan), + code: codeSpan.code, + }; +} diff --git a/packages/website/src/DocModel/comment/CommentNode.ts b/packages/website/src/DocModel/comment/CommentNode.ts index bcaf74a5a..838676c7c 100644 --- a/packages/website/src/DocModel/comment/CommentNode.ts +++ b/packages/website/src/DocModel/comment/CommentNode.ts @@ -1,22 +1,28 @@ -import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model'; -import type { DocNode } from '@microsoft/tsdoc'; +import type { DocNode, DocNodeKind } from '@microsoft/tsdoc'; +import type { DocBlockJSON } from './CommentBlock'; +import type { DocCodeSpanJSON } from './CommentCodeSpan'; +import type { DocNodeContainerJSON } from './CommentNodeContainer'; +import type { DocFencedCodeJSON } from './FencedCodeCommentNode'; +import type { DocLinkTagJSON } from './LinkTagCommentNode'; +import type { DocPlainTextJSON } from './PlainTextCommentNode'; +import type { DocCommentJSON } from './RootComment'; -export class CommentNode { - 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, - }; - } +export interface DocNodeJSON { + kind: DocNodeKind; +} + +export type AnyDocNodeJSON = + | DocNodeJSON + | DocPlainTextJSON + | DocNodeContainerJSON + | DocLinkTagJSON + | DocFencedCodeJSON + | DocBlockJSON + | DocCommentJSON + | DocCodeSpanJSON; + +export function node(node: DocNode): DocNodeJSON { + return { + kind: node.kind as DocNodeKind, + }; } diff --git a/packages/website/src/DocModel/comment/CommentNodeContainer.ts b/packages/website/src/DocModel/comment/CommentNodeContainer.ts index 8ca4210df..bcd513a24 100644 --- a/packages/website/src/DocModel/comment/CommentNodeContainer.ts +++ b/packages/website/src/DocModel/comment/CommentNodeContainer.ts @@ -1,20 +1,19 @@ import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model'; import type { DocNodeContainer } from '@microsoft/tsdoc'; import { createCommentNode } from '.'; -import { CommentNode } from './CommentNode'; +import { AnyDocNodeJSON, DocNodeJSON, node } from './CommentNode'; -export class CommentNodeContainer extends CommentNode { - 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()), - }; - } +export interface DocNodeContainerJSON extends DocNodeJSON { + nodes: AnyDocNodeJSON[]; +} + +export function nodeContainer( + container: DocNodeContainer, + model: ApiModel, + parentItem?: ApiItem, +): DocNodeContainerJSON { + return { + ...node(container), + nodes: container.nodes.map((node) => createCommentNode(node, model, parentItem)), + }; } diff --git a/packages/website/src/DocModel/comment/FencedCodeCommentNode.ts b/packages/website/src/DocModel/comment/FencedCodeCommentNode.ts index 11f7f3e0b..5cc8edd3f 100644 --- a/packages/website/src/DocModel/comment/FencedCodeCommentNode.ts +++ b/packages/website/src/DocModel/comment/FencedCodeCommentNode.ts @@ -1,22 +1,15 @@ -import type { ApiModel, ApiItem } from '@microsoft/api-extractor-model'; import type { DocFencedCode } from '@microsoft/tsdoc'; -import { CommentNode } from './CommentNode'; +import { DocNodeJSON, node } from './CommentNode'; -export class FencedCodeCommentNode extends CommentNode { - 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, - }; - } +export interface DocFencedCodeJSON extends DocNodeJSON { + code: string; + language: string; +} + +export function fencedCode(fencedCode: DocFencedCode) { + return { + ...node(fencedCode), + language: fencedCode.language, + code: fencedCode.code, + }; } diff --git a/packages/website/src/DocModel/comment/LinkTagCommentNode.ts b/packages/website/src/DocModel/comment/LinkTagCommentNode.ts index 7b1253d38..bfcb105ff 100644 --- a/packages/website/src/DocModel/comment/LinkTagCommentNode.ts +++ b/packages/website/src/DocModel/comment/LinkTagCommentNode.ts @@ -1,8 +1,14 @@ import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model'; import type { DocDeclarationReference, DocLinkTag } from '@microsoft/tsdoc'; -import { CommentNode } from './CommentNode'; +import { DocNodeJSON, node } from './CommentNode'; import { generatePath, resolveName } from '~/util/parse.server'; +export interface DocLinkTagJSON extends DocNodeJSON { + text: string | null; + codeDestination: LinkTagCodeLink | null; + urlDestination: string | null; +} + export function genToken( model: ApiModel, ref: DocDeclarationReference, @@ -31,24 +37,16 @@ export interface LinkTagCodeLink { path: string; } -export class LinkTagCommentNode extends CommentNode { - public readonly codeDestination: LinkTagCodeLink | null; - public readonly text: string | null; - public readonly urlDestination: string | null; +export function linkTagNode(linkNode: DocLinkTag, model: ApiModel, parentItem?: ApiItem): DocLinkTagJSON { + const codeDestination = + linkNode.codeDestination && parentItem ? genToken(model, linkNode.codeDestination, parentItem) : null; + const text = linkNode.linkText ?? null; + const urlDestination = linkNode.urlDestination ?? 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, - }; - } + return { + ...node(linkNode), + text, + codeDestination, + urlDestination, + }; } diff --git a/packages/website/src/DocModel/comment/PlainTextCommentNode.ts b/packages/website/src/DocModel/comment/PlainTextCommentNode.ts index 37f960717..7f1217748 100644 --- a/packages/website/src/DocModel/comment/PlainTextCommentNode.ts +++ b/packages/website/src/DocModel/comment/PlainTextCommentNode.ts @@ -1,19 +1,13 @@ -import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model'; import type { DocPlainText } from '@microsoft/tsdoc'; -import { CommentNode } from './CommentNode'; +import { DocNodeJSON, node } from './CommentNode'; -export class PlainTextCommentNode extends CommentNode { - 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, - }; - } +export interface DocPlainTextJSON extends DocNodeJSON { + text: string; +} + +export function plainTextNode(plainTextNode: DocPlainText): DocPlainTextJSON { + return { + ...node(plainTextNode), + text: plainTextNode.text, + }; } diff --git a/packages/website/src/DocModel/comment/RootComment.ts b/packages/website/src/DocModel/comment/RootComment.ts new file mode 100644 index 000000000..5ac2a4a15 --- /dev/null +++ b/packages/website/src/DocModel/comment/RootComment.ts @@ -0,0 +1,20 @@ +import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model'; +import type { DocComment } from '@microsoft/tsdoc'; +import { createCommentNode } from '.'; +import { block, DocBlockJSON } from './CommentBlock'; +import { DocNodeJSON, node } from './CommentNode'; + +export interface DocCommentJSON extends DocNodeJSON { + summary: DocNodeJSON[]; + remarks: DocNodeJSON[]; + customBlocks: DocBlockJSON[]; +} + +export function comment(comment: DocComment, model: ApiModel, parentItem?: ApiItem): DocCommentJSON { + return { + ...node(comment), + summary: comment.summarySection.nodes.map((node) => createCommentNode(node, model, parentItem)), + remarks: comment.remarksBlock?.content.nodes.map((node) => createCommentNode(node, model, parentItem)) ?? [], + customBlocks: comment.customBlocks.map((_block) => block(_block, model, parentItem)), + }; +} diff --git a/packages/website/src/DocModel/comment/index.ts b/packages/website/src/DocModel/comment/index.ts index 641e61aeb..a60a46caf 100644 --- a/packages/website/src/DocModel/comment/index.ts +++ b/packages/website/src/DocModel/comment/index.ts @@ -1,22 +1,43 @@ 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'; +import { + type DocNode, + type DocPlainText, + type DocLinkTag, + type DocParagraph, + type DocFencedCode, + DocNodeKind, + type DocBlock, + DocComment, + DocCodeSpan, +} from '@microsoft/tsdoc'; +import { block } from './CommentBlock'; +import { codeSpan } from './CommentCodeSpan'; +import type { AnyDocNodeJSON } from './CommentNode'; +import { node as _node } from './CommentNode'; +import { nodeContainer } from './CommentNodeContainer'; +import { fencedCode } from './FencedCodeCommentNode'; +import { linkTagNode } from './LinkTagCommentNode'; +import { plainTextNode } from './PlainTextCommentNode'; +import { comment } from './RootComment'; -export function createCommentNode(node: DocNode, model: ApiModel, parentItem?: ApiItem): CommentNode { +export function createCommentNode(node: DocNode, model: ApiModel, parentItem?: ApiItem): AnyDocNodeJSON { 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); + case DocNodeKind.PlainText: + return plainTextNode(node as DocPlainText); + case DocNodeKind.LinkTag: + return linkTagNode(node as DocLinkTag, model, parentItem); + case DocNodeKind.Paragraph: + case DocNodeKind.Section: + return nodeContainer(node as DocParagraph, model, parentItem); + case DocNodeKind.FencedCode: + return fencedCode(node as DocFencedCode); + case DocNodeKind.CodeSpan: + return codeSpan(node as DocCodeSpan); + case DocNodeKind.Block: + return block(node as DocBlock, model, parentItem); + case DocNodeKind.Comment: + return comment(node as DocComment, model, parentItem); default: - return new CommentNode(node, model, parentItem); + return _node(node); } } diff --git a/packages/website/src/components/CodeListing.tsx b/packages/website/src/components/CodeListing.tsx index 12008b1fe..58d62924c 100644 --- a/packages/website/src/components/CodeListing.tsx +++ b/packages/website/src/components/CodeListing.tsx @@ -1,8 +1,9 @@ import { Group, Stack, Title } from '@mantine/core'; import type { ReactNode } from 'react'; -import { CommentSection } from './Comment'; import { HyperlinkedText } from './HyperlinkedText'; +import { TSDoc } from './tsdoc/TSDoc'; import type { DocItem } from '~/DocModel/DocItem'; +import type { AnyDocNodeJSON } from '~/DocModel/comment/CommentNode'; import type { TokenDocumentation } from '~/util/parse.server'; export enum CodeListingSeparatorType { @@ -16,6 +17,7 @@ export function CodeListing({ summary, typeTokens, children, + comment, }: { name: string; summary?: ReturnType['summary']; @@ -23,6 +25,7 @@ export function CodeListing({ separator?: CodeListingSeparatorType; children?: ReactNode; className?: string | undefined; + comment?: AnyDocNodeJSON | null; }) { return ( @@ -35,7 +38,8 @@ export function CodeListing({ - {summary && } + {summary && } + {comment && } {children} ); diff --git a/packages/website/src/components/Comment.tsx b/packages/website/src/components/Comment.tsx deleted file mode 100644 index 5c110acfb..000000000 --- a/packages/website/src/components/Comment.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { Anchor, Box, Text } from '@mantine/core'; -import Link from 'next/link'; -import type { ReactNode } from 'react'; -import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter'; -import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'; -import type { CommentNode } from '~/DocModel/comment/CommentNode'; -import type { CommentNodeContainer } from '~/DocModel/comment/CommentNodeContainer'; -import type { FencedCodeCommentNode } from '~/DocModel/comment/FencedCodeCommentNode'; -import type { LinkTagCommentNode } from '~/DocModel/comment/LinkTagCommentNode'; -import type { PlainTextCommentNode } from '~/DocModel/comment/PlainTextCommentNode'; - -export function CommentSection({ node }: { node: ReturnType }): JSX.Element { - const createNode = (node: ReturnType, idx?: number): ReactNode => { - switch (node.kind) { - case 'PlainText': - return ( - - {(node as ReturnType).text} - - ); - case 'Paragraph': - return ( - - {(node as ReturnType).nodes.map((node, idx) => createNode(node, idx))} - - ); - case 'SoftBreak': - return
; - case 'LinkTag': { - const { codeDestination, urlDestination, text } = node as ReturnType; - - if (codeDestination) { - return ( - - - {text ?? codeDestination.name} - - - ); - } - - if (urlDestination) { - return ( - - - {text ?? urlDestination} - - - ); - } - - return null; - } - case 'FencedCodeBlock': { - const { language, code } = node as ReturnType; - return ( - - {code} - - ); - } - default: - break; - } - - return null; - }; - - return ( - - {node.kind === 'Paragraph' || node.kind === 'Section' ? ( - <>{(node as CommentNodeContainer).nodes.map((node, idx) => createNode(node, idx))} - ) : ( - createNode(node) - )} - - ); -} diff --git a/packages/website/src/components/DocContainer.tsx b/packages/website/src/components/DocContainer.tsx index 43a0ced6e..b76c34e44 100644 --- a/packages/website/src/components/DocContainer.tsx +++ b/packages/website/src/components/DocContainer.tsx @@ -5,11 +5,12 @@ import { VscListSelection, VscSymbolParameter } from 'react-icons/vsc'; import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter'; import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'; import { CodeListingSeparatorType } from './CodeListing'; -import { CommentSection } from './Comment'; import { HyperlinkedText } from './HyperlinkedText'; import { Section } from './Section'; import { TypeParamTable } from './TypeParamTable'; +import { TSDoc } from './tsdoc/TSDoc'; import type { DocItem } from '~/DocModel/DocItem'; +import type { AnyDocNodeJSON } from '~/DocModel/comment/CommentNode'; import { generateIcon } from '~/util/icon'; import type { TokenDocumentation, TypeParameterData } from '~/util/parse.server'; @@ -22,6 +23,7 @@ export interface DocContainerProps { extendsTokens?: TokenDocumentation[] | null; implementsTokens?: TokenDocumentation[][]; typeParams?: TypeParameterData[]; + comment?: AnyDocNodeJSON | null; } export function DocContainer({ @@ -46,7 +48,7 @@ export function DocContainer({
} padded dense={matches}> - {summary ? : No summary provided.} + {summary ? : No summary provided.}
diff --git a/packages/website/src/components/MethodItem.tsx b/packages/website/src/components/MethodItem.tsx index d1c38bcad..04b4ca418 100644 --- a/packages/website/src/components/MethodItem.tsx +++ b/packages/website/src/components/MethodItem.tsx @@ -1,7 +1,7 @@ import { Group, Stack, Title } from '@mantine/core'; -import { CommentSection } from './Comment'; import { HyperlinkedText } from './HyperlinkedText'; import { ParameterTable } from './ParameterTable'; +import { TSDoc } from './tsdoc/TSDoc'; import type { DocMethod } from '~/DocModel/DocMethod'; import type { DocMethodSignature } from '~/DocModel/DocMethodSignature'; @@ -32,7 +32,8 @@ export function MethodItem({ data }: { data: MethodResolvable }) { - {data.summary ? : null} + {data.summary ? : null} + {data.comment ? : null} {data.parameters.length ? : null} diff --git a/packages/website/src/components/PropertyList.tsx b/packages/website/src/components/PropertyList.tsx index 7702f9d64..673efba75 100644 --- a/packages/website/src/components/PropertyList.tsx +++ b/packages/website/src/components/PropertyList.tsx @@ -6,7 +6,13 @@ export function PropertyList({ data }: { data: ReturnType return ( {data.map((prop) => ( - + ))} ); diff --git a/packages/website/src/components/model/Class.tsx b/packages/website/src/components/model/Class.tsx index ddea63330..f0f725a8b 100644 --- a/packages/website/src/components/model/Class.tsx +++ b/packages/website/src/components/model/Class.tsx @@ -12,6 +12,7 @@ export function Class({ data }: { data: ReturnType }) { typeParams={data.typeParameterData} extendsTokens={data.extendsTokens} implementsTokens={data.implementsTokens} + comment={data.comment} > diff --git a/packages/website/src/components/tsdoc/BlockComment.tsx b/packages/website/src/components/tsdoc/BlockComment.tsx new file mode 100644 index 000000000..5f870ab70 --- /dev/null +++ b/packages/website/src/components/tsdoc/BlockComment.tsx @@ -0,0 +1,40 @@ +import { StandardTags } from '@microsoft/tsdoc'; +import type { ReactNode } from 'react'; + +export interface BlockProps { + children: ReactNode; + title: string; +} + +export function Block({ children, title }: BlockProps) { + return ( +
+

{title}

+ {children} +
+ ); +} + +export interface BlockCommentProps { + tagName: string; + children: ReactNode; + index?: number | undefined; +} + +export interface ExampleBlockProps { + children: ReactNode; + exampleIndex?: number | undefined; +} + +export function ExampleBlock({ children, exampleIndex }: ExampleBlockProps): JSX.Element { + return {children}; +} + +export function BlockComment({ children, tagName, index }: BlockCommentProps): JSX.Element { + switch (tagName.toUpperCase()) { + case StandardTags.example.tagNameWithUpperCase: + return {children}; + default: // TODO: Support more blocks in the future. + return <>; + } +} diff --git a/packages/website/src/components/tsdoc/TSDoc.tsx b/packages/website/src/components/tsdoc/TSDoc.tsx new file mode 100644 index 000000000..107679df5 --- /dev/null +++ b/packages/website/src/components/tsdoc/TSDoc.tsx @@ -0,0 +1,124 @@ +import { Anchor, Box, Text } from '@mantine/core'; +import { DocNodeKind, StandardTags } from '@microsoft/tsdoc'; +import Link from 'next/link'; +import type { ReactNode } from 'react'; +import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'; +import { BlockComment } from './BlockComment'; +import type { DocBlockJSON } from '~/DocModel/comment/CommentBlock'; +import type { AnyDocNodeJSON } from '~/DocModel/comment/CommentNode'; +import type { DocNodeContainerJSON } from '~/DocModel/comment/CommentNodeContainer'; +import type { DocFencedCodeJSON } from '~/DocModel/comment/FencedCodeCommentNode'; +import type { DocLinkTagJSON } from '~/DocModel/comment/LinkTagCommentNode'; +import type { DocPlainTextJSON } from '~/DocModel/comment/PlainTextCommentNode'; +import type { DocCommentJSON } from '~/DocModel/comment/RootComment'; + +export function TSDoc({ node }: { node: AnyDocNodeJSON }): JSX.Element { + let numberOfExamples = 0; + let exampleIndex = 0; + + const createNode = (node: AnyDocNodeJSON, idx?: number): ReactNode => { + switch (node.kind) { + case DocNodeKind.PlainText: + return ( + + {(node as DocPlainTextJSON).text} + + ); + case DocNodeKind.Paragraph: + return ( + + {(node as DocNodeContainerJSON).nodes.map((node, idx) => createNode(node, idx))} + + ); + case DocNodeKind.SoftBreak: + return
; + case DocNodeKind.LinkTag: { + const { codeDestination, urlDestination, text } = node as DocLinkTagJSON; + + if (codeDestination) { + return ( + + + {text ?? codeDestination.name} + + + ); + } + + if (urlDestination) { + return ( + + + {text ?? urlDestination} + + + ); + } + + return null; + } + case DocNodeKind.CodeSpan: { + const { code } = node as DocFencedCodeJSON; + return ( +
+						{code}
+					
+ ); + } + case DocNodeKind.FencedCode: { + const { language, code } = node as DocFencedCodeJSON; + return ( + + {code} + + ); + } + case DocNodeKind.Block: { + const { tag } = node as DocBlockJSON; + + if (tag.tagName.toUpperCase() === StandardTags.example.tagNameWithUpperCase) { + exampleIndex++; + } + + const index = numberOfExamples > 1 ? exampleIndex : undefined; + + return ( + + {(node as DocBlockJSON).content.map((node, idx) => createNode(node, idx))} + + ); + } + case DocNodeKind.Comment: { + const comment = node as DocCommentJSON; + // Cheat a bit by finding out how many comments we have beforehand... + numberOfExamples = comment.customBlocks.filter( + (block) => block.tag.tagName.toUpperCase() === StandardTags.example.tagNameWithUpperCase, + ).length; + + return
{comment.customBlocks.map((node, idx) => createNode(node, idx))}
; + } + default: + break; + } + + return null; + }; + + return ( + + {node.kind === 'Paragraph' || node.kind === 'Section' ? ( + <>{(node as DocNodeContainerJSON).nodes.map((node, idx) => createNode(node, idx))} + ) : ( + createNode(node) + )} + + ); +} diff --git a/packages/ws/src/utils/utils.ts b/packages/ws/src/utils/utils.ts index 42bc1465c..aaca45b8a 100644 --- a/packages/ws/src/utils/utils.ts +++ b/packages/ws/src/utils/utils.ts @@ -4,6 +4,7 @@ export type Awaitable = T | Promise; /** * Yields the numbers in the given range as an array + * * @example * ``` * range({ start: 3, end: 5 }); // [3, 4, 5] diff --git a/packages/ws/src/ws/WebSocketManager.ts b/packages/ws/src/ws/WebSocketManager.ts index 32fb4f136..810384f5b 100644 --- a/packages/ws/src/ws/WebSocketManager.ts +++ b/packages/ws/src/ws/WebSocketManager.ts @@ -79,6 +79,7 @@ export interface OptionalWebSocketManagerOptions { /** * The ids of the shards this WebSocketManager should manage. * Use `null` to simply spawn 0 through `shardCount - 1` + * * @example * ``` * const manager = new WebSocketManager({