forked from MapComplete/MapComplete
		
	Add substituting tag, remove some old code
This commit is contained in:
		
							parent
							
								
									120832f241
								
							
						
					
					
						commit
						cd1171e678
					
				
					 8 changed files with 112 additions and 31 deletions
				
			
		|  | @ -5,6 +5,7 @@ import {Or} from "../../Logic/Tags/Or"; | |||
| import {And} from "../../Logic/Tags/And"; | ||||
| import {Tag} from "../../Logic/Tags/Tag"; | ||||
| import {TagsFilter} from "../../Logic/Tags/TagsFilter"; | ||||
| import SubstitutingTag from "../../Logic/Tags/SubstitutingTag"; | ||||
| 
 | ||||
| export class FromJSON { | ||||
| 
 | ||||
|  | @ -12,11 +13,12 @@ export class FromJSON { | |||
|         const tag = Utils.SplitFirst(json, "="); | ||||
|         return new Tag(tag[0], tag[1]); | ||||
|     } | ||||
| 
 | ||||
|     public static Tag(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter { | ||||
|         try{ | ||||
|         try { | ||||
|             return this.TagUnsafe(json, context); | ||||
|         }catch(e){ | ||||
|             console.error("Could not parse tag", json,"in context",context,"due to ", e) | ||||
|         } catch (e) { | ||||
|             console.error("Could not parse tag", json, "in context", context, "due to ", e) | ||||
|             throw e; | ||||
|         } | ||||
|     } | ||||
|  | @ -49,6 +51,11 @@ export class FromJSON { | |||
|                     new RegExp("^" + split[1] + "$") | ||||
|                 ); | ||||
|             } | ||||
|             if(tag.indexOf(":=") >= 0){ | ||||
|                 const split = Utils.SplitFirst(tag, ":="); | ||||
|                 return new SubstitutingTag(split[0], split[1]); | ||||
|             } | ||||
|              | ||||
|             if (tag.indexOf("!=") >= 0) { | ||||
|                 const split = Utils.SplitFirst(tag, "!="); | ||||
|                 if (split[1] === "*") { | ||||
|  |  | |||
|  | @ -35,3 +35,32 @@ Regex equals | |||
| A tag can also be tested against a regex with `key~regex`. Note that this regex __must match__ the entire value. If the value is allowed to appear anywhere as substring, use `key~.*regex.*` | ||||
| 
 | ||||
| Equivalently, `key!~regex` can be used if you _don't_ want to match the regex in order to appear. | ||||
| 
 | ||||
| 
 | ||||
| Using other tags as variables | ||||
| ----------------------------- | ||||
| 
 | ||||
| **This is an advanced feature - use with caution** | ||||
| 
 | ||||
| Some tags are automatically set or calculated - see [CalculatedTags](CalculatedTags.md) for an entire overview. | ||||
| If one wants to apply such a value as tag, use a substituting-tag such, for example`survey:date:={_date:now}`. Note that the separator between key and value here is `:=`. | ||||
| The text between `{` and `}` is interpreted as a key, and the respective value is substituted into the string. | ||||
| 
 | ||||
| One can also append, e.g. `key:={some_key} fixed text {some_other_key}`. | ||||
| 
 | ||||
| An assigning tag _cannot_ be used to query OpenStreetMap/Overpass. | ||||
| 
 | ||||
| If using a key or variable which might not be defined, add a condition in the mapping to hide the option. | ||||
| This is because, if `some_other_key` is not defined, one might actually upload the literal text `key={some_other_key}` to OSM - which we do not want. | ||||
| 
 | ||||
| To mitigate this, use: | ||||
| 
 | ||||
| ``` | ||||
| "mappings": [ | ||||
| { | ||||
|     "if":"key:={some_other_key}" | ||||
|     "then": "...", | ||||
|     "hideInAnswer": "some_other_key=" | ||||
| } | ||||
| ] | ||||
| ``` | ||||
|  | @ -1,2 +1,5 @@ | |||
| <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> | ||||
| 	<s:String x:Key="/Default/CodeInspection/Highlighting/SweaWarningsMode/@EntryValue">ShowAndRun</s:String></wpf:ResourceDictionary> | ||||
| 	<s:String x:Key="/Default/CodeInspection/Highlighting/SweaWarningsMode/@EntryValue">ShowAndRun</s:String> | ||||
| 	<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=d2f95dca_002Defa2_002D40b6_002D8190_002D724496f13a75/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="Session" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> | ||||
|   <Nothing /> | ||||
| </SessionState></s:String></wpf:ResourceDictionary> | ||||
|  | @ -46,14 +46,6 @@ export class And extends TagsFilter { | |||
|         return allChoices; | ||||
|     } | ||||
| 
 | ||||
|     substituteValues(tags: any): TagsFilter { | ||||
|         const newChoices = []; | ||||
|         for (const c of this.and) { | ||||
|             newChoices.push(c.substituteValues(tags)); | ||||
|         } | ||||
|         return new And(newChoices); | ||||
|     } | ||||
| 
 | ||||
|     asHumanString(linkToWiki: boolean, shorten: boolean) { | ||||
|         return this.and.map(t => t.asHumanString(linkToWiki, shorten)).join("&"); | ||||
|     } | ||||
|  |  | |||
|  | @ -30,14 +30,6 @@ export class Or extends TagsFilter { | |||
|         return choices; | ||||
|     } | ||||
| 
 | ||||
|     substituteValues(tags: any): TagsFilter { | ||||
|         const newChoices = []; | ||||
|         for (const c of this.or) { | ||||
|             newChoices.push(c.substituteValues(tags)); | ||||
|         } | ||||
|         return new Or(newChoices); | ||||
|     } | ||||
| 
 | ||||
|     asHumanString(linkToWiki: boolean, shorten: boolean) { | ||||
|         return this.or.map(t => t.asHumanString(linkToWiki, shorten)).join("|"); | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										59
									
								
								Logic/Tags/SubstitutingTag.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								Logic/Tags/SubstitutingTag.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| import {TagsFilter} from "./TagsFilter"; | ||||
| 
 | ||||
| /** | ||||
|  * The substituting-tag uses the tags of a feature a variables and replaces them. | ||||
|  * | ||||
|  * e.g. key:={other_key}_{ref} will match an object that has at least 'key'. | ||||
|  * If {other_key} is _not_ defined, it will not be substituted. | ||||
|  * | ||||
|  * The 'key' is always fixed and should not contain substitutions. | ||||
|  * This cannot be used to query features | ||||
|  */ | ||||
| export default class SubstitutingTag implements TagsFilter { | ||||
|     private readonly _key: string; | ||||
|     private readonly _value: string; | ||||
| 
 | ||||
|     constructor(key: string, value: string) { | ||||
|         this._key = key; | ||||
|         this._value = value; | ||||
|     } | ||||
| 
 | ||||
|     private static substituteString(template: string, dict: any) { | ||||
|         for (const k in dict) { | ||||
|             template = template.replace(new RegExp("\\{" + k + "\\}", 'g'), dict[k]) | ||||
|         } | ||||
|         return template; | ||||
|     } | ||||
| 
 | ||||
|     asHumanString(linkToWiki: boolean, shorten: boolean) { | ||||
|         return this._key + ":=" + this._value; | ||||
|     } | ||||
| 
 | ||||
|     asOverpass(): string[] { | ||||
|         throw "A variable with substitution can not be used to query overpass" | ||||
|     } | ||||
| 
 | ||||
|     isEquivalent(other: TagsFilter): boolean { | ||||
|         if (!(other instanceof SubstitutingTag)) { | ||||
|             return false; | ||||
|         } | ||||
|         return other._key === this._key && other._value === this._value; | ||||
|     } | ||||
| 
 | ||||
|     isUsableAsAnswer(): boolean { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     matchesProperties(properties: any): boolean { | ||||
|         const value = properties[this._key]; | ||||
|         if (value === undefined || value === "") { | ||||
|             return false; | ||||
|         } | ||||
|         const expectedValue = SubstitutingTag.substituteString(this._value, properties); | ||||
|         return value === expectedValue; | ||||
|     } | ||||
| 
 | ||||
|     usedKeys(): string[] { | ||||
|         return [this._key]; | ||||
|     } | ||||
| } | ||||
|  | @ -2,8 +2,6 @@ export abstract class TagsFilter { | |||
| 
 | ||||
|     abstract asOverpass(): string[] | ||||
| 
 | ||||
|     abstract substituteValues(tags: any): TagsFilter; | ||||
| 
 | ||||
|     abstract isUsableAsAnswer(): boolean; | ||||
| 
 | ||||
|     abstract isEquivalent(other: TagsFilter): boolean; | ||||
|  | @ -14,11 +12,4 @@ export abstract class TagsFilter { | |||
| 
 | ||||
|     abstract usedKeys(): string[]; | ||||
|      | ||||
|     public matches(tags: { k: string, v: string }[]) { | ||||
|         const properties = {}; | ||||
|         for (const kv of tags) { | ||||
|             properties[kv.k] = kv.v; | ||||
|         } | ||||
|         return this.matchesProperties(properties); | ||||
|     } | ||||
| } | ||||
|  | @ -79,6 +79,14 @@ new T("Tags", [ | |||
|         equal(nameStartsWith.matchesProperties({"name": "Sint-Anna"}), false) | ||||
|         equal(nameStartsWith.matchesProperties({"name": ""}), false) | ||||
|          | ||||
|          | ||||
|         const assign = FromJSON.Tag("survey:date:={_date:now}") | ||||
|         equal(assign.matchesProperties({"survey:date":"2021-03-29", "_date:now":"2021-03-29"}), true); | ||||
|         equal(assign.matchesProperties({"survey:date":"2021-03-29", "_date:now":"2021-01-01"}), false); | ||||
|         equal(assign.matchesProperties({"survey:date":"2021-03-29"}), false); | ||||
|         equal(assign.matchesProperties({"_date:now":"2021-03-29"}), false); | ||||
|         equal(assign.matchesProperties({"some_key":"2021-03-29"}), false); | ||||
| 
 | ||||
|     })], | ||||
|     ["Is equivalent test", (() => { | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue