diff --git a/apps/website/package.json b/apps/website/package.json index ee4dbbd24..ad202ff1a 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -54,7 +54,7 @@ "ariakit": "^2.0.0-next.41", "cmdk": "^0.1.20", "meilisearch": "^0.30.0", - "next": "^13.0.7-canary.1", + "next": "^13.1.2-canary.4", "next-mdx-remote": "^4.2.0", "next-themes": "npm:@wits/next-themes@latest", "react": "^18.2.0", diff --git a/apps/website/src/app/docAPI.ts b/apps/website/src/app/docAPI.ts new file mode 100644 index 000000000..85f7a0800 --- /dev/null +++ b/apps/website/src/app/docAPI.ts @@ -0,0 +1,26 @@ +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; + +export async function fetchVersions(packageName: string): Promise { + const response = await fetch(`https://docs.discordjs.dev/api/info?package=${packageName}`, { + next: { revalidate: 3_600 }, + }); + + return response.json(); +} + +export async function fetchModelJSON(packageName: string, version: string): Promise { + if (process.env.NEXT_PUBLIC_LOCAL_DEV) { + const res = await readFile( + join(process.cwd(), '..', '..', 'packages', packageName, 'docs', 'docs.api.json'), + 'utf8', + ); + return JSON.parse(res); + } + + const response = await fetch(`https://docs.discordjs.dev/docs/${packageName}/${version}.api.json`, { + next: { revalidate: 3_600 }, + }); + + return response.json(); +} diff --git a/apps/website/src/app/docs/packages/[package]/[...slug]/page.tsx b/apps/website/src/app/docs/packages/[package]/[...slug]/page.tsx deleted file mode 100644 index 800bb507b..000000000 --- a/apps/website/src/app/docs/packages/[package]/[...slug]/page.tsx +++ /dev/null @@ -1,382 +0,0 @@ -/* eslint-disable no-case-declarations */ -import { readFile } from 'node:fs/promises'; -import { join } from 'node:path'; -// eslint-disable-next-line n/prefer-global/process -import process, { cwd } from 'node:process'; -import { - findPackage, - getMembers, - type ApiItemJSON, - type ApiClassJSON, - type ApiFunctionJSON, - type ApiInterfaceJSON, - type ApiTypeAliasJSON, - type ApiVariableJSON, - type ApiEnumJSON, -} from '@discordjs/api-extractor-utils'; -import { createApiModel } from '@discordjs/scripts'; -import { ApiFunction, ApiItemKind, type ApiPackage } from '@microsoft/api-extractor-model'; -import Image from 'next/image'; -// import Head from 'next/head'; -import { notFound } from 'next/navigation'; -import { serialize } from 'next-mdx-remote/serialize'; -import rehypeIgnore from 'rehype-ignore'; -import rehypePrettyCode, { type Options } from 'rehype-pretty-code'; -import rehypeRaw from 'rehype-raw'; -import rehypeSlug from 'rehype-slug'; -import remarkGfm from 'remark-gfm'; -import { getHighlighter } from 'shiki'; -import shikiLangJavascript from 'shiki/languages/javascript.tmLanguage.json'; -import shikiLangTypescript from 'shiki/languages/typescript.tmLanguage.json'; -import shikiThemeDarkPlus from 'shiki/themes/dark-plus.json'; -import shikiThemeLightPlus from 'shiki/themes/light-plus.json'; -import vercelLogo from '../../../../../assets/powered-by-vercel.svg'; -import { MDXRemote } from '~/components/MDXRemote'; -import { Nav } from '~/components/Nav'; -import { Class } from '~/components/model/Class'; -import { Enum } from '~/components/model/Enum'; -import { Function } from '~/components/model/Function'; -import { Interface } from '~/components/model/Interface'; -import { TypeAlias } from '~/components/model/TypeAlias'; -import { Variable } from '~/components/model/Variable'; -import { MemberProvider } from '~/contexts/member'; -import { DESCRIPTION, PACKAGES } from '~/util/constants'; -import { findMember, findMemberByKey } from '~/util/model.server'; -import { tryResolveDescription } from '~/util/summary'; - -export async function generateStaticParams({ params }: { params?: { package: string } }) { - const packageName = params?.package ?? 'builders'; - - try { - let data: any[] = []; - let versions: string[] = []; - if (process.env.NEXT_PUBLIC_LOCAL_DEV) { - const res = await readFile(join(cwd(), '..', '..', 'packages', packageName, 'docs', 'docs.api.json'), 'utf8'); - data = JSON.parse(res); - } else { - const response = await fetch(`https://docs.discordjs.dev/api/info?package=${packageName}`, { - next: { revalidate: 3_600 }, - }); - versions = await response.json(); - versions = versions.slice(-2); - - for (const version of versions) { - const res = await fetch(`https://docs.discordjs.dev/docs/${packageName}/${version}.api.json`); - data = [...data, await res.json()]; - } - } - - if (Array.isArray(data)) { - const models = data.map((innerData) => createApiModel(innerData)); - const pkgs = models.map((model) => findPackage(model, packageName)) as ApiPackage[]; - - return [ - ...versions.map((version) => ({ slug: [version] })), - ...pkgs.flatMap((pkg, idx) => - getMembers(pkg, versions[idx] ?? 'main').map((member) => { - if (member.kind === ApiItemKind.Function && member.overloadIndex && member.overloadIndex > 1) { - return { - slug: [versions[idx] ?? 'main', `${member.name}:${member.overloadIndex}:${member.kind}`], - }; - } - - return { - slug: [versions[idx] ?? 'main', `${member.name}:${member.kind}`], - }; - }), - ), - ]; - } - - const model = createApiModel(data); - const pkg = findPackage(model, packageName)!; - - return [ - { slug: ['main'] }, - ...getMembers(pkg, 'main').map((member) => { - if (member.kind === ApiItemKind.Function && member.overloadIndex && member.overloadIndex > 1) { - return { - slug: ['main', `${member.name}:${member.overloadIndex}:${member.kind}`], - }; - } - - return { slug: ['main', `${member.name}:${member.kind}`] }; - }), - ]; - } catch { - return [{ slug: ['main'] }]; - } -} - -async function getData(packageName: string, slug: string[]) { - const [branchName = 'main', member] = slug; - - if (!PACKAGES.includes(packageName)) { - notFound(); - } - - let data; - try { - if (process.env.NEXT_PUBLIC_LOCAL_DEV) { - const res = await readFile(join(cwd(), '..', '..', 'packages', packageName, 'docs', 'docs.api.json'), 'utf8'); - data = JSON.parse(res); - } else { - const res = await fetch(`https://docs.discordjs.dev/docs/${packageName}/${branchName}.api.json`); - data = await res.json(); - } - } catch { - notFound(); - } - - const [memberName, overloadIndex] = member?.split('%3A') ?? []; - - const readme = await readFile(join(cwd(), 'src', 'assets', 'readme', packageName, 'home-README.md'), 'utf8'); - - const mdxSource = await serialize(readme, { - mdxOptions: { - remarkPlugins: [remarkGfm], - remarkRehypeOptions: { allowDangerousHtml: true }, - rehypePlugins: [ - rehypeRaw, - rehypeIgnore, - rehypeSlug, - [ - rehypePrettyCode, - { - theme: { - dark: shikiThemeDarkPlus, - light: shikiThemeLightPlus, - }, - getHighlighter: async (options?: Partial) => - getHighlighter({ - ...options, - langs: [ - // @ts-expect-error: Working as intended - { id: 'javascript', aliases: ['js'], scopeName: 'source.js', grammar: shikiLangJavascript }, - // @ts-expect-error: Working as intended - { id: 'typescript', aliases: ['ts'], scopeName: 'source.ts', grammar: shikiLangTypescript }, - ], - }), - }, - ], - ], - format: 'md', - }, - }); - - const model = createApiModel(data); - const pkg = findPackage(model, packageName); - - // eslint-disable-next-line prefer-const - let { containerKey, name } = findMember(model, packageName, memberName, branchName) ?? {}; - if (name && overloadIndex && !Number.isNaN(Number.parseInt(overloadIndex, 10))) { - containerKey = ApiFunction.getContainerKey(name, Number.parseInt(overloadIndex, 10)); - } - - const members = pkg - ? getMembers(pkg, branchName).filter((item) => item.overloadIndex === null || item.overloadIndex <= 1) - : []; - const foundMember = - memberName && containerKey ? findMemberByKey(model, packageName, containerKey, branchName) ?? null : null; - const description = foundMember ? tryResolveDescription(foundMember) ?? DESCRIPTION : DESCRIPTION; - - return { - packageName, - branchName, - data: { - members, - member: foundMember, - description, - source: mdxSource, - }, - }; -} - -// function resolveMember(packageName?: string | undefined, member?: SidebarLayoutProps['data']['member']) { -// switch (member?.kind) { -// case 'Class': { -// const typedMember = member as ApiClassJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}&methods=${typedMember.methods.length}&props=${typedMember.properties.length}`; -// } - -// case 'Function': { -// const typedMember = member as ApiFunctionJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}`; -// } - -// case 'Interface': { -// const typedMember = member as ApiInterfaceJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}&methods=${typedMember.methods.length}&props=${typedMember.properties.length}`; -// } - -// case 'TypeAlias': { -// const typedMember = member as ApiTypeAliasJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}`; -// } - -// case 'Variable': { -// const typedMember = member as ApiVariableJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}`; -// } - -// case 'Enum': { -// const typedMember = member as ApiEnumJSON; -// return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}&members=${typedMember.members.length}`; -// } - -// default: { -// return `?pkg=${packageName}&kind=${member?.kind}&name=${member?.name}`; -// } -// } -// } - -function member(props?: ApiItemJSON | undefined) { - switch (props?.kind) { - case 'Class': - return ; - case 'Function': - return ; - case 'Interface': - return ; - case 'TypeAlias': - return ; - case 'Variable': - return ; - case 'Enum': - return ; - default: - return
Cannot render that item type
; - } -} - -export default async function Page({ params }: { params: { package: string; slug: string[] } }) { - const data = await getData(params.package, params.slug); - - // const name = useMemo( - // () => `discord.js${params.data?.member?.name ? ` | ${params.data.member.name}` : ''}`, - // [params.data?.member?.name], - // ); - // const ogTitle = useMemo( - // () => `${params.packageName ?? 'discord.js'}${params.data?.member?.name ? ` | ${params.data.member.name}` : ''}`, - // [params.packageName, params.data?.member?.name], - // ); - // const ogImage = useMemo( - // () => resolveMember(params.packageName, params.data?.member), - // [params.packageName, params.data?.member], - // ); - - // Just in case - // return ; - - return ( - -