Changeset 18757 in josm for trunk


Ignore:
Timestamp:
2023-06-14T18:01:00+02:00 (14 months ago)
Author:
taylor.smock
Message:

Fix #17669, #22096: Allow placeholders in more locations in MapCSS

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/resources/data/validator/numeric.mapcss

    r18731 r18757  
    6868}
    6969
    70 *[height][height =~ /^[0-9]+(\.[0-9]+)?(( )*(metre|metres|meter|meters|Metre|Metres|Meter|Meters)|m)$/] {
    71   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");
    74   assertMatch: "node height=6.78 meters";
    75   assertMatch: "node height=5  metre";
    76   assertMatch: "node height=2m";
    77   assertNoMatch: "node height=2 m";
    78   assertNoMatch: "node height=5";
    79 }
    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");
    84   assertMatch: "node height=6.78 foot";
    85   assertMatch: "node height=5  Feet";
    86   assertMatch: "node height=2ft";
    87   assertNoMatch: "node height=2 ft";
    88   assertNoMatch: "node height=5";
    89 }
    90 *[height][height =~ /^[0-9]+,[0-9][0-9]?( (m|ft))?$/] {
    91   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;
    94   assertMatch: "node height=5,5";
    95   assertMatch: "node height=12,00";
    96   assertMatch: "node height=12,5 ft";
    97   assertNoMatch: "node height=12,000";
    98   assertNoMatch: "node height=3,50,5";
    99   assertNoMatch: "node height=3.5";
    100   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   assertMatch: "node maxheight=5,5";
    128   assertMatch: "node maxheight=12,00";
    129   assertMatch: "node maxheight=12,5 ft";
    130   assertNoMatch: "node maxheight=12,000";
    131   assertNoMatch: "node maxheight=3,50,5";
    132   assertNoMatch: "node maxheight=3.5";
    133   assertNoMatch: "node maxheight=4";
    134 }
    135 
    13670*[roof:height][roof:height =~ /^0*(\.0*)?( (m|ft))?$/][roof:shape=flat] {
    13771  throwWarning: tr("{0} is unnecessary for {1}", "{0.tag}", "{2.tag}");
     
    14478  assertNoMatch: "node roof:height=0 roof:shape=gabled";
    14579}
    146 *[roof:height][roof:height =~ /^[0-9]+(\.[0-9]+)?(( )*(metre|metres|meter|meters|Metre|Metres|Meter|Meters)|m)$/]!.zero_roof_height_flat {
     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)$/] {
     95  set _unit_auto_fix;
    14796  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");
     97  fixAdd: concat("{0.key}", "=", get(regexp_match("([0-9.,]+) *.+", "{0.value}"), 1), " m");
     98  assertMatch: "node height=6.78 meters";
     99  assertMatch: "node height=6,78 meters";
     100  assertMatch: "node height=5  metre";
     101  assertMatch: "node height=2m";
     102  assertNoMatch: "node height=2 m";
     103  assertNoMatch: "node height=5";
     104  assertMatch: "node maxheight=6.78 meters";
     105  assertMatch: "node maxheight=5  metre";
     106  assertMatch: "node maxheight=2m";
     107  assertNoMatch: "node maxheight=2 m";
     108  assertNoMatch: "node maxheight=5";
    150109  assertMatch: "node roof:height=6.78 meters";
    151110  assertMatch: "node roof:height=5  metre";
     
    153112  assertNoMatch: "node roof:height=2 m";
    154113  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   assertMatch: "node roof:height=5,5";
    171   assertMatch: "node roof:height=12,00";
    172   assertMatch: "node roof:height=12,5 ft";
    173   assertNoMatch: "node roof:height=12,000";
    174   assertNoMatch: "node roof:height=3,50,5";
    175   assertNoMatch: "node roof:height=3.5";
    176   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");
    183114  assertMatch: "node maxlength=6.78 meters";
    184115  assertMatch: "node maxlength=5  metre";
     
    186117  assertNoMatch: "node maxlength=2 m";
    187118  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   assertMatch: "node maxlength=5,5";
    204   assertMatch: "node maxlength=12,00";
    205   assertMatch: "node maxlength=12,5 ft";
    206   assertNoMatch: "node maxlength=12,000";
    207   assertNoMatch: "node maxlength=3,50,5";
    208   assertNoMatch: "node maxlength=3.5";
    209   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");
    216119  assertMatch: "node width=6.78 meters";
    217120  assertMatch: "node width=5  metre";
     
    219122  assertNoMatch: "node width=2 m";
    220123  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");
     124  assertMatch: "node maxwidth=6.78 meters";
     125  assertMatch: "node maxwidth=5  metre";
     126  assertMatch: "node maxwidth=2m";
     127  assertNoMatch: "node maxwidth=2 m";
     128  assertNoMatch: "node maxwidth=5";
     129  assertMatch: "node min_height=6.78 meters";
     130  assertMatch: "node min_height=5  metre";
     131  assertMatch: "node min_height=2m";
     132  assertNoMatch: "node min_height=2 m";
     133  assertNoMatch: "node min_height=5";
     134}
     135
     136/* Foot inches */
     137*[height][height            =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/],
     138*[maxheight][maxheight      =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/],
     139*[roof:height][roof:height  =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/]!.zero_roof_height_flat,
     140*[maxlength][maxlength      =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/],
     141*[width][width              =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/],
     142*[maxwidth][maxwidth        =~ /^(?i)[0-9]+([.,][0-9]+)?( *(foot|feet|ft)| +\')$/] {
     143  set _unit_auto_fix;
     144  throwWarning: tr("unusual value of {0}: use '' for foot and \" for inches, no spaces", "{0.key}");
     145  fixAdd: concat("{0.key}", "=", get(regexp_match("([0-9.,]+) *.+", "{0.value}"), 1), "'");
     146  assertMatch: "node height=6.78 foot";
     147  assertMatch: "node height=5  Feet";
     148  assertMatch: "node height=2 '";
     149  assertNoMatch: "node height=2'";
     150  assertNoMatch: "node height=5";
     151  assertMatch: "node maxheight=6.78 foot";
     152  assertMatch: "node maxheight=5  Feet";
     153  assertMatch: "node maxheight=2 '";
     154  assertNoMatch: "node maxheight=2'";
     155  assertNoMatch: "node maxheight=5";
     156  assertMatch: "node roof:height=6.78 foot";
     157  assertMatch: "node roof:height=5  Feet";
     158  assertMatch: "node roof:height=2 '";
     159  assertNoMatch: "node roof:height=2'";
     160  assertNoMatch: "node roof:height=5";
     161  assertMatch: "node maxlength=6.78 foot";
     162  assertMatch: "node maxlength=5  Feet";
     163  assertMatch: "node maxlength=2 '";
     164  assertNoMatch: "node maxlength=2'";
     165  assertNoMatch: "node maxlength=5";
    226166  assertMatch: "node width=6.78 foot";
    227167  assertMatch: "node width=5  Feet";
    228   assertMatch: "node width=2ft";
    229   assertNoMatch: "node width=2 ft";
     168  assertMatch: "node width=2 '";
     169  assertNoMatch: "node width=2'";
    230170  assertNoMatch: "node width=5";
    231 }
    232 *[width][width =~ /^[0-9]+,[0-9][0-9]?( (m|ft))?$/] {
     171  assertMatch: "node maxwidth=6.78 foot";
     172  assertMatch: "node maxwidth=5  Feet";
     173  assertMatch: "node maxwidth=2 '";
     174  assertNoMatch: "node maxwidth=2'";
     175  assertNoMatch: "node maxwidth=5";
     176}
     177
     178/* 2. Convert `,` to `.` */
     179*[height][height            =~   /^[0-9]+,[0-9][0-9]?( m|\')?$/],
     180*[maxheight][maxheight      =~   /^[0-9]+,[0-9][0-9]?( m|\')?$/],
     181*[roof:height][roof:height  =~   /^[0-9]+,[0-9][0-9]?( m|\')?$/],
     182*[maxlength][maxlength      =~   /^[0-9]+,[0-9][0-9]?( m|\')?$/],
     183*[width][width              =~   /^[0-9]+,[0-9][0-9]?( m|\')?$/],
     184*[maxwidth][maxwidth        =~   /^[0-9]+,[0-9][0-9]?( m|\')?$/],
     185*[min_height][min_height    =~ /^-?[0-9]+,[0-9][0-9]?( m|\')?$/],
     186*[maxaxleload][maxaxleload  =~   /^[0-9]+,[0-9][0-9]?( (t|kg|st|lbs))?$/],
     187*[maxweight][maxweight      =~   /^[0-9]+,[0-9][0-9]?( (t|kg|st|lbs))?$/],
     188*[distance][distance        =~   /^[0-9]+,[0-9][0-9]?( (m|km|mi|nmi))?$/] {
     189  set _unit_auto_fix;
    233190  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;
     191  fixAdd: concat("{0.key}", "=", replace(tag("{0.key}"), ",", "."));
     192  assertMatch: "node height=5,5";
     193  assertMatch: "node height=12,00";
     194  assertMatch: "node height=12,5'";
     195  assertNoMatch: "node height=12,000";
     196  assertNoMatch: "node height=3,50,5";
     197  assertNoMatch: "node height=3.5";
     198  assertNoMatch: "node height=4";
     199  assertMatch: "node maxheight=5,5";
     200  assertMatch: "node maxheight=12,00";
     201  assertMatch: "node maxheight=12,5'";
     202  assertNoMatch: "node maxheight=12,000";
     203  assertNoMatch: "node maxheight=3,50,5";
     204  assertNoMatch: "node maxheight=3.5";
     205  assertNoMatch: "node maxheight=4";
     206  assertMatch: "node roof:height=5,5";
     207  assertMatch: "node roof:height=12,00";
     208  assertMatch: "node roof:height=12,5'";
     209  assertNoMatch: "node roof:height=12,000";
     210  assertNoMatch: "node roof:height=3,50,5";
     211  assertNoMatch: "node roof:height=3.5";
     212  assertNoMatch: "node roof:height=4";
     213  assertMatch: "node maxlength=5,5";
     214  assertMatch: "node maxlength=12,00";
     215  assertMatch: "node maxlength=12,5'";
     216  assertNoMatch: "node maxlength=12,000";
     217  assertNoMatch: "node maxlength=3,50,5";
     218  assertNoMatch: "node maxlength=3.5";
     219  assertNoMatch: "node maxlength=4";
    236220  assertMatch: "node width=5,5";
    237221  assertMatch: "node width=12,00";
     
    240224  assertNoMatch: "node width=3.5";
    241225  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;
    268226  assertMatch: "node maxwidth=5,5";
    269227  assertMatch: "node maxwidth=12,00";
     
    272230  assertNoMatch: "node maxwidth=3.5";
    273231  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"));
     232  assertMatch: "node min_height=5,5";
     233  assertMatch: "node min_height=12,00";
     234  assertMatch: "node min_height=12,5'";
     235  assertNoMatch: "node min_height=12,000";
     236  assertNoMatch: "node min_height=3,50,5";
     237  assertNoMatch: "node min_height=3.5";
     238  assertNoMatch: "node min_height=4";
     239  assertMatch: "node maxaxleload=5,5";
     240  assertMatch: "node maxaxleload=12,00";
     241  assertNoMatch: "node maxaxleload=12,000";
     242  assertNoMatch: "node maxaxleload=3,50,5";
     243  assertNoMatch: "node maxaxleload=3.5";
     244  assertNoMatch: "node maxaxleload=4";
     245  assertMatch: "node maxweight=5,5";
     246  assertMatch: "node maxweight=12,00";
     247  assertNoMatch: "node maxweight=12,000";
     248  assertNoMatch: "node maxweight=3,50,5";
     249  assertNoMatch: "node maxweight=3.5";
     250  assertNoMatch: "node maxweight=4";
     251  assertMatch: "node distance=5,5";
     252  assertMatch: "node distance=12,00";
     253  assertNoMatch: "node distance=12,000";
     254  assertNoMatch: "node distance=3,50,5";
     255  assertNoMatch: "node distance=3.5";
     256  assertNoMatch: "node distance=4";
     257}
     258/* 3. Convert to the default unit for usage later. Use the tag prefixed with _. */
     259/* 4. Start doing comparison checks. */
     260
     261*[height     ][height      !~ /^(([0-9]+(\.[0-9]+)?( m)?)|([1-9][0-9]*\'((10|11|[0-9])((\.[0-9]+)?)\")?))$/]!._unit_auto_fix,
     262*[maxheight  ][maxheight   !~ /^(([1-9][0-9]*(\.[0-9]+)?( m)?)|([0-9]+\'(([0-9]|10|11)(\.[0-9]*)?\")?)|none|default|below_default)$/]!._unit_auto_fix,
     263*[min_height ][min_height  !~ /^(-?([0-9]+(\.[0-9]+)?( m)?)|(-?[1-9][0-9]*\'((10|11|[0-9])((\.[0-9]+)?)\")?))$/]!._unit_auto_fix,
     264*[roof:height][roof:height !~ /^(([0-9]+(\.[0-9]+)?( m)?)|([1-9][0-9]*\'((10|11|[0-9])((\.[0-9]+)?)\")?))$/]!.zero_roof_height_flat!._unit_auto_fix,
     265*[maxlength  ][maxlength   !~ /^(([1-9][0-9]*(\.[0-9]+)?( m)?)|([0-9]+\'(([0-9]|10|11)(\.[0-9]*)?\")?)|none|default|below_default)$/]!._unit_auto_fix,
     266*[width      ][width       !~ /^(([0-9]+(\.[0-9]+)?( m)?)|([0-9]+\'([0-9]+(\.[0-9]+)?\")?))$/]!._unit_auto_fix,
     267*[maxwidth   ][maxwidth    !~ /^(([0-9]+(\.[0-9]+)?( m)?)|([0-9]+\'([0-9]+(\.[0-9]+)?\")?))$/]!._unit_auto_fix {
     268  throwWarning: tr("unusual value of {0}: meters is default; only positive values; point is decimal separator; if units, put space then unit", "{0.key}");
    283269  assertMatch: "node height=medium";
    284270  assertMatch: "node maxheight=-5";
     
    288274  assertMatch: "node maxheight=\"2. m\"";
    289275  assertMatch: "node height=\"12. m\"";
    290   assertNoMatch: "node height=6.78 meters";
    291   assertNoMatch: "node height=5  metre";
    292   assertNoMatch: "node height=2m";
     276  assertNoMatch: "node height=6.78 m";
     277  assertNoMatch: "node height=5  m";
     278  assertNoMatch: "node height=2 m";
    293279  assertNoMatch: "node height=3";
    294280  assertNoMatch: "node height=2.22 m";
    295281  assertNoMatch: "node height=7.8";
    296   assertNoMatch: "node maxwidth=7 ft";
     282  assertMatch: "node min_height=\"12. m\"";
     283  assertNoMatch: "node min_height=-5";
     284  assertNoMatch: "node maxwidth=7'";
    297285  assertNoMatch: "node height=22'";
    298286  assertNoMatch: "node width=10'5\"";
     
    300288}
    301289
    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   assertMatch: "node min_height=5,5";
    317   assertMatch: "node min_height=12,00";
    318   assertMatch: "node min_height=12,5'";
    319   assertNoMatch: "node min_height=12,000";
    320   assertNoMatch: "node min_height=3,50,5";
    321   assertNoMatch: "node min_height=3.5";
    322   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   assertMatch: "node maxaxleload=5,5";
    335   assertMatch: "node maxaxleload=12,00";
    336   assertNoMatch: "node maxaxleload=12,000";
    337   assertNoMatch: "node maxaxleload=3,50,5";
    338   assertNoMatch: "node maxaxleload=3.5";
    339   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   assertMatch: "node maxweight=5,5";
    347   assertMatch: "node maxweight=12,00";
    348   assertNoMatch: "node maxweight=12,000";
    349   assertNoMatch: "node maxweight=3,50,5";
    350   assertNoMatch: "node maxweight=3.5";
    351   assertNoMatch: "node maxweight=4";
    352 }
    353 
    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 {
     290*[maxaxleload][maxaxleload !~ /^([0-9]+(\.[0-9]+)?( (t|kg|st|lbs))?)$/],
     291*[maxweight][maxweight !~ /^([0-9]+(\.[0-9]+)?( (t|kg|st|lbs))?)$/] {
    356292  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"));
    357293  assertMatch: "node maxaxleload=something";
     
    380316}
    381317
    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 {
     318*[distance][distance !~ /^(([0-9]+(\.[0-9]+)?( (m|km|mi|nmi))?)|([0-9]+\'([0-9]+(\.[0-9]+)?\")?))$/] {
    394319  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"));
    395320  assertMatch: "way distance=something";
     
    421346  assertNoMatch: "way frequency=123.5 MHz";
    422347}
     348
     349/*******************
     350 * End Unit checks *
     351 *******************/
    423352
    424353way[gauge][gauge      =~ /^(broad|standard|narrow)$/],
     
    524453  assertNoMatch: "node direction=45-100;190-250;300";
    525454  assertNoMatch: "node direction=90;270";
    526   assertNoMatch: "node direction=up"; 
     455  assertNoMatch: "node direction=up";
    527456  assertNoMatch: "node direction=down"; /* up/down are replaced by incline tag, has separate warning */
    528457  assertMatch: "node direction=-10";
  • trunk/resources/data/validator/wikipedia.mapcss

    r18509 r18757  
    5555*[/^wikipedia:[-a-z]{2,12}$/][/^wikipedia:[-a-z]{2,12}$/ =~ /(?i).*%[0-9A-F][0-9A-F]/] {
    5656  throwError: tr("{0} tag should not have URL-encoded values like ''%27''", "{0.key}");
    57   /* fixAdd: concat("{0.key}", "=", get(regexp_match("(?i)^([-a-z]+:)(.*)$", tag("{0.key}")),1), trim(replace(URL_decode(get(regexp_match("(?i)^([-a-z]+:)(.+)$", tag("{0.key}")),2)), "_", " "))); */
    58     /* tag("{0.key}") is not yet supported */
     57  fixAdd: concat("{0.key}", "=", get(regexp_match("(?i)^([-a-z]+:)?(.*)$", tag("{0.key}")),1), trim(replace(URL_decode(get(println(regexp_match("(?i)^([-a-z]+:)?(.+)$", tag("{0.key}"))),2)), "_", " ")));
    5958  assertMatch: "node wikipedia:de=Foo%27s";
    6059  assertNoMatch: "node wikipedia:de=Foo";
  • trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java

    r18365 r18757  
    232232                final Selector selector = check.whichSelectorMatchesEnvironment(env);
    233233                if (selector != null) {
    234                     check.rule.declaration.execute(env);
     234                    final Environment envWithSelector = env.withSelector(selector);
     235                    check.rule.declaration.execute(envWithSelector);
    235236                    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)));
    237238                    }
    238239                }
  • trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerAsserts.java

    r18365 r18757  
    7575                Command fix = check.fixPrimitive(p);
    7676                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()));
    7979                }
    8080            }
  • trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerFixCommand.java

    r17620 r18757  
    4949        final String s;
    5050        if (obj instanceof Expression) {
    51             s = (String) ((Expression) obj).evaluate(new Environment(p));
     51            s = (String) ((Expression) obj).evaluate(new Environment(p).withSelector(matchingSelector));
    5252        } else if (obj instanceof String) {
    5353            s = (String) obj;
  • trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerRule.java

    r18365 r18757  
    1818import java.util.function.Consumer;
    1919import java.util.function.Predicate;
    20 import java.util.regex.Matcher;
    21 import java.util.regex.Pattern;
    2220import java.util.stream.Collectors;
    2321
     
    2725import org.openstreetmap.josm.data.osm.IPrimitive;
    2826import org.openstreetmap.josm.data.osm.OsmPrimitive;
    29 import org.openstreetmap.josm.data.osm.Tag;
    3027import org.openstreetmap.josm.data.osm.Way;
    3128import org.openstreetmap.josm.data.osm.WaySegment;
     
    3532import org.openstreetmap.josm.gui.mappaint.Environment;
    3633import org.openstreetmap.josm.gui.mappaint.Keyword;
     34import org.openstreetmap.josm.gui.mappaint.MultiCascade;
    3735import org.openstreetmap.josm.gui.mappaint.mapcss.Condition;
    38 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.TagCondition;
    3936import org.openstreetmap.josm.gui.mappaint.mapcss.Expression;
    4037import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction;
    4138import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule;
    4239import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
     40import org.openstreetmap.josm.gui.mappaint.mapcss.PlaceholderExpression;
    4341import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
    4442import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
     
    215213
    216214    Selector whichSelectorMatchesPrimitive(OsmPrimitive primitive) {
    217         return whichSelectorMatchesEnvironment(new Environment(primitive));
     215        return whichSelectorMatchesEnvironment(new Environment(primitive, new MultiCascade(), Environment.DEFAULT_LAYER, null));
    218216    }
    219217
     
    226224
    227225    /**
    228      * Determines the {@code index}-th key/value/tag (depending on {@code type}) of the
    229      * {@link org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector}.
    230      *
    231      * @param matchingSelector matching selector
    232      * @param index            index
    233      * @param type             selector type ("key", "value" or "tag")
    234      * @param p                OSM primitive
    235      * @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 TagCondition
    241                     ? ((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     /**
    259226     * Replaces occurrences of <code>{i.key}</code>, <code>{i.value}</code>, <code>{i.tag}</code> in {@code s} by the corresponding
    260227     * key/value/tag of the {@code index}-th {@link Condition} of {@code matchingSelector}.
     
    266233     */
    267234    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);
    287236    }
    288237
     
    329278            return String.valueOf(
    330279                    val instanceof Expression
    331                             ? ((Expression) val).evaluate(new Environment(p))
     280                            ? ((Expression) val).evaluate(new Environment(p).withSelector(p == null ? null : whichSelectorMatchesPrimitive(p)))
    332281                            : val
    333282            );
  • trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java

    r18275 r18757  
    1313import org.openstreetmap.josm.data.osm.WaySegment;
    1414import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
     15import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
    1516import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector;
    1617import org.openstreetmap.josm.tools.CheckParameterUtil;
     
    4243    private Context context = Context.PRIMITIVE;
    4344
     45    /** The selector that is currently being evaluated */
     46    private final Selector selector;
     47
    4448    /**
    4549     * The name of the default layer. It is used if no layer is specified in the MapCSS rule
     
    98102    public Environment() {
    99103        // environment can be initialized later through with* methods
     104        this.selector = null;
    100105    }
    101106
     
    107112     */
    108113    public Environment(IPrimitive osm) {
    109         this.osm = osm;
     114        this(osm, null, null, null);
    110115    }
    111116
     
    123128        this.layer = layer;
    124129        this.source = source;
     130        this.selector = null;
    125131    }
    126132
     
    132138     */
    133139    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) {
    134151        CheckParameterUtil.ensureParameterNotNull(other);
    135152        this.osm = other.osm;
     
    147164        this.mpAreaCache = other.mpAreaCache;
    148165        this.toMatchForSurrounding = other.toMatchForSurrounding;
     166        this.selector = selector;
    149167    }
    150168
     
    264282
    265283    /**
     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
     293    /**
    266294     * Determines if the context of this environment is {@link Context#LINK}.
    267295     * @return {@code true} if the context of this environment is {@code Context#LINK}, {@code false} otherwise
     
    302330            return ((Relation) osm).getMember(index).getRole();
    303331        return null;
     332    }
     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;
    304341    }
    305342
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj

    r18712 r18757  
    3232import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule;
    3333import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
     34import org.openstreetmap.josm.gui.mappaint.mapcss.PlaceholderExpression;
    3435import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
    3536import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
     
    10531054            if (lit == null)
    10541055                return NullExpression.INSTANCE;
     1056            else if (lit instanceof String && PlaceholderExpression.PATTERN_PLACEHOLDER.matcher((String) lit).find()) {
     1057                return new PlaceholderExpression((String) lit);
     1058            }
    10551059            return new LiteralExpression(lit);
    10561060        }
  • trunk/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java

    r18690 r18757  
    4444import org.openstreetmap.josm.io.OsmReader;
    4545import org.openstreetmap.josm.testutils.JOSMTestRules;
     46import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
     47import org.openstreetmap.josm.testutils.annotations.Projection;
    4648import org.openstreetmap.josm.tools.Logging;
    4749
     
    5153 * JUnit Test of {@link MapCSSTagChecker}.
    5254 */
     55@BasicPreferences
     56@Projection
    5357class MapCSSTagCheckerTest {
    5458
     
    5862    @RegisterExtension
    5963    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
    60     public JOSMTestRules test = new JOSMTestRules().projection().territories().preferences();
     64    public JOSMTestRules test = new JOSMTestRules().territories();
    6165
    6266    /**
     
    96100        assertNotNull(check);
    97101        assertEquals("{0.key}=null is deprecated", check.getDescription(null));
    98         assertEquals("fixRemove: {0.key}", check.fixCommands.get(0).toString());
     102        assertEquals("fixRemove: <{0.key}>", check.fixCommands.get(0).toString());
    99103        assertEquals("fixAdd: natural=wetland", check.fixCommands.get(1).toString());
    100104        assertEquals("fixAdd: wetland=marsh", check.fixCommands.get(2).toString());
Note: See TracChangeset for help on using the changeset viewer.