-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbooleanFilter.js
More file actions
61 lines (54 loc) · 1.68 KB
/
Copy pathbooleanFilter.js
File metadata and controls
61 lines (54 loc) · 1.68 KB
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
// Lightweight Boolean filter parser for tags
function parseBooleanQuery(query) {
// Tokenize (AND, OR, NOT, parentheses, quoted strings, words)
const tokens = query.match(/"[^"]+"|\(|\)|AND|OR|NOT|\S+/gi) || [];
let i = 0;
function parseExpr() {
let node = parseTerm();
while (tokens[i] && tokens[i].toUpperCase() === 'OR') {
i++;
node = { type: 'or', left: node, right: parseTerm() };
}
return node;
}
function parseTerm() {
let node = parseFactor();
while (tokens[i] && tokens[i].toUpperCase() === 'AND') {
i++;
node = { type: 'and', left: node, right: parseFactor() };
}
return node;
}
function parseFactor() {
const token = tokens[i++];
if (!token) return { type: 'literal', value: '' };
if (token === '(') {
const expr = parseExpr();
i++; // skip ')'
return expr;
}
if (token.toUpperCase() === 'NOT') {
return { type: 'not', value: parseFactor() };
}
return {
type: 'literal',
value: token.replace(/^"|"$/g, '').toLowerCase()
};
}
return parseExpr();
}
function evaluateAST(ast, tags) {
tags = tags.map(t => t.toLowerCase());
switch (ast.type) {
case 'literal':
return tags.includes(ast.value);
case 'not':
return !evaluateAST(ast.value, tags);
case 'and':
return evaluateAST(ast.left, tags) && evaluateAST(ast.right, tags);
case 'or':
return evaluateAST(ast.left, tags) || evaluateAST(ast.right, tags);
default:
return true;
}
}