Skip to content

Commit 98841f5

Browse files
committed
Fix validation.notDocumentated signature logic
Resolves #1895
1 parent 97a5a9a commit 98841f5

File tree

14 files changed

+192
-36
lines changed

14 files changed

+192
-36
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
### Bug Fixes
44

55
- Fixed missing comments on `@enum` style enum members defined in declaration files, #1880.
6+
- Fixed `--validation.notDocumented` warnings for functions/methods, #1895.
67
- Search results will no longer include random items when the search bar is empty, #1881.
8+
- Comments on overloaded constructors will now be detected in the same way that overloaded functions/methods are.
79

810
### Thanks!
911

src/lib/converter/plugins/CommentPlugin.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,11 @@ export class CommentPlugin extends ConverterComponent {
175175
reflection: Reflection,
176176
node?: ts.Node
177177
) {
178-
if (reflection.kindOf(ReflectionKind.FunctionOrMethod)) {
178+
if (
179+
reflection.kindOf(
180+
ReflectionKind.FunctionOrMethod | ReflectionKind.Constructor
181+
)
182+
) {
179183
// We only want a comment on functions/methods if this is a set of overloaded functions.
180184
// In that case, TypeDoc lets you put a comment on the implementation, and will copy it over to
181185
// the available signatures so that you can avoid documenting things multiple times.
@@ -184,15 +188,18 @@ export class CommentPlugin extends ConverterComponent {
184188
let specialOverloadCase = false;
185189
if (
186190
node &&
187-
(ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node))
191+
(ts.isFunctionDeclaration(node) ||
192+
ts.isMethodDeclaration(node) ||
193+
ts.isConstructorDeclaration(node))
188194
) {
189195
const symbol =
190196
node.name && context.checker.getSymbolAtLocation(node.name);
191197
if (symbol && symbol.declarations) {
192198
const declarations = symbol.declarations.filter(
193199
(d) =>
194200
ts.isFunctionDeclaration(d) ||
195-
ts.isMethodDeclaration(d)
201+
ts.isMethodDeclaration(d) ||
202+
ts.isConstructorDeclaration(d)
196203
);
197204
if (
198205
declarations.length > 1 &&

src/lib/converter/symbols.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -509,10 +509,12 @@ function convertClassOrInterface(
509509
reflection
510510
);
511511
reflectionContext.addChild(constructMember);
512-
// The symbol is already taken by the class.
513-
context.registerReflection(constructMember, undefined);
514512

515513
const ctors = staticType.getConstructSignatures();
514+
context.registerReflection(
515+
constructMember,
516+
ctors?.[0]?.declaration?.symbol
517+
);
516518

517519
// Modifiers are the same for all constructors
518520
if (ctors.length && ctors[0].declaration) {

src/lib/models/reflections/abstract.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,8 @@ export abstract class Reflection {
364364
}
365365

366366
/**
367-
* Return the full name of this reflection.
367+
* Return the full name of this reflection. Intended for use in debugging. For log messages
368+
* intended to be displayed to the user for them to fix, prefer {@link getFriendlyFullName} instead.
368369
*
369370
* The full name contains the name of this reflection and the names of all parent reflections.
370371
*
@@ -379,6 +380,29 @@ export abstract class Reflection {
379380
}
380381
}
381382

383+
/**
384+
* Return the full name of this reflection, with signature names dropped if possible without
385+
* introducing ambiguity in the name.
386+
*/
387+
getFriendlyFullName(): string {
388+
if (this.parent && !this.parent.isProject()) {
389+
if (
390+
this.kindOf(
391+
ReflectionKind.ConstructorSignature |
392+
ReflectionKind.CallSignature |
393+
ReflectionKind.GetSignature |
394+
ReflectionKind.SetSignature
395+
)
396+
) {
397+
return this.parent.getFriendlyFullName();
398+
}
399+
400+
return this.parent.getFriendlyFullName() + "." + this.name;
401+
} else {
402+
return this.name;
403+
}
404+
}
405+
382406
/**
383407
* Set a flag on this reflection.
384408
*/

src/lib/output/plugins/MarkedLinksPlugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export class MarkedLinksPlugin extends ContextAwareRendererComponent {
135135
}
136136
} else {
137137
const fullName = (this.reflection ||
138-
this.project)!.getFullName();
138+
this.project)!.getFriendlyFullName();
139139
this.warnings.push(`In ${fullName}: ${original}`);
140140
return original;
141141
}

src/lib/utils/options/sources/typedoc.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,7 @@ export function addTypeDocOptions(options: Pick<Options, "addDeclaration">) {
372372
"Interface",
373373
"Property",
374374
"Method",
375-
"GetSignature",
376-
"SetSignature",
375+
"Accessor",
377376
"TypeAlias",
378377
],
379378
});

src/lib/validation/documentation.ts

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,66 @@
11
import * as path from "path";
22
import * as ts from "typescript";
3-
import { ProjectReflection, ReflectionKind } from "../models";
3+
import {
4+
DeclarationReflection,
5+
ProjectReflection,
6+
ReflectionKind,
7+
SignatureReflection,
8+
} from "../models";
49
import { Logger, normalizePath } from "../utils";
10+
import { removeFlag } from "../utils/enum";
511

612
export function validateDocumentation(
713
project: ProjectReflection,
814
logger: Logger,
915
requiredToBeDocumented: readonly (keyof typeof ReflectionKind)[]
1016
): void {
11-
const kinds = requiredToBeDocumented.reduce(
12-
(prev, cur) => (prev |= ReflectionKind[cur]),
17+
let kinds = requiredToBeDocumented.reduce(
18+
(prev, cur) => prev | ReflectionKind[cur],
1319
0
1420
);
1521

22+
// Functions, Constructors, and Accessors never have comments directly on them.
23+
// If they are required to be documented, what's really required is that their
24+
// contained signatures have a comment.
25+
if (kinds & ReflectionKind.FunctionOrMethod) {
26+
kinds |= ReflectionKind.CallSignature;
27+
kinds = removeFlag(kinds, ReflectionKind.FunctionOrMethod);
28+
}
29+
if (kinds & ReflectionKind.Constructor) {
30+
kinds |= ReflectionKind.ConstructorSignature;
31+
kinds = removeFlag(kinds, ReflectionKind.Constructor);
32+
}
33+
if (kinds & ReflectionKind.Accessor) {
34+
kinds |= ReflectionKind.GetSignature | ReflectionKind.SetSignature;
35+
kinds = removeFlag(kinds, ReflectionKind.Accessor);
36+
}
37+
1638
for (const ref of project.getReflectionsByKind(kinds)) {
17-
const symbol = project.getSymbolFromReflection(ref);
18-
if (!ref.comment && symbol?.declarations) {
19-
const decl = symbol.declarations[0];
39+
let symbol = project.getSymbolFromReflection(ref);
40+
let index = 0;
41+
42+
// Signatures don't have symbols associated with them, so get the parent and then
43+
// maybe also adjust the declaration index that we care about.
44+
if (!symbol && ref.kindOf(ReflectionKind.SomeSignature)) {
45+
symbol = project.getSymbolFromReflection(ref.parent!);
46+
47+
const parentIndex = (
48+
ref.parent as DeclarationReflection
49+
).signatures?.indexOf(ref as SignatureReflection);
50+
if (parentIndex) {
51+
index = parentIndex;
52+
}
53+
}
54+
55+
const decl = symbol?.declarations?.[index];
56+
57+
if (!ref.hasComment() && decl) {
2058
const sourceFile = decl.getSourceFile();
59+
60+
if (sourceFile.fileName.includes("node_modules")) {
61+
continue;
62+
}
63+
2164
const { line } = ts.getLineAndCharacterOfPosition(
2265
sourceFile,
2366
decl.getStart()
@@ -26,13 +69,9 @@ export function validateDocumentation(
2669
path.relative(process.cwd(), sourceFile.fileName)
2770
);
2871

29-
if (file.includes("node_modules")) {
30-
continue;
31-
}
32-
3372
const loc = `${file}:${line + 1}`;
3473
logger.warn(
35-
`${ref.name}, defined at ${loc}, does not have any documentation.`
74+
`${ref.getFriendlyFullName()}, defined at ${loc}, does not have any documentation.`
3675
);
3776
}
3877
}

src/test/TestLogger.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Logger, LogLevel } from "../lib/utils";
2+
import { deepStrictEqual as equal, fail } from "assert";
3+
4+
const levelMap: Record<LogLevel, string> = {
5+
[LogLevel.Error]: "error: ",
6+
[LogLevel.Warn]: "warn: ",
7+
[LogLevel.Info]: "info: ",
8+
[LogLevel.Verbose]: "debug: ",
9+
};
10+
11+
export class TestLogger extends Logger {
12+
messages: string[] = [];
13+
14+
expectMessage(message: string) {
15+
const index = this.messages.indexOf(message);
16+
if (index === -1) {
17+
const messages = this.messages.join("\n\t") || "(none logged)";
18+
fail(
19+
`Expected "${message}" to be logged. The logged messages were:\n\t${messages}`
20+
);
21+
}
22+
this.messages.splice(index, 1);
23+
}
24+
25+
expectNoOtherMessages() {
26+
equal(this.messages, [], "Expected no other messages to be logged.");
27+
}
28+
29+
override log(message: string, level: LogLevel): void {
30+
this.messages.push(levelMap[level] + message);
31+
}
32+
}

src/test/converter/exports/mod.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ export { a as c } from "./mod";
2020
/**
2121
* Will not be re-exported from export.ts using export * from...
2222
*/
23-
export default function () {
24-
console.log("Default");
25-
}
23+
export default function () {}
2624

2725
/**
2826
* This is annotated with the hidden tag and will therefore not be included in the generated documentation.

src/test/converter2/issues/gh1547.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,5 @@ export class Test {
1919
*
2020
* @param things - Array of things or a thing.
2121
*/
22-
log_thing(things: ValueOrArray<Things>): void {
23-
console.log(things);
24-
}
22+
log_thing(things: ValueOrArray<Things>): void {}
2523
}

0 commit comments

Comments
 (0)