Themes: automatically remove filters that are useless because they would filter everything or nothing; fix some logic bugs and add tests

This commit is contained in:
Pieter Vander Vennet 2025-01-20 18:35:24 +01:00
parent 860fc9994b
commit 50ef2ba636
3 changed files with 37 additions and 12 deletions

View file

@ -124,7 +124,7 @@ export class And extends TagsFilter {
* t0.shadows(t0) // => true
* t1.shadows(t1) // => true
* t2.shadows(t2) // => true
* t0.shadows(t1) // => false
* t0.shadows(t1) // => true
* t0.shadows(t2) // => false
* t1.shadows(t0) // => false
* t1.shadows(t2) // => false
@ -135,13 +135,18 @@ export class And extends TagsFilter {
* const t1 = new And([new Tag("shop","clothes"), new Or([new Tag("brand","XYZ"),new Tag("brand:wikidata","Q1234")])])
* const t2 = new And([new RegexTag("shop","mall",true), new Or([TagUtils.Tag("shop~*"), new Tag("craft","shoemaker")])])
* t1.shadows(t2) // => true
*
* const t1 = new Tag("a","b")
* const t2 = new And([new Tag("x","y"), new Tag("a","b")])
* t2.shadows(t1) // => true
* t1.shadows(t2) // => false
*/
shadows(other: TagsFilter): boolean {
const phrases: TagsFilter[] = other instanceof And ? other.and : [other]
// The phrases of the _other_ and
const phrases: readonly TagsFilter[] = other instanceof And ? other.and : [other]
// A phrase might be shadowed by a certain subsection. We keep track of this here
const shadowedOthers = phrases.map(() => false)
for (const selfTag of this.and) {
let shadowsSome = false
let shadowsAll = true
for (let i = 0; i < phrases.length; i++) {
const otherTag = phrases[i]
@ -149,7 +154,6 @@ export class And extends TagsFilter {
if (doesShadow) {
shadowedOthers[i] = true
}
shadowsSome ||= doesShadow
shadowsAll &&= doesShadow
}
// If A => X and A => Y, then
@ -157,9 +161,6 @@ export class And extends TagsFilter {
if (shadowsAll) {
return true
}
if (!shadowsSome) {
return false
}
}
return !shadowedOthers.some((v) => !v)
}

View file

@ -690,6 +690,9 @@ export class TagUtils {
return result
}
/**
* TagUtils.removeKnownParts(TagUtils.Tag({and: ["vending=excrement_bag"}),TagUtils.Tag({and: ["amenity=waste_basket", "vending=excrement_bag"]}), true) // => true
*/
public static removeKnownParts(
tag: TagsFilter,
known: TagsFilter,
@ -702,7 +705,7 @@ export class TagUtils {
if (tagOrBool instanceof And) {
return tagOrBool.removePhraseConsideredKnown(known, valueOfKnown)
}
return tagOrBool
return new And([tagOrBool]).removePhraseConsideredKnown(known, valueOfKnown)
}
/**