🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

staticsearch

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

staticsearch - npm Package Compare versions

Comparing version
0.2.1
to
0.3.0
+1
-1
dist/css/component.css

@@ -1,1 +0,1 @@

:host{--fsize: var(--staticsearch-fontsize, 1em);--dmax: var(--staticsearch-maxwidth, 60ch);--dmargin: var(--staticsearch-margin, 3vmin);--dpadding: var(--staticsearch-padding, 2vmin);--sheight: var(--staticsearch-fieldset-height, calc(3em + (2 * var(--dpadding))) );--colback0: var(--staticsearch-color-back, Canvas);--colbord0: var(--staticsearch-color-border, ButtonFace);--colfore0: var(--staticsearch-color-fore, CanvasText);--colfore1: var(--staticsearch-color-dim, color-mix(in oklab, CanvasText 70%, Canvas));--collinkd: var(--staticsearch-color-link, color-mix(in oklab, LinkText 70%, CanvasText));--collinkv: var(--staticsearch-color-visited, color-mix(in oklab, VisitedText 70%, CanvasText));--colshad0: var(--staticsearch-color-shadow, #000);--colshad1: var(--staticsearch-color-backdrop, color-mix(in srgb, var(--colshad0), transparent 30%));--colblur0: var(--staticsearch-backdrop-blur, 3px)}template{display:none}*{box-sizing:border-box;font-size:inherit;padding:0;margin:0}@media (prefers-reduced-motion: reduce){*,*:before,*:after,::backdrop{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;transition-behavior:normal!important;scroll-behavior:auto!important}}dialog{position:fixed;font-size:var(--fsize);inline-size:var(--dmax);block-size:100%;max-inline-size:calc(100dvw - (2 * var(--dmargin)));max-block-size:calc(100dvh - (2 * var(--dmargin)));margin:auto;padding:0;color:var(--colfore0);background-color:var(--colback0);border:1px solid var(--colbord0);border-radius:5px;box-shadow:0 2px 4px var(--colshad0);overflow:hidden;transform-origin:50% 0;&,&::backdrop{transition:all .3s ease-in-out;transition-behavior:allow-discrete}&[open]{opacity:1;transform:scale(1);@starting-style{display:block;opacity:.5;transform:scaleX(.5) scaleY(0)}&::backdrop{background-color:var(--colshad1);-webkit-backdrop-filter:blur(var(--colblur0));backdrop-filter:blur(var(--colblur0));@starting-style{background-color:#0000;-webkit-backdrop-filter:blur(0);backdrop-filter:blur(0)}}}&:not([open]){display:none;opacity:0;transform:scaleX(.5) scaleY(0)}}[part=close]{position:absolute;inset-inline-end:0;inset-block-start:0;block-size:1.4em;inline-size:1.4em;min-block-size:unset;min-inline-size:unset;padding:0;margin:0;background-color:transparent;border:0 none;cursor:pointer;z-index:3;&:is(:hover,:focus,:active){color:var(--collinkd)}}[part=search]{position:absolute;block-size:var(--sheight);inset-inline:0;inset-block-start:0;padding-inline:var(--dpadding);padding-block-start:var(--dpadding);box-shadow:0 1px 5px var(--colshad0);overflow:hidden;z-index:2;&:focus-within{label,input{color:var(--colfore0)}input{border-color:var(--colfore1)}}}[part=searchlabel]{display:block;font-size:.8em;padding-inline-start:.625em;padding-block-end:.2em;color:var(--colfore1);-webkit-user-select:none;user-select:none}input[part=searchinput]{display:block;width:100%;line-height:1.5;padding-block:.2em;padding-inline:.5em;color:var(--colfore1);background-color:var(--colback0);border:1px solid transparent;border-radius:3px;outline-style:none}[part=results]{position:absolute;inset-inline:0;inset-block:0;inset-block-start:var(--sheight);padding:var(--dpadding);overflow-x:hidden;overflow-y:auto;&:after{position:fixed;content:"";block-size:5vh;inset-inline:0;inset-block-end:0;background:linear-gradient(transparent,var(--colback0));pointer-events:none}}[part=searchterm]{font-style:italic;&:before,&:after{content:'"'}}[part=item]{margin-block:1.5em;margin-inline-start:1.5em}[part=title]{font-weight:bolder;line-height:1.2;text-wrap:balance;text-underline-offset:.2em;margin-block-end:.1em}[part=description]{font-size:.8em;line-height:1.4;text-wrap:pretty;color:var(--colfore1)}a:focus-visible{outline-color:var(--collinkd);outline-style:solid;outline-offset:.2em;outline-width:.2rem}a:link{display:block;text-decoration:none;color:var(--collinkd)}a:visited{color:var(--collinkv)}a:hover,a:focus,a:active{color:var(--collinkd);[part=title]{text-decoration:underline}[part=description]{color:var(--colfore0)}}
:host{--fsize: var(--staticsearch-fontsize, 1em);--dmax: var(--staticsearch-maxwidth, 60ch);--dmargin: var(--staticsearch-margin, 3vmin);--dpadding: var(--staticsearch-padding, 2vmin);--sheight: var(--staticsearch-fieldset-height, calc(3em + (2 * var(--dpadding))) );--colback0: var(--staticsearch-color-back, Canvas);--colbord0: var(--staticsearch-color-border, ButtonFace);--colfore0: var(--staticsearch-color-fore0, CanvasText);--colfore1: var(--staticsearch-color-fore1, color-mix(in oklab, CanvasText 80%, Canvas));--colfore2: var(--staticsearch-color-fore2, color-mix(in oklab, CanvasText 60%, Canvas));--collinkd: var(--staticsearch-color-link, color-mix(in oklab, LinkText 80%, CanvasText));--collinkv: var(--staticsearch-color-visited, color-mix(in oklab, VisitedText 80%, CanvasText));--colshad0: var(--staticsearch-color-shadow, #000);--colshad1: var(--staticsearch-color-backdrop, color-mix(in srgb, var(--colshad0), transparent 25%));--colblur0: var(--staticsearch-backdrop-blur, 3px)}template{display:none}*{box-sizing:border-box;font-size:inherit;padding:0;margin:0}@media (prefers-reduced-motion: reduce){*,*:before,*:after,::backdrop{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;transition-behavior:normal!important;scroll-behavior:auto!important}}dialog{position:fixed;font-size:var(--fsize);inline-size:var(--dmax);block-size:100%;max-inline-size:calc(100dvw - (2 * var(--dmargin)));max-block-size:calc(100dvh - (2 * var(--dmargin)));margin:auto;padding:0;color:var(--colfore0);background-color:var(--colback0);border:1px solid var(--colbord0);border-radius:5px;box-shadow:0 2px 4px var(--colshad0);overflow:hidden;transform-origin:50% 0;&,&::backdrop{transition:all .3s ease-in-out;transition-behavior:allow-discrete}&[open]{opacity:1;transform:scale(1);@starting-style{display:block;opacity:.5;transform:scaleX(.5) scaleY(0)}&::backdrop{background-color:var(--colshad1);-webkit-backdrop-filter:blur(var(--colblur0));backdrop-filter:blur(var(--colblur0));@starting-style{background-color:#0000;-webkit-backdrop-filter:blur(0);backdrop-filter:blur(0)}}}&:not([open]){display:none;opacity:0;transform:scaleX(.5) scaleY(0)}}[part=close]{position:absolute;inset-inline-end:0;inset-block-start:0;block-size:1.4em;inline-size:1.4em;min-block-size:unset;min-inline-size:unset;padding:0;margin:0;background-color:transparent;border:0 none;cursor:pointer;z-index:3;&:is(:hover,:focus,:active){color:var(--collinkd)}}[part=search]{position:absolute;block-size:var(--sheight);inset-inline:0;inset-block-start:0;padding-inline:var(--dpadding);padding-block-start:var(--dpadding);box-shadow:0 1px 5px var(--colshad0);overflow:hidden;z-index:2;&:focus-within{label,input{color:var(--colfore0)}input{border-color:var(--colfore1)}}}[part=searchlabel]{display:block;font-size:.8em;padding-inline-start:.625em;padding-block-end:.2em;color:var(--colfore1);-webkit-user-select:none;user-select:none}input[part=searchinput]{display:block;inline-size:100%;line-height:1.5;padding-block:.2em;padding-inline:.5em;color:var(--colfore1);background-color:transparent;border:1px solid transparent;border-radius:3px;outline-style:none}[part=results]{position:absolute;inset-inline:0;inset-block:0;inset-block-start:var(--sheight);padding:var(--dpadding);overflow-x:hidden;overflow-y:auto;&:after{position:fixed;content:"";block-size:5vh;inset-inline:0;inset-block-end:0;background:linear-gradient(transparent,var(--colback0));pointer-events:none}}[part=searchterm]{font-style:italic;&:before,&:after{content:'"'}}[part=item]{margin-block:1.5em;margin-inline-start:1.5em}[part=title]{font-weight:bolder;line-height:1.2;text-wrap:balance;text-underline-offset:.2em;margin-block-end:.1em}[part=meta]{font-size:.75em;line-height:1.4;color:var(--colfore2)}[part=description]{font-size:.85em;line-height:1.4;text-wrap:pretty;color:var(--colfore1)}a:focus-visible{outline-color:var(--collinkd);outline-style:solid;outline-offset:.2em;outline-width:.2rem}a:link{display:block;text-decoration:none;color:var(--collinkd)}a:visited{color:var(--collinkv)}a:hover,a:focus,a:active{color:var(--collinkd);[part=title]{text-decoration:underline}}

@@ -1,1 +0,1 @@

import{staticsearch as m}from"./__SSDIR__/staticsearch.js";var f="q",S=0,y="__AGENT__",E=Symbol(y),b=500;(()=>{let t=document.getElementById("staticsearch_search"),r=document.getElementById("staticsearch_result");r&&L(r,r.getAttribute("minscore"),r.getAttribute("maxresults")),t&&t.tagName==="INPUT"&&C(t)})();function v(){return new URLSearchParams(location.search).get(f)||""}function I(t,r){let n=new URL(location);t?n.searchParams.set(f,t):n.searchParams.delete(f),n.hash=r||"",history.replaceState({},"",n.href)}function C(t){if(t[E])return;t[E]=!0,t.name&&(f=t.name);let r=v()||sessionStorage.getItem(y)||"";r&&(t.value=r);let n=t.value;n&&a(n);let p;t.addEventListener("input",s=>{let c=s.target.value;clearTimeout(p),p=setTimeout(()=>a(c),b)},!1);function a(s){sessionStorage.setItem(y,s),!(s.length<2)&&m.find(s).then(c=>{})}}function L(t,r,n,p,a,s){if(t[E])return;t[E]=!0;let c="";r=parseFloat(r)||0,n=parseFloat(n)||0,a=a||document.getElementById("staticsearch_resultmessage"),a||(a=document.createElement("template"),a.innerHTML='<p part="resultmessage"><span part="resultcount">0</span> found for <span part="searchterm"></span>&hellip;</p>'),s=s||document.getElementById("staticsearch_item"),s||(s=document.createElement("template"),s.innerHTML='<li part="item"><a part="link"><h2 part="title"></h2><p part="description"></p></a></li>'),t.addEventListener("click",i=>{let l=i.target.closest("a");l&&c&&I(c,l.id)}),document.addEventListener("staticsearch:result",i=>{c=i.detail.search;let l=i.detail.result;t.innerHTML="";let o=document.createElement(p||"ol");o.setAttribute("part","searchresult"),l.forEach((e,g)=>{if(r&&e.relevancy<r||n&&g>=n)return;let u=s.content.cloneNode(!0);h(u,"link",null,{href:e.url,id:`staticsearchresult-${e.id}`}),h(u,"title",e.title),h(u,"description",e.description),o.appendChild(u)});let d=a.content.cloneNode(!0);if(h(d,"resultcount",o.childElementCount),h(d,"searchterm",c),t.appendChild(d),t.appendChild(o),!S&&location.hash){let e=t.querySelector(location.hash);e&&(e.focus(),e.scrollIntoView({behavior:"smooth",block:"nearest"}))}else t.scrollTop=0;S++},!1);function h(i,l,o,d={}){i.querySelectorAll(`[part="${l}"]`).forEach(e=>{for(let[g,u]of Object.entries(d))e.setAttribute(g,u);if(o){for(;e.firstElementChild;)e=e.firstElementChild;e.textContent=o}})}}export{C as staticSearchInput,v as staticSearchQuery,L as staticSearchResult,I as staticSearchSetQuery};
import{staticsearch as b}from"./__SSDIR__/staticsearch.js";var f="q",T=0,S="__AGENT__",g=Symbol(S),w=500,y={date:new Intl.DateTimeFormat([],{dateStyle:"long"}).format,number:new Intl.NumberFormat([],{maximumFractionDigits:0}).format};(()=>{let e=document.getElementById("staticsearch_search"),a=document.getElementById("staticsearch_result");a&&C(a,{minScore:a.getAttribute("minscore"),maxResults:a.getAttribute("maxresults")}),e&&e.tagName==="INPUT"&&x(e)})();function I(){return new URLSearchParams(location.search).get(f)||""}function v(e,a){let r=new URL(location);e?r.searchParams.set(f,e):r.searchParams.delete(f),r.hash=a||"",history.replaceState({},"",r.href)}function x(e){if(e[g])return;e[g]=!0,e.name&&(f=e.name);let a=I()||sessionStorage.getItem(S)||"";a&&(e.value=a);let r=e.value;r&&p(r);let m;e.addEventListener("input",n=>{let o=n.target.value;clearTimeout(m),m=setTimeout(()=>p(o),w)},!1);function p(n){sessionStorage.setItem(S,n),!(n.length<2)&&b.find(n).then(o=>{})}}function C(e,a={}){if(e[g])return;e[g]=!0;let r="",m=parseFloat(a.minScore)||0,p=parseFloat(a.maxResults)||0,n=a.resultElement||"ol",o=a.messageTemplate||document.getElementById("staticsearch_resultmessage");o||(o=document.createElement("template"),o.innerHTML='<p part="resultmessage"><span part="resultcount">0</span> found for <span part="searchterm"></span>&hellip;</p>');let h=a.itemTemplate||document.getElementById("staticsearch_item");h||(h=document.createElement("template"),h.innerHTML='<li part="item"><a part="link"><h2 part="title"></h2><p part="meta"><time part="date"></time> &ndash; <span part="words">0</span> words</p><p part="description"></p></a></li>'),e.addEventListener("click",i=>{let u=i.target.closest("a");u&&r&&v(r,u.id)}),document.addEventListener("staticsearch:result",i=>{r=i.detail.search;let u=i.detail.result;e.innerHTML="";let l=document.createElement(n);l.setAttribute("part","searchresult"),u.forEach((t,E)=>{if(m&&t.relevancy<m||p&&E>=p)return;let s=h.content.cloneNode(!0);c(s,"link",null,{href:t.url,id:`staticsearchresult-${t.id}`}),c(s,"title",t.title),c(s,"description",t.description),t.date&&c(s,"date",y.date(new Date(t.date)),{datetime:t.date}),t.words&&c(s,"words",y.number(t.words)),l.appendChild(s)});let d=o.content.cloneNode(!0);if(c(d,"resultcount",l.childElementCount),c(d,"searchterm",r),e.appendChild(d),e.appendChild(l),!T&&location.hash){let t=e.querySelector(location.hash);t&&(t.focus(),t.scrollIntoView({behavior:"smooth",block:"nearest"}))}else e.scrollTop=0;T++},!1);function c(i,u,l,d={}){i.querySelectorAll(`[part="${u}"]`).forEach(t=>{for(let[E,s]of Object.entries(d))t.setAttribute(E,s);if(l){for(;t.firstElementChild;)t=t.firstElementChild;t.textContent=l}})}}export{x as staticSearchInput,I as staticSearchQuery,C as staticSearchResult,v as staticSearchSetQuery};

@@ -1,2 +0,2 @@

import{staticSearchQuery as h,staticSearchSetQuery as l,staticSearchInput as o,staticSearchResult as n}from"./__SSDIR__/staticsearch-bind.js";var a=class r extends HTMLElement{static path=new URL(import.meta.url).pathname.replace("__FILENAME__","");#t=null;#e=null;#i=null;constructor(){super()}connectedCallback(){let t=this.firstElementChild;if(this.attachShadow({mode:"open"}),!t)return;t.setAttribute("part","startsearch");let s=document.createElement("link");s.rel="stylesheet",s.href=`${r.path}css/component.css`,this.shadowRoot.appendChild(s);let i=this.shadowRoot.appendChild(t);this.#r(),i.style.cursor="pointer",i.addEventListener("click",e=>{e.preventDefault(),this.#s()}),window.addEventListener("keydown",e=>{e.key==="k"&&(e.ctrlKey||e.metaKey)&&(e.preventDefault(),this.#s())}),h()&&this.#s()}#s(){this.#t.open?this.#a():(this.#t.showModal(),this.setAttribute("aria-expanded","true"),this.#e.focus())}#a(){this.#t.close(),this.removeAttribute("aria-expanded"),l()}#r(){let t=document.createElement("dialog");t.setAttribute("closedby","any"),t.setAttribute("part","dialog"),t.innerHTML=`
import{staticSearchQuery as l,staticSearchSetQuery as h,staticSearchInput as o,staticSearchResult as n}from"./__SSDIR__/staticsearch-bind.js";var a=class r extends HTMLElement{static path=new URL(import.meta.url).pathname.replace("__FILENAME__","");#t=null;#e=null;#i=null;constructor(){super()}connectedCallback(){let t=this.firstElementChild;if(this.attachShadow({mode:"open"}),!t)return;t.setAttribute("part","startsearch");let s=document.createElement("link");s.rel="stylesheet",s.href=`${r.path}css/component.css`,this.shadowRoot.appendChild(s);let i=this.shadowRoot.appendChild(t);this.#r(),i.style.cursor="pointer",i.addEventListener("click",e=>{e.preventDefault(),this.#s()}),window.addEventListener("keydown",e=>{e.key==="k"&&(e.ctrlKey||e.metaKey)&&(e.preventDefault(),this.#s())}),l()&&this.#s()}#s(){this.#t.open?this.#a():(this.#t.showModal(),this.setAttribute("aria-expanded","true"),this.#e.focus())}#a(){this.#t.close(),this.removeAttribute("aria-expanded"),h()}#r(){let t=document.createElement("dialog");t.setAttribute("closedby","any"),t.setAttribute("part","dialog"),t.innerHTML=`
<form method="dialog"><button part="close"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path xmlns="http://www.w3.org/2000/svg" fill="currentColor" d="M5.3 5.3a1 1 0 0 1 1.4 0l5.3 5.3 5.3-5.3a1 1 0 1 1 1.4 1.4L13.4 12l5.3 5.3a1 1 0 0 1-1.4 1.4L12 13.4l-5.3 5.3a1 1 0 0 1-1.4-1.4l5.3-5.3-5.3-5.3a1 1 0 0 1 0-1.4Z"/></svg></button></form>

@@ -8,2 +8,2 @@ <search part="search">

<div part="results"></div>
`,this.#t=this.shadowRoot.appendChild(t),this.#e=this.shadowRoot.querySelector("#search"),this.#i=this.shadowRoot.querySelector('[part="results"]'),n(this.#i,this.getAttribute("minscore"),this.getAttribute("maxresults")),o(this.#e),this.#t.addEventListener("close",()=>this.#a()),this.#t.addEventListener("click",s=>{this.#t.open&&s.target===this.#t&&this.#a()})}};customElements.define("static-search",a);
`,this.#t=this.shadowRoot.appendChild(t),this.#e=this.shadowRoot.querySelector("#search"),this.#i=this.shadowRoot.querySelector('[part="results"]'),n(this.#i,{minScore:this.getAttribute("minscore"),maxResults:this.getAttribute("maxresults")}),o(this.#e),this.#t.addEventListener("close",()=>this.#a()),this.#t.addEventListener("click",s=>{this.#t.open&&s.target===this.#t&&this.#a()})}};customElements.define("static-search",a);

@@ -1,1 +0,1 @@

import{stem as p}from"./stem/__STEMFILE__";function d(o,e,t=7,r=new Set){return new Set(o.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[\u2018\u2019\u201A\u201B\u0027]/g,"").toLowerCase().replace(/[^a-z\s]/g," ").split(/\s+/g).map(s=>e(s.trim()).slice(0,t)).filter(s=>s.length>1&&!r.has(s)).sort())}var h=class{#t=null;#e=null;#r=null;constructor(o,e,t){return this.#e=o||"db",this.#r=e||1,this.#s(t)}connect(){return this.#s().then(()=>!0).catch(()=>!1)}close(){this.#t.close(),this.#t=null}#s(o){return new Promise((e,t)=>{if(!("indexedDB"in window)){t(new Error("No indexedDB support"));return}let r=indexedDB.open(this.#e,this.#r);r.onsuccess=()=>{this.#t=r.result,e(this)},r.onerror=s=>{t(new Error(`IndexedDB error ${s.target.errorCode}: ${s.target.message}`,{cause:s}))},o&&(r.onupgradeneeded=s=>{o(r.result,s.oldVersion,s.newVersion)})})}get isConnected(){return!!this.#t}get name(){return this.#e}get version(){return this.#r}#i(o,e,t){return new Promise((r,s)=>{let{transaction:a,store:i}=this.#a(o,null,!0);a.oncomplete=()=>r(),a.onerror=n=>{s(new Error(n.target.error.message,{cause:n}))},e=Array.isArray(e)?e:[e],e.forEach(n=>{t?i.put(n):i.add(n)}),a.commit()})}add({store:o,item:e=[]}={}){return this.#i(o,e,!1)}put({store:o,item:e=[]}={}){return this.#i(o,e,!0)}#o(o,e,t,r){return new Promise((s,a)=>{r=Array.isArray(r)?r:[r];let i=t==="delete"||t==="clear",n=this.#a(o,e,i).store[t](...r);n.onsuccess=()=>s(n.result),n.onerror=()=>a(n.error??!1)})}count({store:o,index:e,lowerBound:t,upperBound:r}={}){return this.#o(o,e,"count",this.#n(t,r))}get({store:o,index:e,key:t}={}){return this.#o(o,e,"get",t)}getAll({store:o,index:e,lowerBound:t,upperBound:r,count:s}={}){return this.#o(o,e,"getAll",[this.#n(t,r),s])}getAllKeys({store:o,index:e,lowerBound:t,upperBound:r,count:s}={}){return this.#o(o,e,"getAllKeys",[this.#n(t,r),s])}delete({store:o,key:e}={}){return this.#o(o,null,"delete",[e])}deleteAll({store:o,index:e,lowerBound:t,upperBound:r}={}){return this.#o(o,e,"delete",[this.#n(t,r)])}clear({store:o}={}){return this.#o(o,null,"clear")}getCursor({store:o,index:e,lowerBound:t,upperBound:r,direction:s="next",callback:a}={}){return new Promise((i,n)=>{let l=this.#a(o,e).store.openCursor(this.#n(t,r),s);l.onsuccess=()=>{let u=l.result;u?u.advance(a&&a(u)||1):i(!0)},l.onerror=()=>n(l.error)})}drop(){return new Promise((o,e)=>{this.close();let t=indexedDB.deleteDatabase(this.#e);t.onsuccess=()=>{this.#e=null,this.#r=null,o(!0)},t.onerror=()=>e(!1)})}#a(o,e,t){let r=this.#t.transaction(o,t?"readwrite":"readonly",{durability:t?"strict":"default"}),s=r.objectStore(o);return{transaction:r,store:e&&!t?s.index(e):s}}#n(o,e){let t;return o&&e?t=IDBKeyRange.bound(o,e):o?t=IDBKeyRange.lowerBound(o):e&&(t=IDBKeyRange.upperBound(e)),t}};var c=class o{static path=new URL(import.meta.url).pathname.replace("__FILENAME__","");static dbName="__AGENT__";static version="__VERSION__";static wordCrop=__WORDCROP__;#t=!1;#e=null;#r=null;fetchTimeout=5e3;constructor(){}async init(){if(this.#t)return!0;if(this.#e=this.#e||await new h(o.dbName,1,(r,s,a)=>{switch(s){case 0:r.createObjectStore("cfg",{keyPath:"name"}),r.createObjectStore("page",{keyPath:"id"}),r.createObjectStore("file",{keyPath:"id"}),r.createObjectStore("index",{keyPath:"word"})}}),!this.#e?.isConnected)return!1;if((await this.#e.get({store:"cfg",key:"version"}))?.value===o.version)return this.#r=new Set((await this.#e.get({store:"cfg",key:"stopword"}))?.value),this.#t=!0,!0;await Promise.allSettled([this.#e.put({store:"cfg",item:{name:"version",value:o.version}}),this.#e.clear({store:"page"}),this.#e.clear({store:"file"}),this.#e.clear({store:"index"})]);let t=await this.#i("index.json");return t===null?!1:(this.#r=new Set(t.stopword),await this.#e.put({store:"cfg",item:{name:"stopword",value:t.stopword}}),await this.#e.add({store:"page",item:t.page.map((r,s)=>({id:s,url:r.u,title:r.t,description:r.d}))}),await this.#e.add({store:"file",item:t.file.map(r=>({id:r,loaded:!1}))}),this.#t=!0,!0)}async find(e){if(!this.#t)throw new Error("StaticSearch failed to initialize");e=e.trim(),this.#s("find",{search:e});let t=[],r=[...this.wordList(e)];if(!r.length)return this.#s("result",{search:e,result:t}),t;await Promise.allSettled(r.map(i=>this.loadIndex(i)));let s={};(await Promise.allSettled(r.map(i=>this.#e.get({store:"index",key:i})))).forEach(i=>{if(i.value?.page)for(let n in i.value.page)s[n]=s[n]||0,s[n]+=i.value.page[n]});let a=[];for(let i in s)a.push({id:i,relevancy:s[i]});return a.sort((i,n)=>n.relevancy-i.relevancy),(await Promise.allSettled(a.map(i=>this.#e.get({store:"page",key:parseFloat(i.id)})))).forEach((i,n)=>{i.value&&(t[n]=i.value,t[n].relevancy=a[n].relevancy)}),this.#s("result",{search:e,result:t}),t}wordList(e){return d(e,p,o.wordCrop,this.#r)}async loadIndex(e){if(!this.#t)throw new Error("StaticSearch failed to initialize");if(e=e.toLowerCase().replace(/[^a-z]/g,"").slice(0,2),!e)return;let t=e.slice(0,e.length-1)+String.fromCharCode(e.charCodeAt(e.length-1)+1),r=(await this.#e.getAll({store:"file",lowerBound:e,upperBound:t})).filter(i=>!i.loaded);if(!r.length)return;let s=[],a=[];(await Promise.allSettled(r.map(i=>this.#i(`data/${i.id}.json`)))).map((i,n)=>{i.value&&(s.push({id:r[n].id,loaded:!0}),a.push(...Object.getOwnPropertyNames(i.value).map(l=>({word:l,page:i.value[l]}))))}),await Promise.allSettled([this.#e.put({store:"file",item:s}),this.#e.put({store:"index",item:a})])}#s(e="unknown",t={}){document.dispatchEvent(new CustomEvent("staticsearch:"+e,{detail:t}))}async#i(e){let t=o.path+e;try{let r=new AbortController,s=setTimeout(()=>r.abort(),this.fetchTimeout),a=await fetch(t,{signal:r.signal});if(clearTimeout(s),!a.ok)throw new Error(`Fetch failed ${t}: ${a.status}`);return await a.json()}catch{return null}}},g=new c;await g.init();export{g as staticsearch};
import{stem as p}from"./stem/__STEMFILE__";function d(o,e,t=7,r=new Set){return new Set(o.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[\u2018\u2019\u201A\u201B\u0027]/g,"").toLowerCase().replace(/[^a-z\s]/g," ").split(/\s+/g).map(s=>e(s.trim()).slice(0,t)).filter(s=>s.length>1&&!r.has(s)).sort())}var h=class{#t=null;#e=null;#r=null;constructor(o,e,t){return this.#e=o||"db",this.#r=e||1,this.#s(t)}connect(){return this.#s().then(()=>!0).catch(()=>!1)}close(){this.#t.close(),this.#t=null}#s(o){return new Promise((e,t)=>{if(!("indexedDB"in window)){t(new Error("No indexedDB support"));return}let r=indexedDB.open(this.#e,this.#r);r.onsuccess=()=>{this.#t=r.result,e(this)},r.onerror=s=>{t(new Error(`IndexedDB error ${s.target.errorCode}: ${s.target.message}`,{cause:s}))},o&&(r.onupgradeneeded=s=>{o(r.result,s.oldVersion,s.newVersion)})})}get isConnected(){return!!this.#t}get name(){return this.#e}get version(){return this.#r}#i(o,e,t){return new Promise((r,s)=>{let{transaction:a,store:i}=this.#a(o,null,!0);a.oncomplete=()=>r(),a.onerror=n=>{s(new Error(n.target.error.message,{cause:n}))},e=Array.isArray(e)?e:[e],e.forEach(n=>{t?i.put(n):i.add(n)}),a.commit()})}add({store:o,item:e=[]}={}){return this.#i(o,e,!1)}put({store:o,item:e=[]}={}){return this.#i(o,e,!0)}#o(o,e,t,r){return new Promise((s,a)=>{r=Array.isArray(r)?r:[r];let i=t==="delete"||t==="clear",n=this.#a(o,e,i).store[t](...r);n.onsuccess=()=>s(n.result),n.onerror=()=>a(n.error??!1)})}count({store:o,index:e,lowerBound:t,upperBound:r}={}){return this.#o(o,e,"count",this.#n(t,r))}get({store:o,index:e,key:t}={}){return this.#o(o,e,"get",t)}getAll({store:o,index:e,lowerBound:t,upperBound:r,count:s}={}){return this.#o(o,e,"getAll",[this.#n(t,r),s])}getAllKeys({store:o,index:e,lowerBound:t,upperBound:r,count:s}={}){return this.#o(o,e,"getAllKeys",[this.#n(t,r),s])}delete({store:o,key:e}={}){return this.#o(o,null,"delete",[e])}deleteAll({store:o,index:e,lowerBound:t,upperBound:r}={}){return this.#o(o,e,"delete",[this.#n(t,r)])}clear({store:o}={}){return this.#o(o,null,"clear")}getCursor({store:o,index:e,lowerBound:t,upperBound:r,direction:s="next",callback:a}={}){return new Promise((i,n)=>{let l=this.#a(o,e).store.openCursor(this.#n(t,r),s);l.onsuccess=()=>{let u=l.result;u?u.advance(a&&a(u)||1):i(!0)},l.onerror=()=>n(l.error)})}drop(){return new Promise((o,e)=>{this.close();let t=indexedDB.deleteDatabase(this.#e);t.onsuccess=()=>{this.#e=null,this.#r=null,o(!0)},t.onerror=()=>e(!1)})}#a(o,e,t){let r=this.#t.transaction(o,t?"readwrite":"readonly",{durability:t?"strict":"default"}),s=r.objectStore(o);return{transaction:r,store:e&&!t?s.index(e):s}}#n(o,e){let t;return o&&e?t=IDBKeyRange.bound(o,e):o?t=IDBKeyRange.lowerBound(o):e&&(t=IDBKeyRange.upperBound(e)),t}};var c=class o{static path=new URL(import.meta.url).pathname.replace("__FILENAME__","");static dbName="__AGENT__";static version="__VERSION__";static wordCrop=__WORDCROP__;#t=!1;#e=null;#r=null;fetchTimeout=5e3;constructor(){}async init(){if(this.#t)return!0;if(this.#e=this.#e||await new h(o.dbName,1,(r,s,a)=>{switch(s){case 0:r.createObjectStore("cfg",{keyPath:"name"}),r.createObjectStore("page",{keyPath:"id"}),r.createObjectStore("file",{keyPath:"id"}),r.createObjectStore("index",{keyPath:"word"})}}),!this.#e?.isConnected)return!1;if((await this.#e.get({store:"cfg",key:"version"}))?.value===o.version)return this.#r=new Set((await this.#e.get({store:"cfg",key:"stopword"}))?.value),this.#t=!0,!0;await Promise.allSettled([this.#e.put({store:"cfg",item:{name:"version",value:o.version}}),this.#e.clear({store:"page"}),this.#e.clear({store:"file"}),this.#e.clear({store:"index"})]);let t=await this.#i("index.json");return t===null?!1:(this.#r=new Set(t.stopword),await this.#e.put({store:"cfg",item:{name:"stopword",value:t.stopword}}),await this.#e.add({store:"page",item:t.page.map((r,s)=>({id:s,url:r.u,title:r.t||r.u,description:r.d||"",date:r.p||"",words:r.w||0}))}),await this.#e.add({store:"file",item:t.file.map(r=>({id:r,loaded:!1}))}),this.#t=!0,!0)}async find(e){if(!this.#t)throw new Error("StaticSearch failed to initialize");e=e.trim(),this.#s("find",{search:e});let t=[],r=[...this.wordList(e)];if(!r.length)return this.#s("result",{search:e,result:t}),t;await Promise.allSettled(r.map(i=>this.loadIndex(i)));let s={};(await Promise.allSettled(r.map(i=>this.#e.get({store:"index",key:i})))).forEach(i=>{if(i.value?.page)for(let n in i.value.page)s[n]=s[n]||0,s[n]+=i.value.page[n]});let a=[];for(let i in s)a.push({id:i,relevancy:s[i]});return a.sort((i,n)=>n.relevancy-i.relevancy),(await Promise.allSettled(a.map(i=>this.#e.get({store:"page",key:parseFloat(i.id)})))).forEach((i,n)=>{i.value&&(t[n]=i.value,t[n].relevancy=a[n].relevancy)}),this.#s("result",{search:e,result:t}),t}wordList(e){return d(e,p,o.wordCrop,this.#r)}async loadIndex(e){if(!this.#t)throw new Error("StaticSearch failed to initialize");if(e=e.toLowerCase().replace(/[^a-z]/g,"").slice(0,2),!e)return;let t=e.slice(0,e.length-1)+String.fromCharCode(e.charCodeAt(e.length-1)+1),r=(await this.#e.getAll({store:"file",lowerBound:e,upperBound:t})).filter(i=>!i.loaded);if(!r.length)return;let s=[],a=[];(await Promise.allSettled(r.map(i=>this.#i(`data/${i.id}.json`)))).map((i,n)=>{i.value&&(s.push({id:r[n].id,loaded:!0}),a.push(...Object.getOwnPropertyNames(i.value).map(l=>({word:l,page:i.value[l]}))))}),await Promise.allSettled([this.#e.put({store:"file",item:s}),this.#e.put({store:"index",item:a})])}#s(e="unknown",t={}){document.dispatchEvent(new CustomEvent("staticsearch:"+e,{detail:t}))}async#i(e){let t=o.path+e;try{let r=new AbortController,s=setTimeout(()=>r.abort(),this.fetchTimeout),a=await fetch(t,{signal:r.signal});if(clearTimeout(s),!a.ok)throw new Error(`Fetch failed ${t}: ${a.status}`);return await a.json()}catch{return null}}},g=new c;await g.init();export{g as staticsearch};

@@ -1,1 +0,1 @@

var g={skis:"ski",skies:"sky",dying:"die",lying:"lie",tying:"tie",idly:"idl",gently:"gentl",ugly:"ugli",early:"earli",only:"onli",singly:"singl"},h=["sky","news","howe","atlas","cosmos","bias","andes"],r=["inning","outing","canning","herring","earring","proceed","exceed","succeed"],b=["bb","dd","ff","gg","mm","nn","pp","rr","tt"];function s(i,e){for(var n=i.length,t=0,f=e.length;t<f;t++)if(e[t][0].test(i))return n-e[t][3]<e[t][2]?i:i.replace(e[t][0],e[t][1]);return i}function x(i,e){return i[e]?!1:/(^[aeiouy][^aeiouy])|([aeiouy][^aeiouywxY]$)/.test(i)}function m(i){var e,n;if(i.length<=2||h.indexOf(i)!==-1)return i;if(Object.hasOwn(g,i))return g[i];i=i.replace(/^y|([aeiouy])y/,"$1Y"),i=i.replace(/^'/,"");let t=/^(gener|commun|arsen)(\w*?[aeiouy][^aeiouy])?(\w*)$/,f=/^(\w*?[aeiouy][^aeiouy])(\w*?[aeiouy][^aeiouy])?(\w*)$/;var a=t.exec(i)||f.exec(i)||[];if(a[1]&&a[1].length<i.length?e=a[1].length:e=1/0,a[2]&&a[1].length+a[2].length<i.length?n=a[1].length+a[2].length:n=1/0,i=i.replace(/'s'$|'s$|'$/,""),i=s(i,[[/sses$/,"ss"],[/(\w{2,})(ie[d|s])$/,"$1i"],[/(ie[d|s])$/,"ie"],[/(us|ss)$/,"$1"],[/([aeiouy]\w+)(s)$/,"$1"]]),r.indexOf(i)!==-1)return i;return i=s(i,[[/eedly$/,"ee",e,5],[/(\w*[aeiouy]\w*)ingly$/,u],[/(\w*[aeiouy]\w*)edly$/,u],[/eed$/,"ee",e,3],[/(\w*[aeiouy]\w*)ing$/,u],[/(\w*[aeiouy]\w*)ed$/,u]]),i=i.replace(/(\w+[^aeiouy])([yY])$/,"$1i"),e!==1/0&&(i=s(i,[[/ational$/,"ate",e,7],[/fulness$/,"ful",e,7],[/iveness$/,"ive",e,7],[/ization$/,"ize",e,7],[/ousness$/,"ous",e,7],[/biliti$/,"ble",e,6],[/lessli$/,"less",e,6],[/tional$/,"tion",e,6],[/(?:alism|aliti)$/,"al",e,5],[/ation$/,"ate",e,5],[/entli$/,"ent",e,5],[/fulli$/,"ful",e,5],[/iviti$/,"ive",e,5],[/ousli$/,"ous",e,5],[/abli$/,"able",e,4],[/alli$/,"al",e,4],[/anci$/,"ance",e,4],[/ator$/,"ate",e,4],[/enci$/,"ence",e,4],[/izer$/,"ize",e,4],[/bli$/,"ble",e,3],[/(l)ogi$/,"$1og",e,3],[/([cdeghkmnrt])li$/,"$1",e,2]]),i=s(i,[[/ational$/,"ate",e,7],[/tional$/,"tion",e,6],[/alize$/,"al",e,5],[/ative$/,"",n,5],[/(?:icate|iciti)$/,"ic",e,5],[/ical$/,"ic",e,4],[/ness$/,"",e,4],[/ful$/,"",e,3]]),n!==1/0&&(i=s(i,[[/ement$/,"",n,5],[/(?:able|ance|ence|ible|ment)$/,"",n,4],[/(?:ant|ate|ent|ism|iti|ive|ize|ous)$/,"",n,3],[/([s|t])ion$/,"$1",n,3],[/(?:al|er|ic)$/,"",n,2]])),i=s(i,[[/(^[aeiouy][^aeiouy]|[^aeiouy][aeiouy][^aeiouywxY])?e$/,o],[/(l)l$/,"$1",n,1]])),i=i.replace(/Y/,"y"),i;function u(c,y){var l=y,$=l.substring(l.length-2);return["at","bl","iz"].indexOf($)!==-1?l=l+"e":b.indexOf($)!==-1?l=l.substring(0,l.length-1):x(l,e)&&(l=l+"e"),l}function o(c,y,l,$){return $.length-1>=n?y||"":!y&&$.length-1>=e?"":c}}export{m as stem};
var g=new Map([["skis","ski"],["skies","sky"],["dying","die"],["lying","lie"],["tying","tie"],["idly","idl"],["gently","gentl"],["ugly","ugli"],["early","earli"],["only","onli"],["singly","singl"]]),f=new Set(["sky","news","howe","atlas","cosmos","bias","andes"]),r=new Set(["inning","outing","canning","herring","earring","proceed","exceed","succeed"]),h=new Set(["bb","dd","ff","gg","mm","nn","pp","rr","tt"]),o=new Set(["at","bl","iz"]),b=/^y|([aeiouy])y/,m=/Y/,p=/^'/,x=/(^[aeiouy][^aeiouy])|([aeiouy][^aeiouywxY]$)/,v=/^(gener|commun|arsen)(\w*?[aeiouy][^aeiouy])?(\w*)$/,S=/^(\w*?[aeiouy][^aeiouy])(\w*?[aeiouy][^aeiouy])?(\w*)$/,z=/'s'$|'s$|'$/,Y=/(\w+[^aeiouy])([yY])$/;function s(i,e){for(var l=i.length,n=0,a=e.length;n<a;n++)if(e[n][0].test(i))return l-e[n][3]<e[n][2]?i:i.replace(e[n][0],e[n][1]);return i}function k(i,e){return i[e]?!1:x.test(i)}function R(i){var e,l;if(i.length<=2||f.has(i))return i;if(g.has(i))return g.get(i);i=i.replace(b,"$1Y"),i=i.replace(p,"");var n=v.exec(i)||S.exec(i)||[];if(n[1]&&n[1].length<i.length?e=n[1].length:e=1/0,n[2]&&n[1].length+n[2].length<i.length?l=n[1].length+n[2].length:l=1/0,i=i.replace(z,""),i=s(i,[[/sses$/,"ss"],[/(\w{2,})(ie[d|s])$/,"$1i"],[/(ie[d|s])$/,"ie"],[/(us|ss)$/,"$1"],[/([aeiouy]\w+)(s)$/,"$1"]]),r.has(i))return i;return i=s(i,[[/eedly$/,"ee",e,5],[/(\w*[aeiouy]\w*)ingly$/,a],[/(\w*[aeiouy]\w*)edly$/,a],[/eed$/,"ee",e,3],[/(\w*[aeiouy]\w*)ing$/,a],[/(\w*[aeiouy]\w*)ed$/,a]]),i=i.replace(Y,"$1i"),e!==1/0&&(i=s(i,[[/ational$/,"ate",e,7],[/fulness$/,"ful",e,7],[/iveness$/,"ive",e,7],[/ization$/,"ize",e,7],[/ousness$/,"ous",e,7],[/biliti$/,"ble",e,6],[/lessli$/,"less",e,6],[/tional$/,"tion",e,6],[/(?:alism|aliti)$/,"al",e,5],[/ation$/,"ate",e,5],[/entli$/,"ent",e,5],[/fulli$/,"ful",e,5],[/iviti$/,"ive",e,5],[/ousli$/,"ous",e,5],[/abli$/,"able",e,4],[/alli$/,"al",e,4],[/anci$/,"ance",e,4],[/ator$/,"ate",e,4],[/enci$/,"ence",e,4],[/izer$/,"ize",e,4],[/bli$/,"ble",e,3],[/(l)ogi$/,"$1og",e,3],[/([cdeghkmnrt])li$/,"$1",e,2]]),i=s(i,[[/ational$/,"ate",e,7],[/tional$/,"tion",e,6],[/alize$/,"al",e,5],[/ative$/,"",l,5],[/(?:icate|iciti)$/,"ic",e,5],[/ical$/,"ic",e,4],[/ness$/,"",e,4],[/ful$/,"",e,3]]),l!==1/0&&(i=s(i,[[/ement$/,"",l,5],[/(?:able|ance|ence|ible|ment)$/,"",l,4],[/(?:ant|ate|ent|ism|iti|ive|ize|ous)$/,"",l,3],[/([s|t])ion$/,"$1",l,3],[/(?:al|er|ic)$/,"",l,2]])),i=s(i,[[/(^[aeiouy][^aeiouy]|[^aeiouy][aeiouy][^aeiouywxY])?e$/,c],[/(l)l$/,"$1",l,1]])),i=i.replace(m,"y"),i;function a(y,u){var t=u,$=t.substring(t.length-2);return o.has($)?t=t+"e":h.has($)?t=t.substring(0,t.length-1):k(t,e)&&(t=t+"e"),t}function c(y,u,t,$){return $.length-1>=l?u||"":!u&&$.length-1>=e?"":y}}export{R as stem};

@@ -17,3 +17,3 @@ import process from 'node:process';

// console logger
export const concol = new ConCol('StaticSearch', 'cyan');
export const concol = new ConCol('StaticSearch', 'magentaBright');

@@ -184,3 +184,7 @@

// page data
pageIndex[idx] = { u: page.slug, t: page.html.title, d: page.html.description };
pageIndex[idx] = { u: page.slug };
if (page.html.title) pageIndex[idx].t = page.html.title;
if (page.html.description) pageIndex[idx].d = page.html.description;
if (page.html.date) pageIndex[idx].p = page.html.date;
if (page.html.wordcount) pageIndex[idx].w = page.html.wordcount;

@@ -337,2 +341,4 @@ // title scores

'',
]

@@ -339,0 +345,0 @@

@@ -86,8 +86,42 @@ // data parsing functions

// get schema.org data
const schemaOrg = getSchemaOrg(html);
// get title
res.title = (dom.querySelector('title')?.structuredText || dom.querySelector('h1')?.structuredText || 'Untitled').trim();
res.title = (
schemaOrg?.headline ||
dom.querySelector('title')?.structuredText ||
dom.querySelector('h1')?.structuredText ||
''
).trim();
let fullContent = res.title + ' ';
// get description
res.description = (dom.querySelector('meta[name="description"]')?.getAttribute('content') || '').trim();
res.description = (
schemaOrg?.description ||
dom.querySelector('meta[name="description"]')?.getAttribute('content') ||
''
).trim();
// get modified/publication date
if (schemaOrg) {
res.date = (
isDate( schemaOrg.dateModified ) ||
isDate( schemaOrg.datePublished ) ||
isDate( schemaOrg.published ) ||
isDate( schemaOrg.datePosted ) ||
isDate( schemaOrg.generatedAt ) ||
isDate( schemaOrg.uploadDate )
);
}
res.date = res.date || (
isDate( dom.querySelector('meta[property="article:modified_time"]')?.getAttribute('content') ) ||
isDate( dom.querySelector('meta[property="article:published_time"]')?.getAttribute('content') ) ||
isDate( dom.querySelector('time[itemProp="dateModified"]')?.getAttribute('datetime') ) ||
isDate( dom.querySelector('time[itemProp="datePublished"]')?.getAttribute('datetime') ) ||
isDate( dom.querySelector('time[itemProp="dateCreated"]')?.getAttribute('datetime') )
);
// extract words

@@ -125,3 +159,5 @@ res.word = {

// all content
res.word.content = res.word.content.union( wSet( node.structuredText ) );
const content = node.structuredText.replace(/<[^<]+?>/g, '');
fullContent += content + ' ';
res.word.content = res.word.content.union( wSet( content ) );

@@ -173,2 +209,5 @@ // strong, b, em, i

// get word count
res.wordcount = parseFloat(schemaOrg?.wordCount) || wordCount(fullContent);
return res;

@@ -189,1 +228,42 @@

}
// check value is a date and return YYYY-MM-DD string or undefined
function isDate(d) {
d = new Date(d);
if (!isNaN(d)) return d.toISOString().slice(0, 10);
}
// extract schema
function getSchemaOrg(html) {
try {
const
match = html.match(/application\/ld\+json.*?>(.*?)<\/script/s),
data = match?.[1],
schema = data && JSON.parse(data);
return schema;
}
catch (e) {}
}
// count words in a string
function wordCount(str) {
return str
.replace(/<[^<]+?>/g, '')
.replace(/\W/g, ' ')
.replace(/\s+/g, ' ')
.trim()
.replace(/\S/g, '')
.length + 1;
}
{
"name": "staticsearch",
"version": "0.2.1",
"version": "0.3.0",
"description": "Simple static site search system.",

@@ -5,0 +5,0 @@ "type": "module",

+32
-12

@@ -324,2 +324,6 @@ # StaticSearch

<h2 part="title"></h2>
<p part="meta">
<time part="date"></time> &ndash;
<span part="words">0</span> words
</p>
<p part="description"></p>

@@ -330,4 +334,6 @@ </a>

You can override this using a `<template>` with an ID of `staticsearch_item` in your HTML page (it can be within `<static-search>` or anywhere else). It can set the `part` attributes `"item"`, `"link"`, `"title"`, and `"description"` as necessary, e.g. show the title but no description in an `<article>`:
Note that the date and word count number are formatted for the user's locale.
You can override this using a `<template>` with an ID of `staticsearch_item` in your HTML page (it can be within `<static-search>` or anywhere else). Set the `part` attributes `"item"`, `"link"`, `"title"`, `meta`, `date`, `words`, and `"description"` as necessary, e.g. show the title but no meta values or description in an `<article>`:
```html

@@ -365,4 +371,5 @@ <template id="staticsearch_item">

--staticsearch-color-fore: CanvasText;
--staticsearch-color-dim: color-mix(in oklab, CanvasText 70%, Canvas);
--staticsearch-color-fore0: CanvasText;
--staticsearch-color-fore1: color-mix(in oklab, CanvasText 80%, Canvas);
--staticsearch-color-fore2: color-mix(in oklab, CanvasText 60%, Canvas);

@@ -440,2 +447,7 @@ --staticsearch-color-link: color-mix(in oklab, LinkText 70%, CanvasText);

The `staticsearch_result` element can set optional attributes:
* `minscore="<num>"` - only show pages with total relevancy scores of this or above on results
* `maxresults="<num>"` - show up to this number of pages on the results
As [shown above](#overriding-html-templates), you can set your own HTML `<template>`s and style anything as you like:

@@ -462,3 +474,6 @@

<article>
<h2 part="title"><a part="link"></a></h2>
<h2 part="title">
<a part="link"></a>,
<time part="date"></time>
</h2>
</article>

@@ -491,12 +506,11 @@ </li>

`staticSearchInput()` has a single parameter with the input element.
`staticSearchInput(element)` is passed the input element.
`staticSearchResult()` has the following parameters:
`staticSearchResult(element, options)` is passed the result element and an optional options object with the following properties:
* `element` - the result element (required)
* `minScore` - only show pages with total word scores of this or above on results
* `maxResults` - show up to this number of pages on the results
* `resultElement` - the outer list element (defaults to `ol`)
* `messageTemplate` - a DOM `<template>` configuring the results message
* `itemTemplate` - a DOM `<template>` configuring a result item
* `.minScore` - only show pages with total word scores of this or above on results
* `.maxResults` - show up to this number of pages on the results
* `.resultElement` - the outer list element (defaults to `ol`)
* `.messageTemplate` - a DOM `<template>` configuring the results message
* `.itemTemplate` - a DOM `<template>` configuring a result item

@@ -520,2 +534,4 @@

"description": "Do static sites rank better in search engines?",
"date": "2025-01-31",
"words": 1234
"relevancy": 21

@@ -528,2 +544,4 @@ },

"description": "How to output a list of all pages for search engines.",
"date": "2025-02-01",
"words": 954
"relevancy": 12

@@ -536,2 +554,4 @@ },

"description": "Static sites typically perform better than others.",
"date": "2025-02-22",
"words": 222
"relevancy": 2

@@ -538,0 +558,0 @@ }

@@ -5,26 +5,39 @@ // English Porter2 stemming function

const
special = {
skis: 'ski',
skies: 'sky',
dying: 'die',
lying: 'lie',
tying: 'tie',
idly: 'idl',
gently: 'gentl',
ugly: 'ugli',
early: 'earli',
only: 'onli',
singly: 'singl'
},
special = new Map([
[ 'skis', 'ski' ],
[ 'skies', 'sky' ],
[ 'dying', 'die' ],
[ 'lying', 'lie' ],
[ 'tying', 'tie' ],
[ 'idly', 'idl' ],
[ 'gently', 'gentl' ],
[ 'ugly', 'ugli' ],
[ 'early', 'earli' ],
[ 'only', 'onli' ],
[ 'singly', 'singl' ],
]),
exceptions = [
exceptions = new Set([
'sky', 'news', 'howe', 'atlas', 'cosmos', 'bias', 'andes'
],
]),
exceptions1a = [
exceptions1a = new Set([
'inning', 'outing', 'canning', 'herring', 'earring', 'proceed', 'exceed', 'succeed'
],
]),
doubles = ['bb', 'dd', 'ff', 'gg', 'mm', 'nn', 'pp', 'rr', 'tt'];
doubles = new Set(['bb', 'dd', 'ff', 'gg', 'mm', 'nn', 'pp', 'rr', 'tt']),
sb1Suffix = new Set(['at', 'bl', 'iz']),
reReplaceY = /^y|([aeiouy])y/,
reResetY = /Y/,
reReplaceApos = /^'/,
reShort = /(^[aeiouy][^aeiouy])|([aeiouy][^aeiouywxY]$)/,
regionRegex1 = /^(gener|commun|arsen)(\w*?[aeiouy][^aeiouy])?(\w*)$/,
regionRegex2 = /^(\w*?[aeiouy][^aeiouy])(\w*?[aeiouy][^aeiouy])?(\w*)$/,
reStep0 = /'s'$|'s$|'$/,
reStep1c = /(\w+[^aeiouy])([yY])$/;
// suffix handler
function handleSuffix(word, patterns) {

@@ -46,5 +59,6 @@ var wordLen = word.length;

// short handler
function isShort(word, r1) {
if (!word[r1]) {
return /(^[aeiouy][^aeiouy])|([aeiouy][^aeiouywxY]$)/.test(word);
return reShort.test(word);
}

@@ -61,3 +75,3 @@ return false;

// 1 or 2 letter words (and some other exceptions) are returned unchanged
if (word.length <= 2 || exceptions.indexOf(word) !== -1) {
if (word.length <= 2 || exceptions.has(word)) {
return word;

@@ -67,15 +81,13 @@ }

// some words have predefined stem forms
if (Object.hasOwn(special, word)) {
return special[word];
if (special.has(word)) {
return special.get(word);
}
// replace y
word = word.replace(/^y|([aeiouy])y/, '$1Y');
word = word.replace(reReplaceY, '$1Y');
// remove initial '
word = word.replace(/^'/, '');
word = word.replace(reReplaceApos, '');
// find regions
const regionRegex1 = /^(gener|commun|arsen)(\w*?[aeiouy][^aeiouy])?(\w*)$/;
const regionRegex2 = /^(\w*?[aeiouy][^aeiouy])(\w*?[aeiouy][^aeiouy])?(\w*)$/;
var match = regionRegex1.exec(word) || regionRegex2.exec(word) || [];

@@ -98,3 +110,3 @@

// step 0
word = word.replace(/'s'$|'s$|'$/, '');
word = word.replace(reStep0, '');

@@ -111,3 +123,3 @@ // step 1a

// recheck exceptions
if (exceptions1a.indexOf(word) !== -1) {
if (exceptions1a.has(word)) {
return word;

@@ -127,3 +139,3 @@ }

// step 1c
word = word.replace(/(\w+[^aeiouy])([yY])$/, '$1i');
word = word.replace(reStep1c, '$1i');

@@ -189,3 +201,3 @@ if (r1 !== Infinity) {

// reset Y
word = word.replace(/Y/, 'y');
word = word.replace(reResetY, 'y');

@@ -200,5 +212,5 @@ return word;

if (['at', 'bl', 'iz'].indexOf(suffix) !== -1) {
if (sb1Suffix.has(suffix)) {
result = result + 'e';
} else if (doubles.indexOf(suffix) !== -1) {
} else if (doubles.has(suffix)) {
result = result.substring(0, result.length - 1);

@@ -205,0 +217,0 @@ } else if (isShort(result, r1)) {

@@ -88,4 +88,2 @@ a

are
area
areas
aren

@@ -97,4 +95,2 @@ arent

as
aside
asides
ask

@@ -111,4 +107,2 @@ asked

atop
atrule
attr
aug

@@ -118,3 +112,2 @@ aught

august
auth
available

@@ -125,3 +118,2 @@ aw

b
back
backed

@@ -176,7 +168,3 @@ backing

bo
bold
bolder
boldest
boo
boolean
both

@@ -190,3 +178,2 @@ bottom

bs
builtin
but

@@ -211,3 +198,2 @@ buts

causes
cdata
certain

@@ -218,6 +204,4 @@ certainer

changes
char
cheers
circa
class
clear

@@ -237,3 +221,2 @@ clearly

considering
constant
contain

@@ -261,3 +244,2 @@ containing

darn
date
day

@@ -268,4 +250,2 @@ dear

definitely
delete
deleted
describe

@@ -286,3 +266,2 @@ described

do
doctype
doe

@@ -338,4 +317,2 @@ does

entirely
entities
entity
equal

@@ -397,3 +374,2 @@ equals

five
fix
followed

@@ -423,3 +399,2 @@ following

from
front
full

@@ -544,7 +519,4 @@ fully

immediately
importance
important
in
indeed
index
indicate

@@ -557,4 +529,2 @@ indicated

inner
insert
inserted
inside

@@ -575,3 +545,2 @@ insofar

it
italic
itd

@@ -599,3 +568,2 @@ itll

keys
keyword
kg

@@ -610,4 +578,2 @@ kind

la
lang
language
large

@@ -757,4 +723,2 @@ largely

nowheres
number
numbers
o

@@ -790,4 +754,2 @@ obtain

opens
operate
operator
opposite

@@ -870,8 +832,3 @@ or

probably
problem
problems
prolog
promptly
properties
property
proud

@@ -882,4 +839,2 @@ provide

providing
punctuate
punctuation
put

@@ -943,3 +898,2 @@ puts

seconds
section
see

@@ -953,4 +907,2 @@ seeing

sees
select
selector
self

@@ -1031,3 +983,2 @@ selves

stopped
string
strongly

@@ -1049,3 +1000,2 @@ style

sure
symbol
syn

@@ -1132,4 +1082,2 @@ system

tills
time
times
tip

@@ -1140,3 +1088,2 @@ tis

together
token
too

@@ -1200,4 +1147,2 @@ took

v
value
variable
various

@@ -1365,2 +1310,2 @@ versus

zero
zillion
zillion