From 85c76fab37786cf69bc5cac787491563d676337d Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Wed, 14 May 2025 12:24:15 +0200 Subject: [PATCH 1/2] feat: emit warnings for missing jsdoc or typings --- .../api-extractor/src/analyzer/AstEntity.ts | 1 + .../src/analyzer/ExportAnalyzer.ts | 29 +--- .../src/api/ExtractorMessageId.ts | 12 ++ .../src/generators/ApiModelGenerator.ts | 130 ++++++++++++++++++ .../src/generators/DtsRollupGenerator.ts | 27 ++-- 5 files changed, 160 insertions(+), 39 deletions(-) diff --git a/packages/api-extractor/src/analyzer/AstEntity.ts b/packages/api-extractor/src/analyzer/AstEntity.ts index ee08c1298a1a..a75038cc7dfa 100644 --- a/packages/api-extractor/src/analyzer/AstEntity.ts +++ b/packages/api-extractor/src/analyzer/AstEntity.ts @@ -13,6 +13,7 @@ * - AstSyntheticEntity * - AstImport * - AstNamespaceImport + * - AstNamespaceExport * ``` */ export abstract class AstEntity { diff --git a/packages/api-extractor/src/analyzer/ExportAnalyzer.ts b/packages/api-extractor/src/analyzer/ExportAnalyzer.ts index 6b618c0af4d0..0c9e69f0924d 100644 --- a/packages/api-extractor/src/analyzer/ExportAnalyzer.ts +++ b/packages/api-extractor/src/analyzer/ExportAnalyzer.ts @@ -9,7 +9,7 @@ import { AstModule, type IAstModuleExportInfo } from './AstModule.js'; import { AstNamespaceExport } from './AstNamespaceExport.js'; import { AstNamespaceImport } from './AstNamespaceImport.js'; import { AstSymbol } from './AstSymbol.js'; -import type { IFetchAstSymbolOptions } from './AstSymbolTable.js'; +import type { AstSymbolTable, IFetchAstSymbolOptions } from './AstSymbolTable.js'; import { SourceFileLocationFormatter } from './SourceFileLocationFormatter.js'; import { SyntaxHelpers } from './SyntaxHelpers.js'; import { TypeScriptHelpers } from './TypeScriptHelpers.js'; @@ -566,33 +566,6 @@ export class ExportAnalyzer { if (exportDeclaration.moduleSpecifier) { const externalModulePath: string | undefined = this._tryGetExternalModulePath(exportDeclaration); - // if (declaration.kind === ts.SyntaxKind.NamespaceExport) { - // if (externalModulePath === undefined) { - // const astModule: AstModule = this._fetchSpecifierAstModule(exportDeclaration, declarationSymbol); - // let namespaceImport: AstNamespaceImport | undefined = this._astNamespaceImportByModule.get(astModule); - // if (namespaceImport === undefined) { - // namespaceImport = new AstNamespaceImport({ - // namespaceName: declarationSymbol.name, - // astModule, - // declaration, - // symbol: declarationSymbol, - // }); - // this._astNamespaceImportByModule.set(astModule, namespaceImport); - // } - - // return namespaceImport; - // } - - // // Here importSymbol=undefined because {@inheritDoc} and such are not going to work correctly for - // // a package or source file. - // return this._fetchAstImport(undefined, { - // importKind: AstImportKind.StarImport, - // exportName, - // modulePath: externalModulePath, - // isTypeOnly: exportDeclaration.isTypeOnly, - // }); - // } - if (externalModulePath !== undefined) { return this._fetchAstImport(declarationSymbol, { importKind: AstImportKind.NamedImport, diff --git a/packages/api-extractor/src/api/ExtractorMessageId.ts b/packages/api-extractor/src/api/ExtractorMessageId.ts index 094f748fa6de..537ada299439 100644 --- a/packages/api-extractor/src/api/ExtractorMessageId.ts +++ b/packages/api-extractor/src/api/ExtractorMessageId.ts @@ -21,6 +21,16 @@ export const enum ExtractorMessageId { */ DifferentReleaseTags = 'ae-different-release-tags', + /** + * "The symbol ___ has no matching jsdoc equivalent in the JavaScript source files." + */ + DjsMissingJSDoc = 'ae-djs-missing-jsdoc', + + /** + * "The JSDoc comment for___ has no matching type equivalent in the TypeScript declaration file." + */ + DjsMissingTypeScriptType = 'ae-djs-missing-types', + /** * "The doc comment should not contain more than one release tag." */ @@ -127,6 +137,8 @@ export const allExtractorMessageIds: Set = new Set([ 'ae-extra-release-tag', 'ae-undocumented', 'ae-different-release-tags', + 'ae-djs-missing-jsdoc', + 'ae-djs-missing-types', 'ae-incompatible-release-tags', 'ae-missing-release-tag', 'ae-misplaced-package-tag', diff --git a/packages/api-extractor/src/generators/ApiModelGenerator.ts b/packages/api-extractor/src/generators/ApiModelGenerator.ts index e6950c1aff38..0caf69444dbc 100644 --- a/packages/api-extractor/src/generators/ApiModelGenerator.ts +++ b/packages/api-extractor/src/generators/ApiModelGenerator.ts @@ -52,6 +52,7 @@ import { AstNamespaceImport } from '../analyzer/AstNamespaceImport.js'; import { AstSymbol } from '../analyzer/AstSymbol.js'; import { TypeScriptInternals } from '../analyzer/TypeScriptInternals.js'; import type { ExtractorConfig } from '../api/ExtractorConfig'; +import { ExtractorMessageId } from '../api/ExtractorMessageId.js'; import type { ApiItemMetadata } from '../collector/ApiItemMetadata.js'; import type { Collector } from '../collector/Collector.js'; import type { DeclarationMetadata } from '../collector/DeclarationMetadata.js'; @@ -256,6 +257,8 @@ export class ApiModelGenerator { private readonly _jsDocJson: DocgenJson | undefined; + private readonly _mainSourceFile: ts.SourceFile | undefined; + public constructor(collector: Collector, extractorConfig: ExtractorConfig) { this._collector = collector; this._apiModel = new ApiModel(); @@ -271,6 +274,9 @@ export class ApiModelGenerator { // @ts-expect-error we reuse the private tsdocParser from collector here this._tsDocParser = collector._tsdocParser; + this._mainSourceFile = this._collector.workingPackage.entryPoints.find((entry) => + this._collector.workingPackage.isDefaultEntryPoint(entry), + )?.sourceFile; } public get apiModel(): ApiModel { @@ -319,6 +325,15 @@ export class ApiModelGenerator { private _processAstEntity(astEntity: AstEntity, context: IProcessAstEntityContext): void { if (astEntity instanceof AstSymbol) { + if ( + context.parentDocgenJson && + astEntity.followedSymbol.declarations?.some( + (declaration) => declaration.getSourceFile() !== this._mainSourceFile, + ) + ) { + context.parentDocgenJson = undefined; + } + // Skip ancillary declarations; we will process them with the main declaration for (const astDeclaration of this._collector.getNonAncillaryDeclarations(astEntity)) { this._processDeclaration(astDeclaration, context); @@ -608,6 +623,15 @@ export class ApiModelGenerator { } */`, ).docComment : apiItemMetadata.tsdocComment; + + if (!docComment && parent) { + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DjsMissingJSDoc, + `The symbol ${parentApiItem.displayName}#constrcutor() has no matching jsdoc equivalent in the JavaScript source files.`, + astDeclaration, + ); + } + const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; const isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0; const sourceLocation: ISourceLocation = this._getSourceLocation(constructorDeclaration); @@ -698,6 +722,15 @@ export class ApiModelGenerator { } */`, ).docComment : apiItemMetadata.tsdocComment; + + if (!docComment && parent) { + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DjsMissingJSDoc, + `The symbol ${name} has no matching jsdoc equivalent in the JavaScript source files.`, + astDeclaration, + ); + } + const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; const isAbstract: boolean = (ts.getCombinedModifierFlags(classDeclaration) & ts.ModifierFlags.Abstract) !== 0; const sourceLocation: ISourceLocation = this._getSourceLocation(classDeclaration); @@ -768,6 +801,15 @@ export class ApiModelGenerator { } */`, ).docComment : apiItemMetadata.tsdocComment; + + if (!docComment && parent) { + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DjsMissingJSDoc, + `The symbol ${parentApiItem.displayName}#constructor() has no matching jsdoc equivalent in the JavaScript source files.`, + astDeclaration, + ); + } + const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; const sourceLocation: ISourceLocation = this._getSourceLocation(constructSignature); @@ -915,6 +957,15 @@ export class ApiModelGenerator { } */`, ).docComment : apiItemMetadata.tsdocComment; + + if (!docComment && parent) { + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DjsMissingJSDoc, + `The symbol ${name}() has no matching jsdoc equivalent in the JavaScript source files.`, + astDeclaration, + ); + } + const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; const sourceLocation: ISourceLocation = this._getSourceLocation(functionDeclaration); @@ -1037,6 +1088,15 @@ export class ApiModelGenerator { } */`, ).docComment : apiItemMetadata.tsdocComment; + + if (!docComment && parent) { + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DjsMissingJSDoc, + `The symbol ${name} has no matching jsdoc equivalent in the JavaScript source files.`, + astDeclaration, + ); + } + const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; const sourceLocation: ISourceLocation = this._getSourceLocation(interfaceDeclaration); @@ -1118,6 +1178,15 @@ export class ApiModelGenerator { } */`, ).docComment : apiItemMetadata.tsdocComment; + + if (!docComment && parent) { + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DjsMissingJSDoc, + `The symbol ${parentApiItem.displayName}#${name}() has no matching jsdoc equivalent in the JavaScript source files.`, + astDeclaration, + ); + } + const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; if (releaseTag === ReleaseTag.Internal || releaseTag === ReleaseTag.Alpha) { return; // trim out items marked as "@internal" or "@alpha" @@ -1150,6 +1219,13 @@ export class ApiModelGenerator { return; } + this._collector.messageRouter.addAnalyzerIssueForPosition( + ExtractorMessageId.DjsMissingTypeScriptType, + `The JSDoc comment for ${parentApiItem.displayName}#${name}() has no matching type equivalent in the TypeScript declaration file.`, + this._mainSourceFile!, + 0, + ); + const methodOptions = this._mapMethod(jsDoc, parentApiItem.getAssociatedPackage()!.name); if (methodOptions.releaseTag === ReleaseTag.Internal || methodOptions.releaseTag === ReleaseTag.Alpha) { return; // trim out items marked as "@internal" or "@alpha" @@ -1214,6 +1290,15 @@ export class ApiModelGenerator { } */`, ).docComment : apiItemMetadata.tsdocComment; + + if (!docComment && parent) { + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DjsMissingJSDoc, + `The symbol ${parentApiItem.displayName}#${name}() has no matching jsdoc equivalent in the JavaScript source files.`, + astDeclaration, + ); + } + const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0; const sourceLocation: ISourceLocation = this._getSourceLocation(methodSignature); @@ -1233,6 +1318,12 @@ export class ApiModelGenerator { fileColumn: sourceLocation.sourceFileColumn, }); } else if (jsDoc) { + this._collector.messageRouter.addAnalyzerIssueForPosition( + ExtractorMessageId.DjsMissingTypeScriptType, + `The JSDoc comment for ${parentApiItem.displayName}#${name}() has no matching type equivalent in the TypeScript declaration file.`, + this._mainSourceFile!, + 0, + ); apiMethodSignature = new ApiMethodSignature(this._mapMethod(jsDoc, parentApiItem.getAssociatedPackage()!.name)); } @@ -1329,6 +1420,15 @@ export class ApiModelGenerator { } */`, ).docComment : apiItemMetadata.tsdocComment; + + if (!docComment && parent) { + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DjsMissingJSDoc, + `The symbol ${parentApiItem.displayName}#${name} has no matching jsdoc equivalent in the JavaScript source files.`, + astDeclaration, + ); + } + const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0; const isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0; @@ -1353,6 +1453,12 @@ export class ApiModelGenerator { fileColumn: sourceLocation.sourceFileColumn, }); } else if (parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface) { + this._collector.messageRouter.addAnalyzerIssueForPosition( + ExtractorMessageId.DjsMissingTypeScriptType, + `The JSDoc comment for ${parentApiItem.displayName}#${name} has no matching type equivalent in the TypeScript declaration file.`, + this._mainSourceFile!, + 0, + ); const propertyOptions = this._mapProp(jsDoc as DocgenPropertyJson, parentApiItem.getAssociatedPackage()!.name); if (propertyOptions.releaseTag === ReleaseTag.Internal || propertyOptions.releaseTag === ReleaseTag.Alpha) { return; // trim out items marked as "@internal" or "@alpha" @@ -1407,6 +1513,15 @@ export class ApiModelGenerator { } */`, ).docComment : apiItemMetadata.tsdocComment; + + if (!docComment && parent) { + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DjsMissingJSDoc, + `The symbol ${parentApiItem.displayName}#${name} has no matching jsdoc equivalent in the JavaScript source files.`, + astDeclaration, + ); + } + const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; const isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0; const isReadonly: boolean = this._isReadonly(astDeclaration); @@ -1425,6 +1540,12 @@ export class ApiModelGenerator { fileColumn: sourceLocation.sourceFileColumn, }); } else if (parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface) { + this._collector.messageRouter.addAnalyzerIssueForPosition( + ExtractorMessageId.DjsMissingTypeScriptType, + `The JSDoc comment for ${parentApiItem.displayName}#${name} has no matching type equivalent in the TypeScript declaration file.`, + this._mainSourceFile!, + 0, + ); apiPropertySignature = new ApiPropertySignature( this._mapProp(jsDoc as DocgenPropertyJson, parentApiItem.getAssociatedPackage()!.name), ); @@ -1485,6 +1606,15 @@ export class ApiModelGenerator { } */`, ).docComment : apiItemMetadata.tsdocComment; + + if (!docComment && parent) { + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DjsMissingJSDoc, + `The symbol ${name} has no matching jsdoc equivalent in the JavaScript source files.`, + astDeclaration, + ); + } + const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; const sourceLocation: ISourceLocation = this._getSourceLocation(typeAliasDeclaration); diff --git a/packages/api-extractor/src/generators/DtsRollupGenerator.ts b/packages/api-extractor/src/generators/DtsRollupGenerator.ts index 725889f8a64a..79eb650977ef 100644 --- a/packages/api-extractor/src/generators/DtsRollupGenerator.ts +++ b/packages/api-extractor/src/generators/DtsRollupGenerator.ts @@ -108,18 +108,12 @@ export class DtsRollupGenerator { // Emit the imports for (const entity of [...collector.entities.values()][0]!) { if (entity.astEntity instanceof AstImport) { + // Note: it isn't valid to trim imports based on their release tags. + // E.g. class Foo (`@public`) extends interface Bar (`@beta`) from some external library. + // API-Extractor cannot trim `import { Bar } from "external-library"` when generating its public rollup, + // or the export of `Foo` would include a broken reference to `Bar`. const astImport: AstImport = entity.astEntity; - - // For example, if the imported API comes from an external package that supports AEDoc, - // and it was marked as `@internal`, then don't emit it. - const symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(astImport); - const maxEffectiveReleaseTag: ReleaseTag = symbolMetadata - ? symbolMetadata.maxEffectiveReleaseTag - : ReleaseTag.None; - - if (this._shouldIncludeReleaseTag(maxEffectiveReleaseTag, dtsKind)) { - DtsEmitHelpers.emitImport(writer, entity, astImport); - } + DtsEmitHelpers.emitImport(writer, entity, astImport); } } @@ -211,6 +205,17 @@ export class DtsRollupGenerator { ); } + // If the entity's declaration won't be included, then neither should the namespace export it + // This fixes the issue encountered here: https://github.com/microsoft/rushstack/issues/2791 + const exportedSymbolMetadata: SymbolMetadata | undefined = + collector.tryFetchMetadataForAstEntity(exportedEntity); + const exportedMaxEffectiveReleaseTag: ReleaseTag = exportedSymbolMetadata + ? exportedSymbolMetadata.maxEffectiveReleaseTag + : ReleaseTag.None; + if (!this._shouldIncludeReleaseTag(exportedMaxEffectiveReleaseTag, dtsKind)) { + continue; + } + if (collectorEntity.nameForEmit === exportedName) { exportClauses.push(collectorEntity.nameForEmit); } else { From de09d37c692f7ada9f1226fb3d05a957ae77a17f Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Wed, 14 May 2025 23:24:35 +0200 Subject: [PATCH 2/2] chore: improve warnings --- .../src/generators/ApiModelGenerator.ts | 74 +++++++++---------- packages/discord.js/tsdoc.json | 12 +++ 2 files changed, 49 insertions(+), 37 deletions(-) create mode 100644 packages/discord.js/tsdoc.json diff --git a/packages/api-extractor/src/generators/ApiModelGenerator.ts b/packages/api-extractor/src/generators/ApiModelGenerator.ts index 0caf69444dbc..20478e9710de 100644 --- a/packages/api-extractor/src/generators/ApiModelGenerator.ts +++ b/packages/api-extractor/src/generators/ApiModelGenerator.ts @@ -627,7 +627,7 @@ export class ApiModelGenerator { if (!docComment && parent) { this._collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.DjsMissingJSDoc, - `The symbol ${parentApiItem.displayName}#constrcutor() has no matching jsdoc equivalent in the JavaScript source files.`, + `The constructor ${parentApiItem.displayName}() has no matching jsdoc equivalent in the JavaScript source files.`, astDeclaration, ); } @@ -726,7 +726,7 @@ export class ApiModelGenerator { if (!docComment && parent) { this._collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.DjsMissingJSDoc, - `The symbol ${name} has no matching jsdoc equivalent in the JavaScript source files.`, + `The class ${name} has no matching jsdoc equivalent in the JavaScript source files.`, astDeclaration, ); } @@ -805,7 +805,7 @@ export class ApiModelGenerator { if (!docComment && parent) { this._collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.DjsMissingJSDoc, - `The symbol ${parentApiItem.displayName}#constructor() has no matching jsdoc equivalent in the JavaScript source files.`, + `The constructor signature ${parentApiItem.displayName}() has no matching jsdoc equivalent in the JavaScript source files.`, astDeclaration, ); } @@ -961,7 +961,7 @@ export class ApiModelGenerator { if (!docComment && parent) { this._collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.DjsMissingJSDoc, - `The symbol ${name}() has no matching jsdoc equivalent in the JavaScript source files.`, + `The function ${name}() has no matching jsdoc equivalent in the JavaScript source files.`, astDeclaration, ); } @@ -1092,7 +1092,7 @@ export class ApiModelGenerator { if (!docComment && parent) { this._collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.DjsMissingJSDoc, - `The symbol ${name} has no matching jsdoc equivalent in the JavaScript source files.`, + `The interface ${name} has no matching jsdoc equivalent in the JavaScript source files.`, astDeclaration, ); } @@ -1182,7 +1182,7 @@ export class ApiModelGenerator { if (!docComment && parent) { this._collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.DjsMissingJSDoc, - `The symbol ${parentApiItem.displayName}#${name}() has no matching jsdoc equivalent in the JavaScript source files.`, + `The method ${parentApiItem.displayName}#${name}() has no matching jsdoc equivalent in the JavaScript source files.`, astDeclaration, ); } @@ -1221,7 +1221,7 @@ export class ApiModelGenerator { this._collector.messageRouter.addAnalyzerIssueForPosition( ExtractorMessageId.DjsMissingTypeScriptType, - `The JSDoc comment for ${parentApiItem.displayName}#${name}() has no matching type equivalent in the TypeScript declaration file.`, + `The JSDoc comment for method ${parentApiItem.displayName}#${name}() has no matching type equivalent in the TypeScript declaration file.`, this._mainSourceFile!, 0, ); @@ -1294,7 +1294,7 @@ export class ApiModelGenerator { if (!docComment && parent) { this._collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.DjsMissingJSDoc, - `The symbol ${parentApiItem.displayName}#${name}() has no matching jsdoc equivalent in the JavaScript source files.`, + `The method signature ${parentApiItem.displayName}#${name}() has no matching jsdoc equivalent in the JavaScript source files.`, astDeclaration, ); } @@ -1320,7 +1320,7 @@ export class ApiModelGenerator { } else if (jsDoc) { this._collector.messageRouter.addAnalyzerIssueForPosition( ExtractorMessageId.DjsMissingTypeScriptType, - `The JSDoc comment for ${parentApiItem.displayName}#${name}() has no matching type equivalent in the TypeScript declaration file.`, + `The JSDoc comment for method signature ${parentApiItem.displayName}#${name}() has no matching type equivalent in the TypeScript declaration file.`, this._mainSourceFile!, 0, ); @@ -1366,7 +1366,8 @@ export class ApiModelGenerator { private _processApiProperty(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void { const { name, parentApiItem } = context; const parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | DocgenTypedefJson | undefined; - const jsDoc = parent?.props?.find((prop) => prop.name === name); + const inherited = parent && 'extends' in parent ? this._isInherited(parent, name, parentApiItem.kind) : undefined; + const jsDoc = parent?.props?.find((prop) => prop.name === name) ?? inherited; const isStatic: boolean = astDeclaration ? (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0 : parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface @@ -1376,11 +1377,7 @@ export class ApiModelGenerator { let apiProperty: ApiProperty | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiProperty; - if ( - apiProperty === undefined && - (astDeclaration || - !this._isInherited(parent as DocgenClassJson | DocgenInterfaceJson, jsDoc!, parentApiItem.kind)) - ) { + if (apiProperty === undefined && (astDeclaration || !inherited)) { if (astDeclaration) { const declaration: ts.Declaration = astDeclaration.declaration; const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; @@ -1424,7 +1421,7 @@ export class ApiModelGenerator { if (!docComment && parent) { this._collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.DjsMissingJSDoc, - `The symbol ${parentApiItem.displayName}#${name} has no matching jsdoc equivalent in the JavaScript source files.`, + `The property ${parentApiItem.displayName}#${name} has no matching jsdoc equivalent in the JavaScript source files.`, astDeclaration, ); } @@ -1455,7 +1452,7 @@ export class ApiModelGenerator { } else if (parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface) { this._collector.messageRouter.addAnalyzerIssueForPosition( ExtractorMessageId.DjsMissingTypeScriptType, - `The JSDoc comment for ${parentApiItem.displayName}#${name} has no matching type equivalent in the TypeScript declaration file.`, + `The JSDoc comment for property ${parentApiItem.displayName}#${name} has no matching type equivalent in the TypeScript declaration file.`, this._mainSourceFile!, 0, ); @@ -1484,11 +1481,13 @@ export class ApiModelGenerator { containerKey, ) as ApiPropertySignature; const parent = context.parentDocgenJson as DocgenInterfaceJson | DocgenPropertyJson | DocgenTypedefJson | undefined; - const jsDoc = parent?.props?.find((prop) => prop.name === name); + const inherited = parent && 'extends' in parent ? this._isInherited(parent, name, parentApiItem.kind) : undefined; + const jsDoc = parent?.props?.find((prop) => prop.name === name) ?? inherited; if ( apiPropertySignature === undefined && - (astDeclaration || !this._isInherited(parent as DocgenInterfaceJson, jsDoc!, parentApiItem.kind)) + (astDeclaration || !inherited) && + parentApiItem.kind !== ApiItemKind.Class ) { if (astDeclaration) { const propertySignature: ts.PropertySignature = astDeclaration.declaration as ts.PropertySignature; @@ -1517,7 +1516,7 @@ export class ApiModelGenerator { if (!docComment && parent) { this._collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.DjsMissingJSDoc, - `The symbol ${parentApiItem.displayName}#${name} has no matching jsdoc equivalent in the JavaScript source files.`, + `The property signature ${parentApiItem.displayName}#${name} has no matching jsdoc equivalent in the JavaScript source files.`, astDeclaration, ); } @@ -1539,10 +1538,10 @@ export class ApiModelGenerator { fileLine: jsDoc && 'meta' in jsDoc ? jsDoc.meta.line : sourceLocation.sourceFileLine, fileColumn: sourceLocation.sourceFileColumn, }); - } else if (parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface) { + } else if (parentApiItem.kind === ApiItemKind.Interface) { this._collector.messageRouter.addAnalyzerIssueForPosition( ExtractorMessageId.DjsMissingTypeScriptType, - `The JSDoc comment for ${parentApiItem.displayName}#${name} has no matching type equivalent in the TypeScript declaration file.`, + `The JSDoc comment for property signature ${parentApiItem.displayName}#${name} has no matching type equivalent in the TypeScript declaration file.`, this._mainSourceFile!, 0, ); @@ -1610,7 +1609,7 @@ export class ApiModelGenerator { if (!docComment && parent) { this._collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.DjsMissingJSDoc, - `The symbol ${name} has no matching jsdoc equivalent in the JavaScript source files.`, + `The type alias ${name} has no matching jsdoc equivalent in the JavaScript source files.`, astDeclaration, ); } @@ -1848,20 +1847,19 @@ export class ApiModelGenerator { private _isInherited( container: DocgenClassJson | DocgenInterfaceJson, - jsDoc: DocgenParamJson | DocgenPropertyJson, + propertyName: string, containerKind: ApiItemKind, - ): boolean { + ): DocgenPropertyJson | undefined { switch (containerKind) { case ApiItemKind.Class: { const token = (container as DocgenClassJson).extends; const parentName = Array.isArray(token) ? token[0]?.[0]?.[0] : token?.types?.[0]?.[0]?.[0]; const parentJson = this._jsDocJson?.classes.find((clas) => clas.name === parentName); if (parentJson) { - if (parentJson.props?.find((prop) => prop.name === jsDoc.name)) { - return true; - } else { - return this._isInherited(parentJson, jsDoc, containerKind); - } + return ( + parentJson.props?.find((prop) => prop.name === propertyName) ?? + this._isInherited(parentJson, propertyName, containerKind) + ); } break; @@ -1873,13 +1871,15 @@ export class ApiModelGenerator { const parentJsons = parentNames?.map((name) => this._jsDocJson?.interfaces.find((inter) => inter.name === name), ); + if (propertyName === 'content') console.log(container.name, parentNames, parentJsons); if (parentJsons?.length) { for (const parentJson of parentJsons) { - if ( - parentJson?.props?.find((prop) => prop.name === jsDoc.name) || - this._isInherited(parentJson as DocgenInterfaceJson, jsDoc, containerKind) - ) { - return true; + const result = + parentJson?.props?.find((prop) => prop.name === propertyName) ?? + this._isInherited(parentJson as DocgenInterfaceJson, propertyName, containerKind); + + if (result) { + return result; } } } @@ -1888,10 +1888,10 @@ export class ApiModelGenerator { } default: - console.log(`Unexpected parent of type ${containerKind} (${container.name}) of ${jsDoc?.name} `); + console.log(`Unexpected parent of type ${containerKind} (${container.name}) of ${propertyName} `); } - return false; + return undefined; } private _isReadonly(astDeclaration: AstDeclaration): boolean { diff --git a/packages/discord.js/tsdoc.json b/packages/discord.js/tsdoc.json new file mode 100644 index 000000000000..8001b9ed1bba --- /dev/null +++ b/packages/discord.js/tsdoc.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["@discordjs/api-extractor/extends/tsdoc-base.json"], + + "tagDefinitions": [ + { + "tagName": "@unstable", + "syntaxKind": "modifier" + } + ], + "supportForTags": { "@unstable": true } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy