a?1:0}function M(b,a,c){return b?{page:b,next:a?""+a:null,result:c}:c}function V(b,a,c,d,e,g,f){let r,q=[],l;const p=b.length;
-!0===c?(c="0",l=""):l=c&&c.split(":");if(1p;c--)l=f.substring(p,c),Q(A,k,l,b,a,q,h,n-1)}break;default:if(r=Q(A,k,f,b,1,q,h,n-1),t&&1=h)for(r=k._ctx[f]||(k._ctx[f]=v()),f=this.h[f]||(this.h[f]=W(n-(h||0))),q=a-t,l=a+t+1,0>q&&(q=0),l>m&&(l=m);qc;d--)e=f[d-1],f[d]=e,b[e]=d;f[c]=a;b[a]=c}}}return b};return b}();return n}(!1),this);
+'use strict';(function(m,H,I){let z;(z=I.define)&&z.amd?z([],function(){return H}):(z=I.modules)?z[m.toLowerCase()]=H:"object"===typeof exports?module.exports=H:I[m]=H})("FlexSearch",function(){function m(a,b){const c=b?b.id:a&&a.id;this.id=c||0===c?c:aa++;this.init(a,b);z(this,"index",function(){return this.a?Object.keys(this.a.index[this.a.keys[0]].f):Object.keys(this.f)});z(this,"length",function(){return this.index.length})}function H(a,b){const c=a.length,d=J(b),e=[];for(let g=0,f=0;g=f&&(a=a[k-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e}function T(a,b){if(a){const c=Object.keys(a);for(let d=0,e=c.length;da?1:a?-1:0}function ca(a,b){a=a[y];b=b[y];return ab?1:0}function ba(a,b){const c=y.length;for(let d=0;db?1:0}function L(a,b,c){return a?{page:a,next:b?""+b:null,result:c}:c}function V(a,b,c,d,e,g,f){let k,r=[];if(!0===c){c="0";var p=
+""}else p=c&&c.split(":");const q=a.length;if(1f&&(p=0),p=p||0,k=p+b,kq;c--)p=f.substring(q,c),P(v,n,p,a,b,r,h,m-1)}break;default:if(k=P(v,n,f,a,1,r,h,m-1),t&&1=h)for(k=n._ctx[f]||(n._ctx[f]=u()),f=this.h[f]||(this.h[f]=W(m-(h||0))),r=b-t,p=b+t+1,0>r&&(r=0),p>l&&(p=l);rc;d--)e=f[d-1],f[d]=e,b[e]=d;f[c]=a;b[a]=c}}}return b};return a}();return m}(!1),this);
diff --git a/dist/flexsearch.pre.js b/dist/flexsearch.pre.js
new file mode 100644
index 0000000..7a3b396
--- /dev/null
+++ b/dist/flexsearch.pre.js
@@ -0,0 +1,986 @@
+/*
+ FlexSearch v0.6.2
+ Copyright 2019 Nextapps GmbH
+ Author: Thomas Wilkerling
+ Released under the Apache 2.0 Licence
+ https://github.com/nextapps-de/flexsearch
+*/
+'use strict';
+(function(m, H, I) {
+ let z;
+ (z = I.define) && z.amd ? z([], function() {
+ return H;
+ }) : (z = I.modules) ? z[m.toLowerCase()] = H : "object" === typeof exports ? module.exports = H : I[m] = H;
+})("FlexSearch", function() {
+ function m(a, b) {
+ const c = b ? b.id : a && a.id;
+ this.id = c || 0 === c ? c : aa++;
+ this.init(a, b);
+ z(this, "index", function() {
+ return this.a ? Object.keys(this.a.index[this.a.keys[0]].f) : Object.keys(this.f);
+ });
+ z(this, "length", function() {
+ return this.index.length;
+ });
+ }
+ function H(a, b) {
+ const c = a.length, d = J(b), e = [];
+ for (let g = 0, f = 0; g < c; g++) {
+ const c = a[g];
+ if (d && b(c) || !d && !b[c]) {
+ e[f++] = c;
+ }
+ }
+ return e;
+ }
+ function I(a, b, c, d, e, g, f, k, r, p) {
+ c = V(c, f ? 0 : e, k, g, b, r, p);
+ let q;
+ k && (k = c.page, q = c.next, c = c.result);
+ if (f) {
+ b = this.where(f, null, e, c);
+ } else {
+ b = c;
+ c = this.g;
+ e = b.length;
+ g = Array(e);
+ for (f = 0; f < e; f++) {
+ g[f] = c[b[f]];
+ }
+ b = g;
+ }
+ c = b;
+ d && (J(d) || (y = d.split(":"), 1 < y.length ? d = ba : (y = y[0], d = ca)), c.sort(d));
+ c = L(k, q, c);
+ this.cache && this.j.set(a, c);
+ return c;
+ }
+ function z(a, b, c) {
+ Object.defineProperty(a, b, {get:c});
+ }
+ function h(a) {
+ return new RegExp(a, "g");
+ }
+ function K(a, b) {
+ for (let c = 0; c < b.length; c += 2) {
+ a = a.replace(b[c], b[c + 1]);
+ }
+ return a;
+ }
+ function P(a, b, c, d, e, g, f, k) {
+ if (b[c]) {
+ return b[c];
+ }
+ e = e ? (k - (f || k / 1.5)) * g + (f || k / 1.5) * e : g;
+ b[c] = e;
+ e >= f && (a = a[k - (e + 0.5 >> 0)], a = a[c] || (a[c] = []), a[a.length] = d);
+ return e;
+ }
+ function T(a, b) {
+ if (a) {
+ const c = Object.keys(a);
+ for (let d = 0, e = c.length; d < e; d++) {
+ const e = c[d], f = a[e];
+ if (f) {
+ for (let c = 0, d = f.length; c < d; c++) {
+ if (f[c] === b) {
+ 1 === d ? delete a[e] : f.splice(c, 1);
+ break;
+ } else {
+ A(f[c]) && T(f[c], b);
+ }
+ }
+ }
+ }
+ }
+ }
+ function U(a) {
+ let b = "", c = "";
+ var d = "";
+ for (let e = 0; e < a.length; e++) {
+ const g = a[e];
+ if (g !== c) {
+ if (e && "h" === g) {
+ if (d = "a" === d || "e" === d || "i" === d || "o" === d || "u" === d || "y" === d, ("a" === c || "e" === c || "i" === c || "o" === c || "u" === c || "y" === c) && d || " " === c) {
+ b += g;
+ }
+ } else {
+ b += g;
+ }
+ }
+ d = e === a.length - 1 ? "" : a[e + 1];
+ c = g;
+ }
+ return b;
+ }
+ function da(a, b) {
+ a = a.length - b.length;
+ return 0 > a ? 1 : a ? -1 : 0;
+ }
+ function ca(a, b) {
+ a = a[y];
+ b = b[y];
+ return a < b ? -1 : a > b ? 1 : 0;
+ }
+ function ba(a, b) {
+ const c = y.length;
+ for (let d = 0; d < c; d++) {
+ a = a[y[d]], b = b[y[d]];
+ }
+ return a < b ? -1 : a > b ? 1 : 0;
+ }
+ function L(a, b, c) {
+ return a ? {page:a, next:b ? "" + b : null, result:c} : c;
+ }
+ function V(a, b, c, d, e, g, f) {
+ let k, r = [];
+ if (!0 === c) {
+ c = "0";
+ var p = "";
+ } else {
+ p = c && c.split(":");
+ }
+ const q = a.length;
+ if (1 < q) {
+ const R = u();
+ let B = [], M, G;
+ var n = 0, l;
+ let N;
+ var h = !0;
+ let D, E = 0, x, w, y, A;
+ p && (2 === p.length ? (y = p, p = !1) : p = A = parseInt(p[0], 10));
+ if (f) {
+ for (M = u(); n < q; n++) {
+ if ("not" === e[n]) {
+ for (G = a[n], N = G.length, l = 0; l < N; l++) {
+ M["@" + G[l]] = 1;
+ }
+ } else {
+ w = n + 1;
+ }
+ }
+ if (C(w)) {
+ return L(c, k, r);
+ }
+ n = 0;
+ } else {
+ x = F(e) && e;
+ }
+ let z;
+ for (; n < q; n++) {
+ const u = n === (w || q) - 1;
+ if (!x || !n) {
+ if ((l = x || e && e[n]) && "and" !== l) {
+ if ("or" === l) {
+ z = !1;
+ } else {
+ continue;
+ }
+ } else {
+ z = g = !0;
+ }
+ }
+ G = a[n];
+ if (N = G.length) {
+ if (h) {
+ if (D) {
+ var t = D.length;
+ for (l = 0; l < t; l++) {
+ h = D[l];
+ var m = "@" + h;
+ f && M[m] || (R[m] = 1, g || (r[E++] = h));
+ }
+ D = null;
+ h = !1;
+ } else {
+ D = G;
+ continue;
+ }
+ }
+ m = !1;
+ for (l = 0; l < N; l++) {
+ t = G[l];
+ var v = "@" + t;
+ const a = g ? R[v] || 0 : n;
+ if (!(!a && !d || f && M[v] || !g && R[v])) {
+ if (a === n) {
+ if (u) {
+ if (!A || --A < E) {
+ if (r[E++] = t, b && E === b) {
+ return L(c, E + (p || 0), r);
+ }
+ }
+ } else {
+ R[v] = n + 1;
+ }
+ m = !0;
+ } else {
+ d && (v = B[a] || (B[a] = []), v[v.length] = t);
+ }
+ }
+ }
+ if (z && !m && !d) {
+ break;
+ }
+ } else {
+ if (z && !d) {
+ return L(c, k, G);
+ }
+ }
+ }
+ if (D) {
+ if (n = D.length, f) {
+ for (l = p ? parseInt(p, 10) : 0; l < n; l++) {
+ a = D[l], M["@" + a] || (r[E++] = a);
+ }
+ } else {
+ r = D;
+ }
+ }
+ if (d) {
+ for (E = r.length, y ? (n = parseInt(y[0], 10) + 1, l = parseInt(y[1], 10) + 1) : (n = B.length, l = 0); n--;) {
+ if (t = B[n]) {
+ for (N = t.length; l < N; l++) {
+ if (d = t[l], !f || !M["@" + d]) {
+ if (r[E++] = d, b && E === b) {
+ return L(c, n + ":" + l, r);
+ }
+ }
+ }
+ l = 0;
+ }
+ }
+ }
+ } else {
+ !q || e && "not" === e[0] || (r = a[0], p && (p = parseInt(p[0], 10)));
+ }
+ b && (f = r.length, p && p > f && (p = 0), p = p || 0, k = p + b, k < f ? r = r.slice(p, k) : (k = 0, p && (r = r.slice(p))));
+ return L(c, k, r);
+ }
+ function F(a) {
+ return "string" === typeof a;
+ }
+ function x(a) {
+ return a.constructor === Array;
+ }
+ function J(a) {
+ return "function" === typeof a;
+ }
+ function A(a) {
+ return "object" === typeof a;
+ }
+ function C(a) {
+ return "undefined" === typeof a;
+ }
+ function W(a) {
+ const b = Array(a);
+ for (let c = 0; c < a; c++) {
+ b[c] = u();
+ }
+ return b;
+ }
+ function u() {
+ return Object.create(null);
+ }
+ const w = {encode:"icase", c:"forward", split:/\W+/, cache:!1, async:!1, C:!1, v:!1, a:!1, b:9, threshold:0, depth:0}, X = {memory:{encode:"extra", c:"strict", threshold:0, b:1}, speed:{encode:"icase", c:"strict", threshold:1, b:3, depth:2}, match:{encode:"extra", c:"full", threshold:1, b:3}, score:{encode:"extra", c:"strict", threshold:1, b:9, depth:4}, balance:{encode:"balance", c:"strict", threshold:0, b:3, depth:3}, fast:{encode:"icase", c:"strict", threshold:8, b:9, depth:1}}, S = [];
+ let aa = 0;
+ const Y = {}, Z = {};
+ m.create = function(a, b) {
+ return new m(a, b);
+ };
+ m.registerMatcher = function(a) {
+ for (const b in a) {
+ a.hasOwnProperty(b) && S.push(h(b), a[b]);
+ }
+ return this;
+ };
+ m.registerEncoder = function(a, b) {
+ O[a] = b.bind(O);
+ return this;
+ };
+ m.registerLanguage = function(a, b) {
+ Y[a] = b.filter;
+ Z[a] = b.stemmer;
+ return this;
+ };
+ m.encode = function(a, b) {
+ return O[a](b);
+ };
+ m.prototype.init = function(a, b) {
+ this.m = [];
+ if (b) {
+ var c = b.preset;
+ a = b;
+ } else {
+ a || (a = w), c = a.preset;
+ }
+ b = {};
+ F(a) ? (b = X[a], a = {}) : c && (b = X[c]);
+ this.c = a.tokenize || b.c || this.c || w.c;
+ this.split = a.split || this.split || w.split;
+ this.v = a.rtl || this.v || w.v;
+ this.async = "undefined" === typeof Promise || C(c = a.async) ? this.async || w.async : c;
+ this.threshold = C(c = a.threshold) ? b.threshold || this.threshold || w.threshold : c;
+ this.b = C(c = a.resolution) ? c = b.b || this.b || w.b : c;
+ c <= this.threshold && (this.b = this.threshold + 1);
+ this.depth = "strict" !== this.c || C(c = a.depth) ? b.depth || this.depth || w.depth : c;
+ this.o = (c = C(c = a.encode) ? b.encode || w.encode : c) && O[c] && O[c].bind(O) || (J(c) ? c : this.o || !1);
+ (c = a.matcher) && this.addMatcher(c);
+ if (c = (b = a.lang) || a.filter) {
+ F(c) && (c = Y[c]);
+ if (x(c)) {
+ var d = this.o, e = u();
+ for (var g = 0; g < c.length; g++) {
+ var f = d ? d(c[g]) : c[g];
+ e[f] = 1;
+ }
+ c = e;
+ }
+ this.filter = c;
+ }
+ if (c = b || a.stemmer) {
+ var k;
+ b = F(c) ? Z[c] : c;
+ d = this.o;
+ e = [];
+ for (k in b) {
+ b.hasOwnProperty(k) && (g = d ? d(k) : k, e.push(h(g + "($|\\W)"), d ? d(b[k]) : b[k]));
+ }
+ this.stemmer = k = e;
+ }
+ this.a = e = (c = a.doc) ? c : this.a || w.a;
+ this.i = W(this.b - (this.threshold || 0));
+ this.h = u();
+ this.f = u();
+ if (e) {
+ this.g = u();
+ a.doc = null;
+ k = e.index = {};
+ b = e.keys = [];
+ d = e.field;
+ g = e.tag;
+ x(e.id) || (e.id = e.id.split(":"));
+ if (g) {
+ this.w = u();
+ f = u();
+ if (d) {
+ if (F(d)) {
+ f[d] = a;
+ } else {
+ if (x(d)) {
+ for (let b = 0; b < d.length; b++) {
+ f[d[b]] = a;
+ }
+ } else {
+ A(d) && (f = d);
+ }
+ }
+ }
+ x(g) || (e.tag = g = [g]);
+ for (d = 0; d < g.length; d++) {
+ this.w[g[d]] = u();
+ }
+ this.B = g;
+ d = f;
+ }
+ if (d) {
+ let c;
+ x(d) || (A(d) ? (c = d, e.field = d = Object.keys(d)) : e.field = d = [d]);
+ for (e = 0; e < d.length; e++) {
+ g = d[e], x(g) || (c && (a = c[g]), b[e] = g, d[e] = g.split(":")), k[g] = new m(a), k[g].g = this.g;
+ }
+ }
+ }
+ this.u = !0;
+ this.j = (this.cache = c = C(c = a.cache) ? this.cache || w.cache : c) ? new ea(c) : !1;
+ return this;
+ };
+ m.prototype.encode = function(a) {
+ a && S.length && (a = K(a, S));
+ a && this.m.length && (a = K(a, this.m));
+ a && this.o && (a = this.o(a));
+ a && this.stemmer && (a = K(a, this.stemmer));
+ return a;
+ };
+ m.prototype.addMatcher = function(a) {
+ const b = this.m;
+ for (const c in a) {
+ a.hasOwnProperty(c) && b.push(h(c), a[c]);
+ }
+ return this;
+ };
+ m.prototype.add = function(a, b, c, d, e) {
+ if (this.a && A(a)) {
+ return this.s("add", a, b);
+ }
+ if (b && F(b) && (a || 0 === a)) {
+ var g = "@" + a;
+ if (this.f[g] && !d) {
+ return this.update(a, b);
+ }
+ if (!e) {
+ if (this.async) {
+ let e = this;
+ g = new Promise(function(c) {
+ setTimeout(function() {
+ e.add(a, b, null, d, !0);
+ e = null;
+ c();
+ });
+ });
+ if (c) {
+ g.then(c);
+ } else {
+ return g;
+ }
+ return this;
+ }
+ if (c) {
+ return this.add(a, b, null, d, !0), c(), this;
+ }
+ }
+ b = this.encode(b);
+ if (!b.length) {
+ return this;
+ }
+ c = this.c;
+ e = J(c) ? c(b) : b.split(this.split);
+ this.filter && (e = H(e, this.filter));
+ const n = u();
+ n._ctx = u();
+ const l = e.length, h = this.threshold, t = this.depth, m = this.b, v = this.i, Q = this.v;
+ for (let b = 0; b < l; b++) {
+ var f = e[b];
+ if (f) {
+ var k = f.length, r = (Q ? b + 1 : l - b) / l, p = "";
+ switch(c) {
+ case "reverse":
+ case "both":
+ for (var q = k; --q;) {
+ p = f[q] + p, P(v, n, p, a, Q ? 1 : (k - q) / k, r, h, m - 1);
+ }
+ p = "";
+ case "forward":
+ for (q = 0; q < k; q++) {
+ p += f[q], P(v, n, p, a, Q ? (q + 1) / k : 1, r, h, m - 1);
+ }
+ break;
+ case "full":
+ for (q = 0; q < k; q++) {
+ const b = (Q ? q + 1 : k - q) / k;
+ for (let c = k; c > q; c--) {
+ p = f.substring(q, c), P(v, n, p, a, b, r, h, m - 1);
+ }
+ }
+ break;
+ default:
+ if (k = P(v, n, f, a, 1, r, h, m - 1), t && 1 < l && k >= h) {
+ for (k = n._ctx[f] || (n._ctx[f] = u()), f = this.h[f] || (this.h[f] = W(m - (h || 0))), r = b - t, p = b + t + 1, 0 > r && (r = 0), p > l && (p = l); r < p; r++) {
+ r !== b && P(f, k, e[r], a, 0, m - (r < b ? b - r : r - b), h, m - 1);
+ }
+ }
+ }
+ }
+ }
+ this.f[g] = 1;
+ this.u = !1;
+ }
+ return this;
+ };
+ m.prototype.s = function(a, b, c) {
+ if (x(b)) {
+ for (let d = 0, e = b.length; d < e; d++) {
+ if (d === e - 1) {
+ return this.s(a, b[d], c);
+ }
+ this.s(a, b[d]);
+ }
+ } else {
+ const h = this.a.index, p = this.a.keys;
+ var d = this.a.tag, e = this.a.id;
+ let q;
+ let n;
+ for (var g = 0; g < e.length; g++) {
+ q = (q || b)[e[g]];
+ }
+ if (d) {
+ for (e = 0; e < d.length; e++) {
+ var f = d[e];
+ var k = f.split(":");
+ for (g = 0; g < k.length; g++) {
+ n = (n || b)[k[g]];
+ }
+ n = "@" + n;
+ }
+ k = this.w[f];
+ k = k[n] || (k[n] = []);
+ }
+ if ("remove" === a) {
+ delete this.g[q];
+ for (let b = 0, a = p.length; b < a; b++) {
+ if (b === a - 1) {
+ return h[p[b]].remove(q, c), this;
+ }
+ h[p[b]].remove(q);
+ }
+ }
+ e = this.a.field;
+ k && (k[k.length] = b);
+ this.g[q] = b;
+ for (let g = 0, k = e.length; g < k; g++) {
+ d = e[g];
+ let l;
+ for (f = 0; f < d.length; f++) {
+ l = (l || b)[d[f]];
+ }
+ d = h[p[g]];
+ f = "add" === a ? d.add : d.update;
+ g === k - 1 ? f.call(d, q, l, c) : f.call(d, q, l);
+ }
+ }
+ return this;
+ };
+ m.prototype.update = function(a, b, c) {
+ if (this.a && A(a)) {
+ return this.s("update", a, b);
+ }
+ this.f["@" + a] && F(b) && (this.remove(a), this.add(a, b, c, !0));
+ return this;
+ };
+ m.prototype.remove = function(a, b, c) {
+ if (this.a && A(a)) {
+ return this.s("remove", a, b);
+ }
+ var d = "@" + a;
+ if (this.f[d]) {
+ if (!c) {
+ if (this.async && "function" !== typeof importScripts) {
+ let c = this;
+ d = new Promise(function(b) {
+ setTimeout(function() {
+ c.remove(a, null, !0);
+ c = null;
+ b();
+ });
+ });
+ if (b) {
+ d.then(b);
+ } else {
+ return d;
+ }
+ return this;
+ }
+ if (b) {
+ return this.remove(a, null, !0), b(), this;
+ }
+ }
+ for (b = 0; b < this.b - (this.threshold || 0); b++) {
+ T(this.i[b], a);
+ }
+ this.depth && T(this.h, a);
+ delete this.f[d];
+ this.u = !1;
+ }
+ return this;
+ };
+ let y;
+ m.prototype.search = function(a, b, c, d) {
+ if (A(b)) {
+ if (x(b)) {
+ for (var e = 0; e < b.length; e++) {
+ b[e].query = a;
+ }
+ } else {
+ b.query = a;
+ }
+ a = b;
+ b = 1000;
+ } else {
+ b && J(b) ? (c = b, b = 1000) : b || 0 === b || (b = 1000);
+ }
+ let g = [], f = a;
+ let k, h, p;
+ if (A(a) && !x(a)) {
+ c || (c = a.callback) && (f.callback = null);
+ h = a.sort;
+ k = a.page;
+ b = a.limit;
+ var q = a.threshold;
+ p = a.suggest;
+ a = a.query;
+ }
+ if (this.a) {
+ q = this.a.index;
+ const r = f.where;
+ var n = f.bool || "or", l = f.field;
+ let B = n;
+ let v, u;
+ if (l) {
+ x(l) || (l = [l]);
+ } else {
+ if (x(f)) {
+ var m = f;
+ l = [];
+ B = [];
+ for (var t = 0; t < f.length; t++) {
+ d = f[t], e = d.bool || n, l[t] = d.field, B[t] = e, "not" === e ? v = !0 : "and" === e && (u = !0);
+ }
+ } else {
+ l = this.a.keys;
+ }
+ }
+ n = l.length;
+ for (t = 0; t < n; t++) {
+ m && (f = m[t]), k && !F(f) && (f.page = null, f.limit = 0), g[t] = q[l[t]].search(f, 0);
+ }
+ if (c) {
+ return c(I.call(this, a, B, g, h, b, p, r, k, u, v));
+ }
+ if (this.async) {
+ const c = this;
+ return new Promise(function(d) {
+ Promise.all(g).then(function(e) {
+ d(I.call(c, a, B, e, h, b, p, r, k, u, v));
+ });
+ });
+ }
+ return I.call(this, a, B, g, h, b, p, r, k, u, v);
+ }
+ q || (q = this.threshold || 0);
+ if (!d) {
+ if (this.async && "function" !== typeof importScripts) {
+ let a = this;
+ q = new Promise(function(c) {
+ setTimeout(function() {
+ c(a.search(f, b, null, !0));
+ a = null;
+ });
+ });
+ if (c) {
+ q.then(c);
+ } else {
+ return q;
+ }
+ return this;
+ }
+ if (c) {
+ return c(this.search(f, b, null, !0)), this;
+ }
+ }
+ if (!a || !F(a)) {
+ return g;
+ }
+ f = a;
+ if (this.cache) {
+ if (this.u) {
+ if (c = this.j.get(a)) {
+ return c;
+ }
+ } else {
+ this.j.clear(), this.u = !0;
+ }
+ }
+ f = this.encode(f);
+ if (!f.length) {
+ return g;
+ }
+ c = this.c;
+ c = J(c) ? c(f) : f.split(this.split);
+ this.filter && (c = H(c, this.filter));
+ m = c.length;
+ d = !0;
+ e = [];
+ const w = u();
+ let v = 0;
+ 1 < m && (this.depth && "strict" === this.c ? n = !0 : c.sort(da));
+ if (!n || (t = this.h)) {
+ const b = this.b;
+ for (; v < m; v++) {
+ let a = c[v];
+ if (a) {
+ if (n) {
+ if (!l) {
+ if (t[a]) {
+ l = a, w[a] = 1;
+ } else {
+ if (!p) {
+ return g;
+ }
+ }
+ }
+ if (p && v === m - 1 && !e.length) {
+ n = !1, a = l || a, w[a] = 0;
+ } else {
+ if (!l) {
+ continue;
+ }
+ }
+ }
+ if (!w[a]) {
+ const c = [];
+ let f = !1, g = 0;
+ const k = n ? t[l] : this.i;
+ if (k) {
+ let d;
+ for (let e = 0; e < b - q; e++) {
+ if (d = k[e][a]) {
+ c[g++] = d, f = !0;
+ }
+ }
+ }
+ if (f) {
+ l = a, e[e.length] = 1 < g ? c.concat.apply([], c) : c[0];
+ } else {
+ if (!p) {
+ d = !1;
+ break;
+ }
+ }
+ w[a] = 1;
+ }
+ }
+ }
+ } else {
+ d = !1;
+ }
+ d && (g = V(e, b, k, p));
+ this.cache && this.j.set(a, g);
+ return g;
+ };
+ m.prototype.find = function(a, b) {
+ return this.where(a, b, 1)[0] || null;
+ };
+ m.prototype.where = function(a, b, c, d) {
+ const e = this.g, g = [];
+ let f = 0;
+ let k;
+ var h;
+ let p;
+ if (A(a)) {
+ c || (c = b);
+ var q = Object.keys(a);
+ var n = q.length;
+ k = !1;
+ if (1 === n && "id" === q[0]) {
+ return [e[a.id]];
+ }
+ if ((h = this.B) && !d) {
+ for (var l = 0; l < h.length; l++) {
+ var m = h[l], t = a[m];
+ if (!C(t)) {
+ p = this.w[m]["@" + t];
+ if (0 === --n) {
+ return p;
+ }
+ q.splice(q.indexOf(m), 1);
+ delete a[m];
+ break;
+ }
+ }
+ }
+ h = Array(n);
+ for (l = 0; l < n; l++) {
+ h[l] = q[l].split(":");
+ }
+ } else {
+ if (J(a)) {
+ b = d || Object.keys(e);
+ c = b.length;
+ for (q = 0; q < c; q++) {
+ n = e[b[q]], a(n) && (g[f++] = n);
+ }
+ return g;
+ }
+ if (C(b)) {
+ return [e[a]];
+ }
+ if ("id" === a) {
+ return [e[b]];
+ }
+ q = [a];
+ n = 1;
+ h = [a.split(":")];
+ k = !0;
+ }
+ d = p || d || Object.keys(e);
+ l = d.length;
+ for (m = 0; m < l; m++) {
+ t = p ? d[m] : e[d[m]];
+ let l = !0;
+ for (let c = 0; c < n; c++) {
+ k || (b = a[q[c]]);
+ const d = h[c], e = d.length;
+ let f = t;
+ if (1 < e) {
+ for (let a = 0; a < e; a++) {
+ f = f[d[a]];
+ }
+ } else {
+ f = f[d[0]];
+ }
+ if (f !== b) {
+ l = !1;
+ break;
+ }
+ }
+ if (l && (g[f++] = t, c && f === c)) {
+ break;
+ }
+ }
+ return g;
+ };
+ m.prototype.info = function() {
+ return {id:this.id, items:this.length, cache:this.cache && this.cache.l ? this.cache.l.length : !1, matcher:S.length + (this.m ? this.m.length : 0), worker:this.C, threshold:this.threshold, depth:this.depth, resolution:this.b, contextual:this.depth && "strict" === this.c};
+ };
+ m.prototype.clear = function() {
+ return this.destroy().init();
+ };
+ m.prototype.destroy = function() {
+ this.cache && (this.j.clear(), this.j = null);
+ this.i = this.h = this.f = null;
+ if (this.a) {
+ const a = this.a.keys;
+ for (let b = 0; b < a.length; b++) {
+ this.a.index[a[b]].destroy();
+ }
+ this.a = this.g = null;
+ }
+ return this;
+ };
+ m.prototype.export = function() {
+ let a;
+ if (this.a) {
+ const b = this.a.keys;
+ a = Array(b.length + 1);
+ let c = 0;
+ for (; c < b.length; c++) {
+ const d = this.a.index[b[c]];
+ a[c] = [d.i, d.h, Object.keys(d.f)];
+ }
+ a[c] = this.g;
+ } else {
+ a = [this.i, this.h, Object.keys(this.f)];
+ }
+ return JSON.stringify(a);
+ };
+ m.prototype.import = function(a) {
+ a = JSON.parse(a);
+ const b = u();
+ if (this.a) {
+ var c = this.a.keys, d = c.length, e = a[0][2];
+ for (var g = 0; g < e.length; g++) {
+ b[e[g]] = 1;
+ }
+ for (e = 0; e < d; e++) {
+ g = this.a.index[c[e]], g.i = a[e][0], g.h = a[e][1], g.f = b, g.g = a[d];
+ }
+ this.g = a[d];
+ } else {
+ c = a[2];
+ for (d = 0; d < c.length; d++) {
+ b[c[d]] = 1;
+ }
+ this.i = a[0];
+ this.h = a[1];
+ this.f = b;
+ }
+ };
+ const O = {icase:function(a) {
+ return a.toLowerCase();
+ }, simple:function() {
+ const a = [h("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), "a", h("[\u00e8\u00e9\u00ea\u00eb]"), "e", h("[\u00ec\u00ed\u00ee\u00ef]"), "i", h("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), "o", h("[\u00f9\u00fa\u00fb\u00fc\u0171]"), "u", h("[\u00fd\u0177\u00ff]"), "y", h("\u00f1"), "n", h("\u00e7"), "c", h("\u00df"), "s", h(" & "), " and ", h("[-/]"), " ", h("[^a-z0-9 ]"), "", h("\\s+"), " "];
+ return function(b) {
+ b = K(b.toLowerCase(), a);
+ return " " === b ? "" : b;
+ };
+ }(), advanced:function() {
+ const a = [h("ae"), "a", h("ai"), "ei", h("ay"), "ei", h("ey"), "ei", h("oe"), "o", h("ue"), "u", h("ie"), "i", h("sz"), "s", h("zs"), "s", h("sh"), "s", h("ck"), "k", h("cc"), "k", h("dt"), "t", h("ph"), "f", h("pf"), "f", h("ou"), "o", h("uo"), "u"];
+ return function(b, c) {
+ if (!b) {
+ return b;
+ }
+ b = this.simple(b);
+ 2 < b.length && (b = K(b, a));
+ c || 1 < b.length && (b = U(b));
+ return b;
+ };
+ }(), extra:function() {
+ const a = [h("p"), "b", h("z"), "s", h("[cgq]"), "k", h("n"), "m", h("d"), "t", h("[vw]"), "f", h("[aeiouy]"), ""];
+ return function(b) {
+ if (!b) {
+ return b;
+ }
+ b = this.advanced(b, !0);
+ if (1 < b.length) {
+ b = b.split(" ");
+ for (let c = 0; c < b.length; c++) {
+ const d = b[c];
+ 1 < d.length && (b[c] = d[0] + K(d.substring(1), a));
+ }
+ b = b.join(" ");
+ b = U(b);
+ }
+ return b;
+ };
+ }(), balance:function() {
+ const a = [h("[-/]"), " ", h("[^a-z0-9 ]"), "", h("\\s+"), " "];
+ return function(b) {
+ return U(K(b.toLowerCase(), a));
+ };
+ }()}, ea = function() {
+ function a(a) {
+ this.clear();
+ this.A = !0 !== a && a;
+ }
+ a.prototype.clear = function() {
+ this.cache = u();
+ this.count = u();
+ this.index = u();
+ this.l = [];
+ };
+ a.prototype.set = function(a, c) {
+ if (this.A && C(this.cache[a])) {
+ let b = this.l.length;
+ if (b === this.A) {
+ b--;
+ const a = this.l[b];
+ delete this.cache[a];
+ delete this.count[a];
+ delete this.index[a];
+ }
+ this.index[a] = b;
+ this.l[b] = a;
+ this.count[a] = -1;
+ this.cache[a] = c;
+ this.get(a);
+ } else {
+ this.cache[a] = c;
+ }
+ };
+ a.prototype.get = function(a) {
+ const b = this.cache[a];
+ if (this.A && b) {
+ var d = ++this.count[a];
+ const b = this.index;
+ let c = b[a];
+ if (0 < c) {
+ const f = this.l;
+ for (var e = c; this.count[f[--c]] <= d && -1 !== c;) {
+ }
+ c++;
+ if (c !== e) {
+ for (d = e; d > c; d--) {
+ e = f[d - 1], f[d] = e, b[e] = d;
+ }
+ f[c] = a;
+ b[a] = c;
+ }
+ }
+ }
+ return b;
+ };
+ return a;
+ }();
+ return m;
+}(!1), this);
+
diff --git a/flexsearch.js b/flexsearch.js
index 213c665..e07bdc4 100644
--- a/flexsearch.js
+++ b/flexsearch.js
@@ -1,5 +1,5 @@
/**!
- * @preserve FlexSearch v0.6.1
+ * @preserve FlexSearch v0.6.2
* Copyright 2019 Nextapps GmbH
* Author: Thomas Wilkerling
* Released under the Apache 2.0 Licence
@@ -191,12 +191,13 @@
/**
* @param {Object=} options
+ * @param {Object=} settings
* @export
*/
- FlexSearch.create = function(options){
+ FlexSearch.create = function(options, settings){
- return new FlexSearch(options);
+ return new FlexSearch(options, settings);
};
/**
@@ -495,20 +496,6 @@
);
*/
- // if(SUPPORT_SUGGESTION){
- //
- // /** @private */
- // this.suggest = (
- //
- // is_undefined(custom = options["suggest"]) ?
- //
- // this.suggest ||
- // defaults.suggest
- // :
- // custom
- // );
- // }
-
custom = is_undefined(custom = options["encode"]) ?
preset.encode ||
@@ -532,7 +519,9 @@
);
}
- if((custom = options["filter"])) {
+ let lang = options["lang"];
+
+ if((custom = lang || options["filter"])) {
if(is_string(custom)){
@@ -548,7 +537,7 @@
this.filter = custom;
}
- if((custom = options["stemmer"])) {
+ if((custom = lang || options["stemmer"])) {
/** @private */
this.stemmer = init_stemmer(
@@ -860,7 +849,7 @@
if(!_recall){
- if(SUPPORT_ASYNC && this.async && (typeof importScripts !== "function")){
+ if(SUPPORT_ASYNC && this.async && (!SUPPORT_WORKER || (typeof importScripts !== "function"))){
let self = this;
@@ -1171,7 +1160,8 @@
if(z === length - 1){
- return index[keys[z]].remove(id, callback);
+ index[keys[z]].remove(id, callback);
+ return this;
}
else{
@@ -1214,7 +1204,7 @@
if(i === len - 1){
- return fn.call(self, id, content, callback);
+ fn.call(self, id, content, callback);
}
else{
@@ -1222,6 +1212,8 @@
}
}
}
+
+ return this;
};
}
@@ -1474,7 +1466,16 @@
}
query = /** @type {Object} */ (limit);
- limit = 0;
+ limit = 1000;
+ }
+ else if(limit && is_function(limit)){
+
+ callback = /** @type {?Function} */ (limit);
+ limit = 1000;
+ }
+ else{
+
+ limit || (limit === 0 ) || (limit = 1000);
}
let result = [];
@@ -1490,11 +1491,14 @@
if(SUPPORT_ASYNC){
- callback = query["callback"] || (is_function(limit) && /** @type {?Function} */ (limit));
+ if(!callback){
- if(callback) {
+ callback = query["callback"];
- _query["callback"] = null;
+ if(callback){
+
+ _query["callback"] = null;
+ }
}
}
@@ -1636,16 +1640,6 @@
threshold || (threshold = this.threshold || 0);
- if(is_function(limit)){
-
- callback = limit;
- limit = 1000;
- }
- else {
-
- limit || (limit === 0 ) || (limit = 1000);
- }
-
if(SUPPORT_WORKER && this.worker){
this._current_callback = callback;
@@ -1781,14 +1775,13 @@
let ctx_root;
let use_contextual;
+ let a = 0;
if(length > 1){
- if(this.depth){
+ if(this.depth && (this.tokenize === "strict")){
use_contextual = true;
- ctx_root = words[0]; // TODO: iterate roots
- check_words[ctx_root] = 1;
}
else{
@@ -1827,7 +1820,7 @@
let ctx_map;
- if(!use_contextual || (ctx_map = this._ctx)[ctx_root]){
+ if(!use_contextual || (ctx_map = this._ctx)){
const resolution = this.resolution;
@@ -1837,12 +1830,41 @@
// threshold = (threshold || 1) / boost;
// }
- for(let a = (use_contextual ? 1 : 0); a < length; a++){
+ for(; a < length; a++){
- const value = words[a];
+ let value = words[a];
if(value){
+ if(use_contextual){
+
+ if(!ctx_root){
+
+ if(ctx_map[value]){
+
+ ctx_root = value;
+ check_words[value] = 1;
+ }
+ else if(!suggest){
+
+ return result;
+ }
+ }
+
+ if(suggest && (a === length - 1) && !check.length){
+
+ // fall back to single-term-strategy
+
+ use_contextual = false;
+ value = ctx_root || value;
+ check_words[value] = 0;
+ }
+ else if(!ctx_root){
+
+ continue;
+ }
+ }
+
if(!check_words[value]){
const map_check = [];
@@ -1871,7 +1893,10 @@
if(map_found){
+ ctx_root = value;
+
// not handled by intersection:
+
check[check.length] = (
count > 1 ?
@@ -1882,7 +1907,7 @@
);
// handled by intersection:
- //check[check.length] = map_check;
+ // check[check.length] = map_check;
}
else if(!SUPPORT_SUGGESTION || !suggest){
@@ -1892,8 +1917,6 @@
check_words[value] = 1;
}
-
- ctx_root = value;
}
}
}
@@ -1902,24 +1925,21 @@
found = false;
}
- //if(!SUPPORT_DOCUMENT || !this.doc){
-
- if(found){
+ if(found){
- // Not handled by intersection:
- result = /** @type {Array} */ (intersect(check, limit, cursor, SUPPORT_SUGGESTION && suggest));
+ // Not handled by intersection:
+ result = /** @type {Array} */ (intersect(check, limit, cursor, SUPPORT_SUGGESTION && suggest));
- // Handled by intersection:
- //result = intersect_3d(check, limit, suggest);
- }
+ // Handled by intersection:
+ //result = intersect_3d(check, limit, suggest);
+ }
- // store result to cache
+ // store result to cache
- if(SUPPORT_CACHE && this.cache){
+ if(SUPPORT_CACHE && this.cache){
- this._cache.set(query, result);
- }
- //}
+ this._cache.set(query, result);
+ }
if(PROFILER){
@@ -1959,6 +1979,7 @@
let keys_len;
let has_value;
let tree;
+ let tag_results;
if(is_object(key)){
@@ -1983,12 +2004,12 @@
if(!is_undefined(current_where)){
- result = this._tag[current_tag]["@" + current_where];
+ tag_results = this._tag[current_tag]["@" + current_where];
//result = result.slice(0, limit && (limit < result.length) ? limit : result.length);
if(--keys_len === 0){
- return result;
+ return tag_results;
}
keys.splice(keys.indexOf(current_tag), 1);
@@ -2042,12 +2063,12 @@
has_value = true;
}
- const ids = result || get_keys(doc); // this._ids;
+ const ids = tag_results || result || get_keys(doc); // this._ids;
const length = ids.length;
for(let x = 0; x < length; x++){
- const obj = doc[ids[x]];
+ const obj = tag_results ? ids[x] : doc[ids[x]];
let found = true;
for(let i = 0; i < keys_len; i++){
@@ -2214,11 +2235,14 @@
FlexSearch.prototype.export = function(){
+ let payload;
+
if(SUPPORT_DOCUMENT && this.doc){
const keys = this.doc.keys;
const length = keys.length;
- const payload = new Array(length + 1);
+
+ payload = new Array(length + 1);
let i = 0;
@@ -2233,16 +2257,18 @@
}
payload[i] = this._doc;
-
- return JSON.stringify(payload);
}
+ else{
- return JSON.stringify([
+ payload = [
- this._map,
- this._ctx,
- get_keys(this._ids)
- ]);
+ this._map,
+ this._ctx,
+ get_keys(this._ids)
+ ]
+ }
+
+ return JSON.stringify(payload);
};
/**
@@ -3161,7 +3187,6 @@
let page;
let result = [];
let pointer;
- const length_z = arrays.length;
if(cursor === true){
@@ -3173,6 +3198,8 @@
pointer = cursor && cursor.split(":");
}
+ const length_z = arrays.length;
+
// use complex handler when length > 1
if(length_z > 1){
@@ -3186,7 +3213,7 @@
let suggestions = [];
let check_not;
let arr;
- let z = -1; // start from 0
+ let z = 0;
let i = 0;
let length;
let tmp;
@@ -3197,6 +3224,7 @@
let last_index;
let pointer_suggest;
+ let pointer_count;
if(pointer){
@@ -3207,7 +3235,7 @@
}
else{
- pointer = parseInt(pointer[0], 10);
+ pointer = pointer_count = parseInt(pointer[0], 10);
}
}
@@ -3220,17 +3248,16 @@
check_not = create_object();
- while(++z < length_z){
+ for(; z < length_z; z++){
if(bool[z] === "not"){
arr = arrays[z];
length = arr.length;
- i = 0;
- while(i < length){
+ for(i = 0; i < length; i++){
- check_not["@" + arr[i++]] = 1;
+ check_not["@" + arr[i]] = 1;
}
}
else{
@@ -3250,7 +3277,7 @@
return create_page(cursor, page, result);
}
- z = -1;
+ z = 0;
}
else{
@@ -3263,7 +3290,7 @@
// loop through arrays
- while(++z < length_z){
+ for(; z < length_z; z++){
const is_final_loop = (
@@ -3322,13 +3349,11 @@
const result_length = first_result.length;
- i = 0;
-
// fill initial map
- while(i < result_length){
+ for(i = 0; i < result_length; i++){
- const id = first_result[i++];
+ const id = first_result[i];
const index = "@" + id;
// there is no and, add items
@@ -3359,17 +3384,14 @@
let found = false;
- i = 0;
- //suggestions = [];
-
- while(i < length){
+ for(i = 0; i < length; i++){
- tmp = arr[i++];
+ tmp = arr[i];
const index = "@" + tmp;
- const check_val = has_and ? check[index] : z;
+ const check_val = has_and ? check[index] || 0 : z;
- if(check_val){
+ if(check_val || suggest){
if(has_not && check_not[index]){
@@ -3392,13 +3414,13 @@
// should only happened when at least one bool "and" was set
// TODO: check bool and provide complexity reduction
- if(!pointer || (--pointer < count)){
+ if(!pointer_count || (--pointer_count < count)){
result[count++] = tmp;
if(limit && (count === limit)){
- return create_page(cursor, count, result);
+ return create_page(cursor, count + (pointer || 0), result);
}
}
}
@@ -3449,21 +3471,19 @@
i = 0;
}
- while(i < result_length){
+ for(; i < result_length; i++){
- const id = first_result[i++];
+ const id = first_result[i];
if(!check_not["@" + id]){
- if(!pointer || (--pointer < count)){
+ result[count++] = id;
- result[count++] = id;
-
- if(limit && (count === limit)){
-
- return create_page(cursor, i, result);
- }
- }
+ // TODO: is actually not covered
+ // if(limit && (count === limit)){
+ //
+ // return create_page(cursor, (i + 1), result);
+ // }
}
}
}
@@ -3480,7 +3500,7 @@
if(pointer_suggest){
z = parseInt(pointer_suggest[0], 10) + 1;
- i = parseInt(pointer_suggest[1], 10);
+ i = parseInt(pointer_suggest[1], 10) + 1;
}
else{
@@ -3488,7 +3508,7 @@
i = 0;
}
- while(z--){
+ for(; z--;){
tmp = suggestions[z];
@@ -3520,6 +3540,11 @@
result = arrays[0];
+ if(pointer){
+
+ pointer = parseInt(pointer[0], 10);
+ }
+
// TODO: handle references to the original index array
// return result.slice(0);
}
@@ -3527,16 +3552,28 @@
if(limit){
- const start = cursor ? parseInt(cursor, 10) : 0;
+ const length = result.length;
+
+ if(pointer && (pointer > length)){
+
+ pointer = 0;
+ }
+
+ const start = pointer || 0;
page = start + limit;
- if(page < result.length){
+ if(page < length){
result = result.slice(start, page);
}
- else if(start){
+ else {
+
+ page = 0;
+
+ if(start){
- result = result.slice(start);
+ result = result.slice(start);
+ }
}
}
@@ -4014,8 +4051,6 @@
function provide(name, factory, root){
- /* istanbul ignore next */
-
let prop;
// AMD (RequireJS)
diff --git a/package.json b/package.json
index 46cfaa8..647ba13 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "flexsearch",
- "version": "0.6.1",
+ "version": "0.6.2",
"description": "Next-Generation full text search library with zero dependencies.",
"homepage": "https://github.com/nextapps-de/flexsearch/",
"author": "Thomas Wilkerling",
@@ -32,13 +32,15 @@
"build-custom": "node compile RELEASE=custom DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_PRESET=false SUPPORT_SUGGESTION=false SUPPORT_SERIALIZE=false SUPPORT_INFO=false SUPPORT_DOCUMENT=false SUPPORT_OPERATOR=false SUPPORT_WHERE=false SUPPORT_PAGINATION=false SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false",
"build-es5": "node compile RELEASE=es5 DEBUG=true PROFILER=false SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESET=true SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=true SUPPORT_INFO=true SUPPORT_DOCUMENT=true SUPPORT_OPERATOR=true SUPPORT_WHERE=true SUPPORT_PAGINATION=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false LANGUAGE_OUT=ECMASCRIPT5_STRICT",
"build-node": "node compile RELEASE=node DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESET=true SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=true SUPPORT_INFO=true SUPPORT_DOCUMENT=true SUPPORT_OPERATOR=true SUPPORT_WHERE=true SUPPORT_PAGINATION=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false",
+ "build-pre": "node compile RELEASE=pre DEBUG=false PROFILER=false SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_PRESET=true SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=true SUPPORT_INFO=true SUPPORT_DOCUMENT=true SUPPORT_OPERATOR=true SUPPORT_WHERE=true SUPPORT_PAGINATION=true SUPPORT_LANG_DE=false SUPPORT_LANG_EN=false FORMATTING=PRETTY_PRINT",
"build-lang": "node compile RELEASE=lang",
- "build-all": "npm run build && npm run build-light && npm run build-compact && npm run build-es5 && npm run build-node",
- "test-production": "nyc --reporter=html --reporter=text mocha --timeout=3000 test --exit",
- "test-light": "nyc --reporter=html --reporter=text mocha --timeout=3000 test/ --exit",
- "test-develop": "nyc --reporter=html --reporter=text mocha --timeout=3000 --exit",
+ "build-all": "npm run build && npm run build-light && npm run build-compact && npm run build-es5 && npm run build-node && npm run build-pre",
+ "test-production": "mocha --timeout=3000 test --exit",
+ "test-light": "mocha --timeout=3000 test/ --exit",
+ "test-develop": "mocha --timeout=3000 --exit",
"test-browser": "mocha-phantomjs test/index.html",
- "test": "npm run test-develop && npm run test-production && npm run test-light && npm run test-browser",
+ "test-coverage": "nyc --reporter=html --reporter=text mocha --timeout=3000 test/test.js --exit",
+ "test": "npm run test-develop && npm run test-production && npm run test-light && npm run test-browser && npm run test-coverage",
"update": "node_modules/.bin/updtr --to non-breaking",
"coverage": "nyc report --reporter=lcov --reporter=text-lcov | coveralls"
},
diff --git a/test/matching.html b/test/matching.html
index c638e83..441b257 100644
--- a/test/matching.html
+++ b/test/matching.html
@@ -276,8 +276,7 @@ Indexed Text: "Gulliver's Travels" (Swift Jonathan 1726)
bulksearch = new BulkSearch({
type: 'short', // this type specifies the maximum bitlength of assigned IDs!
encode: 'extra',
- multi: true,
- suggest:true
+ multi: true
});
console.time('bulksearch');
@@ -295,8 +294,7 @@ Indexed Text: "Gulliver's Travels" (Swift Jonathan 1726)
tokenize: 'strict',
threshold: 0,
resolution: 9,
- depth: 3,
- suggest: true
+ depth: 3
});
console.time('flexsearch');
@@ -452,11 +450,11 @@ Indexed Text: "Gulliver's Travels" (Swift Jonathan 1726)
switch(i){
case 1:
- results = flexsearch.search(query);
+ results = flexsearch.search(query, {suggest: true});
break;
case 2:
- results = bulksearch.search(query);
+ results = bulksearch.search(query, {suggest: true});
break;
case 3:
diff --git a/test/test.es6.js b/test/test.es6.js
index ccb0fa9..c319405 100644
--- a/test/test.es6.js
+++ b/test/test.es6.js
@@ -1,4 +1,4 @@
-var env = "";
+var env = global.env;
if(typeof module !== "undefined"){
@@ -60,7 +60,6 @@ describe("Index Multi-Field Documents (ES6)", function(){
async: true,
doc: {
-
id: "id",
field: [
"data:title",
@@ -71,8 +70,11 @@ describe("Index Multi-Field Documents (ES6)", function(){
await index.add(data);
- expect(index.doc.index["data:title"].length).to.equal(3);
- expect(index.doc.index["data:body"].length).to.equal(3);
+ if(env === ""){
+
+ expect(index.doc.index["data:title"].length).to.equal(3);
+ expect(index.doc.index["data:body"].length).to.equal(3);
+ }
expect(await index.search({field: "data:body", query: "body"})).to.have.members(data);
expect(await index.search({field: "data:title", query: "title"})).to.have.members(data);
@@ -106,8 +108,11 @@ describe("Index Multi-Field Documents (ES6)", function(){
await index.remove(update);
- expect(await index.doc.index["data:title"].length).to.equal(0);
- expect(await index.doc.index["data:body"].length).to.equal(0);
+ if(env === ""){
+
+ expect(await index.doc.index["data:title"].length).to.equal(0);
+ expect(await index.doc.index["data:body"].length).to.equal(0);
+ }
});
it("Should have been indexed properly (Worker)", async function(){
@@ -128,8 +133,11 @@ describe("Index Multi-Field Documents (ES6)", function(){
await index.add(data);
- expect(index.doc.index["data:title"].length).to.equal(3);
- expect(index.doc.index["data:body"].length).to.equal(3);
+ if(env === ""){
+
+ expect(index.doc.index["data:title"].length).to.equal(3);
+ expect(index.doc.index["data:body"].length).to.equal(3);
+ }
expect(await index.search({field: "data:body", query: "body"})).to.have.members(data);
expect(await index.search({field: "data:title", query: "title"})).to.have.members(data);
@@ -163,7 +171,10 @@ describe("Index Multi-Field Documents (ES6)", function(){
await index.remove(update);
- expect(await index.doc.index["data:title"].length).to.equal(0);
- expect(await index.doc.index["data:body"].length).to.equal(0);
+ if(env === ""){
+
+ expect(await index.doc.index["data:title"].length).to.equal(0);
+ expect(await index.doc.index["data:body"].length).to.equal(0);
+ }
});
});
diff --git a/test/test.js b/test/test.js
index 72cda27..8ac9a31 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1,6 +1,6 @@
if(typeof module !== "undefined"){
- var env = process.argv[3] === "test" ? "min" : process.argv[3] === "test/" ? "light" : "";
+ var env = global.env = process.argv[3] === "test" ? "min" : process.argv[3] === "test/" ? "light" : process.argv[3] === "test/test.js" ? "pre" : "";
var expect = require("chai").expect;
var FlexSearch = require("../" + (env ? "dist/": "") + "flexsearch" + (env ? "." + env : "") + ".js");
//require("../lang/en.min.js");
@@ -130,7 +130,7 @@ describe("Initialize", function(){
encode: "icase",
tokenize: "reverse",
- cache: true
+ cache: 2
});
it("Should have correct constructors", function(){
@@ -186,7 +186,7 @@ describe("Initialize", function(){
expect(flexsearch_async.async).to.equal(true);
}
- if((env !== "light") && (env !== "min")){
+ if((env !== "light") && (env !== "min") && (env !== "pre")){
expect(flexsearch_default.tokenize).to.equal("forward");
expect(flexsearch_strict.tokenize).to.equal("strict");
@@ -403,15 +403,42 @@ if(env !== "light"){
describe("Add (Async)", function(){
+ it("Should have been added to the index", function(done){
+
+ var index = new FlexSearch();
+
+ expect(index.length).to.equal(0);
+
+ index.add(0, "foo", function(){
+
+ expect(index.length).to.equal(1);
+
+ done();
+ });
+
+ expect(index.length).to.equal(0);
+ });
+
it("Should have been added to the index", function(done){
expect(flexsearch_async.length).to.equal(0);
- flexsearch_async.add(0, "foo");
+ flexsearch_async.add(0, "foo", function(){
+
+ done();
+ });
+
+ expect(flexsearch_async.length).to.equal(0);
+ });
+
+ it("Should have been added to the index", function(done){
+
+ expect(flexsearch_async.length).to.equal(1);
+
flexsearch_async.add(2, "bar");
flexsearch_async.add(1, "foobar");
- expect(flexsearch_async.length).to.equal(0);
+ expect(flexsearch_async.length).to.equal(1);
setTimeout(function(){
@@ -448,6 +475,20 @@ if(env !== "light"){
describe("Search (Async)", function(){
+ it("Should have been matched from index", function(done){
+
+ var index = new FlexSearch({doc: {id: "id", field: "title"}});
+ var data = {id: 0, title: "foo"};
+
+ index.add(data);
+
+ index.search("foo", function(result){
+
+ expect(result).to.have.members([data]);
+ done();
+ });
+ });
+
it("Should have been matched from index", function(done){
flexsearch_async.search("foo", function(result){
@@ -580,13 +621,44 @@ if(env !== "light"){
it("Should have been removed from the index", function(done){
- flexsearch_async.remove(0);
+ var index = new FlexSearch();
+
+ index.add(0, "foo");
+
+ expect(index.length).to.equal(1);
+
+ index.remove(0, function(){
+
+ expect(index.length).to.equal(0);
+
+ done();
+ });
+
+ expect(index.length).to.equal(1);
+ });
+
+ it("Should have been removed from the index", function(done){
+
+ expect(flexsearch_async.length).to.equal(3);
+
+ flexsearch_async.remove(0, function(){
+
+ expect(flexsearch_async.length).to.equal(2);
+
+ done();
+ });
+
+ expect(flexsearch_async.length).to.equal(3);
+ });
+
+ it("Should have been removed from the index", function(done){
+
flexsearch_async.remove(2);
flexsearch_async.remove(1).then(function(){
expect(flexsearch_async.length).to.equal(0);
});
- expect(flexsearch_async.length).to.equal(3);
+ expect(flexsearch_async.length).to.equal(2);
flexsearch_async.search("foo", function(result){
expect(result).to.have.lengthOf(0);
@@ -794,7 +866,7 @@ if(env !== "light"){
});
});
- if(env !== "light" && env !== "min"){
+ if((env !== "light") && (env !== "min")){
it("Should have been debug mode activated", function(){
@@ -820,7 +892,7 @@ if(env !== "light"){
worker: 4
});
- if(env !== "min"){
+ if((env !== "min") && (env !== "pre")){
expect(flexsearch_worker.info().worker).to.equal(false);
}
@@ -1130,6 +1202,50 @@ describe("Stemmer", function(){
});
});
+
+describe("Custom Language", function(){
+
+ it("Should have been applied properly", function(){
+
+ FlexSearch.registerLanguage("custom", {
+ filter: ["a", "an"],
+ stemmer: {
+ "ization": "ize",
+ "tional": "tion"
+ }
+ });
+
+ var index = new FlexSearch({
+ encode: "icase",
+ tokenize: "reverse",
+ filter: "custom",
+ stemmer: "custom"
+ });
+
+ index.add(0, "Just a multinational colonization.");
+
+ expect(index.length).to.equal(1);
+ expect(index.search("Just a multinational colonization.")).to.include(0);
+ expect(index.search("Just an multinational colonization.")).to.include(0);
+ expect(index.search("multinational colonization")).to.include(0);
+ expect(index.search("tional tion")).to.have.length(0);
+
+ index = new FlexSearch({
+ encode: "icase",
+ tokenize: "reverse",
+ lang: "custom"
+ });
+
+ index.add(0, "Just a multinational colonization.");
+
+ expect(index.length).to.equal(1);
+ expect(index.search("Just a multinational colonization.")).to.include(0);
+ expect(index.search("Just an multinational colonization.")).to.include(0);
+ expect(index.search("multinational colonization")).to.include(0);
+ expect(index.search("tional tion")).to.have.length(0);
+ });
+});
+
// ------------------------------------------------------------------------
// Relevance Tests
// ------------------------------------------------------------------------
@@ -1209,11 +1325,31 @@ if(env !== "light") describe("Suggestions", function(){
expect(index.search("1 3 4 7", { suggest: false })).to.have.lengthOf(0);
expect(index.search("1 3 4 7", { suggest: true })).to.have.members([0]);
expect(index.search("1 3 9 7", { suggest: true })).to.have.members([0]);
+
+ expect(index.search("foobar one two", { suggest: true })).to.have.members([1, 2]);
expect(index.search("one foobar two", { suggest: true })).to.have.members([1, 2]);
+ expect(index.search("one two foobar", { suggest: true })).to.have.members([1, 2]);
expect(index.search("zero one foobar two foobar", { suggest: true })).to.have.members([1, 2]);
+ });
+
+ it("Should have been suggested properly by context", function(){
+
+ var index = new FlexSearch({
+ encode: "advanced",
+ tokenize: "strict",
+ depth: 3
+ });
+
+ index.add(1, "zero one two three four five six seven eight nine ten");
+ index.add(2, "four two zero one three ten five seven eight six nine");
- //TODO
- //expect(index.search("zero one foobar two foobar")[0]).to.equal(1);
+ expect(index.search("foobar one", { suggest: true })).to.have.members([1, 2]);
+ expect(index.search("foobar foobar foobar one foobar foobar foobar", { suggest: true })).to.have.members([1, 2]);
+ expect(index.search("foobar one two", { suggest: true })).to.have.members([1, 2]);
+ expect(index.search("one foobar two", { suggest: true })).to.have.members([1, 2]);
+ expect(index.search("one two foobar", { suggest: true })).to.have.members([1, 2]);
+ expect(index.search("foobar one foobar two foobar", { suggest: true })).to.have.members([1, 2]);
+ expect(index.search("zero one foobar two foobar", { suggest: true })).to.have.members([1, 2]);
});
});
@@ -1221,7 +1357,7 @@ if(env !== "light") describe("Suggestions", function(){
// Where Clause
// ------------------------------------------------------------------------
-if(env === "" || env === "min") describe("Where/Find", function(){
+if((env === "") || (env === "min") || (env === "pre")) describe("Where/Find", function(){
var data = [{
id: 0,
@@ -1286,6 +1422,145 @@ if(env === "" || env === "min") describe("Where/Find", function(){
}
})).to.have.members([data[2]]);
});
+
+ it("Should have been tagged properly", function(){
+
+ var index = new FlexSearch({
+ doc: {
+ id: "id",
+ field: "title",
+ tag : "cat"
+ }
+ });
+
+ index.add(data);
+
+ expect(index.length).to.equal(3);
+ expect(index.index).to.have.members(["@0", "@1", "@2"]);
+
+ expect(index.where({cat: "1"})).to.have.members([data[0], data[2]]);
+ expect(index.where("cat", "1")).to.have.members([data[0], data[2]]);
+ expect(index.where("cat", "1", 1)).to.have.members([data[0]]);
+
+ expect(index.where({
+ cat: "1",
+ flag: true
+ })).to.have.members([data[2]]);
+
+ expect(index.where({
+ flag: true,
+ cat: "1"
+ })).to.have.members([data[2]]);
+
+ expect(index.search("title", {
+ where: {
+ cat: "1"
+ }
+ })).to.have.members([data[0], data[2]]);
+
+ expect(index.search("title", {
+ where: {
+ cat: "1"
+ },
+ limit: 1
+ })).to.have.members([data[0]]);
+
+ expect(index.search("title", {
+ where: {
+ cat: "3"
+ }
+ })).to.have.lengthOf(0);
+
+ expect(index.search("foobar", {
+ where: {
+ cat: "1"
+ }
+ })).to.have.lengthOf(0);
+
+ // -----------------------------------------
+
+ index = new FlexSearch({
+ doc: {
+ id: "id",
+ field: ["title"],
+ tag : ["cat"]
+ }
+ });
+
+ index.add(data);
+
+ expect(index.length).to.equal(3);
+ expect(index.index).to.have.members(["@0", "@1", "@2"]);
+
+ expect(index.where({cat: "1"})).to.have.members([data[0], data[2]]);
+
+ expect(index.search("title", {
+ where: {
+ cat: "1"
+ }
+ })).to.have.members([data[0], data[2]]);
+
+ expect(index.search("title", {
+ where: {
+ cat: "3"
+ }
+ })).to.have.lengthOf(0);
+
+ expect(index.search("foobar", {
+ where: {
+ cat: "1"
+ }
+ })).to.have.lengthOf(0);
+
+ // ------------------------------------
+
+ index = new FlexSearch({
+ doc: {
+ id: "id",
+ field: "data:title",
+ tag : "data:cat"
+ }
+ });
+
+ data = [{
+ id: 0,
+ data: {
+ title: "Title 1",
+ cat: "1",
+ flag: false
+ }
+ },{
+ id: 1,
+ data: {
+ title: "Title 2",
+ cat: "2",
+ flag: false
+ }
+ },{
+ id: 2,
+ data: {
+ title: "Title 3",
+ cat: "1",
+ flag: true
+ }
+ }];
+
+ index.add(data);
+
+ expect(index.where({"data:cat": "1"})).to.have.members([data[0], data[2]]);
+ expect(index.where("data:cat", "1")).to.have.members([data[0], data[2]]);
+ expect(index.where("data:cat", "1", 1)).to.have.members([data[0]]);
+
+ expect(index.where({
+ "data:cat": "1",
+ "data:flag": true
+ })).to.have.members([data[2]]);
+
+ expect(index.where({
+ "data:flag": true,
+ "data:cat": "1"
+ })).to.have.members([data[2]]);
+ });
});
// ------------------------------------------------------------------------
@@ -1777,7 +2052,79 @@ if(env !== "light") describe("Index Multi-Field Documents", function(){
expect(results[2]).to.equal(data[0]);
});
- if(env === "" && (typeof require !== "undefined") && !this._phantom){
+ it("Should have been sorted suggested and paged", function(){
+
+ var index = new FlexSearch({
+
+ doc: {
+ id: "id",
+ field: ["data:title", "data:body"]
+ }
+ });
+
+ index.add(data);
+
+ var results = index.search({
+
+ field: "data:title",
+ query: "title",
+ suggest: true,
+ page: true,
+ limit: 2
+ });
+
+ expect(results.result).to.have.members([data[0], data[1]]);
+
+ results = index.search({
+
+ field: "data:title",
+ query: "title",
+ suggest: true,
+ page: results.next,
+ limit: 2
+ });
+
+ expect(results.result).to.have.members([data[2]]);
+
+ results = index.search({
+
+ field: "data:title",
+ query: "foobar title foobar title foobar",
+ suggest: true,
+ page: true,
+ limit: 2
+ });
+
+ expect(results.result).to.have.members([data[0], data[1]]);
+
+ results = index.search({
+
+ field: "data:title",
+ query: "foobar title foobar title foobar",
+ suggest: true,
+ page: results.next,
+ limit: 2
+ });
+
+ expect(results.result).to.have.members([data[2]]);
+
+ results = index.search([{
+
+ field: "data:title",
+ query: "title undefined",
+ bool: "and",
+ suggest: true,
+ limit: 2
+ },{
+ field: "data:body",
+ query: "undefined",
+ bool: "not"
+ }]);
+
+ expect(results).to.have.members([data[0], data[1]]);
+ });
+
+ if((!env || (env === "pre")) && (typeof require !== "undefined") && !this._phantom){
require("./test.es6.js");
}
@@ -1829,6 +2176,66 @@ if(env !== "light") describe("Pagination", function(){
expect(result.result).to.have.members([4]);
});
+ it("Should have been properly paged (suggestion)", function(){
+
+ var index = new FlexSearch();
+
+ index.add(0, "foo bar").add(1, "foo bar").add(2, "foo bar test").add(3, "foo bar").add(4, "foo bar");
+
+ expect(index.index).to.have.members(["@0", "@1", "@2", "@3", "@4"]);
+ expect(index.search("foo")).to.have.lengthOf(5);
+ expect(index.search("foo", 2)).to.have.lengthOf(2);
+
+ var result = index.search("foo undefined bar", {
+ suggest: true,
+ page: true,
+ limit: 2
+ });
+
+ expect(result).to.have.keys(["page", "next", "result"]);
+ expect(result.result).to.have.members([0, 1]);
+
+ result = index.search("foo bar test", {
+ suggest: true,
+ page: true,
+ limit: 2
+ });
+
+ expect(result.result).to.have.members([2, 0]);
+
+ result = index.search("foo undefined bar", {
+ suggest: true,
+ page: true,
+ limit: 2
+ });
+
+ expect(result.result).to.have.members([0, 1]);
+
+ result = index.search("foo undefined bar", {
+ suggest: true,
+ page: result.next,
+ limit: 2
+ });
+
+ expect(result.result).to.have.members([2, 3]);
+
+ result = index.search("foo undefined bar", {
+ suggest: true,
+ page: result.page,
+ limit: 2
+ });
+
+ expect(result.result).to.have.members([2, 3]);
+
+ result = index.search("foo undefined bar", {
+ suggest: true,
+ page: result.next,
+ limit: 2
+ });
+
+ expect(result.result).to.have.members([4]);
+ });
+
it("Should have been properly paged (documents)", function(){
var data = [{
@@ -2164,6 +2571,20 @@ if(env !== "light") describe("Operators", function(){
query: "x",
bool: "not"
}])).to.have.length(0);
+
+ expect(index.search([{
+ field: "title",
+ query: "title",
+ bool: "not"
+ },{
+ field: "body",
+ query: "body",
+ bool: "not"
+ },{
+ field: "blacklist",
+ query: "x",
+ bool: "not"
+ }])).to.have.length(0);
});
});
@@ -2220,6 +2641,42 @@ if(env !== "light") describe("Export / Import", function(){
it("Should have been exported properly", function(){
+ var index = new FlexSearch("match");
+
+ index.add(0, "foo");
+ index.add(1, "bar");
+ index.add(2, "foobar");
+
+ data = index.export();
+
+ if(env === ""){
+
+ expect(data).to.equal(JSON.stringify(
+ [
+ index._map,
+ index._ctx,
+ Object.keys(index._ids)
+ ]
+ ));
+ }
+ });
+
+ it("Should have been imported properly", function(){
+
+ var index = new FlexSearch("match");
+
+ index.import(data);
+
+ expect(index.length).to.equal(3);
+
+ expect(index.search("foo")).to.have.lengthOf(2);
+ expect(index.search("bar")).to.have.lengthOf(2);
+ expect(index.search("foobar")).to.have.lengthOf(1);
+ expect(index.search("foobar")[0]).to.equal(2);
+ });
+
+ it("Should have been exported properly (documents)", function(){
+
var index = new FlexSearch({
tokenize: "reverse",
doc: {
@@ -2248,9 +2705,10 @@ if(env !== "light") describe("Export / Import", function(){
}
});
- it("Should have been imported properly", function(){
+ it("Should have been imported properly (documents)", function(){
- var index = new FlexSearch("score", {
+ var index = new FlexSearch({
+ tokenize: "reverse",
doc: {
id: "id",
field: "title"
@@ -2286,6 +2744,19 @@ describe("Presets", function(){
expect(FlexSearch.create("balance").length).to.equal(0);
expect(FlexSearch.create("fast").length).to.equal(0);
});
+
+ it("Should have been properly extended", function(){
+
+ var index = FlexSearch.create("fast");
+ index.add(0, "foobar");
+ expect(index.search("bar")).to.have.lengthOf(0);
+
+ index = FlexSearch.create("fast", {id: "test", tokenize: "reverse"});
+ expect(index.id).to.equal("test");
+ index.add(0, "foobar");
+ expect(index.search("bar")).to.have.lengthOf(1);
+ expect(index.search("bar")).to.have.members([0])
+ });
});
// ------------------------------------------------------------------------
@@ -2418,6 +2889,23 @@ describe("Destroy", function(){
expect(index.search("foo")).to.have.lengthOf(0);
expect(index.search("bar")).to.have.lengthOf(0);
});
+
+ if(env !== "light") it("Should have been destroyed properly (documents)", function(){
+
+ var data = [{id: 0, title: "foo"}, {id: 1, title: "bar"}];
+
+ var index = FlexSearch.create({doc: {id: "id", field: "title"}})
+ .add(data)
+ .add(data);
+
+ expect(index.search("foo")).to.have.members([data[0]]);
+ expect(index.search("bar")).to.have.members([data[1]]);
+
+ index.destroy();
+
+ expect(index.search("foo")).to.have.lengthOf(0);
+ expect(index.search("bar")).to.have.lengthOf(0);
+ });
});
// ------------------------------------------------------------------------