From cbe8fa901b33ab702f42f40bfeb7bf360c96fa22 Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sat, 11 Nov 2023 09:29:23 +0100 Subject: [PATCH 1/6] refactor: use tokenRange for typeParams in heritage --- apps/website/src/components/ExcerptText.tsx | 18 ++-- .../src/components/TableOfContentItems.tsx | 2 +- .../src/mixins/ApiItemContainerMixin.ts | 86 +++++++++---------- .../api-extractor-model/src/model/ApiClass.ts | 2 +- .../src/model/DeserializerContext.ts | 7 +- .../src/model/HeritageType.ts | 6 +- .../src/generators/ApiModelGenerator.ts | 36 +++++--- .../src/generators/ExcerptBuilder.ts | 21 +++-- 8 files changed, 97 insertions(+), 81 deletions(-) diff --git a/apps/website/src/components/ExcerptText.tsx b/apps/website/src/components/ExcerptText.tsx index adf6b4383ace..f2b2243461ca 100644 --- a/apps/website/src/components/ExcerptText.tsx +++ b/apps/website/src/components/ExcerptText.tsx @@ -22,8 +22,6 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) { return ( {excerpt.spannedTokens.map((token, idx) => { - // TODO: Real fix in api-extractor needed - const text = token.text.replaceAll('\n', '').replaceAll(/\s{2}$/g, ''); if (token.kind === ExcerptTokenKind.Reference) { const source = token.canonicalReference?.source; const symbol = token.canonicalReference?.symbol; @@ -34,20 +32,22 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) { // dapi-types doesn't have routes for class members // so we can assume this member is for an enum if (meaning === 'member' && path && 'parent' in path) href += `/enum/${path.parent}#${path.component}`; - else if (meaning === 'type') href += `#${text}`; - else href += `/${meaning}/${text}`; + else if (meaning === 'type' || meaning === 'var') href += `#${token.text}`; + else href += `/${meaning}/${token.text}`; return ( - {text} + {token.text} ); } - const item = model.resolveDeclarationReference(token.canonicalReference!, model).resolvedApiItem; + const item = token.canonicalReference + ? model.resolveDeclarationReference(token.canonicalReference!, model).resolvedApiItem + : null; if (!item) { - return text; + return token.text; } return ( @@ -57,12 +57,12 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) { key={`${item.displayName}-${item.containerKey}-${idx}`} packageName={item.getAssociatedPackage()?.displayName.replace('@discordjs/', '')} > - {text} + {token.text} ); } - return text.replace(/import\("discord-api-types(?:\/v\d+)?"\)\./, ''); + return token.text.replace(/import\("discord-api-types(?:\/v\d+)?"\)\./, ''); })} ); diff --git a/apps/website/src/components/TableOfContentItems.tsx b/apps/website/src/components/TableOfContentItems.tsx index 544b25c785d9..a1e33316085f 100644 --- a/apps/website/src/components/TableOfContentItems.tsx +++ b/apps/website/src/components/TableOfContentItems.tsx @@ -127,7 +127,7 @@ export function TableOfContentItems({ serializedMembers }: TableOfContentsItemPr
- Properties + Events
{eventItems} diff --git a/packages/api-extractor-model/src/mixins/ApiItemContainerMixin.ts b/packages/api-extractor-model/src/mixins/ApiItemContainerMixin.ts index 9da10d3eb5ab..3782457bca38 100644 --- a/packages/api-extractor-model/src/mixins/ApiItemContainerMixin.ts +++ b/packages/api-extractor-model/src/mixins/ApiItemContainerMixin.ts @@ -1,9 +1,13 @@ +/* eslint-disable @typescript-eslint/no-loop-func */ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { TSDocConfiguration } from '@microsoft/tsdoc'; import type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js'; import { InternalError } from '@rushstack/node-core-library'; -import type { ApiDeclaredItem } from '../index.js'; +import type { IExcerptToken, IExcerptTokenRange } from '../index.js'; +import { ApiDeclaredItem } from '../index.js'; +import type { IApiDeclaredItemJson } from '../items/ApiDeclaredItem.js'; import { ApiItem, apiItem_onParentChanged, @@ -15,11 +19,12 @@ import { import type { ApiClass } from '../model/ApiClass.js'; import type { ApiInterface } from '../model/ApiInterface.js'; import type { ApiModel } from '../model/ApiModel.js'; -import type { DeserializerContext } from '../model/DeserializerContext.js'; +import { ApiJsonSchemaVersion, type DeserializerContext } from '../model/DeserializerContext.js'; import type { HeritageType } from '../model/HeritageType.js'; import type { IResolveDeclarationReferenceResult } from '../model/ModelReferenceResolver.js'; import { ApiNameMixin } from './ApiNameMixin.js'; -import { type ExcerptToken, ExcerptTokenKind } from './Excerpt.js'; +import type { ExcerptToken } from './Excerpt.js'; +import { ExcerptTokenKind } from './Excerpt.js'; import { type IFindApiItemsResult, type IFindApiItemsMessage, FindApiItemsMessageId } from './IFindApiItemsResult.js'; /** @@ -39,7 +44,7 @@ export interface IApiItemContainerJson extends IApiItemJson { interface IMappedTypeParameters { item: ApiItem; - mappedTypeParameters: Map; + mappedTypeParameters: Map; } const _members: unique symbol = Symbol('ApiItemContainerMixin._members'); @@ -317,7 +322,7 @@ export function ApiItemContainerMixin( let next: IMappedTypeParameters | undefined = { item: this, mappedTypeParameters: new Map() }; while (next?.item) { - const membersToAdd: ApiItem[] = []; /* + const membersToAdd: ApiItem[] = []; //* const typeParams = next.mappedTypeParameters; const context: DeserializerContext = { apiJsonFilename: '', @@ -325,56 +330,43 @@ export function ApiItemContainerMixin( toolVersion: '', versionToDeserialize: ApiJsonSchemaVersion.LATEST, tsdocConfiguration: new TSDocConfiguration(), - }; */ + }; // */ + + // eslint-disable-next-line @typescript-eslint/consistent-type-imports, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires + const deserializerModule: typeof import('../model/Deserializer') = require('../model/Deserializer'); // For each member, check to see if we've already seen a member with the same name // previously in the inheritance tree. If so, we know we won't inherit it, and thus // do not add it to our `membersToAdd` array. - for (const member of next.item.members) { + for (let member of next.item.members) { // We add the to-be-added members to an intermediate array instead of immediately // to the maps themselves to support method overloads with the same name. - if (ApiNameMixin.isBaseClassOf(member)) { - if (!membersByName.has(member.name)) { - // This was supposed to replace type parameters with their assigned values in inheritance, but doesn't work yet - /* - if ( - ApiTypeParameterListMixin.isBaseClassOf(member) && - member.typeParameters.some((param) => typeParams.has(param.name)) - ) { - const jsonObject: Partial = {}; - member.serializeInto(jsonObject); - member = deserializerModule.Deserializer.deserialize(context, { - ...jsonObject, - typeParameters: (jsonObject as IApiTypeParameterListMixinJson).typeParameters.map( - ({ typeParameterName, constraintTokenRange, defaultTypeTokenRange }) => ({ - typeParameterName: typeParams.get(typeParameterName) ?? typeParameterName, - defaultTypeTokenRange, - constraintTokenRange, - }), - ), - } as IApiTypeParameterListMixinJson); + + // This was supposed to replace type parameters with their assigned values in inheritance, but doesn't work yet + //* + if (member instanceof ApiDeclaredItem && member.excerptTokens.some((token) => typeParams.has(token.text))) { + const jsonObject: Partial = {}; + member.serializeInto(jsonObject); + const excerptTokens = (jsonObject as IApiDeclaredItemJson).excerptTokens.map((token) => { + let x: ExcerptToken | undefined; + if (typeParams.has(token.text) && next?.item instanceof ApiDeclaredItem) + x = (member as ApiDeclaredItem).excerptTokens[typeParams.get(token.text)!.startIndex]; + const excerptToken: IExcerptToken = x ? { kind: x.kind, text: x.text } : token; + if (x?.canonicalReference !== undefined) { + excerptToken.canonicalReference = x.canonicalReference.toString(); } - if (ApiReturnTypeMixin.isBaseClassOf(member)) { - const jsonObject: Partial = {}; - member.serializeInto(jsonObject); - member = deserializerModule.Deserializer.deserialize(context, { - ...(jsonObject as IApiReturnTypeMixinJson), - excerptTokens: (jsonObject as IApiDeclaredItemJson).excerptTokens.map((token) => - token.kind === ExcerptTokenKind.Content - ? { - kind: ExcerptTokenKind.Content, - text: [...typeParams.keys()].reduce( - (tok, typ) => tok.replaceAll(new RegExp(`\b${typ}\b`, 'g'), typeParams.get(typ)!), - token.text, - ), - } - : token, - ), - } as IApiReturnTypeMixinJson); - member[apiItem_onParentChanged](next.item); - } // */ + return excerptToken; + }); + member = deserializerModule.Deserializer.deserialize(context, { + ...jsonObject, + excerptTokens, + } as IApiDeclaredItemJson); + member[apiItem_onParentChanged](next.item); + } + if (ApiNameMixin.isBaseClassOf(member)) { + if (!membersByName.has(member.name)) { membersToAdd.push(member); } } else if (!membersByKind.has(member.kind)) { @@ -478,7 +470,7 @@ export function ApiItemContainerMixin( continue; } - const mappedTypeParameters: Map = new Map(); + const mappedTypeParameters: Map = new Map(); if ( (apiItem.kind === ApiItemKind.Class || apiItem.kind === ApiItemKind.Interface) && next.item.kind === ApiItemKind.Class diff --git a/packages/api-extractor-model/src/model/ApiClass.ts b/packages/api-extractor-model/src/model/ApiClass.ts index e65a88bd84b5..7f8e86ec101b 100644 --- a/packages/api-extractor-model/src/model/ApiClass.ts +++ b/packages/api-extractor-model/src/model/ApiClass.ts @@ -44,7 +44,7 @@ export interface IApiClassOptions } export interface IExcerptTokenRangeWithTypeParameters extends IExcerptTokenRange { - typeParameters: string[]; + typeParameters: IExcerptTokenRange[]; } export interface IApiClassJson diff --git a/packages/api-extractor-model/src/model/DeserializerContext.ts b/packages/api-extractor-model/src/model/DeserializerContext.ts index daf4de626498..b5778c8f961a 100644 --- a/packages/api-extractor-model/src/model/DeserializerContext.ts +++ b/packages/api-extractor-model/src/model/DeserializerContext.ts @@ -91,13 +91,18 @@ export enum ApiJsonSchemaVersion { */ V_1011 = 1_011, + /** + * Add a `fileLine`and `fileColumn` field to track source code location + */ + V_1012 = 1_012, + /** * 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_1011, + LATEST = V_1012, /** * The oldest .api.json schema version that is still supported for backwards compatibility. diff --git a/packages/api-extractor-model/src/model/HeritageType.ts b/packages/api-extractor-model/src/model/HeritageType.ts index 1efe0f649a64..5332f4a9b487 100644 --- a/packages/api-extractor-model/src/model/HeritageType.ts +++ b/packages/api-extractor-model/src/model/HeritageType.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { Excerpt } from '../mixins/Excerpt.js'; +import type { Excerpt, IExcerptTokenRange } from '../mixins/Excerpt.js'; /** * Represents a type referenced via an "extends" or "implements" heritage clause for a TypeScript class @@ -38,9 +38,9 @@ export class HeritageType { */ public readonly excerpt: Excerpt; - public readonly typeParameters?: string[]; + public readonly typeParameters?: IExcerptTokenRange[]; - public constructor(excerpt: Excerpt, typeParameters: string[]) { + public constructor(excerpt: Excerpt, typeParameters: IExcerptTokenRange[]) { this.excerpt = excerpt; this.typeParameters = typeParameters; } diff --git a/packages/api-extractor/src/generators/ApiModelGenerator.ts b/packages/api-extractor/src/generators/ApiModelGenerator.ts index 94a8f7aa7177..db6f3f759d73 100644 --- a/packages/api-extractor/src/generators/ApiModelGenerator.ts +++ b/packages/api-extractor/src/generators/ApiModelGenerator.ts @@ -538,9 +538,6 @@ export class ApiModelGenerator { if (apiClass === undefined) { const classDeclaration: ts.ClassDeclaration = astDeclaration.declaration as ts.ClassDeclaration; - if (name === 'ActionRow') { - console.dir(classDeclaration.heritageClauses?.[0]?.types[0]?.typeArguments, { depth: 3 }); - } const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; @@ -557,9 +554,14 @@ export class ApiModelGenerator { extendsTokenRange = ExcerptBuilder.createEmptyTokenRangeWithTypeParameters(); if (heritageClause.types.length > 0) { extendsTokenRange.typeParameters.push( - ...(heritageClause.types[0]?.typeArguments?.map((typeArgument) => - ts.isTypeReferenceNode(typeArgument) ? typeArgument.typeName.getText() : '', - ) ?? []), + ...(heritageClause.types[0]?.typeArguments?.map((typeArgument) => { + const typeArgumentTokenRange = ExcerptBuilder.createEmptyTokenRange(); + if (ts.isTypeReferenceNode(typeArgument)) { + nodesToCapture.push({ node: typeArgument, tokenRange: typeArgumentTokenRange }); + } + + return typeArgumentTokenRange; + }) ?? []), ); nodesToCapture.push({ node: heritageClause.types[0], tokenRange: extendsTokenRange }); } @@ -568,9 +570,14 @@ export class ApiModelGenerator { const implementsTokenRange: IExcerptTokenRangeWithTypeParameters = ExcerptBuilder.createEmptyTokenRangeWithTypeParameters(); implementsTokenRange.typeParameters.push( - ...(heritageClause.types[0]?.typeArguments?.map((typeArgument) => - ts.isTypeReferenceNode(typeArgument) ? typeArgument.typeName.getText() : '', - ) ?? []), + ...(heritageClause.types[0]?.typeArguments?.map((typeArgument) => { + const typeArgumentTokenRange = ExcerptBuilder.createEmptyTokenRange(); + if (ts.isTypeReferenceNode(typeArgument)) { + nodesToCapture.push({ node: typeArgument, tokenRange: typeArgumentTokenRange }); + } + + return typeArgumentTokenRange; + }) ?? []), ); implementsTokenRanges.push(implementsTokenRange); nodesToCapture.push({ node: heritageType, tokenRange: implementsTokenRange }); @@ -893,9 +900,14 @@ export class ApiModelGenerator { const extendsTokenRange: IExcerptTokenRangeWithTypeParameters = ExcerptBuilder.createEmptyTokenRangeWithTypeParameters(); extendsTokenRange.typeParameters.push( - ...(heritageClause.types[0]?.typeArguments?.map((typeArgument) => - ts.isTypeReferenceNode(typeArgument) ? typeArgument.typeName.getText() : '', - ) ?? []), + ...(heritageClause.types[0]?.typeArguments?.map((typeArgument) => { + const typeArgumentTokenRange = ExcerptBuilder.createEmptyTokenRange(); + if (ts.isTypeReferenceNode(typeArgument)) { + nodesToCapture.push({ node: typeArgument, tokenRange: typeArgumentTokenRange }); + } + + return typeArgumentTokenRange; + }) ?? []), ); extendsTokenRanges.push(extendsTokenRange); nodesToCapture.push({ node: heritageType, tokenRange: extendsTokenRange }); diff --git a/packages/api-extractor/src/generators/ExcerptBuilder.ts b/packages/api-extractor/src/generators/ExcerptBuilder.ts index 39ea83bf561c..da6b0fd69abb 100644 --- a/packages/api-extractor/src/generators/ExcerptBuilder.ts +++ b/packages/api-extractor/src/generators/ExcerptBuilder.ts @@ -176,14 +176,17 @@ export class ExcerptBuilder { if (span.kind === ts.SyntaxKind.Identifier) { const name: ts.Identifier = span.node as ts.Identifier; - if (!ExcerptBuilder._isDeclarationName(name)) { - canonicalReference = state.referenceGenerator.getDeclarationReferenceForIdentifier(name); - } + canonicalReference = state.referenceGenerator.getDeclarationReferenceForIdentifier(name); } if (canonicalReference) { ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Reference, span.prefix, canonicalReference); - } else if (ExcerptBuilder.isPrimitiveKeyword(span.node)) { + } else if ( + ExcerptBuilder.isPrimitiveKeyword(span.node) || + (span.node.kind === ts.SyntaxKind.Identifier && + ((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 { ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.prefix); @@ -209,7 +212,11 @@ export class ExcerptBuilder { } if (span.separator) { - ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.separator); + ExcerptBuilder._appendToken( + excerptTokens, + ExcerptTokenKind.Content, + span.separator.replaceAll('\n', '').replaceAll(/\s{2}/g, ' '), + ); state.lastAppendedTokenIsSeparator = true; } @@ -335,7 +342,7 @@ export class ExcerptBuilder { } } } - } + } /* private static _isDeclarationName(name: ts.Identifier): boolean { return ExcerptBuilder._isDeclaration(name.parent) && name.parent.name === name; @@ -366,5 +373,5 @@ export class ExcerptBuilder { default: return false; } - } + } // */ } From 2acc03ddb6a2c0ebb8a6b5e60848cd355598546b Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sat, 11 Nov 2023 11:42:56 +0100 Subject: [PATCH 2/6] fix: correct type param replacement --- .../src/mixins/ApiItemContainerMixin.ts | 27 ++++++++++++++----- .../src/generators/ApiModelGenerator.ts | 8 +++--- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/packages/api-extractor-model/src/mixins/ApiItemContainerMixin.ts b/packages/api-extractor-model/src/mixins/ApiItemContainerMixin.ts index 3782457bca38..5e50629daeea 100644 --- a/packages/api-extractor-model/src/mixins/ApiItemContainerMixin.ts +++ b/packages/api-extractor-model/src/mixins/ApiItemContainerMixin.ts @@ -42,9 +42,13 @@ export interface IApiItemContainerJson extends IApiItemJson { preserveMemberOrder?: boolean; } +interface ExcerptTokenRangeInDeclaredItem { + item: ApiDeclaredItem; + range: IExcerptTokenRange; +} interface IMappedTypeParameters { item: ApiItem; - mappedTypeParameters: Map; + mappedTypeParameters: Map; } const _members: unique symbol = Symbol('ApiItemContainerMixin._members'); @@ -349,8 +353,11 @@ export function ApiItemContainerMixin( member.serializeInto(jsonObject); const excerptTokens = (jsonObject as IApiDeclaredItemJson).excerptTokens.map((token) => { let x: ExcerptToken | undefined; - if (typeParams.has(token.text) && next?.item instanceof ApiDeclaredItem) - x = (member as ApiDeclaredItem).excerptTokens[typeParams.get(token.text)!.startIndex]; + if (typeParams.has(token.text) && next?.item instanceof ApiDeclaredItem) { + const originalValue = typeParams.get(token.text)!; + x = originalValue.item.excerptTokens[originalValue.range.startIndex]; + } + const excerptToken: IExcerptToken = x ? { kind: x.kind, text: x.text } : token; if (x?.canonicalReference !== undefined) { excerptToken.canonicalReference = x.canonicalReference.toString(); @@ -470,14 +477,20 @@ export function ApiItemContainerMixin( continue; } - const mappedTypeParameters: Map = new Map(); + const mappedTypeParameters: Map = new Map(); if ( (apiItem.kind === ApiItemKind.Class || apiItem.kind === ApiItemKind.Interface) && next.item.kind === ApiItemKind.Class ) { - for (const [index, typeParameter] of extendsType.typeParameters?.entries() ?? []) { - const key = (apiItem as ApiClass | ApiInterface).typeParameters[index]?.name ?? ''; - mappedTypeParameters.set(key, typeParameter); + for (const [index, key] of (apiItem as ApiClass | ApiInterface).typeParameters.entries() ?? []) { + const typeParameter = extendsType.typeParameters?.[index]; + if (typeParameter) + mappedTypeParameters.set(key.name, { item: next.item as ApiDeclaredItem, range: typeParameter }); + else if (key.defaultTypeExcerpt) + mappedTypeParameters.set(key.name, { + item: apiItem as ApiDeclaredItem, + range: key.defaultTypeExcerpt.tokenRange, + }); } } diff --git a/packages/api-extractor/src/generators/ApiModelGenerator.ts b/packages/api-extractor/src/generators/ApiModelGenerator.ts index db6f3f759d73..dc2d0b0122b7 100644 --- a/packages/api-extractor/src/generators/ApiModelGenerator.ts +++ b/packages/api-extractor/src/generators/ApiModelGenerator.ts @@ -556,9 +556,7 @@ export class ApiModelGenerator { extendsTokenRange.typeParameters.push( ...(heritageClause.types[0]?.typeArguments?.map((typeArgument) => { const typeArgumentTokenRange = ExcerptBuilder.createEmptyTokenRange(); - if (ts.isTypeReferenceNode(typeArgument)) { - nodesToCapture.push({ node: typeArgument, tokenRange: typeArgumentTokenRange }); - } + nodesToCapture.push({ node: typeArgument, tokenRange: typeArgumentTokenRange }); return typeArgumentTokenRange; }) ?? []), @@ -570,7 +568,7 @@ export class ApiModelGenerator { const implementsTokenRange: IExcerptTokenRangeWithTypeParameters = ExcerptBuilder.createEmptyTokenRangeWithTypeParameters(); implementsTokenRange.typeParameters.push( - ...(heritageClause.types[0]?.typeArguments?.map((typeArgument) => { + ...(heritageType.typeArguments?.map((typeArgument) => { const typeArgumentTokenRange = ExcerptBuilder.createEmptyTokenRange(); if (ts.isTypeReferenceNode(typeArgument)) { nodesToCapture.push({ node: typeArgument, tokenRange: typeArgumentTokenRange }); @@ -900,7 +898,7 @@ export class ApiModelGenerator { const extendsTokenRange: IExcerptTokenRangeWithTypeParameters = ExcerptBuilder.createEmptyTokenRangeWithTypeParameters(); extendsTokenRange.typeParameters.push( - ...(heritageClause.types[0]?.typeArguments?.map((typeArgument) => { + ...(heritageType.typeArguments?.map((typeArgument) => { const typeArgumentTokenRange = ExcerptBuilder.createEmptyTokenRange(); if (ts.isTypeReferenceNode(typeArgument)) { nodesToCapture.push({ node: typeArgument, tokenRange: typeArgumentTokenRange }); From fe899a871409e01af82875f70ffcdbcbdf0416bf Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sun, 12 Nov 2023 12:15:47 +0100 Subject: [PATCH 3/6] fix: ae config, link builtin in summary, `: | T` => `: T`, mainlib tsdoc --- api-extractor.json | 78 ++++++++++--------- .../components/documentation/tsdoc/TSDoc.tsx | 26 ++++++- .../api-extractor/config/api-extractor.json | 4 +- .../api-extractor/src/collector/Collector.ts | 2 +- .../src/generators/ApiModelGenerator.ts | 27 ++++--- .../src/generators/ExcerptBuilder.ts | 27 +++++-- packages/discord.js/typings/index.d.ts | 68 ++++++++-------- 7 files changed, 135 insertions(+), 97 deletions(-) diff --git a/api-extractor.json b/api-extractor.json index 736568c70792..78b15baef98b 100644 --- a/api-extractor.json +++ b/api-extractor.json @@ -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 diff --git a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx index 3572ad128ce7..7bd83eebfd52 100644 --- a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx +++ b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx @@ -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'; @@ -12,6 +14,7 @@ import { DefaultValueBlock, DeprecatedBlock, ExampleBlock, RemarksBlock, Returns export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: DocNode }): JSX.Element { const createNode = useCallback( (tsdoc: DocNode, idx?: number): ReactNode => { + // console.log(item.displayName, DocNodeKind[tsdoc.kind]); switch (tsdoc.kind) { case DocNodeKind.PlainText: return ( @@ -32,10 +35,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 ( + + {typeName} + + ); + } + + const declarationReference = item.getAssociatedModel()?.resolveDeclarationReference(codeDestination, item); + const foundItem = declarationReference.resolvedApiItem; if (!foundItem) return null; @@ -44,6 +61,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} diff --git a/packages/api-extractor/config/api-extractor.json b/packages/api-extractor/config/api-extractor.json index c4d10dfdc8cb..58691092e178 100644 --- a/packages/api-extractor/config/api-extractor.json +++ b/packages/api-extractor/config/api-extractor.json @@ -5,12 +5,12 @@ "apiReport": { "enabled": true, - "reportFolder": "../../../common/reviews/api" + "reportFolder": "/docs/review" }, "docModel": { "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" + "apiJsonFilePath": "/docs/.api.json" }, "dtsRollup": { diff --git a/packages/api-extractor/src/collector/Collector.ts b/packages/api-extractor/src/collector/Collector.ts index 278b65edf545..11dcf18617e4 100644 --- a/packages/api-extractor/src/collector/Collector.ts +++ b/packages/api-extractor/src/collector/Collector.ts @@ -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'; diff --git a/packages/api-extractor/src/generators/ApiModelGenerator.ts b/packages/api-extractor/src/generators/ApiModelGenerator.ts index dc2d0b0122b7..8863391a533f 100644 --- a/packages/api-extractor/src/generators/ApiModelGenerator.ts +++ b/packages/api-extractor/src/generators/ApiModelGenerator.ts @@ -36,7 +36,6 @@ import { 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'; @@ -220,12 +219,16 @@ export class ApiModelGenerator { 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 { @@ -500,7 +503,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 +589,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 +661,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 +792,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 +919,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 ${ @@ -980,7 +983,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('') ?? '' @@ -1058,7 +1061,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('') ?? '' @@ -1166,7 +1169,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${ 'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : '' }${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${ @@ -1229,7 +1232,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${ 'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\n`).join('') : '' }${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\n' : ''}${ @@ -1290,7 +1293,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 +1428,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('') : ''}${ diff --git a/packages/api-extractor/src/generators/ExcerptBuilder.ts b/packages/api-extractor/src/generators/ExcerptBuilder.ts index da6b0fd69abb..c991b2adbc28 100644 --- a/packages/api-extractor/src/generators/ExcerptBuilder.ts +++ b/packages/api-extractor/src/generators/ExcerptBuilder.ts @@ -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` + 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. diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 876cd8384a06..3f0d67b68e0b 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -986,7 +986,7 @@ export class Client extends BaseClient { public fetchVoiceRegions(): Promise>; public fetchSticker(id: Snowflake): Promise; public fetchStickerPacks(): Promise>; - /** @deprecated Use {@link fetchStickerPacks} instead. */ + /** @deprecated Use {@link Client#fetchStickerPacks} instead. */ public fetchPremiumStickerPacks(): ReturnType; public fetchWebhook(id: Snowflake, token?: string): Promise; public fetchGuildWidget(guild: GuildResolvable): Promise; @@ -1853,7 +1853,7 @@ export class BaseInteraction extends Base public isMessageContextMenuCommand(): this is MessageContextMenuCommandInteraction; public isModalSubmit(): this is ModalSubmitInteraction; public isUserContextMenuCommand(): this is UserContextMenuCommandInteraction; - /** @deprecated Use {@link isStringSelectMenu} instead. */ + /** @deprecated Use {@link BaseInteraction#isStringSelectMenu} instead. */ public isSelectMenu(): this is StringSelectMenuInteraction; public isAnySelectMenu(): this is AnySelectMenuInteraction; public isStringSelectMenu(): this is StringSelectMenuInteraction; @@ -1934,12 +1934,12 @@ export class Invite extends Base { public toJSON(): unknown; public toString(): string; public static InvitesPattern: RegExp; - /** @deprecated */ + /** @deprecated Public Stage Instances don't exist anymore */ public stageInstance: InviteStageInstance | null; public guildScheduledEvent: GuildScheduledEvent | null; } -/** @deprecated */ +/** @deprecated Public Stage Instances don't exist anymore */ export class InviteStageInstance extends Base { private constructor(client: Client, data: RawInviteStageInstance, channelId: Snowflake, guildId: Snowflake); public channelId: Snowflake; @@ -3018,7 +3018,7 @@ export class TeamMember extends Base { private constructor(team: Team, data: RawTeamMemberData); public team: Team; public get id(): Snowflake; - /** @deprecated Use {@link role} instead. */ + /** @deprecated Use {@link TeamMember#role} instead. */ public permissions: string[]; public membershipState: TeamMemberMembershipState; public user: User; @@ -3581,24 +3581,24 @@ export enum DiscordjsErrorCodes { TokenMissing = 'TokenMissing', ApplicationCommandPermissionsTokenMissing = 'ApplicationCommandPermissionsTokenMissing', - /** @deprecated */ + /** @deprecated ws errors are now handled in `@discordjs/ws` */ WSCloseRequested = 'WSCloseRequested', - /** @deprecated */ + /** @deprecated ws errors are now handled in `@discordjs/ws` */ WSConnectionExists = 'WSConnectionExists', - /** @deprecated */ + /** @deprecated ws errors are now handled in `@discordjs/ws` */ WSNotOpen = 'WSNotOpen', - /** @deprecated */ + /** @deprecated was never used */ ManagerDestroyed = 'ManagerDestroyed', BitFieldInvalid = 'BitFieldInvalid', - /** @deprecated */ + /** @deprecated was never used */ ShardingInvalid = 'ShardingInvalid', - /** @deprecated */ + /** @deprecated was never used */ ShardingRequired = 'ShardingRequired', - /** @deprecated */ + /** @deprecated was never used */ InvalidIntents = 'InvalidIntents', - /** @deprecated */ + /** @deprecated was never used */ DisallowedIntents = 'DisallowedIntents', ShardingNoShards = 'ShardingNoShards', ShardingInProcess = 'ShardingInProcess', @@ -3618,29 +3618,29 @@ export enum DiscordjsErrorCodes { InviteOptionsMissingChannel = 'InviteOptionsMissingChannel', - /** @deprecated */ + /** @deprecated was never used */ ButtonLabel = 'ButtonLabel', - /** @deprecated */ + /** @deprecated was never used */ ButtonURL = 'ButtonURL', - /** @deprecated */ + /** @deprecated was never used */ ButtonCustomId = 'ButtonCustomId', - /** @deprecated */ + /** @deprecated was never used */ SelectMenuCustomId = 'SelectMenuCustomId', - /** @deprecated */ + /** @deprecated was never used */ SelectMenuPlaceholder = 'SelectMenuPlaceholder', - /** @deprecated */ + /** @deprecated was never used */ SelectOptionLabel = 'SelectOptionLabel', - /** @deprecated */ + /** @deprecated was never used */ SelectOptionValue = 'SelectOptionValue', - /** @deprecated */ + /** @deprecated was never used */ SelectOptionDescription = 'SelectOptionDescription', InteractionCollectorError = 'InteractionCollectorError', FileNotFound = 'FileNotFound', - /** @deprecated */ + /** @deprecated was never used */ UserBannerNotFetched = 'UserBannerNotFetched', UserNoDMChannel = 'UserNoDMChannel', @@ -3651,16 +3651,16 @@ export enum DiscordjsErrorCodes { ReqResourceType = 'ReqResourceType', - /** @deprecated */ + /** @deprecated was never used */ ImageFormat = 'ImageFormat', - /** @deprecated */ + /** @deprecated was never used */ ImageSize = 'ImageSize', MessageBulkDeleteType = 'MessageBulkDeleteType', MessageNonceType = 'MessageNonceType', MessageContentType = 'MessageContentType', - /** @deprecated */ + /** @deprecated was never used */ SplitMaxLen = 'SplitMaxLen', BanResolveId = 'BanResolveId', @@ -3696,14 +3696,14 @@ export enum DiscordjsErrorCodes { EmojiType = 'EmojiType', EmojiManaged = 'EmojiManaged', MissingManageGuildExpressionsPermission = 'MissingManageGuildExpressionsPermission', - /** @deprecated Use {@link MissingManageGuildExpressionsPermission} instead. */ + /** @deprecated Use {@link DiscordjsErrorCodes.MissingManageGuildExpressionsPermission} instead. */ MissingManageEmojisAndStickersPermission = 'MissingManageEmojisAndStickersPermission', NotGuildSticker = 'NotGuildSticker', ReactionResolveUser = 'ReactionResolveUser', - /** @deprecated */ + /** @deprecated Not used anymore since the introduction of `GUILD_WEB_PAGE_VANITY_URL` feature */ VanityURL = 'VanityURL', InviteResolveCode = 'InviteResolveCode', @@ -3720,7 +3720,7 @@ export enum DiscordjsErrorCodes { InteractionAlreadyReplied = 'InteractionAlreadyReplied', InteractionNotReplied = 'InteractionNotReplied', - /** @deprecated */ + /** @deprecated Not used anymore since ephemeral replies can now be deleted without issue */ InteractionEphemeralReplied = 'InteractionEphemeralReplied', CommandInteractionOptionNotFound = 'CommandInteractionOptionNotFound', @@ -4747,7 +4747,7 @@ export interface AwaitReactionsOptions extends ReactionCollectorOptions { } export interface BanOptions { - /** @deprecated Use {@link deleteMessageSeconds} instead. */ + /** @deprecated Use {@link BanOptions#deleteMessageSeconds} instead. */ deleteMessageDays?: number; deleteMessageSeconds?: number; reason?: string; @@ -4947,7 +4947,7 @@ export interface ClientEvents { typingStart: [typing: Typing]; userUpdate: [oldUser: User | PartialUser, newUser: User]; voiceStateUpdate: [oldState: VoiceState, newState: VoiceState]; - /** @deprecated Use {@link webhooksUpdate} instead. */ + /** @deprecated Use {@link ClientEvents#webhooksUpdate} instead. */ webhookUpdate: ClientEvents['webhooksUpdate']; webhooksUpdate: [channel: TextChannel | NewsChannel | VoiceChannel | ForumChannel | MediaChannel]; interactionCreate: [interaction: Interaction]; @@ -5007,10 +5007,10 @@ export interface ClientUserEditOptions { } export interface CloseEvent { - /** @deprecated */ + /** @deprecated not used anymore since using {@link @discordjs/ws!WebSocketManager:class#} internally */ wasClean: boolean; code: number; - /** @deprecated */ + /** @deprecated not used anymore since using {@link @discordjs/ws!WebSocketManager:class#} internally */ reason: string; } @@ -5336,11 +5336,11 @@ export interface FetchGuildScheduledEventSubscribersOptions { withMember?: boolean; } -interface FetchInviteOptions extends BaseFetchOptions { +export interface FetchInviteOptions extends BaseFetchOptions { code: string; } -interface FetchInvitesOptions { +export interface FetchInvitesOptions { channelId?: GuildInvitableChannelResolvable; cache?: boolean; } From 35655221aa025be6e253a1b7f9fb174b52be629c Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sun, 12 Nov 2023 13:01:41 +0100 Subject: [PATCH 4/6] fix: requested changes and tests --- apps/website/src/components/documentation/tsdoc/TSDoc.tsx | 3 +-- packages/discord.js/typings/index.d.ts | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx index 7bd83eebfd52..686d1cec1fdc 100644 --- a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx +++ b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx @@ -14,7 +14,6 @@ import { DefaultValueBlock, DeprecatedBlock, ExampleBlock, RemarksBlock, Returns export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: DocNode }): JSX.Element { const createNode = useCallback( (tsdoc: DocNode, idx?: number): ReactNode => { - // console.log(item.displayName, DocNodeKind[tsdoc.kind]); switch (tsdoc.kind) { case DocNodeKind.PlainText: return ( @@ -52,7 +51,7 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: } const declarationReference = item.getAssociatedModel()?.resolveDeclarationReference(codeDestination, item); - const foundItem = declarationReference.resolvedApiItem; + const foundItem = declarationReference?.resolvedApiItem; if (!foundItem) return null; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 3f0d67b68e0b..4bde7ec96d78 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -5007,10 +5007,10 @@ export interface ClientUserEditOptions { } export interface CloseEvent { - /** @deprecated not used anymore since using {@link @discordjs/ws!WebSocketManager:class#} internally */ + /** @deprecated Not used anymore since using {@link @discordjs/ws#WebSocketManager} internally */ wasClean: boolean; code: number; - /** @deprecated not used anymore since using {@link @discordjs/ws!WebSocketManager:class#} internally */ + /** @deprecated Not used anymore since using {@link @discordjs/ws#WebSocketManager} internally */ reason: string; } From 148e08bc51405291efdc839479f08f8974d6c321 Mon Sep 17 00:00:00 2001 From: Almeida Date: Sun, 12 Nov 2023 12:34:11 +0000 Subject: [PATCH 5/6] chore: better deprecation messages and code cleanup --- .../components/documentation/tsdoc/TSDoc.tsx | 6 +-- packages/discord.js/typings/index.d.ts | 42 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx index 686d1cec1fdc..fbddbe3c65e2 100644 --- a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx +++ b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx @@ -38,10 +38,10 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: !codeDestination.importPath && !codeDestination.packageName && codeDestination.memberReferences.length === 1 && - codeDestination.memberReferences[0]?.memberIdentifier && - codeDestination.memberReferences[0].memberIdentifier?.identifier in BuiltinDocumentationLinks + codeDestination.memberReferences[0]!.memberIdentifier && + codeDestination.memberReferences[0]!.memberIdentifier.identifier in BuiltinDocumentationLinks ) { - const typeName = codeDestination.memberReferences[0]?.memberIdentifier?.identifier; + const typeName = codeDestination.memberReferences[0]!.memberIdentifier.identifier; const href = BuiltinDocumentationLinks[typeName as keyof typeof BuiltinDocumentationLinks]; return ( diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 4bde7ec96d78..518964af01d2 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -3581,24 +3581,24 @@ export enum DiscordjsErrorCodes { TokenMissing = 'TokenMissing', ApplicationCommandPermissionsTokenMissing = 'ApplicationCommandPermissionsTokenMissing', - /** @deprecated ws errors are now handled in `@discordjs/ws` */ + /** @deprecated WebSocket errors are now handled in `@discordjs/ws` */ WSCloseRequested = 'WSCloseRequested', - /** @deprecated ws errors are now handled in `@discordjs/ws` */ + /** @deprecated WebSocket errors are now handled in `@discordjs/ws` */ WSConnectionExists = 'WSConnectionExists', - /** @deprecated ws errors are now handled in `@discordjs/ws` */ + /** @deprecated WebSocket errors are now handled in `@discordjs/ws` */ WSNotOpen = 'WSNotOpen', - /** @deprecated was never used */ + /** @deprecated No longer in use */ ManagerDestroyed = 'ManagerDestroyed', BitFieldInvalid = 'BitFieldInvalid', - /** @deprecated was never used */ + /** @deprecated This error is now handled in `@discordjs/ws` */ ShardingInvalid = 'ShardingInvalid', - /** @deprecated was never used */ + /** @deprecated This error is now handled in `@discordjs/ws` */ ShardingRequired = 'ShardingRequired', - /** @deprecated was never used */ + /** @deprecated This error is now handled in `@discordjs/ws` */ InvalidIntents = 'InvalidIntents', - /** @deprecated was never used */ + /** @deprecated This error is now handled in `@discordjs/ws` */ DisallowedIntents = 'DisallowedIntents', ShardingNoShards = 'ShardingNoShards', ShardingInProcess = 'ShardingInProcess', @@ -3618,29 +3618,29 @@ export enum DiscordjsErrorCodes { InviteOptionsMissingChannel = 'InviteOptionsMissingChannel', - /** @deprecated was never used */ + /** @deprecated Button validation errors are now handled in `@discordjs/builders` */ ButtonLabel = 'ButtonLabel', - /** @deprecated was never used */ + /** @deprecated Button validation errors are now handled in `@discordjs/builders` */ ButtonURL = 'ButtonURL', - /** @deprecated was never used */ + /** @deprecated Button validation errors are now handled in `@discordjs/builders` */ ButtonCustomId = 'ButtonCustomId', - /** @deprecated was never used */ + /** @deprecated Select Menu validation errors are now handled in `@discordjs/builders` */ SelectMenuCustomId = 'SelectMenuCustomId', - /** @deprecated was never used */ + /** @deprecated Select Menu validation errors are now handled in `@discordjs/builders` */ SelectMenuPlaceholder = 'SelectMenuPlaceholder', - /** @deprecated was never used */ + /** @deprecated Select Menu validation errors are now handled in `@discordjs/builders` */ SelectOptionLabel = 'SelectOptionLabel', - /** @deprecated was never used */ + /** @deprecated Select Menu validation errors are now handled in `@discordjs/builders` */ SelectOptionValue = 'SelectOptionValue', - /** @deprecated was never used */ + /** @deprecated Select Menu validation errors are now handled in `@discordjs/builders` */ SelectOptionDescription = 'SelectOptionDescription', InteractionCollectorError = 'InteractionCollectorError', FileNotFound = 'FileNotFound', - /** @deprecated was never used */ + /** @deprecated No longer in use */ UserBannerNotFetched = 'UserBannerNotFetched', UserNoDMChannel = 'UserNoDMChannel', @@ -3651,16 +3651,16 @@ export enum DiscordjsErrorCodes { ReqResourceType = 'ReqResourceType', - /** @deprecated was never used */ + /** @deprecated This error is now handled in `@discordjs/rest` */ ImageFormat = 'ImageFormat', - /** @deprecated was never used */ + /** @deprecated This error is now handled in `@discordjs/rest` */ ImageSize = 'ImageSize', MessageBulkDeleteType = 'MessageBulkDeleteType', MessageNonceType = 'MessageNonceType', MessageContentType = 'MessageContentType', - /** @deprecated was never used */ + /** @deprecated No longer in use */ SplitMaxLen = 'SplitMaxLen', BanResolveId = 'BanResolveId', @@ -3720,7 +3720,7 @@ export enum DiscordjsErrorCodes { InteractionAlreadyReplied = 'InteractionAlreadyReplied', InteractionNotReplied = 'InteractionNotReplied', - /** @deprecated Not used anymore since ephemeral replies can now be deleted without issue */ + /** @deprecated Not used anymore since ephemeral replies can now be deleted */ InteractionEphemeralReplied = 'InteractionEphemeralReplied', CommandInteractionOptionNotFound = 'CommandInteractionOptionNotFound', From 7a1c20f1a9462040167be1db6424f294eaeda09d Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sun, 12 Nov 2023 14:55:11 +0100 Subject: [PATCH 6/6] fix: cleanup optional chainings --- apps/website/src/components/documentation/tsdoc/TSDoc.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx index 686d1cec1fdc..60c58693fc41 100644 --- a/apps/website/src/components/documentation/tsdoc/TSDoc.tsx +++ b/apps/website/src/components/documentation/tsdoc/TSDoc.tsx @@ -39,9 +39,9 @@ export function TSDoc({ item, tsdoc }: { readonly item: ApiItem; readonly tsdoc: !codeDestination.packageName && codeDestination.memberReferences.length === 1 && codeDestination.memberReferences[0]?.memberIdentifier && - codeDestination.memberReferences[0].memberIdentifier?.identifier in BuiltinDocumentationLinks + codeDestination.memberReferences[0].memberIdentifier.identifier in BuiltinDocumentationLinks ) { - const typeName = codeDestination.memberReferences[0]?.memberIdentifier?.identifier; + const typeName = codeDestination.memberReferences[0].memberIdentifier.identifier; const href = BuiltinDocumentationLinks[typeName as keyof typeof BuiltinDocumentationLinks]; return (