From 1ed605eaa4ddd81ee52233ae10df68796dddfab4 Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Tue, 12 Jul 2022 16:42:32 -0400 Subject: [PATCH] feat(website): add extends clauses, enum members and automatic -types links (#8270) * feat(website): add extends clauses, enum members and automatic -types links * chore: remove vscode settings * refactor: remove util file --- packages/website/src/DocModel/DocEnum.ts | 5 +++ .../website/src/components/CodeListing.tsx | 42 +++++++++++++++++++ .../website/src/components/DocContainer.tsx | 38 ++++++++++------- .../src/components/HyperlinkedText.tsx | 30 +++++++++++++ .../website/src/components/ItemSidebar.tsx | 6 +-- .../website/src/components/MethodItem.tsx | 4 +- .../website/src/components/MethodList.tsx | 1 - .../website/src/components/ParameterTable.tsx | 4 +- .../website/src/components/PropertyItem.tsx | 19 --------- .../website/src/components/PropertyList.tsx | 5 +-- packages/website/src/components/Section.tsx | 18 ++++++++ packages/website/src/components/Sections.tsx | 42 +++++++++++++++++++ packages/website/src/components/Table.tsx | 28 ++++++------- .../website/src/components/TypeParamTable.tsx | 6 +-- .../website/src/components/model/Class.tsx | 22 ++-------- .../website/src/components/model/Enum.tsx | 19 ++++++--- .../website/src/components/model/Function.tsx | 5 +-- .../src/components/model/Interface.tsx | 9 ++-- .../$branchName/packages/$packageName.tsx | 2 +- packages/website/src/util/parse.server.ts | 25 +++++++++++ packages/website/src/util/util.tsx | 23 ---------- 21 files changed, 234 insertions(+), 119 deletions(-) create mode 100644 packages/website/src/components/CodeListing.tsx create mode 100644 packages/website/src/components/HyperlinkedText.tsx delete mode 100644 packages/website/src/components/PropertyItem.tsx create mode 100644 packages/website/src/components/Section.tsx create mode 100644 packages/website/src/components/Sections.tsx delete mode 100644 packages/website/src/util/util.tsx diff --git a/packages/website/src/DocModel/DocEnum.ts b/packages/website/src/DocModel/DocEnum.ts index 8270e684b..5d93616b9 100644 --- a/packages/website/src/DocModel/DocEnum.ts +++ b/packages/website/src/DocModel/DocEnum.ts @@ -1,8 +1,11 @@ import type { ApiEnum, ApiModel } from '@microsoft/api-extractor-model'; import { DocItem } from './DocItem'; +import { genToken, resolveDocComment, TokenDocumentation } from '~/util/parse.server'; export interface EnumMemberData { name: string; + initializerTokens: TokenDocumentation[]; + summary: string | null; } export class DocEnum extends DocItem { @@ -13,6 +16,8 @@ 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: resolveDocComment(member), })); } diff --git a/packages/website/src/components/CodeListing.tsx b/packages/website/src/components/CodeListing.tsx new file mode 100644 index 000000000..35bd70c99 --- /dev/null +++ b/packages/website/src/components/CodeListing.tsx @@ -0,0 +1,42 @@ +import type { ReactNode } from 'react'; +import { HyperlinkedText } from './HyperlinkedText'; +import type { TokenDocumentation } from '~/util/parse.server'; + +export enum CodeListingSeparatorType { + Type = ':', + Value = '=', +} + +export interface CodeListingProps { + name: string; + summary?: string | null; + typeTokens: TokenDocumentation[]; + separator?: CodeListingSeparatorType; + children?: ReactNode; + className?: string | undefined; +} + +export function CodeListing({ + name, + className, + separator = CodeListingSeparatorType.Type, + summary, + typeTokens, + children, +}: CodeListingProps) { + return ( +
+
+
+

{`${name}`}

+

{separator}

+

+ +

+
+ {summary &&

{summary}

} + {children} +
+
+ ); +} diff --git a/packages/website/src/components/DocContainer.tsx b/packages/website/src/components/DocContainer.tsx index 9b4f7718b..3ee128638 100644 --- a/packages/website/src/components/DocContainer.tsx +++ b/packages/website/src/components/DocContainer.tsx @@ -1,28 +1,32 @@ +import type { ReactNode } from 'react'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { vs } from 'react-syntax-highlighter/dist/cjs/styles/prism'; -import { Separator } from './Seperator'; +import { HyperlinkedText } from './HyperlinkedText'; +import { Section } from './Section'; import { TypeParamTable } from './TypeParamTable'; import { generateIcon } from '~/util/icon'; -import type { TypeParameterData } from '~/util/parse.server'; +import type { TokenDocumentation, TypeParameterData } from '~/util/parse.server'; export interface DocContainerProps { name: string; kind: string; excerpt: string; summary?: string | null; - children?: JSX.Element | JSX.Element[]; + children?: ReactNode; + extendsTokens?: TokenDocumentation[] | null; typeParams?: TypeParameterData[]; } -export function DocContainer({ name, kind, excerpt, summary, typeParams, children }: DocContainerProps) { +export function DocContainer({ name, kind, excerpt, summary, typeParams, children, extendsTokens }: DocContainerProps) { return ( <> -
-

+
+

{generateIcon(kind, 'mr-2')} {name} -

+

+
-

Summary

-

{summary ?? 'No summary provided.'}

- + {extendsTokens?.length ? ( +
+

Extends

+

+ +

+
+ ) : null} +
+

{summary ?? 'No summary provided.'}

+
{typeParams?.length ? ( - <> -

Type Parameters

+
- - +
) : null}
{children}
diff --git a/packages/website/src/components/HyperlinkedText.tsx b/packages/website/src/components/HyperlinkedText.tsx new file mode 100644 index 000000000..dfe23f639 --- /dev/null +++ b/packages/website/src/components/HyperlinkedText.tsx @@ -0,0 +1,30 @@ +import type { TokenDocumentation } from '~/util/parse.server'; + +export interface HyperlinkedTextProps { + tokens: TokenDocumentation[]; +} + +/** + * Constructs a hyperlinked html node based on token type references + * + * @param tokens An array of documentation tokens to construct the HTML + * + * @returns An array of JSX elements and string comprising the hyperlinked text + */ +export function HyperlinkedText({ tokens }: HyperlinkedTextProps) { + return ( + <> + {tokens.map((token) => { + if (token.path) { + return ( + + {token.text} + + ); + } + + return token.text; + })} + + ); +} diff --git a/packages/website/src/components/ItemSidebar.tsx b/packages/website/src/components/ItemSidebar.tsx index 7002bdda6..9178ef17e 100644 --- a/packages/website/src/components/ItemSidebar.tsx +++ b/packages/website/src/components/ItemSidebar.tsx @@ -18,11 +18,11 @@ function onMenuClick() { export function ItemSidebar({ packageName, data }: ItemListProps) { return (
-
-

+
+

{`${packageName}`} -

+

diff --git a/packages/website/src/components/MethodItem.tsx b/packages/website/src/components/MethodItem.tsx index c99c4fb3f..751f5ca91 100644 --- a/packages/website/src/components/MethodItem.tsx +++ b/packages/website/src/components/MethodItem.tsx @@ -1,8 +1,8 @@ import { FiLink } from 'react-icons/fi'; +import { HyperlinkedText } from './HyperlinkedText'; import { ParameterTable } from './ParameterTable'; import type { DocMethod } from '~/DocModel/DocMethod'; import type { DocMethodSignature } from '~/DocModel/DocMethodSignature'; -import { constructHyperlinkedText } from '~/util/util'; type MethodResolvable = ReturnType | ReturnType; @@ -37,7 +37,7 @@ export function MethodItem({ data }: MethodItemProps) {

{`${getShorthandName(data)}`}

:

- {constructHyperlinkedText(data.returnTypeTokens)} +

diff --git a/packages/website/src/components/MethodList.tsx b/packages/website/src/components/MethodList.tsx index e2301b3e0..55297261d 100644 --- a/packages/website/src/components/MethodList.tsx +++ b/packages/website/src/components/MethodList.tsx @@ -9,7 +9,6 @@ export interface MethodListProps { export function MethodList({ data }: MethodListProps) { return (
-

Methods

{data.map((method) => ( diff --git a/packages/website/src/components/ParameterTable.tsx b/packages/website/src/components/ParameterTable.tsx index 83256d648..09cb4e883 100644 --- a/packages/website/src/components/ParameterTable.tsx +++ b/packages/website/src/components/ParameterTable.tsx @@ -1,5 +1,5 @@ +import { HyperlinkedText } from './HyperlinkedText'; import { Table } from './Table'; -import { constructHyperlinkedText } from '../util/util'; import type { ParameterDocumentation } from '~/util/parse.server'; interface ParameterDetailProps { @@ -10,7 +10,7 @@ interface ParameterDetailProps { export function ParameterTable({ data, className }: ParameterDetailProps) { const rows = data.map((param) => ({ Name: param.name, - Type: constructHyperlinkedText(param.tokens), + Type: , Optional: param.isOptional ? 'Yes' : 'No', Description: 'None', })); diff --git a/packages/website/src/components/PropertyItem.tsx b/packages/website/src/components/PropertyItem.tsx deleted file mode 100644 index 51f82f9e3..000000000 --- a/packages/website/src/components/PropertyItem.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import type { DocProperty } from '~/DocModel/DocProperty'; -import { constructHyperlinkedText } from '~/util/util'; - -export interface PropertyItemProps { - data: ReturnType; -} - -export function PropertyItem({ data }: PropertyItemProps) { - return ( -
-
-

{`${data.name}`}

-

:

-

{constructHyperlinkedText(data.propertyTypeTokens)}

-
- {data.summary &&

{data.summary}

} -
- ); -} diff --git a/packages/website/src/components/PropertyList.tsx b/packages/website/src/components/PropertyList.tsx index 30d082443..e60b77771 100644 --- a/packages/website/src/components/PropertyList.tsx +++ b/packages/website/src/components/PropertyList.tsx @@ -1,4 +1,4 @@ -import { PropertyItem } from './PropertyItem'; +import { CodeListing } from './CodeListing'; import type { DocProperty } from '~/DocModel/DocProperty'; export interface PropertyListProps { @@ -8,9 +8,8 @@ export interface PropertyListProps { export function PropertyList({ data }: PropertyListProps) { return (
-

Properties

{data.map((prop) => ( - + ))}
); diff --git a/packages/website/src/components/Section.tsx b/packages/website/src/components/Section.tsx new file mode 100644 index 000000000..a8c42e3c3 --- /dev/null +++ b/packages/website/src/components/Section.tsx @@ -0,0 +1,18 @@ +import type { ReactNode } from 'react'; +import { Separator } from './Seperator'; + +export interface SectionProps { + children: ReactNode; + title: string; + className?: string | undefined; +} + +export function Section({ title, children, className }: SectionProps) { + return ( +
+

{title}

+ {children} + +
+ ); +} diff --git a/packages/website/src/components/Sections.tsx b/packages/website/src/components/Sections.tsx new file mode 100644 index 000000000..13c61540b --- /dev/null +++ b/packages/website/src/components/Sections.tsx @@ -0,0 +1,42 @@ +import { MethodList } from './MethodList'; +import { ParameterTable } from './ParameterTable'; +import { PropertyList } from './PropertyList'; +import { Section } from './Section'; +import type { DocInterface } from '~/DocModel/DocInterface'; +import type { ParameterDocumentation } from '~/util/parse.server'; + +export interface PropertiesSectionProps { + data: ReturnType['properties']; +} + +export function PropertiesSection({ data }: PropertiesSectionProps) { + return data.length ? ( +
+ +
+ ) : null; +} + +export interface MethodsSectionProps { + data: ReturnType['methods']; +} + +export function MethodsSection({ data }: MethodsSectionProps) { + return data.length ? ( +
+ +
+ ) : null; +} + +export interface ParametersSectionProps { + data: ParameterDocumentation[]; +} + +export function ParametersSection({ data }: ParametersSectionProps) { + return data.length ? ( +
+ +
+ ) : null; +} diff --git a/packages/website/src/components/Table.tsx b/packages/website/src/components/Table.tsx index e7f070521..cb25a5aef 100644 --- a/packages/website/src/components/Table.tsx +++ b/packages/website/src/components/Table.tsx @@ -1,3 +1,5 @@ +import type { ReactNode } from 'react'; + export interface RowData { monospace?: boolean; content: string; @@ -6,7 +8,7 @@ export interface RowData { export interface TableProps { columns: string[]; columnStyles?: Record; - rows: Record[]; + rows: Record[]; className?: string | undefined; } @@ -26,20 +28,16 @@ export function Table({ rows, columns, columnStyles, className }: TableProps) { {rows.map((row, i) => ( - {Object.entries(row).map(([colName, val]) => { - console.log(colName); - console.log(columnStyles?.[colName]); - return ( - - {val} - - ); - })} + {Object.entries(row).map(([colName, val]) => ( + + {val} + + ))} ))} diff --git a/packages/website/src/components/TypeParamTable.tsx b/packages/website/src/components/TypeParamTable.tsx index 47038e70b..8b8dfb63c 100644 --- a/packages/website/src/components/TypeParamTable.tsx +++ b/packages/website/src/components/TypeParamTable.tsx @@ -1,6 +1,6 @@ +import { HyperlinkedText } from './HyperlinkedText'; import { Table } from './Table'; import type { TypeParameterData } from '~/util/parse.server'; -import { constructHyperlinkedText } from '~/util/util'; export interface TableProps { data: TypeParameterData[]; @@ -10,9 +10,9 @@ export interface TableProps { export function TypeParamTable({ data, className }: TableProps) { const rows = data.map((typeParam) => ({ Name: typeParam.name, - Constraints: constructHyperlinkedText(typeParam.constraintTokens), + Constraints: , Optional: typeParam.optional ? 'Yes' : 'No', - Default: constructHyperlinkedText(typeParam.defaultTokens), + Default: , Description: 'None', })); diff --git a/packages/website/src/components/model/Class.tsx b/packages/website/src/components/model/Class.tsx index a86020666..c55281fbb 100644 --- a/packages/website/src/components/model/Class.tsx +++ b/packages/website/src/components/model/Class.tsx @@ -1,7 +1,5 @@ import { DocContainer } from '../DocContainer'; -import { MethodList } from '../MethodList'; -import { PropertyList } from '../PropertyList'; -import { Separator } from '../Seperator'; +import { MethodsSection, PropertiesSection } from '../Sections'; import type { DocClass } from '~/DocModel/DocClass'; export interface ClassProps { @@ -16,22 +14,10 @@ export function Class({ data }: ClassProps) { excerpt={data.excerpt} summary={data.summary} typeParams={data.typeParameterData} + extendsTokens={data.extendsTokens} > - <> - {data.properties.length ? ( - <> - - - - ) : null} - - {data.methods.length ? ( - <> - - - - ) : null} - + + ); } diff --git a/packages/website/src/components/model/Enum.tsx b/packages/website/src/components/model/Enum.tsx index 97e72169f..84659a6c9 100644 --- a/packages/website/src/components/model/Enum.tsx +++ b/packages/website/src/components/model/Enum.tsx @@ -1,4 +1,6 @@ +import { CodeListing, CodeListingSeparatorType } from '../CodeListing'; import { DocContainer } from '../DocContainer'; +import { Section } from '../Section'; import type { DocEnum } from '~/DocModel/DocEnum'; export interface EnumProps { @@ -8,14 +10,19 @@ export interface EnumProps { export function Enum({ data }: EnumProps) { return ( - <> -

Members

-
    +
    +
    {data.members.map((member) => ( -
  • {member.name}
  • + ))} -
- +
+ ); } diff --git a/packages/website/src/components/model/Function.tsx b/packages/website/src/components/model/Function.tsx index 467458427..77bd86424 100644 --- a/packages/website/src/components/model/Function.tsx +++ b/packages/website/src/components/model/Function.tsx @@ -1,5 +1,5 @@ import { DocContainer } from '../DocContainer'; -import { ParameterTable } from '../ParameterTable'; +import { ParametersSection } from '../Sections'; import type { DocFunction } from '~/DocModel/DocFunction'; export interface FunctionProps { @@ -15,8 +15,7 @@ export function Function({ data }: FunctionProps) { summary={data.summary} typeParams={data.typeParameterData} > -

Parameters

- + ); } diff --git a/packages/website/src/components/model/Interface.tsx b/packages/website/src/components/model/Interface.tsx index 4878bc088..91c14e4a2 100644 --- a/packages/website/src/components/model/Interface.tsx +++ b/packages/website/src/components/model/Interface.tsx @@ -1,6 +1,5 @@ import { DocContainer } from '../DocContainer'; -import { MethodList } from '../MethodList'; -import { PropertyList } from '../PropertyList'; +import { MethodsSection, PropertiesSection } from '../Sections'; import type { DocInterface } from '~/DocModel/DocInterface'; export interface InterfaceProps { @@ -16,10 +15,8 @@ export function Interface({ data }: InterfaceProps) { summary={data.summary} typeParams={data.typeParameterData} > - <> - {data.properties.length ? : null} - {data.methods.length ? : null} - + + ); } diff --git a/packages/website/src/routes/docs/$branchName/packages/$packageName.tsx b/packages/website/src/routes/docs/$branchName/packages/$packageName.tsx index 601e7e4c0..aec83d8db 100644 --- a/packages/website/src/routes/docs/$branchName/packages/$packageName.tsx +++ b/packages/website/src/routes/docs/$branchName/packages/$packageName.tsx @@ -39,7 +39,7 @@ export default function Package() { const { packageName } = useParams(); return ( -
+
diff --git a/packages/website/src/util/parse.server.ts b/packages/website/src/util/parse.server.ts index c84a0b503..81fda76a0 100644 --- a/packages/website/src/util/parse.server.ts +++ b/packages/website/src/util/parse.server.ts @@ -13,6 +13,7 @@ import { type TypeParameter, } from '@microsoft/api-extractor-model'; import type { DocNode, DocParagraph, DocPlainText } from '@microsoft/tsdoc'; +import { Meaning, ModuleSource } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; export function findPackage(model: ApiModel, name: string): ApiPackage | undefined { return (model.findMembersByName(name)[0] ?? model.findMembersByName(`@discordjs/${name}`)[0]) as @@ -135,6 +136,17 @@ export interface ParameterDocumentation { tokens: TokenDocumentation[]; } +function createDapiTypesURL(meaning: Meaning, name: string) { + const base = 'https://discord-api-types.dev/api/discord-api-types-v10'; + + switch (meaning) { + case 'type': + return `${base}#${name}`; + default: + return `${base}/${meaning}/${name}`; + } +} + export function genReference(item: ApiItem) { return { name: resolveName(item), @@ -148,6 +160,19 @@ export function genToken(model: ApiModel, token: ExcerptToken) { token.canonicalReference._navigation = '.'; } + if ( + token.canonicalReference?.source instanceof ModuleSource && + token.canonicalReference.symbol && + token.canonicalReference.source.packageName === 'discord-api-types' && + token.canonicalReference.symbol.meaning + ) { + return { + kind: token.kind, + text: token.text, + path: createDapiTypesURL(token.canonicalReference.symbol.meaning, token.text), + }; + } + const item = token.canonicalReference ? model.resolveDeclarationReference(token.canonicalReference, undefined).resolvedApiItem ?? null : null; diff --git a/packages/website/src/util/util.tsx b/packages/website/src/util/util.tsx deleted file mode 100644 index 9e292eee7..000000000 --- a/packages/website/src/util/util.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { TokenDocumentation } from './parse.server'; - -/** - * Constructs a hyperlinked html node based on token type references - * - * @param tokens An array of documentation tokens to construct the HTML - * - * @returns An array of JSX elements and string comprising the hyperlinked text - */ -export function constructHyperlinkedText(tokens: TokenDocumentation[]) { - const html: (JSX.Element | string)[] = []; - - for (const token of tokens) { - if (token.path) { - html.push({token.text}); - continue; - } - - html.push(token.text); - } - - return html; -}