Skip to content

Commit ed3d8a3

Browse files
committed
Keep the name of an aliased doc searchable
addAlias kept only the alias applyAliases returns, so the name of a doc that has one never made it into the search text: searching for "julia" had to match "julia.1.13", which scores one point lower per character of the version. The versions of Julia were therefore listed 1.9 to 1.0 before 1.13 and 1.12, while CMake, whose name has no alias, was ordered correctly. Pushing the name as well as its alias makes every version match the name exactly, so they score the same and keep the order of the manifest.
1 parent 6f8f80b commit ed3d8a3

2 files changed

Lines changed: 85 additions & 1 deletion

File tree

‎assets/javascripts/models/entry.js‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ app.models.Entry = class Entry extends app.Model {
2929
if (!Array.isArray(this.text)) {
3030
this.text = [this.text];
3131
}
32-
this.text.push(Array.isArray(text) ? text[1] : text);
32+
// applyAliases returns both the name and its alias; keeping only the alias
33+
// would make the name of an aliased doc (e.g. Julia) unsearchable.
34+
this.text.push(...(Array.isArray(text) ? text : [text]));
3335
}
3436

3537
fullPath() {

‎test/assets/search_ranking_test.js‎

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
const assert = require("node:assert/strict");
2+
const fs = require("node:fs");
3+
const test = require("node:test");
4+
const vm = require("node:vm");
5+
6+
const context = {
7+
app: {
8+
config: {
9+
max_results: 50,
10+
docs_aliases: { julia: "jl" },
11+
},
12+
collections: {},
13+
models: {},
14+
},
15+
$: {
16+
escapeRegexp: (string) => string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
17+
},
18+
};
19+
20+
vm.createContext(context);
21+
22+
// The files are concatenated because top-level class declarations aren't
23+
// shared between scripts run in the same context.
24+
vm.runInContext(
25+
[
26+
"assets/javascripts/lib/events.js",
27+
"assets/javascripts/app/searcher.js",
28+
"assets/javascripts/models/model.js",
29+
"assets/javascripts/models/entry.js",
30+
"assets/javascripts/models/doc.js",
31+
]
32+
.map((file) => fs.readFileSync(file, "utf8"))
33+
.join("\n"),
34+
context,
35+
{ filename: "devdocs.js" },
36+
);
37+
38+
const { app } = context;
39+
40+
app.collections.Entries = class Entries {
41+
each() {}
42+
};
43+
app.collections.Types = class Types {
44+
each() {}
45+
};
46+
47+
// The docs are listed in the order of the manifest, latest version first.
48+
const search = (query, name, versions) => {
49+
const entries = versions.map((version) =>
50+
new app.models.Doc({
51+
name,
52+
slug: `${name.toLowerCase()}~${version}`,
53+
version,
54+
}).toEntry(),
55+
);
56+
57+
const searcher = new app.SynchronousSearcher();
58+
let results = [];
59+
searcher.on("results", (found) => (results = found));
60+
searcher.find(entries, "text", query);
61+
return [...results.map((entry) => entry.name)];
62+
};
63+
64+
const JULIA = ["1.13", "1.12", "1.11", "1.10", "1.9", "1.8"];
65+
66+
test("searching for a doc lists its versions from the latest one", () => {
67+
assert.deepEqual(
68+
search("julia", "Julia", JULIA),
69+
JULIA.map((version) => `Julia ${version}`),
70+
);
71+
assert.deepEqual(search("cmake", "CMake", ["3.31", "3.9"]), [
72+
"CMake 3.31",
73+
"CMake 3.9",
74+
]);
75+
});
76+
77+
test("the alias of a doc matches all of its versions", () => {
78+
assert.deepEqual(
79+
search("jl", "Julia", JULIA),
80+
JULIA.map((version) => `Julia ${version}`),
81+
);
82+
});

0 commit comments

Comments
 (0)