Changeset 7174 in josm for trunk/data
- Timestamp:
- 2014-05-24T01:47:59+02:00 (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/data/validator/opening_hours.js
r7046 r7174 1842 1842 // console.log(JSON.stringify(tokens, null, '\t')); 1843 1843 var prettified_value = ''; 1844 var used_subparsers = {}; // Used sub parsers for one block, will be reset for each block. Declared as global, because it is manipulation inside various sub parsers.1844 var used_subparsers = {}; // Used sub parsers for one block, will be reset for each block. Declared in global namespace, because it is manipulation inside various sub parsers. 1845 1845 var week_stable = true; 1846 1846 … … 1905 1905 blocks.push(selectors); 1906 1906 1907 // this handles selectors with time ranges wrapping over midnight (e.g. 10:00-02:00)1908 // it generates wrappers for all selectors and creates a new block 1907 // This handles selectors with time ranges wrapping over midnight (e.g. 10:00-02:00) 1908 // it generates wrappers for all selectors and creates a new block. 1909 1909 if (selectors.wraptime.length > 0) { 1910 1910 var wrapselectors = { … … 1934 1934 // }}} 1935 1935 1936 // Tokenization function: Splits string into parts. {{{ 1937 // output: array of arrays of pairs [content, type] 1936 /* Tokenization function: Splits string into parts. {{{ 1937 * 1938 * :param value: Raw opening_hours value. 1939 * :returns: Tokenized list object. Complex structure. You can print the 1940 * thing as JSON if you would like to know in details. 1941 * The most inner list has the following items: [ internal_value, token_name, value_length ]. 1942 */ 1938 1943 function tokenize(value) { 1939 var all_tokens = new Array();1944 var all_tokens = new Array(); 1940 1945 var curr_block_tokens = new Array(); 1941 1946 … … 1944 1949 while (value != '') { 1945 1950 var tmp; 1946 if (tmp = value.match(/^(?:week\b|open\b|unknown )/i)) {1947 // reserved word1951 if (tmp = value.match(/^(?:week\b|open\b|unknown\b)/i)) { 1952 // Reserved keywords. 1948 1953 curr_block_tokens.push([tmp[0].toLowerCase(), tmp[0].toLowerCase(), value.length ]); 1949 1954 value = value.substr(tmp[0].length); 1950 1955 } else if (tmp = value.match(/^24\/7/i)) { 1951 // reserved word1956 // Reserved keyword. 1952 1957 has_token[tmp[0]] = true; 1953 1958 curr_block_tokens.push([tmp[0], tmp[0], value.length ]); 1954 1959 value = value.substr(tmp[0].length); 1955 1960 } else if (tmp = value.match(/^(?:off|closed)/i)) { 1956 // reserved word1961 // Reserved keywords. 1957 1962 curr_block_tokens.push([tmp[0].toLowerCase(), 'closed', value.length ]); 1958 1963 value = value.substr(tmp[0].length); … … 1965 1970 value = value.substr(tmp[0].length); 1966 1971 } else if (tmp = value.match(/^(&|_|→|–|−|=|opening_hours=|ー|\?|~|~|:|°°|25x7|7[ ]?days( a week|)|all days?|every day|-late|public holidays?|7j?\/7|every day|до|рм|ам|jours fériés|sonn-|[a-zäößàáéøčěíúýřПнВсо]+\b)\.?/i)) { 1967 // Handle all remaining words with error tolerance 1972 // Handle all remaining words with error tolerance. 1968 1973 var correct_val = returnCorrectWordOrToken(tmp[1].toLowerCase(), value.length); 1969 1974 if (typeof correct_val == 'object') { … … 1971 1976 value = value.substr(tmp[0].length); 1972 1977 } else if (typeof correct_val == 'string') { 1978 if (tmp[1].toLowerCase() == 'pm') { 1979 var hours_token_at = curr_block_tokens.length - 3; 1980 if (hours_token_at > 0) { 1981 if (matchTokens(curr_block_tokens, hours_token_at, 1982 'number', 'timesep', 'number') 1983 ) { 1984 var hours_token = curr_block_tokens[hours_token_at]; 1985 } else if (matchTokens(curr_block_tokens, hours_token_at + 2, 1986 'number') 1987 ) { 1988 hours_token_at += 2; 1989 var hours_token = curr_block_tokens[hours_token_at]; 1990 } 1991 if (hours_token[0] <= 12) { 1992 hours_token[0] += 12; 1993 curr_block_tokens[hours_token_at] = hours_token; 1994 } 1995 } 1996 } 1973 1997 value = correct_val + value.substr(tmp[0].length); 1974 1998 } else { … … 1979 2003 } else if (tmp = value.match(/^\d+/)) { 1980 2004 // number 1981 if (tmp[0] > 1900) // assumed to be a year number2005 if (tmp[0] > 1900) // Assumed to be a year number. 1982 2006 curr_block_tokens.push([tmp[0], 'year', value.length ]); 1983 2007 else … … 2032 2056 // }}} 2033 2057 2034 // error correction/tolerance function {{{ 2035 // Go through word_error_correction hash and get correct value back. 2058 /* error correction/tolerance function {{{ 2059 * Go through word_error_correction hash and get correct value back. 2060 * 2061 * :param word: Wrong Word or character. 2062 * :param value_length: Current value_length (used for warnings). 2063 * :returns: 2064 * * (valid) opening_hours sub string. 2065 * * object with [ internal_value, token_name ] if value is correct. 2066 * * undefined if word could not be found (and thus not be corrected). 2067 */ 2036 2068 function returnCorrectWordOrToken(word, value_length) { 2037 2069 for (var token_name in word_error_correction) { … … 2040 2072 if (old_val == word) { 2041 2073 var val = word_error_correction[token_name][comment][old_val]; 2042 if (token_name == 'wrong_words' && !done_with_warnings) { 2074 if (comment == 'default') { 2075 // Return internal representation of word. 2076 return [ val, token_name ]; 2077 } else if (token_name == 'wrong_words' && !done_with_warnings) { 2078 // Replace wrong words or characters with correct ones. 2079 // This will return a string which is then being tokenized. 2043 2080 parsing_warnings.push([ -1, value_length - old_val.length, 2044 2081 comment.replace(/<ko>/, old_val).replace(/<ok>/, val) ]); 2045 2082 return val; 2046 } else if (comment != 'default'){ 2083 } else { 2084 // Get correct string value from the 'default' hash and generate warning. 2047 2085 var correct_abbr; 2048 2086 for (correct_abbr in word_error_correction[token_name]['default']) { 2049 2087 if (word_error_correction[token_name]['default'][correct_abbr] == val) 2050 break; // FIXME2088 break; 2051 2089 } 2052 // FIXME 2053 if (token_name != 'timevar') { // normally written in lower case 2054 correct_abbr = correct_abbr.charAt(0).toUpperCase() + correct_abbr.slice(1); 2090 if (typeof correct_abbr == 'undefined') { 2091 throw 'Please file a bug for opening_hours.js.' 2092 + ' Including the stacktrace.' 2093 } 2094 if (token_name != 'timevar') { 2095 // Everything else than timevar: 2096 // E.g. 'Mo' are start with a upper case letter. 2097 // It just looks better. 2098 correct_abbr = correct_abbr.charAt(0).toUpperCase() 2099 + correct_abbr.slice(1); 2055 2100 } 2056 2101 if (!done_with_warnings) 2057 2102 parsing_warnings.push([ -1, value_length - old_val.length, 2058 2103 comment.replace(/<ko>/, old_val).replace(/<ok>/, correct_abbr) ]); 2104 return [ val, token_name ]; 2059 2105 } 2060 return [ val, token_name ];2061 2106 } 2062 2107 } 2063 2108 } 2064 2109 } 2110 return undefined; 2065 2111 } 2066 2112 // }}} 2067 2113 2068 // return warnings as list {{{ 2114 /* return warnings as list {{{ 2115 * 2116 * :param it: Iterator object if available (optional). 2117 * :returns: Warnings as list with one warning per element. 2118 */ 2069 2119 function getWarnings(it) { 2070 2120 if (typeof it == 'object') { // getWarnings was called in a state without critical errors. We can do extended tests. … … 2090 2140 // }}} 2091 2141 2092 // Function to check token array for specific pattern {{{ 2142 /* Function to check token array for specific pattern {{{ 2143 * 2144 * :param tokens: List of token objects. 2145 * :param at: Position at which the matching should begin. 2146 * :param token_name(s): One or many token_name strings which have to match in that order. 2147 * :returns: true if token_name(s) match in order false otherwise. 2148 */ 2093 2149 function matchTokens(tokens, at /*, matches... */) { 2094 2150 if (at + arguments.length - 2 > tokens.length) … … 2103 2159 // }}} 2104 2160 2105 // Generate selector wrapper with time offset {{{ 2161 /* Generate selector wrapper with time offset {{{ 2162 * 2163 * :param func: Generated selector code function. 2164 * :param shirt: Time to shift in milliseconds. 2165 * :param token_name(s): One or many token_name strings which have to match in that order. 2166 * :returns: See selector code. 2167 */ 2106 2168 function generateDateShifter(func, shift) { 2107 2169 return function(date) { … … 2115 2177 // }}} 2116 2178 2117 // Top-level parser {{{ 2179 /* Top-level parser {{{ 2180 * 2181 * :param tokens: List of token objects. 2182 * :param at: Position at which the matching should begin. 2183 * :param selectors: Reference to selector object. 2184 * :param nblock: Block number starting with 0. 2185 * :param conf: Configuration for prettifyValue. 2186 * :returns: See selector code. 2187 */ 2118 2188 function parseGroup(tokens, at, selectors, nblock, conf) { 2119 2189 var prettified_group_value = ''; … … 2238 2308 2239 2309 if (typeof conf != 'undefined') { 2240 2241 2310 // 'Mo: 12:00-13:00' -> 'Mo 12:00-13:00' 2242 2311 if (used_subparsers['time ranges'] && old_at > 1 && tokens[old_at-1][0] == ':' … … 2284 2353 2285 2354 // helper functions for sub parser {{{ 2286 // for given date, returns date moved to the start of specified day minute 2355 2356 /* For given date, returns date moved to the start of the day with an offset specified in minutes. {{{ 2357 * For example, if date is 2014-05-19_18:17:12, dateAtDayMinutes would 2358 * return 2014-05-19_02:00:00 for minutes=120. 2359 * 2360 * :param date: Date object. 2361 * :param minutes: Minutes used as offset starting from midnight of current day. 2362 * :returns: Moved date object. 2363 */ 2287 2364 function dateAtDayMinutes(date, minutes) { 2288 2365 return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, minutes); 2289 2366 } 2290 2291 // for given date, returns date moved to the specific day of week 2367 // }}} 2368 2369 /* For given date, returns date moved to the specific day of week {{{ 2370 * 2371 * :param date: Date object. 2372 * :param day: Integer number for day of week. Starting with zero (Sunday). 2373 * :returns: Moved date object. 2374 */ 2292 2375 function dateAtNextWeekday(date, day) { 2293 2376 var delta = day - date.getDay(); 2294 2377 return new Date(date.getFullYear(), date.getMonth(), date.getDate() + delta + (delta < 0 ? 7 : 0)); 2295 2378 } 2296 2379 // }}} 2380 2381 /* Function to determine whether an array contains a value {{{ 2382 * Source: http://stackoverflow.com/a/1181586 2383 * 2384 * :param needle: Element to find. 2385 * :returns: Index of element if present, if not present returns -1. 2386 */ 2297 2387 function indexOf(needle) { 2298 2388 if(typeof Array.prototype.indexOf === 'function') { … … 2312 2402 return indexOf.call(this, needle); 2313 2403 } 2314 2315 // Numeric list parser (1,2,3-4,-1), used in weekday parser above 2404 // }}} 2405 2406 /* Numeric list parser (1,2,3-4,-1) {{{ 2407 * Used in weekday parser above. 2408 * 2409 * :param tokens: List of token objects. 2410 * :param at: Position where to start. 2411 * :param func: Function func(from, to, at). 2412 * :returns: Position at which the token does not belong to the list any more. 2413 */ 2316 2414 function parseNumRange(tokens, at, func) { 2317 2415 for (; at < tokens.length; at++) { … … 2339 2437 return at; 2340 2438 } 2341 2439 // }}} 2440 2441 /* List parser for constrained weekdays in month range {{{ 2442 * e.g. Su[-1] which selects the last Sunday of the month. 2443 * 2444 * :param tokens: List of token objects. 2445 * :param at: Position where to start. 2446 * :returns: Array: 2447 * 0. Constrained weekday number. 2448 * 1. Position at which the token does not belong to the list any more (after ']' token). 2449 */ 2342 2450 function getConstrainedWeekday(tokens, at) { 2343 2451 var number = 0; … … 2352 2460 if (number != 0) 2353 2461 throw formatWarnErrorMessage(nblock, at, 2354 'You can not use amore than one constrained weekday in a month range');2462 'You can not use more than one constrained weekday in a month range'); 2355 2463 number = from; 2356 2464 } else { … … 2365 2473 return [ number, endat + 1 ]; 2366 2474 } 2475 // }}} 2367 2476 2368 2477 // Check if period is ok. Period 0 or 1 don’t make much sense. 2478 /* List parser for constrained weekdays in month range {{{ 2479 * e.g. Su[-1] which selects the last Sunday of the month. 2480 * 2481 * :param tokens: List of token objects. 2482 * :param at: Position where to start. 2483 * :returns: Array: 2484 * 0. Constrained weekday number. 2485 * 1. Position at which the token does not belong to the list any more (after ']' token). 2486 */ 2369 2487 function checkPeriod(at, period, period_type, parm_string) { 2370 2488 if (done_with_warnings) … … 3980 4098 // }}} 3981 4099 3982 // generate prettified value based on tokens {{{4100 // Generate prettified value based on tokens {{{ 3983 4101 function prettifySelector(tokens, at, last_at, conf, used_parseTimeRange) { 3984 4102 var value = ''; … … 3993 4111 } 3994 4112 value += weekdays[tokens[at][0]]; 3995 } else if (at - start_at > 0 && used_parseTimeRange > 0 && matchTokens(tokens, at-1, 'timesep') 3996 && matchTokens(tokens, at, 'number')) { // '09:0' -> '09:00' 4113 } else if (at - start_at > 0 // e.g. '09:0' -> '09:00' 4114 && used_parseTimeRange > 0 4115 && matchTokens(tokens, at-1, 'timesep') 4116 && matchTokens(tokens, at, 'number')) { 3997 4117 value += (tokens[at][0] < 10 ? '0' : '') + tokens[at][0].toString(); 3998 } else if (used_parseTimeRange > 0 && conf.leading_zero_hour && at != tokens.length 4118 } else if (used_parseTimeRange > 0 // e.g. '9:00' -> ' 09:00' 4119 && conf.leading_zero_hour 4120 && at != tokens.length 3999 4121 && matchTokens(tokens, at, 'number') 4000 && matchTokens(tokens, at+1, 'timesep')) { // '9:00' -> '19:00' 4001 value += (tokens[at][0] < 10 ? (tokens[at][0] == 0 && conf.one_zero_if_hour_zero ? '' : '0') : '') + tokens[at][0].toString(); 4002 } else if (used_parseTimeRange > 0 && at + 2 < last_at 4122 && matchTokens(tokens, at+1, 'timesep')) { 4123 value += ( 4124 tokens[at][0] < 10 ? 4125 (tokens[at][0] == 0 && conf.one_zero_if_hour_zero ? 4126 '' : '0') : 4127 '') + tokens[at][0].toString(); 4128 } else if (used_parseTimeRange > 0 // e.g. '9-18' -> '09:00-18:00' 4129 && at + 2 < last_at 4003 4130 && matchTokens(tokens, at, 'number') 4004 4131 && matchTokens(tokens, at+1, '-') 4005 && matchTokens(tokens, at+2, 'number')) { // '9-18' -> '09:00-18:00' 4006 value += (tokens[at][0] < 10 ? (tokens[at][0] == 0 && conf.one_zero_if_hour_zero ? '' : '0') : '') + tokens[at][0].toString(); 4007 value += ':00-'; 4008 value += (tokens[at+2][0] < 10 ? '0' : '') + tokens[at+2][0].toString(); 4009 value += ':00'; 4132 && matchTokens(tokens, at+2, 'number')) { 4133 value += (tokens[at][0] < 10 ? 4134 (tokens[at][0] == 0 && conf.one_zero_if_hour_zero ? '' : '0') 4135 : '') + tokens[at][0].toString(); 4136 value += ':00-' 4137 + (tokens[at+2][0] < 10 ? '0' : '') + tokens[at+2][0].toString() 4138 + ':00'; 4010 4139 at += 2; 4011 4140 } else if (matchTokens(tokens, at, 'comment')) { … … 4358 4487 } 4359 4488 })); 4489 // vim: set ts=4 sw=4 tw=0 noet foldmarker={{{,}}} foldlevel=0 foldmethod=marker :
Note:
See TracChangeset
for help on using the changeset viewer.