mirror of
https://github.com/TECHNOFAB11/ergogen.git
synced 2025-12-15 01:13:51 +01:00
86 lines
2.1 KiB
JavaScript
86 lines
2.1 KiB
JavaScript
|
|
const u = require('./utils')
|
||
|
|
const a = require('./assert')
|
||
|
|
const anchor = require('./anchor').parse
|
||
|
|
|
||
|
|
const _true = () => true
|
||
|
|
const _and = arr => p => arr.map(e => e(p)).reduce((a, b) => a && b)
|
||
|
|
const _or = arr => p => arr.map(e => e(p)).reduce((a, b) => a || b)
|
||
|
|
|
||
|
|
const similar = (a, b, name, units) => {
|
||
|
|
let neg = false
|
||
|
|
|
||
|
|
if (b.startsWith('-')) {
|
||
|
|
neg = true
|
||
|
|
b = b.slice(1)
|
||
|
|
}
|
||
|
|
|
||
|
|
if (b.startsWith('/')) {
|
||
|
|
//...
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const comparators = {
|
||
|
|
'~': similar
|
||
|
|
// TODO: extension point for other operators...
|
||
|
|
}
|
||
|
|
const symbols = Object.keys(comparators)
|
||
|
|
|
||
|
|
const simple = (exp, name, units) => {
|
||
|
|
|
||
|
|
let a = ['meta.name', 'meta.tags']
|
||
|
|
let op = '~'
|
||
|
|
let b
|
||
|
|
const parts = exp.split(/\s+/g)
|
||
|
|
|
||
|
|
// full case
|
||
|
|
if (symbols.includes(parts[1])) {
|
||
|
|
a = parts[0].split(',')
|
||
|
|
op = parts[1]
|
||
|
|
b = parts.slice(2).join(' ')
|
||
|
|
|
||
|
|
// middle case, just an operator spec, default "a"
|
||
|
|
} else if (symbols.includes(parts[0])) {
|
||
|
|
op = parts[0]
|
||
|
|
b = parts.slice(1).join(' ')
|
||
|
|
|
||
|
|
// basic case, only "b"
|
||
|
|
} else {
|
||
|
|
b = exp
|
||
|
|
}
|
||
|
|
|
||
|
|
return comparators[op](a, b, name, units)
|
||
|
|
}
|
||
|
|
|
||
|
|
const complex = (config, name, units, aggregator=_and) => {
|
||
|
|
|
||
|
|
// default is all points
|
||
|
|
if (config === undefined) {
|
||
|
|
return _true
|
||
|
|
}
|
||
|
|
|
||
|
|
// otherwise we branch by type
|
||
|
|
const type = a.type(config)()
|
||
|
|
switch(type) {
|
||
|
|
|
||
|
|
// base case is a string, meaning a simple/single filter
|
||
|
|
case 'string':
|
||
|
|
return simple(config, name, units)
|
||
|
|
|
||
|
|
// arrays are aggregated with alternating and/or conditions
|
||
|
|
case 'array':
|
||
|
|
const alternate = aggregator == _and ? _or : _and
|
||
|
|
return aggregator(config.map(elem => complex(elem, name, units, alternate)))
|
||
|
|
|
||
|
|
default:
|
||
|
|
throw new Error(`Unexpected type "${type}" found at filter "${name}"!`)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
exports.parse = (config, name, points={}, units={}) => {
|
||
|
|
|
||
|
|
if (a.type(config)() == 'object') {
|
||
|
|
return [anchor(config, name, points)(units)]
|
||
|
|
}
|
||
|
|
|
||
|
|
return Object.values(points).filter(complex(config, name, units))
|
||
|
|
}
|