Skip to content

Commit 6a41cee

Browse files
committed
precompute category boosts
1 parent 545fc88 commit 6a41cee

File tree

8 files changed

+71
-30
lines changed

8 files changed

+71
-30
lines changed

example/src/classes/Customer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
* An abstract base class for the customer entity in our application.
33
*
44
* Notice how TypeDoc shows the inheritance hierarchy for our class.
5+
*
6+
* @category Model
57
*/
68
export abstract class Customer {
79
/** A public readonly property. */

example/src/reactComponents.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export interface CardAProps {
3636
* This is our recommended way to define React components as it makes your code
3737
* more readable. The minor drawback is you must click the `CardAProps` link to
3838
* see the component's props.
39+
*
40+
* @category Component
3941
*/
4042
export function CardA({ children, variant = "primary" }: PropsWithChildren<CardAProps>): ReactElement {
4143
return <div className={`card card-${variant}`}>{children}</div>;
@@ -66,6 +68,8 @@ export function CardA({ children, variant = "primary" }: PropsWithChildren<CardA
6668
*
6769
* This can make the TypeDoc documentation a bit cleaner for very simple components,
6870
* but it makes your code less readable.
71+
*
72+
* @category Component
6973
*/
7074
export function CardB({
7175
children,
@@ -245,6 +249,7 @@ export interface EasyFormDialogProps {
245249
* )
246250
* }
247251
* ```
252+
* @category Component
248253
*/
249254
export function EasyFormDialog(props: PropsWithChildren<EasyFormDialogProps>): ReactElement {
250255
return <div />;

example/typedoc.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
"entryPoints": ["./src"],
44
"sort": ["source-order"],
55
"media": "media",
6+
"categorizeByGroup": false,
67
"search": {
78
"numResults": 12,
89
"boosts": {
910
"byKind": {
1011
"class": 1.2
1112
},
1213
"byCategory": {
13-
"Lang": 10
14+
"Component": 2,
15+
"Model": 1.2
1416
}
1517
}
1618
}

src/lib/converter/context.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type { Converter } from "./converter";
1414
import { isNamedNode } from "./utils/nodes";
1515
import { ConverterEvents } from "./converter-events";
1616
import { resolveAliasedSymbol } from "./utils/symbols";
17+
import type { SearchConfig } from "../utils/options/declaration";
1718

1819
/**
1920
* The context describes the current state the converter is in.
@@ -118,6 +119,12 @@ export class Context {
118119
return this.converter.application.options.getCompilerOptions();
119120
}
120121

122+
getSearchOptions(): SearchConfig {
123+
return this.converter.application.options.getValue(
124+
"search"
125+
) as SearchConfig;
126+
}
127+
121128
/**
122129
* Return the type declaration of the given node.
123130
*

src/lib/converter/plugins/CategoryPlugin.ts

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import {
44
DeclarationReflection,
55
CommentTag,
66
} from "../../models";
7-
import { ReflectionCategory } from "../../models/ReflectionCategory";
7+
import { ReflectionCategory } from "../../models";
88
import { Component, ConverterComponent } from "../components";
99
import { Converter } from "../converter";
1010
import type { Context } from "../context";
1111
import { BindOption } from "../../utils";
12-
import type { Comment } from "../../models/comments/index";
12+
import type { Comment } from "../../models";
1313

1414
/**
1515
* A handler that sorts and categorizes the found reflections in the resolving phase.
@@ -66,9 +66,12 @@ export class CategoryPlugin extends ConverterComponent {
6666
* @param context The context object describing the current state the converter is in.
6767
* @param reflection The reflection that is currently resolved.
6868
*/
69-
private onResolve(_context: Context, reflection: Reflection) {
69+
private onResolve(context: Context, reflection: Reflection) {
7070
if (reflection instanceof ContainerReflection) {
71-
this.categorize(reflection);
71+
this.categorize(
72+
reflection,
73+
context.getSearchOptions().boosts?.byCategory ?? {}
74+
);
7275
}
7376
}
7477

@@ -79,26 +82,36 @@ export class CategoryPlugin extends ConverterComponent {
7982
*/
8083
private onEndResolve(context: Context) {
8184
const project = context.project;
82-
this.categorize(project);
85+
this.categorize(
86+
project,
87+
context.getSearchOptions().boosts?.byCategory ?? {}
88+
);
8389
}
8490

85-
private categorize(obj: ContainerReflection) {
91+
private categorize(
92+
obj: ContainerReflection,
93+
categorySearchBoosts: { [key: string]: number }
94+
) {
8695
if (this.categorizeByGroup) {
87-
this.groupCategorize(obj);
96+
this.groupCategorize(obj, categorySearchBoosts);
8897
} else {
89-
this.lumpCategorize(obj);
98+
CategoryPlugin.lumpCategorize(obj, categorySearchBoosts);
9099
}
91100
}
92101

93-
private groupCategorize(obj: ContainerReflection) {
102+
private groupCategorize(
103+
obj: ContainerReflection,
104+
categorySearchBoosts: { [key: string]: number }
105+
) {
94106
if (!obj.groups || obj.groups.length === 0) {
95107
return;
96108
}
97109
obj.groups.forEach((group) => {
98110
if (group.categories) return;
99111

100112
group.categories = CategoryPlugin.getReflectionCategories(
101-
group.children
113+
group.children,
114+
categorySearchBoosts
102115
);
103116
if (group.categories && group.categories.length > 1) {
104117
group.categories.sort(CategoryPlugin.sortCatCallback);
@@ -112,11 +125,17 @@ export class CategoryPlugin extends ConverterComponent {
112125
});
113126
}
114127

115-
private lumpCategorize(obj: ContainerReflection) {
128+
static lumpCategorize(
129+
obj: ContainerReflection,
130+
categorySearchBoosts: { [key: string]: number }
131+
) {
116132
if (!obj.children || obj.children.length === 0 || obj.categories) {
117133
return;
118134
}
119-
obj.categories = CategoryPlugin.getReflectionCategories(obj.children);
135+
obj.categories = CategoryPlugin.getReflectionCategories(
136+
obj.children,
137+
categorySearchBoosts
138+
);
120139
if (obj.categories && obj.categories.length > 1) {
121140
obj.categories.sort(CategoryPlugin.sortCatCallback);
122141
} else if (
@@ -132,10 +151,13 @@ export class CategoryPlugin extends ConverterComponent {
132151
* Create a categorized representation of the given list of reflections.
133152
*
134153
* @param reflections The reflections that should be categorized.
154+
* @param categorySearchBoosts A user-supplied map of category titles, for computing a
155+
* relevance boost to be used when searching
135156
* @returns An array containing all children of the given reflection categorized
136157
*/
137158
static getReflectionCategories(
138-
reflections: DeclarationReflection[]
159+
reflections: DeclarationReflection[],
160+
categorySearchBoosts: { [key: string]: number }
139161
): ReflectionCategory[] {
140162
const categories: ReflectionCategory[] = [];
141163
let defaultCat: ReflectionCategory | undefined;
@@ -154,11 +176,17 @@ export class CategoryPlugin extends ConverterComponent {
154176
categories.push(defaultCat);
155177
}
156178
}
179+
157180
defaultCat.children.push(child);
158181
return;
159182
}
160183
for (const childCat of childCategories) {
161184
let category = categories.find((cat) => cat.title === childCat);
185+
186+
const catBoost = categorySearchBoosts[category?.title ?? -1];
187+
if (catBoost != undefined) {
188+
child.categoryBoost = catBoost;
189+
}
162190
if (category) {
163191
category.children.push(child);
164192
continue;

src/lib/models/reflections/container.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ export class ContainerReflection extends Reflection {
2020
*/
2121
categories?: ReflectionCategory[];
2222

23+
/**
24+
* A precomputed boost derived from the searchCategoryBoosts typedoc.json setting, to be used when
25+
* boosting search relevance scores at runtime.
26+
*/
27+
categoryBoost?: number;
28+
2329
/**
2430
* Return a list of all children of a certain kind.
2531
*

src/lib/output/plugins/JavascriptIndexPlugin.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,7 @@ export class JavascriptIndexPlugin extends RendererComponent {
7070
name: reflection.name,
7171
url: reflection.url,
7272
classes: reflection.cssClasses,
73-
categories: (reflection.categories ?? []).map(
74-
(category) => category.title
75-
),
73+
categoryBoost: reflection.categoryBoost,
7674
};
7775

7876
if (parent) {

src/lib/output/themes/default/assets/typedoc/components/Search.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { debounce } from "../utils/debounce";
22
import { Index } from "lunr";
33
import type { SearchConfig } from "../../../../../../utils/options/declaration";
4-
import { ReflectionKind } from "../../../../../../models/reflections/kind";
4+
import { ReflectionKind } from "../../../../../../models";
55

66
export interface IDocument {
77
id: number;
@@ -10,7 +10,7 @@ export interface IDocument {
1010
url: string;
1111
classes?: string;
1212
parent?: string;
13-
categories: Array<string>;
13+
categoryBoost?: number;
1414
}
1515

1616
interface IData {
@@ -174,10 +174,8 @@ function updateResults(
174174
let boost = 1;
175175

176176
// boost by exact match on name
177-
if(row.name
178-
.toLowerCase()
179-
.startsWith(searchText.toLowerCase())) {
180-
boost *= (1 / Math.abs(row.name.length - searchText.length) * 10)
177+
if (row.name.toLowerCase().startsWith(searchText.toLowerCase())) {
178+
boost *= 1 / (Math.abs(row.name.length - searchText.length) * 10);
181179
}
182180

183181
// boost by kind
@@ -197,12 +195,7 @@ function updateResults(
197195
}
198196

199197
// boost by category
200-
for (let categoryTitle in searchConfig.boosts?.byCategory ?? []) {
201-
if (row.categories.indexOf(categoryTitle) > -1) {
202-
boost *=
203-
searchConfig.boosts?.byCategory?.[categoryTitle] ?? 1;
204-
}
205-
}
198+
boost *= row.categoryBoost ?? 1;
206199

207200
item.score *= boost;
208201
}
@@ -226,7 +219,7 @@ function updateResults(
226219
}
227220

228221
const item = document.createElement("li");
229-
item.classList.value = row.classes ?? '';
222+
item.classList.value = row.classes ?? "";
230223

231224
const anchor = document.createElement("a");
232225
anchor.href = state.base + row.url;

0 commit comments

Comments
 (0)