Fix: fix #2343, properly fix "postfixDistinguished", also when marking as unknown

This commit is contained in:
Pieter Vander Vennet 2025-03-09 23:23:37 +01:00
parent 0cf3d07100
commit 2286ec964f
5 changed files with 122 additions and 102 deletions

View file

@ -25,6 +25,11 @@ export class TagTypes {
return <any>and.and
}
static uploadableAnd(and: And & UploadableTag): UploadableTag[] {
return <any>and.and
}
static safeOr(or: Or & OptimizedTag): ((FlatTag | (And & OptimizedTag)) & OptimizedTag)[] {
return <any>or.or
}

View file

@ -21,7 +21,7 @@ export class TagUtils {
["<=", (a, b) => a <= b],
[">=", (a, b) => a >= b],
["<", (a, b) => a < b],
[">", (a, b) => a > b],
[">", (a, b) => a > b]
]
public static modeDocumentation: Record<
string,
@ -48,7 +48,7 @@ export class TagUtils {
"### Removing a key\n" +
"\n" +
"If a key should be deleted in the OpenStreetMap-database, specify `key=` as well. This can be used e.g. to remove a\n" +
"fixme or value from another mapping if another field is filled out.",
"fixme or value from another mapping if another field is filled out."
},
"!=": {
name: "strict not equals",
@ -62,7 +62,7 @@ export class TagUtils {
"### If key is present\n" +
"\n" +
"This implies that, to check if a key is present, `key!=` can be used. This will only match if the key is present and not\n" +
"empty.",
"empty."
},
"~": {
name: "Value matches regex",
@ -73,12 +73,12 @@ export class TagUtils {
"The regex is put within braces as to prevent runaway values.\n" +
"\nUse `key~*` to indicate that any value is allowed. This is effectively the check that the attribute is present (defined _and_ not empty)." +
"\n" +
"Regexes will match the newline character with `.` too - the `s`-flag is enabled by default.",
"Regexes will match the newline character with `.` too - the `s`-flag is enabled by default."
},
"~i~": {
name: "Value matches case-invariant regex",
overpassSupport: true,
docs: "A tag can also be tested against a regex with `key~i~regex`, where the case of the value will be ignored. The regex is still matched against the _entire_ value",
docs: "A tag can also be tested against a regex with `key~i~regex`, where the case of the value will be ignored. The regex is still matched against the _entire_ value"
},
"!~": {
name: "Value should _not_ match regex",
@ -87,27 +87,27 @@ export class TagUtils {
"A tag can also be tested against a regex with `key!~regex`. This filter will match if the value does *not* match the regex. " +
"\n If the\n" +
"value is allowed to appear anywhere as substring, use `key~.*regex.*`.\n" +
"The regex is put within braces as to prevent runaway values.\n",
"The regex is put within braces as to prevent runaway values.\n"
},
"!~i~": {
name: "Value does *not* match case-invariant regex",
overpassSupport: true,
docs: "A tag can also be tested against a regex with `key~i~regex`, where the case of the value will be ignored. The regex is still matched against the _entire_ value. This filter returns true if the value does *not* match",
docs: "A tag can also be tested against a regex with `key~i~regex`, where the case of the value will be ignored. The regex is still matched against the _entire_ value. This filter returns true if the value does *not* match"
},
"~~": {
name: "Key and value should match given regex",
overpassSupport: true,
docs: "Both the `key` and `value` part of this specification are interpreted as regexes, both the key and value musth completely match their respective regexes",
docs: "Both the `key` and `value` part of this specification are interpreted as regexes, both the key and value musth completely match their respective regexes"
},
"~i~~": {
name: "Key and value should match a given regex; value is case-invariant",
overpassSupport: true,
docs: "Similar to ~~, except that the value is case-invariant",
docs: "Similar to ~~, except that the value is case-invariant"
},
"!~i~~": {
name: "Key and value should match a given regex; value is case-invariant",
overpassSupport: true,
docs: "Similar to !~~, except that the value is case-invariant",
docs: "Similar to !~~, except that the value is case-invariant"
},
":=": {
name: "Substitute `... {some_key} ...` and match `key`",
@ -133,24 +133,24 @@ export class TagUtils {
"\n" +
"```json\n" +
"{\n" +
' "mappings": [\n' +
" \"mappings\": [\n" +
" {\n" +
' "if":"key:={some_other_key}",\n' +
' "then": "...",\n' +
' "hideInAnswer": "some_other_key="\n' +
" \"if\":\"key:={some_other_key}\",\n" +
" \"then\": \"...\",\n" +
" \"hideInAnswer\": \"some_other_key=\"\n" +
" }\n" +
" ]\n" +
"}\n" +
"```\n" +
"\n" +
"One can use `key!:=prefix-{other_key}-postfix` as well, to match if `key` is _not_ the same\n" +
"as `prefix-{other_key}-postfix` (with `other_key` substituted by the value)",
"as `prefix-{other_key}-postfix` (with `other_key` substituted by the value)"
},
"!:=": {
name: "Substitute `{some_key}` should not match `key`",
overpassSupport: false,
docs: "See `:=`, except that this filter is inverted",
},
docs: "See `:=`, except that this filter is inverted"
}
}
private static keyCounts: { keys: any; tags: any } = key_counts
public static readonly numberAndDateComparisonDocs =
@ -175,10 +175,10 @@ export class TagUtils {
"\n" +
"```json\n" +
"{\n" +
' "osmTags": {\n' +
' "or": [\n' +
' "amenity=school",\n' +
' "amenity=kindergarten"\n' +
" \"osmTags\": {\n" +
" \"or\": [\n" +
" \"amenity=school\",\n" +
" \"amenity=kindergarten\"\n" +
" ]\n" +
" }\n" +
"}\n" +
@ -194,7 +194,7 @@ export class TagUtils {
"If the schema-files note a type [`TagConfigJson`](https://github.com/pietervdvn/MapComplete/blob/develop/src/Models/ThemeConfig/Json/TagConfigJson.ts), you can use one of these values.\n" +
"\n" +
"In some cases, not every type of tags-filter can be used. For example, _rendering_ an option with a regex is\n" +
'fine (`"if": "brand~[Bb]randname", "then":" The brand is Brandname"`); but this regex can not be used to write a value\n' +
"fine (`\"if\": \"brand~[Bb]randname\", \"then\":\" The brand is Brandname\"`); but this regex can not be used to write a value\n" +
"into the database. The theme loader will however refuse to work with such inconsistencies and notify you of this while\n" +
"you are building your theme.\n" +
"\n" +
@ -205,18 +205,18 @@ export class TagUtils {
"\n" +
"```json\n" +
"{\n" +
' "and": [\n' +
' "key=value",\n' +
" \"and\": [\n" +
" \"key=value\",\n" +
" {\n" +
' "or": [\n' +
' "other_key=value",\n' +
' "other_key=some_other_value"\n' +
" \"or\": [\n" +
" \"other_key=value\",\n" +
" \"other_key=some_other_value\"\n" +
" ]\n" +
" },\n" +
' "key_which_should_be_missing=",\n' +
' "key_which_should_have_a_value~*",\n' +
' "key~.*some_regex_a*_b+_[a-z]?",\n' +
' "height<1"\n' +
" \"key_which_should_be_missing=\",\n" +
" \"key_which_should_have_a_value~*\",\n" +
" \"key~.*some_regex_a*_b+_[a-z]?\",\n" +
" \"height<1\"\n" +
" ]\n" +
"}\n" +
"```\n" +
@ -374,9 +374,9 @@ export class TagUtils {
* TagUtils.FlattenMultiAnswer(([new Tag("x","y"), new Tag("a","b")])) // => new And([new Tag("x","y"), new Tag("a","b")])
* TagUtils.FlattenMultiAnswer(([new Tag("x","")])) // => new And([new Tag("x","")])
*/
static FlattenMultiAnswer(tagsFilters: UploadableTag[]): And {
static FlattenMultiAnswer(tagsFilters: UploadableTag[]): UploadableTag[] {
if (tagsFilters === undefined) {
return new And([])
return []
}
const keyValues = TagUtils.SplitKeys(tagsFilters)
@ -386,7 +386,7 @@ export class TagUtils {
values.sort()
and.push(new Tag(key, values.join(";")))
}
return new And(and)
return and
}
/**
@ -985,10 +985,10 @@ export class TagUtils {
return ["", "## `" + mode + "` " + doc.name, "", doc.docs, "", ""].join("\n")
}),
"## " +
TagUtils.comparators.map((comparator) => "`" + comparator[0] + "`").join(" ") +
" Logical comparators",
TagUtils.comparators.map((comparator) => "`" + comparator[0] + "`").join(" ") +
" Logical comparators",
TagUtils.numberAndDateComparisonDocs,
TagUtils.logicalOperator,
TagUtils.logicalOperator
].join("\n")
}