@robindoc/minisearch 3.7.1 → 3.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"create-static-searcher.d.ts","sourceRoot":"","sources":["../src/create-static-searcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,QAAQ,EAAyC,MAAM,SAAS,CAAC;AA2B/E;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,MAAM,KAAG,QA8BvD,CAAC"}
1
+ {"version":3,"file":"create-static-searcher.d.ts","sourceRoot":"","sources":["../src/create-static-searcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,QAAQ,EAAyC,MAAM,SAAS,CAAC;AA6E/E;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,MAAM,KAAG,QA8BvD,CAAC"}
@@ -1,2 +1,2 @@
1
- import t from"minisearch";let r=null;const e=e=>async(i,n)=>{if(!i.trim())return[];try{const o=await(async e=>{if(r)return r;const i=await fetch(e);if(!i.ok)throw new Error(`Failed to load search index: ${i.statusText}`);const n=await i.json(),o=await t.loadJSAsync(n,{fields:["title","content","headings","description"],storeFields:["id","title","href","headings","description"],searchOptions:{boost:{title:5,headings:3,description:2},fuzzy:.2}});return r=o,o})(e);if(n.signal.aborted)return[];const s=o.search(i,{fuzzy:.2,prefix:!0,boost:{title:5,headings:3,description:2}});return n.signal.aborted?[]:s.slice(0,10).map(t=>({title:t.title,href:t.href,description:t.description}))}catch(t){return t instanceof Error&&"AbortError"===t.name||console.error("Search error:",t),[]}};export{e as createStaticSearcher};
1
+ import t from"minisearch";let e=null;const n=(t,e)=>{if(!t||!e.length)return t;const n=t.toLowerCase(),r=[];for(const t of e){const e=t.toLowerCase();let o=n.indexOf(e);for(;-1!==o;){const t=o+e.length;r.push({start:o,end:t}),o=n.indexOf(e,t)}}if(!r.length)return t;r.sort((t,e)=>t.start-e.start);const o=[];for(const e of r){if(o.reduce((t,e)=>t+e.end-e.start,0)>300)break;const n=o[o.length-1];if(n&&n.end+84>e.start){n.end=e.end;continue}const r=Math.max(0,e.start-40),s=Math.min(t.length,e.end+40);s-r<10||o.push({start:r,end:s})}return[o[0].start>0?"...":"",o.map(e=>t.slice(e.start,e.end)).join(" ... "),o[o.length-1].end<t.length?"...":""].join("")},r=r=>async(o,s)=>{if(!o.trim())return[];try{const i=await(async n=>{if(e)return e;const r=await fetch(n);if(!r.ok)throw new Error(`Failed to load search index: ${r.statusText}`);const o=await r.json(),s=await t.loadJSAsync(o,{fields:["title","content","headings","description"],storeFields:["id","title","href","headings","description","content"],searchOptions:{boost:{title:5,headings:3,description:2},fuzzy:.2}});return e=s,s})(r);if(s.signal.aborted)return[];const a=i.search(o,{fuzzy:.2,prefix:!0,boost:{title:5,headings:3,description:2}});return s.signal.aborted?[]:a.slice(0,10).map(t=>({title:t.title,href:t.href,description:n(t.content,t.terms)}))}catch(t){return t instanceof Error&&"AbortError"===t.name||console.error("Search error:",t),[]}};export{r as createStaticSearcher};
2
2
  //# sourceMappingURL=create-static-searcher.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-static-searcher.js","sources":["../src/create-static-searcher.ts"],"sourcesContent":["import MiniSearch, { type AsPlainObject } from \"minisearch\";\n\nimport { type Searcher, type SearchItem, type SearchIndexItem } from \"./types\";\n\nlet cachedIndex: MiniSearch<SearchIndexItem> | null = null;\n\nconst loadSearchIndex = async (indexUrl: string): Promise<MiniSearch<SearchIndexItem>> => {\n if (cachedIndex) return cachedIndex;\n\n const response = await fetch(indexUrl);\n if (!response.ok) {\n throw new Error(`Failed to load search index: ${response.statusText}`);\n }\n\n const data: AsPlainObject = await response.json();\n const searchIndex = await MiniSearch.loadJSAsync(data, {\n fields: [\"title\", \"content\", \"headings\", \"description\"],\n storeFields: [\"id\", \"title\", \"href\", \"headings\", \"description\"],\n searchOptions: {\n boost: { title: 5, headings: 3, description: 2 },\n fuzzy: 0.2,\n },\n });\n\n cachedIndex = searchIndex;\n\n return searchIndex;\n};\n\n/**\n * Creates a searcher function that loads and queries a static search index.\n *\n * @example\n * ```ts\n * import { createStaticSearcher } from \"@robindoc/minisearch\";\n *\n * const searcher = createStaticSearcher(\"/search-index.json\");\n *\n * // Use with Header component\n * <Header searcher={searcher} />\n * ```\n *\n * @see {@link https://robindoc.com/docs/customization/search Search integration}\n */\nexport const createStaticSearcher = (indexUrl: string): Searcher => {\n return async (search: string, abortController: AbortController): Promise<SearchItem[]> => {\n if (!search.trim()) return [];\n\n try {\n const searchIndex = await loadSearchIndex(indexUrl);\n\n if (abortController.signal.aborted) return [];\n\n const results = searchIndex.search(search, {\n fuzzy: 0.2,\n prefix: true,\n boost: { title: 5, headings: 3, description: 2 },\n });\n\n if (abortController.signal.aborted) return [];\n\n return results.slice(0, 10).map((result) => ({\n title: result.title,\n href: result.href,\n description: result.description,\n }));\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n return [];\n }\n console.error(\"Search error:\", error);\n return [];\n }\n };\n};\n"],"names":["cachedIndex","createStaticSearcher","indexUrl","async","search","abortController","trim","searchIndex","response","fetch","ok","Error","statusText","data","json","MiniSearch","loadJSAsync","fields","storeFields","searchOptions","boost","title","headings","description","fuzzy","loadSearchIndex","signal","aborted","results","prefix","slice","map","result","href","error","name","console"],"mappings":"0BAIA,IAAIA,EAAkD,KAEtD,MAsCaC,EAAwBC,GAC1BC,MAAOC,EAAgBC,KAC1B,IAAKD,EAAOE,OAAQ,MAAO,GAE3B,IACI,MAAMC,OA3CMJ,OAAOD,IAC3B,GAAIF,EAAa,OAAOA,EAExB,MAAMQ,QAAiBC,MAAMP,GAC7B,IAAKM,EAASE,GACV,MAAM,IAAIC,MAAM,gCAAgCH,EAASI,cAG7D,MAAMC,QAA4BL,EAASM,OACrCP,QAAoBQ,EAAWC,YAAYH,EAAM,CACnDI,OAAQ,CAAC,QAAS,UAAW,WAAY,eACzCC,YAAa,CAAC,KAAM,QAAS,OAAQ,WAAY,eACjDC,cAAe,CACXC,MAAO,CAAEC,MAAO,EAAGC,SAAU,EAAGC,YAAa,GAC7CC,MAAO,MAMf,OAFAxB,EAAcO,EAEPA,GAuB2BkB,CAAgBvB,GAE1C,GAAIG,EAAgBqB,OAAOC,QAAS,MAAO,GAE3C,MAAMC,EAAUrB,EAAYH,OAAOA,EAAQ,CACvCoB,MAAO,GACPK,QAAQ,EACRT,MAAO,CAAEC,MAAO,EAAGC,SAAU,EAAGC,YAAa,KAGjD,OAAIlB,EAAgBqB,OAAOC,QAAgB,GAEpCC,EAAQE,MAAM,EAAG,IAAIC,IAAKC,IAAM,CACnCX,MAAOW,EAAOX,MACdY,KAAMD,EAAOC,KACbV,YAAaS,EAAOT,cAE5B,CAAE,MAAOW,GACL,OAAIA,aAAiBvB,OAAwB,eAAfuB,EAAMC,MAGpCC,QAAQF,MAAM,gBAAiBA,GAFpB,EAIf"}
1
+ {"version":3,"file":"create-static-searcher.js","sources":["../src/create-static-searcher.ts"],"sourcesContent":["import MiniSearch, { type AsPlainObject } from \"minisearch\";\n\nimport { type Searcher, type SearchItem, type SearchIndexItem } from \"./types\";\n\nlet cachedIndex: MiniSearch<SearchIndexItem> | null = null;\n\nconst MAX_RESULTS = 10;\nconst MAX_CHARS = 300;\n\nconst buildDescriptionSnippet = (content: string, terms: string[]): string => {\n if (!content || !terms.length) return content;\n\n const lowerContent = content.toLowerCase();\n const matches: Array<{ start: number; end: number }> = [];\n\n for (const term of terms) {\n const lowerTerm = term.toLowerCase();\n let start = lowerContent.indexOf(lowerTerm);\n while (start !== -1) {\n const end = start + lowerTerm.length;\n matches.push({ start, end });\n start = lowerContent.indexOf(lowerTerm, end);\n }\n }\n\n if (!matches.length) return content;\n\n matches.sort((a, b) => a.start - b.start);\n const ranges: Array<{ start: number; end: number }> = [];\n\n for (const match of matches) {\n if (ranges.reduce((acc, range) => acc + range.end - range.start, 0) > MAX_CHARS) break;\n const prevRange = ranges[ranges.length - 1];\n\n if (prevRange && prevRange.end + 84 > match.start) {\n prevRange.end = match.end;\n continue;\n }\n\n const snippetStart = Math.max(0, match.start - 40);\n const snippetEnd = Math.min(content.length, match.end + 40);\n\n if (snippetEnd - snippetStart < 10) {\n continue;\n }\n\n ranges.push({ start: snippetStart, end: snippetEnd });\n }\n\n return [\n ranges[0].start > 0 ? \"...\" : \"\",\n ranges.map((range) => content.slice(range.start, range.end)).join(\" ... \"),\n ranges[ranges.length - 1].end < content.length ? \"...\" : \"\",\n ].join(\"\");\n};\n\nconst loadSearchIndex = async (indexUrl: string): Promise<MiniSearch<SearchIndexItem>> => {\n if (cachedIndex) return cachedIndex;\n\n const response = await fetch(indexUrl);\n if (!response.ok) {\n throw new Error(`Failed to load search index: ${response.statusText}`);\n }\n\n const data: AsPlainObject = await response.json();\n const searchIndex = await MiniSearch.loadJSAsync(data, {\n fields: [\"title\", \"content\", \"headings\", \"description\"],\n storeFields: [\"id\", \"title\", \"href\", \"headings\", \"description\", \"content\"],\n searchOptions: {\n boost: { title: 5, headings: 3, description: 2 },\n fuzzy: 0.2,\n },\n });\n\n cachedIndex = searchIndex;\n\n return searchIndex;\n};\n\n/**\n * Creates a searcher function that loads and queries a static search index.\n *\n * @example\n * ```ts\n * import { createStaticSearcher } from \"@robindoc/minisearch\";\n *\n * const searcher = createStaticSearcher(\"/search-index.json\");\n *\n * // Use with Header component\n * <Header searcher={searcher} />\n * ```\n *\n * @see {@link https://robindoc.com/docs/customization/search Search integration}\n */\nexport const createStaticSearcher = (indexUrl: string): Searcher => {\n return async (search: string, abortController: AbortController): Promise<SearchItem[]> => {\n if (!search.trim()) return [];\n\n try {\n const searchIndex = await loadSearchIndex(indexUrl);\n\n if (abortController.signal.aborted) return [];\n\n const results = searchIndex.search(search, {\n fuzzy: 0.2,\n prefix: true,\n boost: { title: 5, headings: 3, description: 2 },\n });\n\n if (abortController.signal.aborted) return [];\n\n return results.slice(0, MAX_RESULTS).map((result) => ({\n title: result.title,\n href: result.href,\n description: buildDescriptionSnippet(result.content, result.terms),\n }));\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n return [];\n }\n console.error(\"Search error:\", error);\n return [];\n }\n };\n};\n"],"names":["cachedIndex","buildDescriptionSnippet","content","terms","length","lowerContent","toLowerCase","matches","term","lowerTerm","start","indexOf","end","push","sort","a","b","ranges","match","reduce","acc","range","prevRange","snippetStart","Math","max","snippetEnd","min","map","slice","join","createStaticSearcher","indexUrl","async","search","abortController","trim","searchIndex","response","fetch","ok","Error","statusText","data","json","MiniSearch","loadJSAsync","fields","storeFields","searchOptions","boost","title","headings","description","fuzzy","loadSearchIndex","signal","aborted","results","prefix","result","href","error","name","console"],"mappings":"0BAIA,IAAIA,EAAkD,KAEtD,MAGMC,EAA0B,CAACC,EAAiBC,KAC9C,IAAKD,IAAYC,EAAMC,OAAQ,OAAOF,EAEtC,MAAMG,EAAeH,EAAQI,cACvBC,EAAiD,GAEvD,IAAK,MAAMC,KAAQL,EAAO,CACtB,MAAMM,EAAYD,EAAKF,cACvB,IAAII,EAAQL,EAAaM,QAAQF,GACjC,MAAiB,IAAVC,GAAc,CACjB,MAAME,EAAMF,EAAQD,EAAUL,OAC9BG,EAAQM,KAAK,CAAEH,QAAOE,QACtBF,EAAQL,EAAaM,QAAQF,EAAWG,EAC5C,CACJ,CAEA,IAAKL,EAAQH,OAAQ,OAAOF,EAE5BK,EAAQO,KAAK,CAACC,EAAGC,IAAMD,EAAEL,MAAQM,EAAEN,OACnC,MAAMO,EAAgD,GAEtD,IAAK,MAAMC,KAASX,EAAS,CACzB,GAAIU,EAAOE,OAAO,CAACC,EAAKC,IAAUD,EAAMC,EAAMT,IAAMS,EAAMX,MAAO,GAxBvD,IAwBuE,MACjF,MAAMY,EAAYL,EAAOA,EAAOb,OAAS,GAEzC,GAAIkB,GAAaA,EAAUV,IAAM,GAAKM,EAAMR,MAAO,CAC/CY,EAAUV,IAAMM,EAAMN,IACtB,QACJ,CAEA,MAAMW,EAAeC,KAAKC,IAAI,EAAGP,EAAMR,MAAQ,IACzCgB,EAAaF,KAAKG,IAAIzB,EAAQE,OAAQc,EAAMN,IAAM,IAEpDc,EAAaH,EAAe,IAIhCN,EAAOJ,KAAK,CAAEH,MAAOa,EAAcX,IAAKc,GAC5C,CAEA,MAAO,CACHT,EAAO,GAAGP,MAAQ,EAAI,MAAQ,GAC9BO,EAAOW,IAAKP,GAAUnB,EAAQ2B,MAAMR,EAAMX,MAAOW,EAAMT,MAAMkB,KAAK,SAClEb,EAAOA,EAAOb,OAAS,GAAGQ,IAAMV,EAAQE,OAAS,MAAQ,IAC3D0B,KAAK,KAyCEC,EAAwBC,GAC1BC,MAAOC,EAAgBC,KAC1B,IAAKD,EAAOE,OAAQ,MAAO,GAE3B,IACI,MAAMC,OA3CMJ,OAAOD,IAC3B,GAAIhC,EAAa,OAAOA,EAExB,MAAMsC,QAAiBC,MAAMP,GAC7B,IAAKM,EAASE,GACV,MAAM,IAAIC,MAAM,gCAAgCH,EAASI,cAG7D,MAAMC,QAA4BL,EAASM,OACrCP,QAAoBQ,EAAWC,YAAYH,EAAM,CACnDI,OAAQ,CAAC,QAAS,UAAW,WAAY,eACzCC,YAAa,CAAC,KAAM,QAAS,OAAQ,WAAY,cAAe,WAChEC,cAAe,CACXC,MAAO,CAAEC,MAAO,EAAGC,SAAU,EAAGC,YAAa,GAC7CC,MAAO,MAMf,OAFAtD,EAAcqC,EAEPA,GAuB2BkB,CAAgBvB,GAE1C,GAAIG,EAAgBqB,OAAOC,QAAS,MAAO,GAE3C,MAAMC,EAAUrB,EAAYH,OAAOA,EAAQ,CACvCoB,MAAO,GACPK,QAAQ,EACRT,MAAO,CAAEC,MAAO,EAAGC,SAAU,EAAGC,YAAa,KAGjD,OAAIlB,EAAgBqB,OAAOC,QAAgB,GAEpCC,EAAQ7B,MAAM,EAzGb,IAyG6BD,IAAKgC,IAAM,CAC5CT,MAAOS,EAAOT,MACdU,KAAMD,EAAOC,KACbR,YAAapD,EAAwB2D,EAAO1D,QAAS0D,EAAOzD,SAEpE,CAAE,MAAO2D,GACL,OAAIA,aAAiBrB,OAAwB,eAAfqB,EAAMC,MAGpCC,QAAQF,MAAM,gBAAiBA,GAFpB,EAIf"}
@@ -1,2 +1,2 @@
1
- import{mkdir as t,writeFile as i}from"fs/promises";import{lexer as e}from"marked";import{dirname as n}from"path";import o from"minisearch";import s from"gray-matter";const r=t=>t?"tokens"in t?t.tokens?.map(t=>r(t)).join("")||"":"text"in t?t.text:"raw"in t?t.raw:"":"",a=t=>{const{content:i,data:n}=s(t),o=e(i.trim());let a=n.title||"",c=n.description||"";const p=[],d=[];return o.forEach(t=>{if("heading"===t.type){const i=r(t);return void(i&&(a||(a=i),d.push(i),p.push(i)))}if("paragraph"===t.type){const i=r(t);return void(i&&(c||(c=i),p.push(i)))}["list","blockquote","table"].includes(t.type)&&p.push(r(t))}),{title:a,description:c,headings:d.join(" ").trim(),plainText:p.join(" ").trim()}},c=async(e,s,r)=>{const c=[],p=await e();for(const t of p){const i=`/${t.segments.join("/")}`;try{const t=await s(i);if(!t)continue;const e=a(t.raw),n=t.title||e.title,o=e.description||e.plainText.substring(0,200).trim();c.push({id:i,title:n,href:i,headings:e.headings,content:e.plainText,description:o})}catch(t){console.warn(`Failed to index page ${i}:`,t)}}const d=new o({fields:["title","content","headings","description"],storeFields:["id","title","href","headings","description"],searchOptions:{boost:{title:5,headings:3,description:2},fuzzy:.2}});await Promise.all([d.addAllAsync(c),t(n(r),{recursive:!0})]),await i(r,JSON.stringify(d.toJSON()),"utf-8")};export{c as generateSearchIndex};
1
+ import{mkdir as t,writeFile as i}from"fs/promises";import{lexer as e}from"marked";import{dirname as n}from"path";import o from"minisearch";import s from"gray-matter";const r=t=>t?"tokens"in t?t.tokens?.map(t=>r(t)).join("")||"":"text"in t?t.text:"raw"in t?t.raw:"":"",a=t=>{const{content:i,data:n}=s(t),o=e(i.trim());let a=n.title||"",c=n.description||"";const p=[],d=[];return o.forEach(t=>{if("heading"===t.type){const i=r(t);return void(i&&(a||(a=i),d.push(i),p.push(i)))}if("paragraph"===t.type){const i=r(t);return void(i&&(c||(c=i),p.push(i)))}["list","blockquote","table"].includes(t.type)&&p.push(r(t))}),{title:a,description:c,headings:d.join(" ").trim(),plainText:p.join(" ").trim()}},c=async(e,s,r)=>{const c=[],p=await e();for(const t of p){const i=`/${t.segments.join("/")}`;try{const t=await s(i);if(!t)continue;const e=a(t.raw),n=t.title||e.title,o=e.description||e.plainText.substring(0,200).trim();c.push({id:i,title:n,href:i,headings:e.headings,content:e.plainText,description:o})}catch(t){console.warn(`Failed to index page ${i}:`,t)}}const d=new o({fields:["title","content","headings","description"],storeFields:["id","title","href","headings","description","content"],searchOptions:{boost:{title:5,headings:3,description:2},fuzzy:.2}});await Promise.all([d.addAllAsync(c),t(n(r),{recursive:!0})]),await i(r,JSON.stringify(d.toJSON()),"utf-8")};export{c as generateSearchIndex};
2
2
  //# sourceMappingURL=generate-search-index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-search-index.js","sources":["../src/generate-search-index.ts"],"sourcesContent":["import { writeFile, mkdir } from \"fs/promises\";\nimport { lexer, type Token } from \"marked\";\nimport { dirname } from \"path\";\nimport MiniSearch from \"minisearch\";\nimport matter from \"gray-matter\";\n\nimport { type GetPageDataFunction, type GetStaticParamsFunction, type SearchIndexItem } from \"./types\";\n\nconst parseTokenText = (token: Token): string => {\n if (!token) return \"\";\n\n if (\"tokens\" in token) {\n return token.tokens?.map((el: Token) => parseTokenText(el)).join(\"\") || \"\";\n }\n\n if (\"text\" in token) {\n return token.text;\n }\n\n if (\"raw\" in token) {\n return token.raw;\n }\n\n return \"\";\n};\n\nconst parseMarkdownContent = (rawContent: string) => {\n const { content: matterContent, data: matterData } = matter(rawContent);\n const tokens = lexer(matterContent.trim());\n\n let title = matterData.title || \"\";\n let description = matterData.description || \"\";\n const plainTextParts: string[] = [];\n\n const headings: string[] = [];\n tokens.forEach((token: Token) => {\n if (token.type === \"heading\") {\n const headingText = parseTokenText(token);\n if (headingText) {\n if (!title) title = headingText;\n headings.push(headingText);\n plainTextParts.push(headingText);\n }\n return;\n }\n if (token.type === \"paragraph\") {\n const paragraphText = parseTokenText(token);\n if (paragraphText) {\n if (!description) description = paragraphText;\n plainTextParts.push(paragraphText);\n }\n return;\n }\n if ([\"list\", \"blockquote\", \"table\"].includes(token.type)) {\n plainTextParts.push(parseTokenText(token));\n return;\n }\n });\n\n return {\n title,\n description,\n headings: headings.join(\" \").trim(),\n plainText: plainTextParts.join(\" \").trim(),\n };\n};\n\n/**\n * Generates a static search index from all documentation pages.\n * Processes markdown content and creates a MiniSearch index file.\n *\n * @example\n * ```ts\n * import { generateSearchIndex } from \"@robindoc/minisearch\";\n * import { getStaticParams, getPageData } from \"./robindoc\";\n *\n * await generateSearchIndex(\n * getStaticParams,\n * getPageData,\n * \"./public/search-index.json\"\n * );\n * ```\n *\n * @see {@link https://robindoc.com/docs/customization/search Search integration}\n */\nexport const generateSearchIndex = async (\n getStaticParams: GetStaticParamsFunction,\n getPageData: GetPageDataFunction,\n outputPath: string,\n): Promise<void> => {\n const searchItems: SearchIndexItem[] = [];\n\n const staticParams = await getStaticParams();\n\n for (const staticParam of staticParams) {\n const pathname = `/${staticParam.segments.join(\"/\")}`;\n try {\n const pageData = await getPageData(pathname);\n\n if (!pageData) continue;\n\n const parsed = parseMarkdownContent(pageData.raw);\n const title = pageData.title || parsed.title;\n const description = parsed.description || parsed.plainText.substring(0, 200).trim();\n\n searchItems.push({\n id: pathname,\n title,\n href: pathname,\n headings: parsed.headings,\n content: parsed.plainText,\n description,\n });\n } catch (error) {\n console.warn(`Failed to index page ${pathname}:`, error);\n }\n }\n\n const searchIndex = new MiniSearch<SearchIndexItem>({\n fields: [\"title\", \"content\", \"headings\", \"description\"],\n storeFields: [\"id\", \"title\", \"href\", \"headings\", \"description\"],\n searchOptions: {\n boost: { title: 5, headings: 3, description: 2 },\n fuzzy: 0.2,\n },\n });\n\n await Promise.all([searchIndex.addAllAsync(searchItems), mkdir(dirname(outputPath), { recursive: true })]);\n await writeFile(outputPath, JSON.stringify(searchIndex.toJSON()), \"utf-8\");\n};\n"],"names":["parseTokenText","token","tokens","map","el","join","text","raw","parseMarkdownContent","rawContent","content","matterContent","data","matterData","matter","lexer","trim","title","description","plainTextParts","headings","forEach","type","headingText","push","paragraphText","includes","plainText","generateSearchIndex","async","getStaticParams","getPageData","outputPath","searchItems","staticParams","staticParam","pathname","segments","pageData","parsed","substring","id","href","error","console","warn","searchIndex","MiniSearch","fields","storeFields","searchOptions","boost","fuzzy","Promise","all","addAllAsync","mkdir","dirname","recursive","writeFile","JSON","stringify","toJSON"],"mappings":"sKAQA,MAAMA,EAAkBC,GACfA,EAED,WAAYA,EACLA,EAAMC,QAAQC,IAAKC,GAAcJ,EAAeI,IAAKC,KAAK,KAAO,GAGxE,SAAUJ,EACHA,EAAMK,KAGb,QAASL,EACFA,EAAMM,IAGV,GAdY,GAiBjBC,EAAwBC,IAC1B,MAAQC,QAASC,EAAeC,KAAMC,GAAeC,EAAOL,GACtDP,EAASa,EAAMJ,EAAcK,QAEnC,IAAIC,EAAQJ,EAAWI,OAAS,GAC5BC,EAAcL,EAAWK,aAAe,GAC5C,MAAMC,EAA2B,GAE3BC,EAAqB,GAyB3B,OAxBAlB,EAAOmB,QAASpB,IACZ,GAAmB,YAAfA,EAAMqB,KAAoB,CAC1B,MAAMC,EAAcvB,EAAeC,GAMnC,YALIsB,IACKN,IAAOA,EAAQM,GACpBH,EAASI,KAAKD,GACdJ,EAAeK,KAAKD,IAG5B,CACA,GAAmB,cAAftB,EAAMqB,KAAsB,CAC5B,MAAMG,EAAgBzB,EAAeC,GAKrC,YAJIwB,IACKP,IAAaA,EAAcO,GAChCN,EAAeK,KAAKC,IAG5B,CACI,CAAC,OAAQ,aAAc,SAASC,SAASzB,EAAMqB,OAC/CH,EAAeK,KAAKxB,EAAeC,MAKpC,CACHgB,QACAC,cACAE,SAAUA,EAASf,KAAK,KAAKW,OAC7BW,UAAWR,EAAed,KAAK,KAAKW,SAsB/BY,EAAsBC,MAC/BC,EACAC,EACAC,KAEA,MAAMC,EAAiC,GAEjCC,QAAqBJ,IAE3B,IAAK,MAAMK,KAAeD,EAAc,CACpC,MAAME,EAAW,IAAID,EAAYE,SAAShC,KAAK,OAC/C,IACI,MAAMiC,QAAiBP,EAAYK,GAEnC,IAAKE,EAAU,SAEf,MAAMC,EAAS/B,EAAqB8B,EAAS/B,KACvCU,EAAQqB,EAASrB,OAASsB,EAAOtB,MACjCC,EAAcqB,EAAOrB,aAAeqB,EAAOZ,UAAUa,UAAU,EAAG,KAAKxB,OAE7EiB,EAAYT,KAAK,CACbiB,GAAIL,EACJnB,QACAyB,KAAMN,EACNhB,SAAUmB,EAAOnB,SACjBV,QAAS6B,EAAOZ,UAChBT,eAER,CAAE,MAAOyB,GACLC,QAAQC,KAAK,wBAAwBT,KAAaO,EACtD,CACJ,CAEA,MAAMG,EAAc,IAAIC,EAA4B,CAChDC,OAAQ,CAAC,QAAS,UAAW,WAAY,eACzCC,YAAa,CAAC,KAAM,QAAS,OAAQ,WAAY,eACjDC,cAAe,CACXC,MAAO,CAAElC,MAAO,EAAGG,SAAU,EAAGF,YAAa,GAC7CkC,MAAO,YAITC,QAAQC,IAAI,CAACR,EAAYS,YAAYtB,GAAcuB,EAAMC,EAAQzB,GAAa,CAAE0B,WAAW,YAC3FC,EAAU3B,EAAY4B,KAAKC,UAAUf,EAAYgB,UAAW"}
1
+ {"version":3,"file":"generate-search-index.js","sources":["../src/generate-search-index.ts"],"sourcesContent":["import { writeFile, mkdir } from \"fs/promises\";\nimport { lexer, type Token } from \"marked\";\nimport { dirname } from \"path\";\nimport MiniSearch from \"minisearch\";\nimport matter from \"gray-matter\";\n\nimport { type GetPageDataFunction, type GetStaticParamsFunction, type SearchIndexItem } from \"./types\";\n\nconst parseTokenText = (token: Token): string => {\n if (!token) return \"\";\n\n if (\"tokens\" in token) {\n return token.tokens?.map((el: Token) => parseTokenText(el)).join(\"\") || \"\";\n }\n\n if (\"text\" in token) {\n return token.text;\n }\n\n if (\"raw\" in token) {\n return token.raw;\n }\n\n return \"\";\n};\n\nconst parseMarkdownContent = (rawContent: string) => {\n const { content: matterContent, data: matterData } = matter(rawContent);\n const tokens = lexer(matterContent.trim());\n\n let title = matterData.title || \"\";\n let description = matterData.description || \"\";\n const plainTextParts: string[] = [];\n\n const headings: string[] = [];\n tokens.forEach((token: Token) => {\n if (token.type === \"heading\") {\n const headingText = parseTokenText(token);\n if (headingText) {\n if (!title) title = headingText;\n headings.push(headingText);\n plainTextParts.push(headingText);\n }\n return;\n }\n if (token.type === \"paragraph\") {\n const paragraphText = parseTokenText(token);\n if (paragraphText) {\n if (!description) description = paragraphText;\n plainTextParts.push(paragraphText);\n }\n return;\n }\n if ([\"list\", \"blockquote\", \"table\"].includes(token.type)) {\n plainTextParts.push(parseTokenText(token));\n return;\n }\n });\n\n return {\n title,\n description,\n headings: headings.join(\" \").trim(),\n plainText: plainTextParts.join(\" \").trim(),\n };\n};\n\n/**\n * Generates a static search index from all documentation pages.\n * Processes markdown content and creates a MiniSearch index file.\n *\n * @example\n * ```ts\n * import { generateSearchIndex } from \"@robindoc/minisearch\";\n * import { getStaticParams, getPageData } from \"./robindoc\";\n *\n * await generateSearchIndex(\n * getStaticParams,\n * getPageData,\n * \"./public/search-index.json\"\n * );\n * ```\n *\n * @see {@link https://robindoc.com/docs/customization/search Search integration}\n */\nexport const generateSearchIndex = async (\n getStaticParams: GetStaticParamsFunction,\n getPageData: GetPageDataFunction,\n outputPath: string,\n): Promise<void> => {\n const searchItems: SearchIndexItem[] = [];\n\n const staticParams = await getStaticParams();\n\n for (const staticParam of staticParams) {\n const pathname = `/${staticParam.segments.join(\"/\")}`;\n try {\n const pageData = await getPageData(pathname);\n\n if (!pageData) continue;\n\n const parsed = parseMarkdownContent(pageData.raw);\n const title = pageData.title || parsed.title;\n const description = parsed.description || parsed.plainText.substring(0, 200).trim();\n\n searchItems.push({\n id: pathname,\n title,\n href: pathname,\n headings: parsed.headings,\n content: parsed.plainText,\n description,\n });\n } catch (error) {\n console.warn(`Failed to index page ${pathname}:`, error);\n }\n }\n\n const searchIndex = new MiniSearch<SearchIndexItem>({\n fields: [\"title\", \"content\", \"headings\", \"description\"],\n storeFields: [\"id\", \"title\", \"href\", \"headings\", \"description\", \"content\"],\n searchOptions: {\n boost: { title: 5, headings: 3, description: 2 },\n fuzzy: 0.2,\n },\n });\n\n await Promise.all([searchIndex.addAllAsync(searchItems), mkdir(dirname(outputPath), { recursive: true })]);\n await writeFile(outputPath, JSON.stringify(searchIndex.toJSON()), \"utf-8\");\n};\n"],"names":["parseTokenText","token","tokens","map","el","join","text","raw","parseMarkdownContent","rawContent","content","matterContent","data","matterData","matter","lexer","trim","title","description","plainTextParts","headings","forEach","type","headingText","push","paragraphText","includes","plainText","generateSearchIndex","async","getStaticParams","getPageData","outputPath","searchItems","staticParams","staticParam","pathname","segments","pageData","parsed","substring","id","href","error","console","warn","searchIndex","MiniSearch","fields","storeFields","searchOptions","boost","fuzzy","Promise","all","addAllAsync","mkdir","dirname","recursive","writeFile","JSON","stringify","toJSON"],"mappings":"sKAQA,MAAMA,EAAkBC,GACfA,EAED,WAAYA,EACLA,EAAMC,QAAQC,IAAKC,GAAcJ,EAAeI,IAAKC,KAAK,KAAO,GAGxE,SAAUJ,EACHA,EAAMK,KAGb,QAASL,EACFA,EAAMM,IAGV,GAdY,GAiBjBC,EAAwBC,IAC1B,MAAQC,QAASC,EAAeC,KAAMC,GAAeC,EAAOL,GACtDP,EAASa,EAAMJ,EAAcK,QAEnC,IAAIC,EAAQJ,EAAWI,OAAS,GAC5BC,EAAcL,EAAWK,aAAe,GAC5C,MAAMC,EAA2B,GAE3BC,EAAqB,GAyB3B,OAxBAlB,EAAOmB,QAASpB,IACZ,GAAmB,YAAfA,EAAMqB,KAAoB,CAC1B,MAAMC,EAAcvB,EAAeC,GAMnC,YALIsB,IACKN,IAAOA,EAAQM,GACpBH,EAASI,KAAKD,GACdJ,EAAeK,KAAKD,IAG5B,CACA,GAAmB,cAAftB,EAAMqB,KAAsB,CAC5B,MAAMG,EAAgBzB,EAAeC,GAKrC,YAJIwB,IACKP,IAAaA,EAAcO,GAChCN,EAAeK,KAAKC,IAG5B,CACI,CAAC,OAAQ,aAAc,SAASC,SAASzB,EAAMqB,OAC/CH,EAAeK,KAAKxB,EAAeC,MAKpC,CACHgB,QACAC,cACAE,SAAUA,EAASf,KAAK,KAAKW,OAC7BW,UAAWR,EAAed,KAAK,KAAKW,SAsB/BY,EAAsBC,MAC/BC,EACAC,EACAC,KAEA,MAAMC,EAAiC,GAEjCC,QAAqBJ,IAE3B,IAAK,MAAMK,KAAeD,EAAc,CACpC,MAAME,EAAW,IAAID,EAAYE,SAAShC,KAAK,OAC/C,IACI,MAAMiC,QAAiBP,EAAYK,GAEnC,IAAKE,EAAU,SAEf,MAAMC,EAAS/B,EAAqB8B,EAAS/B,KACvCU,EAAQqB,EAASrB,OAASsB,EAAOtB,MACjCC,EAAcqB,EAAOrB,aAAeqB,EAAOZ,UAAUa,UAAU,EAAG,KAAKxB,OAE7EiB,EAAYT,KAAK,CACbiB,GAAIL,EACJnB,QACAyB,KAAMN,EACNhB,SAAUmB,EAAOnB,SACjBV,QAAS6B,EAAOZ,UAChBT,eAER,CAAE,MAAOyB,GACLC,QAAQC,KAAK,wBAAwBT,KAAaO,EACtD,CACJ,CAEA,MAAMG,EAAc,IAAIC,EAA4B,CAChDC,OAAQ,CAAC,QAAS,UAAW,WAAY,eACzCC,YAAa,CAAC,KAAM,QAAS,OAAQ,WAAY,cAAe,WAChEC,cAAe,CACXC,MAAO,CAAElC,MAAO,EAAGG,SAAU,EAAGF,YAAa,GAC7CkC,MAAO,YAITC,QAAQC,IAAI,CAACR,EAAYS,YAAYtB,GAAcuB,EAAMC,EAAQzB,GAAa,CAAE0B,WAAW,YAC3FC,EAAU3B,EAAY4B,KAAKC,UAAUf,EAAYgB,UAAW"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robindoc/minisearch",
3
- "version": "3.7.1",
3
+ "version": "3.7.3",
4
4
  "description": "MiniSearch integration for robindoc documentation sites",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {