Skip to content

Commit

Permalink
fix: Postpone resolution of inherited classes until their parents hav…
Browse files Browse the repository at this point in the history
…e been resolved

Actually fixes #1580 this time!
  • Loading branch information
Gerrit0 committed Jun 26, 2021
1 parent 12236f3 commit fc920bd
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 80 deletions.
186 changes: 108 additions & 78 deletions src/lib/converter/plugins/ImplementsPlugin.ts
Expand Up @@ -6,7 +6,7 @@ import {
SignatureReflection,
} from "../../models/reflections/index";
import { ReferenceType, Type } from "../../models/types/index";
import { zip } from "../../utils/array";
import { filterMap, zip } from "../../utils/array";
import { Component, ConverterComponent } from "../components";
import { Context } from "../context";
import { Converter } from "../converter";
Expand All @@ -18,6 +18,9 @@ import { copyComment } from "../utils/reflections";
*/
@Component({ name: "implements" })
export class ImplementsPlugin extends ConverterComponent {
private resolved = new WeakSet<Reflection>();
private postponed = new WeakMap<Reflection, Set<DeclarationReflection>>();

/**
* Create a new ImplementsPlugin instance.
*/
Expand Down Expand Up @@ -53,101 +56,96 @@ export class ImplementsPlugin extends ConverterComponent {
return;
}

interfaceReflection.children.forEach(
(interfaceMember: DeclarationReflection) => {
if (!(interfaceMember instanceof DeclarationReflection)) {
return;
}
interfaceReflection.children.forEach((interfaceMember) => {
let classMember: DeclarationReflection | undefined;

let classMember: DeclarationReflection | undefined;
if (!classReflection.children) {
return;
}

if (!classReflection.children) {
return;
for (
let index = 0, count = classReflection.children.length;
index < count;
index++
) {
const child = classReflection.children[index];
if (child.name !== interfaceMember.name) {
continue;
}

for (
let index = 0, count = classReflection.children.length;
index < count;
index++
) {
const child = classReflection.children[index];
if (child.name !== interfaceMember.name) {
continue;
}
if (
child.flags.isStatic !== interfaceMember.flags.isStatic
) {
continue;
}

classMember = child;
break;
if (child.flags.isStatic !== interfaceMember.flags.isStatic) {
continue;
}

if (!classMember) {
return;
}
classMember = child;
break;
}

const interfaceMemberName =
interfaceReflection.name + "." + interfaceMember.name;
classMember.implementationOf = new ReferenceType(
interfaceMemberName,
interfaceMember,
context.project
);
copyComment(classMember, interfaceMember);
if (!classMember) {
return;
}

if (
interfaceMember.kindOf(ReflectionKind.Property) &&
classMember.kindOf(ReflectionKind.Accessor)
) {
if (classMember.getSignature) {
copyComment(classMember.getSignature, interfaceMember);
classMember.getSignature.implementationOf =
classMember.implementationOf;
}
if (classMember.setSignature) {
copyComment(classMember.setSignature, interfaceMember);
classMember.setSignature.implementationOf =
classMember.implementationOf;
}
const interfaceMemberName =
interfaceReflection.name + "." + interfaceMember.name;
classMember.implementationOf = new ReferenceType(
interfaceMemberName,
interfaceMember,
context.project
);
copyComment(classMember, interfaceMember);

if (
interfaceMember.kindOf(ReflectionKind.Property) &&
classMember.kindOf(ReflectionKind.Accessor)
) {
if (classMember.getSignature) {
copyComment(classMember.getSignature, interfaceMember);
classMember.getSignature.implementationOf =
classMember.implementationOf;
}
if (classMember.setSignature) {
copyComment(classMember.setSignature, interfaceMember);
classMember.setSignature.implementationOf =
classMember.implementationOf;
}
}

if (
interfaceMember.kindOf(ReflectionKind.FunctionOrMethod) &&
interfaceMember.signatures &&
classMember.signatures
) {
for (const [clsSig, intSig] of zip(
classMember.signatures,
interfaceMember.signatures
)) {
if (clsSig.implementationOf) {
clsSig.implementationOf = new ReferenceType(
clsSig.implementationOf.name,
intSig,
context.project
);
}
copyComment(clsSig, intSig);
if (
interfaceMember.kindOf(ReflectionKind.FunctionOrMethod) &&
interfaceMember.signatures &&
classMember.signatures
) {
for (const [clsSig, intSig] of zip(
classMember.signatures,
interfaceMember.signatures
)) {
if (clsSig.implementationOf) {
clsSig.implementationOf = new ReferenceType(
clsSig.implementationOf.name,
intSig,
context.project
);
}
copyComment(clsSig, intSig);
}
}
);
});
}

private analyzeInheritance(
context: Context,
reflection: DeclarationReflection
) {
const extendedTypes = (reflection.extendedTypes?.filter((type) => {
return (
type instanceof ReferenceType &&
type.reflection instanceof DeclarationReflection
);
}) ?? []) as Array<
ReferenceType & { reflection: DeclarationReflection }
>;
const extendedTypes = filterMap(
reflection.extendedTypes ?? [],
(type) => {
return type instanceof ReferenceType &&
type.reflection instanceof DeclarationReflection
? (type as ReferenceType & {
reflection: DeclarationReflection;
})
: void 0;
}
);

for (const parent of extendedTypes) {
for (const parentMember of parent.reflection.children ?? []) {
Expand Down Expand Up @@ -192,6 +190,38 @@ export class ImplementsPlugin extends ConverterComponent {
* @param reflection The reflection that is currently resolved.
*/
private onResolve(context: Context, reflection: DeclarationReflection) {
this.tryResolve(context, reflection);
}

private tryResolve(context: Context, reflection: DeclarationReflection) {
const requirements = filterMap(
[
...(reflection.implementedTypes ?? []),
...(reflection.extendedTypes ?? []),
],
(type) => {
return type instanceof ReferenceType ? type.reflection : void 0;
}
);

if (requirements.every((req) => this.resolved.has(req))) {
this.doResolve(context, reflection);
this.resolved.add(reflection);

for (const refl of this.postponed.get(reflection) ?? []) {
this.tryResolve(context, refl);
}
this.postponed.delete(reflection);
} else {
for (const req of requirements) {
const future = this.postponed.get(req) ?? new Set();
future.add(reflection);
this.postponed.set(req, future);
}
}
}

private doResolve(context: Context, reflection: DeclarationReflection) {
if (
reflection.kindOf(ReflectionKind.Class) &&
reflection.implementedTypes
Expand Down
6 changes: 4 additions & 2 deletions src/test/converter2/issues/gh1580.ts
@@ -1,4 +1,6 @@
export class A {
export { B, A };

class A {
/** Prop docs */
prop!: string;

Expand All @@ -8,7 +10,7 @@ export class A {
}
}

export class B extends A {
class B extends A {
declare prop: "B";

run(): void {
Expand Down

0 comments on commit fc920bd

Please sign in to comment.