@akryum/flexsearch-es
Version:
Next-Generation full text search library with zero dependencies.
1,563 lines (1,546 loc) • 41.8 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.js
var src_exports = {};
__export(src_exports, {
Document: () => document_default,
Worker: () => worker_default,
create: () => create2,
default: () => src_default,
registerCharset: () => registerCharset,
registerLanguage: () => registerLanguage
});
module.exports = __toCommonJS(src_exports);
// src/config.js
var DEBUG = false;
var SUPPORT_WORKER = true;
var SUPPORT_ENCODER = true;
var SUPPORT_CACHE = true;
var SUPPORT_ASYNC = true;
var SUPPORT_STORE = true;
var SUPPORT_TAGS = true;
var SUPPORT_SUGGESTION = true;
var SUPPORT_SERIALIZE = true;
// src/type.js
function IndexInterface() {
this.cache = null;
this.matcher = null;
this.stemmer = null;
this.filter = null;
}
IndexInterface.prototype.add;
IndexInterface.prototype.append;
IndexInterface.prototype.search;
IndexInterface.prototype.update;
IndexInterface.prototype.remove;
// src/common.js
function parse_option(value, default_value) {
return typeof value !== "undefined" ? value : default_value;
}
function create_object_array(count) {
const array = new Array(count);
for (let i = 0; i < count; i++) {
array[i] = create_object();
}
return array;
}
function get_keys(obj) {
return Object.keys(obj);
}
function create_object() {
return /* @__PURE__ */ Object.create(null);
}
function concat(arrays) {
return [].concat.apply([], arrays);
}
function sort_by_length_down(a, b) {
return b.length - a.length;
}
function is_array(val) {
return val.constructor === Array;
}
function is_string(val) {
return typeof val === "string";
}
function is_object(val) {
return typeof val === "object";
}
function is_function(val) {
return typeof val === "function";
}
// src/lang.js
function pipeline(str, normalize2, split, _collapse) {
if (str) {
if (normalize2) {
str = replace(
str,
/** @type {Array<string|RegExp>} */
normalize2
);
}
if (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 (split || split === "") {
const words = str.split(
/** @type {string|RegExp} */
split
);
return this.filter ? filter(words, this.filter) : words;
}
}
return str;
}
var regex_whitespace = /[\p{Z}\p{S}\p{P}\p{C}]+/u;
function init_filter(words) {
const filter2 = create_object();
for (let i = 0, length = words.length; i < length; i++) {
filter2[words[i]] = 1;
}
return filter2;
}
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, 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;
}
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;
}
function regex(str) {
return new RegExp(str, "g");
}
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;
}
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;
}
// src/lang/latin/default.js
function encode(str) {
return pipeline.call(
this,
/* string: */
("" + str).toLowerCase(),
/* normalize: */
false,
/* split: */
regex_whitespace,
/* collapse: */
false
);
}
// src/global.js
var global_lang = {};
var global_charset = {};
function registerCharset(name, charset) {
global_charset[name] = charset;
}
function registerLanguage(name, lang) {
global_lang[name] = lang;
}
// src/async.js
function async_default(prototype) {
register(prototype, "add");
register(prototype, "append");
register(prototype, "search");
register(prototype, "update");
register(prototype, "remove");
}
function register(prototype, key) {
prototype[key + "Async"] = function() {
const self2 = this;
const args = (
/*[].slice.call*/
arguments
);
const arg = args[args.length - 1];
let callback;
if (is_function(arg)) {
callback = arg;
delete args[args.length - 1];
}
const promise = new Promise(function(resolve) {
setTimeout(function() {
self2.async = true;
const res = self2[key].apply(self2, args);
self2.async = false;
resolve(res);
});
});
if (callback) {
promise.then(callback);
return this;
} else {
return promise;
}
};
}
// src/intersect.js
function intersect(arrays, limit, offset, suggest) {
const length = arrays.length;
let result = [];
let check;
let check_suggest;
let size = 0;
if (suggest) {
suggest = [];
}
for (let x = length - 1; x >= 0; x--) {
const word_arr = arrays[x];
const word_arr_len = word_arr.length;
const check_new = create_object();
let found = !check;
for (let y = 0; y < word_arr_len; y++) {
const arr = word_arr[y];
const arr_len = arr.length;
if (arr_len) {
for (let z = 0, check_idx, id; z < arr_len; z++) {
id = arr[z];
if (check) {
if (check[id]) {
if (!x) {
if (offset) {
offset--;
} else {
result[size++] = id;
if (size === limit) {
return result;
}
}
}
if (x || suggest) {
check_new[id] = 1;
}
found = true;
}
if (suggest) {
check_idx = (check_suggest[id] || 0) + 1;
check_suggest[id] = check_idx;
if (check_idx < length) {
const tmp = suggest[check_idx - 2] || (suggest[check_idx - 2] = []);
tmp[tmp.length] = id;
}
}
} else {
check_new[id] = 1;
}
}
}
}
if (suggest) {
check || (check_suggest = check_new);
} else if (!found) {
return [];
}
check = check_new;
}
if (suggest) {
for (let x = suggest.length - 1, arr, len; x >= 0; x--) {
arr = suggest[x];
len = arr.length;
for (let y = 0, id; y < len; y++) {
id = arr[y];
if (!check[id]) {
if (offset) {
offset--;
} else {
result[size++] = id;
if (size === limit) {
return result;
}
}
check[id] = 1;
}
}
}
}
return result;
}
function intersect_union(mandatory, arrays) {
const check = create_object();
const union = create_object();
const result = [];
for (let x = 0; x < mandatory.length; x++) {
check[mandatory[x]] = 1;
}
for (let x = 0, arr; x < arrays.length; x++) {
arr = arrays[x];
for (let y = 0, id; y < arr.length; y++) {
id = arr[y];
if (check[id]) {
if (!union[id]) {
union[id] = 1;
result[result.length] = id;
}
}
}
}
return result;
}
// src/cache.js
function CacheClass(limit) {
this.limit = limit !== true && limit;
this.cache = create_object();
this.queue = [];
}
var cache_default = CacheClass;
function searchCache(query, limit, options) {
if (is_object(query)) {
query = query["query"];
}
let cache = this.cache.get(query);
if (!cache) {
cache = this.search(query, limit, options);
this.cache.set(query, cache);
}
return cache;
}
CacheClass.prototype.set = function(key, value) {
if (!this.cache[key]) {
let length = this.queue.length;
if (length === this.limit) {
delete this.cache[this.queue[length - 1]];
} else {
length++;
}
for (let x = length - 1; x > 0; x--) {
this.queue[x] = this.queue[x - 1];
}
this.queue[0] = key;
}
this.cache[key] = value;
};
CacheClass.prototype.get = function(key) {
const cache = this.cache[key];
if (this.limit && cache) {
const pos = this.queue.indexOf(key);
if (pos) {
const tmp = this.queue[pos - 1];
this.queue[pos - 1] = this.queue[pos];
this.queue[pos] = tmp;
}
}
return cache;
};
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.includes(id)) {
this.queue.splice(i--, 1);
delete this.cache[key];
}
}
};
// src/preset.js
var preset = {
"memory": {
charset: "latin:extra",
//tokenize: "strict",
resolution: 3,
//threshold: 0,
minlength: 4,
fastupdate: false
},
"performance": {
//charset: "latin",
//tokenize: "strict",
resolution: 3,
minlength: 3,
//fastupdate: true,
optimize: false,
//fastupdate: true,
context: {
depth: 2,
resolution: 1
//bidirectional: false
}
},
"match": {
charset: "latin:extra",
tokenize: "reverse"
//resolution: 9,
//threshold: 0
},
"score": {
charset: "latin:advanced",
//tokenize: "strict",
resolution: 20,
minlength: 3,
context: {
depth: 3,
resolution: 9
//bidirectional: true
}
},
"default": {
// charset: "latin:default",
// tokenize: "strict",
// resolution: 3,
// threshold: 0,
// depth: 3
}
// "fast": {
// //charset: "latin",
// //tokenize: "strict",
// threshold: 8,
// resolution: 9,
// depth: 1
// }
};
function apply_preset(options) {
if (is_string(options)) {
if (DEBUG && !preset[options]) {
console.warn("Preset not found: " + options);
}
options = preset[options];
} else {
const preset2 = options["preset"];
if (preset2) {
if (DEBUG && !preset2[preset2]) {
console.warn("Preset not found: " + preset2);
}
options = Object.assign(
{},
preset2[preset2],
/** @type {Object} */
options
);
}
}
return options;
}
// src/serialize.js
function async(callback, self2, field, key, index_doc, index, data) {
setTimeout(function() {
const res = callback(field ? field + "." + key : key, JSON.stringify(data));
if (res && res["then"]) {
res["then"](function() {
self2.export(callback, self2, field, index_doc, index + 1);
});
} else {
self2.export(callback, self2, field, index_doc, index + 1);
}
});
}
function exportIndex(callback, self2, field, index_doc, index) {
let key, data;
switch (index || (index = 0)) {
case 0:
key = "reg";
if (this.fastupdate) {
data = create_object();
for (let key2 in this.register) {
data[key2] = 1;
}
} else {
data = this.register;
}
break;
case 1:
key = "cfg";
data = {
"doc": 0,
"opt": this.optimize ? 1 : 0
};
break;
case 2:
key = "map";
data = this.map;
break;
case 3:
key = "ctx";
data = this.ctx;
break;
default:
return;
}
async(callback, self2 || this, field, key, index_doc, index, data);
return true;
}
function importIndex(key, data) {
if (!data) {
return;
}
if (is_string(data)) {
data = JSON.parse(data);
}
switch (key) {
case "cfg":
this.optimize = !!data["opt"];
break;
case "reg":
this.fastupdate = false;
this.register = data;
break;
case "map":
this.map = data;
break;
case "ctx":
this.ctx = data;
break;
}
}
function exportDocument(callback, self2, field, index_doc, index) {
index || (index = 0);
index_doc || (index_doc = 0);
if (index_doc < this.field.length) {
const field2 = this.field[index_doc];
const idx = this.index[field2];
self2 = this;
setTimeout(function() {
if (!idx.export(callback, self2, index ? field2 : "", index_doc, index++)) {
index_doc++;
index = 1;
self2.export(callback, self2, field2, index_doc, index);
}
});
} else {
let key, data;
switch (index) {
case 1:
key = "tag";
data = this.tagindex;
break;
case 2:
key = "store";
data = this.store;
break;
default:
return;
}
async(callback, this, field, key, index_doc, index, data);
}
}
function importDocument(key, data) {
if (!data) {
return;
}
if (is_string(data)) {
data = JSON.parse(data);
}
switch (key) {
case "tag":
this.tagindex = data;
break;
case "reg":
this.fastupdate = false;
this.register = data;
for (let i = 0, index; i < this.field.length; i++) {
index = this.index[this.field[i]];
index.register = data;
index.fastupdate = false;
}
break;
case "store":
this.store = data;
break;
default:
key = key.split(".");
const field = key[0];
key = key[1];
if (field && key) {
this.index[field].import(key, data);
}
}
}
// src/worker/handler.js
function handler_default(data) {
data = data["data"];
const index = self["_index"];
const args = data["args"];
const task = data["task"];
switch (task) {
case "init":
const options = data["options"] || {};
const factory2 = data["factory"];
const encode2 = options["encode"];
options["cache"] = false;
if (encode2 && encode2.indexOf("function") === 0) {
options["encode"] = Function("return " + encode2)();
}
if (factory2) {
Function("return " + factory2)()(self);
self["_index"] = new self["FlexSearch"]["Index"](options);
delete self["FlexSearch"];
} else {
self["_index"] = new src_default(options);
}
break;
default:
const id = data["id"];
const message = index[task].apply(index, args);
postMessage(task === "search" ? { "id": id, "msg": message } : { "id": id });
}
}
// src/worker/index.js
var pid = 0;
function WorkerIndex(options) {
if (!(this instanceof WorkerIndex)) {
return new WorkerIndex(options);
}
let opt;
if (options) {
if (is_function(opt = options["encode"])) {
options["encode"] = opt.toString();
}
} else {
options = {};
}
let factory2 = (self || window)["_factory"];
if (factory2) {
factory2 = factory2.toString();
}
const is_node_js2 = typeof window === "undefined" && self["exports"];
const _self = this;
this.worker = create(factory2, is_node_js2, options["worker"]);
this.resolver = create_object();
if (!this.worker) {
return;
}
if (is_node_js2) {
this.worker["on"]("message", function(msg) {
_self.resolver[msg["id"]](msg["msg"]);
delete _self.resolver[msg["id"]];
});
} else {
this.worker.onmessage = function(msg) {
msg = msg["data"];
_self.resolver[msg["id"]](msg["msg"]);
delete _self.resolver[msg["id"]];
};
}
this.worker.postMessage({
"task": "init",
"factory": factory2,
"options": options
});
}
var worker_default = WorkerIndex;
register2("add");
register2("append");
register2("search");
register2("update");
register2("remove");
function register2(key) {
WorkerIndex.prototype[key] = WorkerIndex.prototype[key + "Async"] = function() {
const self2 = this;
const args = [].slice.call(arguments);
const arg = args[args.length - 1];
let callback;
if (is_function(arg)) {
callback = arg;
args.splice(args.length - 1, 1);
}
const promise = new Promise(function(resolve) {
setTimeout(function() {
self2.resolver[++pid] = resolve;
self2.worker.postMessage({
"task": key,
"id": pid,
"args": args
});
});
});
if (callback) {
promise.then(callback);
return this;
} else {
return promise;
}
};
}
function create(factory, is_node_js, worker_path) {
let worker;
try {
worker = is_node_js ? eval('new (require("worker_threads")["Worker"])("../dist/node/node.js")') : factory ? new Worker(URL.createObjectURL(
new Blob([
"onmessage=" + handler_default.toString()
], { "type": "text/javascript" })
)) : new Worker(is_string(worker_path) ? worker_path : "worker/worker.js", { type: "module" });
} catch (e) {
}
return worker;
}
// src/document.js
function Document(options) {
if (!(this instanceof Document)) {
return new Document(options);
}
const document = options["document"] || options["doc"] || options;
let opt;
this.tree = [];
this.field = [];
this.marker = [];
this.register = create_object();
this.key = (opt = document["key"] || document["id"]) && parse_tree(opt, this.marker) || "id";
this.fastupdate = parse_option(options["fastupdate"], true);
if (SUPPORT_STORE) {
this.storetree = (opt = document["store"]) && opt !== true && [];
this.store = opt && create_object();
}
if (SUPPORT_TAGS) {
this.tag = (opt = document["tag"]) && parse_tree(opt, this.marker);
this.tagindex = opt && create_object();
}
if (SUPPORT_CACHE) {
this.cache = (opt = options["cache"]) && new cache_default(opt);
options["cache"] = false;
}
if (SUPPORT_WORKER) {
this.worker = options["worker"];
}
if (SUPPORT_ASYNC) {
this.async = false;
}
this.index = parse_descriptor.call(this, options, document);
}
var document_default = Document;
function parse_descriptor(options, document) {
const index = create_object();
let field = document["index"] || document["field"] || document;
if (is_string(field)) {
field = [field];
}
for (let i = 0, key, opt; i < field.length; i++) {
key = field[i];
if (!is_string(key)) {
opt = key;
key = key["field"];
}
opt = is_object(opt) ? Object.assign({}, options, opt) : options;
if (SUPPORT_WORKER && this.worker) {
index[key] = new worker_default(opt);
if (!index[key].worker) {
this.worker = false;
}
}
if (!this.worker) {
index[key] = new src_default(opt, this.register);
}
this.tree[i] = parse_tree(key, this.marker);
this.field[i] = key;
}
if (SUPPORT_STORE && this.storetree) {
let store = document["store"];
if (is_string(store)) {
store = [store];
}
for (let i = 0; i < store.length; i++) {
this.storetree[i] = parse_tree(store[i], this.marker);
}
}
return index;
}
function parse_tree(key, marker) {
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) {
marker[count] = true;
}
}
if (key) {
tree[count++] = key;
}
}
if (count < tree.length) {
tree.length = count;
}
return count > 1 ? tree : tree[0];
}
function parse_simple(obj, tree) {
if (is_string(tree)) {
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];
if (pos === tree.length - 1) {
store[key] = obj;
} else if (obj) {
if (is_array(obj)) {
store = store[key] = new Array(obj.length);
for (let i = 0; i < obj.length; i++) {
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, marker, pos, index, id, key, _append) {
obj = obj[key];
if (obj) {
if (pos === tree.length - 1) {
if (is_array(obj)) {
if (marker[pos]) {
for (let i = 0; i < obj.length; i++) {
index.add(
id,
obj[i],
/* append: */
true,
/* skip update: */
true
);
}
return;
}
obj = obj.join(" ");
}
index.add(
id,
obj,
_append,
/* skip_update: */
true
);
} else {
if (is_array(obj)) {
for (let i = 0; i < obj.length; i++) {
add_index(obj, tree, marker, pos, index, id, i, _append);
}
} else {
key = tree[++pos];
add_index(obj, tree, marker, pos, index, id, key, _append);
}
}
}
}
Document.prototype.add = function(id, content, _append) {
if (is_object(id)) {
content = id;
id = parse_simple(content, this.key);
}
if (content && (id || id === 0)) {
if (!_append && 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 (is_string(tree)) {
tree = [tree];
}
add_index(content, tree, this.marker, 0, this.index[field], id, tree[0], _append);
}
if (SUPPORT_TAGS && this.tag) {
let tag = parse_simple(content, this.tag);
let dupes = create_object();
if (is_string(tag)) {
tag = [tag];
}
for (let i = 0, key, arr; i < tag.length; i++) {
key = tag[i];
if (!dupes[key]) {
dupes[key] = 1;
arr = this.tagindex[key] || (this.tagindex[key] = []);
if (!_append || !arr.includes(id)) {
arr[arr.length] = id;
if (this.fastupdate) {
const tmp = this.register[id] || (this.register[id] = []);
tmp[tmp.length] = arr;
}
}
}
}
}
if (SUPPORT_STORE && this.store && (!_append || !this.store[id])) {
let store;
if (this.storetree) {
store = create_object();
for (let i = 0, tree; i < this.storetree.length; i++) {
tree = this.storetree[i];
if (is_string(tree)) {
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 (is_object(id)) {
id = parse_simple(id, this.key);
}
if (this.register[id]) {
for (let i = 0; i < this.field.length; i++) {
this.index[this.field[i]].remove(id, !this.worker);
if (this.fastupdate) {
break;
}
}
if (SUPPORT_TAGS && this.tag) {
if (!this.fastupdate) {
for (let key in this.tagindex) {
const tag = this.tagindex[key];
const pos = tag.indexOf(id);
if (pos !== -1) {
if (tag.length > 1) {
tag.splice(pos, 1);
} else {
delete this.tagindex[key];
}
}
}
}
}
if (SUPPORT_STORE && this.store) {
delete this.store[id];
}
delete this.register[id];
}
return this;
};
Document.prototype.search = function(query, limit, options, _resolve) {
if (!options) {
if (!limit && is_object(query)) {
options = /** @type {Object} */
query;
query = "";
} else if (is_object(limit)) {
options = /** @type {Object} */
limit;
limit = 0;
}
}
let result = [], result_field = [];
let pluck, enrich;
let field, tag, bool, offset, count = 0;
if (options) {
if (is_array(options)) {
field = options;
options = null;
} else {
query = options["query"] || query;
pluck = options["pluck"];
field = pluck || options["index"] || options["field"];
tag = SUPPORT_TAGS && options["tag"];
enrich = SUPPORT_STORE && this.store && options["enrich"];
bool = options["bool"] === "and";
limit = options["limit"] || limit || 100;
offset = options["offset"] || 0;
if (tag) {
if (is_string(tag)) {
tag = [tag];
}
if (!query) {
for (let i = 0, res; i < tag.length; i++) {
res = get_tag.call(this, tag[i], limit, offset, enrich);
if (res) {
result[result.length] = res;
count++;
}
}
return count ? result : [];
}
}
if (is_string(field)) {
field = [field];
}
}
}
field || (field = this.field);
bool = bool && (field.length > 1 || tag && tag.length > 1);
const promises = !_resolve && (this.worker || this.async) && [];
for (let i = 0, res, key, len; i < field.length; i++) {
let field_options;
key = field[i];
if (!is_string(key)) {
field_options = key;
key = field_options["field"];
query = field_options["query"] || query;
limit = field_options["limit"] || limit;
}
if (promises) {
promises[i] = this.index[key].searchAsync(query, limit, field_options || options);
continue;
} else if (_resolve) {
res = _resolve[i];
} else {
res = this.index[key].search(query, limit, field_options || options);
}
len = res && res.length;
if (tag && len) {
const arr = [];
let count2 = 0;
if (bool) {
arr[0] = [res];
}
for (let y = 0, key2, res2; y < tag.length; y++) {
key2 = tag[y];
res2 = this.tagindex[key2];
len = res2 && res2.length;
if (len) {
count2++;
arr[arr.length] = bool ? [res2] : res2;
}
}
if (count2) {
if (bool) {
res = intersect(arr, limit || 100, offset || 0);
} else {
res = intersect_union(res, arr);
}
len = res.length;
}
}
if (len) {
result_field[count] = key;
result[count++] = res;
} else if (bool) {
return [];
}
}
if (promises) {
const self2 = this;
return new Promise(function(resolve) {
Promise.all(promises).then(function(result2) {
resolve(self2.search(query, limit, options, result2));
});
});
}
if (!count) {
return [];
}
if (pluck && (!enrich || !this.store)) {
return result[0];
}
for (let i = 0, res; i < result_field.length; i++) {
res = result[i];
if (res.length) {
if (enrich) {
res = apply_enrich.call(this, res);
}
}
if (pluck) {
return res;
}
result[i] = {
"field": result_field[i],
"result": res
};
}
return result;
};
function get_tag(key, limit, offset, enrich) {
let res = this.tagindex[key];
let len = res && res.length - offset;
if (len && len > 0) {
if (len > limit || offset) {
res = res.slice(offset, offset + limit);
}
if (enrich) {
res = apply_enrich.call(this, res);
}
return {
"tag": key,
"result": res
};
}
}
function apply_enrich(res) {
const arr = new Array(res.length);
for (let x = 0, id; x < res.length; x++) {
id = res[x];
arr[x] = {
"id": id,
"doc": this.store[id]
};
}
return arr;
}
Document.prototype.contain = function(id) {
return !!this.register[id];
};
if (SUPPORT_STORE) {
Document.prototype.get = function(id) {
return this.store[id];
};
Document.prototype.set = function(id, data) {
this.store[id] = data;
return this;
};
}
if (SUPPORT_CACHE) {
Document.prototype.searchCache = searchCache;
}
if (SUPPORT_SERIALIZE) {
Document.prototype.export = exportDocument;
Document.prototype.import = importDocument;
}
if (SUPPORT_ASYNC) {
async_default(Document.prototype);
}
// src/index.js
function create2(options) {
return new Index(options);
}
function Index(options, _register) {
if (!(this instanceof Index)) {
return new Index(options);
}
let charset, lang, tmp;
if (options) {
if (SUPPORT_ENCODER) {
options = apply_preset(options);
}
charset = options["charset"];
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];
}
} else {
options = {};
}
let resolution, optimize, context = options["context"] || {};
this.encode = options["encode"] || charset && charset.encode || encode;
this.register = _register || create_object();
this.resolution = resolution = options["resolution"] || 9;
this.tokenize = tmp = charset && charset.tokenize || options["tokenize"] || "strict";
this.depth = tmp === "strict" && context["depth"];
this.bidirectional = parse_option(context["bidirectional"], true);
this.optimize = optimize = parse_option(options["optimize"], true);
this.fastupdate = parse_option(options["fastupdate"], true);
this.minlength = options["minlength"] || 1;
this.boost = options["boost"];
this.map = optimize ? create_object_array(resolution) : create_object();
this.resolution_ctx = resolution = context["resolution"] || 1;
this.ctx = optimize ? create_object_array(resolution) : 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_default(tmp);
}
}
var src_default = Index;
Index.prototype.append = function(id, content) {
return this.add(id, content, true);
};
Index.prototype.add = function(id, content, _append, _skip_update) {
if (content && (id || id === 0)) {
if (!_skip_update && !_append && this.register[id]) {
return this.update(id, content);
}
content = this.encode("" + content);
const length = content.length;
if (length) {
const dupes_ctx = create_object();
const dupes = create_object();
const depth = this.depth;
const resolution = this.resolution;
for (let i = 0; i < length; i++) {
let term = content[this.rtl ? length - 1 - i : i];
let term_length = term.length;
if (term && term_length >= this.minlength && (depth || !dupes[term])) {
let score = get_score(resolution, length, i);
let token = "";
switch (this.tokenize) {
case "full":
if (term_length > 2) {
for (let x = 0; x < term_length; x++) {
for (let y = term_length; y > x; y--) {
if (y - x >= this.minlength) {
const partial_score = get_score(resolution, length, i, term_length, x);
token = term.substring(x, y);
this.push_index(dupes, token, partial_score, id, _append);
}
}
}
break;
}
case "reverse":
if (term_length > 1) {
for (let x = term_length - 1; x > 0; x--) {
token = term[x] + token;
if (token.length >= this.minlength) {
const partial_score = get_score(resolution, length, i, term_length, x);
this.push_index(dupes, token, partial_score, id, _append);
}
}
token = "";
}
case "forward":
if (term_length > 1) {
for (let x = 0; x < term_length; x++) {
token += term[x];
if (token.length >= this.minlength) {
this.push_index(dupes, token, score, id, _append);
}
}
break;
}
default:
if (this.boost) {
score = Math.min(score / this.boost(content, term, i) | 0, resolution - 1);
}
this.push_index(dupes, term, score, id, _append);
if (depth) {
if (length > 1 && i < length - 1) {
const dupes_inner = create_object();
const resolution2 = this.resolution_ctx;
const keyword = term;
const 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 = get_score(resolution2 + (length / 2 > resolution2 ? 0 : 1), length, i, size - 1, x - 1);
const swap = this.bidirectional && term > keyword;
this.push_index(dupes_ctx, swap ? keyword : term, context_score, id, _append, swap ? term : keyword);
}
}
}
}
}
}
}
this.fastupdate || (this.register[id] = 1);
}
}
return this;
};
function get_score(resolution, length, i, term_length, x) {
return i && resolution > 1 ? length + (term_length || 0) <= resolution ? i + (x || 0) : (resolution - 1) / (length + (term_length || 0)) * (i + (x || 0)) + 1 | 0 : 0;
}
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 = dupes[value] || (dupes[value] = create_object());
dupes[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.includes(id)) {
arr[arr.length] = id;
if (this.fastupdate) {
const tmp = this.register[id] || (this.register[id] = []);
tmp[tmp.length] = arr;
}
}
}
};
Index.prototype.search = function(query, limit, options) {
if (!options) {
if (!limit && is_object(query)) {
options = /** @type {Object} */
query;
query = options["query"];
} else if (is_object(limit)) {
options = /** @type {Object} */
limit;
}
}
let result = [];
let length;
let context, suggest, offset = 0;
if (options) {
query = options["query"] || query;
limit = options["limit"];
offset = options["offset"] || 0;
context = options["context"];
suggest = SUPPORT_SUGGESTION && options["suggest"];
}
if (query) {
query = /** @type {Array} */
this.encode("" + query);
length = query.length;
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]) {
if (!this.optimize && !suggest && !this.map[term]) {
return result;
} else {
query_new[count++] = term;
dupes[term] = 1;
}
}
}
query = query_new;
length = query.length;
}
}
if (!length) {
return result;
}
limit || (limit = 100);
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, limit, offset, length === 2, term, keyword);
if (!suggest || arr !== false || !result.length) {
keyword = term;
}
} else {
arr = this.add_result(result, suggest, limit, offset, length === 1, term);
}
if (arr) {
return (
/** @type {Array<number|string>} */
arr
);
}
if (suggest && index === length - 1) {
let length2 = result.length;
if (!length2) {
if (depth) {
depth = 0;
index = -1;
continue;
}
return result;
} else if (length2 === 1) {
return single_result(result[0], limit, offset);
}
}
}
return intersect(result, limit, offset, suggest);
};
Index.prototype.add_result = function(result, suggest, limit, offset, single_term, term, keyword) {
let word_arr = [];
let arr = keyword ? this.ctx : this.map;
if (!this.optimize) {
arr = get_array(arr, term, keyword, this.bidirectional);
}
if (arr) {
let count = 0;
const arr_len = Math.min(arr.length, keyword ? this.resolution_ctx : this.resolution);
for (let x = 0, size = 0, tmp, len; x < arr_len; x++) {
tmp = arr[x];
if (tmp) {
if (this.optimize) {
tmp = get_array(tmp, term, keyword, this.bidirectional);
}
if (offset) {
if (tmp && single_term) {
len = tmp.length;
if (len <= offset) {
offset -= len;
tmp = null;
} else {
tmp = tmp.slice(offset);
offset = 0;
}
}
}
if (tmp) {
word_arr[count++] = tmp;
if (single_term) {
size += tmp.length;
if (size >= limit) {
break;
}
}
}
}
}
if (count) {
if (single_term) {
return single_result(word_arr, limit, 0);
}
result[result.length] = word_arr;
return;
}
}
return !suggest && word_arr;
};
function single_result(result, limit, offset) {
if (result.length === 1) {
result = result[0];
} else {
result = concat(result);
}
return offset || result.length > limit ? result.slice(offset, offset + limit) : result;
}
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;
}
Index.prototype.contain = function(id) {
return !!this.register[id];
};
Index.prototype.update = function(id, content) {
return this.remove(id).add(id, content);
};
Index.prototype.remove = function(id, _skip_deletion) {
const refs = this.register[id];
if (refs) {
if (this.fastupdate) {
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.optimize);
if (this.depth) {
remove_index(this.ctx, id, this.resolution_ctx, this.optimize);
}
}
_skip_deletion || delete this.register[id];
if (SUPPORT_CACHE && this.cache) {
this.cache.del(id);
}
}
return this;
};
function remove_index(map, id, res, optimize, resolution) {
let count = 0;
if (is_array(map)) {
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) {
delete map[x];
}
}
}
} else {
const pos = map.indexOf(id);
if (pos !== -1) {
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_SERIALIZE) {
Index.prototype.export = exportIndex;
Index.prototype.import = importIndex;
}
if (SUPPORT_ASYNC) {
async_default(Index.prototype);
}