diff --git a/hugo.toml b/hugo.toml index 878257f1..e89d1dc5 100644 --- a/hugo.toml +++ b/hugo.toml @@ -66,6 +66,13 @@ source = "paige/node_modules/bootstrap-icons/font" target = "assets/css/paige/bootstrap-icons" includeFiles = ["bootstrap-icons.css"] +# FlexSearch + +[[module.mounts]] +source = "paige/node_modules/flexsearch/dist" +target = "assets/js/paige/flexsearch" +includeFiles = ["flexsearch.bundle.min.js"] + # Katex [[module.mounts]] diff --git a/layouts/partials/paige/search.html b/layouts/partials/paige/search.html index 94c356c7..3ef3c32b 100644 --- a/layouts/partials/paige/search.html +++ b/layouts/partials/paige/search.html @@ -45,7 +45,7 @@ - +{{ partial "paige/tag-script.html" (dict "page" $page "src" "js/paige/flexsearch/flexsearch.bundle.min.js") }} + +``` + +#### ESM/ES6 Modules: + +```html + +``` + +#### ESM/ES6 Bundled Module: + +```html + +``` + +Or via CDN: +```html + +``` + +AMD / CommonJS: + +```javascript +var FlexSearch = require("./node_modules/flexsearch/dist/flexsearch.bundle.min.js"); +``` + +### Node.js + +```npm +npm install flexsearch +``` + +In your code include as follows: + +```js +const { Index, Document, Worker } = require("flexsearch"); + +const index = new Index(options); +const document = new Document(options); +const worker = new Worker(options); +``` + +Or: + +```js +const FlexSearch = require("flexsearch"); + +const index = new FlexSearch.Index(options); +const document = new FlexSearch.Document(options); +const worker = new FlexSearch.Worker(options); +``` + +## Basic Usage and Variants + +```js +index.add(id, text); +index.search(text); +index.search(text, limit); +index.search(text, options); +index.search(text, limit, options); +index.search(options); +``` + +```js +document.add(doc); +document.add(id, doc); +document.search(text); +document.search(text, limit); +document.search(text, options); +document.search(text, limit, options); +document.search(options); +``` + +```js +worker.add(id, text); +worker.search(text); +worker.search(text, limit); +worker.search(text, options); +worker.search(text, limit, options); +worker.search(text, limit, options, callback); +worker.search(options); +``` + +The `worker` inherits from type `Index` and does not inherit from type `Document`. Therefore, a WorkerIndex basically works like a standard FlexSearch Index. Worker-Support in documents needs to be enabled by just passing the appropriate option during creation `{ worker: true }`. + +> Every method called on a `Worker` index is treated as async. You will get back a `Promise` or you can provide a callback function as the last parameter alternatively. + + +## API Overview + +Global methods: + +- FlexSearch.__registerCharset__(name, charset) +- FlexSearch.__registerLanguage__(name, language) + +Index methods: + +- Index.__add__(id, string) * +- Index.__append__(id, string) * +- Index.__update__(id, string) * +- Index.__remove__(id) * +- Index.__search__(string, \, \) * +- Index.__search__(options) * +- _async_ Index.__export__(handler) +- _async_ Index.__import__(key, data) + +WorkerIndex methods: + +- _async_ Index.__add__(id, string) +- _async_ Index.__append__(id, string) +- _async_ Index.__update__(id, string) +- _async_ Index.__remove__(id) +- _async_ Index.__search__(string, \, \) +- _async_ Index.__search__(options) +- _async_ ~~Index.__export__(handler)~~ (WIP) +- _async_ ~~Index.__import__(key, data)~~ (WIP) + +Document methods: + +- Document.__add__(\, document) * +- Document.__append__(\, document) * +- Document.__update__(\, document) * +- Document.__remove__(id || document) * +- Document.__search__(string, \, \) * +- Document.__search__(options) * +- _async_ Document.__export__(handler) +- _async_ Document.__import__(key, data) + +* For each of those methods there exist an asynchronous equivalent: + +Async Version: + +- _async_ .__addAsync__( ... , \) +- _async_ .__appendAsync__( ... , \) +- _async_ .__updateAsync__( ... , \) +- _async_ .__removeAsync__( ... , \) +- _async_ .__searchAsync__( ... , \) + +Async methods will return a `Promise`, alternatively you can pass a callback function as the last parameter. + +Methods `export` and also `import` are always async as well as every method you call on a Worker-based Index. + + +## Options + +FlexSearch is highly customizable. Make use of the right options can really improve your results as well as memory economy and query time. + + +### Index Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionValuesDescriptionDefault
preset + "memory"
+ "performance"
+ "match"
+ "score"
+ "default" +
+ The configuration profile as a shortcut or as a base for your custom settings.
+
"default"
tokenize + "strict"
+ "forward"
+ "reverse"
+ "full" +
+ The indexing mode (tokenizer).

Choose one of the built-ins or pass a custom tokenizer function.
+
"strict"
cache + Boolean
+ Number +
Enable/Disable and/or set capacity of cached entries.

When passing a number as a limit the cache automatically balance stored entries related to their popularity.

Note: When just using "true" the cache has no limits and growth unbounded.
false
resolution + Number + Sets the scoring resolution (default: 9).9
context + Boolean
+ Context Options +
Enable/Disable contextual indexing. When passing "true" as value it will take the default values for the context.false
optimize + Boolean + When enabled it uses a memory-optimized stack flow for the index.true
boost + function(arr, str, int) => float + A custom boost function used when indexing contents to the index. The function has this signature: Function(words[], term, index) => Float. It has 3 parameters where you get an array of all words, the current term and the current index where the term is placed in the word array. You can apply your own calculation e.g. the occurrences of a term and return this factor (<1 means relevance is lowered, >1 means relevance is increased).

Note: this feature is currently limited by using the tokenizer "strict" only.
null
+ Language-specific Options and Encoding: +
charset

+ Charset Payload
+ String (key) +
+ Provide a custom charset payload or pass one of the keys of built-in charsets. + "latin"
language

+ Language Payload
+ String (key) +
+ Provide a custom language payload or pass in language shorthand flag (ISO-3166) of built-in languages. + null
encode






+ false
+ "default"
+ "simple"
+ "balance"
+ "advanced"
+ "extra"
+ function(str) => [words] +
The encoding type.

Choose one of the built-ins or pass a custom encoding function.
"default"
stemmer


+ false
+ String
+ Function +
false
filter


+ false
+ String
+ Function +
false
matcher


+ false
+ String
+ Function +
false
+ Additional Options for Document Indexes: +
worker
+ Boolean + Enable/Disable and set count of running worker threads.false
document
Document Descriptor + Includes definitions for the document index and storage. +
+ + +### Context Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionValuesDescriptionDefault
resolution + Number + Sets the scoring resolution for the context (default: 1).1
depth

+ false
+ Number +
Enable/Disable contextual indexing and also sets contextual distance of relevance. Depth is the maximum number of words/tokens away a term to be considered as relevant.1
bidirectional + Boolean + Sets bidirectional search result. If enabled and the source text contains "red hat", it will be found for queries "red hat" and "hat red".true
+ + +### Document Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionValuesDescriptionDefault
id
String"id""
tag

false
String
"tag"
index


String
Array<String>
Array<Object>
store


Boolean
String
Array<String>
false
+ + +### Charset Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionValuesDescriptionDefault
split

+ false
+ RegExp
+ String +
+ The rule to split words when using non-custom tokenizer (built-ins e.g. "forward"). Use a string/char or use a regular expression (default: /\W+/).
+
/[\W_]+/
rtl
+ Boolean + Enables Right-To-Left encoding.false
encode
+ function(str) => [words] + The custom encoding function./lang/latin/default.js
+ + +### Language Options + + + + + + + + + + + + + + + + + + + + + + + + +
OptionValuesDescription
stemmer


+ false
+ String
+ Function +
Disable or pass in language shorthand flag (ISO-3166) or a custom object. +
filter


+ false
+ String
+ Function +
Disable or pass in language shorthand flag (ISO-3166) or a custom array.
matcher


+ false
+ String
+ Function +
Disable or pass in language shorthand flag (ISO-3166) or a custom array.
+ + +### Search Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionValuesDescriptionDefault
limitnumberSets the limit of results.100
offsetnumberApply offset (skip items).0
suggestBooleanEnables suggestions in results.false
+ + +### Document Search Options + +* Additionally, to the Index search options above. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionValuesDescriptionDefault
indexString
Array<String>
Array<Object>
Sets the document fields which should be searched. When no field is set, all fields will be searched. Custom options per field are also supported.
tagString
Array<String>
Sets the document fields which should be searched. When no field is set, all fields will be searched. Custom options per field are also supported.false
enrichBooleanEnrich IDs from the results with the corresponding documents.false
bool"and"
"or"
Sets the used logical operator when searching through multiple fields or tags."or"
+ + +## Tokenizer (Prefix Search) + +Tokenizer affects the required memory also as query time and flexibility of partial matches. Try to choose the most upper of these tokenizer which fits your needs: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionDescriptionExampleMemory Factor (n = length of word)
"strict"index whole wordsfoobar* 1
"forward"incrementally index words in forward directionfoobar
foobar
* n
"reverse"incrementally index words in both directionsfoobar
foobar
* 2n - 1
"full"index every possible combinationfoobar
foobar
* n * (n - 1)
+ + +## Encoders + +Encoding affects the required memory also as query time and phonetic matches. Try to choose the most upper of these encoders which fits your needs, or pass in a custom encoder: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionDescriptionFalse-PositivesCompression
falseTurn off encodingno0%
"default"Case in-sensitive encodingno0%
"simple"Case in-sensitive encoding
Charset normalizations
no~ 3%
"balance"Case in-sensitive encoding
Charset normalizations
Literal transformations
no~ 30%
"advanced"Case in-sensitive encoding
Charset normalizations
Literal transformations
Phonetic normalizations
no~ 40%
"extra"Case in-sensitive encoding
Charset normalizations
Literal transformations
Phonetic normalizations
Soundex transformations
yes~ 65%
function()Pass custom encoding via function(string):[words]
+ +## Usage + + +#### Create a new index + +```js +var index = new Index(); +``` + +Create a new index and choosing one of the presets: + +```js +var index = new Index("performance"); +``` + +Create a new index with custom options: + +```js +var index = new Index({ + charset: "latin:extra", + tokenize: "reverse", + resolution: 9 +}); +``` + +Create a new index and extend a preset with custom options: + +```js +var index = new FlexSearch({ + preset: "memory", + tokenize: "forward", + resolution: 5 +}); +``` + +See all available custom options. + + +#### Add text item to an index + +Every content which should be added to the index needs an ID. When your content has no ID, then you need to create one by passing an index or count or something else as an ID (a value from type `number` is highly recommended). Those IDs are unique references to a given content. This is important when you update or adding over content through existing IDs. When referencing is not a concern, you can simply use something simple like `count++`. + +> Index.__add(id, string)__ + +```js +index.add(0, "John Doe"); +``` + + +#### Search items + +> Index.__search(string | options, \, \)__ + +```js +index.search("John"); +``` + +Limit the result: + +```js +index.search("John", 10); +``` + +#### Check existence of already indexed IDs + +You can check if an ID was already indexed by: + +```js +if(index.contain(1)){ + console.log("ID is already in index"); +} +``` + + +## Async + +You can call each method in its async version, e.g. `index.addAsync` or `index.searchAsync`. + +You can assign callbacks to each async function: + +```js +index.addAsync(id, content, function(){ + console.log("Task Done"); +}); + +index.searchAsync(query, function(result){ + console.log("Results: ", result); +}); +``` + +Or do not pass a callback function and getting back a `Promise` instead: + +```js +index.addAsync(id, content).then(function(){ + console.log("Task Done"); +}); + +index.searchAsync(query).then(function(result){ + console.log("Results: ", result); +}); +``` + +Or use `async` and `await`: + +```js +async function add(){ + await index.addAsync(id, content); + console.log("Task Done"); +} + +async function search(){ + const results = await index.searchAsync(query); + console.log("Results: ", result); +} +``` + +## Append Contents + +You can append contents to an existing index like: + +```js +index.append(id, content); +``` + +This will not overwrite the old indexed contents as it will do when perform `index.update(id, content)`. Keep in mind that `index.add(id, content)` will also perform "update" under the hood when the id was already being indexed. + +Appended contents will have their own context and also their own full `resolution`. Therefore, the relevance isn't being stacked but gets its own context. + +Let us take this example: + +```js +index.add(0, "some index"); +index.append(0, "some appended content"); + +index.add(1, "some text"); +index.append(1, "index appended content"); +``` + +When you query `index.search("index")` then you will get index id 1 as the first entry in the result, because the context starts from zero for the appended data (isn't stacked to the old context) and here "index" is the first term. + +If you didn't want this behavior than just use the standard `index.add(id, content)` and provide the full length of content. + + +#### Update item from an index + +> Index.__update(id, string)__ + +```js +index.update(0, "Max Miller"); +``` + + +#### Remove item from an index + +> Index.__remove(id)__ + +```js +index.remove(0); +``` + + +#### Add custom tokenizer + +> A tokenizer split words/terms into components or partials. + +Define a private custom tokenizer during creation/initialization: +```js +var index = new FlexSearch({ + + tokenize: function(str){ + + return str.split(/\s-\//g); + } +}); +``` + +> The tokenizer function gets a string as a parameter and has to return an array of strings representing a word or term. In some languages every char is a term and also not separated via whitespaces. + + +#### Add language-specific stemmer and/or filter + +> __Stemmer:__ several linguistic mutations of the same word (e.g. "run" and "running") + +> __Filter:__ a blacklist of words to be filtered out from indexing at all (e.g. "and", "to" or "be") + +Assign a private custom stemmer or filter during creation/initialization: +```js +var index = new FlexSearch({ + + stemmer: { + + // object {key: replacement} + "ational": "ate", + "tional": "tion", + "enci": "ence", + "ing": "" + }, + filter: [ + + // array blacklist + "in", + "into", + "is", + "isn't", + "it", + "it's" + ] +}); +``` + +Using a custom filter, e.g.: +```js +var index = new FlexSearch({ + + filter: function(value){ + + // just add values with length > 1 to the index + + return value.length > 1; + } +}); +``` + +Or assign stemmer/filters globally to a language: + +> Stemmer are passed as a object (key-value-pair), filter as an array. + +```js +FlexSearch.registerLanguage("us", { + + stemmer: { /* ... */ }, + filter: [ /* ... */ ] +}); +``` + +Or use some pre-defined stemmer or filter of your preferred languages: +```html + + + + + + +... +``` + +Now you can assign built-in stemmer during creation/initialization: +```js +var index_en = new FlexSearch.Index({ + language: "en" +}); + +var index_de = new FlexSearch.Index({ + language: "de" +}); +``` + +In Node.js all built-in language packs files are available: + +```js +const { Index } = require("flexsearch"); + +var index_en = new Index({ + language: "en" +}); +``` + + +### Right-To-Left Support + +> Set the tokenizer at least to "reverse" or "full" when using RTL. + +Just set the field "rtl" to _true_ and use a compatible tokenizer: + +```js +var index = new Index({ + encode: str => str.toLowerCase().split(/[^a-z]+/), + tokenize: "reverse", + rtl: true +}); +``` + + +### CJK Word Break (Chinese, Japanese, Korean) + +Set a custom tokenizer which fits your needs, e.g.: + +```js +var index = FlexSearch.create({ + encode: str => str.replace(/[\x00-\x7F]/g, "").split("") +}); +``` + +You can also pass a custom encoder function to apply some linguistic transformations. + +```js +index.add(0, "一个单词"); +``` + +```js +var results = index.search("单词"); +``` + + +## Index Documents (Field-Search) + +### The Document Descriptor + +Assuming our document has a data structure like this: + +```json +{ + "id": 0, + "content": "some text" +} +``` + +Old syntax FlexSearch v0.6.3 (___not supported anymore!___): + +```js +const index = new Document({ + doc: { + id: "id", + field: ["content"] + } +}); +``` + +> The document descriptor has slightly changed, there is no `field` branch anymore, instead just apply one level higher, so `key` becomes a main member of options. + +For the new syntax the field "doc" was renamed to `document` and the field "field" was renamed to `index`: + +```js +const index = new Document({ + document: { + id: "id", + index: ["content"] + } +}); + +index.add({ + id: 0, + content: "some text" +}); +``` + +The field `id` describes where the ID or unique key lives inside your documents. The default key gets the value `id` by default when not passed, so you can shorten the example from above to: + +```js +const index = new Document({ + document: { + index: ["content"] + } +}); +``` + +The member `index` has a list of fields which you want to be indexed from your documents. When just selecting one field, then you can pass a string. When also using default key `id` then this shortens to just: + +```js +const index = new Document({ document: "content" }); +index.add({ id: 0, content: "some text" }); +``` + +Assuming you have several fields, you can add multiple fields to the index: + +```js +var docs = [{ + id: 0, + title: "Title A", + content: "Body A" +},{ + id: 1, + title: "Title B", + content: "Body B" +}]; +``` + +```js +const index = new Document({ + id: "id", + index: ["title", "content"] +}); +``` + +You can pass custom options for each field: + +```js +const index = new Document({ + id: "id", + index: [{ + field: "title", + tokenize: "forward", + optimize: true, + resolution: 9 + },{ + field: "content", + tokenize: "strict", + optimize: true, + resolution: 5, + minlength: 3, + context: { + depth: 1, + resolution: 3 + } + }] +}); +``` + +Field options gets inherited when also global options was passed, e.g.: + +```js +const index = new Document({ + tokenize: "strict", + optimize: true, + resolution: 9, + document: { + id: "id", + index:[{ + field: "title", + tokenize: "forward" + },{ + field: "content", + minlength: 3, + context: { + depth: 1, + resolution: 3 + } + }] + } +}); +``` + +Note: The context options from the field "content" also gets inherited by the corresponding field options, whereas this field options was inherited by the global option. + +### Nested Data Fields (Complex Objects) + +Assume the document array looks more complex (has nested branches etc.), e.g.: + +```json +{ + "record": { + "id": 0, + "title": "some title", + "content": { + "header": "some text", + "footer": "some text" + } + } +} +``` + +Then use the colon separated notation `root:child:child` to define hierarchy within the document descriptor: + +```js +const index = new Document({ + document: { + id: "record:id", + index: [ + "record:title", + "record:content:header", + "record:content:footer" + ] + } +}); +``` +> Just add fields you want to query against. Do not add fields to the index, you just need in the result (but did not query against). For this purpose you can store documents independently of its index (read below). + +When you want to query through a field you have to pass the exact key of the field you have defined in the `doc` as a field name (with colon syntax): + +```js +index.search(query, { + index: [ + "record:title", + "record:content:header", + "record:content:footer" + ] +}); +``` + +Same as: + +```js +index.search(query, [ + "record:title", + "record:content:header", + "record:content:footer" +]); +``` + +Using field-specific options: + +```js +index.search([{ + field: "record:title", + query: "some query", + limit: 100, + suggest: true +},{ + field: "record:title", + query: "some other query", + limit: 100, + suggest: true +}]); +``` + +You can perform a search through the same field with different queries. + +> When passing field-specific options you need to provide the full configuration for each field. They get not inherited like the document descriptor. + +### Complex Documents + +You need to follow 2 rules for your documents: + +1. The document cannot start with an Array at the root index. This will introduce sequential data and isn't supported yet. See below for a workaround for such data. + +```js +[ // <-- not allowed as document start! + { + "id": 0, + "title": "title" + } +] +``` + +2. The id can't be nested inside an array (also none of the parent fields can't be an array). This will introduce sequential data and isn't supported yet. See below for a workaround for such data. + +```js +{ + "records": [ // <-- not allowed when ID or tag lives inside! + { + "id": 0, + "title": "title" + } + ] +} +``` + +Here an example for a supported complex document: + +```json +{ + "meta": { + "tag": "cat", + "id": 0 + }, + "contents": [ + { + "body": { + "title": "some title", + "footer": "some text" + }, + "keywords": ["some", "key", "words"] + }, + { + "body": { + "title": "some title", + "footer": "some text" + }, + "keywords": ["some", "key", "words"] + } + ] +} +``` + +The corresponding document descriptor (when all fields should be indexed) looks like: + +```js +const index = new Document({ + document: { + id: "meta:id", + tag: "meta:tag", + index: [ + "contents[]:body:title", + "contents[]:body:footer", + "contents[]:keywords" + ] + } +}); +``` + +Again, when searching you have to use the same colon-separated-string from your field definition. + +```js +index.search(query, { + index: "contents[]:body:title" +}); +``` + +### Not Supported Documents (Sequential Data) + +This example breaks both rules from above: + +```js +[ // <-- not allowed as document start! + { + "tag": "cat", + "records": [ // <-- not allowed when ID or tag lives inside! + { + "id": 0, + "body": { + "title": "some title", + "footer": "some text" + }, + "keywords": ["some", "key", "words"] + }, + { + "id": 1, + "body": { + "title": "some title", + "footer": "some text" + }, + "keywords": ["some", "key", "words"] + } + ] + } +] +``` + +You need to apply some kind of structure normalization. + +A workaround to such a data structure looks like this: + +```js +const index = new Document({ + document: { + id: "record:id", + tag: "tag", + index: [ + "record:body:title", + "record:body:footer", + "record:body:keywords" + ] + } +}); + +function add(sequential_data){ + + for(let x = 0, data; x < sequential_data.length; x++){ + + data = sequential_data[x]; + + for(let y = 0, record; y < data.records.length; y++){ + + record = data.records[y]; + + index.add({ + id: record.id, + tag: data.tag, + record: record + }); + } + } +} + +// now just use add() helper method as usual: + +add([{ + // sequential structured data + // take the data example above +}]); +``` + +You can skip the first loop when your document data has just one index as the outer array. + +### Add/Update/Remove Documents to/from the Index + +Add a document to the index: + +```js +index.add({ + id: 0, + title: "Foo", + content: "Bar" + }); +``` + +Update index with a single object or an array of objects: + +```js +index.update({ + data:{ + id: 0, + title: "Foo", + body: { + content: "Bar" + } + } +}); +``` + +Remove a single object or an array of objects from the index: + +```js +index.remove(docs); +``` + +When the id is known, you can also simply remove by (faster): + +```js +index.remove(id); +``` + +### Join / Append Arrays + +On the complex example above, the field `keywords` is an array but here the markup did not have brackets like `keywords[]`. That will also detect the array but instead of appending each entry to a new context, the array will be joined into on large string and added to the index. + +The difference of both kinds of adding array contents is the relevance when searching. When adding each item of an array via `append()` to its own context by using the syntax `field[]`, then the relevance of the last entry concurrent with the first entry. When you left the brackets in the notation, it will join the array to one whitespace-separated string. Here the first entry has the highest relevance, whereas the last entry has the lowest relevance. + +So assuming the keyword from the example above are pre-sorted by relevance to its popularity, then you want to keep this order (information of relevance). For this purpose do not add brackets to the notation. Otherwise, it would take the entries in a new scoring context (the old order is getting lost). + +Also you can left bracket notation for better performance and smaller memory footprint. Use it when you did not need the granularity of relevance by the entries. + +### Field-Search + +Search through all fields: + +```js +index.search(query); +``` + +Search through a specific field: + +```js +index.search(query, { index: "title" }); +``` + +Search through a given set of fields: + +```js +index.search(query, { index: ["title", "content"] }); +``` + +Same as: + +```js +index.search(query, ["title", "content"]); +``` + +Pass custom modifiers and queries to each field: + +```js +index.search([{ + field: "content", + query: "some query", + limit: 100, + suggest: true +},{ + field: "content", + query: "some other query", + limit: 100, + suggest: true +}]); +``` + +You can perform a search through the same field with different queries. + +See all available field-search options. + +### The Result Set + +Schema of the result-set: + +> `fields[] => { field, result[] => { document }}` + +The first index is an array of fields the query was applied to. Each of this field has a record (object) with 2 properties "field" and "result". The "result" is also an array and includes the result for this specific field. The result could be an array of IDs or as enriched with stored document data. + +A non-enriched result set now looks like: + +```js +[{ + field: "title", + result: [0, 1, 2] +},{ + field: "content", + result: [3, 4, 5] +}] +``` + +An enriched result set now looks like: + +```js +[{ + field: "title", + result: [ + { id: 0, doc: { /* document */ }}, + { id: 1, doc: { /* document */ }}, + { id: 2, doc: { /* document */ }} + ] +},{ + field: "content", + result: [ + { id: 3, doc: { /* document */ }}, + { id: 4, doc: { /* document */ }}, + { id: 5, doc: { /* document */ }} + ] +}] +``` + +When using `pluck` instead of "field" you can explicitly select just one field and get back a flat representation: + +```js +index.search(query, { pluck: "title", enrich: true }); +``` + +```js +[ + { id: 0, doc: { /* document */ }}, + { id: 1, doc: { /* document */ }}, + { id: 2, doc: { /* document */ }} +] +``` + +This result set is a replacement of "boolean search". Instead of applying your bool logic to a nested object, you can apply your logic by yourself on top of the result-set dynamically. This opens hugely capabilities on how you process the results. Therefore, the results from the fields aren't squashed into one result anymore. That keeps some important information, like the name of the field as well as the relevance of each field results which didn't get mixed anymore. + +> A field search will apply a query with the boolean "or" logic by default. Each field has its own result to the given query. + +There is one situation where the `bool` property is being still supported. When you like to switch the default "or" logic from the field search into "and", e.g.: + +```js +index.search(query, { + index: ["title", "content"], + bool: "and" +}); +``` + +You will just get results which contains the query in both fields. That's it. + +### Tags + +Like the `key` for the ID just define the path to the tag: + +```js +const index = new Document({ + document: { + id: "id", + tag: "tag", + index: "content" + } +}); +``` + +```js +index.add({ + id: 0, + tag: "cat", + content: "Some content ..." +}); +``` + +Your data also can have multiple tags as an array: + +```js +index.add({ + id: 1, + tag: ["animal", "dog"], + content: "Some content ..." +}); +``` + +You can perform a tag-specific search by: + +```js +index.search(query, { + index: "content", + tag: "animal" +}); +``` + +This just gives you result which was tagged with the given tag. + +Use multiple tags when searching: + +```js +index.search(query, { + index: "content", + tag: ["cat", "dog"] +}); +``` + +This gives you result which are tagged with one of the given tag. + +> Multiple tags will apply as the boolean "or" by default. It just needs one of the tags to be existing. + +This is another situation where the `bool` property is still supported. When you like to switch the default "or" logic from the tag search into "and", e.g.: + +```js +index.search(query, { + index: "content", + tag: ["dog", "animal"], + bool: "and" +}); +``` + +You will just get results which contains both tags (in this example there is just one records which has the tag "dog" and "animal"). + +### Tag Search + +You can also fetch results from one or more tags when no query was passed: + +```js +index.search({ tag: ["cat", "dog"] }); +``` + +In this case the result-set looks like: + +```js +[{ + tag: "cat", + result: [ /* all cats */ ] +},{ + tag: "dog", + result: [ /* all dogs */ ] +}] +``` + +### Limit & Offset + +> By default, every query is limited to 100 entries. Unbounded queries leads into issues. You need to set the limit as an option to adjust the size. + +You can set the limit and the offset for each query: + +```js +index.search(query, { limit: 20, offset: 100 }); +``` + +> You cannot pre-count the size of the result-set. That's a limit by the design of FlexSearch. When you really need a count of all results you are able to page through, then just assign a high enough limit and get back all results and apply your paging offset manually (this works also on server-side). FlexSearch is fast enough that this isn't an issue. + +## Document Store + +Only a document index can have a store. You can use a document index instead of a flat index to get this functionality also when only storing ID-content-pairs. + +You can define independently which fields should be indexed and which fields should be stored. This way you can index fields which should not be included in the search result. + +> Do not use a store when: 1. an array of IDs as the result is good enough, or 2. you already have the contents/documents stored elsewhere (outside the index). + +> When the `store` attribute was set, you have to include all fields which should be stored explicitly (acts like a whitelist). + +> When the `store` attribute was not set, the original document is stored as a fallback. + +This will add the whole original content to the store: + +```js +const index = new Document({ + document: { + index: "content", + store: true + } +}); + +index.add({ id: 0, content: "some text" }); +``` + +### Access documents from internal store + +You can get indexed documents from the store: + +```js +var data = index.get(1); +``` + +You can update/change store contents directly without changing the index by: + +```js +index.set(1, data); +``` + +To update the store and also update the index then just use `index.update`, `index.add` or `index.append`. + +When you perform a query, weather it is a document index or a flat index, then you will always get back an array of IDs. + +Optionally you can enrich the query results automatically with stored contents by: + +```js +index.search(query, { enrich: true }); +``` + +Your results look now like: + +```js +[{ + id: 0, + doc: { /* content from store */ } +},{ + id: 1, + doc: { /* content from store */ } +}] +``` + +### Configure Storage (Recommended) + +This will add just specific fields from a document to the store (the ID isn't necessary to keep in store): + +```js +const index = new Document({ + document: { + index: "content", + store: ["author", "email"] + } +}); + +index.add(id, content); +``` + +You can configure independently what should being indexed and what should being stored. It is highly recommended to make use of this whenever you can. + +Here a useful example of configuring doc and store: + +```js +const index = new Document({ + document: { + index: "content", + store: ["author", "email"] + } +}); + +index.add({ + id: 0, + author: "Jon Doe", + email: "john@mail.com", + content: "Some content for the index ..." +}); +``` + +You can query through the contents and will get back the stored values instead: + +```js +index.search("some content", { enrich: true }); +``` + +Your results are now looking like: + +```js +[{ + field: "content", + result: [{ + id: 0, + doc: { + author: "Jon Doe", + email: "john@mail.com", + } + }] +}] +``` + +Both field "author" and "email" are not indexed. + + +### Chaining + +Simply chain methods like: + +```js +var index = FlexSearch.create() + .addMatcher({'â': 'a'}) + .add(0, 'foo') + .add(1, 'bar'); +``` + +```js +index.remove(0).update(1, 'foo').add(2, 'foobar'); +``` + + +## Contextual Search + +> __Note:__ This feature is disabled by default because of its extended memory usage. Read here get more information about and how to enable. + +FlexSearch introduce a new scoring mechanism called __Contextual Search__ which was invented by Thomas Wilkerling, the author of this library. A Contextual Search incredibly boost up queries to a complete new level but also requires some additional memory (depending on ___depth___). +The basic idea of this concept is to limit relevance by its context instead of calculating relevance through the whole distance of its corresponding document. +This way contextual search also improves the results of relevance-based queries on a large amount of text data. + +

+ +

+ + +## Enable Contextual Scoring + +Create an index and use the default context: +```js +var index = new FlexSearch({ + + tokenize: "strict", + context: true +}); +``` + +Create an index and apply custom options for the context: +```js +var index = new FlexSearch({ + + tokenize: "strict", + context: { + resolution: 5, + depth: 3, + bidirectional: true + } +}); +``` + +> Only the tokenizer "strict" is actually supported by the contextual index. + +> The contextual index requires additional amount of memory depending on depth. + + +### Auto-Balanced Cache (By Popularity) + +You need to initialize the cache and its limit during the creation of the index: + +```js +const index = new Index({ cache: 100 }); +``` + +```js +const results = index.searchCache(query); +``` + +A common scenario for using a cache is an autocomplete or instant search when typing. + +> When passing a number as a limit the cache automatically balance stored entries related to their popularity. + +> When just using "true" the cache is unbounded and perform actually 2-3 times faster (because the balancer do not have to run). + + +## Worker Parallelism (Browser + Node.js) + +The new worker model from v0.7.0 is divided into "fields" from the document (1 worker = 1 field index). This way the worker becomes able to solve tasks (subtasks) completely. The downside of this paradigm is they might not have been perfect balanced in storing contents (fields may have different length of contents). On the other hand there is no indication that balancing the storage gives any advantage (they all require the same amount in total). + +When using a document index, then just apply the option "worker": +```js +const index = new Document({ + index: ["tag", "name", "title", "text"], + worker: true +}); + +index.add({ + id: 1, tag: "cat", name: "Tom", title: "some", text: "some" +}).add({ + id: 2, tag: "dog", name: "Ben", title: "title", text: "content" +}).add({ + id: 3, tag: "cat", name: "Max", title: "to", text: "to" +}).add({ + id: 4, tag: "dog", name: "Tim", title: "index", text: "index" +}); +``` + +``` +Worker 1: { 1: "cat", 2: "dog", 3: "cat", 4: "dog" } +Worker 2: { 1: "Tom", 2: "Ben", 3: "Max", 4: "Tim" } +Worker 3: { 1: "some", 2: "title", 3: "to", 4: "index" } +Worker 4: { 1: "some", 2: "content", 3: "to", 4: "index" } +``` + +When you perform a field search through all fields then this task is being balanced perfectly through all workers, which can solve their subtasks independently. + +### Worker Index + +Above we have seen that documents will create worker automatically for each field. You can also create a WorkerIndex directly (same like using `Index` instead of `Document`). + +Use as ES6 module: + +```js +import WorkerIndex from "./worker/index.js"; +const index = new WorkerIndex(options); +index.add(1, "some") + .add(2, "content") + .add(3, "to") + .add(4, "index"); +``` + +Or when bundled version was used instead: + +```js +var index = new FlexSearch.Worker(options); +index.add(1, "some") + .add(2, "content") + .add(3, "to") + .add(4, "index"); +``` + +Such a WorkerIndex works pretty much the same as a created instance of `Index`. + +> A WorkerIndex only support the `async` variant of all methods. That means when you call `index.search()` on a WorkerIndex this will perform also in async the same way as `index.searchAsync()` will do. + +### Worker Threads (Node.js) + +The worker model for Node.js is based on "worker threads" and works exactly the same way: + +```js +const { Document } = require("flexsearch"); + +const index = new Document({ + index: ["tag", "name", "title", "text"], + worker: true +}); +``` + +Or create a single worker instance for a non-document index: + +```js +const { Worker } = require("flexsearch"); +const index = new Worker({ options }); +``` + +### The Worker Async Model (Best Practices) + +A worker will always perform as async. On a query method call you always should handle the returned promise (e.g. use `await`) or pass a callback function as the last parameter. + +```js +const index = new Document({ + index: ["tag", "name", "title", "text"], + worker: true +}); +``` + +All requests and sub-tasks will run in parallel (prioritize "all tasks completed"): + +```js +index.searchAsync(query, callback); +index.searchAsync(query, callback); +index.searchAsync(query, callback); +``` + +Also (prioritize "all tasks completed"): + +```js +index.searchAsync(query).then(callback); +index.searchAsync(query).then(callback); +index.searchAsync(query).then(callback); +``` + +Or when you have just one callback when all requests are done, simply use `Promise.all()` which also prioritize "all tasks completed": + +```js +Promise.all([ + index.searchAsync(query), + index.searchAsync(query), + index.searchAsync(query) +]).then(callback); +``` + +Inside the callback of `Promise.all()` you will also get an array of results as the first parameter respectively for each query you put into. + +When using `await` you can prioritize the order (prioritize "first task completed") and solve requests one by one and just process the sub-tasks in parallel: + +```js +await index.searchAsync(query); +await index.searchAsync(query); +await index.searchAsync(query); +``` + +Same for `index.add()`, `index.append()`, `index.remove()` or `index.update()`. Here there is a special case which isn't disabled by the library, but you need to keep in mind when using Workers. + +When you call the "synced" version on a worker index: + +```js +index.add(doc); +index.add(doc); +index.add(doc); +// contents aren't indexed yet, +// they just queued on the message channel +``` + +Of course, you can do that but keep in mind that the main thread does not have an additional queue for distributed worker tasks. Running these in a long loop fires content massively to the message channel via `worker.postMessage()` internally. Luckily the browser and Node.js will handle such incoming tasks for you automatically (as long enough free RAM is available). When using the "synced" version on a worker index, the content isn't indexed one line below, because all calls are treated as async by default. + +> When adding/updating/removing large bulks of content to the index (or high frequency), it is recommended to use the async version along with `async/await` to keep a low memory footprint during long processes. + + +## Export / Import + +### Export + +The export has slightly changed. The export now consist of several smaller parts, instead of just one large bulk. You need to pass a callback function which has 2 arguments "key" and "data". This callback function is called by each part, e.g.: + +```js +index.export(function(key, data){ + + // you need to store both the key and the data! + // e.g. use the key for the filename and save your data + + localStorage.setItem(key, data); +}); +``` + +Exporting data to the localStorage isn't really a good practice, but if size is not a concern than use it if you like. The export primarily exists for the usage in Node.js or to store indexes you want to delegate from a server to the client. + +> The size of the export corresponds to the memory consumption of the library. To reduce export size you have to use a configuration which has less memory footprint (use the table at the bottom to get information about configs and its memory allocation). + +When your save routine runs asynchronously you have to return a promise: + +```js +index.export(function(key, data){ + + return new Promise(function(resolve){ + + // do the saving as async + + resolve(); + }); +}); +``` + +> You cannot export the additional table for the "fastupdate" feature. These table exists of references and when stored they fully get serialized and becomes too large. The lib will handle these automatically for you. When importing data, the index automatically disables "fastupdate". + +### Import + +Before you can import data, you need to create your index first. For document indexes provide the same document descriptor you used when export the data. This configuration isn't stored in the export. + +```js +var index = new Index({ ... }); +``` + +To import the data just pass a key and data: + +```js +index.import(key, localStorage.getItem(key)); +``` + +You need to import every key! Otherwise, your index does not work. You need to store the keys from the export and use this keys for the import (the order of the keys can differ). + +This is just for demonstration and is not recommended, because you might have other keys in your localStorage which aren't supported as an import: + +```js +var keys = Object.keys(localStorage); + +for(let i = 0, key; i < keys.length; i++){ + + key = keys[i]; + index.import(key, localStorage.getItem(key)); +} +``` + +## Languages + +Language-specific definitions are being divided into two groups: + +1. Charset + 1. ___encode___, type: `function(string):string[]` + 2. ___rtl___, type: `boolean` +2. Language + 1. ___matcher___, type: `{string: string}` + 2. ___stemmer___, type: `{string: string}` + 3. ___filter___, type: `string[]` + +The charset contains the encoding logic, the language contains stemmer, stopword filter and matchers. Multiple language definitions can use the same charset encoder. Also this separation let you manage different language definitions for special use cases (e.g. names, cities, dialects/slang, etc.). + +To fully describe a custom language __on the fly__ you need to pass: + +```js +const index = FlexSearch({ + // mandatory: + encode: (content) => [words], + // optionally: + rtl: false, + stemmer: {}, + matcher: {}, + filter: [] +}); +``` + +When passing no parameter it uses the `latin:default` schema by default. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldCategoryDescription
encodecharsetThe encoder function. Has to return an array of separated words (or an empty string).
rtlcharsetA boolean property which indicates right-to-left encoding.
filterlanguageFilter are also known as "stopwords", they completely filter out words from being indexed.
stemmerlanguageStemmer 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.
matcherlanguageMatcher replaces all occurrences of a given string regardless of its position and is also a kind of "partial normalization".
+ +### 1. Language Packs: ES6 Modules + +The most simple way to assign charset/language specific encoding via modules is: + +```js +import charset from "./dist/module/lang/latin/advanced.js"; +import lang from "./dist/module/lang/en.js"; + +const index = FlexSearch({ + charset: charset, + lang: lang +}); +``` + +Just import the __default export__ by each module and assign them accordingly. + +The full qualified example from above is: + +```js +import { encode, rtl } from "./dist/module/lang/latin/advanced.js"; +import { stemmer, filter, matcher } from "./dist/module/lang/en.js"; + +const index = FlexSearch({ + encode: encode, + rtl: rtl, + stemmer: stemmer, + matcher: matcher, + filter: filter +}); +``` + +The example above is the standard interface which is at least exported from each charset/language. + +You can also define the encoder directly and left all other options: + +```js +import simple from "./dist/module/lang/latin/simple.js"; + +const index = FlexSearch({ + encode: simple +}); +``` + +#### Available Latin Encoders + +1. default +2. simple +3. balance +4. advanced +5. extra + +You can assign a charset by passing the charset during initialization, e.g. `charset: "latin"` for the default charset encoder or `charset: "latin:soundex"` for a encoder variant. + +#### Dialect / Slang + +Language definitions (especially matchers) also could be used to normalize dialect and slang of a specific language. + +### 2. Language Packs: ES5 (Language Packs) + +You need to make the charset and/or language definitions available by: + +1. All charset definitions are included in the `flexsearch.bundle.js` build by default, but no language-specific definitions are included +2. You can load packages located in `/dist/lang/` (files refers to languages, folders are charsets) +3. You can make a custom build + +When loading language packs, make sure that the library was loaded before: + +```html + + + +``` + +When using the full "bundle" version the built-in latin encoders are already included and you just have to load the language file: + +```html + + +``` + +Because you loading packs as external packages (non-ES6-modules) you have to initialize them by shortcuts: + +```js +const index = FlexSearch({ + charset: "latin:soundex", + lang: "en" +}); +``` + +> Use the `charset:variant` notation to assign charset and its variants. When just passing the charset without a variant will automatically resolve as `charset:default`. + +You can also override existing definitions, e.g.: + +```js +const index = FlexSearch({ + charset: "latin", + lang: "en", + matcher: {} +}); +``` + +> Passed definitions will __not__ extend default definitions, they will replace them. + +When you like to extend a definition just create a new language file and put in all the logic. + +#### Encoder Variants + +It is pretty straight forward when using an encoder variant: + +```html + + + + +``` + +When using the full "bundle" version the built-in latin encoders are already included and you just have to load the language file: + +```html + + +``` + +```js +const index_advanced = FlexSearch({ + charset: "latin:advanced" +}); + +const index_extra = FlexSearch({ + charset: "latin:extra" +}); +``` + +### Partial Tokenizer + +In FlexSearch you can't provide your own partial tokenizer, because it is a direct dependency to the core unit. The built-in tokenizer of FlexSearch splits each word into fragments by different patterns: + +1. strict (supports contextual index) +2. forward +3. reverse (including forward) +4. full + +### Language Processing Pipeline + +This is the default pipeline provided by FlexSearch: + +

+ +

+ +#### Custom Pipeline + +At first take a look into the default pipeline in `src/common.js`. It is very simple and straight forward. The pipeline will process as some sort of inversion of control, the final encoder implementation has to handle charset and also language specific transformations. This workaround has left over from many tests. + +Inject the default pipeline by e.g.: + +```js +this.pipeline( + + /* string: */ str.toLowerCase(), + /* normalize: */ false, + /* split: */ split, + /* collapse: */ false +); +``` + +Use the pipeline schema from above to understand the iteration and the difference of pre-encoding and post-encoding. Stemmer and matchers needs to be applied after charset normalization but before language transformations, filters also. + +Here is a good example of extending pipelines: `src/lang/latin/extra.js` → `src/lang/latin/advanced.js` → `src/lang/latin/simple.js`. + +### How to contribute? + +Search for your language in `src/lang/`, if it exists you can extend or provide variants (like dialect/slang). If the language doesn't exist create a new file and check if any of the existing charsets (e.g. latin) fits to your language. When no charset exist, you need to provide a charset as a base for the language. + +A new charset should provide at least: + +1. `encode` A function which normalize the charset of a passed text content (remove special chars, lingual transformations, etc.) and __returns an array of separated words__. Also stemmer, matcher or stopword filter needs to be applied here. When the language has no words make sure to provide something similar, e.g. each chinese sign could also be a "word". Don't return the whole text content without split. +3. `rtl` A boolean flag which indicates right-to-left encoding + +Basically the charset needs just to provide an encoder function along with an indicator for right-to-left encoding: + +```js +export function encode(str){ return [str] } +export const rtl = false; +``` + + +## Encoder Matching Comparison + +> Reference String: __"Björn-Phillipp Mayer"__ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Querydefaultsimpleadvancedextra
björnyesyesyesyes
björyesyesyesyes
bjornnoyesyesyes
bjoernnonoyesyes
philippnonoyesyes
filipnonoyesyes
björnphillipnoyesyesyes
meiernonoyesyes
björn meiernonoyesyes
meier fhilipnonoyesyes
byorn mairnononoyes
(false positives)nononoyes
+ + +## Memory Allocation + +The book "Gulliver's Travels Swift Jonathan 1726" was fully indexed for the examples below. + +The most memory-optimized meaningful setting will allocate just 1.2 Mb for the whole book indexed! This is probably the most tiny memory footprint you will get from a search library. + +```js +import { encode } from "./lang/latin/extra.js"; + +index = new Index({ + encode: encode, + tokenize: "strict", + optimize: true, + resolution: 1, + minlength: 3, + fastupdate: false, + context: false +}); +``` + + +### Memory Consumption + +The book "Gulliver's Travels" (Swift Jonathan 1726) was completely indexed for this test: + +
+ + +### Compare Impact of Memory Allocation + +by default a lexical index is very small:
+`depth: 0, bidirectional: 0, resolution: 3, minlength: 0` => 2.1 Mb + +a higher resolution will increase the memory allocation:
+`depth: 0, bidirectional: 0, resolution: 9, minlength: 0` => 2.9 Mb + +using the contextual index will increase the memory allocation:
+`depth: 1, bidirectional: 0, resolution: 9, minlength: 0` => 12.5 Mb + +a higher contextual depth will increase the memory allocation:
+`depth: 2, bidirectional: 0, resolution: 9, minlength: 0` => 21.5 Mb + +a higher minlength will decrease memory allocation:
+`depth: 2, bidirectional: 0, resolution: 9, minlength: 3` => 19.0 Mb + +using bidirectional will decrease memory allocation:
+`depth: 2, bidirectional: 1, resolution: 9, minlength: 3` => 17.9 Mb + +enable the option "fastupdate" will increase memory allocation:
+`depth: 2, bidirectional: 1, resolution: 9, minlength: 3` => 6.3 Mb + +### Full Comparison Table + +Every search library is constantly in competition with these 4 properties: + +1. Memory Allocation +2. Performance +3. Matching Capabilities +4. Relevance Order (Scoring) + +FlexSearch provides you many parameters you can use to adjust the optimal balance for your specific use-case. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ModifierMemory Impact *Performance Impact **Matching Impact **Scoring Impact **
resolution+1 (per level)+1 (per level)0+2 (per level)
depth+4 (per level)-1 (per level)-10 + depth+10
minlength-2 (per level)+2 (per level)-3 (per level)+2 (per level)
bidirectional-20+3-1
fastupdate+1+10 (update, remove)00
optimize: true-7-10-3
encoder: "icase"0000
encoder: "simple"-2-1+20
encoder: "advanced"-3-2+40
encoder: "extra"-5-5+60
encoder: "soundex"-6-2+80
tokenize: "strict"0000
tokenize: "forward"+3-2+50
tokenize: "reverse"+5-4+70
tokenize: "full"+8-5+100
document index+3 (per field)-1 (per field)00
document tags+1 (per tag)-1 (per tag)00
store: true+5 (per document)000
store: [fields]+1 (per field)000
cache: true+10+1000
cache: 100+1+900
type of ids: number0000
type of ids: string+3-300
+* range from -10 to 10, lower is better (-10 => big decrease, 0 => unchanged, +10 => big increase)
+** range from -10 to 10, higher is better + + +## Presets + +1. `memory` (primary optimize for memory) +2. `performance` (primary optimize for performance) +3. `match` (primary optimize for matching) +4. `score` (primary optimize for scoring) +5. `default` (the default balanced profile) + +These profiles are covering standard use cases. It is recommended to apply custom configuration instead of using profiles to get the best out for your situation. Every profile could be optimized further to its specific task, e.g. extreme performance optimized configuration or extreme memory and so on. + +You can pass a preset during creation/initialization of the index. + + + +## Best Practices + +##### Use numeric IDs + +It is recommended to use numeric id values as reference when adding content to the index. The byte length of passed ids influences the memory consumption significantly. If this is not possible you should consider to use a index table and map the ids with indexes, this becomes important especially when using contextual indexes on a large amount of content. + +##### Split Complexity + +Whenever you can, try to divide content by categories and add them to its own index, e.g.: + +```js +var action = new FlexSearch(); +var adventure = new FlexSearch(); +var comedy = new FlexSearch(); +``` + +This way you can also provide different settings for each category. This is actually the fastest way to perform a fuzzy search. + +To make this workaround more extendable you can use a short helper: + +```js +var index = {}; + +function add(id, cat, content){ + (index[cat] || ( + index[cat] = new FlexSearch + )).add(id, content); +} + +function search(cat, query){ + return index[cat] ? + index[cat].search(query) : []; +} +``` + +Add content to the index: +```js +add(1, "action", "Movie Title"); +add(2, "adventure", "Movie Title"); +add(3, "comedy", "Movie Title"); +``` + +Perform queries: +```js +var results = search("action", "movie title"); // --> [1] +``` + +Split indexes by categories improves performance significantly. + +--- + +Copyright 2018-2023 Thomas Wilkerling, Hosted by Nextapps GmbH
+Released under the Apache 2.0 License
diff --git a/paige/node_modules/flexsearch/dist/flexsearch.bundle.debug.js b/paige/node_modules/flexsearch/dist/flexsearch.bundle.debug.js new file mode 100644 index 00000000..0fd840d9 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/flexsearch.bundle.debug.js @@ -0,0 +1,978 @@ +/**! + * FlexSearch.js v0.7.41 (Bundle) + * Author and Copyright: Thomas Wilkerling + * Licence: Apache-2.0 + * Hosted by Nextapps GmbH + * https://github.com/nextapps-de/flexsearch + */ +(function _f(self){'use strict';try{if(module)self=module}catch(e){}self._factory=_f; +var t; +function u(a) { + return "undefined" !== typeof a ? a : !0; +} +function v(a) { + const b = Array(a); + for (let c = 0; c < a; c++) { + b[c] = x(); + } + return b; +} +function x() { + return Object.create(null); +} +function aa(a, b) { + return b.length - a.length; +} +function C(a) { + return "string" === typeof a; +} +function D(a) { + return "object" === typeof a; +} +function E(a) { + return "function" === typeof a; +} +;function ba(a, b) { + var c = ca; + if (a && (b && (a = F(a, b)), this.H && (a = F(a, this.H)), this.J && 1 < a.length && (a = F(a, this.J)), c || "" === c)) { + b = a.split(c); + if (this.filter) { + a = this.filter; + c = b.length; + const d = []; + for (let e = 0, f = 0; e < c; e++) { + const h = b[e]; + h && !a[h] && (d[f++] = h); + } + a = d; + } else { + a = b; + } + return a; + } + return a; +} +const ca = /[\p{Z}\p{S}\p{P}\p{C}]+/u, da = /[\u0300-\u036f]/g; +function ea(a, b) { + const c = Object.keys(a), d = c.length, e = []; + let f = "", h = 0; + for (let g = 0, k, m; g < d; g++) { + k = c[g], (m = a[k]) ? (e[h++] = G(b ? "(?!\\b)" + k + "(\\b|_)" : k), e[h++] = m) : f += (f ? "|" : "") + k; + } + f && (e[h++] = G(b ? "(?!\\b)(" + f + ")(\\b|_)" : "(" + f + ")"), e[h] = ""); + return e; +} +function F(a, b) { + for (let c = 0, d = b.length; c < d && (a = a.replace(b[c], b[c + 1]), a); c += 2) { + } + return a; +} +function G(a) { + return new RegExp(a, "g"); +} +function fa(a) { + let b = "", c = ""; + for (let d = 0, e = a.length, f; d < e; d++) { + (f = a[d]) !== c && (b += c = f); + } + return b; +} +;var ia = {encode:ha, F:!1, G:""}; +function ha(a) { + return ba.call(this, ("" + a).toLowerCase(), !1); +} +;const ja = {}, I = {}; +function ka(a) { + J(a, "add"); + J(a, "append"); + J(a, "search"); + J(a, "update"); + J(a, "remove"); +} +function J(a, b) { + a[b + "Async"] = function() { + const c = this, d = arguments; + var e = d[d.length - 1]; + let f; + E(e) && (f = e, delete d[d.length - 1]); + e = new Promise(function(h) { + setTimeout(function() { + c.async = !0; + const g = c[b].apply(c, d); + c.async = !1; + h(g); + }); + }); + return f ? (e.then(f), this) : e; + }; +} +;function la(a, b, c, d) { + const e = a.length; + let f = [], h, g, k = 0; + d && (d = []); + for (let m = e - 1; 0 <= m; m--) { + const n = a[m], w = n.length, q = x(); + let r = !h; + for (let l = 0; l < w; l++) { + const p = n[l], A = p.length; + if (A) { + for (let B = 0, z, y; B < A; B++) { + if (y = p[B], h) { + if (h[y]) { + if (!m) { + if (c) { + c--; + } else { + if (f[k++] = y, k === b) { + return f; + } + } + } + if (m || d) { + q[y] = 1; + } + r = !0; + } + if (d && (z = (g[y] || 0) + 1, g[y] = z, z < e)) { + const H = d[z - 2] || (d[z - 2] = []); + H[H.length] = y; + } + } else { + q[y] = 1; + } + } + } + } + if (d) { + h || (g = q); + } else if (!r) { + return []; + } + h = q; + } + if (d) { + for (let m = d.length - 1, n, w; 0 <= m; m--) { + n = d[m]; + w = n.length; + for (let q = 0, r; q < w; q++) { + if (r = n[q], !h[r]) { + if (c) { + c--; + } else { + if (f[k++] = r, k === b) { + return f; + } + } + h[r] = 1; + } + } + } + } + return f; +} +function ma(a, b) { + const c = x(), d = x(), e = []; + for (let f = 0; f < a.length; f++) { + c[a[f]] = 1; + } + for (let f = 0, h; f < b.length; f++) { + h = b[f]; + for (let g = 0, k; g < h.length; g++) { + k = h[g], c[k] && !d[k] && (d[k] = 1, e[e.length] = k); + } + } + return e; +} +;function K(a) { + this.l = !0 !== a && a; + this.cache = x(); + this.h = []; +} +function na(a, b, c) { + D(a) && (a = a.query); + let d = this.cache.get(a); + d || (d = this.search(a, b, c), this.cache.set(a, d)); + return d; +} +K.prototype.set = function(a, b) { + if (!this.cache[a]) { + var c = this.h.length; + c === this.l ? delete this.cache[this.h[c - 1]] : c++; + for (--c; 0 < c; c--) { + this.h[c] = this.h[c - 1]; + } + this.h[0] = a; + } + this.cache[a] = b; +}; +K.prototype.get = function(a) { + const b = this.cache[a]; + if (this.l && b && (a = this.h.indexOf(a))) { + const c = this.h[a - 1]; + this.h[a - 1] = this.h[a]; + this.h[a] = c; + } + return b; +}; +const oa = {memory:{charset:"latin:extra", D:3, B:4, m:!1}, performance:{D:3, B:3, s:!1, context:{depth:2, D:1}}, match:{charset:"latin:extra", G:"reverse"}, score:{charset:"latin:advanced", D:20, B:3, context:{depth:3, D:9}}, "default":{}}; +function qa(a, b, c, d, e, f, h, g) { + setTimeout(function() { + const k = a(c ? c + "." + d : d, JSON.stringify(h)); + k && k.then ? k.then(function() { + b.export(a, b, c, e, f + 1, g); + }) : b.export(a, b, c, e, f + 1, g); + }); +} +;function L(a, b) { + if (!(this instanceof L)) { + return new L(a); + } + var c; + if (a) { + if (C(a)) { + oa[a] || console.warn("Preset not found: " + a), a = oa[a]; + } else { + if (c = a.preset) { + c[c] || console.warn("Preset not found: " + c), a = Object.assign({}, c[c], a); + } + } + c = a.charset; + var d = a.lang; + C(c) && (-1 === c.indexOf(":") && (c += ":default"), c = I[c]); + C(d) && (d = ja[d]); + } else { + a = {}; + } + let e, f, h = a.context || {}; + this.encode = a.encode || c && c.encode || ha; + this.register = b || x(); + this.D = e = a.resolution || 9; + this.G = b = c && c.G || a.tokenize || "strict"; + this.depth = "strict" === b && h.depth; + this.l = u(h.bidirectional); + this.s = f = u(a.optimize); + this.m = u(a.fastupdate); + this.B = a.minlength || 1; + this.C = a.boost; + this.map = f ? v(e) : x(); + this.A = e = h.resolution || 1; + this.h = f ? v(e) : x(); + this.F = c && c.F || a.rtl; + this.H = (b = a.matcher || d && d.H) && ea(b, !1); + this.J = (b = a.stemmer || d && d.J) && ea(b, !0); + if (c = b = a.filter || d && d.filter) { + c = b; + d = x(); + for (let g = 0, k = c.length; g < k; g++) { + d[c[g]] = 1; + } + c = d; + } + this.filter = c; + this.cache = (b = a.cache) && new K(b); +} +t = L.prototype; +t.append = function(a, b) { + return this.add(a, b, !0); +}; +t.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); + if (d = b.length) { + const m = x(), n = x(), w = this.depth, q = this.D; + for (let r = 0; r < d; r++) { + let l = b[this.F ? d - 1 - r : r]; + var e = l.length; + if (l && e >= this.B && (w || !n[l])) { + var f = M(q, d, r), h = ""; + switch(this.G) { + case "full": + if (2 < e) { + for (f = 0; f < e; f++) { + for (var g = e; g > f; g--) { + if (g - f >= this.B) { + var k = M(q, d, r, e, f); + h = l.substring(f, g); + N(this, n, h, k, a, c); + } + } + } + break; + } + case "reverse": + if (1 < e) { + for (g = e - 1; 0 < g; g--) { + h = l[g] + h, h.length >= this.B && N(this, n, h, M(q, d, r, e, g), a, c); + } + h = ""; + } + case "forward": + if (1 < e) { + for (g = 0; g < e; g++) { + h += l[g], h.length >= this.B && N(this, n, h, f, a, c); + } + break; + } + default: + if (this.C && (f = Math.min(f / this.C(b, l, r) | 0, q - 1)), N(this, n, l, f, a, c), w && 1 < d && r < d - 1) { + for (e = x(), h = this.A, f = l, g = Math.min(w + 1, d - r), e[f] = 1, k = 1; k < g; k++) { + if ((l = b[this.F ? d - 1 - r - k : r + k]) && l.length >= this.B && !e[l]) { + e[l] = 1; + const p = this.l && l > f; + N(this, m, p ? f : l, M(h + (d / 2 > h ? 0 : 1), d, r, g - 1, k - 1), a, c, p ? l : f); + } + } + } + } + } + } + this.m || (this.register[a] = 1); + } + } + return this; +}; +function M(a, b, c, d, e) { + return c && 1 < a ? b + (d || 0) <= a ? c + (e || 0) : (a - 1) / (b + (d || 0)) * (c + (e || 0)) + 1 | 0 : 0; +} +function N(a, b, c, d, e, f, h) { + let g = h ? a.h : a.map; + if (!b[c] || h && !b[c][h]) { + a.s && (g = g[d]), h ? (b = b[c] || (b[c] = x()), b[h] = 1, g = g[h] || (g[h] = x())) : b[c] = 1, g = g[c] || (g[c] = []), a.s || (g = g[d] || (g[d] = [])), f && g.includes(e) || (g[g.length] = e, a.m && (a = a.register[e] || (a.register[e] = []), a[a.length] = g)); + } +} +t.search = function(a, b, c) { + c || (!b && D(a) ? (c = a, a = c.query) : D(b) && (c = b)); + let d = [], e; + let f, h = 0; + if (c) { + a = c.query || a; + b = c.limit; + h = c.offset || 0; + var g = c.context; + f = c.suggest; + } + if (a && (a = this.encode("" + a), e = a.length, 1 < e)) { + c = x(); + var k = []; + for (let n = 0, w = 0, q; n < e; n++) { + if ((q = a[n]) && q.length >= this.B && !c[q]) { + if (this.s || f || this.map[q]) { + k[w++] = q, c[q] = 1; + } else { + return d; + } + } + } + a = k; + e = a.length; + } + if (!e) { + return d; + } + b || (b = 100); + g = this.depth && 1 < e && !1 !== g; + c = 0; + let m; + g ? (m = a[0], c = 1) : 1 < e && a.sort(aa); + for (let n, w; c < e; c++) { + w = a[c]; + g ? (n = ra(this, d, f, b, h, 2 === e, w, m), f && !1 === n && d.length || (m = w)) : n = ra(this, d, f, b, h, 1 === e, w); + if (n) { + return n; + } + if (f && c === e - 1) { + k = d.length; + if (!k) { + if (g) { + g = 0; + c = -1; + continue; + } + return d; + } + if (1 === k) { + return sa(d[0], b, h); + } + } + } + return la(d, b, h, f); +}; +function ra(a, b, c, d, e, f, h, g) { + let k = [], m = g ? a.h : a.map; + a.s || (m = ta(m, h, g, a.l)); + if (m) { + let n = 0; + const w = Math.min(m.length, g ? a.A : a.D); + for (let q = 0, r = 0, l, p; q < w; q++) { + if (l = m[q]) { + if (a.s && (l = ta(l, h, g, a.l)), e && l && f && (p = l.length, p <= e ? (e -= p, l = null) : (l = l.slice(e), e = 0)), l && (k[n++] = l, f && (r += l.length, r >= d))) { + break; + } + } + } + if (n) { + if (f) { + return sa(k, d, 0); + } + b[b.length] = k; + return; + } + } + return !c && k; +} +function sa(a, b, c) { + a = 1 === a.length ? a[0] : [].concat.apply([], a); + return c || a.length > b ? a.slice(c, c + b) : a; +} +function ta(a, b, c, d) { + c ? (d = d && b > c, a = (a = a[d ? b : c]) && a[d ? c : b]) : a = a[b]; + return a; +} +t.contain = function(a) { + return !!this.register[a]; +}; +t.update = function(a, b) { + return this.remove(a).add(a, b); +}; +t.remove = function(a, b) { + const c = this.register[a]; + if (c) { + if (this.m) { + for (let d = 0, e; d < c.length; d++) { + e = c[d], e.splice(e.indexOf(a), 1); + } + } else { + O(this.map, a, this.D, this.s), this.depth && O(this.h, a, this.A, this.s); + } + b || delete this.register[a]; + if (this.cache) { + b = this.cache; + for (let d = 0, e, f; d < b.h.length; d++) { + f = b.h[d], e = b.cache[f], e.includes(a) && (b.h.splice(d--, 1), delete b.cache[f]); + } + } + } + return this; +}; +function O(a, b, c, d, e) { + let f = 0; + if (a.constructor === Array) { + if (e) { + b = a.indexOf(b), -1 !== b ? 1 < a.length && (a.splice(b, 1), f++) : f++; + } else { + e = Math.min(a.length, c); + for (let h = 0, g; h < e; h++) { + if (g = a[h]) { + f = O(g, b, c, d, e), d || f || delete a[h]; + } + } + } + } else { + for (let h in a) { + (f = O(a[h], b, c, d, e)) || delete a[h]; + } + } + return f; +} +t.searchCache = na; +t.export = function(a, b, c, d, e, f) { + let h = !0; + "undefined" === typeof f && (h = new Promise(m => { + f = m; + })); + let g, k; + switch(e || (e = 0)) { + case 0: + g = "reg"; + if (this.m) { + k = x(); + for (let m in this.register) { + k[m] = 1; + } + } else { + k = this.register; + } + break; + case 1: + g = "cfg"; + k = {doc:0, opt:this.s ? 1 : 0}; + break; + case 2: + g = "map"; + k = this.map; + break; + case 3: + g = "ctx"; + k = this.h; + break; + default: + "undefined" === typeof c && f && f(); + return; + } + qa(a, b || this, c, g, d, e, k, f); + return h; +}; +t.import = function(a, b) { + if (b) { + switch(C(b) && (b = JSON.parse(b)), a) { + case "cfg": + this.s = !!b.opt; + break; + case "reg": + this.m = !1; + this.register = b; + break; + case "map": + this.map = b; + break; + case "ctx": + this.h = b; + } + } +}; +ka(L.prototype); +function ua(a) { + a = a.data; + var b = self._index; + const c = a.args; + var d = a.task; + switch(d) { + case "init": + d = a.options || {}; + a = a.factory; + b = d.encode; + d.cache = !1; + b && 0 === b.indexOf("function") && (d.encode = Function("return " + b)()); + a ? (Function("return " + a)()(self), self._index = new self.FlexSearch.Index(d), delete self.FlexSearch) : self._index = new L(d); + break; + default: + a = a.id, b = b[d].apply(b, c), postMessage("search" === d ? {id:a, msg:b} : {id:a}); + } +} +;let va = 0; +function P(a) { + if (!(this instanceof P)) { + return new P(a); + } + var b; + a ? E(b = a.encode) && (a.encode = b.toString()) : a = {}; + (b = (self || window)._factory) && (b = b.toString()); + const c = "undefined" === typeof window && self.exports, d = this; + this.o = wa(b, c, a.worker); + this.h = x(); + if (this.o) { + if (c) { + this.o.on("message", function(e) { + d.h[e.id](e.msg); + delete d.h[e.id]; + }); + } else { + this.o.onmessage = function(e) { + e = e.data; + d.h[e.id](e.msg); + delete d.h[e.id]; + }; + } + this.o.postMessage({task:"init", factory:b, options:a}); + } +} +Q("add"); +Q("append"); +Q("search"); +Q("update"); +Q("remove"); +function Q(a) { + P.prototype[a] = P.prototype[a + "Async"] = function() { + const b = this, c = [].slice.call(arguments); + var d = c[c.length - 1]; + let e; + E(d) && (e = d, c.splice(c.length - 1, 1)); + d = new Promise(function(f) { + setTimeout(function() { + b.h[++va] = f; + b.o.postMessage({task:a, id:va, args:c}); + }); + }); + return e ? (d.then(e), this) : d; + }; +} +function wa(a, b, c) { + let d; + try { + d = b ? new (require("worker_threads")["Worker"])(__dirname + "/node/node.js") : a ? new Worker(URL.createObjectURL(new Blob(["onmessage=" + ua.toString()], {type:"text/javascript"}))) : new Worker(C(c) ? c : "worker/worker.js", {type:"module"}); + } catch (e) { + } + return d; +} +;function S(a) { + if (!(this instanceof S)) { + return new S(a); + } + var b = a.document || a.doc || a, c; + this.K = []; + this.h = []; + this.A = []; + this.register = x(); + this.key = (c = b.key || b.id) && T(c, this.A) || "id"; + this.m = u(a.fastupdate); + this.C = (c = b.store) && !0 !== c && []; + this.store = c && x(); + this.I = (c = b.tag) && T(c, this.A); + this.l = c && x(); + this.cache = (c = a.cache) && new K(c); + a.cache = !1; + this.o = a.worker; + this.async = !1; + c = x(); + let d = b.index || b.field || b; + C(d) && (d = [d]); + for (let e = 0, f, h; e < d.length; e++) { + f = d[e], C(f) || (h = f, f = f.field), h = D(h) ? Object.assign({}, a, h) : a, this.o && (c[f] = new P(h), c[f].o || (this.o = !1)), this.o || (c[f] = new L(h, this.register)), this.K[e] = T(f, this.A), this.h[e] = f; + } + if (this.C) { + for (a = b.store, C(a) && (a = [a]), b = 0; b < a.length; b++) { + this.C[b] = T(a[b], this.A); + } + } + this.index = c; +} +function T(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)) && (b[d] = !0), a && (c[d++] = a); + } + d < c.length && (c.length = d); + return 1 < d ? c : c[0]; +} +function U(a, b) { + if (C(b)) { + a = a[b]; + } else { + for (let c = 0; a && c < b.length; c++) { + a = a[b[c]]; + } + } + return a; +} +function V(a, b, c, d, e) { + a = a[e]; + if (d === c.length - 1) { + b[e] = a; + } else if (a) { + if (a.constructor === Array) { + for (b = b[e] = Array(a.length), e = 0; e < a.length; e++) { + V(a, b, c, d, e); + } + } else { + b = b[e] || (b[e] = x()), e = c[++d], V(a, b, c, d, e); + } + } +} +function X(a, b, c, d, e, f, h, g) { + if (a = a[h]) { + if (d === b.length - 1) { + if (a.constructor === Array) { + if (c[d]) { + for (b = 0; b < a.length; b++) { + e.add(f, a[b], !0, !0); + } + return; + } + a = a.join(" "); + } + e.add(f, a, g, !0); + } else { + if (a.constructor === Array) { + for (h = 0; h < a.length; h++) { + X(a, b, c, d, e, f, h, g); + } + } else { + h = b[++d], X(a, b, c, d, e, f, h, g); + } + } + } +} +t = S.prototype; +t.add = function(a, b, c) { + D(a) && (b = a, a = U(b, this.key)); + if (b && (a || 0 === a)) { + if (!c && this.register[a]) { + return this.update(a, b); + } + for (let d = 0, e, f; d < this.h.length; d++) { + f = this.h[d], e = this.K[d], C(e) && (e = [e]), X(b, e, this.A, 0, this.index[f], a, e[0], c); + } + if (this.I) { + let d = U(b, this.I), e = x(); + C(d) && (d = [d]); + for (let f = 0, h, g; f < d.length; f++) { + if (h = d[f], !e[h] && (e[h] = 1, g = this.l[h] || (this.l[h] = []), !c || !g.includes(a))) { + if (g[g.length] = a, this.m) { + const k = this.register[a] || (this.register[a] = []); + k[k.length] = g; + } + } + } + } + if (this.store && (!c || !this.store[a])) { + let d; + if (this.C) { + d = x(); + for (let e = 0, f; e < this.C.length; e++) { + f = this.C[e], C(f) ? d[f] = b[f] : V(b, d, f, 0, f[0]); + } + } + this.store[a] = d || b; + } + } + return this; +}; +t.append = function(a, b) { + return this.add(a, b, !0); +}; +t.update = function(a, b) { + return this.remove(a).add(a, b); +}; +t.remove = function(a) { + D(a) && (a = U(a, this.key)); + if (this.register[a]) { + for (var b = 0; b < this.h.length && (this.index[this.h[b]].remove(a, !this.o), !this.m); b++) { + } + if (this.I && !this.m) { + for (let c in this.l) { + b = this.l[c]; + const d = b.indexOf(a); + -1 !== d && (1 < b.length ? b.splice(d, 1) : delete this.l[c]); + } + } + this.store && delete this.store[a]; + delete this.register[a]; + } + return this; +}; +t.search = function(a, b, c, d) { + c || (!b && D(a) ? (c = a, a = "") : D(b) && (c = b, b = 0)); + let e = [], f = [], h, g, k, m, n, w, q = 0; + if (c) { + if (c.constructor === Array) { + k = c, c = null; + } else { + a = c.query || a; + k = (h = c.pluck) || c.index || c.field; + m = c.tag; + g = this.store && c.enrich; + n = "and" === c.bool; + b = c.limit || b || 100; + w = c.offset || 0; + if (m && (C(m) && (m = [m]), !a)) { + for (let l = 0, p; l < m.length; l++) { + if (p = xa.call(this, m[l], b, w, g)) { + e[e.length] = p, q++; + } + } + return q ? e : []; + } + C(k) && (k = [k]); + } + } + k || (k = this.h); + n = n && (1 < k.length || m && 1 < m.length); + const r = !d && (this.o || this.async) && []; + for (let l = 0, p, A, B; l < k.length; l++) { + let z; + A = k[l]; + C(A) || (z = A, A = z.field, a = z.query || a, b = z.limit || b, g = z.enrich || g); + if (r) { + r[l] = this.index[A].searchAsync(a, b, z || c); + } else { + d ? p = d[l] : p = this.index[A].search(a, b, z || c); + B = p && p.length; + if (m && B) { + const y = []; + let H = 0; + n && (y[0] = [p]); + for (let W = 0, pa, R; W < m.length; W++) { + if (pa = m[W], B = (R = this.l[pa]) && R.length) { + H++, y[y.length] = n ? [R] : R; + } + } + H && (p = n ? la(y, b || 100, w || 0) : ma(p, y), B = p.length); + } + if (B) { + f[q] = A, e[q++] = p; + } else if (n) { + return []; + } + } + } + if (r) { + const l = this; + return new Promise(function(p) { + Promise.all(r).then(function(A) { + p(l.search(a, b, c, A)); + }); + }); + } + if (!q) { + return []; + } + if (h && (!g || !this.store)) { + return e[0]; + } + for (let l = 0, p; l < f.length; l++) { + p = e[l]; + p.length && g && (p = ya.call(this, p)); + if (h) { + return p; + } + e[l] = {field:f[l], result:p}; + } + return e; +}; +function xa(a, b, c, d) { + let e = this.l[a], f = e && e.length - c; + if (f && 0 < f) { + if (f > b || c) { + e = e.slice(c, c + b); + } + d && (e = ya.call(this, e)); + return {tag:a, result:e}; + } +} +function ya(a) { + const b = Array(a.length); + for (let c = 0, d; c < a.length; c++) { + d = a[c], b[c] = {id:d, doc:this.store[d]}; + } + return b; +} +t.contain = function(a) { + return !!this.register[a]; +}; +t.get = function(a) { + return this.store[a]; +}; +t.set = function(a, b) { + this.store[a] = b; + return this; +}; +t.searchCache = na; +t.export = function(a, b, c, d, e, f) { + let h; + "undefined" === typeof f && (h = new Promise(g => { + f = g; + })); + e || (e = 0); + d || (d = 0); + if (d < this.h.length) { + const g = this.h[d], k = this.index[g]; + b = this; + setTimeout(function() { + k.export(a, b, e ? g : "", d, e++, f) || (d++, e = 1, b.export(a, b, g, d, e, f)); + }); + } else { + let g, k; + switch(e) { + case 1: + g = "tag"; + k = this.l; + c = null; + break; + case 2: + g = "store"; + k = this.store; + c = null; + break; + default: + f(); + return; + } + qa(a, this, c, g, d, e, k, f); + } + return h; +}; +t.import = function(a, b) { + if (b) { + switch(C(b) && (b = JSON.parse(b)), a) { + case "tag": + this.l = b; + break; + case "reg": + this.m = !1; + this.register = b; + for (let d = 0, e; d < this.h.length; d++) { + e = this.index[this.h[d]], e.register = b, e.m = !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); + } + } +}; +ka(S.prototype); +var Aa = {encode:za, F:!1, G:""}; +const Ba = [G("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), "a", G("[\u00e8\u00e9\u00ea\u00eb]"), "e", G("[\u00ec\u00ed\u00ee\u00ef]"), "i", G("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), "o", G("[\u00f9\u00fa\u00fb\u00fc\u0171]"), "u", G("[\u00fd\u0177\u00ff]"), "y", G("\u00f1"), "n", G("[\u00e7c]"), "k", G("\u00df"), "s", G(" & "), " and "]; +function za(a) { + var b = a = "" + a; + b.normalize && (b = b.normalize("NFD").replace(da, "")); + return ba.call(this, b.toLowerCase(), !a.normalize && Ba); +} +;var Da = {encode:Ca, F:!1, G:"strict"}; +const Ea = /[^a-z0-9]+/, Fa = {b:"p", v:"f", w:"f", z:"s", x:"s", "\u00df":"s", d:"t", n:"m", c:"k", g:"k", j:"k", q:"k", i:"e", y:"e", u:"o"}; +function Ca(a) { + a = za.call(this, a).join(" "); + const b = []; + if (a) { + const c = a.split(Ea), d = c.length; + for (let e = 0, f, h = 0; e < d; e++) { + if ((a = c[e]) && (!this.filter || !this.filter[a])) { + f = a[0]; + let g = Fa[f] || f, k = g; + for (let m = 1; m < a.length; m++) { + f = a[m]; + const n = Fa[f] || f; + n && n !== k && (g += n, k = n); + } + b[h++] = g; + } + } + } + return b; +} +;var Ha = {encode:Ga, F:!1, G:""}; +const Ia = [G("ae"), "a", G("oe"), "o", G("sh"), "s", G("th"), "t", G("ph"), "f", G("pf"), "f", G("(?![aeo])h(?![aeo])"), "", G("(?!^[aeo])h(?!^[aeo])"), ""]; +function Ga(a, b) { + a && (a = Ca.call(this, a).join(" "), 2 < a.length && (a = F(a, Ia)), b || (1 < a.length && (a = fa(a)), a && (a = a.split(" ")))); + return a || []; +} +;var Ka = {encode:Ja, F:!1, G:""}; +const La = G("(?!\\b)[aeo]"); +function Ja(a) { + a && (a = Ga.call(this, a, !0), 1 < a.length && (a = a.replace(La, "")), 1 < a.length && (a = fa(a)), a && (a = a.split(" "))); + return a || []; +} +;I["latin:default"] = ia; +I["latin:simple"] = Aa; +I["latin:balance"] = Da; +I["latin:advanced"] = Ha; +I["latin:extra"] = Ka; +const Y = {Index:L, Document:S, Worker:P, registerCharset:function(a, b) { + I[a] = b; +}, registerLanguage:function(a, b) { + ja[a] = b; +}}; +let Z; +(Z = self.define) && Z.amd ? Z([], function() { + return Y; +}) : self.exports ? self.exports = Y : self.FlexSearch = Y; +}(this)); diff --git a/paige/node_modules/flexsearch/dist/flexsearch.bundle.min.js b/paige/node_modules/flexsearch/dist/flexsearch.bundle.min.js new file mode 100644 index 00000000..aba4476d --- /dev/null +++ b/paige/node_modules/flexsearch/dist/flexsearch.bundle.min.js @@ -0,0 +1,34 @@ +/**! + * FlexSearch.js v0.7.41 (Bundle) + * Author and Copyright: Thomas Wilkerling + * Licence: Apache-2.0 + * Hosted by Nextapps GmbH + * https://github.com/nextapps-de/flexsearch + */ +(function _f(self){'use strict';try{if(module)self=module}catch(e){}self._factory=_f;var t;function u(a){return"undefined"!==typeof a?a:!0}function v(a){const b=Array(a);for(let c=0;c=this.B&&(w||!n[l])){var f=M(q,d,r),h="";switch(this.G){case "full":if(2f;g--)if(g-f>=this.B){var k=M(q,d,r,e,f);h=l.substring(f,g);N(this,n,h,k,a,c)}break}case "reverse":if(1=this.B&&N(this,n, +h,M(q,d,r,e,g),a,c);h=""}case "forward":if(1=this.B&&N(this,n,h,f,a,c);break}default:if(this.C&&(f=Math.min(f/this.C(b,l,r)|0,q-1)),N(this,n,l,f,a,c),w&&1=this.B&&!e[l]){e[l]=1;const p=this.l&&l>f;N(this,m,p?f:l,M(h+(d/2>h?0:1),d,r,g-1,k-1),a,c,p?l:f)}}}}this.m||(this.register[a]=1)}}return this}; +function M(a,b,c,d,e){return c&&1=this.B&&!c[q])if(this.s||f||this.map[q])k[w++]=q,c[q]=1;else return d;a=k;e=a.length}if(!e)return d;b||(b=100);g=this.depth&&1=d)))break;if(n){if(f)return sa(k,d,0);b[b.length]=k;return}}return!c&&k}function sa(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} +function ta(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a}t.contain=function(a){return!!this.register[a]};t.update=function(a,b){return this.remove(a).add(a,b)}; +t.remove=function(a,b){const c=this.register[a];if(c){if(this.m)for(let d=0,e;d{f=m}));let g,k;switch(e||(e=0)){case 0:g="reg";if(this.m){k=x();for(let m in this.register)k[m]=1}else k=this.register;break;case 1:g="cfg";k={doc:0,opt:this.s?1:0};break;case 2:g="map";k=this.map;break;case 3:g="ctx";k=this.h;break;default:"undefined"===typeof c&&f&&f();return}qa(a,b||this,c,g,d,e,k,f);return h}; +t.import=function(a,b){if(b)switch(C(b)&&(b=JSON.parse(b)),a){case "cfg":this.s=!!b.opt;break;case "reg":this.m=!1;this.register=b;break;case "map":this.map=b;break;case "ctx":this.h=b}};ka(L.prototype);function ua(a){a=a.data;var b=self._index;const c=a.args;var d=a.task;switch(d){case "init":d=a.options||{};a=a.factory;b=d.encode;d.cache=!1;b&&0===b.indexOf("function")&&(d.encode=Function("return "+b)());a?(Function("return "+a)()(self),self._index=new self.FlexSearch.Index(d),delete self.FlexSearch):self._index=new L(d);break;default:a=a.id,b=b[d].apply(b,c),postMessage("search"===d?{id:a,msg:b}:{id:a})}};let va=0;function P(a){if(!(this instanceof P))return new P(a);var b;a?E(b=a.encode)&&(a.encode=b.toString()):a={};(b=(self||window)._factory)&&(b=b.toString());const c="undefined"===typeof window&&self.exports,d=this;this.o=wa(b,c,a.worker);this.h=x();if(this.o){if(c)this.o.on("message",function(e){d.h[e.id](e.msg);delete d.h[e.id]});else this.o.onmessage=function(e){e=e.data;d.h[e.id](e.msg);delete d.h[e.id]};this.o.postMessage({task:"init",factory:b,options:a})}}Q("add");Q("append");Q("search"); +Q("update");Q("remove");function Q(a){P.prototype[a]=P.prototype[a+"Async"]=function(){const b=this,c=[].slice.call(arguments);var d=c[c.length-1];let e;E(d)&&(e=d,c.splice(c.length-1,1));d=new Promise(function(f){setTimeout(function(){b.h[++va]=f;b.o.postMessage({task:a,id:va,args:c})})});return e?(d.then(e),this):d}} +function wa(a,b,c){let d;try{d=b?new (require("worker_threads")["Worker"])(__dirname + "/node/node.js"):a?new Worker(URL.createObjectURL(new Blob(["onmessage="+ua.toString()],{type:"text/javascript"}))):new Worker(C(c)?c:"worker/worker.js",{type:"module"})}catch(e){}return d};function S(a){if(!(this instanceof S))return new S(a);var b=a.document||a.doc||a,c;this.K=[];this.h=[];this.A=[];this.register=x();this.key=(c=b.key||b.id)&&T(c,this.A)||"id";this.m=u(a.fastupdate);this.C=(c=b.store)&&!0!==c&&[];this.store=c&&x();this.I=(c=b.tag)&&T(c,this.A);this.l=c&&x();this.cache=(c=a.cache)&&new K(c);a.cache=!1;this.o=a.worker;this.async=!1;c=x();let d=b.index||b.field||b;C(d)&&(d=[d]);for(let e=0,f,h;eb||c)e=e.slice(c,c+b);d&&(e=ya.call(this,e));return{tag:a,result:e}}}function ya(a){const b=Array(a.length);for(let c=0,d;c{f=g}));e||(e=0);d||(d=0);if(d= this.B && (w || !n[l])) { + var f = O(q, d, r), h = ""; + switch(this.G) { + case "full": + if (2 < e) { + for (f = 0; f < e; f++) { + for (var g = e; g > f; g--) { + if (g - f >= this.B) { + var k = O(q, d, r, e, f); + h = l.substring(f, g); + P(this, n, h, k, a, c); + } + } + } + break; + } + case "reverse": + if (1 < e) { + for (g = e - 1; 0 < g; g--) { + h = l[g] + h, h.length >= this.B && P(this, n, h, O(q, d, r, e, g), a, c); + } + h = ""; + } + case "forward": + if (1 < e) { + for (g = 0; g < e; g++) { + h += l[g], h.length >= this.B && P(this, n, h, f, a, c); + } + break; + } + default: + if (this.C && (f = Math.min(f / this.C(b, l, r) | 0, q - 1)), P(this, n, l, f, a, c), w && 1 < d && r < d - 1) { + for (e = x(), h = this.A, f = l, g = Math.min(w + 1, d - r), e[f] = 1, k = 1; k < g; k++) { + if ((l = b[this.F ? d - 1 - r - k : r + k]) && l.length >= this.B && !e[l]) { + e[l] = 1; + const p = this.l && l > f; + P(this, m, p ? f : l, O(h + (d / 2 > h ? 0 : 1), d, r, g - 1, k - 1), a, c, p ? l : f); + } + } + } + } + } + } + this.m || (this.register[a] = 1); + } + } + return this; +}; +function O(a, b, c, d, e) { + return c && 1 < a ? b + (d || 0) <= a ? c + (e || 0) : (a - 1) / (b + (d || 0)) * (c + (e || 0)) + 1 | 0 : 0; +} +function P(a, b, c, d, e, f, h) { + let g = h ? a.h : a.map; + if (!b[c] || h && !b[c][h]) { + a.s && (g = g[d]), h ? (b = b[c] || (b[c] = x()), b[h] = 1, g = g[h] || (g[h] = x())) : b[c] = 1, g = g[c] || (g[c] = []), a.s || (g = g[d] || (g[d] = [])), f && g.includes(e) || (g[g.length] = e, a.m && (a = a.register[e] || (a.register[e] = []), a[a.length] = g)); + } +} +t.search = function(a, b, c) { + c || (!b && D(a) ? (c = a, a = c.query) : D(b) && (c = b)); + let d = [], e; + let f, h = 0; + if (c) { + a = c.query || a; + b = c.limit; + h = c.offset || 0; + var g = c.context; + f = c.suggest; + } + if (a && (a = this.encode("" + a), e = a.length, 1 < e)) { + c = x(); + var k = []; + for (let n = 0, w = 0, q; n < e; n++) { + if ((q = a[n]) && q.length >= this.B && !c[q]) { + if (this.s || f || this.map[q]) { + k[w++] = q, c[q] = 1; + } else { + return d; + } + } + } + a = k; + e = a.length; + } + if (!e) { + return d; + } + b || (b = 100); + g = this.depth && 1 < e && !1 !== g; + c = 0; + let m; + g ? (m = a[0], c = 1) : 1 < e && a.sort(aa); + for (let n, w; c < e; c++) { + w = a[c]; + g ? (n = pa(this, d, f, b, h, 2 === e, w, m), f && !1 === n && d.length || (m = w)) : n = pa(this, d, f, b, h, 1 === e, w); + if (n) { + return n; + } + if (f && c === e - 1) { + k = d.length; + if (!k) { + if (g) { + g = 0; + c = -1; + continue; + } + return d; + } + if (1 === k) { + return qa(d[0], b, h); + } + } + } + return ja(d, b, h, f); +}; +function pa(a, b, c, d, e, f, h, g) { + let k = [], m = g ? a.h : a.map; + a.s || (m = ra(m, h, g, a.l)); + if (m) { + let n = 0; + const w = Math.min(m.length, g ? a.A : a.D); + for (let q = 0, r = 0, l, p; q < w; q++) { + if (l = m[q]) { + if (a.s && (l = ra(l, h, g, a.l)), e && l && f && (p = l.length, p <= e ? (e -= p, l = null) : (l = l.slice(e), e = 0)), l && (k[n++] = l, f && (r += l.length, r >= d))) { + break; + } + } + } + if (n) { + if (f) { + return qa(k, d, 0); + } + b[b.length] = k; + return; + } + } + return !c && k; +} +function qa(a, b, c) { + a = 1 === a.length ? a[0] : [].concat.apply([], a); + return c || a.length > b ? a.slice(c, c + b) : a; +} +function ra(a, b, c, d) { + c ? (d = d && b > c, a = (a = a[d ? b : c]) && a[d ? c : b]) : a = a[b]; + return a; +} +t.contain = function(a) { + return !!this.register[a]; +}; +t.update = function(a, b) { + return this.remove(a).add(a, b); +}; +t.remove = function(a, b) { + const c = this.register[a]; + if (c) { + if (this.m) { + for (let d = 0, e; d < c.length; d++) { + e = c[d], e.splice(e.indexOf(a), 1); + } + } else { + Q(this.map, a, this.D, this.s), this.depth && Q(this.h, a, this.A, this.s); + } + b || delete this.register[a]; + if (this.cache) { + b = this.cache; + for (let d = 0, e, f; d < b.h.length; d++) { + f = b.h[d], e = b.cache[f], e.includes(a) && (b.h.splice(d--, 1), delete b.cache[f]); + } + } + } + return this; +}; +function Q(a, b, c, d, e) { + let f = 0; + if (a.constructor === Array) { + if (e) { + b = a.indexOf(b), -1 !== b ? 1 < a.length && (a.splice(b, 1), f++) : f++; + } else { + e = Math.min(a.length, c); + for (let h = 0, g; h < e; h++) { + if (g = a[h]) { + f = Q(g, b, c, d, e), d || f || delete a[h]; + } + } + } + } else { + for (let h in a) { + (f = Q(a[h], b, c, d, e)) || delete a[h]; + } + } + return f; +} +t.searchCache = la; +t.export = function(a, b, c, d, e, f) { + let h = !0; + "undefined" === typeof f && (h = new Promise(m => { + f = m; + })); + let g, k; + switch(e || (e = 0)) { + case 0: + g = "reg"; + if (this.m) { + k = x(); + for (let m in this.register) { + k[m] = 1; + } + } else { + k = this.register; + } + break; + case 1: + g = "cfg"; + k = {doc:0, opt:this.s ? 1 : 0}; + break; + case 2: + g = "map"; + k = this.map; + break; + case 3: + g = "ctx"; + k = this.h; + break; + default: + "undefined" === typeof c && f && f(); + return; + } + oa(a, b || this, c, g, d, e, k, f); + return h; +}; +t.import = function(a, b) { + if (b) { + switch(C(b) && (b = JSON.parse(b)), a) { + case "cfg": + this.s = !!b.opt; + break; + case "reg": + this.m = !1; + this.register = b; + break; + case "map": + this.map = b; + break; + case "ctx": + this.h = b; + } + } +}; +ia(N.prototype); +function sa(a) { + a = a.data; + var b = self._index; + const c = a.args; + var d = a.task; + switch(d) { + case "init": + d = a.options || {}; + a = a.factory; + b = d.encode; + d.cache = !1; + b && 0 === b.indexOf("function") && (d.encode = Function("return " + b)()); + a ? (Function("return " + a)()(self), self._index = new self.FlexSearch.Index(d), delete self.FlexSearch) : self._index = new N(d); + break; + default: + a = a.id, b = b[d].apply(b, c), postMessage("search" === d ? {id:a, msg:b} : {id:a}); + } +} +;let ta = 0; +function S(a) { + if (!(this instanceof S)) { + return new S(a); + } + var b; + a ? E(b = a.encode) && (a.encode = b.toString()) : a = {}; + (b = (self || window)._factory) && (b = b.toString()); + const c = "undefined" === typeof window && self.exports, d = this; + this.o = ua(b, c, a.worker); + this.h = x(); + if (this.o) { + if (c) { + this.o.on("message", function(e) { + d.h[e.id](e.msg); + delete d.h[e.id]; + }); + } else { + this.o.onmessage = function(e) { + e = e.data; + d.h[e.id](e.msg); + delete d.h[e.id]; + }; + } + this.o.postMessage({task:"init", factory:b, options:a}); + } +} +T("add"); +T("append"); +T("search"); +T("update"); +T("remove"); +function T(a) { + S.prototype[a] = S.prototype[a + "Async"] = function() { + const b = this, c = [].slice.call(arguments); + var d = c[c.length - 1]; + let e; + E(d) && (e = d, c.splice(c.length - 1, 1)); + d = new Promise(function(f) { + setTimeout(function() { + b.h[++ta] = f; + b.o.postMessage({task:a, id:ta, args:c}); + }); + }); + return e ? (d.then(e), this) : d; + }; +} +function ua(a, b, c) { + let d; + try { + d = b ? new (require("worker_threads")["Worker"])(__dirname + "/node/node.js") : a ? new Worker(URL.createObjectURL(new Blob(["onmessage=" + sa.toString()], {type:"text/javascript"}))) : new Worker(C(c) ? c : "worker/worker.js", {type:"module"}); + } catch (e) { + } + return d; +} +;function U(a) { + if (!(this instanceof U)) { + return new U(a); + } + var b = a.document || a.doc || a, c; + this.K = []; + this.h = []; + this.A = []; + this.register = x(); + this.key = (c = b.key || b.id) && V(c, this.A) || "id"; + this.m = u(a.fastupdate); + this.C = (c = b.store) && !0 !== c && []; + this.store = c && x(); + this.I = (c = b.tag) && V(c, this.A); + this.l = c && x(); + this.cache = (c = a.cache) && new M(c); + a.cache = !1; + this.o = a.worker; + this.async = !1; + c = x(); + let d = b.index || b.field || b; + C(d) && (d = [d]); + for (let e = 0, f, h; e < d.length; e++) { + f = d[e], C(f) || (h = f, f = f.field), h = D(h) ? Object.assign({}, a, h) : a, this.o && (c[f] = new S(h), c[f].o || (this.o = !1)), this.o || (c[f] = new N(h, this.register)), this.K[e] = V(f, this.A), this.h[e] = f; + } + if (this.C) { + for (a = b.store, C(a) && (a = [a]), b = 0; b < a.length; b++) { + this.C[b] = V(a[b], this.A); + } + } + this.index = c; +} +function V(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)) && (b[d] = !0), a && (c[d++] = a); + } + d < c.length && (c.length = d); + return 1 < d ? c : c[0]; +} +function X(a, b) { + if (C(b)) { + a = a[b]; + } else { + for (let c = 0; a && c < b.length; c++) { + a = a[b[c]]; + } + } + return a; +} +function Y(a, b, c, d, e) { + a = a[e]; + if (d === c.length - 1) { + b[e] = a; + } else if (a) { + if (a.constructor === Array) { + for (b = b[e] = Array(a.length), e = 0; e < a.length; e++) { + Y(a, b, c, d, e); + } + } else { + b = b[e] || (b[e] = x()), e = c[++d], Y(a, b, c, d, e); + } + } +} +function Z(a, b, c, d, e, f, h, g) { + if (a = a[h]) { + if (d === b.length - 1) { + if (a.constructor === Array) { + if (c[d]) { + for (b = 0; b < a.length; b++) { + e.add(f, a[b], !0, !0); + } + return; + } + a = a.join(" "); + } + e.add(f, a, g, !0); + } else { + if (a.constructor === Array) { + for (h = 0; h < a.length; h++) { + Z(a, b, c, d, e, f, h, g); + } + } else { + h = b[++d], Z(a, b, c, d, e, f, h, g); + } + } + } +} +t = U.prototype; +t.add = function(a, b, c) { + D(a) && (b = a, a = X(b, this.key)); + if (b && (a || 0 === a)) { + if (!c && this.register[a]) { + return this.update(a, b); + } + for (let d = 0, e, f; d < this.h.length; d++) { + f = this.h[d], e = this.K[d], C(e) && (e = [e]), Z(b, e, this.A, 0, this.index[f], a, e[0], c); + } + if (this.I) { + let d = X(b, this.I), e = x(); + C(d) && (d = [d]); + for (let f = 0, h, g; f < d.length; f++) { + if (h = d[f], !e[h] && (e[h] = 1, g = this.l[h] || (this.l[h] = []), !c || !g.includes(a))) { + if (g[g.length] = a, this.m) { + const k = this.register[a] || (this.register[a] = []); + k[k.length] = g; + } + } + } + } + if (this.store && (!c || !this.store[a])) { + let d; + if (this.C) { + d = x(); + for (let e = 0, f; e < this.C.length; e++) { + f = this.C[e], C(f) ? d[f] = b[f] : Y(b, d, f, 0, f[0]); + } + } + this.store[a] = d || b; + } + } + return this; +}; +t.append = function(a, b) { + return this.add(a, b, !0); +}; +t.update = function(a, b) { + return this.remove(a).add(a, b); +}; +t.remove = function(a) { + D(a) && (a = X(a, this.key)); + if (this.register[a]) { + for (var b = 0; b < this.h.length && (this.index[this.h[b]].remove(a, !this.o), !this.m); b++) { + } + if (this.I && !this.m) { + for (let c in this.l) { + b = this.l[c]; + const d = b.indexOf(a); + -1 !== d && (1 < b.length ? b.splice(d, 1) : delete this.l[c]); + } + } + this.store && delete this.store[a]; + delete this.register[a]; + } + return this; +}; +t.search = function(a, b, c, d) { + c || (!b && D(a) ? (c = a, a = "") : D(b) && (c = b, b = 0)); + let e = [], f = [], h, g, k, m, n, w, q = 0; + if (c) { + if (c.constructor === Array) { + k = c, c = null; + } else { + a = c.query || a; + k = (h = c.pluck) || c.index || c.field; + m = c.tag; + g = this.store && c.enrich; + n = "and" === c.bool; + b = c.limit || b || 100; + w = c.offset || 0; + if (m && (C(m) && (m = [m]), !a)) { + for (let l = 0, p; l < m.length; l++) { + if (p = va.call(this, m[l], b, w, g)) { + e[e.length] = p, q++; + } + } + return q ? e : []; + } + C(k) && (k = [k]); + } + } + k || (k = this.h); + n = n && (1 < k.length || m && 1 < m.length); + const r = !d && (this.o || this.async) && []; + for (let l = 0, p, A, B; l < k.length; l++) { + let z; + A = k[l]; + C(A) || (z = A, A = z.field, a = z.query || a, b = z.limit || b, g = z.enrich || g); + if (r) { + r[l] = this.index[A].searchAsync(a, b, z || c); + } else { + d ? p = d[l] : p = this.index[A].search(a, b, z || c); + B = p && p.length; + if (m && B) { + const y = []; + let H = 0; + n && (y[0] = [p]); + for (let W = 0, na, R; W < m.length; W++) { + if (na = m[W], B = (R = this.l[na]) && R.length) { + H++, y[y.length] = n ? [R] : R; + } + } + H && (p = n ? ja(y, b || 100, w || 0) : ka(p, y), B = p.length); + } + if (B) { + f[q] = A, e[q++] = p; + } else if (n) { + return []; + } + } + } + if (r) { + const l = this; + return new Promise(function(p) { + Promise.all(r).then(function(A) { + p(l.search(a, b, c, A)); + }); + }); + } + if (!q) { + return []; + } + if (h && (!g || !this.store)) { + return e[0]; + } + for (let l = 0, p; l < f.length; l++) { + p = e[l]; + p.length && g && (p = wa.call(this, p)); + if (h) { + return p; + } + e[l] = {field:f[l], result:p}; + } + return e; +}; +function va(a, b, c, d) { + let e = this.l[a], f = e && e.length - c; + if (f && 0 < f) { + if (f > b || c) { + e = e.slice(c, c + b); + } + d && (e = wa.call(this, e)); + return {tag:a, result:e}; + } +} +function wa(a) { + const b = Array(a.length); + for (let c = 0, d; c < a.length; c++) { + d = a[c], b[c] = {id:d, doc:this.store[d]}; + } + return b; +} +t.contain = function(a) { + return !!this.register[a]; +}; +t.get = function(a) { + return this.store[a]; +}; +t.set = function(a, b) { + this.store[a] = b; + return this; +}; +t.searchCache = la; +t.export = function(a, b, c, d, e, f) { + let h; + "undefined" === typeof f && (h = new Promise(g => { + f = g; + })); + e || (e = 0); + d || (d = 0); + if (d < this.h.length) { + const g = this.h[d], k = this.index[g]; + b = this; + setTimeout(function() { + k.export(a, b, e ? g : "", d, e++, f) || (d++, e = 1, b.export(a, b, g, d, e, f)); + }); + } else { + let g, k; + switch(e) { + case 1: + g = "tag"; + k = this.l; + c = null; + break; + case 2: + g = "store"; + k = this.store; + c = null; + break; + default: + f(); + return; + } + oa(a, this, c, g, d, e, k, f); + } + return h; +}; +t.import = function(a, b) { + if (b) { + switch(C(b) && (b = JSON.parse(b)), a) { + case "tag": + this.l = b; + break; + case "reg": + this.m = !1; + this.register = b; + for (let d = 0, e; d < this.h.length; d++) { + e = this.index[this.h[d]], e.register = b, e.m = !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); + } + } +}; +ia(U.prototype); +var ya = {encode:xa, F:!1, G:""}; +const za = [J("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), "a", J("[\u00e8\u00e9\u00ea\u00eb]"), "e", J("[\u00ec\u00ed\u00ee\u00ef]"), "i", J("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), "o", J("[\u00f9\u00fa\u00fb\u00fc\u0171]"), "u", J("[\u00fd\u0177\u00ff]"), "y", J("\u00f1"), "n", J("[\u00e7c]"), "k", J("\u00df"), "s", J(" & "), " and "]; +function xa(a) { + var b = a = "" + a; + b.normalize && (b = b.normalize("NFD").replace(ca, "")); + return F.call(this, b.toLowerCase(), !a.normalize && za); +} +;var Ba = {encode:Aa, F:!1, G:"strict"}; +const Ca = /[^a-z0-9]+/, Da = {b:"p", v:"f", w:"f", z:"s", x:"s", "\u00df":"s", d:"t", n:"m", c:"k", g:"k", j:"k", q:"k", i:"e", y:"e", u:"o"}; +function Aa(a) { + a = xa.call(this, a).join(" "); + const b = []; + if (a) { + const c = a.split(Ca), d = c.length; + for (let e = 0, f, h = 0; e < d; e++) { + if ((a = c[e]) && (!this.filter || !this.filter[a])) { + f = a[0]; + let g = Da[f] || f, k = g; + for (let m = 1; m < a.length; m++) { + f = a[m]; + const n = Da[f] || f; + n && n !== k && (g += n, k = n); + } + b[h++] = g; + } + } + } + return b; +} +;var Fa = {encode:Ea, F:!1, G:""}; +const Ga = [J("ae"), "a", J("oe"), "o", J("sh"), "s", J("th"), "t", J("ph"), "f", J("pf"), "f", J("(?![aeo])h(?![aeo])"), "", J("(?!^[aeo])h(?!^[aeo])"), ""]; +function Ea(a, b) { + a && (a = Aa.call(this, a).join(" "), 2 < a.length && (a = G(a, Ga)), b || (1 < a.length && (a = da(a)), a && (a = a.split(" ")))); + return a || []; +} +;var Ia = {encode:Ha, F:!1, G:""}; +const Ja = J("(?!\\b)[aeo]"); +function Ha(a) { + a && (a = Ea.call(this, a, !0), 1 < a.length && (a = a.replace(Ja, "")), 1 < a.length && (a = da(a)), a && (a = a.split(" "))); + return a || []; +} +;K["latin:default"] = fa; +K["latin:simple"] = ya; +K["latin:balance"] = Ba; +K["latin:advanced"] = Fa; +K["latin:extra"] = Ia; +export default {Index:N, Document:U, Worker:S, registerCharset:function(a, b) { + K[a] = b; +}, registerLanguage:function(a, b) { + ha[a] = b; +}}; + diff --git a/paige/node_modules/flexsearch/dist/flexsearch.bundle.module.min.js b/paige/node_modules/flexsearch/dist/flexsearch.bundle.module.min.js new file mode 100644 index 00000000..f5b31a2a --- /dev/null +++ b/paige/node_modules/flexsearch/dist/flexsearch.bundle.module.min.js @@ -0,0 +1,34 @@ +/**! + * FlexSearch.js v0.7.41 (Bundle.module) + * Author and Copyright: Thomas Wilkerling + * Licence: Apache-2.0 + * Hosted by Nextapps GmbH + * https://github.com/nextapps-de/flexsearch + */ +var t;function u(a){return"undefined"!==typeof a?a:!0}function v(a){const b=Array(a);for(let c=0;c=this.B&&(w||!n[l])){var f=O(q,d,r),h="";switch(this.G){case "full":if(2f;g--)if(g-f>=this.B){var k=O(q,d,r,e,f);h=l.substring(f,g);P(this,n,h,k,a,c)}break}case "reverse":if(1=this.B&&P(this,n, +h,O(q,d,r,e,g),a,c);h=""}case "forward":if(1=this.B&&P(this,n,h,f,a,c);break}default:if(this.C&&(f=Math.min(f/this.C(b,l,r)|0,q-1)),P(this,n,l,f,a,c),w&&1=this.B&&!e[l]){e[l]=1;const p=this.l&&l>f;P(this,m,p?f:l,O(h+(d/2>h?0:1),d,r,g-1,k-1),a,c,p?l:f)}}}}this.m||(this.register[a]=1)}}return this}; +function O(a,b,c,d,e){return c&&1=this.B&&!c[q])if(this.s||f||this.map[q])k[w++]=q,c[q]=1;else return d;a=k;e=a.length}if(!e)return d;b||(b=100);g=this.depth&&1=d)))break;if(n){if(f)return qa(k,d,0);b[b.length]=k;return}}return!c&&k}function qa(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} +function ra(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a}t.contain=function(a){return!!this.register[a]};t.update=function(a,b){return this.remove(a).add(a,b)}; +t.remove=function(a,b){const c=this.register[a];if(c){if(this.m)for(let d=0,e;d{f=m}));let g,k;switch(e||(e=0)){case 0:g="reg";if(this.m){k=x();for(let m in this.register)k[m]=1}else k=this.register;break;case 1:g="cfg";k={doc:0,opt:this.s?1:0};break;case 2:g="map";k=this.map;break;case 3:g="ctx";k=this.h;break;default:"undefined"===typeof c&&f&&f();return}oa(a,b||this,c,g,d,e,k,f);return h}; +t.import=function(a,b){if(b)switch(C(b)&&(b=JSON.parse(b)),a){case "cfg":this.s=!!b.opt;break;case "reg":this.m=!1;this.register=b;break;case "map":this.map=b;break;case "ctx":this.h=b}};ia(N.prototype);function sa(a){a=a.data;var b=self._index;const c=a.args;var d=a.task;switch(d){case "init":d=a.options||{};a=a.factory;b=d.encode;d.cache=!1;b&&0===b.indexOf("function")&&(d.encode=Function("return "+b)());a?(Function("return "+a)()(self),self._index=new self.FlexSearch.Index(d),delete self.FlexSearch):self._index=new N(d);break;default:a=a.id,b=b[d].apply(b,c),postMessage("search"===d?{id:a,msg:b}:{id:a})}};let ta=0;function S(a){if(!(this instanceof S))return new S(a);var b;a?E(b=a.encode)&&(a.encode=b.toString()):a={};(b=(self||window)._factory)&&(b=b.toString());const c="undefined"===typeof window&&self.exports,d=this;this.o=ua(b,c,a.worker);this.h=x();if(this.o){if(c)this.o.on("message",function(e){d.h[e.id](e.msg);delete d.h[e.id]});else this.o.onmessage=function(e){e=e.data;d.h[e.id](e.msg);delete d.h[e.id]};this.o.postMessage({task:"init",factory:b,options:a})}}T("add");T("append");T("search"); +T("update");T("remove");function T(a){S.prototype[a]=S.prototype[a+"Async"]=function(){const b=this,c=[].slice.call(arguments);var d=c[c.length-1];let e;E(d)&&(e=d,c.splice(c.length-1,1));d=new Promise(function(f){setTimeout(function(){b.h[++ta]=f;b.o.postMessage({task:a,id:ta,args:c})})});return e?(d.then(e),this):d}} +function ua(a,b,c){let d;try{d=b?new (require("worker_threads")["Worker"])(__dirname + "/node/node.js"):a?new Worker(URL.createObjectURL(new Blob(["onmessage="+sa.toString()],{type:"text/javascript"}))):new Worker(C(c)?c:"worker/worker.js",{type:"module"})}catch(e){}return d};function U(a){if(!(this instanceof U))return new U(a);var b=a.document||a.doc||a,c;this.K=[];this.h=[];this.A=[];this.register=x();this.key=(c=b.key||b.id)&&V(c,this.A)||"id";this.m=u(a.fastupdate);this.C=(c=b.store)&&!0!==c&&[];this.store=c&&x();this.I=(c=b.tag)&&V(c,this.A);this.l=c&&x();this.cache=(c=a.cache)&&new M(c);a.cache=!1;this.o=a.worker;this.async=!1;c=x();let d=b.index||b.field||b;C(d)&&(d=[d]);for(let e=0,f,h;eb||c)e=e.slice(c,c+b);d&&(e=wa.call(this,e));return{tag:a,result:e}}}function wa(a){const b=Array(a.length);for(let c=0,d;c{f=g}));e||(e=0);d||(d=0);if(d= this.m && (u || !n[l])) { + var f = Q(q, e, r), g = ""; + switch(this.C) { + case "full": + if (2 < d) { + for (f = 0; f < d; f++) { + for (var h = d; h > f; h--) { + if (h - f >= this.m) { + var k = Q(q, e, r, d, f); + g = l.substring(f, h); + S(this, n, g, k, a, c); + } + } + } + break; + } + case "reverse": + if (1 < d) { + for (h = d - 1; 0 < h; h--) { + g = l[h] + g, g.length >= this.m && S(this, n, g, Q(q, e, r, d, h), a, c); + } + g = ""; + } + case "forward": + if (1 < d) { + for (h = 0; h < d; h++) { + g += l[h], g.length >= this.m && S(this, n, g, f, a, c); + } + break; + } + default: + if (this.F && (f = Math.min(f / this.F(b, l, r) | 0, q - 1)), S(this, n, l, f, a, c), u && 1 < e && r < e - 1) { + for (d = z(), g = this.o, f = l, h = Math.min(u + 1, e - r), d[f] = 1, k = 1; k < h; k++) { + if ((l = b[this.B ? e - 1 - r - k : r + k]) && l.length >= this.m && !d[l]) { + d[l] = 1; + const p = this.h && l > f; + S(this, m, p ? f : l, Q(g + (e / 2 > g ? 0 : 1), e, r, h - 1, k - 1), a, c, p ? l : f); + } + } + } + } + } + } + this.D || (this.register[a] = 1); + } + } + return this; +}; +function Q(a, b, c, e, d) { + return c && 1 < a ? b + (e || 0) <= a ? c + (d || 0) : (a - 1) / (b + (e || 0)) * (c + (d || 0)) + 1 | 0 : 0; +} +function S(a, b, c, e, d, f, g) { + let h = g ? a.l : a.map; + if (!b[c] || g && !b[c][g]) { + a.s && (h = h[e]), g ? (b = b[c] || (b[c] = z()), b[g] = 1, h = h[g] || (h[g] = z())) : b[c] = 1, h = h[c] || (h[c] = []), a.s || (h = h[e] || (h[e] = [])), f && h.includes(d) || (h[h.length] = d, a.D && (a = a.register[d] || (a.register[d] = []), a[a.length] = h)); + } +} +t.search = function(a, b, c) { + c || (!b && D(a) ? (c = a, a = c.query) : D(b) && (c = b)); + let e = [], d; + let f, g = 0; + if (c) { + a = c.query || a; + b = c.limit; + g = c.offset || 0; + var h = c.context; + f = c.suggest; + } + if (a && (a = this.encode("" + a), d = a.length, 1 < d)) { + c = z(); + var k = []; + for (let n = 0, u = 0, q; n < d; n++) { + if ((q = a[n]) && q.length >= this.m && !c[q]) { + if (this.s || f || this.map[q]) { + k[u++] = q, c[q] = 1; + } else { + return e; + } + } + } + a = k; + d = a.length; + } + if (!d) { + return e; + } + b || (b = 100); + h = this.depth && 1 < d && !1 !== h; + c = 0; + let m; + h ? (m = a[0], c = 1) : 1 < d && a.sort(aa); + for (let n, u; c < d; c++) { + u = a[c]; + h ? (n = ka(this, e, f, b, g, 2 === d, u, m), f && !1 === n && e.length || (m = u)) : n = ka(this, e, f, b, g, 1 === d, u); + if (n) { + return n; + } + if (f && c === d - 1) { + k = e.length; + if (!k) { + if (h) { + h = 0; + c = -1; + continue; + } + return e; + } + if (1 === k) { + return la(e[0], b, g); + } + } + } + return fa(e, b, g, f); +}; +function ka(a, b, c, e, d, f, g, h) { + let k = [], m = h ? a.l : a.map; + a.s || (m = ma(m, g, h, a.h)); + if (m) { + let n = 0; + const u = Math.min(m.length, h ? a.o : a.A); + for (let q = 0, r = 0, l, p; q < u; q++) { + if (l = m[q]) { + if (a.s && (l = ma(l, g, h, a.h)), d && l && f && (p = l.length, p <= d ? (d -= p, l = null) : (l = l.slice(d), d = 0)), l && (k[n++] = l, f && (r += l.length, r >= e))) { + break; + } + } + } + if (n) { + if (f) { + return la(k, e, 0); + } + b[b.length] = k; + return; + } + } + return !c && k; +} +function la(a, b, c) { + a = 1 === a.length ? a[0] : [].concat.apply([], a); + return c || a.length > b ? a.slice(c, c + b) : a; +} +function ma(a, b, c, e) { + c ? (e = e && b > c, a = (a = a[e ? b : c]) && a[e ? c : b]) : a = a[b]; + return a; +} +t.contain = function(a) { + return !!this.register[a]; +}; +t.update = function(a, b) { + return this.remove(a).add(a, b); +}; +t.remove = function(a, b) { + const c = this.register[a]; + if (c) { + if (this.D) { + for (let e = 0, d; e < c.length; e++) { + d = c[e], d.splice(d.indexOf(a), 1); + } + } else { + T(this.map, a, this.A, this.s), this.depth && T(this.l, a, this.o, this.s); + } + b || delete this.register[a]; + } + return this; +}; +function T(a, b, c, e, d) { + let f = 0; + if (a.constructor === Array) { + if (d) { + b = a.indexOf(b), -1 !== b ? 1 < a.length && (a.splice(b, 1), f++) : f++; + } else { + d = Math.min(a.length, c); + for (let g = 0, h; g < d; g++) { + if (h = a[g]) { + f = T(h, b, c, e, d), e || f || delete a[g]; + } + } + } + } else { + for (let g in a) { + (f = T(a[g], b, c, e, d)) || delete a[g]; + } + } + return f; +} +ea(P.prototype); +function U(a) { + if (!(this instanceof U)) { + return new U(a); + } + var b = a.document || a.doc || a, c; + this.F = []; + this.h = []; + this.o = []; + this.register = z(); + this.key = (c = b.key || b.id) && V(c, this.o) || "id"; + this.D = v(a.fastupdate); + this.l = (c = b.store) && !0 !== c && []; + this.store = c && z(); + this.async = !1; + c = z(); + let e = b.index || b.field || b; + C(e) && (e = [e]); + for (let d = 0, f, g; d < e.length; d++) { + f = e[d], C(f) || (g = f, f = f.field), g = D(g) ? Object.assign({}, a, g) : a, this.I || (c[f] = new P(g, this.register)), this.F[d] = V(f, this.o), this.h[d] = f; + } + if (this.l) { + for (a = b.store, C(a) && (a = [a]), b = 0; b < a.length; b++) { + this.l[b] = V(a[b], this.o); + } + } + this.index = c; +} +function V(a, b) { + const c = a.split(":"); + let e = 0; + for (let d = 0; d < c.length; d++) { + a = c[d], 0 <= a.indexOf("[]") && (a = a.substring(0, a.length - 2)) && (b[e] = !0), a && (c[e++] = a); + } + e < c.length && (c.length = e); + return 1 < e ? c : c[0]; +} +function na(a, b) { + if (C(b)) { + a = a[b]; + } else { + for (let c = 0; a && c < b.length; c++) { + a = a[b[c]]; + } + } + return a; +} +function W(a, b, c, e, d) { + a = a[d]; + if (e === c.length - 1) { + b[d] = a; + } else if (a) { + if (a.constructor === Array) { + for (b = b[d] = Array(a.length), d = 0; d < a.length; d++) { + W(a, b, c, e, d); + } + } else { + b = b[d] || (b[d] = z()), d = c[++e], W(a, b, c, e, d); + } + } +} +function X(a, b, c, e, d, f, g, h) { + if (a = a[g]) { + if (e === b.length - 1) { + if (a.constructor === Array) { + if (c[e]) { + for (b = 0; b < a.length; b++) { + d.add(f, a[b], !0, !0); + } + return; + } + a = a.join(" "); + } + d.add(f, a, h, !0); + } else { + if (a.constructor === Array) { + for (g = 0; g < a.length; g++) { + X(a, b, c, e, d, f, g, h); + } + } else { + g = b[++e], X(a, b, c, e, d, f, g, h); + } + } + } +} +t = U.prototype; +t.add = function(a, b, c) { + D(a) && (b = a, a = na(b, this.key)); + if (b && (a || 0 === a)) { + if (!c && this.register[a]) { + return this.update(a, b); + } + for (let e = 0, d, f; e < this.h.length; e++) { + f = this.h[e], d = this.F[e], C(d) && (d = [d]), X(b, d, this.o, 0, this.index[f], a, d[0], c); + } + if (this.store && (!c || !this.store[a])) { + let e; + if (this.l) { + e = z(); + for (let d = 0, f; d < this.l.length; d++) { + f = this.l[d], C(f) ? e[f] = b[f] : W(b, e, f, 0, f[0]); + } + } + this.store[a] = e || b; + } + } + return this; +}; +t.append = function(a, b) { + return this.add(a, b, !0); +}; +t.update = function(a, b) { + return this.remove(a).add(a, b); +}; +t.remove = function(a) { + D(a) && (a = na(a, this.key)); + if (this.register[a]) { + for (let b = 0; b < this.h.length && (this.index[this.h[b]].remove(a, !this.I), !this.D); b++) { + } + this.store && delete this.store[a]; + delete this.register[a]; + } + return this; +}; +t.search = function(a, b, c, e) { + c || (!b && D(a) ? (c = a, a = "") : D(b) && (c = b, b = 0)); + let d = [], f = [], g, h, k, m, n, u, q = 0; + if (c) { + if (c.constructor === Array) { + k = c, c = null; + } else { + a = c.query || a; + k = (g = c.pluck) || c.index || c.field; + m = !1; + h = this.store && c.enrich; + n = "and" === c.bool; + b = c.limit || b || 100; + u = c.offset || 0; + if (m && (C(m) && (m = [m]), !a)) { + for (let l = 0, p; l < m.length; l++) { + if (p = oa.call(this, m[l], b, u, h)) { + d[d.length] = p, q++; + } + } + return q ? d : []; + } + C(k) && (k = [k]); + } + } + k || (k = this.h); + n = n && (1 < k.length || m && 1 < m.length); + const r = !e && (this.I || this.async) && []; + for (let l = 0, p, A, B; l < k.length; l++) { + let y; + A = k[l]; + C(A) || (y = A, A = y.field, a = y.query || a, b = y.limit || b, h = y.enrich || h); + if (r) { + r[l] = this.index[A].searchAsync(a, b, y || c); + } else { + e ? p = e[l] : p = this.index[A].search(a, b, y || c); + B = p && p.length; + if (m && B) { + const x = []; + let G = 0; + n && (x[0] = [p]); + for (let R = 0, ia, N; R < m.length; R++) { + if (ia = m[R], B = (N = this.J[ia]) && N.length) { + G++, x[x.length] = n ? [N] : N; + } + } + G && (p = n ? fa(x, b || 100, u || 0) : ha(p, x), B = p.length); + } + if (B) { + f[q] = A, d[q++] = p; + } else if (n) { + return []; + } + } + } + if (r) { + const l = this; + return new Promise(function(p) { + Promise.all(r).then(function(A) { + p(l.search(a, b, c, A)); + }); + }); + } + if (!q) { + return []; + } + if (g && (!h || !this.store)) { + return d[0]; + } + for (let l = 0, p; l < f.length; l++) { + p = d[l]; + p.length && h && (p = pa.call(this, p)); + if (g) { + return p; + } + d[l] = {field:f[l], result:p}; + } + return d; +}; +function oa(a, b, c, e) { + let d = this.J[a], f = d && d.length - c; + if (f && 0 < f) { + if (f > b || c) { + d = d.slice(c, c + b); + } + e && (d = pa.call(this, d)); + return {tag:a, result:d}; + } +} +function pa(a) { + const b = Array(a.length); + for (let c = 0, e; c < a.length; c++) { + e = a[c], b[c] = {id:e, doc:this.store[e]}; + } + return b; +} +t.contain = function(a) { + return !!this.register[a]; +}; +t.get = function(a) { + return this.store[a]; +}; +t.set = function(a, b) { + this.store[a] = b; + return this; +}; +ea(U.prototype); +var ra = {encode:qa, B:!1, C:""}; +const sa = [I("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), "a", I("[\u00e8\u00e9\u00ea\u00eb]"), "e", I("[\u00ec\u00ed\u00ee\u00ef]"), "i", I("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), "o", I("[\u00f9\u00fa\u00fb\u00fc\u0171]"), "u", I("[\u00fd\u0177\u00ff]"), "y", I("\u00f1"), "n", I("[\u00e7c]"), "k", I("\u00df"), "s", I(" & "), " and "]; +function qa(a) { + var b = a = "" + a; + b.normalize && (b = b.normalize("NFD").replace(ca, "")); + return E.call(this, b.toLowerCase(), !a.normalize && sa); +} +;var ua = {encode:ta, B:!1, C:"strict"}; +const va = /[^a-z0-9]+/, wa = {b:"p", v:"f", w:"f", z:"s", x:"s", "\u00df":"s", d:"t", n:"m", c:"k", g:"k", j:"k", q:"k", i:"e", y:"e", u:"o"}; +function ta(a) { + a = qa.call(this, a).join(" "); + const b = []; + if (a) { + const c = a.split(va), e = c.length; + for (let d = 0, f, g = 0; d < e; d++) { + if ((a = c[d]) && (!this.filter || !this.filter[a])) { + f = a[0]; + let h = wa[f] || f, k = h; + for (let m = 1; m < a.length; m++) { + f = a[m]; + const n = wa[f] || f; + n && n !== k && (h += n, k = n); + } + b[g++] = h; + } + } + } + return b; +} +;var ya = {encode:xa, B:!1, C:""}; +const za = [I("ae"), "a", I("oe"), "o", I("sh"), "s", I("th"), "t", I("ph"), "f", I("pf"), "f", I("(?![aeo])h(?![aeo])"), "", I("(?!^[aeo])h(?!^[aeo])"), ""]; +function xa(a, b) { + a && (a = ta.call(this, a).join(" "), 2 < a.length && (a = F(a, za)), b || (1 < a.length && (a = J(a)), a && (a = a.split(" ")))); + return a || []; +} +;var Ba = {encode:Aa, B:!1, C:""}; +const Ca = I("(?!\\b)[aeo]"); +function Aa(a) { + a && (a = xa.call(this, a, !0), 1 < a.length && (a = a.replace(Ca, "")), 1 < a.length && (a = J(a)), a && (a = a.split(" "))); + return a || []; +} +;M["latin:default"] = da; +M["latin:simple"] = ra; +M["latin:balance"] = ua; +M["latin:advanced"] = ya; +M["latin:extra"] = Ba; +const Y = {Index:P, Document:U, Worker:null, registerCharset:function(a, b) { + M[a] = b; +}, registerLanguage:function(a, b) { + L[a] = b; +}}; +let Z; +(Z = self.define) && Z.amd ? Z([], function() { + return Y; +}) : self.exports ? self.exports = Y : self.FlexSearch = Y; +}(this)); diff --git a/paige/node_modules/flexsearch/dist/flexsearch.compact.min.js b/paige/node_modules/flexsearch/dist/flexsearch.compact.min.js new file mode 100644 index 00000000..b3879af4 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/flexsearch.compact.min.js @@ -0,0 +1,27 @@ +/**! + * FlexSearch.js v0.7.41 (Compact) + * Author and Copyright: Thomas Wilkerling + * Licence: Apache-2.0 + * Hosted by Nextapps GmbH + * https://github.com/nextapps-de/flexsearch + */ +(function(self){'use strict';var t;function v(a){return"undefined"!==typeof a?a:!0}function w(a){const b=Array(a);for(let c=0;c=this.m&&(u||!n[l])){var f=Q(q,e,r),g="";switch(this.C){case "full":if(2f;h--)if(h-f>=this.m){var k=Q(q,e,r,d,f);g=l.substring(f,h);S(this,n,g,k,a,c)}break}case "reverse":if(1=this.m&&S(this,n, +g,Q(q,e,r,d,h),a,c);g=""}case "forward":if(1=this.m&&S(this,n,g,f,a,c);break}default:if(this.F&&(f=Math.min(f/this.F(b,l,r)|0,q-1)),S(this,n,l,f,a,c),u&&1=this.m&&!d[l]){d[l]=1;const p=this.h&&l>f;S(this,m,p?f:l,Q(g+(e/2>g?0:1),e,r,h-1,k-1),a,c,p?l:f)}}}}this.D||(this.register[a]=1)}}return this}; +function Q(a,b,c,e,d){return c&&1=this.m&&!c[q])if(this.s||f||this.map[q])k[u++]=q,c[q]=1;else return e;a=k;d=a.length}if(!d)return e;b||(b=100);h=this.depth&&1=e)))break;if(n){if(f)return la(k,e,0);b[b.length]=k;return}}return!c&&k}function la(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} +function ma(a,b,c,e){c?(e=e&&b>c,a=(a=a[e?b:c])&&a[e?c:b]):a=a[b];return a}t.contain=function(a){return!!this.register[a]};t.update=function(a,b){return this.remove(a).add(a,b)};t.remove=function(a,b){const c=this.register[a];if(c){if(this.D)for(let e=0,d;eb||c)d=d.slice(c,c+b);e&&(d=pa.call(this,d));return{tag:a,result:d}}}function pa(a){const b=Array(a.length);for(let c=0,e;c= this.m && (u || !n[l])) { + var f = T(q, e, r), g = ""; + switch(this.C) { + case "full": + if (2 < d) { + for (f = 0; f < d; f++) { + for (var h = d; h > f; h--) { + if (h - f >= this.m) { + var k = T(q, e, r, d, f); + g = l.substring(f, h); + U(this, n, g, k, a, c); + } + } + } + break; + } + case "reverse": + if (1 < d) { + for (h = d - 1; 0 < h; h--) { + g = l[h] + g, g.length >= this.m && U(this, n, g, T(q, e, r, d, h), a, c); + } + g = ""; + } + case "forward": + if (1 < d) { + for (h = 0; h < d; h++) { + g += l[h], g.length >= this.m && U(this, n, g, f, a, c); + } + break; + } + default: + if (this.F && (f = Math.min(f / this.F(b, l, r) | 0, q - 1)), U(this, n, l, f, a, c), u && 1 < e && r < e - 1) { + for (d = z(), g = this.o, f = l, h = Math.min(u + 1, e - r), d[f] = 1, k = 1; k < h; k++) { + if ((l = b[this.B ? e - 1 - r - k : r + k]) && l.length >= this.m && !d[l]) { + d[l] = 1; + const p = this.h && l > f; + U(this, m, p ? f : l, T(g + (e / 2 > g ? 0 : 1), e, r, h - 1, k - 1), a, c, p ? l : f); + } + } + } + } + } + } + this.D || (this.register[a] = 1); + } + } + return this; +}; +function T(a, b, c, e, d) { + return c && 1 < a ? b + (e || 0) <= a ? c + (d || 0) : (a - 1) / (b + (e || 0)) * (c + (d || 0)) + 1 | 0 : 0; +} +function U(a, b, c, e, d, f, g) { + let h = g ? a.l : a.map; + if (!b[c] || g && !b[c][g]) { + a.s && (h = h[e]), g ? (b = b[c] || (b[c] = z()), b[g] = 1, h = h[g] || (h[g] = z())) : b[c] = 1, h = h[c] || (h[c] = []), a.s || (h = h[e] || (h[e] = [])), f && h.includes(d) || (h[h.length] = d, a.D && (a = a.register[d] || (a.register[d] = []), a[a.length] = h)); + } +} +t.search = function(a, b, c) { + c || (!b && D(a) ? (c = a, a = c.query) : D(b) && (c = b)); + let e = [], d; + let f, g = 0; + if (c) { + a = c.query || a; + b = c.limit; + g = c.offset || 0; + var h = c.context; + f = c.suggest; + } + if (a && (a = this.encode("" + a), d = a.length, 1 < d)) { + c = z(); + var k = []; + for (let n = 0, u = 0, q; n < d; n++) { + if ((q = a[n]) && q.length >= this.m && !c[q]) { + if (this.s || f || this.map[q]) { + k[u++] = q, c[q] = 1; + } else { + return e; + } + } + } + a = k; + d = a.length; + } + if (!d) { + return e; + } + b || (b = 100); + h = this.depth && 1 < d && !1 !== h; + c = 0; + let m; + h ? (m = a[0], c = 1) : 1 < d && a.sort(aa); + for (let n, u; c < d; c++) { + u = a[c]; + h ? (n = ia(this, e, f, b, g, 2 === d, u, m), f && !1 === n && e.length || (m = u)) : n = ia(this, e, f, b, g, 1 === d, u); + if (n) { + return n; + } + if (f && c === d - 1) { + k = e.length; + if (!k) { + if (h) { + h = 0; + c = -1; + continue; + } + return e; + } + if (1 === k) { + return ja(e[0], b, g); + } + } + } + return Q(e, b, g, f); +}; +function ia(a, b, c, e, d, f, g, h) { + let k = [], m = h ? a.l : a.map; + a.s || (m = ka(m, g, h, a.h)); + if (m) { + let n = 0; + const u = Math.min(m.length, h ? a.o : a.A); + for (let q = 0, r = 0, l, p; q < u; q++) { + if (l = m[q]) { + if (a.s && (l = ka(l, g, h, a.h)), d && l && f && (p = l.length, p <= d ? (d -= p, l = null) : (l = l.slice(d), d = 0)), l && (k[n++] = l, f && (r += l.length, r >= e))) { + break; + } + } + } + if (n) { + if (f) { + return ja(k, e, 0); + } + b[b.length] = k; + return; + } + } + return !c && k; +} +function ja(a, b, c) { + a = 1 === a.length ? a[0] : [].concat.apply([], a); + return c || a.length > b ? a.slice(c, c + b) : a; +} +function ka(a, b, c, e) { + c ? (e = e && b > c, a = (a = a[e ? b : c]) && a[e ? c : b]) : a = a[b]; + return a; +} +t.contain = function(a) { + return !!this.register[a]; +}; +t.update = function(a, b) { + return this.remove(a).add(a, b); +}; +t.remove = function(a, b) { + const c = this.register[a]; + if (c) { + if (this.D) { + for (let e = 0, d; e < c.length; e++) { + d = c[e], d.splice(d.indexOf(a), 1); + } + } else { + V(this.map, a, this.A, this.s), this.depth && V(this.l, a, this.o, this.s); + } + b || delete this.register[a]; + } + return this; +}; +function V(a, b, c, e, d) { + let f = 0; + if (a.constructor === Array) { + if (d) { + b = a.indexOf(b), -1 !== b ? 1 < a.length && (a.splice(b, 1), f++) : f++; + } else { + d = Math.min(a.length, c); + for (let g = 0, h; g < d; g++) { + if (h = a[g]) { + f = V(h, b, c, e, d), e || f || delete a[g]; + } + } + } + } else { + for (let g in a) { + (f = V(a[g], b, c, e, d)) || delete a[g]; + } + } + return f; +} +O(S.prototype); +function W(a) { + if (!(this instanceof W)) { + return new W(a); + } + var b = a.document || a.doc || a, c; + this.F = []; + this.h = []; + this.o = []; + this.register = z(); + this.key = (c = b.key || b.id) && X(c, this.o) || "id"; + this.D = v(a.fastupdate); + this.l = (c = b.store) && !0 !== c && []; + this.store = c && z(); + this.async = !1; + c = z(); + let e = b.index || b.field || b; + C(e) && (e = [e]); + for (let d = 0, f, g; d < e.length; d++) { + f = e[d], C(f) || (g = f, f = f.field), g = D(g) ? Object.assign({}, a, g) : a, this.I || (c[f] = new S(g, this.register)), this.F[d] = X(f, this.o), this.h[d] = f; + } + if (this.l) { + for (a = b.store, C(a) && (a = [a]), b = 0; b < a.length; b++) { + this.l[b] = X(a[b], this.o); + } + } + this.index = c; +} +function X(a, b) { + const c = a.split(":"); + let e = 0; + for (let d = 0; d < c.length; d++) { + a = c[d], 0 <= a.indexOf("[]") && (a = a.substring(0, a.length - 2)) && (b[e] = !0), a && (c[e++] = a); + } + e < c.length && (c.length = e); + return 1 < e ? c : c[0]; +} +function la(a, b) { + if (C(b)) { + a = a[b]; + } else { + for (let c = 0; a && c < b.length; c++) { + a = a[b[c]]; + } + } + return a; +} +function Y(a, b, c, e, d) { + a = a[d]; + if (e === c.length - 1) { + b[d] = a; + } else if (a) { + if (a.constructor === Array) { + for (b = b[d] = Array(a.length), d = 0; d < a.length; d++) { + Y(a, b, c, e, d); + } + } else { + b = b[d] || (b[d] = z()), d = c[++e], Y(a, b, c, e, d); + } + } +} +function Z(a, b, c, e, d, f, g, h) { + if (a = a[g]) { + if (e === b.length - 1) { + if (a.constructor === Array) { + if (c[e]) { + for (b = 0; b < a.length; b++) { + d.add(f, a[b], !0, !0); + } + return; + } + a = a.join(" "); + } + d.add(f, a, h, !0); + } else { + if (a.constructor === Array) { + for (g = 0; g < a.length; g++) { + Z(a, b, c, e, d, f, g, h); + } + } else { + g = b[++e], Z(a, b, c, e, d, f, g, h); + } + } + } +} +t = W.prototype; +t.add = function(a, b, c) { + D(a) && (b = a, a = la(b, this.key)); + if (b && (a || 0 === a)) { + if (!c && this.register[a]) { + return this.update(a, b); + } + for (let e = 0, d, f; e < this.h.length; e++) { + f = this.h[e], d = this.F[e], C(d) && (d = [d]), Z(b, d, this.o, 0, this.index[f], a, d[0], c); + } + if (this.store && (!c || !this.store[a])) { + let e; + if (this.l) { + e = z(); + for (let d = 0, f; d < this.l.length; d++) { + f = this.l[d], C(f) ? e[f] = b[f] : Y(b, e, f, 0, f[0]); + } + } + this.store[a] = e || b; + } + } + return this; +}; +t.append = function(a, b) { + return this.add(a, b, !0); +}; +t.update = function(a, b) { + return this.remove(a).add(a, b); +}; +t.remove = function(a) { + D(a) && (a = la(a, this.key)); + if (this.register[a]) { + for (let b = 0; b < this.h.length && (this.index[this.h[b]].remove(a, !this.I), !this.D); b++) { + } + this.store && delete this.store[a]; + delete this.register[a]; + } + return this; +}; +t.search = function(a, b, c, e) { + c || (!b && D(a) ? (c = a, a = "") : D(b) && (c = b, b = 0)); + let d = [], f = [], g, h, k, m, n, u, q = 0; + if (c) { + if (c.constructor === Array) { + k = c, c = null; + } else { + a = c.query || a; + k = (g = c.pluck) || c.index || c.field; + m = !1; + h = this.store && c.enrich; + n = "and" === c.bool; + b = c.limit || b || 100; + u = c.offset || 0; + if (m && (C(m) && (m = [m]), !a)) { + for (let l = 0, p; l < m.length; l++) { + if (p = ma.call(this, m[l], b, u, h)) { + d[d.length] = p, q++; + } + } + return q ? d : []; + } + C(k) && (k = [k]); + } + } + k || (k = this.h); + n = n && (1 < k.length || m && 1 < m.length); + const r = !e && (this.I || this.async) && []; + for (let l = 0, p, A, B; l < k.length; l++) { + let y; + A = k[l]; + C(A) || (y = A, A = y.field, a = y.query || a, b = y.limit || b, h = y.enrich || h); + if (r) { + r[l] = this.index[A].searchAsync(a, b, y || c); + } else { + e ? p = e[l] : p = this.index[A].search(a, b, y || c); + B = p && p.length; + if (m && B) { + const x = []; + let G = 0; + n && (x[0] = [p]); + for (let R = 0, fa, N; R < m.length; R++) { + if (fa = m[R], B = (N = this.J[fa]) && N.length) { + G++, x[x.length] = n ? [N] : N; + } + } + G && (p = n ? Q(x, b || 100, u || 0) : ea(p, x), B = p.length); + } + if (B) { + f[q] = A, d[q++] = p; + } else if (n) { + return []; + } + } + } + if (r) { + const l = this; + return new Promise(function(p) { + Promise.all(r).then(function(A) { + p(l.search(a, b, c, A)); + }); + }); + } + if (!q) { + return []; + } + if (g && (!h || !this.store)) { + return d[0]; + } + for (let l = 0, p; l < f.length; l++) { + p = d[l]; + p.length && h && (p = na.call(this, p)); + if (g) { + return p; + } + d[l] = {field:f[l], result:p}; + } + return d; +}; +function ma(a, b, c, e) { + let d = this.J[a], f = d && d.length - c; + if (f && 0 < f) { + if (f > b || c) { + d = d.slice(c, c + b); + } + e && (d = na.call(this, d)); + return {tag:a, result:d}; + } +} +function na(a) { + const b = Array(a.length); + for (let c = 0, e; c < a.length; c++) { + e = a[c], b[c] = {id:e, doc:this.store[e]}; + } + return b; +} +t.contain = function(a) { + return !!this.register[a]; +}; +t.get = function(a) { + return this.store[a]; +}; +t.set = function(a, b) { + this.store[a] = b; + return this; +}; +O(W.prototype); +var pa = {encode:oa, B:!1, C:""}; +const qa = [I("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), "a", I("[\u00e8\u00e9\u00ea\u00eb]"), "e", I("[\u00ec\u00ed\u00ee\u00ef]"), "i", I("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), "o", I("[\u00f9\u00fa\u00fb\u00fc\u0171]"), "u", I("[\u00fd\u0177\u00ff]"), "y", I("\u00f1"), "n", I("[\u00e7c]"), "k", I("\u00df"), "s", I(" & "), " and "]; +function oa(a) { + var b = a = "" + a; + b.normalize && (b = b.normalize("NFD").replace(ca, "")); + return E.call(this, b.toLowerCase(), !a.normalize && qa); +} +;var sa = {encode:ra, B:!1, C:"strict"}; +const ta = /[^a-z0-9]+/, ua = {b:"p", v:"f", w:"f", z:"s", x:"s", "\u00df":"s", d:"t", n:"m", c:"k", g:"k", j:"k", q:"k", i:"e", y:"e", u:"o"}; +function ra(a) { + a = oa.call(this, a).join(" "); + const b = []; + if (a) { + const c = a.split(ta), e = c.length; + for (let d = 0, f, g = 0; d < e; d++) { + if ((a = c[d]) && (!this.filter || !this.filter[a])) { + f = a[0]; + let h = ua[f] || f, k = h; + for (let m = 1; m < a.length; m++) { + f = a[m]; + const n = ua[f] || f; + n && n !== k && (h += n, k = n); + } + b[g++] = h; + } + } + } + return b; +} +;var wa = {encode:va, B:!1, C:""}; +const xa = [I("ae"), "a", I("oe"), "o", I("sh"), "s", I("th"), "t", I("ph"), "f", I("pf"), "f", I("(?![aeo])h(?![aeo])"), "", I("(?!^[aeo])h(?!^[aeo])"), ""]; +function va(a, b) { + a && (a = ra.call(this, a).join(" "), 2 < a.length && (a = F(a, xa)), b || (1 < a.length && (a = J(a)), a && (a = a.split(" ")))); + return a || []; +} +;var za = {encode:ya, B:!1, C:""}; +const Aa = I("(?!\\b)[aeo]"); +function ya(a) { + a && (a = va.call(this, a, !0), 1 < a.length && (a = a.replace(Aa, "")), 1 < a.length && (a = J(a)), a && (a = a.split(" "))); + return a || []; +} +;M["latin:default"] = da; +M["latin:simple"] = pa; +M["latin:balance"] = sa; +M["latin:advanced"] = wa; +M["latin:extra"] = za; +export default {Index:S, Document:W, Worker:null, registerCharset:function(a, b) { + M[a] = b; +}, registerLanguage:function(a, b) { + L[a] = b; +}}; +}(this)); diff --git a/paige/node_modules/flexsearch/dist/flexsearch.compact.module.min.js b/paige/node_modules/flexsearch/dist/flexsearch.compact.module.min.js new file mode 100644 index 00000000..8b69f69a --- /dev/null +++ b/paige/node_modules/flexsearch/dist/flexsearch.compact.module.min.js @@ -0,0 +1,27 @@ +/**! + * FlexSearch.js v0.7.41 (Compact.module) + * Author and Copyright: Thomas Wilkerling + * Licence: Apache-2.0 + * Hosted by Nextapps GmbH + * https://github.com/nextapps-de/flexsearch + */ +(function(self){'use strict';var t;function v(a){return"undefined"!==typeof a?a:!0}function w(a){const b=Array(a);for(let c=0;c=this.m&&(u||!n[l])){var f=T(q,e,r),g="";switch(this.C){case "full":if(2f;h--)if(h-f>=this.m){var k=T(q,e,r,d,f);g=l.substring(f,h);U(this,n,g,k,a,c)}break}case "reverse":if(1=this.m&&U(this,n, +g,T(q,e,r,d,h),a,c);g=""}case "forward":if(1=this.m&&U(this,n,g,f,a,c);break}default:if(this.F&&(f=Math.min(f/this.F(b,l,r)|0,q-1)),U(this,n,l,f,a,c),u&&1=this.m&&!d[l]){d[l]=1;const p=this.h&&l>f;U(this,m,p?f:l,T(g+(e/2>g?0:1),e,r,h-1,k-1),a,c,p?l:f)}}}}this.D||(this.register[a]=1)}}return this}; +function T(a,b,c,e,d){return c&&1=this.m&&!c[q])if(this.s||f||this.map[q])k[u++]=q,c[q]=1;else return e;a=k;d=a.length}if(!d)return e;b||(b=100);h=this.depth&&1=e)))break;if(n){if(f)return ja(k,e,0);b[b.length]=k;return}}return!c&&k}function ja(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} +function ka(a,b,c,e){c?(e=e&&b>c,a=(a=a[e?b:c])&&a[e?c:b]):a=a[b];return a}t.contain=function(a){return!!this.register[a]};t.update=function(a,b){return this.remove(a).add(a,b)};t.remove=function(a,b){const c=this.register[a];if(c){if(this.D)for(let e=0,d;eb||c)d=d.slice(c,c+b);e&&(d=na.call(this,d));return{tag:a,result:d}}}function na(a){const b=Array(a.length);for(let c=0,e;c>> 0) + "_", e = 0; + return b; +}); +y("Symbol.iterator", function(a) { + if (a) { + return a; + } + a = Symbol("Symbol.iterator"); + for (var b = "Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "), c = 0; c < b.length; c++) { + var d = x[b[c]]; + "function" === typeof d && "function" != typeof d.prototype[a] && v(d.prototype, a, {configurable:!0, writable:!0, value:function() { + return ca(aa(this)); + }}); + } + return a; +}); +function ca(a) { + a = {next:a}; + a[Symbol.iterator] = function() { + return this; + }; + return a; +} +function da(a, b) { + a instanceof String && (a += ""); + var c = 0, d = !1, e = {next:function() { + if (!d && c < a.length) { + var g = c++; + return {value:b(g, a[g]), done:!1}; + } + d = !0; + return {done:!0, value:void 0}; + }}; + e[Symbol.iterator] = function() { + return e; + }; + return e; +} +y("Array.prototype.keys", function(a) { + return a ? a : function() { + return da(this, function(b) { + return b; + }); + }; +}); +function ea(a) { + var b = "undefined" != typeof Symbol && Symbol.iterator && a[Symbol.iterator]; + if (b) { + return b.call(a); + } + if ("number" == typeof a.length) { + return {next:aa(a)}; + } + throw Error(String(a) + " is not an iterable or ArrayLike"); +} +y("Promise", function(a) { + function b(f) { + this.l = 0; + this.m = void 0; + this.h = []; + this.M = !1; + var h = this.o(); + try { + f(h.resolve, h.reject); + } catch (k) { + h.reject(k); + } + } + function c() { + this.h = null; + } + function d(f) { + return f instanceof b ? f : new b(function(h) { + h(f); + }); + } + if (a) { + return a; + } + c.prototype.l = function(f) { + if (null == this.h) { + this.h = []; + var h = this; + this.m(function() { + h.D(); + }); + } + this.h.push(f); + }; + var e = x.setTimeout; + c.prototype.m = function(f) { + e(f, 0); + }; + c.prototype.D = function() { + for (; this.h && this.h.length;) { + var f = this.h; + this.h = []; + for (var h = 0; h < f.length; ++h) { + var k = f[h]; + f[h] = null; + try { + k(); + } catch (l) { + this.o(l); + } + } + } + this.h = null; + }; + c.prototype.o = function(f) { + this.m(function() { + throw f; + }); + }; + b.prototype.o = function() { + function f(l) { + return function(m) { + k || (k = !0, l.call(h, m)); + }; + } + var h = this, k = !1; + return {resolve:f(this.S), reject:f(this.D)}; + }; + b.prototype.S = function(f) { + if (f === this) { + this.D(new TypeError("A Promise cannot resolve to itself")); + } else { + if (f instanceof b) { + this.U(f); + } else { + a: { + switch(typeof f) { + case "object": + var h = null != f; + break a; + case "function": + h = !0; + break a; + default: + h = !1; + } + } + h ? this.R(f) : this.I(f); + } + } + }; + b.prototype.R = function(f) { + var h = void 0; + try { + h = f.then; + } catch (k) { + this.D(k); + return; + } + "function" == typeof h ? this.V(h, f) : this.I(f); + }; + b.prototype.D = function(f) { + this.N(2, f); + }; + b.prototype.I = function(f) { + this.N(1, f); + }; + b.prototype.N = function(f, h) { + if (0 != this.l) { + throw Error("Cannot settle(" + f + ", " + h + "): Promise already settled in state" + this.l); + } + this.l = f; + this.m = h; + 2 === this.l && this.T(); + this.O(); + }; + b.prototype.T = function() { + var f = this; + e(function() { + if (f.P()) { + var h = x.console; + "undefined" !== typeof h && h.error(f.m); + } + }, 1); + }; + b.prototype.P = function() { + if (this.M) { + return !1; + } + var f = x.CustomEvent, h = x.Event, k = x.dispatchEvent; + if ("undefined" === typeof k) { + return !0; + } + "function" === typeof f ? f = new f("unhandledrejection", {cancelable:!0}) : "function" === typeof h ? f = new h("unhandledrejection", {cancelable:!0}) : (f = x.document.createEvent("CustomEvent"), f.initCustomEvent("unhandledrejection", !1, !0, f)); + f.promise = this; + f.reason = this.m; + return k(f); + }; + b.prototype.O = function() { + if (null != this.h) { + for (var f = 0; f < this.h.length; ++f) { + g.l(this.h[f]); + } + this.h = null; + } + }; + var g = new c(); + b.prototype.U = function(f) { + var h = this.o(); + f.J(h.resolve, h.reject); + }; + b.prototype.V = function(f, h) { + var k = this.o(); + try { + f.call(h, k.resolve, k.reject); + } catch (l) { + k.reject(l); + } + }; + b.prototype.then = function(f, h) { + function k(n, q) { + return "function" == typeof n ? function(r) { + try { + l(n(r)); + } catch (u) { + m(u); + } + } : q; + } + var l, m, p = new b(function(n, q) { + l = n; + m = q; + }); + this.J(k(f, l), k(h, m)); + return p; + }; + b.prototype.catch = function(f) { + return this.then(void 0, f); + }; + b.prototype.J = function(f, h) { + function k() { + switch(l.l) { + case 1: + f(l.m); + break; + case 2: + h(l.m); + break; + default: + throw Error("Unexpected state: " + l.l); + } + } + var l = this; + null == this.h ? g.l(k) : this.h.push(k); + this.M = !0; + }; + b.resolve = d; + b.reject = function(f) { + return new b(function(h, k) { + k(f); + }); + }; + b.race = function(f) { + return new b(function(h, k) { + for (var l = ea(f), m = l.next(); !m.done; m = l.next()) { + d(m.value).J(h, k); + } + }); + }; + b.all = function(f) { + var h = ea(f), k = h.next(); + return k.done ? d([]) : new b(function(l, m) { + function p(r) { + return function(u) { + n[r] = u; + q--; + 0 == q && l(n); + }; + } + var n = [], q = 0; + do { + n.push(void 0), q++, d(k.value).J(p(n.length - 1), m), k = h.next(); + } while (!k.done); + }); + }; + return b; +}); +y("Object.is", function(a) { + return a ? a : function(b, c) { + return b === c ? 0 !== b || 1 / b === 1 / c : b !== b && c !== c; + }; +}); +y("Array.prototype.includes", function(a) { + return a ? a : function(b, c) { + var d = this; + d instanceof String && (d = String(d)); + var e = d.length; + c = c || 0; + for (0 > c && (c = Math.max(c + e, 0)); c < e; c++) { + var g = d[c]; + if (g === b || Object.is(g, b)) { + return !0; + } + } + return !1; + }; +}); +y("String.prototype.includes", function(a) { + return a ? a : function(b, c) { + if (null == this) { + throw new TypeError("The 'this' value for String.prototype.includes must not be null or undefined"); + } + if (b instanceof RegExp) { + throw new TypeError("First argument to String.prototype.includes must not be a regular expression"); + } + return -1 !== this.indexOf(b, c || 0); + }; +}); +var fa = "function" == typeof Object.assign ? Object.assign : function(a, b) { + for (var c = 1; c < arguments.length; c++) { + var d = arguments[c]; + if (d) { + for (var e in d) { + Object.prototype.hasOwnProperty.call(d, e) && (a[e] = d[e]); + } + } + } + return a; +}; +y("Object.assign", function(a) { + return a || fa; +}); +function C(a) { + return "undefined" !== typeof a ? a : !0; +} +function ha(a) { + for (var b = Array(a), c = 0; c < a; c++) { + b[c] = D(); + } + return b; +} +function D() { + return Object.create(null); +} +function ia(a, b) { + return b.length - a.length; +} +function E(a) { + return "string" === typeof a; +} +function F(a) { + return "object" === typeof a; +} +function G(a) { + return "function" === typeof a; +} +;function ja(a, b) { + var c = ka; + if (a && (b && (a = I(a, b)), this.K && (a = I(a, this.K)), this.L && 1 < a.length && (a = I(a, this.L)), c || "" === c)) { + a = a.split(c); + if (this.filter) { + b = this.filter; + c = a.length; + for (var d = [], e = 0, g = 0; e < c; e++) { + var f = a[e]; + f && !b[f] && (d[g++] = f); + } + a = d; + } + return a; + } + return a; +} +var ka = /[\p{Z}\p{S}\p{P}\p{C}]+/u, la = /[\u0300-\u036f]/g; +function ma(a, b) { + for (var c = Object.keys(a), d = c.length, e = [], g = "", f = 0, h = 0, k, l; h < d; h++) { + k = c[h], (l = a[k]) ? (e[f++] = J(b ? "(?!\\b)" + k + "(\\b|_)" : k), e[f++] = l) : g += (g ? "|" : "") + k; + } + g && (e[f++] = J(b ? "(?!\\b)(" + g + ")(\\b|_)" : "(" + g + ")"), e[f] = ""); + return e; +} +function I(a, b) { + for (var c = 0, d = b.length; c < d && (a = a.replace(b[c], b[c + 1]), a); c += 2) { + } + return a; +} +function J(a) { + return new RegExp(a, "g"); +} +function na(a) { + for (var b = "", c = "", d = 0, e = a.length, g = void 0; d < e; d++) { + (g = a[d]) !== c && (b += c = g); + } + return b; +} +;var pa = {encode:oa, G:!1, H:""}; +function oa(a) { + return ja.call(this, ("" + a).toLowerCase(), !1); +} +;var qa = {}, K = {}; +function ra(a) { + L(a, "add"); + L(a, "append"); + L(a, "search"); + L(a, "update"); + L(a, "remove"); +} +function L(a, b) { + a[b + "Async"] = function() { + var c = this, d = arguments, e = d[d.length - 1]; + if (G(e)) { + var g = e; + delete d[d.length - 1]; + } + e = new Promise(function(f) { + setTimeout(function() { + c.async = !0; + var h = c[b].apply(c, d); + c.async = !1; + f(h); + }); + }); + return g ? (e.then(g), this) : e; + }; +} +;function sa(a, b, c, d) { + var e = a.length, g = [], f, h = 0; + d && (d = []); + for (var k = e - 1; 0 <= k; k--) { + for (var l = a[k], m = l.length, p = D(), n = !B, q = 0; q < m; q++) { + var r = l[q], u = r.length; + if (u) { + for (var A = 0, w, z; A < u; A++) { + if (z = r[A], B) { + if (B[z]) { + if (!k) { + if (c) { + c--; + } else { + if (g[h++] = z, h === b) { + return g; + } + } + } + if (k || d) { + p[z] = 1; + } + n = !0; + } + d && (w = (f[z] || 0) + 1, f[z] = w, w < e && (w = d[w - 2] || (d[w - 2] = []), w[w.length] = z)); + } else { + p[z] = 1; + } + } + } + } + if (d) { + B || (f = p); + } else if (!n) { + return []; + } + var B = p; + } + if (d) { + for (a = d.length - 1; 0 <= a; a--) { + for (e = d[a], f = e.length, k = 0; k < f; k++) { + if (l = e[k], !B[l]) { + if (c) { + c--; + } else { + if (g[h++] = l, h === b) { + return g; + } + } + B[l] = 1; + } + } + } + } + return g; +} +function ta(a, b) { + for (var c = D(), d = D(), e = [], g = 0; g < a.length; g++) { + c[a[g]] = 1; + } + for (a = 0; a < b.length; a++) { + g = b[a]; + for (var f = 0, h; f < g.length; f++) { + h = g[f], c[h] && !d[h] && (d[h] = 1, e[e.length] = h); + } + } + return e; +} +;function M(a) { + this.l = !0 !== a && a; + this.cache = D(); + this.h = []; +} +function ua(a, b, c) { + F(a) && (a = a.query); + var d = this.cache.get(a); + d || (d = this.search(a, b, c), this.cache.set(a, d)); + return d; +} +M.prototype.set = function(a, b) { + if (!this.cache[a]) { + var c = this.h.length; + c === this.l ? delete this.cache[this.h[c - 1]] : c++; + for (--c; 0 < c; c--) { + this.h[c] = this.h[c - 1]; + } + this.h[0] = a; + } + this.cache[a] = b; +}; +M.prototype.get = function(a) { + var b = this.cache[a]; + if (this.l && b && (a = this.h.indexOf(a))) { + var c = this.h[a - 1]; + this.h[a - 1] = this.h[a]; + this.h[a] = c; + } + return b; +}; +var va = {memory:{charset:"latin:extra", F:3, C:4, s:!1}, performance:{F:3, C:3, B:!1, context:{depth:2, F:1}}, match:{charset:"latin:extra", H:"reverse"}, score:{charset:"latin:advanced", F:20, C:3, context:{depth:3, F:9}}, "default":{}}; +function wa(a, b, c, d, e, g, f, h) { + setTimeout(function() { + var k = a(c ? c + "." + d : d, JSON.stringify(f)); + k && k.then ? k.then(function() { + b.export(a, b, c, e, g + 1, h); + }) : b.export(a, b, c, e, g + 1, h); + }); +} +;function N(a, b) { + if (!(this instanceof N)) { + return new N(a); + } + var c; + if (a) { + if (E(a)) { + va[a] || console.warn("Preset not found: " + a), a = va[a]; + } else { + if (c = a.preset) { + c[c] || console.warn("Preset not found: " + c), a = Object.assign({}, c[c], a); + } + } + c = a.charset; + var d = a.lang; + E(c) && (-1 === c.indexOf(":") && (c += ":default"), c = K[c]); + E(d) && (d = qa[d]); + } else { + a = {}; + } + var e, g, f = a.context || {}; + this.encode = a.encode || c && c.encode || oa; + this.register = b || D(); + this.F = e = a.resolution || 9; + this.H = b = c && c.H || a.tokenize || "strict"; + this.depth = "strict" === b && f.depth; + this.l = C(f.bidirectional); + this.B = g = C(a.optimize); + this.s = C(a.fastupdate); + this.C = a.minlength || 1; + this.o = a.boost; + this.map = g ? ha(e) : D(); + this.m = e = f.resolution || 1; + this.h = g ? ha(e) : D(); + this.G = c && c.G || a.rtl; + this.K = (b = a.matcher || d && d.K) && ma(b, !1); + this.L = (b = a.stemmer || d && d.L) && ma(b, !0); + if (c = b = a.filter || d && d.filter) { + c = b; + d = D(); + f = 0; + for (e = c.length; f < e; f++) { + d[c[f]] = 1; + } + c = d; + } + this.filter = c; + this.cache = (b = a.cache) && new M(b); +} +t = N.prototype; +t.append = function(a, b) { + return this.add(a, b, !0); +}; +t.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); + if (d = b.length) { + for (var e = D(), g = D(), f = this.depth, h = this.F, k = 0; k < d; k++) { + var l = b[this.G ? d - 1 - k : k], m = l.length; + if (l && m >= this.C && (f || !g[l])) { + var p = O(h, d, k), n = ""; + switch(this.H) { + case "full": + if (2 < m) { + for (p = 0; p < m; p++) { + for (var q = m; q > p; q--) { + if (q - p >= this.C) { + var r = O(h, d, k, m, p); + n = l.substring(p, q); + P(this, g, n, r, a, c); + } + } + } + break; + } + case "reverse": + if (1 < m) { + for (q = m - 1; 0 < q; q--) { + n = l[q] + n, n.length >= this.C && P(this, g, n, O(h, d, k, m, q), a, c); + } + n = ""; + } + case "forward": + if (1 < m) { + for (q = 0; q < m; q++) { + n += l[q], n.length >= this.C && P(this, g, n, p, a, c); + } + break; + } + default: + if (this.o && (p = Math.min(p / this.o(b, l, k) | 0, h - 1)), P(this, g, l, p, a, c), f && 1 < d && k < d - 1) { + for (m = D(), n = this.m, p = l, q = Math.min(f + 1, d - k), r = m[p] = 1; r < q; r++) { + if ((l = b[this.G ? d - 1 - k - r : k + r]) && l.length >= this.C && !m[l]) { + m[l] = 1; + var u = this.l && l > p; + P(this, e, u ? p : l, O(n + (d / 2 > n ? 0 : 1), d, k, q - 1, r - 1), a, c, u ? l : p); + } + } + } + } + } + } + this.s || (this.register[a] = 1); + } + } + return this; +}; +function O(a, b, c, d, e) { + return c && 1 < a ? b + (d || 0) <= a ? c + (e || 0) : (a - 1) / (b + (d || 0)) * (c + (e || 0)) + 1 | 0 : 0; +} +function P(a, b, c, d, e, g, f) { + var h = f ? a.h : a.map; + if (!b[c] || f && !b[c][f]) { + a.B && (h = h[d]), f ? (b = b[c] || (b[c] = D()), b[f] = 1, h = h[f] || (h[f] = D())) : b[c] = 1, h = h[c] || (h[c] = []), a.B || (h = h[d] || (h[d] = [])), g && h.includes(e) || (h[h.length] = e, a.s && (a = a.register[e] || (a.register[e] = []), a[a.length] = h)); + } +} +t.search = function(a, b, c) { + c || (!b && F(a) ? (c = a, a = c.query) : F(b) && (c = b)); + var d = [], e = 0; + if (c) { + a = c.query || a; + b = c.limit; + e = c.offset || 0; + var g = c.context; + var f = c.suggest; + } + if (a) { + a = this.encode("" + a); + var h = a.length; + if (1 < h) { + c = D(); + for (var k = [], l = 0, m = 0, p; l < h; l++) { + if ((p = a[l]) && p.length >= this.C && !c[p]) { + if (this.B || f || this.map[p]) { + k[m++] = p, c[p] = 1; + } else { + return d; + } + } + } + a = k; + h = a.length; + } + } + if (!h) { + return d; + } + b || (b = 100); + g = this.depth && 1 < h && !1 !== g; + c = 0; + if (g) { + var n = a[0]; + c = 1; + } else { + 1 < h && a.sort(ia); + } + for (; c < h; c++) { + l = a[c]; + g ? (k = xa(this, d, f, b, e, 2 === h, l, n), f && !1 === k && d.length || (n = l)) : k = xa(this, d, f, b, e, 1 === h, l); + if (k) { + return k; + } + if (f && c === h - 1) { + k = d.length; + if (!k) { + if (g) { + g = 0; + c = -1; + continue; + } + return d; + } + if (1 === k) { + return ya(d[0], b, e); + } + } + } + return sa(d, b, e, f); +}; +function xa(a, b, c, d, e, g, f, h) { + var k = [], l = h ? a.h : a.map; + a.B || (l = za(l, f, h, a.l)); + if (l) { + for (var m = 0, p = Math.min(l.length, h ? a.m : a.F), n = 0, q = 0, r, u; n < p; n++) { + if (r = l[n]) { + if (a.B && (r = za(r, f, h, a.l)), e && r && g && (u = r.length, u <= e ? (e -= u, r = null) : (r = r.slice(e), e = 0)), r && (k[m++] = r, g && (q += r.length, q >= d))) { + break; + } + } + } + if (m) { + if (g) { + return ya(k, d, 0); + } + b[b.length] = k; + return; + } + } + return !c && k; +} +function ya(a, b, c) { + a = 1 === a.length ? a[0] : [].concat.apply([], a); + return c || a.length > b ? a.slice(c, c + b) : a; +} +function za(a, b, c, d) { + c ? (d = d && b > c, a = (a = a[d ? b : c]) && a[d ? c : b]) : a = a[b]; + return a; +} +t.contain = function(a) { + return !!this.register[a]; +}; +t.update = function(a, b) { + return this.remove(a).add(a, b); +}; +t.remove = function(a, b) { + var c = this.register[a]; + if (c) { + if (this.s) { + for (var d = 0, e; d < c.length; d++) { + e = c[d], e.splice(e.indexOf(a), 1); + } + } else { + Q(this.map, a, this.F, this.B), this.depth && Q(this.h, a, this.m, this.B); + } + b || delete this.register[a]; + if (this.cache) { + for (b = this.cache, c = 0; c < b.h.length; c++) { + e = b.h[c], d = b.cache[e], d.includes(a) && (b.h.splice(c--, 1), delete b.cache[e]); + } + } + } + return this; +}; +function Q(a, b, c, d, e) { + var g = 0; + if (a.constructor === Array) { + if (e) { + b = a.indexOf(b), -1 !== b ? 1 < a.length && (a.splice(b, 1), g++) : g++; + } else { + e = Math.min(a.length, c); + for (var f = 0, h; f < e; f++) { + if (h = a[f]) { + g = Q(h, b, c, d, e), d || g || delete a[f]; + } + } + } + } else { + for (f in a) { + (g = Q(a[f], b, c, d, e)) || delete a[f]; + } + } + return g; +} +t.searchCache = ua; +t.export = function(a, b, c, d, e, g) { + var f = !0; + "undefined" === typeof g && (f = new Promise(function(m) { + g = m; + })); + switch(e || (e = 0)) { + case 0: + var h = "reg"; + if (this.s) { + var k = D(); + for (var l in this.register) { + k[l] = 1; + } + } else { + k = this.register; + } + break; + case 1: + h = "cfg"; + k = {doc:0, opt:this.B ? 1 : 0}; + break; + case 2: + h = "map"; + k = this.map; + break; + case 3: + h = "ctx"; + k = this.h; + break; + default: + "undefined" === typeof c && g && g(); + return; + } + wa(a, b || this, c, h, d, e, k, g); + return f; +}; +t.import = function(a, b) { + if (b) { + switch(E(b) && (b = JSON.parse(b)), a) { + case "cfg": + this.B = !!b.opt; + break; + case "reg": + this.s = !1; + this.register = b; + break; + case "map": + this.map = b; + break; + case "ctx": + this.h = b; + } + } +}; +ra(N.prototype); +function Aa(a) { + a = a.data; + var b = self._index, c = a.args, d = a.task; + switch(d) { + case "init": + d = a.options || {}; + a = a.factory; + b = d.encode; + d.cache = !1; + b && 0 === b.indexOf("function") && (d.encode = Function("return " + b)()); + a ? (Function("return " + a)()(self), self._index = new self.FlexSearch.Index(d), delete self.FlexSearch) : self._index = new N(d); + break; + default: + a = a.id, b = b[d].apply(b, c), postMessage("search" === d ? {id:a, msg:b} : {id:a}); + } +} +;var Ba = 0; +function R(a) { + if (!(this instanceof R)) { + return new R(a); + } + var b; + a ? G(b = a.encode) && (a.encode = b.toString()) : a = {}; + (b = (self || window)._factory) && (b = b.toString()); + var c = "undefined" === typeof window && self.exports, d = this; + this.A = Ca(b, c, a.worker); + this.h = D(); + if (this.A) { + if (c) { + this.A.on("message", function(e) { + d.h[e.id](e.msg); + delete d.h[e.id]; + }); + } else { + this.A.onmessage = function(e) { + e = e.data; + d.h[e.id](e.msg); + delete d.h[e.id]; + }; + } + this.A.postMessage({task:"init", factory:b, options:a}); + } +} +S("add"); +S("append"); +S("search"); +S("update"); +S("remove"); +function S(a) { + R.prototype[a] = R.prototype[a + "Async"] = function() { + var b = this, c = [].slice.call(arguments), d = c[c.length - 1]; + if (G(d)) { + var e = d; + c.splice(c.length - 1, 1); + } + d = new Promise(function(g) { + setTimeout(function() { + b.h[++Ba] = g; + b.A.postMessage({task:a, id:Ba, args:c}); + }); + }); + return e ? (d.then(e), this) : d; + }; +} +function Ca(a, b, c) { + try { + var d = b ? new (require("worker_threads")["Worker"])(__dirname + "/node/node.js") : a ? new Worker(URL.createObjectURL(new Blob(["onmessage=" + Aa.toString()], {type:"text/javascript"}))) : new Worker(E(c) ? c : "worker/worker.js", {type:"module"}); + } catch (e) { + } + return d; +} +;function T(a) { + if (!(this instanceof T)) { + return new T(a); + } + var b = a.document || a.doc || a, c; + this.I = []; + this.h = []; + this.m = []; + this.register = D(); + this.key = (c = b.key || b.id) && U(c, this.m) || "id"; + this.s = C(a.fastupdate); + this.o = (c = b.store) && !0 !== c && []; + this.store = c && D(); + this.D = (c = b.tag) && U(c, this.m); + this.l = c && D(); + this.cache = (c = a.cache) && new M(c); + a.cache = !1; + this.A = a.worker; + this.async = !1; + c = D(); + var d = b.index || b.field || b; + E(d) && (d = [d]); + for (var e = 0, g, f = void 0; e < d.length; e++) { + g = d[e], E(g) || (f = g, g = g.field), f = F(f) ? Object.assign({}, a, f) : a, this.A && (c[g] = new R(f), c[g].A || (this.A = !1)), this.A || (c[g] = new N(f, this.register)), this.I[e] = U(g, this.m), this.h[e] = g; + } + if (this.o) { + for (a = b.store, E(a) && (a = [a]), b = 0; b < a.length; b++) { + this.o[b] = U(a[b], this.m); + } + } + this.index = c; +} +function U(a, b) { + for (var c = a.split(":"), d = 0, e = 0; e < c.length; e++) { + a = c[e], 0 <= a.indexOf("[]") && (a = a.substring(0, a.length - 2)) && (b[d] = !0), a && (c[d++] = a); + } + d < c.length && (c.length = d); + return 1 < d ? c : c[0]; +} +function V(a, b) { + if (E(b)) { + a = a[b]; + } else { + for (var c = 0; a && c < b.length; c++) { + a = a[b[c]]; + } + } + return a; +} +function W(a, b, c, d, e) { + a = a[e]; + if (d === c.length - 1) { + b[e] = a; + } else if (a) { + if (a.constructor === Array) { + for (b = b[e] = Array(a.length), e = 0; e < a.length; e++) { + W(a, b, c, d, e); + } + } else { + b = b[e] || (b[e] = D()), e = c[++d], W(a, b, c, d, e); + } + } +} +function X(a, b, c, d, e, g, f, h) { + if (a = a[f]) { + if (d === b.length - 1) { + if (a.constructor === Array) { + if (c[d]) { + for (b = 0; b < a.length; b++) { + e.add(g, a[b], !0, !0); + } + return; + } + a = a.join(" "); + } + e.add(g, a, h, !0); + } else { + if (a.constructor === Array) { + for (f = 0; f < a.length; f++) { + X(a, b, c, d, e, g, f, h); + } + } else { + f = b[++d], X(a, b, c, d, e, g, f, h); + } + } + } +} +t = T.prototype; +t.add = function(a, b, c) { + F(a) && (b = a, a = V(b, this.key)); + if (b && (a || 0 === a)) { + if (!c && this.register[a]) { + return this.update(a, b); + } + for (var d = 0, e, g; d < this.h.length; d++) { + g = this.h[d], e = this.I[d], E(e) && (e = [e]), X(b, e, this.m, 0, this.index[g], a, e[0], c); + } + if (this.D) { + d = V(b, this.D); + e = D(); + E(d) && (d = [d]); + g = 0; + for (var f; g < d.length; g++) { + if (f = d[g], !e[f] && (e[f] = 1, f = this.l[f] || (this.l[f] = []), !c || !f.includes(a))) { + if (f[f.length] = a, this.s) { + var h = this.register[a] || (this.register[a] = []); + h[h.length] = f; + } + } + } + } + if (this.store && (!c || !this.store[a])) { + if (this.o) { + var k = D(); + for (c = 0; c < this.o.length; c++) { + d = this.o[c], E(d) ? k[d] = b[d] : W(b, k, d, 0, d[0]); + } + } + this.store[a] = k || b; + } + } + return this; +}; +t.append = function(a, b) { + return this.add(a, b, !0); +}; +t.update = function(a, b) { + return this.remove(a).add(a, b); +}; +t.remove = function(a) { + F(a) && (a = V(a, this.key)); + if (this.register[a]) { + for (var b = 0; b < this.h.length && (this.index[this.h[b]].remove(a, !this.A), !this.s); b++) { + } + if (this.D && !this.s) { + for (var c in this.l) { + b = this.l[c]; + var d = b.indexOf(a); + -1 !== d && (1 < b.length ? b.splice(d, 1) : delete this.l[c]); + } + } + this.store && delete this.store[a]; + delete this.register[a]; + } + return this; +}; +t.search = function(a, b, c, d) { + c || (!b && F(a) ? (c = a, a = "") : F(b) && (c = b, b = 0)); + var e = [], g = [], f, h = 0; + if (c) { + if (c.constructor === Array) { + var k = c; + c = null; + } else { + a = c.query || a; + k = (f = c.pluck) || c.index || c.field; + var l = c.tag; + var m = this.store && c.enrich; + var p = "and" === c.bool; + b = c.limit || b || 100; + var n = c.offset || 0; + if (l && (E(l) && (l = [l]), !a)) { + g = 0; + for (f = void 0; g < l.length; g++) { + if (f = Da.call(this, l[g], b, n, m)) { + e[e.length] = f, h++; + } + } + return h ? e : []; + } + E(k) && (k = [k]); + } + } + k || (k = this.h); + p = p && (1 < k.length || l && 1 < l.length); + for (var q = !d && (this.A || this.async) && [], r = 0, u = void 0, A = void 0, w = void 0; r < k.length; r++) { + if (w = void 0, A = k[r], E(A) || (w = A, A = w.field, a = w.query || a, b = w.limit || b, m = w.enrich || m), q) { + q[r] = this.index[A].searchAsync(a, b, w || c); + } else { + d ? u = d[r] : u = this.index[A].search(a, b, w || c); + w = u && u.length; + if (l && w) { + var z = [], B = 0; + p && (z[0] = [u]); + var Y = 0, H = void 0; + for (H = void 0; Y < l.length; Y++) { + if (H = l[Y], w = (H = this.l[H]) && H.length) { + B++, z[z.length] = p ? [H] : H; + } + } + B && (u = p ? sa(z, b || 100, n || 0) : ta(u, z), w = u.length); + } + if (w) { + g[h] = A, e[h++] = u; + } else if (p) { + return []; + } + } + } + if (q) { + var Ka = this; + return new Promise(function(La) { + Promise.all(q).then(function(Ma) { + La(Ka.search(a, b, c, Ma)); + }); + }); + } + if (!h) { + return []; + } + if (f && (!m || !this.store)) { + return e[0]; + } + l = 0; + for (n = void 0; l < g.length; l++) { + n = e[l]; + n.length && m && (n = Ea.call(this, n)); + if (f) { + return n; + } + e[l] = {field:g[l], result:n}; + } + return e; +}; +function Da(a, b, c, d) { + var e = this.l[a], g = e && e.length - c; + if (g && 0 < g) { + if (g > b || c) { + e = e.slice(c, c + b); + } + d && (e = Ea.call(this, e)); + return {tag:a, result:e}; + } +} +function Ea(a) { + for (var b = Array(a.length), c = 0, d; c < a.length; c++) { + d = a[c], b[c] = {id:d, doc:this.store[d]}; + } + return b; +} +t.contain = function(a) { + return !!this.register[a]; +}; +t.get = function(a) { + return this.store[a]; +}; +t.set = function(a, b) { + this.store[a] = b; + return this; +}; +t.searchCache = ua; +t.export = function(a, b, c, d, e, g) { + var f; + "undefined" === typeof g && (f = new Promise(function(p) { + g = p; + })); + e || (e = 0); + d || (d = 0); + if (d < this.h.length) { + var h = this.h[d], k = this.index[h]; + b = this; + setTimeout(function() { + k.export(a, b, e ? h : "", d, e++, g) || (d++, e = 1, b.export(a, b, h, d, e, g)); + }); + } else { + switch(e) { + case 1: + var l = "tag"; + var m = this.l; + c = null; + break; + case 2: + l = "store"; + m = this.store; + c = null; + break; + default: + g(); + return; + } + wa(a, this, c, l, d, e, m, g); + } + return f; +}; +t.import = function(a, b) { + if (b) { + switch(E(b) && (b = JSON.parse(b)), a) { + case "tag": + this.l = b; + break; + case "reg": + this.s = !1; + this.register = b; + a = 0; + for (var c; a < this.h.length; a++) { + c = this.index[this.h[a]], c.register = b, c.s = !1; + } + break; + case "store": + this.store = b; + break; + default: + a = a.split("."), c = a[0], a = a[1], c && a && this.index[c].import(a, b); + } + } +}; +ra(T.prototype); +var Ga = {encode:Fa, G:!1, H:""}, Ha = [J("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), "a", J("[\u00e8\u00e9\u00ea\u00eb]"), "e", J("[\u00ec\u00ed\u00ee\u00ef]"), "i", J("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), "o", J("[\u00f9\u00fa\u00fb\u00fc\u0171]"), "u", J("[\u00fd\u0177\u00ff]"), "y", J("\u00f1"), "n", J("[\u00e7c]"), "k", J("\u00df"), "s", J(" & "), " and "]; +function Fa(a) { + var b = a = "" + a; + b.normalize && (b = b.normalize("NFD").replace(la, "")); + return ja.call(this, b.toLowerCase(), !a.normalize && Ha); +} +;var Ja = {encode:Ia, G:!1, H:"strict"}, Na = /[^a-z0-9]+/, Oa = {b:"p", v:"f", w:"f", z:"s", x:"s", "\u00df":"s", d:"t", n:"m", c:"k", g:"k", j:"k", q:"k", i:"e", y:"e", u:"o"}; +function Ia(a) { + a = Fa.call(this, a).join(" "); + var b = []; + if (a) { + for (var c = a.split(Na), d = c.length, e = 0, g, f = 0; e < d; e++) { + if ((a = c[e]) && (!this.filter || !this.filter[a])) { + g = a[0]; + for (var h = Oa[g] || g, k = h, l = 1; l < a.length; l++) { + g = a[l], (g = Oa[g] || g) && g !== k && (h += g, k = g); + } + b[f++] = h; + } + } + } + return b; +} +;var Qa = {encode:Pa, G:!1, H:""}, Ra = [J("ae"), "a", J("oe"), "o", J("sh"), "s", J("th"), "t", J("ph"), "f", J("pf"), "f", J("(?![aeo])h(?![aeo])"), "", J("(?!^[aeo])h(?!^[aeo])"), ""]; +function Pa(a, b) { + a && (a = Ia.call(this, a).join(" "), 2 < a.length && (a = I(a, Ra)), b || (1 < a.length && (a = na(a)), a && (a = a.split(" ")))); + return a || []; +} +;var Ta = {encode:Sa, G:!1, H:""}, Ua = J("(?!\\b)[aeo]"); +function Sa(a) { + a && (a = Pa.call(this, a, !0), 1 < a.length && (a = a.replace(Ua, "")), 1 < a.length && (a = na(a)), a && (a = a.split(" "))); + return a || []; +} +;K["latin:default"] = pa; +K["latin:simple"] = Ga; +K["latin:balance"] = Ja; +K["latin:advanced"] = Qa; +K["latin:extra"] = Ta; +var Z = {Index:N, Document:T, Worker:R, registerCharset:function(a, b) { + K[a] = b; +}, registerLanguage:function(a, b) { + qa[a] = b; +}}, Va; +(Va = self.define) && Va.amd ? Va([], function() { + return Z; +}) : self.exports ? self.exports = Z : self.FlexSearch = Z; +}(this)); diff --git a/paige/node_modules/flexsearch/dist/flexsearch.es5.min.js b/paige/node_modules/flexsearch/dist/flexsearch.es5.min.js new file mode 100644 index 00000000..0f1857e5 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/flexsearch.es5.min.js @@ -0,0 +1,48 @@ +/**! + * FlexSearch.js v0.7.41 (Es5) + * Author and Copyright: Thomas Wilkerling + * Licence: Apache-2.0 + * Hosted by Nextapps GmbH + * https://github.com/nextapps-de/flexsearch + */ +(function(self){'use strict';var t;function aa(a){var b=0;return function(){return b>>0)+"_",e=0;return b}); +y("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),c=0;cc&&(c=Math.max(c+e,0));c=this.C&&(f||!g[l])){var p=O(h,d,k),n="";switch(this.H){case "full":if(2p;q--)if(q-p>=this.C){var r=O(h,d,k,m,p);n=l.substring(p,q);P(this,g,n,r,a,c)}break}case "reverse":if(1=this.C&&P(this,g,n,O(h,d,k, +m,q),a,c);n=""}case "forward":if(1=this.C&&P(this,g,n,p,a,c);break}default:if(this.o&&(p=Math.min(p/this.o(b,l,k)|0,h-1)),P(this,g,l,p,a,c),f&&1=this.C&&!m[l]){m[l]=1;var u=this.l&&l>p;P(this,e,u?p:l,O(n+(d/2>n?0:1),d,k,q-1,r-1),a,c,u?l:p)}}}}this.s||(this.register[a]=1)}}return this}; +function O(a,b,c,d,e){return c&&1=this.C&&!c[p])if(this.B||f||this.map[p])k[m++]=p,c[p]=1;else return d;a=k;h=a.length}}if(!h)return d;b||(b=100);g=this.depth&&1=d)))break;if(m){if(g)return ya(k,d,0);b[b.length]=k;return}}return!c&&k}function ya(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} +function za(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a}t.contain=function(a){return!!this.register[a]};t.update=function(a,b){return this.remove(a).add(a,b)}; +t.remove=function(a,b){var c=this.register[a];if(c){if(this.s)for(var d=0,e;db||c)e=e.slice(c,c+b);d&&(e=Ea.call(this,e));return{tag:a,result:e}}}function Ea(a){for(var b=Array(a.length),c=0,d;c= this.h && (r || !m[k])) { + var h = J(p, d, q), f = ""; + switch(this.B) { + case "full": + if (2 < e) { + for (h = 0; h < e; h++) { + for (var g = e; g > h; g--) { + if (g - h >= this.h) { + var l = J(p, d, q, e, h); + f = k.substring(h, g); + K(this, m, f, l, a, c); + } + } + } + break; + } + case "reverse": + if (1 < e) { + for (g = e - 1; 0 < g; g--) { + f = k[g] + f, f.length >= this.h && K(this, m, f, J(p, d, q, e, g), a, c); + } + f = ""; + } + case "forward": + if (1 < e) { + for (g = 0; g < e; g++) { + f += k[g], f.length >= this.h && K(this, m, f, h, a, c); + } + break; + } + default: + if (this.C && (h = Math.min(h / this.C(b, k, q) | 0, p - 1)), K(this, m, k, h, a, c), r && 1 < d && q < d - 1) { + for (e = y(), f = this.v, h = k, g = Math.min(r + 1, d - q), e[h] = 1, l = 1; l < g; l++) { + if ((k = b[this.u ? d - 1 - q - l : q + l]) && k.length >= this.h && !e[k]) { + e[k] = 1; + const u = this.j && k > h; + K(this, n, u ? h : k, J(f + (d / 2 > f ? 0 : 1), d, q, g - 1, l - 1), a, c, u ? k : h); + } + } + } + } + } + } + this.m || (this.register[a] = 1); + } + } + return this; +}; +function J(a, b, c, d, e) { + return c && 1 < a ? b + (d || 0) <= a ? c + (e || 0) : (a - 1) / (b + (d || 0)) * (c + (e || 0)) + 1 | 0 : 0; +} +function K(a, b, c, d, e, h, f) { + let g = f ? a.l : a.map; + if (!b[c] || f && !b[c][f]) { + a.g && (g = g[d]), f ? (b = b[c] || (b[c] = y()), b[f] = 1, g = g[f] || (g[f] = y())) : b[c] = 1, g = g[c] || (g[c] = []), a.g || (g = g[d] || (g[d] = [])), h && g.includes(e) || (g[g.length] = e, a.m && (a = a.register[e] || (a.register[e] = []), a[a.length] = g)); + } +} +I.prototype.search = function(a, b, c) { + c || (b || "object" !== typeof a ? "object" === typeof b && (c = b) : (c = a, a = c.query)); + let d = [], e; + let h, f = 0; + if (c) { + a = c.query || a; + b = c.limit; + f = c.offset || 0; + var g = c.context; + h = !1; + } + if (a && (a = this.encode("" + a), e = a.length, 1 < e)) { + c = y(); + var l = []; + for (let m = 0, r = 0, p; m < e; m++) { + if ((p = a[m]) && p.length >= this.h && !c[p]) { + if (this.g || h || this.map[p]) { + l[r++] = p, c[p] = 1; + } else { + return d; + } + } + } + a = l; + e = a.length; + } + if (!e) { + return d; + } + b || (b = 100); + g = this.i && 1 < e && !1 !== g; + c = 0; + let n; + g ? (n = a[0], c = 1) : 1 < e && a.sort(z); + for (let m, r; c < e; c++) { + r = a[c]; + g ? (m = N(this, d, h, b, f, 2 === e, r, n), h && !1 === m && d.length || (n = r)) : m = N(this, d, h, b, f, 1 === e, r); + if (m) { + return m; + } + if (h && c === e - 1) { + l = d.length; + if (!l) { + if (g) { + g = 0; + c = -1; + continue; + } + return d; + } + if (1 === l) { + return O(d[0], b, f); + } + } + } + return H(d, b, f, h); +}; +function N(a, b, c, d, e, h, f, g) { + let l = [], n = g ? a.l : a.map; + a.g || (n = P(n, f, g, a.j)); + if (n) { + let m = 0; + const r = Math.min(n.length, g ? a.v : a.s); + for (let p = 0, q = 0, k, u; p < r; p++) { + if (k = n[p]) { + if (a.g && (k = P(k, f, g, a.j)), e && k && h && (u = k.length, u <= e ? (e -= u, k = null) : (k = k.slice(e), e = 0)), k && (l[m++] = k, h && (q += k.length, q >= d))) { + break; + } + } + } + if (m) { + if (h) { + return O(l, d, 0); + } + b[b.length] = l; + return; + } + } + return !c && l; +} +function O(a, b, c) { + a = 1 === a.length ? a[0] : [].concat.apply([], a); + return c || a.length > b ? a.slice(c, c + b) : a; +} +function P(a, b, c, d) { + c ? (d = d && b > c, a = (a = a[d ? b : c]) && a[d ? c : b]) : a = a[b]; + return a; +} +I.prototype.contain = function(a) { + return !!this.register[a]; +}; +I.prototype.update = function(a, b) { + return this.remove(a).add(a, b); +}; +I.prototype.remove = function(a, b) { + const c = this.register[a]; + if (c) { + if (this.m) { + for (let d = 0, e; d < c.length; d++) { + e = c[d], e.splice(e.indexOf(a), 1); + } + } else { + Q(this.map, a, this.s, this.g), this.i && Q(this.l, a, this.v, this.g); + } + b || delete this.register[a]; + } + return this; +}; +function Q(a, b, c, d, e) { + let h = 0; + if (a.constructor === Array) { + if (e) { + b = a.indexOf(b), -1 !== b ? 1 < a.length && (a.splice(b, 1), h++) : h++; + } else { + e = Math.min(a.length, c); + for (let f = 0, g; f < e; f++) { + if (g = a[f]) { + h = Q(g, b, c, d, e), d || h || delete a[f]; + } + } + } + } else { + for (let f in a) { + (h = Q(a[f], b, c, d, e)) || delete a[f]; + } + } + return h; +} +;const R = {Index:I, Document:null, Worker:null, registerCharset:function(a, b) { + G[a] = b; +}, registerLanguage:function(a, b) { + F[a] = b; +}}; +let S; +(S = self.define) && S.amd ? S([], function() { + return R; +}) : self.exports ? self.exports = R : self.FlexSearch = R; +}(this)); diff --git a/paige/node_modules/flexsearch/dist/flexsearch.light.min.js b/paige/node_modules/flexsearch/dist/flexsearch.light.min.js new file mode 100644 index 00000000..26454d2e --- /dev/null +++ b/paige/node_modules/flexsearch/dist/flexsearch.light.min.js @@ -0,0 +1,18 @@ +/**! + * FlexSearch.js v0.7.41 (Light) + * Author and Copyright: Thomas Wilkerling + * Licence: Apache-2.0 + * Hosted by Nextapps GmbH + * https://github.com/nextapps-de/flexsearch + */ +(function(self){'use strict';function t(a){return"undefined"!==typeof a?a:!0}function v(a){const b=Array(a);for(let c=0;c=this.h&&(r||!m[k])){var h=J(p,d,q),f="";switch(this.B){case "full":if(2h;g--)if(g-h>=this.h){var l=J(p,d,q,e,h);f=k.substring(h,g);K(this,m,f,l,a,c)}break}case "reverse":if(1=this.h&&K(this, +m,f,J(p,d,q,e,g),a,c);f=""}case "forward":if(1=this.h&&K(this,m,f,h,a,c);break}default:if(this.C&&(h=Math.min(h/this.C(b,k,q)|0,p-1)),K(this,m,k,h,a,c),r&&1=this.h&&!e[k]){e[k]=1;const u=this.j&&k>h;K(this,n,u?h:k,J(f+(d/2>f?0:1),d,q,g-1,l-1),a,c,u?k:h)}}}}this.m||(this.register[a]=1)}}return this}; +function J(a,b,c,d,e){return c&&1=this.h&&!c[p])if(this.g||h||this.map[p])l[r++]=p,c[p]=1;else return d;a=l;e=a.length}if(!e)return d;b||(b=100);g=this.i&&1=d)))break;if(m){if(h)return O(l,d,0);b[b.length]=l;return}}return!c&&l}function O(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} +function P(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a}I.prototype.contain=function(a){return!!this.register[a]};I.prototype.update=function(a,b){return this.remove(a).add(a,b)};I.prototype.remove=function(a,b){const c=this.register[a];if(c){if(this.m)for(let d=0,e;d= this.h && (r || !m[k])) { + var h = L(p, d, q), f = ""; + switch(this.B) { + case "full": + if (2 < e) { + for (h = 0; h < e; h++) { + for (var g = e; g > h; g--) { + if (g - h >= this.h) { + var l = L(p, d, q, e, h); + f = k.substring(h, g); + M(this, m, f, l, a, c); + } + } + } + break; + } + case "reverse": + if (1 < e) { + for (g = e - 1; 0 < g; g--) { + f = k[g] + f, f.length >= this.h && M(this, m, f, L(p, d, q, e, g), a, c); + } + f = ""; + } + case "forward": + if (1 < e) { + for (g = 0; g < e; g++) { + f += k[g], f.length >= this.h && M(this, m, f, h, a, c); + } + break; + } + default: + if (this.C && (h = Math.min(h / this.C(b, k, q) | 0, p - 1)), M(this, m, k, h, a, c), r && 1 < d && q < d - 1) { + for (e = y(), f = this.v, h = k, g = Math.min(r + 1, d - q), e[h] = 1, l = 1; l < g; l++) { + if ((k = b[this.u ? d - 1 - q - l : q + l]) && k.length >= this.h && !e[k]) { + e[k] = 1; + const u = this.j && k > h; + M(this, n, u ? h : k, L(f + (d / 2 > f ? 0 : 1), d, q, g - 1, l - 1), a, c, u ? k : h); + } + } + } + } + } + } + this.m || (this.register[a] = 1); + } + } + return this; +}; +function L(a, b, c, d, e) { + return c && 1 < a ? b + (d || 0) <= a ? c + (e || 0) : (a - 1) / (b + (d || 0)) * (c + (e || 0)) + 1 | 0 : 0; +} +function M(a, b, c, d, e, h, f) { + let g = f ? a.l : a.map; + if (!b[c] || f && !b[c][f]) { + a.g && (g = g[d]), f ? (b = b[c] || (b[c] = y()), b[f] = 1, g = g[f] || (g[f] = y())) : b[c] = 1, g = g[c] || (g[c] = []), a.g || (g = g[d] || (g[d] = [])), h && g.includes(e) || (g[g.length] = e, a.m && (a = a.register[e] || (a.register[e] = []), a[a.length] = g)); + } +} +I.prototype.search = function(a, b, c) { + c || (b || "object" !== typeof a ? "object" === typeof b && (c = b) : (c = a, a = c.query)); + let d = [], e; + let h, f = 0; + if (c) { + a = c.query || a; + b = c.limit; + f = c.offset || 0; + var g = c.context; + h = !1; + } + if (a && (a = this.encode("" + a), e = a.length, 1 < e)) { + c = y(); + var l = []; + for (let m = 0, r = 0, p; m < e; m++) { + if ((p = a[m]) && p.length >= this.h && !c[p]) { + if (this.g || h || this.map[p]) { + l[r++] = p, c[p] = 1; + } else { + return d; + } + } + } + a = l; + e = a.length; + } + if (!e) { + return d; + } + b || (b = 100); + g = this.i && 1 < e && !1 !== g; + c = 0; + let n; + g ? (n = a[0], c = 1) : 1 < e && a.sort(z); + for (let m, r; c < e; c++) { + r = a[c]; + g ? (m = N(this, d, h, b, f, 2 === e, r, n), h && !1 === m && d.length || (n = r)) : m = N(this, d, h, b, f, 1 === e, r); + if (m) { + return m; + } + if (h && c === e - 1) { + l = d.length; + if (!l) { + if (g) { + g = 0; + c = -1; + continue; + } + return d; + } + if (1 === l) { + return O(d[0], b, f); + } + } + } + return H(d, b, f, h); +}; +function N(a, b, c, d, e, h, f, g) { + let l = [], n = g ? a.l : a.map; + a.g || (n = P(n, f, g, a.j)); + if (n) { + let m = 0; + const r = Math.min(n.length, g ? a.v : a.s); + for (let p = 0, q = 0, k, u; p < r; p++) { + if (k = n[p]) { + if (a.g && (k = P(k, f, g, a.j)), e && k && h && (u = k.length, u <= e ? (e -= u, k = null) : (k = k.slice(e), e = 0)), k && (l[m++] = k, h && (q += k.length, q >= d))) { + break; + } + } + } + if (m) { + if (h) { + return O(l, d, 0); + } + b[b.length] = l; + return; + } + } + return !c && l; +} +function O(a, b, c) { + a = 1 === a.length ? a[0] : [].concat.apply([], a); + return c || a.length > b ? a.slice(c, c + b) : a; +} +function P(a, b, c, d) { + c ? (d = d && b > c, a = (a = a[d ? b : c]) && a[d ? c : b]) : a = a[b]; + return a; +} +I.prototype.contain = function(a) { + return !!this.register[a]; +}; +I.prototype.update = function(a, b) { + return this.remove(a).add(a, b); +}; +I.prototype.remove = function(a, b) { + const c = this.register[a]; + if (c) { + if (this.m) { + for (let d = 0, e; d < c.length; d++) { + e = c[d], e.splice(e.indexOf(a), 1); + } + } else { + Q(this.map, a, this.s, this.g), this.i && Q(this.l, a, this.v, this.g); + } + b || delete this.register[a]; + } + return this; +}; +function Q(a, b, c, d, e) { + let h = 0; + if (a.constructor === Array) { + if (e) { + b = a.indexOf(b), -1 !== b ? 1 < a.length && (a.splice(b, 1), h++) : h++; + } else { + e = Math.min(a.length, c); + for (let f = 0, g; f < e; f++) { + if (g = a[f]) { + h = Q(g, b, c, d, e), d || h || delete a[f]; + } + } + } + } else { + for (let f in a) { + (h = Q(a[f], b, c, d, e)) || delete a[f]; + } + } + return h; +} +;export default {Index:I, Document:null, Worker:null, registerCharset:function(a, b) { + G[a] = b; +}, registerLanguage:function(a, b) { + F[a] = b; +}}; + diff --git a/paige/node_modules/flexsearch/dist/flexsearch.light.module.min.js b/paige/node_modules/flexsearch/dist/flexsearch.light.module.min.js new file mode 100644 index 00000000..fe7705e6 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/flexsearch.light.module.min.js @@ -0,0 +1,18 @@ +/**! + * FlexSearch.js v0.7.41 (Light.module) + * Author and Copyright: Thomas Wilkerling + * Licence: Apache-2.0 + * Hosted by Nextapps GmbH + * https://github.com/nextapps-de/flexsearch + */ +function t(a){return"undefined"!==typeof a?a:!0}function v(a){const b=Array(a);for(let c=0;c=this.h&&(r||!m[k])){var h=L(p,d,q),f="";switch(this.B){case "full":if(2h;g--)if(g-h>=this.h){var l=L(p,d,q,e,h);f=k.substring(h,g);M(this,m,f,l,a,c)}break}case "reverse":if(1=this.h&&M(this, +m,f,L(p,d,q,e,g),a,c);f=""}case "forward":if(1=this.h&&M(this,m,f,h,a,c);break}default:if(this.C&&(h=Math.min(h/this.C(b,k,q)|0,p-1)),M(this,m,k,h,a,c),r&&1=this.h&&!e[k]){e[k]=1;const u=this.j&&k>h;M(this,n,u?h:k,L(f+(d/2>f?0:1),d,q,g-1,l-1),a,c,u?k:h)}}}}this.m||(this.register[a]=1)}}return this}; +function L(a,b,c,d,e){return c&&1=this.h&&!c[p])if(this.g||h||this.map[p])l[r++]=p,c[p]=1;else return d;a=l;e=a.length}if(!e)return d;b||(b=100);g=this.i&&1=d)))break;if(m){if(h)return O(l,d,0);b[b.length]=l;return}}return!c&&l}function O(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a} +function P(a,b,c,d){c?(d=d&&b>c,a=(a=a[d?b:c])&&a[d?c:b]):a=a[b];return a}I.prototype.contain=function(a){return!!this.register[a]};I.prototype.update=function(a,b){return this.remove(a).add(a,b)};I.prototype.remove=function(a,b){const c=this.register[a];if(c){if(this.m)for(let d=0,e;d} + */ + +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]; + } + } +}; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/common.js b/paige/node_modules/flexsearch/dist/module-debug/common.js new file mode 100644 index 00000000..95e4ace7 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/common.js @@ -0,0 +1,78 @@ +export function parse_option(value, default_value) { + + return "undefined" != typeof value ? value : default_value; +} + +/** + * @param {!number} count + * @returns {Array} + */ + +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} + */ + +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/document.js b/paige/node_modules/flexsearch/dist/module-debug/document.js new file mode 100644 index 00000000..e0f7196b --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/document.js @@ -0,0 +1,731 @@ +/**! + * 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=} _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); \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/engine.js b/paige/node_modules/flexsearch/dist/module-debug/engine.js new file mode 100644 index 00000000..d460eda2 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/engine.js @@ -0,0 +1,35 @@ + +import { searchCache } from "./cache"; + +/** + * @constructor + * @abstract + */ + +function Engine(index) { + + //if(this.constructor === Engine){ + if (this instanceof Engine) { + + throw new Error("Can't instantiate abstract class!"); + } + + + 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; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/global.js b/paige/node_modules/flexsearch/dist/module-debug/global.js new file mode 100644 index 00000000..bd7da48c --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/global.js @@ -0,0 +1,22 @@ +export const global_lang = {}; +export const global_charset = {}; + +/** + * @param {!string} name + * @param {Object} charset + */ + +export function registerCharset(name, charset) { + + global_charset[name] = charset; +} + +/** + * @param {!string} name + * @param {Object} lang + */ + +export function registerLanguage(name, lang) { + + global_lang[name] = lang; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/index.js b/paige/node_modules/flexsearch/dist/module-debug/index.js new file mode 100644 index 00000000..d6f87034 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/index.js @@ -0,0 +1,784 @@ +/**! + * 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} + */ + +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} */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>|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); \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/intersect.js b/paige/node_modules/flexsearch/dist/module-debug/intersect.js new file mode 100644 index 00000000..29357477 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/intersect.js @@ -0,0 +1,394 @@ +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang.js b/paige/node_modules/flexsearch/dist/module-debug/lang.js new file mode 100644 index 00000000..954ae861 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang.js @@ -0,0 +1,321 @@ +import { IndexInterface } from "./type.js"; +import { create_object, get_keys } from "./common.js"; + +/** + * @param {!string} str + * @param {boolean|Array=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} _collapse + * @returns {string|Array} + * @this IndexInterface + */ + +export function pipeline(str, normalize, split, _collapse) { + + if (str) { + + if (normalize) { + + str = replace(str, /** @type {Array} */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=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} _collapse + * @returns {string|Array} + */ + +// FlexSearch.prototype.pipeline = function(str, normalize, split, _collapse){ +// +// if(str){ +// +// if(normalize && str){ +// +// str = replace(str, /** @type {Array} */ (normalize)); +// } +// +// if(str && this.matcher){ +// +// str = replace(str, this.matcher); +// } +// +// if(this.stemmer && str.length > 1){ +// +// str = replace(str, this.stemmer); +// } +// +// if(_collapse && str.length > 1){ +// +// str = collapse(str); +// } +// +// if(str){ +// +// if(split || (split === "")){ +// +// const words = str.split(/** @type {string|RegExp} */ (split)); +// +// return this.filter ? filter(words, this.filter) : words; +// } +// } +// } +// +// return str; +// }; + +// export function pipeline(str, normalize, matcher, stemmer, split, _filter, _collapse){ +// +// if(str){ +// +// if(normalize && str){ +// +// str = replace(str, normalize); +// } +// +// if(matcher && str){ +// +// str = replace(str, matcher); +// } +// +// if(stemmer && str.length > 1){ +// +// str = replace(str, stemmer); +// } +// +// if(_collapse && str.length > 1){ +// +// str = collapse(str); +// } +// +// if(str){ +// +// if(split !== false){ +// +// str = str.split(split); +// +// if(_filter){ +// +// str = filter(str, _filter); +// } +// } +// } +// } +// +// return str; +// } + + +/** + * @param {Array} words + * @returns {Object} + */ + +export function init_filter(words) { + + const filter = create_object(); + + for (let i = 0, length = words.length; i < length; i++) { + + filter[words[i]] = 1; + } + + return filter; +} + +/** + * @param {!Object} obj + * @param {boolean} is_stemmer + * @returns {Array} + */ + +export function init_stemmer_or_matcher(obj, is_stemmer) { + const keys = 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; +// } \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/arabic/default.js b/paige/node_modules/flexsearch/dist/module-debug/lang/arabic/default.js new file mode 100644 index 00000000..89f65a6f --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/arabic/default.js @@ -0,0 +1,27 @@ +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); +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/at.js b/paige/node_modules/flexsearch/dist/module-debug/lang/at.js new file mode 100644 index 00000000..af404df6 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/at.js @@ -0,0 +1,41 @@ +/** + * http://www.ranks.nl/stopwords + * @type {Array} + */ + +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} + */ + +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 +}; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/cjk/default.js b/paige/node_modules/flexsearch/dist/module-debug/lang/cjk/default.js new file mode 100644 index 00000000..a0e94f2e --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/cjk/default.js @@ -0,0 +1,26 @@ +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); +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/cyrillic/default.js b/paige/node_modules/flexsearch/dist/module-debug/lang/cyrillic/default.js new file mode 100644 index 00000000..de452638 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/cyrillic/default.js @@ -0,0 +1,27 @@ +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); +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/de.js b/paige/node_modules/flexsearch/dist/module-debug/lang/de.js new file mode 100644 index 00000000..8196777f --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/de.js @@ -0,0 +1,54 @@ +/** + * 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} + */ + +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} + */ + +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>} + */ + +export const matcher = {}; + +export default { + + filter: filter, + stemmer: stemmer, + matcher: matcher +}; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/en.js b/paige/node_modules/flexsearch/dist/module-debug/lang/en.js new file mode 100644 index 00000000..7b1ba3ac --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/en.js @@ -0,0 +1,100 @@ +/** + * http://www.ranks.nl/stopwords + * @type {Array} + */ + +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} + */ + +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 +}; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/latin/advanced.js b/paige/node_modules/flexsearch/dist/module-debug/lang/latin/advanced.js new file mode 100644 index 00000000..94f5cb1c --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/latin/advanced.js @@ -0,0 +1,89 @@ +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 || []; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/latin/balance.js b/paige/node_modules/flexsearch/dist/module-debug/lang/latin/balance.js new file mode 100644 index 00000000..10de393b --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/latin/balance.js @@ -0,0 +1,119 @@ +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/latin/default.js b/paige/node_modules/flexsearch/dist/module-debug/lang/latin/default.js new file mode 100644 index 00000000..dac5a9cc --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/latin/default.js @@ -0,0 +1,23 @@ +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); +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/latin/extra.js b/paige/node_modules/flexsearch/dist/module-debug/lang/latin/extra.js new file mode 100644 index 00000000..c55ea6ab --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/latin/extra.js @@ -0,0 +1,65 @@ +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 || []; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/latin/simple.js b/paige/node_modules/flexsearch/dist/module-debug/lang/latin/simple.js new file mode 100644 index 00000000..1b9ca40b --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/latin/simple.js @@ -0,0 +1,45 @@ +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); +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/lang/us.js b/paige/node_modules/flexsearch/dist/module-debug/lang/us.js new file mode 100644 index 00000000..7b1ba3ac --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/lang/us.js @@ -0,0 +1,100 @@ +/** + * http://www.ranks.nl/stopwords + * @type {Array} + */ + +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} + */ + +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 +}; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/polyfill.js b/paige/node_modules/flexsearch/dist/module-debug/polyfill.js new file mode 100644 index 00000000..e8c7408f --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/polyfill.js @@ -0,0 +1,74 @@ + +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/preset.js b/paige/node_modules/flexsearch/dist/module-debug/preset.js new file mode 100644 index 00000000..0ea59f9f --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/preset.js @@ -0,0 +1,97 @@ + +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)) { + + if (!preset[options]) { + + console.warn("Preset not found: " + options); + } + + options = preset[options]; + } else { + + const preset = options.preset; + + if (preset) { + + if (!preset[preset]) { + + console.warn("Preset not found: " + preset); + } + + options = Object.assign({}, preset[preset], /** @type {Object} */options); + } + } + + return options; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/serialize.js b/paige/node_modules/flexsearch/dist/module-debug/serialize.js new file mode 100644 index 00000000..0baab853 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/serialize.js @@ -0,0 +1,271 @@ +// 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); + } + } +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/type.js b/paige/node_modules/flexsearch/dist/module-debug/type.js new file mode 100644 index 00000000..1a784b30 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/type.js @@ -0,0 +1,69 @@ +/** + * @interface + */ + +export function IndexInterface() { + + this.cache = null; + this.matcher = null; + this.stemmer = null; + this.filter = null; +} + +/** + * @param {!string} str + * @param {boolean|Array=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} collapse + * @returns {string|Array} + */ + +//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} + */ + +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/worker/handler.js b/paige/node_modules/flexsearch/dist/module-debug/worker/handler.js new file mode 100644 index 00000000..914439c3 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/worker/handler.js @@ -0,0 +1,52 @@ +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 }); + } +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/worker/index.js b/paige/node_modules/flexsearch/dist/module-debug/worker/index.js new file mode 100644 index 00000000..5f42c56f --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/worker/index.js @@ -0,0 +1,136 @@ +//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"])(__dirname + "/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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/worker/node.js b/paige/node_modules/flexsearch/dist/module-debug/worker/node.js new file mode 100644 index 00000000..53260185 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/worker/node.js @@ -0,0 +1,36 @@ +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 }); + } +}); \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-debug/worker/worker.js b/paige/node_modules/flexsearch/dist/module-debug/worker/worker.js new file mode 100644 index 00000000..7d295f28 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-debug/worker/worker.js @@ -0,0 +1,2 @@ +import handler from "./handler.js"; +onmessage = handler; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-min/async.js b/paige/node_modules/flexsearch/dist/module-min/async.js new file mode 100644 index 00000000..98133006 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-min/async.js @@ -0,0 +1 @@ +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}} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module-min/cache.js b/paige/node_modules/flexsearch/dist/module-min/cache.js new file mode 100644 index 00000000..07f45533 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module-min/cache.js @@ -0,0 +1 @@ +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=this.minlength&&(g||!f[i])){let l=get_score(h,e,j),m="";switch(this.tokenize){case"full":if(2b;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=this.minlength){const d=get_score(h,e,j,k,b);this.push_index(f,m,d,a,c)}m=""}case"forward":if(1=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=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=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=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{f=a}));let h,i;switch(e||(e=0)){case 0:if(h="reg",this.fastupdate)for(let a in i=create_object(),this.register)i[a]=1;else i=this.register;break;case 1:h="cfg",i={doc:0,opt:this.optimize?1:0};break;case 2:h="map",i=this.map;break;case 3:h="ctx",i=this.ctx;break;default:return void("undefined"==typeof c&&f&&f());}return async(a,b||this,c,h,d,e,i,f),g}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,f){let g;if("undefined"==typeof f&&(g=new Promise(a=>{f=a})),e||(e=0),d||(d=0),d} + */ + +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]; + } + } +}; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/common.js b/paige/node_modules/flexsearch/dist/module/common.js new file mode 100644 index 00000000..95e4ace7 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/common.js @@ -0,0 +1,78 @@ +export function parse_option(value, default_value) { + + return "undefined" != typeof value ? value : default_value; +} + +/** + * @param {!number} count + * @returns {Array} + */ + +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} + */ + +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/document.js b/paige/node_modules/flexsearch/dist/module/document.js new file mode 100644 index 00000000..e0f7196b --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/document.js @@ -0,0 +1,731 @@ +/**! + * 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=} _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); \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/engine.js b/paige/node_modules/flexsearch/dist/module/engine.js new file mode 100644 index 00000000..715226b3 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/engine.js @@ -0,0 +1,28 @@ + +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; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/global.js b/paige/node_modules/flexsearch/dist/module/global.js new file mode 100644 index 00000000..bd7da48c --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/global.js @@ -0,0 +1,22 @@ +export const global_lang = {}; +export const global_charset = {}; + +/** + * @param {!string} name + * @param {Object} charset + */ + +export function registerCharset(name, charset) { + + global_charset[name] = charset; +} + +/** + * @param {!string} name + * @param {Object} lang + */ + +export function registerLanguage(name, lang) { + + global_lang[name] = lang; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/index.js b/paige/node_modules/flexsearch/dist/module/index.js new file mode 100644 index 00000000..d6f87034 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/index.js @@ -0,0 +1,784 @@ +/**! + * 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} + */ + +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} */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>|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); \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/intersect.js b/paige/node_modules/flexsearch/dist/module/intersect.js new file mode 100644 index 00000000..29357477 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/intersect.js @@ -0,0 +1,394 @@ +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang.js b/paige/node_modules/flexsearch/dist/module/lang.js new file mode 100644 index 00000000..954ae861 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang.js @@ -0,0 +1,321 @@ +import { IndexInterface } from "./type.js"; +import { create_object, get_keys } from "./common.js"; + +/** + * @param {!string} str + * @param {boolean|Array=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} _collapse + * @returns {string|Array} + * @this IndexInterface + */ + +export function pipeline(str, normalize, split, _collapse) { + + if (str) { + + if (normalize) { + + str = replace(str, /** @type {Array} */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=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} _collapse + * @returns {string|Array} + */ + +// FlexSearch.prototype.pipeline = function(str, normalize, split, _collapse){ +// +// if(str){ +// +// if(normalize && str){ +// +// str = replace(str, /** @type {Array} */ (normalize)); +// } +// +// if(str && this.matcher){ +// +// str = replace(str, this.matcher); +// } +// +// if(this.stemmer && str.length > 1){ +// +// str = replace(str, this.stemmer); +// } +// +// if(_collapse && str.length > 1){ +// +// str = collapse(str); +// } +// +// if(str){ +// +// if(split || (split === "")){ +// +// const words = str.split(/** @type {string|RegExp} */ (split)); +// +// return this.filter ? filter(words, this.filter) : words; +// } +// } +// } +// +// return str; +// }; + +// export function pipeline(str, normalize, matcher, stemmer, split, _filter, _collapse){ +// +// if(str){ +// +// if(normalize && str){ +// +// str = replace(str, normalize); +// } +// +// if(matcher && str){ +// +// str = replace(str, matcher); +// } +// +// if(stemmer && str.length > 1){ +// +// str = replace(str, stemmer); +// } +// +// if(_collapse && str.length > 1){ +// +// str = collapse(str); +// } +// +// if(str){ +// +// if(split !== false){ +// +// str = str.split(split); +// +// if(_filter){ +// +// str = filter(str, _filter); +// } +// } +// } +// } +// +// return str; +// } + + +/** + * @param {Array} words + * @returns {Object} + */ + +export function init_filter(words) { + + const filter = create_object(); + + for (let i = 0, length = words.length; i < length; i++) { + + filter[words[i]] = 1; + } + + return filter; +} + +/** + * @param {!Object} obj + * @param {boolean} is_stemmer + * @returns {Array} + */ + +export function init_stemmer_or_matcher(obj, is_stemmer) { + const keys = 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; +// } \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/arabic/default.js b/paige/node_modules/flexsearch/dist/module/lang/arabic/default.js new file mode 100644 index 00000000..89f65a6f --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/arabic/default.js @@ -0,0 +1,27 @@ +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); +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/at.js b/paige/node_modules/flexsearch/dist/module/lang/at.js new file mode 100644 index 00000000..af404df6 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/at.js @@ -0,0 +1,41 @@ +/** + * http://www.ranks.nl/stopwords + * @type {Array} + */ + +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} + */ + +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 +}; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/cjk/default.js b/paige/node_modules/flexsearch/dist/module/lang/cjk/default.js new file mode 100644 index 00000000..a0e94f2e --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/cjk/default.js @@ -0,0 +1,26 @@ +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); +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/cyrillic/default.js b/paige/node_modules/flexsearch/dist/module/lang/cyrillic/default.js new file mode 100644 index 00000000..de452638 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/cyrillic/default.js @@ -0,0 +1,27 @@ +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); +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/de.js b/paige/node_modules/flexsearch/dist/module/lang/de.js new file mode 100644 index 00000000..8196777f --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/de.js @@ -0,0 +1,54 @@ +/** + * 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} + */ + +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} + */ + +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>} + */ + +export const matcher = {}; + +export default { + + filter: filter, + stemmer: stemmer, + matcher: matcher +}; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/en.js b/paige/node_modules/flexsearch/dist/module/lang/en.js new file mode 100644 index 00000000..7b1ba3ac --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/en.js @@ -0,0 +1,100 @@ +/** + * http://www.ranks.nl/stopwords + * @type {Array} + */ + +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} + */ + +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 +}; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/latin/advanced.js b/paige/node_modules/flexsearch/dist/module/lang/latin/advanced.js new file mode 100644 index 00000000..94f5cb1c --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/latin/advanced.js @@ -0,0 +1,89 @@ +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 || []; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/latin/balance.js b/paige/node_modules/flexsearch/dist/module/lang/latin/balance.js new file mode 100644 index 00000000..10de393b --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/latin/balance.js @@ -0,0 +1,119 @@ +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/latin/default.js b/paige/node_modules/flexsearch/dist/module/lang/latin/default.js new file mode 100644 index 00000000..dac5a9cc --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/latin/default.js @@ -0,0 +1,23 @@ +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); +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/latin/extra.js b/paige/node_modules/flexsearch/dist/module/lang/latin/extra.js new file mode 100644 index 00000000..c55ea6ab --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/latin/extra.js @@ -0,0 +1,65 @@ +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 || []; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/latin/simple.js b/paige/node_modules/flexsearch/dist/module/lang/latin/simple.js new file mode 100644 index 00000000..1b9ca40b --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/latin/simple.js @@ -0,0 +1,45 @@ +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); +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/lang/us.js b/paige/node_modules/flexsearch/dist/module/lang/us.js new file mode 100644 index 00000000..7b1ba3ac --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/lang/us.js @@ -0,0 +1,100 @@ +/** + * http://www.ranks.nl/stopwords + * @type {Array} + */ + +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} + */ + +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 +}; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/polyfill.js b/paige/node_modules/flexsearch/dist/module/polyfill.js new file mode 100644 index 00000000..e8c7408f --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/polyfill.js @@ -0,0 +1,74 @@ + +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/preset.js b/paige/node_modules/flexsearch/dist/module/preset.js new file mode 100644 index 00000000..5101a980 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/preset.js @@ -0,0 +1,87 @@ + +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/serialize.js b/paige/node_modules/flexsearch/dist/module/serialize.js new file mode 100644 index 00000000..0baab853 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/serialize.js @@ -0,0 +1,271 @@ +// 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); + } + } +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/type.js b/paige/node_modules/flexsearch/dist/module/type.js new file mode 100644 index 00000000..1a784b30 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/type.js @@ -0,0 +1,69 @@ +/** + * @interface + */ + +export function IndexInterface() { + + this.cache = null; + this.matcher = null; + this.stemmer = null; + this.filter = null; +} + +/** + * @param {!string} str + * @param {boolean|Array=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} collapse + * @returns {string|Array} + */ + +//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} + */ + +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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/worker/handler.js b/paige/node_modules/flexsearch/dist/module/worker/handler.js new file mode 100644 index 00000000..914439c3 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/worker/handler.js @@ -0,0 +1,52 @@ +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 }); + } +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/worker/index.js b/paige/node_modules/flexsearch/dist/module/worker/index.js new file mode 100644 index 00000000..5f42c56f --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/worker/index.js @@ -0,0 +1,136 @@ +//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"])(__dirname + "/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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/worker/node.js b/paige/node_modules/flexsearch/dist/module/worker/node.js new file mode 100644 index 00000000..53260185 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/worker/node.js @@ -0,0 +1,36 @@ +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 }); + } +}); \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/module/worker/worker.js b/paige/node_modules/flexsearch/dist/module/worker/worker.js new file mode 100644 index 00000000..7d295f28 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/module/worker/worker.js @@ -0,0 +1,2 @@ +import handler from "./handler.js"; +onmessage = handler; \ No newline at end of file diff --git a/paige/node_modules/flexsearch/dist/node/node.js b/paige/node_modules/flexsearch/dist/node/node.js new file mode 100644 index 00000000..8a8a4688 --- /dev/null +++ b/paige/node_modules/flexsearch/dist/node/node.js @@ -0,0 +1,35 @@ +const { parentPort } = require("worker_threads"); +const { Index } = require("../flexsearch.bundle.min.js"); + +let index; + +parentPort.on("message", function(data){ + + /** @type Index */ + const args = data["args"]; + const task = data["task"]; + const id = data["id"]; + + switch(task){ + + case "init": + + const options = data["options"] || {}; + const encode = options["encode"]; + + options["cache"] = false; + + if(encode && (encode.indexOf("function") === 0)){ + + options["encode"] = new Function("return " + encode)(); + } + + index = new Index(options); + break; + + default: + + const message = index[task].apply(index, args); + parentPort.postMessage(task === "search" ? { "id": id, "msg": message } : { "id": id }); + } +}); diff --git a/paige/node_modules/flexsearch/index.d.ts b/paige/node_modules/flexsearch/index.d.ts new file mode 100644 index 00000000..9b321db0 --- /dev/null +++ b/paige/node_modules/flexsearch/index.d.ts @@ -0,0 +1,428 @@ +declare module "flexsearch" { + // Type definitions for flexsearch 0.7 + // Project: https://github.com/nextapps-de/flexsearch/ + // Definitions by: LOSSES Don + // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + + /************************************/ + /* Utils */ + /************************************/ + export type Id = number | string; + export type Limit = number; + export type ExportHandler = (id: string | number, value: T) => void; + export type AsyncCallback = T extends undefined + ? () => void + : (result: T) => void; + export type UnknownFunction = (...x: unknown[]) => unknown; + + export type StoreOption = boolean | string | string[]; + export type EnrichStoreOption = true | string | string[]; + + /************************************/ + /* Common Options */ + /************************************/ + + /** + * **Document:** + * * Presets: https://github.com/nextapps-de/flexsearch#presets + */ + export type Preset = "memory" | "performance" | "match" | "score" | "default"; + + /** + * **Document:** + * * Tokenizer: https://github.com/nextapps-de/flexsearch#tokenizer-prefix-search + * * Add custom tokenizer: https://github.com/nextapps-de/flexsearch#add-custom-tokenizer + */ + export type Tokenizer = + | "strict" + | "forward" + | "reverse" + | "full" + | ((x: string) => string[]); + + /** + * **Document:** + * * Encoders: https://github.com/nextapps-de/flexsearch#encoders + */ + export type Encoders = + | false + | "default" + | "simple" + | "balance" + | "advanced" + | "extra" + | ((x: string) => string[]); + + /** + * **Document:** + * * Contextual search: https://github.com/nextapps-de/flexsearch#contextual + */ + export interface ContextOptions { + resolution: number; + depth: false | number; + bidirectional: boolean; + } + + /** + * **Document:** + * * Search options: https://github.com/nextapps-de/flexsearch#search-options + */ + export interface SearchOptions { + query?: string; + limit?: number; + offset?: number; + suggest?: boolean; + } + + /** + * **Document:** + * * The document descriptor: https://github.com/nextapps-de/flexsearch#the-document-descriptor + */ + export interface Descriptor { + id: string | number; + field: string[] | Array>; + } + + /** + * **Document:** + * * Context Options: https://github.com/nextapps-de/flexsearch#context-options + */ + export interface ContextOptions { + resolution: number; + depth: false | number; + bidirectional: boolean; + } + + /** + * **Document:** + * * Charset options: https://github.com/nextapps-de/flexsearch#charset-options + */ + export interface CharsetOptions { + split: false | string | RegExp; + rtl: boolean; + encode: (x: string) => string[]; + } + + export interface Stemmer { + [key: string]: string; + } + + export interface Matcher { + [key: string]: string; + } + + export type FilterFunction = (x: string) => boolean; + export type FilterArray = string[]; + + /** + * **Document:** + * * Language Options: https://github.com/nextapps-de/flexsearch#language-options + * * Language: https://github.com/nextapps-de/flexsearch#languages + */ + export interface LanguageOptions { + stemmer: false | string | Stemmer | UnknownFunction; + filter: false | string | FilterArray | FilterFunction; + matcher: false | string | Matcher | UnknownFunction; + } + + /** + * These options will determine how the documents be indexed. + * + * **Generic type parameters:** + * + * @template T The type of the document. + * @template Store If store is enabled. + * + * **Document:** + * * Index options: https://github.com/nextapps-de/flexsearch#index-options + * * Language: https://github.com/nextapps-de/flexsearch#languages + */ + export interface IndexOptions { + preset?: Preset; + tokenize?: Tokenizer; + cache?: boolean | number; + resolution?: number; + context?: boolean | IndexOptions | ContextOptions; + optimize?: boolean; + boost?: (words: string[], term: string, index: number) => number; + + // Language-specific Options and Encoding + charset?: CharsetOptions | string; + language?: LanguageOptions | string; + encode?: Encoders; + stemmer?: LanguageOptions["stemmer"]; + filter?: LanguageOptions["filter"]; + matcher?: LanguageOptions["matcher"]; + } + + /************************************/ + /* Index Search */ + /************************************/ + + export type IndexSearchResult = Id[]; + + /** + * **Document:** + * * Basic usage and variants: https://github.com/nextapps-de/flexsearch#basic-usage-and-variants + * * API overview: https://github.com/nextapps-de/flexsearch#api-overview + * * Usage: https://github.com/nextapps-de/flexsearch#usage + */ + + export class Index { + constructor(x?: Preset | IndexOptions); + add(id: Id, item: string): this; + append(id: Id, item: string): this; + update(id: Id, item: string): this; + remove(target: Id): this; + search(query: string, options?: Limit | SearchOptions): IndexSearchResult; + search( + query: string, + limit: number, + options: SearchOptions + ): IndexSearchResult; + search(options: SearchOptions): IndexSearchResult; + + // https://github.com/nextapps-de/flexsearch#check-existence-of-already-indexed-ids + contain(id: Id): boolean; + + export(handler: ExportHandler): Promise; + import(id: Id, item: string): Promise; + + // Async Methods + addAsync( + id: Id, + item: string, + callback?: AsyncCallback + ): Promise; + appendAsync( + id: Id, + item: string, + callback?: AsyncCallback + ): Promise; + updateAsync( + id: Id, + item: string, + callback?: AsyncCallback + ): Promise; + removeAsync(target: Id, callback?: AsyncCallback): Promise; + searchAsync( + query: string, + options?: Limit | SearchOptions, + callback?: AsyncCallback + ): Promise; + searchAsync( + query: string, + limit: number, + options?: Limit | SearchOptions + ): IndexSearchResult; + searchAsync(options: SearchOptions): Promise; + } + + /** + * **Document:** + * * Basic usage and variants: https://github.com/nextapps-de/flexsearch#basic-usage-and-variants + * * API overview: https://github.com/nextapps-de/flexsearch#api-overview + * * Worker index: https://github.com/nextapps-de/flexsearch#worker-index + */ + export class Worker { + constructor(x?: Preset | IndexOptions); + + add(id: Id, item: string, callback?: AsyncCallback): Promise; + append(id: Id, item: string, callback?: AsyncCallback): Promise; + update(id: Id, item: string, callback?: AsyncCallback): Promise; + remove(target: Id, callback?: AsyncCallback): Promise; + search( + query: string, + options?: Limit | SearchOptions, + callback?: AsyncCallback + ): Promise; + search( + query: string, + limit: number, + options?: Limit | SearchOptions + ): IndexSearchResult; + search(options: SearchOptions): Promise; + + // Async Methods + addAsync( + id: Id, + item: string, + callback?: AsyncCallback + ): Promise; + appendAsync( + id: Id, + item: string, + callback?: AsyncCallback + ): Promise; + updateAsync( + id: Id, + item: string, + callback?: AsyncCallback + ): Promise; + removeAsync(target: Id, callback?: AsyncCallback): Promise; + searchAsync( + query: string, + options?: Limit | SearchOptions, + callback?: AsyncCallback + ): Promise; + searchAsync( + query: string, + limit: number, + options?: Limit | SearchOptions + ): IndexSearchResult; + searchAsync(options: SearchOptions): Promise; + } + + /************************************/ + /* Document Search */ + /************************************/ + + /* + * **Document:** + * * Document options: https://github.com/nextapps-de/flexsearch#document-options + */ + export interface DocumentOptions { + id: string; + tag?: false | string; + index: + | string + | string[] + | Array & { field: string }>; + store?: Store; + } + + /* + * **Document:** + * * Index options: https://github.com/nextapps-de/flexsearch#index-options + */ + export interface IndexOptionsForDocumentSearch< + T, + Store extends StoreOption = false + > extends IndexOptions { + // Additional Options for Document Indexes + worker?: boolean; + document?: DocumentOptions | Descriptor; + } + + export interface SimpleDocumentSearchResultSetUnit { + field: string; + result: Id[]; + } + + export interface EnrichedDocumentSearchResultSetUnitResultUnit { + id: Id[]; + doc: T; + } + + export interface EnrichedDocumentSearchResultSetUnit { + field: string; + result: Array>; + } + + /** + * # Document Search Result + * + * To make your result return the full document: + * * set `store` to `true` while creating the document; + * * set `enrich` to `true` while searching. + * + * If neither of these conditions is met, then the returned result will be a `ISimpleDocumentSearchResult`. + */ + export type DocumentSearchResult< + T, + Store extends StoreOption = false, + Enrich extends boolean = false + > = [Store, Enrich] extends [EnrichStoreOption, true] + ? Array> + : SimpleDocumentSearchResultSetUnit[]; + + /** + * **Document:** + * * Document search options: https://github.com/nextapps-de/flexsearch#document-search-options + */ + export interface DocumentSearchOptions extends SearchOptions { + index?: string | string[] | SearchOptions[]; + tag?: string | string[]; + enrich?: T; + bool?: "and" | "or"; + } + + /** + * **Document:** + * * Basic usage and variants: https://github.com/nextapps-de/flexsearch#basic-usage-and-variants + * * API overview: https://github.com/nextapps-de/flexsearch#api-overview + * * Document store: https://github.com/nextapps-de/flexsearch#document-store + */ + export class Document { + constructor( + options: IndexOptionsForDocumentSearch, + typeHack?: T + ); + add(document: T): this; + add(id: Id, document: T): this; + append(document: T): this; + append(id: Id, document: T): this; + update(document: T): this; + update(id: Id, document: T): this; + remove(target: Id | T): this; + search(query: string, limit?: number): SimpleDocumentSearchResultSetUnit[]; + + // https://github.com/nextapps-de/flexsearch#field-search + search( + query: string, + options: string[] | Partial> + ): SimpleDocumentSearchResultSetUnit[]; + + search( + query: string, + limit?: number, + options?: Partial> + ): DocumentSearchResult; + search( + options: Partial> + ): SimpleDocumentSearchResultSetUnit[]; + export(handler: ExportHandler): Promise; + import(id: Id, document: T): Promise; + + // Async Methods + addAsync(id: Id, document: T, callback?: AsyncCallback): Promise; + appendAsync(id: Id, document: T, callback?: AsyncCallback): Promise; + updateAsync(id: Id, document: T, callback?: AsyncCallback): Promise; + removeAsync(target: Id | T, callback?: AsyncCallback): Promise; + searchAsync( + query: string, + options: string[] | Partial> + ): Promise>; + searchAsync( + query: string, + limit?: number + ): Promise; + searchAsync( + query: string, + limit: number, + callback: AsyncCallback + ): Promise; + searchAsync( + query: string, + options: Partial>, + callback: AsyncCallback> + ): Promise; + searchAsync( + options: Partial> + ): Promise>; + searchAsync( + options: Partial>, + callback: AsyncCallback> + ): Promise; + } + + /************************************/ + /* Miscellaneous */ + /************************************/ + export function create(options: IndexOptions): Index; + export function registerCharset(name: string, charset: CharsetOptions): void; + export function registerLanguage( + name: string, + language: LanguageOptions + ): void; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/package.json b/paige/node_modules/flexsearch/package.json new file mode 100644 index 00000000..328e053f --- /dev/null +++ b/paige/node_modules/flexsearch/package.json @@ -0,0 +1,91 @@ +{ + "public": true, + "preferGlobal": false, + "name": "flexsearch", + "version": "0.7.43", + "description": "Next-Generation full text search library with zero dependencies.", + "homepage": "https://github.com/nextapps-de/flexsearch/", + "author": "Thomas Wilkerling", + "copyright": "Nextapps GmbH", + "license": "Apache-2.0", + "readme": "README.md", + "keywords": [ + "fulltext search", + "elastic search", + "fastest search", + "contextual search", + "document search", + "fuzzy search", + "fuzzy match", + "search engine" + ], + "repository": { + "type": "git", + "url": "https://github.com/nextapps-de/flexsearch.git" + }, + "bugs": { + "url": "https://github.com/nextapps-de/flexsearch/issues", + "email": "info@nextapps.de" + }, + "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", + "worker_threads": false + }, + "types": "./index.d.ts", + "scripts": { + "build": "npm run copy && npm run build:bundle", + "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 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": "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" + }, + "files": [ + "dist/**", + "src/**", + "task/**", + "index.d.ts", + "README.md", + "CHANGELOG.md", + "LICENSE" + ], + "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.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.1", + "babel-plugin-minify-replace": "^0.5.0", + "babel-plugin-minify-simplify": "^0.5.1", + "babel-plugin-minify-type-constructors": "^0.4.3", + "babel-plugin-transform-member-expression-literals": "^6.9.4", + "babel-plugin-transform-merge-sibling-variables": "^6.9.5", + "babel-plugin-transform-minify-booleans": "^6.9.4", + "babel-plugin-transform-property-literals": "^6.9.4", + "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", + "babel-plugin-transform-undefined-to-void": "^6.9.4", + "google-closure-compiler": "^20230802.0.0" + } +} diff --git a/paige/node_modules/flexsearch/src/_config/bundle/config.js b/paige/node_modules/flexsearch/src/_config/bundle/config.js new file mode 100644 index 00000000..49c23f2c --- /dev/null +++ b/paige/node_modules/flexsearch/src/_config/bundle/config.js @@ -0,0 +1,32 @@ +/** @define {boolean} */ +export const DEBUG = false; + +/** @define {boolean} */ +export const POLYFILL = false; + +/** @define {boolean} */ +export const SUPPORT_WORKER = true; + +/** @define {boolean|string} */ +export const SUPPORT_ENCODER = true; + +/** @define {boolean} */ +export const SUPPORT_CACHE = true; + +/** @define {boolean} */ +export const SUPPORT_ASYNC = true; + +/** @define {boolean} */ +export const SUPPORT_STORE = true; + +/** @define {boolean} */ +export const SUPPORT_TAGS = true; + +/** @define {boolean} */ +export const SUPPORT_SUGGESTION = true; + +/** @define {boolean} */ +export const SUPPORT_SERIALIZE = true; + +/** @define {boolean} */ +export const SUPPORT_DOCUMENT = true; diff --git a/paige/node_modules/flexsearch/src/_config/compact/config.js b/paige/node_modules/flexsearch/src/_config/compact/config.js new file mode 100644 index 00000000..34361cc0 --- /dev/null +++ b/paige/node_modules/flexsearch/src/_config/compact/config.js @@ -0,0 +1,32 @@ +/** @define {boolean} */ +export const DEBUG = false; + +/** @define {boolean} */ +export const POLYFILL = false; + +/** @define {boolean} */ +export const SUPPORT_WORKER = false; + +/** @define {boolean|string} */ +export const SUPPORT_ENCODER = true; + +/** @define {boolean} */ +export const SUPPORT_CACHE = false; + +/** @define {boolean} */ +export const SUPPORT_ASYNC = true; + +/** @define {boolean} */ +export const SUPPORT_STORE = true; + +/** @define {boolean} */ +export const SUPPORT_TAGS = false; + +/** @define {boolean} */ +export const SUPPORT_SUGGESTION = true; + +/** @define {boolean} */ +export const SUPPORT_SERIALIZE = false; + +/** @define {boolean} */ +export const SUPPORT_DOCUMENT = true; diff --git a/paige/node_modules/flexsearch/src/_config/debug/config.js b/paige/node_modules/flexsearch/src/_config/debug/config.js new file mode 100644 index 00000000..80dd0ed0 --- /dev/null +++ b/paige/node_modules/flexsearch/src/_config/debug/config.js @@ -0,0 +1,32 @@ +/** @define {boolean} */ +export const DEBUG = true; + +/** @define {boolean} */ +export const POLYFILL = false; + +/** @define {boolean} */ +export const SUPPORT_WORKER = true; + +/** @define {boolean|string} */ +export const SUPPORT_ENCODER = true; + +/** @define {boolean} */ +export const SUPPORT_CACHE = true; + +/** @define {boolean} */ +export const SUPPORT_ASYNC = true; + +/** @define {boolean} */ +export const SUPPORT_STORE = true; + +/** @define {boolean} */ +export const SUPPORT_TAGS = true; + +/** @define {boolean} */ +export const SUPPORT_SUGGESTION = true; + +/** @define {boolean} */ +export const SUPPORT_SERIALIZE = true; + +/** @define {boolean} */ +export const SUPPORT_DOCUMENT = true; diff --git a/paige/node_modules/flexsearch/src/_config/light/config.js b/paige/node_modules/flexsearch/src/_config/light/config.js new file mode 100644 index 00000000..456f7824 --- /dev/null +++ b/paige/node_modules/flexsearch/src/_config/light/config.js @@ -0,0 +1,32 @@ +/** @define {boolean} */ +export const DEBUG = false; + +/** @define {boolean} */ +export const POLYFILL = false; + +/** @define {boolean} */ +export const SUPPORT_WORKER = false; + +/** @define {boolean|string} */ +export const SUPPORT_ENCODER = false; + +/** @define {boolean} */ +export const SUPPORT_CACHE = false; + +/** @define {boolean} */ +export const SUPPORT_ASYNC = false; + +/** @define {boolean} */ +export const SUPPORT_STORE = false; + +/** @define {boolean} */ +export const SUPPORT_TAGS = false; + +/** @define {boolean} */ +export const SUPPORT_SUGGESTION = false; + +/** @define {boolean} */ +export const SUPPORT_SERIALIZE = false; + +/** @define {boolean} */ +export const SUPPORT_DOCUMENT = false; diff --git a/paige/node_modules/flexsearch/src/async.js b/paige/node_modules/flexsearch/src/async.js new file mode 100644 index 00000000..31f1c083 --- /dev/null +++ b/paige/node_modules/flexsearch/src/async.js @@ -0,0 +1,51 @@ +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; + const args = /*[].slice.call*/(arguments); + const arg = args[args.length - 1]; + let callback; + + if(is_function(arg)){ + + callback = arg; + delete args[args.length - 1]; + } + + const promise = new Promise(function(resolve){ + + setTimeout(function(){ + + self.async = true; + const res = self[key].apply(self, args); + self.async = false; + resolve(res); + }); + }); + + if(callback){ + + promise.then(callback); + return this; + } + else{ + + return promise; + } + }; +} diff --git a/paige/node_modules/flexsearch/src/cache.js b/paige/node_modules/flexsearch/src/cache.js new file mode 100644 index 00000000..5cd74075 --- /dev/null +++ b/paige/node_modules/flexsearch/src/cache.js @@ -0,0 +1,169 @@ +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 = (limit !== true) && 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} + */ + +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; x > 0; x--){ + + this.queue[x] = this.queue[x - 1]; + } + + this.queue[0] = key; + } + + this.cache[key] = value; +}; + +CacheClass.prototype.get = function(key){ + + const cache = this.cache[key]; + + if(this.limit && cache){ + + // 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]; + } + } +}; diff --git a/paige/node_modules/flexsearch/src/common.js b/paige/node_modules/flexsearch/src/common.js new file mode 100644 index 00000000..878eb1f0 --- /dev/null +++ b/paige/node_modules/flexsearch/src/common.js @@ -0,0 +1,78 @@ +export function parse_option(value, default_value){ + + return typeof value !== "undefined" ? value : default_value; +} + +/** + * @param {!number} count + * @returns {Array} + */ + +export function create_object_array(count){ + + const array = new Array(count); + + for(let i = 0; i < count; i++){ + + array[i] = create_object(); + } + + return array; +} + +export function create_arrays(count){ + + const array = new Array(count); + + for(let i = 0; i < count; i++){ + + array[i] = []; + } + + return array; +} + +/** + * @param {!Object} obj + * @returns {Array} + */ + +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 typeof val === "string"; +} + +export function is_object(val){ + + return typeof val === "object"; +} + +export function is_function(val){ + + return typeof val === "function"; +} diff --git a/paige/node_modules/flexsearch/src/config.js b/paige/node_modules/flexsearch/src/config.js new file mode 100644 index 00000000..2a7ad21f --- /dev/null +++ b/paige/node_modules/flexsearch/src/config.js @@ -0,0 +1,35 @@ +/** @define {string} */ +export const RELEASE = "custom"; + +/** @define {boolean} */ +export const DEBUG = false; + +/** @define {boolean} */ +export const POLYFILL = true; + +/** @define {boolean} */ +export const SUPPORT_WORKER = true; + +/** @define {boolean|string} */ +export const SUPPORT_ENCODER = true; + +/** @define {boolean} */ +export const SUPPORT_CACHE = true; + +/** @define {boolean} */ +export const SUPPORT_ASYNC = true; + +/** @define {boolean} */ +export const SUPPORT_STORE = true; + +/** @define {boolean} */ +export const SUPPORT_TAGS = true; + +/** @define {boolean} */ +export const SUPPORT_SUGGESTION = true; + +/** @define {boolean} */ +export const SUPPORT_SERIALIZE = true; + +/** @define {boolean} */ +export const SUPPORT_DOCUMENT = true; diff --git a/paige/node_modules/flexsearch/src/document.js b/paige/node_modules/flexsearch/src/document.js new file mode 100644 index 00000000..9bb16c86 --- /dev/null +++ b/paige/node_modules/flexsearch/src/document.js @@ -0,0 +1,790 @@ +/**! + * FlexSearch.js + * Author and Copyright: Thomas Wilkerling + * Licence: Apache-2.0 + * Hosted by Nextapps GmbH + * https://github.com/nextapps-de/flexsearch + */ + +// COMPILER BLOCK --> +import { + + SUPPORT_ASYNC, + SUPPORT_CACHE, + SUPPORT_SERIALIZE, + SUPPORT_STORE, + SUPPORT_TAGS, + SUPPORT_WORKER + +} from "./config.js"; +// <-- COMPILER BLOCK + +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"], true); + + if(SUPPORT_STORE){ + + this.storetree = (opt = document["store"]) && (opt !== true) && []; + this.store = opt && create_object(); + } + + if(SUPPORT_TAGS){ + + // TODO case-insensitive tags + + this.tag = ((opt = document["tag"]) && parse_tree(opt, this.marker)); + this.tagindex = opt && create_object(); + } + + if(SUPPORT_CACHE){ + + this.cache = (opt = options["cache"]) && new Cache(opt); + + // do not apply cache again for the indexes + + options["cache"] = false; + } + + if(SUPPORT_WORKER){ + + this.worker = options["worker"]; + } + + if(SUPPORT_ASYNC){ + + // this switch is used by recall of promise callbacks + + this.async = false; + } + + /** @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(SUPPORT_WORKER && this.worker){ + + index[key] = new WorkerIndex(opt); + + if(!index[key].worker){ + + this.worker = false; + } + } + + if(!this.worker){ + + index[key] = new Index(opt, this.register); + } + + this.tree[i] = parse_tree(key, this.marker); + this.field[i] = key; + } + + if(SUPPORT_STORE && this.storetree){ + + let store = document["store"]; + + if(is_string(store)){ + + store = [store]; + } + + for(let i = 0; i < store.length; i++){ + + this.storetree[i] = parse_tree(store[i], this.marker); + } + } + + return index; +} + +function parse_tree(key, marker){ + + const tree = key.split(":"); + let count = 0; + + for(let i = 0; i < tree.length; i++){ + + key = tree[i]; + + if(key.indexOf("[]") >= 0){ + + key = key.substring(0, key.length - 2); + + if(key){ + + marker[count] = true; + } + } + + if(key){ + + tree[count++] = key; + } + } + + if(count < tree.length){ + + tree.length = count; + } + + return count > 1 ? tree : tree[0]; +} + +// 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] = new Array(obj.length); + + for(let i = 0; i < obj.length; i++){ + + // do not increase pos (an array is not a field) + store_value(obj, store, tree, pos, i); + } + } + else{ + + store = store[key] || (store[key] = create_object()); + key = tree[++pos]; + + store_value(obj, store, tree, pos, key); + } + } +} + +function add_index(obj, tree, 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], /* append: */ true, /* skip update: */ true); + } + + return; + } + + // or join array contents and use one scoring context + + obj = obj.join(" "); + } + + index.add(id, obj, _append, /* skip_update: */ true); + } + 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 || (id === 0))){ + + if(!_append && this.register[id]){ + + return this.update(id, content); + } + + for(let i = 0, tree, field; i < this.field.length; i++){ + + field = this.field[i]; + tree = this.tree[i]; + + if(is_string(tree)){ + + tree = [tree]; + } + + add_index(content, tree, this.marker, 0, this.index[field], id, tree[0], _append); + } + + if(SUPPORT_TAGS && this.tag){ + + let tag = parse_simple(content, this.tag); + let dupes = create_object(); + + if(is_string(tag)){ + + tag = [tag]; + } + + for(let i = 0, key, arr; i < tag.length; i++){ + + key = tag[i]; + + if(!dupes[key]){ + + dupes[key] = 1; + arr = this.tagindex[key] || (this.tagindex[key] = []); + + if(!_append || !arr.includes(id)){ + + arr[arr.length] = id; + + // 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(SUPPORT_STORE && this.store && (!_append || !this.store[id])){ + + let store; + + if(this.storetree){ + + store = create_object(); + + for(let i = 0, tree; i < this.storetree.length; i++){ + + tree = this.storetree[i]; + + if(is_string(tree)){ + + store[tree] = content[tree]; + } + else{ + + store_value(content, store, tree, 0, tree[0]); + } + } + } + + this.store[id] = store || content; + } + } + + return this; +}; + +Document.prototype.append = function(id, content){ + + return this.add(id, content, true); +}; + +Document.prototype.update = function(id, content){ + + return this.remove(id).add(id, content); +}; + +Document.prototype.remove = function(id){ + + if(is_object(id)){ + + id = parse_simple(id, this.key); + } + + if(this.register[id]){ + + for(let i = 0; i < this.field.length; i++){ + + // 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(SUPPORT_TAGS && 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]; + const pos = tag.indexOf(id); + + if(pos !== -1){ + + if(tag.length > 1){ + + tag.splice(pos, 1); + } + else{ + + delete this.tagindex[key]; + } + } + } + } + } + + if(SUPPORT_STORE && this.store){ + + delete this.store[id]; + } + + delete this.register[id]; + } + + return this; +}; + +/** + * @param {!string|Object} query + * @param {number|Object=} limit + * @param {Object=} options + * @param {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 = []; + let pluck, enrich; + let field, tag, bool, offset, count = 0; + + if(options){ + + if(is_array(options)){ + + field = options; + options = null; + } + else{ + + query = options["query"] || query; + pluck = options["pluck"]; + field = pluck || options["index"] || options["field"] /*|| (is_string(options) && [options])*/; + tag = SUPPORT_TAGS && options["tag"]; + enrich = SUPPORT_STORE && this.store && options["enrich"]; + bool = options["bool"] === "and"; + limit = options["limit"] || limit || 100; + offset = options["offset"] || 0; + + if(tag){ + + if(is_string(tag)){ + + tag = [tag]; + } + + // 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 && ((field.length > 1) || (tag && (tag.length > 1))); + + 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, enrich){ + + let res = this.tagindex[key]; + let len = res && (res.length - offset); + + if(len && (len > 0)){ + + if((len > limit) || offset){ + + res = res.slice(offset, offset + limit); + } + + if(enrich){ + + res = apply_enrich.call(this, res); + } + + return { + + "tag": key, + "result": res + }; + } +} + +/** + * @this Document + */ + +function apply_enrich(res){ + + const arr = new Array(res.length); + + for(let x = 0, id; x < res.length; x++){ + + id = res[x]; + + arr[x] = { + + "id": id, + "doc": this.store[id] + }; + } + + return arr; +} + +Document.prototype.contain = function(id){ + + return !!this.register[id]; +}; + +if(SUPPORT_STORE){ + + Document.prototype.get = function(id){ + + return this.store[id]; + }; + + Document.prototype.set = function(id, data){ + + this.store[id] = data; + return this; + }; +} + +if(SUPPORT_CACHE){ + + Document.prototype.searchCache = searchCache; +} + +if(SUPPORT_SERIALIZE){ + + Document.prototype.export = exportDocument; + Document.prototype.import = importDocument; +} + +if(SUPPORT_ASYNC){ + + apply_async(Document.prototype); +} diff --git a/paige/node_modules/flexsearch/src/engine.js b/paige/node_modules/flexsearch/src/engine.js new file mode 100644 index 00000000..0e3b0a85 --- /dev/null +++ b/paige/node_modules/flexsearch/src/engine.js @@ -0,0 +1,49 @@ +// COMPILER BLOCK --> +import { DEBUG, SUPPORT_ASYNC, SUPPORT_CACHE } from "./config"; +// <-- COMPILER BLOCK +import { searchCache } from "./cache"; + +/** + * @constructor + * @abstract + */ + +function Engine(index){ + + if(DEBUG){ + + //if(this.constructor === Engine){ + if(this instanceof Engine){ + + throw new Error("Can't instantiate abstract class!"); + } + } + + if(SUPPORT_CACHE){ + + index.prototype.searchCache = searchCache; + } + + if(SUPPORT_ASYNC){ + + index.prototype.addAsync = addAsync; + index.prototype.appendAsync = appendAsync; + index.prototype.searchAsync = searchAsync; + index.prototype.updateAsync = updateAsync; + index.prototype.removeAsync = removeAsync; + } +} + +if(SUPPORT_CACHE){ + + Engine.prototype.searchCache = searchCache; +} + +if(SUPPORT_ASYNC){ + + Engine.prototype.addAsync = addAsync; + Engine.prototype.appendAsync = appendAsync; + Engine.prototype.searchAsync = searchAsync; + Engine.prototype.updateAsync = updateAsync; + Engine.prototype.removeAsync = removeAsync; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/src/global.js b/paige/node_modules/flexsearch/src/global.js new file mode 100644 index 00000000..96357044 --- /dev/null +++ b/paige/node_modules/flexsearch/src/global.js @@ -0,0 +1,22 @@ +export const global_lang = {}; +export const global_charset = {}; + +/** + * @param {!string} name + * @param {Object} charset + */ + +export function registerCharset(name, charset){ + + global_charset[name] = charset; +} + +/** + * @param {!string} name + * @param {Object} lang + */ + +export function registerLanguage(name, lang){ + + global_lang[name] = lang; +} diff --git a/paige/node_modules/flexsearch/src/index.js b/paige/node_modules/flexsearch/src/index.js new file mode 100644 index 00000000..49fcdad9 --- /dev/null +++ b/paige/node_modules/flexsearch/src/index.js @@ -0,0 +1,823 @@ +/**! + * FlexSearch.js + * Author and Copyright: Thomas Wilkerling + * Licence: Apache-2.0 + * Hosted by Nextapps GmbH + * https://github.com/nextapps-de/flexsearch + */ + +// COMPILER BLOCK --> +import { + + SUPPORT_ENCODER, + SUPPORT_CACHE, + SUPPORT_ASYNC, + SUPPORT_SUGGESTION, + SUPPORT_SERIALIZE + +} from "./config.js"; +// <-- COMPILER BLOCK + +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){ + + if(SUPPORT_ENCODER){ + + options = apply_preset(options); + } + + charset = options["charset"]; + lang = options["lang"]; + + if(is_string(charset)){ + + if(charset.indexOf(":") === -1){ + + charset += ":default"; + } + + charset = global_charset[charset]; + } + + if(is_string(lang)){ + + lang = global_lang[lang]; + } + } + else{ + + options = {}; + } + + let resolution, optimize, context = options["context"] || {}; + + this.encode = options["encode"] || (charset && charset.encode) || default_encoder; + this.register = _register || create_object(); + this.resolution = resolution = options["resolution"] || 9; + this.tokenize = tmp = (charset && charset.tokenize) || options["tokenize"] || "strict"; + this.depth = (tmp === "strict") && context["depth"]; + this.bidirectional = parse_option(context["bidirectional"], true); + this.optimize = optimize = parse_option(options["optimize"], true); + this.fastupdate = parse_option(options["fastupdate"], true); + this.minlength = options["minlength"] || 1; + this.boost = options["boost"]; + + // 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, false); + this.stemmer = (tmp = options["stemmer"] || (lang && lang.stemmer)) && init_stemmer_or_matcher(tmp, true); + this.filter = (tmp = options["filter"] || (lang && lang.filter)) && init_filter(tmp); + + if(SUPPORT_CACHE){ + + this.cache = (tmp = options["cache"]) && new Cache(tmp); + } +} + +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, true); +}; + +// 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 || (id === 0))){ + + 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(); + const dupes = create_object(); + const depth = this.depth; + const resolution = this.resolution; + + for(let i = 0; i < length; i++){ + + let term = content[this.rtl ? length - 1 - i : i]; + let term_length = term.length; + + // skip dupes will break the context chain + + if(term && (term_length >= this.minlength) && (depth || !dupes[term])){ + + let score = get_score(resolution, length, i); + let token = ""; + + switch(this.tokenize){ + + case "full": + + if(term_length > 2){ + + for(let x = 0; x < term_length; x++){ + + for(let y = term_length; y > x; y--){ + + if((y - x) >= this.minlength){ + + const partial_score = get_score(resolution, length, i, term_length, x); + token = term.substring(x, y); + this.push_index(dupes, token, partial_score, id, _append); + } + } + } + + break; + } + + // fallthrough to next case when term length < 3 + + case "reverse": + + // skip last round (this token exist already in "forward") + + if(term_length > 1){ + + for(let x = term_length - 1; x > 0; x--){ + + token = term[x] + token; + + if(token.length >= this.minlength){ + + const partial_score = get_score(resolution, length, i, term_length, x); + this.push_index(dupes, token, partial_score, id, _append); + } + } + + token = ""; + } + + // fallthrough to next case to apply forward also + + case "forward": + + if(term_length > 1){ + + for(let x = 0; x < term_length; x++){ + + token += term[x]; + + if(token.length >= this.minlength){ + + this.push_index(dupes, token, score, id, _append); + } + } + + break; + } + + // fallthrough to next case when token has a length of 1 + + default: + // case "strict": + + if(this.boost){ + + score = Math.min((score / this.boost(content, term, i)) | 0, resolution - 1); + } + + this.push_index(dupes, term, score, id, _append); + + // context is just supported by tokenizer "strict" + + if(depth){ + + if((length > 1) && (i < (length - 1))){ + + // check inner dupes to skip repeating words in the current context + + const dupes_inner = create_object(); + const resolution = this.resolution_ctx; + const keyword = term; + const size = Math.min(depth + 1, length - i); + + dupes_inner[keyword] = 1; + + for(let x = 1; x < size; x++){ + + term = content[this.rtl ? length - 1 - i - x : i + x]; + + if(term && (term.length >= this.minlength) && !dupes_inner[term]){ + + dupes_inner[term] = 1; + + const context_score = get_score(resolution + ((length / 2) > resolution ? 0 : 1), length, i, size - 1, x - 1); + const swap = this.bidirectional && (term > keyword); + this.push_index(dupes_ctx, swap ? keyword : term, context_score, id, _append, swap ? term : keyword); + } + } + } + } + } + } + } + + this.fastupdate || (this.register[id] = 1); + } + } + + return this; +}; + +/** + * @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 && (resolution > 1) ? ( + + (length + (term_length || 0)) <= resolution ? + + i + (x || 0) + : + ((resolution - 1) / (length + (term_length || 0)) * (i + (x || 0)) + 1) | 0 + ): + 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} + */ + +Index.prototype.search = function(query, limit, options){ + + if(!options){ + + if(!limit && is_object(query)){ + + options = /** @type {Object} */ (query); + query = options["query"]; + } + else if(is_object(limit)){ + + options = /** @type {Object} */ (limit); + } + } + + let result = []; + let length; + let context, suggest, offset = 0; + + if(options){ + + query = options["query"] || query; + limit = options["limit"]; + offset = options["offset"] || 0; + context = options["context"]; + suggest = SUPPORT_SUGGESTION && options["suggest"]; + } + + if(query){ + + query = /** @type {Array} */ (this.encode("" + query)); + length = query.length; + + // TODO: solve this in one single loop below + + if(length > 1){ + + const dupes = create_object(); + const query_new = []; + + for(let i = 0, count = 0, term; i < length; i++){ + + term = query[i]; + + if(term && (term.length >= this.minlength) && !dupes[term]){ + + // 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 && (length > 1) && (context !== false); + let index = 0, keyword; + + if(depth){ + + keyword = query[0]; + index = 1; + } + else{ + + if(length > 1){ + + query.sort(sort_by_length_down); + } + } + + for(let arr, term; index < length; index++){ + + term = query[index]; + + // console.log(keyword); + // console.log(term); + // console.log(""); + + if(depth){ + + arr = this.add_result(result, suggest, limit, offset, length === 2, 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 || (arr !== false) || !result.length){ + + keyword = term; + } + } + else{ + + arr = this.add_result(result, suggest, limit, offset, length === 1, term); + } + + if(arr){ + + return /** @type {Array} */ (arr); + } + + // apply suggestions on last loop or fallback + + if(suggest && (index === length - 1)){ + + let length = result.length; + + if(!length){ + + if(depth){ + + // fallback to non-contextual search when no result was found + + depth = 0; + index = -1; + + continue; + } + + return result; + } + else if(length === 1){ + + // fast path optimization + + 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>|boolean|undefined} + */ + +Index.prototype.add_result = function(result, suggest, limit, offset, single_term, term, keyword){ + + let word_arr = []; + let arr = keyword ? this.ctx : this.map; + + if(!this.optimize){ + + arr = get_array(arr, term, keyword, this.bidirectional); + } + + if(arr){ + + let count = 0; + const arr_len = Math.min(arr.length, keyword ? this.resolution_ctx : this.resolution); + + // 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(result.length === 1){ + + result = result[0]; + } + else{ + + result = concat(result); + } + + return offset || (result.length > limit) ? + + result.slice(offset, offset + limit) + : + result; +} + +function get_array(arr, term, keyword, bidirectional){ + + if(keyword){ + + // 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(SUPPORT_CACHE && this.cache){ + + this.cache.del(id); + } + } + + return this; +}; + +/** + * @param map + * @param id + * @param res + * @param optimize + * @param {number=} resolution + * @return {number} + */ + +function remove_index(map, id, res, optimize, resolution){ + + let count = 0; + + if(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(pos !== -1){ + + // fast path, when length is 1 or lower then the whole field gets deleted + + if(map.length > 1){ + + map.splice(pos, 1); + count++; + } + } + else{ + + count++; + } + } + } + else{ + + for(let key in map){ + + count = remove_index(map[key], id, res, optimize, resolution); + + if(!count){ + + delete map[key]; + } + } + } + + return count; +} + +if(SUPPORT_CACHE){ + + Index.prototype.searchCache = searchCache; +} + +if(SUPPORT_SERIALIZE){ + + Index.prototype.export = exportIndex; + Index.prototype.import = importIndex; +} + +if(SUPPORT_ASYNC){ + + apply_async(Index.prototype); +} diff --git a/paige/node_modules/flexsearch/src/intersect.js b/paige/node_modules/flexsearch/src/intersect.js new file mode 100644 index 00000000..16828e6c --- /dev/null +++ b/paige/node_modules/flexsearch/src/intersect.js @@ -0,0 +1,397 @@ +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 = []; + let check; + let check_suggest; + let 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; x >= 0; x--){ + + const word_arr = arrays[x]; + const word_arr_len = word_arr.length; + const 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]; + const 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 = true; + } + + 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; x >= 0; x--){ + + arr = suggest[x]; + len = arr.length; + + for(let y = 0, id; y < len; y++){ + + id = arr[y]; + + if(!check[id]){ + + if(offset){ + + offset--; + } + else{ + + result[size++] = id; + + if(size === limit){ + + // 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(); + const union = create_object(); + const result = []; + + for(let x = 0; x < mandatory.length; x++){ + + check[mandatory[x]] = 1; + } + + for(let x = 0, arr; x < arrays.length; x++){ + + arr = arrays[x]; + + for(let y = 0, id; y < arr.length; y++){ + + id = arr[y]; + + if(check[id]){ + + if(!union[id]){ + + union[id] = 1; + result[result.length] = id; + } + } + } + } + + return result; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/src/lang.js b/paige/node_modules/flexsearch/src/lang.js new file mode 100644 index 00000000..2882fd92 --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang.js @@ -0,0 +1,321 @@ +import { IndexInterface } from "./type.js"; +import { create_object, get_keys } from "./common.js"; + +/** + * @param {!string} str + * @param {boolean|Array=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} _collapse + * @returns {string|Array} + * @this IndexInterface + */ + +export function pipeline(str, normalize, split, _collapse){ + + if(str){ + + if(normalize){ + + str = replace(str, /** @type {Array} */ (normalize)); + } + + if(this.matcher){ + + str = replace(str, this.matcher); + } + + if(this.stemmer && (str.length > 1)){ + + str = replace(str, this.stemmer); + } + + if(_collapse && (str.length > 1)){ + + str = collapse(str); + } + + if(split || (split === "")){ + + const words = str.split(/** @type {string|RegExp} */ (split)); + + return this.filter ? filter(words, this.filter) : words; + } + } + + return str; +} + +// 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=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} _collapse + * @returns {string|Array} + */ + +// FlexSearch.prototype.pipeline = function(str, normalize, split, _collapse){ +// +// if(str){ +// +// if(normalize && str){ +// +// str = replace(str, /** @type {Array} */ (normalize)); +// } +// +// if(str && this.matcher){ +// +// str = replace(str, this.matcher); +// } +// +// if(this.stemmer && str.length > 1){ +// +// str = replace(str, this.stemmer); +// } +// +// if(_collapse && str.length > 1){ +// +// str = collapse(str); +// } +// +// if(str){ +// +// if(split || (split === "")){ +// +// const words = str.split(/** @type {string|RegExp} */ (split)); +// +// return this.filter ? filter(words, this.filter) : words; +// } +// } +// } +// +// return str; +// }; + +// export function pipeline(str, normalize, matcher, stemmer, split, _filter, _collapse){ +// +// if(str){ +// +// if(normalize && str){ +// +// str = replace(str, normalize); +// } +// +// if(matcher && str){ +// +// str = replace(str, matcher); +// } +// +// if(stemmer && str.length > 1){ +// +// str = replace(str, stemmer); +// } +// +// if(_collapse && str.length > 1){ +// +// str = collapse(str); +// } +// +// if(str){ +// +// if(split !== false){ +// +// str = str.split(split); +// +// if(_filter){ +// +// str = filter(str, _filter); +// } +// } +// } +// } +// +// return str; +// } + + +/** + * @param {Array} words + * @returns {Object} + */ + +export function init_filter(words){ + + const filter = create_object(); + + for(let i = 0, length = words.length; i < length; i++){ + + filter[words[i]] = 1; + } + + return filter; +} + +/** + * @param {!Object} obj + * @param {boolean} is_stemmer + * @returns {Array} + */ + +export function init_stemmer_or_matcher(obj, is_stemmer){ + + const keys = get_keys(obj); + const length = keys.length; + const final = []; + + let removal = "", count = 0; + + for(let i = 0, key, tmp; i < length; i++){ + + key = keys[i]; + tmp = obj[key]; + + if(tmp){ + + final[count++] = regex(is_stemmer ? "(?!\\b)" + key + "(\\b|_)" : key); + final[count++] = tmp; + } + else{ + + removal += (removal ? "|" : "") + key; + } + } + + if(removal){ + + final[count++] = regex(is_stemmer ? "(?!\\b)(" + removal + ")(\\b|_)" : "(" + removal + ")"); + final[count] = ""; + } + + return final; +} + + +/** + * @param {!string} str + * @param {Array} regexp + * @returns {string} + */ + +export function replace(str, regexp){ + + for(let i = 0, len = regexp.length; i < len; i += 2){ + + str = str.replace(regexp[i], regexp[i + 1]); + + if(!str){ + + break; + } + } + + return str; +} + +/** + * @param {!string} str + * @returns {RegExp} + */ + +export function regex(str){ + + return new RegExp(str, "g"); +} + +/** + * Regex: replace(/(?:(\w)(?:\1)*)/g, "$1") + * @param {!string} string + * @returns {string} + */ + +export function collapse(string){ + + let final = "", prev = ""; + + for(let i = 0, len = string.length, char; i < len; i++){ + + if((char = string[i]) !== prev){ + + final += (prev = char); + } + } + + return final; +} + +// TODO using fast-swap +export function filter(words, map){ + + const length = words.length; + const filtered = []; + + for(let i = 0, count = 0; i < length; i++){ + + const word = words[i]; + + if(word && !map[word]){ + + filtered[count++] = word; + } + } + + return filtered; +} + +// const chars = {a:1, e:1, i:1, o:1, u:1, y:1}; +// +// function collapse_repeating_chars(string){ +// +// let collapsed_string = "", +// char_prev = "", +// char_next = ""; +// +// for(let i = 0; i < string.length; i++){ +// +// const char = string[i]; +// +// if(char !== char_prev){ +// +// if(i && (char === "h")){ +// +// if((chars[char_prev] && chars[char_next]) || (char_prev === " ")){ +// +// collapsed_string += char; +// } +// } +// else{ +// +// collapsed_string += char; +// } +// } +// +// char_next = ( +// +// (i === (string.length - 1)) ? +// +// "" +// : +// string[i + 1] +// ); +// +// char_prev = char; +// } +// +// return collapsed_string; +// } diff --git a/paige/node_modules/flexsearch/src/lang/arabic/default.js b/paige/node_modules/flexsearch/src/lang/arabic/default.js new file mode 100644 index 00000000..8b631031 --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/arabic/default.js @@ -0,0 +1,29 @@ +import { IndexInterface } from "../../type.js"; +import { pipeline } from "../../lang.js"; + +export const rtl = true; +export const tokenize = ""; +export default { + encode: encode, + rtl: rtl +} + +const regex = /[\x00-\x7F]+/g; +const split = /\s+/; + +/** + * @param {string|number} str + * @this IndexInterface + */ + +export function encode(str){ + + return pipeline.call( + + this, + /* string: */ ("" + str).replace(regex, " "), + /* normalize: */ false, + /* split: */ split, + /* collapse: */ false + ); +} diff --git a/paige/node_modules/flexsearch/src/lang/at.js b/paige/node_modules/flexsearch/src/lang/at.js new file mode 100644 index 00000000..0fecf05d --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/at.js @@ -0,0 +1,172 @@ +/** + * http://www.ranks.nl/stopwords + * @type {Array} + */ + +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} + */ + +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 +} diff --git a/paige/node_modules/flexsearch/src/lang/cjk/default.js b/paige/node_modules/flexsearch/src/lang/cjk/default.js new file mode 100644 index 00000000..a31f0b5f --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/cjk/default.js @@ -0,0 +1,29 @@ +import { IndexInterface } from "../../type.js"; +import { pipeline } from "../../lang.js"; + +export const rtl = false; +export const tokenize = "strict"; +export default { + encode: encode, + rtl: rtl, + tokenize: tokenize +} + +const regex = /[\x00-\x7F]+/g; + +/** + * @param {string|number} str + * @this IndexInterface + */ + +export function encode(str){ + + return pipeline.call( + + this, + /* string: */ ("" + str).replace(regex, ""), + /* normalize: */ false, + /* split: */ "", + /* collapse: */ false + ); +} diff --git a/paige/node_modules/flexsearch/src/lang/cyrillic/default.js b/paige/node_modules/flexsearch/src/lang/cyrillic/default.js new file mode 100644 index 00000000..5bba75db --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/cyrillic/default.js @@ -0,0 +1,29 @@ +import { IndexInterface } from "../../type.js"; +import { pipeline } from "../../lang.js"; + +export const rtl = false; +export const tokenize = ""; +export default { + encode: encode, + rtl: rtl +} + +const regex = /[\x00-\x7F]+/g; +const split = /\s+/; + +/** + * @param {string|number} str + * @this IndexInterface + */ + +export function encode(str){ + + return pipeline.call( + + this, + /* string: */ ("" + str).replace(regex, " "), + /* normalize: */ false, + /* split: */ split, + /* collapse: */ false + ); +} diff --git a/paige/node_modules/flexsearch/src/lang/de.js b/paige/node_modules/flexsearch/src/lang/de.js new file mode 100644 index 00000000..029a6bdf --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/de.js @@ -0,0 +1,185 @@ +/** + * 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} + */ + +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} + */ + +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>} + */ + +export const matcher = {}; + +export default { + + filter: filter, + stemmer: stemmer, + matcher: matcher +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/src/lang/en.js b/paige/node_modules/flexsearch/src/lang/en.js new file mode 100644 index 00000000..c7e9870d --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/en.js @@ -0,0 +1,276 @@ +/** + * http://www.ranks.nl/stopwords + * @type {Array} + */ + +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} + */ + +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 +} diff --git a/paige/node_modules/flexsearch/src/lang/latin/advanced.js b/paige/node_modules/flexsearch/src/lang/latin/advanced.js new file mode 100644 index 00000000..baa67e4c --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/latin/advanced.js @@ -0,0 +1,92 @@ +import { IndexInterface } from "../../type.js"; +import { regex, replace, collapse } from "../../lang.js"; +import { encode as encode_balance } from "./balance.js"; + +export const rtl = false; +export const tokenize = ""; +export default { + encode: encode, + rtl: rtl, + tokenize: 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"); + //regex_ou = regex("ou"), + //regex_uo = regex("uo"); + +const 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])"), "" +]; + +/** + * @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(str.length > 2){ + + str = replace(str, pairs); + } + + if(!_skip_postprocessing){ + + if(str.length > 1){ + + str = collapse(str); + } + + if(str){ + + str = str.split(" "); + } + } + } + + return str || []; +} diff --git a/paige/node_modules/flexsearch/src/lang/latin/balance.js b/paige/node_modules/flexsearch/src/lang/latin/balance.js new file mode 100644 index 00000000..bc207885 --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/latin/balance.js @@ -0,0 +1,119 @@ +import { IndexInterface } from "../../type.js"; +import { encode as encode_simple } from "./simple.js"; + +// custom soundex implementation + +export const rtl = false; +export const tokenize = "strict"; +export default { + encode: encode, + rtl: rtl, + tokenize: tokenize +} + +//const regex_whitespace = /[\W_]+/g; +const regex_strip = /[^a-z0-9]+/; + +// const pairs = [ +// regex_whitespace, " ", +// regex_strip, "" +// ]; + +// modified + +const 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" +}; + +/** + * @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); + const 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; //str[0]; + let previous = code; //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; +} diff --git a/paige/node_modules/flexsearch/src/lang/latin/default.js b/paige/node_modules/flexsearch/src/lang/latin/default.js new file mode 100644 index 00000000..47870f35 --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/latin/default.js @@ -0,0 +1,27 @@ +import { IndexInterface } from "../../type.js"; +import { pipeline, normalize, regex_whitespace } from "../../lang.js"; + +export const rtl = false; +export const tokenize = ""; +export default { + encode: encode, + rtl: rtl, + tokenize: tokenize +} + +/** + * @param {string|number} str + * @this IndexInterface + */ + +export function encode(str){ + + return pipeline.call( + + this, + /* string: */ ("" + str).toLowerCase(), + /* normalize: */ false, + /* split: */ regex_whitespace, + /* collapse: */ false + ); +} diff --git a/paige/node_modules/flexsearch/src/lang/latin/extra.js b/paige/node_modules/flexsearch/src/lang/latin/extra.js new file mode 100644 index 00000000..cc5dafc7 --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/latin/extra.js @@ -0,0 +1,67 @@ +import { IndexInterface } from "../../type.js"; +import { regex, replace, collapse } from "../../lang.js"; +import { encode as encode_advanced } from "./advanced.js"; + +export const rtl = false; +export const tokenize = ""; +export default { + encode: encode, + rtl: rtl, + tokenize: tokenize +} + +// Soundex Normalization + +const prefix = "(?!\\b)"; +const //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(prefix + "[aeo]"); + +const 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, /* skip post-processing: */ true); + + if(str.length > 1){ + + //str = replace(str, pairs); + str = str.replace(regex_vowel, ""); + } + + if(str.length > 1){ + + str = collapse(str); + } + + if(str){ + + str = str.split(" "); + } + } + + return str || []; +} diff --git a/paige/node_modules/flexsearch/src/lang/latin/simple.js b/paige/node_modules/flexsearch/src/lang/latin/simple.js new file mode 100644 index 00000000..8f0cefed --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/latin/simple.js @@ -0,0 +1,60 @@ +import { IndexInterface } from "../../type.js"; +import { pipeline, normalize, regex_whitespace, regex } from "../../lang.js"; + +export const rtl = false; +export const tokenize = ""; +export default { + encode: encode, + rtl: rtl, + tokenize: 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(" & "); + +const 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, + /* collapse: */ false + ); +} diff --git a/paige/node_modules/flexsearch/src/lang/us.js b/paige/node_modules/flexsearch/src/lang/us.js new file mode 100644 index 00000000..c7e9870d --- /dev/null +++ b/paige/node_modules/flexsearch/src/lang/us.js @@ -0,0 +1,276 @@ +/** + * http://www.ranks.nl/stopwords + * @type {Array} + */ + +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} + */ + +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 +} diff --git a/paige/node_modules/flexsearch/src/polyfill.js b/paige/node_modules/flexsearch/src/polyfill.js new file mode 100644 index 00000000..394fd8a4 --- /dev/null +++ b/paige/node_modules/flexsearch/src/polyfill.js @@ -0,0 +1,79 @@ +// COMPILER BLOCK --> +import { POLYFILL, SUPPORT_ASYNC } from "./config.js"; +// <-- COMPILER BLOCK +export let promise = Promise; + +if(POLYFILL){ + + Object.assign || (Object.assign = function(){ + + const args = arguments; + const size = args.length; + const 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(SUPPORT_ASYNC && !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; + } +} diff --git a/paige/node_modules/flexsearch/src/preset.js b/paige/node_modules/flexsearch/src/preset.js new file mode 100644 index 00000000..a10dd006 --- /dev/null +++ b/paige/node_modules/flexsearch/src/preset.js @@ -0,0 +1,100 @@ +// COMPILER BLOCK --> +import { DEBUG } from "./config.js"; +// <-- COMPILER BLOCK +import { is_string } from "./common.js"; + +/** + * @enum {Object} + * @const + */ + +const preset = { + + "memory": { + charset: "latin:extra", + //tokenize: "strict", + resolution: 3, + //threshold: 0, + minlength: 4, + fastupdate: false + }, + + "performance": { + //charset: "latin", + //tokenize: "strict", + resolution: 3, + minlength: 3, + //fastupdate: true, + optimize: false, + //fastupdate: true, + context: { + depth: 2, + resolution: 1 + //bidirectional: false + } + }, + + "match": { + charset: "latin:extra", + tokenize: "reverse", + //resolution: 9, + //threshold: 0 + }, + + "score": { + charset: "latin:advanced", + //tokenize: "strict", + resolution: 20, + minlength: 3, + context: { + depth: 3, + resolution: 9, + //bidirectional: true + } + }, + + "default": { + // charset: "latin:default", + // tokenize: "strict", + // resolution: 3, + // threshold: 0, + // depth: 3 + }, + + // "fast": { + // //charset: "latin", + // //tokenize: "strict", + // threshold: 8, + // resolution: 9, + // depth: 1 + // } +}; + +export default function apply_preset(options){ + + if(is_string(options)){ + + if(DEBUG && !preset[options]){ + + console.warn("Preset not found: " + options); + } + + options = preset[options]; + } + else{ + + const preset = options["preset"]; + + if(preset){ + + if(DEBUG && !preset[preset]){ + + console.warn("Preset not found: " + preset); + } + + options = Object.assign({}, preset[preset], /** @type {Object} */ (options)); + } + } + + return options; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/src/serialize.js b/paige/node_modules/flexsearch/src/serialize.js new file mode 100644 index 00000000..6362d20b --- /dev/null +++ b/paige/node_modules/flexsearch/src/serialize.js @@ -0,0 +1,274 @@ +// 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 = true + if (typeof on_done === 'undefined') { + 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 (typeof field === 'undefined' && 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 = false; + 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 (typeof on_done === 'undefined') { + 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]; + const 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 = false; + this.register = data; + + for(let i = 0, index; i < this.field.length; i++){ + + index = this.index[this.field[i]]; + index.register = data; + index.fastupdate = false; + } + + break; + + case "store": + + this.store = data; + break; + + default: + + key = key.split("."); + const field = key[0]; + key = key[1]; + + if(field && key){ + + this.index[field].import(key, data); + } + } +} diff --git a/paige/node_modules/flexsearch/src/type.js b/paige/node_modules/flexsearch/src/type.js new file mode 100644 index 00000000..f6acd1bc --- /dev/null +++ b/paige/node_modules/flexsearch/src/type.js @@ -0,0 +1,69 @@ +/** + * @interface + */ + +export function IndexInterface(){ + + this.cache = null; + this.matcher = null; + this.stemmer = null; + this.filter = null; +} + +/** + * @param {!string} str + * @param {boolean|Array=} normalize + * @param {boolean|string|RegExp=} split + * @param {boolean=} collapse + * @returns {string|Array} + */ + +//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} + */ + +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; +} diff --git a/paige/node_modules/flexsearch/src/webpack.js b/paige/node_modules/flexsearch/src/webpack.js new file mode 100644 index 00000000..1e17b969 --- /dev/null +++ b/paige/node_modules/flexsearch/src/webpack.js @@ -0,0 +1,100 @@ +import { RELEASE, SUPPORT_ASYNC, SUPPORT_DOCUMENT, SUPPORT_CACHE, SUPPORT_SERIALIZE, SUPPORT_WORKER, SUPPORT_ENCODER } from "./config.js"; +import Document from "./document.js"; +import Index from "./index.js"; +import WorkerIndex from "./worker/index.js"; +import { registerCharset, registerLanguage } from "./global.js"; +import charset_default from "./lang/latin/default.js" +import charset_simple from "./lang/latin/simple.js" +import charset_balance from "./lang/latin/balance.js" +import charset_advanced from "./lang/latin/advanced.js" +import charset_extra from "./lang/latin/extra.js" + +/** @export */ Document.prototype.add; +/** @export */ Document.prototype.append; +/** @export */ Document.prototype.search; +/** @export */ Document.prototype.update; +/** @export */ Document.prototype.remove; +/** @export */ Document.prototype.contain; +/** @export */ Document.prototype.get; +/** @export */ Document.prototype.set; + +/** @export */ Index.prototype.add; +/** @export */ Index.prototype.append; +/** @export */ Index.prototype.search; +/** @export */ Index.prototype.update; +/** @export */ Index.prototype.remove; +/** @export */ Index.prototype.contain; + +if(SUPPORT_CACHE){ + +/** @export */ Index.prototype.searchCache; +/** @export */ Document.prototype.searchCache; +} + +if(SUPPORT_ASYNC){ + +/** @export */ Document.prototype.addAsync; +/** @export */ Document.prototype.appendAsync; +/** @export */ Document.prototype.searchAsync; +/** @export */ Document.prototype.updateAsync; +/** @export */ Document.prototype.removeAsync; + +/** @export */ Index.prototype.addAsync; +/** @export */ Index.prototype.appendAsync; +/** @export */ Index.prototype.searchAsync; +/** @export */ Index.prototype.updateAsync; +/** @export */ Index.prototype.removeAsync; +} + +if(SUPPORT_SERIALIZE){ + +/** @export */ Index.prototype.export; +/** @export */ Index.prototype.import; +/** @export */ Document.prototype.export; +/** @export */ Document.prototype.import; +} + +if(SUPPORT_ENCODER){ + + registerCharset("latin:default", charset_default); + registerCharset("latin:simple", charset_simple); + registerCharset("latin:balance", charset_balance); + registerCharset("latin:advanced", charset_advanced); + registerCharset("latin:extra", charset_extra); +} + +const FlexSearch = { + + "Index": Index, + "Document": SUPPORT_DOCUMENT ? Document : null, + "Worker": SUPPORT_WORKER ? WorkerIndex : null, + "registerCharset": registerCharset, + "registerLanguage": registerLanguage +}; + +if(RELEASE !== "bundle.module" && RELEASE !== "light.module" && RELEASE !== "compact.module"){ + + let tmp; + + if((tmp = self["define"]) && tmp["amd"]){ + + tmp([], function(){ + + return FlexSearch; + }); + } + else if(self["exports"]){ + + self["exports"] = FlexSearch; + } + else{ + + /** @export */ + self.FlexSearch = FlexSearch; + } +} +else{ + + /** @export */ + self.FlexSearch = FlexSearch; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/src/worker/handler.js b/paige/node_modules/flexsearch/src/worker/handler.js new file mode 100644 index 00000000..b63c847e --- /dev/null +++ b/paige/node_modules/flexsearch/src/worker/handler.js @@ -0,0 +1,51 @@ +import Index from "../index.js"; + +export default function(data) { + + data = data["data"]; + + /** @type Index */ + const index = self["_index"]; + const args = data["args"]; + const task = data["task"]; + + switch(task){ + + case "init": + + const options = data["options"] || {}; + const factory = data["factory"]; + const encode = options["encode"]; + + options["cache"] = false; + + if(encode && (encode.indexOf("function") === 0)){ + + 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"]; + const message = index[task].apply(index, args); + postMessage(task === "search" ? { "id": id, "msg": message } : { "id": id }); + } +}; diff --git a/paige/node_modules/flexsearch/src/worker/index.js b/paige/node_modules/flexsearch/src/worker/index.js new file mode 100644 index 00000000..926e73e0 --- /dev/null +++ b/paige/node_modules/flexsearch/src/worker/index.js @@ -0,0 +1,157 @@ +//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 = typeof window === "undefined" && self["exports"]; + const _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; + const args = [].slice.call(arguments); + const arg = args[args.length - 1]; + let callback; + + if(is_function(arg)){ + + callback = arg; + args.splice(args.length - 1, 1); + } + + const promise = new Promise(function(resolve){ + + setTimeout(function(){ + + 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"])(__dirname + "/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; +} \ No newline at end of file diff --git a/paige/node_modules/flexsearch/src/worker/node.js b/paige/node_modules/flexsearch/src/worker/node.js new file mode 100644 index 00000000..8a8a4688 --- /dev/null +++ b/paige/node_modules/flexsearch/src/worker/node.js @@ -0,0 +1,35 @@ +const { parentPort } = require("worker_threads"); +const { Index } = require("../flexsearch.bundle.min.js"); + +let index; + +parentPort.on("message", function(data){ + + /** @type Index */ + const args = data["args"]; + const task = data["task"]; + const id = data["id"]; + + switch(task){ + + case "init": + + const options = data["options"] || {}; + const encode = options["encode"]; + + options["cache"] = false; + + if(encode && (encode.indexOf("function") === 0)){ + + options["encode"] = new Function("return " + encode)(); + } + + index = new Index(options); + break; + + default: + + const message = index[task].apply(index, args); + parentPort.postMessage(task === "search" ? { "id": id, "msg": message } : { "id": id }); + } +}); diff --git a/paige/node_modules/flexsearch/src/worker/worker.js b/paige/node_modules/flexsearch/src/worker/worker.js new file mode 100644 index 00000000..4772d6c0 --- /dev/null +++ b/paige/node_modules/flexsearch/src/worker/worker.js @@ -0,0 +1,2 @@ +import handler from "./handler.js"; +onmessage = handler; diff --git a/paige/node_modules/flexsearch/task/babel.bundle.json b/paige/node_modules/flexsearch/task/babel.bundle.json new file mode 100644 index 00000000..1b52d66f --- /dev/null +++ b/paige/node_modules/flexsearch/task/babel.bundle.json @@ -0,0 +1,41 @@ +{ + "plugins": [ + ["conditional-compile", { + "dropDebugger": true, + "define": { + "RELEASE": "module", + "DEBUG": false, + "POLYFILL": 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 + } + }], + "babel-plugin-minify-constant-folding", + "babel-plugin-minify-dead-code-elimination", + "babel-plugin-minify-flip-comparisons", + "babel-plugin-minify-guarded-expressions", + "babel-plugin-minify-infinity", + "babel-plugin-minify-replace", + "babel-plugin-minify-type-constructors", + "babel-plugin-transform-member-expression-literals", + "babel-plugin-transform-merge-sibling-variables", + "babel-plugin-transform-minify-booleans", + "babel-plugin-transform-property-literals", + "babel-plugin-transform-simplify-comparison-operators", + "babel-plugin-transform-undefined-to-void" + ], + "ignore": [ + "webpack.js", + "config.js" + ], + "minified": false, + "compact": false, + "comments": true +} diff --git a/paige/node_modules/flexsearch/task/babel.debug.json b/paige/node_modules/flexsearch/task/babel.debug.json new file mode 100644 index 00000000..6faad82e --- /dev/null +++ b/paige/node_modules/flexsearch/task/babel.debug.json @@ -0,0 +1,41 @@ +{ + "plugins": [ + ["conditional-compile", { + "dropDebugger": true, + "define": { + "RELEASE": "module", + "DEBUG": true, + "POLYFILL": 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 + } + }], + "babel-plugin-minify-constant-folding", + "babel-plugin-minify-dead-code-elimination", + "babel-plugin-minify-flip-comparisons", + "babel-plugin-minify-guarded-expressions", + "babel-plugin-minify-infinity", + "babel-plugin-minify-replace", + "babel-plugin-minify-type-constructors", + "babel-plugin-transform-member-expression-literals", + "babel-plugin-transform-merge-sibling-variables", + "babel-plugin-transform-minify-booleans", + "babel-plugin-transform-property-literals", + "babel-plugin-transform-simplify-comparison-operators", + "babel-plugin-transform-undefined-to-void" + ], + "ignore": [ + "webpack.js", + "config.js" + ], + "minified": false, + "compact": false, + "comments": true +} diff --git a/paige/node_modules/flexsearch/task/babel.js b/paige/node_modules/flexsearch/task/babel.js new file mode 100644 index 00000000..7c1bd5c1 --- /dev/null +++ b/paige/node_modules/flexsearch/task/babel.js @@ -0,0 +1,65 @@ +const child_process = require("child_process"); +const fs = require("fs"); +const debug = process.argv[2] && process.argv[2].toLowerCase().includes("debug=true"); +const minify = process.argv[2] && process.argv[2].toLowerCase().includes("release=min"); + +console.log("Start build ....."); +console.log('Bundle: ' + ('module' /* 'custom' */) + (debug ? ":debug" : (minify ? ":min" : ""))); + +//fs.existsSync("log") || fs.mkdirSync("log"); +fs.existsSync("tmp") || fs.mkdirSync("tmp"); +fs.existsSync("dist") || fs.mkdirSync("dist"); + +const files = [ + + "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" +]; + +files.forEach(function(file){ + + let src = String(fs.readFileSync("src/" + file)); + src = src.replace(/\/\/ COMPILER BLOCK -->(.*)<-- COMPILER BLOCK/gs, ""); + fs.writeFileSync("tmp/" + file, src); +}); + +fs.copyFileSync("task/babel." + (debug ? "debug": (minify ? "min" : "bundle")) + ".json", "tmp/.babelrc"); + +exec("npx babel tmp -d dist/module" + (debug ? "-debug" : (minify ? "-min --minified --compact true" : "")) + " --config-file tmp/.babelrc && exit 0", function(){ + + console.log("Build Complete."); +}); + +function exec(prompt, callback){ + + const child = child_process.exec(prompt, function(err, stdout, stderr){ + + if(err){ + + console.error(err); + } + else{ + + if(callback){ + + callback(); + } + } + }); + + child.stdout.pipe(process.stdout); + child.stderr.pipe(process.stderr); +} diff --git a/paige/node_modules/flexsearch/task/babel.min.json b/paige/node_modules/flexsearch/task/babel.min.json new file mode 100644 index 00000000..ee5724a0 --- /dev/null +++ b/paige/node_modules/flexsearch/task/babel.min.json @@ -0,0 +1,43 @@ +{ + "plugins": [ + ["conditional-compile", { + "dropDebugger": true, + "define": { + "RELEASE": "module", + "DEBUG": false, + "POLYFILL": 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 + } + }], + "babel-plugin-minify-constant-folding", + "babel-plugin-minify-dead-code-elimination", + "babel-plugin-minify-flip-comparisons", + "babel-plugin-minify-guarded-expressions", + "babel-plugin-minify-infinity", + "babel-plugin-minify-mangle-names", + "babel-plugin-minify-replace", + "babel-plugin-minify-simplify", + "babel-plugin-minify-type-constructors", + "babel-plugin-transform-member-expression-literals", + "babel-plugin-transform-merge-sibling-variables", + "babel-plugin-transform-minify-booleans", + "babel-plugin-transform-property-literals", + "babel-plugin-transform-simplify-comparison-operators", + "babel-plugin-transform-undefined-to-void" + ], + "ignore": [ + "webpack.js", + "config.js" + ], + "minified": true, + "compact": true, + "comments": false +} diff --git a/paige/node_modules/flexsearch/task/build.js b/paige/node_modules/flexsearch/task/build.js new file mode 100644 index 00000000..2ee21f5d --- /dev/null +++ b/paige/node_modules/flexsearch/task/build.js @@ -0,0 +1,344 @@ +const child_process = require("child_process"); +const fs = require("fs"); + +console.log("Start build ....."); + +fs.rmSync("tmp/", { recursive: true }); +fs.mkdirSync("tmp"); +//fs.existsSync("log") || fs.mkdirSync("log"); +fs.existsSync("dist") || fs.mkdirSync("dist"); + +var supported_lang = [ + + 'en', + 'de', + 'at', + 'us' +]; + +var supported_charset = { + + 'latin': ["default", "advanced", "balance", "extra", "simple"], + 'cjk': ["default"], + 'cyrillic': ["default"], + 'arabic': ["default"], +}; + +let flag_str = ""; +let language_out; +let use_polyfill; +var formatting; +var compilation_level; + +var options = (function(argv){ + + const arr = {}; + let count = 0; + + argv.forEach(function(val, index) { + + if(++count > 2){ + + index = val.split('='); + val = index[1]; + index = index[0].toUpperCase(); + + if(index === "LANGUAGE_OUT"){ + + language_out = val; + } + else if(index === "FORMATTING"){ + + formatting = val; + } + else if(index === "COMPILATION_LEVEL"){ + + compilation_level = val; + } + else if(index === "POLYFILL"){ + + use_polyfill = val === "true"; + } + else{ + + if(val === "false") val = false; + arr[index] = val; + } + } + }); + + console.log('Release: ' + (arr['RELEASE'] || 'custom') + (arr['DEBUG'] ? ":debug" : "")); + + return arr; + +})(process.argv); + +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"); + +// 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)); +// } + +let parameter = (function(opt){ + + if(formatting && !opt["formatting"]){ + + opt["formatting"] = formatting; + } + + let parameter = ''; + + for(let index in opt){ + + if(opt.hasOwnProperty(index)){ + + if((release !== "lang") /*|| (index !== "entry_point")*/){ + + parameter += ' --' + index + '=' + opt[index]; + } + } + } + + return parameter; +})({ + + compilation_level: compilation_level || "ADVANCED_OPTIMIZATIONS", //"SIMPLE" + use_types_for_optimization: true, + generate_exports: true, + export_local_property_definitions: true, + //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",, + strict_mode_input: true, + //assume_function_wrapper: true, + + //transform_amd_modules: true, + process_common_js_modules: false, + module_resolution: "BROWSER", + //dependency_mode: "SORT_ONLY", + //js_module_root: "./", + entry_point: "./tmp/webpack.js", + //manage_closure_dependencies: true, + dependency_mode: "PRUNE_LEGACY", // PRUNE_LEGACY + rewrite_polyfills: use_polyfill || false, + + //isolation_mode: "IIFE", + //output_wrapper: /*release === "lang" ? "%output%" :*/ "\"(function(self){%output%}(this));\"" + //formatting: "PRETTY_PRINT" +}); + +// if(options["DEBUG"]){ +// parameter += ' --formatting=PRETTY_PRINT'; +// } + +if(release !== "bundle.module" && release !== "light.module"){ + //parameter += ' --isolation_mode=IIFE'; + parameter += ' --emit_use_strict=true'; + parameter += ' --output_wrapper="\"(function(self){%output%}(this));\""'; +} + +const custom = (!release || (release === "custom")); + +if(custom){ + + release = "custom." + hashCode(parameter + flag_str).replace(/[^a-zA-Z0-9]/g, "").toLowerCase(); +} + +// 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{ + + if(release === "lang") throw new Error("disabled"); + + +const files = [ + + "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" +]; + +files.forEach(function(file){ + + if(file === "config.js"){ + + let src = String(fs.readFileSync("src/" + file)); + + for(let opt in options){ + + src = src.replace(new RegExp('(export const ' + opt + ' = )(")?[^";]+(")?;'), "$1$2" + options[opt] + "$3;"); + } + + fs.writeFileSync("tmp/" + file, src); + } + else{ + + fs.copyFileSync("src/" + file, "tmp/" + file); + } +}); + +fs.cpSync("src/lang/", "tmp/lang/", { recursive: true }); +fs.cpSync("src/worker/", "tmp/worker/", { recursive: true }); + +const filename = "dist/flexsearch." + (release || "custom") + (options["DEBUG"] ? ".debug" : ".min") + ".js"; + +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"; + +exec(executable + parameter + " --js='tmp/**.js' --js='!tmp/**/node.js'" + flag_str + " --js_output_file='" + filename + "' && exit 0", function(){ + + let build = fs.readFileSync(filename); + let preserve = fs.readFileSync("src/index.js", "utf8"); + + const package_json = require("../package.json"); + + 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; + + if(release === "bundle"){ + + build = build.replace("(function(self){'use strict';", "(function _f(self){'use strict';try{if(module)self=module}catch(e){}self._factory=_f;"); + } + + build = build.replace(/eval\('(.*)'\)/, "$1"); + + if(release === "bundle.module" || release === "light.module" || release === "compact.module"){ + + build = build.replace(/self\.FlexSearch(\s+)?=(\s+)?/, "export default "); + } + + // if(release === "pre"){ + // + // fs.existsSync("test/dist") || fs.mkdirSync("test/dist"); + // fs.writeFileSync("test/" + filename, build); + // } + // else{ + + fs.writeFileSync(filename, build); + // } + + fs.copyFileSync("src/worker/node.js", "dist/node/node.js"); + + console.log("Build Complete."); +}); +//} + +function hashCode(str) { + + let hash = 0, i, chr; + + if(str.length === 0){ + + return hash; + } + + for(i = 0; i < str.length; i++){ + + chr = str.charCodeAt(i); + hash = (hash << 5) - hash + chr; + } + + hash = Math.abs(hash) >> 0; + + return hash.toString(16).substring(0, 5); +} + +function exec(prompt, callback){ + + const child = child_process.exec(prompt, function(err, stdout, stderr){ + + if(err){ + + console.error(err); + } + else{ + + if(callback){ + + callback(); + } + } + }); + + child.stdout.pipe(process.stdout); + child.stderr.pipe(process.stderr); +} diff --git a/paige/package-lock.json b/paige/package-lock.json index 5f159fe3..4af4f03a 100644 --- a/paige/package-lock.json +++ b/paige/package-lock.json @@ -7,6 +7,7 @@ "dependencies": { "bootstrap": "^5.3.3", "bootstrap-icons": "^1.11.0", + "flexsearch": "^0.7.43", "katex": "^0.16.10" } }, @@ -65,6 +66,12 @@ "node": ">= 12" } }, + "node_modules/flexsearch": { + "version": "0.7.43", + "resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.7.43.tgz", + "integrity": "sha512-c5o/+Um8aqCSOXGcZoqZOm+NqtVwNsvVpWv6lfmSclU954O3wvQKxxK8zj74fPaSJbXpSLTs4PRhh+wnoCXnKg==", + "license": "Apache-2.0" + }, "node_modules/katex": { "version": "0.16.21", "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.21.tgz", diff --git a/paige/package.json b/paige/package.json index 1a98708a..a37e0ef9 100644 --- a/paige/package.json +++ b/paige/package.json @@ -2,6 +2,7 @@ "dependencies": { "bootstrap": "^5.3.3", "bootstrap-icons": "^1.11.0", + "flexsearch": "^0.7.43", "katex": "^0.16.10" } }