返回 CodeWhale
search-utils.ts
根目录 / web / lib / search-utils.ts
1 /**
2 * search-utils.ts — shared keyword-search utilities for docs and FAQ.
3 *
4 * Pure functions extracted from the client components so they can be unit-tested
5 * without a DOM. Used by DocsSearch and FaqSearch.
6 */
7
8 import type { DocTopic } from "./docs-map";
9
10 const CATEGORY_LABELS: Record<string, { en: string; zh: string }> = {
11 "getting-started": { en: "Getting started", zh: "入门" },
12 "core-concepts": { en: "Core concepts", zh: "核心概念" },
13 reference: { en: "Reference", zh: "参考" },
14 extending: { en: "Extending", zh: "扩展" },
15 operations: { en: "Operations & community", zh: "运维与社区" },
16 };
17
18 /**
19 * Build a lowercase haystack string for a DocTopic, searching across both
20 * locales, source files, category name, and id/slug.
21 */
22 export function docTopicHaystack(t: DocTopic): string {
23 const sources = Array.isArray(t.repoSource) ? t.repoSource : [t.repoSource];
24 const parts = [
25 t.id,
26 t.slug,
27 t.label.en,
28 t.label.zh,
29 t.description.en,
30 t.description.zh,
31 ...sources,
32 t.category,
33 CATEGORY_LABELS[t.category]?.en ?? "",
34 CATEGORY_LABELS[t.category]?.zh ?? "",
35 ];
36 return parts.join(" ").toLowerCase();
37 }
38
39 /**
40 * Filter DocTopics by keyword query. Returns indices into the input array.
41 * Empty/whitespace query returns all indices.
42 */
43 export function filterDocTopics(topics: DocTopic[], query: string): number[] {
44 const q = query.trim().toLowerCase();
45 if (!q) return topics.map((_, i) => i);
46 return topics
47 .map((t, i) => ({ i, hay: docTopicHaystack(t) }))
48 .filter(({ hay }) => hay.includes(q))
49 .map(({ i }) => i);
50 }
51
52 /**
53 * Normalize a query for matching.
54 */
55 export function normalizeQuery(query: string): string {
56 return query.trim().toLowerCase();
57 }
58
59 /**
60 * Check whether a query matches a haystack (case-insensitive substring).
61 */
62 export function matches(haystack: string, query: string): boolean {
63 const q = normalizeQuery(query);
64 if (!q) return true;
65 return haystack.toLowerCase().includes(q);
66 }
67
67 lines TYPESCRIPT