-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
86 lines (78 loc) · 2.37 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
module.exports = prepareSimpleTextSearch
// Usage:
// ```
// var get = simpleTextSearch(['foo', 'bar', 'foobar'])
// var results = get('foo')
// // -> returns ['foo', 'foobar']
// ```
//
// Objects in a collection get stringified to search it.
// You can also define a property to search in or a pruning function to preprocess
// the collection:
// ```
// var get = simpleTextSearch([{name: 'Zürich'}, {name: 'Marc'}], 'name')
// var results = get('zurich')
// // -> returns [{name: 'Zürich'}]
//
// var get = simpleTextSearch([{name: 'Zürich'}, {name: 'Marc'}], (v) => v.name)
// var results = get('zurich')
// // -> returns [{name: 'Zürich'}]
// ```
function prepareSimpleTextSearch (collection, property) {
let cachedPrunedElements
function prunedElements () {
const elements = []
for (const elem of collection) {
let val = elem
if (typeof property === 'string') val = val && val[property]
else if (typeof property === 'function') val = val && property(val)
if (typeof val === 'object') val = JSON.stringify(val)
else if (typeof val !== 'string') continue
val = { pruned: clean(val), elem }
elements.push(val)
}
cachedPrunedElements = elements
return cachedPrunedElements
}
return function simpleTextSearch (q) {
if (!collection || !q) return collection
const tokens = clean(q).split(/\W/)
const result = []
// eslint-disable-next-line no-labels
entries: for (const { pruned, elem } of cachedPrunedElements || prunedElements()) {
let i = tokens.length
// eslint-disable-next-line no-labels
while (i--) if (pruned.indexOf(tokens[i]) === -1) continue entries
result.push(elem)
}
return result
}
}
const specialCharMap = {
äàáâäæãåā: 'a',
çćč: 'c',
đð: 'd',
èéêëēėę: 'e',
îïíīįì: 'i',
ł: 'l',
ñńň: 'n',
ôöòóœøōõ: 'o',
ř: 'r',
śš: 's',
ß: 'ss',
ť: 't',
ûüùúūů: 'u',
ÿý: 'y',
žżŻź: 'z'
}
const charMap = {}
for (const keys of Object.keys(specialCharMap)) {
for (const char of keys) {
charMap[char] = specialCharMap[keys]
}
}
const toReplace = new RegExp('[' + Object.keys(charMap).join('') + ']|\\W+', 'g')
function replacer (char) { return charMap[char] || ' ' }
function clean (str) {
return String(str).toLowerCase().replace(toReplace, replacer).trim()
}