Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

flexsearch

Package Overview
Dependencies
Maintainers
1
Versions
87
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

flexsearch - npm Package Compare versions

Comparing version 0.0.9 to 0.1.21

.nyc_output/bbb3ccfc95787015bb65e81e26736d87.json

1949

flexsearch.js

@@ -10,415 +10,357 @@ /**!

window['FlexSearch'] = (function(queue, cache){
(function(){
"use strict";
register('FlexSearch', (function factory(register_worker){
/**
* @enum {number|string|boolean}
* @private
* @const
* @final
*/
"use strict";
var defaults = {
/**
* @enum {number|string|boolean}
* @private
* @const
* @final
*/
// bitsize of assigned IDs (data type)
type: 'integer',
var defaults = {
// type of information
result: 'id',
// bitsize of assigned IDs (data type)
type: 'integer',
// type of information
mode: 'forward',
// type of information
mode: 'forward',
// match when starts from beginning
strict: false,
// boolean model of multiple words
boolean: false,
// handle multiple words as separated queries
multi: false,
// use flexible cache (scales automatically)
cache: false,
// boolean model of multiple words
boolean: false,
// use flexible cache (scales automatically)
async: false,
// matching in strict order (multiple words)
ordered: false,
// use flexible cache (scales automatically)
worker: false,
// use flexible cache (scales automatically)
cache: false,
// use on of built-in functions
// or pass custom encoding algorithm
encode: false,
// use flexible cache (scales automatically)
async: false,
// use flexible cache (scales automatically)
threads: 4,
// use on of built-in functions
// or pass custom encoding algorithm
encode: false
};
// debug flag
debug: true
};
/**
* Phonetic Encoders
* @enum {Function|boolean}
* @private
* @const
* @final
*/
/**
* @type {Array<Array>}
* @private
*/
var encoder = {
var custom_matchers = [];
// case insensitive search
/**
* @type {number}
* @private
*/
'icase': function(value){
var id_counter = 0;
return value.toLowerCase();
},
/**
* @enum {number}
*/
// simple phonetic normalization (latin)
var enum_task = {
'simple': (function(){
add: 0,
update: 1,
remove: 2
};
var regex_strip = regex('[^a-z0-9 ]'),
regex_a = regex('[àáâãäå]'),
regex_e = regex('[èéêë]'),
regex_i = regex('[ìíîï]'),
regex_o = regex('[òóôõöő]'),
regex_u = regex('[ùúûüű]'),
regex_y = regex('[ýŷÿ]'),
regex_n = regex('ñ'),
regex_c = regex('ç'),
regex_s = regex('ß');
/**
* @param {Object<string, number|string|boolean>=} options
* @constructor
* @private
*/
return function(str) {
function FlexSearch(options){
return (
options || (options = defaults);
str.toLowerCase()
.replace(regex_a, 'a')
.replace(regex_e, 'e')
.replace(regex_i, 'i')
.replace(regex_o, 'o')
.replace(regex_u, 'u')
.replace(regex_y, 'y')
.replace(regex_n, 'n')
.replace(regex_c, 'c')
.replace(regex_s, 's')
.replace(regex_strip, '')
);
};
}()),
// generate UID
// advanced phonetic transformation (latin)
this.id = options['id'] || id_counter++;
'advanced': (function(){
// initialize index
var regex_space = regex(' '),
regex_ae = regex('ae'),
regex_oe = regex('oe'),
regex_ue = regex('ue'),
regex_ie = regex('ie'),
regex_sz = regex('sz'),
regex_zs = regex('zs'),
regex_ck = regex('ck'),
regex_cc = regex('cc'),
regex_sh = regex('sh'),
regex_th = regex('th'),
regex_dt = regex('dt'),
regex_ph = regex('ph'),
regex_ou = regex('ou'),
regex_uo = regex('uo');
this.init(options);
}
return function(string, _skip_post_processing){
/**
* @param {Object<string, number|string|boolean>=} options
*/
if(!string){
FlexSearch.create = function(options){
return string;
}
return new this(options);
};
// perform simple encoding
string = encoder['simple'](string);
/**
* @param {Object<string, string>} matcher
*/
// normalize special pairs
if(string.length > 2){
FlexSearch.addMatcher = function(matcher){
string = string.replace(regex_ae, 'a')
.replace(regex_oe, 'o')
.replace(regex_ue, 'u')
.replace(regex_ie, 'i')
.replace(regex_sz, 's')
.replace(regex_zs, 's')
.replace(regex_sh, 's')
.replace(regex_ck, 'k')
.replace(regex_cc, 'k')
.replace(regex_th, 't')
.replace(regex_dt, 't')
.replace(regex_ph, 'f')
.replace(regex_ou, 'o')
.replace(regex_uo, 'u');
}
for(var key in matcher){
if(!_skip_post_processing){
if(matcher.hasOwnProperty(key)){
// remove white spaces
string = string.replace(regex_space, '');
custom_matchers[custom_matchers.length] = [
// delete all repeating chars
if(string.length > 1){
string = collapseRepeatingChars(string);
}
regex(key), matcher[key]
];
}
}
};
return string;
};
/**
* @param {Object<string, number|string|boolean>=} options
* @export
*/
})(),
FlexSearch.prototype.init = function(options){
'extra': (function(){
if(options){
var soundex_b = regex('p'),
soundex_c = regex('[sz]'),
soundex_k = regex('[gq]'),
soundex_i = regex('[jy]'),
soundex_m = regex('n'),
soundex_t = regex('d'),
soundex_f = regex('[vw]');
// initialize worker
var regex_vowel = regex('[aeiouy]');
if(options['worker']){
return function(str) {
if(typeof Worker === 'undefined'){
if(!str){
options['worker'] = false;
}
else{
return str;
}
var self = this;
var threads = options['threads'] || defaults['threads'];
// perform advanced encoding
str = encoder['advanced'](str, /* skip post processing? */ true);
self._current_task = -1;
self._task_completed = 0;
self._task_result = [];
self._current_callback = null;
self._worker = new Array(threads);
if(str.length > 1){
for(var i = 0; i < threads; i++){
str = str.split(" ");
self._worker[i] = add_worker(self.id, i, options || defaults, function(id, query, result, limit){
for(var i = 0; i < str.length; i++){
if(self._task_completed === self.threads){
var current = str[i];
return;
}
if(current.length > 1){
self._task_result = self._task_result.concat(result);
self._task_completed++;
// remove all vowels after 2nd char
str[i] = current[0] + current.substring(1)
.replace(soundex_b, 'b')
.replace(soundex_c, 'c')
.replace(soundex_k, 'k')
.replace(soundex_i, 'i')
.replace(soundex_m, 'm')
.replace(soundex_t, 't')
.replace(soundex_f, 'f')
.replace(regex_vowel, '');
}
}
if(limit && (self._task_result.length >= limit)){
str = str.join("");
str = collapseRepeatingChars(str);
}
self._task_completed = self.threads;
}
return str;
};
})()
if(self._current_callback && (self._task_completed === self.threads)){
// TODO: provide some common encoder plugins
// soundex
// cologne
// metaphone
// caverphone
// levinshtein
// hamming
// matchrating
// ngram
};
if(self._task_result.length){
/**
* @type {Array<Array>}
* @private
*/
self._last_empty_query = "";
}
else{
var custom_matchers = [];
self._last_empty_query || (self._last_empty_query = query);
}
/**
* @type {number}
* @private
*/
// store result to cache
var id_counter = 0;
if(self.cache){
/**
* @type {string}
* @private
*/
self._cache.set(query, self._task_result);
}
var last_empty_query = "";
self._current_callback(self._task_result);
self._task_result = [];
}
});
}
}
}
/**
* @type {Object<string, number>}
* @private
*/
// apply options
var scores = {};
this.mode = (
/**
* @param {Object<string, number|string|boolean>=} options
* @constructor
* @implements _search_struct
* @private
*/
options['mode'] ||
this.mode ||
defaults.mode
);
function FlexSearch(options){
this.boolean = (
// generate UID
options['boolean'] === 'or' ||
this.boolean ||
defaults.boolean
);
this.id = id_counter++;
this.cache = (
// initialize index
options['cache'] ||
this.cache ||
defaults.cache
);
this.init(options || defaults);
}
this.async = (
/**
* @param {Object<string, number|string|boolean>=} options
* @returns _search_struct
*/
options['async'] ||
this.async ||
defaults.async
);
FlexSearch.create =
FlexSearch.new = function(options){
this.worker = (
return new this(options);
};
options['worker'] ||
this.worker ||
defaults.worker
);
/**
* @param {Object<string, string>} matcher
*/
this.threads = (
FlexSearch.addMatcher = function(matcher){
options['threads'] ||
this.threads ||
defaults.threads
);
for(var key in matcher){
this.encoder = (
if(matcher.hasOwnProperty(key)){
(options['encode'] && encoder[options['encode']]) ||
this.encoder ||
(defaults.encode && encoder[defaults.encode]) ||
options['encode']
);
custom_matchers[custom_matchers.length] = [
this.debug = (
regex(key), matcher[key]
];
options['debug'] ||
this.debug ||
defaults.debug
);
}
}
};
/**
* @param {Object<string, number|string|boolean>=} options
*/
// initialize index
FlexSearch.prototype.init = function(options){
this._map = {};
this._ids = {};
// apply options
/**
* @type {Object<string|number, Array>}
*/
if(options){
this._stack = {};
this.type = (
/**
* @type {Array<string|number>}
*/
options['type'] ||
this.type ||
defaults.type
);
this._stack_keys = [];
this.result = (
/**
* @type {number|null}
*/
options['result'] ||
this.result ||
defaults.result
);
this._timer = null;
this._last_empty_query = "";
this._status = true;
this._cache = this.cache ?
this.mode = (
(new cache(30 * 1000, 50, true))
:
false;
};
options['mode'] ||
this.mode ||
defaults.mode
);
/**
* @param {!string} value
* @returns {*}
*/
this.strict = (
FlexSearch.prototype.encode = function(value){
options['strict'] ||
this.strict ||
defaults.strict
);
if(this.encoder){
this.ordered = (
value = this.encoder(value);
}
options['ordered'] ||
this.ordered ||
defaults.ordered
);
if(custom_matchers.length){
this.multi = (
for(var i = 0; i < custom_matchers.length; i++){
options['multi'] ||
this.multi ||
defaults.multi
);
var matcher = custom_matchers[i];
this.boolean = (
value = value.replace(matcher[0], matcher[1]);
}
}
options['boolean'] === 'or' ||
this.boolean ||
defaults.boolean
);
return value;
};
this.cache = (
/**
* @param {!number|string} id
* @param {!string} content
* @export
*/
options['cache'] ||
this.cache ||
defaults.cache
);
FlexSearch.prototype.add = function(id, content){
this.async = (
if((typeof content === 'string') && content && (id || (id === 0))){
options['async'] ||
this.async ||
defaults.async
);
// check if index ID already exist
this.encode = (
if(this._ids[id]){
(options['encode'] && encoder[options['encode']]) ||
this.encode ||
(defaults.encode && encoder[defaults.encode])
);
}
this.update(id, content);
}
else{
// initialize index
if(this.worker){
this._map = {};
this._ids = {};
this._status = true;
this._cache = this.cache ?
if(++this._current_task >= this._worker.length) this._current_task = 0;
/** @type _cache_struct */
(new cache(30 * 1000, 50, true))
:
false;
};
this._worker[this._current_task].postMessage(this._current_task, {
/**
* @param {!number|string} id
* @param {!string} content
*/
'add': true,
'id': id,
'content': content
});
FlexSearch.prototype.set =
FlexSearch.prototype.add = function(id, content){
this._ids[id] = "" + this._current_task;
if(content){
return;
}
// check if index ID already exist
if(this.async){
if(this._ids[id]){
this._stack[id] || (
this.update(id, content);
}
else{
this._stack_keys[this._stack_keys.length] = id
);
this._stack[id] = [
enum_task.add,
id,
content
];
register_task(this);
return;
}
var dupes = {};

@@ -433,5 +375,5 @@ var words = content.split(' ');

if(this.encode) {
if(this.encode){
value = apply_encoding(value, this.encode);
value = this.encode(value);
}

@@ -444,4 +386,5 @@

case 'inverse':
case 'both':
var tmp = "";
var tmp = "", arr;

@@ -455,10 +398,26 @@ for(var a = value.length - 1; a >= 1; a--){

dupes[tmp] = "1";
this._map[tmp] || (this._map[tmp] = []);
this._map[tmp].push(id);
(arr = this._map[tmp[0]]) || (
this._map[tmp[0]] = arr = {}
);
if(!arr[tmp]){
arr[tmp] = arr = [];
}
else{
arr = arr[tmp];
}
arr[arr.length] = id;
}
}
// Note: no break here, fallthrough to next case
case 'forward':
var tmp = "";
var tmp = "", arr;

@@ -472,4 +431,18 @@ for(var a = 0; a < value.length; a++){

dupes[tmp] = "1";
this._map[tmp] || (this._map[tmp] = []);
this._map[tmp].push(id);
(arr = this._map[tmp[0]]) || (
this._map[tmp[0]] = arr = {}
);
if(!arr[tmp]){
arr[tmp] = arr = [];
}
else{
arr = arr[tmp];
}
arr[arr.length] = id;
}

@@ -482,3 +455,3 @@ }

var tmp = "";
var tmp = "", arr;

@@ -494,4 +467,18 @@ for(var x = 0; x < value.length; x++){

dupes[tmp] = "1";
this._map[tmp] || (this._map[tmp] = []);
this._map[tmp].push(id);
(arr = this._map[tmp[0]]) || (
this._map[tmp[0]] = arr = {}
);
if(!arr[tmp]){
arr[tmp] = arr = [];
}
else{
arr = arr[tmp];
}
arr[arr.length] = id;
}

@@ -502,2 +489,30 @@ }

break;
case 'strict':
default:
if(!dupes[value]){
var arr;
dupes[value] = "1";
(arr = this._map[value[0]]) || (
this._map[value[0]] = arr = {}
);
if(!arr[value]){
arr[value] = arr = [];
}
else{
arr = arr[value];
}
arr[arr.length] = id;
}
break;
}

@@ -514,223 +529,317 @@ }

}
if(this.async){
return Promise.resolve(this);
}
};
FlexSearch.prototype.update = function(id, content){
/**
* @param id
* @param content
* @export
*/
var marker = this._ids[id];
FlexSearch.prototype.update = function(id, content){
if(marker){
if((typeof content === 'string') && (id || (id === 0))){
this.remove(id);
if(this._ids[id]){
if(content){
if(this.worker){
this.add(id, content);
}
}
var int = parseInt(this._ids[id], 10);
if(this.async){
this._worker[int].postMessage(int, {
return Promise.resolve(this);
}
};
'update': true,
'id': id,
'content': content
});
FlexSearch.prototype.delete =
FlexSearch.prototype.remove = function(id){
return;
}
var keys = Object.keys(this._map);
var tmp;
if(this.async){
for(var i = 0; i < keys.length; i++){
this._stack[id] || (
tmp = this._map[keys[i]];
this._stack_keys[this._stack_keys.length] = id
);
for(var a = 0; a < tmp.length; a++){
this._stack[id] = [
if(tmp[a] === id){
enum_task.update,
id,
content
];
tmp.splice(a, 1);
register_task(this);
break;
return;
}
}
if(!tmp.length){
this.remove(id);
delete this._map[keys[i]];
if(content){
this.add(id, content);
}
}
}
};
delete this._ids[id];
/**
* @param id
* @export
*/
if(this.async){
FlexSearch.prototype.remove = function(id){
return Promise.resolve(this);
}
};
if(this._ids[id]){
/**
* @param {string} query
* @param {number|Function} limit
* @param {Function=} callback
* @returns {Array}
*/
if(this.worker){
FlexSearch.prototype.search =
FlexSearch.prototype.query =
FlexSearch.prototype.find = function(query, limit, callback){
var int = parseInt(this._ids[id], 10);
if(typeof limit === 'function'){
this._worker[int].postMessage(int, {
callback = limit;
limit = 0;
'remove': true,
'id': id
});
delete this._ids[id];
return;
}
limit || (limit = 1000);
if(this.async){
if(callback){
this._stack[id] || (
var self = this;
this._stack_keys[this._stack_keys.length] = id
);
queue(function(){
this._stack[id] = [
callback(self.search(query, limit));
self = null;
enum_task.remove,
id
];
}, 'search-' + this.id);
register_task(this);
return null;
return;
}
var _query = query;
var lexical = Object.keys(this._map);
// invalidate cache
for(var z = 0; z < lexical.length; z++){
if(!this._status){
var keys = Object.keys(this._map[lexical[z]]);
if(this.cache){
for(var i = 0; i < keys.length; i++){
this._cache.reset();
}
var key = keys[i];
var tmp = this._map[lexical[z]];
tmp = tmp && tmp[key];
this._status = true;
}
if(tmp && tmp.length){
// validate cache
for(var a = 0; a < tmp.length; a++){
else if(this.cache){
if(tmp[a] === id){
var cache = this._cache.get(query);
tmp.splice(a, 1);
if(cache){
break;
}
}
}
return cache;
if(!tmp.length){
delete this._map[lexical[z]][key];
}
}
}
// validate last input
delete this._ids[id];
else if(last_empty_query && (query.indexOf(last_empty_query) !== -1)){
this._status = false;
}
};
return [];
}
var regex_split = regex("[ -/]");
// remove trailing spaces
/**
* @param {string} query
* @param {number|Function} limit
* @param {Function=} callback
* @returns {Array}
* @export
*/
var spaces = 0;
FlexSearch.prototype.search = function(query, limit, callback){
while(query[spaces] === " "){
if((typeof query !== 'string') || !query){
spaces++;
return [];
}
else if(typeof limit === 'function'){
callback = limit;
limit = 1000;
}
else{
limit || (limit = 1000);
}
var _query = query;
// invalidate cache
if(!this._status){
if(this.cache){
this._last_empty_query = "";
this._cache.reset();
}
if(spaces){
this._status = true;
}
_query = query.substring(spaces);
// validate cache
else if(this.cache){
var cache = this._cache.get(query);
if(cache){
return cache;
}
}
if(!query){
// validate last input
return [];
else if(this._last_empty_query && (query.indexOf(this._last_empty_query) !== -1)){
return [];
}
if(this.worker){
this._current_callback = callback;
this._task_completed = 0;
this._task_result = [];
for(var i = 0; i < this.threads; i++){
this._worker[i].postMessage(i, {
'search': true,
'limit': limit,
'content': query
});
}
// convert words into single components
return null;
}
var words = (
if(callback){
this.multi ?
var self = this;
_query.split(' ')
:
[_query]
);
queue(function(){
// sort words by length
callback(self.search(query, limit));
self = null;
// if((length > 1) && !this.boolean){
//
// words.sort(sort_by_length);
// }
}, 1, 'search-' + this.id);
// var encoded = new Array(length);
return null;
}
// encode query
// remove trailing spaces
// if(this.encode){
//
// words[0] = apply_encoding(
//
// words[0], this.encode, false
// );
// }
var spaces = 0;
// perform search
while(query[spaces] === " "){
var result = [];
spaces++;
}
var map;
var found = true;
var value;
var check = [];
var check_words = {};
if(spaces){
for(var a = 0; a < words.length; a++){
_query = query.substring(spaces);
}
value = words[a];
if(!_query){
if(check_words[value]){
return [];
}
continue;
}
// convert words into single components
if(value){
var words = _query.split(regex_split);
value = this.encode(value);
}
// sort words by length
if(value){
if(words.length > 1){
if(map = this._map[value]){
words.sort(sort_by_length_down);
}
check[check.length] = map;
}
else{
// perform search
found = false;
break;
}
var result = [];
var found = true;
var check = [];
var check_words = {};
check_words[words[a]] = "1";
for(var a = 0; a < words.length; a++){
var value = words[a];
if(check_words[value]){
continue;
}
if(value && this.encode){
value = this.encode(value);
}
if(value){
var map = this._map[value[0]];
map = map && map[value];
if(map && map.length){
check[check.length] = map;
}
else{
found = false;
break;
}
check_words[words[a]] = "1";
}
}
if(found){
if(found){
// sort by length
if(check.length > 1){
check.sort(sort_by_length_up);
}
var count = 0;
var tmp = check[count++];
if(tmp){
var length = check.length;
var count = 0;
var tmp = check[count];

@@ -741,3 +850,3 @@ while(tmp.length && (count < length)){

tmp = intersect(tmp, item, count === length ? limit : 0);
tmp = intersect(tmp, item, count === length ? /** @type {number} */ (limit) : 0);
}

@@ -752,44 +861,88 @@

}
}
if(result.length){
if(result.length){
last_empty_query = "";
}
else{
this._last_empty_query = "";
}
else{
last_empty_query || (last_empty_query = query);
}
this._last_empty_query || (this._last_empty_query = query);
}
// store result to cache
// store result to cache
if(this.cache) {
if(this.cache){
this._cache.set(query, result);
}
this._cache.set(query, result);
}
return result;
};
return result;
};
FlexSearch.prototype.info = function(){
/**
* @export
*/
var keys = Object.keys(this._map);
var bytes = 0;
FlexSearch.prototype.info = function(){
for(var i = 0; i < keys.length; i++){
if(this.worker){
bytes += this._map[keys[i]].length * 4 + keys[i].length * 2;
}
for(var i = 0; i < this.threads; i++) this._worker[i].postMessage(i, {
return {
'info': true,
'id': this.id
});
'id': this.id,
'bytes': bytes,
'status': this._status,
'matchers': custom_matchers.length
return;
}
var keys;
var bytes = 0,
words = 0,
chars = 0;
keys = Object.keys(this._map);
var length, current;
for(var i = 0; i < keys.length; i++){
current = '' + keys[i];
length = this._map[current].length;
// Note: 1 char values allocates 1 byte "Map (OneByteInternalizedString)"
bytes += length * 1 + current.length * 2;
words += length;
chars += length * current.length;
}
keys = Object.keys(this._ids);
var items = keys.length;
for(var i = 0; i < items; i++){
bytes += keys[i].length * 2 + 2;
}
return {
'id': this.id,
'memory': bytes,
'items': items,
'sequences': words,
'chars': chars,
'status': this._status,
'cache': this._stack_keys.length,
'matchers': custom_matchers.length
};
};
};
FlexSearch.prototype.reset =
FlexSearch.prototype.clear = function(){
/**
* @export
*/
FlexSearch.prototype.reset = function(){
// destroy index

@@ -804,264 +957,786 @@

FlexSearch.prototype.destroy = function(){
/**
* @export
*/
// cleanup cache
FlexSearch.prototype.destroy = function(){
if(this.cache){
// cleanup cache
this._cache.reset();
}
if(this.cache){
// release references
this._cache.reset();
}
this._map = null;
this._cache = null;
};
// release references
return FlexSearch;
this._map = null;
this._ids = null;
this._cache = null;
};
// ---------------------------------------------------------
// Helpers
/**
* Phonetic Encoders
* @enum {Function|boolean}
* @private
* @const
* @final
*/
function regex(str){
var encoder = {
return new RegExp(str, 'g');
}
// case insensitive search
function apply_custom_matchers(str){
'icase': function(value){
for(var i = 0; i < custom_matchers.length; i++){
return value.toLowerCase();
},
var matcher = custom_matchers[i];
// simple phonetic normalization (latin)
str = str.replace(matcher[0], matcher[1]);
}
'simple': (function(){
return str;
}
var regex_strip = regex('[^a-z0-9 ]'),
regex_split = regex('[-/]'),
regex_a = regex('[àáâãäå]'),
regex_e = regex('[èéêë]'),
regex_i = regex('[ìíîï]'),
regex_o = regex('[òóôõöő]'),
regex_u = regex('[ùúûüű]'),
regex_y = regex('[ýŷÿ]'),
regex_n = regex('ñ'),
regex_c = regex('ç'),
regex_s = regex('ß');
function apply_encoding(content, encode){
return function(str){
content = encode(content);
return (
if(custom_matchers.length){
str.toLowerCase()
.replace(regex_a, 'a')
.replace(regex_e, 'e')
.replace(regex_i, 'i')
.replace(regex_o, 'o')
.replace(regex_u, 'u')
.replace(regex_y, 'y')
.replace(regex_n, 'n')
.replace(regex_c, 'c')
.replace(regex_s, 's')
.replace(regex_split, ' ')
.replace(regex_strip, '')
);
};
}()),
content = apply_custom_matchers(content);
// advanced phonetic transformation (latin)
'advanced': (function(){
var regex_space = regex(' '),
regex_ae = regex('ae'),
regex_ai = regex('ai'),
regex_ay = regex('ay'),
regex_ey = regex('ey'),
regex_oe = regex('oe'),
regex_ue = regex('ue'),
regex_ie = regex('ie'),
regex_sz = regex('sz'),
regex_zs = regex('zs'),
regex_ck = regex('ck'),
regex_cc = regex('cc'),
regex_sh = regex('sh'),
//regex_th = regex('th'),
regex_dt = regex('dt'),
regex_ph = regex('ph'),
regex_ou = regex('ou'),
regex_uo = regex('uo');
return function(string, _skip_post_processing){
if(!string){
return string;
}
// perform simple encoding
string = encoder['simple'](string);
// normalize special pairs
if(string.length > 2){
string = string.replace(regex_ae, 'a')
.replace(regex_ai, 'ei')
.replace(regex_ay, 'ei')
.replace(regex_ey, 'ei')
.replace(regex_oe, 'o')
.replace(regex_ue, 'u')
.replace(regex_ie, 'i')
.replace(regex_sz, 's')
.replace(regex_zs, 's')
.replace(regex_sh, 's')
.replace(regex_ck, 'k')
.replace(regex_cc, 'k')
//.replace(regex_th, 't')
.replace(regex_dt, 't')
.replace(regex_ph, 'f')
.replace(regex_ou, 'o')
.replace(regex_uo, 'u');
}
if(!_skip_post_processing){
// remove white spaces
string = string.replace(regex_space, '');
// delete all repeating chars
if(string.length > 1){
string = collapseRepeatingChars(string);
}
}
return string;
};
})(),
'extra': (function(){
var soundex_b = regex('p'),
soundex_c = regex('[sz]'),
soundex_k = regex('[gq]'),
soundex_i = regex('[jy]'),
soundex_m = regex('n'),
soundex_t = regex('d'),
soundex_f = regex('[vw]');
var regex_vowel = regex('[aeiouy]');
return function(str){
if(!str){
return str;
}
// perform advanced encoding
str = encoder['advanced'](str, /* skip post processing? */ true);
if(str.length > 1){
str = str.split(" ");
for(var i = 0; i < str.length; i++){
var current = str[i];
if(current.length > 1){
// remove all vowels after 2nd char
str[i] = current[0] + current.substring(1)
.replace(soundex_b, 'b')
.replace(soundex_c, 'c')
.replace(soundex_k, 'k')
.replace(soundex_i, 'i')
.replace(soundex_m, 'm')
.replace(soundex_t, 't')
.replace(soundex_f, 'f')
.replace(regex_vowel, '');
}
}
str = str.join("");
str = collapseRepeatingChars(str);
}
return str;
};
})()
// TODO: provide some common encoder plugins
// soundex
// cologne
// metaphone
// caverphone
// levinshtein
// hamming
// matchrating
// ngram
};
// Xone Async Handler Fallback
var queue = (function(){
var stack = {};
return function(fn, delay, id){
var timer = stack[id];
if(timer){
clearTimeout(timer);
}
return (
stack[id] = setTimeout(fn, delay)
);
};
})();
// Xone Flexi-Cache Handler Fallback
var cache = (function(){
function Cache(){
this.cache = {};
}
Cache.prototype.reset = function(){
this.cache = {};
};
Cache.prototype.set = function(id, value){
this.cache[id] = value;
};
Cache.prototype.get = function(id){
return this.cache[id];
};
return Cache;
})();
return FlexSearch;
// ---------------------------------------------------------
// Helpers
function regex(str){
return new RegExp(str, 'g');
}
return content;
}
/**
* @param {!string} string
* @returns {string}
*/
// function sort_by_length(a, b){
//
// var diff = a.length - b.length;
//
// return (
//
// diff < 0 ?
//
// 1
// :(
// diff > 0 ?
//
// -1
// :
// 0
// )
// );
// }
function collapseRepeatingChars(string){
/**
* @param {string} string
* @returns {string}
*/
var collapsed_string = '',
char_prev = '',
char_next = '';
function collapseRepeatingChars(string){
for(var i = 0; i < string.length; i++){
var collapsed_string = '',
char_prev = '',
char_next = '';
var char = string[i];
for(var i = 0; i < string.length; i++){
if(char !== char_prev){
var char = string[i];
if(i > 0 && char === 'h'){
if(char !== char_prev){
var char_prev_is_vowel = (
if(i > 0 && char === 'h'){
char_prev === 'a' ||
char_prev === 'e' ||
char_prev === 'i' ||
char_prev === 'o' ||
char_prev === 'u' ||
char_prev === 'y'
);
var char_prev_is_vowel = (
var char_next_is_vowel = (
char_prev === 'a' ||
char_prev === 'e' ||
char_prev === 'i' ||
char_prev === 'o' ||
char_prev === 'u' ||
char_prev === 'y'
);
char_next === 'a' ||
char_next === 'e' ||
char_next === 'i' ||
char_next === 'o' ||
char_next === 'u' ||
char_next === 'y'
);
var char_next_is_vowel = (
if(char_prev_is_vowel && char_next_is_vowel){
char_next === 'a' ||
char_next === 'e' ||
char_next === 'i' ||
char_next === 'o' ||
char_next === 'u' ||
char_next === 'y'
);
collapsed_string += char;
}
}
else{
if(char_prev_is_vowel && char_next_is_vowel){
collapsed_string += char;
}
}
else{
collapsed_string += char;
}
char_next = (
(i === string.length - 1) ?
''
:
string[i + 1]
);
char_prev = char;
}
char_next = (
return collapsed_string;
}
(i === string.length - 1) ?
/**
* @param {!Array|string} a
* @param {!Array|string} b
* @returns {number}
*/
''
function sort_by_length_down(a, b){
var diff = a.length - b.length;
return (
diff < 0 ?
1
:(
diff > 0 ?
-1
:
string[i + 1]
0
)
);
}
char_prev = char;
/**
* @param {!Array|string} a
* @param {!Array|string} b
* @returns {number}
*/
function sort_by_length_up(a, b){
var diff = a.length - b.length;
return (
diff < 0 ?
-1
:(
diff > 0 ?
1
:
0
)
);
}
return collapsed_string;
}
/**
* @param {!Array<number|string>} a
* @param {!Array<number|string>} b
* @param {number|boolean=} limit
* @returns {Array}
*/
function intersect(a, b, limit){
function intersect(a, b, limit){
var length_a = a.length,
length_b = b.length;
var length_a = a.length,
length_b = b.length;
var tmp;
var result = [];
if(length_b < length_a){
if(length_a && length_b){
tmp = b;
b = a;
a = tmp;
var count = 0,
tmp;
// swap order, shortest first
// if(length_b < length_a){
//
// tmp = b;
// b = a;
// a = tmp;
//
// tmp = length_b;
// length_b = length_a;
// length_a = tmp;
// }
for(var y = 0; y < length_a; y++){
var current_a = a[y];
for(var x = 0; x < length_b; x++){
if(b[x] === current_a){
result[count++] = current_a;
if(limit && (count === limit)){
return result;
}
break;
}
}
}
}
return result;
}
var result = [],
count = 0;
/**
* @param {FlexSearch} ref
*/
for(var y = 0; y < length_a; y++){
function runner(ref){
var current_a = a[y];
var async = ref.async;
var current;
for(var x = 0; x < length_b; x++){
if(async){
if(b[x] === current_a){
ref.async = false;
}
result[count++] = current_a;
if(ref._stack_keys.length){
if(limit && (count === limit)){
var start = time();
var key;
return result;
while((key = ref._stack_keys.shift()) || (key === 0)){
current = ref._stack[key];
switch(current[0]){
case enum_task.add:
ref.add(current[1], current[2]);
break;
case enum_task.update:
ref.update(current[1], current[2]);
break;
case enum_task.remove:
ref.remove(current[1]);
break;
}
break;
ref._stack[key] = null;
delete ref._stack[key];
if((time() - start) > 100){
break;
}
}
if(ref._stack_keys.length){
register_task(ref);
}
}
if(async){
ref.async = async;
}
}
return result;
}
})(
// Xone Async Handler Fallback
/**
* @param {FlexSearch} ref
*/
(function(){
function register_task(ref){
var stack = {};
ref._timer || (
return function(fn, id){
ref._timer = queue(function(){
var timer = stack[id];
ref._timer = null;
if(timer) {
runner(ref);
clearTimeout(timer);
}
}, 1, 'search-async-' + ref.id)
);
}
/**
* @returns {number}
*/
function time(){
return (
stack[id] = setTimeout(fn)
typeof performance !== 'undefined' ?
performance.now()
:
(new Date()).getTime()
);
};
})(),
}
// Xone Flexi-Cache Handler Fallback
function add_worker(id, core, options, callback){
(function(){
var thread = register_worker(
function Cache(){
// name:
'flexsearch-' + id,
this.cache = {};
// worker:
function(){
var id;
/** @type {FlexSearch} */
var flexsearch;
/** @lends {Worker} */
self.onmessage = function(event){
var data = event['data'];
if(data){
if(flexsearch.debug){
console.log("Worker Job Started: " + data['id']);
}
if(data['search']){
/** @lends {Worker} */
self.postMessage({
'result': flexsearch['search'](data['content'], data['limit']),
'id': id,
'content': data['content'],
'limit': data['limit']
});
}
else if(data['add']){
flexsearch['add'](data['id'], data['content']);
}
else if(data['update']){
flexsearch['update'](data['id'], data['content']);
}
else if(data['remove']){
flexsearch['remove'](data['id']);
}
else if(data['reset']){
flexsearch['reset']();
}
else if(data['info']){
var info = flexsearch['info']();
info['worker'] = id;
if(flexsearch.debug){
console.log(info);
}
/** @lends {Worker} */
//self.postMessage(info);
}
else if(data['register']){
id = data['id'];
flexsearch = Function(
data['register'].substring(
data['register'].indexOf('{') + 1,
data['register'].lastIndexOf('}')
)
)();
data['options']['cache'] = false;
data['options']['async'] = true;
data['options']['worker'] = false;
flexsearch = new flexsearch(data['options']);
}
}
};
},
// callback:
function(event){
var data = event['data'];
if(data && data['result']){
callback(data['id'], data['content'], data['result'], data['limit']);
}
else{
if(flexsearch.debug){
console.log(data);
}
}
},
// cores:
core
);
var fn_str = factory.toString();
options['id'] = core;
thread.postMessage(core, {
'register': fn_str,
'options': options,
'id': core
});
return thread;
}
})(
// Xone Worker Handler Fallback
Cache.prototype.reset = function(){
(function register_worker(){
this.cache = {};
};
var cores = 0;
var worker_stack = {};
var inline_is_supported = !!((typeof Blob !== 'undefined') && URL && URL.createObjectURL);
Cache.prototype.set = function(id, value){
return (
this.cache[id] = value;
};
/**
* @param {!string} _name
* @param {!Function} _worker
* @param {!Function} _callback
* @param {number=} _core
*/
Cache.prototype.get = function(id){
function(_name, _worker, _callback, _core){
return this.cache[id];
};
var name = _name,
worker = _worker,
callback = _callback,
core = _core;
return Cache;
})()
);
var current_index = 0;
var worker_payload;
/**
* Search Interface
* @interface
* @this {_search_struct}
* @const
*/
worker_payload = (
function _search_struct(options) {}
/** @type {Function} */
_search_struct.register;
/** @type {Function} */
_search_struct.prototype.add;
/** @type {Function} */
_search_struct.prototype.update;
/** @type {Function} */
_search_struct.prototype.remove;
/** @type {Function} */
_search_struct.prototype.clear;
/** @type {Function} */
_search_struct.prototype.destroy;
/** @type {Function} */
_search_struct.prototype.search;
inline_is_supported ?
/**
* Cache Interface
* @interface
* @this {_cache_struct}
* @param {number=} expiration
* @const
*/
/* Load Inline Worker */
function _cache_struct(expiration) {}
/** @type {function(string, *, boolean=)} */
_cache_struct.prototype.set;
/** @type {function(string, boolean=):*} */
_cache_struct.prototype.get;
/** @type {function(string):*} */
_cache_struct.prototype.remove;
/** @type {function()} */
_cache_struct.prototype.clear;
URL.createObjectURL(
new Blob(
['(' + worker.toString() + ')()'], {
'type': 'text/javascript'
}
)
)
:
/* Load Extern Worker (but also requires CORS) */
'js/worker/' + name + '.js'
);
//cores || (cores = 1);
worker_stack[name] || (worker_stack[name] = []); //new Array(cores);
//for(var i = 0; i < cores; i++){
worker_stack[name][core] = new Worker(worker_payload);
worker_stack[name][core]['onmessage'] = callback;
//}
console.log('Register Worker@' + name);
return {
'postMessage': function(id, data){
//console.log('Worker@' + name + ':' + id);
worker_stack[name][id]['postMessage'](data);
}
};
}
);
})()
));
/** --------------------------------------------------------------------------------------
* UMD Wrapper for Browser and Node.js
* @param {!string} name
* @param {!Function|Object} factory
* @param {!Function|Object=} root
*/
function register(name, factory, root){
root || (root = this);
var define = root['define'];
var modules = root['module'];
// CommonJS (Browser)
if(modules && modules['exports']){
modules['exports'] = factory;
}
// AMD (RequireJS)
else if(define && define['amd']){
define([], function(){
return factory;
});
}
// Universal (Xone)
else if((modules = root['modules'])){
modules[name.toLowerCase()] = factory;
}
// CommonJS (Node.js)
else if(typeof window === 'undefined'){
module.exports = factory;
}
// Global (window)
else{
root[name] = factory;
}
}
// Note: May this workaround is more Node-compatible:
// https://github.com/efacilitation/commonjs-require
})();

@@ -9,12 +9,19 @@ /**!

*/
window.FlexSearch=function(m,r){function b(e){this.id=x++;this.l(e||h)}function a(e){return new RegExp(e,"g")}function w(e){for(var k="",l="",a="",g=0;g<e.length;g++){var c=e[g];c!==l&&(0<g&&"h"===c?(a="a"===a||"e"===a||"i"===a||"o"===a||"u"===a||"y"===a,"a"!==l&&"e"!==l&&"i"!==l&&"o"!==l&&"u"!==l&&"y"!==l||!a||(k+=c)):k+=c);a=g===e.length-1?"":e[g+1];l=c}return k}function z(e,a,l){var k=e.length,g=a.length;if(g<k){var c=a;a=e;e=c}c=[];for(var d=0,f=0;f<k;f++)for(var n=e[f],b=0;b<g;b++)if(a[b]===
n){c[d++]=n;if(l&&d===l)return c;break}return c}var h={type:"integer",result:"id",mode:"forward",j:!1,g:!1,h:!1,i:!1,cache:!1,async:!1,encode:!1},u={icase:function(e){return e.toLowerCase()},simple:function(){var e=a("[^a-z0-9 ]"),k=a("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"),l=a("[\u00e8\u00e9\u00ea\u00eb]"),b=a("[\u00ec\u00ed\u00ee\u00ef]"),g=a("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"),c=a("[\u00f9\u00fa\u00fb\u00fc\u0171]"),d=a("[\u00fd\u0177\u00ff]"),f=a("\u00f1"),n=a("\u00e7"),v=a("\u00df");
return function(a){return a.toLowerCase().replace(k,"a").replace(l,"e").replace(b,"i").replace(g,"o").replace(c,"u").replace(d,"y").replace(f,"n").replace(n,"c").replace(v,"s").replace(e,"")}}(),advanced:function(){var e=a(" "),k=a("ae"),l=a("oe"),b=a("ue"),g=a("ie"),c=a("sz"),d=a("zs"),f=a("ck"),n=a("cc"),v=a("sh"),p=a("th"),h=a("dt"),m=a("ph"),r=a("ou"),q=a("uo");return function(a,y){if(!a)return a;a=u.simple(a);2<a.length&&(a=a.replace(k,"a").replace(l,"o").replace(b,"u").replace(g,"i").replace(c,
"s").replace(d,"s").replace(v,"s").replace(f,"k").replace(n,"k").replace(p,"t").replace(h,"t").replace(m,"f").replace(r,"o").replace(q,"u"));y||(a=a.replace(e,""),1<a.length&&(a=w(a)));return a}}(),extra:function(){var e=a("p"),k=a("[sz]"),l=a("[gq]"),b=a("[jy]"),g=a("n"),c=a("d"),d=a("[vw]"),f=a("[aeiouy]");return function(a){if(!a)return a;a=u.advanced(a,!0);if(1<a.length){a=a.split(" ");for(var n=0;n<a.length;n++){var h=a[n];1<h.length&&(a[n]=h[0]+h.substring(1).replace(e,"b").replace(k,"c").replace(l,
"k").replace(b,"i").replace(g,"m").replace(c,"t").replace(d,"f").replace(f,""))}a=a.join("");a=w(a)}return a}}()},q=[],x=0,t="";b.create=b.s=function(a){return new this(a)};b.o=function(e){for(var k in e)e.hasOwnProperty(k)&&(q[q.length]=[a(k),e[k]])};b.prototype.l=function(a){a&&(this.type=a.type||this.type||h.type,this.result=a.result||this.result||h.result,this.mode=a.mode||this.mode||h.mode,this.j=a.strict||this.j||h.j,this.i=a.ordered||this.i||h.i,this.g=a.multi||this.g||h.g,this.h="or"===a["boolean"]||
this.h||h.h,this.cache=a.cache||this.cache||h.cache,this.async=a.async||this.async||h.async,this.encode=a.encode&&u[a.encode]||this.encode||h.encode&&u[h.encode]);this.a={};this.c={};this.f=!0;this.b=this.cache?new r(3E4,50,!0):!1};b.prototype.set=b.prototype.add=function(a,k){if(k)if(this.c[a])this.update(a,k);else{for(var e={},b=k.split(" "),g=0;g<b.length;g++){var c=b[g];if(c){if(this.encode&&(c=(0,this.encode)(c),q.length))for(var d=0;d<q.length;d++){var f=q[d];c=c.replace(f[0],f[1])}if(c)switch(this.mode){case "inverse":for(d=
"",f=c.length-1;1<=f;f--)d=c[f]+d,e[d]||(e[d]="1",this.a[d]||(this.a[d]=[]),this.a[d].push(a));case "forward":d="";for(f=0;f<c.length;f++)d+=c[f],e[d]||(e[d]="1",this.a[d]||(this.a[d]=[]),this.a[d].push(a));break;case "full":for(f=0;f<c.length;f++)for(var n=c.length;n>f;n--)d=c.substring(f,n),e[d]||(e[d]="1",this.a[d]||(this.a[d]=[]),this.a[d].push(a))}}}this.c[a]="1";this.f=!1}if(this.async)return Promise.resolve(this)};b.prototype.update=function(a,k){this.c[a]&&(this.remove(a),k&&this.add(a,k));
if(this.async)return Promise.resolve(this)};b.prototype["delete"]=b.prototype.remove=function(a){for(var e=Object.keys(this.a),b,h=0;h<e.length;h++){b=this.a[e[h]];for(var g=0;g<b.length;g++)if(b[g]===a){b.splice(g,1);break}b.length||delete this.a[e[h]]}delete this.c[a];if(this.async)return Promise.resolve(this)};b.prototype.search=b.prototype.query=b.prototype.find=function(a,b,l){"function"===typeof b&&(l=b,b=0);b||(b=1E3);if(l){var e=this;m(function(){l(e.search(a,b));e=null},"search-"+this.id);
return null}var g=a;if(!this.f)this.cache&&this.b.reset(),this.f=!0;else if(this.cache){var c=this.b.get(a);if(c)return c}else if(t&&-1!==a.indexOf(t))return[];for(c=0;" "===a[c];)c++;c&&(g=a.substring(c));if(!a)return[];c=this.g?g.split(" "):[g];var d=[],f=!0;g=[];for(var k={},h=0;h<c.length;h++){var p=c[h];if(!k[p]&&(p&&(p=this.encode(p)),p)){if(p=this.a[p])g[g.length]=p;else{f=!1;break}k[c[h]]="1"}}if(f){c=g.length;d=0;for(f=g[d];f.length&&d<c;)k=g[d++],f=z(f,k,d===c?b:0);b&&f.length>b&&(f=f.slice(0,
b));d=f}d.length?t="":t||(t=a);this.cache&&this.b.set(a,d);return d};b.prototype.info=function(){for(var a=Object.keys(this.a),b=0,h=0;h<a.length;h++)b+=4*this.a[a[h]].length+2*a[h].length;return{id:this.id,bytes:b,status:this.f,matchers:q.length}};b.prototype.reset=b.prototype.clear=function(){this.m();this.l()};b.prototype.m=function(){this.cache&&this.b.reset();this.b=this.a=null};return b}(function(){var m={};return function(r,b){var a=m[b];a&&clearTimeout(a);return m[b]=setTimeout(r)}}(),function(){function m(){this.cache=
{}}m.prototype.reset=function(){this.cache={}};m.prototype.set=function(m,b){this.cache[m]=b};m.prototype.get=function(m){return this.cache[m]};return m}());
(function(n,v,g){g||(g=this);var b=g.define,p=g.module;p&&p.exports?p.exports=v:b&&b.amd?b([],function(){return v}):(p=g.modules)?p[n.toLowerCase()]=v:"undefined"===typeof window?module.G=v:g[n]=v})("FlexSearch",function D(n){function g(a){a||(a=l);this.id=a.id||E++;this.C(a)}function b(a){return new RegExp(a,"g")}function p(a){for(var c="",k="",f="",h=0;h<a.length;h++){var q=a[h];q!==k&&(0<h&&"h"===q?(f="a"===f||"e"===f||"i"===f||"o"===f||"u"===f||"y"===f,"a"!==k&&"e"!==k&&"i"!==k&&"o"!==k&&"u"!==
k&&"y"!==k||!f||(c+=q)):c+=q);f=h===a.length-1?"":a[h+1];k=q}return c}function w(a,c){var k=a.length-c.length;return 0>k?1:0<k?-1:0}function A(a,c){var k=a.length-c.length;return 0>k?-1:0<k?1:0}function F(a,c,k){var f=a.length,h=c.length,q=[];if(f&&h)for(var e=0,d=0;d<f;d++)for(var b=a[d],g=0;g<h;g++)if(c[g]===b){q[e++]=b;if(k&&e===k)return q;break}return q}function x(a){a.w||(a.w=B(function(){a.w=null;var c=a.async;c&&(a.async=!1);if(a.c.length){for(var k=C(),f;(f=a.c.shift())||0===f;){var h=a.g[f];
switch(h[0]){case t.add:a.add(h[1],h[2]);break;case t.update:a.update(h[1],h[2]);break;case t.remove:a.remove(h[1])}a.g[f]=null;delete a.g[f];if(100<C()-k)break}a.c.length&&x(a)}c&&(a.async=c)},1,"search-async-"+a.id))}function C(){return"undefined"!==typeof performance?performance.now():(new Date).getTime()}function G(a,c,k,f){a=n("flexsearch-"+a,function(){var a,c;self.onmessage=function(d){if(d=d.data)c.debug&&console.log("Worker Job Started: "+d.id),d.search?self.postMessage({result:c.search(d.content,
d.limit),id:a,content:d.content,limit:d.limit}):d.add?c.add(d.id,d.content):d.update?c.update(d.id,d.content):d.remove?c.remove(d.id):d.reset?c.reset():d.info?(d=c.info(),d.worker=a,c.debug&&console.log(d)):d.register&&(a=d.id,c=Function(d.register.substring(d.register.indexOf("{")+1,d.register.lastIndexOf("}")))(),d.options.cache=!1,d.options.async=!0,d.options.worker=!1,c=new c(d.options))}},function(a){(a=a.data)&&a.result?f(a.id,a.content,a.result,a.limit):flexsearch.debug&&console.log(a)},c);
var h=D.toString();k.id=c;a.postMessage(c,{register:h,options:k,id:c});return a}var l={type:"integer",mode:"forward",A:!1,cache:!1,async:!1,j:!1,encode:!1,i:4,debug:!0},u=[],E=0,t={add:0,update:1,remove:2};g.create=function(a){return new this(a)};g.F=function(a){for(var c in a)a.hasOwnProperty(c)&&(u[u.length]=[b(c),a[c]])};g.prototype.C=function(a){if(a){if(a.worker)if("undefined"===typeof Worker)a.worker=!1;else{var c=this,k=a.threads||l.threads;c.o=-1;c.u=0;c.h=[];c.v=null;c.l=Array(k);for(var f=
0;f<k;f++)c.l[f]=G(c.id,f,a||l,function(a,k,e,d){c.u!==c.i&&(c.h=c.h.concat(e),c.u++,d&&c.h.length>=d&&(c.u=c.i),c.v&&c.u===c.i&&(c.h.length?c.f="":c.f||(c.f=k),c.cache&&c.m.set(k,c.h),c.v(c.h),c.h=[]))})}this.mode=a.mode||this.mode||l.mode;this.A="or"===a["boolean"]||this.A||l.A;this.cache=a.cache||this.cache||l.cache;this.async=a.async||this.async||l.async;this.j=a.worker||this.j||l.j;this.i=a.threads||this.i||l.i;this.B=a.encode&&z[a.encode]||this.B||l.encode&&z[l.encode]||a.encode;this.debug=
a.debug||this.debug||l.debug}this.a={};this.b={};this.g={};this.c=[];this.w=null;this.f="";this.s=!0;this.m=this.cache?new H(3E4,50,!0):!1};g.prototype.encode=function(a){this.B&&(a=this.B(a));if(u.length)for(var c=0;c<u.length;c++){var k=u[c];a=a.replace(k[0],k[1])}return a};g.prototype.add=function(a,c){if("string"===typeof c&&c&&(a||0===a))if(this.b[a])this.update(a,c);else if(this.j)++this.o>=this.l.length&&(this.o=0),this.l[this.o].postMessage(this.o,{add:!0,id:a,content:c}),this.b[a]=""+this.o;
else if(this.async)this.g[a]||(this.c[this.c.length]=a),this.g[a]=[t.add,a,c],x(this);else{for(var k={},f=c.split(" "),h=0;h<f.length;h++){var b=f[h];if(b&&(this.encode&&(b=this.encode(b)),b))switch(this.mode){case "inverse":case "both":for(var e="",d,m=b.length-1;1<=m;m--)e=b[m]+e,k[e]||(k[e]="1",(d=this.a[e[0]])||(this.a[e[0]]=d={}),d[e]?d=d[e]:d[e]=d=[],d[d.length]=a);case "forward":e="";for(m=0;m<b.length;m++)e+=b[m],k[e]||(k[e]="1",(d=this.a[e[0]])||(this.a[e[0]]=d={}),d[e]?d=d[e]:d[e]=d=[],
d[d.length]=a);break;case "full":for(m=0;m<b.length;m++)for(var g=b.length;g>m;g--)e=b.substring(m,g),k[e]||(k[e]="1",(d=this.a[e[0]])||(this.a[e[0]]=d={}),d[e]?d=d[e]:d[e]=d=[],d[d.length]=a);break;default:k[b]||(k[b]="1",(d=this.a[b[0]])||(this.a[b[0]]=d={}),d[b]?d=d[b]:d[b]=d=[],d[d.length]=a)}}this.b[a]="1";this.s=!1}};g.prototype.update=function(a,c){if("string"===typeof c&&(a||0===a)&&this.b[a])if(this.j){var b=parseInt(this.b[a],10);this.l[b].postMessage(b,{update:!0,id:a,content:c})}else this.async?
(this.g[a]||(this.c[this.c.length]=a),this.g[a]=[t.update,a,c],x(this)):(this.remove(a),c&&this.add(a,c))};g.prototype.remove=function(a){if(this.b[a])if(this.j){var c=parseInt(this.b[a],10);this.l[c].postMessage(c,{remove:!0,id:a});delete this.b[a]}else if(this.async)this.g[a]||(this.c[this.c.length]=a),this.g[a]=[t.remove,a],x(this);else{c=Object.keys(this.a);for(var b=0;b<c.length;b++)for(var f=Object.keys(this.a[c[b]]),h=0;h<f.length;h++){var g=f[h],e=this.a[c[b]];if((e=e&&e[g])&&e.length)for(var d=
0;d<e.length;d++)if(e[d]===a){e.splice(d,1);break}e.length||delete this.a[c[b]][g]}delete this.b[a];this.s=!1}};var I=b("[ -/]");g.prototype.search=function(a,c,b){if("string"===typeof a&&a)"function"===typeof c?(b=c,c=1E3):c||(c=1E3);else return[];var f=a;if(!this.s)this.cache&&(this.f="",this.m.reset()),this.s=!0;else if(this.cache){var h=this.m.get(a);if(h)return h}else if(this.f&&-1!==a.indexOf(this.f))return[];if(this.j){this.v=b;this.u=0;this.h=[];for(f=0;f<this.i;f++)this.l[f].postMessage(f,
{search:!0,limit:c,content:a});return null}if(b){var k=this;B(function(){b(k.search(a,c));k=null},1,"search-"+this.id);return null}for(h=0;" "===a[h];)h++;h&&(f=a.substring(h));if(!f)return[];var e=f.split(I);1<e.length&&e.sort(w);h=[];var d=!0;f=[];for(var g={},y=0;y<e.length;y++){var r=e[y];if(!g[r]&&(r&&this.encode&&(r=this.encode(r)),r)){var l=this.a[r[0]];if((l=l&&l[r])&&l.length)f[f.length]=l;else{d=!1;break}g[e[y]]="1"}}if(d&&(1<f.length&&f.sort(A),e=0,d=f[e++])){for(h=f.length;d.length&&e<
h;)g=f[e++],d=F(d,g,e===h?c:0);c&&d.length>c&&(d=d.slice(0,c));h=d}h.length?this.f="":this.f||(this.f=a);this.cache&&this.m.set(a,h);return h};g.prototype.info=function(){if(this.j)for(var a=0;a<this.i;a++)this.l[a].postMessage(a,{info:!0,id:this.id});else{var c=0,b=0,f=0;var h=Object.keys(this.a);for(a=0;a<h.length;a++){var g=""+h[a];var e=this.a[g].length;c+=1*e+2*g.length;b+=e;f+=e*g.length}h=Object.keys(this.b);e=h.length;for(a=0;a<e;a++)c+=2*h[a].length+2;return{id:this.id,memory:c,items:e,sequences:b,
chars:f,status:this.s,cache:this.c.length,matchers:u.length}}};g.prototype.reset=function(){this.D();this.C()};g.prototype.D=function(){this.cache&&this.m.reset();this.m=this.b=this.a=null};var z={icase:function(a){return a.toLowerCase()},simple:function(){var a=b("[^a-z0-9 ]"),c=b("[-/]"),k=b("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"),f=b("[\u00e8\u00e9\u00ea\u00eb]"),h=b("[\u00ec\u00ed\u00ee\u00ef]"),g=b("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"),e=b("[\u00f9\u00fa\u00fb\u00fc\u0171]"),d=b("[\u00fd\u0177\u00ff]"),
m=b("\u00f1"),l=b("\u00e7"),r=b("\u00df");return function(b){return b.toLowerCase().replace(k,"a").replace(f,"e").replace(h,"i").replace(g,"o").replace(e,"u").replace(d,"y").replace(m,"n").replace(l,"c").replace(r,"s").replace(c," ").replace(a,"")}}(),advanced:function(){var a=b(" "),c=b("ae"),k=b("ai"),f=b("ay"),h=b("ey"),g=b("oe"),e=b("ue"),d=b("ie"),m=b("sz"),l=b("zs"),r=b("ck"),n=b("cc"),t=b("sh"),u=b("dt"),w=b("ph"),x=b("ou"),A=b("uo");return function(b,q){if(!b)return b;b=z.simple(b);2<b.length&&
(b=b.replace(c,"a").replace(k,"ei").replace(f,"ei").replace(h,"ei").replace(g,"o").replace(e,"u").replace(d,"i").replace(m,"s").replace(l,"s").replace(t,"s").replace(r,"k").replace(n,"k").replace(u,"t").replace(w,"f").replace(x,"o").replace(A,"u"));q||(b=b.replace(a,""),1<b.length&&(b=p(b)));return b}}(),extra:function(){var a=b("p"),c=b("[sz]"),k=b("[gq]"),f=b("[jy]"),h=b("n"),g=b("d"),e=b("[vw]"),d=b("[aeiouy]");return function(b){if(!b)return b;b=z.advanced(b,!0);if(1<b.length){b=b.split(" ");
for(var l=0;l<b.length;l++){var m=b[l];1<m.length&&(b[l]=m[0]+m.substring(1).replace(a,"b").replace(c,"c").replace(k,"k").replace(f,"i").replace(h,"m").replace(g,"t").replace(e,"f").replace(d,""))}b=b.join("");b=p(b)}return b}}()},B=function(){var a={};return function(b,g,f){var c=a[f];c&&clearTimeout(c);return a[f]=setTimeout(b,g)}}(),H=function(){function a(){this.cache={}}a.prototype.reset=function(){this.cache={}};a.prototype.set=function(a,b){this.cache[a]=b};a.prototype.get=function(a){return this.cache[a]};
return a}();return g}(function(){var n={},v=!("undefined"===typeof Blob||!URL||!URL.createObjectURL);return function(g,b,p,w){b=v?URL.createObjectURL(new Blob(["("+b.toString()+")()"],{type:"text/javascript"})):"js/worker/"+g+".js";n[g]||(n[g]=[]);n[g][w]=new Worker(b);n[g][w].onmessage=p;console.log("Register Worker@"+g);return{postMessage:function(b,p){n[g][b].postMessage(p)}}}}()));
{
"name": "flexsearch",
"version": "0.0.9",
"version": "0.1.21",
"description": "Superfast, lightweight and memory efficient full text search library.",

@@ -11,3 +11,3 @@ "keywords": [],

"main": "flexsearch.js",
"preferGlobal": false,
"preferGlobal": true,
"bin": {},

@@ -18,3 +18,6 @@ "repository": {

},
"scripts": {},
"scripts": {
"test": "nyc --reporter=html --reporter=text mocha --timeout=3000",
"coverage": "nyc report --reporter=text-lcov | coveralls"
},
"homepage": "https://nextapps-de.github.io/xone/",

@@ -24,3 +27,8 @@ "author": "Thomas Wilkerling",

"dependencies": {},
"devDependencies": {}
"devDependencies": {
"chai": "^4.1.2",
"coveralls": "^3.0.0",
"mocha": "^5.0.1",
"nyc": "^11.5.0"
}
}
# FlexSearch
### Superfast lightweight full text search engine for JavaScript.
### Superfast, lightweight and memory efficient full text search library with zero dependencies.
Searching full text with FlexSearch is up to 1,000 times faster than with ElasticSearch.
When it comes to raw search speed FlexSearch outperforms every searching library out there and also provides flexible search capabilities like multi-word, phonetics or partial matching. Keep in mind that updating / removing items from the index has a significant cost. When your index needs to be updated continuously then <a href="https://github.com/nextapps-de/bulksearch" target="_blank">BulkSearch</a> may be a better choice. FlexSearch also provides you a asynchronous processing model as well as web workers to perform any updates on the index in background.
Benchmark: <a href="https://jsperf.com/flexsearch" target="_blank">https://jsperf.com/flexsearch</a>
Supported Platforms:
- Browser
- Node.js
Supported Module Definitions:
- AMD (RequireJS, Xone)
- CommonJS (Node.js, Xone)
- Global (window)
All Features:
<ul>
<li>Partial Words</li>
<li>Web-Worker Support (not available in Node.js)</li>
<li>Partial Matching</li>
<li>Multiple Words</li>

@@ -21,4 +32,48 @@ <li>Flexible Word Order</li>

#### Web-Worker Support
Workers get its own dedicated memory. Especially for larger indexes, web worker improves speed and available memory a lot. FlexSearch index was tested with a 250 Mb text file including __10 Million words__. The indexing was done silently in background by multiple parallel running workers in about 7 minutes and __reserve ~ 8.2 Mb__ memory. The search result __took ~ 0.25 ms__!
__Note:__ It is slightly faster to use no web worker when the index isn't too big (< 100,000 words).
#### Compare BulkSearch vs. FlexSearch
<table>
<tr></tr>
<tr>
<th align="left">Description</th>
<th align="left">BulkSearch</th>
<th align="left">FlexSearch</th>
</tr>
<tr>
<td>Access</td>
<td>Read-Write optimized index</td>
<td>Read-Memory optimized index</td>
</tr>
<tr></tr>
<tr>
<td>Memory</td>
<td>Large (~ 1 kb per word)</td>
<td>Tiny (~ 16 bytes per word)</td>
</tr>
<tr></tr>
<tr>
<td>Usage</td>
<td>Limited content, <br>Index updates continously</td>
<td>Fastest possible search, <br>Rare updates on index<br>Low memory capabilities</td>
</tr>
</table>
## Installation
##### HTML / Javascript
```html
<html>
<head>
<script src="https://cdn.rawgit.com/nextapps-de/flexsearch/master/flexsearch.min.js"></script>
</head>
...
```
##### Node.js

@@ -33,13 +88,9 @@

```javascript
var FlexSearch = require("FlexSearch");
var FlexSearch = require("flexsearch");
```
##### HTML / Javascript
Or pass in options when requiring:
```html
<html>
<head>
<script src="https://cdn.rawgit.com/nextapps-de/flexsearch/master/flexsearch.min.js"></script>
</head>
...
```javascript
var index = require("flexsearch").create({/* options */});
```

@@ -50,3 +101,3 @@

```javascript
var FlexSearch = require("FlexSearch");
var FlexSearch = require("./flexsearch.js");
```

@@ -77,9 +128,5 @@

type: "integer",
encode: "icase",
boolean: "and",
size: 4000,
depth: 3,
mode: "forward",
multi: false,
strict: false,
ordered: false,

@@ -192,7 +239,3 @@ async: false,

"bytes": 3600356288,
"chunks": 9,
"fragmentation": 0,
"fragments": 0,
"id": 0,
"length": 7798,
"matchers": 0,

@@ -216,18 +259,17 @@ "size": 10000,

<table>
<tr></tr>
<tr>
<th align="left">Option</th>
<th align="left">Values</th>
<th align="left">Description</th>
<th align="left">Option      </th>
<th align="left">Values      </th>
<th align="left">Description      </th>
</tr>
<tr></tr>
<tr>
<td align="top">type</td>
<td align="top">mode</td>
<td vertical="top" vertical-align="top">
"byte"<br>
"short"<br>
"integer"<br>
"float"<br>
"string"
"strict"<br>
"foward"<br>
"inverse"<br>
"full"
</td>
<td vertical-align="top">The data type of passed IDs has to be specified on creation. It is recommended to uses to most lowest possible data range here, e.g. use "short" when IDs are not higher than 65,535.</td>
<td vertical-align="top">The indexing mode.</td>
</tr>

@@ -258,14 +300,2 @@ <tr></tr>

<tr>
<td align="top">size</td>
<td>2500 - 10000</td>
<td>The size of chunks. It depends on content length which value fits best. Short content length (e.g. User names) are faster with a chunk size of 2,500. Bigger text runs faster with a chunk size of 10,000. <b>Note:</b> It is recommended to use a minimum chunk size of the maximum content length which has to be indexed to prevent fragmentation.</td>
</tr>
<tr></tr>
<tr>
<td align="top">depth</td>
<td>0 - 6</td>
<td>Set the depth of register. It is recommended to use a value in relation to the number of stored index and content length for an optimum performance-memory value. <b>Note:</b> Increase this options carefully!</td>
</tr>
<tr></tr>
<tr>
<td align="top">multi</td>

@@ -289,3 +319,3 @@ <td>

<tr>
<td align="top">strict</td>
<td align="top">cache</td>
<td>

@@ -295,7 +325,7 @@ true<br>

</td>
<td>Matches exactly needs to be started with the query.</td>
<td>Enable/Disable caching.</td>
</tr>
<tr></tr>
<tr>
<td align="top">cache</td>
<td align="top">async</td>
<td>

@@ -305,3 +335,3 @@ true<br>

</td>
<td>Enable caching.</td>
<td>Enable/Disable asynchronous processing.</td>
</tr>

@@ -314,2 +344,3 @@ </table>

<table>
<tr></tr>
<tr>

@@ -319,6 +350,5 @@ <th align="left">Option</th>

<th align="left">Example</th>
<th align="left">False Positives</th>
<th align="left">Compression Level</th>
<th align="left">False-Positives</th>
<th align="left">Compression</th>
</tr>
<tr></tr>
<tr>

@@ -354,3 +384,3 @@ <td><b>false</b></td>

<td>no</td>
<td>~ 3%</td>
<td>~ 7%</td>
</tr>

@@ -366,3 +396,3 @@ <tr></tr>

<td>no</td>
<td>~ 25%</td>
<td>~ 35%</td>
</tr>

@@ -378,3 +408,3 @@ <tr></tr>

<td>yes</td>
<td>~ 50%</td>
<td>~ 60%</td>
</tr>

@@ -384,3 +414,3 @@ </table>

<a name="compare" id="compare"></a>
### Compare Phonetic Search Results
### Compare Phonetic Encoder

@@ -390,11 +420,10 @@ Reference String: __"Björn-Phillipp Mayer"__

<table>
<tr></tr>
<tr>
<th align="left">Query</th>
<th align="left">ElasticSearch</th>
<th align="left">FlexSearch (iCase)</th>
<th align="left">FlexSearch (Simple)</th>
<th align="left">FlexSearch (Adv.)</th>
<th align="left">FlexSearch (Extra)</th>
<th align="left">iCase</th>
<th align="left">Simple</th>
<th align="left">Advanced</th>
<th align="left">Extra</th>
</tr>
<tr></tr>
<tr>

@@ -406,3 +435,2 @@ <td>björn</td>

<td><b>yes</b></td>
<td><b>yes</b></td>
</tr>

@@ -412,3 +440,2 @@ <tr></tr>

<td>björ</td>
<td>no</td>
<td><b>yes</b></td>

@@ -423,3 +450,2 @@ <td><b>yes</b></td>

<td>no</td>
<td>no</td>
<td><b>yes</b></td>

@@ -434,3 +460,2 @@ <td><b>yes</b></td>

<td>no</td>
<td>no</td>
<td><b>yes</b></td>

@@ -444,3 +469,2 @@ <td><b>yes</b></td>

<td>no</td>
<td>no</td>
<td><b>yes</b></td>

@@ -454,3 +478,2 @@ <td><b>yes</b></td>

<td>no</td>
<td>no</td>
<td><b>yes</b></td>

@@ -463,3 +486,2 @@ <td><b>yes</b></td>

<td>no</td>
<td>no</td>
<td><b>yes</b></td>

@@ -474,3 +496,2 @@ <td><b>yes</b></td>

<td>no</td>
<td>no</td>
<td><b>yes</b></td>

@@ -484,3 +505,2 @@ <td><b>yes</b></td>

<td>no</td>
<td>no</td>
<td><b>yes</b></td>

@@ -494,3 +514,2 @@ <td><b>yes</b></td>

<td>no</td>
<td>no</td>
<td><b>yes</b></td>

@@ -505,3 +524,2 @@ <td><b>yes</b></td>

<td>no</td>
<td>no</td>
<td><b>yes</b></td>

@@ -511,3 +529,2 @@ </tr>

<td><i>(false positives)</i></td>
<td>yes</td>
<td><b>no</b></td>

@@ -521,50 +538,56 @@ <td><b>no</b></td>

<a name="memory" id="memory"></a>
## Improve Memory Usage
## Compare Memory Usage
__Note:__ The data type of passed IDs has to be specified on creation. It is recommended to uses to most lowest possible data range here, e.g. use "short" when IDs are not higher than 65,535.
__Note:__ The required memory depends on several options.
<table>
<tr></tr>
<tr>
<th align="left">ID Type</th>
<th align="left">Range of Values</th>
<th align="left">Memory usage of every ~ 100,000 indexed words (Index + Content)</th>
<th align="left">Encoding</th>
<th align="left">Memory usage of every ~ 100,000 indexed words</th>
</tr>
<tr>
<td>"icase" (default) / false</td>
<td>210 kb</td>
</tr>
<tr></tr>
<tr>
<td>Byte</td>
<td>0 - 255</td>
<td>683 kb + 2.4 Mb</td>
<td>"simple"</td>
<td>190 kb</td>
</tr>
<tr></tr>
<tr>
<td>Short</td>
<td>0 - 65,535</td>
<td>1.3 Mb + 2.4 Mb</td>
<td>"advanced"</td>
<td>150 kb</td>
</tr>
<tr></tr>
<tr>
<td>Integer</td>
<td>0 - 4,294,967,295</td>
<td>2.7 Mb + 2.4 Mb</td>
<td>"extra"</td>
<td>90 kb</td>
</tr>
<tr>
<th align="left">Mode</th>
<th align="left">Multiplied with:</th>
</tr>
<tr>
<td>"strict"</td>
<td>x 1</td>
</tr>
<tr></tr>
<tr>
<td>Float</td>
<td>0 - * (16 digits)</td>
<td>5.3 Mb + 2.4 Mb</td>
<td>"forward" (default)</td>
<td>x 1.5</td>
</tr>
<tr></tr>
<tr>
<td>String</td>
<td>* (unlimited)</td>
<td>1.3 Mb <b>* <u>char length of IDs</u></b> + 2.4 Mb</td>
<td>"inverse"</td>
<td>x 2</td>
</tr>
<tr></tr>
<tr>
<td>"full"</td>
<td>x 2.3</td>
</tr>
</table>
The required RAM per instance can be calculated as follow:
`BYTES = CONTENT_CHAR_COUNT * (BYTES_OF_ID + 2) + CONTENT_WORD_COUNT * 8`
__Note:__ Character count may be less related to the phonetic settings, e.g. when using "extra" the count of chars shrinks to ~ 50%.
---

@@ -571,0 +594,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc