Logic: enable to re-export tagsFilter as TagsConfig; improve optimization for comparingTag

This commit is contained in:
Pieter Vander Vennet 2023-11-29 14:29:11 +01:00
parent 3ce21f61cb
commit 78238dccc7
12 changed files with 140 additions and 20 deletions

View file

@ -0,0 +1,25 @@
import Script from "./Script"
import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson"
import { readFileSync, writeFileSync } from "fs"
import { AllSharedLayers } from "../src/Customizations/AllSharedLayers"
class PrepareFavouritesLayerJson extends Script {
constructor() {
super("Prepares the 'favourites'-layer")
}
async main(args: string[]): Promise<void> {
const allConfigs = AllSharedLayers.getSharedLayersConfigs()
const proto = this.readLayer("favourite/favourite.proto.json")
const questions = allConfigs.get("questions")
proto.tagRenderings.push(...questions.tagRenderings)
writeFileSync("./assets/layers/favourite/favourite.json", JSON.stringify(proto, null, " "))
}
private readLayer(path: string): LayerConfigJson {
return JSON.parse(readFileSync("./assets/layers/" + path, "utf8"))
}
}
new PrepareFavouritesLayerJson().run()

View file

@ -3,6 +3,7 @@ import { Or } from "./Or"
import { TagUtils } from "./TagUtils"
import { Tag } from "./Tag"
import { RegexTag } from "./RegexTag"
import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson"
export class And extends TagsFilter {
public and: TagsFilter[]
@ -72,6 +73,10 @@ export class And extends TagsFilter {
return allChoices
}
asJson(): TagConfigJson {
return { and: this.and.map((a) => a.asJson()) }
}
asHumanString(linkToWiki: boolean, shorten: boolean, properties: Record<string, string>) {
return this.and
.map((t) => {

View file

@ -1,18 +1,23 @@
import { TagsFilter } from "./TagsFilter"
import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson"
import { Tag } from "./Tag"
export default class ComparingTag implements TagsFilter {
private readonly _key: string
private readonly _predicate: (value: string) => boolean
private readonly _representation: string
private readonly _representation: "<" | ">" | "<=" | ">="
private readonly _boundary: string
constructor(
key: string,
predicate: (value: string | undefined) => boolean,
representation: string = ""
representation: "<" | ">" | "<=" | ">=",
boundary: string
) {
this._key = key
this._predicate = predicate
this._representation = representation
this._boundary = boundary
}
asChange(properties: Record<string, string>): { k: string; v: string }[] {
@ -20,15 +25,64 @@ export default class ComparingTag implements TagsFilter {
}
asHumanString(linkToWiki: boolean, shorten: boolean, properties: Record<string, string>) {
return this._key + this._representation
return this._key + this._representation + this._boundary
}
asOverpass(): string[] {
throw "A comparable tag can not be used as overpass filter"
}
/**
* const tg = new ComparingTag("key", value => (Number(value) < 42), "<", "42")
* const tg0 = new ComparingTag("key", value => (Number(value) < 42), "<", "42")
* const tg1 = new ComparingTag("key", value => (Number(value) <= 42), "<=", "42")
* const against = new ComparingTag("key", value => (Number(value) > 0), ">", "0")
* tg.shadows(new Tag("key", "41")) // => true
* tg.shadows(new Tag("key", "0")) // => true
* tg.shadows(new Tag("key", "43")) // => false
* tg.shadows(new Tag("key", "0")) // => true
* tg.shadows(tg) // => true
* tg.shadows(tg0) // => true
* tg.shadows(against) // => false
* tg1.shadows(tg0) // => true
* tg0.shadows(tg1) // => false
*
*/
shadows(other: TagsFilter): boolean {
return other === this
if (other === this) {
return true
}
if (other instanceof ComparingTag) {
if (other._key !== this._key) {
return false
}
const selfDesc = this._representation === "<" || this._representation === "<="
const otherDesc = other._representation === "<" || other._representation === "<="
if (selfDesc !== otherDesc) {
return false
}
if (
this._boundary === other._boundary &&
this._representation === other._representation
) {
return true
}
if (this._predicate(other._boundary)) {
return true
}
return false
}
if (other instanceof Tag) {
if (other.key !== this._key) {
return false
}
if (this.matchesProperties({ [other.key]: other.value })) {
return true
}
}
return false
}
isUsableAsAnswer(): boolean {
@ -38,7 +92,7 @@ export default class ComparingTag implements TagsFilter {
/**
* Checks if the properties match
*
* const t = new ComparingTag("key", (x => Number(x) < 42))
* const t = new ComparingTag("key", (x => Number(x) < 42), "<", "42")
* t.matchesProperties({key: 42}) // => false
* t.matchesProperties({key: 41}) // => true
* t.matchesProperties({key: 0}) // => true
@ -56,6 +110,10 @@ export default class ComparingTag implements TagsFilter {
return []
}
asJson(): TagConfigJson {
return this._key + this._representation
}
optimize(): TagsFilter | boolean {
return this
}

View file

@ -1,6 +1,7 @@
import { TagsFilter } from "./TagsFilter"
import { TagUtils } from "./TagUtils"
import { And } from "./And"
import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson"
export class Or extends TagsFilter {
public or: TagsFilter[]
@ -27,6 +28,10 @@ export class Or extends TagsFilter {
return false
}
asJson(): TagConfigJson {
return { or: this.or.map((o) => o.asJson()) }
}
/**
*
* import {Tag} from "./Tag";
@ -174,9 +179,9 @@ export class Or extends TagsFilter {
const newOrs: TagsFilter[] = []
let containedAnds: And[] = []
for (const tf of optimized) {
if (tf instanceof Or) {
if (tf["or"]) {
// expand all the nested ors...
newOrs.push(...tf.or)
newOrs.push(...tf["or"])
} else if (tf instanceof And) {
// partition of all the ands
containedAnds.push(tf)
@ -191,7 +196,7 @@ export class Or extends TagsFilter {
const cleanedContainedANds: And[] = []
outer: for (let containedAnd of containedAnds) {
for (const known of newOrs) {
// input for optimazation: (K=V | (X=Y & K=V))
// input for optimization: (K=V | (X=Y & K=V))
// containedAnd: (X=Y & K=V)
// newOrs (and thus known): (K=V) --> false
const cleaned = containedAnd.removePhraseConsideredKnown(known, false)

View file

@ -1,5 +1,6 @@
import { Tag } from "./Tag"
import { TagsFilter } from "./TagsFilter"
import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson"
export class RegexTag extends TagsFilter {
public readonly key: RegExp | string
@ -82,6 +83,10 @@ export class RegexTag extends TagsFilter {
}
}
asJson(): TagConfigJson {
return this.asHumanString()
}
isUsableAsAnswer(): boolean {
return false
}

View file

@ -1,6 +1,7 @@
import { TagsFilter } from "./TagsFilter"
import { Tag } from "./Tag"
import { Utils } from "../../Utils"
import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson"
/**
* The substituting-tag uses the tags of a feature a variables and replaces them.
@ -45,6 +46,10 @@ export default class SubstitutingTag implements TagsFilter {
)
}
asJson(): TagConfigJson {
return this._key + (this._invert ? "!" : "") + ":=" + this._value
}
asOverpass(): string[] {
throw "A variable with substitution can not be used to query overpass"
}

View file

@ -1,5 +1,6 @@
import { Utils } from "../../Utils"
import { TagsFilter } from "./TagsFilter"
import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson"
export class Tag extends TagsFilter {
public key: string
@ -67,6 +68,10 @@ export class Tag extends TagsFilter {
return [`["${this.key}"="${this.value}"]`]
}
asJson(): TagConfigJson {
return this.key + "=" + this.value
}
/**
const t = new Tag("key", "value")

View file

@ -15,13 +15,14 @@ type Tags = Record<string, string>
export type UploadableTag = Tag | SubstitutingTag | And
export class TagUtils {
public static readonly comparators: ReadonlyArray<[string, (a: number, b: number) => boolean]> =
[
["<=", (a, b) => a <= b],
[">=", (a, b) => a >= b],
["<", (a, b) => a < b],
[">", (a, b) => a > b],
]
public static readonly comparators: ReadonlyArray<
["<" | ">" | "<=" | ">=", (a: number, b: number) => boolean]
> = [
["<=", (a, b) => a <= b],
[">=", (a, b) => a >= b],
["<", (a, b) => a < b],
[">", (a, b) => a > b],
]
public static modeDocumentation: Record<
string,
{ name: string; docs: string; uploadable?: boolean; overpassSupport: boolean }
@ -735,11 +736,10 @@ export class TagUtils {
const tag = json as string
for (const [operator, comparator] of TagUtils.comparators) {
if (tag.indexOf(operator) >= 0) {
const split = Utils.SplitFirst(tag, operator)
let val = Number(split[1].trim())
const split = Utils.SplitFirst(tag, operator).map((v) => v.trim())
let val = Number(split[1])
if (isNaN(val)) {
val = new Date(split[1].trim()).getTime()
val = new Date(split[1]).getTime()
}
const f = (value: string | number | undefined) => {
@ -762,7 +762,7 @@ export class TagUtils {
}
return comparator(b, val)
}
return new ComparingTag(split[0], f, operator + val)
return new ComparingTag(split[0], f, operator, "" + val)
}
}

View file

@ -1,3 +1,5 @@
import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson"
export abstract class TagsFilter {
abstract asOverpass(): string[]
@ -17,6 +19,8 @@ export abstract class TagsFilter {
properties: Record<string, string>
): string
abstract asJson(): TagConfigJson
abstract usedKeys(): string[]
/**

View file

@ -0,0 +1,8 @@
<script lang="ts">
import { SpecialVisualization } from "../SpecialVisualization";
/**
* A panel showing all your favourites
*/
export let state: SpecialVisualizationState
</script>