UNPKG

vuepress-plugin-full-text-search2

Version:
165 lines (161 loc) 4.29 kB
// src/index.ts import { path } from "@vuepress/utils"; import { fileURLToPath } from "url"; // src/prepare-search-index.ts import { Parser } from "htmlparser2"; var HMR_CODE = ` if (import.meta.webpackHot) { import.meta.webpackHot.accept() if (__VUE_HMR_RUNTIME__[UPD_NAME]) { __VUE_HMR_RUNTIME__[UPD_NAME](searchIndex) } } if (import.meta.hot) { import.meta.hot.accept(({ searchIndex }) => { if (__VUE_HMR_RUNTIME__[UPD_NAME]) { __VUE_HMR_RUNTIME__[UPD_NAME](searchIndex) } }) } `; async function prepareSearchIndex({ app }) { const searchIndex = []; for (const page of app.pages) { searchIndex.push({ path: page.path, title: page.title, pathLocale: page.pathLocale, contents: extractPageContents(page) }); } let content = ` export const searchIndex = ${JSON.stringify(searchIndex, null, 2)} export const UPD_NAME = 'update-vuepress-plugin-full-text-search2-search-index' `; if (app.env.isDev) { content += HMR_CODE; } return app.writeTemp( "internal/vuepress-plugin-full-text-search2-search-index.js", content ); } function extractPageContents(page) { const results = []; const slugs = /* @__PURE__ */ new Map(); const headers = [...page.headers]; while (headers.length) { const h = headers.shift(); slugs.set(h.slug, h.title); headers.push(...h.children); } let ignoreElement = 0; let withinHeader = 0; let scope = { header: "", slug: "", content: "" }; results.push(scope); const parser = new Parser({ ontext(text) { if (ignoreElement) { return; } const prop = withinHeader ? "header" : "content"; scope[prop] += text; }, onopentag(name, attribute) { if (ignoreElement || name === "script" || name === "style" || name === "div" && attribute.class === "line-numbers") { ignoreElement++; return; } if (withinHeader) { withinHeader++; return; } if (!/^h\d$/u.test(name)) { return; } const id = attribute.id; const title = slugs.get(id); if (title) { scope = { header: title, slug: id, content: "" }; results.push(scope); ignoreElement++; } else { scope = { header: "", slug: id, content: "" }; results.push(scope); withinHeader++; } }, onclosetag() { if (ignoreElement) { ignoreElement--; return; } if (withinHeader) { withinHeader--; } } }); parser.parseComplete(page.contentRendered); return results.map((p) => { p.header = p.header.replace(/\s{2,}/g, " ").replace(/^#/g, "").trim(); p.content = p.content.replace(/\s{2,}/g, " ").trim(); return p; }).filter((p) => p.content || p.header); } // src/index.ts import * as chokidar from "chokidar"; var filename = typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url); var dirname = path.dirname(filename); var fullTextSearchPlugin = fullTextSearchPluginFunction; var src_default = fullTextSearchPlugin; function fullTextSearchPluginFunction(options = {}) { return { name: "vuepress-plugin-full-text-search2", define: { __SEARCH_LOCALES__: ("locales" in options ? options == null ? void 0 : options.locales : {}) ?? {} }, clientConfigFile: path.resolve(dirname, "./client/clientConfig.js"), // @ts-expect-error -- Backward compatibility for vuepress@<=2.0.0-beta.43 clientAppEnhanceFiles: path.resolve( dirname, "./client/clientAppEnhance.js" ), onPrepared(app) { prepareSearchIndex({ app }); }, onWatched: (app, watchers) => { const searchIndexWatcher = chokidar.watch("internal/pageData/*", { cwd: app.dir.temp(), ignoreInitial: true }); searchIndexWatcher.on("add", () => { prepareSearchIndex({ app }); }); searchIndexWatcher.on("change", () => { prepareSearchIndex({ app }); }); searchIndexWatcher.on("unlink", () => { prepareSearchIndex({ app }); }); watchers.push(searchIndexWatcher); } }; } export { src_default as default, fullTextSearchPlugin };