diff --git a/dist/flexsearch.compact.js b/dist/flexsearch.compact.js deleted file mode 100644 index c6da016..0000000 --- a/dist/flexsearch.compact.js +++ /dev/null @@ -1,29 +0,0 @@ -/**! - * FlexSearch.js v0.7.0 - * Copyright 2019 Nextapps GmbH - * Author: Thomas Wilkerling - * Licence: Apache-2.0 - * https://github.com/nextapps-de/flexsearch - */ -(function(){'use strict';Object.assign||(Object.assign=function(){for(var a=arguments,b=a.length,c=a[0],d=1,e,g,f;dx;B--)v=u.substring(x,B),U(l,e,v,a,K,r,k,m-1);break;default:if(w=U(l,e,u,a,1,r,k,m-1),p&&1=k)for(w=e._ctx[u]||(e._ctx[u]=F()),u=this.g[u]||(this.g[u]=C(m-(k||0))),r=t-p,v=t+p+1,0>r&&(r=0),v>h&&(v=h);r=f&&(a=a[h-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e}function W(a,b){if(a)for(var c=Object.keys(a),d=0,e=c.length;db?1:0}function ja(a,b){for(var c=X.length,d=0;db?1:0}function Z(a,b,c){return a?{page:a,next:b?""+b:null,result:c}:c} -function ia(a,b,c,d,e,g){var f=[];if(!0===c){c="0";var h=""}else h=c&&c.split(":");var k=a.length;if(1 -m&&(h=0);h=h||0;var E=h+b;E 1) { - str = replace$$module$src$common(str, this.stemmer); - } - if (_collapse && str.length > 1) { - str = collapse$$module$src$common(str); - } - if (str) { - if (split || split === "") { - var words = str.split(split); - return this.filter ? filter$$module$src$common(words, this.filter) : words; - } - } - } - return str; -}; -var module$src$common = {}; -module$src$common.collapse = collapse$$module$src$common; -module$src$common.create_object = create_object$$module$src$common; -module$src$common.create_object_array = create_object_array$$module$src$common; -module$src$common.filter = filter$$module$src$common; -module$src$common.get_keys = get_keys$$module$src$common; -module$src$common.is_array = is_array$$module$src$common; -module$src$common.is_function = is_function$$module$src$common; -module$src$common.is_object = is_object$$module$src$common; -module$src$common.is_string = is_string$$module$src$common; -module$src$common.is_undefined = is_undefined$$module$src$common; -module$src$common.regex = regex$$module$src$common; -module$src$common.replace = replace$$module$src$common; -if (SUPPORT_SERIALIZE) { - FlexSearch$$module$src$flexsearch.prototype.export = function(config) { - var serialize = !config || is_undefined$$module$src$common(config["serialize"]) || config["serialize"]; - var payload; - if (SUPPORT_DOCUMENT && this.doc) { - var export_doc = !config || is_undefined$$module$src$common(config["doc"]) || config["doc"]; - var export_index = !config || is_undefined$$module$src$common(config["index"]) || config["index"]; - payload = []; - var i = 0; - if (export_index) { - var keys = this.doc.keys; - for (; i < keys.length; i++) { - var idx = this.doc.index[keys[i]]; - payload[i] = [idx._map, idx._ctx, get_keys$$module$src$common(idx._ids)]; - } - } - if (export_doc) { - payload[i] = this._doc; - } - } else { - payload = [this._map, this._ctx, get_keys$$module$src$common(this._ids)]; - } - if (serialize) { - payload = JSON.stringify(payload); - } - return payload; - }; - FlexSearch$$module$src$flexsearch.prototype.import = function(payload, config) { - var serialize = !config || is_undefined$$module$src$common(config["serialize"]) || config["serialize"]; - if (serialize) { - payload = JSON.parse(payload); - } - var ids = {}; - if (SUPPORT_DOCUMENT && this.doc) { - var import_doc = !config || is_undefined$$module$src$common(config["doc"]) || config["doc"]; - var import_index = !config || is_undefined$$module$src$common(config["index"]) || config["index"]; - var i = 0; - if (import_index) { - var keys = this.doc.keys; - var length = keys.length; - var current = payload[0][2]; - for (; i < current.length; i++) { - ids[current[i]] = 1; - } - for (i = 0; i < length; i++) { - var idx = this.doc.index[keys[i]]; - var item = payload[i]; - if (item) { - idx._map = item[0]; - idx._ctx = item[1]; - idx._ids = ids; - } - } - } - if (import_doc) { - this._doc = is_object$$module$src$common(import_doc) ? import_doc : payload[i]; - } - } else { - var current$0 = payload[2]; - for (var i$1 = 0; i$1 < current$0.length; i$1++) { - ids[current$0[i$1]] = 1; - } - this._map = payload[0]; - this._ctx = payload[1]; - this._ids = ids; - } - }; -} -var module$src$serialize = {}; -if (SUPPORT_DOCUMENT && SUPPORT_WHERE) { - FlexSearch$$module$src$flexsearch.prototype.find = function(key, value) { - return this.where(key, value, 1)[0] || null; - }; - FlexSearch$$module$src$flexsearch.prototype.where = function(key, value, limit, result) { - var doc = this._doc; - var results = []; - var count = 0; - var keys; - var keys_len; - var has_value; - var tree; - var tag_results; - if (is_object$$module$src$common(key)) { - limit || (limit = value); - keys = get_keys$$module$src$common(key); - keys_len = keys.length; - has_value = false; - if (keys_len === 1 && keys[0] === "id") { - return [doc[key["id"]]]; - } - var tags = this._tags; - if (tags && !result) { - for (var i = 0; i < tags.length; i++) { - var current_tag = tags[i]; - var current_where = key[current_tag]; - if (!is_undefined$$module$src$common(current_where)) { - tag_results = this._tag[current_tag]["@" + current_where]; - if (--keys_len === 0) { - return tag_results; - } - keys.splice(keys.indexOf(current_tag), 1); - delete key[current_tag]; - break; - } - } - } - tree = new Array(keys_len); - for (var i$2 = 0; i$2 < keys_len; i$2++) { - tree[i$2] = keys[i$2].split(":"); - } - } else { - if (is_function$$module$src$common(key)) { - var ids$3 = result || get_keys$$module$src$common(doc); - var length$4 = ids$3.length; - for (var x = 0; x < length$4; x++) { - var obj = doc[ids$3[x]]; - if (key(obj)) { - results[count++] = obj; - } - } - return results; - } else { - if (is_undefined$$module$src$common(value)) { - return [doc[key]]; - } - if (key === "id") { - return [doc[value]]; - } - keys = [key]; - keys_len = 1; - tree = [key.split(":")]; - has_value = true; - } - } - var ids = tag_results || result || get_keys$$module$src$common(doc); - var length = ids.length; - for (var x$5 = 0; x$5 < length; x$5++) { - var obj$6 = tag_results ? ids[x$5] : doc[ids[x$5]]; - var found = true; - for (var i$7 = 0; i$7 < keys_len; i$7++) { - has_value || (value = key[keys[i$7]]); - var tree_cur = tree[i$7]; - var tree_len = tree_cur.length; - var ref = obj$6; - if (tree_len > 1) { - for (var z = 0; z < tree_len; z++) { - ref = ref[tree_cur[z]]; - } - } else { - ref = ref[tree_cur[0]]; - } - if (ref !== value) { - found = false; - break; - } - } - if (found) { - results[count++] = obj$6; - if (limit && count === limit) { - break; - } - } - } - return results; - }; -} -var module$src$where = {}; -function CacheClass$$module$src$cache(limit) { - this.clear(); - this.limit = limit !== true && limit; -} -CacheClass$$module$src$cache.prototype.clear = function() { - this.cache = create_object$$module$src$common(); - this.count = create_object$$module$src$common(); - this.index = create_object$$module$src$common(); - this.ids = []; -}; -CacheClass$$module$src$cache.prototype.set = function(key, value) { - if (this.limit && is_undefined$$module$src$common(this.cache[key])) { - var length = this.ids.length; - if (length === this.limit) { - length--; - var last_id = this.ids[length]; - delete this.cache[last_id]; - delete this.count[last_id]; - delete this.index[last_id]; - } - this.ids[length] = key; - this.index[key] = length; - this.count[key] = -1; - this.cache[key] = value; - this.get(key); - } else { - this.cache[key] = value; - } -}; -CacheClass$$module$src$cache.prototype.get = function(key) { - var cache = this.cache[key]; - if (this.limit && cache) { - var count = ++this.count[key]; - var index = this.index; - var current_index = index[key]; - if (current_index > 0) { - var ids = this.ids; - var old_index = current_index; - while (this.count[ids[--current_index]] <= count) { - if (current_index === -1) { - break; - } - } - current_index++; - if (current_index !== old_index) { - for (var i = old_index; i > current_index; i--) { - var tmp = ids[i - 1]; - ids[i] = tmp; - index[tmp] = i; - } - ids[current_index] = key; - index[key] = current_index; - } - } - } - return cache; -}; -var module$src$cache = {}; -module$src$cache.default = CacheClass$$module$src$cache; -var worker_stack$$module$src$worker = {}; -var inline_supported$$module$src$worker = typeof Blob !== "undefined" && typeof URL !== "undefined" && URL.createObjectURL; -function init$$module$src$worker(_name, _id, _worker, _callback, _core) { - var name = _name; - var worker_payload = inline_supported$$module$src$worker ? URL.createObjectURL(new Blob([(RELEASE ? "" : "var RELEASE = '" + RELEASE + "';" + "var DEBUG = " + (DEBUG ? "true" : "false") + ";" + "var PROFILER = " + (PROFILER ? "true" : "false") + ";" + "var SUPPORT_PRESET = " + (SUPPORT_PRESET ? "true" : "false") + ";" + "var SUPPORT_SUGGESTION = " + (SUPPORT_SUGGESTION ? "true" : "false") + ";" + "var SUPPORT_ENCODER = " + (SUPPORT_ENCODER ? "true" : "false") + ";" + "var SUPPORT_CACHE = " + (SUPPORT_CACHE ? - "true" : "false") + ";" + "var SUPPORT_ASYNC = " + (SUPPORT_ASYNC ? "true" : "false") + ";" + "var SUPPORT_SERIALIZE = " + (SUPPORT_SERIALIZE ? "true" : "false") + ";" + "var SUPPORT_INFO = " + (SUPPORT_INFO ? "true" : "false") + ";" + "var SUPPORT_DOCUMENT = " + (SUPPORT_DOCUMENT ? "true" : "false") + ";" + "var SUPPORT_WHERE = " + (SUPPORT_WHERE ? "true" : "false") + ";" + "var SUPPORT_PAGINATION = " + (SUPPORT_PAGINATION ? "true" : "false") + ";" + "var SUPPORT_OPERATOR = " + (SUPPORT_OPERATOR ? - "true" : "false") + ";" + "var SUPPORT_CALLBACK = " + (SUPPORT_CALLBACK ? "true" : "false") + ";" + "var SUPPORT_WORKER = true;") + "(" + _worker.toString() + ")()"], {"type":"text/javascript"})) : name + (RELEASE ? "." + RELEASE : "") + ".js"; - name += "-" + _id; - worker_stack$$module$src$worker[name] || (worker_stack$$module$src$worker[name] = []); - worker_stack$$module$src$worker[name][_core] = new Worker(worker_payload); - worker_stack$$module$src$worker[name][_core]["onmessage"] = _callback; - if (DEBUG) { - console.log("Register Worker: " + name + "@" + _core); - } - return worker_stack$$module$src$worker[name][_core]; -} -function worker_module$$module$src$worker() { - var id; - var FlexSearchWorker; - self.onmessage = function(event) { - var data = event["data"]; - if (data) { - if (data["search"]) { - var results = FlexSearchWorker["search"](data["content"], data["threshold"] ? {"limit":data["limit"], "threshold":data["threshold"], "where":data["where"]} : data["limit"]); - self.postMessage({"id":id, "content":data["content"], "limit":data["limit"], "result":results}); - } else { - if (data["add"]) { - FlexSearchWorker["add"](data["id"], data["content"]); - } else { - if (data["update"]) { - FlexSearchWorker["update"](data["id"], data["content"]); - } else { - if (data["remove"]) { - FlexSearchWorker["remove"](data["id"]); - } else { - if (data["clear"]) { - FlexSearchWorker["clear"](); - } else { - if (SUPPORT_INFO && data["info"]) { - var info = FlexSearchWorker["info"](); - info["worker"] = id; - console.log(info); - } else { - if (data["register"]) { - id = data["id"]; - data["options"]["cache"] = false; - data["options"]["async"] = false; - data["options"]["worker"] = false; - FlexSearchWorker = (new Function(data["register"].substring(data["register"].indexOf("{") + 1, data["register"].lastIndexOf("}"))))(); - FlexSearchWorker = new FlexSearchWorker(data["options"]); - } - } - } - } - } - } - } - } - }; -} -function addWorker$$module$src$worker(id, core, options, callback) { - var thread = init$$module$src$worker("flexsearch", "id" + id, worker_module$$module$src$worker, function(event) { - var data = event["data"]; - if (data && data["result"]) { - callback(data["id"], data["content"], data["result"], data["limit"], data["where"], data["cursor"], data["suggest"]); - } - }, core); - var fnStr = FlexSearch$$module$src$flexsearch.toString(); - options["id"] = core; - thread.postMessage({"register":fnStr, "options":options, "id":core}); - return thread; -} -if (SUPPORT_WORKER) { - FlexSearch$$module$src$flexsearch.prototype.worker_handler = function(id, query, result, limit, where, cursor, suggest) { - if (this._task_completed !== this.worker) { - this._task_result = this._task_result.concat(result); - this._task_completed++; - if (limit && this._task_result.length >= limit) { - this._task_completed = this.worker; - } - if (this._task_completed === this.worker) { - if (this.cache) { - this._cache.set(query, this._task_result); - } - if (this._current_callback) { - this._current_callback(this._task_result); - } - } - } - return this; - }; -} -var module$src$worker = {}; -module$src$worker.addWorker = addWorker$$module$src$worker; -module$src$worker.default = init$$module$src$worker; -var $jscompDefaultExport$$module$src$presets = {"memory":{charset:"latin:extra", threshold:0, resolution:1}, "speed":{threshold:1, resolution:3, depth:2}, "match":{charset:"latin:extra", tokenize:"full", threshold:1, resolution:3}, "score":{charset:"latin:extra", threshold:1, resolution:9, depth:4}, "balance":{charset:"latin:balance", threshold:0, resolution:3, depth:3}, "fast":{threshold:8, resolution:9, depth:1}}; -var module$src$presets = {}; -module$src$presets.default = $jscompDefaultExport$$module$src$presets; -var rtl$$module$src$lang$latin$default = false; -var tokenize$$module$src$lang$latin$default = ""; -var $jscompDefaultExport$$module$src$lang$latin$default = {encode:encode$$module$src$lang$latin$default, rtl:rtl$$module$src$lang$latin$default}; -var regex_whitespace$$module$src$lang$latin$default = /[\W_]+/; -function encode$$module$src$lang$latin$default(str) { - return this.pipeline(str.toLowerCase(), false, regex_whitespace$$module$src$lang$latin$default, false); -} -var module$src$lang$latin$default = {}; -module$src$lang$latin$default.default = $jscompDefaultExport$$module$src$lang$latin$default; -module$src$lang$latin$default.encode = encode$$module$src$lang$latin$default; -module$src$lang$latin$default.rtl = rtl$$module$src$lang$latin$default; -module$src$lang$latin$default.tokenize = tokenize$$module$src$lang$latin$default; -var id_counter$$module$src$flexsearch = 0; -var global_lang$$module$src$flexsearch = {}; -var global_charset$$module$src$flexsearch = {}; -function FlexSearch$$module$src$flexsearch(options) { - if (!(this instanceof FlexSearch$$module$src$flexsearch)) { - return new FlexSearch$$module$src$flexsearch(options); - } - var id = options && options["id"]; - this.id = id || id === 0 ? id : id_counter$$module$src$flexsearch++; - this.init(options); - register_property$$module$src$flexsearch(this, "index", function() { - if (SUPPORT_DOCUMENT && this.doc) { - return get_keys$$module$src$common(this.doc.index[this.doc.keys[0]]._ids); - } - return get_keys$$module$src$common(this._ids); - }); - register_property$$module$src$flexsearch(this, "length", function() { - return this["index"].length; - }); -} -FlexSearch$$module$src$flexsearch["registerCharset"] = function(name, charset) { - global_charset$$module$src$flexsearch[name] = charset; - return FlexSearch$$module$src$flexsearch; -}; -FlexSearch$$module$src$flexsearch["registerLanguage"] = function(name, lang) { - global_lang$$module$src$flexsearch[name] = lang; - return FlexSearch$$module$src$flexsearch; -}; -FlexSearch$$module$src$flexsearch.prototype.init = function(options) { - var custom; - var doc; - if (SUPPORT_PRESET && options) { - if (is_string$$module$src$common(options)) { - if (DEBUG && !$jscompDefaultExport$$module$src$presets[options]) { - console.warn("Preset not found: " + options); - } - options = $jscompDefaultExport$$module$src$presets[options]; - } else { - if (custom = options["preset"]) { - if (DEBUG && !$jscompDefaultExport$$module$src$presets[custom]) { - console.warn("Preset not found: " + custom); - } - options = Object.assign({}, $jscompDefaultExport$$module$src$presets[custom], options); - } - } - } - options || (options = {}); - if (SUPPORT_WORKER && (custom = options["worker"])) { - if (typeof init$$module$src$worker === "undefined") { - options["worker"] = false; - this._worker = null; - } else { - var threads = parseInt(custom, 10) || 4; - this._current_task = -1; - this._task_completed = 0; - this._task_result = []; - this._current_callback = null; - this._worker = new Array(threads); - for (var i = 0; i < threads; i++) { - this._worker[i] = addWorker$$module$src$worker(this.id, i, options, this.worker_handler); - } - } - this.worker = custom; - } - if (SUPPORT_ASYNC) { - this.async = options["async"]; - this.timer = 0; - } - var charset = options["charset"]; - var lang = options["lang"]; - if (is_string$$module$src$common(charset)) { - if (charset.indexOf(":") === -1) { - charset += ":default"; - } - charset = global_charset$$module$src$flexsearch[charset]; - } - if (is_string$$module$src$common(lang)) { - lang = global_lang$$module$src$flexsearch[lang]; - } - this.tokenizer = custom = charset && charset.tokenize || options["tokenize"] || "strict"; - this.depth = custom === "strict" && options["depth"] || 0; - this.rtl = charset && charset.rtl || options["rtl"] || false; - this.resolution = options["resolution"] || 9; - this.threshold = custom = options["threshold"] || 0; - if (this.resolution <= custom) { - this.resolution = custom + 1; - } - this.encode = options["encode"] || charset && charset.encode || encode$$module$src$lang$latin$default; - this.matcher = (custom = options["matcher"] || lang && lang.matcher) && init_stemmer_or_matcher$$module$src$flexsearch(custom, false); - this.stemmer = (custom = options["stemmer"] || lang && lang.stemmer) && init_stemmer_or_matcher$$module$src$flexsearch(custom, true); - this.filter = (custom = options["filter"] || lang && lang.filter) && init_filter$$module$src$flexsearch(custom); - if (SUPPORT_DOCUMENT) { - this.doc = doc = (custom = options["doc"]) && clone_object$$module$src$flexsearch(custom); - if (doc) { - options["doc"] = null; - } - } - this._map = create_object_array$$module$src$common(this.resolution - this.threshold); - this._ctx = create_object$$module$src$common(); - this._ids = create_object$$module$src$common(); - if (SUPPORT_DOCUMENT && doc) { - this._doc = create_object$$module$src$common(); - var index = doc.index = {}; - var keys = doc.keys = []; - var field = doc["field"]; - var tag = doc["tag"]; - var store = doc["store"]; - if (!is_array$$module$src$common(doc["id"])) { - doc["id"] = doc["id"].split(":"); - } - if (store) { - var store_custom = create_object$$module$src$common(); - if (is_string$$module$src$common(store)) { - store_custom[store] = 1; - } else { - if (is_array$$module$src$common(store)) { - for (var i$8 = 0; i$8 < store.length; i$8++) { - store_custom[store[i$8]] = 1; - } - } else { - if (is_object$$module$src$common(store)) { - store_custom = store; - } - } - } - doc["store"] = store_custom; - } - if (SUPPORT_WHERE && tag) { - this._tag = create_object$$module$src$common(); - var field_custom = create_object$$module$src$common(); - if (field) { - if (is_string$$module$src$common(field)) { - field_custom[field] = options; - } else { - if (is_array$$module$src$common(field)) { - for (var i$9 = 0; i$9 < field.length; i$9++) { - field_custom[field[i$9]] = options; - } - } else { - if (is_object$$module$src$common(field)) { - field_custom = field; - } - } - } - } - if (!is_array$$module$src$common(tag)) { - doc["tag"] = tag = [tag]; - } - for (var i$10 = 0; i$10 < tag.length; i$10++) { - this._tag[tag[i$10]] = create_object$$module$src$common(); - } - this._tags = tag; - field = field_custom; - } - if (field) { - var has_custom; - if (!is_array$$module$src$common(field)) { - if (is_object$$module$src$common(field)) { - has_custom = field; - doc["field"] = field = get_keys$$module$src$common(field); - } else { - doc["field"] = field = [field]; - } - } - for (var i$11 = 0; i$11 < field.length; i$11++) { - var ref = field[i$11]; - if (!is_array$$module$src$common(ref)) { - if (has_custom) { - options = has_custom[ref]; - } - keys[i$11] = ref; - field[i$11] = ref.split(":"); - } - index[ref] = new FlexSearch$$module$src$flexsearch(options); - } - } - } - if (SUPPORT_CACHE) { - this._cache_status = true; - this._cache = (custom = options["cache"]) && new CacheClass$$module$src$cache(custom); - } - return this; -}; -function clone_object$$module$src$flexsearch(obj) { - var clone = create_object$$module$src$common(); - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - var value = obj[key]; - if (is_array$$module$src$common(value)) { - clone[key] = value.slice(0); - } else { - if (is_object$$module$src$common(value)) { - clone[key] = clone_object$$module$src$flexsearch(value); - } else { - clone[key] = value; - } - } - } - } - return clone; -} -FlexSearch$$module$src$flexsearch.prototype.add = function(id, content, callback, _skip_update, _recall) { - if (SUPPORT_DOCUMENT && this.doc && is_object$$module$src$common(id)) { - return this.handle_docs("add", id, content); - } - if (content && is_string$$module$src$common(content) && (id || id === 0)) { - if (this._ids[id] && !_skip_update) { - return this.update(id, content); - } - if (!_recall) { - if (SUPPORT_ASYNC && this.async && (!SUPPORT_WORKER || typeof importScripts !== "function")) { - var self$12 = this; - var promise = new Promise(function(resolve) { - setTimeout(function() { - self$12.add(id, content, null, _skip_update, true); - self$12 = null; - resolve(); - }); - }); - if (callback) { - promise.then(callback); - } else { - return promise; - } - return this; - } - if (callback) { - this.add(id, content, null, _skip_update, true); - callback(); - return this; - } - } - content = this.encode(content); - if (!content.length) { - return this; - } - var words = content; - var dupes = create_object$$module$src$common(); - dupes["_ctx"] = create_object$$module$src$common(); - var word_length = words.length; - var threshold = this.threshold; - var depth = this.depth; - var resolution = this.resolution; - var map = this._map; - var rtl = this.rtl; - var has_content; - for (var i = 0; i < word_length; i++) { - var value = words[i]; - if (value) { - has_content = 1; - var length = value.length; - var context_score = (rtl ? i + 1 : word_length - i) / word_length; - var token = ""; - switch(this.tokenizer) { - case "reverse": - case "both": - for (var a = length; --a;) { - token = value[a] + token; - add_index$$module$src$flexsearch(map, dupes, token, id, rtl ? 1 : (length - a) / length, context_score, threshold, resolution - 1); - } - token = ""; - case "forward": - for (var a$13 = 0; a$13 < length; a$13++) { - token += value[a$13]; - add_index$$module$src$flexsearch(map, dupes, token, id, rtl ? (a$13 + 1) / length : 1, context_score, threshold, resolution - 1); - } - break; - case "full": - for (var x = 0; x < length; x++) { - var partial_score = (rtl ? x + 1 : length - x) / length; - for (var y = length; y > x; y--) { - token = value.substring(x, y); - add_index$$module$src$flexsearch(map, dupes, token, id, partial_score, context_score, threshold, resolution - 1); - } - } - break; - default: - var score = add_index$$module$src$flexsearch(map, dupes, value, id, 1, context_score, threshold, resolution - 1); - if (depth && word_length > 1 && score >= threshold) { - var ctxDupes = dupes["_ctx"][value] || (dupes["_ctx"][value] = create_object$$module$src$common()); - var ctxTmp = this._ctx[value] || (this._ctx[value] = create_object_array$$module$src$common(resolution - (threshold || 0))); - var x$14 = i - depth; - var y$15 = i + depth + 1; - if (x$14 < 0) { - x$14 = 0; - } - if (y$15 > word_length) { - y$15 = word_length; - } - for (; x$14 < y$15; x$14++) { - if (x$14 !== i) { - add_index$$module$src$flexsearch(ctxTmp, ctxDupes, words[x$14], id, 0, resolution - (x$14 < i ? i - x$14 : x$14 - i), threshold, resolution - 1); - } - } - } - break; - } - } - } - if (has_content) { - this._ids[id] = 1; - } - if (SUPPORT_CACHE) { - this._cache_status = false; - } - } - return this; -}; -if (SUPPORT_DOCUMENT) { - FlexSearch$$module$src$flexsearch.prototype.handle_docs = function(job, doc, callback) { - if (is_array$$module$src$common(doc)) { - var len = doc.length; - if (len) { - for (var i = 0; i < len; i++) { - this.handle_docs(job, doc[i], i === len - 1 && callback); - } - } - } else { - var index = this.doc.index; - var keys = this.doc.keys; - var tags = this.doc["tag"]; - var store = this.doc["store"]; - var tree; - var tag; - tree = this.doc["id"]; - var id = doc; - for (var i$16 = 0; i$16 < tree.length; i$16++) { - id = id[tree[i$16]]; - } - if (job === "remove") { - delete this._doc[id]; - var len$17 = keys.length; - if (len$17) { - for (var i$18 = 0; i$18 < len$17; i$18++) { - index[keys[i$18]].remove(id, i$18 === len$17 - 1 && callback); - } - } - } else { - if (tags) { - var tag_key; - var tag_value; - for (var i$19 = 0; i$19 < tags.length; i$19++) { - tag_key = tags[i$19]; - tag_value = doc; - var tag_split = tag_key.split(":"); - for (var a = 0; a < tag_split.length; a++) { - tag_value = tag_value[tag_split[a]]; - } - tag_value = "@" + tag_value; - } - tag = this._tag[tag_key]; - tag = tag[tag_value] || (tag[tag_value] = []); - } - tree = this.doc["field"]; - for (var i$20 = 0, len$21 = tree.length; i$20 < len$21; i$20++) { - var branch = tree[i$20]; - var content = doc; - for (var x = 0; x < branch.length; x++) { - content = content[branch[x]]; - } - var self$22 = index[keys[i$20]]; - if (job === "add") { - self$22.add(id, content, i$20 === len$21 - 1 && callback); - } else { - self$22.update(id, content, i$20 === len$21 - 1 && callback); - } - } - if (store) { - var store_keys = get_keys$$module$src$common(store); - var store_doc = create_object$$module$src$common(); - for (var i$23 = 0; i$23 < store_keys.length; i$23++) { - var store_key = store_keys[i$23]; - if (store[store_key]) { - var store_split = store_key.split(":"); - var store_value = undefined; - var store_doc_value = undefined; - for (var a$24 = 0; a$24 < store_split.length; a$24++) { - var store_split_key = store_split[a$24]; - store_value = (store_value || doc)[store_split_key]; - store_doc_value = (store_doc_value || store_doc)[store_split_key] = store_value; - } - } - } - doc = store_doc; - } - if (tag) { - tag[tag.length] = doc; - } - this._doc[id] = doc; - } - } - return this; - }; -} -FlexSearch$$module$src$flexsearch.prototype.update = function(id, content, callback) { - if (SUPPORT_DOCUMENT && this.doc && is_object$$module$src$common(id)) { - return this.handle_docs("update", id, content); - } - if (this._ids[id] && is_string$$module$src$common(content)) { - this.remove(id); - this.add(id, content, callback, true); - } - return this; -}; -FlexSearch$$module$src$flexsearch.prototype.remove = function(id, callback, _recall) { - if (SUPPORT_DOCUMENT && this.doc && is_object$$module$src$common(id)) { - return this.handle_docs("remove", id, callback); - } - var index = id; - if (this._ids[index]) { - if (!_recall) { - if (SUPPORT_ASYNC && this.async && typeof importScripts !== "function") { - var self$25 = this; - var promise = new Promise(function(resolve) { - setTimeout(function() { - self$25.remove(id, null, true); - self$25 = null; - resolve(); - }); - }); - if (callback) { - promise.then(callback); - } else { - return promise; - } - return this; - } - if (callback) { - this.remove(id, null, true); - callback(); - return this; - } - } - for (var z = 0; z < this.resolution - (this.threshold || 0); z++) { - remove_index$$module$src$flexsearch(this._map[z], id); - } - if (this.depth) { - remove_index$$module$src$flexsearch(this._ctx, id); - } - delete this._ids[index]; - if (SUPPORT_CACHE) { - this._cache_status = false; - } - } - return this; -}; -var field_to_sort$$module$src$flexsearch; -function enrich_documents$$module$src$flexsearch(arr, docs) { - var length = arr.length; - var result = new Array(length); - for (var i = 0; i < length; i++) { - result[i] = docs[arr[i]]; - } - return result; -} -FlexSearch$$module$src$flexsearch.prototype.merge_and_sort = function(query, bool, result, sort, limit, suggest, where, cursor, has_and, has_not) { - result = intersect$$module$src$flexsearch(result, where ? 0 : limit, SUPPORT_PAGINATION && cursor, SUPPORT_SUGGESTION && suggest, bool, has_and, has_not); - var next; - if (cursor) { - cursor = result.page; - next = result.next; - result = result.result; - } - if (where) { - result = this.where(where, null, limit, result); - } else { - result = enrich_documents$$module$src$flexsearch(result, this._doc); - } - if (sort) { - if (!is_function$$module$src$common(sort)) { - field_to_sort$$module$src$flexsearch = sort.split(":"); - if (field_to_sort$$module$src$flexsearch.length > 1) { - sort = sort_by_deep_field_up$$module$src$flexsearch; - } else { - sort = sort_by_field_up$$module$src$flexsearch; - } - } - result.sort(sort); - } - result = create_page$$module$src$flexsearch(cursor, next, result); - if (SUPPORT_CACHE && this._cache) { - this._cache.set(query, result); - } - return result; -}; -FlexSearch$$module$src$flexsearch.prototype.search = function(query, limit, callback, _recall) { - if (SUPPORT_DOCUMENT && is_object$$module$src$common(limit)) { - if (is_array$$module$src$common(limit)) { - for (var i = 0; i < limit.length; i++) { - limit[i]["query"] = query; - } - } else { - limit["query"] = query; - } - query = limit; - limit = 1000; - } else { - if (limit && is_function$$module$src$common(limit)) { - callback = limit; - limit = 1000; - } else { - limit || limit === 0 || (limit = 1000); - } - } - var result = []; - var _query = query; - var threshold; - var cursor; - var sort; - var suggest; - if (is_object$$module$src$common(query) && (!SUPPORT_DOCUMENT || !is_array$$module$src$common(query))) { - if (SUPPORT_ASYNC) { - if (!callback) { - callback = query["callback"]; - if (callback) { - _query["callback"] = null; - } - } - } - sort = SUPPORT_DOCUMENT && query["sort"]; - cursor = SUPPORT_PAGINATION && query["page"]; - limit = query["limit"]; - threshold = query["threshold"]; - suggest = SUPPORT_SUGGESTION && query["suggest"]; - query = query["query"]; - } - if (SUPPORT_DOCUMENT && this.doc) { - var doc_idx = this.doc.index; - var where = SUPPORT_WHERE && _query["where"]; - var bool_main = SUPPORT_OPERATOR && _query["bool"] || "or"; - var field = _query["field"]; - var bool = bool_main; - var queries; - var has_not; - var has_and; - if (field) { - if (!is_array$$module$src$common(field)) { - field = [field]; - } - } else { - if (is_array$$module$src$common(_query)) { - queries = _query; - field = []; - bool = []; - for (var i$26 = 0; i$26 < _query.length; i$26++) { - var current = _query[i$26]; - var current_bool = SUPPORT_OPERATOR && current["bool"] || bool_main; - field[i$26] = current["field"]; - bool[i$26] = current_bool; - if (current_bool === "not") { - has_not = true; - } else { - if (current_bool === "and") { - has_and = true; - } - } - } - } else { - field = this.doc.keys; - } - } - var len = field.length; - for (var i$27 = 0; i$27 < len; i$27++) { - if (queries) { - _query = queries[i$27]; - } - if (cursor && !is_string$$module$src$common(_query)) { - _query["page"] = null; - _query["limit"] = 0; - } - result[i$27] = doc_idx[field[i$27]].search(_query, 0); - } - if (callback) { - return callback(this.merge_and_sort(query, bool, result, sort, limit, suggest, where, cursor, has_and, has_not)); - } else { - if (SUPPORT_ASYNC && this.async) { - var self$28 = this; - return new Promise(function(resolve) { - Promise.all(result).then(function(values) { - resolve(self$28.merge_and_sort(query, bool, values, sort, limit, suggest, where, cursor, has_and, has_not)); - }); - }); - } else { - return this.merge_and_sort(query, bool, result, sort, limit, suggest, where, cursor, has_and, has_not); - } - } - } - threshold || (threshold = this.threshold || 0); - if (!_recall) { - if (SUPPORT_ASYNC && this.async && typeof importScripts !== "function") { - var self$29 = this; - var promise = new Promise(function(resolve) { - setTimeout(function() { - resolve(self$29.search(_query, limit, null, true)); - self$29 = null; - }); - }); - if (callback) { - promise.then(callback); - } else { - return promise; - } - return this; - } - if (callback) { - callback(this.search(_query, limit, null, true)); - return this; - } - } - if (!query || !is_string$$module$src$common(query)) { - return result; - } - _query = query; - if (SUPPORT_CACHE && this._cache) { - if (this._cache_status) { - var cache = this._cache.get(query); - if (cache) { - return cache; - } - } else { - this._cache.clear(); - this._cache_status = true; - } - } - _query = this.encode(_query); - if (!_query.length) { - return result; - } - var words = _query; - var length = words.length; - var found = true; - var check = []; - var check_words = create_object$$module$src$common(); - var ctx_root; - var use_contextual; - var a = 0; - if (length > 1) { - if (this.depth) { - use_contextual = true; - } else { - words.sort(sort_by_length_down$$module$src$flexsearch); - } - } - var ctx_map; - if (!use_contextual || (ctx_map = this._ctx)) { - var resolution = this.resolution; - for (; a < length; a++) { - var 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) { - use_contextual = false; - value = ctx_root || value; - check_words[value] = 0; - } else { - if (!ctx_root) { - continue; - } - } - } - if (!check_words[value]) { - var map_check = []; - var map_found = false; - var count = 0; - var map = use_contextual ? ctx_map[ctx_root] : this._map; - if (map) { - var map_value = undefined; - for (var z = 0; z < resolution - threshold; z++) { - if (map_value = map[z] && map[z][value]) { - map_check[count++] = map_value; - map_found = true; - } - } - } - if (map_found) { - ctx_root = value; - check[check.length] = count > 1 ? map_check.concat.apply([], map_check) : map_check[0]; - } else { - if (!SUPPORT_SUGGESTION || !suggest) { - found = false; - break; - } - } - check_words[value] = 1; - } - } - } - } else { - found = false; - } - if (found) { - result = intersect$$module$src$flexsearch(check, limit, cursor, SUPPORT_SUGGESTION && suggest); - } - if (SUPPORT_CACHE && this._cache) { - this._cache.set(query, result); - } - return result; -}; -if (SUPPORT_INFO) { - FlexSearch$$module$src$flexsearch.prototype.info = function() { - return {"id":this.id, "items":this["length"], "matcher":this.matcher.length, "worker":this.worker, "threshold":this.threshold, "depth":this.depth, "resolution":this.resolution, "contextual":this.depth && this.tokenizer === "strict"}; - }; -} -FlexSearch$$module$src$flexsearch.prototype.clear = function() { - return this.destroy().init(); -}; -FlexSearch$$module$src$flexsearch.prototype.destroy = function() { - if (SUPPORT_CACHE && this._cache) { - this._cache.clear(); - this._cache = null; - } - this._map = this._ctx = this._ids = null; - if (SUPPORT_DOCUMENT && this.doc) { - var keys = this.doc.keys; - for (var i = 0; i < keys.length; i++) { - this.doc.index[keys[i]].destroy(); - } - this.doc = this._doc = null; - } - return this; -}; -function register_property$$module$src$flexsearch(obj, key, fn) { - Object.defineProperty(obj, key, {get:fn}); -} -function add_index$$module$src$flexsearch(map, dupes, value, id, partial_score, context_score, threshold, resolution) { - if (dupes[value]) { - return dupes[value]; - } - var score = partial_score ? (resolution - (threshold || resolution / 1.5)) * context_score + (threshold || resolution / 1.5) * partial_score : context_score; - dupes[value] = score; - if (score >= threshold) { - var arr = map[resolution - (score + 0.5 >> 0)]; - arr = arr[value] || (arr[value] = []); - arr[arr.length] = id; - } - return score; -} -function remove_index$$module$src$flexsearch(map, id) { - if (map) { - var keys = get_keys$$module$src$common(map); - for (var i = 0, lengthKeys = keys.length; i < lengthKeys; i++) { - var key = keys[i]; - var tmp = map[key]; - if (tmp) { - for (var a = 0, lengthMap = tmp.length; a < lengthMap; a++) { - if (tmp[a] === id) { - if (lengthMap === 1) { - delete map[key]; - } else { - tmp.splice(a, 1); - } - break; - } else { - if (is_object$$module$src$common(tmp[a])) { - remove_index$$module$src$flexsearch(tmp[a], id); - } - } - } - } - } - } -} -function init_filter$$module$src$flexsearch(words) { - var filter = create_object$$module$src$common(); - for (var i = 0, length = words.length; i < length; i++) { - filter[words[i]] = 1; - } - return filter; -} -function init_stemmer_or_matcher$$module$src$flexsearch(obj, is_stemmer) { - var keys = get_keys$$module$src$common(obj); - var length = keys.length; - var final = []; - var removal = ""; - var count = 0; - for (var i = 0, tmp = undefined; i < length; i++) { - var key = keys[i]; - if (tmp = obj[key]) { - final[count++] = regex$$module$src$common(is_stemmer ? "(?!\\b)" + key + "(\\b|_)" : key); - final[count++] = tmp; - } else { - removal += (removal ? "|" : "") + key; - } - } - if (removal) { - final[count++] = regex$$module$src$common(is_stemmer ? "(?!\\b)(" + removal + ")(\\b|_)" : "(" + removal + ")"); - final[count] = ""; - } - return final; -} -function sort_by_length_down$$module$src$flexsearch(a, b) { - return b.length - a.length; -} -function sort_by_field_up$$module$src$flexsearch(a, b) { - a = a[field_to_sort$$module$src$flexsearch]; - b = b[field_to_sort$$module$src$flexsearch]; - return a < b ? -1 : a > b ? 1 : 0; -} -function sort_by_deep_field_up$$module$src$flexsearch(a, b) { - var field_len = field_to_sort$$module$src$flexsearch.length; - for (var i = 0; i < field_len; i++) { - a = a[field_to_sort$$module$src$flexsearch[i]]; - b = b[field_to_sort$$module$src$flexsearch[i]]; - } - return a < b ? -1 : a > b ? 1 : 0; -} -function create_page$$module$src$flexsearch(cursor, page, result) { - return cursor ? {"page":cursor, "next":page ? "" + page : null, "result":result} : result; -} -function intersect$$module$src$flexsearch(arrays, limit, cursor, suggest, bool, has_and, has_not) { - var page; - var result = []; - var pointer; - if (cursor === true) { - cursor = "0"; - pointer = ""; - } else { - pointer = cursor && cursor.split(":"); - } - var length_z = arrays.length; - if (length_z > 1) { - var check = create_object$$module$src$common(); - var suggestions = []; - var check_not; - var arr; - var z = 0; - var i = 0; - var length; - var tmp; - var init = true; - var first_result; - var count = 0; - var bool_main; - var last_index; - var pointer_suggest; - var pointer_count; - if (pointer) { - if (pointer.length === 2) { - pointer_suggest = pointer; - pointer = false; - } else { - pointer = pointer_count = parseInt(pointer[0], 10); - } - } - if (SUPPORT_DOCUMENT && SUPPORT_OPERATOR) { - if (has_not) { - check_not = create_object$$module$src$common(); - for (; z < length_z; z++) { - if (bool[z] === "not") { - arr = arrays[z]; - length = arr.length; - for (i = 0; i < length; i++) { - check_not["@" + arr[i]] = 1; - } - } else { - last_index = z + 1; - } - } - if (is_undefined$$module$src$common(last_index)) { - return create_page$$module$src$flexsearch(cursor, page, result); - } - z = 0; - } else { - bool_main = is_string$$module$src$common(bool) && bool; - } - } - var bool_and; - var bool_or; - for (; z < length_z; z++) { - var is_final_loop = z === (last_index || length_z) - 1; - if (SUPPORT_DOCUMENT && SUPPORT_OPERATOR) { - if (!bool_main || !z) { - var bool_current = bool_main || bool && bool[z]; - if (!bool_current || bool_current === "and") { - bool_and = has_and = true; - bool_or = false; - } else { - if (bool_current === "or") { - bool_or = true; - bool_and = false; - } else { - continue; - } - } - } - } else { - bool_and = has_and = true; - } - arr = arrays[z]; - length = arr.length; - if (!length) { - if (bool_and && !suggest) { - return create_page$$module$src$flexsearch(cursor, page, arr); - } - continue; - } - if (init) { - if (first_result) { - var result_length = first_result.length; - for (i = 0; i < result_length; i++) { - var id = first_result[i]; - var index = "@" + id; - if (!has_not || !check_not[index]) { - check[index] = 1; - if (!has_and) { - result[count++] = id; - } - } - } - first_result = null; - init = false; - } else { - first_result = arr; - continue; - } - } - var found = false; - for (i = 0; i < length; i++) { - tmp = arr[i]; - var index$30 = "@" + tmp; - var check_val = has_and ? check[index$30] || 0 : z; - if (check_val || suggest) { - if (has_not && check_not[index$30]) { - continue; - } - if (!has_and && check[index$30]) { - continue; - } - if (check_val === z) { - if (is_final_loop) { - if (!pointer_count || --pointer_count < count) { - result[count++] = tmp; - if (limit && count === limit) { - return create_page$$module$src$flexsearch(cursor, count + (pointer || 0), result); - } - } - } else { - check[index$30] = z + 1; - } - found = true; - } else { - if (suggest) { - var current_suggestion = suggestions[check_val] || (suggestions[check_val] = []); - current_suggestion[current_suggestion.length] = tmp; - } - } - } - } - if (bool_and && !found && !suggest) { - break; - } - } - if (first_result) { - var result_length$31 = first_result.length; - if (has_not) { - if (pointer) { - i = parseInt(pointer, 10); - } else { - i = 0; - } - for (; i < result_length$31; i++) { - var id$32 = first_result[i]; - if (!check_not["@" + id$32]) { - result[count++] = id$32; - } - } - } else { - result = first_result; - } - } - if (suggest) { - count = result.length; - if (pointer_suggest) { - z = parseInt(pointer_suggest[0], 10) + 1; - i = parseInt(pointer_suggest[1], 10) + 1; - } else { - z = suggestions.length; - i = 0; - } - for (; z--;) { - tmp = suggestions[z]; - if (tmp) { - for (length = tmp.length; i < length; i++) { - var id$33 = tmp[i]; - if (!has_not || !check_not["@" + id$33]) { - result[count++] = id$33; - if (limit && count === limit) { - return create_page$$module$src$flexsearch(cursor, z + ":" + i, result); - } - } - } - i = 0; - } - } - } - } else { - if (length_z) { - if (!bool || SUPPORT_OPERATOR && bool[0] !== "not") { - result = arrays[0]; - if (pointer) { - pointer = parseInt(pointer[0], 10); - } - } - } - } - if (limit) { - var length$34 = result.length; - if (pointer && pointer > length$34) { - pointer = 0; - } - var start = pointer || 0; - page = start + limit; - if (page < length$34) { - result = result.slice(start, page); - } else { - page = 0; - if (start) { - result = result.slice(start); - } - } - } - return create_page$$module$src$flexsearch(cursor, page, result); -} -var module$src$flexsearch = {}; -module$src$flexsearch.default = FlexSearch$$module$src$flexsearch; -module$src$flexsearch.global_charset = global_charset$$module$src$flexsearch; -module$src$flexsearch.global_lang = global_lang$$module$src$flexsearch; -var rtl$$module$src$lang$latin$simple = false; -var tokenize$$module$src$lang$latin$simple = ""; -var $jscompDefaultExport$$module$src$lang$latin$simple = {encode:encode$$module$src$lang$latin$simple, rtl:rtl$$module$src$lang$latin$simple}; -var regex_whitespace$$module$src$lang$latin$simple = /[\W_]+/; -var regex_a$$module$src$lang$latin$simple = regex$$module$src$common("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"); -var regex_e$$module$src$lang$latin$simple = regex$$module$src$common("[\u00e8\u00e9\u00ea\u00eb]"); -var regex_i$$module$src$lang$latin$simple = regex$$module$src$common("[\u00ec\u00ed\u00ee\u00ef]"); -var regex_o$$module$src$lang$latin$simple = regex$$module$src$common("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"); -var regex_u$$module$src$lang$latin$simple = regex$$module$src$common("[\u00f9\u00fa\u00fb\u00fc\u0171]"); -var regex_y$$module$src$lang$latin$simple = regex$$module$src$common("[\u00fd\u0177\u00ff]"); -var regex_n$$module$src$lang$latin$simple = regex$$module$src$common("\u00f1"); -var regex_c$$module$src$lang$latin$simple = regex$$module$src$common("[\u00e7c]"); -var regex_s$$module$src$lang$latin$simple = regex$$module$src$common("\u00df"); -var regex_and$$module$src$lang$latin$simple = regex$$module$src$common(" & "); -var pairs$$module$src$lang$latin$simple = [regex_a$$module$src$lang$latin$simple, "a", regex_e$$module$src$lang$latin$simple, "e", regex_i$$module$src$lang$latin$simple, "i", regex_o$$module$src$lang$latin$simple, "o", regex_u$$module$src$lang$latin$simple, "u", regex_y$$module$src$lang$latin$simple, "y", regex_n$$module$src$lang$latin$simple, "n", regex_c$$module$src$lang$latin$simple, "k", regex_s$$module$src$lang$latin$simple, "s", regex_and$$module$src$lang$latin$simple, " and "]; -function encode$$module$src$lang$latin$simple(str, self) { - return (self || this).pipeline(str.toLowerCase(), pairs$$module$src$lang$latin$simple, regex_whitespace$$module$src$lang$latin$simple, false); -} -var module$src$lang$latin$simple = {}; -module$src$lang$latin$simple.default = $jscompDefaultExport$$module$src$lang$latin$simple; -module$src$lang$latin$simple.encode = encode$$module$src$lang$latin$simple; -module$src$lang$latin$simple.rtl = rtl$$module$src$lang$latin$simple; -module$src$lang$latin$simple.tokenize = tokenize$$module$src$lang$latin$simple; -var rtl$$module$src$lang$latin$advanced = false; -var tokenize$$module$src$lang$latin$advanced = ""; -var $jscompDefaultExport$$module$src$lang$latin$advanced = {encode:encode$$module$src$lang$latin$advanced, rtl:rtl$$module$src$lang$latin$advanced}; -var regex_ae$$module$src$lang$latin$advanced = regex$$module$src$common("ae"); -var regex_ai$$module$src$lang$latin$advanced = regex$$module$src$common("ai"); -var regex_ay$$module$src$lang$latin$advanced = regex$$module$src$common("ay"); -var regex_ey$$module$src$lang$latin$advanced = regex$$module$src$common("ey"); -var regex_oe$$module$src$lang$latin$advanced = regex$$module$src$common("oe"); -var regex_ue$$module$src$lang$latin$advanced = regex$$module$src$common("ue"); -var regex_ie$$module$src$lang$latin$advanced = regex$$module$src$common("ie"); -var regex_sz$$module$src$lang$latin$advanced = regex$$module$src$common("sz"); -var regex_zs$$module$src$lang$latin$advanced = regex$$module$src$common("zs"); -var regex_ck$$module$src$lang$latin$advanced = regex$$module$src$common("ck"); -var regex_cc$$module$src$lang$latin$advanced = regex$$module$src$common("cc"); -var regex_sh$$module$src$lang$latin$advanced = regex$$module$src$common("sh"); -var regex_th$$module$src$lang$latin$advanced = regex$$module$src$common("th"); -var regex_dt$$module$src$lang$latin$advanced = regex$$module$src$common("dt"); -var regex_ph$$module$src$lang$latin$advanced = regex$$module$src$common("ph"); -var regex_pf$$module$src$lang$latin$advanced = regex$$module$src$common("pf"); -var regex_ou$$module$src$lang$latin$advanced = regex$$module$src$common("ou"); -var regex_uo$$module$src$lang$latin$advanced = regex$$module$src$common("uo"); -var pairs$$module$src$lang$latin$advanced = [regex_ae$$module$src$lang$latin$advanced, "a", regex_ai$$module$src$lang$latin$advanced, "ei", regex_ay$$module$src$lang$latin$advanced, "ei", regex_ey$$module$src$lang$latin$advanced, "ei", regex_oe$$module$src$lang$latin$advanced, "o", regex_ue$$module$src$lang$latin$advanced, "u", regex_ie$$module$src$lang$latin$advanced, "i", regex_sz$$module$src$lang$latin$advanced, "s", regex_zs$$module$src$lang$latin$advanced, "s", regex_sh$$module$src$lang$latin$advanced, -"s", regex_ck$$module$src$lang$latin$advanced, "k", regex_cc$$module$src$lang$latin$advanced, "k", regex_th$$module$src$lang$latin$advanced, "t", regex_dt$$module$src$lang$latin$advanced, "t", regex_ph$$module$src$lang$latin$advanced, "f", regex_pf$$module$src$lang$latin$advanced, "f", regex_ou$$module$src$lang$latin$advanced, "o", regex_uo$$module$src$lang$latin$advanced, "u"]; -function encode$$module$src$lang$latin$advanced(str, self, _skip_postprocessing) { - if (str) { - str = encode$$module$src$lang$latin$simple(str, self || this).join(" "); - if (str.length > 2) { - str = replace$$module$src$common(str, pairs$$module$src$lang$latin$advanced); - } - if (!_skip_postprocessing) { - if (str.length > 1) { - str = collapse$$module$src$common(str); - } - if (str) { - str = str.split(" "); - } - } - } - return str; -} -var module$src$lang$latin$advanced = {}; -module$src$lang$latin$advanced.default = $jscompDefaultExport$$module$src$lang$latin$advanced; -module$src$lang$latin$advanced.encode = encode$$module$src$lang$latin$advanced; -module$src$lang$latin$advanced.rtl = rtl$$module$src$lang$latin$advanced; -module$src$lang$latin$advanced.tokenize = tokenize$$module$src$lang$latin$advanced; -var rtl$$module$src$lang$latin$balance = false; -var tokenize$$module$src$lang$latin$balance = ""; -var $jscompDefaultExport$$module$src$lang$latin$balance = {encode:encode$$module$src$lang$latin$balance, rtl:rtl$$module$src$lang$latin$balance}; -var regex_whitespace$$module$src$lang$latin$balance = /[\W_]+/; -function encode$$module$src$lang$latin$balance(str) { - return this.pipeline(str.toLowerCase(), false, regex_whitespace$$module$src$lang$latin$balance, false); -} -var module$src$lang$latin$balance = {}; -module$src$lang$latin$balance.default = $jscompDefaultExport$$module$src$lang$latin$balance; -module$src$lang$latin$balance.encode = encode$$module$src$lang$latin$balance; -module$src$lang$latin$balance.rtl = rtl$$module$src$lang$latin$balance; -module$src$lang$latin$balance.tokenize = tokenize$$module$src$lang$latin$balance; -var rtl$$module$src$lang$latin$extra = false; -var tokenize$$module$src$lang$latin$extra = ""; -var $jscompDefaultExport$$module$src$lang$latin$extra = {encode:encode$$module$src$lang$latin$extra, rtl:rtl$$module$src$lang$latin$extra}; -var prefix$$module$src$lang$latin$extra = "(?!\\b)"; -var soundex_b$$module$src$lang$latin$extra = regex$$module$src$common(prefix$$module$src$lang$latin$extra + "p"); -var soundex_s$$module$src$lang$latin$extra = regex$$module$src$common(prefix$$module$src$lang$latin$extra + "z"); -var soundex_k$$module$src$lang$latin$extra = regex$$module$src$common(prefix$$module$src$lang$latin$extra + "[cgq]"); -var soundex_m$$module$src$lang$latin$extra = regex$$module$src$common(prefix$$module$src$lang$latin$extra + "n"); -var soundex_t$$module$src$lang$latin$extra = regex$$module$src$common(prefix$$module$src$lang$latin$extra + "d"); -var soundex_f$$module$src$lang$latin$extra = regex$$module$src$common(prefix$$module$src$lang$latin$extra + "[vw]"); -var regex_vowel$$module$src$lang$latin$extra = regex$$module$src$common(prefix$$module$src$lang$latin$extra + "[aeiouy]"); -var pairs$$module$src$lang$latin$extra = [soundex_b$$module$src$lang$latin$extra, "b", soundex_s$$module$src$lang$latin$extra, "s", soundex_k$$module$src$lang$latin$extra, "k", soundex_m$$module$src$lang$latin$extra, "m", soundex_t$$module$src$lang$latin$extra, "t", soundex_f$$module$src$lang$latin$extra, "f", regex_vowel$$module$src$lang$latin$extra, ""]; -function encode$$module$src$lang$latin$extra(str) { - if (str) { - str = encode$$module$src$lang$latin$advanced(str, this, true); - if (str.length > 1) { - str = replace$$module$src$common(str, pairs$$module$src$lang$latin$extra); - } - if (str.length > 1) { - str = collapse$$module$src$common(str); - } - if (str) { - str = str.split(" "); - } - } - return str; -} -var module$src$lang$latin$extra = {}; -module$src$lang$latin$extra.default = $jscompDefaultExport$$module$src$lang$latin$extra; -module$src$lang$latin$extra.encode = encode$$module$src$lang$latin$extra; -module$src$lang$latin$extra.rtl = rtl$$module$src$lang$latin$extra; -module$src$lang$latin$extra.tokenize = tokenize$$module$src$lang$latin$extra; -var rtl$$module$src$lang$latin$soundex = false; -var tokenize$$module$src$lang$latin$soundex = "strict"; -var $jscompDefaultExport$$module$src$lang$latin$soundex = {encode:encode$$module$src$lang$latin$soundex, rtl:rtl$$module$src$lang$latin$soundex, tokenize:tokenize$$module$src$lang$latin$soundex}; -var regex_strip$$module$src$lang$latin$soundex = /[^a-z]+/; -function encode$$module$src$lang$latin$soundex(str) { - str = this.pipeline(str.toLowerCase(), false, false, false); - var result = []; - if (str) { - var words = str.split(regex_strip$$module$src$lang$latin$soundex); - var length = words.length; - for (var x = 0, count = 0; x < length; x++) { - if ((str = words[x]) && str.length > 2 && (!this.filter || !this.filter[str])) { - var code = str[0]; - var previous = getCode$$module$src$lang$latin$soundex(code); - for (var i = 1; i < str.length; i++) { - var current = getCode$$module$src$lang$latin$soundex(str[i]); - if (current !== previous) { - code += current; - previous = current; - if (code.length === 4) { - break; - } - } - } - result[count++] = (code + "0000").substring(0, 4); - } - } - } - return result; -} -function getCode$$module$src$lang$latin$soundex(char) { - switch(char) { - case "b": - case "f": - case "p": - case "v": - return 1; - case "c": - case "g": - case "j": - case "k": - case "q": - case "s": - case "x": - case "z": - return 2; - case "d": - case "t": - return 3; - case "l": - return 4; - case "m": - case "n": - return 5; - case "r": - return 6; - } - return ""; -} -var module$src$lang$latin$soundex = {}; -module$src$lang$latin$soundex.default = $jscompDefaultExport$$module$src$lang$latin$soundex; -module$src$lang$latin$soundex.encode = encode$$module$src$lang$latin$soundex; -module$src$lang$latin$soundex.rtl = rtl$$module$src$lang$latin$soundex; -module$src$lang$latin$soundex.tokenize = tokenize$$module$src$lang$latin$soundex; -var rtl$$module$src$lang$arabic$default = true; -var tokenize$$module$src$lang$arabic$default = ""; -var $jscompDefaultExport$$module$src$lang$arabic$default = {encode:encode$$module$src$lang$arabic$default, rtl:rtl$$module$src$lang$arabic$default}; -var regex$$module$src$lang$arabic$default = /[\x00-\x7F]+/g; -function encode$$module$src$lang$arabic$default(str) { - return this.pipeline(str.replace(regex$$module$src$lang$arabic$default, " "), false, " ", false); -} -var module$src$lang$arabic$default = {}; -module$src$lang$arabic$default.default = $jscompDefaultExport$$module$src$lang$arabic$default; -module$src$lang$arabic$default.encode = encode$$module$src$lang$arabic$default; -module$src$lang$arabic$default.rtl = rtl$$module$src$lang$arabic$default; -module$src$lang$arabic$default.tokenize = tokenize$$module$src$lang$arabic$default; -var rtl$$module$src$lang$cjk$default = false; -var tokenize$$module$src$lang$cjk$default = "strict"; -var $jscompDefaultExport$$module$src$lang$cjk$default = {encode:encode$$module$src$lang$cjk$default, rtl:rtl$$module$src$lang$cjk$default, tokenize:tokenize$$module$src$lang$cjk$default}; -var regex$$module$src$lang$cjk$default = /[\x00-\x7F]+/g; -function encode$$module$src$lang$cjk$default(str) { - return this.pipeline(str.replace(regex$$module$src$lang$cjk$default, ""), false, "", false); -} -var module$src$lang$cjk$default = {}; -module$src$lang$cjk$default.default = $jscompDefaultExport$$module$src$lang$cjk$default; -module$src$lang$cjk$default.encode = encode$$module$src$lang$cjk$default; -module$src$lang$cjk$default.rtl = rtl$$module$src$lang$cjk$default; -module$src$lang$cjk$default.tokenize = tokenize$$module$src$lang$cjk$default; -var rtl$$module$src$lang$cyrillic$default = false; -var tokenize$$module$src$lang$cyrillic$default = ""; -var $jscompDefaultExport$$module$src$lang$cyrillic$default = {encode:encode$$module$src$lang$cyrillic$default, rtl:rtl$$module$src$lang$cyrillic$default}; -var regex$$module$src$lang$cyrillic$default = /[\x00-\x7F]+/g; -function encode$$module$src$lang$cyrillic$default(str) { - return this.pipeline(str.replace(regex$$module$src$lang$cyrillic$default, " "), false, " ", false); -} -var module$src$lang$cyrillic$default = {}; -module$src$lang$cyrillic$default.default = $jscompDefaultExport$$module$src$lang$cyrillic$default; -module$src$lang$cyrillic$default.encode = encode$$module$src$lang$cyrillic$default; -module$src$lang$cyrillic$default.rtl = rtl$$module$src$lang$cyrillic$default; -module$src$lang$cyrillic$default.tokenize = tokenize$$module$src$lang$cyrillic$default; -var filter$$module$src$lang$de = ["aber", "als", "am", "an", "auch", "auf", "aus", "bei", "bin", "bis", "bist", "da", "dadurch", "daher", "darum", "das", "da\u00df", "dass", "dein", "deine", "dem", "den", "der", "des", "dessen", "deshalb", "die", "dies", "dieser", "dieses", "doch", "dort", "du", "durch", "ein", "eine", "einem", "einen", "einer", "eines", "er", "es", "euer", "eure", "f\u00fcr", "hatte", "hatten", "hattest", "hattet", "hier", "hinter", "ich", "ihr", "ihre", "im", "in", "ist", "ja", -"jede", "jedem", "jeden", "jeder", "jedes", "jener", "jenes", "jetzt", "kann", "kannst", "k\u00f6nnen", "k\u00f6nnt", "machen", "mein", "meine", "mit", "mu\u00df", "mu\u00dft", "musst", "m\u00fcssen", "m\u00fc\u00dft", "nach", "nachdem", "nein", "nicht", "nun", "oder", "seid", "sein", "seine", "sich", "sie", "sind", "soll", "sollen", "sollst", "sollt", "sonst", "soweit", "sowie", "und", "unser", "unsere", "unter", "vom", "von", "vor", "wann", "warum", "was", "weiter", "weitere", "wenn", "wer", "werde", -"werden", "werdet", "weshalb", "wie", "wieder", "wieso", "wir", "wird", "wirst", "wo", "woher", "wohin", "zu", "zum", "zur", "\u00fcber"]; -var stemmer$$module$src$lang$de = {"niss":"", "isch":"", "lich":"", "heit":"", "keit":"", "ell":"", "bar":"", "end":"", "ung":"", "est":"", "ern":"", "em":"", "er":"", "en":"", "es":"", "st":"", "ig":"", "ik":"", "e":"", "s":""}; -var matcher$$module$src$lang$de = {}; -var $jscompDefaultExport$$module$src$lang$de = {filter:filter$$module$src$lang$de, stemmer:stemmer$$module$src$lang$de, matcher:matcher$$module$src$lang$de}; -var module$src$lang$de = {}; -module$src$lang$de.default = $jscompDefaultExport$$module$src$lang$de; -module$src$lang$de.filter = filter$$module$src$lang$de; -module$src$lang$de.matcher = matcher$$module$src$lang$de; -module$src$lang$de.stemmer = stemmer$$module$src$lang$de; -var filter$$module$src$lang$en = ["a", "about", "above", "after", "again", "against", "all", "also", "am", "an", "and", "any", "are", "aren't", "as", "at", "be", "because", "been", "before", "being", "below", "both", "but", "by", "can", "cannot", "can't", "come", "could", "couldn't", "did", "didn't", "do", "does", "doesn't", "doing", "dont", "down", "during", "each", "even", "few", "first", "for", "from", "further", "get", "go", "had", "hadn't", "has", "hasn't", "have", "haven't", "having", "he", -"hed", "her", "here", "here's", "hers", "herself", "hes", "him", "himself", "his", "how", "how's", "i", "id", "if", "ill", "im", "in", "into", "is", "isn't", "it", "it's", "itself", "i've", "just", "know", "let's", "like", "make", "me", "more", "most", "mustn't", "my", "myself", "new", "no", "nor", "not", "now", "of", "off", "on", "once", "only", "or", "other", "ought", "our", "our's", "ourselves", "out", "over", "own", "same", "say", "see", "shan't", "she", "she'd", "shell", "shes", "should", "shouldn't", -"so", "some", "such", "than", "that", "that's", "the", "their", "theirs", "them", "themselves", "then", "there", "there's", "these", "they", "they'd", "they'll", "they're", "they've", "this", "those", "through", "time", "to", "too", "until", "up", "us", "very", "want", "was", "wasn't", "way", "we", "wed", "well", "were", "weren't", "we've", "what", "what's", "when", "when's", "where", "where's", "which", "while", "who", "whom", "who's", "why", "why's", "will", "with", "won't", "would", "wouldn't", -"you", "you'd", "you'll", "your", "you're", "your's", "yourself", "yourselves", "you've"]; -var stemmer$$module$src$lang$en = {"ational":"ate", "iveness":"ive", "fulness":"ful", "ousness":"ous", "ization":"ize", "tional":"tion", "biliti":"ble", "icate":"ic", "ative":"", "alize":"al", "iciti":"ic", "entli":"ent", "ousli":"ous", "alism":"al", "ation":"ate", "aliti":"al", "iviti":"ive", "ement":"", "enci":"ence", "anci":"ance", "izer":"ize", "alli":"al", "ator":"ate", "logi":"log", "ical":"ic", "ance":"", "ence":"", "ness":"", "able":"", "ible":"", "ment":"", "eli":"e", "bli":"ble", "ful":"", -"ant":"", "ent":"", "ism":"", "ate":"", "iti":"", "ous":"", "ive":"", "ize":"", "al":"", "ou":"", "er":"", "ic":""}; -var matcher$$module$src$lang$en = {}; -var $jscompDefaultExport$$module$src$lang$en = {filter:filter$$module$src$lang$en, stemmer:stemmer$$module$src$lang$en, matcher:matcher$$module$src$lang$en}; -var module$src$lang$en = {}; -module$src$lang$en.default = $jscompDefaultExport$$module$src$lang$en; -module$src$lang$en.filter = filter$$module$src$lang$en; -module$src$lang$en.matcher = matcher$$module$src$lang$en; -module$src$lang$en.stemmer = stemmer$$module$src$lang$en; -var filter$$module$src$lang$at = ["aber", "als", "am", "an", "auch", "auf", "aus", "bei", "bin", "bis", "bist", "da", "dadurch", "daher", "darum", "das", "da\u00df", "dass", "dein", "deine", "dem", "den", "der", "des", "dessen", "deshalb", "die", "dies", "dieser", "dieses", "doch", "dort", "du", "durch", "ein", "eine", "einem", "einen", "einer", "eines", "er", "es", "euer", "eure", "f\u00fcr", "hatte", "hatten", "hattest", "hattet", "hier", "hinter", "ich", "ihr", "ihre", "im", "in", "ist", "ja", -"jede", "jedem", "jeden", "jeder", "jedes", "jener", "jenes", "jetzt", "kann", "kannst", "k\u00f6nnen", "k\u00f6nnt", "machen", "mein", "meine", "mit", "mu\u00df", "mu\u00dft", "musst", "m\u00fcssen", "m\u00fc\u00dft", "nach", "nachdem", "nein", "nicht", "nun", "oder", "seid", "sein", "seine", "sich", "sie", "sind", "soll", "sollen", "sollst", "sollt", "sonst", "soweit", "sowie", "und", "unser", "unsere", "unter", "vom", "von", "vor", "wann", "warum", "was", "weiter", "weitere", "wenn", "wer", "werde", -"werden", "werdet", "weshalb", "wie", "wieder", "wieso", "wir", "wird", "wirst", "wo", "woher", "wohin", "zu", "zum", "zur", "\u00fcber"]; -var stemmer$$module$src$lang$at = {"niss":"", "isch":"", "lich":"", "heit":"", "keit":"", "end":"", "ung":"", "est":"", "ern":"", "em":"", "er":"", "en":"", "es":"", "st":"", "ig":"", "ik":"", "e":"", "s":""}; -var matcher$$module$src$lang$at = {}; -var $jscompDefaultExport$$module$src$lang$at = {filter:filter$$module$src$lang$at, stemmer:stemmer$$module$src$lang$at, matcher:matcher$$module$src$lang$at}; -var module$src$lang$at = {}; -module$src$lang$at.default = $jscompDefaultExport$$module$src$lang$at; -module$src$lang$at.filter = filter$$module$src$lang$at; -module$src$lang$at.matcher = matcher$$module$src$lang$at; -module$src$lang$at.stemmer = stemmer$$module$src$lang$at; -var filter$$module$src$lang$us = ["a", "about", "above", "after", "again", "against", "all", "also", "am", "an", "and", "any", "are", "aren't", "as", "at", "be", "because", "been", "before", "being", "below", "both", "but", "by", "can", "cannot", "can't", "come", "could", "couldn't", "did", "didn't", "do", "does", "doesn't", "doing", "dont", "down", "during", "each", "even", "few", "first", "for", "from", "further", "get", "go", "had", "hadn't", "has", "hasn't", "have", "haven't", "having", "he", -"hed", "her", "here", "here's", "hers", "herself", "hes", "him", "himself", "his", "how", "how's", "i", "id", "if", "ill", "im", "in", "into", "is", "isn't", "it", "it's", "itself", "i've", "just", "know", "let's", "like", "make", "me", "more", "most", "mustn't", "my", "myself", "new", "no", "nor", "not", "now", "of", "off", "on", "once", "only", "or", "other", "ought", "our", "our's", "ourselves", "out", "over", "own", "same", "say", "see", "shan't", "she", "she'd", "shell", "shes", "should", "shouldn't", -"so", "some", "such", "than", "that", "that's", "the", "their", "theirs", "them", "themselves", "then", "there", "there's", "these", "they", "they'd", "they'll", "they're", "they've", "this", "those", "through", "time", "to", "too", "until", "up", "us", "very", "want", "was", "wasn't", "way", "we", "wed", "well", "were", "weren't", "we've", "what", "what's", "when", "when's", "where", "where's", "which", "while", "who", "whom", "who's", "why", "why's", "will", "with", "won't", "would", "wouldn't", -"you", "you'd", "you'll", "your", "you're", "your's", "yourself", "yourselves", "you've"]; -var stemmer$$module$src$lang$us = {"ational":"ate", "iveness":"ive", "fulness":"ful", "ousness":"ous", "ization":"ize", "tional":"tion", "biliti":"ble", "icate":"ic", "ative":"", "alize":"al", "iciti":"ic", "entli":"ent", "ousli":"ous", "alism":"al", "ation":"ate", "aliti":"al", "iviti":"ive", "ement":"", "enci":"ence", "anci":"ance", "izer":"ize", "alli":"al", "ator":"ate", "logi":"log", "ical":"ic", "ance":"", "ence":"", "ness":"", "able":"", "ible":"", "ment":"", "eli":"e", "bli":"ble", "ful":"", -"ant":"", "ent":"", "ism":"", "ate":"", "iti":"", "ous":"", "ive":"", "ize":"", "al":"", "ou":"", "er":"", "ic":""}; -var matcher$$module$src$lang$us = {}; -var $jscompDefaultExport$$module$src$lang$us = {filter:filter$$module$src$lang$us, stemmer:stemmer$$module$src$lang$us, matcher:matcher$$module$src$lang$us}; -var module$src$lang$us = {}; -module$src$lang$us.default = $jscompDefaultExport$$module$src$lang$us; -module$src$lang$us.filter = filter$$module$src$lang$us; -module$src$lang$us.matcher = matcher$$module$src$lang$us; -module$src$lang$us.stemmer = stemmer$$module$src$lang$us; -FlexSearch$$module$src$flexsearch.prototype.init; -FlexSearch$$module$src$flexsearch.prototype.search; -FlexSearch$$module$src$flexsearch.prototype.add; -FlexSearch$$module$src$flexsearch.prototype.update; -FlexSearch$$module$src$flexsearch.prototype.remove; -FlexSearch$$module$src$flexsearch.prototype.find; -FlexSearch$$module$src$flexsearch.prototype.where; -FlexSearch$$module$src$flexsearch.prototype.info; -FlexSearch$$module$src$flexsearch.prototype.clear; -FlexSearch$$module$src$flexsearch.prototype.destroy; -FlexSearch$$module$src$flexsearch.prototype.export; -FlexSearch$$module$src$flexsearch.prototype.import; -Promise.prototype.then; -var module$src$export = {}; -if (SUPPORT_ENCODER === true || SUPPORT_ENCODER && (SUPPORT_ENCODER === "latin" || SUPPORT_ENCODER.indexOf("latin:advanced") !== -1)) { - global_charset$$module$src$flexsearch["latin:advanced"] = $jscompDefaultExport$$module$src$lang$latin$advanced; -} -if (SUPPORT_ENCODER === true || SUPPORT_ENCODER && (SUPPORT_ENCODER === "latin" || SUPPORT_ENCODER.indexOf("latin:balance") !== -1)) { - global_charset$$module$src$flexsearch["latin:balance"] = $jscompDefaultExport$$module$src$lang$latin$balance; -} -if (SUPPORT_ENCODER === true || SUPPORT_ENCODER && (SUPPORT_ENCODER === "latin" || SUPPORT_ENCODER.indexOf("latin:default") !== -1)) { - global_charset$$module$src$flexsearch["latin:default"] = $jscompDefaultExport$$module$src$lang$latin$default; -} -if (SUPPORT_ENCODER === true || SUPPORT_ENCODER && (SUPPORT_ENCODER === "latin" || SUPPORT_ENCODER.indexOf("latin:extra") !== -1)) { - global_charset$$module$src$flexsearch["latin:extra"] = $jscompDefaultExport$$module$src$lang$latin$extra; -} -if (SUPPORT_ENCODER === true || SUPPORT_ENCODER && (SUPPORT_ENCODER === "latin" || SUPPORT_ENCODER.indexOf("latin:simple") !== -1)) { - global_charset$$module$src$flexsearch["latin:simple"] = $jscompDefaultExport$$module$src$lang$latin$simple; -} -if (SUPPORT_ENCODER === true || SUPPORT_ENCODER && (SUPPORT_ENCODER === "latin" || SUPPORT_ENCODER.indexOf("latin:soundex") !== -1)) { - global_charset$$module$src$flexsearch["latin:soundex"] = $jscompDefaultExport$$module$src$lang$latin$soundex; -} -if (SUPPORT_ENCODER === true || SUPPORT_ENCODER && (SUPPORT_ENCODER === "arabic" || SUPPORT_ENCODER.indexOf("arabic:default") !== -1)) { - global_charset$$module$src$flexsearch["arabic:default"] = $jscompDefaultExport$$module$src$lang$arabic$default; -} -if (SUPPORT_ENCODER === true || SUPPORT_ENCODER && (SUPPORT_ENCODER === "cjk" || SUPPORT_ENCODER.indexOf("cjk:default") !== -1)) { - global_charset$$module$src$flexsearch["cjk:default"] = $jscompDefaultExport$$module$src$lang$cjk$default; -} -if (SUPPORT_ENCODER === true || SUPPORT_ENCODER && (SUPPORT_ENCODER === "cyrillic" || SUPPORT_ENCODER.indexOf("cyrillic:default") !== -1)) { - global_charset$$module$src$flexsearch["cyrillic:default"] = $jscompDefaultExport$$module$src$lang$cyrillic$default; -} -if (SUPPORT_LANG === true || SUPPORT_LANG && SUPPORT_LANG.indexOf("de") !== -1) { - global_lang$$module$src$flexsearch["de"] = $jscompDefaultExport$$module$src$lang$de; -} -if (SUPPORT_LANG === true || SUPPORT_LANG && SUPPORT_LANG.indexOf("en") !== -1) { - global_lang$$module$src$flexsearch["en"] = $jscompDefaultExport$$module$src$lang$en; -} -if (SUPPORT_LANG === true || SUPPORT_LANG && SUPPORT_LANG.indexOf("at") !== -1) { - global_lang$$module$src$flexsearch["at"] = $jscompDefaultExport$$module$src$lang$at; -} -if (SUPPORT_LANG === true || SUPPORT_LANG && SUPPORT_LANG.indexOf("us") !== -1) { - global_lang$$module$src$flexsearch["us"] = $jscompDefaultExport$$module$src$lang$us; -} -(function() { - var name = "FlexSearch"; - var root = this || window; - var prop; - if ((prop = root["define"]) && prop["amd"]) { - prop([], function() { - return FlexSearch$$module$src$flexsearch; - }); - } else { - if (typeof root["exports"] === "object") { - root["module"].exports = FlexSearch$$module$src$flexsearch; - } else { - root[name] = FlexSearch$$module$src$flexsearch; - } - } -})(); -var module$src$bundle = {}; -}).call(this); diff --git a/dist/flexsearch.es5.js b/dist/flexsearch.es5.js deleted file mode 100644 index 8697ac3..0000000 --- a/dist/flexsearch.es5.js +++ /dev/null @@ -1,37 +0,0 @@ -/**! - * FlexSearch.js v0.7.0 (ES5) - * Copyright 2019 Nextapps GmbH - * Author: Thomas Wilkerling - * Licence: Apache-2.0 - * https://github.com/nextapps-de/flexsearch - */ -(function(){'use strict';Object.assign||(Object.assign=function(){for(var a=arguments,b=a.length,c=a[0],d=1,e,f,g;de;c--)g=f[c-1],f[c]=g,d[g]=c;f[e]=a;d[a]=e}}}return b};var S={},ea="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;function fa(a,b,c){var d=ha,e="flexsearch";d=ea?URL.createObjectURL(new Blob(["("+d.toString()+")()"],{type:"text/javascript"})):e+".browser.js";e+="-"+a;S[e]||(S[e]=[]);S[e][c]=new Worker(d);S[e][c].onmessage=b;console.log("Register Worker: "+e+"@"+c);return S[e][c]} -function ha(){var a,b;self.onmessage=function(c){if(c=c.data)if(c.search){var d=b.search(c.content,c.threshold?{limit:c.limit,threshold:c.threshold,where:c.where}:c.limit);self.postMessage({id:a,content:c.content,limit:c.limit,result:d})}else c.add?b.add(c.id,c.content):c.update?b.update(c.id,c.content):c.remove?b.remove(c.id):c.clear?b.clear():c.info?(c=b.info(),c.worker=a,console.log(c)):c.register&&(a=c.id,c.options.cache=!1,c.options.async=!1,c.options.worker=!1,b=(new Function(c.register.substring(c.register.indexOf("{")+ -1,c.register.lastIndexOf("}"))))(),b=new b(c.options))}}function ia(a,b,c,d){a=fa("id"+a,function(f){(f=f.data)&&f.result&&d(f.id,f.content,f.result,f.limit,f.where,f.cursor,f.suggest)},b);var e=O.toString();c.id=b;a.postMessage({register:e,options:c,id:b});return a}O.prototype.G=function(a,b,c,d){this.s!==this.v&&(this.o=this.o.concat(c),this.s++,d&&this.o.length>=d&&(this.s=this.v),this.s===this.v&&(this.cache&&this.g.set(b,this.o),this.C&&this.C(this.o)));return this};var U={memory:{charset:"latin:extra",threshold:0,c:1},speed:{threshold:1,c:3,depth:2},match:{charset:"latin:extra",B:"full",threshold:1,c:3},score:{charset:"latin:extra",threshold:1,c:9,depth:4},balance:{charset:"latin:balance",threshold:0,c:3,depth:3},fast:{threshold:8,c:9,depth:1}};var ka={encode:ja,h:!1},la=/[\W_]+/;function ja(a){return L(this,a.toLowerCase(),!1,la)};var ma=0,na={},V={};function O(a){if(!(this instanceof O))return new O(a);var b=a&&a.id;this.id=b||0===b?b:ma++;this.init(a);oa(this,"index",function(){return this.a?Object.keys(this.a.index[this.a.keys[0]].f):Object.keys(this.f)});oa(this,"length",function(){return this.index.length})}O.registerCharset=function(a,b){V[a]=b;return O};O.registerLanguage=function(a,b){na[a]=b;return O}; -O.prototype.init=function(a){var b,c;if(a)if(t(a))U[a]||console.warn("Preset not found: "+a),a=U[a];else if(b=a.preset)U[b]||console.warn("Preset not found: "+b),a=Object.assign({},U[b],a);a||(a={});if(b=a.worker){if("undefined"===typeof fa)a.worker=!1,this.m=null;else{var d=parseInt(b,10)||4;this.s=0;this.o=[];this.C=null;this.m=Array(d);for(var e=0;eu;B--)x=n.substring(u,B),X(r,e,x,a,A,v,k,q-1);break;default:if(w=X(r,e,n,a,1,v,k,q-1),m&&1=k)for(w=e._ctx[n]||(e._ctx[n]=F()),n=this.i[n]||(this.i[n]=ba(q-(k||0))),v=l-m, -x=l+m+1,0>v&&(v=0),x>h&&(x=h);v=g&&(a=a[h-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e} -function ra(a,b){if(a)for(var c=Object.keys(a),d=0,e=c.length;db?1:0}function ua(a,b){for(var c=Y.length,d=0;db?1:0}function Z(a,b,c){return a?{page:a,next:b?""+b:null,result:c}:c} -function ta(a,b,c,d,e,f,g){var h=[];if(!0===c){c="0";var k=""}else k=c&&c.split(":");var m=a.length;if(1g&&(k=0);k=k||0;var J=k+b;Jk;z--)l=n.substring(k,z),N(f,c,l,a,w,r,d,g-1);break;default:if(p=N(f,c,n,a,1,r,d,g-1),h&&1=d)for(p=c._ctx[n]||(c._ctx[n]=B()),n=this.c[n]||(this.c[n]=y(g-(d||0))),r=q-h,l=q+h+1,0>r&&(r=0),l>e&&(l=e);rx&&(f=0);A=f||0;var D=A+b;D=g&&(a=a[f-(d+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=e);return d}function Q(a,b){if(a)for(var c=Object.keys(a),e=0,d=c.length;ee;c--)g=f[c-1],f[c]=g,d[g]=c;f[e]=a;d[a]=e}}}return b};var U={},da="undefined"!==typeof Blob&&"undefined"!==typeof URL&&URL.createObjectURL;function ea(a,b,c){var d=fa,e="flexsearch";d=da?URL.createObjectURL(new Blob(["("+d.toString()+")()"],{type:"text/javascript"})):e+".browser.js";e+="-"+a;U[e]||(U[e]=[]);U[e][c]=new Worker(d);U[e][c].onmessage=b;return U[e][c]} -function fa(){var a,b;self.onmessage=function(c){if(c=c.data)if(c.search){var d=b.search(c.content,c.threshold?{limit:c.limit,threshold:c.threshold,where:c.where}:c.limit);self.postMessage({id:a,content:c.content,limit:c.limit,result:d})}else c.add?b.add(c.id,c.content):c.update?b.update(c.id,c.content):c.remove?b.remove(c.id):c.clear?b.clear():c.info?(c=b.info(),c.worker=a,console.log(c)):c.register&&(a=c.id,c.options.cache=!1,c.options.async=!1,c.options.worker=!1,b=(new Function(c.register.substring(c.register.indexOf("{")+ -1,c.register.lastIndexOf("}"))))(),b=new b(c.options))}}function ha(a,b,c,d){a=ea("id"+a,function(f){(f=f.data)&&f.result&&d(f.id,f.content,f.result,f.limit,f.where,f.cursor,f.suggest)},b);var e=P.toString();c.id=b;a.postMessage({register:e,options:c,id:b});return a}P.prototype.G=function(a,b,c,d){this.s!==this.v&&(this.o=this.o.concat(c),this.s++,d&&this.o.length>=d&&(this.s=this.v),this.s===this.v&&(this.cache&&this.g.set(b,this.o),this.C&&this.C(this.o)));return this};var ia={memory:{charset:"latin:extra",threshold:0,c:1},speed:{threshold:1,c:3,depth:2},match:{charset:"latin:extra",B:"full",threshold:1,c:3},score:{charset:"latin:extra",threshold:1,c:9,depth:4},balance:{charset:"latin:balance",threshold:0,c:3,depth:3},fast:{threshold:8,c:9,depth:1}};var ka={encode:ja,h:!1},la=/[\W_]+/;function ja(a){return O(this,a.toLowerCase(),!1,la)};var ma=0,na={},V={};function P(a){if(!(this instanceof P))return new P(a);var b=a&&a.id;this.id=b||0===b?b:ma++;this.init(a);oa(this,"index",function(){return this.a?Object.keys(this.a.index[this.a.keys[0]].f):Object.keys(this.f)});oa(this,"length",function(){return this.index.length})}P.registerCharset=function(a,b){V[a]=b;return P};P.registerLanguage=function(a,b){na[a]=b;return P}; -P.prototype.init=function(a){var b,c;if(a)if(t(a))a=ia[a];else if(b=a.preset)a=Object.assign({},ia[b],a);a||(a={});if(b=a.worker){if("undefined"===typeof ea)a.worker=!1,this.m=null;else{var d=parseInt(b,10)||4;this.s=0;this.o=[];this.C=null;this.m=Array(d);for(var e=0;eu;B--)x=n.substring(u,B),X(r,e,x,a,A,v,k,q-1);break;default:if(w=X(r,e,n,a,1,v,k,q-1),m&&1=k)for(w=e._ctx[n]||(e._ctx[n]=G()),n=this.i[n]||(this.i[n]=aa(q-(k||0))),v=l-m, -x=l+m+1,0>v&&(v=0),x>h&&(x=h);v=g&&(a=a[h-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e} -function ra(a,b){if(a)for(var c=Object.keys(a),d=0,e=c.length;db?1:0}function ua(a,b){for(var c=Y.length,d=0;db?1:0}function Z(a,b,c){return a?{page:a,next:b?""+b:null,result:c}:c} -function ta(a,b,c,d,e,f,g){var h=[];if(!0===c){c="0";var k=""}else k=c&&c.split(":");var m=a.length;if(1g&&(k=0);k=k||0;var J=k+b;J=b)return e.concat(d.slice(0,b-f));e=e.concat(d);f+=h}return e};function Q(a,b){if(!(this instanceof Q))return new Q(a);if(a){a=ca(a);var c=a.charset;var d=a.lang;"string"===typeof c&&(-1===c.indexOf(":")&&(c+=":default"),c=E[c]);"string"===typeof d&&(d=D[d])}else a={};var e,h=a.context||{};this.encode=a.encode||c&&c.encode||aa;this.register=b||x();var f=a.resolution||9;var g=a.threshold||0;g>=f&&(g=f-1);this.m=f;this.threshold=g;this.D=b=c&&c.F||a.tokenize||"strict";this.depth="strict"===b&&h.depth;this.s=R(h.bidirectional,!0);this.l=e="memory"===a.optimize; +this.v=R(a.fastupdate,!0);this.j=a.minlength||1;this.g=e?t(f-g):x();f=h.resolution||f;g=h.threshold||g;g>=f&&(g=f-1);this.h=f;this.o=g;this.i=e?t(f-g):x();this.B=c&&c.B||a.rtl;this.A=(b=a.matcher||d&&d.A)&&C(b,!1);this.C=(b=a.stemmer||d&&d.C)&&C(b,!0);this.filter=(b=a.filter||d&&d.filter)&&ba(b);this.cache=(b=a.cache)&&new N(b);this.u=(b=a.worker)&&new Worker("worker.js",{type:"module"});b&&(this.u.onmessage=function(k){console.log(k.data)},this.u.postMessage({G:"register",options:a}))} +function R(a,b){return"undefined"!==typeof a?a:b}r=Q.prototype;r.append=function(a,b){return this.add(a,b,!0)}; +r.add=function(a,b,c){if(this.register[a]&&!c)return this.update(a,b);if(b&&(a||0===a)){b=this.encode(b);var d=b.length;if(d){for(var e=this.depth,h=this.m-this.threshold,f=x(),g=x(),k=0;k=this.j&&(e||!f[l])){var m=Math.min(this.m/d*k|0,k);if(mq;v--)n=l.substring(q,v),n.length>=this.j&&S(this,f,n,u,a,c)}break}case "reverse":if(2< +p){for(q=p-1;0=this.j&&S(this,f,n,m,a,c);n=""}case "forward":if(1=this.j&&S(this,f,n,m,a,c);break;default:if(S(this,f,l,m,a,c),e&&1=this.j&&!m[l]){if(m[l]=1,v=Math.min((this.h-q)/d*k+u|0,k+(u-1)),vn;S(this,g,y?n:l,v,a,c,y?l:n)}}else q=Math.min(q+1,d-k)}}}}this.v||(this.register[a]=1)}}return this}; +function S(a,b,c,d,e,h,f){var g=f?a.i:a.g;if(!b[c]||f&&!b[c][f])a.l&&(g=g[d]),f?(b[c]||(b[c]=x()),b[c][f]=1,g=g[f]||(g[f]=x())):b[c]=1,g=g[c]||(g[c]=[]),a.l||(g=g[d]||(g[d]=[])),h&&-1!==g.indexOf(e)||(g[g.length]=e,a.v&&((b=a.register[e])?b[b.length]=g:a.register[e]=[g]))} +r.search=function(a,b,c){"object"===typeof a?(c=a,a=c.query):"object"===typeof b&&(c=b);var d=[],e=this.threshold;if(c){b=c.limit;e=R(c.threshold,e);var h=c.context;var f=c.suggest}if(a){a=this.encode(a);var g=a.length;if(1=this.j&&!c[m])if(this.l||f||this.g[m])k[p++]=m,c[m]=1;else return d;a=k;g=a.length}}if(!g)return d;b||(b=100);c=this.m-e;e=this.h-e;h=this.depth&&1b?d.slice(0,b):d}}return da(d,b,f)};function U(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a} +function T(a,b,c,d,e,h,f,g){var k=[],l=g?a.i:a.g;a.l||(l=U(l,f,g,a.s));if(l){var p=0;d=Math.min(l.length,d);for(var m=0,n=0,q;m=e)));m++);if(p){if(h)return k=1===p?k[0]:[].concat.apply([],k),k.length>e?k.slice(0,e):k;b[b.length]=k;return}}return!c&&k}r.contain=function(a){return!!this.register[a]};r.update=function(a,b){return this.remove(a).add(a,b)}; +r.remove=function(a,b){var c=this.register[a];if(c){if(this.v)for(var d=0,e;de;c--)g=f[c-1],f[c]=g,d[g]=c;f[e]=a;d[a]=e}}}return b};var da={memory:{charset:"latin:extra",threshold:0,c:1},speed:{threshold:1,c:3,depth:2},match:{charset:"latin:extra",u:"full",threshold:1,c:3},score:{charset:"latin:extra",threshold:1,c:9,depth:4},balance:{charset:"latin:balance",threshold:0,c:3,depth:3},fast:{threshold:8,c:9,depth:1}};var fa={encode:ea,g:!1},ha=/[\W_]+/;function ea(a){return O(this,a.toLowerCase(),!1,ha)};var ia=0,ja={},U={};function P(a){if(!(this instanceof P))return new P(a);var b=a&&a.id;this.id=b||0===b?b:ia++;this.init(a);ka(this,"index",function(){return this.a?Object.keys(this.a.index[this.a.keys[0]].f):Object.keys(this.f)});ka(this,"length",function(){return this.index.length})}P.registerCharset=function(a,b){U[a]=b;return P};P.registerLanguage=function(a,b){ja[a]=b;return P}; -P.prototype.init=function(a){var b,c;if(a)if(t(a))a=da[a];else if(b=a.preset)a=Object.assign({},da[b],a);a||(a={});this.async=a.async;var d=a.charset,e=a.lang;t(d)&&(-1===d.indexOf(":")&&(d+=":default"),d=U[d]);t(e)&&(e=ja[e]);this.v=b=d&&d.u||a.tokenize||"strict";this.depth="strict"===b&&a.depth||0;this.g=d&&d.g||a.rtl||!1;this.c=a.resolution||9;this.threshold=b=a.threshold||0;this.c<=b&&(this.c=b+1);this.encode=a.encode||d&&d.encode||ea;this.m=(b=a.matcher||e&&e.m)&&la(b,!1);this.s=(b=a.stemmer|| -e&&e.s)&&la(b,!0);if(d=b=a.filter||e&&e.filter){d=b;e=G();var f=0;for(c=d.length;fu;B--)x=n.substring(u,B),W(r,e,x,a,A,v,k,q-1);break;default:if(w=W(r,e,n,a,1,v,k,q-1),m&&1=k)for(w=e._ctx[n]||(e._ctx[n]=G()),n=this.h[n]||(this.h[n]=aa(q-(k||0))),v=l-m,x=l+m+1,0>v&&(v=0),x>h&&(x=h);v=g&&(a=a[h-(e+.5>>0)],a=a[c]||(a[c]=[]),a[a.length]=d);return e} -function X(a,b){if(a)for(var c=Object.keys(a),d=0,e=c.length;db?1:0}function pa(a,b){for(var c=Y.length,d=0;db?1:0}function Z(a,b,c){return a?{page:a,next:b?""+b:null,result:c}:c} -function oa(a,b,c,d,e,f,g){var h=[];if(!0===c){c="0";var k=""}else k=c&&c.split(":");var m=a.length;if(1g&&(k=0);k=k||0;var J=k+b;J d; c--) { - f = g[c - 1], g[c] = f, e[f] = c; - } - g[d] = a; - e[a] = d; - } - } - } - return b; -}; -var ba = {memory:{charset:"latin:extra", threshold:0, resolution:1}, speed:{threshold:1, resolution:3, depth:2}, match:{charset:"latin:extra", tokenize:"full", threshold:1, resolution:3}, score:{charset:"latin:extra", threshold:1, resolution:9, depth:4}, balance:{charset:"latin:balance", threshold:0, resolution:3, depth:3}, fast:{threshold:8, resolution:9, depth:1}}; -var da = {encode:ca, rtl:!1}, ea = /[\W_]+/; -function ca(a) { - return this.pipeline(a.toLowerCase(), !1, ea, !1); -} -;var fa = 0, U = {}, V = {}; -function R(a) { - if (!(this instanceof R)) { - return new R(a); - } - var b = a && a.id; - this.id = b || 0 === b ? b : fa++; - this.init(a); - ha(this, "index", function() { - return this.doc ? Object.keys(this.doc.index[this.doc.keys[0]]._ids) : Object.keys(this._ids); - }); - ha(this, "length", function() { - return this.index.length; - }); -} -R.registerCharset = function(a, b) { - V[a] = b; - return R; -}; -R.registerLanguage = function(a, b) { - U[a] = b; - return R; -}; -R.prototype.init = function(a) { - var b, c; - if (a) { - if (r(a)) { - a = ba[a]; - } else { - if (b = a.preset) { - a = Object.assign({}, ba[b], a); - } - } - } - a || (a = {}); - this.async = a.async; - this.timer = 0; - var e = a.charset, d = a.lang; - r(e) && (-1 === e.indexOf(":") && (e += ":default"), e = V[e]); - r(d) && (d = U[d]); - this.tokenizer = b = e && e.tokenize || a.tokenize || "strict"; - this.depth = "strict" === b && a.depth || 0; - this.rtl = e && e.rtl || a.rtl || !1; - this.resolution = a.resolution || 9; - this.threshold = b = a.threshold || 0; - this.resolution <= b && (this.resolution = b + 1); - this.encode = a.encode || e && e.encode || ca; - this.matcher = (b = a.matcher || d && d.matcher) && ia(b, !1); - this.stemmer = (b = a.stemmer || d && d.stemmer) && ia(b, !0); - if (e = b = a.filter || d && d.filter) { - e = b; - d = G(); - var g = 0; - for (c = e.length; g < c; g++) { - d[e[g]] = 1; - } - e = d; - } - this.filter = e; - (this.doc = c = (b = a.doc) && ja(b)) && (a.doc = null); - this._map = aa(this.resolution - this.threshold); - this._ctx = G(); - this._ids = G(); - if (c) { - this._doc = G(); - e = c.index = {}; - d = c.keys = []; - g = c.field; - var f = c.tag, h = c.store; - y(c.id) || (c.id = c.id.split(":")); - if (h) { - var k = G(); - if (r(h)) { - k[h] = 1; - } else { - if (y(h)) { - for (var m = 0; m < h.length; m++) { - k[h[m]] = 1; - } - } else { - E(h) && (k = h); - } - } - c.store = k; - } - if (f) { - this._tag = G(); - h = G(); - if (g) { - if (r(g)) { - h[g] = a; - } else { - if (y(g)) { - for (k = 0; k < g.length; k++) { - h[g[k]] = a; - } - } else { - E(g) && (h = g); - } - } - } - y(f) || (c.tag = f = [f]); - for (g = 0; g < f.length; g++) { - this._tag[f[g]] = G(); - } - this._tags = f; - g = h; - } - if (g) { - if (!y(g)) { - if (E(g)) { - var q = g; - c.field = g = Object.keys(g); - } else { - c.field = g = [g]; - } - } - for (c = 0; c < g.length; c++) { - f = g[c], y(f) || (q && (a = q[f]), d[c] = f, g[c] = f.split(":")), e[f] = new R(a); - } - } - } - this._cache_status = !0; - this._cache = (b = a.cache) && new S(b); - return this; -}; -function ja(a) { - var b = G(), c; - for (c in a) { - if (a.hasOwnProperty(c)) { - var e = a[c]; - y(e) ? b[c] = e.slice(0) : E(e) ? b[c] = ja(e) : b[c] = e; - } - } - return b; -} -R.prototype.add = function(a, b, c, e, d) { - if (this.doc && E(a)) { - return this.handle_docs("add", a, b); - } - if (b && r(b) && (a || 0 === a)) { - if (this._ids[a] && !e) { - return this.update(a, b); - } - if (!d) { - if (this.async) { - var g = this, f = new Promise(function(c) { - setTimeout(function() { - g.add(a, b, null, e, !0); - g = null; - c(); - }); - }); - if (c) { - f.then(c); - } else { - return f; - } - return this; - } - if (c) { - return this.add(a, b, null, e, !0), c(), this; - } - } - b = this.encode(b); - if (!b.length) { - return this; - } - c = b; - d = G(); - d._ctx = G(); - for (var h = c.length, k = this.threshold, m = this.depth, q = this.resolution, u = this._map, p = this.rtl, l = 0; l < h; l++) { - var n = c[l]; - if (n) { - f = 1; - var w = n.length, v = (p ? l + 1 : h - l) / h, x = ""; - switch(this.tokenizer) { - case "reverse": - case "both": - for (var t = w; --t;) { - x = n[t] + x, W(u, d, x, a, p ? 1 : (w - t) / w, v, k, q - 1); - } - x = ""; - case "forward": - for (t = 0; t < w; t++) { - x += n[t], W(u, d, x, a, p ? (t + 1) / w : 1, v, k, q - 1); - } - break; - case "full": - for (t = 0; t < w; t++) { - for (var A = (p ? t + 1 : w - t) / w, B = w; B > t; B--) { - x = n.substring(t, B), W(u, d, x, a, A, v, k, q - 1); - } - } - break; - default: - if (w = W(u, d, n, a, 1, v, k, q - 1), m && 1 < h && w >= k) { - for (w = d._ctx[n] || (d._ctx[n] = G()), n = this._ctx[n] || (this._ctx[n] = aa(q - (k || 0))), v = l - m, x = l + m + 1, 0 > v && (v = 0), x > h && (x = h); v < x; v++) { - v !== l && W(n, w, c[v], a, 0, q - (v < l ? l - v : v - l), k, q - 1); - } - } - } - } - } - f && (this._ids[a] = 1); - this._cache_status = !1; - } - return this; -}; -R.prototype.handle_docs = function(a, b, c) { - if (y(b)) { - var e = b.length; - if (e) { - for (var d = 0; d < e; d++) { - this.handle_docs(a, b[d], d === e - 1 && c); - } - } - } else { - var g = this.doc.index, f = this.doc.keys, h = this.doc.tag; - d = this.doc.store; - var k; - var m = this.doc.id; - e = b; - for (var q = 0; q < m.length; q++) { - e = e[m[q]]; - } - if ("remove" === a) { - if (delete this._doc[e], b = f.length) { - for (d = 0; d < b; d++) { - g[f[d]].remove(e, d === b - 1 && c); - } - } - } else { - if (h) { - for (k = 0; k < h.length; k++) { - var u = h[k]; - var p = b; - m = u.split(":"); - for (q = 0; q < m.length; q++) { - p = p[m[q]]; - } - p = "@" + p; - } - k = this._tag[u]; - k = k[p] || (k[p] = []); - } - m = this.doc.field; - h = 0; - for (u = m.length; h < u; h++) { - q = m[h]; - p = b; - for (var l = 0; l < q.length; l++) { - p = p[q[l]]; - } - q = g[f[h]]; - "add" === a ? q.add(e, p, h === u - 1 && c) : q.update(e, p, h === u - 1 && c); - } - if (d) { - c = Object.keys(d); - a = G(); - for (g = 0; g < c.length; g++) { - if (f = c[g], d[f]) { - for (f = f.split(":"), h = m = void 0, u = 0; u < f.length; u++) { - p = f[u], m = (m || b)[p], h = (h || a)[p] = m; - } - } - } - b = a; - } - k && (k[k.length] = b); - this._doc[e] = b; - } - } - return this; -}; -R.prototype.update = function(a, b, c) { - if (this.doc && E(a)) { - return this.handle_docs("update", a, b); - } - this._ids[a] && r(b) && (this.remove(a), this.add(a, b, c, !0)); - return this; -}; -R.prototype.remove = function(a, b, c) { - if (this.doc && E(a)) { - return this.handle_docs("remove", a, b); - } - if (this._ids[a]) { - if (!c) { - if (this.async && "function" !== typeof importScripts) { - var e = this; - c = new Promise(function(b) { - setTimeout(function() { - e.remove(a, null, !0); - e = null; - b(); - }); - }); - if (b) { - c.then(b); - } else { - return c; - } - return this; - } - if (b) { - return this.remove(a, null, !0), b(), this; - } - } - for (b = 0; b < this.resolution - (this.threshold || 0); b++) { - X(this._map[b], a); - } - this.depth && X(this._ctx, a); - delete this._ids[a]; - this._cache_status = !1; - } - return this; -}; -var Y; -R.prototype.merge_and_sort = function(a, b, c, e, d, g, f, h, k, m) { - c = ka(c, f ? 0 : d, h, g, b, k, m); - if (h) { - h = c.page; - var q = c.next; - c = c.result; - } - if (f) { - c = this.where(f, null, d, c); - } else { - b = c; - c = this._doc; - d = b.length; - g = Array(d); - for (f = 0; f < d; f++) { - g[f] = c[b[f]]; - } - c = g; - } - e && (z(e) || (Y = e.split(":"), e = 1 < Y.length ? la : ma), c.sort(e)); - c = Z(h, q, c); - this._cache && this._cache.set(a, c); - return c; -}; -R.prototype.search = function(a, b, c, e) { - if (E(b)) { - if (y(b)) { - for (var d = 0; d < b.length; d++) { - b[d].query = a; - } - } else { - b.query = a; - } - a = b; - b = 1000; - } else { - b && z(b) ? (c = b, b = 1000) : b || 0 === b || (b = 1000); - } - var g = [], f = a; - if (E(a) && !y(a)) { - c || (c = a.callback) && (f.callback = null); - var h = a.sort; - var k = a.page; - b = a.limit; - var m = a.threshold; - var q = a.suggest; - a = a.query; - } - if (this.doc) { - m = this.doc.index; - var u = f.where, p = f.bool || "or", l = f.field, n = p, w, v; - if (l) { - y(l) || (l = [l]); - } else { - if (y(f)) { - var x = f; - l = []; - n = []; - for (var t = 0; t < f.length; t++) { - e = f[t], d = e.bool || p, l[t] = e.field, n[t] = d, "not" === d ? w = !0 : "and" === d && (v = !0); - } - } else { - l = this.doc.keys; - } - } - p = l.length; - for (t = 0; t < p; t++) { - x && (f = x[t]), k && !r(f) && (f.page = null, f.limit = 0), g[t] = m[l[t]].search(f, 0); - } - if (c) { - return c(this.merge_and_sort(a, n, g, h, b, q, u, k, v, w)); - } - if (this.async) { - var A = this; - return new Promise(function(c) { - Promise.all(g).then(function(d) { - c(A.merge_and_sort(a, n, d, h, b, q, u, k, v, w)); - }); - }); - } - return this.merge_and_sort(a, n, g, h, b, q, u, k, v, w); - } - m || (m = this.threshold || 0); - if (!e) { - if (this.async && "function" !== typeof importScripts) { - var B = this; - m = new Promise(function(a) { - setTimeout(function() { - a(B.search(f, b, null, !0)); - B = null; - }); - }); - if (c) { - m.then(c); - } else { - return m; - } - return this; - } - if (c) { - return c(this.search(f, b, null, !0)), this; - } - } - if (!a || !r(a)) { - return g; - } - f = a; - if (this._cache) { - if (this._cache_status) { - if (c = this._cache.get(a)) { - return c; - } - } else { - this._cache.clear(), this._cache_status = !0; - } - } - f = this.encode(f); - if (!f.length) { - return g; - } - c = f; - x = c.length; - e = !0; - d = []; - var N = G(), P = 0; - 1 < x && (this.depth ? p = !0 : c.sort(na)); - if (!p || (t = this._ctx)) { - for (var T = this.resolution; P < x; P++) { - var C = c[P]; - if (C) { - if (p) { - if (!l) { - if (t[C]) { - l = C, N[C] = 1; - } else { - if (!q) { - return g; - } - } - } - if (q && P === x - 1 && !d.length) { - p = !1, C = l || C, N[C] = 0; - } else { - if (!l) { - continue; - } - } - } - if (!N[C]) { - var D = [], M = !1, H = 0, I = p ? t[l] : this._map; - if (I) { - for (var Q = void 0, J = 0; J < T - m; J++) { - if (Q = I[J] && I[J][C]) { - D[H++] = Q, M = !0; - } - } - } - if (M) { - l = C, d[d.length] = 1 < H ? D.concat.apply([], D) : D[0]; - } else { - if (!q) { - e = !1; - break; - } - } - N[C] = 1; - } - } - } - } else { - e = !1; - } - e && (g = ka(d, b, k, q)); - this._cache && this._cache.set(a, g); - return g; -}; -R.prototype.info = function() { - return {id:this.id, items:this.length, matcher:this.matcher.length, worker:this.worker, threshold:this.threshold, depth:this.depth, resolution:this.resolution, contextual:this.depth && "strict" === this.tokenizer}; -}; -R.prototype.clear = function() { - return this.destroy().init(); -}; -R.prototype.destroy = function() { - this._cache && (this._cache.clear(), this._cache = null); - this._map = this._ctx = this._ids = null; - if (this.doc) { - for (var a = this.doc.keys, b = 0; b < a.length; b++) { - this.doc.index[a[b]].destroy(); - } - this.doc = this._doc = null; - } - return this; -}; -function ha(a, b, c) { - Object.defineProperty(a, b, {get:c}); -} -function W(a, b, c, e, d, g, f, h) { - if (b[c]) { - return b[c]; - } - d = d ? (h - (f || h / 1.5)) * g + (f || h / 1.5) * d : g; - b[c] = d; - d >= f && (a = a[h - (d + 0.5 >> 0)], a = a[c] || (a[c] = []), a[a.length] = e); - return d; -} -function X(a, b) { - if (a) { - for (var c = Object.keys(a), e = 0, d = c.length; e < d; e++) { - var g = c[e], f = a[g]; - if (f) { - for (var h = 0, k = f.length; h < k; h++) { - if (f[h] === b) { - 1 === k ? delete a[g] : f.splice(h, 1); - break; - } else { - E(f[h]) && X(f[h], b); - } - } - } - } - } -} -function ia(a, b) { - for (var c = Object.keys(a), e = c.length, d = [], g = "", f = 0, h = 0, k; h < e; h++) { - var m = c[h]; - (k = a[m]) ? (d[f++] = L(b ? "(?!\\b)" + m + "(\\b|_)" : m), d[f++] = k) : g += (g ? "|" : "") + m; - } - g && (d[f++] = L(b ? "(?!\\b)(" + g + ")(\\b|_)" : "(" + g + ")"), d[f] = ""); - return d; -} -function na(a, b) { - return b.length - a.length; -} -function ma(a, b) { - a = a[Y]; - b = b[Y]; - return a < b ? -1 : a > b ? 1 : 0; -} -function la(a, b) { - for (var c = Y.length, e = 0; e < c; e++) { - a = a[Y[e]], b = b[Y[e]]; - } - return a < b ? -1 : a > b ? 1 : 0; -} -function Z(a, b, c) { - return a ? {page:a, next:b ? "" + b : null, result:c} : c; -} -function ka(a, b, c, e, d, g, f) { - var h = []; - if (!0 === c) { - c = "0"; - var k = ""; - } else { - k = c && c.split(":"); - } - var m = a.length; - if (1 < m) { - var q = G(), u = [], p, l = 0, n, w = !0, v = 0, x; - if (k) { - if (2 === k.length) { - var t = k; - k = !1; - } else { - k = x = parseInt(k[0], 10); - } - } - if (f) { - for (p = G(); l < m; l++) { - if ("not" === d[l]) { - var A = a[l]; - var B = A.length; - for (n = 0; n < B; n++) { - p["@" + A[n]] = 1; - } - } else { - var N = l + 1; - } - } - if (F(N)) { - return Z(c, J, h); - } - l = 0; - } else { - var P = r(d) && d; - } - for (var T; l < m; l++) { - var C = l === (N || m) - 1; - if (!P || !l) { - if ((n = P || d && d[l]) && "and" !== n) { - if ("or" === n) { - T = !1; - } else { - continue; - } - } else { - T = g = !0; - } - } - A = a[l]; - if (B = A.length) { - if (w) { - if (H) { - var D = H.length; - for (n = 0; n < D; n++) { - w = H[n]; - var M = "@" + w; - f && p[M] || (q[M] = 1, g || (h[v++] = w)); - } - var H = null; - w = !1; - } else { - H = A; - continue; - } - } - M = !1; - for (n = 0; n < B; n++) { - D = A[n]; - var I = "@" + D, Q = g ? q[I] || 0 : l; - if (!(!Q && !e || f && p[I] || !g && q[I])) { - if (Q === l) { - if (C) { - if (!x || --x < v) { - if (h[v++] = D, b && v === b) { - return Z(c, v + (k || 0), h); - } - } - } else { - q[I] = l + 1; - } - M = !0; - } else { - e && (I = u[Q] || (u[Q] = []), I[I.length] = D); - } - } - } - if (T && !M && !e) { - break; - } - } else { - if (T && !e) { - return Z(c, J, A); - } - } - } - if (H) { - if (l = H.length, f) { - for (n = k ? parseInt(k, 10) : 0; n < l; n++) { - a = H[n], p["@" + a] || (h[v++] = a); - } - } else { - h = H; - } - } - if (e) { - for (v = h.length, t ? (l = parseInt(t[0], 10) + 1, n = parseInt(t[1], 10) + 1) : (l = u.length, n = 0); l--;) { - if (D = u[l]) { - for (B = D.length; n < B; n++) { - if (e = D[n], !f || !p["@" + e]) { - if (h[v++] = e, b && v === b) { - return Z(c, l + ":" + n, h); - } - } - } - n = 0; - } - } - } - } else { - !m || d && "not" === d[0] || (h = a[0], k && (k = parseInt(k[0], 10))); - } - if (b) { - f = h.length; - k && k > f && (k = 0); - k = k || 0; - var J = k + b; - J < f ? h = h.slice(k, J) : (J = 0, k && (h = h.slice(k))); - } - return Z(c, J, h); -} -;var pa = {encode:oa, rtl:!1}, qa = /[\W_]+/, ra = L("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), sa = L("[\u00e8\u00e9\u00ea\u00eb]"), ta = L("[\u00ec\u00ed\u00ee\u00ef]"), ua = L("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), va = L("[\u00f9\u00fa\u00fb\u00fc\u0171]"), wa = L("[\u00fd\u0177\u00ff]"), xa = L("\u00f1"), ya = L("[\u00e7c]"), za = L("\u00df"), Aa = L(" & "), Ba = [ra, "a", sa, "e", ta, "i", ua, "o", va, "u", wa, "y", xa, "n", ya, "k", za, "s", Aa, " and "]; -function oa(a, b) { - return (b || this).pipeline(a.toLowerCase(), Ba, qa, !1); -} -;var Da = {encode:Ca, rtl:!1}, Ea = L("ae"), Fa = L("ai"), Ga = L("ay"), Ha = L("ey"), Ia = L("oe"), Ja = L("ue"), Ka = L("ie"), La = L("sz"), Ma = L("zs"), Na = L("ck"), Oa = L("cc"), Pa = L("sh"), Qa = L("th"), Ra = L("dt"), Sa = L("ph"), Ta = L("pf"), Ua = L("ou"), Va = L("uo"), Wa = [Ea, "a", Fa, "ei", Ga, "ei", Ha, "ei", Ia, "o", Ja, "u", Ka, "i", La, "s", Ma, "s", Pa, "s", Na, "k", Oa, "k", Qa, "t", Ra, "t", Sa, "f", Ta, "f", Ua, "o", Va, "u"]; -function Ca(a, b, c) { - a && (a = oa(a, b || this).join(" "), 2 < a.length && (a = K(a, Wa)), c || (1 < a.length && (a = O(a)), a && (a = a.split(" ")))); - return a; -} -;var Ya = {encode:Xa, rtl:!1}, Za = /[\W_]+/; -function Xa(a) { - return this.pipeline(a.toLowerCase(), !1, Za, !1); -} -;var ab = {encode:$a, rtl:!1}, bb = L("(?!\\b)p"), cb = L("(?!\\b)z"), db = L("(?!\\b)[cgq]"), eb = L("(?!\\b)n"), fb = L("(?!\\b)d"), gb = L("(?!\\b)[vw]"), hb = L("(?!\\b)[aeiouy]"), ib = [bb, "b", cb, "s", db, "k", eb, "m", fb, "t", gb, "f", hb, ""]; -function $a(a) { - a && (a = Ca(a, this, !0), 1 < a.length && (a = K(a, ib)), 1 < a.length && (a = O(a)), a && (a = a.split(" "))); - return a; -} -;var kb = {encode:jb, rtl:!1, tokenize:"strict"}, lb = /[^a-z]+/; -function jb(a) { - a = this.pipeline(a.toLowerCase(), !1, !1, !1); - var b = []; - if (a) { - for (var c = a.split(lb), e = c.length, d = 0, g = 0; d < e; d++) { - if ((a = c[d]) && 2 < a.length && (!this.filter || !this.filter[a])) { - for (var f = a[0], h = mb(f), k = 1; k < a.length; k++) { - var m = mb(a[k]); - if (m !== h && (f += m, h = m, 4 === f.length)) { - break; - } - } - b[g++] = (f + "0000").substring(0, 4); - } - } - } - return b; -} -function mb(a) { - switch(a) { - case "b": - case "f": - case "p": - case "v": - return 1; - case "c": - case "g": - case "j": - case "k": - case "q": - case "s": - case "x": - case "z": - return 2; - case "d": - case "t": - return 3; - case "l": - return 4; - case "m": - case "n": - return 5; - case "r": - return 6; - } - return ""; -} -;var ob = {encode:nb, rtl:!0}, pb = /[\x00-\x7F]+/g; -function nb(a) { - return this.pipeline(a.replace(pb, " "), !1, " ", !1); -} -;var rb = {encode:qb, rtl:!1, tokenize:"strict"}, sb = /[\x00-\x7F]+/g; -function qb(a) { - return this.pipeline(a.replace(sb, ""), !1, "", !1); -} -;var ub = {encode:tb, rtl:!1}, vb = /[\x00-\x7F]+/g; -function tb(a) { - return this.pipeline(a.replace(vb, " "), !1, " ", !1); -} -;V["latin:advanced"] = Da; -V["latin:balance"] = Ya; -V["latin:default"] = da; -V["latin:extra"] = ab; -V["latin:simple"] = pa; -V["latin:soundex"] = kb; -V["arabic:default"] = ob; -V["cjk:default"] = rb; -V["cyrillic:default"] = ub; -U.de = {filter:"aber als am an auch auf aus bei bin bis bist da dadurch daher darum das da\u00df dass dein deine dem den der des dessen deshalb die dies dieser dieses doch dort du durch ein eine einem einen einer eines er es euer eure f\u00fcr hatte hatten hattest hattet hier hinter ich ihr ihre im in ist ja jede jedem jeden jeder jedes jener jenes jetzt kann kannst k\u00f6nnen k\u00f6nnt machen mein meine mit mu\u00df mu\u00dft musst m\u00fcssen m\u00fc\u00dft nach nachdem nein nicht nun oder seid sein seine sich sie sind soll sollen sollst sollt sonst soweit sowie und unser unsere unter vom von vor wann warum was weiter weitere wenn wer werde werden werdet weshalb wie wieder wieso wir wird wirst wo woher wohin zu zum zur \u00fcber".split(" "), -stemmer:{niss:"", isch:"", lich:"", heit:"", keit:"", ell:"", bar:"", end:"", ung:"", est:"", ern:"", em:"", er:"", en:"", es:"", st:"", ig:"", ik:"", e:"", s:""}, matcher:{}}; -U.en = {filter:"a about above after again against all also am an and any are aren't as at be because been before being below both but by can cannot can't come could couldn't did didn't do does doesn't doing dont down during each even few first for from further get go had hadn't has hasn't have haven't having he hed her here here's hers herself hes him himself his how how's i id if ill im in into is isn't it it's itself i've just know let's like make me more most mustn't my myself new no nor not now of off on once only or other ought our our's ourselves out over own same say see shan't she she'd shell shes should shouldn't so some such than that that's the their theirs them themselves then there there's these they they'd they'll they're they've this those through time to too until up us very want was wasn't way we wed well were weren't we've what what's when when's where where's which while who whom who's why why's will with won't would wouldn't you you'd you'll your you're your's yourself yourselves you've".split(" "), -stemmer:{ational:"ate", iveness:"ive", fulness:"ful", ousness:"ous", ization:"ize", tional:"tion", biliti:"ble", icate:"ic", ative:"", alize:"al", iciti:"ic", entli:"ent", ousli:"ous", alism:"al", ation:"ate", aliti:"al", iviti:"ive", ement:"", enci:"ence", anci:"ance", izer:"ize", alli:"al", ator:"ate", logi:"log", ical:"ic", ance:"", ence:"", ness:"", able:"", ible:"", ment:"", eli:"e", bli:"ble", ful:"", ant:"", ent:"", ism:"", ate:"", iti:"", ous:"", ive:"", ize:"", al:"", ou:"", er:"", ic:""}, -matcher:{}}; -U.at = {filter:"aber als am an auch auf aus bei bin bis bist da dadurch daher darum das da\u00df dass dein deine dem den der des dessen deshalb die dies dieser dieses doch dort du durch ein eine einem einen einer eines er es euer eure f\u00fcr hatte hatten hattest hattet hier hinter ich ihr ihre im in ist ja jede jedem jeden jeder jedes jener jenes jetzt kann kannst k\u00f6nnen k\u00f6nnt machen mein meine mit mu\u00df mu\u00dft musst m\u00fcssen m\u00fc\u00dft nach nachdem nein nicht nun oder seid sein seine sich sie sind soll sollen sollst sollt sonst soweit sowie und unser unsere unter vom von vor wann warum was weiter weitere wenn wer werde werden werdet weshalb wie wieder wieso wir wird wirst wo woher wohin zu zum zur \u00fcber".split(" "), -stemmer:{niss:"", isch:"", lich:"", heit:"", keit:"", end:"", ung:"", est:"", ern:"", em:"", er:"", en:"", es:"", st:"", ig:"", ik:"", e:"", s:""}, matcher:{}}; -U.us = {filter:"a about above after again against all also am an and any are aren't as at be because been before being below both but by can cannot can't come could couldn't did didn't do does doesn't doing dont down during each even few first for from further get go had hadn't has hasn't have haven't having he hed her here here's hers herself hes him himself his how how's i id if ill im in into is isn't it it's itself i've just know let's like make me more most mustn't my myself new no nor not now of off on once only or other ought our our's ourselves out over own same say see shan't she she'd shell shes should shouldn't so some such than that that's the their theirs them themselves then there there's these they they'd they'll they're they've this those through time to too until up us very want was wasn't way we wed well were weren't we've what what's when when's where where's which while who whom who's why why's will with won't would wouldn't you you'd you'll your you're your's yourself yourselves you've".split(" "), -stemmer:{ational:"ate", iveness:"ive", fulness:"ful", ousness:"ous", ization:"ize", tional:"tion", biliti:"ble", icate:"ic", ative:"", alize:"al", iciti:"ic", entli:"ent", ousli:"ous", alism:"al", ation:"ate", aliti:"al", iviti:"ive", ement:"", enci:"ence", anci:"ance", izer:"ize", alli:"al", ator:"ate", logi:"log", ical:"ic", ance:"", ence:"", ness:"", able:"", ible:"", ment:"", eli:"e", bli:"ble", ful:"", ant:"", ent:"", ism:"", ate:"", iti:"", ous:"", ive:"", ize:"", al:"", ou:"", er:"", ic:""}, -matcher:{}}; -(function() { - var a = this || window, b; - (b = a.define) && b.amd ? b([], function() { - return R; - }) : "object" === typeof a.exports ? a.module.exports = R : a.FlexSearch = R; -})(); -}).call(this); diff --git a/dist/lang/arabic/default.min.js b/dist/lang/arabic/default.min.js deleted file mode 100644 index 26a8c48..0000000 --- a/dist/lang/arabic/default.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(){'use strict';var a=/[\x00-\x7F]+/g;window.FlexSearch.registerCharset("arabic:default",{encode:function(b){return this.a(b.replace(a," "),!1," ",!1)},b:!0});}).call(this); diff --git a/dist/lang/at.min.js b/dist/lang/at.min.js deleted file mode 100644 index 231c36b..0000000 --- a/dist/lang/at.min.js +++ /dev/null @@ -1,2 +0,0 @@ -(function(){'use strict';window.FlexSearch.registerLanguage("at",{filter:"aber als am an auch auf aus bei bin bis bist da dadurch daher darum das da\u00df dass dein deine dem den der des dessen deshalb die dies dieser dieses doch dort du durch ein eine einem einen einer eines er es euer eure f\u00fcr hatte hatten hattest hattet hier hinter ich ihr ihre im in ist ja jede jedem jeden jeder jedes jener jenes jetzt kann kannst k\u00f6nnen k\u00f6nnt machen mein meine mit mu\u00df mu\u00dft musst m\u00fcssen m\u00fc\u00dft nach nachdem nein nicht nun oder seid sein seine sich sie sind soll sollen sollst sollt sonst soweit sowie und unser unsere unter vom von vor wann warum was weiter weitere wenn wer werde werden werdet weshalb wie wieder wieso wir wird wirst wo woher wohin zu zum zur \u00fcber".split(" "), -b:{niss:"",isch:"",lich:"",heit:"",keit:"",end:"",ung:"",est:"",ern:"",em:"",er:"",en:"",es:"",st:"",ig:"",ik:"",e:"",s:""},a:{}});}).call(this); diff --git a/dist/lang/cjk/default.min.js b/dist/lang/cjk/default.min.js deleted file mode 100644 index d4471ee..0000000 --- a/dist/lang/cjk/default.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(){'use strict';var a=/[\x00-\x7F]+/g;window.FlexSearch.registerCharset("cjk:default",{encode:function(b){return this.a(b.replace(a,""),!1,"",!1)},b:!1,c:"strict"});}).call(this); diff --git a/dist/lang/cyrillic/default.min.js b/dist/lang/cyrillic/default.min.js deleted file mode 100644 index 8ff8695..0000000 --- a/dist/lang/cyrillic/default.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(){'use strict';var a=/[\x00-\x7F]+/g;window.FlexSearch.registerCharset("cyrillic:default",{encode:function(b){return this.a(b.replace(a," "),!1," ",!1)},b:!1});}).call(this); diff --git a/dist/lang/de.min.js b/dist/lang/de.min.js deleted file mode 100644 index 288cc8d..0000000 --- a/dist/lang/de.min.js +++ /dev/null @@ -1,2 +0,0 @@ -(function(){'use strict';window.FlexSearch.registerLanguage("de",{filter:"aber als am an auch auf aus bei bin bis bist da dadurch daher darum das da\u00df dass dein deine dem den der des dessen deshalb die dies dieser dieses doch dort du durch ein eine einem einen einer eines er es euer eure f\u00fcr hatte hatten hattest hattet hier hinter ich ihr ihre im in ist ja jede jedem jeden jeder jedes jener jenes jetzt kann kannst k\u00f6nnen k\u00f6nnt machen mein meine mit mu\u00df mu\u00dft musst m\u00fcssen m\u00fc\u00dft nach nachdem nein nicht nun oder seid sein seine sich sie sind soll sollen sollst sollt sonst soweit sowie und unser unsere unter vom von vor wann warum was weiter weitere wenn wer werde werden werdet weshalb wie wieder wieso wir wird wirst wo woher wohin zu zum zur \u00fcber".split(" "), -b:{niss:"",isch:"",lich:"",heit:"",keit:"",ell:"",bar:"",end:"",ung:"",est:"",ern:"",em:"",er:"",en:"",es:"",st:"",ig:"",ik:"",e:"",s:""},a:{}});}).call(this); diff --git a/dist/lang/en.min.js b/dist/lang/en.min.js deleted file mode 100644 index 6f18d0e..0000000 --- a/dist/lang/en.min.js +++ /dev/null @@ -1,2 +0,0 @@ -(function(){'use strict';window.FlexSearch.registerLanguage("en",{filter:"a about above after again against all also am an and any are aren't as at be because been before being below both but by can cannot can't come could couldn't did didn't do does doesn't doing dont down during each even few first for from further get go had hadn't has hasn't have haven't having he hed her here here's hers herself hes him himself his how how's i id if ill im in into is isn't it it's itself i've just know let's like make me more most mustn't my myself new no nor not now of off on once only or other ought our our's ourselves out over own same say see shan't she she'd shell shes should shouldn't so some such than that that's the their theirs them themselves then there there's these they they'd they'll they're they've this those through time to too until up us very want was wasn't way we wed well were weren't we've what what's when when's where where's which while who whom who's why why's will with won't would wouldn't you you'd you'll your you're your's yourself yourselves you've".split(" "), -b:{ational:"ate",iveness:"ive",fulness:"ful",ousness:"ous",ization:"ize",tional:"tion",biliti:"ble",icate:"ic",ative:"",alize:"al",iciti:"ic",entli:"ent",ousli:"ous",alism:"al",ation:"ate",aliti:"al",iviti:"ive",ement:"",enci:"ence",anci:"ance",izer:"ize",alli:"al",ator:"ate",logi:"log",ical:"ic",ance:"",ence:"",ness:"",able:"",ible:"",ment:"",eli:"e",bli:"ble",ful:"",ant:"",ent:"",ism:"",ate:"",iti:"",ous:"",ive:"",ize:"",al:"",ou:"",er:"",ic:""},a:{}});}).call(this); diff --git a/dist/lang/latin/advanced.min.js b/dist/lang/latin/advanced.min.js deleted file mode 100644 index da44177..0000000 --- a/dist/lang/latin/advanced.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(){'use strict';function a(b){return new RegExp(b,"g")};var f=/[\W_]+/,h=[a("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"),"a",a("[\u00e8\u00e9\u00ea\u00eb]"),"e",a("[\u00ec\u00ed\u00ee\u00ef]"),"i",a("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"),"o",a("[\u00f9\u00fa\u00fb\u00fc\u0171]"),"u",a("[\u00fd\u0177\u00ff]"),"y",a("\u00f1"),"n",a("[\u00e7c]"),"k",a("\u00df"),"s",a(" & ")," and "];function k(b,c){return(c||this).a(b.toLowerCase(),h,f,!1)};var l=[a("ae"),"a",a("ai"),"ei",a("ay"),"ei",a("ey"),"ei",a("oe"),"o",a("ue"),"u",a("ie"),"i",a("sz"),"s",a("zs"),"s",a("sh"),"s",a("ck"),"k",a("cc"),"k",a("th"),"t",a("dt"),"t",a("ph"),"f",a("pf"),"f",a("ou"),"o",a("uo"),"u"];window.FlexSearch.registerCharset("latin:advanced",{encode:function(b,c,e){if(b){b=k(b,c||this).join(" ");if(2d;a--){const b=e[a-1];e[a]=b,c[b]=a}e[d]=a,c[a]=d}}}return b}; \ No newline at end of file diff --git a/dist/module/common.js b/dist/module/common.js deleted file mode 100644 index 4acb461..0000000 --- a/dist/module/common.js +++ /dev/null @@ -1 +0,0 @@ -import FlexSearch from"./flexsearch.js";export function is_string(a){return"string"==typeof a}export function is_array(a){return a.constructor===Array}export function is_function(a){return"function"==typeof a}export function is_object(a){return"object"==typeof a}export function is_undefined(a){return"undefined"==typeof a}export function get_keys(a){return Object.keys(a)}export function create_object_array(a){const b=Array(a);for(let c=0;ca;h--)i=c.substring(a,h),add_index(m,g,i,b,f,e,j,l-1)}break;default:const o=add_index(m,g,c,b,1,e,j,l-1);if(k&&1=j){const d=g._ctx[c]||(g._ctx[c]=create_object()),e=this._ctx[c]||(this._ctx[c]=create_object_array(l-(j||0)));let i=a-k,m=a+k+1;for(0>i&&(i=0),m>h&&(m=h);i=g){let b=a[h-(i+0.5>>0)];b=b[c]||(b[c]=[]),b[b.length]=d}return i}function remove_index(b,c){if(b){const a=get_keys(b);for(let d=0,e=a.length;dd?1:0}function sort_by_deep_field_up(c,d){const e=field_to_sort.length;for(let a=0;ad?1:0}function create_page(a,b,c){return a?{page:a,next:b?""+b:null,result:c}:c}function intersect(a,b,c,d,e,f,g){let h,j,k=[];!0===c?(c="0",j=""):j=c&&c.split(":");const l=a.length;if(1a&&(j=0);const c=j||0;h=c+b,h=d&&(this._task_completed=this.worker),this._task_completed===this.worker&&(this.cache&&this._cache.set(b,this._task_result),this._current_callback&&this._current_callback(this._task_result))),this}; \ No newline at end of file diff --git a/doc/0.7.0.md b/doc/0.7.0.md index 9d9f145..f2b67fa 100644 --- a/doc/0.7.0.md +++ b/doc/0.7.0.md @@ -40,6 +40,27 @@ document.search(text, limit, options); document.search(options); ``` +## Source Code + +Source Code v0.7.0-pre-alpha available here:
+https://github.com/nextapps-de/flexsearch/tree/0.7.0/src + +What is not included yet but comes soon? + +- Worker (almost done) +- Pagination (not implemented yet) +- Export/Import (not implemented yet) +- Engines (almost done) +- Tags (almost done) +- Bundles: Light, Compact, Full (almost done) +- Test Automation (needs to be migrated) +- Benchmark Suite (almost done) + +What will be dropped? + +- Where-Clause +- Index Information `index.info()` + ## Builtin Profiles 1. `memory` (primary optimize for memory) @@ -425,11 +446,90 @@ index.search({ #### Complex Documents +You need to follow 2 rules for your documents: + +1. The document cannot start with an Array at the root index. This will introduce sequential data and isn't supported yet. See below for a workaround for such data. + +```js +[ // <-- not allowed as document start! + { + "id": 0, + "title": "title" + } +] +``` + +2. The id can't be nested inside an array (also none of the parent fields can't be an array). This will introduce sequential data and isn't supported yet. See below for a workaround for such data. + +```js +{ + "records": [ // <-- not allowed when id lives inside! + { + "id": 0, + "title": "title" + } + ] +} +``` + +Here an example for a supported complex document: + ```json -[ +{ + "meta": { + "tag": "cat", + "id": 0 + }, + "contents": [ + { + "body": { + "title": "some title", + "footer": "some text" + }, + "keywords": ["some", "key", "words"] + }, + { + "body": { + "title": "some title", + "footer": "some text" + }, + "keywords": ["some", "key", "words"] + } + ] +} +``` + +The corresponding document descriptor (when all fields should be indexed) looks like: + +```js +const index = new Document({ + key: "meta:id", + tag: "meta:tag", + doc: [ + "contents[]:body:title", + "contents[]:body:footer", + "contents[]:keywords" + ] +}); +``` + +Again, when searching you have to use the same colon-separated-string from your field definition. + +```js +index.search(query, { + field: "contents[]:body:title" +}); +``` + +#### Not Supported Documents (Sequential Data) + +This example breaks both rules from above: + +```js +[ // <-- not allowed as document start! { "tag": "cat", - "records": [ + "records": [ // <-- not allowed when id lives inside! { "id": 0, "body": { @@ -451,33 +551,57 @@ index.search({ ] ``` -Please notice this complex structure has its records as nested array which also includes the `key`. +You need to apply some kind of structure normalization. + +A workaround to such a data structure looks like this: ```js const index = new Document({ - key: "records[]:id", + key: "record:id", tag: "tag", doc: [ - "records[]:body:title", - "records[]:body:footer", - "records[]:body:keywords" + "record:body:title", + "record:body:footer", + "record:body:keywords" ] }); + +function add(sequential_data){ + + for(let x = 0, data; x < sequential_data.length; x++){ + + data = sequential_data[x]; + + for(let y = 0, record; y < data.records.length; y++){ + + record = data.records[y]; + + index.add({ + tag: data.tag, + id: record.id, + record: record + }); + } + } +} + +// now just use add() helper method as usual: + +add([{ + + // sequential structured data + // take the data example above + +}]); ``` -Again, when searching you have to use the same colon-separated-string from your field definition. - -```js -index.search(query, { - field: "records[]:body:title" -}); -``` +You can skip the first loop when your document data has just one index as the outer array. #### Join / Append Arrays On the complex example above, the field `keywords` is an array but here the markup did not have brackets like `keywords[]`. That will also detect the array but instead of appending each entry to a new context, the array will be joined into on large string and added to the index. -The difference of both kinds of adding array contents is the relevance when searching. When adding each item from an array via append to its own context with the syntax `field[]`, then the relevance of the last entry concurrent with the first entry. When you left the brackets in the notation, it will join the array to one string. Here the first entry has the highest relevance, whereas the last entry has the lowest relevance. +The difference of both kinds of adding array contents is the relevance when searching. When adding each item of an array via `append()` to its own context by using the syntax `field[]`, then the relevance of the last entry concurrent with the first entry. When you left the brackets in the notation, it will join the array to one whitespace-separated string. Here the first entry has the highest relevance, whereas the last entry has the lowest relevance. So assuming the keyword from the example above are pre-sorted by relevance to its popularity, then you want to keep this order (information of relevance). For this purpose do not add brackets to the notation. Otherwise, it would take the entries in a new scoring context (the old order is getting lost). @@ -1108,21 +1232,21 @@ FlexSearch provides you many parameters you can use to adjust the optimal balanc +1 (per level) +1 (per level) 0 - +3 (per level) + +2 (per level) threshold -4 (per level) - +2 (per level) -3 (per level) + +2 (per level) 0 depth +4 (per level) - +2 (per level) + -1 (per level) -10 + depth +10 @@ -1132,15 +1256,15 @@ FlexSearch provides you many parameters you can use to adjust the optimal balanc -2 (per level) +2 (per level) -3 (per level) - +3 (per level) + +2 (per level) bidirectional -2 0 - +3 (per level) - 0 + +3 + -1 @@ -1153,10 +1277,10 @@ FlexSearch provides you many parameters you can use to adjust the optimal balanc optimize: "memory" - -5 + -7 -1 0 - -1 + -3 @@ -1241,7 +1365,7 @@ FlexSearch provides you many parameters you can use to adjust the optimal balanc store: [fields] - +2 (per field) + +1 (per field) 0 0 0 diff --git a/package.json b/package.json index dfe27d9..4d1f146 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,6 @@ "browser": "dist/flexsearch.min.js", "types": "index.d.ts", "preferGlobal": false, - "bin": {}, "repository": { "type": "git", "url": "https://github.com/nextapps-de/flexsearch.git" @@ -53,7 +52,6 @@ "LICENSE" ], "readme": "README.md", - "dependencies": {}, "devDependencies": { "babel-cli": "^6.26.0", "babel-plugin-conditional-compile": "0.0.5", @@ -72,6 +70,6 @@ "babel-plugin-transform-property-literals": "^6.9.4", "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", "babel-plugin-transform-undefined-to-void": "^6.9.4", - "google-closure-compiler": "^20191027.0.0" + "google-closure-compiler": "^20210505.0.0" } } diff --git a/src/async.js b/src/async.js new file mode 100644 index 0000000..1ed8af1 --- /dev/null +++ b/src/async.js @@ -0,0 +1,107 @@ +import Index from "./index.js"; +import Document from "./document.js"; +import { promise as Promise } from "./polyfill.js"; + +/** + * @param {Function=} callback + */ + +export function addAsync(id, content, callback){ + + return caller.call( + /** @type {Document|Index} */ (this), + /** @type {Document|Index} */ (this).add, + arguments + ); +} + +/** + * @param {Function=} callback + */ + +export function appendAsync(id, content, callback){ + + return caller.call( + /** @type {Document|Index} */ (this), + /** @type {Document|Index} */ (this).append, + arguments + ); +} + +/** + * @param {!string} query + * @param {number|Object|Function=} options + * @param {Function=} callback + */ + +export function searchAsync(query, options, callback){ + + return caller.call( + /** @type {Document|Index} */ (this), + /** @type {Document|Index} */ (this).search, + arguments + ); +} + +/** + * @param {Function=} callback + */ + +export function updateAsync(id, content, callback){ + + return caller.call( + /** @type {Document|Index} */ (this), + /** @type {Document|Index} */ (this).update, + arguments + ); +} + +/** + * @param {Function=} callback + */ + +export function removeAsync(id, callback){ + + return caller.call( + /** @type {Document|Index} */ (this), + /** @type {Document|Index} */ (this).remove, + arguments + ); +} + +function caller(method, args){ + + let callback; + + for(let i = 0; i < args.length; i++){ + + if(typeof args[i] === "function"){ + + callback = args[i]; + delete args[i]; + break; + } + } + + const self = /** @type {Document|Index} */ (this); + + const promise = new Promise(function(resolve){ + + // Promises are bullshit, they will block the main thread + + setTimeout(function(){ + + resolve(method.apply(self, args)); + }); + }); + + if(callback){ + + promise.then(callback); + return this; + } + else{ + + return promise; + } +} \ No newline at end of file diff --git a/src/bundle.js b/src/bundle.js deleted file mode 100644 index a4b7b94..0000000 --- a/src/bundle.js +++ /dev/null @@ -1,102 +0,0 @@ -import { default as FlexSearch, global_charset, global_lang } from "./flexsearch.js"; -import charset_latin_advanced from "./lang/latin/advanced.js"; -import charset_latin_balance from "./lang/latin/balance.js"; -import charset_latin_default from "./lang/latin/default.js"; -import charset_latin_extra from "./lang/latin/extra.js"; -import charset_latin_simple from "./lang/latin/simple.js"; -import charset_latin_soundex from "./lang/latin/soundex.js"; -import charset_arabic_default from "./lang/arabic/default.js"; -import charset_cjk_default from "./lang/cjk/default.js"; -import charset_cyrillic_default from "./lang/cyrillic/default.js"; -import lang_de from "./lang/de.js"; -import lang_en from "./lang/en.js"; -import lang_at from "./lang/at.js"; -import lang_us from "./lang/us.js"; -import "./export.js"; - -if(SUPPORT_ENCODER === true || (SUPPORT_ENCODER && ((SUPPORT_ENCODER === "latin") || (SUPPORT_ENCODER.indexOf("latin:advanced") !== -1)))){ - - global_charset["latin:advanced"] = charset_latin_advanced; -} -if(SUPPORT_ENCODER === true || (SUPPORT_ENCODER && ((SUPPORT_ENCODER === "latin") || (SUPPORT_ENCODER.indexOf("latin:balance") !== -1)))){ - - global_charset["latin:balance"] = charset_latin_balance; -} -if(SUPPORT_ENCODER === true || (SUPPORT_ENCODER && ((SUPPORT_ENCODER === "latin") || (SUPPORT_ENCODER.indexOf("latin:default") !== -1)))){ - - global_charset["latin:default"] = charset_latin_default; -} -if(SUPPORT_ENCODER === true || (SUPPORT_ENCODER && ((SUPPORT_ENCODER === "latin") || (SUPPORT_ENCODER.indexOf("latin:extra") !== -1)))){ - - global_charset["latin:extra"] = charset_latin_extra; -} -if(SUPPORT_ENCODER === true || (SUPPORT_ENCODER && ((SUPPORT_ENCODER === "latin") || (SUPPORT_ENCODER.indexOf("latin:simple") !== -1)))){ - - global_charset["latin:simple"] = charset_latin_simple; -} -if(SUPPORT_ENCODER === true || (SUPPORT_ENCODER && ((SUPPORT_ENCODER === "latin") || (SUPPORT_ENCODER.indexOf("latin:soundex") !== -1)))){ - - global_charset["latin:soundex"] = charset_latin_soundex; -} -if(SUPPORT_ENCODER === true || (SUPPORT_ENCODER && ((SUPPORT_ENCODER === "arabic") || (SUPPORT_ENCODER.indexOf("arabic:default") !== -1)))){ - - global_charset["arabic:default"] = charset_arabic_default; -} -if(SUPPORT_ENCODER === true || (SUPPORT_ENCODER && ((SUPPORT_ENCODER === "cjk") || (SUPPORT_ENCODER.indexOf("cjk:default") !== -1)))){ - - global_charset["cjk:default"] = charset_cjk_default; -} -if(SUPPORT_ENCODER === true || (SUPPORT_ENCODER && ((SUPPORT_ENCODER === "cyrillic") || (SUPPORT_ENCODER.indexOf("cyrillic:default") !== -1)))){ - - global_charset["cyrillic:default"] = charset_cyrillic_default; -} - -if(SUPPORT_LANG === true || (SUPPORT_LANG && SUPPORT_LANG.indexOf("de") !== -1)){ - - global_lang["de"] = lang_de; -} -if(SUPPORT_LANG === true || (SUPPORT_LANG && SUPPORT_LANG.indexOf("en") !== -1)){ - - global_lang["en"] = lang_en; -} -if(SUPPORT_LANG === true || (SUPPORT_LANG && SUPPORT_LANG.indexOf("at") !== -1)){ - - global_lang["at"] = lang_at; -} -if(SUPPORT_LANG === true || (SUPPORT_LANG && SUPPORT_LANG.indexOf("us") !== -1)){ - - global_lang["us"] = lang_us; -} - -(function(){ - - const name = "FlexSearch"; - const root = this || window; - let prop; - - // AMD (RequireJS) - if((prop = root["define"]) && prop["amd"]){ - - prop([], function(){ - - return FlexSearch; - }); - } - // CommonJS (Node.js) - // else if(typeof exports === "object"){ - // - // /** @export */ - // module.exports = factory; - // } - else if(typeof root["exports"] === "object"){ - - /** @export */ - root["module"].exports = FlexSearch; - } - // Global (window) - else{ - - root[name] = FlexSearch; - } - -}()); \ No newline at end of file diff --git a/src/cache.js b/src/cache.js index 8dd0797..76849e0 100644 --- a/src/cache.js +++ b/src/cache.js @@ -1,111 +1,169 @@ -import { is_undefined, create_object } from "./common.js"; +import Index from "./index.js"; +import Document from "./index.js"; +import { create_object } from "./common.js"; /** * @param {boolean|number=} limit * @constructor */ -export default function CacheClass(limit){ - - this.clear(); +function CacheClass(limit){ /** @private */ this.limit = (limit !== true) && limit; -} - -CacheClass.prototype.clear = function(){ /** @private */ this.cache = create_object(); + /** @private */ - this.count = create_object(); - /** @private */ - this.index = create_object(); - /** @private */ - this.ids = []; -}; + this.queue = []; + + //this.clear(); +} + +export default CacheClass; + +/** + * @param {!string} query + * @param {number|Object=} limit + * @param {Object=} options + * @returns {Array} + */ + +export function searchCache(query, limit, options){ + + if(typeof query === "object"){ + + query = query["query"]; + } + + let cache = /** @type {Document|Index} */ (this).cache.get(query); + + if(!cache){ + + cache = /** @type {Document|Index} */ (this).search(query, limit, options); + /** @type {Document|Index} */ (this).cache.set(query, cache); + } + + return cache; +} + +// CacheClass.prototype.clear = function(){ +// +// /** @private */ +// this.cache = create_object(); +// +// /** @private */ +// this.queue = []; +// }; CacheClass.prototype.set = function(key, value){ - if(this.limit && is_undefined(this.cache[key])){ + if(!this.cache[key]){ - let length = this.ids.length; + // it is just a shame that native function array.shift() performs so bad + + // const length = this.queue.length; + // + // this.queue[length] = key; + // + // if(length === this.limit){ + // + // delete this.cache[this.queue.shift()]; + // } + + // the same bad performance + + // this.queue.unshift(key); + // + // if(this.queue.length === this.limit){ + // + // this.queue.pop(); + // } + + // fast implementation variant + + // let length = this.queue.length; + // + // if(length === this.limit){ + // + // length--; + // + // delete this.cache[this.queue[0]]; + // + // for(let x = 0; x < length; x++){ + // + // this.queue[x] = this.queue[x + 1]; + // } + // } + // + // this.queue[length] = key; + + // current fastest implementation variant + // theoretically that should not perform better compared to the example above + + let length = this.queue.length; if(length === this.limit){ - length--; + delete this.cache[this.queue[length - 1]]; + } + else{ - const last_id = this.ids[length]; - - delete this.cache[last_id]; - delete this.count[last_id]; - delete this.index[last_id]; + length++; } - this.ids[length] = key; - this.index[key] = length; - this.count[key] = -1; - this.cache[key] = value; + for(let x = length - 1; x > 0; x--){ - // TODO: remove extra call - // shift up counter +1 + this.queue[x] = this.queue[x - 1]; + } - this.get(key); + this.queue[0] = key; } - else{ - this.cache[key] = value; - } + this.cache[key] = value; }; -/** - * Note: It is better to have the complexity when fetching the cache: - */ - CacheClass.prototype.get = function(key){ const cache = this.cache[key]; if(this.limit && cache){ - const count = ++this.count[key]; - const index = this.index; - let current_index = index[key]; + // probably the indexOf() method performs faster when matched content is on front (left-to-right) + // using lastIndexOf() does not help, it performs almost slower - if(current_index > 0){ + const pos = this.queue.indexOf(key); - const ids = this.ids; - const old_index = current_index; + // if(pos < this.queue.length - 1){ + // + // const tmp = this.queue[pos]; + // this.queue[pos] = this.queue[pos + 1]; + // this.queue[pos + 1] = tmp; + // } - // forward pointer - while(this.count[ids[--current_index]] <= count){ + if(pos){ - if(current_index === -1){ - - break; - } - } - - // move pointer back - current_index++; - - if(current_index !== old_index){ - - // copy values from predecessors - for(let i = old_index; i > current_index; i--) { - - const tmp = ids[i - 1]; - - ids[i] = tmp; - index[tmp] = i; - } - - // push new value on top - ids[current_index] = key; - index[key] = current_index; - } + const tmp = this.queue[pos - 1]; + this.queue[pos - 1] = this.queue[pos]; + this.queue[pos] = tmp; } } return cache; -}; \ No newline at end of file +}; + +CacheClass.prototype.del = function(id){ + + for(let i = 0, item, key; i < this.queue.length; i++){ + + key = this.queue[i]; + item = this.cache[key]; + + if(item.indexOf(id) !== -1){ + + this.queue.splice(i--, 1); + delete this.cache[key]; + } + } +}; diff --git a/src/common.js b/src/common.js index fd8949c..b4dee19 100644 --- a/src/common.js +++ b/src/common.js @@ -1,54 +1,4 @@ -import FlexSearch from "./flexsearch.js"; - -/** - * @param {*} val - * @returns {boolean} - */ - -export function is_string(val){ - - return typeof val === "string"; -} - -/** - * @param {*} val - * @returns {boolean} - */ - -export function is_array(val){ - - return val.constructor === Array; -} - -/** - * @param {*} val - * @returns {boolean} - */ - -export function is_function(val){ - - return typeof val === "function"; -} - -/** - * @param {*} val - * @returns {boolean} - */ - -export function is_object(val){ - - return typeof val === "object"; -} - -/** - * @param {*} val - * @returns {boolean} - */ - -export function is_undefined(val){ - - return typeof val === "undefined"; -} +//import FlexSearch from "./flexsearch.js"; /** * @param {!Object} obj @@ -61,9 +11,8 @@ export function get_keys(obj){ } /** - * https://jsperf.com/comparison-object-index-type * @param {!number} count - * @returns {Object|Array} + * @returns {Array} */ export function create_object_array(count){ @@ -78,207 +27,29 @@ export function create_object_array(count){ return array; } +export function create_arrays(count){ + + const array = new Array(count); + + for(let i = 0; i < count; i++){ + + array[i] = []; + } + + return array; +} + export function create_object(){ return Object.create(null); } -/** - * @param {!string} str - * @param {Array} regexp - * @returns {string} - */ +export function concat(arrays){ -export function replace(str, regexp){ - - for(let i = 0, len = regexp.length; i < len; i += 2){ - - str = str.replace(regexp[i], regexp[i + 1]); - - if(!str){ - - break; - } - } - - return str; + return [].concat.apply([], arrays); } -/** - * @param {!string} str - * @returns {RegExp} - */ +export function sort_by_length_down(a, b){ -export function regex(str){ - - return new RegExp(str, "g"); -} - -/** - * Regex: replace(/(?:(\w)(?:\1)*)/g, "$1") - * @param {!string} string - * @returns {string} - */ - -export function collapse(string){ - - let final = "", prev = ""; - - for(let i = 0, len = string.length, char; i < len; i++){ - - if((char = string[i]) !== prev){ - - final += (prev = char); - } - } - - return final; -} - -// TODO using fast-swap -export function filter(words, map){ - - const length = words.length; - const filtered = []; - - for(let i = 0, count = 0; i < length; i++){ - - const word = words[i]; - - if(word && !map[word]){ - - filtered[count++] = word; - } - } - - return filtered; -} - -/** - * @param {!string} str - * @param {boolean|Array=} normalize - * @param {boolean|string|RegExp=} split - * @param {boolean=} _collapse - * @returns {string|Array} - */ - -FlexSearch.prototype.pipeline = function(str, normalize, split, _collapse){ - - if(str){ - - if(normalize && str){ - - str = replace(str, /** @type {Array} */ (normalize)); - } - - if(str && this.matcher){ - - str = replace(str, this.matcher); - } - - if(this.stemmer && str.length > 1){ - - str = replace(str, this.stemmer); - } - - if(_collapse && str.length > 1){ - - str = collapse(str); - } - - if(str){ - - if(split || (split === "")){ - - const words = str.split(/** @type {string|RegExp} */ (split)); - - return this.filter ? filter(words, this.filter) : words; - } - } - } - - return str; -}; - -// export function pipeline(str, normalize, matcher, stemmer, split, _filter, _collapse){ -// -// if(str){ -// -// if(normalize && str){ -// -// str = replace(str, normalize); -// } -// -// if(matcher && str){ -// -// str = replace(str, matcher); -// } -// -// if(stemmer && str.length > 1){ -// -// str = replace(str, stemmer); -// } -// -// if(_collapse && str.length > 1){ -// -// str = collapse(str); -// } -// -// if(str){ -// -// if(split !== false){ -// -// str = str.split(split); -// -// if(_filter){ -// -// str = filter(str, _filter); -// } -// } -// } -// } -// -// return str; -// } - -// const chars = {a:1, e:1, i:1, o:1, u:1, y:1}; -// -// function collapse_repeating_chars(string){ -// -// let collapsed_string = "", -// char_prev = "", -// char_next = ""; -// -// for(let i = 0; i < string.length; i++){ -// -// const char = string[i]; -// -// if(char !== char_prev){ -// -// if(i && (char === "h")){ -// -// if((chars[char_prev] && chars[char_next]) || (char_prev === " ")){ -// -// collapsed_string += char; -// } -// } -// else{ -// -// collapsed_string += char; -// } -// } -// -// char_next = ( -// -// (i === (string.length - 1)) ? -// -// "" -// : -// string[i + 1] -// ); -// -// char_prev = char; -// } -// -// return collapsed_string; -// } \ No newline at end of file + return b.length - a.length; +} \ No newline at end of file diff --git a/src/config.js b/src/config.js index 53afe90..5f75b15 100644 --- a/src/config.js +++ b/src/config.js @@ -1,53 +1,53 @@ /** @define {string} */ -const RELEASE = "browser"; +export const RELEASE = "browser"; /** @define {boolean} */ -const DEBUG = true; +export const DEBUG = true; /** @define {boolean} */ -const PROFILER = false; +export const PROFILER = false; /** @define {boolean} */ -const POLYFILL = true; +export const POLYFILL = true; /** @define {boolean} */ -const SUPPORT_WORKER = true; +export const SUPPORT_WORKER = true; /** @define {boolean|string} */ -const SUPPORT_ENCODER = true; +export const SUPPORT_ENCODER = true; /** @define {boolean|string} */ -const SUPPORT_LANG = true; +export const SUPPORT_LANG = true; /** @define {boolean} */ -const SUPPORT_CACHE = true; +export const SUPPORT_CACHE = true; /** @define {boolean} */ -const SUPPORT_ASYNC = true; +export const SUPPORT_ASYNC = true; /** @define {boolean} */ -const SUPPORT_PRESET = true; +export const SUPPORT_PRESET = true; /** @define {boolean} */ -const SUPPORT_SUGGESTION = true; +export const SUPPORT_SUGGESTION = true; /** @define {boolean} */ -const SUPPORT_SERIALIZE = true; +export const SUPPORT_SERIALIZE = true; /** @define {boolean} */ -const SUPPORT_INFO = true; +export const SUPPORT_INFO = true; /** @define {boolean} */ -const SUPPORT_DOCUMENT = true; +export const SUPPORT_DOCUMENT = true; /** @define {boolean} */ -const SUPPORT_WHERE = true; +export const SUPPORT_WHERE = true; /** @define {boolean} */ -const SUPPORT_PAGINATION = true; +export const SUPPORT_PAGINATION = true; /** @define {boolean} */ -const SUPPORT_OPERATOR = true; +export const SUPPORT_OPERATOR = true; /** @define {boolean} */ -const SUPPORT_CALLBACK = true; +export const SUPPORT_CALLBACK = true; diff --git a/src/document.js b/src/document.js new file mode 100644 index 0000000..961bfb3 --- /dev/null +++ b/src/document.js @@ -0,0 +1,523 @@ +/**! + * FlexSearch.js + * Copyright 2019 Nextapps GmbH + * Author: Thomas Wilkerling + * Licence: Apache-2.0 + * https://github.com/nextapps-de/flexsearch + */ + +import { SUPPORT_ASYNC, SUPPORT_CACHE } from "./config.js"; +import { create_object } from "./common.js"; +import Index from "./index.js"; +import { addAsync, appendAsync, removeAsync, searchAsync, updateAsync } from "./async.js"; +import Cache, { searchCache } from "./cache.js"; + +/** + * @param {Object=} options + * @return {Document} + * @constructor + */ + +function Document(options){ + + if(!(this instanceof Document)) { + + return new Document(options); + } + + let opt; + + options || (options = {}); + + this.register = create_object(); + this.store = (opt = options["store"]) && create_object(); + this.storetree = opt && (opt !== true) && []; + this.markup = []; + this.key = ((opt = options["key"]) && parse_tree(opt, this.markup)) || "id"; + this.tree = []; + this.field = []; + + if(SUPPORT_CACHE){ + + this.cache = (opt = options["cache"]) && new Cache(opt); + options["cache"] = false; + } + + /** @private */ + this.index = parse_descriptor.call(this, options); +} + +export default Document; + +/** + * @this Document + */ + +function parse_descriptor(options){ + + const index = create_object(); + let field = options["doc"]; // options["document"] + let field_options; + + if(typeof field === "string"){ + + field = [field]; + } + else if(field.constructor !== Array){ + + field_options = field; + field = Object.keys(field); + } + + for(let i = 0, key, item; i < field.length; i++){ + + key = field[i]; + + if(field_options){ + + item = field_options[key]; + item = typeof item === "object" ? Object.assign({}, options, item) : options; + } + else{ + + item = options; + } + + index[key] = new Index(item, this.register); + this.tree[i] = parse_tree(key, this.markup); + this.field[i] = key; + } + + if(this.storetree){ + + let store = options["store"]; + + if(typeof store === "string"){ + + store = [store]; + } + + for(let i = 0; i < store.length; i++){ + + this.storetree[i] = parse_tree(store[i], this.markup); + } + } + + return index; +} + +function parse_tree(key, markup){ + + const tree = key.split(":"); + let count = 0; + + for(let i = 0; i < tree.length; i++){ + + key = tree[i]; + + if(key.indexOf("[]") >= 0){ + + key = key.substring(0, key.length - 2); + + if(key){ + + markup[count] = true; + } + } + + if(key){ + + tree[count++] = key; + } + } + + if(count < tree.length){ + + tree.length = count; + } + + return count > 1 ? tree : tree[0]; +} + +function get_id(obj, tree){ + + if(typeof tree === "string"){ + + obj = obj[tree]; + } + else{ + + for(let i = 0; obj && (i < tree.length); i++){ + + obj = obj[tree[i]]; + } + } + + return obj; +} + +function store_value(obj, store, tree, pos, key){ + + obj = obj[key]; + + // reached target field + + if(pos === (tree.length - 1)){ + + // store target value + + store[key] = obj; + } + else if(obj){ + + if(obj.constructor === Array){ + + store = store[key] = new Array(obj.length); + + for(let i = 0; i < obj.length; i++){ + + // do not increase pos (an array is not a field) + store_value(obj, store, tree, pos, i); + } + } + else{ + + store = store[key] || (store[key] = create_object()); + key = tree[++pos]; + + store_value(obj, store, tree, pos, key); + } + } +} + +function add_index(obj, tree, markup, pos, index, id, key, _append){ + + obj = obj[key]; + + // reached target field + + if(pos === (tree.length - 1)){ + + // handle target value + + if(obj.constructor === Array){ + + if(markup[pos]){ + + for(let i = 0; i < obj.length; i++){ + + index.add(id, obj[i], true); + } + + return; + } + + obj = obj.join(" "); + } + + index.add(id, obj, _append); + } + else if(obj){ + + if(obj.constructor === Array){ + + for(let i = 0; i < obj.length; i++){ + + // do not increase index, an array is not a field + add_index(obj, tree, markup, pos, index, id, i, _append); + } + } + else{ + + key = tree[++pos]; + + add_index(obj, tree, markup, pos, index, id, key, _append); + } + } +} + +/** + * + * @param id + * @param content + * @param {boolean=} _append + * @returns {Document} + */ + +Document.prototype.add = function(id, content, _append){ + + if(typeof id === "object"){ + + content = id; + id = get_id(content, this.key); + } + + if(content && (id || (id === 0))){ + + if(this.register[id]){ + + return this.update(id, content); + } + + for(let i = 0, tree, field; i < this.field.length; i++){ + + field = this.field[i]; + tree = this.tree[i]; + + if(typeof tree === "string"){ + + tree = [tree]; + } + + add_index(content, tree, this.markup, 0, this.index[field], id, tree[0], _append); + } + + if(this.store){ + + let store; + + if(this.storetree){ + + store = create_object(); + + for(let i = 0, tree; i < this.storetree.length; i++){ + + tree = this.storetree[i]; + + if(typeof tree === "string"){ + + store[tree] = content[tree]; + } + else{ + + store_value(content, store, tree, 0, tree[0]); + } + } + } + + this.store[id] = store || content; + } + } + + return this; +}; + +Document.prototype.append = function(id, content){ + + return this.add(id, content, true); +}; + +Document.prototype.update = function(id, content){ + + return this.remove(id).add(id, content); +}; + +Document.prototype.remove = function(id){ + + if(typeof id === "object"){ + + id = id[this.key]; + } + + if(this.register[id]){ + + for(let i = 0; i < this.field.length; i++){ + + this.index[this.field[i]].remove(id, true); + } + + if(this.store){ + + delete this.store[id]; + } + + delete this.register[id]; + } + + return this; +}; + +Document.prototype.search = function(query, limit, options){ + + if(typeof query === "object"){ + + options = query; + query = options["query"]; + } + else if(typeof limit === "object"){ + + options = limit; + } + + let result = []; + let pluck, enrich; + let field, field_options, bool, count = 0; + + if(options){ + + pluck = options["pluck"]; + field = pluck || options["field"]; + enrich = options["enrich"]; + bool = options["bool"] === "and"; + limit = options["limit"]; + } + + if(field){ + + if(typeof field === "string"){ + + field = [field]; + } + else if(field.constructor !== Array){ + + field_options = field; + field = Object.keys(field); + } + } + else{ + + field = this.field; + } + + bool = bool && (field.length > 1); + + for(let i = 0, res, key, item; i < field.length; i++){ + + key = field[i]; + + if(field_options){ + + item = field_options[key]; + + // inherit options? + //item = typeof item === "object" ? Object.assign({}, options, item) : options; + } + else{ + + item = options; + } + + res = this.index[key].search(query, limit, item); + + if(bool){ + + if(!res.length){ + + // fast path optimization + + return []; + } + + // add a pseudo relevance index for the intersection + // used when squash the results on boolean "and" + //res = [res]; + } + + count += res.length; + result[i] = res; + } + + if(!count){ + + // fast path optimization + + return []; + } + + // squash the results on boolean "and"? + + // if(bool){ + // + // limit || (limit = 100); + // + // if(enrich && this.store){ + // + // return apply_enrich.call(this, intersect(result, limit)); + // } + // + // return intersect(result, limit); + // } + + if(pluck && (!enrich || !this.store)){ + + // fast path optimization + + return result[0]; + } + + for(let i = 0, res, key; i < field.length; i++){ + + key = field[i]; + res = result[i]; + + if(enrich && this.store){ + + res = apply_enrich.call(this, res); + } + + if(pluck){ + + return res; + } + + result[i] = { + + "field": key, + "result": res + }; + } + + return result; +}; + +/** + * @this Document + */ + +function apply_enrich(res){ + + const arr = new Array(res.length); + + for(let x = 0, id; x < res.length; x++){ + + id = res[x]; + + arr[x] = { + + "key": id, + "doc": this.store[id] + }; + } + + return arr; +} + +Document.prototype.get = function(id){ + + return this.store[id]; +}; + +Document.prototype.set = function(id, data){ + + this.store[id] = data; + return this; +}; + +Document.prototype.contain = function(id){ + + return !!this.register[id]; +}; + +if(SUPPORT_CACHE){ + + Document.prototype.searchCache = searchCache; +} + +if(SUPPORT_ASYNC){ + + Document.prototype.addAsync = addAsync; + Document.prototype.appendAsync = appendAsync; + Document.prototype.searchAsync = searchAsync; + Document.prototype.updateAsync = updateAsync; + Document.prototype.removeAsync = removeAsync; +} \ No newline at end of file diff --git a/src/engine.js b/src/engine.js new file mode 100644 index 0000000..933e263 --- /dev/null +++ b/src/engine.js @@ -0,0 +1,48 @@ +import { addAsync, appendAsync, removeAsync, searchAsync, updateAsync } from "./async.js"; +import Document from "./document"; +import { DEBUG, SUPPORT_ASYNC, SUPPORT_CACHE } from "./config"; +import { searchCache } from "./cache"; + +/** + * @constructor + * @abstract + */ + +function Engine(index){ + + if(DEBUG){ + + if(this.constructor === Engine){ + + throw new Error("Can't instantiate abstract class!"); + } + } + + if(SUPPORT_CACHE){ + + index.prototype.searchCache = searchCache; + } + + if(SUPPORT_ASYNC){ + + index.prototype.addAsync = addAsync; + index.prototype.appendAsync = appendAsync; + index.prototype.searchAsync = searchAsync; + index.prototype.updateAsync = updateAsync; + index.prototype.removeAsync = removeAsync; + } +} + +if(SUPPORT_CACHE){ + + Engine.prototype.searchCache = searchCache; +} + +if(SUPPORT_ASYNC){ + + Engine.prototype.addAsync = addAsync; + Engine.prototype.appendAsync = appendAsync; + Engine.prototype.searchAsync = searchAsync; + Engine.prototype.updateAsync = updateAsync; + Engine.prototype.removeAsync = removeAsync; +} \ No newline at end of file diff --git a/src/export.js b/src/export.js deleted file mode 100644 index 3d001f4..0000000 --- a/src/export.js +++ /dev/null @@ -1,33 +0,0 @@ -import FlexSearch from "./flexsearch.js"; - -/** @export */ -FlexSearch.prototype.init; -/** @export */ -FlexSearch.prototype.search; -/** @export */ -FlexSearch.prototype.add; -/** @export */ -FlexSearch.prototype.update; -/** @export */ -FlexSearch.prototype.remove; -/** @export */ -FlexSearch.prototype.find; -/** @export */ -FlexSearch.prototype.where; -/** @export */ -FlexSearch.prototype.info; -/** @export */ -FlexSearch.prototype.clear; -/** @export */ -FlexSearch.prototype.destroy; -/** @export */ -FlexSearch.prototype.export; -/** @export */ -FlexSearch.prototype.import; -/** @export */ -//FlexSearch.encode; -/** @export */ -//FlexSearch.prototype.addMatcher; - -/** @export */ -Promise.prototype.then; diff --git a/src/flexsearch.js b/src/flexsearch.js deleted file mode 100644 index 62f6be7..0000000 --- a/src/flexsearch.js +++ /dev/null @@ -1,2569 +0,0 @@ -/**! - * FlexSearch.js - * Copyright 2019 Nextapps GmbH - * Author: Thomas Wilkerling - * Licence: Apache-2.0 - * https://github.com/nextapps-de/flexsearch - */ - -"use strict"; - -import "./serialize.js"; -import "./where.js"; -import Cache from "./cache.js"; -import Worker from "./worker.js"; -import presets from "./presets.js"; -//import { profile_start, profile_end } from "./profiler.js"; -import { encode as default_encoder } from "./lang/latin/default.js"; // , split as default_split -import { addWorker } from "./worker.js"; -import { - is_undefined, - is_string, - is_array, - is_function, - is_object, - get_keys, - create_object, - create_object_array, - //replace, - regex -} from "./common.js"; - -let id_counter = 0; -export const global_lang = {}; -export const global_charset = {}; - -/** - * TODO: inlining them - * @const - * @enum {boolean|string|number|RegExp|Function} - */ - -// const defaults = { -// -// "encode": default_encoder, -// "tokenize": "strict", -// // split: default_split, -// // enrich: true, -// // clone: false, -// // suggest: false, -// "cache": false, -// "async": false, -// "worker": false, -// "rtl": false, -// "doc": false, -// -// // maximum scoring -// "resolution": 9, -// -// // minimum scoring -// "threshold": 0, -// -// // contextual depth -// "depth": 0 -// }; - -/** - * NOTE: Actually not really required when using bare objects via: Object.create(null) - * @const {Object} - */ - -// const index_blacklist = (function(){ -// const array = Object.getOwnPropertyNames(/** @type {!Array} */ (({}).__proto__)); -// const map = create_object(); -// for(let i = 0; i < array.length; i++) map[array[i]] = 1; -// return map; -// }()); - -/** - * @param {string|Object=} options - * @constructor - */ - -export default function FlexSearch(options){ - - // if(PROFILER){ - // - // profile = profiles[id_counter] || (profiles[id_counter] = {}); - // - // /** @export */ - // this.stats = profile; - // } - - if(!(this instanceof FlexSearch)) { - - return new FlexSearch(options); - } - - const id = options && options["id"]; - - /** @export */ - this.id = id || (id === 0) ? id : id_counter++; - - this.init(options); - - register_property(this, "index", /** @this {FlexSearch} */ function(){ - - if(SUPPORT_DOCUMENT && this.doc){ - - return get_keys(this.doc.index[this.doc.keys[0]]._ids); - } - - return get_keys(this._ids); - }); - - register_property(this, "length", /** @this {FlexSearch} */ function(){ - - return this["index"].length; - }); -} - -/** - * @param {Object} matcher - */ - -// FlexSearch["registerMatcher"] = function(matcher){ -// -// for(const key in matcher){ -// -// if(matcher.hasOwnProperty(key)){ -// -// this.matcher.push(regex(key), matcher[key]); -// } -// } -// -// return FlexSearch; -// }; - -/** - * @param {!string} name - * @param {Object} charset - */ - -FlexSearch["registerCharset"] = function(name, charset){ - - global_charset[name] = charset; - - return FlexSearch; -}; - -/** - * @param {!string} name - * @param {Object} lang - */ - -FlexSearch["registerLanguage"] = function(name, lang){ - - global_lang[name] = lang; - - return FlexSearch; -}; - -/** - * @param {string} name - * @param {number|string} value - * @returns {string} - */ - -// FlexSearch["encode"] = function(name, value){ -// -// return global_encoder[name](value); -// }; - -/* -const tag_options = { - - "encode": false, - "tokenize": function(doc){ - return [doc]; - } -}; -*/ - -/** - * @param {Object|string=} options - */ - -FlexSearch.prototype.init = function(options){ - - /** - * @type {Array} - * @private - */ - - let custom; - let doc; - - if(SUPPORT_PRESET && options){ - - if(is_string(options)){ - - if(DEBUG && !presets[options]){ - - console.warn("Preset not found: " + options); - } - - options = presets[options]; - } - else if((custom = options["preset"])){ - - if(DEBUG && !presets[custom]){ - - console.warn("Preset not found: " + custom); - } - - options = Object.assign({}, presets[custom], /** @type {Object} */ (options)); - } - } - - options || (options = {}); - - // TODO reset state and rebuild index - - // if(this.encode){ - // - // } - - // if(!this.encode){ - // - // if(options){ - // - // options = Object.assign({}, defaults, /** @type {Object} */ (options)); - // } - // else{ - // - // options = defaults; - // } - // } - - //if(options){ - - // initialize worker - - if(SUPPORT_WORKER && (custom = options["worker"])){ - - if(typeof Worker === "undefined"){ - - options["worker"] = false; - - /** @private */ - this._worker = null; - } - else{ - - const threads = parseInt(custom, 10) || 4; - - /** @private */ - this._current_task = -1; - /** @private */ - this._task_completed = 0; - /** @private */ - this._task_result = []; - /** @private */ - this._current_callback = null; - //this._ids_count = new Array(threads); - /** @private */ - this._worker = new Array(threads); - - for(let i = 0; i < threads; i++){ - - //this._ids_count[i] = 0; - - this._worker[i] = addWorker(this.id, i, options /*|| defaults*/, this.worker_handler); - } - } - - /** @private */ - this.worker = custom; - } - - if(SUPPORT_ASYNC){ - - /** @private */ - this.async = options["async"]; - /** @private */ - this.timer = 0; - } - - let charset = options["charset"]; - let lang = options["lang"]; - - if(is_string(charset)){ - - if(charset.indexOf(":") === -1){ - - charset += ":default"; - } - - charset = global_charset[charset]; - } - - if(is_string(lang)){ - - lang = global_lang[lang]; - } - - /** @private */ - this.tokenizer = custom = (charset && charset.tokenize) || options["tokenize"] || "strict"; - /** @private */ - this.depth = ((custom === "strict") && options["depth"]) || 0; - /** @private */ - this.rtl = (charset && charset.rtl) || options["rtl"] || false; - /** @private */ - this.resolution = options["resolution"] || 9; - /** @private */ - this.threshold = custom = options["threshold"] || 0; - if(this.resolution <= custom) this.resolution = custom + 1; - /** @export */ - this.encode = options["encode"] || (charset && charset.encode) || default_encoder; - /** @private */ - this.matcher = (custom = options["matcher"] || (lang && lang.matcher)) && init_stemmer_or_matcher(custom, false); - /** @private */ - this.stemmer = (custom = options["stemmer"] || (lang && lang.stemmer)) && init_stemmer_or_matcher(custom, true); - /** @private */ - this.filter = (custom = options["filter"] || (lang && lang.filter)) && init_filter(custom); - - // TODO: provide boost - /** @private */ - //this.boost = (custom = options["boost"]) ? custom : 0; - - if(SUPPORT_DOCUMENT){ - - /** @private */ - this.doc = doc = (custom = options["doc"]) && clone_object(custom); - - if(doc){ - - options["doc"] = null; - } - } - //} - - // initialize primary index - - /** @private */ - this._map = create_object_array(this.resolution - this.threshold); - /** @private */ - this._ctx = create_object(); - /** @private */ - this._ids = create_object(); - - if(SUPPORT_DOCUMENT && doc){ - - this._doc = create_object(); - - const index = doc.index = {}; - const keys = doc.keys = []; - - let field = doc["field"]; - let tag = doc["tag"]; - let store = doc["store"]; - - if(!is_array(doc["id"])){ - - doc["id"] = doc["id"].split(":"); - } - - if(store){ - - let store_custom = create_object(); - - if(is_string(store)){ - - store_custom[store] = 1; - } - else if(is_array(store)){ - - for(let i = 0; i < store.length; i++){ - - store_custom[store[i]] = 1; - } - } - else if(is_object(store)){ - - store_custom = store; - } - - doc["store"] = store_custom; - } - - if(SUPPORT_WHERE && tag){ - - this._tag = create_object(); - - let field_custom = create_object(); - - if(field){ - - if(is_string(field)){ - - field_custom[field] = options; - } - else if(is_array(field)){ - - for(let i = 0; i < field.length; i++){ - - field_custom[field[i]] = options; - } - } - else if(is_object(field)){ - - field_custom = field; - } - } - - if(!is_array(tag)){ - - doc["tag"] = tag = [tag]; - } - - for(let i = 0; i < tag.length; i++){ - - //TODO: delegate tag indexes to intersection - //field_custom[tag[i]] = tag_options; - this._tag[tag[i]] = create_object(); - } - - this._tags = tag; - - field = field_custom; - } - - if(field){ - - let has_custom; - - if(!is_array(field)){ - - if(is_object(field)){ - - has_custom = field; - doc["field"] = field = get_keys(field); - } - else{ - - doc["field"] = field = [field]; - } - } - - for(let i = 0; i < field.length; i++){ - - const ref = field[i]; - - if(!is_array(ref)){ - - if(has_custom){ - - options = has_custom[ref]; - } - - keys[i] = ref; - field[i] = ref.split(":"); - } - - // TODO: move fields to main index to provide pagination - - index[ref] = new FlexSearch(options); - //index[ref]._doc = this._doc; - - // if(SUPPORT_WHERE && tag){ - // - // index[i]._tag = this._tag; - // index[i]._tags = tag; - // } - } - } - - //options["doc"] = custom; - } - - if(SUPPORT_CACHE) { - - /** @private */ - this._cache_status = true; - - /** @private */ - this._cache = (custom = options["cache"]) && new Cache(custom); - } - - return this; -}; - -function clone_object(obj){ - - const clone = create_object(); - - for(const key in obj){ - - if(obj.hasOwnProperty(key)){ - - const value = obj[key]; - - if(is_array(value)){ - - clone[key] = value.slice(0); - } - else if(is_object(value)){ - - clone[key] = clone_object(value); - } - else{ - - clone[key] = value; - } - } - } - - return clone; -} - -/** - * @param {number|string} id - * @param {string|Function} content - * @param {Function=} callback - * @param {boolean=} _skip_update - * @param {boolean=} _recall - * @this {FlexSearch} - */ - -FlexSearch.prototype.add = function(id, content, callback, _skip_update, _recall){ - - if(SUPPORT_DOCUMENT && this.doc && is_object(id)){ - - return this.handle_docs("add", id, /** @type {Function} */ (content)); - } - - if(content && is_string(content) && ((id /*&& !index_blacklist[id]*/) || (id === 0))){ - - //id = "" + id; - - // TODO: do not mix ids as string "1" and as number 1 - - //const index = "" + id; - - if(this._ids[id] && !_skip_update){ - - return this.update(id, content); - } - - // if(SUPPORT_WORKER && this.worker){ - // - // if(++this._current_task >= this._worker.length){ - // - // this._current_task = 0; - // } - // - // this._worker[this._current_task].postMessage({ - // - // "add": true, - // "id": id, - // "content": content - // }); - // - // this._ids[id] = "" + this._current_task; - // - // // TODO: provide worker auto-balancing instead of rotation - // //this._ids_count[this._current_task]++; - // - // if(callback){ - // - // callback(); - // } - // - // return this; - // } - - if(!_recall){ - - if(SUPPORT_ASYNC && this.async && (!SUPPORT_WORKER || (typeof importScripts !== "function"))){ - - let self = this; - - const promise = new Promise(function(resolve){ - - setTimeout(function(){ - - self.add(id, content, null, _skip_update, true); - self = null; - resolve(); - }); - }); - - if(callback){ - - promise.then(callback); - } - else{ - - return promise; - } - - return this; - } - - if(callback){ - - this.add(id, content, null, _skip_update, true); - callback(); - - return this; - } - } - - // if(PROFILER){ - // - // profile_start("add"); - // } - - content = this.encode(/** @type {string} */ (content)); - - if(!content.length){ - - return this; - } - - const words = content; //this.tokenize(content); - const dupes = create_object(); - dupes["_ctx"] = create_object(); - - const word_length = words.length; - const threshold = this.threshold; - const depth = this.depth; - const resolution = this.resolution; - const map = this._map; - const rtl = this.rtl; - - let has_content; - - // tokenize - - for(let i = 0; i < word_length; i++){ - - /** @type {string} */ - const value = words[i]; - - if(value){ - - has_content = 1; - - const length = value.length; - const context_score = (rtl ? i + 1 : word_length - i) / word_length; - - let token = ""; - - switch(this.tokenizer){ - - case "reverse": - case "both": - - // NOTE: skip last round (this token exist already in "forward") - - for(let a = length; --a;){ - - token = value[a] + token; - - add_index( - - map, - dupes, - token, - id, - rtl ? 1 : (length - a) / length, - context_score, - threshold, - resolution - 1 - ); - } - - token = ""; - - // Note: no break here, fallthrough to next case - - case "forward": - - for(let a = 0; a < length; a++){ - - token += value[a]; - - add_index( - - map, - dupes, - token, - id, - rtl ? (a + 1) / length : 1, - context_score, - threshold, - resolution - 1 - ); - } - - break; - - case "full": - - for(let x = 0; x < length; x++){ - - const partial_score = (rtl ? x + 1 : length - x) / length; - - for(let y = length; y > x; y--){ - - token = value.substring(x, y); - - add_index( - - map, - dupes, - token, - id, - partial_score, - context_score, - threshold, - resolution - 1 - ); - } - } - - break; - - //case "strict": - //case "ngram": - default: - - const score = add_index( - - map, - dupes, - value, - id, - // Note: ngrams has partial scoring (sequence->word) and contextual scoring (word->context) - // TODO compute and pass distance of ngram sequences as the initial score for each word - 1, - context_score, - threshold, - resolution - 1 - ); - - if(depth && (word_length > 1) && (score >= threshold)){ - - const ctxDupes = dupes["_ctx"][value] || (dupes["_ctx"][value] = create_object()); - const ctxTmp = this._ctx[value] || (this._ctx[value] = create_object_array(resolution - (threshold || 0))); - - let x = i - depth; - let y = i + depth + 1; - - if(x < 0) x = 0; - if(y > word_length) y = word_length; - - for(; x < y; x++){ - - if(x !== i) add_index( - - ctxTmp, - ctxDupes, - words[x], - id, - 0, - resolution - (x < i ? i - x : x - i), - threshold, - resolution - 1 - ); - } - } - - break; - } - } - } - - if(has_content){ - - // update status - - this._ids[id] = 1; - } - - if(SUPPORT_CACHE){ - - this._cache_status = false; - } - - // if(PROFILER){ - // - // profile_end("add"); - // } - } - - return this; -}; - -if(SUPPORT_DOCUMENT){ - - /** - * @param {!string} job - * @param doc - * @param {Function|boolean=} callback - * @returns {*} - */ - - FlexSearch.prototype.handle_docs = function(job, doc, callback){ - - if(is_array(doc)){ - - let len = doc.length; - - if(len){ - - for(let i = 0; i < len; i++){ - - this.handle_docs(job, doc[i], (i === len - 1) && callback); - } - - //return this.handle_docs(job, doc[len], callback); - } - } - else{ - - const index = this.doc.index; - const keys = this.doc.keys; - const tags = this.doc["tag"]; - const store = this.doc["store"]; - - let tree; - let tag; - - // --------------------------------------------------------------- - - tree = this.doc["id"]; - - let id = doc; - - for(let i = 0; i < tree.length; i++){ - - id = id[tree[i]]; - } - - // --------------------------------------------------------------- - - if(job === "remove"){ - - delete this._doc[id]; - - let len = keys.length; - - if(len){ - - for(let i = 0; i < len; i++){ - - index[keys[i]].remove(id, (i === len - 1) && callback); - } - - //return index[keys[len]].remove(id, callback); - } - } - - // --------------------------------------------------------------- - - else{ - - if(tags){ - - let tag_key; - let tag_value; - - for(let i = 0; i < tags.length; i++){ - - tag_key = tags[i]; - tag_value = doc; - - const tag_split = tag_key.split(":"); - - for(let a = 0; a < tag_split.length; a++){ - - tag_value = tag_value[tag_split[a]]; - } - - tag_value = "@" + tag_value; - } - - tag = this._tag[tag_key]; - tag = tag[tag_value] || (tag[tag_value] = []); - } - - // --------------------------------------------------------------- - - tree = this.doc["field"]; - - for(let i = 0, len = tree.length; i < len; i++){ - - const branch = tree[i]; - let content = doc; - - for(let x = 0; x < branch.length; x++){ - - content = content[branch[x]]; - } - - const self = index[keys[i]]; - - if(job === "add"){ - - self.add(id, content, (i === (len - 1)) && callback); - } - else{ - - self.update(id, content, (i === (len - 1)) && callback); - } - } - - // --------------------------------------------------------------- - - if(store){ - - const store_keys = get_keys(store); - let store_doc = create_object(); - - for(let i = 0; i < store_keys.length; i++){ - - let store_key = store_keys[i]; - - if(store[store_key]){ - - const store_split = store_key.split(":"); - - let store_value; - let store_doc_value; - - for(let a = 0; a < store_split.length; a++){ - - const store_split_key = store_split[a]; - - store_value = (store_value || doc)[store_split_key]; - store_doc_value = (store_doc_value || store_doc)[store_split_key] = store_value; - } - } - } - - doc = store_doc; - } - - // --------------------------------------------------------------- - - if(tag){ - - tag[tag.length] = doc; // tag[tag.length] = id; - } - - this._doc[id] = doc; - } - } - - return this; - }; -} - -/** - * @param {number|string} id - * @param {string|Function} content - * @param {Function=} callback - */ - -FlexSearch.prototype.update = function(id, content, callback){ - - if(SUPPORT_DOCUMENT && this.doc && is_object(id)){ - - return this.handle_docs("update", id, /** @type {Function} */ (content)); - } - - if(this._ids[id] && is_string(content)){ - - // if(PROFILER){ - // - // profile_start("update"); - // } - - this.remove(id); - this.add(id, content, callback, /* skip_update: */ true); - - // if(PROFILER){ - // - // profile_end("update"); - // } - } - - return this; -}; - -/** - * @param {number|string} id - * @param {Function=} callback - * @param {boolean=} _recall - */ - -FlexSearch.prototype.remove = function(id, callback, _recall){ - - if(SUPPORT_DOCUMENT && this.doc && is_object(id)){ - - return this.handle_docs("remove", id, callback); - } - - const index = id; - - if(this._ids[index]){ - - // if(SUPPORT_WORKER && this.worker){ - // - // const current_task = this._ids[index]; - // - // this._worker[current_task].postMessage({ - // - // "remove": true, - // "id": id - // }); - // - // //this._ids_count[current_task]--; - // - // delete this._ids[index]; - // - // if(callback){ - // - // callback(); - // } - // - // return this; - // } - - if(!_recall){ - - if(SUPPORT_ASYNC && this.async && (typeof importScripts !== "function")){ - - let self = this; - - const promise = new Promise(function(resolve){ - - setTimeout(function(){ - - self.remove(id, null, true); - self = null; - resolve(); - }); - }); - - if(callback){ - - promise.then(callback); - } - else{ - - return promise; - } - - return this; - } - - if(callback){ - - this.remove(id, null, true); - callback(); - - return this; - } - } - - // if(PROFILER){ - // - // profile_start("remove"); - // } - - for(let z = 0; z < (this.resolution - (this.threshold || 0)); z++){ - - remove_index(this._map[z], id); - } - - if(this.depth){ - - remove_index(this._ctx, id); - } - - delete this._ids[index]; - - if(SUPPORT_CACHE){ - - this._cache_status = false; - } - - // if(PROFILER){ - // - // profile_end("remove"); - // } - } - - return this; -}; - -let field_to_sort; - -function enrich_documents(arr, docs){ - - const length = arr.length; - const result = new Array(length); - - for(let i = 0; i < length; i++){ - - result[i] = docs[arr[i]]; - } - - return result; -} - -FlexSearch.prototype.merge_and_sort = function(query, bool, result, sort, limit, suggest, where, cursor, has_and, has_not){ - - result = intersect( - - result, - where ? 0 : limit, - SUPPORT_PAGINATION && cursor, - SUPPORT_SUGGESTION && suggest, - bool, - has_and, - has_not - ); - - let next; - - if(cursor){ - - cursor = result.page; - next = result.next; - result = result.result; - } - - if(where){ - - result = this.where(where, null, limit, result); - } - else{ - - // TODO apply during last round of intersection - result = enrich_documents(result, this._doc); - } - - // custom sort replaces the default sort by relevance - - if(sort){ - - if(!is_function(sort)){ - - field_to_sort = sort.split(":"); - - if(field_to_sort.length > 1){ - - sort = sort_by_deep_field_up; - } - else{ - - //field_to_sort = field_to_sort[0]; - sort = sort_by_field_up; - } - } - - result.sort(sort); - } - - result = create_page(cursor, next, result); - - if(SUPPORT_CACHE && this._cache){ - - this._cache.set(query, result); - } - - return result; -}; - -/** - * TODO: move fields to main index to provide pagination - * - * @param {!string|Object|Array} query - * @param {number|Function=} limit - * @param {Function=} callback - * @param {boolean=} _recall - * @returns {FlexSearch|Array|Promise|undefined} - */ - -FlexSearch.prototype.search = function(query, limit, callback, _recall){ - - if(SUPPORT_DOCUMENT && is_object(limit)){ - - if(is_array(limit)){ - - for(let i = 0; i < limit.length; i++){ - - limit[i]["query"] = query; - } - } - else{ - - limit["query"] = query; - } - - query = /** @type {Object} */ (limit); - limit = 1000; - } - else if(limit && is_function(limit)){ - - callback = /** @type {?Function} */ (limit); - limit = 1000; - } - else{ - - limit || (limit === 0 ) || (limit = 1000); - } - - // if(SUPPORT_WORKER && this.worker){ - // - // this._current_callback = callback; - // this._task_completed = 0; - // this._task_result = []; - // - // for(let i = 0; i < this.worker; i++){ - // - // this._worker[i].postMessage({ - // - // "search": true, - // "limit": limit, - // "content": query - // }); - // } - // - // return; - // } - - let result = []; - let _query = query; - let threshold; - let cursor; - let sort; - let suggest; - - if(is_object(query) && (!SUPPORT_DOCUMENT || !is_array(query))){ - - // re-assign properties - - if(SUPPORT_ASYNC){ - - if(!callback){ - - callback = query["callback"]; - - if(callback){ - - _query["callback"] = null; - } - } - } - - sort = SUPPORT_DOCUMENT && query["sort"]; - cursor = SUPPORT_PAGINATION && query["page"]; - limit = query["limit"]; - threshold = query["threshold"]; - suggest = SUPPORT_SUGGESTION && query["suggest"]; - query = query["query"]; - } - - if(SUPPORT_DOCUMENT && this.doc){ - - const doc_idx = this.doc.index; - const where = SUPPORT_WHERE && _query["where"]; - const bool_main = (SUPPORT_OPERATOR && _query["bool"]) || "or"; - let field = _query["field"]; - let bool = bool_main; - let queries; - let has_not; - let has_and; - - if(field){ - - if(!is_array(field)){ - - field = [field]; - } - } - else if(is_array(_query)){ - - queries = _query; - field = []; - bool = []; - - // TODO: make some unit tests and check if the fields should be sorted (not > and > or)? - - for(let i = 0; i < _query.length; i++){ - - const current = _query[i]; - const current_bool = (SUPPORT_OPERATOR && current["bool"]) || bool_main; - - field[i] = current["field"]; - bool[i] = current_bool; - - if(current_bool === "not"){ - - has_not = true; - } - else if(current_bool === "and"){ - - has_and = true; - } - } - } - else{ - - field = this.doc.keys; - } - - const len = field.length; - - for(let i = 0; i < len; i++){ - - if(queries){ - - _query = queries[i]; - } - - if(cursor && !is_string(_query)){ - - _query["page"] = null; - _query["limit"] = 0; - } - - result[i] = doc_idx[field[i]].search(_query, 0); - } - - if(callback){ - - return callback( - - this.merge_and_sort( - query, - bool, - result, - sort, - limit, - suggest, - where, - cursor, - has_and, - has_not - ) - ); - } - else if(SUPPORT_ASYNC && this.async){ - - const self = this; - - return new Promise(function(resolve){ - - Promise.all(/** @type {!Iterable} */ (result)).then(function(values){ - - resolve( - - self.merge_and_sort( - query, - bool, - values, - sort, - limit, - suggest, - where, - cursor, - has_and, - has_not - ) - ); - }); - }); - } - else{ - - return this.merge_and_sort( - query, - bool, - result, - sort, - limit, - suggest, - where, - cursor, - has_and, - has_not - ); - } - } - - threshold || (threshold = this.threshold || 0); - - if(!_recall){ - - if(SUPPORT_ASYNC && this.async && (typeof importScripts !== "function")){ - - let self = this; - - const promise = new Promise(function(resolve){ - - setTimeout(function(){ - - resolve(self.search(_query, limit, null, true)); - self = null; - }); - }); - - if(callback){ - - promise.then(callback); - } - else{ - - return promise; - } - - return this; - } - - if(callback){ - - callback(this.search(_query, limit, null, true)); - - return this; - } - } - - // if(PROFILER){ - // - // profile_start("search"); - // } - - if(!query || !is_string(query)){ - - return result; - } - - /** @type {!string|Array} */ - (_query = query); - - if(SUPPORT_CACHE && this._cache){ - - // invalidate cache - - if(this._cache_status){ - - const cache = this._cache.get(query); - - if(cache){ - - return cache; - } - } - - // validate cache - - else { - - this._cache.clear(); - this._cache_status = true; - } - } - - // encode string - - _query = this.encode(/** @type {string} */ (_query)); - - if(!_query.length){ - - return result; - } - - const words = _query; //this.tokenize(_query); - const length = words.length; - let found = true; - const check = []; - const check_words = create_object(); - - let ctx_root; - let use_contextual; - let a = 0; - - if(length > 1){ - - if(this.depth /*&& (this.tokenizer === "strict")*/){ - - use_contextual = true; - } - else{ - - // Note: sort words by length only in non-contextual mode - words.sort(sort_by_length_down); - } - } - - /* - if(SUPPORT_WHERE && where){ - - const tags = this._tags; - - if(tags){ - - for(let i = 0; i < tags.length; i++){ - - const current_tag = tags[i]; - const current_where = where[current_tag]; - - if(!is_undefined(current_where)){ - - check[check.length] = this._tag[current_tag]["@" + current_where]; - - delete where[current_tag]; - } - } - - if(get_keys(where).length === 0){ - - where = false; - } - } - } - */ - - let ctx_map; - - if(!use_contextual || (ctx_map = this._ctx)){ - - const resolution = this.resolution; - - // TODO: boost on custom search is actually not possible, move to adding index instead - // if(SUPPORT_DOCUMENT && boost){ - // - // threshold = (threshold || 1) / boost; - // } - - for(; a < length; 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 = []; - let map_found = false; - let count = 0; - - const map = use_contextual ? - - ctx_map[ctx_root] - : - this._map; - - if(map){ - - let map_value; - - for(let z = 0; z < (resolution - threshold); z++){ - - if((map_value = (map[z] && map[z][value]))){ - - map_check[count++] = map_value; - map_found = true; - } - } - } - - if(map_found){ - - ctx_root = value; - - // not handled by intersection: - - check[check.length] = ( - - count > 1 ? - - map_check.concat.apply([], map_check) - : - map_check[0] - ); - - // handled by intersection: - // check[check.length] = map_check; - } - else if(!SUPPORT_SUGGESTION || !suggest){ - - found = false; - break; - } - - check_words[value] = 1; - } - } - } - } - else{ - - found = false; - } - - if(found){ - - // Not handled by intersection: - result = /** @type {Array} */ (intersect(check, limit, cursor, SUPPORT_SUGGESTION && suggest)); - - // Handled by intersection: - //result = intersect_3d(check, limit, suggest); - } - - // store result to cache - - if(SUPPORT_CACHE && this._cache){ - - this._cache.set(query, result); - } - - // if(PROFILER){ - // - // profile_end("search"); - // } - - return result; -}; - -if(SUPPORT_INFO){ - - FlexSearch.prototype.info = function(){ - - // if(SUPPORT_WORKER && this.worker){ - // - // for(let i = 0; i < this.worker; i++) this._worker[i].postMessage({ - // - // "info": true, - // "id": this.id - // }); - // - // return; - // } - - // TODO: improve info - /* - let keys; - let length; - - let bytes = 0, - words = 0, - chars = 0; - - for(let z = 0; z < (this.resolution - (this.threshold || 0)); z++){ - - keys = get_keys(this._map[z]); - - for(let i = 0; i < keys.length; i++){ - - length = this._map[z][keys[i]].length; - - // TODO: Proof if 1 char values allocates 1 byte "Map (OneByteInternalizedString)" - bytes += length * 1 + keys[i].length * 2 + 4; - words += length; - chars += keys[i].length * 2; - } - } - - keys = get_keys(this._ids); - - const items = keys.length; - - for(let i = 0; i < items; i++){ - - bytes += keys[i].length * 2 + 2; - } - */ - - return { - - "id": this.id, - //"memory": bytes, - "items": this["length"], //items, - //"sequences": words, - //"chars": chars, - //"cache": this.cache && this.cache.ids ? this.cache.ids.length : false, - "matcher": this.matcher.length, - "worker": this.worker, - "threshold": this.threshold, - "depth": this.depth, - "resolution": this.resolution, - "contextual": this.depth && (this.tokenizer === "strict") - }; - }; -} - -FlexSearch.prototype.clear = function(){ - - return this.destroy().init(); -}; - -FlexSearch.prototype.destroy = function(){ - - if(SUPPORT_CACHE && this._cache){ - - this._cache.clear(); - this._cache = null; - } - - this._map = - this._ctx = - this._ids = null; - - if(SUPPORT_DOCUMENT && this.doc){ - - const keys = this.doc.keys; - - for(let i = 0; i < keys.length; i++){ - - this.doc.index[keys[i]].destroy(); - } - - this.doc = - this._doc = null; - } - - return this; -}; - -// --------------------------------------------------------- -// Helpers - -function register_property(obj, key, fn){ - - // define functional properties - - Object.defineProperty(obj, key, { - - get: fn - }); -} - -/** - * @param {Array} map - * @param {Object} dupes - * @param {string} value - * @param {string|number} id - * @param {number} partial_score - * @param {number} context_score - * @param {number} threshold - * @param {number} resolution - */ - -function add_index(map, dupes, value, id, partial_score, context_score, threshold, resolution){ - - /* - if(index_blacklist[value]){ - - return 0; - } - */ - - if(dupes[value]){ - - return dupes[value]; - } - - const score = ( - - partial_score ? - - (resolution - (threshold || (resolution / 1.5))) * context_score + (threshold || (resolution / 1.5)) * partial_score - //(9 - (threshold || 4.5)) * context_score + (threshold || 4.5) * partial_score - //4.5 * (context_score + partial_score) - : - context_score - ); - - dupes[value] = score; - - if(score >= threshold){ - - let arr = map[resolution - ((score + 0.5) >> 0)]; - arr = arr[value] || (arr[value] = []); - - arr[arr.length] = id; - } - - return score; -} - -/** - * @param {Object} map - * @param {string|number} id - */ - -function remove_index(map, id){ - - if(map){ - - const keys = get_keys(map); - - for(let i = 0, lengthKeys = keys.length; i < lengthKeys; i++){ - - const key = keys[i]; - const tmp = map[key]; - - if(tmp){ - - for(let a = 0, lengthMap = tmp.length; a < lengthMap; a++){ - - if(tmp[a] === id){ - - if(lengthMap === 1){ - - delete map[key]; - } - else{ - - tmp.splice(a, 1); - } - - break; - } - else if(is_object(tmp[a])){ - - remove_index(tmp[a], id); - } - } - } - } - } -} - -// FlexSearch.prototype.encode = function(value){ -// -// // if(PROFILER){ -// // -// // profile_start("encode"); -// // } -// -// // if(value && this.normalize){ -// // -// // value = this.normalize(value); -// // } -// // -// // if(value && this.matcher){ -// // -// // value = replace(value, this.matcher); -// // } -// // -// // if(value && this.stemmer){ -// // -// // value = replace(value, this.stemmer); -// // } -// -// if(value && this.encoder){ -// -// value = this.encoder(value); -// } -// -// // if(value && this.split){ -// // -// // value = value.split(this.split); -// // } -// // -// // if(this.filter){ -// // -// // value = filter_words(value, this.filter); -// // } -// -// // if(PROFILER){ -// // -// // profile_end("encode"); -// // } -// -// return value; -// }; - -// FlexSearch.prototype.tokenize = function(content){ -// -// let words = ( -// -// this.split ? -// -// content.split(this.split) -// : -// content -// ); -// -// if(this.filter){ -// -// words = filter_words(words, this.filter); -// } -// -// return words; -// }; - -// TODO using fast-swap -// function filter_words(words, fn_or_map){ -// -// const length = words.length; -// const filtered = []; -// -// for(let i = 0, count = 0; i < length; i++){ -// -// const word = words[i]; -// -// if(word){ -// -// if(!fn_or_map[word]){ -// -// filtered[count++] = word; -// } -// } -// } -// -// return filtered; -// } - -/** - * @param {Array} words - * @returns {Object} - */ - -function init_filter(words){ - - const filter = create_object(); - - for(let i = 0, length = words.length; i < length; i++){ - - filter[words[i]] = 1; - } - - return filter; -} - -/** - * @param {!Object} obj - * @param {boolean} is_stemmer - * @returns {Array} - */ - -function init_stemmer_or_matcher(obj, is_stemmer){ - - const keys = get_keys(obj); - const length = keys.length; - const final = []; - - let removal = "", count = 0; - - for(let i = 0, tmp; i < length; i++){ - - const key = keys[i]; - - if((tmp = obj[key])){ - - final[count++] = regex(is_stemmer ? "(?!\\b)" + key + "(\\b|_)" : key); - final[count++] = tmp; - } - else{ - - removal += (removal ? "|" : "") + key; - } - } - - if(removal){ - - final[count++] = regex(is_stemmer ? "(?!\\b)(" + removal + ")(\\b|_)" : "(" + removal + ")"); - final[count] = ""; - } - - return final; -} - -/* -function sort_by_length_up(a, b){ - - return a.length - b.length; -} -*/ - -function sort_by_length_down(a, b){ - - return b.length - a.length; -} - -function sort_by_field_up(a, b){ - - a = a[field_to_sort]; - b = b[field_to_sort]; - - return a < b ? - 1 : (a > b ? 1 : 0); -} - -function sort_by_deep_field_up(a, b){ - - const field_len = field_to_sort.length; - - for(let i = 0; i < field_len; i++){ - - a = a[field_to_sort[i]]; - b = b[field_to_sort[i]]; - } - - return a < b ? - 1 : (a > b ? 1 : 0); -} - -function create_page(cursor, page, result){ - - return cursor ? { - - "page": cursor, - "next": page ? "" + page : null, - "result": result - - } : result; -} - -/** - * This is the main hot spot. - * Any possible performance improvements should be applied here. - * TODO: Do not return the original array as reference! - * TODO: Make use of performance benefits of a cursor when no "and" operator was used - * - * @param {!Array>} arrays* - * @param {number=} limit - * @param {string|boolean=} cursor - * @param {boolean=} suggest - * @param {Array=} bool - * @param {boolean=} has_and - * @param {boolean=} has_not - * @returns {Array|Object} - */ - -function intersect(arrays, limit, cursor, suggest, bool, has_and, has_not) { - - let page; - let result = []; - let pointer; - - if(cursor === true){ - - cursor = "0"; - pointer = ""; - } - else{ - - pointer = cursor && cursor.split(":"); - } - - const length_z = arrays.length; - - // use complex handler when length > 1 - - if(length_z > 1){ - - // TODO: test strategy - // pre-sort arrays - //arrays.sort(sort_by_length_down); - - const check = create_object(); - const suggestions = []; - - let check_not; - let arr; - let z = 0; - let i = 0; - let length; - let tmp; - let init = true; - let first_result; - let count = 0; - let bool_main; - let last_index; - - let pointer_suggest; - let pointer_count; - - if(pointer){ - - if(pointer.length === 2){ - - pointer_suggest = pointer; - pointer = false; - } - else{ - - pointer = pointer_count = parseInt(pointer[0], 10); - } - } - - if(SUPPORT_DOCUMENT && SUPPORT_OPERATOR){ - - // there are two possible strategies: 1. pre-fill (actually), 2. filter during last round - // TODO: compare both strategies - - if(has_not){ - - check_not = create_object(); - - for(; z < length_z; z++){ - - if(bool[z] === "not"){ - - arr = arrays[z]; - length = arr.length; - - for(i = 0; i < length; i++){ - - check_not["@" + arr[i]] = 1; - } - } - else{ - - // this additional loop provides a proofed last result - // TODO: could be handled before intersection, or use sorted fields - - last_index = z + 1; - } - } - - // there was no field with "and" / "or" - // TODO: this could also checked before intersection - - if(is_undefined(last_index)){ - - return create_page(cursor, page, result); - } - - z = 0; - } - else{ - - bool_main = is_string(bool) && bool; - } - } - - let bool_and; - let bool_or; - - // loop through arrays - - for(; z < length_z; z++){ - - const is_final_loop = ( - - z === (last_index || length_z) - 1 - ); - - if(SUPPORT_DOCUMENT && SUPPORT_OPERATOR){ - - if(!bool_main || !z){ - - const bool_current = bool_main || (bool && bool[z]); - - if(!bool_current || (bool_current === "and")){ - - bool_and = has_and = true; - bool_or = false; - } - else if(bool_current === "or"){ - - bool_or = true; - bool_and = false; - } - else{ - - // already done, go next - - continue; - } - } - } - else{ - - bool_and = has_and = true; - } - - arr = arrays[z]; - length = arr.length; - - if(!length){ - - // return empty on specific conditions - - if(bool_and && !suggest){ - - return create_page(cursor, page, arr); - } - - continue; - } - - if(init){ - - // pre-fill first just right before an additional result - - if(first_result){ - - const result_length = first_result.length; - - // fill initial map - - for(i = 0; i < result_length; i++){ - - const id = first_result[i]; - const index = "@" + id; - - // there is no and, add items - - if(!has_not || !check_not[index]){ - - check[index] = 1; - - if(!has_and){ - - result[count++] = id; - } - } - } - - first_result = null; - init = false; - } - else{ - - // hold first result and wait for additional result - - first_result = arr; - - continue; - } - } - - let found = false; - - for(i = 0; i < length; i++){ - - tmp = arr[i]; - - const index = "@" + tmp; - const check_val = has_and ? check[index] || 0 : z; - - if(check_val || suggest){ - - if(has_not && check_not[index]){ - - continue; - } - - if(!has_and && check[index]){ - - continue; - } - - if(check_val === z){ - - // fill in during last round - - if(is_final_loop){ - - // sadly the pointer could just applied here at the earliest - // that's why pagination cannot reduce complexity actually - // should only happened when at least one bool "and" was set - // TODO: check bool and provide complexity reduction - - if(!pointer_count || (--pointer_count < count)){ - - result[count++] = tmp; - - if(limit && (count === limit)){ - - return create_page(cursor, count + (pointer || 0), result); - } - } - } - else{ - - check[index] = z + 1; - } - - found = true; - } - else if(suggest){ - - const current_suggestion = ( - - suggestions[check_val] || ( - - suggestions[check_val] = [] - ) - ); - - current_suggestion[current_suggestion.length] = tmp; - } - } - } - - // nothing found, break the main loop - - if(bool_and && !found && !suggest){ - - break; - } - } - - // a first result was hold - - if(first_result){ - - const result_length = first_result.length; - - if(has_not){ - - if(pointer){ - - i = parseInt(pointer, 10); - } - else{ - - i = 0; - } - - for(; i < result_length; i++){ - - const id = first_result[i]; - - if(!check_not["@" + id]){ - - result[count++] = id; - - // TODO: is actually not covered - // if(limit && (count === limit)){ - // - // return create_page(cursor, (i + 1), result); - // } - } - } - } - else{ - - result = first_result; - } - } - - if(suggest){ - - count = result.length; - - if(pointer_suggest){ - - z = parseInt(pointer_suggest[0], 10) + 1; - i = parseInt(pointer_suggest[1], 10) + 1; - } - else{ - - z = suggestions.length; - i = 0; - } - - for(; z--;){ - - tmp = suggestions[z]; - - if(tmp){ - - for(length = tmp.length; i < length; i++){ - - const id = tmp[i]; - - if(!has_not || !check_not["@" + id]){ - - result[count++] = id; - - if(limit && (count === limit)){ - - return create_page(cursor, z + ":" + i, result); - } - } - } - - i = 0; - } - } - } - } - else if(length_z){ - - if(!bool || (SUPPORT_OPERATOR && (bool[0] !== "not"))){ - - result = arrays[0]; - - if(pointer){ - - pointer = parseInt(pointer[0], 10); - } - - // TODO: handle references to the original index array - // return result.slice(0); - } - } - - if(limit){ - - const length = result.length; - - if(pointer && (pointer > length)){ - - pointer = 0; - } - - const start = /** @type number */ (pointer) || 0; - page = start + limit; - - if(page < length){ - - result = result.slice(start, page); - } - else { - - page = 0; - - if(start){ - - result = result.slice(start); - } - } - } - - return create_page(cursor, page, result); -} - -/** - * @param {Array>|Array} arrays - * @param {number=} limit - * @param {boolean=} suggest - * @returns {Array} - */ - -/* -function intersect_3d(arrays, limit, suggest) { - - let result = []; - const length_z = arrays.length; - const check = {}; - - if(length_z > 1){ - - // pre-sort arrays by length up - - arrays.sort(sort_by_length_up); - - const arr_tmp = arrays[0]; - - for(let a = 0, len = arr_tmp.length; a < len; a++){ - - // fill initial map - - const arr = arr_tmp[a]; - - for(let i = 0, length = arr.length; i < length; i++) { - - check[arr[i]] = 1; - } - } - - // loop through arrays - - let tmp, count = 0; - let z = 1; - - while(z < length_z){ - - // get each array one by one - - let found = false; - - const arr_tmp = arrays[0]; - - for(let a = 0, len = arr_tmp.length; a < len; a++){ - - const arr = arr_tmp[a]; - - for(let i = 0, length = arr.length; i < length; i++){ - - if((check[tmp = arr[i]]) === z){ - - // fill in during last round - - if(z === (length_z - 1)){ - - result[count++] = tmp; - - if(limit && (count === limit)){ - - found = false; - break; - } - } - - // apply count status - - found = true; - check[tmp] = z + 1; - } - } - } - - if(!found){ - - break; - } - - z++; - } - } - else if(length_z){ - - arrays = arrays[0]; - - result = arrays.length > 1 ? result.concat.apply(result, arrays) : arrays[0]; - - if(limit && (result.length > limit)){ - - // Note: do not touch original array! - - result = result.slice(0, limit); - } - } - - return result; -} -*/ diff --git a/src/global.js b/src/global.js new file mode 100644 index 0000000..9635704 --- /dev/null +++ b/src/global.js @@ -0,0 +1,22 @@ +export const global_lang = {}; +export const global_charset = {}; + +/** + * @param {!string} name + * @param {Object} charset + */ + +export function registerCharset(name, charset){ + + global_charset[name] = charset; +} + +/** + * @param {!string} name + * @param {Object} lang + */ + +export function registerLanguage(name, lang){ + + global_lang[name] = lang; +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..0fb8393 --- /dev/null +++ b/src/index.js @@ -0,0 +1,800 @@ +/**! + * FlexSearch.js + * Copyright 2019 Nextapps GmbH + * Author: Thomas Wilkerling + * Licence: Apache-2.0 + * https://github.com/nextapps-de/flexsearch + */ + +import { SUPPORT_PRESET, SUPPORT_CACHE, SUPPORT_ASYNC, SUPPORT_WORKER } from "./config.js"; +import { encode as default_encoder } from "./lang/latin/default.js"; +import { create_object, create_object_array, concat, sort_by_length_down } from "./common.js"; +import { pipeline, init_stemmer_or_matcher, init_filter } from "./lang.js"; +import { global_lang, global_charset } from "./global.js"; +import { addAsync, appendAsync, removeAsync, searchAsync, updateAsync } from "./async.js"; +import Cache, { searchCache } from "./cache.js"; +import apply_preset from "./presets.js"; +import intersect from "./intersect.js"; + +/** + * @param {Object=} options + * @param {Object=} _register + * @return {Index} + * @constructor + */ + +function Index(options, _register){ + + if(!(this instanceof Index)) { + + return new Index(options); + } + + let charset, lang, tmp; + + if(options){ + + if(SUPPORT_PRESET){ + + options = apply_preset(options); + } + + charset = options["charset"]; + lang = options["lang"]; + + if(typeof charset === "string"){ + + if(charset.indexOf(":") === -1){ + + charset += ":default"; + } + + charset = global_charset[charset]; + } + + if(typeof lang === "string"){ + + lang = global_lang[lang]; + } + } + else{ + + options = {}; + } + + let resolution, threshold, optimize, context = options["context"] || {}; + + this.encode = options["encode"] || (charset && charset.encode) || default_encoder; + this.register = _register || create_object(); + + resolution = options["resolution"] || 9; + threshold = options["threshold"] || 0; + + if(threshold >= resolution){ + + threshold = resolution - 1; + } + + this.resolution = resolution; + this.threshold = threshold; + this.tokenizer = tmp = (charset && charset.tokenize) || options["tokenize"] || "strict"; + this.depth = (tmp === "strict") && context["depth"]; + this.bidirectional = parse_option(context["bidirectional"], true); + this.optimize = optimize = options["optimize"] === "memory"; + this.fastupdate = parse_option(options["fastupdate"], true); + this.minlength = options["minlength"] || 1; + + // when not using the memory strategy the score array should not pre-allocated to its full length + + this.map = optimize ? create_object_array(resolution - threshold) : create_object(); + + resolution = context["resolution"] || resolution; + threshold = context["threshold"] || threshold; + + if(threshold >= resolution){ + + threshold = resolution - 1; + } + + this.resolution_ctx = resolution; + this.threshold_ctx = threshold; + this.ctx = optimize ? create_object_array(resolution - threshold) : create_object(); + this.rtl = (charset && charset.rtl) || options["rtl"]; + this.matcher = (tmp = options["matcher"] || (lang && lang.matcher)) && init_stemmer_or_matcher(tmp, false); + this.stemmer = (tmp = options["stemmer"] || (lang && lang.stemmer)) && init_stemmer_or_matcher(tmp, true); + this.filter = (tmp = options["filter"] || (lang && lang.filter)) && init_filter(tmp); + + if(SUPPORT_CACHE){ + + this.cache = (tmp = options["cache"]) && new Cache(tmp); + } + + if(SUPPORT_WORKER){ + + /** @private */ + this.worker = (tmp = options["worker"]) && new Worker("worker.js", { type: "module" }); + + if(tmp){ + + this.worker.onmessage = function(e){ console.log(e.data) }; + this.worker.postMessage({ task: "register", options: options }); + } + } +} + +export default Index; + +function parse_option(value, default_value){ + + return typeof value !== "undefined" ? value : default_value; +} + +Index.prototype.pipeline = pipeline; + +/** + * @param {!number|string} id + * @param {!string} content + */ + +Index.prototype.append = function(id, content){ + + return this.add(id, content, true); +}; + +/** + * @param {!number|string} id + * @param {!string} content + * @param {boolean=} _append + */ + +Index.prototype.add = function(id, content, _append){ + + if(this.register[id] && !_append){ + + return this.update(id, content); + } + + if(content && (id || (id === 0))){ + + content = this.encode(content); + const length = content.length; + + if(length){ + + const depth = this.depth; + const resolution = this.resolution - this.threshold; + const dupes = create_object(); + // check context dupes to skip all contextual redundancy in the whole document + const dupes_ctx = create_object(); + + for(let i = 0; i < length; i++){ + + let term = content[this.rtl ? length - 1 - i : i]; + let term_length = term.length; + + // skip dupes will break the context chain + if(term && (term_length >= this.minlength) && (depth || !dupes[term])){ + + const score = Math.min((this.resolution / length * i) | 0, i); + + if(score < resolution){ + + let token = ""; + + switch(this.tokenizer){ + + case "full": + + if(term_length > 3){ + + for(let x = 0; x < term_length; x++){ + + const partial_score = x ? Math.min((score / 2 + this.resolution / term_length * x / 2) | 0, score + x) : score; + + if(partial_score < resolution){ + + for(let y = term_length; y > x; y--){ + + token = term.substring(x, y); + + if(token.length >= this.minlength){ + + this.push_index(dupes, token, partial_score, id, _append); + } + } + } + } + + break; + } + + // fallthrough to next case when term length < 4 + + case "reverse": + + // skip last round (this token exist already in "forward") + + if(term_length > 2){ + + for(let a = term_length - 1; a > 0; a--){ + + token = term[a] + token; + + if(token.length >= this.minlength){ + + this.push_index(dupes, token, score, id, _append); + } + } + + token = ""; + } + + // fallthrough to next case to apply forward also + + case "forward": + + if(term_length > 1){ + + for(let a = 0; a < term_length; a++){ + + token += term[a]; + + if(token.length >= this.minlength){ + + this.push_index(dupes, token, score, id, _append); + } + } + } + + break; + + //case "strict": + default: + + this.push_index(dupes, term, score, id, _append); + + if(depth){ + + if((length > 1) && (i < (length - 1))){ + + const resolution = this.resolution_ctx - this.threshold_ctx; + // check inner dupes to skip repeating words in the current context + const dupes_inner = create_object(); + const keyword = term; + let size = Math.min(depth + 1, length - i); + + dupes_inner[keyword] = 1; + + for(let x = 1; x < size; x++){ + + term = content[this.rtl ? length - 1 - i - x : i + x]; + + if(term && (term.length >= this.minlength) && !dupes_inner[term]){ + + dupes_inner[term] = 1; + + const context_score = Math.min(((this.resolution_ctx - size /*+ 1*/) / length * i + x) | 0, i + (x - 1)); + + if(context_score < resolution){ + + const swap = this.bidirectional && (term > keyword); + + this.push_index(dupes_ctx, swap ? keyword : term, context_score, id, _append, swap ? term : keyword); + } + } + else{ + + size = Math.min(size + 1, length - i); + } + } + } + } + } + } + } + } + + this.fastupdate || (this.register[id] = 1); + } + } + + return this; +}; + +/** + * @private + * @param dupes + * @param value + * @param score + * @param id + * @param {boolean=} append + * @param {string=} keyword + */ + +Index.prototype.push_index = function(dupes, value, score, id, append, keyword){ + + let arr = keyword ? this.ctx : this.map; + + if(!dupes[value] || (keyword && !dupes[value][keyword])){ + + if(this.optimize){ + + arr = arr[score]; + } + + if(keyword){ + + dupes[value] || (dupes[value] = create_object()); + dupes[value][keyword] = 1; + + arr = arr[keyword] || (arr[keyword] = create_object()); + } + else{ + + dupes[value] = 1; + } + + arr = arr[value] || (arr[value] = []); + + if(!this.optimize){ + + arr = arr[score] || (arr[score] = []); + } + + if(!append || (arr.indexOf(id) === -1)){ + + arr[arr.length] = id; + + // add a reference to the register for fast updates + + if(this.fastupdate){ + + const tmp = this.register[id]; + + if(tmp){ + + tmp[tmp.length] = arr; + } + else{ + + this.register[id] = [arr]; + } + } + } + } +} + +/** + * @param {!string|Object} query + * @param {number|Object=} limit + * @param {Object=} options + * @returns {Array} + */ + +Index.prototype.search = function(query, limit, options){ + + if(typeof query === "object"){ + + options = query; + query = options["query"]; + } + else if(typeof limit === "object"){ + + options = limit; + } + + let result = []; + let length; + let threshold = this.threshold, context, suggest; + + if(options){ + + limit = options["limit"]; + threshold = parse_option(options["threshold"], threshold); + context = options["context"]; + suggest = options["suggest"]; + } + + if(query){ + + query = /** @type {Array} */ (this.encode(query)); + length = query.length; + + // TODO: solve this in one single loop below + + if(length > 1){ + + const dupes = create_object(); + const query_new = []; + + for(let i = 0, count = 0, term; i < length; i++){ + + term = query[i]; + + if(term && (term.length >= this.minlength) && !dupes[term]){ + + // the fast path just could applied when not in memory-optimized mode + + if(!this.optimize && !suggest && !this.map[term]){ + + // fast path "not found" + + return result; + } + else{ + + query_new[count++] = term; + dupes[term] = 1; + } + } + } + + query = query_new; + length = query.length; + } + } + + if(!length){ + + return result; + } + + limit || (limit = 100); + + const resolution = this.resolution - threshold; + const resolution_ctx = this.resolution_ctx - threshold; + let depth = this.depth && (length > 1) && (context !== false); + let index = 0, keyword; + + if(depth){ + + keyword = query[0]; + index = 1; + } + else{ + + if(length > 1){ + + query.sort(sort_by_length_down); + } + } + + for(let arr, term; index < length; index++){ + + term = query[index]; + + if(depth){ + + arr = this.add_result(result, suggest, resolution_ctx, limit, length === 2, term, keyword); + + // when suggestion enabled just forward keyword if term was found + // as long as the result is empty forward the pointer also + + if(!suggest || (arr !== false) || !result.length){ + + keyword = term; + } + } + else{ + + arr = this.add_result(result, suggest, resolution, limit, length === 1, term); + } + + if(arr){ + + return /** @type {Array} */ (arr); + } + + // apply suggestions on last loop or fallback + + if(suggest && (index === length - 1)){ + + let length = result.length; + + if(!length){ + + if(depth){ + + // fallback to non-contextual search when no result was found + + depth = 0; + index = -1; + + continue; + } + + return result; + } + else if(length === 1){ + + // fast path optimization + + result = result[0]; + + if(result.length === 1){ + + result = result[0]; + } + else{ + + result = concat(result); + } + + return result.length > limit ? result.slice(0, limit) : result; + } + } + } + + return intersect(result, limit, suggest); +}; + +function get_array(arr, term, keyword, bidirectional){ + + if(keyword){ + + const swap = bidirectional && (term > keyword); + + arr = arr[swap ? term : keyword]; + arr = arr && arr[swap ? keyword : term]; + } + else{ + + arr = arr[term]; + } + + return arr; +} + +/** + * Returns an array when the result is done (to stop the process immediately), + * returns false when suggestions is enabled and no result was found, + * or returns nothing when a set was pushed successfully to the results + * + * @private + * @param {Array} result + * @param {Array} suggest + * @param {number} resolution + * @param {number} limit + * @param {boolean} just_one_loop + * @param {string} term + * @param {string=} keyword + * @return {Array>|boolean|undefined} + */ + +Index.prototype.add_result = function(result, suggest, resolution, limit, just_one_loop, term, keyword){ + + let word_arr = []; + let arr = keyword ? this.ctx : this.map; + + if(!this.optimize){ + + arr = get_array(arr, term, keyword, this.bidirectional); + + // if(keyword){ + // + // const swap = this.bidirectional && (term > keyword); + // + // arr = arr[swap ? term : keyword]; + // arr = arr && arr[swap ? keyword : term]; + // } + // else{ + // + // arr = arr[term]; + // } + } + + if(arr){ + + let count = 0; + const arr_len = Math.min(arr.length, resolution); + + for(let x = 0, size = 0, tmp; x < arr_len; x++){ + + tmp = arr[x]; + + if(this.optimize){ + + tmp = get_array(tmp, term, keyword, this.bidirectional); + + // if(keyword){ + // + // const swap = this.bidirectional && (term > keyword); + // + // tmp = tmp[swap ? term : keyword]; + // tmp = tmp && tmp[swap ? keyword : term]; + // } + // else{ + // + // tmp = tmp[term]; + // } + } + + if(tmp){ + + // keep score (sparse array): + //word_arr[x] = arr; + + // simplified score order: + word_arr[count++] = tmp; + + if(just_one_loop){ + + size += tmp.length; + + if(size >= limit){ + + // fast path optimization + + break; + } + } + } + } + + if(count){ + + if(just_one_loop){ + + // fast path optimization + + if(count === 1){ + + word_arr = word_arr[0]; + } + else{ + + word_arr = concat(word_arr); + } + + return word_arr.length > limit ? word_arr.slice(0, limit) : word_arr; + } + + result[result.length] = word_arr; + return; + } + } + + // return an empty array will stop the loop, + // to prevent stop when using suggestions return a false value + + return !suggest && word_arr; +}; + +Index.prototype.contain = function(id){ + + return !!this.register[id]; +}; + +Index.prototype.update = function(id, content){ + + return this.remove(id).add(id, content); +}; + +/** + * @param {boolean=} _skip_deletion + */ + +Index.prototype.remove = function(id, _skip_deletion){ + + const refs = this.register[id]; + + if(refs){ + + if(this.fastupdate){ + + // fast updates performs really fast but did not cleanup the key entries + + for(let i = 0, tmp; i < refs.length; i++){ + + tmp = refs[i]; + tmp.splice(tmp.indexOf(id), 1); + } + } + else{ + + remove_index(this.map, id, this.resolution - this.threshold, this.optimize); + + if(this.depth){ + + remove_index(this.ctx, id, this.resolution_ctx - this.threshold_ctx, this.optimize); + } + } + + _skip_deletion || delete this.register[id]; + + if(SUPPORT_CACHE && this.cache){ + + this.cache.del(id); + } + } + + return this; +}; + +/** + * @param map + * @param id + * @param res + * @param optimize + * @param {number=} resolution + * @return {number} + */ + +function remove_index(map, id, res, optimize, resolution){ + + let count = 0; + + if(map.constructor === Array){ + + // the first array is the score array in both strategies + + if(!resolution){ + + resolution = Math.min(map.length, res); + + for(let x = 0, arr; x < resolution; x++){ + + arr = map[x]; + + if(arr){ + + count = remove_index(arr, id, res, optimize, resolution); + + if(!optimize && !count){ + + // when not memory optimized the score index should removed + + delete map[x]; + } + } + } + } + else{ + + const pos = map.indexOf(id); + + if(pos !== -1){ + + // fast path, when length is 1 or lower then the whole field gets deleted + + if(map.length > 1){ + + map.splice(pos, 1); + count++; + } + } + else{ + + count++; + } + } + } + else{ + + for(let key in map){ + + count = remove_index(map[key], id, res, optimize, resolution); + + if(!count){ + + delete map[key]; + } + } + } + + return count; +} + +if(SUPPORT_CACHE){ + + Index.prototype.searchCache = searchCache; +} + +if(SUPPORT_ASYNC){ + + Index.prototype.addAsync = addAsync; + Index.prototype.appendAsync = appendAsync; + Index.prototype.searchAsync = searchAsync; + Index.prototype.updateAsync = updateAsync; + Index.prototype.removeAsync = removeAsync; +} \ No newline at end of file diff --git a/src/intersect.js b/src/intersect.js new file mode 100644 index 0000000..0aeef07 --- /dev/null +++ b/src/intersect.js @@ -0,0 +1,137 @@ +import { create_object, concat } from "./common.js"; + +/** + * @param arrays + * @param limit + * @param {boolean|Array=} suggest + * @returns {Array} + */ + +export default function(arrays, limit, suggest) { + + const length = arrays.length; + let result = []; + + // if(!length){ + // + // return result; + // } + // + // if(length === 1){ + // + // const tmp = arrays[0]; + // + // if(tmp.length === 1){ + // + // return tmp[0]; + // } + // + // return concat(tmp); + // } + + // arrays.sort(function(a, b){ + // + // return a.length - b.length; + // }); + + let check = create_object(); + let count = 0; + + if(suggest){ + + suggest = []; + } + + // terms + for(let x = 0; x < length; x++){ + + const word_arr = arrays[x]; + const word_arr_len = word_arr.length; + const new_check = create_object(); + + let found = !x; + + // relevance + for(let y = 0; y < word_arr_len; y++){ + + //const arr = [].concat.apply([], word_arr); + const arr = word_arr[y]; + const arr_len = arr.length; + + if(arr_len){ + + if(suggest){ + + suggest[y] = []; + } + + // ids + for(let z = 0, count_suggest = 0, id; z < arr_len; z++){ + + id = arr[z]; + + if(!x){ + + new_check[id] = 1; + } + else if(check[id]){ + + if(x === (length - 1)){ + + result[count++] = id; + + if(count === limit){ + + // fast path "end reached" + + return result; + } + } + else{ + + if(suggest && (count_suggest < limit)){ + + suggest[y][count_suggest++] = id; + } + + new_check[id] = 1; + } + + found = true; + } + } + } + } + + if(!found && !suggest){ + + return []; + } + + check = new_check; + } + + if(suggest){ + + for(let i = suggest.length - 1, res, len; i >= 0; i--){ + + res = suggest[i]; + len = res && res.length; + + if(len){ + + if(count + len >= limit){ + + return result.concat(res.slice(0, limit - count)); + } + else{ + + result = result.concat(res); + count += len; + } + } + } + } + + return result; +} diff --git a/src/lang.js b/src/lang.js new file mode 100644 index 0000000..45e0aa6 --- /dev/null +++ b/src/lang.js @@ -0,0 +1,307 @@ +import Index from "./index.js"; +import { create_object } from "./common.js"; + +/** + * @param {!string} str + * @param {boolean|Array=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} _collapse + * @returns {string|Array} + * @this Index + */ + +export function pipeline(str, normalize, split, _collapse){ + + if(str){ + + if(normalize && str){ + + str = replace(str, /** @type {Array} */ (normalize)); + } + + if(str && this.matcher){ + + str = replace(str, this.matcher); + } + + if(this.stemmer && str.length > 1){ + + str = replace(str, this.stemmer); + } + + if(_collapse && str.length > 1){ + + str = collapse(str); + } + + if(str){ + + if(split || (split === "")){ + + const words = str.split(/** @type {string|RegExp} */ (split)); + + return this.filter ? filter(words, this.filter) : words; + } + } + } + + return str; +} + +/** + * @param {!string} str + * @param {boolean|Array=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} _collapse + * @returns {string|Array} + */ + +// FlexSearch.prototype.pipeline = function(str, normalize, split, _collapse){ +// +// if(str){ +// +// if(normalize && str){ +// +// str = replace(str, /** @type {Array} */ (normalize)); +// } +// +// if(str && this.matcher){ +// +// str = replace(str, this.matcher); +// } +// +// if(this.stemmer && str.length > 1){ +// +// str = replace(str, this.stemmer); +// } +// +// if(_collapse && str.length > 1){ +// +// str = collapse(str); +// } +// +// if(str){ +// +// if(split || (split === "")){ +// +// const words = str.split(/** @type {string|RegExp} */ (split)); +// +// return this.filter ? filter(words, this.filter) : words; +// } +// } +// } +// +// return str; +// }; + +// export function pipeline(str, normalize, matcher, stemmer, split, _filter, _collapse){ +// +// if(str){ +// +// if(normalize && str){ +// +// str = replace(str, normalize); +// } +// +// if(matcher && str){ +// +// str = replace(str, matcher); +// } +// +// if(stemmer && str.length > 1){ +// +// str = replace(str, stemmer); +// } +// +// if(_collapse && str.length > 1){ +// +// str = collapse(str); +// } +// +// if(str){ +// +// if(split !== false){ +// +// str = str.split(split); +// +// if(_filter){ +// +// str = filter(str, _filter); +// } +// } +// } +// } +// +// return str; +// } + + +/** + * @param {Array} words + * @returns {Object} + */ + +export function init_filter(words){ + + const filter = create_object(); + + for(let i = 0, length = words.length; i < length; i++){ + + filter[words[i]] = 1; + } + + return filter; +} + +/** + * @param {!Object} obj + * @param {boolean} is_stemmer + * @returns {Array} + */ + +export function init_stemmer_or_matcher(obj, is_stemmer){ + + const keys = Object.keys(obj); + const length = keys.length; + const final = []; + + let removal = "", count = 0; + + for(let i = 0, key, tmp; i < length; i++){ + + key = keys[i]; + tmp = obj[key]; + + if(tmp){ + + final[count++] = regex(is_stemmer ? "(?!\\b)" + key + "(\\b|_)" : key); + final[count++] = tmp; + } + else{ + + removal += (removal ? "|" : "") + key; + } + } + + if(removal){ + + final[count++] = regex(is_stemmer ? "(?!\\b)(" + removal + ")(\\b|_)" : "(" + removal + ")"); + final[count] = ""; + } + + return final; +} + + +/** + * @param {!string} str + * @param {Array} regexp + * @returns {string} + */ + +export function replace(str, regexp){ + + for(let i = 0, len = regexp.length; i < len; i += 2){ + + str = str.replace(regexp[i], regexp[i + 1]); + + if(!str){ + + break; + } + } + + return str; +} + +/** + * @param {!string} str + * @returns {RegExp} + */ + +export function regex(str){ + + return new RegExp(str, "g"); +} + +/** + * Regex: replace(/(?:(\w)(?:\1)*)/g, "$1") + * @param {!string} string + * @returns {string} + */ + +export function collapse(string){ + + let final = "", prev = ""; + + for(let i = 0, len = string.length, char; i < len; i++){ + + if((char = string[i]) !== prev){ + + final += (prev = char); + } + } + + return final; +} + +// TODO using fast-swap +export function filter(words, map){ + + const length = words.length; + const filtered = []; + + for(let i = 0, count = 0; i < length; i++){ + + const word = words[i]; + + if(word && !map[word]){ + + filtered[count++] = word; + } + } + + return filtered; +} + +// const chars = {a:1, e:1, i:1, o:1, u:1, y:1}; +// +// function collapse_repeating_chars(string){ +// +// let collapsed_string = "", +// char_prev = "", +// char_next = ""; +// +// for(let i = 0; i < string.length; i++){ +// +// const char = string[i]; +// +// if(char !== char_prev){ +// +// if(i && (char === "h")){ +// +// if((chars[char_prev] && chars[char_next]) || (char_prev === " ")){ +// +// collapsed_string += char; +// } +// } +// else{ +// +// collapsed_string += char; +// } +// } +// +// char_next = ( +// +// (i === (string.length - 1)) ? +// +// "" +// : +// string[i + 1] +// ); +// +// char_prev = char; +// } +// +// return collapsed_string; +// } diff --git a/src/lang/arabic/default.js b/src/lang/arabic/default.js index a48e7dd..91a0726 100644 --- a/src/lang/arabic/default.js +++ b/src/lang/arabic/default.js @@ -1,4 +1,4 @@ -import FlexSearch from "../../flexsearch.js"; +import Document from "../../flexsearch.js"; export const rtl = true; export const tokenize = ""; @@ -10,7 +10,7 @@ export default { const regex = /[\x00-\x7F]+/g; /** - * @this FlexSearch + * @this Document */ export function encode(str){ diff --git a/src/lang/cjk/default.js b/src/lang/cjk/default.js index 27e4f61..78cd6ce 100644 --- a/src/lang/cjk/default.js +++ b/src/lang/cjk/default.js @@ -1,4 +1,4 @@ -import FlexSearch from "../../flexsearch.js"; +import Document from "../../flexsearch.js"; export const rtl = false; export const tokenize = "strict"; @@ -11,7 +11,7 @@ export default { const regex = /[\x00-\x7F]+/g; /** - * @this FlexSearch + * @this Document */ export function encode(str){ diff --git a/src/lang/cyrillic/default.js b/src/lang/cyrillic/default.js index 0388c24..b3bc8c9 100644 --- a/src/lang/cyrillic/default.js +++ b/src/lang/cyrillic/default.js @@ -1,4 +1,4 @@ -import FlexSearch from "../../flexsearch.js"; +import Document from "../../flexsearch.js"; export const rtl = false; export const tokenize = ""; @@ -10,7 +10,7 @@ export default { const regex = /[\x00-\x7F]+/g; /** - * @this FlexSearch + * @this Document */ export function encode(str){ diff --git a/src/lang/latin/advanced.js b/src/lang/latin/advanced.js index 5ff34fc..49090b5 100644 --- a/src/lang/latin/advanced.js +++ b/src/lang/latin/advanced.js @@ -1,5 +1,4 @@ -import FlexSearch from "../../flexsearch.js"; -import { regex, replace, collapse } from "../../common.js"; +import { regex, replace, collapse } from "../../lang.js"; import { encode as encode_simple } from "./simple.js"; export const rtl = false; @@ -55,7 +54,7 @@ export function encode(str, self, _skip_postprocessing){ if(str){ - str = encode_simple(str, /** @type {FlexSearch} */ (self || this)).join(" "); + str = encode_simple(str, /** @type {Document} */ (self || this)).join(" "); if(str.length > 2){ diff --git a/src/lang/latin/balance.js b/src/lang/latin/balance.js index 2b8a4fd..452bd37 100644 --- a/src/lang/latin/balance.js +++ b/src/lang/latin/balance.js @@ -1,4 +1,4 @@ -import FlexSearch from "../../flexsearch.js"; +import Index from "../../index.js"; export const rtl = false; export const tokenize = ""; @@ -16,7 +16,7 @@ const regex_whitespace = /[\W_]+/; // ]; /** - * @this FlexSearch + * @this Index */ export function encode(str){ diff --git a/src/lang/latin/default.js b/src/lang/latin/default.js index 794aec9..d66d801 100644 --- a/src/lang/latin/default.js +++ b/src/lang/latin/default.js @@ -1,4 +1,4 @@ -import FlexSearch from "../../flexsearch.js"; +import Index from "../../index.js"; export const rtl = false; export const tokenize = ""; @@ -10,7 +10,7 @@ export default { const regex_whitespace = /[\W_]+/; /** - * @this FlexSearch + * @this Index */ export function encode(str){ diff --git a/src/lang/latin/extra.js b/src/lang/latin/extra.js index 9e118f4..6311e6f 100644 --- a/src/lang/latin/extra.js +++ b/src/lang/latin/extra.js @@ -1,5 +1,4 @@ -import FlexSearch from "../../flexsearch.js"; -import { regex, replace, collapse } from "../../common.js"; +import { regex, replace, collapse } from "../../lang.js"; import { encode as encode_advanced } from "./advanced.js"; export const rtl = false; @@ -35,7 +34,7 @@ export function encode(str){ if(str){ - str = encode_advanced(str, /** @type {FlexSearch} */ (this), /* skip post-processing: */ true); + str = encode_advanced(str, /** @type {Document} */ (this), /* skip post-processing: */ true); if(str.length > 1){ diff --git a/src/lang/latin/simple.js b/src/lang/latin/simple.js index f61a8f8..7584e56 100644 --- a/src/lang/latin/simple.js +++ b/src/lang/latin/simple.js @@ -1,5 +1,5 @@ -import FlexSearch from "../../flexsearch.js"; -import { regex } from "../../common.js"; +import Index from "../../index.js"; +import { regex } from "../../lang.js"; export const rtl = false; export const tokenize = ""; @@ -45,7 +45,7 @@ const pairs = [ export function encode(str, self){ - return /** @type {FlexSearch} */ (self || this).pipeline( + return /** @type {Index} */ (self || this).pipeline( /* string: */ str.toLowerCase(), /* normalize: */ pairs, diff --git a/src/lang/latin/soundex.js b/src/lang/latin/soundex.js index 4728f44..223c055 100644 --- a/src/lang/latin/soundex.js +++ b/src/lang/latin/soundex.js @@ -1,4 +1,4 @@ -import FlexSearch from "../../flexsearch.js"; +import Index from "../../index.js"; export const rtl = false; export const tokenize = "strict"; @@ -16,8 +16,38 @@ const regex_strip = /[^a-z]+/; // regex_strip, "" // ]; +// modified + +const soundex = { + + "b": 1, + "f": 1, + "p": 1, + "v": 1, + + "c": 7, + "g": 7, + "j": 7, + "k": 7, + "q": 7, + + "s": 2, + "x": 2, + "z": 2, + + "d": 3, + "t": 3, + + "l": 4, + + "m": 5, + "n": 5, + + "r": 6 +}; + /** - * @this FlexSearch + * @this Index */ export function encode(str){ @@ -46,9 +76,9 @@ export function encode(str){ for(let i = 1; i < str.length; i++){ - const current = getCode(str[i]); + const current = soundex[str[i]]; - if(current !== previous){ + if(current && (current !== previous)){ code += current; previous = current; @@ -68,37 +98,38 @@ export function encode(str){ return result; } + // https://www.rosettacode.org/wiki/Soundex -function getCode(char){ - - switch(char){ - - case 'b': - case 'f': - case 'p': - case 'v': - return 1; - case 'c': - case 'g': - case 'j': - case 'k': - case 'q': - case 's': - case 'x': - case 'z': - return 2; - case 'd': - case 't': - return 3; - case 'l': - return 4; - case 'm': - case 'n': - return 5; - case 'r': - return 6; - } - - return ""; -} +// function getCode(char){ +// +// switch(char){ +// +// case 'b': +// case 'f': +// case 'p': +// case 'v': +// return 1; +// case 'c': +// case 'g': +// case 'j': +// case 'k': +// case 'q': +// case 's': +// case 'x': +// case 'z': +// return 2; +// case 'd': +// case 't': +// return 3; +// case 'l': +// return 4; +// case 'm': +// case 'n': +// return 5; +// case 'r': +// return 6; +// } +// +// return ""; +// } diff --git a/src/polyfill.js b/src/polyfill.js index 5139544..90cb6e9 100644 --- a/src/polyfill.js +++ b/src/polyfill.js @@ -1,3 +1,7 @@ +import { POLYFILL, SUPPORT_ASYNC } from "./config.js"; + +export let promise = Promise; + if(POLYFILL){ Object.assign || (Object.assign = function(){ @@ -36,23 +40,20 @@ if(POLYFILL){ // return values; // }); - if(SUPPORT_ASYNC){ + if(SUPPORT_ASYNC && !promise){ - window["requestAnimationFrame"] || (window["requestAnimationFrame"] = window.setTimeout); - window["cancelAnimationFrame"] || (window["cancelAnimationFrame"] = window.clearTimeout); + /** + * @param {Function} fn + * @constructor + */ - window["Promise"] || (window["Promise"] = function(){ + function SimplePromise(fn){ - /** - * @param {Function} fn - * @constructor - */ + this.callback = null; - function Promise(fn){ + let self = this; - this.callback = null; - - const self = this; + //setTimeout(function(){ fn(function(val){ @@ -60,20 +61,21 @@ if(POLYFILL){ self.callback(val); self.callback = null; + self = null; } }); - } + //}); + } - /** - * @param {Function} callback - */ + /** + * @param {Function} callback + */ - Promise.prototype.then = function(callback){ + SimplePromise.prototype.then = function(callback){ - this.callback = callback; - }; + this.callback = callback; + }; - return Promise; - }()); + promise = SimplePromise; } } diff --git a/src/presets.js b/src/presets.js index 7676524..345842c 100644 --- a/src/presets.js +++ b/src/presets.js @@ -1,53 +1,95 @@ +import { DEBUG } from "./config.js"; + /** * @enum {Object} * @const */ -export default { +const presets = { "memory": { charset: "latin:extra", //tokenize: "strict", - threshold: 0, - resolution: 1 + resolution: 3, + //threshold: 0, + minlength: 3, + fastupdate: false, + optimize: "memory" }, - "speed": { + "performance": { //charset: "latin", //tokenize: "strict", - threshold: 1, - resolution: 3, - depth: 2 + //resolution: 9, + threshold: 8, + minlength: 3, + //fastupdate: true, + context: { + depth: 1, + bidirectional: true + } }, "match": { charset: "latin:extra", tokenize: "full", - threshold: 1, - resolution: 3 + resolution: 3, + //threshold: 0 }, "score": { - charset: "latin:extra", + charset: "latin:advanced", //tokenize: "strict", + //resolution: 9, threshold: 1, - resolution: 9, - depth: 4 + context: { + depth: 3, + bidirectional: true + } }, - "balance": { - charset: "latin:balance", + "default": { + //charset: "latin:default", //tokenize: "strict", - threshold: 0, resolution: 3, + threshold: 0, depth: 3 }, - "fast": { - //charset: "latin", - //tokenize: "strict", - threshold: 8, - resolution: 9, - depth: 1 + // "fast": { + // //charset: "latin", + // //tokenize: "strict", + // threshold: 8, + // resolution: 9, + // depth: 1 + // } +}; + +export default function apply_preset(options){ + + if(typeof options === "string"){ + + if(DEBUG && !presets[options]){ + + console.warn("Preset not found: " + options); + } + + options = presets[options]; } -}; \ No newline at end of file + else{ + + const preset = options["preset"]; + + if(preset){ + + if(DEBUG && !presets[preset]){ + + console.warn("Preset not found: " + preset); + } + + options = Object.assign({}, presets[preset], /** @type {Object} */ (options)); + } + } + + return options; +} \ No newline at end of file diff --git a/src/profiler.js b/src/profiler.js deleted file mode 100644 index fcde4ba..0000000 --- a/src/profiler.js +++ /dev/null @@ -1,33 +0,0 @@ -const profiles = []; -let profile; - -export function profile_start(key){ - - (profile[key] || (profile[key] = { - - /** @export */ time: 0, - /** @export */ count: 0, - /** @export */ ops: 0, - /** @export */ nano: 0 - - })).ops = (typeof performance === "undefined" ? Date : performance).now(); -} - -export function profile_end(key){ - - const current = profile[key]; - - current.time += (typeof performance === "undefined" ? Date : performance).now() - current.ops; - current.count++; - current.ops = 1000 / current.time * current.count; - current.micro = current.time / current.count * 1000; -} - -if(PROFILER){ - - if(typeof window !== "undefined") { - - /** @export */ - window.stats = profiles; - } -} \ No newline at end of file diff --git a/src/serialize.js b/src/serialize.js deleted file mode 100644 index 7a77408..0000000 --- a/src/serialize.js +++ /dev/null @@ -1,127 +0,0 @@ -import FlexSearch from "./flexsearch.js"; -import { is_undefined, is_object, get_keys } from "./common.js"; - -if(SUPPORT_SERIALIZE){ - - /** - * TODO: also export settings? - * @param {Object=} config - */ - - FlexSearch.prototype.export = function(config){ - - const serialize = !config || is_undefined(config["serialize"]) || config["serialize"]; - - let payload; - - if(SUPPORT_DOCUMENT && this.doc){ - - const export_doc = !config || is_undefined(config["doc"]) || config["doc"]; - const export_index = !config || is_undefined(config["index"]) || config["index"]; - - payload = []; - - let i = 0; - - if(export_index){ - - const keys = this.doc.keys; - - for(; i < keys.length; i++){ - - const idx = this.doc.index[keys[i]]; - - payload[i] = [ - - idx._map, idx._ctx, get_keys(idx._ids) - ]; - } - } - - if(export_doc){ - - payload[i] = this._doc; - } - } - else{ - - payload = [ - - this._map, - this._ctx, - get_keys(this._ids) - ]; - } - - if(serialize){ - - payload = JSON.stringify(payload); - } - - return payload; - }; - - FlexSearch.prototype.import = function(payload, config){ - - const serialize = !config || is_undefined(config["serialize"]) || config["serialize"]; - - if(serialize){ - - payload = JSON.parse(payload); - } - - const ids = {}; - - if(SUPPORT_DOCUMENT && this.doc){ - - const import_doc = !config || is_undefined(config["doc"]) || config["doc"]; - const import_index = !config || is_undefined(config["index"]) || config["index"]; - - let i = 0; - - if(import_index){ - - const keys = this.doc.keys; - const length = keys.length; - const current = payload[0][2]; - - for(; i < current.length; i++){ - - ids[current[i]] = 1; - } - - for(i = 0; i < length; i++){ - - const idx = this.doc.index[keys[i]]; - const item = payload[i]; - - if(item){ - - idx._map = item[0]; - idx._ctx = item[1]; - idx._ids = ids; - // idx._doc = payload[length]; - } - } - } - - if(import_doc){ - - this._doc = is_object(import_doc) ? import_doc : payload[i]; - } - } - else{ - - const current = payload[2]; - - for(let i = 0; i < current.length; i++){ - - ids[current[i]] = 1; - } - - this._map = payload[0]; - this._ctx = payload[1]; - this._ids = ids; - } - }; -} \ No newline at end of file diff --git a/src/webpack.js b/src/webpack.js new file mode 100644 index 0000000..b0204b1 --- /dev/null +++ b/src/webpack.js @@ -0,0 +1,49 @@ +import { SUPPORT_ASYNC, SUPPORT_DOCUMENT, SUPPORT_CACHE } from "./config.js"; +import Document from "./document.js"; +import Index from "./index.js"; +import { registerCharset, registerLanguage } from "./global.js"; + +/** @export */ Document.prototype.add; +/** @export */ Document.prototype.append; +/** @export */ Document.prototype.search; +/** @export */ Document.prototype.update; +/** @export */ Document.prototype.remove; +/** @export */ Document.prototype.contain; +/** @export */ Document.prototype.get; +/** @export */ Document.prototype.set; + +/** @export */ Index.prototype.add; +/** @export */ Index.prototype.append; +/** @export */ Index.prototype.search; +/** @export */ Index.prototype.update; +/** @export */ Index.prototype.remove; +/** @export */ Index.prototype.contain; + +if(SUPPORT_CACHE){ + +/** @export */ Index.prototype.searchCache; +/** @export */ Document.prototype.searchCache; +} + +if(SUPPORT_ASYNC){ + +/** @export */ Document.prototype.addAsync; +/** @export */ Document.prototype.appendAsync; +/** @export */ Document.prototype.searchAsync; +/** @export */ Document.prototype.updateAsync; +/** @export */ Document.prototype.removeAsync; + +/** @export */ Index.prototype.addAsync; +/** @export */ Index.prototype.appendAsync; +/** @export */ Index.prototype.searchAsync; +/** @export */ Index.prototype.updateAsync; +/** @export */ Index.prototype.removeAsync; +} + +window["FlexSearch"] = { + + "Index": Index, + "Document": SUPPORT_DOCUMENT ? Document : null, + "registerCharset": registerCharset, + "registerLanguage": registerLanguage +} \ No newline at end of file diff --git a/src/where.js b/src/where.js deleted file mode 100644 index a6dd6b0..0000000 --- a/src/where.js +++ /dev/null @@ -1,162 +0,0 @@ -import FlexSearch from "./flexsearch.js"; -import { get_keys, is_function, is_object, is_undefined } from "./common.js"; - -if(SUPPORT_DOCUMENT && SUPPORT_WHERE){ - - FlexSearch.prototype.find = function(key, value){ - - return this.where(key, value, 1)[0] || null; - }; - - /** - * @param key - * @param value - * @param limit - * @param {Array=} result - * @returns {Array} - */ - - FlexSearch.prototype.where = function(key, value, limit, result){ - - const doc = this._doc; - const results = []; - - let count = 0; - let keys; - let keys_len; - let has_value; - let tree; - let tag_results; - - if(is_object(key)){ - - limit || (limit = value); - keys = get_keys(key); - keys_len = keys.length; - has_value = false; - - if((keys_len === 1) && (keys[0] === "id")){ - - return [doc[key["id"]]]; - } - - const tags = this._tags; - - if(tags && !result){ - - for(let i = 0; i < tags.length; i++){ - - const current_tag = tags[i]; - const current_where = key[current_tag]; - - if(!is_undefined(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 tag_results; - } - - keys.splice(keys.indexOf(current_tag), 1); - - // TODO: delete from original reference? - delete key[current_tag]; - break; - } - } - } - - tree = new Array(keys_len); - - for(let i = 0; i < keys_len; i++){ - - tree[i] = keys[i].split(":"); - } - } - else if(is_function(key)){ - - const ids = result || get_keys(doc); - const length = ids.length; - - for(let x = 0; x < length; x++){ - - const obj = doc[ids[x]]; - - if(key(obj)){ - - results[count++] = obj; - } - } - - return results; - } - else{ - - if(is_undefined(value)){ - - return [doc[key]]; - } - - if(key === "id"){ - - return [doc[value]]; - } - - keys = [key]; - keys_len = 1; - tree = [key.split(":")]; - has_value = true; - } - - const ids = tag_results || result || get_keys(doc); // this._ids; - const length = ids.length; - - for(let x = 0; x < length; x++){ - - const obj = tag_results ? ids[x] : doc[ids[x]]; - let found = true; - - for(let i = 0; i < keys_len; i++){ - - has_value || (value = key[keys[i]]); - - const tree_cur = tree[i]; - const tree_len = tree_cur.length; - - let ref = obj; - - if(tree_len > 1){ - - for(let z = 0; z < tree_len; z++){ - - ref = ref[tree_cur[z]]; - } - } - else{ - - ref = ref[tree_cur[0]]; - } - - if(ref !== value){ - - found = false; - break; - } - } - - if(found){ - - results[count++] = obj; - - if(limit && (count === limit)){ - - break; - } - } - } - - return results; - }; -} \ No newline at end of file diff --git a/src/worker.js b/src/worker.js index 01c3baf..9c0fa50 100644 --- a/src/worker.js +++ b/src/worker.js @@ -1,248 +1,50 @@ -import FlexSearch from "./flexsearch.js"; -const worker_stack = {}; -const inline_supported = (typeof Blob !== "undefined") && (typeof URL !== "undefined") && URL.createObjectURL; +import Index from "./index.js"; -/** - * @param {!string} _name - * @param {!number|string} _id - * @param {!Function} _worker - * @param {!Function} _callback - * @param {number=} _core - */ +let index, id; -export default function init(_name, _id, _worker, _callback, _core){ +onmessage = function(event) { - let name = _name; - const worker_payload = ( + const data = event.data; - inline_supported ? + switch(data["task"]){ - // Load Inline Worker + case "register": - URL.createObjectURL( + const options = data["options"] || {}; - new Blob([ + options["cache"] = false; + // options["async"] = false; + // options["worker"] = false; - (RELEASE ? + id = data["id"]; + index = new Index(options); + break; - "" - : - "var RELEASE = '" + RELEASE + "';" + - "var DEBUG = " + (DEBUG ? "true" : "false") + ";" + - "var PROFILER = " + (PROFILER ? "true" : "false") + ";" + - "var SUPPORT_PRESET = " + (SUPPORT_PRESET ? "true" : "false") + ";" + - "var SUPPORT_SUGGESTION = " + (SUPPORT_SUGGESTION ? "true" : "false") + ";" + - "var SUPPORT_ENCODER = " + (SUPPORT_ENCODER ? "true" : "false") + ";" + - "var SUPPORT_CACHE = " + (SUPPORT_CACHE ? "true" : "false") + ";" + - "var SUPPORT_ASYNC = " + (SUPPORT_ASYNC ? "true" : "false") + ";" + - "var SUPPORT_SERIALIZE = " + (SUPPORT_SERIALIZE ? "true" : "false") + ";" + - "var SUPPORT_INFO = " + (SUPPORT_INFO ? "true" : "false") + ";" + - "var SUPPORT_DOCUMENT = " + (SUPPORT_DOCUMENT ? "true" : "false") + ";" + - "var SUPPORT_WHERE = " + (SUPPORT_WHERE ? "true" : "false") + ";" + - "var SUPPORT_PAGINATION = " + (SUPPORT_PAGINATION ? "true" : "false") + ";" + - "var SUPPORT_OPERATOR = " + (SUPPORT_OPERATOR ? "true" : "false") + ";" + - "var SUPPORT_CALLBACK = " + (SUPPORT_CALLBACK ? "true" : "false") + ";" + - "var SUPPORT_WORKER = true;" + case "search": - ) + "(" + _worker.toString() + ")()" - ],{ - "type": "text/javascript" - }) - ) - : - // Load Extern Worker (but also requires CORS) + const results = index.search(data["query"], data); - name + (RELEASE ? "." + RELEASE : "") + ".js" - ); + postMessage({ id, results }); + break; - name += "-" + _id; + case "add": - worker_stack[name] || (worker_stack[name] = []); - worker_stack[name][_core] = new Worker(worker_payload); - worker_stack[name][_core]["onmessage"] = _callback; + index.add(data["id"], data["content"]); + break; - if(DEBUG){ + case "update": - console.log("Register Worker: " + name + "@" + _core); + index.update(data["id"], data["content"]); + break; + + case "remove": + + index.remove(data["id"]); + break; + + // case "clear": + // + // index.clear(); + // break; } - - return worker_stack[name][_core]; -} - -function worker_module(){ - - let id; - - /** @type {FlexSearch} */ - let FlexSearchWorker; - - /** @lends {Worker} */ - self.onmessage = function(event){ - - const data = event["data"]; - - if(data){ - - if(data["search"]){ - - const results = FlexSearchWorker["search"](data["content"], - - data["threshold"] ? - - { - "limit": data["limit"], - "threshold": data["threshold"], - "where": data["where"] - } - : - data["limit"] - ); - - /** @lends {Worker} */ - self.postMessage({ - - "id": id, - "content": data["content"], - "limit": data["limit"], - "result": results - }); - } - else if(data["add"]){ - - FlexSearchWorker["add"](data["id"], data["content"]); - } - else if(data["update"]){ - - FlexSearchWorker["update"](data["id"], data["content"]); - } - else if(data["remove"]){ - - FlexSearchWorker["remove"](data["id"]); - } - else if(data["clear"]){ - - FlexSearchWorker["clear"](); - } - else if(SUPPORT_INFO && data["info"]){ - - const info = FlexSearchWorker["info"](); - - info["worker"] = id; - - console.log(info); - - /** @lends {Worker} */ - //self.postMessage(info); - } - else if(data["register"]){ - - id = data["id"]; - - data["options"]["cache"] = false; - data["options"]["async"] = false; - data["options"]["worker"] = false; - - FlexSearchWorker = new Function( - - data["register"].substring( - - data["register"].indexOf("{") + 1, - data["register"].lastIndexOf("}") - ) - )(); - - FlexSearchWorker = new FlexSearchWorker(data["options"]); - } - } - }; -} - -export function addWorker(id, core, options, callback){ - - const thread = init( - - // name: - "flexsearch", - - // id: - "id" + id, - - // worker: - worker_module, - - // callback: - function(event){ - - const data = event["data"]; - - if(data && data["result"]){ - - callback( - - data["id"], - data["content"], - data["result"], - data["limit"], - data["where"], - data["cursor"], - data["suggest"] - ); - } - }, - - // cores: - core - ); - - const fnStr = FlexSearch.toString(); - - options["id"] = core; - - thread.postMessage({ - - "register": fnStr, - "options": options, - "id": core - }); - - return thread; -} - -if(SUPPORT_WORKER){ - - FlexSearch.prototype.worker_handler = function(id, query, result, limit, where, cursor, suggest){ - - if(this._task_completed !== this.worker){ - - this._task_result = this._task_result.concat(result); - this._task_completed++; - - // TODO: sort results, return array of relevance [0...9] and apply in main thread - - if(limit && (this._task_result.length >= limit)){ - - this._task_completed = this.worker; - } - - if(this._task_completed === this.worker){ - - // this._task_result = intersect(this._task_result, where ? 0 : limit, cursor, suggest); - - if(this.cache){ - - this._cache.set(query, this._task_result); - } - - if(this._current_callback){ - - this._current_callback(this._task_result); - } - - //this._task_completed = 0; - //this._task_result = []; - } - } - - return this; - }; -} \ No newline at end of file +}; diff --git a/task/build.js b/task/build.js index bfd07f9..29cfe9b 100644 --- a/task/build.js +++ b/task/build.js @@ -106,9 +106,9 @@ let parameter = (function(opt){ compilation_level: compilation_level || (release === "pre" ? "SIMPLE" : (release === "debug" ? "WHITESPACE" : "ADVANCED_OPTIMIZATIONS")), //"SIMPLE" use_types_for_optimization: true, //new_type_inf: true, - jscomp_warning: "newCheckTypes", + //jscomp_warning: "newCheckTypes", //jscomp_error: "strictCheckTypes", - jscomp_error: "newCheckTypesExtraChecks", + //jscomp_error: "newCheckTypesExtraChecks", generate_exports: true, export_local_property_definitions: true, language_in: "ECMASCRIPT6_STRICT", @@ -119,19 +119,19 @@ let parameter = (function(opt){ emit_use_strict: true, output_manifest: "log/manifest.log", - output_module_dependencies: "log/module_dependencies.log", + //output_module_dependencies: "log/module_dependencies.log", property_renaming_report: "log/property_renaming.log", create_source_map: "log/source_map.log", variable_renaming_report: "log/variable_renaming.log", strict_mode_input: true, assume_function_wrapper: true, - transform_amd_modules: true, + //transform_amd_modules: true, process_common_js_modules: true, module_resolution: "BROWSER", //dependency_mode: "SORT_ONLY", //js_module_root: "./", - entry_point: "./src/bundle.js", + entry_point: "./src/webpack.js", //manage_closure_dependencies: true, dependency_mode: "PRUNE_LEGACY", rewrite_polyfills: use_polyfill || false, @@ -216,10 +216,16 @@ else{ var filename = "dist/flexsearch." + (release || "custom") + ".js"; - exec("java -jar node_modules/google-closure-compiler-java/compiler.jar" + parameter + " --js='src/**.js'" + flag_str + " --js_output_file='" + filename + "' && exit 0", function(){ + exec((/^win/.test(process.platform) ? + + "\"node_modules/google-closure-compiler-windows/compiler.exe\"" + : + "java -jar node_modules/google-closure-compiler-java/compiler.jar" + + ) + parameter + " --js='src/**.js'" + flag_str + " --js_output_file='" + filename + "' && exit 0", function(){ let build = fs.readFileSync(filename); - let preserve = fs.readFileSync("src/flexsearch.js", "utf8"); + let preserve = fs.readFileSync("src/index.js", "utf8"); const package_json = require("../package.json");