(charSet)
| 291 | } |
| 292 | |
| 293 | function caseFoldCharset(charSet) { |
| 294 | var charsetParts = charSet.substring(1, charSet.length - 1).match( |
| 295 | new RegExp( |
| 296 | '\\\\u[0-9A-Fa-f]{4}' |
| 297 | + '|\\\\x[0-9A-Fa-f]{2}' |
| 298 | + '|\\\\[0-3][0-7]{0,2}' |
| 299 | + '|\\\\[0-7]{1,2}' |
| 300 | + '|\\\\[\\s\\S]' |
| 301 | + '|-' |
| 302 | + '|[^-\\\\]', |
| 303 | 'g')); |
| 304 | var ranges = []; |
| 305 | var inverse = charsetParts[0] === '^'; |
| 306 | |
| 307 | var out = ['[']; |
| 308 | if (inverse) { out.push('^'); } |
| 309 | |
| 310 | for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) { |
| 311 | var p = charsetParts[i]; |
| 312 | if (/\\[bdsw]/i.test(p)) { // Don't muck with named groups. |
| 313 | out.push(p); |
| 314 | } else { |
| 315 | var start = decodeEscape(p); |
| 316 | var end; |
| 317 | if (i + 2 < n && '-' === charsetParts[i + 1]) { |
| 318 | end = decodeEscape(charsetParts[i + 2]); |
| 319 | i += 2; |
| 320 | } else { |
| 321 | end = start; |
| 322 | } |
| 323 | ranges.push([start, end]); |
| 324 | // If the range might intersect letters, then expand it. |
| 325 | // This case handling is too simplistic. |
| 326 | // It does not deal with non-latin case folding. |
| 327 | // It works for latin source code identifiers though. |
| 328 | if (!(end < 65 || start > 122)) { |
| 329 | if (!(end < 65 || start > 90)) { |
| 330 | ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]); |
| 331 | } |
| 332 | if (!(end < 97 || start > 122)) { |
| 333 | ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]); |
| 334 | } |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]] |
| 340 | // -> [[1, 12], [14, 14], [16, 17]] |
| 341 | ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1] - a[1]); }); |
| 342 | var consolidatedRanges = []; |
| 343 | var lastRange = []; |
| 344 | for (var i = 0; i < ranges.length; ++i) { |
| 345 | var range = ranges[i]; |
| 346 | if (range[0] <= lastRange[1] + 1) { |
| 347 | lastRange[1] = Math.max(lastRange[1], range[1]); |
| 348 | } else { |
| 349 | consolidatedRanges.push(lastRange = range); |
| 350 | } |
no test coverage detected