mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-16 19:43:29 +01:00
feat(website): add support for function overloads (#8474)
Co-authored-by: Noel <buechler.noel@outlook.com>
This commit is contained in:
@@ -15,6 +15,7 @@ export class DocItem<T extends ApiDeclaredItem = ApiDeclaredItem> {
|
|||||||
public readonly kind: string;
|
public readonly kind: string;
|
||||||
public readonly remarks: CommentNodeContainer | null;
|
public readonly remarks: CommentNodeContainer | null;
|
||||||
public readonly summary: CommentNodeContainer | null;
|
public readonly summary: CommentNodeContainer | null;
|
||||||
|
public readonly containerKey: string;
|
||||||
|
|
||||||
public constructor(model: ApiModel, item: T) {
|
public constructor(model: ApiModel, item: T) {
|
||||||
this.item = item;
|
this.item = item;
|
||||||
@@ -30,6 +31,23 @@ export class DocItem<T extends ApiDeclaredItem = ApiDeclaredItem> {
|
|||||||
this.summary = item.tsdocComment?.summarySection
|
this.summary = item.tsdocComment?.summarySection
|
||||||
? new CommentNodeContainer(item.tsdocComment.summarySection, model, item.parent)
|
? new CommentNodeContainer(item.tsdocComment.summarySection, model, item.parent)
|
||||||
: null;
|
: null;
|
||||||
|
this.containerKey = item.containerKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get path() {
|
||||||
|
const path = [];
|
||||||
|
for (const item of this.item.getHierarchy()) {
|
||||||
|
switch (item.kind) {
|
||||||
|
case 'None':
|
||||||
|
case 'EntryPoint':
|
||||||
|
case 'Model':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
path.push(resolveName(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toJSON() {
|
public toJSON() {
|
||||||
@@ -41,6 +59,8 @@ export class DocItem<T extends ApiDeclaredItem = ApiDeclaredItem> {
|
|||||||
excerptTokens: this.excerptTokens,
|
excerptTokens: this.excerptTokens,
|
||||||
kind: this.kind,
|
kind: this.kind,
|
||||||
remarks: this.remarks?.toJSON() ?? null,
|
remarks: this.remarks?.toJSON() ?? null,
|
||||||
|
path: this.path,
|
||||||
|
containerKey: this.containerKey,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,13 @@ export function DocContainer({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="min-h-full overflow-y-auto overflow-x-clip px-10 pt-5 pb-10">
|
<div className="min-h-full overflow-y-auto overflow-x-clip px-10 pt-5 pb-10">
|
||||||
|
<Section iconElement={<VscListSelection />} title="Summary" className="dark:text-white">
|
||||||
|
{summary ? (
|
||||||
|
<CommentSection textClassName="text-dark-100 dark:text-gray-300" node={summary} />
|
||||||
|
) : (
|
||||||
|
<p className="text-dark-100 dark:text-gray-300">No summary provided.</p>
|
||||||
|
)}
|
||||||
|
</Section>
|
||||||
<SyntaxHighlighter
|
<SyntaxHighlighter
|
||||||
wrapLines
|
wrapLines
|
||||||
wrapLongLines
|
wrapLongLines
|
||||||
@@ -75,13 +82,6 @@ export function DocContainer({
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="space-y-10">
|
<div className="space-y-10">
|
||||||
<Section iconElement={<VscListSelection />} title="Summary" className="dark:text-white">
|
|
||||||
{summary ? (
|
|
||||||
<CommentSection textClassName="text-dark-100 dark:text-gray-300" node={summary} />
|
|
||||||
) : (
|
|
||||||
<p className="text-dark-100 dark:text-gray-300">No summary provided.</p>
|
|
||||||
)}
|
|
||||||
</Section>
|
|
||||||
{typeParams?.length ? (
|
{typeParams?.length ? (
|
||||||
<Section
|
<Section
|
||||||
iconElement={<VscSymbolParameter />}
|
iconElement={<VscSymbolParameter />}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { FiMenu } from 'react-icons/fi';
|
import { FiMenu } from 'react-icons/fi';
|
||||||
import { VscPackage } from 'react-icons/vsc';
|
import { VscPackage } from 'react-icons/vsc';
|
||||||
import { ListSidebar } from './ListSidebar';
|
import { ListSidebar } from './ListSidebar';
|
||||||
|
import type { DocItem } from '~/DocModel/DocItem';
|
||||||
import type { getMembers } from '~/util/parse.server';
|
import type { getMembers } from '~/util/parse.server';
|
||||||
|
|
||||||
export interface ItemListProps {
|
export interface ItemListProps {
|
||||||
@@ -9,7 +10,7 @@ export interface ItemListProps {
|
|||||||
members: ReturnType<typeof getMembers>;
|
members: ReturnType<typeof getMembers>;
|
||||||
};
|
};
|
||||||
|
|
||||||
selectedMember?: string | undefined;
|
selectedMember?: ReturnType<DocItem['toJSON']> | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMenuClick() {
|
function onMenuClick() {
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ import {
|
|||||||
} from 'react-icons/vsc';
|
} from 'react-icons/vsc';
|
||||||
import type { ItemListProps } from './ItemSidebar';
|
import type { ItemListProps } from './ItemSidebar';
|
||||||
import { Section } from './Section';
|
import { Section } from './Section';
|
||||||
|
import type { DocItem } from '~/DocModel/DocItem';
|
||||||
|
|
||||||
export type Members = ItemListProps['data']['members'];
|
export type Members = ItemListProps['data']['members'];
|
||||||
|
|
||||||
export interface ListSidebarSectionProps {
|
export interface ListSidebarSectionProps {
|
||||||
members: Members;
|
members: Members;
|
||||||
selectedMember?: string | undefined;
|
selectedMember?: ReturnType<DocItem['toJSON']> | undefined;
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,12 +94,12 @@ export function ListSidebar({ members, selectedMember }: ListSidebarSectionProps
|
|||||||
{groupItems[group].map((member, i) => (
|
{groupItems[group].map((member, i) => (
|
||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
className="flex gap-2 whitespace-pre-wrap no-underline break-all text-blue-500 dark:text-blue-300"
|
className="flex gap-2 whitespace-pre-wrap no-underline break-all justify-between text-blue-500 dark:text-blue-300"
|
||||||
>
|
>
|
||||||
<Link href={member.path}>
|
<Link href={member.path}>
|
||||||
<a
|
<a
|
||||||
className={`no-underline m-0 text-sm font-semibold ${
|
className={`no-underline m-0 text-sm font-semibold ${
|
||||||
selectedMember === member.name
|
selectedMember?.containerKey === member.containerKey
|
||||||
? 'text-blue-500 dark:text-blue-300'
|
? 'text-blue-500 dark:text-blue-300'
|
||||||
: 'text-gray-500 dark:text-gray-300 hover:text-dark-100 dark:hover:text-white'
|
: 'text-gray-500 dark:text-gray-300 hover:text-dark-100 dark:hover:text-white'
|
||||||
}`}
|
}`}
|
||||||
@@ -106,6 +107,13 @@ export function ListSidebar({ members, selectedMember }: ListSidebarSectionProps
|
|||||||
{member.name}
|
{member.name}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
<div>
|
||||||
|
{member.overloadIndex && member.overloadIndex > 1 ? (
|
||||||
|
<div className="flex font-mono w-[15px] h-[15px] items-center justify-center rounded-md border border-2 font-bold text-sm color-gray-500 dark:color-gray-300">
|
||||||
|
<p className="font-semibold">{`${member.overloadIndex}`}</p>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ export function SidebarLayout({
|
|||||||
<div className="flex flex-col lg:flex-row overflow-hidden">
|
<div className="flex flex-col lg:flex-row overflow-hidden">
|
||||||
<div className="h-full w-full lg:max-w-[310px] lg:min-w-[310px]">
|
<div className="h-full w-full lg:max-w-[310px] lg:min-w-[310px]">
|
||||||
{packageName && data ? (
|
{packageName && data ? (
|
||||||
<ItemSidebar packageName={packageName} data={data} selectedMember={data.member?.name} />
|
<ItemSidebar packageName={packageName} data={data} selectedMember={data.member} />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full grow">{children}</div>
|
<div className="h-full grow">{children}</div>
|
||||||
<div className="h-full w-full lg:max-w-[310px] lg:min-w-[310px]">
|
<div className="h-full w-full lg:max-w-[310px] lg:min-w-[310px]">
|
||||||
{packageName && data?.member ? (
|
{packageName && data?.member ? (
|
||||||
<ItemSidebar packageName={packageName} data={data} selectedMember={data.member.name} />
|
<ItemSidebar packageName={packageName} data={data} selectedMember={data.member} />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export interface FunctionProps {
|
|||||||
export function Function({ data }: FunctionProps) {
|
export function Function({ data }: FunctionProps) {
|
||||||
return (
|
return (
|
||||||
<DocContainer
|
<DocContainer
|
||||||
name={data.name}
|
name={`${data.name}${data.overloadIndex ? ` (${data.overloadIndex})` : ''}`}
|
||||||
kind={data.kind}
|
kind={data.kind}
|
||||||
excerpt={data.excerpt}
|
excerpt={data.excerpt}
|
||||||
summary={data.summary}
|
summary={data.summary}
|
||||||
|
|||||||
15
packages/website/src/contexts/member.tsx
Normal file
15
packages/website/src/contexts/member.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { createContext } from 'react';
|
||||||
|
import type { DocItem } from '~/DocModel/DocItem';
|
||||||
|
|
||||||
|
export type DocItemJSON = ReturnType<DocItem['toJSON']>;
|
||||||
|
|
||||||
|
export const MemberContext = createContext<DocItemJSON | undefined>(undefined);
|
||||||
|
|
||||||
|
export interface MemberProviderProps {
|
||||||
|
member: DocItemJSON | undefined;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MemberProvider = ({ member, children }: MemberProviderProps) => (
|
||||||
|
<MemberContext.Provider value={member}>{children}</MemberContext.Provider>
|
||||||
|
);
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-throw-literal */
|
/* eslint-disable @typescript-eslint/no-throw-literal */
|
||||||
|
import { ApiFunction } from '@microsoft/api-extractor-model';
|
||||||
import type { GetStaticPaths, GetStaticProps } from 'next/types';
|
import type { GetStaticPaths, GetStaticProps } from 'next/types';
|
||||||
import type { DocClass } from '~/DocModel/DocClass';
|
import type { DocClass } from '~/DocModel/DocClass';
|
||||||
import type { DocEnum } from '~/DocModel/DocEnum';
|
import type { DocEnum } from '~/DocModel/DocEnum';
|
||||||
@@ -14,8 +15,9 @@ import { Function } from '~/components/model/Function';
|
|||||||
import { Interface } from '~/components/model/Interface';
|
import { Interface } from '~/components/model/Interface';
|
||||||
import { TypeAlias } from '~/components/model/TypeAlias';
|
import { TypeAlias } from '~/components/model/TypeAlias';
|
||||||
import { Variable } from '~/components/model/Variable';
|
import { Variable } from '~/components/model/Variable';
|
||||||
|
import { MemberProvider } from '~/contexts/member';
|
||||||
import { createApiModel } from '~/util/api-model.server';
|
import { createApiModel } from '~/util/api-model.server';
|
||||||
import { findMember } from '~/util/model.server';
|
import { findMember, findMemberByKey } from '~/util/model.server';
|
||||||
import { findPackage, getMembers } from '~/util/parse.server';
|
import { findPackage, getMembers } from '~/util/parse.server';
|
||||||
|
|
||||||
export const getStaticPaths: GetStaticPaths = async () => {
|
export const getStaticPaths: GetStaticPaths = async () => {
|
||||||
@@ -38,7 +40,16 @@ export const getStaticPaths: GetStaticPaths = async () => {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
{ params: { slug: ['main', 'packages', packageName] } },
|
{ params: { slug: ['main', 'packages', packageName] } },
|
||||||
...getMembers(pkg!).map((member) => ({ params: { slug: ['main', 'packages', packageName, member.name] } })),
|
...getMembers(pkg!).map((member) => {
|
||||||
|
if (member.kind === 'Function' && member.overloadIndex) {
|
||||||
|
return {
|
||||||
|
params: {
|
||||||
|
slug: ['main', 'packages', packageName, `${member.name}:${member.overloadIndex}`],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { params: { slug: ['main', 'packages', packageName, member.name] } };
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
} catch {
|
} catch {
|
||||||
return { params: { slug: ['', '', '', ''] } };
|
return { params: { slug: ['', '', '', ''] } };
|
||||||
@@ -54,7 +65,9 @@ export const getStaticPaths: GetStaticPaths = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getStaticProps: GetStaticProps = async ({ params }) => {
|
export const getStaticProps: GetStaticProps = async ({ params }) => {
|
||||||
const [branchName = 'main', , packageName = 'builders', memberName] = params!.slug as string[];
|
const [branchName = 'main', , packageName = 'builders', member = 'ActionRowBuilder'] = params!.slug as string[];
|
||||||
|
|
||||||
|
const [memberName, overloadIndex] = member.split(':') as [string, string | undefined];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`https://docs.discordjs.dev/docs/${packageName}/${branchName}.api.json`);
|
const res = await fetch(`https://docs.discordjs.dev/docs/${packageName}/${branchName}.api.json`);
|
||||||
@@ -64,12 +77,17 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
|
|||||||
const model = createApiModel(data);
|
const model = createApiModel(data);
|
||||||
const pkg = findPackage(model, packageName);
|
const pkg = findPackage(model, packageName);
|
||||||
|
|
||||||
|
let { containerKey, name } = findMember(model, packageName, memberName)!;
|
||||||
|
if (overloadIndex) {
|
||||||
|
containerKey = ApiFunction.getContainerKey(name, parseInt(overloadIndex, 10));
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
packageName,
|
packageName,
|
||||||
data: {
|
data: {
|
||||||
members: pkg ? getMembers(pkg) : [],
|
members: pkg ? getMembers(pkg) : [],
|
||||||
member: memberName ? findMember(model, packageName, memberName)?.toJSON() ?? null : null,
|
member: memberName ? findMemberByKey(model, packageName, containerKey)?.toJSON() ?? null : null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -108,6 +126,8 @@ export default function Slug(
|
|||||||
return props.error ? (
|
return props.error ? (
|
||||||
<div className="flex max-w-full h-full bg-white dark:bg-dark">{props.error}</div>
|
<div className="flex max-w-full h-full bg-white dark:bg-dark">{props.error}</div>
|
||||||
) : (
|
) : (
|
||||||
<SidebarLayout {...props}>{props.data?.member ? member(props.data.member) : null}</SidebarLayout>
|
<MemberProvider member={props.data?.member}>
|
||||||
|
<SidebarLayout {...props}>{props.data?.member ? member(props.data.member) : null}</SidebarLayout>
|
||||||
|
</MemberProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
ApiEnum,
|
ApiEnum,
|
||||||
ApiFunction,
|
ApiFunction,
|
||||||
ApiInterface,
|
ApiInterface,
|
||||||
|
ApiItem,
|
||||||
ApiItemKind,
|
ApiItemKind,
|
||||||
ApiModel,
|
ApiModel,
|
||||||
ApiTypeAlias,
|
ApiTypeAlias,
|
||||||
@@ -24,10 +25,7 @@ export interface ReferenceData {
|
|||||||
path: string;
|
path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findMember(model: ApiModel, packageName: string, memberName: string): DocItem | undefined {
|
function createDocItem(model: ApiModel, member: ApiItem) {
|
||||||
const pkg = findPackage(model, packageName)!;
|
|
||||||
const member = (pkg.members[0] as ApiEntryPoint).findMembersByName(memberName)[0];
|
|
||||||
|
|
||||||
if (!(member instanceof ApiDeclaredItem)) {
|
if (!(member instanceof ApiDeclaredItem)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -48,19 +46,26 @@ export function findMember(model: ApiModel, packageName: string, memberName: str
|
|||||||
default:
|
default:
|
||||||
return new DocItem(model, member);
|
return new DocItem(model, member);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// return {
|
|
||||||
// name: resolveName(member),
|
export function findMemberByKey(model: ApiModel, packageName: string, containerKey: string) {
|
||||||
// kind: member.kind,
|
const pkg = findPackage(model, packageName)!;
|
||||||
// summary: resolveDocComment(member),
|
const member = (pkg.members[0] as ApiEntryPoint).tryGetMemberByKey(containerKey);
|
||||||
// excerpt: member.excerpt.text,
|
|
||||||
// tokens: member.excerpt.spannedTokens.map((token) => genToken(model, token)),
|
if (!member) {
|
||||||
// refs: [...findReferences(model, member.excerpt).values()].map(genReference),
|
return undefined;
|
||||||
// members: getProperties(member).map((member) => ({
|
}
|
||||||
// tokens: member.excerpt.spannedTokens.map((token) => genToken(model, token)),
|
|
||||||
// summary: resolveDocComment(member),
|
return createDocItem(model, member);
|
||||||
// })),
|
}
|
||||||
// parameters: member instanceof ApiFunction ? member.parameters.map((param) => genParameter(model, param)) : [],
|
|
||||||
// foo: excerpt.spannedTokens.map((token) => genToken(model, token)),
|
export function findMember(model: ApiModel, packageName: string, memberName: string): DocItem | undefined {
|
||||||
// };
|
const pkg = findPackage(model, packageName)!;
|
||||||
|
const member = (pkg.members[0] as ApiEntryPoint).findMembersByName(memberName)[0];
|
||||||
|
|
||||||
|
if (!member) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createDocItem(model, member);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
type ExcerptToken,
|
type ExcerptToken,
|
||||||
type Parameter,
|
type Parameter,
|
||||||
type TypeParameter,
|
type TypeParameter,
|
||||||
|
ApiFunction,
|
||||||
} from '@microsoft/api-extractor-model';
|
} from '@microsoft/api-extractor-model';
|
||||||
import type { DocNode, DocParagraph, DocPlainText } from '@microsoft/tsdoc';
|
import type { DocNode, DocParagraph, DocPlainText } from '@microsoft/tsdoc';
|
||||||
import { Meaning, ModuleSource } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';
|
import { Meaning, ModuleSource } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';
|
||||||
@@ -32,6 +33,9 @@ export function generatePath(items: readonly ApiItem[]) {
|
|||||||
case ApiItemKind.Package:
|
case ApiItemKind.Package:
|
||||||
path += `${item.displayName}/`;
|
path += `${item.displayName}/`;
|
||||||
break;
|
break;
|
||||||
|
case ApiItemKind.Function:
|
||||||
|
path += `${item.displayName}:${(item as ApiFunction).overloadIndex}/`;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
path += `${item.displayName}/`;
|
path += `${item.displayName}/`;
|
||||||
}
|
}
|
||||||
@@ -195,8 +199,10 @@ export function genParameter(model: ApiModel, param: Parameter): ParameterDocume
|
|||||||
export function getMembers(pkg: ApiPackage) {
|
export function getMembers(pkg: ApiPackage) {
|
||||||
return pkg.members[0]!.members.map((member) => ({
|
return pkg.members[0]!.members.map((member) => ({
|
||||||
name: member.displayName,
|
name: member.displayName,
|
||||||
kind: member.kind,
|
kind: member.kind as string,
|
||||||
path: generatePath(member.getHierarchy()),
|
path: generatePath(member.getHierarchy()),
|
||||||
|
containerKey: member.containerKey,
|
||||||
|
overloadIndex: member.kind === 'Function' ? (member as ApiFunction).overloadIndex : null,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user