From a14e3cb61245196a7bf4ad824df52001b77eeddf Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sun, 19 Nov 2023 20:37:33 +0100 Subject: [PATCH 1/8] fix(website): correctly link to discord-api-types in link tags --- .../components/documentation/tsdoc/TSDoc.tsx | 34 ++++- .../src/components/documentation/util.ts | 57 ++++---- .../src/generators/ApiModelGenerator.ts | 125 +++++++++++------- 3 files changed, 133 insertions(+), 83 deletions(-) diff --git a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx index a0a0854fbe1e..6525638cfa26 100644 --- a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx +++ b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx @@ -1,14 +1,23 @@ -import type { ApiItem } from '@discordjs/api-extractor-model'; -import type { DocComment, DocFencedCode, DocLinkTag, DocNode, DocNodeContainer, DocPlainText } from '@microsoft/tsdoc'; +import { type ApiItem, ApiItemKind } from '@discordjs/api-extractor-model'; +import type { + DocComment, + DocFencedCode, + DocInlineTag, + DocLinkTag, + DocNode, + DocNodeContainer, + DocPlainText, +} from '@microsoft/tsdoc'; 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 { DISCORD_API_TYPES_DOCS_URL } from '~/util/constants'; import { ItemLink } from '../../ItemLink'; import { SyntaxHighlighter } from '../../SyntaxHighlighter'; -import { resolveCanonicalReference, resolveItemURI } from '../util'; +import { mapKindToMeaning, resolveCanonicalReference, resolveItemURI } from '../util'; import { DefaultValueBlock, DeprecatedBlock, ExampleBlock, RemarksBlock, ReturnsBlock, SeeBlock } from './BlockComment'; export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: DocNode }): JSX.Element { @@ -32,7 +41,6 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: return ; case DocNodeKind.LinkTag: { const { codeDestination, urlDestination, linkText } = tsdoc as DocLinkTag; - if (codeDestination) { if ( !codeDestination.importPath && @@ -56,6 +64,24 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: if (!foundItem && !resolved) return null; + if (resolved && resolved.package === 'discord-api-types') { + const { displayName, kind, members, containerKey } = resolved.item; + let href = DISCORD_API_TYPES_DOCS_URL; + + // dapi-types doesn't have routes for class members + // so we can assume this member is for an enum + if (kind === 'enum' && members[0]) href += `/enum/${displayName}#${members[0].displayName}`; + else if (kind === 'type' || kind === 'var') href += `#${displayName}`; + else href += `/${mapKindToMeaning(kind)}/${displayName}`; + + return ( + + {displayName} + {members?.map((member) => `.${member.displayName}`).join('') ?? ''} + + ); + } + return ( member.kind === ApiItemKind.Property || member.kind === ApiItemKind.PropertySignature, @@ -86,6 +103,9 @@ export function resolveCanonicalReference( kind: member.selector!.selector as ApiItemKind, displayName: member.memberIdentifier!.identifier, containerKey: `|${member.selector!.selector}|${member.memberIdentifier!.identifier}`, + members: canonicalReference.memberReferences + .slice(1) + .map((member) => ({ kind: member.kind, displayName: member.memberIdentifier?.identifier })), }, }; } @@ -93,37 +113,12 @@ export function resolveCanonicalReference( 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 mapMeaningToKind(meaning: Meaning): ApiItemKind { + return [...kindToMeaning.entries()].find((mapping) => mapping[1] === meaning)?.[0]; +} + +export function mapKindToMeaning(kind: ApiItemKind): Meaning { + return kindToMeaning.get(kind); } export function memberPredicate( diff --git a/packages/api-extractor/src/generators/ApiModelGenerator.ts b/packages/api-extractor/src/generators/ApiModelGenerator.ts index 983ee49a9187..32f4c0ba712a 100644 --- a/packages/api-extractor/src/generators/ApiModelGenerator.ts +++ b/packages/api-extractor/src/generators/ApiModelGenerator.ts @@ -210,14 +210,7 @@ interface IProcessAstEntityContext { parentDocgenJson?: DocgenContainerJson | undefined; } -const linkRegEx = /{@link\s(?\w+)#(?event:)?(?[\w()]+)(?\s[^}]*)?}/g; -function fixLinkTags(input?: string): string | undefined { - return input?.replaceAll( - linkRegEx, - (_match, _p1, _p2, _p3, _p4, _offset, _string, groups) => - `{@link ${groups.class}.${groups.prop}${groups.name ? ` |${groups.name}` : ''}}`, - ); -} +const linkRegEx = /{@link\s(?\w+)[#.](?event:)?(?[\w()]+)(?\s[^}]*)?}/g; function filePathFromJson(meta: DocgenMetaJson): string { return `${meta.path.slice('packages/discord.js/'.length)}/${meta.file}`; @@ -243,6 +236,8 @@ export class ApiModelGenerator { private readonly _referenceGenerator: DeclarationReferenceGenerator; + private readonly _jsDocJson: DocgenJson | undefined; + public constructor(collector: Collector) { this._collector = collector; this._apiModel = new ApiModel(); @@ -257,11 +252,11 @@ export class ApiModelGenerator { public buildApiPackage(): ApiPackage { const packageDocComment: tsdoc.DocComment | undefined = this._collector.workingPackage.tsdocComment; - let jsDocJson: DocgenJson | undefined; const jsDocFilepath = `${this._collector.extractorConfig.apiJsonFilePath.slice(0, -8)}json`; if (existsSync(jsDocFilepath)) { - jsDocJson = JsonFile.load(jsDocFilepath); + // @ts-expect-error assign value only when starting to build a new ApiPackage + this._jsDocJson = JsonFile.load(jsDocFilepath); } const apiPackage: ApiPackage = new ApiPackage({ @@ -284,7 +279,7 @@ export class ApiModelGenerator { name: entity.nameForEmit!, isExported: entity.exportedFromEntryPoint, parentApiItem: apiEntryPoint, - parentDocgenJson: jsDocJson, + parentDocgenJson: this._jsDocJson, }); } } @@ -560,9 +555,9 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = parent?.construct ? this._tsDocParser.parseString( - `/*+\n * ${fixLinkTags(parent.construct.description)}\n${ + `/*+\n * ${this._fixLinkTags(parent.construct.description) ?? ''}\n${ parent.construct.params - ?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`) + ?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\n`) .join('') ?? '' } */`, ).docComment @@ -646,10 +641,12 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( - `/**\n * ${fixLinkTags(jsDoc.description)}\n${jsDoc.see?.map((see) => ` * @see ${see}\n`).join('') ?? ''}${ + `/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${ + jsDoc.see?.map((see) => ` * @see ${see}\n`).join('') ?? '' + }${ jsDoc.deprecated ? ` * @deprecated ${ - typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated + typeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated }\n` : '' } */`, @@ -718,9 +715,9 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = parent?.construct ? this._tsDocParser.parseString( - `/*+\n * ${fixLinkTags(parent.construct.description)}\n${ + `/*+\n * ${this._fixLinkTags(parent.construct.description) ?? ''}\n${ parent.construct.params - ?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`) + ?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\n`) .join('') ?? '' } */`, ).docComment @@ -849,17 +846,18 @@ export class ApiModelGenerator { 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('') ?? - '' + `/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${ + jsDoc.params + ?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\n`) + .join('') ?? '' }${ jsDoc.returns?.length && !Array.isArray(jsDoc.returns[0]) - ? ` * @returns ${fixLinkTags(jsDoc.returns[0]!.description ?? '')}` + ? ` * @returns ${this._fixLinkTags(jsDoc.returns[0]!.description) ?? ''}` : '' }${ jsDoc.deprecated ? ` * @deprecated ${ - typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated + typeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated }\n` : '' } */`, @@ -976,10 +974,12 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( - `/**\n * ${fixLinkTags(jsDoc.description)}\n${jsDoc.see?.map((see) => ` * @see ${see}\n`).join('') ?? ''}${ + `/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${ + jsDoc.see?.map((see) => ` * @see ${see}\n`).join('') ?? '' + }${ jsDoc.deprecated ? ` * @deprecated ${ - typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated + typeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated }\n` : '' } */`, @@ -1046,20 +1046,20 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( - `/**\n * ${fixLinkTags(jsDoc.description)}\n${ + `/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${ jsDoc.params - ?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`) + ?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\n`) .join('') ?? '' }${ jsDoc.returns?.length && !Array.isArray(jsDoc.returns[0]) - ? ` * @returns ${fixLinkTags(jsDoc.returns[0]!.description ?? '')}` + ? ` * @returns ${this._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 + typeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated }\n` : '' } */`, @@ -1136,18 +1136,18 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( - `/**\n * ${fixLinkTags(jsDoc.description)}\n${ + `/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${ jsDoc.params - ?.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`) + ?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\n`) .join('') ?? '' }${ jsDoc.returns?.length && !Array.isArray(jsDoc.returns[0]) - ? ` * @returns ${fixLinkTags(jsDoc.returns[0]!.description ?? '')}` + ? ` * @returns ${this._fixLinkTags(jsDoc.returns[0]!.description) ?? ''}` : '' }${ jsDoc.deprecated ? ` * @deprecated ${ - typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated + typeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated }\n` : '' } */`, @@ -1253,12 +1253,12 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( - `/**\n * ${fixLinkTags(jsDoc.description)}\n${ + `/**\n * ${this._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 + typeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated }\n` : '' } */`, @@ -1328,10 +1328,14 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( - `/**\n * ${fixLinkTags(jsDoc.description)}\n${ + `/**\n * ${this._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` : '' + 'deprecated' in jsDoc && jsDoc.deprecated + ? ` * @deprecated ${ + typeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated + }\n` + : '' } */`, ).docComment : apiItemMetadata.tsdocComment; @@ -1396,13 +1400,17 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( - `/**\n * ${fixLinkTags(jsDoc.description) ?? ''}\n${ + `/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${ 'params' in jsDoc - ? jsDoc.params.map((param) => ` * @param ${param.name} - ${fixLinkTags(param.description)}\n`).join('') + ? jsDoc.params + .map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\n`) + .join('') : '' }${ 'returns' in jsDoc - ? jsDoc.returns.map((ret) => ` * @returns ${Array.isArray(ret) ? '' : fixLinkTags(ret.description)}\n`) + ? jsDoc.returns.map( + (ret) => ` * @returns ${Array.isArray(ret) ? '' : this._fixLinkTags(ret.description) ?? ''}\n`, + ) : '' } */`, ).docComment @@ -1531,12 +1539,14 @@ export class ApiModelGenerator { } 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('') ?? '' + `/**\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\n${ + jsDoc.params + ?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\n`) + .join('') ?? '' }${'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : ''}${ 'deprecated' in jsDoc && jsDoc.deprecated ? ` * @deprecated ${ - typeof jsDoc.deprecated === 'string' ? fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated + typeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated }\n` : '' } */`, @@ -1672,6 +1682,23 @@ export class ApiModelGenerator { return sourceLocation; } + private _fixLinkTags(input?: string): string | undefined { + return input?.replaceAll(linkRegEx, (_match, _p1, _p2, _p3, _p4, _offset, _string, groups) => { + const external = this._jsDocJson?.externals.find((external) => external.name === groups.class); + let target = groups.class; + const match = /discord-api-types-(?[^#]*?)(?:#|\/(?[^#/]*)\/)(?[^/}]*)}$/.exec( + external?.see?.[0] ?? '', + ); + if (match) { + target = `discord-api-types#(${match.groups!.name}:${ + /^v\d+$/.test(match.groups!.type!) ? match.groups!.kind : 'type' + })`; + } + + return `{@link ${target}.${groups.prop}${groups.name ? ` |${groups.name}` : ''}}`; + }); + } + private _mapVarType(typey: DocgenVarTypeJson): IExcerptToken[] { const mapper = Array.isArray(typey) ? typey : typey.types ?? []; const lookup: { [K in ts.SyntaxKind]?: string } = { @@ -1729,9 +1756,9 @@ export class ApiModelGenerator { 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' : '' - } */`, + `/**\n * ${this._fixLinkTags(prop.description) ?? ''}\n${ + prop.see?.map((see) => ` * @see ${see}\n`).join('') ?? '' + }${prop.readonly ? ' * @readonly\n' : ''} */`, ).docComment, excerptTokens: [ { @@ -1820,11 +1847,13 @@ export class ApiModelGenerator { : { startIndex: 0, endIndex: 0 }, typeParameters: [], docComment: this._tsDocParser.parseString( - `/**\n * ${method.description}\n${ - method.params?.map((param) => ` * @param ${param.name} - ${param.description}\n`).join('') ?? '' + `/**\n * ${this._fixLinkTags(method.description) ?? ''}\n${ + method.params + ?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\n`) + .join('') ?? '' }${ method.returns?.length && !Array.isArray(method.returns[0]) - ? ` * @returns ${method.returns[0]!.description}` + ? ` * @returns ${this._fixLinkTags(method.returns[0]!.description) ?? ''}` : '' }${method.examples?.map((example) => ` * @example\n * \`\`\`js\n * ${example}\n * \`\`\`\n`).join('') ?? ''}${ method.deprecated From 53b53578283cd7f2f8a1e1f49a9181bacec7c199 Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sun, 19 Nov 2023 21:08:02 +0100 Subject: [PATCH 2/8] fix: url links and some minor doc issues --- .../api-extractor/src/generators/ApiModelGenerator.ts | 11 ++++++----- packages/discord.js/src/client/BaseClient.js | 2 +- .../discord.js/src/client/voice/ClientVoiceManager.js | 2 +- packages/discord.js/src/structures/Guild.js | 2 +- packages/discord.js/src/util/Sweepers.js | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/api-extractor/src/generators/ApiModelGenerator.ts b/packages/api-extractor/src/generators/ApiModelGenerator.ts index 32f4c0ba712a..701b54ccd671 100644 --- a/packages/api-extractor/src/generators/ApiModelGenerator.ts +++ b/packages/api-extractor/src/generators/ApiModelGenerator.ts @@ -210,7 +210,8 @@ interface IProcessAstEntityContext { parentDocgenJson?: DocgenContainerJson | undefined; } -const linkRegEx = /{@link\s(?\w+)[#.](?event:)?(?[\w()]+)(?\s[^}]*)?}/g; +const linkRegEx = + /{@link\s(?:(?\w+)(?:[#.](?event:)?(?[\w()]+))?|(?https?:\/\/[^\s}]*))(?\s[^}]*)?}/g; function filePathFromJson(meta: DocgenMetaJson): string { return `${meta.path.slice('packages/discord.js/'.length)}/${meta.file}`; @@ -1683,9 +1684,9 @@ export class ApiModelGenerator { } private _fixLinkTags(input?: string): string | undefined { - return input?.replaceAll(linkRegEx, (_match, _p1, _p2, _p3, _p4, _offset, _string, groups) => { - const external = this._jsDocJson?.externals.find((external) => external.name === groups.class); - let target = groups.class; + return input?.replaceAll(linkRegEx, (_match, _p1, _p2, _p3, _p4, _p5, _offset, _string, groups) => { + let target = groups.class ?? groups.url; + const external = this._jsDocJson?.externals.find((external) => groups.class && external.name === groups.class); const match = /discord-api-types-(?[^#]*?)(?:#|\/(?[^#/]*)\/)(?[^/}]*)}$/.exec( external?.see?.[0] ?? '', ); @@ -1695,7 +1696,7 @@ export class ApiModelGenerator { })`; } - return `{@link ${target}.${groups.prop}${groups.name ? ` |${groups.name}` : ''}}`; + return `{@link ${target}${groups.prop ? `.${groups.prop}` : ''}${groups.name ? ` |${groups.name}` : ''}}`; }); } diff --git a/packages/discord.js/src/client/BaseClient.js b/packages/discord.js/src/client/BaseClient.js index 8b1c261fab7e..8df5e549de3c 100644 --- a/packages/discord.js/src/client/BaseClient.js +++ b/packages/discord.js/src/client/BaseClient.js @@ -19,11 +19,11 @@ class BaseClient extends EventEmitter { throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true); } + const defaultOptions = Options.createDefault(); /** * The options the client was instantiated with * @type {ClientOptions} */ - const defaultOptions = Options.createDefault(); this.options = { ...defaultOptions, ...options, diff --git a/packages/discord.js/src/client/voice/ClientVoiceManager.js b/packages/discord.js/src/client/voice/ClientVoiceManager.js index 192e7001a4bc..55b0d830ed38 100644 --- a/packages/discord.js/src/client/voice/ClientVoiceManager.js +++ b/packages/discord.js/src/client/voice/ClientVoiceManager.js @@ -16,7 +16,7 @@ class ClientVoiceManager { Object.defineProperty(this, 'client', { value: client }); /** - * Maps guild ids to voice adapters created for use with @discordjs/voice. + * Maps guild ids to voice adapters created for use with `@discordjs/voice`. * @type {Map} */ this.adapters = new Map(); diff --git a/packages/discord.js/src/structures/Guild.js b/packages/discord.js/src/structures/Guild.js index da3843855b4d..51a26750a751 100644 --- a/packages/discord.js/src/structures/Guild.js +++ b/packages/discord.js/src/structures/Guild.js @@ -1405,7 +1405,7 @@ class Guild extends AnonymousGuild { } /** - * The voice state adapter for this guild that can be used with @discordjs/voice to play audio in voice + * The voice state adapter for this guild that can be used with `@discordjs/voice` to play audio in voice * and stage channels. * @type {Function} * @readonly diff --git a/packages/discord.js/src/util/Sweepers.js b/packages/discord.js/src/util/Sweepers.js index 3cc910838c2d..3402f2fe9aa6 100644 --- a/packages/discord.js/src/util/Sweepers.js +++ b/packages/discord.js/src/util/Sweepers.js @@ -8,7 +8,7 @@ const { DiscordjsTypeError, ErrorCodes } = require('../errors'); /** * @typedef {Function} GlobalSweepFilter * @returns {?Function} Return `null` to skip sweeping, otherwise a function passed to `sweep()`, - * See {@link [Collection#sweep](https://discord.js.org/docs/packages/collection/stable/Collection:Class#sweep)} + * See {@link https://discord.js.org/docs/packages/collection/stable/Collection:Class#sweep Collection#sweep} * for the definition of this function. */ From 7110365ae107c493d2bfd440cc49fc78aed2cd2d Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sun, 19 Nov 2023 21:11:54 +0100 Subject: [PATCH 3/8] fix: unneeded import --- .../src/components/documentation/tsdoc/TSDoc.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx index 6525638cfa26..4f2ab824c2d6 100644 --- a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx +++ b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx @@ -1,13 +1,5 @@ import { type ApiItem, ApiItemKind } from '@discordjs/api-extractor-model'; -import type { - DocComment, - DocFencedCode, - DocInlineTag, - DocLinkTag, - DocNode, - DocNodeContainer, - DocPlainText, -} from '@microsoft/tsdoc'; +import type { DocComment, DocFencedCode, DocLinkTag, DocNode, DocNodeContainer, DocPlainText } from '@microsoft/tsdoc'; import { DocNodeKind, StandardTags } from '@microsoft/tsdoc'; import type { Route } from 'next'; import Link from 'next/link'; From 3269bb7b6e0899f6458a66e67baea6caa361c107 Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sun, 19 Nov 2023 21:20:04 +0100 Subject: [PATCH 4/8] fix: another unneccessary import --- apps/website/src/components/documentation/tsdoc/TSDoc.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx index 4f2ab824c2d6..906c5a0171f4 100644 --- a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx +++ b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx @@ -1,4 +1,4 @@ -import { type ApiItem, ApiItemKind } from '@discordjs/api-extractor-model'; +import type { ApiItem } from '@discordjs/api-extractor-model'; import type { DocComment, DocFencedCode, DocLinkTag, DocNode, DocNodeContainer, DocPlainText } from '@microsoft/tsdoc'; import { DocNodeKind, StandardTags } from '@microsoft/tsdoc'; import type { Route } from 'next'; From 2ed577d9c29fd2408dd405f0d5630e18bfd8f00d Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sun, 19 Nov 2023 21:34:59 +0100 Subject: [PATCH 5/8] fix: several linting issues --- .../components/documentation/tsdoc/TSDoc.tsx | 6 +++--- .../src/components/documentation/util.ts | 20 +++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx index 906c5a0171f4..4253f2129c4d 100644 --- a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx +++ b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx @@ -9,7 +9,7 @@ import { BuiltinDocumentationLinks } from '~/util/builtinDocumentationLinks'; import { DISCORD_API_TYPES_DOCS_URL } from '~/util/constants'; import { ItemLink } from '../../ItemLink'; import { SyntaxHighlighter } from '../../SyntaxHighlighter'; -import { mapKindToMeaning, resolveCanonicalReference, resolveItemURI } from '../util'; +import { resolveCanonicalReference, resolveItemURI } from '../util'; import { DefaultValueBlock, DeprecatedBlock, ExampleBlock, RemarksBlock, ReturnsBlock, SeeBlock } from './BlockComment'; export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: DocNode }): JSX.Element { @@ -62,9 +62,9 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: // dapi-types doesn't have routes for class members // so we can assume this member is for an enum - if (kind === 'enum' && members[0]) href += `/enum/${displayName}#${members[0].displayName}`; + if (kind === 'enum' && members?.[0]) href += `/enum/${displayName}#${members[0].displayName}`; else if (kind === 'type' || kind === 'var') href += `#${displayName}`; - else href += `/${mapKindToMeaning(kind)}/${displayName}`; + else href += `/${kind}/${displayName}`; return ( diff --git a/apps/website/src/components/documentation/util.ts b/apps/website/src/components/documentation/util.ts index 95820a2f929e..9c2f233db568 100644 --- a/apps/website/src/components/documentation/util.ts +++ b/apps/website/src/components/documentation/util.ts @@ -19,11 +19,15 @@ import { resolveParameters } from '~/util/model'; import type { TableOfContentsSerialized } from '../TableOfContentItems'; export type ApiItemLike = { - [K in keyof ApiItem]?: K extends 'displayName' | 'kind' + [K in keyof ApiItem]?: K extends 'displayName' ? ApiItem[K] - : K extends 'parent' - ? ApiItemLike | undefined - : ApiItem[K] | undefined; + : K extends 'kind' + ? string + : K extends 'parent' + ? ApiItemLike | undefined + : K extends 'members' + ? readonly ApiItemLike[] + : ApiItem[K] | undefined; }; interface ResolvedCanonicalReference { @@ -100,12 +104,12 @@ export function resolveCanonicalReference( return { package: canonicalReference.packageName?.replace('@discordjs/', ''), item: { - kind: member.selector!.selector as ApiItemKind, + kind: member.selector!.selector, displayName: member.memberIdentifier!.identifier, containerKey: `|${member.selector!.selector}|${member.memberIdentifier!.identifier}`, members: canonicalReference.memberReferences .slice(1) - .map((member) => ({ kind: member.kind, displayName: member.memberIdentifier?.identifier })), + .map((member) => ({ kind: member.kind, displayName: member.memberIdentifier!.identifier! })), }, }; } @@ -114,11 +118,11 @@ export function resolveCanonicalReference( } export function mapMeaningToKind(meaning: Meaning): ApiItemKind { - return [...kindToMeaning.entries()].find((mapping) => mapping[1] === meaning)?.[0]; + return [...kindToMeaning.entries()].find((mapping) => mapping[1] === meaning)?.[0] ?? ApiItemKind.None; } export function mapKindToMeaning(kind: ApiItemKind): Meaning { - return kindToMeaning.get(kind); + return kindToMeaning.get(kind) ?? Meaning.Variable; } export function memberPredicate( From 7d1ec92cd1bb6964585ddd9b1e8458481ca320ea Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Mon, 20 Nov 2023 17:10:25 +0100 Subject: [PATCH 6/8] refactor: simplify ApiItemLike interface --- .../src/components/documentation/util.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/apps/website/src/components/documentation/util.ts b/apps/website/src/components/documentation/util.ts index 9c2f233db568..6ef4df07ccd6 100644 --- a/apps/website/src/components/documentation/util.ts +++ b/apps/website/src/components/documentation/util.ts @@ -18,17 +18,13 @@ 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' - ? ApiItem[K] - : K extends 'kind' - ? string - : K extends 'parent' - ? ApiItemLike | undefined - : K extends 'members' - ? readonly ApiItemLike[] - : ApiItem[K] | undefined; -}; +export interface ApiItemLike { + containerKey?: string; + displayName: string; + kind: string; + members?: readonly ApiItemLike[]; + parent?: ApiItemLike | undefined; +} interface ResolvedCanonicalReference { item: ApiItemLike; From d800dbb8294a5a3aa53c52d1be2a36ed7babe191 Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:39:41 +0100 Subject: [PATCH 7/8] refactor: apply suggestions --- apps/website/src/components/ExcerptText.tsx | 10 +++++++--- .../src/components/documentation/tsdoc/TSDoc.tsx | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/website/src/components/ExcerptText.tsx b/apps/website/src/components/ExcerptText.tsx index bcf5525632e5..c5050ef2fbcd 100644 --- a/apps/website/src/components/ExcerptText.tsx +++ b/apps/website/src/components/ExcerptText.tsx @@ -38,9 +38,13 @@ export function ExcerptText({ excerpt }: ExcerptTextProps) { // dapi-types doesn't have routes for class members // so we can assume this member is for an enum - if (meaning === 'member' && path && 'parent' in path) href += `/enum/${path.parent}#${path.component}`; - else if (meaning === 'type' || meaning === 'var') href += `#${token.text}`; - else href += `/${meaning}/${token.text}`; + if (meaning === 'member' && path && 'parent' in path) { + href += `/enum/${path.parent}#${path.component}`; + } else if (meaning === 'type' || meaning === 'var') { + href += `#${token.text}`; + } else { + href += `/${meaning}/${token.text}`; + } return ( diff --git a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx index 4253f2129c4d..487e2edb0c8e 100644 --- a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx +++ b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx @@ -62,9 +62,13 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: // dapi-types doesn't have routes for class members // so we can assume this member is for an enum - if (kind === 'enum' && members?.[0]) href += `/enum/${displayName}#${members[0].displayName}`; - else if (kind === 'type' || kind === 'var') href += `#${displayName}`; - else href += `/${kind}/${displayName}`; + if (kind === 'enum' && members?.[0]) { + href += `/enum/${displayName}#${members[0].displayName}`; + } else if (kind === 'type' || kind === 'var') { + href += `#${displayName}`; + } else { + href += `/${kind}/${displayName}`; + } return ( From f6d86bf11ff1c4d51d43b4ed88056c3dac2fae82 Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Wed, 22 Nov 2023 07:55:50 +0100 Subject: [PATCH 8/8] fix: missing newline in docComment --- .../src/generators/ApiModelGenerator.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/api-extractor/src/generators/ApiModelGenerator.ts b/packages/api-extractor/src/generators/ApiModelGenerator.ts index 701b54ccd671..567d232c9adb 100644 --- a/packages/api-extractor/src/generators/ApiModelGenerator.ts +++ b/packages/api-extractor/src/generators/ApiModelGenerator.ts @@ -1053,7 +1053,7 @@ export class ApiModelGenerator { .join('') ?? '' }${ jsDoc.returns?.length && !Array.isArray(jsDoc.returns[0]) - ? ` * @returns ${this._fixLinkTags(jsDoc.returns[0]!.description) ?? ''}` + ? ` * @returns ${this._fixLinkTags(jsDoc.returns[0]!.description) ?? ''}\n` : '' }${ jsDoc.examples?.map((example) => ` * @example\n * \`\`\`js\n * ${example}\n * \`\`\`\n`).join('') ?? '' @@ -1143,7 +1143,7 @@ export class ApiModelGenerator { .join('') ?? '' }${ jsDoc.returns?.length && !Array.isArray(jsDoc.returns[0]) - ? ` * @returns ${this._fixLinkTags(jsDoc.returns[0]!.description) ?? ''}` + ? ` * @returns ${this._fixLinkTags(jsDoc.returns[0]!.description) ?? ''}\n` : '' }${ jsDoc.deprecated @@ -1409,9 +1409,9 @@ export class ApiModelGenerator { : '' }${ 'returns' in jsDoc - ? jsDoc.returns.map( - (ret) => ` * @returns ${Array.isArray(ret) ? '' : this._fixLinkTags(ret.description) ?? ''}\n`, - ) + ? jsDoc.returns + .map((ret) => ` * @returns ${Array.isArray(ret) ? '' : this._fixLinkTags(ret.description) ?? ''}\n`) + .join('') : '' } */`, ).docComment @@ -1854,7 +1854,7 @@ export class ApiModelGenerator { .join('') ?? '' }${ method.returns?.length && !Array.isArray(method.returns[0]) - ? ` * @returns ${this._fixLinkTags(method.returns[0]!.description) ?? ''}` + ? ` * @returns ${this._fixLinkTags(method.returns[0]!.description) ?? ''}\n` : '' }${method.examples?.map((example) => ` * @example\n * \`\`\`js\n * ${example}\n * \`\`\`\n`).join('') ?? ''}${ method.deprecated