1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', { value: true });
|
4 |
|
5 | var _extends = require('@babel/runtime/helpers/extends');
|
6 | var removeAccents = require('remove-accents');
|
7 |
|
8 | function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
9 |
|
10 | var _extends__default = _interopDefaultLegacy(_extends);
|
11 | var removeAccents__default = _interopDefaultLegacy(removeAccents);
|
12 |
|
13 | var rankings = {
|
14 | CASE_SENSITIVE_EQUAL: 7,
|
15 | EQUAL: 6,
|
16 | STARTS_WITH: 5,
|
17 | WORD_STARTS_WITH: 4,
|
18 | CONTAINS: 3,
|
19 | ACRONYM: 2,
|
20 | MATCHES: 1,
|
21 | NO_MATCH: 0
|
22 | };
|
23 | matchSorter.rankings = rankings;
|
24 |
|
25 | var defaultBaseSortFn = function defaultBaseSortFn(a, b) {
|
26 | return String(a.rankedValue).localeCompare(String(b.rankedValue));
|
27 | };
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | function matchSorter(items, value, options) {
|
38 | if (options === void 0) {
|
39 | options = {};
|
40 | }
|
41 |
|
42 | var _options = options,
|
43 | keys = _options.keys,
|
44 | _options$threshold = _options.threshold,
|
45 | threshold = _options$threshold === void 0 ? rankings.MATCHES : _options$threshold,
|
46 | _options$baseSort = _options.baseSort,
|
47 | baseSort = _options$baseSort === void 0 ? defaultBaseSortFn : _options$baseSort,
|
48 | _options$sorter = _options.sorter,
|
49 | sorter = _options$sorter === void 0 ? function (matchedItems) {
|
50 | return matchedItems.sort(function (a, b) {
|
51 | return sortRankedValues(a, b, baseSort);
|
52 | });
|
53 | } : _options$sorter;
|
54 | var matchedItems = items.reduce(reduceItemsToRanked, []);
|
55 | return sorter(matchedItems).map(function (_ref) {
|
56 | var item = _ref.item;
|
57 | return item;
|
58 | });
|
59 |
|
60 | function reduceItemsToRanked(matches, item, index) {
|
61 | var rankingInfo = getHighestRanking(item, keys, value, options);
|
62 | var rank = rankingInfo.rank,
|
63 | _rankingInfo$keyThres = rankingInfo.keyThreshold,
|
64 | keyThreshold = _rankingInfo$keyThres === void 0 ? threshold : _rankingInfo$keyThres;
|
65 |
|
66 | if (rank >= keyThreshold) {
|
67 | matches.push(_extends__default['default']({}, rankingInfo, {
|
68 | item: item,
|
69 | index: index
|
70 | }));
|
71 | }
|
72 |
|
73 | return matches;
|
74 | }
|
75 | }
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 | function getHighestRanking(item, keys, value, options) {
|
87 | if (!keys) {
|
88 |
|
89 | var stringItem = item;
|
90 | return {
|
91 |
|
92 | rankedValue: stringItem,
|
93 | rank: getMatchRanking(stringItem, value, options),
|
94 | keyIndex: -1,
|
95 | keyThreshold: options.threshold
|
96 | };
|
97 | }
|
98 |
|
99 | var valuesToRank = getAllValuesToRank(item, keys);
|
100 | return valuesToRank.reduce(function (_ref2, _ref3, i) {
|
101 | var rank = _ref2.rank,
|
102 | rankedValue = _ref2.rankedValue,
|
103 | keyIndex = _ref2.keyIndex,
|
104 | keyThreshold = _ref2.keyThreshold;
|
105 | var itemValue = _ref3.itemValue,
|
106 | attributes = _ref3.attributes;
|
107 | var newRank = getMatchRanking(itemValue, value, options);
|
108 | var newRankedValue = rankedValue;
|
109 | var minRanking = attributes.minRanking,
|
110 | maxRanking = attributes.maxRanking,
|
111 | threshold = attributes.threshold;
|
112 |
|
113 | if (newRank < minRanking && newRank >= rankings.MATCHES) {
|
114 | newRank = minRanking;
|
115 | } else if (newRank > maxRanking) {
|
116 | newRank = maxRanking;
|
117 | }
|
118 |
|
119 | if (newRank > rank) {
|
120 | rank = newRank;
|
121 | keyIndex = i;
|
122 | keyThreshold = threshold;
|
123 | newRankedValue = itemValue;
|
124 | }
|
125 |
|
126 | return {
|
127 | rankedValue: newRankedValue,
|
128 | rank: rank,
|
129 | keyIndex: keyIndex,
|
130 | keyThreshold: keyThreshold
|
131 | };
|
132 | }, {
|
133 | rankedValue: item,
|
134 | rank: rankings.NO_MATCH,
|
135 | keyIndex: -1,
|
136 | keyThreshold: options.threshold
|
137 | });
|
138 | }
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 | function getMatchRanking(testString, stringToRank, options) {
|
149 | testString = prepareValueForComparison(testString, options);
|
150 | stringToRank = prepareValueForComparison(stringToRank, options);
|
151 |
|
152 | if (stringToRank.length > testString.length) {
|
153 | return rankings.NO_MATCH;
|
154 | }
|
155 |
|
156 |
|
157 | if (testString === stringToRank) {
|
158 | return rankings.CASE_SENSITIVE_EQUAL;
|
159 | }
|
160 |
|
161 |
|
162 | testString = testString.toLowerCase();
|
163 | stringToRank = stringToRank.toLowerCase();
|
164 |
|
165 | if (testString === stringToRank) {
|
166 | return rankings.EQUAL;
|
167 | }
|
168 |
|
169 |
|
170 | if (testString.startsWith(stringToRank)) {
|
171 | return rankings.STARTS_WITH;
|
172 | }
|
173 |
|
174 |
|
175 | if (testString.includes(" " + stringToRank)) {
|
176 | return rankings.WORD_STARTS_WITH;
|
177 | }
|
178 |
|
179 |
|
180 | if (testString.includes(stringToRank)) {
|
181 | return rankings.CONTAINS;
|
182 | } else if (stringToRank.length === 1) {
|
183 |
|
184 |
|
185 |
|
186 | return rankings.NO_MATCH;
|
187 | }
|
188 |
|
189 |
|
190 | if (getAcronym(testString).includes(stringToRank)) {
|
191 | return rankings.ACRONYM;
|
192 | }
|
193 |
|
194 |
|
195 |
|
196 | return getClosenessRanking(testString, stringToRank);
|
197 | }
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 | function getAcronym(string) {
|
207 | var acronym = '';
|
208 | var wordsInString = string.split(' ');
|
209 | wordsInString.forEach(function (wordInString) {
|
210 | var splitByHyphenWords = wordInString.split('-');
|
211 | splitByHyphenWords.forEach(function (splitByHyphenWord) {
|
212 | acronym += splitByHyphenWord.substr(0, 1);
|
213 | });
|
214 | });
|
215 | return acronym;
|
216 | }
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 | function getClosenessRanking(testString, stringToRank) {
|
230 | var matchingInOrderCharCount = 0;
|
231 | var charNumber = 0;
|
232 |
|
233 | function findMatchingCharacter(matchChar, string, index) {
|
234 | for (var j = index, J = string.length; j < J; j++) {
|
235 | var stringChar = string[j];
|
236 |
|
237 | if (stringChar === matchChar) {
|
238 | matchingInOrderCharCount += 1;
|
239 | return j + 1;
|
240 | }
|
241 | }
|
242 |
|
243 | return -1;
|
244 | }
|
245 |
|
246 | function getRanking(spread) {
|
247 | var spreadPercentage = 1 / spread;
|
248 | var inOrderPercentage = matchingInOrderCharCount / stringToRank.length;
|
249 | var ranking = rankings.MATCHES + inOrderPercentage * spreadPercentage;
|
250 | return ranking;
|
251 | }
|
252 |
|
253 | var firstIndex = findMatchingCharacter(stringToRank[0], testString, 0);
|
254 |
|
255 | if (firstIndex < 0) {
|
256 | return rankings.NO_MATCH;
|
257 | }
|
258 |
|
259 | charNumber = firstIndex;
|
260 |
|
261 | for (var i = 1, I = stringToRank.length; i < I; i++) {
|
262 | var matchChar = stringToRank[i];
|
263 | charNumber = findMatchingCharacter(matchChar, testString, charNumber);
|
264 | var found = charNumber > -1;
|
265 |
|
266 | if (!found) {
|
267 | return rankings.NO_MATCH;
|
268 | }
|
269 | }
|
270 |
|
271 | var spread = charNumber - firstIndex;
|
272 | return getRanking(spread);
|
273 | }
|
274 |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 | function sortRankedValues(a, b, baseSort) {
|
283 | var aFirst = -1;
|
284 | var bFirst = 1;
|
285 | var aRank = a.rank,
|
286 | aKeyIndex = a.keyIndex;
|
287 | var bRank = b.rank,
|
288 | bKeyIndex = b.keyIndex;
|
289 | var same = aRank === bRank;
|
290 |
|
291 | if (same) {
|
292 | if (aKeyIndex === bKeyIndex) {
|
293 |
|
294 | return baseSort(a, b);
|
295 | } else {
|
296 | return aKeyIndex < bKeyIndex ? aFirst : bFirst;
|
297 | }
|
298 | } else {
|
299 | return aRank > bRank ? aFirst : bFirst;
|
300 | }
|
301 | }
|
302 |
|
303 |
|
304 |
|
305 |
|
306 |
|
307 |
|
308 |
|
309 |
|
310 | function prepareValueForComparison(value, _ref4) {
|
311 | var keepDiacritics = _ref4.keepDiacritics;
|
312 |
|
313 |
|
314 | value = "" + value;
|
315 |
|
316 | if (!keepDiacritics) {
|
317 | value = removeAccents__default['default'](value);
|
318 | }
|
319 |
|
320 | return value;
|
321 | }
|
322 |
|
323 |
|
324 |
|
325 |
|
326 |
|
327 |
|
328 |
|
329 |
|
330 | function getItemValues(item, key) {
|
331 | if (typeof key === 'object') {
|
332 | key = key.key;
|
333 | }
|
334 |
|
335 | var value;
|
336 |
|
337 | if (typeof key === 'function') {
|
338 | value = key(item);
|
339 | } else if (item == null) {
|
340 | value = null;
|
341 | } else if (Object.hasOwnProperty.call(item, key)) {
|
342 | value = item[key];
|
343 | } else if (key.includes('.')) {
|
344 |
|
345 | return getNestedValues(key, item);
|
346 | } else {
|
347 | value = null;
|
348 | }
|
349 |
|
350 |
|
351 | if (value == null) {
|
352 | return [];
|
353 | }
|
354 |
|
355 | if (Array.isArray(value)) {
|
356 | return value;
|
357 | }
|
358 |
|
359 | return [String(value)];
|
360 | }
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 | function getNestedValues(path, item) {
|
371 | var keys = path.split('.');
|
372 | var values = [item];
|
373 |
|
374 | for (var i = 0, I = keys.length; i < I; i++) {
|
375 | var nestedKey = keys[i];
|
376 | var nestedValues = [];
|
377 |
|
378 | for (var j = 0, J = values.length; j < J; j++) {
|
379 | var nestedItem = values[j];
|
380 | if (nestedItem == null) continue;
|
381 |
|
382 | if (Object.hasOwnProperty.call(nestedItem, nestedKey)) {
|
383 | var nestedValue = nestedItem[nestedKey];
|
384 |
|
385 | if (nestedValue != null) {
|
386 | nestedValues.push(nestedValue);
|
387 | }
|
388 | } else if (nestedKey === '*') {
|
389 |
|
390 | nestedValues = nestedValues.concat(nestedItem);
|
391 | }
|
392 | }
|
393 |
|
394 | values = nestedValues;
|
395 | }
|
396 |
|
397 | if (Array.isArray(values[0])) {
|
398 |
|
399 |
|
400 | var result = [];
|
401 | return result.concat.apply(result, values);
|
402 | }
|
403 |
|
404 |
|
405 |
|
406 | return values;
|
407 | }
|
408 |
|
409 |
|
410 |
|
411 |
|
412 |
|
413 |
|
414 |
|
415 |
|
416 | function getAllValuesToRank(item, keys) {
|
417 | var allValues = [];
|
418 |
|
419 | for (var j = 0, J = keys.length; j < J; j++) {
|
420 | var key = keys[j];
|
421 | var attributes = getKeyAttributes(key);
|
422 | var itemValues = getItemValues(item, key);
|
423 |
|
424 | for (var i = 0, I = itemValues.length; i < I; i++) {
|
425 | allValues.push({
|
426 | itemValue: itemValues[i],
|
427 | attributes: attributes
|
428 | });
|
429 | }
|
430 | }
|
431 |
|
432 | return allValues;
|
433 | }
|
434 |
|
435 | var defaultKeyAttributes = {
|
436 | maxRanking: Infinity,
|
437 | minRanking: -Infinity
|
438 | };
|
439 |
|
440 |
|
441 |
|
442 |
|
443 |
|
444 |
|
445 | function getKeyAttributes(key) {
|
446 | if (typeof key === 'string') {
|
447 | return defaultKeyAttributes;
|
448 | }
|
449 |
|
450 | return _extends__default['default']({}, defaultKeyAttributes, key);
|
451 | }
|
452 |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 | exports.defaultBaseSortFn = defaultBaseSortFn;
|
458 | exports.matchSorter = matchSorter;
|
459 | exports.rankings = rankings;
|