flexsearch
Advanced tools
Comparing version 0.7.34 to 0.7.39
@@ -1,1 +0,51 @@ | ||
import{IndexInterface,DocumentInterface}from"./type.js";import{is_function,is_object,is_string}from"./common.js";export default function(a){register(a,"add"),register(a,"append"),register(a,"search"),register(a,"update"),register(a,"remove")}function register(a,b){a[b+"Async"]=function(){const a=this,c=arguments,d=c[c.length-1];let e;is_function(d)&&(e=d,delete c[c.length-1]);const f=new Promise(function(d){setTimeout(function(){a.async=!0;const e=a[b].apply(a,c);a.async=!1,d(e)})});return e?(f.then(e),this):f}} | ||
import { IndexInterface, DocumentInterface } from "./type.js"; | ||
//import { promise as Promise } from "./polyfill.js"; | ||
import { is_function, is_object, is_string } from "./common.js"; | ||
export default function (prototype) { | ||
register(prototype, "add"); | ||
register(prototype, "append"); | ||
register(prototype, "search"); | ||
register(prototype, "update"); | ||
register(prototype, "remove"); | ||
} | ||
function register(prototype, key) { | ||
prototype[key + "Async"] = function () { | ||
/** @type {IndexInterface|DocumentInterface} */ | ||
const self = this, | ||
args = /*[].slice.call*/arguments, | ||
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 () { | ||
self.async = !0; | ||
const res = self[key].apply(self, args); | ||
self.async = !1; | ||
resolve(res); | ||
}); | ||
}); | ||
if (callback) { | ||
promise.then(callback); | ||
return this; | ||
} else { | ||
return promise; | ||
} | ||
}; | ||
} |
@@ -1,1 +0,168 @@ | ||
import{IndexInterface,DocumentInterface}from"./type.js";import{create_object,is_object}from"./common.js";function CacheClass(a){this.limit=!0!==a&&a,this.cache=create_object(),this.queue=[]}export default CacheClass;export function searchCache(a,b,c){is_object(a)&&(a=a.query);let d=this.cache.get(a);return d||(d=this.search(a,b,c),this.cache.set(a,d)),d}CacheClass.prototype.set=function(a,b){if(!this.cache[a]){let b=this.queue.length;b===this.limit?delete this.cache[this.queue[b-1]]:b++;for(let a=b-1;0<a;a--)this.queue[a]=this.queue[a-1];this.queue[0]=a}this.cache[a]=b},CacheClass.prototype.get=function(a){const b=this.cache[a];if(this.limit&&b){const b=this.queue.indexOf(a);if(b){const a=this.queue[b-1];this.queue[b-1]=this.queue[b],this.queue[b]=a}}return b},CacheClass.prototype.del=function(a){for(let b,c,d=0;d<this.queue.length;d++)c=this.queue[d],b=this.cache[c],b.includes(a)&&(this.queue.splice(d--,1),delete this.cache[c])}; | ||
import { IndexInterface, DocumentInterface } from "./type.js"; | ||
import { create_object, is_object } from "./common.js"; | ||
/** | ||
* @param {boolean|number=} limit | ||
* @constructor | ||
*/ | ||
function CacheClass(limit) { | ||
/** @private */ | ||
this.limit = !0 !== limit && limit; | ||
/** @private */ | ||
this.cache = create_object(); | ||
/** @private */ | ||
this.queue = []; | ||
//this.clear(); | ||
} | ||
export default CacheClass; | ||
/** | ||
* @param {string|Object} query | ||
* @param {number|Object=} limit | ||
* @param {Object=} options | ||
* @this {IndexInterface} | ||
* @returns {Array<number|string>} | ||
*/ | ||
export 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.clear = function(){ | ||
// | ||
// /** @private */ | ||
// this.cache = create_object(); | ||
// | ||
// /** @private */ | ||
// this.queue = []; | ||
// }; | ||
CacheClass.prototype.set = function (key, value) { | ||
if (!this.cache[key]) { | ||
// it is just a shame that native function array.shift() performs so bad | ||
// const length = this.queue.length; | ||
// | ||
// this.queue[length] = key; | ||
// | ||
// if(length === this.limit){ | ||
// | ||
// delete this.cache[this.queue.shift()]; | ||
// } | ||
// the same bad performance | ||
// this.queue.unshift(key); | ||
// | ||
// if(this.queue.length === this.limit){ | ||
// | ||
// this.queue.pop(); | ||
// } | ||
// fast implementation variant | ||
// let length = this.queue.length; | ||
// | ||
// if(length === this.limit){ | ||
// | ||
// length--; | ||
// | ||
// delete this.cache[this.queue[0]]; | ||
// | ||
// for(let x = 0; x < length; x++){ | ||
// | ||
// this.queue[x] = this.queue[x + 1]; | ||
// } | ||
// } | ||
// | ||
// this.queue[length] = key; | ||
// current fastest implementation variant | ||
// theoretically that should not perform better compared to the example above | ||
let length = this.queue.length; | ||
if (length === this.limit) { | ||
delete this.cache[this.queue[length - 1]]; | ||
} else { | ||
length++; | ||
} | ||
for (let x = length - 1; 0 < x; 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) { | ||
// probably the indexOf() method performs faster when matched content is on front (left-to-right) | ||
// using lastIndexOf() does not help, it performs almost slower | ||
const pos = this.queue.indexOf(key); | ||
// if(pos < this.queue.length - 1){ | ||
// | ||
// const tmp = this.queue[pos]; | ||
// this.queue[pos] = this.queue[pos + 1]; | ||
// this.queue[pos + 1] = tmp; | ||
// } | ||
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]; | ||
} | ||
} | ||
}; |
@@ -1,1 +0,78 @@ | ||
export function parse_option(a,b){return"undefined"==typeof a?b:a}export function create_object_array(a){const b=Array(a);for(let c=0;c<a;c++)b[c]=create_object();return b}export function create_arrays(a){const b=Array(a);for(let c=0;c<a;c++)b[c]=[];return b}export function get_keys(a){return Object.keys(a)}export function create_object(){return Object.create(null)}export function concat(a){return[].concat.apply([],a)}export function sort_by_length_down(c,a){return a.length-c.length}export function is_array(a){return a.constructor===Array}export function is_string(a){return"string"==typeof a}export function is_object(a){return"object"==typeof a}export function is_function(a){return"function"==typeof a} | ||
export function parse_option(value, default_value) { | ||
return "undefined" != typeof value ? value : default_value; | ||
} | ||
/** | ||
* @param {!number} count | ||
* @returns {Array<Object>} | ||
*/ | ||
export function create_object_array(count) { | ||
const array = Array(count); | ||
for (let i = 0; i < count; i++) { | ||
array[i] = create_object(); | ||
} | ||
return array; | ||
} | ||
export function create_arrays(count) { | ||
const array = Array(count); | ||
for (let i = 0; i < count; i++) { | ||
array[i] = []; | ||
} | ||
return array; | ||
} | ||
/** | ||
* @param {!Object} obj | ||
* @returns {Array<string>} | ||
*/ | ||
export function get_keys(obj) { | ||
return Object.keys(obj); | ||
} | ||
export function create_object() { | ||
return Object.create(null); | ||
} | ||
export function concat(arrays) { | ||
return [].concat.apply([], arrays); | ||
} | ||
export function sort_by_length_down(a, b) { | ||
return b.length - a.length; | ||
} | ||
export function is_array(val) { | ||
return val.constructor === Array; | ||
} | ||
export function is_string(val) { | ||
return "string" == typeof val; | ||
} | ||
export function is_object(val) { | ||
return "object" == typeof val; | ||
} | ||
export function is_function(val) { | ||
return "function" == typeof val; | ||
} |
@@ -1,1 +0,731 @@ | ||
import{SUPPORT_ASYNC,SUPPORT_CACHE,SUPPORT_SERIALIZE,SUPPORT_STORE,SUPPORT_TAGS,SUPPORT_WORKER}from"./config.js";import Index from"./index.js";import{DocumentInterface}from"./type.js";import Cache,{searchCache}from"./cache.js";import{create_object,is_array,is_string,is_object,parse_option,get_keys}from"./common.js";import apply_async from"./async.js";import{intersect,intersect_union}from"./intersect.js";import{exportDocument,importDocument}from"./serialize.js";import WorkerIndex from"./worker/index.js";function Document(a){if(!(this instanceof Document))return new Document(a);const b=a.document||a.doc||a;let c;this.tree=[],this.field=[],this.marker=[],this.register=create_object(),this.key=(c=b.key||b.id)&&parse_tree(c,this.marker)||"id",this.fastupdate=parse_option(a.fastupdate,!0),SUPPORT_STORE&&(this.storetree=(c=b.store)&&!0!==c&&[],this.store=c&&create_object()),SUPPORT_TAGS&&(this.tag=(c=b.tag)&&parse_tree(c,this.marker),this.tagindex=c&&create_object()),SUPPORT_CACHE&&(this.cache=(c=a.cache)&&new Cache(c),a.cache=!1),SUPPORT_WORKER&&(this.worker=a.worker),SUPPORT_ASYNC&&(this.async=!1),this.index=parse_descriptor.call(this,a,b)}export default Document;function parse_descriptor(a,b){const c=create_object();let d=b.index||b.field||b;is_string(d)&&(d=[d]);for(let e,f,g=0;g<d.length;g++)e=d[g],is_string(e)||(f=e,e=e.field),f=is_object(f)?Object.assign({},a,f):a,SUPPORT_WORKER&&this.worker&&(c[e]=new WorkerIndex(f),!c[e].worker&&(this.worker=!1)),this.worker||(c[e]=new Index(f,this.register)),this.tree[g]=parse_tree(e,this.marker),this.field[g]=e;if(SUPPORT_STORE&&this.storetree){let a=b.store;is_string(a)&&(a=[a]);for(let b=0;b<a.length;b++)this.storetree[b]=parse_tree(a[b],this.marker)}return c}function parse_tree(a,b){const c=a.split(":");let d=0;for(let e=0;e<c.length;e++)a=c[e],0<=a.indexOf("[]")&&(a=a.substring(0,a.length-2),a&&(b[d]=!0)),a&&(c[d++]=a);return d<c.length&&(c.length=d),1<d?c:c[0]}function parse_simple(a,b){if(is_string(b))a=a[b];else for(let c=0;a&&c<b.length;c++)a=a[b[c]];return a}function store_value(a,b,c,d,e){if(a=a[e],d===c.length-1)b[e]=a;else if(a)if(is_array(a)){b=b[e]=Array(a.length);for(let e=0;e<a.length;e++)store_value(a,b,c,d,e)}else b=b[e]||(b[e]=create_object()),e=c[++d],store_value(a,b,c,d,e)}function add_index(a,b,c,d,e,f,g,h){if(a=a[g],a)if(d===b.length-1){if(is_array(a)){if(c[d]){for(let b=0;b<a.length;b++)e.add(f,a[b],!0,!0);return}a=a.join(" ")}e.add(f,a,h,!0)}else if(is_array(a))for(let g=0;g<a.length;g++)add_index(a,b,c,d,e,f,g,h);else g=b[++d],add_index(a,b,c,d,e,f,g,h)}Document.prototype.add=function(a,b,c){if(is_object(a)&&(b=a,a=parse_simple(b,this.key)),b&&(a||0===a)){if(!c&&this.register[a])return this.update(a,b);for(let d,e,f=0;f<this.field.length;f++)e=this.field[f],d=this.tree[f],is_string(d)&&(d=[d]),add_index(b,d,this.marker,0,this.index[e],a,d[0],c);if(SUPPORT_TAGS&&this.tag){let d=parse_simple(b,this.tag),e=create_object();is_string(d)&&(d=[d]);for(let b,f,g=0;g<d.length;g++)if(b=d[g],!e[b]&&(e[b]=1,f=this.tagindex[b]||(this.tagindex[b]=[]),(!c||!f.includes(a))&&(f[f.length]=a,this.fastupdate))){const b=this.register[a]||(this.register[a]=[]);b[b.length]=f}}if(SUPPORT_STORE&&this.store&&(!c||!this.store[a])){let c;if(this.storetree){c=create_object();for(let a,d=0;d<this.storetree.length;d++)a=this.storetree[d],is_string(a)?c[a]=b[a]:store_value(b,c,a,0,a[0])}this.store[a]=c||b}}return this},Document.prototype.append=function(a,b){return this.add(a,b,!0)},Document.prototype.update=function(a,b){return this.remove(a).add(a,b)},Document.prototype.remove=function(a){if(is_object(a)&&(a=parse_simple(a,this.key)),this.register[a]){for(let b=0;b<this.field.length&&(this.index[this.field[b]].remove(a,!this.worker),!this.fastupdate);b++);if(SUPPORT_TAGS&&this.tag&&!this.fastupdate)for(let b in this.tagindex){const c=this.tagindex[b],d=c.indexOf(a);-1!==d&&(1<c.length?c.splice(d,1):delete this.tagindex[b])}SUPPORT_STORE&&this.store&&delete this.store[a],delete this.register[a]}return this},Document.prototype.search=function(a,b,c,d){c||(!b&&is_object(a)?(c=a,a=""):is_object(b)&&(c=b,b=0));let e,f,g,h,j,k,l=[],m=[],n=0;if(c)if(is_array(c))g=c,c=null;else{if(a=c.query||a,e=c.pluck,g=e||c.index||c.field,h=SUPPORT_TAGS&&c.tag,f=SUPPORT_STORE&&this.store&&c.enrich,j="and"===c.bool,b=c.limit||b||100,k=c.offset||0,h&&(is_string(h)&&(h=[h]),!a)){for(let a,c=0;c<h.length;c++)a=get_tag.call(this,h[c],b,k,f),a&&(l[l.length]=a,n++);return n?l:[]}is_string(g)&&(g=[g])}g||(g=this.field),j=j&&(1<g.length||h&&1<h.length);const o=!d&&(this.worker||this.async)&&[];for(let e,f,p,q=0;q<g.length;q++){let i;if(f=g[q],is_string(f)||(i=f,f=i.field,a=i.query||a,b=i.limit||b),o){o[q]=this.index[f].searchAsync(a,b,i||c);continue}else e=d?d[q]:this.index[f].search(a,b,i||c);if(p=e&&e.length,h&&p){const a=[];let c=0;j&&(a[0]=[e]);for(let b,d,e=0;e<h.length;e++)b=h[e],d=this.tagindex[b],p=d&&d.length,p&&(c++,a[a.length]=j?[d]:d);c&&(e=j?intersect(a,b||100,k||0):intersect_union(e,a),p=e.length)}if(p)m[n]=f,l[n++]=e;else if(j)return[]}if(o){const d=this;return new Promise(function(e){Promise.all(o).then(function(f){e(d.search(a,b,c,f))})})}if(!n)return[];if(e&&(!f||!this.store))return l[0];for(let g,h=0;h<m.length;h++){if(g=l[h],g.length&&f&&(g=apply_enrich.call(this,g)),e)return g;l[h]={field:m[h],result:g}}return l};function get_tag(a,b,c,d){let e=this.tagindex[a],f=e&&e.length-c;if(f&&0<f)return(f>b||c)&&(e=e.slice(c,c+b)),d&&(e=apply_enrich.call(this,e)),{tag:a,result:e}}function apply_enrich(a){const b=Array(a.length);for(let c,d=0;d<a.length;d++)c=a[d],b[d]={id:c,doc:this.store[c]};return b}Document.prototype.contain=function(a){return!!this.register[a]},SUPPORT_STORE&&(Document.prototype.get=function(a){return this.store[a]},Document.prototype.set=function(a,b){return this.store[a]=b,this}),SUPPORT_CACHE&&(Document.prototype.searchCache=searchCache),SUPPORT_SERIALIZE&&(Document.prototype.export=exportDocument,Document.prototype.import=importDocument),SUPPORT_ASYNC&&apply_async(Document.prototype); | ||
/**! | ||
* FlexSearch.js | ||
* Author and Copyright: Thomas Wilkerling | ||
* Licence: Apache-2.0 | ||
* Hosted by Nextapps GmbH | ||
* https://github.com/nextapps-de/flexsearch | ||
*/ | ||
import Index from "./index.js"; | ||
import { DocumentInterface } from "./type.js"; | ||
import Cache, { searchCache } from "./cache.js"; | ||
import { create_object, is_array, is_string, is_object, parse_option, get_keys } from "./common.js"; | ||
import apply_async from "./async.js"; | ||
import { intersect, intersect_union } from "./intersect.js"; | ||
import { exportDocument, importDocument } from "./serialize.js"; | ||
import WorkerIndex from "./worker/index.js"; | ||
/** | ||
* @constructor | ||
* @implements {DocumentInterface} | ||
* @param {Object=} options | ||
* @return {Document} | ||
*/ | ||
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, /* append: */ /* skip update: */ /* skip_update: */!0); | ||
this.storetree = (opt = document.store) && !0 !== opt && []; | ||
this.store = opt && create_object(); | ||
// TODO case-insensitive tags | ||
this.tag = (opt = document.tag) && parse_tree(opt, this.marker); | ||
this.tagindex = opt && create_object(); | ||
this.cache = (opt = options.cache) && new Cache(opt); | ||
// do not apply cache again for the indexes | ||
options.cache = !1; | ||
this.worker = options.worker; | ||
// this switch is used by recall of promise callbacks | ||
this.async = !1; | ||
/** @export */ | ||
this.index = parse_descriptor.call(this, options, document); | ||
} | ||
export default Document; | ||
/** | ||
* @this 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 (this.worker) { | ||
index[key] = new WorkerIndex(opt); | ||
if (!index[key].worker) { | ||
this.worker = !1; | ||
} | ||
} | ||
if (!this.worker) { | ||
index[key] = new Index(opt, this.register); | ||
} | ||
this.tree[i] = parse_tree(key, this.marker); | ||
this.field[i] = key; | ||
} | ||
if (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 (0 <= key.indexOf("[]")) { | ||
key = key.substring(0, key.length - 2); | ||
if (key) { | ||
marker[count] = !0; | ||
} | ||
} | ||
if (key) { | ||
tree[count++] = key; | ||
} | ||
} | ||
if (count < tree.length) { | ||
tree.length = count; | ||
} | ||
return 1 < count ? tree : tree[0]; | ||
} | ||
// TODO support generic function created from string when tree depth > 1 | ||
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; | ||
} | ||
// TODO support generic function created from string when tree depth > 1 | ||
function store_value(obj, store, tree, pos, key) { | ||
obj = obj[key]; | ||
// reached target field | ||
if (pos === tree.length - 1) { | ||
// store target value | ||
store[key] = obj; | ||
} else if (obj) { | ||
if (is_array(obj)) { | ||
store = store[key] = Array(obj.length); | ||
for (let i = 0; i < obj.length; i++) { | ||
// do not increase pos (an array is not a field) | ||
store_value(obj, store, tree, pos, i); | ||
} | ||
} else { | ||
store = store[key] || (store[key] = create_object()); | ||
key = tree[++pos]; | ||
store_value(obj, store, tree, pos, key); | ||
} | ||
} | ||
} | ||
function add_index(obj, tree, marker, pos, index, id, key, _append) { | ||
obj = obj[key]; | ||
if (obj) { | ||
// reached target field | ||
if (pos === tree.length - 1) { | ||
// handle target value | ||
if (is_array(obj)) { | ||
// append array contents so each entry gets a new scoring context | ||
if (marker[pos]) { | ||
for (let i = 0; i < obj.length; i++) { | ||
index.add(id, obj[i], !0, !0); | ||
} | ||
return; | ||
} | ||
// or join array contents and use one scoring context | ||
obj = obj.join(" "); | ||
} | ||
index.add(id, obj, _append, !0); | ||
} else { | ||
if (is_array(obj)) { | ||
for (let i = 0; i < obj.length; i++) { | ||
// do not increase index, an array is not a field | ||
add_index(obj, tree, marker, pos, index, id, i, _append); | ||
} | ||
} else { | ||
key = tree[++pos]; | ||
add_index(obj, tree, marker, pos, index, id, key, _append); | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
* | ||
* @param id | ||
* @param content | ||
* @param {boolean=} _append | ||
* @returns {Document|Promise} | ||
*/ | ||
Document.prototype.add = function (id, content, _append) { | ||
if (is_object(id)) { | ||
content = id; | ||
id = parse_simple(content, this.key); | ||
} | ||
if (content && (id || 0 === id)) { | ||
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 (this.tag) { | ||
let tag = parse_simple(content, this.tag), | ||
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; | ||
// add a reference to the register for fast updates | ||
if (this.fastupdate) { | ||
const tmp = this.register[id] || (this.register[id] = []); | ||
tmp[tmp.length] = arr; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
// TODO: how to handle store when appending contents? | ||
if (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, !0); | ||
}; | ||
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++) { | ||
// workers does not share the register | ||
this.index[this.field[i]].remove(id, !this.worker); | ||
if (this.fastupdate) { | ||
// when fastupdate was enabled all ids are removed | ||
break; | ||
} | ||
} | ||
if (this.tag) { | ||
// when fastupdate was enabled all ids are already removed | ||
if (!this.fastupdate) { | ||
for (let key in this.tagindex) { | ||
const tag = this.tagindex[key], | ||
pos = tag.indexOf(id); | ||
if (-1 !== pos) { | ||
if (1 < tag.length) { | ||
tag.splice(pos, 1); | ||
} else { | ||
delete this.tagindex[key]; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
if (this.store) { | ||
delete this.store[id]; | ||
} | ||
delete this.register[id]; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* @param {!string|Object} query | ||
* @param {number|Object=} limit | ||
* @param {Object=} options | ||
* @param {Array<Array>=} _resolve For internal use only. | ||
* @returns {Promise|Array} | ||
*/ | ||
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 = [], | ||
pluck, | ||
enrich, | ||
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 /*|| (is_string(options) && [options])*/; | ||
tag = options.tag; | ||
enrich = this.store && options.enrich; | ||
bool = "and" === options.bool; | ||
limit = options.limit || limit || 100; | ||
offset = options.offset || 0; | ||
if (tag) { | ||
if (is_string(tag)) { | ||
tag = [tag]; | ||
} | ||
// when tags is used and no query was set, | ||
// then just return the tag indexes | ||
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 && (1 < field.length || tag && 1 < tag.length); | ||
const promises = !_resolve && (this.worker || this.async) && []; | ||
// TODO solve this in one loop below | ||
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; | ||
enrich = field_options.enrich || enrich; | ||
} | ||
if (promises) { | ||
promises[i] = this.index[key].searchAsync(query, limit, field_options || options); | ||
// just collect and continue | ||
continue; | ||
} else if (_resolve) { | ||
res = _resolve[i]; | ||
} else { | ||
// inherit options also when search? it is just for laziness, Object.assign() has a cost | ||
res = this.index[key].search(query, limit, field_options || options); | ||
} | ||
len = res && res.length; | ||
if (tag && len) { | ||
const arr = []; | ||
let count = 0; | ||
if (bool) { | ||
// prepare for intersection | ||
arr[0] = [res]; | ||
} | ||
for (let y = 0, key, res; y < tag.length; y++) { | ||
key = tag[y]; | ||
res = this.tagindex[key]; | ||
len = res && res.length; | ||
if (len) { | ||
count++; | ||
arr[arr.length] = bool ? [res] : res; | ||
} | ||
} | ||
if (count) { | ||
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 self = this; | ||
// anyone knows a better workaround of optionally having async promises? | ||
// the promise.all() needs to be wrapped into additional promise, | ||
// otherwise the recursive callback wouldn't run before return | ||
return new Promise(function (resolve) { | ||
Promise.all(promises).then(function (result) { | ||
resolve(self.search(query, limit, options, result)); | ||
}); | ||
}); | ||
} | ||
if (!count) { | ||
// fast path "not found" | ||
return []; | ||
} | ||
if (pluck && (!enrich || !this.store)) { | ||
// fast path optimization | ||
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; | ||
}; | ||
/** | ||
* @this Document | ||
*/ | ||
function get_tag(key, limit, offset) { | ||
let res = this.tagindex[key], | ||
len = res && res.length - offset; | ||
} | ||
/** | ||
* @this Document | ||
*/ | ||
function apply_enrich(res) { | ||
const arr = 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]; | ||
}; | ||
Document.prototype.get = function (id) { | ||
return this.store[id]; | ||
}; | ||
Document.prototype.set = function (id, data) { | ||
this.store[id] = data; | ||
return this; | ||
}; | ||
Document.prototype.searchCache = searchCache; | ||
Document.prototype.export = exportDocument; | ||
Document.prototype.import = importDocument; | ||
apply_async(Document.prototype); |
@@ -1,1 +0,28 @@ | ||
import{DEBUG,SUPPORT_ASYNC,SUPPORT_CACHE}from"./config";import{searchCache}from"./cache";function Engine(a){if(DEBUG&&this instanceof Engine)throw new Error("Can't instantiate abstract class!");SUPPORT_CACHE&&(a.prototype.searchCache=searchCache),SUPPORT_ASYNC&&(a.prototype.addAsync=addAsync,a.prototype.appendAsync=appendAsync,a.prototype.searchAsync=searchAsync,a.prototype.updateAsync=updateAsync,a.prototype.removeAsync=removeAsync)}SUPPORT_CACHE&&(Engine.prototype.searchCache=searchCache),SUPPORT_ASYNC&&(Engine.prototype.addAsync=addAsync,Engine.prototype.appendAsync=appendAsync,Engine.prototype.searchAsync=searchAsync,Engine.prototype.updateAsync=updateAsync,Engine.prototype.removeAsync=removeAsync); | ||
import { searchCache } from "./cache"; | ||
/** | ||
* @constructor | ||
* @abstract | ||
*/ | ||
function Engine(index) { | ||
index.prototype.searchCache = searchCache; | ||
index.prototype.addAsync = addAsync; | ||
index.prototype.appendAsync = appendAsync; | ||
index.prototype.searchAsync = searchAsync; | ||
index.prototype.updateAsync = updateAsync; | ||
index.prototype.removeAsync = removeAsync; | ||
} | ||
Engine.prototype.searchCache = searchCache; | ||
Engine.prototype.addAsync = addAsync; | ||
Engine.prototype.appendAsync = appendAsync; | ||
Engine.prototype.searchAsync = searchAsync; | ||
Engine.prototype.updateAsync = updateAsync; | ||
Engine.prototype.removeAsync = removeAsync; |
@@ -1,1 +0,22 @@ | ||
export const global_lang={};export const global_charset={};export function registerCharset(a,b){global_charset[a]=b}export function registerLanguage(a,b){global_lang[a]=b} | ||
export const global_lang = {}; | ||
export const global_charset = {}; | ||
/** | ||
* @param {!string} name | ||
* @param {Object} charset | ||
*/ | ||
export function registerCharset(name, charset) { | ||
global_charset[name] = charset; | ||
} | ||
/** | ||
* @param {!string} name | ||
* @param {Object} lang | ||
*/ | ||
export function registerLanguage(name, lang) { | ||
global_lang[name] = lang; | ||
} |
@@ -1,1 +0,784 @@ | ||
import{SUPPORT_ENCODER,SUPPORT_CACHE,SUPPORT_ASYNC,SUPPORT_SUGGESTION,SUPPORT_SERIALIZE}from"./config.js";import{IndexInterface}from"./type.js";import{encode as default_encoder}from"./lang/latin/default.js";import{create_object,create_object_array,concat,sort_by_length_down,is_array,is_string,is_object,parse_option}from"./common.js";import{pipeline,init_stemmer_or_matcher,init_filter}from"./lang.js";import{global_lang,global_charset}from"./global.js";import apply_async from"./async.js";import{intersect}from"./intersect.js";import Cache,{searchCache}from"./cache.js";import apply_preset from"./preset.js";import{exportIndex,importIndex}from"./serialize.js";function Index(a,b){if(!(this instanceof Index))return new Index(a);let c,d,e;a?(SUPPORT_ENCODER&&(a=apply_preset(a)),c=a.charset,d=a.lang,is_string(c)&&(-1===c.indexOf(":")&&(c+=":default"),c=global_charset[c]),is_string(d)&&(d=global_lang[d])):a={};let f,g,h=a.context||{};this.encode=a.encode||c&&c.encode||default_encoder,this.register=b||create_object(),this.resolution=f=a.resolution||9,this.tokenize=e=c&&c.tokenize||a.tokenize||"strict",this.depth="strict"===e&&h.depth,this.bidirectional=parse_option(h.bidirectional,!0),this.optimize=g=parse_option(a.optimize,!0),this.fastupdate=parse_option(a.fastupdate,!0),this.minlength=a.minlength||1,this.boost=a.boost,this.map=g?create_object_array(f):create_object(),this.resolution_ctx=f=h.resolution||1,this.ctx=g?create_object_array(f):create_object(),this.rtl=c&&c.rtl||a.rtl,this.matcher=(e=a.matcher||d&&d.matcher)&&init_stemmer_or_matcher(e,!1),this.stemmer=(e=a.stemmer||d&&d.stemmer)&&init_stemmer_or_matcher(e,!0),this.filter=(e=a.filter||d&&d.filter)&&init_filter(e),SUPPORT_CACHE&&(this.cache=(e=a.cache)&&new Cache(e))}export default Index;Index.prototype.append=function(a,b){return this.add(a,b,!0)},Index.prototype.add=function(a,b,c,d){if(b&&(a||0===a)){if(!d&&!c&&this.register[a])return this.update(a,b);b=this.encode(""+b);const e=b.length;if(e){const d=create_object(),f=create_object(),g=this.depth,h=this.resolution;for(let j=0;j<e;j++){let i=b[this.rtl?e-1-j:j],k=i.length;if(i&&k>=this.minlength&&(g||!f[i])){let l=get_score(h,e,j),m="";switch(this.tokenize){case"full":if(2<k){for(let b=0;b<k;b++)for(let d=k;d>b;d--)if(d-b>=this.minlength){const g=get_score(h,e,j,k,b);m=i.substring(b,d),this.push_index(f,m,g,a,c)}break}case"reverse":if(1<k){for(let b=k-1;0<b;b--)if(m=i[b]+m,m.length>=this.minlength){const d=get_score(h,e,j,k,b);this.push_index(f,m,d,a,c)}m=""}case"forward":if(1<k){for(let b=0;b<k;b++)m+=i[b],m.length>=this.minlength&&this.push_index(f,m,l,a,c);break}default:if(this.boost&&(l=Math.min(0|l/this.boost(b,i,j),h-1)),this.push_index(f,i,l,a,c),g&&1<e&&j<e-1){const f=create_object(),h=this.resolution_ctx,k=i,l=Math.min(g+1,e-j);f[k]=1;for(let g=1;g<l;g++)if(i=b[this.rtl?e-1-j-g:j+g],i&&i.length>=this.minlength&&!f[i]){f[i]=1;const b=get_score(h+(e/2>h?0:1),e,j,l-1,g-1),m=this.bidirectional&&i>k;this.push_index(d,m?k:i,b,a,c,m?i:k)}}}}}this.fastupdate||(this.register[a]=1)}}return this};function get_score(a,b,c,d,e){return c&&1<a?b+(d||0)<=a?c+(e||0):0|(a-1)/(b+(d||0))*(c+(e||0))+1:0}Index.prototype.push_index=function(a,b,c,d,e,f){let g=f?this.ctx:this.map;if((!a[b]||f&&!a[b][f])&&(this.optimize&&(g=g[c]),f?(a=a[b]||(a[b]=create_object()),a[f]=1,g=g[f]||(g[f]=create_object())):a[b]=1,g=g[b]||(g[b]=[]),this.optimize||(g=g[c]||(g[c]=[])),(!e||!g.includes(d))&&(g[g.length]=d,this.fastupdate))){const a=this.register[d]||(this.register[d]=[]);a[a.length]=g}},Index.prototype.search=function(a,b,c){c||(!b&&is_object(a)?(c=a,a=c.query):is_object(b)&&(c=b));let d,e,f,g=[],h=0;if(c&&(a=c.query||a,b=c.limit,h=c.offset||0,e=c.context,f=SUPPORT_SUGGESTION&&c.suggest),a&&(a=this.encode(""+a),d=a.length,1<d)){const b=create_object(),c=[];for(let e,h=0,i=0;h<d;h++)if(e=a[h],e&&e.length>=this.minlength&&!b[e]){if(!this.optimize&&!f&&!this.map[e])return g;c[i++]=e,b[e]=1}a=c,d=a.length}if(!d)return g;b||(b=100);let i,j=this.depth&&1<d&&!1!==e,k=0;j?(i=a[0],k=1):1<d&&a.sort(sort_by_length_down);for(let e,l;k<d;k++){if(l=a[k],j?(e=this.add_result(g,f,b,h,2===d,l,i),(!f||!1!==e||!g.length)&&(i=l)):e=this.add_result(g,f,b,h,1===d,l),e)return e;if(f&&k==d-1){let a=g.length;if(!a){if(j){j=0,k=-1;continue}return g}if(1===a)return single_result(g[0],b,h)}}return intersect(g,b,h,f)},Index.prototype.add_result=function(a,b,c,d,e,f,g){let h=[],i=g?this.ctx:this.map;if(this.optimize||(i=get_array(i,f,g,this.bidirectional)),i){let b=0;const j=Math.min(i.length,g?this.resolution_ctx:this.resolution);for(let a,k,l=0,m=0;l<j&&(a=i[l],!(a&&(this.optimize&&(a=get_array(a,f,g,this.bidirectional)),d&&a&&e&&(k=a.length,k<=d?(d-=k,a=null):(a=a.slice(d),d=0)),a&&(h[b++]=a,e&&(m+=a.length,m>=c)))));l++);if(b)return e?single_result(h,c,0):void(a[a.length]=h)}return!b&&h};function single_result(a,b,c){return a=1===a.length?a[0]:concat(a),c||a.length>b?a.slice(c,c+b):a}function get_array(a,b,c,d){if(c){const e=d&&b>c;a=a[e?b:c],a=a&&a[e?c:b]}else a=a[b];return a}Index.prototype.contain=function(a){return!!this.register[a]},Index.prototype.update=function(a,b){return this.remove(a).add(a,b)},Index.prototype.remove=function(a,b){const c=this.register[a];if(c){if(this.fastupdate)for(let b,d=0;d<c.length;d++)b=c[d],b.splice(b.indexOf(a),1);else remove_index(this.map,a,this.resolution,this.optimize),this.depth&&remove_index(this.ctx,a,this.resolution_ctx,this.optimize);b||delete this.register[a],SUPPORT_CACHE&&this.cache&&this.cache.del(a)}return this};function remove_index(a,b,c,d,e){let f=0;if(!is_array(a))for(let g in a)f=remove_index(a[g],b,c,d,e),f||delete a[g];else if(!e){e=Math.min(a.length,c);for(let g,h=0;h<e;h++)g=a[h],g&&(f=remove_index(g,b,c,d,e),!d&&!f&&delete a[h])}else{const c=a.indexOf(b);-1===c?f++:1<a.length&&(a.splice(c,1),f++)}return f}SUPPORT_CACHE&&(Index.prototype.searchCache=searchCache),SUPPORT_SERIALIZE&&(Index.prototype.export=exportIndex,Index.prototype.import=importIndex),SUPPORT_ASYNC&&apply_async(Index.prototype); | ||
/**! | ||
* FlexSearch.js | ||
* Author and Copyright: Thomas Wilkerling | ||
* Licence: Apache-2.0 | ||
* Hosted by Nextapps GmbH | ||
* https://github.com/nextapps-de/flexsearch | ||
*/ | ||
import { IndexInterface } from "./type.js"; | ||
import { encode as default_encoder } from "./lang/latin/default.js"; | ||
import { create_object, create_object_array, concat, sort_by_length_down, is_array, is_string, is_object, parse_option } from "./common.js"; | ||
import { pipeline, init_stemmer_or_matcher, init_filter } from "./lang.js"; | ||
import { global_lang, global_charset } from "./global.js"; | ||
import apply_async from "./async.js"; | ||
import { intersect } from "./intersect.js"; | ||
import Cache, { searchCache } from "./cache.js"; | ||
import apply_preset from "./preset.js"; | ||
import { exportIndex, importIndex } from "./serialize.js"; | ||
/** | ||
* @constructor | ||
* @implements IndexInterface | ||
* @param {Object=} options | ||
* @param {Object=} _register | ||
* @return {Index} | ||
*/ | ||
function Index(options, _register) { | ||
if (!(this instanceof Index)) { | ||
return new Index(options); | ||
} | ||
let charset, lang, tmp; | ||
if (options) { | ||
options = apply_preset(options); | ||
charset = options.charset; | ||
lang = options.lang; | ||
if (is_string(charset)) { | ||
if (-1 === charset.indexOf(":")) { | ||
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 || default_encoder; | ||
this.register = _register || create_object(); | ||
this.resolution = resolution = options.resolution || 9; | ||
this.tokenize = tmp = charset && charset.tokenize || options.tokenize || "strict"; | ||
this.depth = "strict" === tmp && context.depth; | ||
this.bidirectional = parse_option(context.bidirectional, /* append: */ /* skip update: */ /* skip_update: */!0); | ||
this.optimize = optimize = parse_option(options.optimize, !0); | ||
this.fastupdate = parse_option(options.fastupdate, !0); | ||
this.minlength = options.minlength || 1; | ||
this.boost = options.boost; | ||
// when not using the memory strategy the score array should not pre-allocated to its full length | ||
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, !1); | ||
this.stemmer = (tmp = options.stemmer || lang && lang.stemmer) && init_stemmer_or_matcher(tmp, !0); | ||
this.filter = (tmp = options.filter || lang && lang.filter) && init_filter(tmp); | ||
this.cache = (tmp = options.cache) && new Cache(tmp); | ||
} | ||
export default Index; | ||
//Index.prototype.pipeline = pipeline; | ||
/** | ||
* @param {!number|string} id | ||
* @param {!string} content | ||
*/ | ||
Index.prototype.append = function (id, content) { | ||
return this.add(id, content, !0); | ||
}; | ||
// TODO: | ||
// string + number as text | ||
// boolean, null, undefined as ? | ||
/** | ||
* @param {!number|string} id | ||
* @param {!string} content | ||
* @param {boolean=} _append | ||
* @param {boolean=} _skip_update | ||
*/ | ||
Index.prototype.add = function (id, content, _append, _skip_update) { | ||
if (content && (id || 0 === id)) { | ||
if (!_skip_update && !_append && this.register[id]) { | ||
return this.update(id, content); | ||
} | ||
content = this.encode("" + content); | ||
const length = content.length; | ||
if (length) { | ||
// check context dupes to skip all contextual redundancy along a document | ||
const dupes_ctx = create_object(), | ||
dupes = create_object(), | ||
depth = this.depth, | ||
resolution = this.resolution; | ||
for (let i = 0; i < length; i++) { | ||
let term = content[this.rtl ? length - 1 - i : i], | ||
term_length = term.length; | ||
// skip dupes will break the context chain | ||
if (term && term_length >= this.minlength && (depth || !dupes[term])) { | ||
let score = get_score(resolution, length, i), | ||
token = ""; | ||
switch (this.tokenize) { | ||
case "full": | ||
if (2 < term_length) { | ||
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; | ||
} | ||
// fallthrough to next case when term length < 3 | ||
case "reverse": | ||
// skip last round (this token exist already in "forward") | ||
if (1 < term_length) { | ||
for (let x = term_length - 1; 0 < x; 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 = ""; | ||
} | ||
// fallthrough to next case to apply forward also | ||
case "forward": | ||
if (1 < term_length) { | ||
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; | ||
} | ||
// fallthrough to next case when token has a length of 1 | ||
default: | ||
// case "strict": | ||
if (this.boost) { | ||
score = Math.min(0 | score / this.boost(content, term, i), resolution - 1); | ||
} | ||
this.push_index(dupes, term, score, id, _append); | ||
// context is just supported by tokenizer "strict" | ||
if (depth) { | ||
if (1 < length && i < length - 1) { | ||
// check inner dupes to skip repeating words in the current context | ||
const dupes_inner = create_object(), | ||
resolution = this.resolution_ctx, | ||
keyword = term, | ||
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(resolution + (length / 2 > resolution ? 0 : 1), length, i, size - 1, x - 1), | ||
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; | ||
}; | ||
/** | ||
* @param {number} resolution | ||
* @param {number} length | ||
* @param {number} i | ||
* @param {number=} term_length | ||
* @param {number=} x | ||
* @returns {number} | ||
*/ | ||
function get_score(resolution, length, i, term_length, x) { | ||
// console.log("resolution", resolution); | ||
// console.log("length", length); | ||
// console.log("term_length", term_length); | ||
// console.log("i", i); | ||
// console.log("x", x); | ||
// console.log((resolution - 1) / (length + (term_length || 0)) * (i + (x || 0)) + 1); | ||
// the first resolution slot is reserved for the best match, | ||
// when a query matches the first word(s). | ||
// also to stretch score to the whole range of resolution, the | ||
// calculation is shift by one and cut the floating point. | ||
// this needs the resolution "1" to be handled additionally. | ||
// do not stretch the resolution more than the term length will | ||
// improve performance and memory, also it improves scoring in | ||
// most cases between a short document and a long document | ||
return i && 1 < resolution ? length + (term_length || 0) <= resolution ? i + (x || 0) : 0 | (resolution - 1) / (length + (term_length || 0)) * (i + (x || 0)) + 1 : 0; | ||
} | ||
/** | ||
* @private | ||
* @param dupes | ||
* @param value | ||
* @param score | ||
* @param id | ||
* @param {boolean=} append | ||
* @param {string=} keyword | ||
*/ | ||
Index.prototype.push_index = function (dupes, value, score, id, append, keyword) { | ||
let arr = keyword ? this.ctx : this.map; | ||
if (!dupes[value] || keyword && !dupes[value][keyword]) { | ||
if (this.optimize) { | ||
arr = arr[score]; | ||
} | ||
if (keyword) { | ||
dupes = 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; | ||
// add a reference to the register for fast updates | ||
if (this.fastupdate) { | ||
const tmp = this.register[id] || (this.register[id] = []); | ||
tmp[tmp.length] = arr; | ||
} | ||
} | ||
} | ||
}; | ||
/** | ||
* @param {string|Object} query | ||
* @param {number|Object=} limit | ||
* @param {Object=} options | ||
* @returns {Array<number|string>} | ||
*/ | ||
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 = [], | ||
length, | ||
context, | ||
suggest, | ||
offset = 0; | ||
if (options) { | ||
query = options.query || query; | ||
limit = options.limit; | ||
offset = options.offset || 0; | ||
context = options.context; | ||
suggest = options.suggest; | ||
} | ||
if (query) { | ||
query = /** @type {Array} */this.encode("" + query); | ||
length = query.length; | ||
// TODO: solve this in one single loop below | ||
if (1 < length) { | ||
const dupes = create_object(), | ||
query_new = []; | ||
for (let i = 0, count = 0, term; i < length; i++) { | ||
term = query[i]; | ||
if (term && term.length >= this.minlength && !dupes[term]) { | ||
// this fast path can just apply when not in memory-optimized mode | ||
if (!this.optimize && !suggest && !this.map[term]) { | ||
// fast path "not found" | ||
return result; | ||
} else { | ||
query_new[count++] = term; | ||
dupes[term] = 1; | ||
} | ||
} | ||
} | ||
query = query_new; | ||
length = query.length; | ||
} | ||
} | ||
if (!length) { | ||
return result; | ||
} | ||
limit || (limit = 100); | ||
let depth = this.depth && 1 < length && !1 !== context, | ||
index = 0, | ||
keyword; | ||
if (depth) { | ||
keyword = query[0]; | ||
index = 1; | ||
} else { | ||
if (1 < length) { | ||
query.sort(sort_by_length_down); | ||
} | ||
} | ||
for (let arr, term; index < length; index++) { | ||
term = query[index]; | ||
// console.log(keyword); | ||
// console.log(term); | ||
// console.log(""); | ||
if (depth) { | ||
arr = this.add_result(result, suggest, limit, offset, 2 === length, term, keyword); | ||
// console.log(arr); | ||
// console.log(result); | ||
// when suggestion enabled just forward keyword if term was found | ||
// as long as the result is empty forward the pointer also | ||
if (!suggest || !1 !== arr || !result.length) { | ||
keyword = term; | ||
} | ||
} else { | ||
arr = this.add_result(result, suggest, limit, offset, 1 === length, term); | ||
} | ||
if (arr) { | ||
return (/** @type {Array<number|string>} */arr | ||
); | ||
} | ||
// apply suggestions on last loop or fallback | ||
if (suggest && index == length - 1) { | ||
let length = result.length; | ||
if (!length) { | ||
if (depth) { | ||
// fallback to non-contextual search when no result was found | ||
depth = 0; | ||
index = -1; | ||
continue; | ||
} | ||
return result; | ||
} else if (1 === length) { | ||
// fast path optimization | ||
return single_result(result[0], limit, offset); | ||
} | ||
} | ||
} | ||
return intersect(result, limit, offset, suggest); | ||
}; | ||
/** | ||
* Returns an array when the result is done (to stop the process immediately), | ||
* returns false when suggestions is enabled and no result was found, | ||
* or returns nothing when a set was pushed successfully to the results | ||
* | ||
* @private | ||
* @param {Array} result | ||
* @param {Array} suggest | ||
* @param {number} limit | ||
* @param {number} offset | ||
* @param {boolean} single_term | ||
* @param {string} term | ||
* @param {string=} keyword | ||
* @return {Array<Array<string|number>>|boolean|undefined} | ||
*/ | ||
Index.prototype.add_result = function (result, suggest, limit, offset, single_term, term, keyword) { | ||
let word_arr = [], | ||
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); | ||
// relevance: | ||
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) { | ||
// keep score (sparse array): | ||
//word_arr[x] = tmp; | ||
// simplified score order: | ||
word_arr[count++] = tmp; | ||
if (single_term) { | ||
size += tmp.length; | ||
if (size >= limit) { | ||
// fast path optimization | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
if (count) { | ||
if (single_term) { | ||
// fast path optimization | ||
// offset was already applied at this point | ||
return single_result(word_arr, limit, 0); | ||
} | ||
result[result.length] = word_arr; | ||
return; | ||
} | ||
} | ||
// return an empty array will stop the loop, | ||
// to prevent stop when using suggestions return a false value | ||
return !suggest && word_arr; | ||
}; | ||
function single_result(result, limit, offset) { | ||
if (1 === result.length) { | ||
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) { | ||
// the frequency of the starting letter is slightly less | ||
// on the last half of the alphabet (m-z) in almost every latin language, | ||
// so we sort downwards (https://en.wikipedia.org/wiki/Letter_frequency) | ||
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); | ||
}; | ||
/** | ||
* @param {boolean=} _skip_deletion | ||
*/ | ||
Index.prototype.remove = function (id, _skip_deletion) { | ||
const refs = this.register[id]; | ||
if (refs) { | ||
if (this.fastupdate) { | ||
// fast updates performs really fast but did not fully cleanup the key entries | ||
for (let i = 0, tmp; i < refs.length; i++) { | ||
tmp = refs[i]; | ||
tmp.splice(tmp.indexOf(id), 1); | ||
} | ||
} else { | ||
remove_index(this.map, id, this.resolution, this.optimize); | ||
if (this.depth) { | ||
remove_index(this.ctx, id, this.resolution_ctx, this.optimize); | ||
} | ||
} | ||
_skip_deletion || delete this.register[id]; | ||
if (this.cache) { | ||
this.cache.del(id); | ||
} | ||
} | ||
return this; | ||
}; | ||
/** | ||
* @param map | ||
* @param id | ||
* @param res | ||
* @param optimize | ||
* @param {number=} resolution | ||
* @return {number} | ||
*/ | ||
function remove_index(map, id, res, optimize, resolution) { | ||
let count = 0; | ||
if (is_array(map)) { | ||
// the first array is the score array in both strategies | ||
if (!resolution) { | ||
resolution = Math.min(map.length, res); | ||
for (let x = 0, arr; x < resolution; x++) { | ||
arr = map[x]; | ||
if (arr) { | ||
count = remove_index(arr, id, res, optimize, resolution); | ||
if (!optimize && !count) { | ||
// when not memory optimized the score index should removed | ||
delete map[x]; | ||
} | ||
} | ||
} | ||
} else { | ||
const pos = map.indexOf(id); | ||
if (-1 !== pos) { | ||
// fast path, when length is 1 or lower then the whole field gets deleted | ||
if (1 < map.length) { | ||
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; | ||
} | ||
Index.prototype.searchCache = searchCache; | ||
Index.prototype.export = exportIndex; | ||
Index.prototype.import = importIndex; | ||
apply_async(Index.prototype); |
@@ -1,1 +0,394 @@ | ||
import{create_object,concat}from"./common.js";export function intersect(a,b,c,d){const e=a.length;let f,g,h=[],i=0;d&&(d=[]);for(let j=e-1;0<=j;j--){const k=a[j],l=k.length,m=create_object();let n=!f;for(let a=0;a<l;a++){const l=k[a],o=l.length;if(o)for(let a,k,p=0;p<o;p++)if(k=l[p],f){if(f[k]){if(!j)if(c)c--;else if(h[i++]=k,i===b)return h;(j||d)&&(m[k]=1),n=!0}if(d&&(a=(g[k]||0)+1,g[k]=a,a<e)){const b=d[a-2]||(d[a-2]=[]);b[b.length]=k}}else m[k]=1}if(d)f||(g=m);else if(!n)return[];f=m}if(d)for(let a,e,g=d.length-1;0<=g;g--){a=d[g],e=a.length;for(let d,g=0;g<e;g++)if(d=a[g],!f[d]){if(c)c--;else if(h[i++]=d,i===b)return h;f[d]=1}}return h}export function intersect_union(a,b){const c=create_object(),d=create_object(),e=[];for(let d=0;d<a.length;d++)c[a[d]]=1;for(let f,g=0;g<b.length;g++){f=b[g];for(let a,b=0;b<f.length;b++)a=f[b],c[a]&&!d[a]&&(d[a]=1,e[e.length]=a)}return e} | ||
import { create_object, concat } from "./common.js"; | ||
/** | ||
* Implementation based on Array.includes() provides better performance, | ||
* but it needs at least one word in the query which is less frequent. | ||
* Also on large indexes it does not scale well performance-wise. | ||
* This strategy also lacks of suggestion capabilities (matching & sorting). | ||
* | ||
* @param arrays | ||
* @param limit | ||
* @param offset | ||
* @param {boolean|Array=} suggest | ||
* @returns {Array} | ||
*/ | ||
// export function intersect(arrays, limit, offset, suggest) { | ||
// | ||
// const length = arrays.length; | ||
// let result = []; | ||
// let check; | ||
// | ||
// // determine shortest array and collect results | ||
// // from the sparse relevance arrays | ||
// | ||
// let smallest_size; | ||
// let smallest_arr; | ||
// let smallest_index; | ||
// | ||
// for(let x = 0; x < length; x++){ | ||
// | ||
// const arr = arrays[x]; | ||
// const len = arr.length; | ||
// | ||
// let size = 0; | ||
// | ||
// for(let y = 0, tmp; y < len; y++){ | ||
// | ||
// tmp = arr[y]; | ||
// | ||
// if(tmp){ | ||
// | ||
// size += tmp.length; | ||
// } | ||
// } | ||
// | ||
// if(!smallest_size || (size < smallest_size)){ | ||
// | ||
// smallest_size = size; | ||
// smallest_arr = arr; | ||
// smallest_index = x; | ||
// } | ||
// } | ||
// | ||
// smallest_arr = smallest_arr.length === 1 ? | ||
// | ||
// smallest_arr[0] | ||
// : | ||
// concat(smallest_arr); | ||
// | ||
// if(suggest){ | ||
// | ||
// suggest = [smallest_arr]; | ||
// check = create_object(); | ||
// } | ||
// | ||
// let size = 0; | ||
// let steps = 0; | ||
// | ||
// // process terms in reversed order often results in better performance. | ||
// // the outer loop must be the words array, using the | ||
// // smallest array here disables the "fast fail" optimization. | ||
// | ||
// for(let x = length - 1; x >= 0; x--){ | ||
// | ||
// if(x !== smallest_index){ | ||
// | ||
// steps++; | ||
// | ||
// const word_arr = arrays[x]; | ||
// const word_arr_len = word_arr.length; | ||
// const new_arr = []; | ||
// | ||
// let count = 0; | ||
// | ||
// for(let z = 0, id; z < smallest_arr.length; z++){ | ||
// | ||
// id = smallest_arr[z]; | ||
// | ||
// let found; | ||
// | ||
// // process relevance in forward order (direction is | ||
// // important for adding IDs during the last round) | ||
// | ||
// for(let y = 0; y < word_arr_len; y++){ | ||
// | ||
// const arr = word_arr[y]; | ||
// | ||
// if(arr.length){ | ||
// | ||
// found = arr.includes(id); | ||
// | ||
// if(found){ | ||
// | ||
// // check if in last round | ||
// | ||
// if(steps === length - 1){ | ||
// | ||
// if(offset){ | ||
// | ||
// offset--; | ||
// } | ||
// else{ | ||
// | ||
// result[size++] = id; | ||
// | ||
// if(size === limit){ | ||
// | ||
// // fast path "end reached" | ||
// | ||
// return result; | ||
// } | ||
// } | ||
// | ||
// if(suggest){ | ||
// | ||
// check[id] = 1; | ||
// } | ||
// } | ||
// | ||
// break; | ||
// } | ||
// } | ||
// } | ||
// | ||
// if(found){ | ||
// | ||
// new_arr[count++] = id; | ||
// } | ||
// } | ||
// | ||
// if(suggest){ | ||
// | ||
// suggest[steps] = new_arr; | ||
// } | ||
// else if(!count){ | ||
// | ||
// return []; | ||
// } | ||
// | ||
// smallest_arr = new_arr; | ||
// } | ||
// } | ||
// | ||
// if(suggest){ | ||
// | ||
// // needs to iterate in reverse direction | ||
// | ||
// for(let x = suggest.length - 1, arr, len; x >= 0; x--){ | ||
// | ||
// arr = suggest[x]; | ||
// len = arr && arr.length; | ||
// | ||
// if(len){ | ||
// | ||
// for(let y = 0, id; y < len; y++){ | ||
// | ||
// id = arr[y]; | ||
// | ||
// if(!check[id]){ | ||
// | ||
// check[id] = 1; | ||
// | ||
// if(offset){ | ||
// | ||
// offset--; | ||
// } | ||
// else{ | ||
// | ||
// result[size++] = id; | ||
// | ||
// if(size === limit){ | ||
// | ||
// // fast path "end reached" | ||
// | ||
// return result; | ||
// } | ||
// } | ||
// } | ||
// } | ||
// } | ||
// } | ||
// } | ||
// | ||
// return result; | ||
// } | ||
/** | ||
* Implementation based on Object[key] provides better suggestions | ||
* capabilities and has less performance scaling issues on large indexes. | ||
* | ||
* @param arrays | ||
* @param limit | ||
* @param offset | ||
* @param {boolean|Array=} suggest | ||
* @returns {Array} | ||
*/ | ||
export function intersect(arrays, limit, offset, suggest) { | ||
const length = arrays.length; | ||
let result = [], | ||
check, | ||
check_suggest, | ||
size = 0; | ||
if (suggest) { | ||
suggest = []; | ||
} | ||
// process terms in reversed order often has advantage for the fast path "end reached". | ||
// also a reversed order prioritize the order of words from a query. | ||
for (let x = length - 1; 0 <= x; x--) { | ||
const word_arr = arrays[x], | ||
word_arr_len = word_arr.length, | ||
check_new = create_object(); | ||
let found = !check; | ||
// process relevance in forward order (direction is | ||
// important for adding IDs during the last round) | ||
for (let y = 0; y < word_arr_len; y++) { | ||
const arr = word_arr[y], | ||
arr_len = arr.length; | ||
if (arr_len) { | ||
// loop through IDs | ||
for (let z = 0, check_idx, id; z < arr_len; z++) { | ||
id = arr[z]; | ||
if (check) { | ||
if (check[id]) { | ||
// check if in last round | ||
if (!x) { | ||
if (offset) { | ||
offset--; | ||
} else { | ||
result[size++] = id; | ||
if (size === limit) { | ||
// fast path "end reached" | ||
return result; | ||
} | ||
} | ||
} | ||
if (x || suggest) { | ||
check_new[id] = 1; | ||
} | ||
found = /* append: */ /* skip update: */ /* skip_update: */!0; | ||
} | ||
if (suggest) { | ||
check_idx = (check_suggest[id] || 0) + 1; | ||
check_suggest[id] = check_idx; | ||
// do not adding IDs which are already included in the result (saves one loop) | ||
// the first intersection match has the check index 2, so shift by -2 | ||
if (check_idx < length) { | ||
const tmp = suggest[check_idx - 2] || (suggest[check_idx - 2] = []); | ||
tmp[tmp.length] = id; | ||
} | ||
} | ||
} else { | ||
// pre-fill in first round | ||
check_new[id] = 1; | ||
} | ||
} | ||
} | ||
} | ||
if (suggest) { | ||
// re-use the first pre-filled check for suggestions | ||
check || (check_suggest = check_new); | ||
} else if (!found) { | ||
return []; | ||
} | ||
check = check_new; | ||
} | ||
if (suggest) { | ||
// needs to iterate in reverse direction | ||
for (let x = suggest.length - 1, arr, len; 0 <= x; 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) { | ||
// fast path "end reached" | ||
return result; | ||
} | ||
} | ||
check[id] = 1; | ||
} | ||
} | ||
} | ||
} | ||
return result; | ||
} | ||
/** | ||
* @param mandatory | ||
* @param arrays | ||
* @returns {Array} | ||
*/ | ||
export function intersect_union(mandatory, arrays) { | ||
const check = create_object(), | ||
union = create_object(), | ||
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; | ||
} |
@@ -1,1 +0,321 @@ | ||
import{IndexInterface}from"./type.js";import{create_object,get_keys}from"./common.js";export function pipeline(a,b,c,d){if(a&&(b&&(a=replace(a,b)),this.matcher&&(a=replace(a,this.matcher)),this.stemmer&&1<a.length&&(a=replace(a,this.stemmer)),d&&1<a.length&&(a=collapse(a)),c||""===c)){const b=a.split(c);return this.filter?filter(b,this.filter):b}return a}export const regex_whitespace=/[\p{Z}\p{S}\p{P}\p{C}]+/u;const regex_normalize=/[\u0300-\u036f]/g;export function normalize(a){return a.normalize&&(a=a.normalize("NFD").replace(regex_normalize,"")),a}export function init_filter(a){const b=create_object();for(let c=0,d=a.length;c<d;c++)b[a[c]]=1;return b}export function init_stemmer_or_matcher(a,b){const c=get_keys(a),d=c.length,e=[];let f="",g=0;for(let h,j,k=0;k<d;k++)h=c[k],j=a[h],j?(e[g++]=regex(b?"(?!\\b)"+h+"(\\b|_)":h),e[g++]=j):f+=(f?"|":"")+h;return f&&(e[g++]=regex(b?"(?!\\b)("+f+")(\\b|_)":"("+f+")"),e[g]=""),e}export function replace(a,b){for(let c=0,d=b.length;c<d&&(a=a.replace(b[c],b[c+1]),!!a);c+=2);return a}export function regex(a){return new RegExp(a,"g")}export function collapse(a){let b="",c="";for(let d,e=0,f=a.length;e<f;e++)(d=a[e])!==c&&(b+=c=d);return b}export function filter(a,b){const c=a.length,d=[];for(let e=0,f=0;e<c;e++){const c=a[e];c&&!b[c]&&(d[f++]=c)}return d} | ||
import { IndexInterface } from "./type.js"; | ||
import { create_object, get_keys } from "./common.js"; | ||
/** | ||
* @param {!string} str | ||
* @param {boolean|Array<string|RegExp>=} normalize | ||
* @param {boolean|string|RegExp=} split | ||
* @param {boolean=} _collapse | ||
* @returns {string|Array<string>} | ||
* @this IndexInterface | ||
*/ | ||
export function pipeline(str, normalize, split, _collapse) { | ||
if (str) { | ||
if (normalize) { | ||
str = replace(str, /** @type {Array<string|RegExp>} */normalize); | ||
} | ||
if (this.matcher) { | ||
str = replace(str, this.matcher); | ||
} | ||
if (this.stemmer && 1 < str.length) { | ||
str = replace(str, this.stemmer); | ||
} | ||
if (_collapse && 1 < str.length) { | ||
str = collapse(str); | ||
} | ||
if (split || "" === split) { | ||
const words = str.split( /** @type {string|RegExp} */split); | ||
return this.filter ? filter(words, this.filter) : words; | ||
} | ||
} | ||
return str; | ||
} | ||
// TODO improve normalize + remove non-delimited chars like in "I'm" + split on whitespace+ | ||
export const regex_whitespace = /[\p{Z}\p{S}\p{P}\p{C}]+/u; | ||
// https://github.com/nextapps-de/flexsearch/pull/414 | ||
//export const regex_whitespace = /[\s\xA0\u2000-\u200B\u2028\u2029\u3000\ufeff!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]/ | ||
const regex_normalize = /[\u0300-\u036f]/g; | ||
export function normalize(str) { | ||
if (str.normalize) { | ||
str = str.normalize("NFD").replace(regex_normalize, ""); | ||
} | ||
return str; | ||
} | ||
/** | ||
* @param {!string} str | ||
* @param {boolean|Array<string|RegExp>=} normalize | ||
* @param {boolean|string|RegExp=} split | ||
* @param {boolean=} _collapse | ||
* @returns {string|Array<string>} | ||
*/ | ||
// FlexSearch.prototype.pipeline = function(str, normalize, split, _collapse){ | ||
// | ||
// if(str){ | ||
// | ||
// if(normalize && str){ | ||
// | ||
// str = replace(str, /** @type {Array<string|RegExp>} */ (normalize)); | ||
// } | ||
// | ||
// if(str && this.matcher){ | ||
// | ||
// str = replace(str, this.matcher); | ||
// } | ||
// | ||
// if(this.stemmer && str.length > 1){ | ||
// | ||
// str = replace(str, this.stemmer); | ||
// } | ||
// | ||
// if(_collapse && str.length > 1){ | ||
// | ||
// str = collapse(str); | ||
// } | ||
// | ||
// if(str){ | ||
// | ||
// if(split || (split === "")){ | ||
// | ||
// const words = str.split(/** @type {string|RegExp} */ (split)); | ||
// | ||
// return this.filter ? filter(words, this.filter) : words; | ||
// } | ||
// } | ||
// } | ||
// | ||
// return str; | ||
// }; | ||
// export function pipeline(str, normalize, matcher, stemmer, split, _filter, _collapse){ | ||
// | ||
// if(str){ | ||
// | ||
// if(normalize && str){ | ||
// | ||
// str = replace(str, normalize); | ||
// } | ||
// | ||
// if(matcher && str){ | ||
// | ||
// str = replace(str, matcher); | ||
// } | ||
// | ||
// if(stemmer && str.length > 1){ | ||
// | ||
// str = replace(str, stemmer); | ||
// } | ||
// | ||
// if(_collapse && str.length > 1){ | ||
// | ||
// str = collapse(str); | ||
// } | ||
// | ||
// if(str){ | ||
// | ||
// if(split !== false){ | ||
// | ||
// str = str.split(split); | ||
// | ||
// if(_filter){ | ||
// | ||
// str = filter(str, _filter); | ||
// } | ||
// } | ||
// } | ||
// } | ||
// | ||
// return str; | ||
// } | ||
/** | ||
* @param {Array<string>} words | ||
* @returns {Object<string, string>} | ||
*/ | ||
export function init_filter(words) { | ||
const filter = create_object(); | ||
for (let i = 0, length = words.length; i < length; i++) { | ||
filter[words[i]] = 1; | ||
} | ||
return filter; | ||
} | ||
/** | ||
* @param {!Object<string, string>} obj | ||
* @param {boolean} is_stemmer | ||
* @returns {Array} | ||
*/ | ||
export function init_stemmer_or_matcher(obj, is_stemmer) { | ||
const keys = get_keys(obj), | ||
length = keys.length, | ||
final = []; | ||
let removal = "", | ||
count = 0; | ||
for (let i = 0, key, tmp; i < length; i++) { | ||
key = keys[i]; | ||
tmp = obj[key]; | ||
if (tmp) { | ||
final[count++] = regex(is_stemmer ? "(?!\\b)" + key + "(\\b|_)" : key); | ||
final[count++] = tmp; | ||
} else { | ||
removal += (removal ? "|" : "") + key; | ||
} | ||
} | ||
if (removal) { | ||
final[count++] = regex(is_stemmer ? "(?!\\b)(" + removal + ")(\\b|_)" : "(" + removal + ")"); | ||
final[count] = ""; | ||
} | ||
return final; | ||
} | ||
/** | ||
* @param {!string} str | ||
* @param {Array} regexp | ||
* @returns {string} | ||
*/ | ||
export function replace(str, regexp) { | ||
for (let i = 0, len = regexp.length; i < len; i += 2) { | ||
str = str.replace(regexp[i], regexp[i + 1]); | ||
if (!str) { | ||
break; | ||
} | ||
} | ||
return str; | ||
} | ||
/** | ||
* @param {!string} str | ||
* @returns {RegExp} | ||
*/ | ||
export function regex(str) { | ||
return new RegExp(str, "g"); | ||
} | ||
/** | ||
* Regex: replace(/(?:(\w)(?:\1)*)/g, "$1") | ||
* @param {!string} string | ||
* @returns {string} | ||
*/ | ||
export function collapse(string) { | ||
let final = "", | ||
prev = ""; | ||
for (let i = 0, len = string.length, char; i < len; i++) { | ||
if ((char = string[i]) !== prev) { | ||
final += prev = char; | ||
} | ||
} | ||
return final; | ||
} | ||
// TODO using fast-swap | ||
export function filter(words, map) { | ||
const length = words.length, | ||
filtered = []; | ||
for (let i = 0, count = 0; i < length; i++) { | ||
const word = words[i]; | ||
if (word && !map[word]) { | ||
filtered[count++] = word; | ||
} | ||
} | ||
return filtered; | ||
} | ||
// const chars = {a:1, e:1, i:1, o:1, u:1, y:1}; | ||
// | ||
// function collapse_repeating_chars(string){ | ||
// | ||
// let collapsed_string = "", | ||
// char_prev = "", | ||
// char_next = ""; | ||
// | ||
// for(let i = 0; i < string.length; i++){ | ||
// | ||
// const char = string[i]; | ||
// | ||
// if(char !== char_prev){ | ||
// | ||
// if(i && (char === "h")){ | ||
// | ||
// if((chars[char_prev] && chars[char_next]) || (char_prev === " ")){ | ||
// | ||
// collapsed_string += char; | ||
// } | ||
// } | ||
// else{ | ||
// | ||
// collapsed_string += char; | ||
// } | ||
// } | ||
// | ||
// char_next = ( | ||
// | ||
// (i === (string.length - 1)) ? | ||
// | ||
// "" | ||
// : | ||
// string[i + 1] | ||
// ); | ||
// | ||
// char_prev = char; | ||
// } | ||
// | ||
// return collapsed_string; | ||
// } |
@@ -1,1 +0,27 @@ | ||
import{IndexInterface}from"../../type.js";import{pipeline}from"../../lang.js";export const rtl=!0;export const tokenize="";export default{encode:encode,rtl:!0};const regex=/[\x00-\x7F]+/g,split=/\s+/;export function encode(a){return pipeline.call(this,(""+a).replace(regex," "),!1,split,!1)} | ||
import { IndexInterface } from "../../type.js"; | ||
import { pipeline } from "../../lang.js"; | ||
export const rtl = /* append: */ /* skip update: */ /* skip_update: */!0; | ||
export const tokenize = ""; | ||
export default { | ||
encode: encode, | ||
rtl: !0 | ||
}; | ||
const regex = /[\x00-\x7F]+/g, | ||
split = /\s+/; | ||
/** | ||
* @param {string|number} str | ||
* @this IndexInterface | ||
*/ | ||
export function encode(str) { | ||
return pipeline.call(this, | ||
/* string: */("" + str).replace(regex, " "), | ||
/* normalize: */ | ||
/* collapse: */!1, | ||
/* split: */split, !1); | ||
} |
@@ -1,1 +0,41 @@ | ||
export const filter=["aber","als","am","an","auch","auf","aus","bei","bin","bis","bist","da","dadurch","daher","darum","das","da\xDF","dass","dein","deine","dem","den","der","des","dessen","deshalb","die","dies","dieser","dieses","doch","dort","du","durch","ein","eine","einem","einen","einer","eines","er","es","euer","eure","f\xFCr","hatte","hatten","hattest","hattet","hier","hinter","ich","ihr","ihre","im","in","ist","ja","jede","jedem","jeden","jeder","jedes","jener","jenes","jetzt","kann","kannst","k\xF6nnen","k\xF6nnt","machen","mein","meine","mit","mu\xDF","mu\xDFt","musst","m\xFCssen","m\xFC\xDFt","nach","nachdem","nein","nicht","nun","oder","seid","sein","seine","sich","sie","sind","soll","sollen","sollst","sollt","sonst","soweit","sowie","und","unser","unsere","unter","vom","von","vor","wann","warum","was","weiter","weitere","wenn","wer","werde","werden","werdet","weshalb","wie","wieder","wieso","wir","wird","wirst","wo","woher","wohin","zu","zum","zur","\xFCber"];export const stemmer={niss:"",isch:"",lich:"",heit:"",keit:"",end:"",ung:"",est:"",ern:"",em:"",er:"",en:"",es:"",st:"",ig:"",ik:"",e:"",s:""};export const matcher={};export default{filter:filter,stemmer:stemmer,matcher:matcher}; | ||
/** | ||
* http://www.ranks.nl/stopwords | ||
* @type {Array<string>} | ||
*/ | ||
export const filter = ["aber", "als", "am", "an", "auch", "auf", "aus", "bei", "bin", "bis", "bist", "da", "dadurch", "daher", "darum", "das", "daß", "dass", "dein", "deine", "dem", "den", "der", "des", "dessen", "deshalb", "die", "dies", "dieser", "dieses", "doch", "dort", "du", "durch", "ein", "eine", "einem", "einen", "einer", "eines", "er", "es", "euer", "eure", "für", "hatte", "hatten", "hattest", "hattet", "hier", "hinter", "ich", "ihr", "ihre", "im", "in", "ist", "ja", "jede", "jedem", "jeden", "jeder", "jedes", "jener", "jenes", "jetzt", "kann", "kannst", "können", "könnt", "machen", "mein", "meine", "mit", "muß", "mußt", "musst", "müssen", "müßt", "nach", "nachdem", "nein", "nicht", "nun", "oder", "seid", "sein", "seine", "sich", "sie", "sind", "soll", "sollen", "sollst", "sollt", "sonst", "soweit", "sowie", "und", "unser", "unsere", "unter", "vom", "von", "vor", "wann", "warum", "was", "weiter", "weitere", "wenn", "wer", "werde", "werden", "werdet", "weshalb", "wie", "wieder", "wieso", "wir", "wird", "wirst", "wo", "woher", "wohin", "zu", "zum", "zur", "über"]; | ||
/** | ||
* @type {Object<string, string>} | ||
*/ | ||
export const stemmer = { | ||
niss: "", | ||
isch: "", | ||
lich: "", | ||
heit: "", | ||
keit: "", | ||
end: "", | ||
ung: "", | ||
est: "", | ||
ern: "", | ||
em: "", | ||
er: "", | ||
en: "", | ||
es: "", | ||
st: "", | ||
ig: "", | ||
ik: "", | ||
e: "", | ||
s: "" | ||
}; | ||
export const matcher = {}; | ||
export default { | ||
filter: filter, | ||
stemmer: stemmer, | ||
matcher: matcher | ||
}; |
@@ -1,1 +0,26 @@ | ||
import{IndexInterface}from"../../type.js";import{pipeline}from"../../lang.js";export const rtl=!1;export const tokenize="strict";export default{encode:encode,rtl:!1,tokenize:"strict"};const regex=/[\x00-\x7F]+/g;export function encode(a){return pipeline.call(this,(""+a).replace(regex,""),!1,"",!1)} | ||
import { IndexInterface } from "../../type.js"; | ||
import { pipeline } from "../../lang.js"; | ||
export const rtl = /* normalize: */ /* collapse: */ | ||
/* normalize: */ | ||
/* collapse: */!1; | ||
export const tokenize = "strict"; | ||
export default { | ||
encode: encode, | ||
rtl: !1, | ||
tokenize: "strict" | ||
}; | ||
const regex = /[\x00-\x7F]+/g; | ||
/** | ||
* @param {string|number} str | ||
* @this IndexInterface | ||
*/ | ||
export function encode(str) { | ||
return pipeline.call(this, | ||
/* string: */("" + str).replace(regex, ""), !1, | ||
/* split: */"", !1); | ||
} |
@@ -1,1 +0,27 @@ | ||
import{IndexInterface}from"../../type.js";import{pipeline}from"../../lang.js";export const rtl=!1;export const tokenize="";export default{encode:encode,rtl:!1};const regex=/[\x00-\x7F]+/g,split=/\s+/;export function encode(a){return pipeline.call(this,(""+a).replace(regex," "),!1,split,!1)} | ||
import { IndexInterface } from "../../type.js"; | ||
import { pipeline } from "../../lang.js"; | ||
export const rtl = /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ | ||
/* normalize: */ | ||
/* collapse: */!1; | ||
export const tokenize = ""; | ||
export default { | ||
encode: encode, | ||
rtl: !1 | ||
}; | ||
const regex = /[\x00-\x7F]+/g, | ||
split = /\s+/; | ||
/** | ||
* @param {string|number} str | ||
* @this IndexInterface | ||
*/ | ||
export function encode(str) { | ||
return pipeline.call(this, | ||
/* string: */("" + str).replace(regex, " "), !1, | ||
/* split: */split, !1); | ||
} |
@@ -1,1 +0,54 @@ | ||
export const filter=["aber","als","am","an","auch","auf","aus","bei","bin","bis","bist","da","dadurch","daher","darum","das","da\xDF","dass","dein","deine","dem","den","der","des","dessen","deshalb","die","dies","dieser","dieses","doch","dort","du","durch","ein","eine","einem","einen","einer","eines","er","es","euer","eure","f\xFCr","hatte","hatten","hattest","hattet","hier","hinter","ich","ihr","ihre","im","in","ist","ja","jede","jedem","jeden","jeder","jedes","jener","jenes","jetzt","kann","kannst","k\xF6nnen","k\xF6nnt","machen","mein","meine","mit","mu\xDF","mu\xDFt","musst","m\xFCssen","m\xFC\xDFt","nach","nachdem","nein","nicht","nun","oder","seid","sein","seine","sich","sie","sind","soll","sollen","sollst","sollt","sonst","soweit","sowie","und","unser","unsere","unter","vom","von","vor","wann","warum","was","weiter","weitere","wenn","wer","werde","werden","werdet","weshalb","wie","wieder","wieso","wir","wird","wirst","wo","woher","wohin","zu","zum","zur","\xFCber"];export const stemmer={niss:"",isch:"",lich:"",heit:"",keit:"",ell:"",bar:"",end:"",ung:"",est:"",ern:"",em:"",er:"",en:"",es:"",st:"",ig:"",ik:"",e:"",s:""};export const matcher={};export default{filter:filter,stemmer:stemmer,matcher:matcher}; | ||
/** | ||
* Filter are also known as "stopwords", they completely filter out words from being indexed. | ||
* Source: http://www.ranks.nl/stopwords | ||
* Object Definition: Just provide an array of words. | ||
* @type {Array<string>} | ||
*/ | ||
export const filter = ["aber", "als", "am", "an", "auch", "auf", "aus", "bei", "bin", "bis", "bist", "da", "dadurch", "daher", "darum", "das", "daß", "dass", "dein", "deine", "dem", "den", "der", "des", "dessen", "deshalb", "die", "dies", "dieser", "dieses", "doch", "dort", "du", "durch", "ein", "eine", "einem", "einen", "einer", "eines", "er", "es", "euer", "eure", "für", "hatte", "hatten", "hattest", "hattet", "hier", "hinter", "ich", "ihr", "ihre", "im", "in", "ist", "ja", "jede", "jedem", "jeden", "jeder", "jedes", "jener", "jenes", "jetzt", "kann", "kannst", "können", "könnt", "machen", "mein", "meine", "mit", "muß", "mußt", "musst", "müssen", "müßt", "nach", "nachdem", "nein", "nicht", "nun", "oder", "seid", "sein", "seine", "sich", "sie", "sind", "soll", "sollen", "sollst", "sollt", "sonst", "soweit", "sowie", "und", "unser", "unsere", "unter", "vom", "von", "vor", "wann", "warum", "was", "weiter", "weitere", "wenn", "wer", "werde", "werden", "werdet", "weshalb", "wie", "wieder", "wieso", "wir", "wird", "wirst", "wo", "woher", "wohin", "zu", "zum", "zur", "über"]; | ||
/** | ||
* Stemmer removes word endings and is a kind of "partial normalization". A word ending just matched when the word length is bigger than the matched partial. | ||
* Example: The word "correct" and "correctness" could be the same word, so you can define {"ness": ""} to normalize the ending. | ||
* Object Definition: the key represents the word ending, the value contains the replacement (or empty string for removal). | ||
* @type {Object<string, string>} | ||
*/ | ||
export const stemmer = { | ||
niss: "", | ||
isch: "", | ||
lich: "", | ||
heit: "", | ||
keit: "", | ||
ell: "", | ||
bar: "", | ||
end: "", | ||
ung: "", | ||
est: "", | ||
ern: "", | ||
em: "", | ||
er: "", | ||
en: "", | ||
es: "", | ||
st: "", | ||
ig: "", | ||
ik: "", | ||
e: "", | ||
s: "" | ||
}; | ||
/** | ||
* Matcher replaces all occurrences of a given string regardless of its position and is also a kind of "partial normalization". | ||
* Object Definition: the key represents the target term, the value contains the search string which should be replaced (could also be an array of multiple terms). | ||
* @type {Object<string, Array<string>|string>} | ||
*/ | ||
export const matcher = {}; | ||
export default { | ||
filter: filter, | ||
stemmer: stemmer, | ||
matcher: matcher | ||
}; |
@@ -1,1 +0,100 @@ | ||
export const filter=["a","about","above","after","again","against","all","also","am","an","and","any","are","aren't","as","at","be","because","been","before","being","below","both","but","by","can","cannot","can't","come","could","couldn't","did","didn't","do","does","doesn't","doing","dont","down","during","each","even","few","first","for","from","further","get","go","had","hadn't","has","hasn't","have","haven't","having","he","hed","her","here","here's","hers","herself","hes","him","himself","his","how","how's","i","id","if","ill","im","in","into","is","isn't","it","it's","itself","i've","just","know","let's","like","make","me","more","most","mustn't","my","myself","new","no","nor","not","now","of","off","on","once","only","or","other","ought","our","our's","ourselves","out","over","own","same","say","see","shan't","she","she'd","shell","shes","should","shouldn't","so","some","such","than","that","that's","the","their","theirs","them","themselves","then","there","there's","these","they","they'd","they'll","they're","they've","this","those","through","time","to","too","until","up","us","very","want","was","wasn't","way","we","wed","well","were","weren't","we've","what","what's","when","when's","where","where's","which","while","who","whom","who's","why","why's","will","with","won't","would","wouldn't","you","you'd","you'll","your","you're","your's","yourself","yourselves","you've"];export const stemmer={ational:"ate",iveness:"ive",fulness:"ful",ousness:"ous",ization:"ize",tional:"tion",biliti:"ble",icate:"ic",ative:"",alize:"al",iciti:"ic",entli:"ent",ousli:"ous",alism:"al",ation:"ate",aliti:"al",iviti:"ive",ement:"",enci:"ence",anci:"ance",izer:"ize",alli:"al",ator:"ate",logi:"log",ical:"ic",ance:"",ence:"",ness:"",able:"",ible:"",ment:"",eli:"e",bli:"ble",ful:"",ant:"",ent:"",ism:"",ate:"",iti:"",ous:"",ive:"",ize:"",al:"",ou:"",er:"",ic:""};export const matcher={};export default{filter:filter,stemmer:stemmer,matcher:matcher}; | ||
/** | ||
* http://www.ranks.nl/stopwords | ||
* @type {Array<string>} | ||
*/ | ||
export const filter = ["a", "about", "above", "after", "again", "against", "all", "also", "am", "an", "and", "any", "are", "aren't", "as", "at", | ||
//"back", | ||
"be", "because", "been", "before", "being", "below", | ||
//"between", | ||
"both", "but", "by", "can", "cannot", "can't", "come", "could", "couldn't", | ||
//"day", | ||
"did", "didn't", "do", "does", "doesn't", "doing", "dont", "down", "during", "each", "even", "few", "first", "for", "from", "further", "get", | ||
//"give", | ||
"go", | ||
//"good", | ||
"had", "hadn't", "has", "hasn't", "have", "haven't", "having", "he", "hed", | ||
//"hell", | ||
"her", "here", "here's", "hers", "herself", "hes", "him", "himself", "his", "how", "how's", "i", "id", "if", "ill", "im", "in", "into", "is", "isn't", "it", "it's", "itself", "i've", "just", "know", "let's", "like", | ||
//"look", | ||
"make", "me", "more", "most", "mustn't", "my", "myself", "new", "no", "nor", "not", "now", "of", "off", "on", "once", | ||
//"one", | ||
"only", "or", "other", "ought", "our", "our's", "ourselves", "out", "over", "own", | ||
//"people", | ||
"same", "say", "see", "shan't", "she", "she'd", "shell", "shes", "should", "shouldn't", "so", "some", "such", | ||
//"take", | ||
"than", "that", "that's", "the", "their", "theirs", "them", "themselves", "then", "there", "there's", "these", "they", "they'd", "they'll", "they're", "they've", | ||
//"think", | ||
"this", "those", "through", "time", "to", "too", | ||
//"two", | ||
//"under", | ||
"until", "up", "us", | ||
//"use", | ||
"very", "want", "was", "wasn't", "way", "we", "wed", "well", "were", "weren't", "we've", "what", "what's", "when", "when's", "where", "where's", "which", "while", "who", "whom", "who's", "why", "why's", "will", "with", "won't", | ||
//"work", | ||
"would", "wouldn't", | ||
//"year", | ||
"you", "you'd", "you'll", "your", "you're", "your's", "yourself", "yourselves", "you've"]; | ||
/** | ||
* @type {Object<string, string>} | ||
*/ | ||
export const stemmer = { | ||
ational: "ate", | ||
iveness: "ive", | ||
fulness: "ful", | ||
ousness: "ous", | ||
ization: "ize", | ||
tional: "tion", | ||
biliti: "ble", | ||
icate: "ic", | ||
ative: "", | ||
alize: "al", | ||
iciti: "ic", | ||
entli: "ent", | ||
ousli: "ous", | ||
alism: "al", | ||
ation: "ate", | ||
aliti: "al", | ||
iviti: "ive", | ||
ement: "", | ||
enci: "ence", | ||
anci: "ance", | ||
izer: "ize", | ||
alli: "al", | ||
ator: "ate", | ||
logi: "log", | ||
ical: "ic", | ||
ance: "", | ||
ence: "", | ||
ness: "", | ||
able: "", | ||
ible: "", | ||
ment: "", | ||
eli: "e", | ||
bli: "ble", | ||
ful: "", | ||
ant: "", | ||
ent: "", | ||
ism: "", | ||
ate: "", | ||
iti: "", | ||
ous: "", | ||
ive: "", | ||
ize: "", | ||
al: "", | ||
ou: "", | ||
er: "", | ||
ic: "" | ||
}; | ||
export const matcher = {}; | ||
export default { | ||
filter: filter, | ||
stemmer: stemmer, | ||
matcher: matcher | ||
}; |
@@ -1,1 +0,89 @@ | ||
import{IndexInterface}from"../../type.js";import{regex,replace,collapse}from"../../lang.js";import{encode as encode_balance}from"./balance.js";export const rtl=!1;export const tokenize="";export default{encode:encode,rtl:!1,tokenize:""};const regex_ae=regex("ae"),regex_oe=regex("oe"),regex_sh=regex("sh"),regex_th=regex("th"),regex_ph=regex("ph"),regex_pf=regex("pf"),pairs=[regex_ae,"a",regex_oe,"o",regex_sh,"s",regex_th,"t",regex_ph,"f",regex_pf,"f",regex("(?![aeo])h(?![aeo])"),"",regex("(?!^[aeo])h(?!^[aeo])"),""];export function encode(a,b){return a&&(a=encode_balance.call(this,a).join(" "),2<a.length&&(a=replace(a,pairs)),!b&&(1<a.length&&(a=collapse(a)),a&&(a=a.split(" ")))),a||[]} | ||
import { IndexInterface } from "../../type.js"; | ||
import { regex, replace, collapse } from "../../lang.js"; | ||
import { encode as encode_balance } from "./balance.js"; | ||
export const rtl = /* normalize: */ | ||
/* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */!1; | ||
export const tokenize = ""; | ||
export default { | ||
encode: encode, | ||
rtl: !1, | ||
tokenize: "" | ||
// Phonetic Normalization | ||
};const 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_pf = regex("pf"), | ||
pairs = [regex_ae, "a", | ||
// regex_ai, "ei", | ||
// regex_ay, "ei", | ||
// regex_ey, "ei", | ||
regex_oe, "o", | ||
// regex_ue, "u", | ||
// regex_ie, "i", | ||
// regex_sz, "s", | ||
// regex_zs, "s", | ||
regex_sh, "s", | ||
// regex_ck, "k", | ||
// regex_cc, "k", | ||
regex_th, "t", | ||
// regex_dt, "t", | ||
regex_ph, "f", regex_pf, "f", | ||
// regex_ou, "o", | ||
// regex_uo, "u" | ||
// regex("(?![aeiouy])h(?![aeiouy])"), "", | ||
// regex("(?!^[aeiouy])h(?!^[aeiouy])"), "" | ||
regex("(?![aeo])h(?![aeo])"), "", regex("(?!^[aeo])h(?!^[aeo])"), ""]; | ||
//regex_ou = regex("ou"), | ||
//regex_uo = regex("uo"); | ||
/** | ||
* @param {string|number} str | ||
* @param {boolean=} _skip_postprocessing | ||
* @this IndexInterface | ||
*/ | ||
export function encode(str, _skip_postprocessing) { | ||
if (str) { | ||
str = encode_balance.call(this, str).join(" "); | ||
if (2 < str.length) { | ||
str = replace(str, pairs); | ||
} | ||
if (!_skip_postprocessing) { | ||
if (1 < str.length) { | ||
str = collapse(str); | ||
} | ||
if (str) { | ||
str = str.split(" "); | ||
} | ||
} | ||
} | ||
return str || []; | ||
} |
@@ -1,1 +0,119 @@ | ||
import{IndexInterface}from"../../type.js";import{encode as encode_simple}from"./simple.js";export const rtl=!1;export const tokenize="strict";export default{encode:encode,rtl:!1,tokenize:"strict"};const regex_strip=/[^a-z0-9]+/,soundex={b:"p",v:"f",w:"f",z:"s",x:"s",ß:"s",d:"t",n:"m",c:"k",g:"k",j:"k",q:"k",i:"e",y:"e",u:"o"};export function encode(a){a=encode_simple.call(this,a).join(" ");const b=[];if(a){const c=a.split(regex_strip),d=c.length;for(let e,f=0,g=0;f<d;f++)if((a=c[f])&&(!this.filter||!this.filter[a])){e=a[0];let c=soundex[e]||e,d=c;for(let b=1;b<a.length;b++){e=a[b];const f=soundex[e]||e;f&&f!==d&&(c+=f,d=f)}b[g++]=c}}return b} | ||
import { IndexInterface } from "../../type.js"; | ||
import { encode as encode_simple } from "./simple.js"; | ||
// custom soundex implementation | ||
export const rtl = /* normalize: */ /* collapse: */ | ||
/* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */!1; | ||
export const tokenize = "strict"; | ||
export default { | ||
encode: encode, | ||
rtl: !1, | ||
tokenize: "strict" | ||
//const regex_whitespace = /[\W_]+/g; | ||
};const regex_strip = /[^a-z0-9]+/, | ||
soundex = { | ||
b: "p", | ||
//"p": "p", | ||
//"f": "f", | ||
v: "f", w: "f", | ||
//"s": "s", | ||
z: "s", | ||
x: "s", | ||
ß: "s", | ||
d: "t", | ||
//"t": "t", | ||
//"l": "l", | ||
//"m": "m", | ||
n: "m", | ||
c: "k", | ||
g: "k", | ||
j: "k", | ||
//"k": "k", | ||
q: "k", | ||
//"r": "r", | ||
//"h": "h", | ||
//"a": "a", | ||
//"e": "e", | ||
i: "e", | ||
y: "e", | ||
//"o": "o", | ||
u: "o" | ||
}; | ||
// const pairs = [ | ||
// regex_whitespace, " ", | ||
// regex_strip, "" | ||
// ]; | ||
// modified | ||
/** | ||
* @param {string|number} str | ||
* @this IndexInterface | ||
*/ | ||
export function encode(str) { | ||
str = encode_simple.call(this, str).join(" "); | ||
// str = this.pipeline( | ||
// | ||
// /* string: */ normalize("" + str).toLowerCase(), | ||
// /* normalize: */ false, | ||
// /* split: */ false, | ||
// /* collapse: */ false | ||
// ); | ||
const result = []; | ||
if (str) { | ||
const words = str.split(regex_strip), | ||
length = words.length; | ||
for (let x = 0, tmp, count = 0; x < length; x++) { | ||
if ((str = words[x]) && ( /*&& (str.length > 2)*/!this.filter || !this.filter[str])) { | ||
tmp = str[0]; | ||
let code = soundex[tmp] || tmp, | ||
previous = code; //str[0]; | ||
//soundex[code] || code; | ||
for (let i = 1; i < str.length; i++) { | ||
tmp = str[i]; | ||
const current = soundex[tmp] || tmp; | ||
if (current && current !== previous) { | ||
code += current; | ||
previous = current; | ||
// if(code.length === 7){ | ||
// | ||
// break; | ||
// } | ||
} | ||
} | ||
result[count++] = code; //(code + "0000").substring(0, 4); | ||
} | ||
} | ||
} | ||
return result; | ||
} |
@@ -1,1 +0,23 @@ | ||
import{IndexInterface}from"../../type.js";import{pipeline,normalize,regex_whitespace}from"../../lang.js";export const rtl=!1;export const tokenize="";export default{encode:encode,rtl:!1,tokenize:""};export function encode(a){return pipeline.call(this,(""+a).toLowerCase(),!1,regex_whitespace,!1)} | ||
import { IndexInterface } from "../../type.js"; | ||
import { pipeline, normalize, regex_whitespace } from "../../lang.js"; | ||
export const rtl = /* normalize: */ | ||
/* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ | ||
/* normalize: */ | ||
/* collapse: */!1; | ||
export const tokenize = ""; | ||
export default { | ||
encode: encode, | ||
rtl: !1, | ||
tokenize: "" | ||
/** | ||
* @param {string|number} str | ||
* @this IndexInterface | ||
*/ | ||
};export function encode(str) { | ||
return pipeline.call(this, | ||
/* string: */("" + str).toLowerCase(), !1, /* split: */regex_whitespace, !1); | ||
} |
@@ -1,1 +0,65 @@ | ||
import{IndexInterface}from"../../type.js";import{regex,replace,collapse}from"../../lang.js";import{encode as encode_advanced}from"./advanced.js";export const rtl=!1;export const tokenize="";export default{encode:encode,rtl:!1,tokenize:""};const prefix="(?!\\b)",regex_vowel=regex("(?!\\b)[aeo]"),pairs=[regex_vowel,""];export function encode(a){return a&&(a=encode_advanced.call(this,a,!0),1<a.length&&(a=a.replace(regex_vowel,"")),1<a.length&&(a=collapse(a)),a&&(a=a.split(" "))),a||[]} | ||
import { IndexInterface } from "../../type.js"; | ||
import { regex, replace, collapse } from "../../lang.js"; | ||
import { encode as encode_advanced } from "./advanced.js"; | ||
export const rtl = /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */!1; | ||
export const tokenize = ""; | ||
export default { | ||
encode: encode, | ||
rtl: !1, | ||
tokenize: "" | ||
// Soundex Normalization | ||
};const prefix = "(?!\\b)", | ||
//soundex_b = regex(prefix + "p"), | ||
// soundex_s = regex(prefix + "z"), | ||
// soundex_k = regex(prefix + "[cgq]"), | ||
// soundex_m = regex(prefix + "n"), | ||
// soundex_t = regex(prefix + "d"), | ||
// soundex_f = regex(prefix + "[vw]"), | ||
//regex_vowel = regex(prefix + "[aeiouy]"); | ||
regex_vowel = regex("(?!\\b)[aeo]"), | ||
pairs = [ | ||
// soundex_b, "b", | ||
// soundex_s, "s", | ||
// soundex_k, "k", | ||
// soundex_m, "m", | ||
// soundex_t, "t", | ||
// soundex_f, "f", | ||
// regex("(?![aeiouy])h(?![aeiouy])"), "", | ||
// regex("(?!^[aeiouy])h(?!^[aeiouy])"), "", | ||
regex_vowel, ""]; | ||
/** | ||
* @param {string|number} str | ||
* @this IndexInterface | ||
*/ | ||
export function encode(str) { | ||
if (str) { | ||
str = encode_advanced.call(this, str, /* append: */ /* skip update: */ /* skip_update: */ /* skip post-processing: */!0); | ||
if (1 < str.length) { | ||
//str = replace(str, pairs); | ||
str = str.replace(regex_vowel, ""); | ||
} | ||
if (1 < str.length) { | ||
str = collapse(str); | ||
} | ||
if (str) { | ||
str = str.split(" "); | ||
} | ||
} | ||
return str || []; | ||
} |
@@ -1,1 +0,45 @@ | ||
import{IndexInterface}from"../../type.js";import{pipeline,normalize,regex_whitespace,regex}from"../../lang.js";export const rtl=!1;export const tokenize="";export default{encode:encode,rtl:!1,tokenize:""};const regex_a=regex("[\xE0\xE1\xE2\xE3\xE4\xE5]"),regex_e=regex("[\xE8\xE9\xEA\xEB]"),regex_i=regex("[\xEC\xED\xEE\xEF]"),regex_o=regex("[\xF2\xF3\xF4\xF5\xF6\u0151]"),regex_u=regex("[\xF9\xFA\xFB\xFC\u0171]"),regex_y=regex("[\xFD\u0177\xFF]"),regex_n=regex("\xF1"),regex_c=regex("[\xE7c]"),regex_s=regex("\xDF"),regex_and=regex(" & "),pairs=[regex_a,"a",regex_e,"e",regex_i,"i",regex_o,"o",regex_u,"u",regex_y,"y",regex_n,"n",regex_c,"k",regex_s,"s",regex_and," and "];export function encode(a){return a=""+a,pipeline.call(this,normalize(a).toLowerCase(),!a.normalize&&pairs,regex_whitespace,!1)} | ||
import { IndexInterface } from "../../type.js"; | ||
import { pipeline, normalize, regex_whitespace, regex } from "../../lang.js"; | ||
export const rtl = /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ | ||
/* collapse: */!1; | ||
export const tokenize = ""; | ||
export default { | ||
encode: encode, | ||
rtl: !1, | ||
tokenize: "" | ||
// Charset Normalization | ||
};const //regex_whitespace = /\W+/, | ||
//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("[çc]"), | ||
regex_s = regex("ß"), | ||
regex_and = regex(" & "), | ||
pairs = [regex_a, "a", regex_e, "e", regex_i, "i", regex_o, "o", regex_u, "u", regex_y, "y", regex_n, "n", regex_c, "k", regex_s, "s", regex_and, " and " | ||
//regex_whitespace, " " | ||
//regex_strip, "" | ||
]; | ||
/** | ||
* @param {string|number} str | ||
* @this IndexInterface | ||
*/ | ||
export function encode(str) { | ||
str = "" + str; | ||
return pipeline.call(this, | ||
/* string: */normalize(str).toLowerCase(), | ||
/* normalize: */!str.normalize && pairs, | ||
/* split: */regex_whitespace, !1); | ||
} |
@@ -1,1 +0,100 @@ | ||
export const filter=["a","about","above","after","again","against","all","also","am","an","and","any","are","aren't","as","at","be","because","been","before","being","below","both","but","by","can","cannot","can't","come","could","couldn't","did","didn't","do","does","doesn't","doing","dont","down","during","each","even","few","first","for","from","further","get","go","had","hadn't","has","hasn't","have","haven't","having","he","hed","her","here","here's","hers","herself","hes","him","himself","his","how","how's","i","id","if","ill","im","in","into","is","isn't","it","it's","itself","i've","just","know","let's","like","make","me","more","most","mustn't","my","myself","new","no","nor","not","now","of","off","on","once","only","or","other","ought","our","our's","ourselves","out","over","own","same","say","see","shan't","she","she'd","shell","shes","should","shouldn't","so","some","such","than","that","that's","the","their","theirs","them","themselves","then","there","there's","these","they","they'd","they'll","they're","they've","this","those","through","time","to","too","until","up","us","very","want","was","wasn't","way","we","wed","well","were","weren't","we've","what","what's","when","when's","where","where's","which","while","who","whom","who's","why","why's","will","with","won't","would","wouldn't","you","you'd","you'll","your","you're","your's","yourself","yourselves","you've"];export const stemmer={ational:"ate",iveness:"ive",fulness:"ful",ousness:"ous",ization:"ize",tional:"tion",biliti:"ble",icate:"ic",ative:"",alize:"al",iciti:"ic",entli:"ent",ousli:"ous",alism:"al",ation:"ate",aliti:"al",iviti:"ive",ement:"",enci:"ence",anci:"ance",izer:"ize",alli:"al",ator:"ate",logi:"log",ical:"ic",ance:"",ence:"",ness:"",able:"",ible:"",ment:"",eli:"e",bli:"ble",ful:"",ant:"",ent:"",ism:"",ate:"",iti:"",ous:"",ive:"",ize:"",al:"",ou:"",er:"",ic:""};export const matcher={};export default{filter:filter,stemmer:stemmer,matcher:matcher}; | ||
/** | ||
* http://www.ranks.nl/stopwords | ||
* @type {Array<string>} | ||
*/ | ||
export const filter = ["a", "about", "above", "after", "again", "against", "all", "also", "am", "an", "and", "any", "are", "aren't", "as", "at", | ||
//"back", | ||
"be", "because", "been", "before", "being", "below", | ||
//"between", | ||
"both", "but", "by", "can", "cannot", "can't", "come", "could", "couldn't", | ||
//"day", | ||
"did", "didn't", "do", "does", "doesn't", "doing", "dont", "down", "during", "each", "even", "few", "first", "for", "from", "further", "get", | ||
//"give", | ||
"go", | ||
//"good", | ||
"had", "hadn't", "has", "hasn't", "have", "haven't", "having", "he", "hed", | ||
//"hell", | ||
"her", "here", "here's", "hers", "herself", "hes", "him", "himself", "his", "how", "how's", "i", "id", "if", "ill", "im", "in", "into", "is", "isn't", "it", "it's", "itself", "i've", "just", "know", "let's", "like", | ||
//"look", | ||
"make", "me", "more", "most", "mustn't", "my", "myself", "new", "no", "nor", "not", "now", "of", "off", "on", "once", | ||
//"one", | ||
"only", "or", "other", "ought", "our", "our's", "ourselves", "out", "over", "own", | ||
//"people", | ||
"same", "say", "see", "shan't", "she", "she'd", "shell", "shes", "should", "shouldn't", "so", "some", "such", | ||
//"take", | ||
"than", "that", "that's", "the", "their", "theirs", "them", "themselves", "then", "there", "there's", "these", "they", "they'd", "they'll", "they're", "they've", | ||
//"think", | ||
"this", "those", "through", "time", "to", "too", | ||
//"two", | ||
//"under", | ||
"until", "up", "us", | ||
//"use", | ||
"very", "want", "was", "wasn't", "way", "we", "wed", "well", "were", "weren't", "we've", "what", "what's", "when", "when's", "where", "where's", "which", "while", "who", "whom", "who's", "why", "why's", "will", "with", "won't", | ||
//"work", | ||
"would", "wouldn't", | ||
//"year", | ||
"you", "you'd", "you'll", "your", "you're", "your's", "yourself", "yourselves", "you've"]; | ||
/** | ||
* @type {Object<string, string>} | ||
*/ | ||
export const stemmer = { | ||
ational: "ate", | ||
iveness: "ive", | ||
fulness: "ful", | ||
ousness: "ous", | ||
ization: "ize", | ||
tional: "tion", | ||
biliti: "ble", | ||
icate: "ic", | ||
ative: "", | ||
alize: "al", | ||
iciti: "ic", | ||
entli: "ent", | ||
ousli: "ous", | ||
alism: "al", | ||
ation: "ate", | ||
aliti: "al", | ||
iviti: "ive", | ||
ement: "", | ||
enci: "ence", | ||
anci: "ance", | ||
izer: "ize", | ||
alli: "al", | ||
ator: "ate", | ||
logi: "log", | ||
ical: "ic", | ||
ance: "", | ||
ence: "", | ||
ness: "", | ||
able: "", | ||
ible: "", | ||
ment: "", | ||
eli: "e", | ||
bli: "ble", | ||
ful: "", | ||
ant: "", | ||
ent: "", | ||
ism: "", | ||
ate: "", | ||
iti: "", | ||
ous: "", | ||
ive: "", | ||
ize: "", | ||
al: "", | ||
ou: "", | ||
er: "", | ||
ic: "" | ||
}; | ||
export const matcher = {}; | ||
export default { | ||
filter: filter, | ||
stemmer: stemmer, | ||
matcher: matcher | ||
}; |
@@ -1,1 +0,74 @@ | ||
import{POLYFILL,SUPPORT_ASYNC}from"./config.js";export let promise=Promise;if(POLYFILL&&(Object.assign||(Object.assign=function(){const a=arguments,b=a.length,c=a[0];for(let d,e,f,g=1;g<b;g++){d=a[g],e=Object.keys(d),f=e.length;for(let a,b=0;b<f;b++)a=e[b],c[a]=d[a]}return c}),SUPPORT_ASYNC&&!promise)){function a(a){this.callback=null;const b=this;a(function(a){b.callback&&b.callback(a)})}a.prototype.then=function(a){this.callback=a},promise=a} | ||
export let promise = Promise; | ||
Object.assign || (Object.assign = function () { | ||
const args = arguments, | ||
size = args.length, | ||
obj = args[0]; | ||
for (let x = 1, current, keys, length; x < size; x++) { | ||
current = args[x]; | ||
keys = Object.keys(current); | ||
length = keys.length; | ||
for (let i = 0, key; i < length; i++) { | ||
key = keys[i]; | ||
obj[key] = current[key]; | ||
} | ||
} | ||
return obj; | ||
}); | ||
// Object.values || (Object.values = function(obj){ | ||
// | ||
// const keys = Object.keys(obj); | ||
// const length = keys.length; | ||
// const values = new Array(length); | ||
// | ||
// for(let x = 0; x < length; x++){ | ||
// | ||
// values[x] = obj[keys[x]]; | ||
// } | ||
// | ||
// return values; | ||
// }); | ||
if (!promise) { | ||
/** | ||
* @param {Function} fn | ||
* @constructor | ||
*/ | ||
function SimplePromise(fn) { | ||
this.callback = null; | ||
const self = this; | ||
fn(function (val) { | ||
if (self.callback) { | ||
self.callback(val); | ||
// self.callback = null; | ||
// self = null; | ||
} | ||
}); | ||
} | ||
/** | ||
* @param {Function} callback | ||
*/ | ||
SimplePromise.prototype.then = function (callback) { | ||
this.callback = callback; | ||
}; | ||
promise = SimplePromise; | ||
} |
@@ -1,1 +0,87 @@ | ||
import{DEBUG}from"./config.js";import{is_string}from"./common.js";const preset={memory:{charset:"latin:extra",resolution:3,minlength:4,fastupdate:!1},performance:{resolution:3,minlength:3,optimize:!1,context:{depth:2,resolution:1}},match:{charset:"latin:extra",tokenize:"reverse"},score:{charset:"latin:advanced",resolution:20,minlength:3,context:{depth:3,resolution:9}},default:{}};export default function apply_preset(a){if(is_string(a))DEBUG&&!preset[a]&&console.warn("Preset not found: "+a),a=preset[a];else{const b=a.preset;b&&(DEBUG&&!b[b]&&console.warn("Preset not found: "+b),a=Object.assign({},b[b],a))}return a} | ||
import { is_string } from "./common.js"; | ||
/** | ||
* @enum {Object} | ||
* @const | ||
*/ | ||
const preset = { | ||
memory: { | ||
charset: "latin:extra", | ||
//tokenize: "strict", | ||
resolution: 3, | ||
//threshold: 0, | ||
minlength: 4, | ||
fastupdate: /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ | ||
/* collapse: */ | ||
/* collapse: */!1 | ||
}, | ||
performance: { | ||
//charset: "latin", | ||
//tokenize: "strict", | ||
resolution: 3, | ||
minlength: 3, | ||
//fastupdate: true, | ||
optimize: !1, //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 | ||
// } | ||
}; | ||
export default function apply_preset(options) { | ||
if (is_string(options)) { | ||
options = preset[options]; | ||
} else { | ||
const preset = options.preset; | ||
if (preset) { | ||
options = Object.assign({}, preset[preset], /** @type {Object} */options); | ||
} | ||
} | ||
return options; | ||
} |
@@ -1,1 +0,271 @@ | ||
import{IndexInterface,DocumentInterface}from"./type.js";import{create_object,is_string}from"./common.js";function async(a,b,c,d,e,f,g){setTimeout(function(){const h=a(c?c+"."+d:d,JSON.stringify(g));h&&h.then?h.then(function(){b.export(a,b,c,e,f+1)}):b.export(a,b,c,e,f+1)})}export function exportIndex(a,b,c,d,e){let f,g;switch(e||(e=0)){case 0:if(f="reg",this.fastupdate)for(let a in g=create_object(),this.register)g[a]=1;else g=this.register;break;case 1:f="cfg",g={doc:0,opt:this.optimize?1:0};break;case 2:f="map",g=this.map;break;case 3:f="ctx",g=this.ctx;break;default:return;}return async(a,b||this,c,f,d,e,g),!0}export function importIndex(a,b){b&&(is_string(b)&&(b=JSON.parse(b)),"cfg"===a?this.optimize=!!b.opt:"reg"===a?(this.fastupdate=!1,this.register=b):"map"===a?this.map=b:"ctx"===a?this.ctx=b:void 0)}export function exportDocument(a,b,c,d,e){if(e||(e=0),d||(d=0),d<this.field.length){const c=this.field[d],f=this.index[c];b=this,setTimeout(function(){f.export(a,b,e?c:"",d,e++)||(d++,e=1,b.export(a,b,c,d,e))})}else{let b,f;switch(e){case 1:b="tag",f=this.tagindex;break;case 2:b="store",f=this.store;break;default:return;}async(a,this,c,b,d,e,f)}}export function importDocument(a,b){if(b)switch(is_string(b)&&(b=JSON.parse(b)),a){case"tag":this.tagindex=b;break;case"reg":this.fastupdate=!1,this.register=b;for(let a,c=0;c<this.field.length;c++)a=this.index[this.field[c]],a.register=b,a.fastupdate=!1;break;case"store":this.store=b;break;default:a=a.split(".");const c=a[0];a=a[1],c&&a&&this.index[c].import(a,b);}} | ||
// TODO return promises instead of inner await | ||
import { IndexInterface, DocumentInterface } from "./type.js"; | ||
import { create_object, is_string } from "./common.js"; | ||
function async(callback, self, field, key, index_doc, index, data, on_done) { | ||
setTimeout(function () { | ||
const res = callback(field ? field + "." + key : key, JSON.stringify(data)); | ||
// await isn't supported by ES5 | ||
if (res && res.then) { | ||
res.then(function () { | ||
self.export(callback, self, field, index_doc, index + 1, on_done); | ||
}); | ||
} else { | ||
self.export(callback, self, field, index_doc, index + 1, on_done); | ||
} | ||
}); | ||
} | ||
/** | ||
* @this IndexInterface | ||
*/ | ||
export function exportIndex(callback, self, field, index_doc, index, on_done) { | ||
let return_value = /* append: */ /* skip update: */ /* skip_update: */ /* skip post-processing: */!0; | ||
if ('undefined' == typeof on_done) { | ||
return_value = new Promise(resolve => { | ||
on_done = resolve; | ||
}); | ||
} | ||
let key, data; | ||
switch (index || (index = 0)) { | ||
case 0: | ||
key = "reg"; | ||
// fastupdate isn't supported by export | ||
if (this.fastupdate) { | ||
data = create_object(); | ||
for (let key in this.register) { | ||
data[key] = 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: | ||
if ('undefined' == typeof field && on_done) { | ||
on_done(); | ||
} | ||
return; | ||
} | ||
async(callback, self || this, field, key, index_doc, index, data, on_done); | ||
return return_value; | ||
} | ||
/** | ||
* @this IndexInterface | ||
*/ | ||
export 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": | ||
// fastupdate isn't supported by import | ||
this.fastupdate = /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* collapse: */!1; | ||
this.register = data; | ||
break; | ||
case "map": | ||
this.map = data; | ||
break; | ||
case "ctx": | ||
this.ctx = data; | ||
break; | ||
} | ||
} | ||
/** | ||
* @this DocumentInterface | ||
*/ | ||
export function exportDocument(callback, self, field, index_doc, index, on_done) { | ||
let return_value; | ||
if ('undefined' == typeof on_done) { | ||
return_value = new Promise(resolve => { | ||
on_done = resolve; | ||
}); | ||
} | ||
index || (index = 0); | ||
index_doc || (index_doc = 0); | ||
if (index_doc < this.field.length) { | ||
const field = this.field[index_doc], | ||
idx = this.index[field]; | ||
self = this; | ||
setTimeout(function () { | ||
if (!idx.export(callback, self, index ? field /*.replace(":", "-")*/ : "", index_doc, index++, on_done)) { | ||
index_doc++; | ||
index = 1; | ||
self.export(callback, self, field, index_doc, index, on_done); | ||
} | ||
}); | ||
} else { | ||
let key, data; | ||
switch (index) { | ||
case 1: | ||
key = "tag"; | ||
data = this.tagindex; | ||
field = null; | ||
break; | ||
case 2: | ||
key = "store"; | ||
data = this.store; | ||
field = null; | ||
break; | ||
// case 3: | ||
// | ||
// key = "reg"; | ||
// data = this.register; | ||
// break; | ||
default: | ||
on_done(); | ||
return; | ||
} | ||
async(callback, this, field, key, index_doc, index, data, on_done); | ||
} | ||
return return_value; | ||
} | ||
/** | ||
* @this DocumentInterface | ||
*/ | ||
export 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": | ||
// fastupdate isn't supported by import | ||
this.fastupdate = !1; | ||
this.register = data; | ||
for (let i = 0, index; i < this.field.length; i++) { | ||
index = this.index[this.field[i]]; | ||
index.register = data; | ||
index.fastupdate = !1; | ||
} | ||
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); | ||
} | ||
} | ||
} |
@@ -1,1 +0,69 @@ | ||
export 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;export function DocumentInterface(){this.field=null,this.index=null} | ||
/** | ||
* @interface | ||
*/ | ||
export function IndexInterface() { | ||
this.cache = null; | ||
this.matcher = null; | ||
this.stemmer = null; | ||
this.filter = null; | ||
} | ||
/** | ||
* @param {!string} str | ||
* @param {boolean|Array<string|RegExp>=} normalize | ||
* @param {boolean|string|RegExp=} split | ||
* @param {boolean=} collapse | ||
* @returns {string|Array<string>} | ||
*/ | ||
//IndexInterface.prototype.pipeline; | ||
/** | ||
* @param {!number|string} id | ||
* @param {!string} content | ||
*/ | ||
IndexInterface.prototype.add; | ||
/** | ||
* @param {!number|string} id | ||
* @param {!string} content | ||
*/ | ||
IndexInterface.prototype.append; | ||
/** | ||
* @param {!string|Object} query | ||
* @param {number|Object=} limit | ||
* @param {Object=} options | ||
* @returns {Array<number|string>} | ||
*/ | ||
IndexInterface.prototype.search; | ||
/** | ||
* @param {!number|string} id | ||
* @param {!string} content | ||
*/ | ||
IndexInterface.prototype.update; | ||
/** | ||
* @param {!number|string} id | ||
*/ | ||
IndexInterface.prototype.remove; | ||
/** | ||
* @interface | ||
*/ | ||
export function DocumentInterface() { | ||
this.field = null; | ||
/** @type IndexInterface */ | ||
this.index = null; | ||
} |
@@ -1,1 +0,52 @@ | ||
import Index from"../index.js";export default function(a){a=a.data;const b=self._index,c=a.args,d=a.task;switch(d){case"init":const e=a.options||{},f=a.factory,g=e.encode;e.cache=!1,g&&0===g.indexOf("function")&&(e.encode=Function("return "+g)()),f?(Function("return "+f)()(self),self._index=new self.FlexSearch.Index(e),delete self.FlexSearch):self._index=new Index(e);break;default:const h=a.id,i=b[d].apply(b,c);postMessage("search"===d?{id:h,msg:i}:{id:h});}} | ||
import Index from "../index.js"; | ||
export default function (data) { | ||
data = data.data; | ||
/** @type Index */ | ||
const index = self._index, | ||
args = data.args, | ||
task = data.task; | ||
switch (task) { | ||
case "init": | ||
const options = data.options || {}, | ||
factory = data.factory, | ||
encode = options.encode; | ||
options.cache = /* normalize: */ /* collapse: */ /* normalize: */ | ||
/* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* collapse: */!1; | ||
if (encode && 0 === encode.indexOf("function")) { | ||
options.encode = Function("return " + encode)(); | ||
} | ||
if (factory) { | ||
// export the FlexSearch global payload to "self" | ||
Function("return " + factory)()(self); | ||
/** @type Index */ | ||
self._index = new self.FlexSearch.Index(options); | ||
// destroy the exported payload | ||
delete self.FlexSearch; | ||
} else { | ||
self._index = new Index(options); | ||
} | ||
break; | ||
default: | ||
const id = data.id, | ||
message = index[task].apply(index, args); | ||
postMessage("search" === task ? { id: id, msg: message } : { id: id }); | ||
} | ||
} |
@@ -1,1 +0,136 @@ | ||
import{create_object,is_function,is_object,is_string}from"../common.js";import handler from"./handler.js";let pid=0;function WorkerIndex(a){if(!(this instanceof WorkerIndex))return new WorkerIndex(a);let b;a?is_function(b=a.encode)&&(a.encode=b.toString()):a={};let c=(self||window)._factory;c&&(c=c.toString());const d="undefined"==typeof window&&self.exports,e=this;this.worker=create(c,d,a.worker),this.resolver=create_object();this.worker&&(d?this.worker.on("message",function(a){e.resolver[a.id](a.msg),delete e.resolver[a.id]}):this.worker.onmessage=function(a){a=a.data,e.resolver[a.id](a.msg),delete e.resolver[a.id]},this.worker.postMessage({task:"init",factory:c,options:a}))}export default WorkerIndex;register("add"),register("append"),register("search"),register("update"),register("remove");function register(a){WorkerIndex.prototype[a]=WorkerIndex.prototype[a+"Async"]=function(){const b=this,c=[].slice.call(arguments),d=c[c.length-1];let e;is_function(d)&&(e=d,c.splice(c.length-1,1));const f=new Promise(function(d){setTimeout(function(){b.resolver[++pid]=d,b.worker.postMessage({task:a,id:pid,args:c})})});return e?(f.then(e),this):f}}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.toString()],{type:"text/javascript"}))):new Worker(is_string(worker_path)?worker_path:"worker/worker.js",{type:"module"})}catch(a){}return worker} | ||
//import { promise as Promise } from "../polyfill.js"; | ||
import { create_object, is_function, is_object, is_string } from "../common.js"; | ||
import handler from "./handler.js"; | ||
let pid = 0; | ||
/** | ||
* @param {Object=} options | ||
* @constructor | ||
*/ | ||
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 = {}; | ||
} | ||
// the factory is the outer wrapper from the build | ||
// we use "self" as a trap for node.js | ||
let factory = (self || window)._factory; | ||
if (factory) { | ||
factory = factory.toString(); | ||
} | ||
const is_node_js = "undefined" == typeof window && self.exports, | ||
_self = this; | ||
this.worker = create(factory, is_node_js, options.worker); | ||
this.resolver = create_object(); | ||
if (!this.worker) { | ||
return; | ||
} | ||
if (is_node_js) { | ||
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: factory, | ||
options: options | ||
}); | ||
} | ||
export default WorkerIndex; | ||
register("add"); | ||
register("append"); | ||
register("search"); | ||
register("update"); | ||
register("remove"); | ||
function register(key) { | ||
WorkerIndex.prototype[key] = WorkerIndex.prototype[key + "Async"] = function () { | ||
const self = this, | ||
args = [].slice.call(arguments), | ||
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 () { | ||
self.resolver[++pid] = resolve; | ||
self.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.toString()], { type: "text/javascript" }))) : new Worker(is_string(worker_path) ? worker_path : "worker/worker.js", { type: "module" }); | ||
} catch (e) {} | ||
return worker; | ||
} |
@@ -1,1 +0,36 @@ | ||
const{parentPort}=require("worker_threads"),{Index}=require("../flexsearch.bundle.js");let index;parentPort.on("message",function(a){const b=a.args,c=a.task,d=a.id;switch(c){case"init":const e=a.options||{},f=e.encode;e.cache=!1,f&&0===f.indexOf("function")&&(e.encode=new Function("return "+f)()),index=new Index(e);break;default:const g=index[c].apply(index,b);parentPort.postMessage("search"===c?{id:d,msg:g}:{id:d});}}); | ||
const { parentPort } = require("worker_threads"), | ||
{ Index } = require("../flexsearch.bundle.min.js"); | ||
let index; | ||
parentPort.on("message", function (data) { | ||
/** @type Index */ | ||
const args = data.args, | ||
task = data.task, | ||
id = data.id; | ||
switch (task) { | ||
case "init": | ||
const options = data.options || {}, | ||
encode = options.encode; | ||
options.cache = /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* normalize: */ /* collapse: */ /* collapse: */!1; | ||
if (encode && 0 === encode.indexOf("function")) { | ||
options.encode = new Function("return " + encode)(); | ||
} | ||
index = new Index(options); | ||
break; | ||
default: | ||
const message = index[task].apply(index, args); | ||
parentPort.postMessage("search" === task ? { id: id, msg: message } : { id: id }); | ||
} | ||
}); |
@@ -1,1 +0,2 @@ | ||
import handler from"./handler.js";onmessage=handler; | ||
import handler from "./handler.js"; | ||
onmessage = handler; |
const { parentPort } = require("worker_threads"); | ||
const { Index } = require("../flexsearch.bundle.js"); | ||
const { Index } = require("../flexsearch.bundle.min.js"); | ||
@@ -4,0 +4,0 @@ let index; |
{ | ||
"public": true, | ||
"preferGlobal": false, | ||
"name": "flexsearch", | ||
"version": "0.7.34", | ||
"version": "0.7.39", | ||
"description": "Next-Generation full text search library with zero dependencies.", | ||
@@ -9,2 +11,3 @@ "homepage": "https://github.com/nextapps-de/flexsearch/", | ||
"license": "Apache-2.0", | ||
"readme": "README.md", | ||
"keywords": [ | ||
@@ -20,2 +23,6 @@ "fulltext search", | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/nextapps-de/flexsearch.git" | ||
}, | ||
"bugs": { | ||
@@ -25,26 +32,31 @@ "url": "https://github.com/nextapps-de/flexsearch/issues", | ||
}, | ||
"main": "dist/flexsearch.bundle.js", | ||
"browser": "dist/flexsearch.bundle.js", | ||
"module": "dist/module/index.js", | ||
"preferGlobal": false, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/nextapps-de/flexsearch.git" | ||
"main": "dist/flexsearch.bundle.min.js", | ||
"module": "dist/flexsearch.bundle.module.min.js", | ||
"browser": { | ||
"dist/flexsearch.bundle.min.js": "dist/flexsearch.bundle.min.js", | ||
"dist/flexsearch.bundle.module.min.js": "dist/flexsearch.bundle.module.min.js" | ||
}, | ||
"scripts": { | ||
"copy": "npm run clean && cpx \"src/**\" tmp/", | ||
"clean": "npx shx rm -rf tmp && mkdir tmp", | ||
"build": "npm run copy && npm run build:bundle", | ||
"build:bundle": "node task/build RELEASE=bundle && cpx \"src/worker/node.js\" dist/node/", | ||
"build:debug": "node task/build RELEASE=debug COMPILATION_LEVEL=SIMPLE FORMATTING=PRETTY_PRINT", | ||
"build:compact": "node task/build RELEASE=compact", | ||
"build:light": "node task/build RELEASE=light", | ||
"build:bundle": "node task/build RELEASE=bundle DEBUG=false SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_STORE=true SUPPORT_TAGS=true SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=true SUPPORT_DOCUMENT=true POLYFILL=false", | ||
"build:bundle:debug": "node task/build RELEASE=bundle DEBUG=true SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_STORE=true SUPPORT_TAGS=true SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=true SUPPORT_DOCUMENT=true POLYFILL=false FORMATTING=PRETTY_PRINT", | ||
"build:compact": "node task/build RELEASE=compact DEBUG=false SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=false SUPPORT_ASYNC=true SUPPORT_STORE=true SUPPORT_TAGS=false SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=false SUPPORT_DOCUMENT=true POLYFILL=false", | ||
"build:compact:debug": "node task/build RELEASE=compact DEBUG=true SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=false SUPPORT_ASYNC=true SUPPORT_STORE=true SUPPORT_TAGS=false SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=false SUPPORT_DOCUMENT=true POLYFILL=false FORMATTING=PRETTY_PRINT", | ||
"build:light": "node task/build RELEASE=light DEBUG=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_STORE=false SUPPORT_TAGS=false SUPPORT_SUGGESTION=false SUPPORT_SERIALIZE=false SUPPORT_DOCUMENT=false POLYFILL=false", | ||
"build:light:debug": "node task/build RELEASE=light DEBUG=true SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_STORE=false SUPPORT_TAGS=false SUPPORT_SUGGESTION=false SUPPORT_SERIALIZE=false SUPPORT_DOCUMENT=false POLYFILL=false FORMATTING=PRETTY_PRINT", | ||
"build:custom": "node task/build RELEASE=custom", | ||
"build:es5": "node task/build RELEASE=es5 LANGUAGE_OUT=ECMASCRIPT5_STRICT POLYFILL=true", | ||
"build:pre": "node task/build RELEASE=pre COMPILATION_LEVEL=WHITESPACE FORMATTING=PRETTY_PRINT", | ||
"build:es5": "node task/build RELEASE=es5 DEBUG=false SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_STORE=true SUPPORT_TAGS=true SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=true SUPPORT_DOCUMENT=true LANGUAGE_OUT=ECMASCRIPT5_STRICT POLYFILL=true", | ||
"build:es5:debug": "node task/build RELEASE=es5 DEBUG=true SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_STORE=true SUPPORT_TAGS=true SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=true SUPPORT_DOCUMENT=true LANGUAGE_OUT=ECMASCRIPT5_STRICT POLYFILL=true FORMATTING=PRETTY_PRINT", | ||
"build:lang": "node task/build RELEASE=lang", | ||
"build:module": "npx babel src -d dist/module && exit 0", | ||
"build:all": "npm run build && npm run build:light && npm run build:compact && npm run build:es5 && npm run build:debug && npm run build:module", | ||
"test": "cd test && npm install && npm run test", | ||
"server": "node task/server" | ||
"build:module": "node task/babel && exit 0", | ||
"build:module:debug": "node task/babel DEBUG=true && exit 0", | ||
"build:module:min": "node task/babel RELEASE=min && exit 0", | ||
"build:module:bundle": "node task/build RELEASE=bundle.module DEBUG=false SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_STORE=true SUPPORT_TAGS=true SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=true SUPPORT_DOCUMENT=true POLYFILL=false", | ||
"build:module:bundle:debug": "node task/build RELEASE=bundle.module DEBUG=true SUPPORT_WORKER=true SUPPORT_ENCODER=true SUPPORT_CACHE=true SUPPORT_ASYNC=true SUPPORT_STORE=true SUPPORT_TAGS=true SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=true SUPPORT_DOCUMENT=true POLYFILL=false FORMATTING=PRETTY_PRINT", | ||
"build:module:compact": "node task/build RELEASE=compact.module DEBUG=false SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=false SUPPORT_ASYNC=true SUPPORT_STORE=true SUPPORT_TAGS=false SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=false SUPPORT_DOCUMENT=true POLYFILL=false", | ||
"build:module:compact:debug": "node task/build RELEASE=compact.module DEBUG=true SUPPORT_WORKER=false SUPPORT_ENCODER=true SUPPORT_CACHE=false SUPPORT_ASYNC=true SUPPORT_STORE=true SUPPORT_TAGS=false SUPPORT_SUGGESTION=true SUPPORT_SERIALIZE=false SUPPORT_DOCUMENT=true POLYFILL=false FORMATTING=PRETTY_PRINT", | ||
"build:module:light": "node task/build RELEASE=light.module DEBUG=false SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_STORE=false SUPPORT_TAGS=false SUPPORT_SUGGESTION=false SUPPORT_SERIALIZE=false SUPPORT_DOCUMENT=false POLYFILL=false", | ||
"build:module:light:debug": "node task/build RELEASE=light.module DEBUG=true SUPPORT_WORKER=false SUPPORT_ENCODER=false SUPPORT_CACHE=false SUPPORT_ASYNC=false SUPPORT_STORE=false SUPPORT_TAGS=false SUPPORT_SUGGESTION=false SUPPORT_SERIALIZE=false SUPPORT_DOCUMENT=false POLYFILL=false FORMATTING=PRETTY_PRINT", | ||
"build:all": "npm version --no-git-tag-version patch && npm run build:bundle && npm run build:bundle:debug && npm run build:light && npm run build:light:debug && npm run build:compact && npm run build:compact:debug && npm run build:es5 && npm run build:es5:debug && npm run build:module && npm run build:module:debug && npm run build:module:min && npm run build:module:bundle && npm run build:module:bundle:debug && npm run build:module:light && npm run build:module:light:debug && npm run build:module:compact && npm run build:module:compact:debug", | ||
"test": "cd test && npm install && npm run test" | ||
}, | ||
@@ -55,2 +67,3 @@ "files": [ | ||
"task/**", | ||
"index.d.ts", | ||
"README.md", | ||
@@ -60,11 +73,11 @@ "CHANGELOG.md", | ||
], | ||
"readme": "README.md", | ||
"devDependencies": { | ||
"babel-cli": "^6.26.0", | ||
"babel-plugin-conditional-compile": "^0.0.5", | ||
"babel-plugin-minify-constant-folding": "^0.5.0", | ||
"babel-plugin-minify-dead-code-elimination": "^0.5.1", | ||
"babel-plugin-minify-dead-code-elimination": "^0.5.2", | ||
"babel-plugin-minify-flip-comparisons": "^0.4.3", | ||
"babel-plugin-minify-guarded-expressions": "^0.4.4", | ||
"babel-plugin-minify-infinity": "^0.4.3", | ||
"babel-plugin-minify-mangle-names": "^0.5.0", | ||
"babel-plugin-minify-mangle-names": "^0.5.1", | ||
"babel-plugin-minify-replace": "^0.5.0", | ||
@@ -74,3 +87,3 @@ "babel-plugin-minify-simplify": "^0.5.1", | ||
"babel-plugin-transform-member-expression-literals": "^6.9.4", | ||
"babel-plugin-transform-merge-sibling-variables": "^6.9.4", | ||
"babel-plugin-transform-merge-sibling-variables": "^6.9.5", | ||
"babel-plugin-transform-minify-booleans": "^6.9.4", | ||
@@ -80,7 +93,4 @@ "babel-plugin-transform-property-literals": "^6.9.4", | ||
"babel-plugin-transform-undefined-to-void": "^6.9.4", | ||
"cpx": "^1.5.0", | ||
"google-closure-compiler": "^20220905.0.0", | ||
"shx": "^0.3.3", | ||
"web-servo": "^0.5.1" | ||
"google-closure-compiler": "^20230802.0.0" | ||
} | ||
} |
@@ -9,2 +9,3 @@ /**! | ||
// COMPILER BLOCK --> | ||
import { | ||
@@ -20,2 +21,3 @@ | ||
} from "./config.js"; | ||
// <-- COMPILER BLOCK | ||
@@ -33,3 +35,3 @@ import Index from "./index.js"; | ||
* @constructor | ||
* @implements DocumentInterface | ||
* @implements {DocumentInterface} | ||
* @param {Object=} options | ||
@@ -36,0 +38,0 @@ * @return {Document} |
@@ -0,2 +1,4 @@ | ||
// COMPILER BLOCK --> | ||
import { DEBUG, SUPPORT_ASYNC, SUPPORT_CACHE } from "./config"; | ||
// <-- COMPILER BLOCK | ||
import { searchCache } from "./cache"; | ||
@@ -3,0 +5,0 @@ |
@@ -9,2 +9,3 @@ /**! | ||
// COMPILER BLOCK --> | ||
import { | ||
@@ -19,2 +20,3 @@ | ||
} from "./config.js"; | ||
// <-- COMPILER BLOCK | ||
@@ -21,0 +23,0 @@ import { IndexInterface } from "./type.js"; |
@@ -0,3 +1,4 @@ | ||
// COMPILER BLOCK --> | ||
import { POLYFILL, SUPPORT_ASYNC } from "./config.js"; | ||
// <-- COMPILER BLOCK | ||
export let promise = Promise; | ||
@@ -4,0 +5,0 @@ |
@@ -0,2 +1,4 @@ | ||
// COMPILER BLOCK --> | ||
import { DEBUG } from "./config.js"; | ||
// <-- COMPILER BLOCK | ||
import { is_string } from "./common.js"; | ||
@@ -3,0 +5,0 @@ |
const { parentPort } = require("worker_threads"); | ||
const { Index } = require("../flexsearch.bundle.js"); | ||
const { Index } = require("../flexsearch.bundle.min.js"); | ||
@@ -4,0 +4,0 @@ let index; |
@@ -1,9 +0,9 @@ | ||
const child_process = require('child_process'); | ||
const fs = require('fs'); | ||
const child_process = require("child_process"); | ||
const fs = require("fs"); | ||
console.log("Start build ....."); | ||
console.log(); | ||
fs.existsSync("log") || fs.mkdirSync("log"); | ||
fs.existsSync("tmp") || fs.mkdirSync("tmp"); | ||
fs.rmSync("tmp/", { recursive: true }); | ||
fs.mkdirSync("tmp"); | ||
//fs.existsSync("log") || fs.mkdirSync("log"); | ||
fs.existsSync("dist") || fs.mkdirSync("dist"); | ||
@@ -64,15 +64,9 @@ | ||
// if(index !== "RELEASE"){ | ||
// | ||
// flag_str += " --define='" + index + "=" + val + "'"; | ||
// } | ||
if(val === "false") val = false; | ||
arr[index] = val; | ||
} | ||
if(count > 3) console.log(index + ': ' + val); | ||
} | ||
}); | ||
console.log('RELEASE: ' + (arr['RELEASE'] || 'custom')); | ||
console.log('Release: ' + (arr['RELEASE'] || 'custom') + (arr['DEBUG'] ? ":debug" : "")); | ||
@@ -83,25 +77,19 @@ return arr; | ||
var release = options["RELEASE"]; | ||
let release = options["RELEASE"].toLowerCase(); | ||
const light_version = (release === "light") || (process.argv[2] === "--light"); | ||
const es5_version = (release === "es5") || (process.argv[2] === "--es5"); | ||
const module_version = (release === "module") || (process.argv[2] === "--module"); | ||
// const light_version = (release === "light") || (process.argv[2] === "--light"); | ||
// const es5_version = (release === "es5") || (process.argv[2] === "--es5"); | ||
// const module_version = (release === "module") || (process.argv[2] === "--module"); | ||
// if(release){ | ||
// | ||
// let filename | ||
// | ||
// if(!fs.existsSync(filename = "src/config/" + release + "/config.js")){ | ||
// | ||
// filename = "src/config/bundle/config.js"; | ||
// } | ||
// | ||
// fs.writeFileSync("tmp/config.js", fs.readFileSync(filename)); | ||
// } | ||
if(release){ | ||
let filename | ||
if(!fs.existsSync(filename = "src/config/" + release + "/config.js")){ | ||
filename = "src/config/bundle/config.js"; | ||
} | ||
fs.writeFileSync("tmp/config.js", fs.readFileSync(filename)); | ||
} | ||
if(release === "es5"){ | ||
release = "ES5"; | ||
} | ||
let parameter = (function(opt){ | ||
@@ -120,3 +108,3 @@ | ||
if((release !== "lang") || (index !== "entry_point")){ | ||
if((release !== "lang") /*|| (index !== "entry_point")*/){ | ||
@@ -133,22 +121,12 @@ parameter += ' --' + index + '=' + opt[index]; | ||
use_types_for_optimization: true, | ||
//new_type_inf: true, | ||
//jscomp_warning: "newCheckTypes", | ||
//jscomp_error: "strictCheckTypes", | ||
//jscomp_error: "newCheckTypesExtraChecks", | ||
generate_exports: true, | ||
export_local_property_definitions: true, | ||
language_in: "ECMASCRIPT_2017", | ||
language_out: language_out || "ECMASCRIPT6_STRICT", | ||
//language_in: "ECMASCRIPT_2017", | ||
language_out: language_out || "ECMASCRIPT_2020", | ||
process_closure_primitives: true, | ||
summary_detail_level: 3, | ||
warning_level: "VERBOSE", | ||
emit_use_strict: true, // release !== "lang", | ||
output_manifest: "log/manifest.log", | ||
//output_module_dependencies: "log/module_dependencies.log", | ||
property_renaming_report: "log/property_renaming.log", | ||
create_source_map: "log/source_map.log", | ||
variable_renaming_report: "log/variable_renaming.log", | ||
//emit_use_strict: true, // release !== "lang",, | ||
strict_mode_input: true, | ||
assume_function_wrapper: true, | ||
//assume_function_wrapper: true, | ||
@@ -162,20 +140,19 @@ //transform_amd_modules: true, | ||
//manage_closure_dependencies: true, | ||
dependency_mode: "PRUNE", // PRUNE_LEGACY | ||
dependency_mode: "PRUNE_LEGACY", // PRUNE_LEGACY | ||
rewrite_polyfills: use_polyfill || false, | ||
// isolation_mode: "IIFE", | ||
output_wrapper: /*release === "lang" ? "%output%" :*/ "\"(function(self){%output%}(this));\"" | ||
//isolation_mode: "IIFE", | ||
//output_wrapper: /*release === "lang" ? "%output%" :*/ "\"(function(self){%output%}(this));\"" | ||
//formatting: "PRETTY_PRINT" | ||
}); | ||
// if(release === "pre" || release === "debug"){ | ||
// | ||
// if(options["DEBUG"]){ | ||
// parameter += ' --formatting=PRETTY_PRINT'; | ||
// } | ||
// if(release === "demo"){ | ||
// | ||
// options['RELEASE'] = "custom"; | ||
// } | ||
if(release !== "bundle.module" && release !== "light.module"){ | ||
//parameter += ' --isolation_mode=IIFE'; | ||
parameter += ' --emit_use_strict=true'; | ||
parameter += ' --output_wrapper="\"(function(self){%output%}(this));\""'; | ||
} | ||
@@ -189,99 +166,147 @@ const custom = (!release || (release === "custom")); | ||
if(release === "lang"){ | ||
// if(release === "lang"){ | ||
// | ||
// const charsets = Object.keys(supported_charset); | ||
// | ||
// (function next(x, y, z){ | ||
// | ||
// if(x < supported_lang.length){ | ||
// | ||
// (function(lang){ | ||
// | ||
// fs.writeFileSync("tmp/" + lang + ".js", ` | ||
// import lang from "../src/lang/${lang}.js"; | ||
// self["FlexSearch"]["registerLanguage"]("${lang}", lang); | ||
// `); | ||
// | ||
// exec("java -jar node_modules/google-closure-compiler-java/compiler.jar" + parameter + " --entry_point='tmp/" + lang + ".js' --js='tmp/" + lang + ".js' --js='src/**.js'" + flag_str + " --js_output_file='dist/lang/" + lang + ".min.js' && exit 0", function(){ | ||
// | ||
// console.log("Build Complete: " + lang + ".min.js"); | ||
// next(++x, y, z); | ||
// }); | ||
// | ||
// })(supported_lang[x]); | ||
// } | ||
// else if(y < charsets.length){ | ||
// | ||
// const charset = charsets[y]; | ||
// const variants = supported_charset[charset]; | ||
// | ||
// if(z < variants.length){ | ||
// | ||
// (function(charset, variant){ | ||
// | ||
// fs.writeFileSync("tmp/" + charset + "_" + variant + ".js", ` | ||
// import charset from "../src/lang/${charset}/${variant}.js"; | ||
// /*try{if(module)self=module}catch(e){}*/ | ||
// self["FlexSearch"]["registerCharset"]("${charset}:${variant}", charset); | ||
// `); | ||
// | ||
// exec("java -jar node_modules/google-closure-compiler-java/compiler.jar" + parameter + " --entry_point='tmp/" + charset + "_" + variant + ".js' --js='tmp/" + charset + "_" + variant + ".js' --js='src/**.js'" + flag_str + " --js_output_file='dist/lang/" + charset + "/" + variant + ".min.js' && exit 0", function(){ | ||
// | ||
// console.log("Build Complete: " + charset + "/" + variant + ".min.js"); | ||
// next(x, y, ++z); | ||
// }); | ||
// | ||
// })(charset, variants[z]); | ||
// } | ||
// else{ | ||
// | ||
// next(x, ++y, 0); | ||
// } | ||
// } | ||
// | ||
// }(0, 0, 0)); | ||
// } | ||
// else{ | ||
const charsets = Object.keys(supported_charset); | ||
if(release === "lang") throw new Error("disabled"); | ||
(function next(x, y, z){ | ||
if(x < supported_lang.length){ | ||
const files = [ | ||
(function(lang){ | ||
"async.js", | ||
"cache.js", | ||
"common.js", | ||
"config.js", | ||
"document.js", | ||
"engine.js", | ||
"global.js", | ||
"index.js", | ||
"intersect.js", | ||
"lang.js", | ||
"polyfill.js", | ||
"preset.js", | ||
"serialize.js", | ||
"type.js", | ||
"webpack.js" | ||
]; | ||
fs.writeFileSync("tmp/" + lang + ".js", ` | ||
import lang from "../src/lang/${lang}.js"; | ||
/*try{if(module)self=module}catch(e){}*/ | ||
self["FlexSearch"]["registerLanguage"]("${lang}", lang); | ||
`); | ||
files.forEach(function(file){ | ||
exec("java -jar node_modules/google-closure-compiler-java/compiler.jar" + parameter + " --entry_point='tmp/" + lang + ".js' --js='tmp/" + lang + ".js' --js='src/**.js'" + flag_str + " --js_output_file='dist/lang/" + lang + ".min.js' && exit 0", function(){ | ||
if(file === "config.js"){ | ||
console.log("Build Complete: " + lang + ".min.js"); | ||
next(++x, y, z); | ||
}); | ||
let src = String(fs.readFileSync("src/" + file)); | ||
})(supported_lang[x]); | ||
for(let opt in options){ | ||
src = src.replace(new RegExp('(export const ' + opt + ' = )(")?[^";]+(")?;'), "$1$2" + options[opt] + "$3;"); | ||
} | ||
else if(y < charsets.length){ | ||
const charset = charsets[y]; | ||
const variants = supported_charset[charset]; | ||
fs.writeFileSync("tmp/" + file, src); | ||
} | ||
else{ | ||
if(z < variants.length){ | ||
fs.copyFileSync("src/" + file, "tmp/" + file); | ||
} | ||
}); | ||
(function(charset, variant){ | ||
fs.cpSync("src/lang/", "tmp/lang/", { recursive: true }); | ||
fs.cpSync("src/worker/", "tmp/worker/", { recursive: true }); | ||
fs.writeFileSync("tmp/" + charset + "_" + variant + ".js", ` | ||
import charset from "../src/lang/${charset}/${variant}.js"; | ||
/*try{if(module)self=module}catch(e){}*/ | ||
self["FlexSearch"]["registerCharset"]("${charset}:${variant}", charset); | ||
`); | ||
const filename = "dist/flexsearch." + (release || "custom") + (options["DEBUG"] ? ".debug" : ".min") + ".js"; | ||
exec("java -jar node_modules/google-closure-compiler-java/compiler.jar" + parameter + " --entry_point='tmp/" + charset + "_" + variant + ".js' --js='tmp/" + charset + "_" + variant + ".js' --js='src/**.js'" + flag_str + " --js_output_file='dist/lang/" + charset + "/" + variant + ".min.js' && exit 0", function(){ | ||
const executable = process.platform === "win32" ? "\"node_modules/google-closure-compiler-windows/compiler.exe\"" : | ||
process.platform === "darwin" ? "\"node_modules/google-closure-compiler-osx/compiler\"" : | ||
"java -jar node_modules/google-closure-compiler-java/compiler.jar"; | ||
console.log("Build Complete: " + charset + "/" + variant + ".min.js"); | ||
next(x, y, ++z); | ||
}); | ||
exec(executable + parameter + " --js='tmp/**.js' --js='!tmp/**/node.js'" + flag_str + " --js_output_file='" + filename + "' && exit 0", function(){ | ||
})(charset, variants[z]); | ||
} | ||
else{ | ||
let build = fs.readFileSync(filename); | ||
let preserve = fs.readFileSync("src/index.js", "utf8"); | ||
next(x, ++y, 0); | ||
} | ||
} | ||
const package_json = require("../package.json"); | ||
}(0, 0, 0)); | ||
} | ||
else{ | ||
preserve = preserve.replace("* FlexSearch.js", "* FlexSearch.js v" + package_json.version + (release ? " (" + (release.charAt(0).toUpperCase() + release.substring(1)) + ")" : "")); | ||
build = preserve.substring(0, preserve.indexOf('*/') + 2) + "\n" + build; | ||
var filename = "dist/flexsearch." + (release || "custom") + ".js"; | ||
if(release === "bundle"){ | ||
exec((/^win/.test(process.platform) ? | ||
build = build.replace("(function(self){'use strict';", "(function _factory(self){'use strict';"); | ||
} | ||
"\"node_modules/google-closure-compiler-windows/compiler.exe\"" | ||
: | ||
"java -jar node_modules/google-closure-compiler-java/compiler.jar" | ||
if(release === "bundle.module" || release === "light.module"){ | ||
) + parameter + " --js='tmp/**.js' --js='!tmp/**/node.js'" + flag_str + " --js_output_file='" + filename + "' && exit 0", function(){ | ||
build = build.replace(/window\.FlexSearch(\s+)?=(\s+)?/, "export default "); | ||
} | ||
let build = fs.readFileSync(filename); | ||
let preserve = fs.readFileSync("src/index.js", "utf8"); | ||
// if(release === "pre"){ | ||
// | ||
// fs.existsSync("test/dist") || fs.mkdirSync("test/dist"); | ||
// fs.writeFileSync("test/" + filename, build); | ||
// } | ||
// else{ | ||
const package_json = require("../package.json"); | ||
fs.writeFileSync(filename, build); | ||
// } | ||
preserve = preserve.replace("* FlexSearch.js", "* FlexSearch.js v" + package_json.version + (release ? " (" + (release.charAt(0).toUpperCase() + release.substring(1)) + ")" : "")); | ||
build = preserve.substring(0, preserve.indexOf('*/') + 2) + "\n" + build; | ||
fs.copyFileSync("src/worker/node.js", "dist/node/node.js"); | ||
if(release === "bundle"){ | ||
console.log("Build Complete."); | ||
}); | ||
//} | ||
build = build.replace("(function(self){'use strict';", "(function _f(self){'use strict';try{if(module)self=module}catch(e){}self._factory=_f;"); | ||
} | ||
if(release === "pre"){ | ||
fs.existsSync("test/dist") || fs.mkdirSync("test/dist"); | ||
fs.writeFileSync("test/" + filename, build); | ||
} | ||
else{ | ||
fs.writeFileSync(filename, build); | ||
} | ||
console.log("Build Complete."); | ||
}); | ||
} | ||
function hashCode(str) { | ||
var hash = 0, i, chr; | ||
let hash = 0, i, chr; | ||
@@ -288,0 +313,0 @@ if(str.length === 0){ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
719860
18
159
16427
2
20