mirror of
https://github.com/krisk/Fuse.git
synced 2026-02-01 17:21:26 +00:00
9 lines
9.6 KiB
JavaScript
9 lines
9.6 KiB
JavaScript
/**
|
|
* Fuse.js v6.0.0-beta.0 - Lightweight fuzzy-search (http://fusejs.io)
|
|
*
|
|
* Copyright (c) 2020 Kiro Risk (http://kiro.me)
|
|
* All Rights Reserved. Apache Software License 2.0
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*/
|
|
function e(e){return Array.isArray?Array.isArray(e):"[object Array]"===Object.prototype.toString.call(e)}function t(e){return"string"==typeof e}function s(e){return"number"==typeof e}function n(e){return null!=e}function r(e){return!e.trim().length}const i=Object.prototype.hasOwnProperty;class c{constructor(e){this._keys={},this._keyNames=[];let s=0;e.forEach(e=>{let n,r=1;if(t(e))n=e;else{if(!i.call(e,"name"))throw new Error("Key must contain a name");if(n=e.name,i.call(e,"weight")&&(r=e.weight,r<=0))throw new Error('"weight" property in key must be a positive integer')}this._keyNames.push(n),this._keys[n]={weight:r},s+=r}),this._keyNames.forEach(e=>{this._keys[e].weight/=s})}get(e,t){return this._keys[e]&&this._keys[e][t]}keys(){return this._keyNames}toJSON(){return JSON.stringify(this._keys)}}var o={isCaseSensitive:!1,includeScore:!1,keys:[],shouldSort:!0,sortFn:(e,t)=>e.score===t.score?e.idx<t.idx?-1:1:e.score<t.score?-1:1,includeMatches:!1,findAllMatches:!1,minMatchCharLength:1,location:0,threshold:.6,distance:100,...{useExtendedSearch:!1,getFn:function(r,i){let c=[],o=!1;const h=(r,i)=>{if(i){const a=i.indexOf(".");let l=i,d=null;-1!==a&&(l=i.slice(0,a),d=i.slice(a+1));const u=r[l];if(n(u))if(d||!t(u)&&!s(u))if(e(u)){o=!0;for(let e=0,t=u.length;e<t;e+=1)h(u[e],d)}else d&&h(u,d);else c.push(function(e){return null==e?"":function(e){if("string"==typeof e)return e;let t=e+"";return"0"==t&&1/e==-1/0?"-0":t}(e)}(u))}else c.push(r)};return h(r,i),o?c:c[0]}}};const h=/[^ ]+/g;class a{constructor({getFn:e=o.getFn}={}){this.norm=function(e=3){const t=new Map;return{get(s){const n=s.match(h).length;if(t.has(n))return t.get(n);const r=parseFloat((1/Math.sqrt(n)).toFixed(e));return t.set(n,r),r},clear(){t.clear()}}}(3),this.getFn=e,this.isCreated=!1,this.setRecords()}setCollection(e=[]){this.docs=e}setRecords(e=[]){this.records=e}setKeys(e=[]){this.keys=e}create(){!this.isCreated&&this.docs.length&&(this.isCreated=!0,t(this.docs[0])?this.docs.forEach((e,t)=>{this._addString(e,t)}):this.docs.forEach((e,t)=>{this._addObject(e,t)}),this.norm.clear())}add(e){const s=this.size();t(e)?this._addString(e,s):this._addObject(e,s)}removeAt(e){this.records.splice(e,1);for(let t=e,s=this.size();t<s;t+=1)this.records[t].i-=1}size(){return this.records.length}_addString(e,t){if(!n(e)||r(e))return;let s={v:e,i:t,n:this.norm.get(e)};this.records.push(s)}_addObject(s,i){let c={i:i,$:{}};this.keys.forEach((i,o)=>{let h=this.getFn(s,i);if(n(h))if(e(h)){let s=[];const i=[{nestedArrIndex:-1,value:h}];for(;i.length;){const{nestedArrIndex:c,value:o}=i.pop();if(n(o))if(t(o)&&!r(o)){let e={v:o,i:c,n:this.norm.get(o)};s.push(e)}else e(o)&&o.forEach((e,t)=>{i.push({nestedArrIndex:t,value:e})})}c.$[o]=s}else if(!r(h)){let e={v:h,n:this.norm.get(h)};c.$[o]=e}}),this.records.push(c)}toJSON(){return{keys:this.keys,records:this.records}}}function l(e,t,{getFn:s=o.getFn}={}){let n=new a({getFn:s});return n.setKeys(e),n.setCollection(t),n.create(),n}function d(e,t){const s=e.matches;if(t.matches=[],n(s))for(let e=0,r=s.length;e<r;e+=1){let r=s[e];if(!n(r.indices)||0===r.indices.length)continue;const{indices:i,value:c}=r;let o={indices:i,value:c};r.key&&(o.key=r.key),r.idx>-1&&(o.refIndex=r.idx),t.matches.push(o)}}function u(e,t){t.score=e.score}function f(e,{errors:t=0,currentLocation:s=0,expectedLocation:n=0,distance:r=o.distance}={}){const i=t/e.length,c=Math.abs(n-s);return r?i+c/r:c?1:i}function g(e,t,s,{location:n=o.location,distance:r=o.distance,threshold:i=o.threshold,findAllMatches:c=o.findAllMatches,minMatchCharLength:h=o.minMatchCharLength,includeMatches:a=o.includeMatches}={}){if(t.length>32)throw new Error("Pattern length exceeds max of 32.");const l=t.length,d=e.length,u=Math.max(0,Math.min(n,d));let g=i,p=u;const y=[];if(a)for(let e=0;e<d;e+=1)y[e]=0;let m;for(;(m=e.indexOf(t,p))>-1;){let e=f(t,{currentLocation:m,expectedLocation:u,distance:r});if(g=Math.min(e,g),p=m+l,a){let e=0;for(;e<l;)y[m+e]=1,e+=1}}p=-1;let M=[],k=1,x=l+d;const _=1<<(l<=31?l-1:30);for(let n=0;n<l;n+=1){let i=0,o=x;for(;i<o;){f(t,{errors:n,currentLocation:u+o,expectedLocation:u,distance:r})<=g?i=o:x=o,o=Math.floor((x-i)/2+i)}x=o;let h=Math.max(1,u-o+1),m=c?d:Math.min(u+o,d)+l,v=Array(m+2);v[m+1]=(1<<n)-1;for(let i=m;i>=h;i-=1){let c=i-1,o=s[e.charAt(c)];if(o&&a&&(y[c]=1),v[i]=(v[i+1]<<1|1)&o,0!==n&&(v[i]|=(M[i+1]|M[i])<<1|1|M[i+1]),v[i]&_&&(k=f(t,{errors:n,currentLocation:c,expectedLocation:u,distance:r}),k<=g)){if(g=k,p=c,p<=u)break;h=Math.max(1,2*u-p)}}if(f(t,{errors:n+1,currentLocation:u,expectedLocation:u,distance:r})>g)break;M=v}let v={isMatch:p>=0,score:Math.max(.001,k)};return a&&(v.indices=function(e=[],t=o.minMatchCharLength){let s=[],n=-1,r=-1,i=0;for(let c=e.length;i<c;i+=1){let c=e[i];c&&-1===n?n=i:c||-1===n||(r=i-1,r-n+1>=t&&s.push([n,r]),n=-1)}return e[i-1]&&i-n>=t&&s.push([n,i-1]),s}(y,h)),v}function p(e){let t={},s=e.length;for(let n=0;n<s;n+=1)t[e.charAt(n)]=0;for(let n=0;n<s;n+=1)t[e.charAt(n)]|=1<<s-n-1;return t}class y{constructor(e,{location:t=o.location,threshold:s=o.threshold,distance:n=o.distance,includeMatches:r=o.includeMatches,findAllMatches:i=o.findAllMatches,minMatchCharLength:c=o.minMatchCharLength,isCaseSensitive:h=o.isCaseSensitive}={}){this.options={location:t,threshold:s,distance:n,includeMatches:r,findAllMatches:i,minMatchCharLength:c,isCaseSensitive:h},this.pattern=h?e:e.toLowerCase(),this.chunks=[];let a=0;for(;a<this.pattern.length;){let e=this.pattern.substring(a,a+32);this.chunks.push({pattern:e,alphabet:p(e)}),a+=32}}searchIn(e){const{isCaseSensitive:t,includeMatches:s}=this.options;if(t||(e=e.toLowerCase()),this.pattern===e){let t={isMatch:!0,score:0};return s&&(t.indices=[[0,e.length-1]]),t}const{location:n,distance:r,threshold:i,findAllMatches:c,minMatchCharLength:o}=this.options;let h=[],a=0,l=!1;this.chunks.forEach(({pattern:t,alphabet:d},u)=>{const{isMatch:f,score:p,indices:y}=g(e,t,d,{location:n+32*u,distance:r,threshold:i,findAllMatches:c,minMatchCharLength:o,includeMatches:s});f&&(l=!0),a+=p,f&&y&&(h=[...h,...y])});let d={isMatch:l,score:l?a/this.chunks.length:1};return l&&s&&(d.indices=h),d}}const m=[];function M(e,t){for(let s=0,n=m.length;s<n;s+=1){let n=m[s];if(n.condition(e,t))return new n(e,t)}return new y(e,t)}const k="$and",x="$or",_=e=>!(!e[k]&&!e[x]),v=e=>({[k]:Object.keys(e).map(t=>({[t]:e[t]}))});function A(s,n,{auto:r=!0}={}){const i=s=>{let c=Object.keys(s);if(c.length>1&&!_(s))return i(v(s));let o=c[0];if((t=>!e(t)&&"object"==typeof t&&!_(t))(s)){const e=s[o];if(!t(e))throw new Error(`Invalid value for key "${o}"`);const i={key:o,pattern:e};return r&&(i.searcher=M(e,n)),i}let h={children:[],operator:o};return c.forEach(t=>{const n=s[t];e(n)&&n.forEach(e=>{h.children.push(i(e))})}),h};return _(s)||(s=v(s)),i(s)}class w{constructor(e,t={},s){this.options={...o,...t},this._keyStore=new c(this.options.keys),this.setCollection(e,s)}setCollection(e,t){if(this._docs=e,t&&!(t instanceof a))throw new Error("Incorrect index type");this._myIndex=t||l(this._keyStore.keys(),this._docs,{getFn:this.options.getFn})}add(e){n(e)&&(this._docs.push(e),this._myIndex.add(e))}removeAt(e){this._docs.splice(e,1),this._myIndex.removeAt(e)}getIndex(){return this._myIndex}search(e,{limit:n=-1}={}){let r=[];const{includeMatches:i,includeScore:c,shouldSort:h,sortFn:a}=this.options;if(t(e)){const s=M(e,this.options);r=t(this._docs[0])?this._searchStringArrayWith(s):this._searchObjectArrayWith(s)}else r=this._searchLogical(e);return function(e,t){e.forEach(e=>{let s=1;e.matches.forEach(({key:e,norm:n,score:r})=>{const i=t.get(e,"weight");s*=Math.pow(0===r&&i?Number.EPSILON:r,(i||1)*n)}),e.score=s})}(r,this._keyStore),h&&r.sort(a),s(n)&&n>-1&&(r=r.slice(0,n)),function(e,t,{includeMatches:s=o.includeMatches,includeScore:n=o.includeScore}={}){const r=[];s&&r.push(d);n&&r.push(u);return e.map(e=>{const{idx:s}=e,n={item:t[s],refIndex:s};return r.length&&r.forEach(t=>{t(e,n)}),n})}(r,this._docs,{includeMatches:i,includeScore:c})}_searchStringArrayWith(e){const{records:t}=this._myIndex,s=[];return t.forEach(({v:t,i:r,n:i})=>{if(!n(t))return;const{isMatch:c,score:o,indices:h}=e.searchIn(t);c&&s.push({item:t,idx:r,matches:[{score:o,value:t,norm:i,indices:h}]})}),s}_searchLogical(e){const t=A(e,this.options),{keys:s,records:r}=this._myIndex,i={},c=[],o=(e,t,n)=>{if(!e.children){const{key:n,searcher:r}=e,i=t[s.indexOf(n)];return this._findMatches({key:n,value:i,searcher:r})}{const s=e.operator;let r=[];for(let i=0;i<e.children.length;i+=1){let c=e.children[i],h=o(c,t,n);if(h&&h.length){if(r.push({idx:n,item:t,matches:h}),s===x)break}else if(s===k){r.length=0;break}}r.length&&(i[n]||(i[n]={idx:n,item:t,matches:[]},c.push(i[n])),r.forEach(({matches:e})=>{i[n].matches.push(...e)}))}};return r.forEach(({$:e,i:s})=>{n(e)&&o(t,e,s)}),c}_searchObjectArrayWith(e){const{keys:t,records:s}=this._myIndex,r=[];return s.forEach(({$:s,i:i})=>{if(!n(s))return;let c=[];t.forEach((t,n)=>{c.push(...this._findMatches({key:t,value:s[n],searcher:e}))}),c.length&&r.push({idx:i,item:s,matches:c})}),r}_findMatches({key:t,value:s,searcher:r}){if(!n(s))return[];let i=[];if(e(s))s.forEach(({v:e,i:s,n:c})=>{if(!n(e))return;const{isMatch:o,score:h,indices:a}=r.searchIn(e);o&&i.push({score:h,key:t,value:e,idx:s,norm:c,indices:a})});else{const{v:e,n:n}=s,{isMatch:c,score:o,indices:h}=r.searchIn(e);c&&i.push({score:o,key:t,value:e,norm:n,indices:h})}return i}}w.version="6.0.0-beta.0",w.createIndex=l,w.parseIndex=function(e,{getFn:t=o.getFn}={}){const{keys:s,records:n}=e;let r=new a({getFn:t});return r.setKeys(s),r.setRecords(n),r},w.config=o;export default w; |