feat: mainlib docs on new website (#9930)

* fix(ExceptText): don't display import("d..-types/v10"). in return type

* Squashed 'packages/api-extractor-model/' content from commit 39ecb196c

git-subtree-dir: packages/api-extractor-model
git-subtree-split: 39ecb196ca210bdf84ba6c9cadb1bb93571849d7

* Squashed 'packages/api-extractor/' content from commit 341ad6c51

git-subtree-dir: packages/api-extractor
git-subtree-split: 341ad6c51b01656d4f73b74ad4bdb3095f9262c4

* feat(api-extractor): add api-extractor and -model

* fix: package.json docs script

* fix(SourcLink): use <> instead of function syntax

* fix: make packages private

* fix: rest params showing in docs, added labels

* fix: missed two files

* feat: merge docs.json from docgen and docs.api.json

* fix: cpy-cli & pnpm-lock

* fix: increase icon size

* fix: icon size again

* feat: run both docs on mainlib

* chore: website fixes

* fix: more website fixes

* fix: tests and dev database script

* chore: comment out old docs

* fix: increase max fetch cache

* fix: env should always be a string

* fix: try to reapply patches

* fix: remove prepare for docgen

* fix: temporary cosmetic fixes

* fix: horizontal scroll

* feat: generate index for new docs

---------

Co-authored-by: Noel <buechler.noel@outlook.com>
This commit is contained in:
Qjuh
2023-11-08 10:16:54 +01:00
committed by GitHub
parent f713e47b0a
commit da455bceea
63 changed files with 1877 additions and 253 deletions

View File

@@ -23,7 +23,7 @@ export async function fetchVersions(packageName: string): Promise<string[]> {
return rows.map((row) => row.version);
}
export async function fetchModelJSON(packageName: string, version: string): Promise<unknown> {
export async function fetchModelJSON(packageName: string, version: string): Promise<unknown | null> {
if (process.env.NEXT_PUBLIC_LOCAL_DEV) {
const res = await readFile(
join(process.cwd(), '..', '..', 'packages', packageName, 'docs', 'docs.api.json'),

View File

@@ -32,9 +32,15 @@ import { findMember } from '~/util/model';
async function fetchHeadMember({ package: packageName, version, item }: ItemRouteParams) {
const modelJSON = await fetchModelJSON(packageName, version);
if (!modelJSON) {
return undefined;
}
const model = addPackageToModel(new ApiModel(), modelJSON);
const pkg = model.tryGetPackageByName(packageName);
const entry = pkg?.entryPoints[0];
if (!entry) {
return undefined;
}
@@ -88,7 +94,11 @@ export async function generateMetadata({ params }: { params: ItemRouteParams })
const searchParams = resolveMemberSearchParams(params.package, member);
url.search = searchParams.toString();
const ogImage = url.toString();
const description = tryResolveSummaryText(member as ApiDeclaredItem);
let description;
if (member) {
description = tryResolveSummaryText(member as ApiDeclaredItem);
}
return {
title: name,

View File

@@ -4,7 +4,7 @@ import dynamic from 'next/dynamic';
import { notFound } from 'next/navigation';
import type { PropsWithChildren } from 'react';
import { fetchModelJSON, fetchVersions } from '~/app/docAPI';
import { Banner } from '~/components/Banner';
// import { Banner } from '~/components/Banner';
import { CmdKDialog } from '~/components/CmdK';
import { Nav } from '~/components/Nav';
import type { SidebarSectionItemData } from '~/components/Sidebar';
@@ -46,6 +46,11 @@ function serializeIntoSidebarItemData(item: ApiItem): SidebarSectionItemData {
export default async function PackageLayout({ children, params }: PropsWithChildren<{ params: VersionRouteParams }>) {
const modelJSON = await fetchModelJSON(params.package, params.version);
if (!modelJSON) {
notFound();
}
const model = addPackageToModel(new ApiModel(), modelJSON);
const pkg = model.tryGetPackageByName(params.package);
@@ -72,7 +77,7 @@ export default async function PackageLayout({ children, params }: PropsWithChild
return (
<Providers>
<Banner className="mb-6" />
{/* <Banner className="mb-6" /> */}
<main className="mx-auto max-w-7xl px-4 lg:max-w-full">
<Header />
<div className="relative top-2.5 mx-auto max-w-7xl gap-6 lg:max-w-full lg:flex">

View File

@@ -7,22 +7,12 @@ import { fetchVersions } from '~/app/docAPI';
import { buttonVariants } from '~/styles/Button';
import { PACKAGES } from '~/util/constants';
async function getData(pkg: string) {
if (!PACKAGES.includes(pkg)) {
export default async function Page({ params }: { params: { package: string } }) {
if (!PACKAGES.includes(params.package)) {
notFound();
}
const data = await fetchVersions(pkg);
if (!data.length) {
throw new Error('Failed to fetch data');
}
return data;
}
export default async function Page({ params }: { params: { package: string } }) {
const data = await getData(params.package);
const data = await fetchVersions(params.package);
return (
<div className="mx-auto min-h-screen min-w-xs flex flex-col gap-8 px-4 py-6 sm:w-md lg:px-6 lg:py-6">

View File

@@ -11,7 +11,7 @@ export default function Page() {
<div className="mx-auto min-h-screen min-w-xs flex flex-col gap-8 px-4 py-6 sm:w-md lg:px-6 lg:py-6">
<h1 className="text-2xl font-semibold">Select a package:</h1>
<div className="flex flex-col gap-4">
<a className={buttonVariants({ variant: 'secondary' })} href="https://old.discordjs.dev/#/docs/discord.js">
{/* <a className={buttonVariants({ variant: 'secondary' })} href="https://old.discordjs.dev/#/docs/discord.js">
<div className="flex grow flex-row place-content-between place-items-center gap-4">
<div className="flex flex-row place-content-between place-items-center gap-4">
<VscPackage size={25} />
@@ -19,7 +19,7 @@ export default function Page() {
</div>
<VscArrowRight size={20} />
</div>
</a>
</a> */}
{PACKAGES.map((pkg, idx) => (
<Link
className={buttonVariants({ variant: 'secondary' })}

View File

@@ -4,7 +4,7 @@ import Image from 'next/image';
import Link from 'next/link';
import vercelLogo from '~/assets/powered-by-vercel.svg';
import workersLogo from '~/assets/powered-by-workers.png';
import { Banner } from '~/components/Banner';
// import { Banner } from '~/components/Banner';
import { InstallButton } from '~/components/InstallButton';
import { buttonVariants } from '~/styles/Button';
import { DESCRIPTION } from '~/util/constants';
@@ -12,7 +12,7 @@ import { DESCRIPTION } from '~/util/constants';
export default function Page() {
return (
<div className="min-h-screen">
<Banner />
{/* <Banner /> */}
<div className="mx-auto max-w-6xl flex flex-col place-items-center gap-24 px-8 pb-16 pt-12 lg:min-h-[calc(100vh_-_40px)] lg:place-content-center lg:py-10">
<div className="flex flex-col place-items-center gap-10 lg:flex-row lg:gap-6">
<div className="flex flex-col place-items-center gap-10 text-center">
@@ -22,11 +22,11 @@ export default function Page() {
</h1>
<p className="my-6 leading-normal text-neutral-700 dark:text-neutral-300">{DESCRIPTION}</p>
<div className="flex flex-wrap place-content-center gap-4 md:flex-row">
<a className={buttonVariants()} href="https://old.discordjs.dev/#/docs" rel="noopener noreferrer">
{/* <a className={buttonVariants()} href="https://old.discordjs.dev/#/docs" rel="noopener noreferrer">
Docs
</a>
</a> */}
<Link className={buttonVariants()} href={'/docs' as Route}>
Module docs
Docs
</Link>
<a
className={buttonVariants({ variant: 'secondary' })}

View File

@@ -22,6 +22,8 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
return (
<span>
{excerpt.spannedTokens.map((token, idx) => {
// TODO: Real fix in api-extractor needed
const text = token.text.replaceAll('\n', '').replaceAll(/\s{2}$/g, '');
if (token.kind === ExcerptTokenKind.Reference) {
const source = token.canonicalReference?.source;
const symbol = token.canonicalReference?.symbol;
@@ -32,12 +34,12 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
// dapi-types doesn't have routes for class members
// so we can assume this member is for an enum
if (meaning === 'member' && path && 'parent' in path) href += `/enum/${path.parent}#${path.component}`;
else if (meaning === 'type') href += `#${token.text}`;
else href += `/${meaning}/${token.text}`;
else if (meaning === 'type') href += `#${text}`;
else href += `/${meaning}/${text}`;
return (
<a className="text-blurple" href={href} key={idx} rel="external noreferrer noopener" target="_blank">
{token.text}
{text}
</a>
);
}
@@ -45,7 +47,7 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
const item = model.resolveDeclarationReference(token.canonicalReference!, model).resolvedApiItem;
if (!item) {
return token.text;
return text;
}
return (
@@ -55,12 +57,12 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
key={`${item.displayName}-${item.containerKey}-${idx}`}
packageName={item.getAssociatedPackage()?.displayName.replace('@discordjs/', '')}
>
{token.text}
{text}
</ItemLink>
);
}
return token.text.replace(/import\("discord-api-types(?:\/v\d+)?"\)\./, '');
return text.replace(/import\("discord-api-types(?:\/v\d+)?"\)\./, '');
})}
</span>
);

View File

@@ -15,18 +15,18 @@ export default function PackageSelect() {
const packageMenu = useMenuState({ gutter: 8, sameWidth: true, fitViewport: true });
const packageMenuItems = useMemo(
() => [
<a href="https://old.discordjs.dev/#/docs/discord.js" key="discord.js">
<MenuItem
className="my-0.5 rounded bg-white p-3 text-sm outline-none active:bg-light-800 dark:bg-dark-600 hover:bg-light-700 focus:ring focus:ring-width-2 focus:ring-blurple dark:active:bg-dark-400 dark:hover:bg-dark-500"
id="discord-js"
onClick={() => packageMenu.setOpen(false)}
state={packageMenu}
>
discord.js
</MenuItem>
</a>,
...PACKAGES.map((pkg, idx) => (
() =>
// <a href="https://old.discordjs.dev/#/docs/discord.js" key="discord.js">
// <MenuItem
// className="my-0.5 rounded bg-white p-3 text-sm outline-none active:bg-light-800 dark:bg-dark-600 hover:bg-light-700 focus:ring focus:ring-width-2 focus:ring-blurple dark:active:bg-dark-400 dark:hover:bg-dark-500"
// id="discord-js"
// onClick={() => packageMenu.setOpen(false)}
// state={packageMenu}
// >
// discord.js
// </MenuItem>
// </a>,
PACKAGES.map((pkg, idx) => (
<Link href={`/docs/packages/${pkg}/main`} key={`${pkg}-${idx}`}>
<MenuItem
className="my-0.5 rounded bg-white p-3 text-sm outline-none active:bg-light-800 dark:bg-dark-600 hover:bg-light-700 focus:ring focus:ring-width-2 focus:ring-blurple dark:active:bg-dark-400 dark:hover:bg-dark-500"
@@ -38,7 +38,6 @@ export default function PackageSelect() {
</MenuItem>
</Link>
)),
],
[packageMenu],
);

View File

@@ -38,7 +38,7 @@ export function Property({
</CodeHeading>
</div>
{hasSummary || inheritedFrom ? (
<div className="mb-4 flex flex-col gap-4">
<div className="mb-4 w-full flex flex-col gap-4">
{item.tsdocComment ? <TSDoc item={item} tsdoc={item.tsdocComment} /> : null}
{inheritedFrom ? <InheritanceText parent={inheritedFrom} /> : null}
{children}

View File

@@ -1,6 +1,7 @@
'use client';
import { VscListSelection } from '@react-icons/all-files/vsc/VscListSelection';
import { VscSymbolEvent } from '@react-icons/all-files/vsc/VscSymbolEvent';
import { VscSymbolMethod } from '@react-icons/all-files/vsc/VscSymbolMethod';
import { VscSymbolProperty } from '@react-icons/all-files/vsc/VscSymbolProperty';
import { useMemo } from 'react';
@@ -16,7 +17,15 @@ export interface TableOfContentsSerializedProperty {
name: string;
}
export type TableOfContentsSerialized = TableOfContentsSerializedMethod | TableOfContentsSerializedProperty;
export interface TableOfContentsSerializedEvent {
kind: 'Event';
name: string;
}
export type TableOfContentsSerialized =
| TableOfContentsSerializedEvent
| TableOfContentsSerializedMethod
| TableOfContentsSerializedProperty;
export interface TableOfContentsItemProps {
readonly serializedMembers: TableOfContentsSerialized[];
@@ -57,6 +66,19 @@ export function TableOfContentsMethodItem({ method }: { readonly method: TableOf
);
}
export function TableOfContentsEventItem({ event }: { readonly event: TableOfContentsSerializedEvent }) {
return (
<a
className="ml-[10px] border-l border-light-800 p-[5px] pl-6.5 text-sm outline-none focus:border-0 dark:border-dark-100 focus:rounded active:bg-light-800 hover:bg-light-700 focus:ring focus:ring-width-2 focus:ring-blurple dark:active:bg-dark-100 dark:hover:bg-dark-200"
href={`#${event.name}`}
key={`${event.name}-${event.kind}`}
title={event.name}
>
<span className="line-clamp-1">{event.name}</span>
</a>
);
}
export function TableOfContentItems({ serializedMembers }: TableOfContentsItemProps) {
const propertyItems = useMemo(
() =>
@@ -85,6 +107,14 @@ export function TableOfContentItems({ serializedMembers }: TableOfContentsItemPr
[serializedMembers],
);
const eventItems = useMemo(
() =>
serializedMembers
.filter((member): member is TableOfContentsSerializedEvent => member.kind === 'Event')
.map((event, idx) => <TableOfContentsEventItem key={`${event.name}-${event.kind}-${idx}`} event={event} />),
[serializedMembers],
);
return (
<div className="flex flex-col break-all p-3 pb-8">
<div className="ml-2 mt-4 flex flex-row gap-2">
@@ -92,6 +122,17 @@ export function TableOfContentItems({ serializedMembers }: TableOfContentsItemPr
<span className="font-semibold">Contents</span>
</div>
<div className="ml-2 mt-5.5 flex flex-col gap-2">
{eventItems.length ? (
<div className="flex flex-col">
<div className="flex flex-row place-items-center gap-4">
<VscSymbolEvent size={20} />
<div className="p-3 pl-0">
<span className="font-semibold">Properties</span>
</div>
</div>
{eventItems}
</div>
) : null}
{propertyItems.length ? (
<div className="flex flex-col">
<div className="flex flex-row place-items-center gap-4">

View File

@@ -1,11 +1,13 @@
import type { ApiDeclaredItem, ApiItemContainerMixin } from '@discordjs/api-extractor-model';
import { EventsSection } from './section/EventsSection';
import { MethodsSection } from './section/MethodsSection';
import { PropertiesSection } from './section/PropertiesSection';
import { hasProperties, hasMethods } from './util';
import { hasEvents, hasProperties, hasMethods } from './util';
export function Members({ item }: { readonly item: ApiDeclaredItem & ApiItemContainerMixin }) {
return (
<>
{hasEvents(item) ? <EventsSection item={item} /> : null}
{hasProperties(item) ? <PropertiesSection item={item} /> : null}
{hasMethods(item) ? <MethodsSection item={item} /> : null}
</>

View File

@@ -0,0 +1,42 @@
import {
ApiItemKind,
type ApiEvent,
type ApiItem,
type ApiItemContainerMixin,
type ApiDeclaredItem,
} from '@discordjs/api-extractor-model';
import { VscSymbolEvent } from '@react-icons/all-files/vsc/VscSymbolEvent';
import { Fragment, useMemo } from 'react';
import { Event } from '~/components/model/Event';
import { resolveMembers } from '~/util/members';
import { DocumentationSection } from './DocumentationSection';
function isEventLike(item: ApiItem): item is ApiEvent {
return item.kind === ApiItemKind.Event;
}
export function EventsSection({ item }: { readonly item: ApiItemContainerMixin }) {
const members = resolveMembers(item, isEventLike);
const eventItems = useMemo(
() =>
members.map((event, idx) => {
return (
<Fragment key={`${event.item.displayName}-${idx}`}>
<Event
inheritedFrom={event.inherited as ApiDeclaredItem & ApiItemContainerMixin}
item={event.item as ApiEvent}
/>
<div className="border-t-2 border-light-900 dark:border-dark-100" />
</Fragment>
);
}),
[members],
);
return (
<DocumentationSection icon={<VscSymbolEvent size={20} />} padded title="Events">
<div className="flex flex-col gap-4">{eventItems}</div>
</DocumentationSection>
);
}

View File

@@ -32,7 +32,9 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc:
const { codeDestination, urlDestination, linkText } = tsdoc as DocLinkTag;
if (codeDestination) {
const foundItem = item.getAssociatedModel()?.resolveDeclarationReference(codeDestination, item)
// TODO: Real fix in api-extractor needed
const currentItem = item.getAssociatedPackage();
const foundItem = item.getAssociatedModel()?.resolveDeclarationReference(codeDestination, currentItem)
.resolvedApiItem;
if (!foundItem) return null;

View File

@@ -8,6 +8,7 @@ import type {
ApiPropertySignature,
ApiDocumentedItem,
ApiParameterListMixin,
ApiEvent,
} from '@discordjs/api-extractor-model';
import { METHOD_SEPARATOR, OVERLOAD_SEPARATOR } from '~/util/constants';
import { resolveMembers } from '~/util/members';
@@ -26,6 +27,10 @@ export function hasMethods(item: ApiItemContainerMixin) {
);
}
export function hasEvents(item: ApiItemContainerMixin) {
return resolveMembers(item, memberPredicate).some(({ item: member }) => member.kind === ApiItemKind.Event);
}
export function resolveItemURI(item: ApiItem): string {
return !item.parent || item.parent.kind === ApiItemKind.EntryPoint
? `${item.displayName}${OVERLOAD_SEPARATOR}${item.kind}`
@@ -34,12 +39,13 @@ export function resolveItemURI(item: ApiItem): string {
export function memberPredicate(
item: ApiItem,
): item is ApiMethod | ApiMethodSignature | ApiProperty | ApiPropertySignature {
): item is ApiEvent | ApiMethod | ApiMethodSignature | ApiProperty | ApiPropertySignature {
return (
item.kind === ApiItemKind.Property ||
item.kind === ApiItemKind.PropertySignature ||
item.kind === ApiItemKind.Method ||
item.kind === ApiItemKind.MethodSignature
item.kind === ApiItemKind.MethodSignature ||
item.kind === ApiItemKind.Event
);
}
@@ -50,6 +56,11 @@ export function serializeMembers(clazz: ApiItemContainerMixin): TableOfContentsS
kind: member.kind as 'Method' | 'MethodSignature',
name: member.displayName,
};
} else if (member.kind === 'Event') {
return {
kind: member.kind as 'Event',
name: member.displayName,
};
} else {
return {
kind: member.kind as 'Property' | 'PropertySignature',

View File

@@ -0,0 +1,39 @@
import type { ApiDeclaredItem, ApiItemContainerMixin, ApiEvent } from '@discordjs/api-extractor-model';
import { Badges } from '../Badges';
import { CodeHeading } from '../CodeHeading';
import { InheritanceText } from '../InheritanceText';
import { ParameterTable } from '../ParameterTable';
import { TSDoc } from '../documentation/tsdoc/TSDoc';
import { parametersString } from '../documentation/util';
export function Event({
item,
inheritedFrom,
}: {
readonly inheritedFrom?: (ApiDeclaredItem & ApiItemContainerMixin) | undefined;
readonly item: ApiEvent;
}) {
const hasSummary = Boolean(item.tsdocComment?.summarySection);
return (
<div className="flex flex-col scroll-mt-30 gap-4" id={item.displayName}>
<div className="flex flex-col gap-2 md:-ml-9">
<Badges item={item} />
<CodeHeading
href={`#${item.displayName}`}
sourceURL={item.sourceLocation.fileUrl}
sourceLine={item.sourceLocation.fileLine}
>
{`${item.name}(${parametersString(item)})`}
</CodeHeading>
</div>
{hasSummary || inheritedFrom ? (
<div className="mb-4 w-full flex flex-col gap-4">
{item.tsdocComment ? <TSDoc item={item} tsdoc={item.tsdocComment} /> : null}
{item.parameters.length ? <ParameterTable item={item} /> : null}
{inheritedFrom ? <InheritanceText parent={inheritedFrom} /> : null}
</div>
) : null}
</div>
);
}

View File

@@ -1,8 +1,9 @@
import type {
ApiDeclaredItem,
ApiItemContainerMixin,
ApiMethod,
ApiMethodSignature,
import {
ApiItemKind,
type ApiDeclaredItem,
type ApiItemContainerMixin,
type ApiMethod,
type ApiMethodSignature,
} from '@discordjs/api-extractor-model';
import dynamic from 'next/dynamic';
import { Fragment } from 'react';
@@ -18,15 +19,23 @@ export function Method({
readonly inheritedFrom?: (ApiDeclaredItem & ApiItemContainerMixin) | undefined;
readonly method: ApiMethod | ApiMethodSignature;
}) {
if (method.getMergedSiblings().length > 1) {
if (
method
.getMergedSiblings()
.filter((sibling) => sibling.kind === ApiItemKind.Method || sibling.kind === ApiItemKind.MethodSignature).length >
1
) {
// We have overloads, use the overload switcher, but render
// each overload node on the server.
const overloads = method.getMergedSiblings().map((sibling, idx) => (
<Fragment key={`${sibling.displayName}-${idx}`}>
<MethodHeader method={sibling as ApiMethod | ApiMethodSignature} />
<MethodDocumentation method={sibling as ApiMethod | ApiMethodSignature} />
</Fragment>
));
const overloads = method
.getMergedSiblings()
.filter((sibling) => sibling.kind === ApiItemKind.Method || sibling.kind === ApiItemKind.MethodSignature)
.map((sibling, idx) => (
<Fragment key={`${sibling.displayName}-${idx}`}>
<MethodHeader method={sibling as ApiMethod | ApiMethodSignature} />
<MethodDocumentation method={sibling as ApiMethod | ApiMethodSignature} />
</Fragment>
));
return <OverloadSwitcher methodName={method.displayName} overloads={overloads} />;
}

View File

@@ -21,7 +21,7 @@ export function MethodDocumentation({ method, inheritedFrom }: MethodDocumentati
}
return (
<div className="mb-4 flex flex-col gap-4">
<div className="mb-4 w-full flex flex-col gap-4">
{method.tsdocComment ? <TSDoc item={method} tsdoc={method.tsdocComment} /> : null}
{method.parameters.length ? <ParameterTable item={method} /> : null}
{inheritedFrom && parent ? <InheritanceText parent={inheritedFrom} /> : null}

View File

@@ -12,7 +12,7 @@ export function MethodHeader({ method }: { readonly method: ApiMethod | ApiMetho
);
return (
<div className="flex flex-col scroll-mt-30" id={key}>
<div className="w-full flex flex-col scroll-mt-30" id={key}>
<div className="flex flex-col gap-2 md:-ml-9">
<Badges item={method} />
<CodeHeading

View File

@@ -21,7 +21,7 @@ async function fetchLatestVersion(packageName: string) {
]);
// @ts-expect-error: https://github.com/planetscale/database-js/issues/71
return rows[0].data.at(1);
return rows.map((row) => row.version).at(1);
}
export default async function middleware(request: NextRequest) {
@@ -35,9 +35,9 @@ export default async function middleware(request: NextRequest) {
} catch {}
}
if (request.nextUrl.pathname.includes('discord.js')) {
/* if (request.nextUrl.pathname.includes('discord.js')) {
return NextResponse.redirect('https://old.discordjs.dev/#/docs/discord.js');
}
} */
if (PACKAGES.some((pkg) => request.nextUrl.pathname.includes(pkg))) {
// eslint-disable-next-line prefer-named-capture-group
@@ -52,5 +52,5 @@ export default async function middleware(request: NextRequest) {
}
export const config = {
matcher: ['/docs', '/docs/packages/discord.js(.*)?', '/docs/packages/:package/stable/:member*'],
matcher: ['/docs', /* '/docs/packages/discord.js(.*)?',*/ '/docs/packages/:package/stable/:member*'],
};

View File

@@ -4,17 +4,23 @@ import { TSDocConfiguration } from '@microsoft/tsdoc';
import { TSDocConfigFile } from '@microsoft/tsdoc-config';
export function addPackageToModel(model: ApiModel, data: any) {
const tsdocConfiguration = new TSDocConfiguration();
const tsdocConfigFile = TSDocConfigFile.loadFromObject(data.metadata.tsdocConfig);
tsdocConfigFile.configureParser(tsdocConfiguration);
let apiPackage: ApiPackage;
if (data.metadata) {
const tsdocConfiguration = new TSDocConfiguration();
const tsdocConfigFile = TSDocConfigFile.loadFromObject(data.metadata.tsdocConfig);
tsdocConfigFile.configureParser(tsdocConfiguration);
apiPackage = ApiItem.deserialize(data, {
apiJsonFilename: '',
toolPackage: data.metadata.toolPackage,
toolVersion: data.metadata.toolVersion,
versionToDeserialize: data.metadata.schemaVersion,
tsdocConfiguration,
}) as ApiPackage;
} else {
apiPackage = ApiItem.deserializeDocgen(data, 'discord.js') as ApiPackage;
}
const apiPackage = ApiItem.deserialize(data, {
apiJsonFilename: '',
toolPackage: data.metadata.toolPackage,
toolVersion: data.metadata.toolVersion,
versionToDeserialize: data.metadata.schemaVersion,
tsdocConfiguration,
}) as ApiPackage;
model.addMember(apiPackage);
return model;
}

View File

@@ -1,4 +1,5 @@
export const PACKAGES = [
'discord.js',
'brokers',
'builders',
'collection',

View File

@@ -1,5 +1,4 @@
import { ApiModel, ApiFunction } from '@discordjs/api-extractor-model';
import { notFound } from 'next/navigation';
import { fetchModelJSON } from '~/app/docAPI';
import { addPackageToModel } from './addPackageToModel';
import { OVERLOAD_SEPARATOR, PACKAGES } from './constants';
@@ -13,7 +12,7 @@ export interface ItemRouteParams {
export async function fetchMember({ package: packageName, version: branchName = 'main', item }: ItemRouteParams) {
if (!PACKAGES.includes(packageName)) {
notFound();
return null;
}
const model = new ApiModel();
@@ -22,10 +21,19 @@ export async function fetchMember({ package: packageName, version: branchName =
const modelJSONFiles = await Promise.all(PACKAGES.map(async (pkg) => fetchModelJSON(pkg, branchName)));
for (const modelJSONFile of modelJSONFiles) {
if (!modelJSONFile) {
continue;
}
addPackageToModel(model, modelJSONFile);
}
} else {
const modelJSON = await fetchModelJSON(packageName, branchName);
if (!modelJSON) {
return null;
}
addPackageToModel(model, modelJSON);
}

View File

@@ -8,7 +8,7 @@ import type {
import type { DocSection } from '@microsoft/tsdoc';
export function findMemberByKey(model: ApiModel, packageName: string, containerKey: string) {
const pkg = model.tryGetPackageByName(`@discordjs/${packageName}`)!;
const pkg = model.tryGetPackageByName(packageName === 'discord.js' ? packageName : `@discordjs/${packageName}`)!;
return (pkg.members[0] as ApiEntryPoint).tryGetMemberByKey(containerKey);
}
@@ -17,7 +17,7 @@ export function findMember(model: ApiModel, packageName: string, memberName: str
return undefined;
}
const pkg = model.tryGetPackageByName(`@discordjs/${packageName}`)!;
const pkg = model.tryGetPackageByName(packageName === 'discord.js' ? packageName : `@discordjs/${packageName}`)!;
return pkg.entryPoints[0]?.findMembersByName(memberName)[0];
}