UNPKG

slimsearch

Version:

Tiny but powerful full-text search engine for browser and Node

3 lines (2 loc) 4.21 kB
const U="ENTRIES",L="KEYS",m="VALUES",N="";class E{set;_type;_path;constructor(t,e){const s=t._tree,n=Array.from(s.keys());this.set=t,this._type=e,this._path=n.length>0?[{node:s,keys:n}]:[]}next(){const t=this.dive();return this.backtrack(),t}dive(){if(this._path.length===0)return{done:!0,value:void 0};const{node:t,keys:e}=l(this._path);if(l(e)==="")return{done:!1,value:this.result()};const s=t.get(l(e));return this._path.push({node:s,keys:Array.from(s.keys())}),this.dive()}backtrack(){if(this._path.length===0)return;const t=l(this._path).keys;t.pop(),!(t.length>0)&&(this._path.pop(),this.backtrack())}key(){return this.set._prefix+this._path.map(({keys:t})=>l(t)).filter(t=>t!=="").join("")}value(){return l(this._path).node.get("")}result(){switch(this._type){case m:return this.value();case L:return this.key();default:return[this.key(),this.value()]}}[Symbol.iterator](){return this}}const l=i=>i[i.length-1],V=(i,t,e)=>{const s=new Map;if(typeof t!="string")return s;const n=t.length+1,o=n+e,h=new Uint8Array(o*n).fill(e+1);for(let r=0;r<n;++r)h[r]=r;for(let r=1;r<o;++r)h[r*n]=r;return F(i,t,e,s,h,1,n,""),s},F=(i,t,e,s,n,o,h,r)=>{const g=o*h;t:for(const c of i.keys())if(c===""){const f=n[g-1];f<=e&&s.set(r,[i.get(c),f])}else{let f=o;for(let y=0;y<c.length;++y,++f){const M=c[y],_=h*f,z=_-h;let d=n[_];const S=Math.max(0,f-e-1),j=Math.min(h-1,f+e);for(let u=S;u<j;++u){const T=M!==t[u],W=n[z+u]+ +T,I=n[z+u+1]+1,R=n[_+u]+1,A=n[_+u+1]=Math.min(W,I,R);A<d&&(d=A)}if(d>e)continue t}F(i.get(c),t,e,s,n,f,h,r+c)}};class a{_tree;_prefix;_size=void 0;constructor(t=new Map,e=""){this._tree=t,this._prefix=e}atPrefix(t){if(!t.startsWith(this._prefix))throw new Error("Mismatched prefix");const[e,s]=p(this._tree,t.slice(this._prefix.length));if(e===void 0){const[n,o]=w(s);for(const h of n.keys())if(h!==""&&h.startsWith(o)){const r=new Map;return r.set(h.slice(o.length),n.get(h)),new a(r,t)}}return new a(e,t)}clear(){this._size=void 0,this._tree.clear()}delete(t){return this._size=void 0,K(this._tree,t)}entries(){return new E(this,U)}forEach(t){for(const[e,s]of this)t(e,s,this)}fuzzyGet(t,e){return V(this._tree,t,e)}get(t){const e=k(this._tree,t);return e!==void 0?e.get(""):void 0}has(t){return k(this._tree,t)?.has("")??!1}keys(){return new E(this,L)}set(t,e){if(typeof t!="string")throw new Error("key must be a string");return this._size=void 0,v(this._tree,t).set("",e),this}get size(){if(this._size)return this._size;this._size=0;const t=this.entries();for(;!t.next().done;)this._size+=1;return this._size}update(t,e){if(typeof t!="string")throw new Error("key must be a string");this._size=void 0;const s=v(this._tree,t);return s.set("",e(s.get(""))),this}fetch(t,e){if(typeof t!="string")throw new Error("key must be a string");this._size=void 0;const s=v(this._tree,t);let n=s.get("");return n===void 0&&s.set("",n=e()),n}values(){return new E(this,m)}[Symbol.iterator](){return this.entries()}static from(t){const e=new a;for(const[s,n]of t)e.set(s,n);return e}static fromObject(t){return a.from(Object.entries(t))}}const p=(i,t,e=[])=>{if(t.length===0||i==null)return[i,e];for(const s of i.keys())if(s!==""&&t.startsWith(s))return e.push([i,s]),p(i.get(s),t.slice(s.length),e);return e.push([i,t]),p(void 0,"",e)},k=(i,t)=>{if(t.length===0||!i)return i;for(const e of i.keys())if(e!==""&&t.startsWith(e))return k(i.get(e),t.slice(e.length))},v=(i,t)=>{const e=t.length;t:for(let s=0;i&&s<e;){for(const o of i.keys())if(o!==""&&t[s]===o[0]){const h=Math.min(e-s,o.length);let r=1;for(;r<h&&t[s+r]===o[r];)++r;const g=i.get(o);if(r===o.length)i=g;else{const c=new Map;c.set(o.slice(r),g),i.set(t.slice(s,s+r),c),i.delete(o),i=c}s+=r;continue t}const n=new Map;return i.set(t.slice(s),n),n}return i},K=(i,t)=>{const[e,s]=p(i,t);if(e!==void 0){if(e.delete(""),e.size===0)x(s);else if(e.size===1){const[n,o]=e.entries().next().value;b(s,n,o)}}},x=i=>{if(i.length===0)return;const[t,e]=w(i);if(t.delete(e),t.size===0)x(i.slice(0,-1));else if(t.size===1){const[s,n]=t.entries().next().value;s!==""&&b(i.slice(0,-1),s,n)}},b=(i,t,e)=>{if(i.length===0)return;const[s,n]=w(i);s.set(n+t,e),s.delete(n)},w=i=>i[i.length-1];export{a as SearchableMap}; //# sourceMappingURL=SearchableMap.js.map