main
ts 119 lines 3.33 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 import type {DocSearchHit, InternalDocSearchHit} from '../types/algolia';
9 import {liteClient, type Hit, type SearchResponse} from 'algoliasearch/lite';
10
11 // https://github.com/reactjs/react.dev/blob/55986965fbf69c2584040039c9586a01bd54eba7/src/siteConfig.js#L15-L19
12 const ALGOLIA_CONFIG = {
13 appId: '1FCF9AYYAT',
14 apiKey: '1b7ad4e1c89e645e351e59d40544eda1',
15 indexName: 'beta-react',
16 };
17
18 export const ALGOLIA_CLIENT = liteClient(
19 ALGOLIA_CONFIG.appId,
20 ALGOLIA_CONFIG.apiKey,
21 );
22
23 export function printHierarchy(
24 hit: DocSearchHit | InternalDocSearchHit,
25 ): string {
26 let val = `${hit.hierarchy.lvl0} > ${hit.hierarchy.lvl1}`;
27 if (hit.hierarchy.lvl2 != null) {
28 val = val.concat(` > ${hit.hierarchy.lvl2}`);
29 }
30 if (hit.hierarchy.lvl3 != null) {
31 val = val.concat(` > ${hit.hierarchy.lvl3}`);
32 }
33 if (hit.hierarchy.lvl4 != null) {
34 val = val.concat(` > ${hit.hierarchy.lvl4}`);
35 }
36 if (hit.hierarchy.lvl5 != null) {
37 val = val.concat(` > ${hit.hierarchy.lvl5}`);
38 }
39 if (hit.hierarchy.lvl6 != null) {
40 val = val.concat(` > ${hit.hierarchy.lvl6}`);
41 }
42 return val;
43 }
44
45 export async function queryAlgolia(
46 message: string | Array<string>,
47 ): Promise<Array<string>> {
48 const {results} = await ALGOLIA_CLIENT.search<DocSearchHit>({
49 requests: [
50 {
51 query: Array.isArray(message) ? message.join('\n') : message,
52 indexName: ALGOLIA_CONFIG.indexName,
53 attributesToRetrieve: [
54 'hierarchy.lvl0',
55 'hierarchy.lvl1',
56 'hierarchy.lvl2',
57 'hierarchy.lvl3',
58 'hierarchy.lvl4',
59 'hierarchy.lvl5',
60 'hierarchy.lvl6',
61 'content',
62 'url',
63 ],
64 attributesToSnippet: [
65 `hierarchy.lvl1:10`,
66 `hierarchy.lvl2:10`,
67 `hierarchy.lvl3:10`,
68 `hierarchy.lvl4:10`,
69 `hierarchy.lvl5:10`,
70 `hierarchy.lvl6:10`,
71 `content:10`,
72 ],
73 snippetEllipsisText: '',
74 hitsPerPage: 30,
75 attributesToHighlight: [
76 'hierarchy.lvl0',
77 'hierarchy.lvl1',
78 'hierarchy.lvl2',
79 'hierarchy.lvl3',
80 'hierarchy.lvl4',
81 'hierarchy.lvl5',
82 'hierarchy.lvl6',
83 'content',
84 ],
85 },
86 ],
87 });
88 const firstResult = results[0] as SearchResponse<DocSearchHit>;
89 const {hits} = firstResult;
90 const deduped = new Map();
91 for (const hit of hits) {
92 // drop hashes to dedupe properly
93 const u = new URL(hit.url);
94 if (deduped.has(u.pathname)) {
95 continue;
96 }
97 deduped.set(u.pathname, hit);
98 }
99 const pages: Array<string | null> = await Promise.all(
100 Array.from(deduped.values()).map(hit => {
101 return fetch(hit.url, {
102 headers: {
103 'User-Agent':
104 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36',
105 },
106 }).then(res => {
107 if (res.ok === true) {
108 return res.text();
109 } else {
110 console.error(
111 `Could not fetch docs: ${res.status} ${res.statusText}`,
112 );
113 return null;
114 }
115 });
116 }),
117 );
118 return pages.filter(page => page !== null);
119 }