mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-19 13:03:31 +01:00
fix(website): doc links to other packages (#9994)
* fix(website): doc links to other packages * fix: missing parameter * Apply suggestions from code review Co-authored-by: Almeida <almeidx@pm.me> --------- Co-authored-by: Almeida <almeidx@pm.me>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import type { Excerpt } from '@discordjs/api-extractor-model';
|
import type { ApiPackage, Excerpt } from '@discordjs/api-extractor-model';
|
||||||
import { ExcerptTokenKind } from '@discordjs/api-extractor-model';
|
import { ExcerptTokenKind } from '@discordjs/api-extractor-model';
|
||||||
import { BuiltinDocumentationLinks } from '~/util/builtinDocumentationLinks';
|
import { BuiltinDocumentationLinks } from '~/util/builtinDocumentationLinks';
|
||||||
import { DISCORD_API_TYPES_DOCS_URL } from '~/util/constants';
|
import { DISCORD_API_TYPES_DOCS_URL } from '~/util/constants';
|
||||||
@@ -7,6 +7,11 @@ import { ItemLink } from './ItemLink';
|
|||||||
import { resolveCanonicalReference, resolveItemURI } from './documentation/util';
|
import { resolveCanonicalReference, resolveItemURI } from './documentation/util';
|
||||||
|
|
||||||
export interface ExcerptTextProps {
|
export interface ExcerptTextProps {
|
||||||
|
/**
|
||||||
|
* The package this excerpt is referenced from.
|
||||||
|
*/
|
||||||
|
readonly apiPackage: ApiPackage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The tokens to render.
|
* The tokens to render.
|
||||||
*/
|
*/
|
||||||
@@ -16,7 +21,7 @@ export interface ExcerptTextProps {
|
|||||||
/**
|
/**
|
||||||
* A component that renders excerpt tokens from an api item.
|
* A component that renders excerpt tokens from an api item.
|
||||||
*/
|
*/
|
||||||
export function ExcerptText({ excerpt }: ExcerptTextProps) {
|
export function ExcerptText({ excerpt, apiPackage }: ExcerptTextProps) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{excerpt.spannedTokens.map((token, idx) => {
|
{excerpt.spannedTokens.map((token, idx) => {
|
||||||
@@ -53,7 +58,9 @@ export function ExcerptText({ excerpt }: ExcerptTextProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolved = token.canonicalReference ? resolveCanonicalReference(token.canonicalReference) : null;
|
const resolved = token.canonicalReference
|
||||||
|
? resolveCanonicalReference(token.canonicalReference, apiPackage)
|
||||||
|
: null;
|
||||||
|
|
||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
return token.text;
|
return token.text;
|
||||||
@@ -65,6 +72,7 @@ export function ExcerptText({ excerpt }: ExcerptTextProps) {
|
|||||||
itemURI={resolveItemURI(resolved.item)}
|
itemURI={resolveItemURI(resolved.item)}
|
||||||
key={`${resolved.item.displayName}-${resolved.item.containerKey}-${idx}`}
|
key={`${resolved.item.displayName}-${resolved.item.containerKey}-${idx}`}
|
||||||
packageName={resolved.package}
|
packageName={resolved.package}
|
||||||
|
version={resolved.version}
|
||||||
>
|
>
|
||||||
{token.text}
|
{token.text}
|
||||||
</ItemLink>
|
</ItemLink>
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ export interface ItemLinkProps<Route extends string> extends Omit<LinkProps<Rout
|
|||||||
|
|
||||||
// TODO: This needs to be properly typed above but monkey-patching it for now.
|
// TODO: This needs to be properly typed above but monkey-patching it for now.
|
||||||
readonly title?: string | undefined;
|
readonly title?: string | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version of the package the item belongs to.
|
||||||
|
*/
|
||||||
|
readonly version?: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +42,7 @@ export function ItemLink<Route extends string>(props: PropsWithChildren<ItemLink
|
|||||||
throw new Error('ItemLink must be used inside a Next.js page. (e.g. /docs/packages/foo/main)');
|
throw new Error('ItemLink must be used inside a Next.js page. (e.g. /docs/packages/foo/main)');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { itemURI, packageName: pkgName, ...linkProps } = props;
|
const { itemURI, packageName: pkgName, version: pkgVersion, ...linkProps } = props;
|
||||||
|
|
||||||
return <Link {...linkProps} href={`/docs/packages/${pkgName ?? packageName}/${version}/${itemURI}`} />;
|
return <Link {...linkProps} href={`/docs/packages/${pkgName ?? packageName}/${pkgVersion ?? version}/${itemURI}`} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export function ParameterTable({ item }: { readonly item: ApiDocumentedItem & Ap
|
|||||||
() =>
|
() =>
|
||||||
params.map((param) => ({
|
params.map((param) => ({
|
||||||
Name: param.isRest ? `...${param.name}` : param.name,
|
Name: param.isRest ? `...${param.name}` : param.name,
|
||||||
Type: <ExcerptText excerpt={param.parameterTypeExcerpt} />,
|
Type: <ExcerptText excerpt={param.parameterTypeExcerpt} apiPackage={item.getAssociatedPackage()!} />,
|
||||||
Optional: param.isOptional ? 'Yes' : 'No',
|
Optional: param.isOptional ? 'Yes' : 'No',
|
||||||
Description: param.description ? <TSDoc item={item} tsdoc={param.description} /> : 'None',
|
Description: param.description ? <TSDoc item={item} tsdoc={param.description} /> : 'None',
|
||||||
})),
|
})),
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ export function Property({
|
|||||||
>
|
>
|
||||||
{`${item.displayName}${item.isOptional ? '?' : ''}`}
|
{`${item.displayName}${item.isOptional ? '?' : ''}`}
|
||||||
<span>:</span>
|
<span>:</span>
|
||||||
{item.propertyTypeExcerpt.text ? <ExcerptText excerpt={item.propertyTypeExcerpt} /> : null}
|
{item.propertyTypeExcerpt.text ? (
|
||||||
|
<ExcerptText excerpt={item.propertyTypeExcerpt} apiPackage={item.getAssociatedPackage()!} />
|
||||||
|
) : null}
|
||||||
</CodeHeading>
|
</CodeHeading>
|
||||||
</div>
|
</div>
|
||||||
{hasSummary || inheritedFrom ? (
|
{hasSummary || inheritedFrom ? (
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { Excerpt } from '@discordjs/api-extractor-model';
|
import type { ApiPackage, Excerpt } from '@discordjs/api-extractor-model';
|
||||||
import { ExcerptText } from './ExcerptText';
|
import { ExcerptText } from './ExcerptText';
|
||||||
|
|
||||||
export function SignatureText({ excerpt }: { readonly excerpt: Excerpt }) {
|
export function SignatureText({ excerpt, apiPackage }: { readonly apiPackage: ApiPackage; readonly excerpt: Excerpt }) {
|
||||||
return (
|
return (
|
||||||
<h4 className="break-all text-lg font-bold font-mono">
|
<h4 className="break-all text-lg font-bold font-mono">
|
||||||
<ExcerptText excerpt={excerpt} />
|
<ExcerptText excerpt={excerpt} apiPackage={apiPackage} />
|
||||||
</h4>
|
</h4>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ export function TypeParamTable({ item }: { readonly item: ApiTypeParameterListMi
|
|||||||
() =>
|
() =>
|
||||||
item.typeParameters.map((typeParam) => ({
|
item.typeParameters.map((typeParam) => ({
|
||||||
Name: typeParam.name,
|
Name: typeParam.name,
|
||||||
Constraints: <ExcerptText excerpt={typeParam.constraintExcerpt} />,
|
Constraints: <ExcerptText excerpt={typeParam.constraintExcerpt} apiPackage={item.getAssociatedPackage()!} />,
|
||||||
Optional: typeParam.isOptional ? 'Yes' : 'No',
|
Optional: typeParam.isOptional ? 'Yes' : 'No',
|
||||||
Default: <ExcerptText excerpt={typeParam.defaultTypeExcerpt} />,
|
Default: <ExcerptText excerpt={typeParam.defaultTypeExcerpt} apiPackage={item.getAssociatedPackage()!} />,
|
||||||
Description: typeParam.tsdocTypeParamBlock ? (
|
Description: typeParam.tsdocTypeParamBlock ? (
|
||||||
<TSDoc item={item} tsdoc={typeParam.tsdocTypeParamBlock.content} />
|
<TSDoc item={item} tsdoc={typeParam.tsdocTypeParamBlock.content} />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export function HierarchyText({
|
|||||||
<div className="flex flex-row place-items-center gap-4" key={`${type}-${idx}`}>
|
<div className="flex flex-row place-items-center gap-4" key={`${type}-${idx}`}>
|
||||||
<h3 className="text-xl font-bold">{type}</h3>
|
<h3 className="text-xl font-bold">{type}</h3>
|
||||||
<span className="break-all font-mono space-y-2">
|
<span className="break-all font-mono space-y-2">
|
||||||
<ExcerptText excerpt={excerpt} />
|
<ExcerptText excerpt={excerpt} apiPackage={item.getAssociatedPackage()!} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc:
|
|||||||
|
|
||||||
const declarationReference = item.getAssociatedModel()?.resolveDeclarationReference(codeDestination, item);
|
const declarationReference = item.getAssociatedModel()?.resolveDeclarationReference(codeDestination, item);
|
||||||
const foundItem = declarationReference?.resolvedApiItem;
|
const foundItem = declarationReference?.resolvedApiItem;
|
||||||
const resolved = resolveCanonicalReference(codeDestination);
|
const resolved = resolveCanonicalReference(codeDestination, item.getAssociatedPackage());
|
||||||
|
|
||||||
if (!foundItem && !resolved) return null;
|
if (!foundItem && !resolved) return null;
|
||||||
|
|
||||||
@@ -84,6 +84,12 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc:
|
|||||||
itemURI={resolveItemURI(foundItem ?? resolved!.item)}
|
itemURI={resolveItemURI(foundItem ?? resolved!.item)}
|
||||||
key={idx}
|
key={idx}
|
||||||
packageName={resolved?.package ?? item.getAssociatedPackage()?.displayName.replace('@discordjs/', '')}
|
packageName={resolved?.package ?? item.getAssociatedPackage()?.displayName.replace('@discordjs/', '')}
|
||||||
|
version={
|
||||||
|
resolved?.package
|
||||||
|
? // eslint-disable-next-line unicorn/better-regex
|
||||||
|
item.getAssociatedPackage()?.dependencies?.[resolved.package]?.replace(/[~^]/, '')
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{linkText ?? foundItem?.displayName ?? resolved!.item.displayName}
|
{linkText ?? foundItem?.displayName ?? resolved!.item.displayName}
|
||||||
</ItemLink>
|
</ItemLink>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import type {
|
|||||||
ApiDocumentedItem,
|
ApiDocumentedItem,
|
||||||
ApiParameterListMixin,
|
ApiParameterListMixin,
|
||||||
ApiEvent,
|
ApiEvent,
|
||||||
|
ApiPackage,
|
||||||
} from '@discordjs/api-extractor-model';
|
} from '@discordjs/api-extractor-model';
|
||||||
import type { DocDeclarationReference } from '@microsoft/tsdoc';
|
import type { DocDeclarationReference } from '@microsoft/tsdoc';
|
||||||
import { SelectorKind } from '@microsoft/tsdoc';
|
import { SelectorKind } from '@microsoft/tsdoc';
|
||||||
@@ -29,6 +30,7 @@ export interface ApiItemLike {
|
|||||||
interface ResolvedCanonicalReference {
|
interface ResolvedCanonicalReference {
|
||||||
item: ApiItemLike;
|
item: ApiItemLike;
|
||||||
package: string | undefined;
|
package: string | undefined;
|
||||||
|
version: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const kindToMeaning = new Map([
|
const kindToMeaning = new Map([
|
||||||
@@ -72,6 +74,7 @@ export function resolveItemURI(item: ApiItemLike): string {
|
|||||||
|
|
||||||
export function resolveCanonicalReference(
|
export function resolveCanonicalReference(
|
||||||
canonicalReference: DeclarationReference | DocDeclarationReference,
|
canonicalReference: DeclarationReference | DocDeclarationReference,
|
||||||
|
apiPackage: ApiPackage | undefined,
|
||||||
): ResolvedCanonicalReference | null {
|
): ResolvedCanonicalReference | null {
|
||||||
if (
|
if (
|
||||||
'source' in canonicalReference &&
|
'source' in canonicalReference &&
|
||||||
@@ -89,6 +92,8 @@ export function resolveCanonicalReference(
|
|||||||
canonicalReference.symbol.meaning
|
canonicalReference.symbol.meaning
|
||||||
}|${canonicalReference.symbol.componentPath.component.toString()}`,
|
}|${canonicalReference.symbol.componentPath.component.toString()}`,
|
||||||
},
|
},
|
||||||
|
// eslint-disable-next-line unicorn/better-regex
|
||||||
|
version: apiPackage?.dependencies?.[canonicalReference.source.packageName]?.replace(/[~^]/, ''),
|
||||||
};
|
};
|
||||||
else if (
|
else if (
|
||||||
'memberReferences' in canonicalReference &&
|
'memberReferences' in canonicalReference &&
|
||||||
@@ -107,6 +112,8 @@ export function resolveCanonicalReference(
|
|||||||
.slice(1)
|
.slice(1)
|
||||||
.map((member) => ({ kind: member.kind, displayName: member.memberIdentifier!.identifier! })),
|
.map((member) => ({ kind: member.kind, displayName: member.memberIdentifier!.identifier! })),
|
||||||
},
|
},
|
||||||
|
// eslint-disable-next-line unicorn/better-regex
|
||||||
|
version: apiPackage?.dependencies?.[canonicalReference.packageName ?? '']?.replace(/[~^]/, ''),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ export function EnumMember({ member }: { readonly member: ApiEnumMember }) {
|
|||||||
>
|
>
|
||||||
{member.name}
|
{member.name}
|
||||||
<span>=</span>
|
<span>=</span>
|
||||||
{member.initializerExcerpt ? <SignatureText excerpt={member.initializerExcerpt} /> : null}
|
{member.initializerExcerpt ? (
|
||||||
|
<SignatureText excerpt={member.initializerExcerpt} apiPackage={member.getAssociatedPackage()!} />
|
||||||
|
) : null}
|
||||||
</CodeHeading>
|
</CodeHeading>
|
||||||
{member.tsdocComment ? <TSDoc item={member} tsdoc={member.tsdocComment.summarySection} /> : null}
|
{member.tsdocComment ? <TSDoc item={member} tsdoc={member.tsdocComment.summarySection} /> : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export function MethodHeader({ method }: { readonly method: ApiMethod | ApiMetho
|
|||||||
>
|
>
|
||||||
{`${method.name}(${parametersString(method)})`}
|
{`${method.name}(${parametersString(method)})`}
|
||||||
<span>:</span>
|
<span>:</span>
|
||||||
<ExcerptText excerpt={method.returnTypeExcerpt} />
|
<ExcerptText excerpt={method.returnTypeExcerpt} apiPackage={method.getAssociatedPackage()!} />
|
||||||
</CodeHeading>
|
</CodeHeading>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1094,6 +1094,10 @@ export class ApiModelGenerator {
|
|||||||
fileColumn: sourceLocation.sourceFileColumn,
|
fileColumn: sourceLocation.sourceFileColumn,
|
||||||
});
|
});
|
||||||
} else if (jsDoc) {
|
} else if (jsDoc) {
|
||||||
|
if (jsDoc.inherited) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const methodOptions = this._mapMethod(jsDoc, parentApiItem.getAssociatedPackage()!.name);
|
const methodOptions = this._mapMethod(jsDoc, parentApiItem.getAssociatedPackage()!.name);
|
||||||
if (methodOptions.releaseTag === ReleaseTag.Internal || methodOptions.releaseTag === ReleaseTag.Alpha) {
|
if (methodOptions.releaseTag === ReleaseTag.Internal || methodOptions.releaseTag === ReleaseTag.Alpha) {
|
||||||
return; // trim out items marked as "@internal" or "@alpha"
|
return; // trim out items marked as "@internal" or "@alpha"
|
||||||
@@ -1802,7 +1806,7 @@ export class ApiModelGenerator {
|
|||||||
text: `${
|
text: `${
|
||||||
method.scope === 'global'
|
method.scope === 'global'
|
||||||
? `export function ${method.name}(`
|
? `export function ${method.name}(`
|
||||||
: `${method.access}${method.scope === 'static' ? ' static' : ''} ${method.name}(`
|
: `${method.access ? `${method.access} ` : ''}${method.scope === 'static' ? 'static ' : ''}${method.name}(`
|
||||||
}${
|
}${
|
||||||
method.params?.length
|
method.params?.length
|
||||||
? `${method.params[0]!.name}${method.params[0]!.nullable || method.params[0]!.optional ? '?' : ''}`
|
? `${method.params[0]!.name}${method.params[0]!.nullable || method.params[0]!.optional ? '?' : ''}`
|
||||||
@@ -1853,8 +1857,8 @@ export class ApiModelGenerator {
|
|||||||
?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\n`)
|
?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\n`)
|
||||||
.join('') ?? ''
|
.join('') ?? ''
|
||||||
}${
|
}${
|
||||||
method.returns?.length && !Array.isArray(method.returns[0])
|
method.returns?.length && !Array.isArray(method.returns[0]) && method.returns[0]!.description
|
||||||
? ` * @returns ${this._fixLinkTags(method.returns[0]!.description) ?? ''}\n`
|
? ` * @returns ${this._fixLinkTags(method.returns[0]!.description) ?? ''}`
|
||||||
: ''
|
: ''
|
||||||
}${method.examples?.map((example) => ` * @example\n * \`\`\`js\n * ${example}\n * \`\`\`\n`).join('') ?? ''}${
|
}${method.examples?.map((example) => ` * @example\n * \`\`\`js\n * ${example}\n * \`\`\`\n`).join('') ?? ''}${
|
||||||
method.deprecated
|
method.deprecated
|
||||||
|
|||||||
Reference in New Issue
Block a user