mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-11 17:13:31 +01:00
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:
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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],
|
||||
);
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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}
|
||||
</>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
|
||||
39
apps/website/src/components/model/Event.tsx
Normal file
39
apps/website/src/components/model/Event.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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} />;
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user