Filter negation bugfix
This commit is contained in:
parent
3eac7f8e6d
commit
4d65eb19a6
2 changed files with 23 additions and 15 deletions
|
@ -9,9 +9,8 @@ const _false = () => false
|
||||||
const _and = arr => p => arr.map(e => e(p)).reduce((a, b) => a && b)
|
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 _or = arr => p => arr.map(e => e(p)).reduce((a, b) => a || b)
|
||||||
|
|
||||||
const similar = (key, reference, name, units) => {
|
const similar = (keys, reference, name, units) => {
|
||||||
let neg = false
|
let neg = false
|
||||||
|
|
||||||
if (reference.startsWith('-')) {
|
if (reference.startsWith('-')) {
|
||||||
neg = true
|
neg = true
|
||||||
reference = reference.slice(1)
|
reference = reference.slice(1)
|
||||||
|
@ -20,15 +19,19 @@ const similar = (key, reference, name, units) => {
|
||||||
// support both string or regex as reference
|
// support both string or regex as reference
|
||||||
let internal_tester = val => (''+val) == reference
|
let internal_tester = val => (''+val) == reference
|
||||||
if (reference.startsWith('/')) {
|
if (reference.startsWith('/')) {
|
||||||
const regex_parts = reference.split('/')
|
try {
|
||||||
regex_parts.shift() // remove starting slash
|
const regex_parts = reference.split('/')
|
||||||
const flags = regex_parts.pop()
|
regex_parts.shift() // remove starting slash
|
||||||
const regex = new RegExp(regex_parts.join('/'), flags)
|
const flags = regex_parts.pop()
|
||||||
internal_tester = val => regex.test(''+val)
|
const regex = new RegExp(regex_parts.join('/'), flags)
|
||||||
|
internal_tester = val => regex.test(''+val)
|
||||||
|
} catch (ex) {
|
||||||
|
throw new Error(`Invalid regex "${reference}" found at filter "${name}"!`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// support strings, arrays, or objects as key
|
// support strings, arrays, or objects as key
|
||||||
const external_tester = point => {
|
const external_tester = (point, key) => {
|
||||||
const value = u.deep(point, key)
|
const value = u.deep(point, key)
|
||||||
if (a.type(value)() == 'array') {
|
if (a.type(value)() == 'array') {
|
||||||
return value.some(subkey => internal_tester(subkey))
|
return value.some(subkey => internal_tester(subkey))
|
||||||
|
@ -39,11 +42,12 @@ const similar = (key, reference, name, units) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// negation happens at the end
|
// consider negation
|
||||||
if (neg) {
|
if (neg) {
|
||||||
return point => !external_tester(point)
|
return point => keys.every(key => !external_tester(point, key))
|
||||||
|
} else {
|
||||||
|
return point => keys.some(key => external_tester(point, key))
|
||||||
}
|
}
|
||||||
return external_tester
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const comparators = {
|
const comparators = {
|
||||||
|
@ -75,7 +79,7 @@ const simple = (exp, name, units) => {
|
||||||
value = exp
|
value = exp
|
||||||
}
|
}
|
||||||
|
|
||||||
return point => keys.some(key => comparators[op](key, value, name, units)(point))
|
return point => comparators[op](keys, value, name, units)(point)
|
||||||
}
|
}
|
||||||
|
|
||||||
const complex = (config, name, units, aggregator=_or) => {
|
const complex = (config, name, units, aggregator=_or) => {
|
||||||
|
@ -109,7 +113,7 @@ const contains_object = (val) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.parse = (config, name, points={}, units={}, asym='source') => {
|
exports.parse = (config, name, points={}, units={}, asym='source') => {
|
||||||
|
|
||||||
let result = []
|
let result = []
|
||||||
|
|
||||||
// if a filter decl is undefined, it's just the default point at [0, 0]
|
// if a filter decl is undefined, it's just the default point at [0, 0]
|
||||||
|
|
|
@ -49,17 +49,21 @@ describe('Filter', function() {
|
||||||
names(filter('/^o/', '', points)).should.deep.equal(['one', 'three', 'mirror_one'])
|
names(filter('/^o/', '', points)).should.deep.equal(['one', 'three', 'mirror_one'])
|
||||||
// middle spec, should be the same as above, only explicit
|
// middle spec, should be the same as above, only explicit
|
||||||
names(filter('~ /^o/', '', points)).should.deep.equal(['one', 'three', 'mirror_one'])
|
names(filter('~ /^o/', '', points)).should.deep.equal(['one', 'three', 'mirror_one'])
|
||||||
// full spec (n would normally match both one and even, but on the tags level, it's just even)
|
// full spec (/n/ would normally match both "one" and "even", but on the tags level, it's just even)
|
||||||
names(filter('meta.tags ~ /n/', '', points)).should.deep.equal(['two'])
|
names(filter('meta.tags ~ /n/', '', points)).should.deep.equal(['two'])
|
||||||
|
names(filter('meta.name,meta.tags ~ /n/', '', points)).should.deep.equal(['one', 'two', 'mirror_one'])
|
||||||
// negation
|
// negation
|
||||||
names(filter('meta.tags ~ -/n/', '', points)).should.deep.equal(['one', 'three', 'mirror_one'])
|
names(filter('meta.tags ~ -/n/', '', points)).should.deep.equal(['one', 'three', 'mirror_one'])
|
||||||
|
names(filter('meta.name,meta.tags ~ -/n/', '', points)).should.deep.equal(['three'])
|
||||||
// arrays OR by default at odd levels (including top level)...
|
// arrays OR by default at odd levels (including top level)...
|
||||||
names(filter(['one', 'two'], '', points)).should.deep.equal(['one', 'two'])
|
names(filter(['one', 'two'], '', points)).should.deep.equal(['one', 'two'])
|
||||||
// ...and AND at even levels
|
// ...and AND at even levels
|
||||||
names(filter([['even', 'prime']], '', points)).should.deep.equal(['two'])
|
names(filter([['even', 'prime']], '', points)).should.deep.equal(['two'])
|
||||||
// arbitrary nesting should be possible
|
// arbitrary nesting should be possible
|
||||||
names(filter([[['even', 'odd'], 'prime']], '', points)).should.deep.equal(['two', 'three'])
|
names(filter([[['even', 'odd'], 'prime']], '', points)).should.deep.equal(['two', 'three'])
|
||||||
// anything other than string/array/object/undefined is an error
|
// invalid regexes should throw meaningful errors
|
||||||
|
filter.bind(this, '/\\/', '', points).should.throw('Invalid regex')
|
||||||
|
// anything other than string/array/object/undefined is also an error
|
||||||
filter.bind(this, 28, '', points).should.throw('Unexpected type')
|
filter.bind(this, 28, '', points).should.throw('Unexpected type')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue