mirror of
https://github.com/discordjs/discord.js.git
synced 2026-05-23 03:50:09 +00:00
Compare commits
42 Commits
@discordjs
...
@discordjs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae58053dc8 | ||
|
|
5da5be2bc9 | ||
|
|
55be1c901a | ||
|
|
492f86af39 | ||
|
|
9868772b64 | ||
|
|
6df233de14 | ||
|
|
0aa7dc1b86 | ||
|
|
cab60142ff | ||
|
|
4b88306dcb | ||
|
|
f9177be61b | ||
|
|
75137bac6f | ||
|
|
00063912ee | ||
|
|
8f432400d8 | ||
|
|
75fc7f2454 | ||
|
|
01c63d2e0f | ||
|
|
ffc3ea5c3f | ||
|
|
1d2d01e1f5 | ||
|
|
0063dae43b | ||
|
|
69c949ab28 | ||
|
|
25d552b318 | ||
|
|
c4767bacde | ||
|
|
9a8110047e | ||
|
|
d4ebc369ca | ||
|
|
b150d4ac27 | ||
|
|
81a892e27f | ||
|
|
bc8f83368a | ||
|
|
7c935dc84b | ||
|
|
8d04cbc203 | ||
|
|
356cadb382 | ||
|
|
978a39f6d3 | ||
|
|
516be87a87 | ||
|
|
b79351ba99 | ||
|
|
2d63d93558 | ||
|
|
b305194841 | ||
|
|
2550c7931d | ||
|
|
40726db722 | ||
|
|
1e4ef35436 | ||
|
|
4bc1dae36f | ||
|
|
cc07a28f12 | ||
|
|
f93abf7e35 | ||
|
|
f0ec70dfda | ||
|
|
8a6045f600 |
24
.github/workflows/deploy-website.yml
vendored
24
.github/workflows/deploy-website.yml
vendored
@@ -8,21 +8,19 @@ jobs:
|
||||
deploy-website:
|
||||
name: Deploy website
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
if: github.repository_owner == 'discordjs'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Build & deploy website
|
||||
uses: BetaHuhn/deploy-to-vercel-action@643bc80032ba62ca41d1a9aaba7b38b51c2b8646
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
VERCEL_SCOPE: 'discordjs'
|
||||
GITHUB_DEPLOYMENT_ENV: 'Production – discord-js'
|
||||
PRODUCTION: true
|
||||
- name: Pull vercel production environment
|
||||
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
|
||||
|
||||
- name: Build website artifacts
|
||||
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
|
||||
|
||||
- name: Deploy website artifacts to vercel
|
||||
run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
|
||||
|
||||
25
.github/workflows/documentation.yml
vendored
25
.github/workflows/documentation.yml
vendored
@@ -71,6 +71,7 @@ jobs:
|
||||
if: ${{ github.ref_type == 'tag' }}
|
||||
env:
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||
uses: ./packages/actions/src/uploadDocumentation
|
||||
with:
|
||||
package: ${{ steps.extract-tag.outputs.package }}
|
||||
@@ -94,6 +95,7 @@ jobs:
|
||||
if: ${{ github.ref_type == 'branch' }}
|
||||
env:
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||
uses: ./packages/actions/src/uploadDocumentation
|
||||
|
||||
- name: Move docs to correct directory
|
||||
@@ -149,26 +151,3 @@ jobs:
|
||||
SEARCH_API_URL: ${{ secrets.SEARCH_API_URL }}
|
||||
SEARCH_API_KEY: ${{ secrets.SEARCH_API_KEY }}
|
||||
uses: ./packages/actions/src/uploadSearchIndices
|
||||
|
||||
deploy-website:
|
||||
needs: build-docs
|
||||
name: Deploy website
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
if: github.repository_owner == 'discordjs'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Build & deploy website
|
||||
uses: BetaHuhn/deploy-to-vercel-action@643bc80032ba62ca41d1a9aaba7b38b51c2b8646
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
VERCEL_SCOPE: 'discordjs'
|
||||
GITHUB_DEPLOYMENT_ENV: 'Production – discord-js'
|
||||
PRODUCTION: true
|
||||
|
||||
@@ -89,48 +89,50 @@
|
||||
* DEFAULT VALUE: no overrideTsconfig section
|
||||
*/
|
||||
"overrideTsconfig": {
|
||||
// Type Checking
|
||||
"allowUnreachableCode": false,
|
||||
"allowUnusedLabels": false,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noPropertyAccessFromIndexSignature": false,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"strict": true,
|
||||
"compilerOptions": {
|
||||
// Type Checking
|
||||
"allowUnreachableCode": false,
|
||||
"allowUnusedLabels": false,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noPropertyAccessFromIndexSignature": false,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"strict": true,
|
||||
|
||||
// Modules
|
||||
"allowArbitraryExtensions": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"resolvePackageJsonExports": false,
|
||||
"resolvePackageJsonImports": false,
|
||||
// Modules
|
||||
"allowArbitraryExtensions": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "nodenext",
|
||||
"resolveJsonModule": true,
|
||||
"resolvePackageJsonExports": false,
|
||||
"resolvePackageJsonImports": false,
|
||||
|
||||
// Emit
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"importHelpers": false,
|
||||
"newLine": "lf",
|
||||
"noEmitHelpers": true,
|
||||
"outDir": "dist",
|
||||
"removeComments": false,
|
||||
"sourceMap": true,
|
||||
// Emit
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"importHelpers": false,
|
||||
"newLine": "lf",
|
||||
"noEmitHelpers": true,
|
||||
"outDir": "dist",
|
||||
"removeComments": false,
|
||||
"sourceMap": true,
|
||||
|
||||
// Interop Constraints
|
||||
"esModuleInterop": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
// Interop Constraints
|
||||
"esModuleInterop": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
|
||||
// Language and Environment
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["ESNext"],
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": true
|
||||
// Language and Environment
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["ESNext"],
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": true
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"ariakit": "2.0.0-next.44",
|
||||
"cmdk": "^0.2.0",
|
||||
"contentlayer": "^0.3.4",
|
||||
"next": "14.0.3-canary.2",
|
||||
"next": "14.0.3-canary.5",
|
||||
"next-contentlayer": "^0.3.4",
|
||||
"next-themes": "^0.2.1",
|
||||
"react": "^18.2.0",
|
||||
@@ -65,7 +65,7 @@
|
||||
"sharp": "^0.32.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "14.0.3-canary.2",
|
||||
"@next/bundle-analyzer": "14.0.3-canary.5",
|
||||
"@testing-library/react": "^14.1.0",
|
||||
"@testing-library/user-event": "^14.5.1",
|
||||
"@types/html-escaper": "^3.0.2",
|
||||
@@ -86,7 +86,7 @@
|
||||
"hastscript": "^8.0.0",
|
||||
"html-escaper": "^3.0.3",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"turbo": "^1.10.17-canary.0",
|
||||
"typescript": "^5.2.2",
|
||||
"unocss": "^0.57.3",
|
||||
|
||||
@@ -23,7 +23,9 @@ export function Nav() {
|
||||
)}
|
||||
universal
|
||||
>
|
||||
<Sidebar />
|
||||
<div className="flex flex-col gap-4 p-3">
|
||||
<Sidebar />
|
||||
</div>
|
||||
</Scrollbars>
|
||||
</nav>
|
||||
);
|
||||
|
||||
@@ -32,7 +32,7 @@ export function Sidebar() {
|
||||
const { setOpened } = useNav();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-3 p-3">
|
||||
<div className="flex flex-col gap-4">
|
||||
{Object.keys(itemsByCategory).map((category, idx) => (
|
||||
<Section
|
||||
buttonClassName="bg-light-600 hover:bg-light-700 active:bg-light-800 dark:bg-dark-400 dark:hover:bg-dark-300 dark:active:bg-dark-400 focus:ring-width-2 focus:ring-blurple rounded p-3 outline-none focus:ring z-10"
|
||||
@@ -41,7 +41,7 @@ export function Sidebar() {
|
||||
>
|
||||
{itemsByCategory[category]?.map((member, index) => (
|
||||
<Link
|
||||
className={`dark:border-dark-100 border-light-800 focus:ring-width-2 focus:ring-blurple ml-5 flex flex-col border-l p-[5px] pl-6 outline-none focus:rounded focus:border-0 focus:ring ${
|
||||
className={`dark:border-dark-100 border-light-800 focus:ring-width-2 focus:ring-blurple ml-5 flex flex-col border-l first:mt-1 p-[5px] pl-6 outline-none focus:rounded focus:border-0 focus:ring ${
|
||||
decodeURIComponent(pathname ?? '') === member.href
|
||||
? 'bg-blurple text-white'
|
||||
: 'dark:hover:bg-dark-200 dark:active:bg-dark-100 hover:bg-light-700 active:bg-light-800'
|
||||
|
||||
2
apps/website/.lintstagedrc.cjs
Normal file
2
apps/website/.lintstagedrc.cjs
Normal file
@@ -0,0 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
@@ -1 +0,0 @@
|
||||
export * from '../../.lintstagedrc.json' assert { type: 'json' };
|
||||
2
apps/website/.prettierrc.cjs
Normal file
2
apps/website/.prettierrc.cjs
Normal file
@@ -0,0 +1,2 @@
|
||||
/** @type {import('prettier').Config} */
|
||||
module.exports = require('../../.prettierrc.json');
|
||||
@@ -1 +0,0 @@
|
||||
export * from '../../.prettierrc.json' assert { type: 'json' };
|
||||
@@ -52,17 +52,17 @@
|
||||
"@discordjs/ui": "workspace:^",
|
||||
"@microsoft/tsdoc": "^0.14.2",
|
||||
"@microsoft/tsdoc-config": "0.16.2",
|
||||
"@planetscale/database": "^1.11.0",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@vercel/analytics": "^1.1.1",
|
||||
"@vercel/edge-config": "^0.4.1",
|
||||
"@vercel/og": "^0.5.20",
|
||||
"@vercel/postgres": "^0.5.1",
|
||||
"ariakit": "2.0.0-next.44",
|
||||
"bright": "^0.8.4",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"cmdk": "^0.2.0",
|
||||
"meilisearch": "^0.35.0",
|
||||
"next": "14.0.3-canary.2",
|
||||
"next": "14.0.3-canary.5",
|
||||
"next-mdx-remote": "^4.4.1",
|
||||
"next-themes": "^0.2.1",
|
||||
"react": "^18.2.0",
|
||||
@@ -74,7 +74,7 @@
|
||||
"sharp": "^0.32.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "14.0.3-canary.2",
|
||||
"@next/bundle-analyzer": "14.0.3-canary.5",
|
||||
"@testing-library/react": "^14.1.0",
|
||||
"@testing-library/user-event": "^14.5.1",
|
||||
"@types/node": "18.18.8",
|
||||
@@ -92,7 +92,7 @@
|
||||
"eslint-formatter-pretty": "^5.0.0",
|
||||
"happy-dom": "^12.10.3",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"turbo": "^1.10.17-canary.0",
|
||||
"typescript": "^5.2.2",
|
||||
"vercel": "^32.5.3",
|
||||
|
||||
@@ -3,13 +3,9 @@ import { generateAllIndices } from '@discordjs/scripts';
|
||||
|
||||
console.log('Generating all indices...');
|
||||
await generateAllIndices({
|
||||
fetchPackageVersions: async (pkg) => {
|
||||
console.log(`Fetching versions for ${pkg}...`);
|
||||
return ['main'];
|
||||
},
|
||||
fetchPackageVersionDocs: async (pkg, version) => {
|
||||
console.log(`Fetching data for ${pkg} ${version}...`);
|
||||
return JSON.parse(await readFile(`${process.cwd()}/../../packages/${pkg}/docs/docs.api.json`, 'utf8'));
|
||||
return JSON.parse(await readFile(`${process.cwd()}/../../../docs/${pkg}/${version}.api.json`, 'utf8'));
|
||||
},
|
||||
});
|
||||
console.log('Generated all indices.');
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import type { ApiItemKind } from '@discordjs/api-extractor-model';
|
||||
import { ImageResponse } from '@vercel/og';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { resolvePackageName } from '~/util/resolvePackageName';
|
||||
|
||||
export const runtime = 'edge';
|
||||
|
||||
@@ -87,7 +88,7 @@ export async function GET(request: NextRequest) {
|
||||
const hasMethods = searchParams.has('methods');
|
||||
const hasProps = searchParams.has('props');
|
||||
const hasMembers = searchParams.has('members');
|
||||
const pkg = hasPkg ? searchParams.get('pkg') : '';
|
||||
const pkg = hasPkg ? resolvePackageName(searchParams.get('pkg')!) : '';
|
||||
const kind = hasKind ? searchParams.get('kind')! : 'Method';
|
||||
const name = hasName ? searchParams.get('name')!.slice(0, 100) : 'My default name which is super long to overflow';
|
||||
const methods = hasMethods ? searchParams.get('methods') : '';
|
||||
@@ -103,7 +104,7 @@ export async function GET(request: NextRequest) {
|
||||
tw="flex flex-row bg-[#181818] h-full w-full p-24"
|
||||
>
|
||||
<div tw="flex flex-col mx-auto h-full text-white">
|
||||
<div tw="flex flex-row text-4xl text-gray-400">@discordjs/{pkg}</div>
|
||||
<div tw="flex flex-row text-4xl text-gray-400">{pkg}</div>
|
||||
<div tw="flex flex-col justify-between h-full w-full pt-14">
|
||||
<div tw="flex flex-row items-center max-w-full">
|
||||
<span tw="mr-6">{resolveIcon(kind as keyof typeof ApiItemKind)}</span>
|
||||
|
||||
@@ -1,36 +1,23 @@
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { connect } from '@planetscale/database';
|
||||
import { cache } from 'react';
|
||||
import { N_RECENT_VERSIONS } from '~/util/constants';
|
||||
import { sql } from '@vercel/postgres';
|
||||
|
||||
const sql = connect({
|
||||
url: process.env.DATABASE_URL!,
|
||||
async fetch(url, init) {
|
||||
delete init?.cache;
|
||||
return fetch(url, { ...init, next: { revalidate: 3_600 } });
|
||||
},
|
||||
});
|
||||
|
||||
export const fetchVersions = cache(async (packageName: string): Promise<string[]> => {
|
||||
if (process.env.NEXT_PUBLIC_LOCAL_DEV || process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview') {
|
||||
export const fetchVersions = async (packageName: string): Promise<string[]> => {
|
||||
if (process.env.NEXT_PUBLIC_LOCAL_DEV === 'true' || process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview') {
|
||||
return ['main'];
|
||||
}
|
||||
|
||||
try {
|
||||
const { rows } = await sql.execute('select version from documentation where name = ? order by version desc', [
|
||||
packageName,
|
||||
]);
|
||||
const { rows } = await sql`select version from documentation where name = ${packageName} order by version desc`;
|
||||
|
||||
// @ts-expect-error: https://github.com/planetscale/database-js/issues/71
|
||||
return rows.map((row) => row.version).slice(0, N_RECENT_VERSIONS);
|
||||
return rows.map((row) => row.version);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchModelJSON = cache(async (packageName: string, version: string) => {
|
||||
if (process.env.NEXT_PUBLIC_LOCAL_DEV) {
|
||||
export const fetchModelJSON = async (packageName: string, version: string) => {
|
||||
if (process.env.NEXT_PUBLIC_LOCAL_DEV === 'true') {
|
||||
try {
|
||||
const res = await readFile(
|
||||
join(process.cwd(), '..', '..', 'packages', packageName, 'docs', 'docs.api.json'),
|
||||
@@ -45,27 +32,21 @@ export const fetchModelJSON = cache(async (packageName: string, version: string)
|
||||
|
||||
if (process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview') {
|
||||
try {
|
||||
const { rows } = await sql.execute('select data from documentation where name = ? and version = ?', [
|
||||
packageName,
|
||||
'main',
|
||||
]);
|
||||
const { rows } = await sql`select url from documentation where name = ${packageName} and version = ${'main'}`;
|
||||
const res = await fetch(rows[0]?.url ?? '');
|
||||
|
||||
// @ts-expect-error: https://github.com/planetscale/database-js/issues/71
|
||||
return rows[0]?.data ?? null;
|
||||
return await res.json();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const { rows } = await sql.execute('select data from documentation where name = ? and version = ?', [
|
||||
packageName,
|
||||
version,
|
||||
]);
|
||||
const { rows } = await sql`select url from documentation where name = ${packageName} and version = ${version}`;
|
||||
const res = await fetch(rows[0]?.url ?? '');
|
||||
|
||||
// @ts-expect-error: https://github.com/planetscale/database-js/issues/71
|
||||
return rows[0]?.data ?? null;
|
||||
return await res.json();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
export default function Loading() {
|
||||
return (
|
||||
<div className="relative top-6 mx-4 min-h-xl flex flex-col items-center justify-center gap-4">
|
||||
<svg
|
||||
className="h-9 w-9 animate-spin text-black dark:text-white"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
|
||||
<path
|
||||
className="opacity-75 dark:opacity-100"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<div className="text-lg font-medium">Loading...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -119,10 +119,14 @@ export async function generateMetadata({ params }: { params: ItemRouteParams })
|
||||
}
|
||||
|
||||
export async function generateStaticParams({ params: { package: packageName, version } }: { params: ItemRouteParams }) {
|
||||
if (process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const modelJSON = await fetchModelJSON(packageName, version);
|
||||
|
||||
if (!modelJSON) {
|
||||
return [{ package: packageName, version, item: '' }];
|
||||
return [];
|
||||
}
|
||||
|
||||
const model = addPackageToModel(new ApiModel(), modelJSON);
|
||||
@@ -131,7 +135,7 @@ export async function generateStaticParams({ params: { package: packageName, ver
|
||||
const entry = pkg?.entryPoints[0];
|
||||
|
||||
if (!entry) {
|
||||
return [{ package: packageName, version, item: '' }];
|
||||
return [];
|
||||
}
|
||||
|
||||
return entry.members.map((member: ApiItem) => ({
|
||||
@@ -168,7 +172,7 @@ export default async function Page({ params }: { params: ItemRouteParams }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative top-6">
|
||||
<div className="relative">
|
||||
<Member member={member} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,14 +2,15 @@ import type { ApiFunction, ApiItem } from '@discordjs/api-extractor-model';
|
||||
import { ApiModel } from '@discordjs/api-extractor-model';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { cache, type PropsWithChildren } from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { fetchModelJSON, fetchVersions } from '~/app/docAPI';
|
||||
import { CmdKDialog } from '~/components/CmdK';
|
||||
import { Nav } from '~/components/Nav';
|
||||
import { Outline } from '~/components/Outline';
|
||||
import type { SidebarSectionItemData } from '~/components/Sidebar';
|
||||
import { resolveItemURI } from '~/components/documentation/util';
|
||||
import { addPackageToModel } from '~/util/addPackageToModel';
|
||||
import { PACKAGES } from '~/util/constants';
|
||||
import { N_RECENT_VERSIONS, PACKAGES } from '~/util/constants';
|
||||
import { Providers } from './providers';
|
||||
|
||||
export const revalidate = 3_600;
|
||||
@@ -23,11 +24,15 @@ interface VersionRouteParams {
|
||||
}
|
||||
|
||||
export const generateStaticParams = async () => {
|
||||
if (process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const params: VersionRouteParams[] = [];
|
||||
|
||||
await Promise.all(
|
||||
PACKAGES.slice(1).map(async (packageName) => {
|
||||
const versions = await fetchVersions(packageName);
|
||||
PACKAGES.map(async (packageName) => {
|
||||
const versions = (await fetchVersions(packageName)).slice(1, N_RECENT_VERSIONS);
|
||||
|
||||
params.push(...versions.map((version) => ({ package: packageName, version })));
|
||||
}),
|
||||
@@ -36,14 +41,14 @@ export const generateStaticParams = async () => {
|
||||
return params;
|
||||
};
|
||||
|
||||
const serializeIntoSidebarItemData = cache((item: ApiItem) => {
|
||||
const serializeIntoSidebarItemData = (item: ApiItem) => {
|
||||
return {
|
||||
kind: item.kind,
|
||||
name: item.displayName,
|
||||
href: resolveItemURI(item),
|
||||
overloadIndex: 'overloadIndex' in item ? (item.overloadIndex as number) : undefined,
|
||||
} as SidebarSectionItemData;
|
||||
});
|
||||
};
|
||||
|
||||
export default async function PackageLayout({ children, params }: PropsWithChildren<{ params: VersionRouteParams }>) {
|
||||
const modelJSON = await fetchModelJSON(params.package, params.version);
|
||||
@@ -80,15 +85,17 @@ export default async function PackageLayout({ children, params }: PropsWithChild
|
||||
<Providers>
|
||||
<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">
|
||||
<div className="relative top-6.5 mx-auto max-w-7xl gap-6 lg:max-w-full lg:flex">
|
||||
<div className="lg:sticky lg:top-23 lg:h-[calc(100vh_-_105px)]">
|
||||
<Nav members={members.map((member) => serializeIntoSidebarItemData(member))} versions={versions} />
|
||||
</div>
|
||||
|
||||
<div className="mx-auto max-w-5xl min-w-xs w-full pb-10">
|
||||
<div className="relative top-4.5 mx-auto max-w-5xl min-w-xs w-full pb-10">
|
||||
{children}
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
<Outline />
|
||||
</div>
|
||||
</main>
|
||||
<CmdKDialog />
|
||||
|
||||
@@ -15,10 +15,6 @@ const loadREADME = cache(async (packageName: string) => {
|
||||
return readFile(join(process.cwd(), 'src', 'assets', 'readme', packageName, 'home-README.md'), 'utf8');
|
||||
});
|
||||
|
||||
export async function generateStaticParams({ params }: { params: VersionRouteParams }) {
|
||||
return [{ package: params.package, version: params.version }];
|
||||
}
|
||||
|
||||
export default async function Page({ params }: { params: VersionRouteParams }) {
|
||||
const readmeSource = await loadREADME(params.package);
|
||||
const { content } = await compileMDX({
|
||||
|
||||
@@ -4,13 +4,16 @@ import type { PropsWithChildren } from 'react';
|
||||
import { CmdKProvider } from '~/contexts/cmdK';
|
||||
import { MemberProvider } from '~/contexts/member';
|
||||
import { NavProvider } from '~/contexts/nav';
|
||||
import { OutlineProvider } from '~/contexts/outline';
|
||||
|
||||
export function Providers({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<NavProvider>
|
||||
<MemberProvider>
|
||||
<CmdKProvider>{children}</CmdKProvider>
|
||||
</MemberProvider>
|
||||
<OutlineProvider>
|
||||
<MemberProvider>
|
||||
<CmdKProvider>{children}</CmdKProvider>
|
||||
</MemberProvider>
|
||||
</OutlineProvider>
|
||||
</NavProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@ export function Badges({ item }: { readonly item: ApiDocumentedItem }) {
|
||||
const isAbstract = ApiAbstractMixin.isBaseClassOf(item) && item.isAbstract;
|
||||
const isDeprecated = Boolean(item.tsdocComment?.deprecatedBlock);
|
||||
|
||||
return (
|
||||
const isAny = isStatic || isProtected || isReadonly || isAbstract || isDeprecated;
|
||||
|
||||
return isAny ? (
|
||||
<div className="flex flex-row gap-1 md:ml-7">
|
||||
{isDeprecated ? <Badge color={BadgeColor.Danger}>Deprecated</Badge> : null}
|
||||
{isProtected ? <Badge>Protected</Badge> : null}
|
||||
@@ -36,5 +38,5 @@ export function Badges({ item }: { readonly item: ApiDocumentedItem }) {
|
||||
{isAbstract ? <Badge>Abstract</Badge> : null}
|
||||
{isReadonly ? <Badge>Readonly</Badge> : null}
|
||||
</div>
|
||||
);
|
||||
) : null;
|
||||
}
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
import type { ApiModel, Excerpt } from '@discordjs/api-extractor-model';
|
||||
import type { Excerpt } from '@discordjs/api-extractor-model';
|
||||
import { ExcerptTokenKind } from '@discordjs/api-extractor-model';
|
||||
import { BuiltinDocumentationLinks } from '~/util/builtinDocumentationLinks';
|
||||
import { DISCORD_API_TYPES_DOCS_URL } from '~/util/constants';
|
||||
import { DocumentationLink } from './DocumentationLink';
|
||||
import { ItemLink } from './ItemLink';
|
||||
import { resolveItemURI } from './documentation/util';
|
||||
import { resolveCanonicalReference, resolveItemURI } from './documentation/util';
|
||||
|
||||
export interface ExcerptTextProps {
|
||||
/**
|
||||
* The tokens to render.
|
||||
*/
|
||||
readonly excerpt: Excerpt;
|
||||
/**
|
||||
* The model to resolve item references from.
|
||||
*/
|
||||
readonly model: ApiModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* A component that renders excerpt tokens from an api item.
|
||||
*/
|
||||
export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
|
||||
export function ExcerptText({ excerpt }: ExcerptTextProps) {
|
||||
return (
|
||||
<span>
|
||||
{excerpt.spannedTokens.map((token, idx) => {
|
||||
@@ -53,20 +49,18 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
|
||||
);
|
||||
}
|
||||
|
||||
const item = token.canonicalReference
|
||||
? model.resolveDeclarationReference(token.canonicalReference!, model).resolvedApiItem
|
||||
: null;
|
||||
const resolved = token.canonicalReference ? resolveCanonicalReference(token.canonicalReference) : null;
|
||||
|
||||
if (!item) {
|
||||
if (!resolved) {
|
||||
return token.text;
|
||||
}
|
||||
|
||||
return (
|
||||
<ItemLink
|
||||
className="text-blurple"
|
||||
itemURI={resolveItemURI(item)}
|
||||
key={`${item.displayName}-${item.containerKey}-${idx}`}
|
||||
packageName={item.getAssociatedPackage()?.displayName.replace('@discordjs/', '')}
|
||||
itemURI={resolveItemURI(resolved.item)}
|
||||
key={`${resolved.item.displayName}-${resolved.item.containerKey}-${idx}`}
|
||||
packageName={resolved.package}
|
||||
>
|
||||
{token.text}
|
||||
</ItemLink>
|
||||
|
||||
@@ -17,7 +17,10 @@ export function InstallButton() {
|
||||
|
||||
return (
|
||||
<button
|
||||
className={buttonVariants({ variant: 'secondary', className: 'cursor-copy font-mono' })}
|
||||
className={buttonVariants({
|
||||
variant: 'secondary',
|
||||
className: 'cursor-copy font-mono',
|
||||
})}
|
||||
onClick={() => {
|
||||
setInteracted(true);
|
||||
copyToClipboard('npm install discord.js');
|
||||
|
||||
@@ -35,10 +35,12 @@ export function Nav({
|
||||
universal
|
||||
>
|
||||
<div className="flex flex-col gap-4 p-3">
|
||||
<PackageSelect />
|
||||
<VersionSelect versions={versions} />
|
||||
<div className="flex flex-col gap-4">
|
||||
<PackageSelect />
|
||||
<VersionSelect versions={versions} />
|
||||
</div>
|
||||
<Sidebar members={members} />
|
||||
</div>
|
||||
<Sidebar members={members} />
|
||||
</Scrollbars>
|
||||
</nav>
|
||||
);
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
'use client';
|
||||
|
||||
import { useOutline } from '~/contexts/outline';
|
||||
import { Scrollbars } from './Scrollbars';
|
||||
import type { TableOfContentsSerialized } from './TableOfContentItems';
|
||||
import { TableOfContentItems } from './TableOfContentItems';
|
||||
|
||||
export function Outline({ members }: { readonly members: TableOfContentsSerialized[] }) {
|
||||
export function Outline() {
|
||||
const { members } = useOutline();
|
||||
|
||||
if (!members) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className="fixed bottom-0 right-0 top-[50px] z-20 hidden h-[calc(100vh_-_65px)] w-64 border-l border-light-800 bg-white pr-2 xl:block dark:border-dark-100 dark:bg-dark-600">
|
||||
<Scrollbars
|
||||
autoHide
|
||||
hideTracksWhenNotNeeded
|
||||
renderThumbVertical={(props) => <div {...props} className="z-30 rounded bg-light-900 dark:bg-dark-100" />}
|
||||
renderTrackVertical={(props) => (
|
||||
<div {...props} className="absolute bottom-0.5 right-0.5 top-0.5 z-30 w-1.5 rounded" />
|
||||
)}
|
||||
universal
|
||||
>
|
||||
<TableOfContentItems serializedMembers={members} />
|
||||
</Scrollbars>
|
||||
</aside>
|
||||
<div className="lg:sticky lg:top-23 lg:h-[calc(100vh_-_105px)]">
|
||||
<aside className="fixed bottom-4 left-4 right-4 top-22 z-20 mx-auto hidden max-w-5xl border border-light-900 rounded-md bg-white/75 shadow backdrop-blur-md lg:sticky lg:block lg:h-full lg:max-w-xs lg:min-w-xs lg:w-full dark:border-dark-100 dark:bg-dark-600/75">
|
||||
<Scrollbars
|
||||
autoHide
|
||||
className="[&>div]:overscroll-none"
|
||||
hideTracksWhenNotNeeded
|
||||
renderThumbVertical={(props) => <div {...props} className="z-30 rounded bg-light-900 dark:bg-dark-100" />}
|
||||
renderTrackVertical={(props) => (
|
||||
<div {...props} className="absolute bottom-0.5 right-0.5 top-0.5 z-30 w-1.5 rounded" />
|
||||
)}
|
||||
universal
|
||||
>
|
||||
<TableOfContentItems serializedMembers={members} />
|
||||
</Scrollbars>
|
||||
</aside>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@ export default function OverloadSwitcher({
|
||||
methodName,
|
||||
overloads,
|
||||
children,
|
||||
}: PropsWithChildren<{ readonly methodName: string; readonly overloads: ReactNode[] }>) {
|
||||
}: PropsWithChildren<{
|
||||
readonly methodName: string;
|
||||
readonly overloads: ReactNode[];
|
||||
}>) {
|
||||
const [hash, setHash] = useState(() => (typeof window === 'undefined' ? '' : window.location.hash));
|
||||
const hashChangeHandler = useCallback(() => {
|
||||
setHash(window.location.hash);
|
||||
|
||||
@@ -12,7 +12,11 @@ export default function PackageSelect() {
|
||||
const pathname = usePathname();
|
||||
const packageName = pathname?.split('/').slice(3, 4)[0];
|
||||
|
||||
const packageMenu = useMenuState({ gutter: 8, sameWidth: true, fitViewport: true });
|
||||
const packageMenu = useMenuState({
|
||||
gutter: 8,
|
||||
sameWidth: true,
|
||||
fitViewport: true,
|
||||
});
|
||||
|
||||
const packageMenuItems = useMemo(
|
||||
() =>
|
||||
|
||||
@@ -17,7 +17,7 @@ export function ParameterTable({ item }: { readonly item: ApiDocumentedItem & Ap
|
||||
() =>
|
||||
params.map((param) => ({
|
||||
Name: param.isRest ? `...${param.name}` : param.name,
|
||||
Type: <ExcerptText excerpt={param.parameterTypeExcerpt} model={item.getAssociatedModel()!} />,
|
||||
Type: <ExcerptText excerpt={param.parameterTypeExcerpt} />,
|
||||
Optional: param.isOptional ? 'Yes' : 'No',
|
||||
Description: param.description ? <TSDoc item={item} tsdoc={param.description} /> : 'None',
|
||||
})),
|
||||
|
||||
@@ -32,9 +32,7 @@ export function Property({
|
||||
>
|
||||
{`${item.displayName}${item.isOptional ? '?' : ''}`}
|
||||
<span>:</span>
|
||||
{item.propertyTypeExcerpt.text ? (
|
||||
<ExcerptText excerpt={item.propertyTypeExcerpt} model={item.getAssociatedModel()!} />
|
||||
) : null}
|
||||
{item.propertyTypeExcerpt.text ? <ExcerptText excerpt={item.propertyTypeExcerpt} /> : null}
|
||||
</CodeHeading>
|
||||
</div>
|
||||
{hasSummary || inheritedFrom ? (
|
||||
|
||||
@@ -87,7 +87,7 @@ export function Sidebar({ members }: { readonly members: SidebarSectionItemData[
|
||||
const groupItems = useMemo(() => groupMembers(members), [members]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-3 p-3">
|
||||
<div className="flex flex-col gap-4">
|
||||
{(Object.keys(groupItems) as (keyof GroupedMembers)[])
|
||||
.filter((group) => groupItems[group].length)
|
||||
.map((group, idx) => (
|
||||
@@ -99,7 +99,7 @@ export function Sidebar({ members }: { readonly members: SidebarSectionItemData[
|
||||
>
|
||||
{groupItems[group].map((member, index) => (
|
||||
<ItemLink
|
||||
className={`dark:border-dark-100 border-light-800 focus:ring-width-2 focus:ring-blurple ml-5 flex flex-col border-l p-[5px] pl-6 outline-none focus:rounded focus:border-0 focus:ring ${
|
||||
className={`dark:border-dark-100 border-light-800 focus:ring-width-2 focus:ring-blurple ml-5 flex flex-col border-l first:mt-1 p-[5px] pl-6 outline-none focus:rounded focus:border-0 focus:ring ${
|
||||
decodeURIComponent(segment ?? '') === member.href
|
||||
? 'bg-blurple text-white'
|
||||
: 'dark:hover:bg-dark-200 dark:active:bg-dark-100 hover:bg-light-700 active:bg-light-800'
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { ApiModel, Excerpt } from '@discordjs/api-extractor-model';
|
||||
import type { Excerpt } from '@discordjs/api-extractor-model';
|
||||
import { ExcerptText } from './ExcerptText';
|
||||
|
||||
export function SignatureText({ excerpt, model }: { readonly excerpt: Excerpt; readonly model: ApiModel }) {
|
||||
export function SignatureText({ excerpt }: { readonly excerpt: Excerpt }) {
|
||||
return (
|
||||
<h4 className="break-all text-lg font-bold font-mono">
|
||||
<ExcerptText excerpt={excerpt} model={model} />
|
||||
<ExcerptText excerpt={excerpt} />
|
||||
</h4>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,21 +11,20 @@ const rowElements = {
|
||||
};
|
||||
|
||||
export function TypeParamTable({ item }: { readonly item: ApiTypeParameterListMixin }) {
|
||||
const model = item.getAssociatedModel()!;
|
||||
const rows = useMemo(
|
||||
() =>
|
||||
item.typeParameters.map((typeParam) => ({
|
||||
Name: typeParam.name,
|
||||
Constraints: <ExcerptText excerpt={typeParam.constraintExcerpt} model={model} />,
|
||||
Constraints: <ExcerptText excerpt={typeParam.constraintExcerpt} />,
|
||||
Optional: typeParam.isOptional ? 'Yes' : 'No',
|
||||
Default: <ExcerptText excerpt={typeParam.defaultTypeExcerpt} model={model} />,
|
||||
Default: <ExcerptText excerpt={typeParam.defaultTypeExcerpt} />,
|
||||
Description: typeParam.tsdocTypeParamBlock ? (
|
||||
<TSDoc item={item} tsdoc={typeParam.tsdocTypeParamBlock.content} />
|
||||
) : (
|
||||
'None'
|
||||
),
|
||||
})),
|
||||
[item, model],
|
||||
[item],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -7,14 +7,18 @@ import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const isDev = process.env.NEXT_PUBLIC_LOCAL_DEV ?? process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview';
|
||||
const isDev = process.env.NEXT_PUBLIC_LOCAL_DEV === 'true' ?? process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview';
|
||||
|
||||
export default function VersionSelect({ versions }: { readonly versions: string[] }) {
|
||||
const pathname = usePathname();
|
||||
const packageName = pathname?.split('/').slice(3, 4)[0];
|
||||
const branchName = pathname?.split('/').slice(4, 5)[0];
|
||||
|
||||
const versionMenu = useMenuState({ gutter: 8, sameWidth: true, fitViewport: true });
|
||||
const versionMenu = useMenuState({
|
||||
gutter: 8,
|
||||
sameWidth: true,
|
||||
fitViewport: true,
|
||||
});
|
||||
|
||||
const versionMenuItems = useMemo(
|
||||
() =>
|
||||
|
||||
@@ -4,5 +4,5 @@ import type { PropsWithChildren } from 'react';
|
||||
* Layout parent of documentation pages.
|
||||
*/
|
||||
export function Documentation({ children }: PropsWithChildren) {
|
||||
return <div className="w-full flex-col space-y-4">{children}</div>;
|
||||
return <div className="w-full flex flex-col gap-4">{children}</div>;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ export function HierarchyText({
|
||||
readonly item: ApiClass | ApiInterface;
|
||||
readonly type: 'Extends' | 'Implements';
|
||||
}) {
|
||||
const model = item.getAssociatedModel()!;
|
||||
|
||||
if (
|
||||
(item.kind === ApiItemKind.Class &&
|
||||
(item as ApiClass).extendsType === undefined &&
|
||||
@@ -50,7 +48,7 @@ export function HierarchyText({
|
||||
<div className="flex flex-row place-items-center gap-4" key={`${type}-${idx}`}>
|
||||
<h3 className="text-xl font-bold">{type}</h3>
|
||||
<span className="break-all font-mono space-y-2">
|
||||
<ExcerptText excerpt={excerpt} model={model} />
|
||||
<ExcerptText excerpt={excerpt} />
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -13,7 +13,9 @@ export function Block({ children, title }: PropsWithChildren<{ readonly title: s
|
||||
export function ExampleBlock({
|
||||
children,
|
||||
exampleIndex,
|
||||
}: PropsWithChildren<{ readonly exampleIndex?: number | undefined }>): JSX.Element {
|
||||
}: PropsWithChildren<{
|
||||
readonly exampleIndex?: number | undefined;
|
||||
}>): JSX.Element {
|
||||
return <Block title={`Example ${exampleIndex ? exampleIndex : ''}`}>{children}</Block>;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import { DocNodeKind, StandardTags } from '@microsoft/tsdoc';
|
||||
import type { Route } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Fragment, useCallback, type ReactNode } from 'react';
|
||||
import { DocumentationLink } from '~/components/DocumentationLink';
|
||||
import { BuiltinDocumentationLinks } from '~/util/builtinDocumentationLinks';
|
||||
import { ItemLink } from '../../ItemLink';
|
||||
import { SyntaxHighlighter } from '../../SyntaxHighlighter';
|
||||
import { resolveItemURI } from '../util';
|
||||
@@ -32,10 +34,24 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc:
|
||||
const { codeDestination, urlDestination, linkText } = tsdoc as DocLinkTag;
|
||||
|
||||
if (codeDestination) {
|
||||
// TODO: Real fix in api-extractor needed
|
||||
const currentItem = item.getAssociatedPackage();
|
||||
const foundItem = item.getAssociatedModel()?.resolveDeclarationReference(codeDestination, currentItem)
|
||||
.resolvedApiItem;
|
||||
if (
|
||||
!codeDestination.importPath &&
|
||||
!codeDestination.packageName &&
|
||||
codeDestination.memberReferences.length === 1 &&
|
||||
codeDestination.memberReferences[0]!.memberIdentifier &&
|
||||
codeDestination.memberReferences[0]!.memberIdentifier.identifier in BuiltinDocumentationLinks
|
||||
) {
|
||||
const typeName = codeDestination.memberReferences[0]!.memberIdentifier.identifier;
|
||||
const href = BuiltinDocumentationLinks[typeName as keyof typeof BuiltinDocumentationLinks];
|
||||
return (
|
||||
<DocumentationLink key={`${typeName}-${idx}`} href={href}>
|
||||
{typeName}
|
||||
</DocumentationLink>
|
||||
);
|
||||
}
|
||||
|
||||
const declarationReference = item.getAssociatedModel()?.resolveDeclarationReference(codeDestination, item);
|
||||
const foundItem = declarationReference?.resolvedApiItem;
|
||||
|
||||
if (!foundItem) return null;
|
||||
|
||||
@@ -44,6 +60,7 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc:
|
||||
className="rounded font-mono text-blurple outline-none focus:ring focus:ring-width-2 focus:ring-blurple"
|
||||
itemURI={resolveItemURI(foundItem)}
|
||||
key={idx}
|
||||
packageName={item.getAssociatedPackage()?.displayName.replace('@discordjs/', '')}
|
||||
>
|
||||
{linkText ?? foundItem.displayName}
|
||||
</ItemLink>
|
||||
@@ -92,7 +109,7 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc:
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col space-y-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
{comment.deprecatedBlock ? (
|
||||
<DeprecatedBlock>{createNode(comment.deprecatedBlock.content)}</DeprecatedBlock>
|
||||
) : null}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ApiItemKind } from '@discordjs/api-extractor-model';
|
||||
import { ApiItemKind, Meaning } from '@discordjs/api-extractor-model';
|
||||
import type {
|
||||
ApiItem,
|
||||
ApiItemContainerMixin,
|
||||
@@ -10,11 +10,25 @@ import type {
|
||||
ApiParameterListMixin,
|
||||
ApiEvent,
|
||||
} from '@discordjs/api-extractor-model';
|
||||
import type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';
|
||||
import { METHOD_SEPARATOR, OVERLOAD_SEPARATOR } from '~/util/constants';
|
||||
import { resolveMembers } from '~/util/members';
|
||||
import { resolveParameters } from '~/util/model';
|
||||
import type { TableOfContentsSerialized } from '../TableOfContentItems';
|
||||
|
||||
export type ApiItemLike = {
|
||||
[K in keyof ApiItem]?: K extends 'displayName' | 'kind'
|
||||
? ApiItem[K]
|
||||
: K extends 'parent'
|
||||
? ApiItemLike | undefined
|
||||
: ApiItem[K] | undefined;
|
||||
};
|
||||
|
||||
interface ResolvedCanonicalReference {
|
||||
item: ApiItemLike;
|
||||
package: string;
|
||||
}
|
||||
|
||||
export function hasProperties(item: ApiItemContainerMixin) {
|
||||
return resolveMembers(item, memberPredicate).some(
|
||||
({ item: member }) => member.kind === ApiItemKind.Property || member.kind === ApiItemKind.PropertySignature,
|
||||
@@ -31,12 +45,65 @@ export function hasEvents(item: ApiItemContainerMixin) {
|
||||
return resolveMembers(item, memberPredicate).some(({ item: member }) => member.kind === ApiItemKind.Event);
|
||||
}
|
||||
|
||||
export function resolveItemURI(item: ApiItem): string {
|
||||
export function resolveItemURI(item: ApiItemLike): string {
|
||||
return !item.parent || item.parent.kind === ApiItemKind.EntryPoint
|
||||
? `${item.displayName}${OVERLOAD_SEPARATOR}${item.kind}`
|
||||
: `${item.parent.displayName}${OVERLOAD_SEPARATOR}${item.parent.kind}${METHOD_SEPARATOR}${item.displayName}`;
|
||||
}
|
||||
|
||||
export function resolveCanonicalReference(canonicalReference: DeclarationReference): ResolvedCanonicalReference | null {
|
||||
if (
|
||||
canonicalReference.source &&
|
||||
'packageName' in canonicalReference.source &&
|
||||
canonicalReference.symbol?.componentPath &&
|
||||
canonicalReference.symbol.meaning
|
||||
)
|
||||
return {
|
||||
package: canonicalReference.source.unscopedPackageName,
|
||||
item: {
|
||||
kind: mapMeaningToKind(canonicalReference.symbol.meaning as unknown as Meaning),
|
||||
displayName: canonicalReference.symbol.componentPath.component.toString(),
|
||||
containerKey: `|${
|
||||
canonicalReference.symbol.meaning
|
||||
}|${canonicalReference.symbol.componentPath.component.toString()}`,
|
||||
},
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
function mapMeaningToKind(meaning: Meaning): ApiItemKind {
|
||||
switch (meaning) {
|
||||
case Meaning.CallSignature:
|
||||
return ApiItemKind.CallSignature;
|
||||
case Meaning.Class:
|
||||
return ApiItemKind.Class;
|
||||
case Meaning.ComplexType:
|
||||
throw new Error('Not a valid canonicalReference: Meaning.ComplexType');
|
||||
case Meaning.ConstructSignature:
|
||||
return ApiItemKind.ConstructSignature;
|
||||
case Meaning.Constructor:
|
||||
return ApiItemKind.Constructor;
|
||||
case Meaning.Enum:
|
||||
return ApiItemKind.Enum;
|
||||
case Meaning.Event:
|
||||
return ApiItemKind.Event;
|
||||
case Meaning.Function:
|
||||
return ApiItemKind.Function;
|
||||
case Meaning.IndexSignature:
|
||||
return ApiItemKind.IndexSignature;
|
||||
case Meaning.Interface:
|
||||
return ApiItemKind.Interface;
|
||||
case Meaning.Member:
|
||||
return ApiItemKind.Property;
|
||||
case Meaning.Namespace:
|
||||
return ApiItemKind.Namespace;
|
||||
case Meaning.TypeAlias:
|
||||
return ApiItemKind.TypeAlias;
|
||||
case Meaning.Variable:
|
||||
return ApiItemKind.Variable;
|
||||
}
|
||||
}
|
||||
|
||||
export function memberPredicate(
|
||||
item: ApiItem,
|
||||
): item is ApiEvent | ApiMethod | ApiMethodSignature | ApiProperty | ApiPropertySignature {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { ApiClass, ApiConstructor } from '@discordjs/api-extractor-model';
|
||||
import { ApiItemKind } from '@discordjs/api-extractor-model';
|
||||
// import { Outline } from '../Outline';
|
||||
import { Badges } from '../Badges';
|
||||
import { Documentation } from '../documentation/Documentation';
|
||||
import { HierarchyText } from '../documentation/HierarchyText';
|
||||
@@ -8,13 +7,16 @@ import { Members } from '../documentation/Members';
|
||||
import { ObjectHeader } from '../documentation/ObjectHeader';
|
||||
import { ConstructorSection } from '../documentation/section/ConstructorSection';
|
||||
import { TypeParameterSection } from '../documentation/section/TypeParametersSection';
|
||||
// import { serializeMembers } from '../documentation/util';
|
||||
import { serializeMembers } from '../documentation/util';
|
||||
import { OutlineSetter } from './OutlineSetter';
|
||||
|
||||
export function Class({ clazz }: { readonly clazz: ApiClass }) {
|
||||
const constructor = clazz.members.find((member) => member.kind === ApiItemKind.Constructor) as
|
||||
| ApiConstructor
|
||||
| undefined;
|
||||
|
||||
const outlineMembers = serializeMembers(clazz);
|
||||
|
||||
return (
|
||||
<Documentation>
|
||||
<Badges item={clazz} />
|
||||
@@ -24,7 +26,7 @@ export function Class({ clazz }: { readonly clazz: ApiClass }) {
|
||||
{clazz.typeParameters.length ? <TypeParameterSection item={clazz} /> : null}
|
||||
{constructor ? <ConstructorSection item={constructor} /> : null}
|
||||
<Members item={clazz} />
|
||||
{/* <Outline members={serializeMembers(clazz)} /> */}
|
||||
<OutlineSetter members={outlineMembers} />
|
||||
</Documentation>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import type { ApiInterface } from '@discordjs/api-extractor-model';
|
||||
// import { Outline } from '../Outline';
|
||||
import { Documentation } from '../documentation/Documentation';
|
||||
import { HierarchyText } from '../documentation/HierarchyText';
|
||||
import { Members } from '../documentation/Members';
|
||||
import { ObjectHeader } from '../documentation/ObjectHeader';
|
||||
import { TypeParameterSection } from '../documentation/section/TypeParametersSection';
|
||||
// import { serializeMembers } from '../documentation/util';
|
||||
import { serializeMembers } from '../documentation/util';
|
||||
import { OutlineSetter } from './OutlineSetter';
|
||||
|
||||
export function Interface({ item }: { readonly item: ApiInterface }) {
|
||||
const outlineMembers = serializeMembers(item);
|
||||
|
||||
return (
|
||||
<Documentation>
|
||||
<ObjectHeader item={item} />
|
||||
<HierarchyText item={item} type="Extends" />
|
||||
{item.typeParameters.length ? <TypeParameterSection item={item} /> : null}
|
||||
<Members item={item} />
|
||||
{/* <Outline members={serializeMembers(item)} /> */}
|
||||
<OutlineSetter members={outlineMembers} />
|
||||
</Documentation>
|
||||
);
|
||||
}
|
||||
|
||||
19
apps/website/src/components/model/OutlineSetter.tsx
Normal file
19
apps/website/src/components/model/OutlineSetter.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, type PropsWithChildren } from 'react';
|
||||
import { useOutline } from '~/contexts/outline';
|
||||
import type { TableOfContentsSerialized } from '../TableOfContentItems';
|
||||
|
||||
export function OutlineSetter({ members }: PropsWithChildren<{ readonly members: TableOfContentsSerialized[] }>) {
|
||||
const { setMembers } = useOutline();
|
||||
|
||||
useEffect(() => {
|
||||
setMembers(members);
|
||||
|
||||
return () => {
|
||||
setMembers(null);
|
||||
};
|
||||
}, [members, setMembers]);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -14,9 +14,7 @@ export function EnumMember({ member }: { readonly member: ApiEnumMember }) {
|
||||
>
|
||||
{member.name}
|
||||
<span>=</span>
|
||||
{member.initializerExcerpt ? (
|
||||
<SignatureText excerpt={member.initializerExcerpt} model={member.getAssociatedModel()!} />
|
||||
) : null}
|
||||
{member.initializerExcerpt ? <SignatureText excerpt={member.initializerExcerpt} /> : null}
|
||||
</CodeHeading>
|
||||
{member.tsdocComment ? <TSDoc item={member} tsdoc={member.tsdocComment.summarySection} /> : null}
|
||||
</div>
|
||||
|
||||
@@ -1,37 +1,29 @@
|
||||
import type { ApiFunction } from '@discordjs/api-extractor-model';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { Header } from '../../documentation/Header';
|
||||
import { Documentation } from '~/components/documentation/Documentation';
|
||||
import { ObjectHeader } from '~/components/documentation/ObjectHeader';
|
||||
import { FunctionBody } from './FunctionBody';
|
||||
|
||||
const OverloadSwitcher = dynamic(async () => import('../../OverloadSwitcher'));
|
||||
|
||||
export function Function({ item }: { readonly item: ApiFunction }) {
|
||||
const header = (
|
||||
<Header
|
||||
kind={item.kind}
|
||||
name={item.name}
|
||||
sourceURL={item.sourceLocation.fileUrl}
|
||||
sourceLine={item.sourceLocation.fileLine}
|
||||
/>
|
||||
);
|
||||
|
||||
if (item.getMergedSiblings().length > 1) {
|
||||
const overloads = item
|
||||
.getMergedSiblings()
|
||||
.map((sibling, idx) => <FunctionBody item={sibling as ApiFunction} key={`${sibling.displayName}-${idx}`} />);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{header}
|
||||
<Documentation>
|
||||
<ObjectHeader item={item} />
|
||||
<OverloadSwitcher methodName={item.displayName} overloads={overloads} />
|
||||
</div>
|
||||
</Documentation>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{header}
|
||||
<Documentation>
|
||||
<ObjectHeader item={item} />
|
||||
<FunctionBody item={item} />
|
||||
</div>
|
||||
</Documentation>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import type { ApiFunction } from '@discordjs/api-extractor-model';
|
||||
import { SyntaxHighlighter } from '../../SyntaxHighlighter';
|
||||
import { Documentation } from '../../documentation/Documentation';
|
||||
import { ParameterSection } from '../../documentation/section/ParametersSection';
|
||||
import { SummarySection } from '../../documentation/section/SummarySection';
|
||||
import { TypeParameterSection } from '../../documentation/section/TypeParametersSection';
|
||||
|
||||
export interface FunctionBodyProps {
|
||||
@@ -12,12 +9,9 @@ export interface FunctionBodyProps {
|
||||
|
||||
export function FunctionBody({ item }: { readonly item: ApiFunction }) {
|
||||
return (
|
||||
<Documentation>
|
||||
{/* @ts-expect-error async component */}
|
||||
<SyntaxHighlighter code={item.excerpt.text} />
|
||||
<SummarySection item={item} />
|
||||
<>
|
||||
{item.typeParameters.length ? <TypeParameterSection item={item} /> : null}
|
||||
{item.parameters.length ? <ParameterSection item={item} /> : null}
|
||||
</Documentation>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export function MethodHeader({ method }: { readonly method: ApiMethod | ApiMetho
|
||||
>
|
||||
{`${method.name}(${parametersString(method)})`}
|
||||
<span>:</span>
|
||||
<ExcerptText excerpt={method.returnTypeExcerpt} model={method.getAssociatedModel()!} />
|
||||
<ExcerptText excerpt={method.returnTypeExcerpt} />
|
||||
</CodeHeading>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,10 @@ import {
|
||||
useMemo,
|
||||
} from 'react';
|
||||
|
||||
export const NavContext = createContext<{ opened: boolean; setOpened: Dispatch<SetStateAction<boolean>> }>({
|
||||
export const NavContext = createContext<{
|
||||
opened: boolean;
|
||||
setOpened: Dispatch<SetStateAction<boolean>>;
|
||||
}>({
|
||||
opened: false,
|
||||
setOpened: (_) => {},
|
||||
});
|
||||
|
||||
22
apps/website/src/contexts/outline.tsx
Normal file
22
apps/website/src/contexts/outline.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
'use client';
|
||||
|
||||
import { createContext, useContext, useMemo, useState } from 'react';
|
||||
import type { PropsWithChildren, Dispatch, SetStateAction } from 'react';
|
||||
import type { TableOfContentsSerialized } from '~/components/TableOfContentItems';
|
||||
|
||||
export const OutlineContext = createContext<{
|
||||
members: TableOfContentsSerialized[] | null | undefined;
|
||||
setMembers: Dispatch<SetStateAction<TableOfContentsSerialized[] | null | undefined>>;
|
||||
}>({ members: undefined, setMembers: (_) => {} });
|
||||
|
||||
export const OutlineProvider = ({ children }: PropsWithChildren) => {
|
||||
const [members, setMembers] = useState<TableOfContentsSerialized[] | null | undefined>(undefined);
|
||||
|
||||
const value = useMemo(() => ({ members, setMembers }), [members]);
|
||||
|
||||
return <OutlineContext.Provider value={value}>{children}</OutlineContext.Provider>;
|
||||
};
|
||||
|
||||
export function useOutline() {
|
||||
return useContext(OutlineContext);
|
||||
}
|
||||
@@ -1,26 +1,15 @@
|
||||
import { connect } from '@planetscale/database';
|
||||
import { get } from '@vercel/edge-config';
|
||||
import { sql } from '@vercel/postgres';
|
||||
import { NextResponse, type NextRequest } from 'next/server';
|
||||
import { PACKAGES } from './util/constants';
|
||||
|
||||
const sql = connect({
|
||||
url: process.env.DATABASE_URL!,
|
||||
async fetch(url, init) {
|
||||
delete init?.cache;
|
||||
return fetch(url, { ...init, next: { revalidate: 3_600 } });
|
||||
},
|
||||
});
|
||||
|
||||
async function fetchLatestVersion(packageName: string): Promise<string> {
|
||||
if (process.env.NEXT_PUBLIC_LOCAL_DEV || process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview') {
|
||||
if (process.env.NEXT_PUBLIC_LOCAL_DEV === 'true' || process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview') {
|
||||
return 'main';
|
||||
}
|
||||
|
||||
const { rows } = await sql.execute('select version from documentation where name = ? order by version desc', [
|
||||
packageName,
|
||||
]);
|
||||
const { rows } = await sql`select version from documentation where name = ${packageName} order by version desc`;
|
||||
|
||||
// @ts-expect-error: https://github.com/planetscale/database-js/issues/71
|
||||
return rows.map((row) => row.version).at(1) ?? 'main';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,9 @@
|
||||
import type { ApiModel, ApiPackage } from '@discordjs/api-extractor-model';
|
||||
import { ApiItem } from '@discordjs/api-extractor-model';
|
||||
import { TSDocConfiguration } from '@microsoft/tsdoc';
|
||||
import { TSDocConfigFile } from '@microsoft/tsdoc-config';
|
||||
import { cache } from 'react';
|
||||
import { ApiPackage } from '@discordjs/api-extractor-model';
|
||||
import type { ApiModel } from '@discordjs/api-extractor-model';
|
||||
|
||||
export const addPackageToModel = cache((model: ApiModel, data: any) => {
|
||||
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;
|
||||
}
|
||||
export const addPackageToModel = (model: ApiModel, data: any) => {
|
||||
const apiPackage = ApiPackage.loadFromJson(data);
|
||||
|
||||
model.addMember(apiPackage);
|
||||
return model;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { ApiModel, ApiFunction } from '@discordjs/api-extractor-model';
|
||||
import { cache } from 'react';
|
||||
import { fetchModelJSON } from '~/app/docAPI';
|
||||
import { addPackageToModel } from './addPackageToModel';
|
||||
import { OVERLOAD_SEPARATOR, PACKAGES } from './constants';
|
||||
import { findMember, findMemberByKey } from './model';
|
||||
|
||||
export const fetchMember = cache(async (packageName: string, branchName: string, item?: string) => {
|
||||
export const fetchMember = async (packageName: string, branchName: string, item?: string) => {
|
||||
if (!PACKAGES.includes(packageName)) {
|
||||
return null;
|
||||
}
|
||||
@@ -16,26 +15,14 @@ export const fetchMember = cache(async (packageName: string, branchName: string,
|
||||
|
||||
const model = new ApiModel();
|
||||
|
||||
if (branchName === 'main') {
|
||||
const modelJSONFiles = await Promise.all(PACKAGES.map(async (pkg) => fetchModelJSON(pkg, branchName)));
|
||||
const modelJSON = await fetchModelJSON(packageName, 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);
|
||||
if (!modelJSON) {
|
||||
return null;
|
||||
}
|
||||
|
||||
addPackageToModel(model, modelJSON);
|
||||
|
||||
const [memberName, overloadIndex] = decodeURIComponent(item).split(OVERLOAD_SEPARATOR);
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
@@ -45,4 +32,4 @@ export const fetchMember = cache(async (packageName: string, branchName: string,
|
||||
}
|
||||
|
||||
return memberName && containerKey ? findMemberByKey(model, packageName, containerKey) ?? null : null;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,21 +6,21 @@ import type {
|
||||
Excerpt,
|
||||
} from '@discordjs/api-extractor-model';
|
||||
import type { DocSection } from '@microsoft/tsdoc';
|
||||
import { cache } from 'react';
|
||||
import { resolvePackageName } from './resolvePackageName';
|
||||
|
||||
export const findMemberByKey = cache((model: ApiModel, packageName: string, containerKey: string) => {
|
||||
const pkg = model.tryGetPackageByName(packageName === 'discord.js' ? packageName : `@discordjs/${packageName}`)!;
|
||||
export const findMemberByKey = (model: ApiModel, packageName: string, containerKey: string) => {
|
||||
const pkg = model.tryGetPackageByName(resolvePackageName(packageName))!;
|
||||
return (pkg.members[0] as ApiEntryPoint).tryGetMemberByKey(containerKey);
|
||||
});
|
||||
};
|
||||
|
||||
export const findMember = cache((model: ApiModel, packageName: string, memberName: string | undefined) => {
|
||||
export const findMember = (model: ApiModel, packageName: string, memberName: string | undefined) => {
|
||||
if (!memberName) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const pkg = model.tryGetPackageByName(packageName === 'discord.js' ? packageName : `@discordjs/${packageName}`)!;
|
||||
const pkg = model.tryGetPackageByName(resolvePackageName(packageName))!;
|
||||
return pkg.entryPoints[0]?.findMembersByName(memberName)[0];
|
||||
});
|
||||
};
|
||||
|
||||
interface ResolvedParameter {
|
||||
description?: DocSection | undefined;
|
||||
|
||||
3
apps/website/src/util/resolvePackageName.ts
Normal file
3
apps/website/src/util/resolvePackageName.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function resolvePackageName(packageName: string) {
|
||||
return packageName === 'discord.js' ? packageName : `@discordjs/${packageName}`;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"$schema": "https://openapi.vercel.sh/vercel.json",
|
||||
"git": {
|
||||
"deploymentEnabled": {
|
||||
"main": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^18.4.0",
|
||||
"@commitlint/cli": "^18.4.1",
|
||||
"@commitlint/config-angular": "^18.4.0",
|
||||
"@favware/cliff-jumper": "^2.2.1",
|
||||
"@favware/npm-deprecate": "^1.0.7",
|
||||
@@ -63,6 +63,7 @@
|
||||
"is-ci": "^3.0.1",
|
||||
"lint-staged": "^15.1.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"prettier": "^3.1.0",
|
||||
"tsup": "^7.2.0",
|
||||
"turbo": "^1.10.17-canary.0",
|
||||
"typescript": "^5.2.2",
|
||||
|
||||
2
packages/actions/.lintstagedrc.cjs
Normal file
2
packages/actions/.lintstagedrc.cjs
Normal file
@@ -0,0 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
@@ -1 +0,0 @@
|
||||
export * from '../../.lintstagedrc.json' assert { type: 'json' };
|
||||
2
packages/actions/.prettierrc.cjs
Normal file
2
packages/actions/.prettierrc.cjs
Normal file
@@ -0,0 +1,2 @@
|
||||
/** @type {import('prettier').Config} */
|
||||
module.exports = require('../../.prettierrc.json');
|
||||
@@ -1 +0,0 @@
|
||||
export * from '../../.prettierrc.json' assert { type: 'json' };
|
||||
@@ -3,24 +3,44 @@ import { formatTag } from '../src/index.js';
|
||||
|
||||
describe('Format Tag', () => {
|
||||
test('GIVEN tag with a prefix THEN format tag to not contain the prefix', () => {
|
||||
expect(formatTag('@discordjs/rest@0.4.0')).toEqual({ isSubpackage: true, package: 'rest', semver: '0.4.0' });
|
||||
expect(formatTag('@discordjs/rest@0.4.0')).toEqual({
|
||||
isSubpackage: true,
|
||||
package: 'rest',
|
||||
semver: '0.4.0',
|
||||
});
|
||||
expect(formatTag('@discordjs/collection@0.6.0')).toEqual({
|
||||
isSubpackage: true,
|
||||
package: 'collection',
|
||||
semver: '0.6.0',
|
||||
});
|
||||
expect(formatTag('@discordjs/proxy@0.1.0')).toEqual({ isSubpackage: true, package: 'proxy', semver: '0.1.0' });
|
||||
expect(formatTag('@discordjs/proxy@0.1.0')).toEqual({
|
||||
isSubpackage: true,
|
||||
package: 'proxy',
|
||||
semver: '0.1.0',
|
||||
});
|
||||
expect(formatTag('@discordjs/builders@0.13.0')).toEqual({
|
||||
isSubpackage: true,
|
||||
package: 'builders',
|
||||
semver: '0.13.0',
|
||||
});
|
||||
expect(formatTag('@discordjs/voice@0.9.0')).toEqual({ isSubpackage: true, package: 'voice', semver: '0.9.0' });
|
||||
expect(formatTag('@discordjs/voice@0.9.0')).toEqual({
|
||||
isSubpackage: true,
|
||||
package: 'voice',
|
||||
semver: '0.9.0',
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN tag with no prefix THEN return tag', () => {
|
||||
expect(formatTag('13.5.1')).toEqual({ isSubpackage: false, package: 'discord.js', semver: '13.5.1' });
|
||||
expect(formatTag('13.7.0')).toEqual({ isSubpackage: false, package: 'discord.js', semver: '13.7.0' });
|
||||
expect(formatTag('13.5.1')).toEqual({
|
||||
isSubpackage: false,
|
||||
package: 'discord.js',
|
||||
semver: '13.5.1',
|
||||
});
|
||||
expect(formatTag('13.7.0')).toEqual({
|
||||
isSubpackage: false,
|
||||
package: 'discord.js',
|
||||
semver: '13.7.0',
|
||||
});
|
||||
expect(formatTag('create-discord-bot@1.0.0')).toEqual({
|
||||
isSubpackage: false,
|
||||
package: 'create-discord-bot',
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/glob": "^0.4.0",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@planetscale/database": "^1.11.0",
|
||||
"@vercel/blob": "^0.15.0",
|
||||
"@vercel/postgres": "^0.5.1",
|
||||
"meilisearch": "^0.35.0",
|
||||
"tslib": "^2.6.2",
|
||||
"undici": "5.27.2"
|
||||
@@ -55,7 +56,7 @@
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-neon": "^0.1.57",
|
||||
"eslint-formatter-pretty": "^5.0.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"tsup": "^7.2.0",
|
||||
"turbo": "^1.10.17-canary.0",
|
||||
"typescript": "^5.2.2",
|
||||
|
||||
@@ -2,8 +2,8 @@ import { readFile } from 'node:fs/promises';
|
||||
import process from 'node:process';
|
||||
import { getInput, setFailed } from '@actions/core';
|
||||
import { create } from '@actions/glob';
|
||||
import { connect } from '@planetscale/database';
|
||||
import { fetch } from 'undici';
|
||||
import { put } from '@vercel/blob';
|
||||
import { createPool } from '@vercel/postgres';
|
||||
|
||||
if (!process.env.DATABASE_URL) {
|
||||
setFailed('DATABASE_URL is not set');
|
||||
@@ -12,9 +12,8 @@ if (!process.env.DATABASE_URL) {
|
||||
const pkg = getInput('package') || '*';
|
||||
const version = getInput('version') || 'main';
|
||||
|
||||
const sql = connect({
|
||||
fetch,
|
||||
url: process.env.DATABASE_URL!,
|
||||
const pool = createPool({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
});
|
||||
|
||||
const globber = await create(`packages/${pkg}/docs/docs.api.json`);
|
||||
@@ -22,9 +21,18 @@ for await (const file of globber.globGenerator()) {
|
||||
const data = await readFile(file, 'utf8');
|
||||
try {
|
||||
console.log(`Uploading ${file} with ${version}...`);
|
||||
await sql.execute('replace into documentation (version, data) values (?, ?)', [version, data]);
|
||||
const json = JSON.parse(data);
|
||||
const name = json.name ?? json.n;
|
||||
const { url } = await put(`${name.replace('@discordjs/', '')}/${version}.json`, data, {
|
||||
access: 'public',
|
||||
addRandomSuffix: false,
|
||||
});
|
||||
await pool.sql`insert into documentation (name, version, url) values (${name.replace(
|
||||
'@discordjs/',
|
||||
'',
|
||||
)}, ${version}, ${url}) on conflict (name, version) do update set url = EXCLUDED.url`;
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
setFailed(err.message);
|
||||
console.log(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import process from 'node:process';
|
||||
import { setFailed } from '@actions/core';
|
||||
import { generateAllIndices } from '@discordjs/scripts';
|
||||
import { connect } from '@planetscale/database';
|
||||
import { createPool } from '@vercel/postgres';
|
||||
import { MeiliSearch } from 'meilisearch';
|
||||
import { fetch } from 'undici';
|
||||
|
||||
@@ -17,9 +17,8 @@ if (!process.env.SEARCH_API_KEY) {
|
||||
setFailed('SEARCH_API_KEY is not set');
|
||||
}
|
||||
|
||||
const sql = connect({
|
||||
fetch,
|
||||
url: process.env.DATABASE_URL!,
|
||||
const pool = createPool({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
});
|
||||
|
||||
const client = new MeiliSearch({
|
||||
@@ -32,30 +31,32 @@ try {
|
||||
const indices = await generateAllIndices({
|
||||
fetchPackageVersions: async (pkg) => {
|
||||
console.log(`Fetching versions for ${pkg}...`);
|
||||
const { rows } = await sql.execute('select version from documentation where name = ?', [pkg]);
|
||||
const { rows } = await pool.sql`select version from documentation where name = ${pkg}`;
|
||||
|
||||
// @ts-expect-error: https://github.com/planetscale/database-js/issues/71
|
||||
return rows.map((row) => row.version);
|
||||
},
|
||||
fetchPackageVersionDocs: async (pkg, version) => {
|
||||
console.log(`Fetching data for ${pkg} ${version}...`);
|
||||
const { rows } = await sql.execute('select data from documentation where name = ? and version = ?', [
|
||||
pkg,
|
||||
version,
|
||||
]);
|
||||
const { rows } = await pool.sql`select url from documentation where name = ${pkg} and version = ${version}`;
|
||||
const res = await fetch(rows[0]?.url ?? '');
|
||||
|
||||
// @ts-expect-error: https://github.com/planetscale/database-js/issues/71
|
||||
return rows[0].data;
|
||||
return res.json();
|
||||
},
|
||||
writeToFile: false,
|
||||
});
|
||||
console.log('Generated all indices.');
|
||||
|
||||
console.log('Uploading indices...');
|
||||
for (const index of indices) {
|
||||
console.log(`Uploading ${index.index}...`);
|
||||
await client.index(index.index).addDocuments(index.data);
|
||||
}
|
||||
|
||||
try {
|
||||
await Promise.all(
|
||||
indices.map(async (index) => {
|
||||
console.log(`Uploading ${index.index}...`);
|
||||
await client.createIndex(index.index);
|
||||
await client.index(index.index).addDocuments(index.data);
|
||||
}),
|
||||
);
|
||||
} catch {}
|
||||
|
||||
console.log('Uploaded all indices.');
|
||||
} catch (error) {
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('prettier').Config} */
|
||||
module.exports = require('../../.prettierrc.json');
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
"eslint-config-neon": "^0.1.57",
|
||||
"eslint-formatter-pretty": "^5.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"tsup": "^7.2.0",
|
||||
"turbo": "^1.10.17-canary.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
import { Buffer } from 'node:buffer';
|
||||
import path from 'node:path';
|
||||
import util from 'node:util';
|
||||
import { TSDocConfiguration } from '@microsoft/tsdoc';
|
||||
import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';
|
||||
import { TSDocConfigFile } from '@microsoft/tsdoc-config';
|
||||
@@ -10,6 +13,7 @@ import {
|
||||
PackageJsonLookup,
|
||||
type IPackageJson,
|
||||
type JsonObject,
|
||||
FileSystem,
|
||||
} from '@rushstack/node-core-library';
|
||||
import { ApiDocumentedItem, type IApiDocumentedItemOptions } from '../items/ApiDocumentedItem.js';
|
||||
import { ApiItem, ApiItemKind, type IApiItemJson } from '../items/ApiItem.js';
|
||||
@@ -27,10 +31,58 @@ export interface IApiPackageOptions
|
||||
extends IApiItemContainerMixinOptions,
|
||||
IApiNameMixinOptions,
|
||||
IApiDocumentedItemOptions {
|
||||
dependencies?: Record<string, string> | undefined;
|
||||
projectFolderUrl?: string | undefined;
|
||||
tsdocConfiguration: TSDocConfiguration;
|
||||
}
|
||||
|
||||
const MinifyJSONMapping = {
|
||||
canonicalReference: 'c',
|
||||
constraintTokenRange: 'ctr',
|
||||
dependencies: 'dp',
|
||||
defaultTypeTokenRange: 'dtr',
|
||||
docComment: 'd',
|
||||
endIndex: 'en',
|
||||
excerptTokens: 'ex',
|
||||
extendsTokenRange: 'etr',
|
||||
extendsTokenRanges: 'etrs',
|
||||
fileColumn: 'co',
|
||||
fileLine: 'l',
|
||||
fileUrlPath: 'pat',
|
||||
implementsTokenRanges: 'itrs',
|
||||
initializerTokenRange: 'itr',
|
||||
isAbstract: 'ab',
|
||||
isOptional: 'op',
|
||||
isProtected: 'pr',
|
||||
isReadonly: 'ro',
|
||||
isRest: 'rs',
|
||||
isStatic: 'sta',
|
||||
kind: 'k',
|
||||
members: 'ms',
|
||||
metadata: 'meta',
|
||||
name: 'n',
|
||||
oldestForwardsCompatibleVersion: 'ov',
|
||||
overloadIndex: 'oi',
|
||||
parameterName: 'pn',
|
||||
parameterTypeTokenRange: 'ptr',
|
||||
parameters: 'ps',
|
||||
preserveMemberOrder: 'pmo',
|
||||
projectFolderUrl: 'pdir',
|
||||
propertyTypeTokenRange: 'prtr',
|
||||
releaseTag: 'r',
|
||||
returnTypeTokenRange: 'rtr',
|
||||
schemaVersion: 'v',
|
||||
startIndex: 'st',
|
||||
text: 't',
|
||||
toolPackage: 'tpk',
|
||||
toolVersion: 'tv',
|
||||
tsdocConfig: 'ts',
|
||||
typeParameterName: 'tp',
|
||||
typeParameters: 'tps',
|
||||
typeTokenRange: 'ttr',
|
||||
variableTypeTokenRange: 'vtr',
|
||||
};
|
||||
|
||||
export interface IApiPackageMetadataJson {
|
||||
/**
|
||||
* To support forwards compatibility, the `oldestForwardsCompatibleVersion` field tracks the oldest schema version
|
||||
@@ -75,10 +127,15 @@ export interface IApiPackageMetadataJson {
|
||||
* Normally this configuration is loaded from the project's tsdoc.json file. It is stored
|
||||
* in the .api.json file so that doc comments can be parsed accurately when loading the file.
|
||||
*/
|
||||
tsdocConfig: JsonObject;
|
||||
tsdocConfig?: JsonObject;
|
||||
}
|
||||
|
||||
export interface IApiPackageJson extends IApiItemJson {
|
||||
/**
|
||||
* Names of packages in the same monorepo this one uses mapped to the version of said package.
|
||||
*/
|
||||
dependencies?: Record<string, string>;
|
||||
|
||||
/**
|
||||
* A file header that stores metadata about the tool that wrote the *.api.json file.
|
||||
*/
|
||||
@@ -98,6 +155,11 @@ export interface IApiPackageJson extends IApiItemJson {
|
||||
* @public
|
||||
*/
|
||||
export interface IApiPackageSaveOptions extends IJsonFileSaveOptions {
|
||||
/**
|
||||
* Set to true to not have indentation or newlines in resulting JSON.
|
||||
*/
|
||||
minify?: boolean;
|
||||
|
||||
/**
|
||||
* Set to true only when invoking API Extractor's test harness.
|
||||
*
|
||||
@@ -134,11 +196,31 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented
|
||||
|
||||
private readonly _projectFolderUrl?: string | undefined;
|
||||
|
||||
private readonly _dependencies?: Record<string, string> | undefined;
|
||||
|
||||
public constructor(options: IApiPackageOptions) {
|
||||
super(options);
|
||||
|
||||
this._tsdocConfiguration = options.tsdocConfiguration;
|
||||
this._projectFolderUrl = options.projectFolderUrl;
|
||||
|
||||
if (options.dependencies) {
|
||||
this._dependencies = options.dependencies;
|
||||
} else {
|
||||
const packageJson = PackageJsonLookup.instance.tryLoadPackageJsonFor('.');
|
||||
if (packageJson?.dependencies) {
|
||||
this._dependencies = {};
|
||||
for (const [pack, semVer] of Object.entries(packageJson.dependencies)) {
|
||||
const pathToPackage = path.join('..', pack.includes('/') ? pack.slice(pack.lastIndexOf('/')) : pack);
|
||||
if (semVer === 'workspace:^') {
|
||||
this._dependencies[pack] =
|
||||
PackageJsonLookup.instance.tryLoadPackageJsonFor(pathToPackage)?.version ?? 'unknown';
|
||||
} else if (FileSystem.exists(pathToPackage)) {
|
||||
this._dependencies[pack] = semVer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,11 +234,17 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented
|
||||
super.onDeserializeInto(options, context, jsonObject);
|
||||
|
||||
options.projectFolderUrl = jsonObject.projectFolderUrl;
|
||||
options.dependencies = jsonObject.dependencies;
|
||||
}
|
||||
|
||||
public static loadFromJsonFile(apiJsonFilename: string): ApiPackage {
|
||||
const jsonObject: IApiPackageJson = JsonFile.load(apiJsonFilename);
|
||||
return this.loadFromJson(JsonFile.load(apiJsonFilename), apiJsonFilename);
|
||||
}
|
||||
|
||||
public static loadFromJson(rawJson: any, apiJsonFilename: string = ''): ApiPackage {
|
||||
const jsonObject =
|
||||
MinifyJSONMapping.metadata in rawJson ? this._mapFromMinified(rawJson) : (rawJson as IApiPackageJson);
|
||||
if (!jsonObject?.metadata) throw new Error(util.inspect(rawJson, { depth: 2 }));
|
||||
if (!jsonObject?.metadata || typeof jsonObject.metadata.schemaVersion !== 'number') {
|
||||
throw new Error(
|
||||
`Error loading ${apiJsonFilename}:` +
|
||||
@@ -205,7 +293,7 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented
|
||||
|
||||
const tsdocConfiguration: TSDocConfiguration = new TSDocConfiguration();
|
||||
|
||||
if (versionToDeserialize >= ApiJsonSchemaVersion.V_1004) {
|
||||
if (versionToDeserialize >= ApiJsonSchemaVersion.V_1004 && 'tsdocConfiguration' in jsonObject) {
|
||||
const tsdocConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromObject(jsonObject.metadata.tsdocConfig);
|
||||
if (tsdocConfigFile.hasErrors) {
|
||||
throw new Error(`Error loading ${apiJsonFilename}:\n` + tsdocConfigFile.getErrorSummary());
|
||||
@@ -244,6 +332,10 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented
|
||||
return this.members as readonly ApiEntryPoint[];
|
||||
}
|
||||
|
||||
public get dependencies(): Record<string, string> | undefined {
|
||||
return this._dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* The TSDoc configuration that was used when analyzing the API for this package.
|
||||
*
|
||||
@@ -299,8 +391,18 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented
|
||||
jsonObject.projectFolderUrl = this.projectFolderUrl;
|
||||
}
|
||||
|
||||
if (this._dependencies) {
|
||||
jsonObject.dependencies = this._dependencies;
|
||||
}
|
||||
|
||||
this.serializeInto(jsonObject);
|
||||
JsonFile.save(jsonObject, apiJsonFilename, ioptions);
|
||||
if (ioptions.minify) {
|
||||
FileSystem.writeFile(apiJsonFilename, Buffer.from(JSON.stringify(this._mapToMinified(jsonObject)), 'utf8'), {
|
||||
ensureFolderExists: ioptions.ensureFolderExists ?? true,
|
||||
});
|
||||
} else {
|
||||
JsonFile.save(jsonObject, apiJsonFilename, ioptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,4 +411,47 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented
|
||||
public override buildCanonicalReference(): DeclarationReference {
|
||||
return DeclarationReference.package(this.name);
|
||||
}
|
||||
|
||||
private _mapToMinified(jsonObject: IApiPackageJson) {
|
||||
const mapper = (item: any): any => {
|
||||
if (Array.isArray(item)) return item.map(mapper);
|
||||
else {
|
||||
const result: any = {};
|
||||
for (const key of Object.keys(item)) {
|
||||
if (key === 'dependencies') {
|
||||
result[MinifyJSONMapping.dependencies] = item.dependencies;
|
||||
} else
|
||||
result[MinifyJSONMapping[key as keyof typeof MinifyJSONMapping]] =
|
||||
typeof item[key] === 'object' ? mapper(item[key]) : item[key];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
return mapper(jsonObject);
|
||||
}
|
||||
|
||||
private static _mapFromMinified(jsonObject: any): IApiPackageJson {
|
||||
const mapper = (item: any): any => {
|
||||
if (Array.isArray(item)) return item.map(mapper);
|
||||
else {
|
||||
const result: any = {};
|
||||
for (const key of Object.keys(item)) {
|
||||
if (key === MinifyJSONMapping.dependencies) {
|
||||
result.dependencies = item[MinifyJSONMapping.dependencies];
|
||||
} else
|
||||
result[
|
||||
Object.keys(MinifyJSONMapping).find(
|
||||
(look) => MinifyJSONMapping[look as keyof typeof MinifyJSONMapping] === key,
|
||||
)!
|
||||
] = typeof item[key] === 'object' ? mapper(item[key]) : item[key];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
return mapper(jsonObject) as IApiPackageJson;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,13 +96,18 @@ export enum ApiJsonSchemaVersion {
|
||||
*/
|
||||
V_1012 = 1_012,
|
||||
|
||||
/**
|
||||
* Make tsdocConfiguration optional
|
||||
*/
|
||||
V_1013 = 1_013,
|
||||
|
||||
/**
|
||||
* The current latest .api.json schema version.
|
||||
*
|
||||
* IMPORTANT: When incrementing this number, consider whether `OLDEST_SUPPORTED` or `OLDEST_FORWARDS_COMPATIBLE`
|
||||
* should be updated.
|
||||
*/
|
||||
LATEST = V_1012,
|
||||
LATEST = V_1013,
|
||||
|
||||
/**
|
||||
* The oldest .api.json schema version that is still supported for backwards compatibility.
|
||||
@@ -119,7 +124,7 @@ export enum ApiJsonSchemaVersion {
|
||||
* if the older library would not be able to deserialize your new file format. Adding a nonessential field
|
||||
* is generally okay. Removing, modifying, or reinterpreting existing fields is NOT safe.
|
||||
*/
|
||||
OLDEST_FORWARDS_COMPATIBLE = V_1001,
|
||||
OLDEST_FORWARDS_COMPATIBLE = V_1013,
|
||||
}
|
||||
|
||||
export class DeserializerContext {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { createTsupConfig } from '../../tsup.config.js';
|
||||
|
||||
export default createTsupConfig();
|
||||
export default createTsupConfig({
|
||||
minify: 'terser',
|
||||
});
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('prettier').Config} */
|
||||
module.exports = require('../../.prettierrc.json');
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-neon": "^0.1.57",
|
||||
"eslint-formatter-pretty": "^5.0.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"tsup": "^7.2.0",
|
||||
"turbo": "^1.10.17-canary.0",
|
||||
"typescript": "^5.2.2"
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('prettier').Config} */
|
||||
module.exports = require('../../.prettierrc.json');
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
"apiReport": {
|
||||
"enabled": true,
|
||||
"reportFolder": "../../../common/reviews/api"
|
||||
"reportFolder": "<projectFolder>/docs/review"
|
||||
},
|
||||
|
||||
"docModel": {
|
||||
"enabled": true,
|
||||
"apiJsonFilePath": "../../../common/temp/api/<unscopedPackageName>.api.json"
|
||||
"apiJsonFilePath": "<projectFolder>/docs/<unscopedPackageName>.api.json"
|
||||
},
|
||||
|
||||
"dtsRollup": {
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
"eslint-config-neon": "^0.1.57",
|
||||
"eslint-formatter-pretty": "^5.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"tsup": "^7.2.0",
|
||||
"turbo": "^1.10.17-canary.0"
|
||||
}
|
||||
|
||||
@@ -41,6 +41,11 @@ export interface IExtractorInvokeOptions {
|
||||
*/
|
||||
compilerState?: CompilerState;
|
||||
|
||||
/**
|
||||
* Whether to minify the resulting doc model JSON, i.e. without any indentation or newlines.
|
||||
*/
|
||||
docModelMinify?: boolean;
|
||||
|
||||
/**
|
||||
* Indicates that API Extractor is running as part of a local build, e.g. on developer's
|
||||
* machine.
|
||||
@@ -270,7 +275,7 @@ export class Extractor {
|
||||
apiPackage.saveToJsonFile(extractorConfig.apiJsonFilePath, {
|
||||
toolPackage: Extractor.packageName,
|
||||
toolVersion: Extractor.version,
|
||||
|
||||
minify: options?.docModelMinify ?? false,
|
||||
newlineConversion: extractorConfig.newlineKind,
|
||||
ensureFolderExists: true,
|
||||
testMode: extractorConfig.testMode,
|
||||
|
||||
@@ -27,6 +27,8 @@ export class RunAction extends CommandLineAction {
|
||||
|
||||
private readonly _typescriptCompilerFolder: CommandLineStringParameter;
|
||||
|
||||
private readonly _minify: CommandLineFlagParameter;
|
||||
|
||||
public constructor(_parser: ApiExtractorCommandLine) {
|
||||
super({
|
||||
actionName: 'run',
|
||||
@@ -57,6 +59,12 @@ export class RunAction extends CommandLineAction {
|
||||
description: 'Show additional informational messages in the output.',
|
||||
});
|
||||
|
||||
this._minify = this.defineFlagParameter({
|
||||
parameterLongName: '--minify',
|
||||
parameterShortName: '-m',
|
||||
description: 'Minify the resulting doc model JSON, i.e. without any indentation or newlines.',
|
||||
});
|
||||
|
||||
this._diagnosticsParameter = this.defineFlagParameter({
|
||||
parameterLongName: '--diagnostics',
|
||||
description:
|
||||
@@ -136,6 +144,7 @@ export class RunAction extends CommandLineAction {
|
||||
|
||||
const extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, {
|
||||
localBuild: this._localParameter.value,
|
||||
docModelMinify: this._minify.value,
|
||||
showVerboseMessages: this._verboseParameter.value,
|
||||
showDiagnostics: this._diagnosticsParameter.value,
|
||||
typescriptCompilerFolder,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { ReleaseTag } from '@discordjs/api-extractor-model';
|
||||
import * as tsdoc from '@microsoft/tsdoc';
|
||||
import { PackageJsonLookup, Sort, InternalError } from '@rushstack/node-core-library';
|
||||
import * as ts from 'typescript';
|
||||
import ts from 'typescript';
|
||||
import { PackageDocComment } from '../aedoc/PackageDocComment.js';
|
||||
import type { AstDeclaration } from '../analyzer/AstDeclaration.js';
|
||||
import type { AstEntity } from '../analyzer/AstEntity.js';
|
||||
|
||||
@@ -3,7 +3,18 @@
|
||||
|
||||
import { existsSync } from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type {
|
||||
IApiMethodOptions,
|
||||
ApiItemContainerMixin,
|
||||
IApiParameterOptions,
|
||||
IExcerptTokenRange,
|
||||
IExcerptTokenRangeWithTypeParameters,
|
||||
IExcerptToken,
|
||||
IApiTypeParameterOptions,
|
||||
IApiPropertyOptions,
|
||||
} from '@discordjs/api-extractor-model';
|
||||
import {
|
||||
ApiItemKind,
|
||||
ApiModel,
|
||||
ApiClass,
|
||||
ApiPackage,
|
||||
@@ -13,16 +24,11 @@ import {
|
||||
ApiNamespace,
|
||||
ApiInterface,
|
||||
ApiPropertySignature,
|
||||
type ApiItemContainerMixin,
|
||||
ReleaseTag,
|
||||
ApiProperty,
|
||||
ApiMethodSignature,
|
||||
type IApiParameterOptions,
|
||||
ApiEnum,
|
||||
ApiEnumMember,
|
||||
type IExcerptTokenRange,
|
||||
type IExcerptTokenRangeWithTypeParameters,
|
||||
type IExcerptToken,
|
||||
ApiConstructor,
|
||||
ApiConstructSignature,
|
||||
ApiFunction,
|
||||
@@ -30,13 +36,11 @@ import {
|
||||
ApiVariable,
|
||||
ApiTypeAlias,
|
||||
ApiCallSignature,
|
||||
type IApiTypeParameterOptions,
|
||||
EnumMemberOrder,
|
||||
ExcerptTokenKind,
|
||||
Navigation,
|
||||
} from '@discordjs/api-extractor-model';
|
||||
import type * as tsdoc from '@microsoft/tsdoc';
|
||||
import { TSDocParser } from '@microsoft/tsdoc';
|
||||
import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';
|
||||
import { JsonFile, Path } from '@rushstack/node-core-library';
|
||||
import * as ts from 'typescript';
|
||||
@@ -208,24 +212,43 @@ interface IProcessAstEntityContext {
|
||||
|
||||
const linkRegEx = /{@link\s(?<class>\w+)#(?<event>event:)?(?<prop>[\w()]+)(?<name>\s[^}]*)?}/g;
|
||||
function fixLinkTags(input?: string): string | undefined {
|
||||
return input?.replaceAll(linkRegEx, '{@link $<class>.$<prop>$<name>}');
|
||||
return input?.replaceAll(
|
||||
linkRegEx,
|
||||
(_match, _p1, _p2, _p3, _p4, _offset, _string, groups) =>
|
||||
`{@link ${groups.class}.${groups.prop}${groups.name ? ` |${groups.name}` : ''}}`,
|
||||
);
|
||||
}
|
||||
|
||||
function filePathFromJson(meta: DocgenMetaJson): string {
|
||||
return `${meta.path.slice('packages/discord.js/'.length)}/${meta.file}`;
|
||||
}
|
||||
|
||||
function fixPrimitiveTypes(type: string, symbol: string | undefined) {
|
||||
switch (type) {
|
||||
case '*':
|
||||
return 'any';
|
||||
case 'Object':
|
||||
return symbol === '<' ? 'Record' : 'object';
|
||||
default:
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
export class ApiModelGenerator {
|
||||
private readonly _collector: Collector;
|
||||
|
||||
private readonly _apiModel: ApiModel;
|
||||
|
||||
private readonly _tsDocParser: tsdoc.TSDocParser;
|
||||
|
||||
private readonly _referenceGenerator: DeclarationReferenceGenerator;
|
||||
|
||||
public constructor(collector: Collector) {
|
||||
this._collector = collector;
|
||||
this._apiModel = new ApiModel();
|
||||
this._referenceGenerator = new DeclarationReferenceGenerator(collector);
|
||||
// @ts-expect-error we reuse the private tsdocParser from collector here
|
||||
this._tsDocParser = collector._tsdocParser;
|
||||
}
|
||||
|
||||
public get apiModel(): ApiModel {
|
||||
@@ -430,6 +453,42 @@ export class ApiModelGenerator {
|
||||
name: childDeclaration.astSymbol.localName,
|
||||
});
|
||||
}
|
||||
|
||||
for (const method of (context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined)?.methods ??
|
||||
[]) {
|
||||
switch (context.parentApiItem.kind) {
|
||||
case ApiItemKind.Class:
|
||||
this._processApiMethod(null, { ...context, name: method.name });
|
||||
break;
|
||||
|
||||
case ApiItemKind.Interface:
|
||||
this._processApiMethodSignature(null, { ...context, name: method.name });
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(
|
||||
`Found docgen method not in TS typings for ApiItem of kind ${ApiItemKind[context.parentApiItem.kind]}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const property of (context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined)?.props ??
|
||||
[]) {
|
||||
switch (context.parentApiItem.kind) {
|
||||
case ApiItemKind.Class:
|
||||
this._processApiProperty(null, { ...context, name: property.name });
|
||||
break;
|
||||
|
||||
case ApiItemKind.Interface:
|
||||
this._processApiPropertySignature(null, { ...context, name: property.name });
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(
|
||||
`Found docgen property not in TS typings for ApiItem of kind ${ApiItemKind[context.parentApiItem.kind]}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _processApiCallSignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {
|
||||
@@ -500,7 +559,7 @@ export class ApiModelGenerator {
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = parent?.construct
|
||||
? new TSDocParser().parseString(
|
||||
? this._tsDocParser.parseString(
|
||||
`/*+\n * ${fixLinkTags(parent.construct.description)}\n${
|
||||
parent.construct.params
|
||||
?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`)
|
||||
@@ -586,7 +645,7 @@ export class ApiModelGenerator {
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? new TSDocParser().parseString(
|
||||
? this._tsDocParser.parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${jsDoc.see?.map((see) => ` * @see ${see}\n`).join('') ?? ''}${
|
||||
jsDoc.deprecated
|
||||
? ` * @deprecated ${
|
||||
@@ -658,7 +717,7 @@ export class ApiModelGenerator {
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = parent?.construct
|
||||
? new TSDocParser().parseString(
|
||||
? this._tsDocParser.parseString(
|
||||
`/*+\n * ${fixLinkTags(parent.construct.description)}\n${
|
||||
parent.construct.params
|
||||
?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`)
|
||||
@@ -789,7 +848,7 @@ export class ApiModelGenerator {
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? new TSDocParser().parseString(
|
||||
? this._tsDocParser.parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${
|
||||
jsDoc.params?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`).join('') ??
|
||||
''
|
||||
@@ -916,7 +975,7 @@ export class ApiModelGenerator {
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? new TSDocParser().parseString(
|
||||
? this._tsDocParser.parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${jsDoc.see?.map((see) => ` * @see ${see}\n`).join('') ?? ''}${
|
||||
jsDoc.deprecated
|
||||
? ` * @deprecated ${
|
||||
@@ -952,86 +1011,103 @@ export class ApiModelGenerator {
|
||||
});
|
||||
}
|
||||
|
||||
private _processApiMethod(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {
|
||||
private _processApiMethod(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void {
|
||||
const { name, parentApiItem } = context;
|
||||
const isStatic: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0;
|
||||
const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration);
|
||||
const parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined;
|
||||
const jsDoc = parent?.methods?.find((method) => method.name === name);
|
||||
const isStatic: boolean = astDeclaration
|
||||
? (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0
|
||||
: jsDoc?.scope === 'static';
|
||||
const overloadIndex: number = astDeclaration ? this._collector.getOverloadIndex(astDeclaration) : 1;
|
||||
const containerKey: string = ApiMethod.getContainerKey(name, isStatic, overloadIndex);
|
||||
|
||||
let apiMethod: ApiMethod | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiMethod;
|
||||
const parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined;
|
||||
const jsDoc = parent?.methods?.find((method) => method.name === name);
|
||||
|
||||
if (apiMethod === undefined) {
|
||||
const methodDeclaration: ts.MethodDeclaration = astDeclaration.declaration as ts.MethodDeclaration;
|
||||
if (astDeclaration) {
|
||||
const methodDeclaration: ts.MethodDeclaration = astDeclaration.declaration as ts.MethodDeclaration;
|
||||
|
||||
const nodesToCapture: IExcerptBuilderNodeToCapture[] = [];
|
||||
const nodesToCapture: IExcerptBuilderNodeToCapture[] = [];
|
||||
|
||||
const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();
|
||||
nodesToCapture.push({ node: methodDeclaration.type, tokenRange: returnTypeTokenRange });
|
||||
const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();
|
||||
nodesToCapture.push({ node: methodDeclaration.type, tokenRange: returnTypeTokenRange });
|
||||
|
||||
const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(
|
||||
nodesToCapture,
|
||||
methodDeclaration.typeParameters,
|
||||
);
|
||||
const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(
|
||||
nodesToCapture,
|
||||
methodDeclaration.typeParameters,
|
||||
);
|
||||
|
||||
const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, methodDeclaration.parameters);
|
||||
const parameters: IApiParameterOptions[] = this._captureParameters(
|
||||
nodesToCapture,
|
||||
methodDeclaration.parameters,
|
||||
);
|
||||
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? new TSDocParser().parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${
|
||||
jsDoc.params?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`).join('') ??
|
||||
''
|
||||
}${
|
||||
jsDoc.returns?.length && !Array.isArray(jsDoc.returns[0])
|
||||
? ` * @returns ${fixLinkTags(jsDoc.returns[0]!.description ?? '')}`
|
||||
: ''
|
||||
}${
|
||||
jsDoc.deprecated
|
||||
? ` * @deprecated ${
|
||||
typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated
|
||||
}\n`
|
||||
: ''
|
||||
} */`,
|
||||
).docComment
|
||||
: apiItemMetadata.tsdocComment;
|
||||
const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;
|
||||
if (releaseTag === ReleaseTag.Internal || releaseTag === ReleaseTag.Alpha) {
|
||||
return; // trim out items marked as "@internal" or "@alpha"
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? this._tsDocParser.parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${
|
||||
jsDoc.params
|
||||
?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`)
|
||||
.join('') ?? ''
|
||||
}${
|
||||
jsDoc.returns?.length && !Array.isArray(jsDoc.returns[0])
|
||||
? ` * @returns ${fixLinkTags(jsDoc.returns[0]!.description ?? '')}`
|
||||
: ''
|
||||
}${
|
||||
jsDoc.examples?.map((example) => ` * @example\n * \`\`\`js\n * ${example}\n * \`\`\`\n`).join('') ?? ''
|
||||
}${
|
||||
jsDoc.deprecated
|
||||
? ` * @deprecated ${
|
||||
typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated
|
||||
}\n`
|
||||
: ''
|
||||
} */`,
|
||||
).docComment
|
||||
: apiItemMetadata.tsdocComment;
|
||||
const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;
|
||||
if (releaseTag === ReleaseTag.Internal || releaseTag === ReleaseTag.Alpha) {
|
||||
return; // trim out items marked as "@internal" or "@alpha"
|
||||
}
|
||||
|
||||
const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;
|
||||
const isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0;
|
||||
const isAbstract: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Abstract) !== 0;
|
||||
const sourceLocation: ISourceLocation = this._getSourceLocation(methodDeclaration);
|
||||
|
||||
apiMethod = new ApiMethod({
|
||||
name,
|
||||
isAbstract,
|
||||
docComment,
|
||||
releaseTag,
|
||||
isProtected,
|
||||
isStatic,
|
||||
isOptional,
|
||||
typeParameters,
|
||||
parameters,
|
||||
overloadIndex,
|
||||
excerptTokens,
|
||||
returnTypeTokenRange,
|
||||
fileUrlPath: jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,
|
||||
fileLine: jsDoc?.meta.line ?? sourceLocation.sourceFileLine,
|
||||
fileColumn: sourceLocation.sourceFileColumn,
|
||||
});
|
||||
} else if (jsDoc) {
|
||||
const methodOptions = this._mapMethod(jsDoc, parentApiItem.getAssociatedPackage()!.name);
|
||||
if (methodOptions.releaseTag === ReleaseTag.Internal || methodOptions.releaseTag === ReleaseTag.Alpha) {
|
||||
return; // trim out items marked as "@internal" or "@alpha"
|
||||
}
|
||||
|
||||
apiMethod = new ApiMethod(methodOptions);
|
||||
}
|
||||
|
||||
const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;
|
||||
const isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0;
|
||||
const isAbstract: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Abstract) !== 0;
|
||||
const sourceLocation: ISourceLocation = this._getSourceLocation(methodDeclaration);
|
||||
|
||||
apiMethod = new ApiMethod({
|
||||
name,
|
||||
isAbstract,
|
||||
docComment,
|
||||
releaseTag,
|
||||
isProtected,
|
||||
isStatic,
|
||||
isOptional,
|
||||
typeParameters,
|
||||
parameters,
|
||||
overloadIndex,
|
||||
excerptTokens,
|
||||
returnTypeTokenRange,
|
||||
fileUrlPath: jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,
|
||||
fileLine: jsDoc?.meta.line ?? sourceLocation.sourceFileLine,
|
||||
fileColumn: sourceLocation.sourceFileColumn,
|
||||
});
|
||||
|
||||
parentApiItem.addMember(apiMethod);
|
||||
}
|
||||
}
|
||||
|
||||
private _processApiMethodSignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {
|
||||
private _processApiMethodSignature(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void {
|
||||
const { name, parentApiItem } = context;
|
||||
const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration);
|
||||
const overloadIndex: number = astDeclaration ? this._collector.getOverloadIndex(astDeclaration) : 1;
|
||||
const containerKey: string = ApiMethodSignature.getContainerKey(name, overloadIndex);
|
||||
|
||||
let apiMethodSignature: ApiMethodSignature | undefined = parentApiItem.tryGetMemberByKey(
|
||||
@@ -1041,58 +1117,63 @@ export class ApiModelGenerator {
|
||||
const jsDoc = parent?.methods?.find((method) => method.name === name);
|
||||
|
||||
if (apiMethodSignature === undefined) {
|
||||
const methodSignature: ts.MethodSignature = astDeclaration.declaration as ts.MethodSignature;
|
||||
if (astDeclaration) {
|
||||
const methodSignature: ts.MethodSignature = astDeclaration.declaration as ts.MethodSignature;
|
||||
|
||||
const nodesToCapture: IExcerptBuilderNodeToCapture[] = [];
|
||||
const nodesToCapture: IExcerptBuilderNodeToCapture[] = [];
|
||||
|
||||
const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();
|
||||
nodesToCapture.push({ node: methodSignature.type, tokenRange: returnTypeTokenRange });
|
||||
const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();
|
||||
nodesToCapture.push({ node: methodSignature.type, tokenRange: returnTypeTokenRange });
|
||||
|
||||
const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(
|
||||
nodesToCapture,
|
||||
methodSignature.typeParameters,
|
||||
);
|
||||
const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(
|
||||
nodesToCapture,
|
||||
methodSignature.typeParameters,
|
||||
);
|
||||
|
||||
const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, methodSignature.parameters);
|
||||
const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, methodSignature.parameters);
|
||||
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? new TSDocParser().parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${
|
||||
jsDoc.params?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`).join('') ??
|
||||
''
|
||||
}${
|
||||
jsDoc.returns?.length && !Array.isArray(jsDoc.returns[0])
|
||||
? ` * @returns ${fixLinkTags(jsDoc.returns[0]!.description ?? '')}`
|
||||
: ''
|
||||
}${
|
||||
jsDoc.deprecated
|
||||
? ` * @deprecated ${
|
||||
typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated
|
||||
}\n`
|
||||
: ''
|
||||
} */`,
|
||||
).docComment
|
||||
: apiItemMetadata.tsdocComment;
|
||||
const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;
|
||||
const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;
|
||||
const sourceLocation: ISourceLocation = this._getSourceLocation(methodSignature);
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? this._tsDocParser.parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${
|
||||
jsDoc.params
|
||||
?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`)
|
||||
.join('') ?? ''
|
||||
}${
|
||||
jsDoc.returns?.length && !Array.isArray(jsDoc.returns[0])
|
||||
? ` * @returns ${fixLinkTags(jsDoc.returns[0]!.description ?? '')}`
|
||||
: ''
|
||||
}${
|
||||
jsDoc.deprecated
|
||||
? ` * @deprecated ${
|
||||
typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated
|
||||
}\n`
|
||||
: ''
|
||||
} */`,
|
||||
).docComment
|
||||
: apiItemMetadata.tsdocComment;
|
||||
const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;
|
||||
const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;
|
||||
const sourceLocation: ISourceLocation = this._getSourceLocation(methodSignature);
|
||||
|
||||
apiMethodSignature = new ApiMethodSignature({
|
||||
name,
|
||||
docComment,
|
||||
releaseTag,
|
||||
isOptional,
|
||||
typeParameters,
|
||||
parameters,
|
||||
overloadIndex,
|
||||
excerptTokens,
|
||||
returnTypeTokenRange,
|
||||
fileUrlPath: jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,
|
||||
fileLine: jsDoc?.meta.line ?? sourceLocation.sourceFileLine,
|
||||
fileColumn: sourceLocation.sourceFileColumn,
|
||||
});
|
||||
apiMethodSignature = new ApiMethodSignature({
|
||||
name,
|
||||
docComment,
|
||||
releaseTag,
|
||||
isOptional,
|
||||
typeParameters,
|
||||
parameters,
|
||||
overloadIndex,
|
||||
excerptTokens,
|
||||
returnTypeTokenRange,
|
||||
fileUrlPath: jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,
|
||||
fileLine: jsDoc?.meta.line ?? sourceLocation.sourceFileLine,
|
||||
fileColumn: sourceLocation.sourceFileColumn,
|
||||
});
|
||||
} else if (jsDoc) {
|
||||
apiMethodSignature = new ApiMethodSignature(this._mapMethod(jsDoc, parentApiItem.getAssociatedPackage()!.name));
|
||||
}
|
||||
|
||||
parentApiItem.addMember(apiMethodSignature);
|
||||
}
|
||||
@@ -1130,77 +1211,93 @@ export class ApiModelGenerator {
|
||||
});
|
||||
}
|
||||
|
||||
private _processApiProperty(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {
|
||||
private _processApiProperty(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void {
|
||||
const { name, parentApiItem } = context;
|
||||
const isStatic: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0;
|
||||
const parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | DocgenTypedefJson | undefined;
|
||||
const jsDoc = parent?.props?.find((prop) => prop.name === name);
|
||||
const isStatic: boolean = astDeclaration
|
||||
? (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0
|
||||
: parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface
|
||||
? (jsDoc as DocgenPropertyJson).scope === 'static'
|
||||
: false;
|
||||
const containerKey: string = ApiProperty.getContainerKey(name, isStatic);
|
||||
|
||||
let apiProperty: ApiProperty | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiProperty;
|
||||
const parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | DocgenTypedefJson | undefined;
|
||||
const jsDoc = parent?.props?.find((prop) => prop.name === name);
|
||||
|
||||
if (apiProperty === undefined) {
|
||||
const declaration: ts.Declaration = astDeclaration.declaration;
|
||||
const nodesToCapture: IExcerptBuilderNodeToCapture[] = [];
|
||||
if (astDeclaration) {
|
||||
const declaration: ts.Declaration = astDeclaration.declaration;
|
||||
const nodesToCapture: IExcerptBuilderNodeToCapture[] = [];
|
||||
|
||||
const propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();
|
||||
let propertyTypeNode: ts.TypeNode | undefined;
|
||||
const propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();
|
||||
let propertyTypeNode: ts.TypeNode | undefined;
|
||||
|
||||
if (ts.isPropertyDeclaration(declaration) || ts.isGetAccessorDeclaration(declaration)) {
|
||||
propertyTypeNode = declaration.type;
|
||||
if (ts.isPropertyDeclaration(declaration) || ts.isGetAccessorDeclaration(declaration)) {
|
||||
propertyTypeNode = declaration.type;
|
||||
}
|
||||
|
||||
if (ts.isSetAccessorDeclaration(declaration)) {
|
||||
// Note that TypeScript always reports an error if a setter does not have exactly one parameter.
|
||||
propertyTypeNode = declaration.parameters[0]!.type;
|
||||
}
|
||||
|
||||
nodesToCapture.push({ node: propertyTypeNode, tokenRange: propertyTypeTokenRange });
|
||||
|
||||
let initializerTokenRange: IExcerptTokenRange | undefined;
|
||||
if (ts.isPropertyDeclaration(declaration) && declaration.initializer) {
|
||||
initializerTokenRange = ExcerptBuilder.createEmptyTokenRange();
|
||||
nodesToCapture.push({ node: declaration.initializer, tokenRange: initializerTokenRange });
|
||||
}
|
||||
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? this._tsDocParser.parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${
|
||||
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
|
||||
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
|
||||
'deprecated' in jsDoc && jsDoc.deprecated
|
||||
? ` * @deprecated ${
|
||||
typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated
|
||||
}\n`
|
||||
: ''
|
||||
} */`,
|
||||
).docComment
|
||||
: apiItemMetadata.tsdocComment;
|
||||
const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;
|
||||
const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;
|
||||
const isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0;
|
||||
const isAbstract: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Abstract) !== 0;
|
||||
const isReadonly: boolean = this._isReadonly(astDeclaration);
|
||||
const sourceLocation: ISourceLocation = this._getSourceLocation(declaration);
|
||||
|
||||
apiProperty = new ApiProperty({
|
||||
name,
|
||||
docComment,
|
||||
releaseTag,
|
||||
isAbstract,
|
||||
isProtected,
|
||||
isStatic,
|
||||
isOptional,
|
||||
isReadonly,
|
||||
excerptTokens,
|
||||
propertyTypeTokenRange,
|
||||
initializerTokenRange,
|
||||
fileUrlPath: jsDoc && 'meta' in jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,
|
||||
fileLine: jsDoc && 'meta' in jsDoc ? jsDoc.meta.line : sourceLocation.sourceFileLine,
|
||||
fileColumn: sourceLocation.sourceFileColumn,
|
||||
});
|
||||
} else if (parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface) {
|
||||
const propertyOptions = this._mapProp(jsDoc as DocgenPropertyJson, parentApiItem.getAssociatedPackage()!.name);
|
||||
if (propertyOptions.releaseTag === ReleaseTag.Internal || propertyOptions.releaseTag === ReleaseTag.Alpha) {
|
||||
return; // trim out items marked as "@internal" or "@alpha"
|
||||
}
|
||||
|
||||
apiProperty = new ApiProperty(propertyOptions);
|
||||
} else {
|
||||
console.log(`We got a property in ApiItem of kind ${ApiItemKind[parentApiItem.kind]}`);
|
||||
}
|
||||
|
||||
if (ts.isSetAccessorDeclaration(declaration)) {
|
||||
// Note that TypeScript always reports an error if a setter does not have exactly one parameter.
|
||||
propertyTypeNode = declaration.parameters[0]!.type;
|
||||
}
|
||||
|
||||
nodesToCapture.push({ node: propertyTypeNode, tokenRange: propertyTypeTokenRange });
|
||||
|
||||
let initializerTokenRange: IExcerptTokenRange | undefined;
|
||||
if (ts.isPropertyDeclaration(declaration) && declaration.initializer) {
|
||||
initializerTokenRange = ExcerptBuilder.createEmptyTokenRange();
|
||||
nodesToCapture.push({ node: declaration.initializer, tokenRange: initializerTokenRange });
|
||||
}
|
||||
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? new TSDocParser().parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${
|
||||
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
|
||||
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
|
||||
'deprecated' in jsDoc && jsDoc.deprecated
|
||||
? ` * @deprecated ${
|
||||
typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated
|
||||
}\n`
|
||||
: ''
|
||||
} */`,
|
||||
).docComment
|
||||
: apiItemMetadata.tsdocComment;
|
||||
const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;
|
||||
const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;
|
||||
const isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0;
|
||||
const isAbstract: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Abstract) !== 0;
|
||||
const isReadonly: boolean = this._isReadonly(astDeclaration);
|
||||
const sourceLocation: ISourceLocation = this._getSourceLocation(declaration);
|
||||
|
||||
apiProperty = new ApiProperty({
|
||||
name,
|
||||
docComment,
|
||||
releaseTag,
|
||||
isAbstract,
|
||||
isProtected,
|
||||
isStatic,
|
||||
isOptional,
|
||||
isReadonly,
|
||||
excerptTokens,
|
||||
propertyTypeTokenRange,
|
||||
initializerTokenRange,
|
||||
fileUrlPath: jsDoc && 'meta' in jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,
|
||||
fileLine: jsDoc && 'meta' in jsDoc ? jsDoc.meta.line : sourceLocation.sourceFileLine,
|
||||
fileColumn: sourceLocation.sourceFileColumn,
|
||||
});
|
||||
parentApiItem.addMember(apiProperty);
|
||||
} else {
|
||||
// If the property was already declared before (via a merged interface declaration),
|
||||
@@ -1208,7 +1305,7 @@ export class ApiModelGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private _processApiPropertySignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {
|
||||
private _processApiPropertySignature(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void {
|
||||
const { name, parentApiItem } = context;
|
||||
const containerKey: string = ApiPropertySignature.getContainerKey(name);
|
||||
|
||||
@@ -1219,41 +1316,49 @@ export class ApiModelGenerator {
|
||||
const jsDoc = parent?.props?.find((prop) => prop.name === name);
|
||||
|
||||
if (apiPropertySignature === undefined) {
|
||||
const propertySignature: ts.PropertySignature = astDeclaration.declaration as ts.PropertySignature;
|
||||
if (astDeclaration) {
|
||||
const propertySignature: ts.PropertySignature = astDeclaration.declaration as ts.PropertySignature;
|
||||
|
||||
const nodesToCapture: IExcerptBuilderNodeToCapture[] = [];
|
||||
const nodesToCapture: IExcerptBuilderNodeToCapture[] = [];
|
||||
|
||||
const propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();
|
||||
nodesToCapture.push({ node: propertySignature.type, tokenRange: propertyTypeTokenRange });
|
||||
const propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();
|
||||
nodesToCapture.push({ node: propertySignature.type, tokenRange: propertyTypeTokenRange });
|
||||
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? new TSDocParser().parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${
|
||||
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
|
||||
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
|
||||
'deprecated' in jsDoc && jsDoc.deprecated ? ` * @deprecated ${jsDoc.deprecated}\n` : ''
|
||||
} */`,
|
||||
).docComment
|
||||
: apiItemMetadata.tsdocComment;
|
||||
const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;
|
||||
const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;
|
||||
const isReadonly: boolean = this._isReadonly(astDeclaration);
|
||||
const sourceLocation: ISourceLocation = this._getSourceLocation(propertySignature);
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? this._tsDocParser.parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${
|
||||
'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''
|
||||
}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${
|
||||
'deprecated' in jsDoc && jsDoc.deprecated ? ` * @deprecated ${jsDoc.deprecated}\n` : ''
|
||||
} */`,
|
||||
).docComment
|
||||
: apiItemMetadata.tsdocComment;
|
||||
const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;
|
||||
const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;
|
||||
const isReadonly: boolean = this._isReadonly(astDeclaration);
|
||||
const sourceLocation: ISourceLocation = this._getSourceLocation(propertySignature);
|
||||
|
||||
apiPropertySignature = new ApiPropertySignature({
|
||||
name,
|
||||
docComment,
|
||||
releaseTag,
|
||||
isOptional,
|
||||
excerptTokens,
|
||||
propertyTypeTokenRange,
|
||||
isReadonly,
|
||||
fileUrlPath: jsDoc && 'meta' in jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,
|
||||
fileLine: jsDoc && 'meta' in jsDoc ? jsDoc.meta.line : sourceLocation.sourceFileLine,
|
||||
fileColumn: sourceLocation.sourceFileColumn,
|
||||
});
|
||||
apiPropertySignature = new ApiPropertySignature({
|
||||
name,
|
||||
docComment,
|
||||
releaseTag,
|
||||
isOptional,
|
||||
excerptTokens,
|
||||
propertyTypeTokenRange,
|
||||
isReadonly,
|
||||
fileUrlPath: jsDoc && 'meta' in jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,
|
||||
fileLine: jsDoc && 'meta' in jsDoc ? jsDoc.meta.line : sourceLocation.sourceFileLine,
|
||||
fileColumn: sourceLocation.sourceFileColumn,
|
||||
});
|
||||
} else if (parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface) {
|
||||
apiPropertySignature = new ApiPropertySignature(
|
||||
this._mapProp(jsDoc as DocgenPropertyJson, parentApiItem.getAssociatedPackage()!.name),
|
||||
);
|
||||
} else {
|
||||
console.log(`We got a property in ApiItem of kind ${ApiItemKind[parentApiItem.kind]}`);
|
||||
}
|
||||
|
||||
parentApiItem.addMember(apiPropertySignature);
|
||||
} else {
|
||||
@@ -1290,7 +1395,7 @@ export class ApiModelGenerator {
|
||||
const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture);
|
||||
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
|
||||
const docComment: tsdoc.DocComment | undefined = jsDoc
|
||||
? new TSDocParser().parseString(
|
||||
? this._tsDocParser.parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description) ?? ''}\n${
|
||||
'params' in jsDoc
|
||||
? jsDoc.params.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`).join('')
|
||||
@@ -1425,7 +1530,7 @@ export class ApiModelGenerator {
|
||||
});
|
||||
}
|
||||
|
||||
const docComment: tsdoc.DocComment | undefined = new TSDocParser().parseString(
|
||||
const docComment: tsdoc.DocComment | undefined = this._tsDocParser.parseString(
|
||||
`/**\n * ${fixLinkTags(jsDoc.description)}\n${
|
||||
jsDoc.params?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`).join('') ?? ''
|
||||
}${'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''}${
|
||||
@@ -1574,35 +1679,162 @@ export class ApiModelGenerator {
|
||||
[ts.SyntaxKind.InterfaceDeclaration]: 'interface',
|
||||
[ts.SyntaxKind.TypeAliasDeclaration]: 'type',
|
||||
};
|
||||
return mapper.flatMap((typ) =>
|
||||
typ.reduce<IExcerptToken[]>(
|
||||
(arr, [type, symbol]) => [
|
||||
...arr,
|
||||
{
|
||||
kind: ExcerptTokenKind.Reference,
|
||||
text: type ?? 'unknown',
|
||||
canonicalReference: DeclarationReference.package(this._apiModel.packages[0]!.name)
|
||||
.addNavigationStep(Navigation.Members as any, DeclarationReference.parseComponent(type ?? 'unknown'))
|
||||
.withMeaning(
|
||||
lookup[
|
||||
(
|
||||
(this._collector.entities.find(
|
||||
(entity) => entity.nameForEmit === type && 'astDeclarations' in entity.astEntity,
|
||||
)?.astEntity as AstSymbol | undefined) ??
|
||||
(
|
||||
this._collector.entities.find(
|
||||
(entity) => entity.nameForEmit === type && 'astSymbol' in entity.astEntity,
|
||||
)?.astEntity as AstImport | undefined
|
||||
)?.astSymbol
|
||||
)?.astDeclarations[0]?.declaration.kind ?? ts.SyntaxKind.ClassDeclaration
|
||||
] ?? ('class' as any),
|
||||
)
|
||||
.toString(),
|
||||
},
|
||||
{ kind: ExcerptTokenKind.Content, text: symbol ?? '' },
|
||||
],
|
||||
[],
|
||||
),
|
||||
);
|
||||
return mapper
|
||||
.flatMap((typ, index) => {
|
||||
const result = typ.reduce<IExcerptToken[]>(
|
||||
(arr, [type, symbol]) => [
|
||||
...arr,
|
||||
{
|
||||
kind: type?.includes("'") ? ExcerptTokenKind.Content : ExcerptTokenKind.Reference,
|
||||
text: fixPrimitiveTypes(type ?? 'unknown', symbol),
|
||||
canonicalReference: type?.includes("'")
|
||||
? undefined
|
||||
: DeclarationReference.package(this._apiModel.packages[0]!.name)
|
||||
.addNavigationStep(
|
||||
Navigation.Members as any,
|
||||
DeclarationReference.parseComponent(type ?? 'unknown'),
|
||||
)
|
||||
.withMeaning(
|
||||
lookup[
|
||||
(
|
||||
(this._collector.entities.find(
|
||||
(entity) => entity.nameForEmit === type && 'astDeclarations' in entity.astEntity,
|
||||
)?.astEntity as AstSymbol | undefined) ??
|
||||
(
|
||||
this._collector.entities.find(
|
||||
(entity) => entity.nameForEmit === type && 'astSymbol' in entity.astEntity,
|
||||
)?.astEntity as AstImport | undefined
|
||||
)?.astSymbol
|
||||
)?.astDeclarations[0]?.declaration.kind ?? ts.SyntaxKind.ClassDeclaration
|
||||
] ?? ('class' as any),
|
||||
)
|
||||
.toString(),
|
||||
},
|
||||
{ kind: ExcerptTokenKind.Content, text: symbol ?? '' },
|
||||
],
|
||||
[],
|
||||
);
|
||||
return index === 0 ? result : [{ kind: ExcerptTokenKind.Content, text: ' | ' }, ...result];
|
||||
})
|
||||
.filter((excerpt) => excerpt.text.length);
|
||||
}
|
||||
|
||||
private _mapProp(prop: DocgenPropertyJson, _package: string): IApiPropertyOptions {
|
||||
const mappedVarType = this._mapVarType(prop.type);
|
||||
return {
|
||||
name: prop.name,
|
||||
isAbstract: Boolean(prop.abstract),
|
||||
isProtected: prop.access === 'protected',
|
||||
isStatic: prop.scope === 'static',
|
||||
isOptional: Boolean(prop.nullable),
|
||||
isReadonly: Boolean(prop.readonly),
|
||||
docComment: this._tsDocParser.parseString(
|
||||
`/**\n * ${prop.description}\n${prop.see?.map((see) => ` * @see ${see}\n`).join('') ?? ''}${
|
||||
prop.readonly ? ' * @readonly\n' : ''
|
||||
} */`,
|
||||
).docComment,
|
||||
excerptTokens: [
|
||||
{
|
||||
kind: ExcerptTokenKind.Content,
|
||||
text: `${prop.access} ${prop.scope === 'static' ? 'static ' : ''}${prop.readonly ? 'readonly ' : ''}${
|
||||
prop.name
|
||||
} :`,
|
||||
},
|
||||
...mappedVarType,
|
||||
{ kind: ExcerptTokenKind.Content, text: ';' },
|
||||
],
|
||||
propertyTypeTokenRange: { startIndex: 1, endIndex: 1 + mappedVarType.length },
|
||||
releaseTag: prop.access === 'private' ? ReleaseTag.Internal : ReleaseTag.Public,
|
||||
fileLine: prop.meta?.line ?? 0,
|
||||
fileUrlPath: prop.meta ? `${prop.meta.path.slice(`packages/${_package}/`.length)}/${prop.meta.file}` : '',
|
||||
};
|
||||
}
|
||||
|
||||
private _mapParam(
|
||||
param: DocgenParamJson,
|
||||
index: number,
|
||||
_package: string,
|
||||
paramTokens: number[],
|
||||
): IApiParameterOptions {
|
||||
return {
|
||||
parameterName: param.name.startsWith('...') ? param.name.slice(3) : param.name,
|
||||
isOptional: Boolean(param.optional),
|
||||
isRest: param.name.startsWith('...'),
|
||||
parameterTypeTokenRange: {
|
||||
startIndex: 1 + index + paramTokens.slice(0, index).reduce((akk, num) => akk + num, 0),
|
||||
endIndex: 1 + index + paramTokens.slice(0, index + 1).reduce((akk, num) => akk + num, 0),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private _mapMethod(method: DocgenMethodJson, _package: string): IApiMethodOptions {
|
||||
const excerptTokens: IExcerptToken[] = [];
|
||||
excerptTokens.push({
|
||||
kind: ExcerptTokenKind.Content,
|
||||
text: `${
|
||||
method.scope === 'global'
|
||||
? `export function ${method.name}(`
|
||||
: `${method.access}${method.scope === 'static' ? ' static' : ''} ${method.name}(`
|
||||
}${
|
||||
method.params?.length
|
||||
? `${method.params[0]!.name}${method.params[0]!.nullable || method.params[0]!.optional ? '?' : ''}`
|
||||
: '): '
|
||||
}`,
|
||||
});
|
||||
const paramTokens: number[] = [];
|
||||
for (let index = 0; index < (method.params?.length ?? 0) - 1; index++) {
|
||||
const newTokens = this._mapVarType(method.params![index]!.type);
|
||||
paramTokens.push(newTokens.length);
|
||||
excerptTokens.push(...newTokens);
|
||||
excerptTokens.push({
|
||||
kind: ExcerptTokenKind.Content,
|
||||
text: `, ${method.params![index + 1]!.name}${
|
||||
method.params![index + 1]!.nullable || method.params![index + 1]!.optional ? '?' : ''
|
||||
}: `,
|
||||
});
|
||||
}
|
||||
|
||||
if (method.params?.length) {
|
||||
const newTokens = this._mapVarType(method.params[method.params.length - 1]!.type);
|
||||
paramTokens.push(newTokens.length);
|
||||
excerptTokens.push(...newTokens);
|
||||
excerptTokens.push({ kind: ExcerptTokenKind.Content, text: `): ` });
|
||||
}
|
||||
|
||||
const returnTokens = this._mapVarType(method.returns?.[0] ?? []);
|
||||
excerptTokens.push(...returnTokens);
|
||||
|
||||
excerptTokens.push({ kind: ExcerptTokenKind.Content, text: ';' });
|
||||
|
||||
return {
|
||||
name: method.name,
|
||||
isAbstract: Boolean(method.abstract),
|
||||
isOptional: false,
|
||||
isProtected: method.access === 'protected',
|
||||
isStatic: method.scope === 'static',
|
||||
overloadIndex: 1,
|
||||
parameters: method.params?.map((param, index) => this._mapParam(param, index, _package, paramTokens)) ?? [],
|
||||
releaseTag: method.access === 'private' ? ReleaseTag.Internal : ReleaseTag.Public,
|
||||
returnTypeTokenRange: method.returns?.length
|
||||
? { startIndex: excerptTokens.length - 1 - returnTokens.length, endIndex: excerptTokens.length - 1 }
|
||||
: { startIndex: 0, endIndex: 0 },
|
||||
typeParameters: [],
|
||||
docComment: this._tsDocParser.parseString(
|
||||
`/**\n * ${method.description}\n${
|
||||
method.params?.map((param) => ` * @param ${param.name} - ${param.description}\n`).join('') ?? ''
|
||||
}${
|
||||
method.returns?.length && !Array.isArray(method.returns[0])
|
||||
? ` * @returns ${method.returns[0]!.description}`
|
||||
: ''
|
||||
}${method.examples?.map((example) => ` * @example\n * \`\`\`js\n * ${example}\n * \`\`\`\n`).join('') ?? ''}${
|
||||
method.deprecated
|
||||
? ` * @deprecated ${typeof method.deprecated === 'boolean' ? 'yes' : method.deprecated}\n`
|
||||
: ''
|
||||
} */`,
|
||||
).docComment,
|
||||
excerptTokens,
|
||||
fileLine: method.meta.line,
|
||||
fileUrlPath: `${method.meta.path.slice(`packages/${_package}/`.length)}/${method.meta.file}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ export class ExcerptBuilder {
|
||||
return { startIndex: 0, endIndex: 0, typeParameters: [] };
|
||||
}
|
||||
|
||||
public static isPrimitiveKeyword(node: ts.Node): boolean {
|
||||
private static _isPrimitiveKeyword(node: ts.Node): boolean {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.AnyKeyword:
|
||||
case ts.SyntaxKind.BigIntKeyword:
|
||||
@@ -156,6 +156,15 @@ export class ExcerptBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private static _isRedundantBarAfterColon(span: Span) {
|
||||
return (
|
||||
span.kind === ts.SyntaxKind.BarToken &&
|
||||
span.previousSibling === undefined &&
|
||||
(span.parent?.parent?.previousSibling?.kind === ts.SyntaxKind.LessThanToken ||
|
||||
span.parent?.parent?.previousSibling?.kind === ts.SyntaxKind.ColonToken)
|
||||
);
|
||||
}
|
||||
|
||||
private static _buildSpan(excerptTokens: IExcerptToken[], span: Span, state: IBuildSpanState): boolean {
|
||||
if (span.kind === ts.SyntaxKind.JSDocComment) {
|
||||
// Discard any comments
|
||||
@@ -174,21 +183,21 @@ export class ExcerptBuilder {
|
||||
if (span.prefix) {
|
||||
let canonicalReference: DeclarationReference | undefined;
|
||||
|
||||
if (span.kind === ts.SyntaxKind.Identifier) {
|
||||
const name: ts.Identifier = span.node as ts.Identifier;
|
||||
if (ts.isIdentifier(span.node)) {
|
||||
const name: ts.Identifier = span.node;
|
||||
canonicalReference = state.referenceGenerator.getDeclarationReferenceForIdentifier(name);
|
||||
}
|
||||
|
||||
if (canonicalReference) {
|
||||
ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Reference, span.prefix, canonicalReference);
|
||||
} else if (
|
||||
ExcerptBuilder.isPrimitiveKeyword(span.node) ||
|
||||
(span.node.kind === ts.SyntaxKind.Identifier &&
|
||||
ExcerptBuilder._isPrimitiveKeyword(span.node) ||
|
||||
(ts.isIdentifier(span.node) &&
|
||||
((ts.isTypeReferenceNode(span.node.parent) && span.node.parent.typeName === span.node) ||
|
||||
(ts.isTypeParameterDeclaration(span.node.parent) && span.node.parent.name === span.node)))
|
||||
) {
|
||||
ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Reference, span.prefix);
|
||||
} else {
|
||||
} else if (!ExcerptBuilder._isRedundantBarAfterColon(span)) {
|
||||
ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.prefix);
|
||||
}
|
||||
|
||||
@@ -313,6 +322,12 @@ export class ExcerptBuilder {
|
||||
!startOrEndIndices.has(currentIndex)
|
||||
) {
|
||||
prevToken.text += currentToken.text;
|
||||
// Remove BarTokens from excerpts if they immediately follow a LessThanToken, e.g. `Promise< | Something>`
|
||||
// would become `Promise<Something>`
|
||||
if (/<\s*\|/.test(prevToken.text)) {
|
||||
prevToken.text = prevToken.text.replace(/<\s*\|\s*/, '<');
|
||||
}
|
||||
|
||||
mergeCount = 1;
|
||||
} else {
|
||||
// Otherwise, no merging can occur here. Continue to the next index.
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createTsupConfig } from '../../tsup.config.js';
|
||||
|
||||
export default createTsupConfig({
|
||||
entry: ['src/**/*.ts'],
|
||||
minify: 'terser',
|
||||
cjsInterop: true,
|
||||
noExternal: ['@microsoft/tsdoc*'],
|
||||
});
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"lint": "prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__",
|
||||
"format": "prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__",
|
||||
"fmt": "pnpm run format",
|
||||
"docs": "pnpm run build:docs && api-extractor run --local",
|
||||
"docs": "pnpm run build:docs && api-extractor run --local --minify",
|
||||
"prepack": "pnpm run lint && pnpm run test && pnpm run build",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/brokers/*'",
|
||||
"release": "cliff-jumper"
|
||||
@@ -71,15 +71,16 @@
|
||||
"ioredis": "^5.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@favware/cliff-jumper": "^2.2.1",
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@favware/cliff-jumper": "^2.2.1",
|
||||
"@types/node": "18.18.8",
|
||||
"@vitest/coverage-v8": "^0.34.6",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild-plugin-version-injector": "^1.2.1",
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-neon": "^0.1.57",
|
||||
"eslint-formatter-pretty": "^5.0.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"tsup": "^7.2.0",
|
||||
"turbo": "^1.10.17-canary.0",
|
||||
"typescript": "^5.2.2",
|
||||
|
||||
@@ -3,3 +3,11 @@ export * from './brokers/redis/PubSubRedis.js';
|
||||
export * from './brokers/redis/RPCRedis.js';
|
||||
|
||||
export * from './brokers/Broker.js';
|
||||
|
||||
/**
|
||||
* The {@link https://github.com/discordjs/discord.js/blob/main/packages/brokers#readme | @discordjs/brokers} version
|
||||
* that you are currently using.
|
||||
*
|
||||
* @privateRemarks This needs to explicitly be `string` so it is not typed as a "const string" that gets injected by esbuild.
|
||||
*/
|
||||
export const version = '[VI]{{inject}}[/VI]' as string;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';
|
||||
import { createTsupConfig } from '../../tsup.config.js';
|
||||
|
||||
export default createTsupConfig();
|
||||
export default createTsupConfig({
|
||||
esbuildPlugins: [esbuildPluginVersionInjector()],
|
||||
});
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('prettier').Config} */
|
||||
module.exports = require('../../.prettierrc.json');
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"lint": "prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__",
|
||||
"format": "prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__",
|
||||
"fmt": "pnpm run format",
|
||||
"docs": "pnpm run build:docs && api-extractor run --local",
|
||||
"docs": "pnpm run build:docs && api-extractor run --local --minify",
|
||||
"prepack": "pnpm run lint && pnpm run test && pnpm run build",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/builders/*'",
|
||||
"release": "cliff-jumper"
|
||||
@@ -73,8 +73,8 @@
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@favware/cliff-jumper": "^2.2.1",
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@favware/cliff-jumper": "^2.2.1",
|
||||
"@types/node": "16.18.60",
|
||||
"@vitest/coverage-v8": "^0.34.6",
|
||||
"cross-env": "^7.0.3",
|
||||
@@ -83,7 +83,7 @@
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-neon": "^0.1.57",
|
||||
"eslint-formatter-pretty": "^5.0.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"tsup": "^7.2.0",
|
||||
"turbo": "^1.10.17-canary.0",
|
||||
"typescript": "^5.2.2",
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('prettier').Config} */
|
||||
module.exports = require('../../.prettierrc.json');
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"lint": "prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__",
|
||||
"format": "prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__",
|
||||
"fmt": "pnpm run format",
|
||||
"docs": "pnpm run build:docs && api-extractor run --local",
|
||||
"docs": "pnpm run build:docs && api-extractor run --local --minify",
|
||||
"prepack": "pnpm run lint && pnpm run test && pnpm run build",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/collection/*'",
|
||||
"release": "cliff-jumper"
|
||||
@@ -60,8 +60,8 @@
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"devDependencies": {
|
||||
"@favware/cliff-jumper": "^2.2.1",
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@favware/cliff-jumper": "^2.2.1",
|
||||
"@types/node": "18.18.8",
|
||||
"@vitest/coverage-v8": "^0.34.6",
|
||||
"cross-env": "^7.0.3",
|
||||
@@ -69,7 +69,7 @@
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-neon": "^0.1.57",
|
||||
"eslint-formatter-pretty": "^5.0.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"tsup": "^7.2.0",
|
||||
"turbo": "^1.10.17-canary.0",
|
||||
"typescript": "^5.2.2",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export * from './collection.js';
|
||||
|
||||
/**
|
||||
* The {@link https://github.com/discordjs/discord.js/blob/main/packages/collection/#readme | @discordjs/collection} version
|
||||
* The {@link https://github.com/discordjs/discord.js/blob/main/packages/collection#readme | @discordjs/collection} version
|
||||
* that you are currently using.
|
||||
*/
|
||||
// This needs to explicitly be `string` so it is not typed as a "const string" that gets injected by esbuild
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/** @type {import('prettier').Config} */
|
||||
module.exports = require('../../.prettierrc.json');
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
# [@discordjs/core@1.1.1](https://github.com/discordjs/discord.js/compare/@discordjs/core@1.1.0...@discordjs/core@1.1.1) - (2023-11-17)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))
|
||||
|
||||
# [@discordjs/core@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@1.0.1...@discordjs/core@1.1.0) - (2023-11-12)
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@discordjs/core",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"description": "A thinly abstracted wrapper around the rest API, and gateway.",
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
@@ -9,7 +9,7 @@
|
||||
"build:docs": "tsc -p tsconfig.docs.json",
|
||||
"lint": "prettier --check . && cross-env TIMING=1 eslint --format=pretty src",
|
||||
"format": "prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src",
|
||||
"docs": "pnpm run build:docs && api-extractor run --local",
|
||||
"docs": "pnpm run build:docs && api-extractor run --local --minify",
|
||||
"prepack": "pnpm run build && pnpm run lint",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/core/*'",
|
||||
"release": "cliff-jumper"
|
||||
@@ -72,8 +72,8 @@
|
||||
"discord-api-types": "0.37.61"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@favware/cliff-jumper": "^2.2.1",
|
||||
"@discordjs/api-extractor": "workspace:^",
|
||||
"@favware/cliff-jumper": "^2.2.1",
|
||||
"@types/node": "18.18.8",
|
||||
"@vitest/coverage-v8": "^0.34.6",
|
||||
"cross-env": "^7.0.3",
|
||||
@@ -81,7 +81,7 @@
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-neon": "^0.1.57",
|
||||
"eslint-formatter-pretty": "^5.0.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"tsup": "^7.2.0",
|
||||
"turbo": "^1.10.17-canary.0",
|
||||
"typescript": "^5.2.2",
|
||||
|
||||
@@ -4,7 +4,7 @@ export * from '../util/index.js';
|
||||
export * from 'discord-api-types/v10';
|
||||
|
||||
/**
|
||||
* The {@link https://github.com/discordjs/discord.js/blob/main/packages/core/#readme | @discordjs/core} version
|
||||
* The {@link https://github.com/discordjs/discord.js/blob/main/packages/core#readme | @discordjs/core} version
|
||||
* that you are currently using.
|
||||
*/
|
||||
// This needs to explicitly be `string` so it is not typed as a "const string" that gets injected by esbuild
|
||||
|
||||
@@ -5,7 +5,7 @@ export * from './util/index.js';
|
||||
export * from 'discord-api-types/v10';
|
||||
|
||||
/**
|
||||
* The {@link https://github.com/discordjs/discord.js/blob/main/packages/core/#readme | @discordjs/core} version
|
||||
* The {@link https://github.com/discordjs/discord.js/blob/main/packages/core#readme | @discordjs/core} version
|
||||
* that you are currently using.
|
||||
*/
|
||||
// This needs to explicitly be `string` so it is not typed as a "const string" that gets injected by esbuild
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';
|
||||
import { createTsupConfig } from '../../tsup.config.js';
|
||||
|
||||
export default createTsupConfig({
|
||||
entry: {
|
||||
index: 'src/index.ts',
|
||||
'http-only': 'src/http-only/index.ts',
|
||||
},
|
||||
esbuildPlugins: [esbuildPluginVersionInjector()],
|
||||
});
|
||||
export default [
|
||||
createTsupConfig({
|
||||
esbuildPlugins: [esbuildPluginVersionInjector()],
|
||||
}),
|
||||
createTsupConfig({
|
||||
entry: {
|
||||
'http-only': 'src/http-only/index.ts',
|
||||
},
|
||||
esbuildPlugins: [esbuildPluginVersionInjector()],
|
||||
}),
|
||||
];
|
||||
|
||||
2
packages/create-discord-bot/.lintstagedrc.cjs
Normal file
2
packages/create-discord-bot/.lintstagedrc.cjs
Normal file
@@ -0,0 +1,2 @@
|
||||
/** @type {import('lint-staged').Config} */
|
||||
module.exports = require('../../.lintstagedrc.json');
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user