Skip to content

Commit

Permalink
Improve link resolution prioritization
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerrit0 committed Dec 20, 2024
1 parent 2c10f67 commit 23008f6
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ title: Changelog

- `@include` and `@includeCode` now work in the readme file, #2814.
- TypeDoc will now avoid making references to references, #2811.
- Improved link resolution logic to prioritize type alias properties with the
same symbol over type literal properties within function parameters.

## v0.27.5 (2024-12-14)

Expand Down
35 changes: 27 additions & 8 deletions src/lib/converter/comments/linkResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
parseDeclarationReference,
} from "./declarationReference.js";
import { resolveDeclarationReference } from "./declarationReferenceResolver.js";
import { maxElementByScore } from "../../utils/array.js";

const urlPrefix = /^(http|ftp)s?:\/\//;

Expand Down Expand Up @@ -138,14 +139,32 @@ function resolveLinkTag(

if (tsTargets.length) {
// Find the target most likely to have a real url in the generated documentation
target =
tsTargets.find((r) => r.kindOf(ReflectionKind.SomeExport)) ||
tsTargets.find(
(r) =>
r.kindOf(ReflectionKind.SomeMember) &&
r.parent?.kindOf(ReflectionKind.SomeExport),
) ||
tsTargets[0];
// 1. A direct export (class, interface, variable)
// 2. A property of a direct export (class/interface property)
// 3. A property of a type of an export (property on type alias)
// 4. Whatever the first symbol found was
target = maxElementByScore(tsTargets, (r) => {
if (r.kindOf(ReflectionKind.SomeExport)) {
return 4;
}
if (
r.kindOf(ReflectionKind.SomeMember) &&
r.parent?.kindOf(ReflectionKind.SomeExport)
) {
return 3;
}
if (
r.kindOf(ReflectionKind.SomeMember) &&
r.parent?.kindOf(ReflectionKind.TypeLiteral) &&
r.parent.parent?.kindOf(
ReflectionKind.TypeAlias | ReflectionKind.Variable,
)
) {
return 2;
}

return 1;
})!;
pos = end;
defaultDisplayText =
part.tsLinkText ||
Expand Down
22 changes: 22 additions & 0 deletions src/lib/utils/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,25 @@ export function joinArray<T>(
}
return "";
}

export function maxElementByScore<T>(
arr: readonly T[],
score: (a: T) => number,
): T | undefined {
if (arr.length === 0) {
return undefined;
}

let largest = arr[0];
let largestScore = score(arr[0]);

for (let i = 1; i < arr.length; ++i) {
const itemScore = score(arr[i]);
if (itemScore > largestScore) {
largest = arr[i];
largestScore = itemScore;
}
}

return largest;
}
4 changes: 2 additions & 2 deletions src/test/converter/exports/specs.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@
"url": "typedoc://mod.ts#L13"
}
],
"target": 31
"target": 30
},
{
"id": 40,
Expand Down Expand Up @@ -412,7 +412,7 @@
"url": "typedoc://mod.ts#L40"
}
],
"target": 34
"target": 29
}
],
"groups": [
Expand Down
2 changes: 1 addition & 1 deletion src/test/converter/exports/specs.nodoc.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"url": "typedoc://mod.ts#L13"
}
],
"target": 31
"target": 30
},
{
"id": 43,
Expand Down
21 changes: 21 additions & 0 deletions src/test/utils/array.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
binaryFindPartition,
insertOrderSorted,
insertPrioritySorted,
maxElementByScore,
removeIfPresent,
} from "../../lib/utils/array.js";

Expand Down Expand Up @@ -138,4 +139,24 @@ describe("Array utils", () => {
equal(arr, [2, 1]);
});
});

describe("maxElementByScore", () => {
it("Gets the max element", () => {
const arr = [1, 2, 3];
const item = maxElementByScore(arr, (x) => x);
equal(item, 3);
});

it("Prioritizes elements earlier in the array", () => {
const arr = [1, 2, 3];
const item = maxElementByScore(arr, () => 1);
equal(item, 1);
});

it("Returns undefined for an empty array", () => {
const arr: unknown[] = [];
const item = maxElementByScore(arr, () => 1);
equal(item, undefined);
});
});
});

0 comments on commit 23008f6

Please sign in to comment.