feat(website): render tsdoc examples (#8494)

This commit is contained in:
Suneet Tipirneni
2022-08-16 10:33:49 -04:00
committed by GitHub
parent c99b808882
commit 7116647947
22 changed files with 382 additions and 209 deletions

View File

@@ -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<ApiEnum> {
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,
}));
}

View File

@@ -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<T extends ApiDeclaredItem = ApiDeclaredItem> {
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<T extends ApiDeclaredItem = ApiDeclaredItem> {
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<T extends ApiDeclaredItem = ApiDeclaredItem> {
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,
};
}
}

View File

@@ -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),
};
}

View File

@@ -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,
};
}

View File

@@ -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,
};
}

View File

@@ -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<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,
};
}
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,
};
}

View File

@@ -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<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()),
};
}
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)),
};
}

View File

@@ -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<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,
};
}
export interface DocFencedCodeJSON extends DocNodeJSON {
code: string;
language: string;
}
export function fencedCode(fencedCode: DocFencedCode) {
return {
...node(fencedCode),
language: fencedCode.language,
code: fencedCode.code,
};
}

View File

@@ -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<DocLinkTag> {
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,
};
}

View File

@@ -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<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,
};
}
export interface DocPlainTextJSON extends DocNodeJSON {
text: string;
}
export function plainTextNode(plainTextNode: DocPlainText): DocPlainTextJSON {
return {
...node(plainTextNode),
text: plainTextNode.text,
};
}

View File

@@ -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)),
};
}

View File

@@ -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);
}
}

View File

@@ -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<DocItem['toJSON']>['summary'];
@@ -23,6 +25,7 @@ export function CodeListing({
separator?: CodeListingSeparatorType;
children?: ReactNode;
className?: string | undefined;
comment?: AnyDocNodeJSON | null;
}) {
return (
<Stack key={name}>
@@ -35,7 +38,8 @@ export function CodeListing({
<HyperlinkedText tokens={typeTokens} />
</Title>
</Group>
{summary && <CommentSection node={summary} />}
{summary && <TSDoc node={summary} />}
{comment && <TSDoc node={comment} />}
{children}
</Stack>
);

View File

@@ -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<CommentNode['toJSON']> }): JSX.Element {
const createNode = (node: ReturnType<CommentNode['toJSON']>, idx?: number): ReactNode => {
switch (node.kind) {
case 'PlainText':
return (
<Text key={idx} span>
{(node as ReturnType<PlainTextCommentNode['toJSON']>).text}
</Text>
);
case 'Paragraph':
return (
<Text key={idx} inline>
{(node as ReturnType<CommentNodeContainer['toJSON']>).nodes.map((node, idx) => createNode(node, idx))}
</Text>
);
case 'SoftBreak':
return <br key={idx} />;
case 'LinkTag': {
const { codeDestination, urlDestination, text } = node as ReturnType<LinkTagCommentNode['toJSON']>;
if (codeDestination) {
return (
<Link key={idx} href={codeDestination.path} passHref>
<Anchor component="a" className="font-mono">
{text ?? codeDestination.name}
</Anchor>
</Link>
);
}
if (urlDestination) {
return (
<Link key={idx} href={urlDestination} passHref>
<Anchor component="a" className="font-mono">
{text ?? urlDestination}
</Anchor>
</Link>
);
}
return null;
}
case 'FencedCodeBlock': {
const { language, code } = node as ReturnType<FencedCodeCommentNode['toJSON']>;
return (
<SyntaxHighlighter
key={idx}
wrapLines
wrapLongLines
language={language}
style={vscDarkPlus}
codeTagProps={{ style: { fontFamily: 'JetBrains Mono' } }}
>
{code}
</SyntaxHighlighter>
);
}
default:
break;
}
return null;
};
return (
<Box>
{node.kind === 'Paragraph' || node.kind === 'Section' ? (
<>{(node as CommentNodeContainer).nodes.map((node, idx) => createNode(node, idx))}</>
) : (
createNode(node)
)}
</Box>
);
}

View File

@@ -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({
</Title>
<Section title="Summary" icon={<VscListSelection />} padded dense={matches}>
{summary ? <CommentSection node={summary} /> : <Text>No summary provided.</Text>}
{summary ? <TSDoc node={summary} /> : <Text>No summary provided.</Text>}
</Section>
<Box px="xs" pb="xs">

View File

@@ -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 }) {
</Stack>
</Group>
<Group sx={{ display: data.summary || data.parameters.length ? 'block' : 'none' }} mb="lg">
{data.summary ? <CommentSection node={data.summary} /> : null}
{data.summary ? <TSDoc node={data.summary} /> : null}
{data.comment ? <TSDoc node={data.comment} /> : null}
{data.parameters.length ? <ParameterTable data={data.parameters} /> : null}
</Group>
</Stack>

View File

@@ -6,7 +6,13 @@ export function PropertyList({ data }: { data: ReturnType<DocProperty['toJSON']>
return (
<Stack>
{data.map((prop) => (
<CodeListing key={prop.name} name={prop.name} typeTokens={prop.propertyTypeTokens} summary={prop.summary} />
<CodeListing
key={prop.name}
name={prop.name}
typeTokens={prop.propertyTypeTokens}
summary={prop.summary}
comment={prop.comment}
/>
))}
</Stack>
);

View File

@@ -12,6 +12,7 @@ export function Class({ data }: { data: ReturnType<DocClass['toJSON']> }) {
typeParams={data.typeParameterData}
extendsTokens={data.extendsTokens}
implementsTokens={data.implementsTokens}
comment={data.comment}
>
<PropertiesSection data={data.properties} />
<MethodsSection data={data.methods} />

View File

@@ -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 (
<div>
<h3 className="m-0">{title}</h3>
{children}
</div>
);
}
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 <Block title={`Example ${exampleIndex ? exampleIndex : ''}`}>{children}</Block>;
}
export function BlockComment({ children, tagName, index }: BlockCommentProps): JSX.Element {
switch (tagName.toUpperCase()) {
case StandardTags.example.tagNameWithUpperCase:
return <ExampleBlock exampleIndex={index}>{children}</ExampleBlock>;
default: // TODO: Support more blocks in the future.
return <></>;
}
}

View File

@@ -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 (
<Text key={idx} span>
{(node as DocPlainTextJSON).text}
</Text>
);
case DocNodeKind.Paragraph:
return (
<Text key={idx} inline>
{(node as DocNodeContainerJSON).nodes.map((node, idx) => createNode(node, idx))}
</Text>
);
case DocNodeKind.SoftBreak:
return <br key={idx} />;
case DocNodeKind.LinkTag: {
const { codeDestination, urlDestination, text } = node as DocLinkTagJSON;
if (codeDestination) {
return (
<Link key={idx} href={codeDestination.path} passHref>
<Anchor component="a" className="font-mono">
{text ?? codeDestination.name}
</Anchor>
</Link>
);
}
if (urlDestination) {
return (
<Link key={idx} href={urlDestination} passHref>
<Anchor component="a" className="font-mono">
{text ?? urlDestination}
</Anchor>
</Link>
);
}
return null;
}
case DocNodeKind.CodeSpan: {
const { code } = node as DocFencedCodeJSON;
return (
<pre key={idx} className="inline">
{code}
</pre>
);
}
case DocNodeKind.FencedCode: {
const { language, code } = node as DocFencedCodeJSON;
return (
<SyntaxHighlighter
key={idx}
wrapLines
wrapLongLines
language={language}
style={vscDarkPlus}
codeTagProps={{ style: { fontFamily: 'JetBrains Mono' } }}
>
{code}
</SyntaxHighlighter>
);
}
case DocNodeKind.Block: {
const { tag } = node as DocBlockJSON;
if (tag.tagName.toUpperCase() === StandardTags.example.tagNameWithUpperCase) {
exampleIndex++;
}
const index = numberOfExamples > 1 ? exampleIndex : undefined;
return (
<BlockComment tagName={tag.tagName} key={idx} index={index}>
{(node as DocBlockJSON).content.map((node, idx) => createNode(node, idx))}
</BlockComment>
);
}
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 <div>{comment.customBlocks.map((node, idx) => createNode(node, idx))}</div>;
}
default:
break;
}
return null;
};
return (
<Box>
{node.kind === 'Paragraph' || node.kind === 'Section' ? (
<>{(node as DocNodeContainerJSON).nodes.map((node, idx) => createNode(node, idx))}</>
) : (
createNode(node)
)}
</Box>
);
}

View File

@@ -4,6 +4,7 @@ export type Awaitable<T> = T | Promise<T>;
/**
* Yields the numbers in the given range as an array
*
* @example
* ```
* range({ start: 3, end: 5 }); // [3, 4, 5]

View File

@@ -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({