Ticket #17669: 17669,22096.patch
| File 17669,22096.patch, 45.7 KB (added by , 3 years ago) |
|---|
-
resources/data/validator/numeric.mapcss
Subject: [PATCH] Fix #17669, #22096: Replace placeholders in calculations --- IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/resources/data/validator/numeric.mapcss b/resources/data/validator/numeric.mapcss
a b 67 67 assertNoMatch: "node building:levels=0"; /* valid because there can be building:levels:underground > 0 or roof:levels > 0 */ 68 68 } 69 69 70 *[height][height =~ /^[0-9]+(\.[0-9]+)?(( )*(metre|metres|meter|meters|Metre|Metres|Meter|Meters)|m)$/] { 70 *[roof:height][roof:height =~ /^0*(\.0*)?( (m|ft))?$/][roof:shape=flat] { 71 throwWarning: tr("{0} is unnecessary for {1}", "{0.tag}", "{2.tag}"); 72 group: tr("unnecessary tag"); 73 fixRemove: "{0.key}"; 74 set zero_roof_height_flat; 75 assertMatch: "node roof:height=0 roof:shape=flat"; 76 assertMatch: "node roof:shape=flat roof:height=\"00.00000 ft\" roof:shape=flat"; 77 assertNoMatch: "node roof:shape=flat roof:height=2 m roof:shape=flat"; 78 assertNoMatch: "node roof:height=0 roof:shape=gabled"; 79 } 80 81 /********************* 82 * Begin Unit checks * 83 *********************/ 84 /* See https://wiki.openstreetmap.org/wiki/Map_features/Units */ 85 /* 1. Replace aliases to make the rest of the checks easier to implement */ 86 /* Distance measurements, note that these should look also match `,` separators to ensure that at least one error is matched */ 87 /* Meters; Note that we cannot assertMatch "2 m" since we replace the double space with a single space */ 88 *[height][height =~ /^(?i)[0-9]+([.,][0-9]+)?( *(metres?|meters?)|m| {2,}m)$/], 89 *[roof:height][roof:height =~ /^(?i)[0-9]+([.,][0-9]+)?( *(metres?|meters?)|m| {2,}m)$/]!.zero_roof_height_flat, 90 *[width][width =~ /^(?i)[0-9]+([.,][0-9]+)?( *(metres?|meters?)|m| {2,}m)$/], 91 *[maxwidth][maxwidth =~ /^(?i)[0-9]+([.,][0-9]+)?( *(metres?|meters?)|m| {2,}m)$/], 92 *[min_height][min_height =~ /^(?i)-?[0-9]+([.,][0-9]+)?( *(metres?|meters?)|m| {2,}m)$/], 93 *[maxheight][maxheight =~ /^(?i)[1-9][0-9]*([.,][0-9]+)?( *(metres?|meters?)|m| {2,}m)$/], 94 *[maxlength][maxlength =~ /^(?i)[1-9][0-9]*([.,][0-9]+)?( *(metres?|meters?)|m| {2,}m)$/] { 71 95 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}"); 72 set height_meter_autofix; 73 fixAdd: concat("height=", get(regexp_match("([0-9.]+)( )*(.+)",tag("height")),1)," m"); 96 fixAdd: concat("{0.key}", "=", get(regexp_match("([0-9.]+) *.+", "{0.value}"), 1), " m"); 74 97 assertMatch: "node height=6.78 meters"; 98 assertMatch: "node height=6,78 meters"; 75 99 assertMatch: "node height=5 metre"; 76 100 assertMatch: "node height=2m"; 77 101 assertNoMatch: "node height=2 m"; 78 102 assertNoMatch: "node height=5"; 103 assertMatch: "node maxheight=6.78 meters"; 104 assertMatch: "node maxheight=5 metre"; 105 assertMatch: "node maxheight=2m"; 106 assertNoMatch: "node maxheight=2 m"; 107 assertNoMatch: "node maxheight=5"; 108 assertMatch: "node roof:height=6.78 meters"; 109 assertMatch: "node roof:height=5 metre"; 110 assertMatch: "node roof:height=2m"; 111 assertNoMatch: "node roof:height=2 m"; 112 assertNoMatch: "node roof:height=5"; 113 assertMatch: "node maxlength=6.78 meters"; 114 assertMatch: "node maxlength=5 metre"; 115 assertMatch: "node maxlength=2m"; 116 assertNoMatch: "node maxlength=2 m"; 117 assertNoMatch: "node maxlength=5"; 118 assertMatch: "node width=6.78 meters"; 119 assertMatch: "node width=5 metre"; 120 assertMatch: "node width=2m"; 121 assertNoMatch: "node width=2 m"; 122 assertNoMatch: "node width=5"; 123 assertMatch: "node maxwidth=6.78 meters"; 124 assertMatch: "node maxwidth=5 metre"; 125 assertMatch: "node maxwidth=2m"; 126 assertNoMatch: "node maxwidth=2 m"; 127 assertNoMatch: "node maxwidth=5"; 128 assertMatch: "node min_height=6.78 meters"; 129 assertMatch: "node min_height=5 metre"; 130 assertMatch: "node min_height=2m"; 131 assertNoMatch: "node min_height=2 m"; 132 assertNoMatch: "node min_height=5"; 79 133 } 80 *[height][height =~ /^[0-9]+(\.[0-9]+)?(( )*(foot|Foot|feet|Feet)|ft)$/] { 81 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}"); 82 set height_foot_autofix; 83 fixAdd: concat("height=", get(regexp_match("([0-9.]+)( )*(.+)",tag("height")),1)," ft"); 134 135 /* Foot inches */ 136 *[height][height =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/], 137 *[maxheight][maxheight =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/], 138 *[roof:height][roof:height =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/]!.zero_roof_height_flat, 139 *[maxlength][maxlength =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/], 140 *[width][width =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/], 141 *[maxwidth][maxwidth =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/] { 142 throwWarning: tr("unusual value of {0}: use abbreviation for '' for foot and \" for inches, no spaces", "{0.key}"); 143 fixAdd: concat("{0.key}", "=", get(regexp_match("([0-9.]+) *.+", "{0.value}"), 1), "'"); 84 144 assertMatch: "node height=6.78 foot"; 85 145 assertMatch: "node height=5 Feet"; 86 assertMatch: "node height=2 ft";87 assertNoMatch: "node height=2 ft";146 assertMatch: "node height=2 '"; 147 assertNoMatch: "node height=2'"; 88 148 assertNoMatch: "node height=5"; 149 assertMatch: "node maxheight=6.78 foot"; 150 assertMatch: "node maxheight=5 Feet"; 151 assertMatch: "node maxheight=2 '"; 152 assertNoMatch: "node maxheight=2'"; 153 assertNoMatch: "node maxheight=5"; 154 assertMatch: "node roof:height=6.78 foot"; 155 assertMatch: "node roof:height=5 Feet"; 156 assertMatch: "node roof:height=2 '"; 157 assertNoMatch: "node roof:height=2'"; 158 assertNoMatch: "node roof:height=5"; 159 assertMatch: "node maxlength=6.78 foot"; 160 assertMatch: "node maxlength=5 Feet"; 161 assertMatch: "node maxlength=2 '"; 162 assertNoMatch: "node maxlength=2'"; 163 assertNoMatch: "node maxlength=5"; 164 assertMatch: "node width=6.78 foot"; 165 assertMatch: "node width=5 Feet"; 166 assertMatch: "node width=2 '"; 167 assertNoMatch: "node width=2'"; 168 assertNoMatch: "node width=5"; 169 assertMatch: "node maxwidth=6.78 foot"; 170 assertMatch: "node maxwidth=5 Feet"; 171 assertMatch: "node maxwidth=2 '"; 172 assertNoMatch: "node maxwidth=2'"; 173 assertNoMatch: "node maxwidth=5"; 89 174 } 90 *[height][height =~ /^[0-9]+,[0-9][0-9]?( (m|ft))?$/] { 175 176 /* 2. Convert `,` to `.` */ 177 *[height][height =~ /^[0-9]+,[0-9][0-9]?( m|\')?$/], 178 *[maxheight][maxheight =~ /^[0-9]+,[0-9][0-9]?( m|\')?$/], 179 *[roof:height][roof:height =~ /^[0-9]+,[0-9][0-9]?( m|\')?$/], 180 *[maxlength][maxlength =~ /^[0-9]+,[0-9][0-9]?( m|\')?$/], 181 *[width][width =~ /^[0-9]+,[0-9][0-9]?( m|\')?$/], 182 *[maxwidth][maxwidth =~ /^[0-9]+,[0-9][0-9]?( m|\')?$/], 183 *[min_height][min_height =~ /^-?[0-9]+,[0-9][0-9]?( m|\')?$/], 184 *[maxaxleload][maxaxleload =~ /^[0-9]+,[0-9][0-9]?( (t|kg|st|lbs))?$/], 185 *[maxweight][maxweight =~ /^[0-9]+,[0-9][0-9]?( (t|kg|st|lbs))?$/], 186 *[distance][distance =~ /^[0-9]+,[0-9][0-9]?( (m|km|mi|nmi))?$/] { 91 187 throwWarning: tr("unusual value of {0}: use . instead of , as decimal separator", "{0.key}"); 92 fixAdd: concat(" height=", replace(tag("height"), ",", "."));93 set height_separator_autofix;188 fixAdd: concat("{0.key}", "=", replace(tag("{0.key}"), ",", ".")); 189 set separator_autofix; 94 190 assertMatch: "node height=5,5"; 95 191 assertMatch: "node height=12,00"; 96 assertMatch: "node height=12,5 ft";192 assertMatch: "node height=12,5'"; 97 193 assertNoMatch: "node height=12,000"; 98 194 assertNoMatch: "node height=3,50,5"; 99 195 assertNoMatch: "node height=3.5"; 100 196 assertNoMatch: "node height=4"; 101 }102 103 *[maxheight][maxheight =~ /^[1-9][0-9]*(\.[0-9]+)?(( )*(metre|metres|meter|meters|Metre|Metres|Meter|Meters)|m)$/] {104 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");105 set maxheight_meter_autofix;106 fixAdd: concat("maxheight=", get(regexp_match("([0-9.]+)( )*(.+)",tag("maxheight")),1)," m");107 assertMatch: "node maxheight=6.78 meters";108 assertMatch: "node maxheight=5 metre";109 assertMatch: "node maxheight=2m";110 assertNoMatch: "node maxheight=2 m";111 assertNoMatch: "node maxheight=5";112 }113 *[maxheight][maxheight =~ /^[0-9]+(\.[0-9]+)?(( )*(foot|Foot|feet|Feet)|ft)$/] {114 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");115 set maxheight_foot_autofix;116 fixAdd: concat("maxheight=", get(regexp_match("([0-9.]+)( )*(.+)",tag("maxheight")),1)," ft");117 assertMatch: "node maxheight=6.78 foot";118 assertMatch: "node maxheight=5 Feet";119 assertMatch: "node maxheight=2ft";120 assertNoMatch: "node maxheight=2 ft";121 assertNoMatch: "node maxheight=5";122 }123 *[maxheight][maxheight =~ /^[0-9]+,[0-9][0-9]?( (m|ft))?$/] {124 throwWarning: tr("unusual value of {0}: use . instead of , as decimal separator", "{0.key}");125 fixAdd: concat("maxheight=", replace(tag("maxheight"), ",", "."));126 set maxheight_separator_autofix;127 197 assertMatch: "node maxheight=5,5"; 128 198 assertMatch: "node maxheight=12,00"; 129 assertMatch: "node maxheight=12,5 ft";199 assertMatch: "node maxheight=12,5'"; 130 200 assertNoMatch: "node maxheight=12,000"; 131 201 assertNoMatch: "node maxheight=3,50,5"; 132 202 assertNoMatch: "node maxheight=3.5"; 133 203 assertNoMatch: "node maxheight=4"; 134 }135 136 *[roof:height][roof:height =~ /^0*(\.0*)?( (m|ft))?$/][roof:shape=flat] {137 throwWarning: tr("{0} is unnecessary for {1}", "{0.tag}", "{2.tag}");138 group: tr("unnecessary tag");139 fixRemove: "{0.key}";140 set zero_roof_height_flat;141 assertMatch: "node roof:height=0 roof:shape=flat";142 assertMatch: "node roof:shape=flat roof:height=\"00.00000 ft\" roof:shape=flat";143 assertNoMatch: "node roof:shape=flat roof:height=2 m roof:shape=flat";144 assertNoMatch: "node roof:height=0 roof:shape=gabled";145 }146 *[roof:height][roof:height =~ /^[0-9]+(\.[0-9]+)?(( )*(metre|metres|meter|meters|Metre|Metres|Meter|Meters)|m)$/]!.zero_roof_height_flat {147 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");148 set roof_height_meter_autofix;149 fixAdd: concat("roof:height=", get(regexp_match("([0-9.]+)( )*(.+)",tag("roof:height")),1)," m");150 assertMatch: "node roof:height=6.78 meters";151 assertMatch: "node roof:height=5 metre";152 assertMatch: "node roof:height=2m";153 assertNoMatch: "node roof:height=2 m";154 assertNoMatch: "node roof:height=5";155 }156 *[roof:height][roof:height =~ /^[0-9]+(\.[0-9]+)?(( )*(foot|Foot|feet|Feet)|ft)$/]!.zero_roof_height_flat {157 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");158 set roof_height_foot_autofix;159 fixAdd: concat("roof:height=", get(regexp_match("([0-9.]+)( )*(.+)",tag("roof:height")),1)," ft");160 assertMatch: "node roof:height=6.78 foot";161 assertMatch: "node roof:height=5 Feet";162 assertMatch: "node roof:height=2ft";163 assertNoMatch: "node roof:height=2 ft";164 assertNoMatch: "node roof:height=5";165 }166 *[roof:height][roof:height =~ /^[0-9]+,[0-9][0-9]?( (m|ft))?$/] {167 throwWarning: tr("unusual value of {0}: use . instead of , as decimal separator", "{0.key}");168 fixAdd: concat("roof:height=", replace(tag("roof:height"), ",", "."));169 set roof_height_separator_autofix;170 204 assertMatch: "node roof:height=5,5"; 171 205 assertMatch: "node roof:height=12,00"; 172 assertMatch: "node roof:height=12,5 ft";206 assertMatch: "node roof:height=12,5'"; 173 207 assertNoMatch: "node roof:height=12,000"; 174 208 assertNoMatch: "node roof:height=3,50,5"; 175 209 assertNoMatch: "node roof:height=3.5"; 176 210 assertNoMatch: "node roof:height=4"; 177 }178 179 *[maxlength][maxlength =~ /^[1-9][0-9]*(\.[0-9]+)?(( )*(metre|metres|meter|meters|Metre|Metres|Meter|Meters)|m)$/] {180 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");181 set maxlength_meter_autofix;182 fixAdd: concat("maxlength=", get(regexp_match("([0-9.]+)( )*(.+)",tag("maxlength")),1)," m");183 assertMatch: "node maxlength=6.78 meters";184 assertMatch: "node maxlength=5 metre";185 assertMatch: "node maxlength=2m";186 assertNoMatch: "node maxlength=2 m";187 assertNoMatch: "node maxlength=5";188 }189 *[maxlength][maxlength =~ /^[0-9]+(\.[0-9]+)?(( )*(foot|Foot|feet|Feet)|ft)$/] {190 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");191 set maxlength_foot_autofix;192 fixAdd: concat("maxlength=", get(regexp_match("([0-9.]+)( )*(.+)",tag("maxlength")),1)," ft");193 assertMatch: "node maxlength=6.78 foot";194 assertMatch: "node maxlength=5 Feet";195 assertMatch: "node maxlength=2ft";196 assertNoMatch: "node maxlength=2 ft";197 assertNoMatch: "node maxlength=5";198 }199 *[maxlength][maxlength =~ /^[0-9]+,[0-9][0-9]?( (m|ft))?$/] {200 throwWarning: tr("unusual value of {0}: use . instead of , as decimal separator", "{0.key}");201 fixAdd: concat("maxlength=", replace(tag("maxlength"), ",", "."));202 set maxlength_separator_autofix;203 211 assertMatch: "node maxlength=5,5"; 204 212 assertMatch: "node maxlength=12,00"; 205 assertMatch: "node maxlength=12,5 ft";213 assertMatch: "node maxlength=12,5'"; 206 214 assertNoMatch: "node maxlength=12,000"; 207 215 assertNoMatch: "node maxlength=3,50,5"; 208 216 assertNoMatch: "node maxlength=3.5"; 209 217 assertNoMatch: "node maxlength=4"; 210 }211 212 *[width][width =~ /^[0-9]+(\.[0-9]+)?(( )*(metre|metres|meter|meters|Metre|Metres|Meter|Meters)|m)$/] {213 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");214 set width_meter_autofix;215 fixAdd: concat("width=", get(regexp_match("([0-9.]+)( )*(.+)",tag("width")),1)," m");216 assertMatch: "node width=6.78 meters";217 assertMatch: "node width=5 metre";218 assertMatch: "node width=2m";219 assertNoMatch: "node width=2 m";220 assertNoMatch: "node width=5";221 }222 *[width][width =~ /^[0-9]+(\.[0-9]+)?(( )*(foot|Foot|feet|Feet)|ft)$/] {223 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");224 set width_foot_autofix;225 fixAdd: concat("width=", get(regexp_match("([0-9.]+)( )*(.+)",tag("width")),1)," ft");226 assertMatch: "node width=6.78 foot";227 assertMatch: "node width=5 Feet";228 assertMatch: "node width=2ft";229 assertNoMatch: "node width=2 ft";230 assertNoMatch: "node width=5";231 }232 *[width][width =~ /^[0-9]+,[0-9][0-9]?( (m|ft))?$/] {233 throwWarning: tr("unusual value of {0}: use . instead of , as decimal separator", "{0.key}");234 fixAdd: concat("width=", replace(tag("width"), ",", "."));235 set width_separator_autofix;236 218 assertMatch: "node width=5,5"; 237 219 assertMatch: "node width=12,00"; 238 220 assertNoMatch: "node width=12,000"; 239 221 assertNoMatch: "node width=3,50,5"; 240 222 assertNoMatch: "node width=3.5"; 241 223 assertNoMatch: "node width=4"; 242 }243 244 *[maxwidth][maxwidth=~ /^[0-9]+(\.[0-9]+)?(( )*(metre|metres|meter|meters|Metre|Metres|Meter|Meters)|m)$/] {245 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");246 set maxwidth_meter_autofix;247 fixAdd: concat("maxwidth=", get(regexp_match("([0-9.]+)( )*(.+)",tag("maxwidth")),1)," m");248 assertMatch: "node maxwidth=6.78 meters";249 assertMatch: "node maxwidth=5 metre";250 assertMatch: "node maxwidth=2m";251 assertNoMatch: "node maxwidth=2 m";252 assertNoMatch: "node maxwidth=5";253 }254 *[maxwidth][maxwidth =~ /^[0-9]+(\.[0-9]+)?(( )*(foot|Foot|feet|Feet)|ft)$/] {255 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");256 set maxwidth_foot_autofix;257 fixAdd: concat("maxwidth=", get(regexp_match("([0-9.]+)( )*(.+)",tag("maxwidth")),1)," ft");258 assertMatch: "node maxwidth=6.78 foot";259 assertMatch: "node maxwidth=5 Feet";260 assertMatch: "node maxwidth=2ft";261 assertNoMatch: "node maxwidth=2 ft";262 assertNoMatch: "node maxwidth=5";263 }264 *[maxwidth][maxwidth =~ /^[0-9]+,[0-9][0-9]?( (m|ft))?$/] {265 throwWarning: tr("unusual value of {0}: use . instead of , as decimal separator", "{0.key}");266 fixAdd: concat("maxwidth=", replace(tag("maxwidth"), ",", "."));267 set maxwidth_separator_autofix;268 224 assertMatch: "node maxwidth=5,5"; 269 225 assertMatch: "node maxwidth=12,00"; 270 226 assertNoMatch: "node maxwidth=12,000"; 271 227 assertNoMatch: "node maxwidth=3,50,5"; 272 228 assertNoMatch: "node maxwidth=3.5"; 273 229 assertNoMatch: "node maxwidth=4"; 274 }275 276 *[height ][height !~ /^(([0-9]+(\.[0-9]+)?( (m|ft))?)|([1-9][0-9]*\'((10|11|[0-9])((\.[0-9]+)?)\")?))$/]!.height_separator_autofix!.height_meter_autofix!.height_foot_autofix,277 *[maxheight ][maxheight !~ /^(([1-9][0-9]*(\.[0-9]+)?( (m|ft))?)|([0-9]+\'(([0-9]|10|11)(\.[0-9]*)?\")?)|none|default|below_default)$/]!.maxheight_separator_autofix!.maxheight_meter_autofix!.maxheight_foot_autofix,278 *[roof:height][roof:height !~ /^(([0-9]+(\.[0-9]+)?( (m|ft))?)|([1-9][0-9]*\'((10|11|[0-9])((\.[0-9]+)?)\")?))$/]!.roof_height_separator_autofix!.roof_height_meter_autofix!.roof_height_foot_autofix!.zero_roof_height_flat,279 *[maxlength ][maxlength !~ /^(([1-9][0-9]*(\.[0-9]+)?( (m|ft))?)|([0-9]+\'(([0-9]|10|11)(\.[0-9]*)?\")?)|none|default|below_default)$/]!.maxlength_separator_autofix!.maxlength_meter_autofix!.maxlength_foot_autofix,280 *[width ][width !~ /^(([0-9]+(\.[0-9]+)?( (m|ft))?)|([0-9]+\'([0-9]+(\.[0-9]+)?\")?))$/]!.width_separator_autofix!.width_meter_autofix!.width_foot_autofix,281 *[maxwidth ][maxwidth !~ /^(([0-9]+(\.[0-9]+)?( (m|ft))?)|([0-9]+\'([0-9]+(\.[0-9]+)?\")?))$/]!.maxwidth_separator_autofix!.maxwidth_meter_autofix!.maxwidth_foot_autofix {282 throwWarning: tr("unusual value of {0}: {1} is default; only positive values; point is decimal separator; if units, put space then unit", "{0.key}", tr("meters"));283 assertMatch: "node height=medium";284 assertMatch: "node maxheight=-5";285 assertMatch: "node maxlength=0";286 assertMatch: "node maxlength=10'13\"";287 assertMatch: "node width=10'2.\"";288 assertMatch: "node maxheight=\"2. m\"";289 assertMatch: "node height=\"12. m\"";290 assertNoMatch: "node height=6.78 meters";291 assertNoMatch: "node height=5 metre";292 assertNoMatch: "node height=2m";293 assertNoMatch: "node height=3";294 assertNoMatch: "node height=2.22 m";295 assertNoMatch: "node height=7.8";296 assertNoMatch: "node maxwidth=7 ft";297 assertNoMatch: "node height=22'";298 assertNoMatch: "node width=10'5\"";299 assertNoMatch: "node width=10'";300 }301 302 *[min_height][min_height =~ /^-?[0-9]+(\.[0-9]+)?(( )*(metre|metres|meter|meters|Metre|Metres|Meter|Meters)|m)$/] {303 throwWarning: tr("unusual value of {0}: use abbreviation for unit and space between value and unit", "{0.key}");304 fixAdd: concat("min_height=", get(regexp_match("(-?[0-9.]+)( )*(.+)",tag("min_height")),1)," m");305 set min_height_meter_autofix;306 assertMatch: "node min_height=6.78 meters";307 assertMatch: "node min_height=5 metre";308 assertMatch: "node min_height=2m";309 assertNoMatch: "node min_height=2 m";310 assertNoMatch: "node min_height=5";311 }312 *[min_height][min_height =~ /^-?[0-9]+,[0-9][0-9]?( m|\')?$/] {313 throwWarning: tr("unusual value of {0}: use . instead of , as decimal separator", "{0.key}");314 fixAdd: concat("min_height=", replace(tag("min_height"), ",", "."));315 set min_height_separator_autofix;316 230 assertMatch: "node min_height=5,5"; 317 231 assertMatch: "node min_height=12,00"; 318 232 assertMatch: "node min_height=12,5'"; … … 320 234 assertNoMatch: "node min_height=3,50,5"; 321 235 assertNoMatch: "node min_height=3.5"; 322 236 assertNoMatch: "node min_height=4"; 323 }324 *[min_height ][min_height !~ /^(-?([0-9]+(\.[0-9]+)?( m)?)|(-?[1-9][0-9]*\'((10|11|[0-9])((\.[0-9]+)?)\")?))$/]!.min_height_separator_autofix!.min_height_meter_autofix!.min_height_foot_autofix {325 throwWarning: tr("unusual value of {0}: {1} is default; point is decimal separator; if units, put space then unit", "{0.key}", tr("meters"));326 assertMatch: "node min_height=\"12. m\"";327 assertNoMatch: "node min_height=-5";328 }329 330 *[maxaxleload][maxaxleload =~ /^[0-9]+,[0-9][0-9]?( (t|kg|st|lbs))?$/] {331 throwWarning: tr("unusual value of {0}: use . instead of , as decimal separator", "{0.key}");332 fixAdd: concat("maxaxleload=", replace(tag("maxaxleload"), ",", "."));333 set maxaxleload_separator_autofix;334 237 assertMatch: "node maxaxleload=5,5"; 335 238 assertMatch: "node maxaxleload=12,00"; 336 239 assertNoMatch: "node maxaxleload=12,000"; 337 240 assertNoMatch: "node maxaxleload=3,50,5"; 338 241 assertNoMatch: "node maxaxleload=3.5"; 339 242 assertNoMatch: "node maxaxleload=4"; 340 }341 342 *[maxweight][maxweight =~ /^[0-9]+,[0-9][0-9]?( (t|kg|st|lbs))?$/] {343 throwWarning: tr("unusual value of {0}: use . instead of , as decimal separator", "{0.key}");344 fixAdd: concat("maxweight=", replace(tag("maxweight"), ",", "."));345 set maxweight_separator_autofix;346 243 assertMatch: "node maxweight=5,5"; 347 244 assertMatch: "node maxweight=12,00"; 348 245 assertNoMatch: "node maxweight=12,000"; 349 246 assertNoMatch: "node maxweight=3,50,5"; 350 247 assertNoMatch: "node maxweight=3.5"; 351 248 assertNoMatch: "node maxweight=4"; 249 assertMatch: "node distance=5,5"; 250 assertMatch: "node distance=12,00"; 251 assertNoMatch: "node distance=12,000"; 252 assertNoMatch: "node distance=3,50,5"; 253 assertNoMatch: "node distance=3.5"; 254 assertNoMatch: "node distance=4"; 255 } 256 /* 3. Convert to the default unit for usage later. Use the tag prefixed with _. */ 257 /* 4. Start doing comparison checks. */ 258 259 *[height ][height !~ /^(([0-9]+(\.[0-9]+)?( m)?)|([1-9][0-9]*\'((10|11|[0-9])((\.[0-9]+)?)\")?))$/], 260 *[maxheight ][maxheight !~ /^(([1-9][0-9]*(\.[0-9]+)?( m)?)|([0-9]+\'(([0-9]|10|11)(\.[0-9]*)?\")?)|none|default|below_default)$/], 261 *[min_height ][min_height !~ /^(-?([0-9]+(\.[0-9]+)?( m)?)|(-?[1-9][0-9]*\'((10|11|[0-9])((\.[0-9]+)?)\")?))$/], 262 *[roof:height][roof:height !~ /^(([0-9]+(\.[0-9]+)?( m)?)|([1-9][0-9]*\'((10|11|[0-9])((\.[0-9]+)?)\")?))$/]!.zero_roof_height_flat, 263 *[maxlength ][maxlength !~ /^(([1-9][0-9]*(\.[0-9]+)?( m)?)|([0-9]+\'(([0-9]|10|11)(\.[0-9]*)?\")?)|none|default|below_default)$/], 264 *[width ][width !~ /^(([0-9]+(\.[0-9]+)?( m)?)|([0-9]+\'([0-9]+(\.[0-9]+)?\")?))$/], 265 *[maxwidth ][maxwidth !~ /^(([0-9]+(\.[0-9]+)?( m)?)|([0-9]+\'([0-9]+(\.[0-9]+)?\")?))$/] { 266 throwWarning: tr("unusual value of {0}: meters is default; only positive values; point is decimal separator; if units, put space then unit", "{0.key}"); 267 assertMatch: "node height=medium"; 268 assertMatch: "node maxheight=-5"; 269 assertMatch: "node maxlength=0"; 270 assertMatch: "node maxlength=10'13\""; 271 assertMatch: "node width=10'2.\""; 272 assertMatch: "node maxheight=\"2. m\""; 273 assertMatch: "node height=\"12. m\""; 274 assertNoMatch: "node height=6.78 m"; 275 assertNoMatch: "node height=5 m"; 276 assertNoMatch: "node height=2 m"; 277 assertNoMatch: "node height=3"; 278 assertNoMatch: "node height=2.22 m"; 279 assertNoMatch: "node height=7.8"; 280 assertMatch: "node min_height=\"12. m\""; 281 assertNoMatch: "node min_height=-5"; 282 assertNoMatch: "node maxwidth=7'"; 283 assertNoMatch: "node height=22'"; 284 assertNoMatch: "node width=10'5\""; 285 assertNoMatch: "node width=10'"; 352 286 } 353 287 354 *[maxaxleload][maxaxleload !~ /^([0-9]+(\.[0-9]+)?( (t|kg|st|lbs))?)$/] !.maxaxleload_separator_autofix,355 *[maxweight][maxweight !~ /^([0-9]+(\.[0-9]+)?( (t|kg|st|lbs))?)$/] !.maxweight_separator_autofix{288 *[maxaxleload][maxaxleload !~ /^([0-9]+(\.[0-9]+)?( (t|kg|st|lbs))?)$/], 289 *[maxweight][maxweight !~ /^([0-9]+(\.[0-9]+)?( (t|kg|st|lbs))?)$/] { 356 290 throwWarning: tr("unusual value of {0}: {1} is default; only positive values; point is decimal separator; if units, put space then unit", "{0.key}", tr("tonne")); 357 291 assertMatch: "node maxaxleload=something"; 358 292 assertMatch: "node maxweight=-5"; … … 379 313 assertNoMatch: "way maxspeed=variable"; 380 314 } 381 315 382 *[distance][distance =~ /^[0-9]+,[0-9][0-9]?( (m|km|mi|nmi))?$/] { 383 throwWarning: tr("unusual value of {0}: use . instead of , as decimal separator", "{0.key}"); 384 fixAdd: concat("distance=", replace(tag("distance"), ",", ".")); 385 set distance_separator_autofix; 386 assertMatch: "node distance=5,5"; 387 assertMatch: "node distance=12,00"; 388 assertNoMatch: "node distance=12,000"; 389 assertNoMatch: "node distance=3,50,5"; 390 assertNoMatch: "node distance=3.5"; 391 assertNoMatch: "node distance=4"; 392 } 393 *[distance][distance !~ /^(([0-9]+(\.[0-9]+)?( (m|km|mi|nmi))?)|([0-9]+\'([0-9]+(\.[0-9]+)?\")?))$/]!.distance_separator_autofix { 316 *[distance][distance !~ /^(([0-9]+(\.[0-9]+)?( (m|km|mi|nmi))?)|([0-9]+\'([0-9]+(\.[0-9]+)?\")?))$/] { 394 317 throwWarning: tr("unusual value of {0}: {1} is default; only positive values; point is decimal separator; if units, put space then unit", "{0.key}", tr("kilometers")); 395 318 assertMatch: "way distance=something"; 396 319 assertMatch: "way distance=-5"; … … 421 344 assertNoMatch: "way frequency=123.5 MHz"; 422 345 } 423 346 347 /******************* 348 * End Unit checks * 349 *******************/ 350 424 351 way[gauge][gauge =~ /^(broad|standard|narrow)$/], 425 352 relation[gauge][gauge =~ /^(broad|standard|narrow)$/] { 426 353 throwWarning: tr("imprecise value of {0}", "{0.tag}"); … … 523 450 assertMatch: "node direction=45-100;190-250;300-"; 524 451 assertNoMatch: "node direction=45-100;190-250;300"; 525 452 assertNoMatch: "node direction=90;270"; 526 assertNoMatch: "node direction=up"; 453 assertNoMatch: "node direction=up"; 527 454 assertNoMatch: "node direction=down"; /* up/down are replaced by incline tag, has separate warning */ 528 455 assertMatch: "node direction=-10"; 529 456 assertNoMatch: "node direction=0"; -
src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
a b 231 231 } 232 232 final Selector selector = check.whichSelectorMatchesEnvironment(env); 233 233 if (selector != null) { 234 check.rule.declaration.execute(env); 234 final Environment envWithSelector = env.withSelector(selector); 235 check.rule.declaration.execute(envWithSelector); 235 236 if (!ignoreError && !check.errors.isEmpty()) { 236 r.addAll(check.getErrorsForPrimitive(p, selector, env , new MapCSSTagCheckerAndRule(check.rule)));237 r.addAll(check.getErrorsForPrimitive(p, selector, envWithSelector, new MapCSSTagCheckerAndRule(check.rule))); 237 238 } 238 239 } 239 240 } -
src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerAsserts.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerAsserts.java b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerAsserts.java
a b 74 74 // Check that autofix works as expected 75 75 Command fix = check.fixPrimitive(p); 76 76 if (fix != null && fix.executeCommand() && !MapCSSTagChecker.getErrorsForPrimitive(p, true, checksToRun).isEmpty()) { 77 assertionConsumer.accept(MessageFormat.format("Autofix does not work for test ''{0}'' (i.e., {1}) ",78 check.getMessage(p), check.rule.selectors ));77 assertionConsumer.accept(MessageFormat.format("Autofix does not work for test ''{0}'' (i.e., {1}). Failing test: {2}", 78 check.getMessage(p), check.rule.selectors, i.getKey())); 79 79 } 80 80 } 81 81 ds.removePrimitive(p); -
src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerFixCommand.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerFixCommand.java b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerFixCommand.java
a b 48 48 static String evaluateObject(final Object obj, final OsmPrimitive p, final Selector matchingSelector) { 49 49 final String s; 50 50 if (obj instanceof Expression) { 51 s = (String) ((Expression) obj).evaluate(new Environment(p) );51 s = (String) ((Expression) obj).evaluate(new Environment(p).withSelector(matchingSelector)); 52 52 } else if (obj instanceof String) { 53 53 s = (String) obj; 54 54 } else { -
src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerRule.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerRule.java b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerRule.java
a b 17 17 import java.util.Set; 18 18 import java.util.function.Consumer; 19 19 import java.util.function.Predicate; 20 import java.util.regex.Matcher;21 import java.util.regex.Pattern;22 20 import java.util.stream.Collectors; 23 21 24 22 import org.openstreetmap.josm.command.Command; … … 26 24 import org.openstreetmap.josm.command.SequenceCommand; 27 25 import org.openstreetmap.josm.data.osm.IPrimitive; 28 26 import org.openstreetmap.josm.data.osm.OsmPrimitive; 29 import org.openstreetmap.josm.data.osm.Tag;30 27 import org.openstreetmap.josm.data.osm.Way; 31 28 import org.openstreetmap.josm.data.osm.WaySegment; 32 29 import org.openstreetmap.josm.data.validation.Severity; … … 34 31 import org.openstreetmap.josm.data.validation.TestError; 35 32 import org.openstreetmap.josm.gui.mappaint.Environment; 36 33 import org.openstreetmap.josm.gui.mappaint.Keyword; 34 import org.openstreetmap.josm.gui.mappaint.MultiCascade; 37 35 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition; 38 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.TagCondition;39 36 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression; 40 37 import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction; 41 38 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule; 42 39 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource; 40 import org.openstreetmap.josm.gui.mappaint.mapcss.PlaceholderExpression; 43 41 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector; 44 42 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser; 45 43 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException; … … 214 212 } 215 213 216 214 Selector whichSelectorMatchesPrimitive(OsmPrimitive primitive) { 217 return whichSelectorMatchesEnvironment(new Environment(primitive ));215 return whichSelectorMatchesEnvironment(new Environment(primitive, new MultiCascade(), Environment.DEFAULT_LAYER, null)); 218 216 } 219 217 220 218 Selector whichSelectorMatchesEnvironment(Environment env) { … … 224 222 .orElse(null); 225 223 } 226 224 227 /**228 * Determines the {@code index}-th key/value/tag (depending on {@code type}) of the229 * {@link org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector}.230 *231 * @param matchingSelector matching selector232 * @param index index233 * @param type selector type ("key", "value" or "tag")234 * @param p OSM primitive235 * @return argument value, can be {@code null}236 */237 static String determineArgument(Selector.GeneralSelector matchingSelector, int index, String type, OsmPrimitive p) {238 try {239 final Condition c = matchingSelector.getConditions().get(index);240 final Tag tag = c instanceof TagCondition241 ? ((TagCondition) c).asTag(p)242 : null;243 if (tag == null) {244 return null;245 } else if ("key".equals(type)) {246 return tag.getKey();247 } else if ("value".equals(type)) {248 return tag.getValue();249 } else if ("tag".equals(type)) {250 return tag.toString();251 }252 } catch (IndexOutOfBoundsException ignore) {253 Logging.debug(ignore);254 }255 return null;256 }257 258 225 /** 259 226 * Replaces occurrences of <code>{i.key}</code>, <code>{i.value}</code>, <code>{i.tag}</code> in {@code s} by the corresponding 260 227 * key/value/tag of the {@code index}-th {@link Condition} of {@code matchingSelector}. … … 265 232 * @return string with arguments inserted 266 233 */ 267 234 static String insertArguments(Selector matchingSelector, String s, OsmPrimitive p) { 268 if (s != null && matchingSelector instanceof Selector.ChildOrParentSelector) { 269 return insertArguments(((Selector.ChildOrParentSelector) matchingSelector).right, s, p); 270 } else if (s == null || !(matchingSelector instanceof Selector.GeneralSelector)) { 271 return s; 272 } 273 final Matcher m = Pattern.compile("\\{(\\d+)\\.(key|value|tag)\\}").matcher(s); 274 final StringBuffer sb = new StringBuffer(); 275 while (m.find()) { 276 final String argument = determineArgument((Selector.GeneralSelector) matchingSelector, 277 Integer.parseInt(m.group(1)), m.group(2), p); 278 try { 279 // Perform replacement with null-safe + regex-safe handling 280 m.appendReplacement(sb, String.valueOf(argument).replace("^(", "").replace(")$", "")); 281 } catch (IndexOutOfBoundsException | IllegalArgumentException e) { 282 Logging.log(Logging.LEVEL_ERROR, tr("Unable to replace argument {0} in {1}: {2}", argument, sb, e.getMessage()), e); 283 } 284 } 285 m.appendTail(sb); 286 return sb.toString(); 235 return PlaceholderExpression.insertArguments(matchingSelector, s, p); 287 236 } 288 237 289 238 /** … … 328 277 final Object val = errors.keySet().iterator().next().val; 329 278 return String.valueOf( 330 279 val instanceof Expression 331 ? ((Expression) val).evaluate(new Environment(p) )280 ? ((Expression) val).evaluate(new Environment(p).withSelector(p == null ? null : whichSelectorMatchesPrimitive(p))) 332 281 : val 333 282 ); 334 283 } -
src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj b/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj
a b 31 31 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSException; 32 32 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule; 33 33 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource; 34 import org.openstreetmap.josm.gui.mappaint.mapcss.PlaceholderExpression; 34 35 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector; 35 36 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector; 36 37 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector; … … 1052 1053 { 1053 1054 if (lit == null) 1054 1055 return NullExpression.INSTANCE; 1056 else if (lit instanceof String && PlaceholderExpression.PATTERN_PLACEHOLDER.matcher((String) lit).find()) { 1057 return new PlaceholderExpression((String) lit); 1058 } 1055 1059 return new LiteralExpression(lit); 1056 1060 } 1057 1061 | -
new file src/org/openstreetmap/josm/gui/mappaint/mapcss/PlaceholderExpression.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/PlaceholderExpression.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/PlaceholderExpression.java new file mode 100644
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.mappaint.mapcss; 3 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import java.util.regex.Matcher; 7 import java.util.regex.Pattern; 8 9 import org.openstreetmap.josm.data.osm.Tag; 10 import org.openstreetmap.josm.data.osm.Tagged; 11 import org.openstreetmap.josm.gui.mappaint.Environment; 12 import org.openstreetmap.josm.tools.CheckParameterUtil; 13 import org.openstreetmap.josm.tools.Logging; 14 15 /** 16 * Used for expressions that contain placeholders 17 * @since xxx 18 */ 19 public final class PlaceholderExpression implements Expression { 20 /** 21 * The regex used for pattern replacement 22 */ 23 public static final Pattern PATTERN_PLACEHOLDER = Pattern.compile("\\{(\\d+)\\.(key|value|tag)}"); 24 private final String placeholder; 25 26 /** 27 * Constructs a new {@link PlaceholderExpression}. 28 * @param placeholder The placeholder expression 29 */ 30 public PlaceholderExpression(String placeholder) { 31 CheckParameterUtil.ensureParameterNotNull(placeholder); 32 this.placeholder = placeholder.intern(); 33 } 34 35 @Override 36 public Object evaluate(Environment env) { 37 if (env.selector() == null) { 38 return placeholder; 39 } 40 return insertArguments(env.selector(), placeholder, env.osm); 41 } 42 43 /** 44 * Replaces occurrences of <code>{i.key}</code>, <code>{i.value}</code>, <code>{i.tag}</code> in {@code s} by the corresponding 45 * key/value/tag of the {@code index}-th {@link Condition} of {@code matchingSelector}. 46 * 47 * @param matchingSelector matching selector 48 * @param s any string 49 * @param p OSM primitive 50 * @return string with arguments inserted 51 */ 52 public static String insertArguments(Selector matchingSelector, String s, Tagged p) { 53 if (s != null && matchingSelector instanceof Selector.ChildOrParentSelector) { 54 return insertArguments(((Selector.ChildOrParentSelector) matchingSelector).right, s, p); 55 } else if (s == null || !(matchingSelector instanceof Selector.GeneralSelector)) { 56 return s; 57 } 58 final Matcher m = PATTERN_PLACEHOLDER.matcher(s); 59 final StringBuffer sb = new StringBuffer(); 60 while (m.find()) { 61 final String argument = determineArgument(matchingSelector, 62 Integer.parseInt(m.group(1)), m.group(2), p); 63 try { 64 // Perform replacement with null-safe + regex-safe handling 65 m.appendReplacement(sb, String.valueOf(argument).replace("^(", "").replace(")$", "")); 66 } catch (IndexOutOfBoundsException | IllegalArgumentException e) { 67 Logging.log(Logging.LEVEL_ERROR, tr("Unable to replace argument {0} in {1}: {2}", argument, sb, e.getMessage()), e); 68 } 69 } 70 m.appendTail(sb); 71 return sb.toString(); 72 } 73 74 /** 75 * Determines the {@code index}-th key/value/tag (depending on {@code type}) of the 76 * {@link org.openstreetmap.josm.gui.mappaint.mapcss.Selector}. 77 * 78 * @param matchingSelector matching selector 79 * @param index index 80 * @param type selector type ("key", "value" or "tag") 81 * @param p OSM primitive 82 * @return argument value, can be {@code null} 83 */ 84 private static String determineArgument(Selector matchingSelector, int index, String type, Tagged p) { 85 try { 86 final Condition c = matchingSelector.getConditions().get(index); 87 final Tag tag = c instanceof Condition.TagCondition 88 ? ((Condition.TagCondition) c).asTag(p) 89 : null; 90 if (tag == null) { 91 return null; 92 } else if ("key".equals(type)) { 93 return tag.getKey(); 94 } else if ("value".equals(type)) { 95 return tag.getValue(); 96 } else if ("tag".equals(type)) { 97 return tag.toString(); 98 } 99 } catch (IndexOutOfBoundsException ioobe) { 100 Logging.debug(ioobe); 101 } 102 return null; 103 } 104 105 @Override 106 public String toString() { 107 return '<' + placeholder + '>'; 108 } 109 } -
src/org/openstreetmap/josm/gui/mappaint/Environment.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/gui/mappaint/Environment.java b/src/org/openstreetmap/josm/gui/mappaint/Environment.java
a b 12 12 import org.openstreetmap.josm.data.osm.Way; 13 13 import org.openstreetmap.josm.data.osm.WaySegment; 14 14 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context; 15 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector; 15 16 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector; 16 17 import org.openstreetmap.josm.tools.CheckParameterUtil; 17 18 … … 41 42 public StyleSource source; 42 43 private Context context = Context.PRIMITIVE; 43 44 45 /** The selector that is currently being evaluated */ 46 private final Selector selector; 47 44 48 /** 45 49 * The name of the default layer. It is used if no layer is specified in the MapCSS rule 46 50 */ … … 97 101 */ 98 102 public Environment() { 99 103 // environment can be initialized later through with* methods 104 this.selector = null; 100 105 } 101 106 102 107 /** … … 106 111 * @since 13810 (signature) 107 112 */ 108 113 public Environment(IPrimitive osm) { 109 this .osm = osm;114 this(osm, null, null, null); 110 115 } 111 116 112 117 /** … … 122 127 this.mc = mc; 123 128 this.layer = layer; 124 129 this.source = source; 130 this.selector = null; 125 131 } 126 132 127 133 /** … … 131 137 * @throws IllegalArgumentException if {@code param} is {@code null} 132 138 */ 133 139 public Environment(Environment other) { 140 this(other, other.selector); 141 } 142 143 /** 144 * Creates a clone of the environment {@code other}. 145 * 146 * @param other the other environment. Must not be null. 147 * @param selector the selector for this environment. May be null. 148 * @throws IllegalArgumentException if {@code param} is {@code null} 149 */ 150 private Environment(Environment other, Selector selector) { 134 151 CheckParameterUtil.ensureParameterNotNull(other); 135 152 this.osm = other.osm; 136 153 this.mc = other.mc; … … 146 163 this.crossingWaysMap = other.crossingWaysMap; 147 164 this.mpAreaCache = other.mpAreaCache; 148 165 this.toMatchForSurrounding = other.toMatchForSurrounding; 166 this.selector = selector; 149 167 } 150 168 151 169 /** … … 262 280 return e; 263 281 } 264 282 283 /** 284 * Creates a clone of this environment, with the selector set 285 * @param selector The selector to use 286 * @return A clone of this environment, with the specified selector 287 * @since xxx 288 */ 289 public Environment withSelector(Selector selector) { 290 return new Environment(this, selector); 291 } 292 265 293 /** 266 294 * Determines if the context of this environment is {@link Context#LINK}. 267 295 * @return {@code true} if the context of this environment is {@code Context#LINK}, {@code false} otherwise … … 303 331 return null; 304 332 } 305 333 334 /** 335 * Get the selector for this environment 336 * @return The selector. May be {@code null}. 337 * @since xxx 338 */ 339 public Selector selector() { 340 return this.selector; 341 } 342 306 343 /** 307 344 * Clears all matching context information 308 345 * @return this -
test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java b/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
a b 95 95 final MapCSSTagCheckerRule check = checks.get(0); 96 96 assertNotNull(check); 97 97 assertEquals("{0.key}=null is deprecated", check.getDescription(null)); 98 assertEquals("fixRemove: {0.key}", check.fixCommands.get(0).toString());98 assertEquals("fixRemove: <{0.key}>", check.fixCommands.get(0).toString()); 99 99 assertEquals("fixAdd: natural=wetland", check.fixCommands.get(1).toString()); 100 100 assertEquals("fixAdd: wetland=marsh", check.fixCommands.get(2).toString()); 101 101 final OsmPrimitive n1 = OsmUtils.createPrimitive("node natural=marsh");
