Skip to content

Commit 59b11bd

Browse files
committed
Use parent comment class when reviving
Resolves #2622
1 parent 794d4ae commit 59b11bd

File tree

3 files changed

+171
-100
lines changed

3 files changed

+171
-100
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
### Bug Fixes
44

55
- Constructor parameters which share a name with a property on a parent class will no longer inherit the comment on the parent class, #2636.
6+
- Packages mode will now attempt to use the comment declared in the comment class for inherited members, #2622.
67

78
## v0.26.4 (2024-07-10)
89

src/lib/converter/plugins/ImplementsPlugin.ts

Lines changed: 127 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import type { TranslatedString } from "../../internationalization/internationali
2525
export class ImplementsPlugin extends ConverterComponent {
2626
private resolved = new WeakSet<Reflection>();
2727
private postponed = new WeakMap<Reflection, Set<DeclarationReflection>>();
28+
private revivingSerialized = false;
2829

2930
/**
3031
* Create a new ImplementsPlugin instance.
@@ -44,7 +45,7 @@ export class ImplementsPlugin extends ConverterComponent {
4445
this.onSignature.bind(this),
4546
1000,
4647
);
47-
this.application.on(ApplicationEvents.REVIVE, this.resolve.bind(this));
48+
this.application.on(ApplicationEvents.REVIVE, this.onRevive.bind(this));
4849
}
4950

5051
/**
@@ -55,7 +56,7 @@ export class ImplementsPlugin extends ConverterComponent {
5556
classReflection: DeclarationReflection,
5657
interfaceReflection: DeclarationReflection,
5758
) {
58-
handleInheritedComments(classReflection, interfaceReflection);
59+
this.handleInheritedComments(classReflection, interfaceReflection);
5960
if (!interfaceReflection.children) {
6061
return;
6162
}
@@ -109,7 +110,7 @@ export class ImplementsPlugin extends ConverterComponent {
109110
}
110111
}
111112

112-
handleInheritedComments(classMember, interfaceMember);
113+
this.handleInheritedComments(classMember, interfaceMember);
113114
});
114115
}
115116

@@ -130,7 +131,7 @@ export class ImplementsPlugin extends ConverterComponent {
130131
);
131132

132133
for (const parent of extendedTypes) {
133-
handleInheritedComments(reflection, parent.reflection);
134+
this.handleInheritedComments(reflection, parent.reflection);
134135

135136
for (const parentMember of parent.reflection.children ?? []) {
136137
const child = findMatchingMember(parentMember, reflection);
@@ -157,7 +158,7 @@ export class ImplementsPlugin extends ConverterComponent {
157158
project,
158159
);
159160

160-
handleInheritedComments(child, parentMember);
161+
this.handleInheritedComments(child, parentMember);
161162
}
162163
}
163164
}
@@ -167,6 +168,12 @@ export class ImplementsPlugin extends ConverterComponent {
167168
this.resolve(context.project);
168169
}
169170

171+
private onRevive(project: ProjectReflection) {
172+
this.revivingSerialized = true;
173+
this.resolve(project);
174+
this.revivingSerialized = false;
175+
}
176+
170177
private resolve(project: ProjectReflection) {
171178
for (const id in project.reflections) {
172179
const refl = project.reflections[id];
@@ -362,6 +369,105 @@ export class ImplementsPlugin extends ConverterComponent {
362369
}
363370
}
364371
}
372+
373+
/**
374+
* Responsible for copying comments from "parent" reflections defined
375+
* in either a base class or implemented interface to the child class.
376+
*/
377+
private handleInheritedComments(
378+
child: DeclarationReflection,
379+
parent: DeclarationReflection,
380+
) {
381+
this.copyComment(child, parent);
382+
383+
if (
384+
parent.kindOf(ReflectionKind.Property) &&
385+
child.kindOf(ReflectionKind.Accessor)
386+
) {
387+
if (child.getSignature) {
388+
this.copyComment(child.getSignature, parent);
389+
child.getSignature.implementationOf = child.implementationOf;
390+
}
391+
if (child.setSignature) {
392+
this.copyComment(child.setSignature, parent);
393+
child.setSignature.implementationOf = child.implementationOf;
394+
}
395+
}
396+
if (
397+
parent.kindOf(ReflectionKind.Accessor) &&
398+
child.kindOf(ReflectionKind.Accessor)
399+
) {
400+
if (parent.getSignature && child.getSignature) {
401+
this.copyComment(child.getSignature, parent.getSignature);
402+
}
403+
if (parent.setSignature && child.setSignature) {
404+
this.copyComment(child.setSignature, parent.setSignature);
405+
}
406+
}
407+
408+
if (
409+
parent.kindOf(ReflectionKind.FunctionOrMethod) &&
410+
parent.signatures &&
411+
child.signatures
412+
) {
413+
for (const [cs, ps] of zip(child.signatures, parent.signatures)) {
414+
this.copyComment(cs, ps);
415+
}
416+
} else if (
417+
parent.kindOf(ReflectionKind.Property) &&
418+
parent.type instanceof ReflectionType &&
419+
parent.type.declaration.signatures &&
420+
child.signatures
421+
) {
422+
for (const [cs, ps] of zip(
423+
child.signatures,
424+
parent.type.declaration.signatures,
425+
)) {
426+
this.copyComment(cs, ps);
427+
}
428+
}
429+
}
430+
431+
/**
432+
* Copy the comment of the source reflection to the target reflection with a JSDoc style copy
433+
* function. The TSDoc copy function is in the InheritDocPlugin.
434+
*/
435+
private copyComment(target: Reflection, source: Reflection) {
436+
if (!shouldCopyComment(target, source, this.revivingSerialized)) {
437+
return;
438+
}
439+
440+
target.comment = source.comment!.clone();
441+
442+
if (
443+
target instanceof DeclarationReflection &&
444+
source instanceof DeclarationReflection
445+
) {
446+
for (const [tt, ts] of zip(
447+
target.typeParameters || [],
448+
source.typeParameters || [],
449+
)) {
450+
this.copyComment(tt, ts);
451+
}
452+
}
453+
if (
454+
target instanceof SignatureReflection &&
455+
source instanceof SignatureReflection
456+
) {
457+
for (const [tt, ts] of zip(
458+
target.typeParameters || [],
459+
source.typeParameters || [],
460+
)) {
461+
this.copyComment(tt, ts);
462+
}
463+
for (const [pt, ps] of zip(
464+
target.parameters || [],
465+
source.parameters || [],
466+
)) {
467+
this.copyComment(pt, ps);
468+
}
469+
}
470+
}
365471
}
366472

367473
function constructorInheritance(
@@ -419,7 +525,9 @@ function createLink(
419525
}
420526

421527
// Intentionally create broken links here. These will be replaced with real links during
422-
// resolution if we can do so.
528+
// resolution if we can do so. We create broken links rather than real links because in the
529+
// case of an inherited symbol, we'll end up referencing a single symbol ID rather than one
530+
// for each class.
423531
function link(
424532
target: DeclarationReflection | SignatureReflection | undefined,
425533
) {
@@ -448,111 +556,30 @@ function createLink(
448556
}
449557
}
450558

451-
/**
452-
* Responsible for copying comments from "parent" reflections defined
453-
* in either a base class or implemented interface to the child class.
454-
*/
455-
function handleInheritedComments(
456-
child: DeclarationReflection,
457-
parent: DeclarationReflection,
559+
function shouldCopyComment(
560+
target: Reflection,
561+
source: Reflection,
562+
revivingSerialized: boolean,
458563
) {
459-
copyComment(child, parent);
460-
461-
if (
462-
parent.kindOf(ReflectionKind.Property) &&
463-
child.kindOf(ReflectionKind.Accessor)
464-
) {
465-
if (child.getSignature) {
466-
copyComment(child.getSignature, parent);
467-
child.getSignature.implementationOf = child.implementationOf;
468-
}
469-
if (child.setSignature) {
470-
copyComment(child.setSignature, parent);
471-
child.setSignature.implementationOf = child.implementationOf;
472-
}
473-
}
474-
if (
475-
parent.kindOf(ReflectionKind.Accessor) &&
476-
child.kindOf(ReflectionKind.Accessor)
477-
) {
478-
if (parent.getSignature && child.getSignature) {
479-
copyComment(child.getSignature, parent.getSignature);
480-
}
481-
if (parent.setSignature && child.setSignature) {
482-
copyComment(child.setSignature, parent.setSignature);
483-
}
564+
if (!source.comment) {
565+
return false;
484566
}
485567

486-
if (
487-
parent.kindOf(ReflectionKind.FunctionOrMethod) &&
488-
parent.signatures &&
489-
child.signatures
490-
) {
491-
for (const [cs, ps] of zip(child.signatures, parent.signatures)) {
492-
copyComment(cs, ps);
493-
}
494-
} else if (
495-
parent.kindOf(ReflectionKind.Property) &&
496-
parent.type instanceof ReflectionType &&
497-
parent.type.declaration.signatures &&
498-
child.signatures
499-
) {
500-
for (const [cs, ps] of zip(
501-
child.signatures,
502-
parent.type.declaration.signatures,
503-
)) {
504-
copyComment(cs, ps);
568+
if (target.comment) {
569+
// If we're reviving, then the revived project might have a better comment
570+
// on source, so copy it.
571+
if (revivingSerialized && source.comment.similarTo(target.comment)) {
572+
return true;
505573
}
506-
}
507-
}
508574

509-
/**
510-
* Copy the comment of the source reflection to the target reflection with a JSDoc style copy
511-
* function. The TSDoc copy function is in the InheritDocPlugin.
512-
*/
513-
function copyComment(target: Reflection, source: Reflection) {
514-
if (target.comment) {
515575
// We might still want to copy, if the child has a JSDoc style inheritDoc tag.
516576
const tag = target.comment.getTag("@inheritDoc");
517577
if (!tag || tag.name) {
518-
return;
578+
return false;
519579
}
520580
}
521581

522-
if (!source.comment) {
523-
return;
524-
}
525-
526-
target.comment = source.comment.clone();
527-
528-
if (
529-
target instanceof DeclarationReflection &&
530-
source instanceof DeclarationReflection
531-
) {
532-
for (const [tt, ts] of zip(
533-
target.typeParameters || [],
534-
source.typeParameters || [],
535-
)) {
536-
copyComment(tt, ts);
537-
}
538-
}
539-
if (
540-
target instanceof SignatureReflection &&
541-
source instanceof SignatureReflection
542-
) {
543-
for (const [tt, ts] of zip(
544-
target.typeParameters || [],
545-
source.typeParameters || [],
546-
)) {
547-
copyComment(tt, ts);
548-
}
549-
for (const [pt, ps] of zip(
550-
target.parameters || [],
551-
source.parameters || [],
552-
)) {
553-
copyComment(pt, ps);
554-
}
555-
}
582+
return true;
556583
}
557584

558585
function findMatchingMember(

src/lib/models/comments/comment.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,20 @@ export class CommentTag {
102102
this.content = text;
103103
}
104104

105+
/**
106+
* Checks if this block tag is roughly equal to the other tag.
107+
* This isn't exactly equal, but just "roughly equal" by the tag
108+
* text.
109+
*/
110+
similarTo(other: CommentTag) {
111+
return (
112+
this.tag === other.tag &&
113+
this.name === other.tag &&
114+
Comment.combineDisplayParts(this.content) ===
115+
Comment.combineDisplayParts(other.content)
116+
);
117+
}
118+
105119
clone(): CommentTag {
106120
const tag = new CommentTag(
107121
this.tag,
@@ -420,6 +434,35 @@ export class Comment {
420434
extractLabelTag(this);
421435
}
422436

437+
/**
438+
* Checks if this comment is roughly equal to the other comment.
439+
* This isn't exactly equal, but just "roughly equal" by the comment
440+
* text.
441+
*/
442+
similarTo(other: Comment): boolean {
443+
if (
444+
Comment.combineDisplayParts(this.summary) !==
445+
Comment.combineDisplayParts(other.summary)
446+
) {
447+
return false;
448+
}
449+
450+
// Ignore modifier tags, as they could cause false negatives
451+
// if a cascaded modifier tag is present in one comment but not the other.
452+
453+
if (this.blockTags.length !== other.blockTags.length) {
454+
return false;
455+
}
456+
457+
for (let i = 0; i < this.blockTags.length; ++i) {
458+
if (!this.blockTags[i].similarTo(other.blockTags[i])) {
459+
return false;
460+
}
461+
}
462+
463+
return true;
464+
}
465+
423466
/**
424467
* Create a deep clone of this comment.
425468
*/

0 commit comments

Comments
 (0)