UNPKG

vuepress-plugin-full-text-search2

Version:
177 lines (176 loc) 4.85 kB
// src/client/engine.ts import { searchIndex as searchIndexRaw, UPD_NAME } from "@internal/vuepress-plugin-full-text-search2-search-index"; import { computed, ref, watch } from "vue"; var searchIndex = ref(searchIndexRaw); var pathToPage = computed(() => { const map = /* @__PURE__ */ new Map(); for (const page of searchIndex.value) { map.set(page.path, page); } return map; }); if ( // @ts-expect-error -- ignore import.meta.webpackHot || // @ts-expect-error -- ignore import.meta.hot ) { __VUE_HMR_RUNTIME__[UPD_NAME] = (data) => { searchIndex.value = data; }; } function useSuggestions(query) { const suggestions = ref([]); let id = null; watch(query, () => { if (id) { clearTimeout(id); } id = setTimeout(search, 100); }); return suggestions; function search() { const queryStr = query.value.toLowerCase().trim(); if (!queryStr) { suggestions.value = []; return; } const suggestionResults = /* @__PURE__ */ new Map(); const suggestionSubTitles = /* @__PURE__ */ new Set(); for (const page of searchIndex.value) { for (const suggest of extractSuggestions(page, queryStr)) { suggestionSubTitles.add(suggest.parentPageTitle); let list = suggestionResults.get(suggest.parentPageTitle); if (!list) { list = []; suggestionResults.set(suggest.parentPageTitle, list); } list.push(suggest); } } const sortedSuggestionSubTitles = [...suggestionSubTitles].sort((a, b) => { const listA = suggestionResults.get(a); const listB = suggestionResults.get(b); return listB.length - listA.length; }); suggestions.value = [...suggestionResults].flatMap(([, s]) => s).sort( (a, b) => a.parentPagePriority - b.parentPagePriority || sortedSuggestionSubTitles.indexOf(a.parentPageTitle) - sortedSuggestionSubTitles.indexOf(b.parentPageTitle) || a.priority - b.priority ); } } function* extractSuggestions(page, queryStr) { const matchTitle = buildMatch(page.title, queryStr); if (matchTitle) { yield { path: page.path, parentPageTitle: getParentPageTitle(page), title: page.title, display: matchTitle, page, content: null, parentPagePriority: 1, priority: 1 }; return; } for (const content of page.contents) { const matchHeader = buildMatch(content.header, queryStr); if (matchHeader) { yield { path: page.path + (content.slug ? `#${content.slug}` : ""), parentPageTitle: getParentPageTitle(page), title: page.title, display: matchHeader, page, content: null, parentPagePriority: 10, priority: 2 }; continue; } const matchContent = buildMatch(content.content, queryStr); if (matchContent) { yield { path: page.path + (content.slug ? `#${content.slug}` : ""), parentPageTitle: getParentPageTitle(page), title: page.title, display: [ { type: "header", str: `${content.header} ` }, ...matchContent ], page, content: null, parentPagePriority: 10, priority: 10 }; } } } function getParentPageTitle(page) { const pathParts = page.path.split("/"); let parentPagePath = "/"; if (pathParts[1]) parentPagePath = `/${pathParts[1]}/`; const parentPage = pathToPage.value.get(parentPagePath) || page; return parentPage.title; } function buildMatch(text, queryStr) { const result = []; let totalLength = 0; const lower = text.toLowerCase().replace(/\s/gu, " "); let start = 0; let matchIndex = lower.indexOf(queryStr, start); if (matchIndex < 0) { return null; } while (matchIndex >= 0) { const end = matchIndex + queryStr.length; append(text.slice(start, matchIndex), "normal"); append(text.slice(matchIndex, end), "highlight"); start = end; matchIndex = lower.indexOf(queryStr, start); if (totalLength > 100) break; } append(text.slice(start), "normal"); return result.filter((w) => w.str); function append(s, type) { let str = s; if (type === "normal") { if (str.length > 100) { if (totalLength === 0) { str = `\u2026 ${str.slice(-10)}`; } } } let needEllipsis = false; if (totalLength + str.length > 100) { if (result.some((w) => w.type === "ellipsis")) { return; } str = str.slice(0, Math.max(100 - totalLength, 1)); needEllipsis = true; } result.push({ type, str }); totalLength += str.length; if (needEllipsis) { result.push({ type: "ellipsis", str: " \u2026" }); totalLength += 2; } } } export { useSuggestions };