diff --git a/dist/Empty Document b/dist/Empty Document deleted file mode 100644 index e69de29..0000000 diff --git a/dist/cjs/diacritics.js b/dist/cjs/diacritics.js new file mode 100644 index 0000000..762c818 --- /dev/null +++ b/dist/cjs/diacritics.js @@ -0,0 +1,123 @@ +/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +// https://github.com/andrewrk/node-diacritics/blob/master/index.js +/** + * code points generated from toCodePoints(); + * removed 65339 to 65345 + */ + +var code_points = [[67, 67], [160, 160], [192, 438], [452, 652], [961, 961], [1019, 1019], [1083, 1083], [1281, 1289], [1984, 1984], [5095, 5095], [7429, 7441], [7545, 7549], [7680, 7935], [8580, 8580], [9398, 9449], [11360, 11391], [42792, 42793], [42802, 42851], [42873, 42897], [42912, 42922], [64256, 64260], [65313, 65338], [65345, 65370]]; +/** + * Remove accents + * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703 + * + */ + +function asciifold(str) { + return str.normalize('NFD').replace(/[\u0300-\u036F]/g, '').normalize('NFKD').toLowerCase(); +} +/** + * Generate a list of diacritics from the list of code points + * + */ + + +function generateDiacritics() { + var latin_convert = { + 'l·': 'l', + 'ʼn': 'n', + 'æ': 'ae', + 'ø': 'o', + 'aʾ': 'a', + 'dž': 'dz' + }; + var diacritics = {}; //var no_latin = []; + + code_points.forEach(code_range => { + for (let i = code_range[0]; i <= code_range[1]; i++) { + let diacritic = String.fromCharCode(i); + let latin = diacritic.normalize('NFD').replace(/[\u0300-\u036F]/g, '').normalize('NFKD'); + + if (latin == diacritic) { + //no_latin.push(diacritic); + continue; + } + + latin = latin.toLowerCase(); + + if (latin in latin_convert) { + latin = latin_convert[latin]; + } + + if (!(latin in diacritics)) { + diacritics[latin] = latin + latin.toUpperCase(); + } + + diacritics[latin] += diacritic; + } + }); //console.log('no_latin',JSON.stringify(no_latin)); + + return diacritics; +} +/** + * Expand a regular expression pattern to include diacritics + * eg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/ + * + */ + +var diacritics = null; +function diacriticRegexPoints(regex) { + if (diacritics === null) { + diacritics = generateDiacritics(); + } + + for (let latin in diacritics) { + if (diacritics.hasOwnProperty(latin)) { + regex = regex.replace(new RegExp(latin, 'g'), '[' + diacritics[latin] + ']'); + } + } + + return regex; +} +/** + * Expand a regular expression pattern to include diacritics + * eg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/ + * + * rollup will bundle this function (and the DIACRITICS constant) unless commented out + * +var diacriticRegex = (function() { + + var list = []; + for( let letter in DIACRITICS ){ + + if( letter.toLowerCase() != letter && letter.toLowerCase() in DIACRITICS ){ + continue; + } + + if( DIACRITICS.hasOwnProperty(letter) ){ + + var replace = letter + DIACRITICS[letter]; + if( letter.toUpperCase() in DIACRITICS ){ + replace += letter.toUpperCase() + DIACRITICS[letter.toUpperCase()]; + } + + list.push({let:letter,pat:'['+replace+']'}); + } + } + + return function(regex:string):string{ + list.forEach((item)=>{ + regex = regex.replace( new RegExp(item.let,'g'),item.pat); + }); + return regex; + } +})(); +*/ + +exports.asciifold = asciifold; +exports.diacriticRegexPoints = diacriticRegexPoints; +exports.generateDiacritics = generateDiacritics; +//# sourceMappingURL=diacritics.js.map diff --git a/dist/cjs/diacritics.js.map b/dist/cjs/diacritics.js.map new file mode 100644 index 0000000..c77bb5e --- /dev/null +++ b/dist/cjs/diacritics.js.map @@ -0,0 +1 @@ +{"version":3,"file":"diacritics.js","sources":["../../lib/diacritics.ts"],"sourcesContent":["\ntype TDiacraticList = {[key:string]:string};\n\n// https://github.com/andrewrk/node-diacritics/blob/master/index.js\nvar DIACRITICS:TDiacraticList = {\n\t\" \":\" \",\n\t0:\"߀\",\n\tA:\"ⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ\",\n\tAA:\"Ꜳ\",\n\tAE:\"ÆǼǢ\",\n\tAO:\"Ꜵ\",\n\tAU:\"Ꜷ\",\n\tAV:\"ꜸꜺ\",\n\tAY:\"Ꜽ\",\n\tB:\"ⒷBḂḄḆɃƁ\",\n\tC:\"ⒸCꜾḈĆCĈĊČÇƇȻ\",\n\tD:\"ⒹDḊĎḌḐḒḎĐƊƉᴅꝹ\",\n\tDh:\"Ð\",\n\tDZ:\"DZDŽ\",\n\tDz:\"DzDž\",\n\tE:\"ɛⒺEÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚƐƎᴇ\",\n\tF:\"ꝼⒻFḞƑꝻ\",\n\tG:\"ⒼGǴĜḠĞĠǦĢǤƓꞠꝽꝾɢ\",\n\tH:\"ⒽHĤḢḦȞḤḨḪĦⱧⱵꞍ\",\n\tI:\"ⒾIÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬƗ\",\n\tJ:\"ⒿJĴɈȷ\",\n\tK:\"ⓀKḰǨḲĶḴƘⱩꝀꝂꝄꞢ\",\n\tL:\"ⓁLĿĹĽḶḸĻḼḺŁȽⱢⱠꝈꝆꞀ\",\n\tLJ:\"LJ\",\n\tLj:\"Lj\",\n\tM:\"ⓂMḾṀṂⱮƜϻ\",\n\tN:\"ꞤȠⓃNǸŃÑṄŇṆŅṊṈƝꞐᴎ\",\n\tNJ:\"NJ\",\n\tNj:\"Nj\",\n\tO:\"ⓄOÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘǪǬØǾƆƟꝊꝌ\",\n\tOE:\"Œ\",\n\tOI:\"Ƣ\",\n\tOO:\"Ꝏ\",\n\tOU:\"Ȣ\",\n\tP:\"ⓅPṔṖƤⱣꝐꝒꝔ\",\n\tQ:\"ⓆQꝖꝘɊ\",\n\tR:\"ⓇRŔṘŘȐȒṚṜŖṞɌⱤꝚꞦꞂ\",\n\tS:\"ⓈSẞŚṤŜṠŠṦṢṨȘŞⱾꞨꞄ\",\n\tT:\"ⓉTṪŤṬȚŢṰṮŦƬƮȾꞆ\",\n\tTh:\"Þ\",\n\tTZ:\"Ꜩ\",\n\tU:\"ⓊUÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴɄ\",\n\tV:\"ⓋVṼṾƲꝞɅ\",\n\tVY:\"Ꝡ\",\n\tW:\"ⓌWẀẂŴẆẄẈⱲ\",\n\tX:\"ⓍXẊẌ\",\n\tY:\"ⓎYỲÝŶỸȲẎŸỶỴƳɎỾ\",\n\tZ:\"ⓏZŹẐŻŽẒẔƵȤⱿⱫꝢ\",\n\ta:\"ⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑ\",\n\taa:\"ꜳ\",\n\tae:\"æǽǣ\",\n\tao:\"ꜵ\",\n\tau:\"ꜷ\",\n\tav:\"ꜹꜻ\",\n\tay:\"ꜽ\",\n\tb:\"ⓑbḃḅḇƀƃɓƂ\",\n\tc:\"cⓒćĉċčçḉƈȼꜿↄ\",\n\td:\"ⓓdḋďḍḑḓḏđƌɖɗƋᏧԁꞪ\",\n\tdh:\"ð\",\n\tdz:\"dzdž\",\n\te:\"ⓔeèéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛɇǝ\",\n\tf:\"ⓕfḟƒ\",\n\tff:\"ff\",\n\tfi:\"fi\",\n\tfl:\"fl\",\n\tffi:\"ffi\",\n\tffl:\"ffl\",\n\tg:\"ⓖgǵĝḡğġǧģǥɠꞡꝿᵹ\",\n\th:\"ⓗhĥḣḧȟḥḩḫẖħⱨⱶɥ\",\n\thv:\"ƕ\",\n\ti:\"ⓘiìíîĩīĭïḯỉǐȉȋịįḭɨı\",\n\tj:\"ⓙjĵǰɉ\",\n\tk:\"ⓚkḱǩḳķḵƙⱪꝁꝃꝅꞣ\",\n\tl:\"ⓛlŀĺľḷḹļḽḻſłƚɫⱡꝉꞁꝇɭ\",\n\tlj:\"lj\",\n\tm:\"ⓜmḿṁṃɱɯ\",\n\tn:\"ⓝnǹńñṅňṇņṋṉƞɲʼnꞑꞥлԉ\",\n\tnj:\"nj\",\n\to:\"ⓞoòóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộǫǭøǿꝋꝍɵɔᴑ\",\n\toe:\"œ\",\n\toi:\"ƣ\",\n\too:\"ꝏ\",\n\tou:\"ȣ\",\n\tp:\"ⓟpṕṗƥᵽꝑꝓꝕρ\",\n\tq:\"ⓠqɋꝗꝙ\",\n\tr:\"ⓡrŕṙřȑȓṛṝŗṟɍɽꝛꞧꞃ\",\n\ts:\"ⓢsśṥŝṡšṧṣṩșşȿꞩꞅẛʂ\",\n\tss:\"ß\",\n\tt:\"ⓣtṫẗťṭțţṱṯŧƭʈⱦꞇ\",\n\tth:\"þ\",\n\ttz:\"ꜩ\",\n\tu:\"ⓤuùúûũṹūṻŭüǜǘǖǚủůűǔȕȗưừứữửựụṳųṷṵʉ\",\n\tv:\"ⓥvṽṿʋꝟʌ\",\n\tvy:\"ꝡ\",\n\tw:\"ⓦwẁẃŵẇẅẘẉⱳ\",\n\tx:\"ⓧxẋẍ\",\n\ty:\"ⓨyỳýŷỹȳẏÿỷẙỵƴɏỿ\",\n\tz:\"ⓩzźẑżžẓẕƶȥɀⱬꝣ\"\n}\n\n/**\n * code points generated from toCodePoints();\n * removed 65339 to 65345\n */\nvar code_points = [\n\t[ 67, 67 ],\n\t[ 160, 160 ],\n\t[ 192, 438 ],\n\t[ 452, 652 ],\n\t[ 961, 961 ],\n\t[ 1019, 1019 ],\n\t[ 1083, 1083 ],\n\t[ 1281, 1289 ],\n\t[ 1984, 1984 ],\n\t[ 5095, 5095 ],\n\t[ 7429, 7441 ],\n\t[ 7545, 7549 ],\n\t[ 7680, 7935 ],\n\t[ 8580, 8580 ],\n\t[ 9398, 9449 ],\n\t[ 11360, 11391 ],\n\t[ 42792, 42793 ],\n\t[ 42802, 42851 ],\n\t[ 42873, 42897 ],\n\t[ 42912, 42922 ],\n\t[ 64256, 64260 ],\n\t[ 65313, 65338 ],\n\t[ 65345, 65370 ]\n];\n\n/**\n * Remove accents\n * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703\n *\n */\nexport function asciifold(str:string):string{\n\treturn str.normalize('NFD').replace(/[\\u0300-\\u036F]/g, '').normalize('NFKD').toLowerCase();\n};\n\n\n/**\n * Convert list of diacritics to array of code points\n *\n */\n// @ts-ignore\nfunction toCodePoints(tolerance=8){\n\tvar char_codes = [];\n\n\tfor( let letter in DIACRITICS ){\n\t\tlet _diacritics = DIACRITICS[letter];\n\t\tfor( let n = 0; n < _diacritics.length; n++ ){\n\t\t\tvar code_point = _diacritics.codePointAt(n);\n\t\t\tchar_codes.push( code_point );\n\t\t}\n\t}\n\n\t//https://stackoverflow.com/questions/40431572/is-there-a-simple-way-to-group-js-array-values-by-range\n\tchar_codes.sort((a, b) => a - b);\n var result = char_codes.reduce(function (accumulator, currentValue, index, source) {\n\n\t\tif( !index ){\n\t\t\taccumulator.push( [currentValue,currentValue] );\n\n\t\t}else if( currentValue - source[index - 1] > tolerance ){\n\t\t\taccumulator.push( [currentValue,currentValue] );\n\n\t\t}else{\n\n\t\t\taccumulator.push( [accumulator.pop()[0],currentValue]);\n\t\t}\n\n return accumulator;\n }, []);\n\n\tconsole.log(`char_codes (${result.length})`,result);\n}\n\n/**\n * Generate a list of diacritics from the list of code points\n *\n */\nexport function generateDiacritics():TDiacraticList{\n\n\tvar latin_convert = {\n\t\t'l·': 'l',\n\t\t'ʼn': 'n',\n\t\t'æ': 'ae',\n\t\t'ø': 'o',\n\t\t'aʾ': 'a',\n\t\t'dž': 'dz',\n\t};\n\n\tvar diacritics\t= {};\n\t//var no_latin\t= [];\n\tcode_points.forEach((code_range)=>{\n\n\t\tfor(let i = code_range[0]; i <= code_range[1]; i++){\n\t\t\tlet diacritic\t= String.fromCharCode(i);\n\t\t\tlet latin\t\t= diacritic.normalize('NFD').replace(/[\\u0300-\\u036F]/g, '').normalize('NFKD');\n\n\t\t\tif( latin == diacritic ){\n\t\t\t\t//no_latin.push(diacritic);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlatin = latin.toLowerCase();\n\n\t\t\tif( latin in latin_convert ){\n\t\t\t\tlatin = latin_convert[latin];\n\t\t\t}\n\n\t\t\tif( !(latin in diacritics) ){\n\t\t\t\tdiacritics[latin] = latin + latin.toUpperCase();\n\t\t\t}\n\t\t\tdiacritics[latin] += diacritic;\n\t\t}\n\t});\n\n\t//console.log('no_latin',JSON.stringify(no_latin));\n\n\treturn diacritics;\n}\n\n/**\n * Expand a regular expression pattern to include diacritics\n * \teg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/\n *\n */\nvar diacritics:TDiacraticList = null\nexport function diacriticRegexPoints(regex:string):string{\n\n\tif( diacritics === null ){\n\t\tdiacritics = generateDiacritics();\n\t}\n\n\tfor( let latin in diacritics ){\n\t\tif( diacritics.hasOwnProperty(latin) ){\n\t\t\tregex = regex.replace( new RegExp(latin,'g'), '['+diacritics[latin]+']');\n\t\t}\n\t}\n\treturn regex;\n}\n\n\n/**\n * Expand a regular expression pattern to include diacritics\n * \teg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/\n *\n * rollup will bundle this function (and the DIACRITICS constant) unless commented out\n *\nvar diacriticRegex = (function() {\n\n\tvar list = [];\n\tfor( let letter in DIACRITICS ){\n\n\t\tif( letter.toLowerCase() != letter && letter.toLowerCase() in DIACRITICS ){\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( DIACRITICS.hasOwnProperty(letter) ){\n\n\t\t\tvar replace = letter + DIACRITICS[letter];\n\t\t\tif( letter.toUpperCase() in DIACRITICS ){\n\t\t\t\treplace += letter.toUpperCase() + DIACRITICS[letter.toUpperCase()];\n\t\t\t}\n\n\t\t\tlist.push({let:letter,pat:'['+replace+']'});\n\t\t}\n\t}\n\n\treturn function(regex:string):string{\n\t\tlist.forEach((item)=>{\n\t\t\tregex = regex.replace( new RegExp(item.let,'g'),item.pat);\n\t\t});\n\t\treturn regex;\n\t}\n})();\n*/\n"],"names":["code_points","asciifold","str","normalize","replace","toLowerCase","generateDiacritics","latin_convert","diacritics","forEach","code_range","i","diacritic","String","fromCharCode","latin","toUpperCase","diacriticRegexPoints","regex","hasOwnProperty","RegExp"],"mappings":"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"} \ No newline at end of file diff --git a/dist/cjs/sifter.js b/dist/cjs/sifter.js new file mode 100644 index 0000000..4659774 --- /dev/null +++ b/dist/cjs/sifter.js @@ -0,0 +1,382 @@ +/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */ +'use strict'; + +var utils = require('./utils.js'); +var diacritics = require('./diacritics.js'); + +/** + * sifter.js + * Copyright (c) 2013–2020 Brian Reavis & contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + * ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + * + * @author Brian Reavis + */ +class Sifter { + /** + * Textually searches arrays and hashes of objects + * by property (or multiple properties). Designed + * specifically for autocomplete. + * + * @constructor + * @param {array|object} items + * @param {object} items + */ + constructor(items, settings) { + this.items = void 0; + this.settings = void 0; + this.items = items; + this.settings = settings || { + diacritics: true + }; + } + + /** + * Splits a search string into an array of individual + * regexps to be used to match results. + * + */ + tokenize(query, respect_word_boundaries, weights) { + if (!query || !query.length) return []; + var tokens = []; + var words = query.split(/\s+/); + var field_regex; + + if (weights) { + field_regex = new RegExp('^(' + Object.keys(weights).map(utils.escape_regex).join('|') + ')\:(.*)$'); + } + + words.forEach(word => { + let field_match; + let field = null; + let regex = null; // look for "field:query" tokens + + if (field_regex && (field_match = word.match(field_regex))) { + field = field_match[1]; + word = field_match[2]; + } + + if (word.length > 0) { + regex = utils.escape_regex(word); + + if (this.settings.diacritics) { + regex = diacritics.diacriticRegexPoints(regex); + } + + if (respect_word_boundaries) regex = "\\b" + regex; + regex = new RegExp(regex, 'i'); + } + + tokens.push({ + string: word, + regex: regex, + field: field + }); + }); + return tokens; + } + + /** + * Returns a function to be used to score individual results. + * + * Good matches will have a higher score than poor matches. + * If an item is not a match, 0 will be returned by the function. + * + * @returns {function} + */ + getScoreFunction(query, options) { + var search = this.prepareSearch(query, options); + return this._getScoreFunction(search); + } + + _getScoreFunction(search) { + const tokens = search.tokens, + token_count = tokens.length; + + if (!token_count) { + return function () { + return 0; + }; + } + + const fields = search.options.fields, + weights = search.weights, + field_count = fields.length, + getAttrFn = search.getAttrFn; + /** + * Calculates the score of an object + * against the search query. + * + * @param {TToken} token + * @param {object} data + * @return {number} + */ + + var scoreObject = function () { + if (!field_count) { + return function () { + return 0; + }; + } + + if (field_count === 1) { + return function (token, data) { + const field = fields[0].field; + return utils.scoreValue(getAttrFn(data, field), token, weights[field]); + }; + } + + return function (token, data) { + var sum = 0; // is the token specific to a field? + + if (token.field) { + const value = getAttrFn(data, token.field); + + if (!token.regex && value) { + sum += 0.1; + } else { + sum += utils.scoreValue(value, token, weights[token.field]); + } + } else { + utils.iterate(weights, (weight, field) => { + sum += utils.scoreValue(getAttrFn(data, field), token, weight); + }); + } + + return sum / field_count; + }; + }(); + + if (token_count === 1) { + return function (data) { + return scoreObject(tokens[0], data); + }; + } + + if (search.options.conjunction === 'and') { + return function (data) { + var i = 0, + score, + sum = 0; + + for (; i < token_count; i++) { + score = scoreObject(tokens[i], data); + if (score <= 0) return 0; + sum += score; + } + + return sum / token_count; + }; + } else { + return function (data) { + var sum = 0; + utils.iterate(tokens, token => { + sum += scoreObject(token, data); + }); + return sum / token_count; + }; + } + } + + /** + * Returns a function that can be used to compare two + * results, for sorting purposes. If no sorting should + * be performed, `null` will be returned. + * + * @return function(a,b) + */ + getSortFunction(query, options) { + var search = this.prepareSearch(query, options); + return this._getSortFunction(search); + } + + _getSortFunction(search) { + var i, n, self, sort_fld, sort_flds, sort_flds_count, multiplier, multipliers, get_field, implicit_score, sort, options; + self = this; + options = search.options; + sort = !search.query && options.sort_empty || options.sort; + /** + * Fetches the specified sort field value + * from a search result item. + * + * @param {string} name + * @param {object} result + * @return {string} + */ + + get_field = function (name, result) { + if (name === '$score') return result.score; + return search.getAttrFn(self.items[result.id], name); + }; // parse options + + + sort_flds = []; + + if (sort) { + for (i = 0, n = sort.length; i < n; i++) { + if (search.query || sort[i].field !== '$score') { + sort_flds.push(sort[i]); + } + } + } // the "$score" field is implied to be the primary + // sort field, unless it's manually specified + + + if (search.query) { + implicit_score = true; + + for (i = 0, n = sort_flds.length; i < n; i++) { + if (sort_flds[i].field === '$score') { + implicit_score = false; + break; + } + } + + if (implicit_score) { + sort_flds.unshift({ + field: '$score', + direction: 'desc' + }); + } + } else { + for (i = 0, n = sort_flds.length; i < n; i++) { + if (sort_flds[i].field === '$score') { + sort_flds.splice(i, 1); + break; + } + } + } + + multipliers = []; + + for (i = 0, n = sort_flds.length; i < n; i++) { + multipliers.push(sort_flds[i].direction === 'desc' ? -1 : 1); + } // build function + + + sort_flds_count = sort_flds.length; + + if (!sort_flds_count) { + return null; + } else if (sort_flds_count === 1) { + sort_fld = sort_flds[0].field; + multiplier = multipliers[0]; + return function (a, b) { + return multiplier * utils.cmp(get_field(sort_fld, a), get_field(sort_fld, b)); + }; + } else { + return function (a, b) { + var i, result, field; + + for (i = 0; i < sort_flds_count; i++) { + field = sort_flds[i].field; + result = multipliers[i] * utils.cmp(get_field(field, a), get_field(field, b)); + if (result) return result; + } + + return 0; + }; + } + } + + /** + * Parses a search query and returns an object + * with tokens and fields ready to be populated + * with results. + * + */ + prepareSearch(query, optsUser) { + const weights = {}; + var options = Object.assign({}, optsUser); + utils.propToArray(options, 'sort'); + utils.propToArray(options, 'sort_empty'); // convert fields to new format + + if (options.fields) { + utils.propToArray(options, 'fields'); + + if (Array.isArray(options.fields) && typeof options.fields[0] !== 'object') { + var fields = []; + options.fields.forEach(fld_name => { + fields.push({ + field: fld_name + }); + }); + options.fields = fields; + } + + options.fields.forEach(field_params => { + weights[field_params.field] = 'weight' in field_params ? field_params.weight : 1; + }); + } + + query = diacritics.asciifold(String(query || '')).toLowerCase().trim(); + return { + options: options, + query: query, + tokens: this.tokenize(query, options.respect_word_boundaries, weights), + total: 0, + items: [], + weights: weights, + getAttrFn: options.nesting ? utils.getAttrNesting : utils.getAttr + }; + } + + /** + * Searches through all items and returns a sorted array of matches. + * + */ + search(query, options) { + var self = this, + score, + search; + var fn_sort; + var fn_score; + search = this.prepareSearch(query, options); + options = search.options; + query = search.query; // generate result scoring function + + fn_score = options.score || self._getScoreFunction(search); // perform search and sort + + if (query.length) { + utils.iterate(self.items, (item, id) => { + score = fn_score(item); + + if (options.filter === false || score > 0) { + search.items.push({ + 'score': score, + 'id': id + }); + } + }); + } else { + utils.iterate(self.items, (item, id) => { + search.items.push({ + 'score': 1, + 'id': id + }); + }); + } + + fn_sort = self._getSortFunction(search); + if (fn_sort) search.items.sort(fn_sort); // apply limits + + search.total = search.items.length; + + if (typeof options.limit === 'number') { + search.items = search.items.slice(0, options.limit); + } + + return search; + } + +} + +module.exports = Sifter; +//# sourceMappingURL=sifter.js.map diff --git a/dist/cjs/sifter.js.map b/dist/cjs/sifter.js.map new file mode 100644 index 0000000..5d62446 --- /dev/null +++ b/dist/cjs/sifter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sifter.js","sources":["../../lib/sifter.ts"],"sourcesContent":["/**\n * sifter.js\n * Copyright (c) 2013–2020 Brian Reavis & contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n * file except in compliance with the License. You may obtain a copy of the License at:\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n * ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n *\n * @author Brian Reavis \n */\n\n// @ts-ignore\nimport { scoreValue, getAttr, getAttrNesting, escape_regex, propToArray, iterate, cmp } from './utils.ts';\n// @ts-ignore\nimport { diacriticRegexPoints, asciifold } from './diacritics.ts';\n\n\ntype TField = {\n\tfield: string,\n\tweight?: number,\n}\n\ntype TOptions = {\n \tfields: TField[],\n \tsort: any[],\n \tscore?: ()=>any,\n \tfilter?: boolean,\n \tlimit?: number,\n \tsort_empty?: any,\n \tnesting?: boolean,\n\trespect_word_boundaries?: boolean,\n\tconjunction?: string,\n}\n\ntype TToken = {\n\tstring:string,\n\tregex:RegExp,\n\tfield:string\n}\n\ntype TWeights = {[key:string]:number}\n\ntype TPrepareObj = {\n\toptions: TOptions,\n\tquery: string,\n\ttokens: TToken[],\n\ttotal: number,\n\titems: any[],\n\tweights: TWeights,\n\tgetAttrFn: (any,string)=>any,\n\n}\n\n\nexport default class Sifter{\n\n\tpublic items: []|{};\n\tpublic settings: {diacritics:boolean};\n\n\t/**\n\t * Textually searches arrays and hashes of objects\n\t * by property (or multiple properties). Designed\n\t * specifically for autocomplete.\n\t *\n\t * @constructor\n\t * @param {array|object} items\n\t * @param {object} items\n\t */\n\tconstructor(items, settings) {\n\t\tthis.items = items;\n\t\tthis.settings = settings || {diacritics: true};\n\t};\n\n\t/**\n\t * Splits a search string into an array of individual\n\t * regexps to be used to match results.\n\t *\n\t */\n\ttokenize(query:string, respect_word_boundaries?:boolean, weights?:TWeights ):TToken[] {\n\t\tif (!query || !query.length) return [];\n\n\t\tvar tokens = [];\n\t\tvar words = query.split(/\\s+/);\n\t\tvar field_regex;\n\n\t\tif( weights ){\n\t\t\tfield_regex = new RegExp( '^('+ Object.keys(weights).map(escape_regex).join('|')+')\\:(.*)$');\n\t\t}\n\n\t\twords.forEach((word:string) => {\n\t\t\tlet field_match;\n\t\t\tlet field\t= null;\n\t\t\tlet regex\t= null;\n\n\t\t\t// look for \"field:query\" tokens\n\t\t\tif( field_regex && (field_match = word.match(field_regex)) ){\n\t\t\t\tfield\t= field_match[1];\n\t\t\t\tword\t= field_match[2];\n\t\t\t}\n\n\t\t\tif( word.length > 0 ){\n\t\t\t\tregex = escape_regex(word);\n\t\t\t\tif( this.settings.diacritics ){\n\t\t\t\t\tregex = diacriticRegexPoints(regex);\n\t\t\t\t}\n\t\t\t\tif( respect_word_boundaries ) regex = \"\\\\b\"+regex\n\t\t\t\tregex = new RegExp(regex, 'i');\n\t\t\t}\n\n\t\t\ttokens.push({\n\t\t\t\tstring : word,\n\t\t\t\tregex : regex,\n\t\t\t\tfield : field,\n\t\t\t});\n\t\t});\n\n\t\treturn tokens;\n\t};\n\n\n\t/**\n\t * Returns a function to be used to score individual results.\n\t *\n\t * Good matches will have a higher score than poor matches.\n\t * If an item is not a match, 0 will be returned by the function.\n\t *\n\t * @returns {function}\n\t */\n\tgetScoreFunction(query:string, options ){\n\t\tvar search = this.prepareSearch(query, options);\n\t\treturn this._getScoreFunction(search);\n\t}\n\n\t_getScoreFunction(search:TPrepareObj ){\n\t\tconst tokens\t\t= search.tokens,\n\t\ttoken_count\t\t\t= tokens.length;\n\n\t\tif (!token_count) {\n\t\t\treturn function() { return 0; };\n\t\t}\n\n\t\tconst fields\t= search.options.fields,\n\t\tweights\t\t\t= search.weights,\n\t\tfield_count\t\t= fields.length,\n\t\tgetAttrFn\t\t= search.getAttrFn;\n\n\n\n\t\t/**\n\t\t * Calculates the score of an object\n\t\t * against the search query.\n\t\t *\n\t\t * @param {TToken} token\n\t\t * @param {object} data\n\t\t * @return {number}\n\t\t */\n\t\tvar scoreObject = (function() {\n\n\t\t\tif (!field_count) {\n\t\t\t\treturn function() { return 0; };\n\t\t\t}\n\n\t\t\tif (field_count === 1) {\n\t\t\t\treturn function(token:TToken, data) {\n\t\t\t\t\tconst field = fields[0].field;\n\t\t\t\t\treturn scoreValue(getAttrFn(data, field), token, weights[field]);\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn function(token:TToken, data) {\n\t\t\t\tvar sum = 0;\n\n\t\t\t\t// is the token specific to a field?\n\t\t\t\tif( token.field ){\n\n\t\t\t\t\tconst value = getAttrFn(data, token.field);\n\n\t\t\t\t\tif( !token.regex && value ){\n\t\t\t\t\t\tsum += 0.1;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tsum += scoreValue(value, token, weights[token.field]);\n\t\t\t\t\t}\n\n\n\n\t\t\t\t}else{\n\t\t\t\t\titerate(weights, (weight, field) => {\n\t\t\t\t\t\tsum += scoreValue(getAttrFn(data, field), token, weight);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn sum / field_count;\n\t\t\t};\n\t\t})();\n\n\t\tif (token_count === 1) {\n\t\t\treturn function(data) {\n\t\t\t\treturn scoreObject(tokens[0], data);\n\t\t\t};\n\t\t}\n\n\t\tif (search.options.conjunction === 'and') {\n\t\t\treturn function(data) {\n\t\t\t\tvar i = 0, score, sum = 0;\n\t\t\t\tfor (; i < token_count; i++) {\n\t\t\t\t\tscore = scoreObject(tokens[i], data);\n\t\t\t\t\tif (score <= 0) return 0;\n\t\t\t\t\tsum += score;\n\t\t\t\t}\n\t\t\t\treturn sum / token_count;\n\t\t\t};\n\t\t} else {\n\t\t\treturn function(data) {\n\t\t\t\tvar sum = 0;\n\t\t\t\titerate(tokens,(token:TToken)=>{\n\t\t\t\t\tsum += scoreObject(token, data);\n\t\t\t\t});\n\t\t\t\treturn sum / token_count;\n\t\t\t};\n\t\t}\n\t};\n\n\t/**\n\t * Returns a function that can be used to compare two\n\t * results, for sorting purposes. If no sorting should\n\t * be performed, `null` will be returned.\n\t *\n\t * @return function(a,b)\n\t */\n\tgetSortFunction(query:string, options) {\n\t\tvar search = this.prepareSearch(query, options);\n\t\treturn this._getSortFunction(search);\n\t}\n\n\t_getSortFunction(search:TPrepareObj){\n\t\tvar i, n, self, sort_fld, sort_flds, sort_flds_count, multiplier, multipliers, get_field, implicit_score, sort, options;\n\n\t\tself\t\t= this;\n\t\toptions\t\t= search.options;\n\t\tsort\t\t= (!search.query && options.sort_empty) || options.sort;\n\n\t\t/**\n\t\t * Fetches the specified sort field value\n\t\t * from a search result item.\n\t\t *\n\t\t * @param {string} name\n\t\t * @param {object} result\n\t\t * @return {string}\n\t\t */\n\t\tget_field = function(name, result) {\n\t\t\tif (name === '$score') return result.score;\n\t\t\treturn search.getAttrFn(self.items[result.id], name);\n\t\t};\n\n\t\t// parse options\n\t\tsort_flds = [];\n\t\tif (sort) {\n\t\t\tfor (i = 0, n = sort.length; i < n; i++) {\n\t\t\t\tif (search.query || sort[i].field !== '$score') {\n\t\t\t\t\tsort_flds.push(sort[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// the \"$score\" field is implied to be the primary\n\t\t// sort field, unless it's manually specified\n\t\tif (search.query) {\n\t\t\timplicit_score = true;\n\t\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\t\tif (sort_flds[i].field === '$score') {\n\t\t\t\t\timplicit_score = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (implicit_score) {\n\t\t\t\tsort_flds.unshift({field: '$score', direction: 'desc'});\n\t\t\t}\n\t\t} else {\n\t\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\t\tif (sort_flds[i].field === '$score') {\n\t\t\t\t\tsort_flds.splice(i, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tmultipliers = [];\n\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\tmultipliers.push(sort_flds[i].direction === 'desc' ? -1 : 1);\n\t\t}\n\n\t\t// build function\n\t\tsort_flds_count = sort_flds.length;\n\t\tif (!sort_flds_count) {\n\t\t\treturn null;\n\t\t} else if (sort_flds_count === 1) {\n\t\t\tsort_fld = sort_flds[0].field;\n\t\t\tmultiplier = multipliers[0];\n\t\t\treturn function(a, b) {\n\t\t\t\treturn multiplier * cmp(\n\t\t\t\t\tget_field(sort_fld, a),\n\t\t\t\t\tget_field(sort_fld, b)\n\t\t\t\t);\n\t\t\t};\n\t\t} else {\n\t\t\treturn function(a, b) {\n\t\t\t\tvar i, result, field;\n\t\t\t\tfor (i = 0; i < sort_flds_count; i++) {\n\t\t\t\t\tfield = sort_flds[i].field;\n\t\t\t\t\tresult = multipliers[i] * cmp(\n\t\t\t\t\t\tget_field(field, a),\n\t\t\t\t\t\tget_field(field, b)\n\t\t\t\t\t);\n\t\t\t\t\tif (result) return result;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t};\n\t\t}\n\t};\n\n\t/**\n\t * Parses a search query and returns an object\n\t * with tokens and fields ready to be populated\n\t * with results.\n\t *\n\t */\n\tprepareSearch(query:string, optsUser):TPrepareObj {\n\t\tconst weights\t= {};\n\t\tvar options\t\t= Object.assign({},optsUser);\n\n\t\tpropToArray(options,'sort');\n\t\tpropToArray(options,'sort_empty');\n\n\t\t// convert fields to new format\n\t\tif( options.fields ){\n\t\t\tpropToArray(options,'fields');\n\t\t\tif( Array.isArray(options.fields) && typeof options.fields[0] !== 'object' ){\n\t\t\t\tvar fields = [];\n\t\t\t\toptions.fields.forEach((fld_name) => {\n\t\t\t\t\tfields.push({field:fld_name});\n\t\t\t\t});\n\t\t\t\toptions.fields = fields;\n\t\t\t}\n\n\n\t\t\toptions.fields.forEach((field_params)=>{\n\t\t\t\tweights[field_params.field] = ('weight' in field_params) ? field_params.weight : 1;\n\t\t\t});\n\t\t}\n\n\t\tquery = asciifold( String(query || '') ).toLowerCase().trim();\n\n\t\treturn {\n\t\t\toptions\t\t: options,\n\t\t\tquery\t\t: query,\n\t\t\ttokens\t\t: this.tokenize(query, options.respect_word_boundaries, weights),\n\t\t\ttotal\t\t: 0,\n\t\t\titems\t\t: [],\n\t\t\tweights\t\t: weights,\n\t\t\tgetAttrFn\t: (options.nesting) ? getAttrNesting : getAttr,\n\t\t};\n\t};\n\n\t/**\n\t * Searches through all items and returns a sorted array of matches.\n\t *\n\t */\n\tsearch(query:string, options:TOptions) : TPrepareObj {\n\t\tvar self = this, score, search;\n\t\tvar fn_sort;\n\t\tvar fn_score;\n\n\t\tsearch = this.prepareSearch(query, options);\n\t\toptions = search.options;\n\t\tquery = search.query;\n\n\t\t// generate result scoring function\n\t\tfn_score = options.score || self._getScoreFunction(search);\n\n\t\t// perform search and sort\n\t\tif (query.length) {\n\t\t\titerate(self.items, (item, id) => {\n\t\t\t\tscore = fn_score(item);\n\t\t\t\tif (options.filter === false || score > 0) {\n\t\t\t\t\tsearch.items.push({'score': score, 'id': id});\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\titerate(self.items, (item, id) => {\n\t\t\t\tsearch.items.push({'score': 1, 'id': id});\n\t\t\t});\n\t\t}\n\n\t\tfn_sort = self._getSortFunction(search);\n\t\tif (fn_sort) search.items.sort(fn_sort);\n\n\t\t// apply limits\n\t\tsearch.total = search.items.length;\n\t\tif (typeof options.limit === 'number') {\n\t\t\tsearch.items = search.items.slice(0, options.limit);\n\t\t}\n\n\t\treturn search;\n\t};\n}\n"],"names":["Sifter","constructor","items","settings","diacritics","tokenize","query","respect_word_boundaries","weights","length","tokens","words","split","field_regex","RegExp","Object","keys","map","escape_regex","join","forEach","word","field_match","field","regex","match","diacriticRegexPoints","push","string","getScoreFunction","options","search","prepareSearch","_getScoreFunction","token_count","fields","field_count","getAttrFn","scoreObject","token","data","scoreValue","sum","value","iterate","weight","conjunction","i","score","getSortFunction","_getSortFunction","n","self","sort_fld","sort_flds","sort_flds_count","multiplier","multipliers","get_field","implicit_score","sort","sort_empty","name","result","id","unshift","direction","splice","a","b","cmp","optsUser","assign","propToArray","Array","isArray","fld_name","field_params","asciifold","String","toLowerCase","trim","total","nesting","getAttrNesting","getAttr","fn_sort","fn_score","item","filter","limit","slice"],"mappings":"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"} \ No newline at end of file diff --git a/dist/cjs/utils.js b/dist/cjs/utils.js new file mode 100644 index 0000000..2f9dd7b --- /dev/null +++ b/dist/cjs/utils.js @@ -0,0 +1,110 @@ +/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var diacritics = require('./diacritics.js'); + +// @ts-ignore +/** + * A property getter resolving dot-notation + * @param {Object} obj The root object to fetch property on + * @param {String} name The optionally dotted property name to fetch + * @return {Object} The resolved property value + */ + +function getAttr(obj, name) { + if (!obj) return; + return obj[name]; +} +/** + * A property getter resolving dot-notation + * @param {Object} obj The root object to fetch property on + * @param {String} name The optionally dotted property name to fetch + * @return {Object} The resolved property value + */ + +function getAttrNesting(obj, name) { + if (!obj) return; + var names = name.split("."); + + while (names.length && (obj = obj[names.shift()])); + + return obj; +} +/** + * Calculates how close of a match the + * given value is against a search token. + * + * @param {object} token + * @return {number} + */ + +function scoreValue(value, token, weight) { + var score, pos; + if (!value) return 0; + value = String(value || ''); + pos = value.search(token.regex); + if (pos === -1) return 0; + score = token.string.length / value.length; + if (pos === 0) score += 0.5; + return score * weight; +} +function escape_regex(str) { + return (str + '').replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); +} +/** + * Cast object property to an array if it exists and has a value + * + */ + +function propToArray(obj, key) { + var value = obj[key]; + + if (value && !Array.isArray(value)) { + obj[key] = [value]; + } +} +/** + * Iterates over arrays and hashes. + * + * ``` + * iterate(this.items, function(item, id) { + * // invoked for each item + * }); + * ``` + * + * @param {array|object} object + */ + +function iterate(object, callback) { + if (Array.isArray(object)) { + object.forEach(callback); + } else { + for (var key in object) { + if (object.hasOwnProperty(key)) { + callback(object[key], key); + } + } + } +} +function cmp(a, b) { + if (typeof a === 'number' && typeof b === 'number') { + return a > b ? 1 : a < b ? -1 : 0; + } + + a = diacritics.asciifold(String(a || '')).toLowerCase(); + b = diacritics.asciifold(String(b || '')).toLowerCase(); + if (a > b) return 1; + if (b > a) return -1; + return 0; +} + +exports.cmp = cmp; +exports.escape_regex = escape_regex; +exports.getAttr = getAttr; +exports.getAttrNesting = getAttrNesting; +exports.iterate = iterate; +exports.propToArray = propToArray; +exports.scoreValue = scoreValue; +//# sourceMappingURL=utils.js.map diff --git a/dist/cjs/utils.js.map b/dist/cjs/utils.js.map new file mode 100644 index 0000000..8599a0c --- /dev/null +++ b/dist/cjs/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","sources":["../../lib/utils.ts"],"sourcesContent":["\n// @ts-ignore\nimport { asciifold } from './diacritics.ts';\n\n/**\n * A property getter resolving dot-notation\n * @param {Object} obj The root object to fetch property on\n * @param {String} name The optionally dotted property name to fetch\n * @return {Object} The resolved property value\n */\nexport function getAttr(obj:{[key:string]:any}, name:string ) {\n if (!obj ) return;\n return obj[name];\n};\n\n/**\n * A property getter resolving dot-notation\n * @param {Object} obj The root object to fetch property on\n * @param {String} name The optionally dotted property name to fetch\n * @return {Object} The resolved property value\n */\nexport function getAttrNesting(obj:{[key:string]:any}, name:string ) {\n if (!obj ) return;\n var names = name.split(\".\");\n while(names.length && (obj = obj[names.shift()]));\n return obj;\n};\n\n/**\n * Calculates how close of a match the\n * given value is against a search token.\n *\n * @param {object} token\n * @return {number}\n */\nexport function scoreValue(value:string, token, weight:number ) {\n\tvar score, pos;\n\n\tif (!value) return 0;\n\n\tvalue = String(value || '');\n\tpos = value.search(token.regex);\n\tif (pos === -1) return 0;\n\n\tscore = token.string.length / value.length;\n\tif (pos === 0) score += 0.5;\n\n\treturn score * weight;\n};\n\nexport function escape_regex(str) {\n\treturn (str + '').replace(/([.?*+^$[\\]\\\\(){}|-])/g, '\\\\$1');\n};\n\n\n/**\n * Cast object property to an array if it exists and has a value\n *\n */\nexport function propToArray(obj, key){\n\tvar value = obj[key];\n\tif( value && !Array.isArray(value) ){\n\t\tobj[key] = [value];\n\t}\n}\n\n\n/**\n * Iterates over arrays and hashes.\n *\n * ```\n * iterate(this.items, function(item, id) {\n * // invoked for each item\n * });\n * ```\n *\n * @param {array|object} object\n */\nexport function iterate(object, callback) {\n\n\tif ( Array.isArray(object)) {\n\t\tobject.forEach(callback);\n\n\t}else{\n\n\t\tfor (var key in object) {\n\t\t\tif (object.hasOwnProperty(key)) {\n\t\t\t\tcallback(object[key], key);\n\t\t\t}\n\t\t}\n\t}\n};\n\n\n\nexport function cmp(a, b) {\n\tif (typeof a === 'number' && typeof b === 'number') {\n\t\treturn a > b ? 1 : (a < b ? -1 : 0);\n\t}\n\ta = asciifold(String(a || '')).toLowerCase();\n\tb = asciifold(String(b || '')).toLowerCase();\n\tif (a > b) return 1;\n\tif (b > a) return -1;\n\treturn 0;\n};\n"],"names":["getAttr","obj","name","getAttrNesting","names","split","length","shift","scoreValue","value","token","weight","score","pos","String","search","regex","string","escape_regex","str","replace","propToArray","key","Array","isArray","iterate","object","callback","forEach","hasOwnProperty","cmp","a","b","asciifold","toLowerCase"],"mappings":";;;;;;;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;;AACO,SAASA,OAAT,CAAiBC,GAAjB,EAAyCC,IAAzC,EAAuD;AAC1D,MAAI,CAACD,GAAL,EAAW;AACX,SAAOA,GAAG,CAACC,IAAD,CAAV;AACH;AAED;AACA;AACA;AACA;AACA;AACA;;AACO,SAASC,cAAT,CAAwBF,GAAxB,EAAgDC,IAAhD,EAA8D;AACjE,MAAI,CAACD,GAAL,EAAW;AACX,MAAIG,KAAK,GAAGF,IAAI,CAACG,KAAL,CAAW,GAAX,CAAZ;;AACA,SAAMD,KAAK,CAACE,MAAN,KAAiBL,GAAG,GAAGA,GAAG,CAACG,KAAK,CAACG,KAAN,EAAD,CAA1B,CAAN,CAAiD;;AACjD,SAAON,GAAP;AACH;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;AACO,SAASO,UAAT,CAAoBC,KAApB,EAAkCC,KAAlC,EAAyCC,MAAzC,EAAyD;AAC/D,MAAIC,KAAJ,EAAWC,GAAX;AAEA,MAAI,CAACJ,KAAL,EAAY,OAAO,CAAP;AAEZA,EAAAA,KAAK,GAAGK,MAAM,CAACL,KAAK,IAAI,EAAV,CAAd;AACAI,EAAAA,GAAG,GAAGJ,KAAK,CAACM,MAAN,CAAaL,KAAK,CAACM,KAAnB,CAAN;AACA,MAAIH,GAAG,KAAK,CAAC,CAAb,EAAgB,OAAO,CAAP;AAEhBD,EAAAA,KAAK,GAAGF,KAAK,CAACO,MAAN,CAAaX,MAAb,GAAsBG,KAAK,CAACH,MAApC;AACA,MAAIO,GAAG,KAAK,CAAZ,EAAeD,KAAK,IAAI,GAAT;AAEf,SAAOA,KAAK,GAAGD,MAAf;AACA;AAEM,SAASO,YAAT,CAAsBC,GAAtB,EAA2B;AACjC,SAAO,CAACA,GAAG,GAAG,EAAP,EAAWC,OAAX,CAAmB,wBAAnB,EAA6C,MAA7C,CAAP;AACA;AAGD;AACA;AACA;AACA;;AACO,SAASC,WAAT,CAAqBpB,GAArB,EAA0BqB,GAA1B,EAA8B;AACpC,MAAIb,KAAK,GAAGR,GAAG,CAACqB,GAAD,CAAf;;AACA,MAAIb,KAAK,IAAI,CAACc,KAAK,CAACC,OAAN,CAAcf,KAAd,CAAd,EAAoC;AACnCR,IAAAA,GAAG,CAACqB,GAAD,CAAH,GAAW,CAACb,KAAD,CAAX;AACA;AACD;AAGD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACO,SAASgB,OAAT,CAAiBC,MAAjB,EAAyBC,QAAzB,EAAmC;AAEzC,MAAKJ,KAAK,CAACC,OAAN,CAAcE,MAAd,CAAL,EAA4B;AAC3BA,IAAAA,MAAM,CAACE,OAAP,CAAeD,QAAf;AAEA,GAHD,MAGK;AAEJ,SAAK,IAAIL,GAAT,IAAgBI,MAAhB,EAAwB;AACvB,UAAIA,MAAM,CAACG,cAAP,CAAsBP,GAAtB,CAAJ,EAAgC;AAC/BK,QAAAA,QAAQ,CAACD,MAAM,CAACJ,GAAD,CAAP,EAAcA,GAAd,CAAR;AACA;AACD;AACD;AACD;AAIM,SAASQ,GAAT,CAAaC,CAAb,EAAgBC,CAAhB,EAAmB;AACzB,MAAI,OAAOD,CAAP,KAAa,QAAb,IAAyB,OAAOC,CAAP,KAAa,QAA1C,EAAoD;AACnD,WAAOD,CAAC,GAAGC,CAAJ,GAAQ,CAAR,GAAaD,CAAC,GAAGC,CAAJ,GAAQ,CAAC,CAAT,GAAa,CAAjC;AACA;;AACDD,EAAAA,CAAC,GAAGE,oBAAS,CAACnB,MAAM,CAACiB,CAAC,IAAI,EAAN,CAAP,CAAT,CAA2BG,WAA3B,EAAJ;AACAF,EAAAA,CAAC,GAAGC,oBAAS,CAACnB,MAAM,CAACkB,CAAC,IAAI,EAAN,CAAP,CAAT,CAA2BE,WAA3B,EAAJ;AACA,MAAIH,CAAC,GAAGC,CAAR,EAAW,OAAO,CAAP;AACX,MAAIA,CAAC,GAAGD,CAAR,EAAW,OAAO,CAAC,CAAR;AACX,SAAO,CAAP;AACA;;;;;;;;;;"} \ No newline at end of file diff --git a/dist/esm/diacritics.js b/dist/esm/diacritics.js new file mode 100644 index 0000000..9417e86 --- /dev/null +++ b/dist/esm/diacritics.js @@ -0,0 +1,117 @@ +/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */ +// https://github.com/andrewrk/node-diacritics/blob/master/index.js +/** + * code points generated from toCodePoints(); + * removed 65339 to 65345 + */ + +var code_points = [[67, 67], [160, 160], [192, 438], [452, 652], [961, 961], [1019, 1019], [1083, 1083], [1281, 1289], [1984, 1984], [5095, 5095], [7429, 7441], [7545, 7549], [7680, 7935], [8580, 8580], [9398, 9449], [11360, 11391], [42792, 42793], [42802, 42851], [42873, 42897], [42912, 42922], [64256, 64260], [65313, 65338], [65345, 65370]]; +/** + * Remove accents + * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703 + * + */ + +function asciifold(str) { + return str.normalize('NFD').replace(/[\u0300-\u036F]/g, '').normalize('NFKD').toLowerCase(); +} +/** + * Generate a list of diacritics from the list of code points + * + */ + + +function generateDiacritics() { + var latin_convert = { + 'l·': 'l', + 'ʼn': 'n', + 'æ': 'ae', + 'ø': 'o', + 'aʾ': 'a', + 'dž': 'dz' + }; + var diacritics = {}; //var no_latin = []; + + code_points.forEach(code_range => { + for (let i = code_range[0]; i <= code_range[1]; i++) { + let diacritic = String.fromCharCode(i); + let latin = diacritic.normalize('NFD').replace(/[\u0300-\u036F]/g, '').normalize('NFKD'); + + if (latin == diacritic) { + //no_latin.push(diacritic); + continue; + } + + latin = latin.toLowerCase(); + + if (latin in latin_convert) { + latin = latin_convert[latin]; + } + + if (!(latin in diacritics)) { + diacritics[latin] = latin + latin.toUpperCase(); + } + + diacritics[latin] += diacritic; + } + }); //console.log('no_latin',JSON.stringify(no_latin)); + + return diacritics; +} +/** + * Expand a regular expression pattern to include diacritics + * eg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/ + * + */ + +var diacritics = null; +function diacriticRegexPoints(regex) { + if (diacritics === null) { + diacritics = generateDiacritics(); + } + + for (let latin in diacritics) { + if (diacritics.hasOwnProperty(latin)) { + regex = regex.replace(new RegExp(latin, 'g'), '[' + diacritics[latin] + ']'); + } + } + + return regex; +} +/** + * Expand a regular expression pattern to include diacritics + * eg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/ + * + * rollup will bundle this function (and the DIACRITICS constant) unless commented out + * +var diacriticRegex = (function() { + + var list = []; + for( let letter in DIACRITICS ){ + + if( letter.toLowerCase() != letter && letter.toLowerCase() in DIACRITICS ){ + continue; + } + + if( DIACRITICS.hasOwnProperty(letter) ){ + + var replace = letter + DIACRITICS[letter]; + if( letter.toUpperCase() in DIACRITICS ){ + replace += letter.toUpperCase() + DIACRITICS[letter.toUpperCase()]; + } + + list.push({let:letter,pat:'['+replace+']'}); + } + } + + return function(regex:string):string{ + list.forEach((item)=>{ + regex = regex.replace( new RegExp(item.let,'g'),item.pat); + }); + return regex; + } +})(); +*/ + +export { asciifold, diacriticRegexPoints, generateDiacritics }; +//# sourceMappingURL=diacritics.js.map diff --git a/dist/esm/diacritics.js.map b/dist/esm/diacritics.js.map new file mode 100644 index 0000000..4ff2c5d --- /dev/null +++ b/dist/esm/diacritics.js.map @@ -0,0 +1 @@ +{"version":3,"file":"diacritics.js","sources":["../../lib/diacritics.ts"],"sourcesContent":["\ntype TDiacraticList = {[key:string]:string};\n\n// https://github.com/andrewrk/node-diacritics/blob/master/index.js\nvar DIACRITICS:TDiacraticList = {\n\t\" \":\" \",\n\t0:\"߀\",\n\tA:\"ⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ\",\n\tAA:\"Ꜳ\",\n\tAE:\"ÆǼǢ\",\n\tAO:\"Ꜵ\",\n\tAU:\"Ꜷ\",\n\tAV:\"ꜸꜺ\",\n\tAY:\"Ꜽ\",\n\tB:\"ⒷBḂḄḆɃƁ\",\n\tC:\"ⒸCꜾḈĆCĈĊČÇƇȻ\",\n\tD:\"ⒹDḊĎḌḐḒḎĐƊƉᴅꝹ\",\n\tDh:\"Ð\",\n\tDZ:\"DZDŽ\",\n\tDz:\"DzDž\",\n\tE:\"ɛⒺEÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚƐƎᴇ\",\n\tF:\"ꝼⒻFḞƑꝻ\",\n\tG:\"ⒼGǴĜḠĞĠǦĢǤƓꞠꝽꝾɢ\",\n\tH:\"ⒽHĤḢḦȞḤḨḪĦⱧⱵꞍ\",\n\tI:\"ⒾIÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬƗ\",\n\tJ:\"ⒿJĴɈȷ\",\n\tK:\"ⓀKḰǨḲĶḴƘⱩꝀꝂꝄꞢ\",\n\tL:\"ⓁLĿĹĽḶḸĻḼḺŁȽⱢⱠꝈꝆꞀ\",\n\tLJ:\"LJ\",\n\tLj:\"Lj\",\n\tM:\"ⓂMḾṀṂⱮƜϻ\",\n\tN:\"ꞤȠⓃNǸŃÑṄŇṆŅṊṈƝꞐᴎ\",\n\tNJ:\"NJ\",\n\tNj:\"Nj\",\n\tO:\"ⓄOÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘǪǬØǾƆƟꝊꝌ\",\n\tOE:\"Œ\",\n\tOI:\"Ƣ\",\n\tOO:\"Ꝏ\",\n\tOU:\"Ȣ\",\n\tP:\"ⓅPṔṖƤⱣꝐꝒꝔ\",\n\tQ:\"ⓆQꝖꝘɊ\",\n\tR:\"ⓇRŔṘŘȐȒṚṜŖṞɌⱤꝚꞦꞂ\",\n\tS:\"ⓈSẞŚṤŜṠŠṦṢṨȘŞⱾꞨꞄ\",\n\tT:\"ⓉTṪŤṬȚŢṰṮŦƬƮȾꞆ\",\n\tTh:\"Þ\",\n\tTZ:\"Ꜩ\",\n\tU:\"ⓊUÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴɄ\",\n\tV:\"ⓋVṼṾƲꝞɅ\",\n\tVY:\"Ꝡ\",\n\tW:\"ⓌWẀẂŴẆẄẈⱲ\",\n\tX:\"ⓍXẊẌ\",\n\tY:\"ⓎYỲÝŶỸȲẎŸỶỴƳɎỾ\",\n\tZ:\"ⓏZŹẐŻŽẒẔƵȤⱿⱫꝢ\",\n\ta:\"ⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑ\",\n\taa:\"ꜳ\",\n\tae:\"æǽǣ\",\n\tao:\"ꜵ\",\n\tau:\"ꜷ\",\n\tav:\"ꜹꜻ\",\n\tay:\"ꜽ\",\n\tb:\"ⓑbḃḅḇƀƃɓƂ\",\n\tc:\"cⓒćĉċčçḉƈȼꜿↄ\",\n\td:\"ⓓdḋďḍḑḓḏđƌɖɗƋᏧԁꞪ\",\n\tdh:\"ð\",\n\tdz:\"dzdž\",\n\te:\"ⓔeèéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛɇǝ\",\n\tf:\"ⓕfḟƒ\",\n\tff:\"ff\",\n\tfi:\"fi\",\n\tfl:\"fl\",\n\tffi:\"ffi\",\n\tffl:\"ffl\",\n\tg:\"ⓖgǵĝḡğġǧģǥɠꞡꝿᵹ\",\n\th:\"ⓗhĥḣḧȟḥḩḫẖħⱨⱶɥ\",\n\thv:\"ƕ\",\n\ti:\"ⓘiìíîĩīĭïḯỉǐȉȋịįḭɨı\",\n\tj:\"ⓙjĵǰɉ\",\n\tk:\"ⓚkḱǩḳķḵƙⱪꝁꝃꝅꞣ\",\n\tl:\"ⓛlŀĺľḷḹļḽḻſłƚɫⱡꝉꞁꝇɭ\",\n\tlj:\"lj\",\n\tm:\"ⓜmḿṁṃɱɯ\",\n\tn:\"ⓝnǹńñṅňṇņṋṉƞɲʼnꞑꞥлԉ\",\n\tnj:\"nj\",\n\to:\"ⓞoòóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộǫǭøǿꝋꝍɵɔᴑ\",\n\toe:\"œ\",\n\toi:\"ƣ\",\n\too:\"ꝏ\",\n\tou:\"ȣ\",\n\tp:\"ⓟpṕṗƥᵽꝑꝓꝕρ\",\n\tq:\"ⓠqɋꝗꝙ\",\n\tr:\"ⓡrŕṙřȑȓṛṝŗṟɍɽꝛꞧꞃ\",\n\ts:\"ⓢsśṥŝṡšṧṣṩșşȿꞩꞅẛʂ\",\n\tss:\"ß\",\n\tt:\"ⓣtṫẗťṭțţṱṯŧƭʈⱦꞇ\",\n\tth:\"þ\",\n\ttz:\"ꜩ\",\n\tu:\"ⓤuùúûũṹūṻŭüǜǘǖǚủůűǔȕȗưừứữửựụṳųṷṵʉ\",\n\tv:\"ⓥvṽṿʋꝟʌ\",\n\tvy:\"ꝡ\",\n\tw:\"ⓦwẁẃŵẇẅẘẉⱳ\",\n\tx:\"ⓧxẋẍ\",\n\ty:\"ⓨyỳýŷỹȳẏÿỷẙỵƴɏỿ\",\n\tz:\"ⓩzźẑżžẓẕƶȥɀⱬꝣ\"\n}\n\n/**\n * code points generated from toCodePoints();\n * removed 65339 to 65345\n */\nvar code_points = [\n\t[ 67, 67 ],\n\t[ 160, 160 ],\n\t[ 192, 438 ],\n\t[ 452, 652 ],\n\t[ 961, 961 ],\n\t[ 1019, 1019 ],\n\t[ 1083, 1083 ],\n\t[ 1281, 1289 ],\n\t[ 1984, 1984 ],\n\t[ 5095, 5095 ],\n\t[ 7429, 7441 ],\n\t[ 7545, 7549 ],\n\t[ 7680, 7935 ],\n\t[ 8580, 8580 ],\n\t[ 9398, 9449 ],\n\t[ 11360, 11391 ],\n\t[ 42792, 42793 ],\n\t[ 42802, 42851 ],\n\t[ 42873, 42897 ],\n\t[ 42912, 42922 ],\n\t[ 64256, 64260 ],\n\t[ 65313, 65338 ],\n\t[ 65345, 65370 ]\n];\n\n/**\n * Remove accents\n * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703\n *\n */\nexport function asciifold(str:string):string{\n\treturn str.normalize('NFD').replace(/[\\u0300-\\u036F]/g, '').normalize('NFKD').toLowerCase();\n};\n\n\n/**\n * Convert list of diacritics to array of code points\n *\n */\n// @ts-ignore\nfunction toCodePoints(tolerance=8){\n\tvar char_codes = [];\n\n\tfor( let letter in DIACRITICS ){\n\t\tlet _diacritics = DIACRITICS[letter];\n\t\tfor( let n = 0; n < _diacritics.length; n++ ){\n\t\t\tvar code_point = _diacritics.codePointAt(n);\n\t\t\tchar_codes.push( code_point );\n\t\t}\n\t}\n\n\t//https://stackoverflow.com/questions/40431572/is-there-a-simple-way-to-group-js-array-values-by-range\n\tchar_codes.sort((a, b) => a - b);\n var result = char_codes.reduce(function (accumulator, currentValue, index, source) {\n\n\t\tif( !index ){\n\t\t\taccumulator.push( [currentValue,currentValue] );\n\n\t\t}else if( currentValue - source[index - 1] > tolerance ){\n\t\t\taccumulator.push( [currentValue,currentValue] );\n\n\t\t}else{\n\n\t\t\taccumulator.push( [accumulator.pop()[0],currentValue]);\n\t\t}\n\n return accumulator;\n }, []);\n\n\tconsole.log(`char_codes (${result.length})`,result);\n}\n\n/**\n * Generate a list of diacritics from the list of code points\n *\n */\nexport function generateDiacritics():TDiacraticList{\n\n\tvar latin_convert = {\n\t\t'l·': 'l',\n\t\t'ʼn': 'n',\n\t\t'æ': 'ae',\n\t\t'ø': 'o',\n\t\t'aʾ': 'a',\n\t\t'dž': 'dz',\n\t};\n\n\tvar diacritics\t= {};\n\t//var no_latin\t= [];\n\tcode_points.forEach((code_range)=>{\n\n\t\tfor(let i = code_range[0]; i <= code_range[1]; i++){\n\t\t\tlet diacritic\t= String.fromCharCode(i);\n\t\t\tlet latin\t\t= diacritic.normalize('NFD').replace(/[\\u0300-\\u036F]/g, '').normalize('NFKD');\n\n\t\t\tif( latin == diacritic ){\n\t\t\t\t//no_latin.push(diacritic);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlatin = latin.toLowerCase();\n\n\t\t\tif( latin in latin_convert ){\n\t\t\t\tlatin = latin_convert[latin];\n\t\t\t}\n\n\t\t\tif( !(latin in diacritics) ){\n\t\t\t\tdiacritics[latin] = latin + latin.toUpperCase();\n\t\t\t}\n\t\t\tdiacritics[latin] += diacritic;\n\t\t}\n\t});\n\n\t//console.log('no_latin',JSON.stringify(no_latin));\n\n\treturn diacritics;\n}\n\n/**\n * Expand a regular expression pattern to include diacritics\n * \teg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/\n *\n */\nvar diacritics:TDiacraticList = null\nexport function diacriticRegexPoints(regex:string):string{\n\n\tif( diacritics === null ){\n\t\tdiacritics = generateDiacritics();\n\t}\n\n\tfor( let latin in diacritics ){\n\t\tif( diacritics.hasOwnProperty(latin) ){\n\t\t\tregex = regex.replace( new RegExp(latin,'g'), '['+diacritics[latin]+']');\n\t\t}\n\t}\n\treturn regex;\n}\n\n\n/**\n * Expand a regular expression pattern to include diacritics\n * \teg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/\n *\n * rollup will bundle this function (and the DIACRITICS constant) unless commented out\n *\nvar diacriticRegex = (function() {\n\n\tvar list = [];\n\tfor( let letter in DIACRITICS ){\n\n\t\tif( letter.toLowerCase() != letter && letter.toLowerCase() in DIACRITICS ){\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( DIACRITICS.hasOwnProperty(letter) ){\n\n\t\t\tvar replace = letter + DIACRITICS[letter];\n\t\t\tif( letter.toUpperCase() in DIACRITICS ){\n\t\t\t\treplace += letter.toUpperCase() + DIACRITICS[letter.toUpperCase()];\n\t\t\t}\n\n\t\t\tlist.push({let:letter,pat:'['+replace+']'});\n\t\t}\n\t}\n\n\treturn function(regex:string):string{\n\t\tlist.forEach((item)=>{\n\t\t\tregex = regex.replace( new RegExp(item.let,'g'),item.pat);\n\t\t});\n\t\treturn regex;\n\t}\n})();\n*/\n"],"names":["code_points","asciifold","str","normalize","replace","toLowerCase","generateDiacritics","latin_convert","diacritics","forEach","code_range","i","diacritic","String","fromCharCode","latin","toUpperCase","diacriticRegexPoints","regex","hasOwnProperty","RegExp"],"mappings":";AAGA;AAsGA;AACA;AACA;AACA;;AACA,IAAIA,WAAW,GAAG,CACjB,CAAE,EAAF,EAAM,EAAN,CADiB,EAEjB,CAAE,GAAF,EAAO,GAAP,CAFiB,EAGjB,CAAE,GAAF,EAAO,GAAP,CAHiB,EAIjB,CAAE,GAAF,EAAO,GAAP,CAJiB,EAKjB,CAAE,GAAF,EAAO,GAAP,CALiB,EAMjB,CAAE,IAAF,EAAQ,IAAR,CANiB,EAOjB,CAAE,IAAF,EAAQ,IAAR,CAPiB,EAQjB,CAAE,IAAF,EAAQ,IAAR,CARiB,EASjB,CAAE,IAAF,EAAQ,IAAR,CATiB,EAUjB,CAAE,IAAF,EAAQ,IAAR,CAViB,EAWjB,CAAE,IAAF,EAAQ,IAAR,CAXiB,EAYjB,CAAE,IAAF,EAAQ,IAAR,CAZiB,EAajB,CAAE,IAAF,EAAQ,IAAR,CAbiB,EAcjB,CAAE,IAAF,EAAQ,IAAR,CAdiB,EAejB,CAAE,IAAF,EAAQ,IAAR,CAfiB,EAgBjB,CAAE,KAAF,EAAS,KAAT,CAhBiB,EAiBjB,CAAE,KAAF,EAAS,KAAT,CAjBiB,EAkBjB,CAAE,KAAF,EAAS,KAAT,CAlBiB,EAmBjB,CAAE,KAAF,EAAS,KAAT,CAnBiB,EAoBjB,CAAE,KAAF,EAAS,KAAT,CApBiB,EAqBjB,CAAE,KAAF,EAAS,KAAT,CArBiB,EAsBjB,CAAE,KAAF,EAAS,KAAT,CAtBiB,EAuBjB,CAAE,KAAF,EAAS,KAAT,CAvBiB,CAAlB;AA0BA;AACA;AACA;AACA;AACA;;AACO,SAASC,SAAT,CAAmBC,GAAnB,EAAqC;AAC3C,SAAOA,GAAG,CAACC,SAAJ,CAAc,KAAd,EAAqBC,OAArB,CAA6B,kBAA7B,EAAiD,EAAjD,EAAqDD,SAArD,CAA+D,MAA/D,EAAuEE,WAAvE,EAAP;AACA;AAwCD;AACA;AACA;AACA;;;AACO,SAASC,kBAAT,GAA4C;AAElD,MAAIC,aAAa,GAAG;AACnB,UAAM,GADa;AAEnB,UAAM,GAFa;AAGnB,SAAK,IAHc;AAInB,SAAK,GAJc;AAKnB,UAAM,GALa;AAMnB,WAAO;AANY,GAApB;AASA,MAAIC,UAAU,GAAG,EAAjB,CAXkD;;AAalDR,EAAAA,WAAW,CAACS,OAAZ,CAAqBC,UAAD,IAAc;AAEjC,SAAI,IAAIC,CAAC,GAAGD,UAAU,CAAC,CAAD,CAAtB,EAA2BC,CAAC,IAAID,UAAU,CAAC,CAAD,CAA1C,EAA+CC,CAAC,EAAhD,EAAmD;AAClD,UAAIC,SAAS,GAAGC,MAAM,CAACC,YAAP,CAAoBH,CAApB,CAAhB;AACA,UAAII,KAAK,GAAIH,SAAS,CAACT,SAAV,CAAoB,KAApB,EAA2BC,OAA3B,CAAmC,kBAAnC,EAAuD,EAAvD,EAA2DD,SAA3D,CAAqE,MAArE,CAAb;;AAEA,UAAIY,KAAK,IAAIH,SAAb,EAAwB;AACvB;AACA;AACA;;AAEDG,MAAAA,KAAK,GAAGA,KAAK,CAACV,WAAN,EAAR;;AAEA,UAAIU,KAAK,IAAIR,aAAb,EAA4B;AAC3BQ,QAAAA,KAAK,GAAGR,aAAa,CAACQ,KAAD,CAArB;AACA;;AAED,UAAI,EAAEA,KAAK,IAAIP,UAAX,CAAJ,EAA4B;AAC3BA,QAAAA,UAAU,CAACO,KAAD,CAAV,GAAoBA,KAAK,GAAGA,KAAK,CAACC,WAAN,EAA5B;AACA;;AACDR,MAAAA,UAAU,CAACO,KAAD,CAAV,IAAqBH,SAArB;AACA;AACD,GAtBD,EAbkD;;AAuClD,SAAOJ,UAAP;AACA;AAED;AACA;AACA;AACA;AACA;;AACA,IAAIA,UAAyB,GAAG,IAAhC;AACO,SAASS,oBAAT,CAA8BC,KAA9B,EAAkD;AAExD,MAAIV,UAAU,KAAK,IAAnB,EAAyB;AACxBA,IAAAA,UAAU,GAAGF,kBAAkB,EAA/B;AACA;;AAED,OAAK,IAAIS,KAAT,IAAkBP,UAAlB,EAA8B;AAC7B,QAAIA,UAAU,CAACW,cAAX,CAA0BJ,KAA1B,CAAJ,EAAsC;AACrCG,MAAAA,KAAK,GAAGA,KAAK,CAACd,OAAN,CAAe,IAAIgB,MAAJ,CAAWL,KAAX,EAAiB,GAAjB,CAAf,EAAsC,MAAIP,UAAU,CAACO,KAAD,CAAd,GAAsB,GAA5D,CAAR;AACA;AACD;;AACD,SAAOG,KAAP;AACA;AAGD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;"} \ No newline at end of file diff --git a/dist/esm/sifter.js b/dist/esm/sifter.js new file mode 100644 index 0000000..1858ed0 --- /dev/null +++ b/dist/esm/sifter.js @@ -0,0 +1,380 @@ +/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */ +import { escape_regex, iterate, cmp, propToArray, getAttrNesting, getAttr, scoreValue } from './utils.js'; +import { diacriticRegexPoints, asciifold } from './diacritics.js'; + +/** + * sifter.js + * Copyright (c) 2013–2020 Brian Reavis & contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + * ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + * + * @author Brian Reavis + */ +class Sifter { + /** + * Textually searches arrays and hashes of objects + * by property (or multiple properties). Designed + * specifically for autocomplete. + * + * @constructor + * @param {array|object} items + * @param {object} items + */ + constructor(items, settings) { + this.items = void 0; + this.settings = void 0; + this.items = items; + this.settings = settings || { + diacritics: true + }; + } + + /** + * Splits a search string into an array of individual + * regexps to be used to match results. + * + */ + tokenize(query, respect_word_boundaries, weights) { + if (!query || !query.length) return []; + var tokens = []; + var words = query.split(/\s+/); + var field_regex; + + if (weights) { + field_regex = new RegExp('^(' + Object.keys(weights).map(escape_regex).join('|') + ')\:(.*)$'); + } + + words.forEach(word => { + let field_match; + let field = null; + let regex = null; // look for "field:query" tokens + + if (field_regex && (field_match = word.match(field_regex))) { + field = field_match[1]; + word = field_match[2]; + } + + if (word.length > 0) { + regex = escape_regex(word); + + if (this.settings.diacritics) { + regex = diacriticRegexPoints(regex); + } + + if (respect_word_boundaries) regex = "\\b" + regex; + regex = new RegExp(regex, 'i'); + } + + tokens.push({ + string: word, + regex: regex, + field: field + }); + }); + return tokens; + } + + /** + * Returns a function to be used to score individual results. + * + * Good matches will have a higher score than poor matches. + * If an item is not a match, 0 will be returned by the function. + * + * @returns {function} + */ + getScoreFunction(query, options) { + var search = this.prepareSearch(query, options); + return this._getScoreFunction(search); + } + + _getScoreFunction(search) { + const tokens = search.tokens, + token_count = tokens.length; + + if (!token_count) { + return function () { + return 0; + }; + } + + const fields = search.options.fields, + weights = search.weights, + field_count = fields.length, + getAttrFn = search.getAttrFn; + /** + * Calculates the score of an object + * against the search query. + * + * @param {TToken} token + * @param {object} data + * @return {number} + */ + + var scoreObject = function () { + if (!field_count) { + return function () { + return 0; + }; + } + + if (field_count === 1) { + return function (token, data) { + const field = fields[0].field; + return scoreValue(getAttrFn(data, field), token, weights[field]); + }; + } + + return function (token, data) { + var sum = 0; // is the token specific to a field? + + if (token.field) { + const value = getAttrFn(data, token.field); + + if (!token.regex && value) { + sum += 0.1; + } else { + sum += scoreValue(value, token, weights[token.field]); + } + } else { + iterate(weights, (weight, field) => { + sum += scoreValue(getAttrFn(data, field), token, weight); + }); + } + + return sum / field_count; + }; + }(); + + if (token_count === 1) { + return function (data) { + return scoreObject(tokens[0], data); + }; + } + + if (search.options.conjunction === 'and') { + return function (data) { + var i = 0, + score, + sum = 0; + + for (; i < token_count; i++) { + score = scoreObject(tokens[i], data); + if (score <= 0) return 0; + sum += score; + } + + return sum / token_count; + }; + } else { + return function (data) { + var sum = 0; + iterate(tokens, token => { + sum += scoreObject(token, data); + }); + return sum / token_count; + }; + } + } + + /** + * Returns a function that can be used to compare two + * results, for sorting purposes. If no sorting should + * be performed, `null` will be returned. + * + * @return function(a,b) + */ + getSortFunction(query, options) { + var search = this.prepareSearch(query, options); + return this._getSortFunction(search); + } + + _getSortFunction(search) { + var i, n, self, sort_fld, sort_flds, sort_flds_count, multiplier, multipliers, get_field, implicit_score, sort, options; + self = this; + options = search.options; + sort = !search.query && options.sort_empty || options.sort; + /** + * Fetches the specified sort field value + * from a search result item. + * + * @param {string} name + * @param {object} result + * @return {string} + */ + + get_field = function (name, result) { + if (name === '$score') return result.score; + return search.getAttrFn(self.items[result.id], name); + }; // parse options + + + sort_flds = []; + + if (sort) { + for (i = 0, n = sort.length; i < n; i++) { + if (search.query || sort[i].field !== '$score') { + sort_flds.push(sort[i]); + } + } + } // the "$score" field is implied to be the primary + // sort field, unless it's manually specified + + + if (search.query) { + implicit_score = true; + + for (i = 0, n = sort_flds.length; i < n; i++) { + if (sort_flds[i].field === '$score') { + implicit_score = false; + break; + } + } + + if (implicit_score) { + sort_flds.unshift({ + field: '$score', + direction: 'desc' + }); + } + } else { + for (i = 0, n = sort_flds.length; i < n; i++) { + if (sort_flds[i].field === '$score') { + sort_flds.splice(i, 1); + break; + } + } + } + + multipliers = []; + + for (i = 0, n = sort_flds.length; i < n; i++) { + multipliers.push(sort_flds[i].direction === 'desc' ? -1 : 1); + } // build function + + + sort_flds_count = sort_flds.length; + + if (!sort_flds_count) { + return null; + } else if (sort_flds_count === 1) { + sort_fld = sort_flds[0].field; + multiplier = multipliers[0]; + return function (a, b) { + return multiplier * cmp(get_field(sort_fld, a), get_field(sort_fld, b)); + }; + } else { + return function (a, b) { + var i, result, field; + + for (i = 0; i < sort_flds_count; i++) { + field = sort_flds[i].field; + result = multipliers[i] * cmp(get_field(field, a), get_field(field, b)); + if (result) return result; + } + + return 0; + }; + } + } + + /** + * Parses a search query and returns an object + * with tokens and fields ready to be populated + * with results. + * + */ + prepareSearch(query, optsUser) { + const weights = {}; + var options = Object.assign({}, optsUser); + propToArray(options, 'sort'); + propToArray(options, 'sort_empty'); // convert fields to new format + + if (options.fields) { + propToArray(options, 'fields'); + + if (Array.isArray(options.fields) && typeof options.fields[0] !== 'object') { + var fields = []; + options.fields.forEach(fld_name => { + fields.push({ + field: fld_name + }); + }); + options.fields = fields; + } + + options.fields.forEach(field_params => { + weights[field_params.field] = 'weight' in field_params ? field_params.weight : 1; + }); + } + + query = asciifold(String(query || '')).toLowerCase().trim(); + return { + options: options, + query: query, + tokens: this.tokenize(query, options.respect_word_boundaries, weights), + total: 0, + items: [], + weights: weights, + getAttrFn: options.nesting ? getAttrNesting : getAttr + }; + } + + /** + * Searches through all items and returns a sorted array of matches. + * + */ + search(query, options) { + var self = this, + score, + search; + var fn_sort; + var fn_score; + search = this.prepareSearch(query, options); + options = search.options; + query = search.query; // generate result scoring function + + fn_score = options.score || self._getScoreFunction(search); // perform search and sort + + if (query.length) { + iterate(self.items, (item, id) => { + score = fn_score(item); + + if (options.filter === false || score > 0) { + search.items.push({ + 'score': score, + 'id': id + }); + } + }); + } else { + iterate(self.items, (item, id) => { + search.items.push({ + 'score': 1, + 'id': id + }); + }); + } + + fn_sort = self._getSortFunction(search); + if (fn_sort) search.items.sort(fn_sort); // apply limits + + search.total = search.items.length; + + if (typeof options.limit === 'number') { + search.items = search.items.slice(0, options.limit); + } + + return search; + } + +} + +export default Sifter; +//# sourceMappingURL=sifter.js.map diff --git a/dist/esm/sifter.js.map b/dist/esm/sifter.js.map new file mode 100644 index 0000000..31d8e07 --- /dev/null +++ b/dist/esm/sifter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sifter.js","sources":["../../lib/sifter.ts"],"sourcesContent":["/**\n * sifter.js\n * Copyright (c) 2013–2020 Brian Reavis & contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n * file except in compliance with the License. You may obtain a copy of the License at:\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n * ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n *\n * @author Brian Reavis \n */\n\n// @ts-ignore\nimport { scoreValue, getAttr, getAttrNesting, escape_regex, propToArray, iterate, cmp } from './utils.ts';\n// @ts-ignore\nimport { diacriticRegexPoints, asciifold } from './diacritics.ts';\n\n\ntype TField = {\n\tfield: string,\n\tweight?: number,\n}\n\ntype TOptions = {\n \tfields: TField[],\n \tsort: any[],\n \tscore?: ()=>any,\n \tfilter?: boolean,\n \tlimit?: number,\n \tsort_empty?: any,\n \tnesting?: boolean,\n\trespect_word_boundaries?: boolean,\n\tconjunction?: string,\n}\n\ntype TToken = {\n\tstring:string,\n\tregex:RegExp,\n\tfield:string\n}\n\ntype TWeights = {[key:string]:number}\n\ntype TPrepareObj = {\n\toptions: TOptions,\n\tquery: string,\n\ttokens: TToken[],\n\ttotal: number,\n\titems: any[],\n\tweights: TWeights,\n\tgetAttrFn: (any,string)=>any,\n\n}\n\n\nexport default class Sifter{\n\n\tpublic items: []|{};\n\tpublic settings: {diacritics:boolean};\n\n\t/**\n\t * Textually searches arrays and hashes of objects\n\t * by property (or multiple properties). Designed\n\t * specifically for autocomplete.\n\t *\n\t * @constructor\n\t * @param {array|object} items\n\t * @param {object} items\n\t */\n\tconstructor(items, settings) {\n\t\tthis.items = items;\n\t\tthis.settings = settings || {diacritics: true};\n\t};\n\n\t/**\n\t * Splits a search string into an array of individual\n\t * regexps to be used to match results.\n\t *\n\t */\n\ttokenize(query:string, respect_word_boundaries?:boolean, weights?:TWeights ):TToken[] {\n\t\tif (!query || !query.length) return [];\n\n\t\tvar tokens = [];\n\t\tvar words = query.split(/\\s+/);\n\t\tvar field_regex;\n\n\t\tif( weights ){\n\t\t\tfield_regex = new RegExp( '^('+ Object.keys(weights).map(escape_regex).join('|')+')\\:(.*)$');\n\t\t}\n\n\t\twords.forEach((word:string) => {\n\t\t\tlet field_match;\n\t\t\tlet field\t= null;\n\t\t\tlet regex\t= null;\n\n\t\t\t// look for \"field:query\" tokens\n\t\t\tif( field_regex && (field_match = word.match(field_regex)) ){\n\t\t\t\tfield\t= field_match[1];\n\t\t\t\tword\t= field_match[2];\n\t\t\t}\n\n\t\t\tif( word.length > 0 ){\n\t\t\t\tregex = escape_regex(word);\n\t\t\t\tif( this.settings.diacritics ){\n\t\t\t\t\tregex = diacriticRegexPoints(regex);\n\t\t\t\t}\n\t\t\t\tif( respect_word_boundaries ) regex = \"\\\\b\"+regex\n\t\t\t\tregex = new RegExp(regex, 'i');\n\t\t\t}\n\n\t\t\ttokens.push({\n\t\t\t\tstring : word,\n\t\t\t\tregex : regex,\n\t\t\t\tfield : field,\n\t\t\t});\n\t\t});\n\n\t\treturn tokens;\n\t};\n\n\n\t/**\n\t * Returns a function to be used to score individual results.\n\t *\n\t * Good matches will have a higher score than poor matches.\n\t * If an item is not a match, 0 will be returned by the function.\n\t *\n\t * @returns {function}\n\t */\n\tgetScoreFunction(query:string, options ){\n\t\tvar search = this.prepareSearch(query, options);\n\t\treturn this._getScoreFunction(search);\n\t}\n\n\t_getScoreFunction(search:TPrepareObj ){\n\t\tconst tokens\t\t= search.tokens,\n\t\ttoken_count\t\t\t= tokens.length;\n\n\t\tif (!token_count) {\n\t\t\treturn function() { return 0; };\n\t\t}\n\n\t\tconst fields\t= search.options.fields,\n\t\tweights\t\t\t= search.weights,\n\t\tfield_count\t\t= fields.length,\n\t\tgetAttrFn\t\t= search.getAttrFn;\n\n\n\n\t\t/**\n\t\t * Calculates the score of an object\n\t\t * against the search query.\n\t\t *\n\t\t * @param {TToken} token\n\t\t * @param {object} data\n\t\t * @return {number}\n\t\t */\n\t\tvar scoreObject = (function() {\n\n\t\t\tif (!field_count) {\n\t\t\t\treturn function() { return 0; };\n\t\t\t}\n\n\t\t\tif (field_count === 1) {\n\t\t\t\treturn function(token:TToken, data) {\n\t\t\t\t\tconst field = fields[0].field;\n\t\t\t\t\treturn scoreValue(getAttrFn(data, field), token, weights[field]);\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn function(token:TToken, data) {\n\t\t\t\tvar sum = 0;\n\n\t\t\t\t// is the token specific to a field?\n\t\t\t\tif( token.field ){\n\n\t\t\t\t\tconst value = getAttrFn(data, token.field);\n\n\t\t\t\t\tif( !token.regex && value ){\n\t\t\t\t\t\tsum += 0.1;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tsum += scoreValue(value, token, weights[token.field]);\n\t\t\t\t\t}\n\n\n\n\t\t\t\t}else{\n\t\t\t\t\titerate(weights, (weight, field) => {\n\t\t\t\t\t\tsum += scoreValue(getAttrFn(data, field), token, weight);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn sum / field_count;\n\t\t\t};\n\t\t})();\n\n\t\tif (token_count === 1) {\n\t\t\treturn function(data) {\n\t\t\t\treturn scoreObject(tokens[0], data);\n\t\t\t};\n\t\t}\n\n\t\tif (search.options.conjunction === 'and') {\n\t\t\treturn function(data) {\n\t\t\t\tvar i = 0, score, sum = 0;\n\t\t\t\tfor (; i < token_count; i++) {\n\t\t\t\t\tscore = scoreObject(tokens[i], data);\n\t\t\t\t\tif (score <= 0) return 0;\n\t\t\t\t\tsum += score;\n\t\t\t\t}\n\t\t\t\treturn sum / token_count;\n\t\t\t};\n\t\t} else {\n\t\t\treturn function(data) {\n\t\t\t\tvar sum = 0;\n\t\t\t\titerate(tokens,(token:TToken)=>{\n\t\t\t\t\tsum += scoreObject(token, data);\n\t\t\t\t});\n\t\t\t\treturn sum / token_count;\n\t\t\t};\n\t\t}\n\t};\n\n\t/**\n\t * Returns a function that can be used to compare two\n\t * results, for sorting purposes. If no sorting should\n\t * be performed, `null` will be returned.\n\t *\n\t * @return function(a,b)\n\t */\n\tgetSortFunction(query:string, options) {\n\t\tvar search = this.prepareSearch(query, options);\n\t\treturn this._getSortFunction(search);\n\t}\n\n\t_getSortFunction(search:TPrepareObj){\n\t\tvar i, n, self, sort_fld, sort_flds, sort_flds_count, multiplier, multipliers, get_field, implicit_score, sort, options;\n\n\t\tself\t\t= this;\n\t\toptions\t\t= search.options;\n\t\tsort\t\t= (!search.query && options.sort_empty) || options.sort;\n\n\t\t/**\n\t\t * Fetches the specified sort field value\n\t\t * from a search result item.\n\t\t *\n\t\t * @param {string} name\n\t\t * @param {object} result\n\t\t * @return {string}\n\t\t */\n\t\tget_field = function(name, result) {\n\t\t\tif (name === '$score') return result.score;\n\t\t\treturn search.getAttrFn(self.items[result.id], name);\n\t\t};\n\n\t\t// parse options\n\t\tsort_flds = [];\n\t\tif (sort) {\n\t\t\tfor (i = 0, n = sort.length; i < n; i++) {\n\t\t\t\tif (search.query || sort[i].field !== '$score') {\n\t\t\t\t\tsort_flds.push(sort[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// the \"$score\" field is implied to be the primary\n\t\t// sort field, unless it's manually specified\n\t\tif (search.query) {\n\t\t\timplicit_score = true;\n\t\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\t\tif (sort_flds[i].field === '$score') {\n\t\t\t\t\timplicit_score = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (implicit_score) {\n\t\t\t\tsort_flds.unshift({field: '$score', direction: 'desc'});\n\t\t\t}\n\t\t} else {\n\t\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\t\tif (sort_flds[i].field === '$score') {\n\t\t\t\t\tsort_flds.splice(i, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tmultipliers = [];\n\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\tmultipliers.push(sort_flds[i].direction === 'desc' ? -1 : 1);\n\t\t}\n\n\t\t// build function\n\t\tsort_flds_count = sort_flds.length;\n\t\tif (!sort_flds_count) {\n\t\t\treturn null;\n\t\t} else if (sort_flds_count === 1) {\n\t\t\tsort_fld = sort_flds[0].field;\n\t\t\tmultiplier = multipliers[0];\n\t\t\treturn function(a, b) {\n\t\t\t\treturn multiplier * cmp(\n\t\t\t\t\tget_field(sort_fld, a),\n\t\t\t\t\tget_field(sort_fld, b)\n\t\t\t\t);\n\t\t\t};\n\t\t} else {\n\t\t\treturn function(a, b) {\n\t\t\t\tvar i, result, field;\n\t\t\t\tfor (i = 0; i < sort_flds_count; i++) {\n\t\t\t\t\tfield = sort_flds[i].field;\n\t\t\t\t\tresult = multipliers[i] * cmp(\n\t\t\t\t\t\tget_field(field, a),\n\t\t\t\t\t\tget_field(field, b)\n\t\t\t\t\t);\n\t\t\t\t\tif (result) return result;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t};\n\t\t}\n\t};\n\n\t/**\n\t * Parses a search query and returns an object\n\t * with tokens and fields ready to be populated\n\t * with results.\n\t *\n\t */\n\tprepareSearch(query:string, optsUser):TPrepareObj {\n\t\tconst weights\t= {};\n\t\tvar options\t\t= Object.assign({},optsUser);\n\n\t\tpropToArray(options,'sort');\n\t\tpropToArray(options,'sort_empty');\n\n\t\t// convert fields to new format\n\t\tif( options.fields ){\n\t\t\tpropToArray(options,'fields');\n\t\t\tif( Array.isArray(options.fields) && typeof options.fields[0] !== 'object' ){\n\t\t\t\tvar fields = [];\n\t\t\t\toptions.fields.forEach((fld_name) => {\n\t\t\t\t\tfields.push({field:fld_name});\n\t\t\t\t});\n\t\t\t\toptions.fields = fields;\n\t\t\t}\n\n\n\t\t\toptions.fields.forEach((field_params)=>{\n\t\t\t\tweights[field_params.field] = ('weight' in field_params) ? field_params.weight : 1;\n\t\t\t});\n\t\t}\n\n\t\tquery = asciifold( String(query || '') ).toLowerCase().trim();\n\n\t\treturn {\n\t\t\toptions\t\t: options,\n\t\t\tquery\t\t: query,\n\t\t\ttokens\t\t: this.tokenize(query, options.respect_word_boundaries, weights),\n\t\t\ttotal\t\t: 0,\n\t\t\titems\t\t: [],\n\t\t\tweights\t\t: weights,\n\t\t\tgetAttrFn\t: (options.nesting) ? getAttrNesting : getAttr,\n\t\t};\n\t};\n\n\t/**\n\t * Searches through all items and returns a sorted array of matches.\n\t *\n\t */\n\tsearch(query:string, options:TOptions) : TPrepareObj {\n\t\tvar self = this, score, search;\n\t\tvar fn_sort;\n\t\tvar fn_score;\n\n\t\tsearch = this.prepareSearch(query, options);\n\t\toptions = search.options;\n\t\tquery = search.query;\n\n\t\t// generate result scoring function\n\t\tfn_score = options.score || self._getScoreFunction(search);\n\n\t\t// perform search and sort\n\t\tif (query.length) {\n\t\t\titerate(self.items, (item, id) => {\n\t\t\t\tscore = fn_score(item);\n\t\t\t\tif (options.filter === false || score > 0) {\n\t\t\t\t\tsearch.items.push({'score': score, 'id': id});\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\titerate(self.items, (item, id) => {\n\t\t\t\tsearch.items.push({'score': 1, 'id': id});\n\t\t\t});\n\t\t}\n\n\t\tfn_sort = self._getSortFunction(search);\n\t\tif (fn_sort) search.items.sort(fn_sort);\n\n\t\t// apply limits\n\t\tsearch.total = search.items.length;\n\t\tif (typeof options.limit === 'number') {\n\t\t\tsearch.items = search.items.slice(0, options.limit);\n\t\t}\n\n\t\treturn search;\n\t};\n}\n"],"names":["Sifter","constructor","items","settings","diacritics","tokenize","query","respect_word_boundaries","weights","length","tokens","words","split","field_regex","RegExp","Object","keys","map","escape_regex","join","forEach","word","field_match","field","regex","match","diacriticRegexPoints","push","string","getScoreFunction","options","search","prepareSearch","_getScoreFunction","token_count","fields","field_count","getAttrFn","scoreObject","token","data","scoreValue","sum","value","iterate","weight","conjunction","i","score","getSortFunction","_getSortFunction","n","self","sort_fld","sort_flds","sort_flds_count","multiplier","multipliers","get_field","implicit_score","sort","sort_empty","name","result","id","unshift","direction","splice","a","b","cmp","optsUser","assign","propToArray","Array","isArray","fld_name","field_params","asciifold","String","toLowerCase","trim","total","nesting","getAttrNesting","getAttr","fn_sort","fn_score","item","filter","limit","slice"],"mappings":"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"} \ No newline at end of file diff --git a/dist/esm/utils.js b/dist/esm/utils.js new file mode 100644 index 0000000..9901e11 --- /dev/null +++ b/dist/esm/utils.js @@ -0,0 +1,100 @@ +/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */ +import { asciifold } from './diacritics.js'; + +// @ts-ignore +/** + * A property getter resolving dot-notation + * @param {Object} obj The root object to fetch property on + * @param {String} name The optionally dotted property name to fetch + * @return {Object} The resolved property value + */ + +function getAttr(obj, name) { + if (!obj) return; + return obj[name]; +} +/** + * A property getter resolving dot-notation + * @param {Object} obj The root object to fetch property on + * @param {String} name The optionally dotted property name to fetch + * @return {Object} The resolved property value + */ + +function getAttrNesting(obj, name) { + if (!obj) return; + var names = name.split("."); + + while (names.length && (obj = obj[names.shift()])); + + return obj; +} +/** + * Calculates how close of a match the + * given value is against a search token. + * + * @param {object} token + * @return {number} + */ + +function scoreValue(value, token, weight) { + var score, pos; + if (!value) return 0; + value = String(value || ''); + pos = value.search(token.regex); + if (pos === -1) return 0; + score = token.string.length / value.length; + if (pos === 0) score += 0.5; + return score * weight; +} +function escape_regex(str) { + return (str + '').replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); +} +/** + * Cast object property to an array if it exists and has a value + * + */ + +function propToArray(obj, key) { + var value = obj[key]; + + if (value && !Array.isArray(value)) { + obj[key] = [value]; + } +} +/** + * Iterates over arrays and hashes. + * + * ``` + * iterate(this.items, function(item, id) { + * // invoked for each item + * }); + * ``` + * + * @param {array|object} object + */ + +function iterate(object, callback) { + if (Array.isArray(object)) { + object.forEach(callback); + } else { + for (var key in object) { + if (object.hasOwnProperty(key)) { + callback(object[key], key); + } + } + } +} +function cmp(a, b) { + if (typeof a === 'number' && typeof b === 'number') { + return a > b ? 1 : a < b ? -1 : 0; + } + + a = asciifold(String(a || '')).toLowerCase(); + b = asciifold(String(b || '')).toLowerCase(); + if (a > b) return 1; + if (b > a) return -1; + return 0; +} + +export { cmp, escape_regex, getAttr, getAttrNesting, iterate, propToArray, scoreValue }; +//# sourceMappingURL=utils.js.map diff --git a/dist/esm/utils.js.map b/dist/esm/utils.js.map new file mode 100644 index 0000000..960b4fc --- /dev/null +++ b/dist/esm/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","sources":["../../lib/utils.ts"],"sourcesContent":["\n// @ts-ignore\nimport { asciifold } from './diacritics.ts';\n\n/**\n * A property getter resolving dot-notation\n * @param {Object} obj The root object to fetch property on\n * @param {String} name The optionally dotted property name to fetch\n * @return {Object} The resolved property value\n */\nexport function getAttr(obj:{[key:string]:any}, name:string ) {\n if (!obj ) return;\n return obj[name];\n};\n\n/**\n * A property getter resolving dot-notation\n * @param {Object} obj The root object to fetch property on\n * @param {String} name The optionally dotted property name to fetch\n * @return {Object} The resolved property value\n */\nexport function getAttrNesting(obj:{[key:string]:any}, name:string ) {\n if (!obj ) return;\n var names = name.split(\".\");\n while(names.length && (obj = obj[names.shift()]));\n return obj;\n};\n\n/**\n * Calculates how close of a match the\n * given value is against a search token.\n *\n * @param {object} token\n * @return {number}\n */\nexport function scoreValue(value:string, token, weight:number ) {\n\tvar score, pos;\n\n\tif (!value) return 0;\n\n\tvalue = String(value || '');\n\tpos = value.search(token.regex);\n\tif (pos === -1) return 0;\n\n\tscore = token.string.length / value.length;\n\tif (pos === 0) score += 0.5;\n\n\treturn score * weight;\n};\n\nexport function escape_regex(str) {\n\treturn (str + '').replace(/([.?*+^$[\\]\\\\(){}|-])/g, '\\\\$1');\n};\n\n\n/**\n * Cast object property to an array if it exists and has a value\n *\n */\nexport function propToArray(obj, key){\n\tvar value = obj[key];\n\tif( value && !Array.isArray(value) ){\n\t\tobj[key] = [value];\n\t}\n}\n\n\n/**\n * Iterates over arrays and hashes.\n *\n * ```\n * iterate(this.items, function(item, id) {\n * // invoked for each item\n * });\n * ```\n *\n * @param {array|object} object\n */\nexport function iterate(object, callback) {\n\n\tif ( Array.isArray(object)) {\n\t\tobject.forEach(callback);\n\n\t}else{\n\n\t\tfor (var key in object) {\n\t\t\tif (object.hasOwnProperty(key)) {\n\t\t\t\tcallback(object[key], key);\n\t\t\t}\n\t\t}\n\t}\n};\n\n\n\nexport function cmp(a, b) {\n\tif (typeof a === 'number' && typeof b === 'number') {\n\t\treturn a > b ? 1 : (a < b ? -1 : 0);\n\t}\n\ta = asciifold(String(a || '')).toLowerCase();\n\tb = asciifold(String(b || '')).toLowerCase();\n\tif (a > b) return 1;\n\tif (b > a) return -1;\n\treturn 0;\n};\n"],"names":["getAttr","obj","name","getAttrNesting","names","split","length","shift","scoreValue","value","token","weight","score","pos","String","search","regex","string","escape_regex","str","replace","propToArray","key","Array","isArray","iterate","object","callback","forEach","hasOwnProperty","cmp","a","b","asciifold","toLowerCase"],"mappings":"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"} \ No newline at end of file diff --git a/dist/umd/sifter.js b/dist/umd/sifter.js new file mode 100644 index 0000000..c9486b3 --- /dev/null +++ b/dist/umd/sifter.js @@ -0,0 +1,594 @@ +/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.sifter = factory()); +}(this, (function () { 'use strict'; + + // https://github.com/andrewrk/node-diacritics/blob/master/index.js + /** + * code points generated from toCodePoints(); + * removed 65339 to 65345 + */ + + var code_points = [[67, 67], [160, 160], [192, 438], [452, 652], [961, 961], [1019, 1019], [1083, 1083], [1281, 1289], [1984, 1984], [5095, 5095], [7429, 7441], [7545, 7549], [7680, 7935], [8580, 8580], [9398, 9449], [11360, 11391], [42792, 42793], [42802, 42851], [42873, 42897], [42912, 42922], [64256, 64260], [65313, 65338], [65345, 65370]]; + /** + * Remove accents + * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703 + * + */ + + function asciifold(str) { + return str.normalize('NFD').replace(/[\u0300-\u036F]/g, '').normalize('NFKD').toLowerCase(); + } + /** + * Generate a list of diacritics from the list of code points + * + */ + + + function generateDiacritics() { + var latin_convert = { + 'l·': 'l', + 'ʼn': 'n', + 'æ': 'ae', + 'ø': 'o', + 'aʾ': 'a', + 'dž': 'dz' + }; + var diacritics = {}; //var no_latin = []; + + code_points.forEach(code_range => { + for (let i = code_range[0]; i <= code_range[1]; i++) { + let diacritic = String.fromCharCode(i); + let latin = diacritic.normalize('NFD').replace(/[\u0300-\u036F]/g, '').normalize('NFKD'); + + if (latin == diacritic) { + //no_latin.push(diacritic); + continue; + } + + latin = latin.toLowerCase(); + + if (latin in latin_convert) { + latin = latin_convert[latin]; + } + + if (!(latin in diacritics)) { + diacritics[latin] = latin + latin.toUpperCase(); + } + + diacritics[latin] += diacritic; + } + }); //console.log('no_latin',JSON.stringify(no_latin)); + + return diacritics; + } + /** + * Expand a regular expression pattern to include diacritics + * eg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/ + * + */ + + var diacritics = null; + function diacriticRegexPoints(regex) { + if (diacritics === null) { + diacritics = generateDiacritics(); + } + + for (let latin in diacritics) { + if (diacritics.hasOwnProperty(latin)) { + regex = regex.replace(new RegExp(latin, 'g'), '[' + diacritics[latin] + ']'); + } + } + + return regex; + } + /** + * Expand a regular expression pattern to include diacritics + * eg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/ + * + * rollup will bundle this function (and the DIACRITICS constant) unless commented out + * + var diacriticRegex = (function() { + + var list = []; + for( let letter in DIACRITICS ){ + + if( letter.toLowerCase() != letter && letter.toLowerCase() in DIACRITICS ){ + continue; + } + + if( DIACRITICS.hasOwnProperty(letter) ){ + + var replace = letter + DIACRITICS[letter]; + if( letter.toUpperCase() in DIACRITICS ){ + replace += letter.toUpperCase() + DIACRITICS[letter.toUpperCase()]; + } + + list.push({let:letter,pat:'['+replace+']'}); + } + } + + return function(regex:string):string{ + list.forEach((item)=>{ + regex = regex.replace( new RegExp(item.let,'g'),item.pat); + }); + return regex; + } + })(); + */ + + // @ts-ignore + /** + * A property getter resolving dot-notation + * @param {Object} obj The root object to fetch property on + * @param {String} name The optionally dotted property name to fetch + * @return {Object} The resolved property value + */ + + function getAttr(obj, name) { + if (!obj) return; + return obj[name]; + } + /** + * A property getter resolving dot-notation + * @param {Object} obj The root object to fetch property on + * @param {String} name The optionally dotted property name to fetch + * @return {Object} The resolved property value + */ + + function getAttrNesting(obj, name) { + if (!obj) return; + var names = name.split("."); + + while (names.length && (obj = obj[names.shift()])); + + return obj; + } + /** + * Calculates how close of a match the + * given value is against a search token. + * + * @param {object} token + * @return {number} + */ + + function scoreValue(value, token, weight) { + var score, pos; + if (!value) return 0; + value = String(value || ''); + pos = value.search(token.regex); + if (pos === -1) return 0; + score = token.string.length / value.length; + if (pos === 0) score += 0.5; + return score * weight; + } + function escape_regex(str) { + return (str + '').replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); + } + /** + * Cast object property to an array if it exists and has a value + * + */ + + function propToArray(obj, key) { + var value = obj[key]; + + if (value && !Array.isArray(value)) { + obj[key] = [value]; + } + } + /** + * Iterates over arrays and hashes. + * + * ``` + * iterate(this.items, function(item, id) { + * // invoked for each item + * }); + * ``` + * + * @param {array|object} object + */ + + function iterate(object, callback) { + if (Array.isArray(object)) { + object.forEach(callback); + } else { + for (var key in object) { + if (object.hasOwnProperty(key)) { + callback(object[key], key); + } + } + } + } + function cmp(a, b) { + if (typeof a === 'number' && typeof b === 'number') { + return a > b ? 1 : a < b ? -1 : 0; + } + + a = asciifold(String(a || '')).toLowerCase(); + b = asciifold(String(b || '')).toLowerCase(); + if (a > b) return 1; + if (b > a) return -1; + return 0; + } + + /** + * sifter.js + * Copyright (c) 2013–2020 Brian Reavis & contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + * ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + * + * @author Brian Reavis + */ + class Sifter { + /** + * Textually searches arrays and hashes of objects + * by property (or multiple properties). Designed + * specifically for autocomplete. + * + * @constructor + * @param {array|object} items + * @param {object} items + */ + constructor(items, settings) { + this.items = void 0; + this.settings = void 0; + this.items = items; + this.settings = settings || { + diacritics: true + }; + } + + /** + * Splits a search string into an array of individual + * regexps to be used to match results. + * + */ + tokenize(query, respect_word_boundaries, weights) { + if (!query || !query.length) return []; + var tokens = []; + var words = query.split(/\s+/); + var field_regex; + + if (weights) { + field_regex = new RegExp('^(' + Object.keys(weights).map(escape_regex).join('|') + ')\:(.*)$'); + } + + words.forEach(word => { + let field_match; + let field = null; + let regex = null; // look for "field:query" tokens + + if (field_regex && (field_match = word.match(field_regex))) { + field = field_match[1]; + word = field_match[2]; + } + + if (word.length > 0) { + regex = escape_regex(word); + + if (this.settings.diacritics) { + regex = diacriticRegexPoints(regex); + } + + if (respect_word_boundaries) regex = "\\b" + regex; + regex = new RegExp(regex, 'i'); + } + + tokens.push({ + string: word, + regex: regex, + field: field + }); + }); + return tokens; + } + + /** + * Returns a function to be used to score individual results. + * + * Good matches will have a higher score than poor matches. + * If an item is not a match, 0 will be returned by the function. + * + * @returns {function} + */ + getScoreFunction(query, options) { + var search = this.prepareSearch(query, options); + return this._getScoreFunction(search); + } + + _getScoreFunction(search) { + const tokens = search.tokens, + token_count = tokens.length; + + if (!token_count) { + return function () { + return 0; + }; + } + + const fields = search.options.fields, + weights = search.weights, + field_count = fields.length, + getAttrFn = search.getAttrFn; + /** + * Calculates the score of an object + * against the search query. + * + * @param {TToken} token + * @param {object} data + * @return {number} + */ + + var scoreObject = function () { + if (!field_count) { + return function () { + return 0; + }; + } + + if (field_count === 1) { + return function (token, data) { + const field = fields[0].field; + return scoreValue(getAttrFn(data, field), token, weights[field]); + }; + } + + return function (token, data) { + var sum = 0; // is the token specific to a field? + + if (token.field) { + const value = getAttrFn(data, token.field); + + if (!token.regex && value) { + sum += 0.1; + } else { + sum += scoreValue(value, token, weights[token.field]); + } + } else { + iterate(weights, (weight, field) => { + sum += scoreValue(getAttrFn(data, field), token, weight); + }); + } + + return sum / field_count; + }; + }(); + + if (token_count === 1) { + return function (data) { + return scoreObject(tokens[0], data); + }; + } + + if (search.options.conjunction === 'and') { + return function (data) { + var i = 0, + score, + sum = 0; + + for (; i < token_count; i++) { + score = scoreObject(tokens[i], data); + if (score <= 0) return 0; + sum += score; + } + + return sum / token_count; + }; + } else { + return function (data) { + var sum = 0; + iterate(tokens, token => { + sum += scoreObject(token, data); + }); + return sum / token_count; + }; + } + } + + /** + * Returns a function that can be used to compare two + * results, for sorting purposes. If no sorting should + * be performed, `null` will be returned. + * + * @return function(a,b) + */ + getSortFunction(query, options) { + var search = this.prepareSearch(query, options); + return this._getSortFunction(search); + } + + _getSortFunction(search) { + var i, n, self, sort_fld, sort_flds, sort_flds_count, multiplier, multipliers, get_field, implicit_score, sort, options; + self = this; + options = search.options; + sort = !search.query && options.sort_empty || options.sort; + /** + * Fetches the specified sort field value + * from a search result item. + * + * @param {string} name + * @param {object} result + * @return {string} + */ + + get_field = function (name, result) { + if (name === '$score') return result.score; + return search.getAttrFn(self.items[result.id], name); + }; // parse options + + + sort_flds = []; + + if (sort) { + for (i = 0, n = sort.length; i < n; i++) { + if (search.query || sort[i].field !== '$score') { + sort_flds.push(sort[i]); + } + } + } // the "$score" field is implied to be the primary + // sort field, unless it's manually specified + + + if (search.query) { + implicit_score = true; + + for (i = 0, n = sort_flds.length; i < n; i++) { + if (sort_flds[i].field === '$score') { + implicit_score = false; + break; + } + } + + if (implicit_score) { + sort_flds.unshift({ + field: '$score', + direction: 'desc' + }); + } + } else { + for (i = 0, n = sort_flds.length; i < n; i++) { + if (sort_flds[i].field === '$score') { + sort_flds.splice(i, 1); + break; + } + } + } + + multipliers = []; + + for (i = 0, n = sort_flds.length; i < n; i++) { + multipliers.push(sort_flds[i].direction === 'desc' ? -1 : 1); + } // build function + + + sort_flds_count = sort_flds.length; + + if (!sort_flds_count) { + return null; + } else if (sort_flds_count === 1) { + sort_fld = sort_flds[0].field; + multiplier = multipliers[0]; + return function (a, b) { + return multiplier * cmp(get_field(sort_fld, a), get_field(sort_fld, b)); + }; + } else { + return function (a, b) { + var i, result, field; + + for (i = 0; i < sort_flds_count; i++) { + field = sort_flds[i].field; + result = multipliers[i] * cmp(get_field(field, a), get_field(field, b)); + if (result) return result; + } + + return 0; + }; + } + } + + /** + * Parses a search query and returns an object + * with tokens and fields ready to be populated + * with results. + * + */ + prepareSearch(query, optsUser) { + const weights = {}; + var options = Object.assign({}, optsUser); + propToArray(options, 'sort'); + propToArray(options, 'sort_empty'); // convert fields to new format + + if (options.fields) { + propToArray(options, 'fields'); + + if (Array.isArray(options.fields) && typeof options.fields[0] !== 'object') { + var fields = []; + options.fields.forEach(fld_name => { + fields.push({ + field: fld_name + }); + }); + options.fields = fields; + } + + options.fields.forEach(field_params => { + weights[field_params.field] = 'weight' in field_params ? field_params.weight : 1; + }); + } + + query = asciifold(String(query || '')).toLowerCase().trim(); + return { + options: options, + query: query, + tokens: this.tokenize(query, options.respect_word_boundaries, weights), + total: 0, + items: [], + weights: weights, + getAttrFn: options.nesting ? getAttrNesting : getAttr + }; + } + + /** + * Searches through all items and returns a sorted array of matches. + * + */ + search(query, options) { + var self = this, + score, + search; + var fn_sort; + var fn_score; + search = this.prepareSearch(query, options); + options = search.options; + query = search.query; // generate result scoring function + + fn_score = options.score || self._getScoreFunction(search); // perform search and sort + + if (query.length) { + iterate(self.items, (item, id) => { + score = fn_score(item); + + if (options.filter === false || score > 0) { + search.items.push({ + 'score': score, + 'id': id + }); + } + }); + } else { + iterate(self.items, (item, id) => { + search.items.push({ + 'score': 1, + 'id': id + }); + }); + } + + fn_sort = self._getSortFunction(search); + if (fn_sort) search.items.sort(fn_sort); // apply limits + + search.total = search.items.length; + + if (typeof options.limit === 'number') { + search.items = search.items.slice(0, options.limit); + } + + return search; + } + + } + + return Sifter; + +}))); +//# sourceMappingURL=sifter.js.map diff --git a/dist/umd/sifter.js.map b/dist/umd/sifter.js.map new file mode 100644 index 0000000..b0e8ad8 --- /dev/null +++ b/dist/umd/sifter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sifter.js","sources":["../../lib/diacritics.ts","../../lib/utils.ts","../../lib/sifter.ts"],"sourcesContent":["\ntype TDiacraticList = {[key:string]:string};\n\n// https://github.com/andrewrk/node-diacritics/blob/master/index.js\nvar DIACRITICS:TDiacraticList = {\n\t\" \":\" \",\n\t0:\"߀\",\n\tA:\"ⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ\",\n\tAA:\"Ꜳ\",\n\tAE:\"ÆǼǢ\",\n\tAO:\"Ꜵ\",\n\tAU:\"Ꜷ\",\n\tAV:\"ꜸꜺ\",\n\tAY:\"Ꜽ\",\n\tB:\"ⒷBḂḄḆɃƁ\",\n\tC:\"ⒸCꜾḈĆCĈĊČÇƇȻ\",\n\tD:\"ⒹDḊĎḌḐḒḎĐƊƉᴅꝹ\",\n\tDh:\"Ð\",\n\tDZ:\"DZDŽ\",\n\tDz:\"DzDž\",\n\tE:\"ɛⒺEÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚƐƎᴇ\",\n\tF:\"ꝼⒻFḞƑꝻ\",\n\tG:\"ⒼGǴĜḠĞĠǦĢǤƓꞠꝽꝾɢ\",\n\tH:\"ⒽHĤḢḦȞḤḨḪĦⱧⱵꞍ\",\n\tI:\"ⒾIÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬƗ\",\n\tJ:\"ⒿJĴɈȷ\",\n\tK:\"ⓀKḰǨḲĶḴƘⱩꝀꝂꝄꞢ\",\n\tL:\"ⓁLĿĹĽḶḸĻḼḺŁȽⱢⱠꝈꝆꞀ\",\n\tLJ:\"LJ\",\n\tLj:\"Lj\",\n\tM:\"ⓂMḾṀṂⱮƜϻ\",\n\tN:\"ꞤȠⓃNǸŃÑṄŇṆŅṊṈƝꞐᴎ\",\n\tNJ:\"NJ\",\n\tNj:\"Nj\",\n\tO:\"ⓄOÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘǪǬØǾƆƟꝊꝌ\",\n\tOE:\"Œ\",\n\tOI:\"Ƣ\",\n\tOO:\"Ꝏ\",\n\tOU:\"Ȣ\",\n\tP:\"ⓅPṔṖƤⱣꝐꝒꝔ\",\n\tQ:\"ⓆQꝖꝘɊ\",\n\tR:\"ⓇRŔṘŘȐȒṚṜŖṞɌⱤꝚꞦꞂ\",\n\tS:\"ⓈSẞŚṤŜṠŠṦṢṨȘŞⱾꞨꞄ\",\n\tT:\"ⓉTṪŤṬȚŢṰṮŦƬƮȾꞆ\",\n\tTh:\"Þ\",\n\tTZ:\"Ꜩ\",\n\tU:\"ⓊUÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴɄ\",\n\tV:\"ⓋVṼṾƲꝞɅ\",\n\tVY:\"Ꝡ\",\n\tW:\"ⓌWẀẂŴẆẄẈⱲ\",\n\tX:\"ⓍXẊẌ\",\n\tY:\"ⓎYỲÝŶỸȲẎŸỶỴƳɎỾ\",\n\tZ:\"ⓏZŹẐŻŽẒẔƵȤⱿⱫꝢ\",\n\ta:\"ⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑ\",\n\taa:\"ꜳ\",\n\tae:\"æǽǣ\",\n\tao:\"ꜵ\",\n\tau:\"ꜷ\",\n\tav:\"ꜹꜻ\",\n\tay:\"ꜽ\",\n\tb:\"ⓑbḃḅḇƀƃɓƂ\",\n\tc:\"cⓒćĉċčçḉƈȼꜿↄ\",\n\td:\"ⓓdḋďḍḑḓḏđƌɖɗƋᏧԁꞪ\",\n\tdh:\"ð\",\n\tdz:\"dzdž\",\n\te:\"ⓔeèéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛɇǝ\",\n\tf:\"ⓕfḟƒ\",\n\tff:\"ff\",\n\tfi:\"fi\",\n\tfl:\"fl\",\n\tffi:\"ffi\",\n\tffl:\"ffl\",\n\tg:\"ⓖgǵĝḡğġǧģǥɠꞡꝿᵹ\",\n\th:\"ⓗhĥḣḧȟḥḩḫẖħⱨⱶɥ\",\n\thv:\"ƕ\",\n\ti:\"ⓘiìíîĩīĭïḯỉǐȉȋịįḭɨı\",\n\tj:\"ⓙjĵǰɉ\",\n\tk:\"ⓚkḱǩḳķḵƙⱪꝁꝃꝅꞣ\",\n\tl:\"ⓛlŀĺľḷḹļḽḻſłƚɫⱡꝉꞁꝇɭ\",\n\tlj:\"lj\",\n\tm:\"ⓜmḿṁṃɱɯ\",\n\tn:\"ⓝnǹńñṅňṇņṋṉƞɲʼnꞑꞥлԉ\",\n\tnj:\"nj\",\n\to:\"ⓞoòóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộǫǭøǿꝋꝍɵɔᴑ\",\n\toe:\"œ\",\n\toi:\"ƣ\",\n\too:\"ꝏ\",\n\tou:\"ȣ\",\n\tp:\"ⓟpṕṗƥᵽꝑꝓꝕρ\",\n\tq:\"ⓠqɋꝗꝙ\",\n\tr:\"ⓡrŕṙřȑȓṛṝŗṟɍɽꝛꞧꞃ\",\n\ts:\"ⓢsśṥŝṡšṧṣṩșşȿꞩꞅẛʂ\",\n\tss:\"ß\",\n\tt:\"ⓣtṫẗťṭțţṱṯŧƭʈⱦꞇ\",\n\tth:\"þ\",\n\ttz:\"ꜩ\",\n\tu:\"ⓤuùúûũṹūṻŭüǜǘǖǚủůűǔȕȗưừứữửựụṳųṷṵʉ\",\n\tv:\"ⓥvṽṿʋꝟʌ\",\n\tvy:\"ꝡ\",\n\tw:\"ⓦwẁẃŵẇẅẘẉⱳ\",\n\tx:\"ⓧxẋẍ\",\n\ty:\"ⓨyỳýŷỹȳẏÿỷẙỵƴɏỿ\",\n\tz:\"ⓩzźẑżžẓẕƶȥɀⱬꝣ\"\n}\n\n/**\n * code points generated from toCodePoints();\n * removed 65339 to 65345\n */\nvar code_points = [\n\t[ 67, 67 ],\n\t[ 160, 160 ],\n\t[ 192, 438 ],\n\t[ 452, 652 ],\n\t[ 961, 961 ],\n\t[ 1019, 1019 ],\n\t[ 1083, 1083 ],\n\t[ 1281, 1289 ],\n\t[ 1984, 1984 ],\n\t[ 5095, 5095 ],\n\t[ 7429, 7441 ],\n\t[ 7545, 7549 ],\n\t[ 7680, 7935 ],\n\t[ 8580, 8580 ],\n\t[ 9398, 9449 ],\n\t[ 11360, 11391 ],\n\t[ 42792, 42793 ],\n\t[ 42802, 42851 ],\n\t[ 42873, 42897 ],\n\t[ 42912, 42922 ],\n\t[ 64256, 64260 ],\n\t[ 65313, 65338 ],\n\t[ 65345, 65370 ]\n];\n\n/**\n * Remove accents\n * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703\n *\n */\nexport function asciifold(str:string):string{\n\treturn str.normalize('NFD').replace(/[\\u0300-\\u036F]/g, '').normalize('NFKD').toLowerCase();\n};\n\n\n/**\n * Convert list of diacritics to array of code points\n *\n */\n// @ts-ignore\nfunction toCodePoints(tolerance=8){\n\tvar char_codes = [];\n\n\tfor( let letter in DIACRITICS ){\n\t\tlet _diacritics = DIACRITICS[letter];\n\t\tfor( let n = 0; n < _diacritics.length; n++ ){\n\t\t\tvar code_point = _diacritics.codePointAt(n);\n\t\t\tchar_codes.push( code_point );\n\t\t}\n\t}\n\n\t//https://stackoverflow.com/questions/40431572/is-there-a-simple-way-to-group-js-array-values-by-range\n\tchar_codes.sort((a, b) => a - b);\n var result = char_codes.reduce(function (accumulator, currentValue, index, source) {\n\n\t\tif( !index ){\n\t\t\taccumulator.push( [currentValue,currentValue] );\n\n\t\t}else if( currentValue - source[index - 1] > tolerance ){\n\t\t\taccumulator.push( [currentValue,currentValue] );\n\n\t\t}else{\n\n\t\t\taccumulator.push( [accumulator.pop()[0],currentValue]);\n\t\t}\n\n return accumulator;\n }, []);\n\n\tconsole.log(`char_codes (${result.length})`,result);\n}\n\n/**\n * Generate a list of diacritics from the list of code points\n *\n */\nexport function generateDiacritics():TDiacraticList{\n\n\tvar latin_convert = {\n\t\t'l·': 'l',\n\t\t'ʼn': 'n',\n\t\t'æ': 'ae',\n\t\t'ø': 'o',\n\t\t'aʾ': 'a',\n\t\t'dž': 'dz',\n\t};\n\n\tvar diacritics\t= {};\n\t//var no_latin\t= [];\n\tcode_points.forEach((code_range)=>{\n\n\t\tfor(let i = code_range[0]; i <= code_range[1]; i++){\n\t\t\tlet diacritic\t= String.fromCharCode(i);\n\t\t\tlet latin\t\t= diacritic.normalize('NFD').replace(/[\\u0300-\\u036F]/g, '').normalize('NFKD');\n\n\t\t\tif( latin == diacritic ){\n\t\t\t\t//no_latin.push(diacritic);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlatin = latin.toLowerCase();\n\n\t\t\tif( latin in latin_convert ){\n\t\t\t\tlatin = latin_convert[latin];\n\t\t\t}\n\n\t\t\tif( !(latin in diacritics) ){\n\t\t\t\tdiacritics[latin] = latin + latin.toUpperCase();\n\t\t\t}\n\t\t\tdiacritics[latin] += diacritic;\n\t\t}\n\t});\n\n\t//console.log('no_latin',JSON.stringify(no_latin));\n\n\treturn diacritics;\n}\n\n/**\n * Expand a regular expression pattern to include diacritics\n * \teg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/\n *\n */\nvar diacritics:TDiacraticList = null\nexport function diacriticRegexPoints(regex:string):string{\n\n\tif( diacritics === null ){\n\t\tdiacritics = generateDiacritics();\n\t}\n\n\tfor( let latin in diacritics ){\n\t\tif( diacritics.hasOwnProperty(latin) ){\n\t\t\tregex = regex.replace( new RegExp(latin,'g'), '['+diacritics[latin]+']');\n\t\t}\n\t}\n\treturn regex;\n}\n\n\n/**\n * Expand a regular expression pattern to include diacritics\n * \teg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/\n *\n * rollup will bundle this function (and the DIACRITICS constant) unless commented out\n *\nvar diacriticRegex = (function() {\n\n\tvar list = [];\n\tfor( let letter in DIACRITICS ){\n\n\t\tif( letter.toLowerCase() != letter && letter.toLowerCase() in DIACRITICS ){\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( DIACRITICS.hasOwnProperty(letter) ){\n\n\t\t\tvar replace = letter + DIACRITICS[letter];\n\t\t\tif( letter.toUpperCase() in DIACRITICS ){\n\t\t\t\treplace += letter.toUpperCase() + DIACRITICS[letter.toUpperCase()];\n\t\t\t}\n\n\t\t\tlist.push({let:letter,pat:'['+replace+']'});\n\t\t}\n\t}\n\n\treturn function(regex:string):string{\n\t\tlist.forEach((item)=>{\n\t\t\tregex = regex.replace( new RegExp(item.let,'g'),item.pat);\n\t\t});\n\t\treturn regex;\n\t}\n})();\n*/\n","\n// @ts-ignore\nimport { asciifold } from './diacritics.ts';\n\n/**\n * A property getter resolving dot-notation\n * @param {Object} obj The root object to fetch property on\n * @param {String} name The optionally dotted property name to fetch\n * @return {Object} The resolved property value\n */\nexport function getAttr(obj:{[key:string]:any}, name:string ) {\n if (!obj ) return;\n return obj[name];\n};\n\n/**\n * A property getter resolving dot-notation\n * @param {Object} obj The root object to fetch property on\n * @param {String} name The optionally dotted property name to fetch\n * @return {Object} The resolved property value\n */\nexport function getAttrNesting(obj:{[key:string]:any}, name:string ) {\n if (!obj ) return;\n var names = name.split(\".\");\n while(names.length && (obj = obj[names.shift()]));\n return obj;\n};\n\n/**\n * Calculates how close of a match the\n * given value is against a search token.\n *\n * @param {object} token\n * @return {number}\n */\nexport function scoreValue(value:string, token, weight:number ) {\n\tvar score, pos;\n\n\tif (!value) return 0;\n\n\tvalue = String(value || '');\n\tpos = value.search(token.regex);\n\tif (pos === -1) return 0;\n\n\tscore = token.string.length / value.length;\n\tif (pos === 0) score += 0.5;\n\n\treturn score * weight;\n};\n\nexport function escape_regex(str) {\n\treturn (str + '').replace(/([.?*+^$[\\]\\\\(){}|-])/g, '\\\\$1');\n};\n\n\n/**\n * Cast object property to an array if it exists and has a value\n *\n */\nexport function propToArray(obj, key){\n\tvar value = obj[key];\n\tif( value && !Array.isArray(value) ){\n\t\tobj[key] = [value];\n\t}\n}\n\n\n/**\n * Iterates over arrays and hashes.\n *\n * ```\n * iterate(this.items, function(item, id) {\n * // invoked for each item\n * });\n * ```\n *\n * @param {array|object} object\n */\nexport function iterate(object, callback) {\n\n\tif ( Array.isArray(object)) {\n\t\tobject.forEach(callback);\n\n\t}else{\n\n\t\tfor (var key in object) {\n\t\t\tif (object.hasOwnProperty(key)) {\n\t\t\t\tcallback(object[key], key);\n\t\t\t}\n\t\t}\n\t}\n};\n\n\n\nexport function cmp(a, b) {\n\tif (typeof a === 'number' && typeof b === 'number') {\n\t\treturn a > b ? 1 : (a < b ? -1 : 0);\n\t}\n\ta = asciifold(String(a || '')).toLowerCase();\n\tb = asciifold(String(b || '')).toLowerCase();\n\tif (a > b) return 1;\n\tif (b > a) return -1;\n\treturn 0;\n};\n","/**\n * sifter.js\n * Copyright (c) 2013–2020 Brian Reavis & contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n * file except in compliance with the License. You may obtain a copy of the License at:\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n * ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n *\n * @author Brian Reavis \n */\n\n// @ts-ignore\nimport { scoreValue, getAttr, getAttrNesting, escape_regex, propToArray, iterate, cmp } from './utils.ts';\n// @ts-ignore\nimport { diacriticRegexPoints, asciifold } from './diacritics.ts';\n\n\ntype TField = {\n\tfield: string,\n\tweight?: number,\n}\n\ntype TOptions = {\n \tfields: TField[],\n \tsort: any[],\n \tscore?: ()=>any,\n \tfilter?: boolean,\n \tlimit?: number,\n \tsort_empty?: any,\n \tnesting?: boolean,\n\trespect_word_boundaries?: boolean,\n\tconjunction?: string,\n}\n\ntype TToken = {\n\tstring:string,\n\tregex:RegExp,\n\tfield:string\n}\n\ntype TWeights = {[key:string]:number}\n\ntype TPrepareObj = {\n\toptions: TOptions,\n\tquery: string,\n\ttokens: TToken[],\n\ttotal: number,\n\titems: any[],\n\tweights: TWeights,\n\tgetAttrFn: (any,string)=>any,\n\n}\n\n\nexport default class Sifter{\n\n\tpublic items: []|{};\n\tpublic settings: {diacritics:boolean};\n\n\t/**\n\t * Textually searches arrays and hashes of objects\n\t * by property (or multiple properties). Designed\n\t * specifically for autocomplete.\n\t *\n\t * @constructor\n\t * @param {array|object} items\n\t * @param {object} items\n\t */\n\tconstructor(items, settings) {\n\t\tthis.items = items;\n\t\tthis.settings = settings || {diacritics: true};\n\t};\n\n\t/**\n\t * Splits a search string into an array of individual\n\t * regexps to be used to match results.\n\t *\n\t */\n\ttokenize(query:string, respect_word_boundaries?:boolean, weights?:TWeights ):TToken[] {\n\t\tif (!query || !query.length) return [];\n\n\t\tvar tokens = [];\n\t\tvar words = query.split(/\\s+/);\n\t\tvar field_regex;\n\n\t\tif( weights ){\n\t\t\tfield_regex = new RegExp( '^('+ Object.keys(weights).map(escape_regex).join('|')+')\\:(.*)$');\n\t\t}\n\n\t\twords.forEach((word:string) => {\n\t\t\tlet field_match;\n\t\t\tlet field\t= null;\n\t\t\tlet regex\t= null;\n\n\t\t\t// look for \"field:query\" tokens\n\t\t\tif( field_regex && (field_match = word.match(field_regex)) ){\n\t\t\t\tfield\t= field_match[1];\n\t\t\t\tword\t= field_match[2];\n\t\t\t}\n\n\t\t\tif( word.length > 0 ){\n\t\t\t\tregex = escape_regex(word);\n\t\t\t\tif( this.settings.diacritics ){\n\t\t\t\t\tregex = diacriticRegexPoints(regex);\n\t\t\t\t}\n\t\t\t\tif( respect_word_boundaries ) regex = \"\\\\b\"+regex\n\t\t\t\tregex = new RegExp(regex, 'i');\n\t\t\t}\n\n\t\t\ttokens.push({\n\t\t\t\tstring : word,\n\t\t\t\tregex : regex,\n\t\t\t\tfield : field,\n\t\t\t});\n\t\t});\n\n\t\treturn tokens;\n\t};\n\n\n\t/**\n\t * Returns a function to be used to score individual results.\n\t *\n\t * Good matches will have a higher score than poor matches.\n\t * If an item is not a match, 0 will be returned by the function.\n\t *\n\t * @returns {function}\n\t */\n\tgetScoreFunction(query:string, options ){\n\t\tvar search = this.prepareSearch(query, options);\n\t\treturn this._getScoreFunction(search);\n\t}\n\n\t_getScoreFunction(search:TPrepareObj ){\n\t\tconst tokens\t\t= search.tokens,\n\t\ttoken_count\t\t\t= tokens.length;\n\n\t\tif (!token_count) {\n\t\t\treturn function() { return 0; };\n\t\t}\n\n\t\tconst fields\t= search.options.fields,\n\t\tweights\t\t\t= search.weights,\n\t\tfield_count\t\t= fields.length,\n\t\tgetAttrFn\t\t= search.getAttrFn;\n\n\n\n\t\t/**\n\t\t * Calculates the score of an object\n\t\t * against the search query.\n\t\t *\n\t\t * @param {TToken} token\n\t\t * @param {object} data\n\t\t * @return {number}\n\t\t */\n\t\tvar scoreObject = (function() {\n\n\t\t\tif (!field_count) {\n\t\t\t\treturn function() { return 0; };\n\t\t\t}\n\n\t\t\tif (field_count === 1) {\n\t\t\t\treturn function(token:TToken, data) {\n\t\t\t\t\tconst field = fields[0].field;\n\t\t\t\t\treturn scoreValue(getAttrFn(data, field), token, weights[field]);\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn function(token:TToken, data) {\n\t\t\t\tvar sum = 0;\n\n\t\t\t\t// is the token specific to a field?\n\t\t\t\tif( token.field ){\n\n\t\t\t\t\tconst value = getAttrFn(data, token.field);\n\n\t\t\t\t\tif( !token.regex && value ){\n\t\t\t\t\t\tsum += 0.1;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tsum += scoreValue(value, token, weights[token.field]);\n\t\t\t\t\t}\n\n\n\n\t\t\t\t}else{\n\t\t\t\t\titerate(weights, (weight, field) => {\n\t\t\t\t\t\tsum += scoreValue(getAttrFn(data, field), token, weight);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn sum / field_count;\n\t\t\t};\n\t\t})();\n\n\t\tif (token_count === 1) {\n\t\t\treturn function(data) {\n\t\t\t\treturn scoreObject(tokens[0], data);\n\t\t\t};\n\t\t}\n\n\t\tif (search.options.conjunction === 'and') {\n\t\t\treturn function(data) {\n\t\t\t\tvar i = 0, score, sum = 0;\n\t\t\t\tfor (; i < token_count; i++) {\n\t\t\t\t\tscore = scoreObject(tokens[i], data);\n\t\t\t\t\tif (score <= 0) return 0;\n\t\t\t\t\tsum += score;\n\t\t\t\t}\n\t\t\t\treturn sum / token_count;\n\t\t\t};\n\t\t} else {\n\t\t\treturn function(data) {\n\t\t\t\tvar sum = 0;\n\t\t\t\titerate(tokens,(token:TToken)=>{\n\t\t\t\t\tsum += scoreObject(token, data);\n\t\t\t\t});\n\t\t\t\treturn sum / token_count;\n\t\t\t};\n\t\t}\n\t};\n\n\t/**\n\t * Returns a function that can be used to compare two\n\t * results, for sorting purposes. If no sorting should\n\t * be performed, `null` will be returned.\n\t *\n\t * @return function(a,b)\n\t */\n\tgetSortFunction(query:string, options) {\n\t\tvar search = this.prepareSearch(query, options);\n\t\treturn this._getSortFunction(search);\n\t}\n\n\t_getSortFunction(search:TPrepareObj){\n\t\tvar i, n, self, sort_fld, sort_flds, sort_flds_count, multiplier, multipliers, get_field, implicit_score, sort, options;\n\n\t\tself\t\t= this;\n\t\toptions\t\t= search.options;\n\t\tsort\t\t= (!search.query && options.sort_empty) || options.sort;\n\n\t\t/**\n\t\t * Fetches the specified sort field value\n\t\t * from a search result item.\n\t\t *\n\t\t * @param {string} name\n\t\t * @param {object} result\n\t\t * @return {string}\n\t\t */\n\t\tget_field = function(name, result) {\n\t\t\tif (name === '$score') return result.score;\n\t\t\treturn search.getAttrFn(self.items[result.id], name);\n\t\t};\n\n\t\t// parse options\n\t\tsort_flds = [];\n\t\tif (sort) {\n\t\t\tfor (i = 0, n = sort.length; i < n; i++) {\n\t\t\t\tif (search.query || sort[i].field !== '$score') {\n\t\t\t\t\tsort_flds.push(sort[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// the \"$score\" field is implied to be the primary\n\t\t// sort field, unless it's manually specified\n\t\tif (search.query) {\n\t\t\timplicit_score = true;\n\t\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\t\tif (sort_flds[i].field === '$score') {\n\t\t\t\t\timplicit_score = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (implicit_score) {\n\t\t\t\tsort_flds.unshift({field: '$score', direction: 'desc'});\n\t\t\t}\n\t\t} else {\n\t\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\t\tif (sort_flds[i].field === '$score') {\n\t\t\t\t\tsort_flds.splice(i, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tmultipliers = [];\n\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\tmultipliers.push(sort_flds[i].direction === 'desc' ? -1 : 1);\n\t\t}\n\n\t\t// build function\n\t\tsort_flds_count = sort_flds.length;\n\t\tif (!sort_flds_count) {\n\t\t\treturn null;\n\t\t} else if (sort_flds_count === 1) {\n\t\t\tsort_fld = sort_flds[0].field;\n\t\t\tmultiplier = multipliers[0];\n\t\t\treturn function(a, b) {\n\t\t\t\treturn multiplier * cmp(\n\t\t\t\t\tget_field(sort_fld, a),\n\t\t\t\t\tget_field(sort_fld, b)\n\t\t\t\t);\n\t\t\t};\n\t\t} else {\n\t\t\treturn function(a, b) {\n\t\t\t\tvar i, result, field;\n\t\t\t\tfor (i = 0; i < sort_flds_count; i++) {\n\t\t\t\t\tfield = sort_flds[i].field;\n\t\t\t\t\tresult = multipliers[i] * cmp(\n\t\t\t\t\t\tget_field(field, a),\n\t\t\t\t\t\tget_field(field, b)\n\t\t\t\t\t);\n\t\t\t\t\tif (result) return result;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t};\n\t\t}\n\t};\n\n\t/**\n\t * Parses a search query and returns an object\n\t * with tokens and fields ready to be populated\n\t * with results.\n\t *\n\t */\n\tprepareSearch(query:string, optsUser):TPrepareObj {\n\t\tconst weights\t= {};\n\t\tvar options\t\t= Object.assign({},optsUser);\n\n\t\tpropToArray(options,'sort');\n\t\tpropToArray(options,'sort_empty');\n\n\t\t// convert fields to new format\n\t\tif( options.fields ){\n\t\t\tpropToArray(options,'fields');\n\t\t\tif( Array.isArray(options.fields) && typeof options.fields[0] !== 'object' ){\n\t\t\t\tvar fields = [];\n\t\t\t\toptions.fields.forEach((fld_name) => {\n\t\t\t\t\tfields.push({field:fld_name});\n\t\t\t\t});\n\t\t\t\toptions.fields = fields;\n\t\t\t}\n\n\n\t\t\toptions.fields.forEach((field_params)=>{\n\t\t\t\tweights[field_params.field] = ('weight' in field_params) ? field_params.weight : 1;\n\t\t\t});\n\t\t}\n\n\t\tquery = asciifold( String(query || '') ).toLowerCase().trim();\n\n\t\treturn {\n\t\t\toptions\t\t: options,\n\t\t\tquery\t\t: query,\n\t\t\ttokens\t\t: this.tokenize(query, options.respect_word_boundaries, weights),\n\t\t\ttotal\t\t: 0,\n\t\t\titems\t\t: [],\n\t\t\tweights\t\t: weights,\n\t\t\tgetAttrFn\t: (options.nesting) ? getAttrNesting : getAttr,\n\t\t};\n\t};\n\n\t/**\n\t * Searches through all items and returns a sorted array of matches.\n\t *\n\t */\n\tsearch(query:string, options:TOptions) : TPrepareObj {\n\t\tvar self = this, score, search;\n\t\tvar fn_sort;\n\t\tvar fn_score;\n\n\t\tsearch = this.prepareSearch(query, options);\n\t\toptions = search.options;\n\t\tquery = search.query;\n\n\t\t// generate result scoring function\n\t\tfn_score = options.score || self._getScoreFunction(search);\n\n\t\t// perform search and sort\n\t\tif (query.length) {\n\t\t\titerate(self.items, (item, id) => {\n\t\t\t\tscore = fn_score(item);\n\t\t\t\tif (options.filter === false || score > 0) {\n\t\t\t\t\tsearch.items.push({'score': score, 'id': id});\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\titerate(self.items, (item, id) => {\n\t\t\t\tsearch.items.push({'score': 1, 'id': id});\n\t\t\t});\n\t\t}\n\n\t\tfn_sort = self._getSortFunction(search);\n\t\tif (fn_sort) search.items.sort(fn_sort);\n\n\t\t// apply limits\n\t\tsearch.total = search.items.length;\n\t\tif (typeof options.limit === 'number') {\n\t\t\tsearch.items = search.items.slice(0, options.limit);\n\t\t}\n\n\t\treturn search;\n\t};\n}\n"],"names":["code_points","asciifold","str","normalize","replace","toLowerCase","generateDiacritics","latin_convert","diacritics","forEach","code_range","i","diacritic","String","fromCharCode","latin","toUpperCase","diacriticRegexPoints","regex","hasOwnProperty","RegExp","getAttr","obj","name","getAttrNesting","names","split","length","shift","scoreValue","value","token","weight","score","pos","search","string","escape_regex","propToArray","key","Array","isArray","iterate","object","callback","cmp","a","b","Sifter","constructor","items","settings","tokenize","query","respect_word_boundaries","weights","tokens","words","field_regex","Object","keys","map","join","word","field_match","field","match","push","getScoreFunction","options","prepareSearch","_getScoreFunction","token_count","fields","field_count","getAttrFn","scoreObject","data","sum","conjunction","getSortFunction","_getSortFunction","n","self","sort_fld","sort_flds","sort_flds_count","multiplier","multipliers","get_field","implicit_score","sort","sort_empty","result","id","unshift","direction","splice","optsUser","assign","fld_name","field_params","trim","total","nesting","fn_sort","fn_score","item","filter","limit","slice"],"mappings":"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"} \ No newline at end of file diff --git a/dist/umd/sifter.min.js b/dist/umd/sifter.min.js new file mode 100644 index 0000000..e7a1b12 --- /dev/null +++ b/dist/umd/sifter.min.js @@ -0,0 +1,53 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).sifter=t()}(this,(function(){"use strict" +var e=[[67,67],[160,160],[192,438],[452,652],[961,961],[1019,1019],[1083,1083],[1281,1289],[1984,1984],[5095,5095],[7429,7441],[7545,7549],[7680,7935],[8580,8580],[9398,9449],[11360,11391],[42792,42793],[42802,42851],[42873,42897],[42912,42922],[64256,64260],[65313,65338],[65345,65370]] +function t(e){return e.normalize("NFD").replace(/[\u0300-\u036F]/g,"").normalize("NFKD").toLowerCase()}var r=null +function n(t){null===r&&(r=function(){var t={"l·":"l","ʼn":"n","æ":"ae","ø":"o","aʾ":"a","dž":"dz"},r={} +return e.forEach((e=>{for(let n=e[0];n<=e[1];n++){let e=String.fromCharCode(n),i=e.normalize("NFD").replace(/[\u0300-\u036F]/g,"").normalize("NFKD") +i!=e&&(i=i.toLowerCase(),i in t&&(i=t[i]),i in r||(r[i]=i+i.toUpperCase()),r[i]+=e)}})),r}()) +for(let e in r)r.hasOwnProperty(e)&&(t=t.replace(new RegExp(e,"g"),"["+r[e]+"]")) +return t}function i(e,t){if(e)return e[t]}function o(e,t){if(e){for(var r=t.split(".");r.length&&(e=e[r.shift()]););return e}}function s(e,t,r){var n,i +return e?-1===(i=(e=String(e||"")).search(t.regex))?0:(n=t.string.length/e.length,0===i&&(n+=.5),n*r):0}function u(e){return(e+"").replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}function f(e,t){var r=e[t] +r&&!Array.isArray(r)&&(e[t]=[r])}function c(e,t){if(Array.isArray(e))e.forEach(t) +else for(var r in e)e.hasOwnProperty(r)&&t(e[r],r)}function l(e,r){return"number"==typeof e&&"number"==typeof r?e>r?1:e(r=t(String(r||"")).toLowerCase())?1:r>e?-1:0} +/** + * sifter.js + * Copyright (c) 2013–2020 Brian Reavis & contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + * ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + * + * @author Brian Reavis + */return class{constructor(e,t){this.items=void 0,this.settings=void 0,this.items=e,this.settings=t||{diacritics:!0}}tokenize(e,t,r){if(!e||!e.length)return[] +var i,o=[],s=e.split(/\s+/) +return r&&(i=new RegExp("^("+Object.keys(r).map(u).join("|")+"):(.*)$")),s.forEach((e=>{let r,s=null,f=null +i&&(r=e.match(i))&&(s=r[1],e=r[2]),e.length>0&&(f=u(e),this.settings.diacritics&&(f=n(f)),t&&(f="\\b"+f),f=new RegExp(f,"i")),o.push({string:e,regex:f,field:s})})),o}getScoreFunction(e,t){var r=this.prepareSearch(e,t) +return this._getScoreFunction(r)}_getScoreFunction(e){const t=e.tokens,r=t.length +if(!r)return function(){return 0} +const n=e.options.fields,i=e.weights,o=n.length,u=e.getAttrFn +var f=o?1===o?function(e,t){const r=n[0].field +return s(u(t,r),e,i[r])}:function(e,t){var r=0 +if(e.field){const n=u(t,e.field) +!e.regex&&n?r+=.1:r+=s(n,e,i[e.field])}else c(i,((n,i)=>{r+=s(u(t,i),e,n)})) +return r/o}:function(){return 0} +return 1===r?function(e){return f(t[0],e)}:"and"===e.options.conjunction?function(e){for(var n,i=0,o=0;i{n+=f(t,e)})),n/r}}getSortFunction(e,t){var r=this.prepareSearch(e,t) +return this._getSortFunction(r)}_getSortFunction(e){var t,r,n,i,o,s,u,f,c,a,h,g +if(n=this,g=e.options,h=!e.query&&g.sort_empty||g.sort,c=function(t,r){return"$score"===t?r.score:e.getAttrFn(n.items[r.id],t)},o=[],h)for(t=0,r=h.length;t{u.push({field:e})})),s.fields=u}s.fields.forEach((e=>{n[e.field]="weight"in e?e.weight:1}))}return{options:s,query:e=t(String(e||"")).toLowerCase().trim(),tokens:this.tokenize(e,s.respect_word_boundaries,n),total:0,items:[],weights:n,getAttrFn:s.nesting?o:i}}search(e,t){var r,n,i,o,s=this +return n=this.prepareSearch(e,t),t=n.options,e=n.query,o=t.score||s._getScoreFunction(n),e.length?c(s.items,((e,i)=>{r=o(e),(!1===t.filter||r>0)&&n.items.push({score:r,id:i})})):c(s.items,((e,t)=>{n.items.push({score:1,id:t})})),(i=s._getSortFunction(n))&&n.items.sort(i),n.total=n.items.length,"number"==typeof t.limit&&(n.items=n.items.slice(0,t.limit)),n}}})) +//# sourceMappingURL=sifter.min.js.map diff --git a/dist/umd/sifter.min.js.map b/dist/umd/sifter.min.js.map new file mode 100644 index 0000000..b5a31d8 --- /dev/null +++ b/dist/umd/sifter.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sifter.min.js","sources":["../../lib/diacritics.ts","../../lib/utils.ts","../../lib/sifter.ts"],"sourcesContent":["\ntype TDiacraticList = {[key:string]:string};\n\n// https://github.com/andrewrk/node-diacritics/blob/master/index.js\nvar DIACRITICS:TDiacraticList = {\n\t\" \":\" \",\n\t0:\"߀\",\n\tA:\"ⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ\",\n\tAA:\"Ꜳ\",\n\tAE:\"ÆǼǢ\",\n\tAO:\"Ꜵ\",\n\tAU:\"Ꜷ\",\n\tAV:\"ꜸꜺ\",\n\tAY:\"Ꜽ\",\n\tB:\"ⒷBḂḄḆɃƁ\",\n\tC:\"ⒸCꜾḈĆCĈĊČÇƇȻ\",\n\tD:\"ⒹDḊĎḌḐḒḎĐƊƉᴅꝹ\",\n\tDh:\"Ð\",\n\tDZ:\"DZDŽ\",\n\tDz:\"DzDž\",\n\tE:\"ɛⒺEÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚƐƎᴇ\",\n\tF:\"ꝼⒻFḞƑꝻ\",\n\tG:\"ⒼGǴĜḠĞĠǦĢǤƓꞠꝽꝾɢ\",\n\tH:\"ⒽHĤḢḦȞḤḨḪĦⱧⱵꞍ\",\n\tI:\"ⒾIÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬƗ\",\n\tJ:\"ⒿJĴɈȷ\",\n\tK:\"ⓀKḰǨḲĶḴƘⱩꝀꝂꝄꞢ\",\n\tL:\"ⓁLĿĹĽḶḸĻḼḺŁȽⱢⱠꝈꝆꞀ\",\n\tLJ:\"LJ\",\n\tLj:\"Lj\",\n\tM:\"ⓂMḾṀṂⱮƜϻ\",\n\tN:\"ꞤȠⓃNǸŃÑṄŇṆŅṊṈƝꞐᴎ\",\n\tNJ:\"NJ\",\n\tNj:\"Nj\",\n\tO:\"ⓄOÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘǪǬØǾƆƟꝊꝌ\",\n\tOE:\"Œ\",\n\tOI:\"Ƣ\",\n\tOO:\"Ꝏ\",\n\tOU:\"Ȣ\",\n\tP:\"ⓅPṔṖƤⱣꝐꝒꝔ\",\n\tQ:\"ⓆQꝖꝘɊ\",\n\tR:\"ⓇRŔṘŘȐȒṚṜŖṞɌⱤꝚꞦꞂ\",\n\tS:\"ⓈSẞŚṤŜṠŠṦṢṨȘŞⱾꞨꞄ\",\n\tT:\"ⓉTṪŤṬȚŢṰṮŦƬƮȾꞆ\",\n\tTh:\"Þ\",\n\tTZ:\"Ꜩ\",\n\tU:\"ⓊUÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴɄ\",\n\tV:\"ⓋVṼṾƲꝞɅ\",\n\tVY:\"Ꝡ\",\n\tW:\"ⓌWẀẂŴẆẄẈⱲ\",\n\tX:\"ⓍXẊẌ\",\n\tY:\"ⓎYỲÝŶỸȲẎŸỶỴƳɎỾ\",\n\tZ:\"ⓏZŹẐŻŽẒẔƵȤⱿⱫꝢ\",\n\ta:\"ⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑ\",\n\taa:\"ꜳ\",\n\tae:\"æǽǣ\",\n\tao:\"ꜵ\",\n\tau:\"ꜷ\",\n\tav:\"ꜹꜻ\",\n\tay:\"ꜽ\",\n\tb:\"ⓑbḃḅḇƀƃɓƂ\",\n\tc:\"cⓒćĉċčçḉƈȼꜿↄ\",\n\td:\"ⓓdḋďḍḑḓḏđƌɖɗƋᏧԁꞪ\",\n\tdh:\"ð\",\n\tdz:\"dzdž\",\n\te:\"ⓔeèéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛɇǝ\",\n\tf:\"ⓕfḟƒ\",\n\tff:\"ff\",\n\tfi:\"fi\",\n\tfl:\"fl\",\n\tffi:\"ffi\",\n\tffl:\"ffl\",\n\tg:\"ⓖgǵĝḡğġǧģǥɠꞡꝿᵹ\",\n\th:\"ⓗhĥḣḧȟḥḩḫẖħⱨⱶɥ\",\n\thv:\"ƕ\",\n\ti:\"ⓘiìíîĩīĭïḯỉǐȉȋịįḭɨı\",\n\tj:\"ⓙjĵǰɉ\",\n\tk:\"ⓚkḱǩḳķḵƙⱪꝁꝃꝅꞣ\",\n\tl:\"ⓛlŀĺľḷḹļḽḻſłƚɫⱡꝉꞁꝇɭ\",\n\tlj:\"lj\",\n\tm:\"ⓜmḿṁṃɱɯ\",\n\tn:\"ⓝnǹńñṅňṇņṋṉƞɲʼnꞑꞥлԉ\",\n\tnj:\"nj\",\n\to:\"ⓞoòóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộǫǭøǿꝋꝍɵɔᴑ\",\n\toe:\"œ\",\n\toi:\"ƣ\",\n\too:\"ꝏ\",\n\tou:\"ȣ\",\n\tp:\"ⓟpṕṗƥᵽꝑꝓꝕρ\",\n\tq:\"ⓠqɋꝗꝙ\",\n\tr:\"ⓡrŕṙřȑȓṛṝŗṟɍɽꝛꞧꞃ\",\n\ts:\"ⓢsśṥŝṡšṧṣṩșşȿꞩꞅẛʂ\",\n\tss:\"ß\",\n\tt:\"ⓣtṫẗťṭțţṱṯŧƭʈⱦꞇ\",\n\tth:\"þ\",\n\ttz:\"ꜩ\",\n\tu:\"ⓤuùúûũṹūṻŭüǜǘǖǚủůűǔȕȗưừứữửựụṳųṷṵʉ\",\n\tv:\"ⓥvṽṿʋꝟʌ\",\n\tvy:\"ꝡ\",\n\tw:\"ⓦwẁẃŵẇẅẘẉⱳ\",\n\tx:\"ⓧxẋẍ\",\n\ty:\"ⓨyỳýŷỹȳẏÿỷẙỵƴɏỿ\",\n\tz:\"ⓩzźẑżžẓẕƶȥɀⱬꝣ\"\n}\n\n/**\n * code points generated from toCodePoints();\n * removed 65339 to 65345\n */\nvar code_points = [\n\t[ 67, 67 ],\n\t[ 160, 160 ],\n\t[ 192, 438 ],\n\t[ 452, 652 ],\n\t[ 961, 961 ],\n\t[ 1019, 1019 ],\n\t[ 1083, 1083 ],\n\t[ 1281, 1289 ],\n\t[ 1984, 1984 ],\n\t[ 5095, 5095 ],\n\t[ 7429, 7441 ],\n\t[ 7545, 7549 ],\n\t[ 7680, 7935 ],\n\t[ 8580, 8580 ],\n\t[ 9398, 9449 ],\n\t[ 11360, 11391 ],\n\t[ 42792, 42793 ],\n\t[ 42802, 42851 ],\n\t[ 42873, 42897 ],\n\t[ 42912, 42922 ],\n\t[ 64256, 64260 ],\n\t[ 65313, 65338 ],\n\t[ 65345, 65370 ]\n];\n\n/**\n * Remove accents\n * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703\n *\n */\nexport function asciifold(str:string):string{\n\treturn str.normalize('NFD').replace(/[\\u0300-\\u036F]/g, '').normalize('NFKD').toLowerCase();\n};\n\n\n/**\n * Convert list of diacritics to array of code points\n *\n */\n// @ts-ignore\nfunction toCodePoints(tolerance=8){\n\tvar char_codes = [];\n\n\tfor( let letter in DIACRITICS ){\n\t\tlet _diacritics = DIACRITICS[letter];\n\t\tfor( let n = 0; n < _diacritics.length; n++ ){\n\t\t\tvar code_point = _diacritics.codePointAt(n);\n\t\t\tchar_codes.push( code_point );\n\t\t}\n\t}\n\n\t//https://stackoverflow.com/questions/40431572/is-there-a-simple-way-to-group-js-array-values-by-range\n\tchar_codes.sort((a, b) => a - b);\n var result = char_codes.reduce(function (accumulator, currentValue, index, source) {\n\n\t\tif( !index ){\n\t\t\taccumulator.push( [currentValue,currentValue] );\n\n\t\t}else if( currentValue - source[index - 1] > tolerance ){\n\t\t\taccumulator.push( [currentValue,currentValue] );\n\n\t\t}else{\n\n\t\t\taccumulator.push( [accumulator.pop()[0],currentValue]);\n\t\t}\n\n return accumulator;\n }, []);\n\n\tconsole.log(`char_codes (${result.length})`,result);\n}\n\n/**\n * Generate a list of diacritics from the list of code points\n *\n */\nexport function generateDiacritics():TDiacraticList{\n\n\tvar latin_convert = {\n\t\t'l·': 'l',\n\t\t'ʼn': 'n',\n\t\t'æ': 'ae',\n\t\t'ø': 'o',\n\t\t'aʾ': 'a',\n\t\t'dž': 'dz',\n\t};\n\n\tvar diacritics\t= {};\n\t//var no_latin\t= [];\n\tcode_points.forEach((code_range)=>{\n\n\t\tfor(let i = code_range[0]; i <= code_range[1]; i++){\n\t\t\tlet diacritic\t= String.fromCharCode(i);\n\t\t\tlet latin\t\t= diacritic.normalize('NFD').replace(/[\\u0300-\\u036F]/g, '').normalize('NFKD');\n\n\t\t\tif( latin == diacritic ){\n\t\t\t\t//no_latin.push(diacritic);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlatin = latin.toLowerCase();\n\n\t\t\tif( latin in latin_convert ){\n\t\t\t\tlatin = latin_convert[latin];\n\t\t\t}\n\n\t\t\tif( !(latin in diacritics) ){\n\t\t\t\tdiacritics[latin] = latin + latin.toUpperCase();\n\t\t\t}\n\t\t\tdiacritics[latin] += diacritic;\n\t\t}\n\t});\n\n\t//console.log('no_latin',JSON.stringify(no_latin));\n\n\treturn diacritics;\n}\n\n/**\n * Expand a regular expression pattern to include diacritics\n * \teg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/\n *\n */\nvar diacritics:TDiacraticList = null\nexport function diacriticRegexPoints(regex:string):string{\n\n\tif( diacritics === null ){\n\t\tdiacritics = generateDiacritics();\n\t}\n\n\tfor( let latin in diacritics ){\n\t\tif( diacritics.hasOwnProperty(latin) ){\n\t\t\tregex = regex.replace( new RegExp(latin,'g'), '['+diacritics[latin]+']');\n\t\t}\n\t}\n\treturn regex;\n}\n\n\n/**\n * Expand a regular expression pattern to include diacritics\n * \teg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/\n *\n * rollup will bundle this function (and the DIACRITICS constant) unless commented out\n *\nvar diacriticRegex = (function() {\n\n\tvar list = [];\n\tfor( let letter in DIACRITICS ){\n\n\t\tif( letter.toLowerCase() != letter && letter.toLowerCase() in DIACRITICS ){\n\t\t\tcontinue;\n\t\t}\n\n\t\tif( DIACRITICS.hasOwnProperty(letter) ){\n\n\t\t\tvar replace = letter + DIACRITICS[letter];\n\t\t\tif( letter.toUpperCase() in DIACRITICS ){\n\t\t\t\treplace += letter.toUpperCase() + DIACRITICS[letter.toUpperCase()];\n\t\t\t}\n\n\t\t\tlist.push({let:letter,pat:'['+replace+']'});\n\t\t}\n\t}\n\n\treturn function(regex:string):string{\n\t\tlist.forEach((item)=>{\n\t\t\tregex = regex.replace( new RegExp(item.let,'g'),item.pat);\n\t\t});\n\t\treturn regex;\n\t}\n})();\n*/\n","\n// @ts-ignore\nimport { asciifold } from './diacritics.ts';\n\n/**\n * A property getter resolving dot-notation\n * @param {Object} obj The root object to fetch property on\n * @param {String} name The optionally dotted property name to fetch\n * @return {Object} The resolved property value\n */\nexport function getAttr(obj:{[key:string]:any}, name:string ) {\n if (!obj ) return;\n return obj[name];\n};\n\n/**\n * A property getter resolving dot-notation\n * @param {Object} obj The root object to fetch property on\n * @param {String} name The optionally dotted property name to fetch\n * @return {Object} The resolved property value\n */\nexport function getAttrNesting(obj:{[key:string]:any}, name:string ) {\n if (!obj ) return;\n var names = name.split(\".\");\n while(names.length && (obj = obj[names.shift()]));\n return obj;\n};\n\n/**\n * Calculates how close of a match the\n * given value is against a search token.\n *\n * @param {object} token\n * @return {number}\n */\nexport function scoreValue(value:string, token, weight:number ) {\n\tvar score, pos;\n\n\tif (!value) return 0;\n\n\tvalue = String(value || '');\n\tpos = value.search(token.regex);\n\tif (pos === -1) return 0;\n\n\tscore = token.string.length / value.length;\n\tif (pos === 0) score += 0.5;\n\n\treturn score * weight;\n};\n\nexport function escape_regex(str) {\n\treturn (str + '').replace(/([.?*+^$[\\]\\\\(){}|-])/g, '\\\\$1');\n};\n\n\n/**\n * Cast object property to an array if it exists and has a value\n *\n */\nexport function propToArray(obj, key){\n\tvar value = obj[key];\n\tif( value && !Array.isArray(value) ){\n\t\tobj[key] = [value];\n\t}\n}\n\n\n/**\n * Iterates over arrays and hashes.\n *\n * ```\n * iterate(this.items, function(item, id) {\n * // invoked for each item\n * });\n * ```\n *\n * @param {array|object} object\n */\nexport function iterate(object, callback) {\n\n\tif ( Array.isArray(object)) {\n\t\tobject.forEach(callback);\n\n\t}else{\n\n\t\tfor (var key in object) {\n\t\t\tif (object.hasOwnProperty(key)) {\n\t\t\t\tcallback(object[key], key);\n\t\t\t}\n\t\t}\n\t}\n};\n\n\n\nexport function cmp(a, b) {\n\tif (typeof a === 'number' && typeof b === 'number') {\n\t\treturn a > b ? 1 : (a < b ? -1 : 0);\n\t}\n\ta = asciifold(String(a || '')).toLowerCase();\n\tb = asciifold(String(b || '')).toLowerCase();\n\tif (a > b) return 1;\n\tif (b > a) return -1;\n\treturn 0;\n};\n","/**\n * sifter.js\n * Copyright (c) 2013–2020 Brian Reavis & contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n * file except in compliance with the License. You may obtain a copy of the License at:\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n * ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n *\n * @author Brian Reavis \n */\n\n// @ts-ignore\nimport { scoreValue, getAttr, getAttrNesting, escape_regex, propToArray, iterate, cmp } from './utils.ts';\n// @ts-ignore\nimport { diacriticRegexPoints, asciifold } from './diacritics.ts';\n\n\ntype TField = {\n\tfield: string,\n\tweight?: number,\n}\n\ntype TOptions = {\n \tfields: TField[],\n \tsort: any[],\n \tscore?: ()=>any,\n \tfilter?: boolean,\n \tlimit?: number,\n \tsort_empty?: any,\n \tnesting?: boolean,\n\trespect_word_boundaries?: boolean,\n\tconjunction?: string,\n}\n\ntype TToken = {\n\tstring:string,\n\tregex:RegExp,\n\tfield:string\n}\n\ntype TWeights = {[key:string]:number}\n\ntype TPrepareObj = {\n\toptions: TOptions,\n\tquery: string,\n\ttokens: TToken[],\n\ttotal: number,\n\titems: any[],\n\tweights: TWeights,\n\tgetAttrFn: (any,string)=>any,\n\n}\n\n\nexport default class Sifter{\n\n\tpublic items: []|{};\n\tpublic settings: {diacritics:boolean};\n\n\t/**\n\t * Textually searches arrays and hashes of objects\n\t * by property (or multiple properties). Designed\n\t * specifically for autocomplete.\n\t *\n\t * @constructor\n\t * @param {array|object} items\n\t * @param {object} items\n\t */\n\tconstructor(items, settings) {\n\t\tthis.items = items;\n\t\tthis.settings = settings || {diacritics: true};\n\t};\n\n\t/**\n\t * Splits a search string into an array of individual\n\t * regexps to be used to match results.\n\t *\n\t */\n\ttokenize(query:string, respect_word_boundaries?:boolean, weights?:TWeights ):TToken[] {\n\t\tif (!query || !query.length) return [];\n\n\t\tvar tokens = [];\n\t\tvar words = query.split(/\\s+/);\n\t\tvar field_regex;\n\n\t\tif( weights ){\n\t\t\tfield_regex = new RegExp( '^('+ Object.keys(weights).map(escape_regex).join('|')+')\\:(.*)$');\n\t\t}\n\n\t\twords.forEach((word:string) => {\n\t\t\tlet field_match;\n\t\t\tlet field\t= null;\n\t\t\tlet regex\t= null;\n\n\t\t\t// look for \"field:query\" tokens\n\t\t\tif( field_regex && (field_match = word.match(field_regex)) ){\n\t\t\t\tfield\t= field_match[1];\n\t\t\t\tword\t= field_match[2];\n\t\t\t}\n\n\t\t\tif( word.length > 0 ){\n\t\t\t\tregex = escape_regex(word);\n\t\t\t\tif( this.settings.diacritics ){\n\t\t\t\t\tregex = diacriticRegexPoints(regex);\n\t\t\t\t}\n\t\t\t\tif( respect_word_boundaries ) regex = \"\\\\b\"+regex\n\t\t\t\tregex = new RegExp(regex, 'i');\n\t\t\t}\n\n\t\t\ttokens.push({\n\t\t\t\tstring : word,\n\t\t\t\tregex : regex,\n\t\t\t\tfield : field,\n\t\t\t});\n\t\t});\n\n\t\treturn tokens;\n\t};\n\n\n\t/**\n\t * Returns a function to be used to score individual results.\n\t *\n\t * Good matches will have a higher score than poor matches.\n\t * If an item is not a match, 0 will be returned by the function.\n\t *\n\t * @returns {function}\n\t */\n\tgetScoreFunction(query:string, options ){\n\t\tvar search = this.prepareSearch(query, options);\n\t\treturn this._getScoreFunction(search);\n\t}\n\n\t_getScoreFunction(search:TPrepareObj ){\n\t\tconst tokens\t\t= search.tokens,\n\t\ttoken_count\t\t\t= tokens.length;\n\n\t\tif (!token_count) {\n\t\t\treturn function() { return 0; };\n\t\t}\n\n\t\tconst fields\t= search.options.fields,\n\t\tweights\t\t\t= search.weights,\n\t\tfield_count\t\t= fields.length,\n\t\tgetAttrFn\t\t= search.getAttrFn;\n\n\n\n\t\t/**\n\t\t * Calculates the score of an object\n\t\t * against the search query.\n\t\t *\n\t\t * @param {TToken} token\n\t\t * @param {object} data\n\t\t * @return {number}\n\t\t */\n\t\tvar scoreObject = (function() {\n\n\t\t\tif (!field_count) {\n\t\t\t\treturn function() { return 0; };\n\t\t\t}\n\n\t\t\tif (field_count === 1) {\n\t\t\t\treturn function(token:TToken, data) {\n\t\t\t\t\tconst field = fields[0].field;\n\t\t\t\t\treturn scoreValue(getAttrFn(data, field), token, weights[field]);\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn function(token:TToken, data) {\n\t\t\t\tvar sum = 0;\n\n\t\t\t\t// is the token specific to a field?\n\t\t\t\tif( token.field ){\n\n\t\t\t\t\tconst value = getAttrFn(data, token.field);\n\n\t\t\t\t\tif( !token.regex && value ){\n\t\t\t\t\t\tsum += 0.1;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tsum += scoreValue(value, token, weights[token.field]);\n\t\t\t\t\t}\n\n\n\n\t\t\t\t}else{\n\t\t\t\t\titerate(weights, (weight, field) => {\n\t\t\t\t\t\tsum += scoreValue(getAttrFn(data, field), token, weight);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn sum / field_count;\n\t\t\t};\n\t\t})();\n\n\t\tif (token_count === 1) {\n\t\t\treturn function(data) {\n\t\t\t\treturn scoreObject(tokens[0], data);\n\t\t\t};\n\t\t}\n\n\t\tif (search.options.conjunction === 'and') {\n\t\t\treturn function(data) {\n\t\t\t\tvar i = 0, score, sum = 0;\n\t\t\t\tfor (; i < token_count; i++) {\n\t\t\t\t\tscore = scoreObject(tokens[i], data);\n\t\t\t\t\tif (score <= 0) return 0;\n\t\t\t\t\tsum += score;\n\t\t\t\t}\n\t\t\t\treturn sum / token_count;\n\t\t\t};\n\t\t} else {\n\t\t\treturn function(data) {\n\t\t\t\tvar sum = 0;\n\t\t\t\titerate(tokens,(token:TToken)=>{\n\t\t\t\t\tsum += scoreObject(token, data);\n\t\t\t\t});\n\t\t\t\treturn sum / token_count;\n\t\t\t};\n\t\t}\n\t};\n\n\t/**\n\t * Returns a function that can be used to compare two\n\t * results, for sorting purposes. If no sorting should\n\t * be performed, `null` will be returned.\n\t *\n\t * @return function(a,b)\n\t */\n\tgetSortFunction(query:string, options) {\n\t\tvar search = this.prepareSearch(query, options);\n\t\treturn this._getSortFunction(search);\n\t}\n\n\t_getSortFunction(search:TPrepareObj){\n\t\tvar i, n, self, sort_fld, sort_flds, sort_flds_count, multiplier, multipliers, get_field, implicit_score, sort, options;\n\n\t\tself\t\t= this;\n\t\toptions\t\t= search.options;\n\t\tsort\t\t= (!search.query && options.sort_empty) || options.sort;\n\n\t\t/**\n\t\t * Fetches the specified sort field value\n\t\t * from a search result item.\n\t\t *\n\t\t * @param {string} name\n\t\t * @param {object} result\n\t\t * @return {string}\n\t\t */\n\t\tget_field = function(name, result) {\n\t\t\tif (name === '$score') return result.score;\n\t\t\treturn search.getAttrFn(self.items[result.id], name);\n\t\t};\n\n\t\t// parse options\n\t\tsort_flds = [];\n\t\tif (sort) {\n\t\t\tfor (i = 0, n = sort.length; i < n; i++) {\n\t\t\t\tif (search.query || sort[i].field !== '$score') {\n\t\t\t\t\tsort_flds.push(sort[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// the \"$score\" field is implied to be the primary\n\t\t// sort field, unless it's manually specified\n\t\tif (search.query) {\n\t\t\timplicit_score = true;\n\t\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\t\tif (sort_flds[i].field === '$score') {\n\t\t\t\t\timplicit_score = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (implicit_score) {\n\t\t\t\tsort_flds.unshift({field: '$score', direction: 'desc'});\n\t\t\t}\n\t\t} else {\n\t\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\t\tif (sort_flds[i].field === '$score') {\n\t\t\t\t\tsort_flds.splice(i, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tmultipliers = [];\n\t\tfor (i = 0, n = sort_flds.length; i < n; i++) {\n\t\t\tmultipliers.push(sort_flds[i].direction === 'desc' ? -1 : 1);\n\t\t}\n\n\t\t// build function\n\t\tsort_flds_count = sort_flds.length;\n\t\tif (!sort_flds_count) {\n\t\t\treturn null;\n\t\t} else if (sort_flds_count === 1) {\n\t\t\tsort_fld = sort_flds[0].field;\n\t\t\tmultiplier = multipliers[0];\n\t\t\treturn function(a, b) {\n\t\t\t\treturn multiplier * cmp(\n\t\t\t\t\tget_field(sort_fld, a),\n\t\t\t\t\tget_field(sort_fld, b)\n\t\t\t\t);\n\t\t\t};\n\t\t} else {\n\t\t\treturn function(a, b) {\n\t\t\t\tvar i, result, field;\n\t\t\t\tfor (i = 0; i < sort_flds_count; i++) {\n\t\t\t\t\tfield = sort_flds[i].field;\n\t\t\t\t\tresult = multipliers[i] * cmp(\n\t\t\t\t\t\tget_field(field, a),\n\t\t\t\t\t\tget_field(field, b)\n\t\t\t\t\t);\n\t\t\t\t\tif (result) return result;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t};\n\t\t}\n\t};\n\n\t/**\n\t * Parses a search query and returns an object\n\t * with tokens and fields ready to be populated\n\t * with results.\n\t *\n\t */\n\tprepareSearch(query:string, optsUser):TPrepareObj {\n\t\tconst weights\t= {};\n\t\tvar options\t\t= Object.assign({},optsUser);\n\n\t\tpropToArray(options,'sort');\n\t\tpropToArray(options,'sort_empty');\n\n\t\t// convert fields to new format\n\t\tif( options.fields ){\n\t\t\tpropToArray(options,'fields');\n\t\t\tif( Array.isArray(options.fields) && typeof options.fields[0] !== 'object' ){\n\t\t\t\tvar fields = [];\n\t\t\t\toptions.fields.forEach((fld_name) => {\n\t\t\t\t\tfields.push({field:fld_name});\n\t\t\t\t});\n\t\t\t\toptions.fields = fields;\n\t\t\t}\n\n\n\t\t\toptions.fields.forEach((field_params)=>{\n\t\t\t\tweights[field_params.field] = ('weight' in field_params) ? field_params.weight : 1;\n\t\t\t});\n\t\t}\n\n\t\tquery = asciifold( String(query || '') ).toLowerCase().trim();\n\n\t\treturn {\n\t\t\toptions\t\t: options,\n\t\t\tquery\t\t: query,\n\t\t\ttokens\t\t: this.tokenize(query, options.respect_word_boundaries, weights),\n\t\t\ttotal\t\t: 0,\n\t\t\titems\t\t: [],\n\t\t\tweights\t\t: weights,\n\t\t\tgetAttrFn\t: (options.nesting) ? getAttrNesting : getAttr,\n\t\t};\n\t};\n\n\t/**\n\t * Searches through all items and returns a sorted array of matches.\n\t *\n\t */\n\tsearch(query:string, options:TOptions) : TPrepareObj {\n\t\tvar self = this, score, search;\n\t\tvar fn_sort;\n\t\tvar fn_score;\n\n\t\tsearch = this.prepareSearch(query, options);\n\t\toptions = search.options;\n\t\tquery = search.query;\n\n\t\t// generate result scoring function\n\t\tfn_score = options.score || self._getScoreFunction(search);\n\n\t\t// perform search and sort\n\t\tif (query.length) {\n\t\t\titerate(self.items, (item, id) => {\n\t\t\t\tscore = fn_score(item);\n\t\t\t\tif (options.filter === false || score > 0) {\n\t\t\t\t\tsearch.items.push({'score': score, 'id': id});\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\titerate(self.items, (item, id) => {\n\t\t\t\tsearch.items.push({'score': 1, 'id': id});\n\t\t\t});\n\t\t}\n\n\t\tfn_sort = self._getSortFunction(search);\n\t\tif (fn_sort) search.items.sort(fn_sort);\n\n\t\t// apply limits\n\t\tsearch.total = search.items.length;\n\t\tif (typeof options.limit === 'number') {\n\t\t\tsearch.items = search.items.slice(0, options.limit);\n\t\t}\n\n\t\treturn search;\n\t};\n}\n"],"names":["code_points","asciifold","str","normalize","replace","toLowerCase","diacritics","diacriticRegexPoints","regex","latin_convert","forEach","code_range","i","diacritic","String","fromCharCode","latin","toUpperCase","generateDiacritics","hasOwnProperty","RegExp","getAttr","obj","name","getAttrNesting","names","split","length","shift","scoreValue","value","token","weight","score","pos","search","string","escape_regex","propToArray","key","Array","isArray","iterate","object","callback","cmp","a","b","constructor","items","settings","tokenize","query","respect_word_boundaries","weights","field_regex","tokens","words","Object","keys","map","join","word","field_match","field","match","this","push","getScoreFunction","options","prepareSearch","_getScoreFunction","token_count","fields","field_count","getAttrFn","scoreObject","data","sum","conjunction","getSortFunction","_getSortFunction","n","self","sort_fld","sort_flds","sort_flds_count","multiplier","multipliers","get_field","implicit_score","sort","sort_empty","result","id","unshift","direction","splice","optsUser","assign","fld_name","field_params","trim","total","nesting","fn_sort","fn_score","item","filter","limit","slice"],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json index 9edca99..5f8aa5f 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "autocomplete" ], "description": "A library for textually searching arrays and hashes of objects by property (or multiple properties). Designed specifically for autocomplete.", - "version": "0.6.0", + "version": "0.7.0", "license": "Apache-2.0", "author": "Brian Reavis ", "main": "dist/umd/sifter.js",