-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.ts
74 lines (72 loc) · 1.99 KB
/
utils.ts
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
import { ParserToken } from './parser'
/**
* Filter data based on parsed query
*
* @param parsed - parsed query
* @param data - data to filter
* @param map - map function to apply to data before filtering
* @returns filtered data
*
* @example
* ```ts
* const data = ['Hello', 'World', 'Foo', 'Bar']
* const parsed = parse('Hello OR (World AND Bar)')
* const filtered = filter(parsed, data)
* console.log(filtered) // ['Hello', 'World', 'Bar']
* ```
*/
export function filter(
parsed: ParserToken[],
data: string[],
map?: (item: string) => string,
): string[]
export function filter<T>(parsed: ParserToken[], data: T[], map: (item: T) => string): string[]
export function filter<T = string>(
parsed: ParserToken[],
data: T[],
map?: (item: T) => string,
): T[] {
return data.filter((_item) => {
let item: string
item = map?.(_item) ?? String(_item)
for (const check of parsed) {
if (checkItem(check, item)) {
return true
}
}
return false
})
}
/**
* Check if item matches a single token
* @param check - token to check
* @param item - item to check
* @returns true if item matches token
*
* @example
* ```ts
* const check = parse('Hello OR (World AND Bar)')
* const item = 'Hello'
* const matches = checkItem(check, item)
* console.log(matches) // true
* ```
*/
export function checkItem(check: ParserToken, item: string): boolean {
item = String(item).toLowerCase()
switch (check.type) {
case 'word':
return item.includes(check.value.toLowerCase())
case 'operator':
if (check.value.toUpperCase() === 'OR') {
return checkItem(check.left, item) || checkItem(check.right, item)
}
if (check.value.toUpperCase() === 'AND') {
return checkItem(check.left, item) && checkItem(check.right, item)
}
throw new Error(`Unknown operator: ${check.value}`)
case 'group':
return filter(check.children, [item]).length > 0
case 'phrase':
return item.includes(check.value.toLowerCase())
}
}