UNPKG

typedoc

Version:

Create api documentation for TypeScript projects.

92 lines (91 loc) 4.58 kB
import { DeclarationReflection, ReflectionKind, ReflectionType, } from "../models/index.js"; import { i18n, removeFlag } from "#utils"; export function validateDocumentation(project, logger, requiredToBeDocumented, intentionallyNotDocumented, packagesRequiringDocumentation) { let kinds = requiredToBeDocumented.reduce((prev, cur) => prev | ReflectionKind[cur], 0); // Functions, Constructors, and Accessors never have comments directly on them. // If they are required to be documented, what's really required is that their // contained signatures have a comment. if (kinds & ReflectionKind.FunctionOrMethod) { kinds |= ReflectionKind.CallSignature; kinds = removeFlag(kinds, ReflectionKind.FunctionOrMethod); } if (kinds & ReflectionKind.Constructor) { kinds |= ReflectionKind.ConstructorSignature; kinds = removeFlag(kinds, ReflectionKind.Constructor); } if (kinds & ReflectionKind.Accessor) { kinds |= ReflectionKind.GetSignature | ReflectionKind.SetSignature; kinds = removeFlag(kinds, ReflectionKind.Accessor); } const toProcess = project.getReflectionsByKind(kinds); const seen = new Set(); const intentionalUsage = new Set(); outer: while (toProcess.length) { const ref = toProcess.shift(); if (seen.has(ref)) continue; seen.add(ref); // If inside a parameter, we shouldn't care. Callback parameter's values don't get deeply documented. let r = ref.parent; while (r) { if (r.kindOf(ReflectionKind.Parameter)) { continue outer; } r = r.parent; } // Type aliases own their comments, even if they're function-likes. // So if we're a type literal owned by a type alias, don't do anything. if (ref.kindOf(ReflectionKind.TypeLiteral) && ref.parent?.kindOf(ReflectionKind.TypeAlias)) { toProcess.push(ref.parent); continue; } // Call signatures are considered documented if they have a comment directly, or their // container has a comment and they are directly within a type literal belonging to that container. if (ref.kindOf(ReflectionKind.CallSignature) && ref.parent?.kindOf(ReflectionKind.TypeLiteral)) { toProcess.push(ref.parent.parent); continue; } // Construct signatures are considered documented if they are directly within a documented type alias. if (ref.kindOf(ReflectionKind.ConstructorSignature) && ref.parent?.parent?.kindOf(ReflectionKind.TypeAlias)) { toProcess.push(ref.parent.parent); continue; } if (ref instanceof DeclarationReflection) { const signatures = ref.type instanceof ReflectionType ? ref.type.declaration.getNonIndexSignatures() : ref.getNonIndexSignatures(); if (signatures.length) { // We've been asked to validate this reflection, so we should validate that // signatures all have comments toProcess.push(...signatures); if (ref.kindOf(ReflectionKind.SignatureContainer)) { // Comments belong to each signature, and will not be included on this object. continue; } } } const symbolId = project.getSymbolIdFromReflection(ref); // #2644, signatures may be documented by their parent reflection. const hasComment = ref.hasComment() || (ref.kindOf(ReflectionKind.SomeSignature) && ref.parent?.hasComment()); if (!hasComment && symbolId) { if (!packagesRequiringDocumentation.includes(symbolId.packageName)) { continue; } const intentionalIndex = intentionallyNotDocumented.indexOf(ref.getFriendlyFullName()); if (intentionalIndex !== -1) { intentionalUsage.add(intentionalIndex); continue; } logger.warn(i18n.reflection_0_kind_1_defined_in_2_does_not_have_any_documentation(ref.getFriendlyFullName(), ReflectionKind[ref.kind], `${symbolId.packageName}/${symbolId.packagePath}`)); } } const unusedIntentional = intentionallyNotDocumented.filter((_, i) => !intentionalUsage.has(i)); if (unusedIntentional.length) { logger.warn(i18n.invalid_intentionally_not_documented_names_0(unusedIntentional.join("\n\t"))); } }