Refactoring: split AndOrTagConfigJson into an AndTagConfig and an OrTagConfig

This commit is contained in:
Pieter Vander Vennet 2022-07-18 00:10:41 +02:00
parent e225b8e45b
commit 9ae40d8af2
10 changed files with 41 additions and 32 deletions

View file

@ -6,12 +6,11 @@ import ComparingTag from "./ComparingTag";
import {RegexTag} from "./RegexTag"; import {RegexTag} from "./RegexTag";
import SubstitutingTag from "./SubstitutingTag"; import SubstitutingTag from "./SubstitutingTag";
import {Or} from "./Or"; import {Or} from "./Or";
import {AndOrTagConfigJson} from "../../Models/ThemeConfig/Json/TagConfigJson"; import {TagConfigJson} from "../../Models/ThemeConfig/Json/TagConfigJson";
import {isRegExp} from "util"; import {isRegExp} from "util";
import * as key_counts from "../../assets/key_totals.json" import * as key_counts from "../../assets/key_totals.json"
type Tags = Record<string, string> type Tags = Record<string, string>
type OsmTags = Tags & {id: string}
export class TagUtils { export class TagUtils {
private static keyCounts: { keys: any, tags: any } = key_counts["default"] ?? key_counts private static keyCounts: { keys: any, tags: any } = key_counts["default"] ?? key_counts
@ -249,7 +248,7 @@ export class TagUtils {
* // Must match case insensitive * // Must match case insensitive
* TagUtils.Tag("name~i~somename").matchesProperties({name: "SoMeName"}) // => true * TagUtils.Tag("name~i~somename").matchesProperties({name: "SoMeName"}) // => true
*/ */
public static Tag(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter { public static Tag(json: TagConfigJson, context: string = ""): TagsFilter {
try { try {
return this.TagUnsafe(json, context); return this.TagUnsafe(json, context);
} catch (e) { } catch (e) {
@ -308,20 +307,20 @@ export class TagUtils {
return {key, value, invert: invert == "!", modifier: (modifier == "i~" ? "i" : "")}; return {key, value, invert: invert == "!", modifier: (modifier == "i~" ? "i" : "")};
} }
private static TagUnsafe(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter { private static TagUnsafe(json: TagConfigJson, context: string = ""): TagsFilter {
if (json === undefined) { if (json === undefined) {
throw new Error(`Error while parsing a tag: 'json' is undefined in ${context}. Make sure all the tags are defined and at least one tag is present in a complex expression`) throw new Error(`Error while parsing a tag: 'json' is undefined in ${context}. Make sure all the tags are defined and at least one tag is present in a complex expression`)
} }
if (typeof (json) != "string") { if (typeof (json) != "string") {
if (json.and !== undefined && json.or !== undefined) { if (json["and"] !== undefined && json["or"] !== undefined) {
throw `Error while parsing a TagConfig: got an object where both 'and' and 'or' are defined` throw `Error while parsing a TagConfig: got an object where both 'and' and 'or' are defined`
} }
if (json.and !== undefined) { if (json["and"] !== undefined) {
return new And(json.and.map(t => TagUtils.Tag(t, context))); return new And(json["and"].map(t => TagUtils.Tag(t, context)));
} }
if (json.or !== undefined) { if (json["or"] !== undefined) {
return new Or(json.or.map(t => TagUtils.Tag(t, context))); return new Or(json["or"].map(t => TagUtils.Tag(t, context)));
} }
throw "At " + context + ": unrecognized tag" throw "At " + context + ": unrecognized tag"
} }

View file

@ -4,7 +4,7 @@ import FilterConfigJson from "./Json/FilterConfigJson";
import Translations from "../../UI/i18n/Translations"; import Translations from "../../UI/i18n/Translations";
import {TagUtils} from "../../Logic/Tags/TagUtils"; import {TagUtils} from "../../Logic/Tags/TagUtils";
import ValidatedTextField from "../../UI/Input/ValidatedTextField"; import ValidatedTextField from "../../UI/Input/ValidatedTextField";
import {AndOrTagConfigJson} from "./Json/TagConfigJson"; import {TagConfigJson} from "./Json/TagConfigJson";
import {UIEventSource} from "../../Logic/UIEventSource"; import {UIEventSource} from "../../Logic/UIEventSource";
import {FilterState} from "../FilteredLayer"; import {FilterState} from "../FilteredLayer";
import {QueryParameters} from "../../Logic/Web/QueryParameters"; import {QueryParameters} from "../../Logic/Web/QueryParameters";
@ -16,7 +16,7 @@ export default class FilterConfig {
public readonly options: { public readonly options: {
question: Translation; question: Translation;
osmTags: TagsFilter | undefined; osmTags: TagsFilter | undefined;
originalTagsSpec: string | AndOrTagConfigJson originalTagsSpec: TagConfigJson
fields: { name: string, type: string }[] fields: { name: string, type: string }[]
}[]; }[];
public readonly defaultSelection? : number public readonly defaultSelection? : number

View file

@ -1,4 +1,4 @@
import {AndOrTagConfigJson} from "./TagConfigJson"; import {TagConfigJson} from "./TagConfigJson";
export default interface FilterConfigJson { export default interface FilterConfigJson {
/** /**
@ -13,7 +13,7 @@ export default interface FilterConfigJson {
*/ */
options: { options: {
question: string | any; question: string | any;
osmTags?: AndOrTagConfigJson | string, osmTags?: TagConfigJson,
default?: boolean, default?: boolean,
fields?: { fields?: {
/** /**

View file

@ -1,5 +1,5 @@
import {TagRenderingConfigJson} from "./TagRenderingConfigJson"; import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
import {AndOrTagConfigJson} from "./TagConfigJson"; import {TagConfigJson} from "./TagConfigJson";
/** /**
* The PointRenderingConfig gives all details onto how to render a single point of a feature. * The PointRenderingConfig gives all details onto how to render a single point of a feature.
@ -39,7 +39,7 @@ export default interface PointRenderingConfigJson {
* Note: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle * Note: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle
*/ */
iconBadges?: { iconBadges?: {
if: string | AndOrTagConfigJson, if: TagConfigJson,
/** /**
* Badge to show * Badge to show
* Type: icon * Type: icon

View file

@ -1,4 +1,4 @@
import {AndOrTagConfigJson} from "./TagConfigJson"; import {TagConfigJson} from "./TagConfigJson";
import {TagRenderingConfigJson} from "./TagRenderingConfigJson"; import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
@ -7,7 +7,7 @@ export interface MappingConfigJson {
/** /**
* @inheritDoc * @inheritDoc
*/ */
if: AndOrTagConfigJson | string, if: TagConfigJson,
/** /**
* Shown if the 'if is fulfilled * Shown if the 'if is fulfilled
* Type: rendered * Type: rendered
@ -89,7 +89,7 @@ export interface MappingConfigJson {
* hideInAnswer: "_country!=be" * hideInAnswer: "_country!=be"
* } * }
*/ */
hideInAnswer?: boolean | string | AndOrTagConfigJson, hideInAnswer?: boolean | TagConfigJson,
/** /**
* Only applicable if 'multiAnswer' is set. * Only applicable if 'multiAnswer' is set.
* This is for situations such as: * This is for situations such as:
@ -98,7 +98,7 @@ export interface MappingConfigJson {
* Note that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`. * Note that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.
* If this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer` * If this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`
*/ */
ifnot?: AndOrTagConfigJson | string ifnot?: TagConfigJson
/** /**
* If chosen as answer, these tags will be applied as well onto the object. * If chosen as answer, these tags will be applied as well onto the object.
@ -117,7 +117,7 @@ export interface MappingConfigJson {
* If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden * If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden
* Use this sparingly * Use this sparingly
*/ */
priorityIf?: string | AndOrTagConfigJson priorityIf?: TagConfigJson
} }

View file

@ -1,9 +1,22 @@
/** /**
* A small interface to combine tags and tagsfilters. * The main representation of Tags.
* * See https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation
*/
export type TagConfigJson = string | AndTagConfigJson | OrTagConfigJson
/**
* Chain many tags, to match, all of these should be true
* See https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation * See https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation
*/ */
export interface AndOrTagConfigJson { export type OrTagConfigJson = {
and?: (string | AndOrTagConfigJson)[] or: TagConfigJson[]
or?: (string | AndOrTagConfigJson)[] }
} /**
* Chain many tags, to match, a single of these should be true
* See https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation
*/
export type AndTagConfigJson = {
and: TagConfigJson[]
}

View file

@ -1,4 +1,4 @@
import {AndOrTagConfigJson} from "./TagConfigJson"; import {TagConfigJson} from "./TagConfigJson";
/** /**
* A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet. * A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.
@ -39,7 +39,7 @@ export interface TagRenderingConfigJson {
* *
* This is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables... * This is useful to ask a follow-up question. E.g. if there is a diaper table, then ask a follow-up question on diaper tables...
* */ * */
condition?: AndOrTagConfigJson | string; condition?: TagConfigJson;
/** /**
* Allow freeform text input from the user * Allow freeform text input from the user
@ -66,7 +66,7 @@ export interface TagRenderingConfigJson {
* *
* This can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'} * This can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}
*/ */
if: AndOrTagConfigJson | string, if: TagConfigJson,
/** /**
* If the condition `if` is met, the text `then` will be rendered. * If the condition `if` is met, the text `then` will be rendered.
* If not known yet, the user will be presented with `then` as an option * If not known yet, the user will be presented with `then` as an option

View file

@ -71,7 +71,6 @@ export default class LineRenderingConfig extends WithContextLoader {
} }
const fillStr = render(this.fill, undefined) const fillStr = render(this.fill, undefined)
let fill: boolean = undefined;
if (fillStr !== undefined && fillStr !== "") { if (fillStr !== undefined && fillStr !== "") {
style["fill"] = fillStr === "yes" || fillStr === "true" style["fill"] = fillStr === "yes" || fillStr === "true"
} }

View file

@ -1,6 +1,5 @@
import {TagsFilter} from "../../Logic/Tags/TagsFilter"; import {TagsFilter} from "../../Logic/Tags/TagsFilter";
import {RegexTag} from "../../Logic/Tags/RegexTag"; import {RegexTag} from "../../Logic/Tags/RegexTag";
import {param} from "jquery";
export default class SourceConfig { export default class SourceConfig {

View file

@ -14,7 +14,6 @@ import List from "../../UI/Base/List";
import {MappingConfigJson, QuestionableTagRenderingConfigJson} from "./Json/QuestionableTagRenderingConfigJson"; import {MappingConfigJson, QuestionableTagRenderingConfigJson} from "./Json/QuestionableTagRenderingConfigJson";
import {FixedUiElement} from "../../UI/Base/FixedUiElement"; import {FixedUiElement} from "../../UI/Base/FixedUiElement";
import {Paragraph} from "../../UI/Base/Paragraph"; import {Paragraph} from "../../UI/Base/Paragraph";
import UserDetails from "../../Logic/Osm/OsmConnection";
export interface Mapping { export interface Mapping {
readonly if: TagsFilter, readonly if: TagsFilter,