Skip to content

Commit 65c83a9

Browse files
committed
Conversion order should not affect link resolution
Resolves #2466
1 parent a0aa060 commit 65c83a9

File tree

5 files changed

+73
-9
lines changed

5 files changed

+73
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
- Fix crash when converting some complicated union/intersection types, #2451.
2828
- Navigation triangle markers should no longer display on a separate line with some font settings, #2457.
2929
- `@group` and `@category` organization is now applied later to allow inherited comments to create groups/categories, #2459.
30+
- Conversion order should no longer affect link resolution for classes with properties whose type does not rely on `this`, #2466.
3031
- Keyword syntax highlighting introduced in 0.25.4 was not always applied to keywords.
3132
- If all members in a group are hidden from the page, the group will be hidden in the page index on page load.
3233

src/lib/converter/symbols.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,10 @@ export function convertSymbol(
182182
flags = removeFlag(flags, ts.SymbolFlags.Property);
183183
}
184184

185-
for (const flag of getEnumFlags(flags ^ allConverterFlags)) {
186-
if (!(flag & allConverterFlags)) {
187-
context.logger.verbose(
188-
`Missing converter for symbol: ${symbol.name} with flag ${ts.SymbolFlags[flag]}`,
189-
);
190-
}
185+
for (const flag of getEnumFlags(flags & ~allConverterFlags)) {
186+
context.logger.verbose(
187+
`Missing converter for symbol: ${symbol.name} with flag ${ts.SymbolFlags[flag]}`,
188+
);
191189
}
192190

193191
// Note: This method does not allow skipping earlier converters.
@@ -628,7 +626,7 @@ function convertClassOrInterface(
628626
// And finally, index signatures
629627
convertIndexSignature(reflectionContext, symbol);
630628

631-
// Normally this shouldn't matter, unless someone did something with skipLibCheck off.
629+
// Normally this shouldn't matter, unless someone did something with skipLibCheck on.
632630
return ts.SymbolFlags.Alias;
633631
}
634632

src/lib/models/reflections/project.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { SignatureReflection } from "./signature";
66
import type { ParameterReflection } from "./parameter";
77
import { IntrinsicType } from "../types";
88
import type { TypeParameterReflection } from "./type-parameter";
9-
import { removeIfPresent } from "../../utils";
9+
import { removeIf, removeIfPresent } from "../../utils";
1010
import type * as ts from "typescript";
1111
import { ReflectionKind } from "./kind";
1212
import { Comment, CommentDisplayPart } from "../comments";
@@ -103,7 +103,37 @@ export class ProjectReflection extends ContainerReflection {
103103

104104
if (symbol) {
105105
this.reflectionIdToSymbolMap.set(reflection.id, symbol);
106-
this.registerSymbolId(reflection, new ReflectionSymbolId(symbol));
106+
const id = new ReflectionSymbolId(symbol);
107+
this.registerSymbolId(reflection, id);
108+
109+
// #2466
110+
// If we just registered a member of a class or interface, then we need to check if
111+
// we've registered this symbol before under the wrong parent reflection.
112+
// This can happen because the compiler API will use non-dependently-typed symbols
113+
// for properties of classes/interfaces which inherit them, so we can't rely on the
114+
// property being unique for each class.
115+
if (
116+
reflection.parent?.kindOf(ReflectionKind.ClassOrInterface) &&
117+
reflection.kindOf(ReflectionKind.SomeMember)
118+
) {
119+
const saved = this.symbolToReflectionIdMap.get(id);
120+
const parentSymbolReflection =
121+
symbol.parent &&
122+
this.getReflectionFromSymbol(symbol.parent);
123+
124+
if (
125+
typeof saved === "object" &&
126+
saved.length > 1 &&
127+
parentSymbolReflection
128+
) {
129+
removeIf(
130+
saved,
131+
(item) =>
132+
this.getReflectionById(item)?.parent !==
133+
parentSymbolReflection,
134+
);
135+
}
136+
}
107137
}
108138
}
109139

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Conversion order test for @link
2+
3+
export interface One extends Two {}
4+
5+
/** {@link method1} */
6+
export interface Two {
7+
method1(): string;
8+
}
9+
10+
/** {@link method2} */
11+
export interface Three {
12+
method2(): string;
13+
}
14+
15+
export interface Four extends Three {}

src/test/issues.c2.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,4 +1330,24 @@ describe("Issue Tests", () => {
13301330
const is = querySig(project, "FooA.is");
13311331
equal(is.type?.toString(), "this is Foo & Object");
13321332
});
1333+
1334+
it("Does not care about conversion order for @link resolution, #2466", () => {
1335+
const project = convert();
1336+
1337+
const Two = query(project, "Two");
1338+
equal(getLinks(Two), [
1339+
{
1340+
display: "method1",
1341+
target: [ReflectionKind.Method, "Two.method1"],
1342+
},
1343+
]);
1344+
1345+
const Three = query(project, "Three");
1346+
equal(getLinks(Three), [
1347+
{
1348+
display: "method2",
1349+
target: [ReflectionKind.Method, "Three.method2"],
1350+
},
1351+
]);
1352+
});
13331353
});

0 commit comments

Comments
 (0)