Projekt

Obecné

Profil

Stáhnout (33.7 KB) Statistiky
| Větev: | Revize:
1
/*! https://mths.be/regenerate v1.3.3 by @mathias | MIT license */
2
;(function(root) {
3

    
4
	// Detect free variables `exports`.
5
	var freeExports = typeof exports == 'object' && exports;
6

    
7
	// Detect free variable `module`.
8
	var freeModule = typeof module == 'object' && module &&
9
		module.exports == freeExports && module;
10

    
11
	// Detect free variable `global`, from Node.js/io.js or Browserified code,
12
	// and use it as `root`.
13
	var freeGlobal = typeof global == 'object' && global;
14
	if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
15
		root = freeGlobal;
16
	}
17

    
18
	/*--------------------------------------------------------------------------*/
19

    
20
	var ERRORS = {
21
		'rangeOrder': 'A range\u2019s `stop` value must be greater than or equal ' +
22
			'to the `start` value.',
23
		'codePointRange': 'Invalid code point value. Code points range from ' +
24
			'U+000000 to U+10FFFF.'
25
	};
26

    
27
	// https://mathiasbynens.be/notes/javascript-encoding#surrogate-pairs
28
	var HIGH_SURROGATE_MIN = 0xD800;
29
	var HIGH_SURROGATE_MAX = 0xDBFF;
30
	var LOW_SURROGATE_MIN = 0xDC00;
31
	var LOW_SURROGATE_MAX = 0xDFFF;
32

    
33
	// In Regenerate output, `\0` is never preceded by `\` because we sort by
34
	// code point value, so let’s keep this regular expression simple.
35
	var regexNull = /\\x00([^0123456789]|$)/g;
36

    
37
	var object = {};
38
	var hasOwnProperty = object.hasOwnProperty;
39
	var extend = function(destination, source) {
40
		var key;
41
		for (key in source) {
42
			if (hasOwnProperty.call(source, key)) {
43
				destination[key] = source[key];
44
			}
45
		}
46
		return destination;
47
	};
48

    
49
	var forEach = function(array, callback) {
50
		var index = -1;
51
		var length = array.length;
52
		while (++index < length) {
53
			callback(array[index], index);
54
		}
55
	};
56

    
57
	var toString = object.toString;
58
	var isArray = function(value) {
59
		return toString.call(value) == '[object Array]';
60
	};
61
	var isNumber = function(value) {
62
		return typeof value == 'number' ||
63
			toString.call(value) == '[object Number]';
64
	};
65

    
66
	// This assumes that `number` is a positive integer that `toString()`s nicely
67
	// (which is the case for all code point values).
68
	var zeroes = '0000';
69
	var pad = function(number, totalCharacters) {
70
		var string = String(number);
71
		return string.length < totalCharacters
72
			? (zeroes + string).slice(-totalCharacters)
73
			: string;
74
	};
75

    
76
	var hex = function(number) {
77
		return Number(number).toString(16).toUpperCase();
78
	};
79

    
80
	var slice = [].slice;
81

    
82
	/*--------------------------------------------------------------------------*/
83

    
84
	var dataFromCodePoints = function(codePoints) {
85
		var index = -1;
86
		var length = codePoints.length;
87
		var max = length - 1;
88
		var result = [];
89
		var isStart = true;
90
		var tmp;
91
		var previous = 0;
92
		while (++index < length) {
93
			tmp = codePoints[index];
94
			if (isStart) {
95
				result.push(tmp);
96
				previous = tmp;
97
				isStart = false;
98
			} else {
99
				if (tmp == previous + 1) {
100
					if (index != max) {
101
						previous = tmp;
102
						continue;
103
					} else {
104
						isStart = true;
105
						result.push(tmp + 1);
106
					}
107
				} else {
108
					// End the previous range and start a new one.
109
					result.push(previous + 1, tmp);
110
					previous = tmp;
111
				}
112
			}
113
		}
114
		if (!isStart) {
115
			result.push(tmp + 1);
116
		}
117
		return result;
118
	};
119

    
120
	var dataRemove = function(data, codePoint) {
121
		// Iterate over the data per `(start, end)` pair.
122
		var index = 0;
123
		var start;
124
		var end;
125
		var length = data.length;
126
		while (index < length) {
127
			start = data[index];
128
			end = data[index + 1];
129
			if (codePoint >= start && codePoint < end) {
130
				// Modify this pair.
131
				if (codePoint == start) {
132
					if (end == start + 1) {
133
						// Just remove `start` and `end`.
134
						data.splice(index, 2);
135
						return data;
136
					} else {
137
						// Just replace `start` with a new value.
138
						data[index] = codePoint + 1;
139
						return data;
140
					}
141
				} else if (codePoint == end - 1) {
142
					// Just replace `end` with a new value.
143
					data[index + 1] = codePoint;
144
					return data;
145
				} else {
146
					// Replace `[start, end]` with `[startA, endA, startB, endB]`.
147
					data.splice(index, 2, start, codePoint, codePoint + 1, end);
148
					return data;
149
				}
150
			}
151
			index += 2;
152
		}
153
		return data;
154
	};
155

    
156
	var dataRemoveRange = function(data, rangeStart, rangeEnd) {
157
		if (rangeEnd < rangeStart) {
158
			throw Error(ERRORS.rangeOrder);
159
		}
160
		// Iterate over the data per `(start, end)` pair.
161
		var index = 0;
162
		var start;
163
		var end;
164
		while (index < data.length) {
165
			start = data[index];
166
			end = data[index + 1] - 1; // Note: the `- 1` makes `end` inclusive.
167

    
168
			// Exit as soon as no more matching pairs can be found.
169
			if (start > rangeEnd) {
170
				return data;
171
			}
172

    
173
			// Check if this range pair is equal to, or forms a subset of, the range
174
			// to be removed.
175
			// E.g. we have `[0, 11, 40, 51]` and want to remove 0-10 → `[40, 51]`.
176
			// E.g. we have `[40, 51]` and want to remove 0-100 → `[]`.
177
			if (rangeStart <= start && rangeEnd >= end) {
178
				// Remove this pair.
179
				data.splice(index, 2);
180
				continue;
181
			}
182

    
183
			// Check if both `rangeStart` and `rangeEnd` are within the bounds of
184
			// this pair.
185
			// E.g. we have `[0, 11]` and want to remove 4-6 → `[0, 4, 7, 11]`.
186
			if (rangeStart >= start && rangeEnd < end) {
187
				if (rangeStart == start) {
188
					// Replace `[start, end]` with `[startB, endB]`.
189
					data[index] = rangeEnd + 1;
190
					data[index + 1] = end + 1;
191
					return data;
192
				}
193
				// Replace `[start, end]` with `[startA, endA, startB, endB]`.
194
				data.splice(index, 2, start, rangeStart, rangeEnd + 1, end + 1);
195
				return data;
196
			}
197

    
198
			// Check if only `rangeStart` is within the bounds of this pair.
199
			// E.g. we have `[0, 11]` and want to remove 4-20 → `[0, 4]`.
200
			if (rangeStart >= start && rangeStart <= end) {
201
				// Replace `end` with `rangeStart`.
202
				data[index + 1] = rangeStart;
203
				// Note: we cannot `return` just yet, in case any following pairs still
204
				// contain matching code points.
205
				// E.g. we have `[0, 11, 14, 31]` and want to remove 4-20
206
				// → `[0, 4, 21, 31]`.
207
			}
208

    
209
			// Check if only `rangeEnd` is within the bounds of this pair.
210
			// E.g. we have `[14, 31]` and want to remove 4-20 → `[21, 31]`.
211
			else if (rangeEnd >= start && rangeEnd <= end) {
212
				// Just replace `start`.
213
				data[index] = rangeEnd + 1;
214
				return data;
215
			}
216

    
217
			index += 2;
218
		}
219
		return data;
220
	};
221

    
222
	 var dataAdd = function(data, codePoint) {
223
		// Iterate over the data per `(start, end)` pair.
224
		var index = 0;
225
		var start;
226
		var end;
227
		var lastIndex = null;
228
		var length = data.length;
229
		if (codePoint < 0x0 || codePoint > 0x10FFFF) {
230
			throw RangeError(ERRORS.codePointRange);
231
		}
232
		while (index < length) {
233
			start = data[index];
234
			end = data[index + 1];
235

    
236
			// Check if the code point is already in the set.
237
			if (codePoint >= start && codePoint < end) {
238
				return data;
239
			}
240

    
241
			if (codePoint == start - 1) {
242
				// Just replace `start` with a new value.
243
				data[index] = codePoint;
244
				return data;
245
			}
246

    
247
			// At this point, if `start` is `greater` than `codePoint`, insert a new
248
			// `[start, end]` pair before the current pair, or after the current pair
249
			// if there is a known `lastIndex`.
250
			if (start > codePoint) {
251
				data.splice(
252
					lastIndex != null ? lastIndex + 2 : 0,
253
					0,
254
					codePoint,
255
					codePoint + 1
256
				);
257
				return data;
258
			}
259

    
260
			if (codePoint == end) {
261
				// Check if adding this code point causes two separate ranges to become
262
				// a single range, e.g. `dataAdd([0, 4, 5, 10], 4)` → `[0, 10]`.
263
				if (codePoint + 1 == data[index + 2]) {
264
					data.splice(index, 4, start, data[index + 3]);
265
					return data;
266
				}
267
				// Else, just replace `end` with a new value.
268
				data[index + 1] = codePoint + 1;
269
				return data;
270
			}
271
			lastIndex = index;
272
			index += 2;
273
		}
274
		// The loop has finished; add the new pair to the end of the data set.
275
		data.push(codePoint, codePoint + 1);
276
		return data;
277
	};
278

    
279
	var dataAddData = function(dataA, dataB) {
280
		// Iterate over the data per `(start, end)` pair.
281
		var index = 0;
282
		var start;
283
		var end;
284
		var data = dataA.slice();
285
		var length = dataB.length;
286
		while (index < length) {
287
			start = dataB[index];
288
			end = dataB[index + 1] - 1;
289
			if (start == end) {
290
				data = dataAdd(data, start);
291
			} else {
292
				data = dataAddRange(data, start, end);
293
			}
294
			index += 2;
295
		}
296
		return data;
297
	};
298

    
299
	var dataRemoveData = function(dataA, dataB) {
300
		// Iterate over the data per `(start, end)` pair.
301
		var index = 0;
302
		var start;
303
		var end;
304
		var data = dataA.slice();
305
		var length = dataB.length;
306
		while (index < length) {
307
			start = dataB[index];
308
			end = dataB[index + 1] - 1;
309
			if (start == end) {
310
				data = dataRemove(data, start);
311
			} else {
312
				data = dataRemoveRange(data, start, end);
313
			}
314
			index += 2;
315
		}
316
		return data;
317
	};
318

    
319
	var dataAddRange = function(data, rangeStart, rangeEnd) {
320
		if (rangeEnd < rangeStart) {
321
			throw Error(ERRORS.rangeOrder);
322
		}
323
		if (
324
			rangeStart < 0x0 || rangeStart > 0x10FFFF ||
325
			rangeEnd < 0x0 || rangeEnd > 0x10FFFF
326
		) {
327
			throw RangeError(ERRORS.codePointRange);
328
		}
329
		// Iterate over the data per `(start, end)` pair.
330
		var index = 0;
331
		var start;
332
		var end;
333
		var added = false;
334
		var length = data.length;
335
		while (index < length) {
336
			start = data[index];
337
			end = data[index + 1];
338

    
339
			if (added) {
340
				// The range has already been added to the set; at this point, we just
341
				// need to get rid of the following ranges in case they overlap.
342

    
343
				// Check if this range can be combined with the previous range.
344
				if (start == rangeEnd + 1) {
345
					data.splice(index - 1, 2);
346
					return data;
347
				}
348

    
349
				// Exit as soon as no more possibly overlapping pairs can be found.
350
				if (start > rangeEnd) {
351
					return data;
352
				}
353

    
354
				// E.g. `[0, 11, 12, 16]` and we’ve added 5-15, so we now have
355
				// `[0, 16, 12, 16]`. Remove the `12,16` part, as it lies within the
356
				// `0,16` range that was previously added.
357
				if (start >= rangeStart && start <= rangeEnd) {
358
					// `start` lies within the range that was previously added.
359

    
360
					if (end > rangeStart && end - 1 <= rangeEnd) {
361
						// `end` lies within the range that was previously added as well,
362
						// so remove this pair.
363
						data.splice(index, 2);
364
						index -= 2;
365
						// Note: we cannot `return` just yet, as there may still be other
366
						// overlapping pairs.
367
					} else {
368
						// `start` lies within the range that was previously added, but
369
						// `end` doesn’t. E.g. `[0, 11, 12, 31]` and we’ve added 5-15, so
370
						// now we have `[0, 16, 12, 31]`. This must be written as `[0, 31]`.
371
						// Remove the previously added `end` and the current `start`.
372
						data.splice(index - 1, 2);
373
						index -= 2;
374
					}
375

    
376
					// Note: we cannot return yet.
377
				}
378

    
379
			}
380

    
381
			else if (start == rangeEnd + 1) {
382
				data[index] = rangeStart;
383
				return data;
384
			}
385

    
386
			// Check if a new pair must be inserted *before* the current one.
387
			else if (start > rangeEnd) {
388
				data.splice(index, 0, rangeStart, rangeEnd + 1);
389
				return data;
390
			}
391

    
392
			else if (rangeStart >= start && rangeStart < end && rangeEnd + 1 <= end) {
393
				// The new range lies entirely within an existing range pair. No action
394
				// needed.
395
				return data;
396
			}
397

    
398
			else if (
399
				// E.g. `[0, 11]` and you add 5-15 → `[0, 16]`.
400
				(rangeStart >= start && rangeStart < end) ||
401
				// E.g. `[0, 3]` and you add 3-6 → `[0, 7]`.
402
				end == rangeStart
403
			) {
404
				// Replace `end` with the new value.
405
				data[index + 1] = rangeEnd + 1;
406
				// Make sure the next range pair doesn’t overlap, e.g. `[0, 11, 12, 14]`
407
				// and you add 5-15 → `[0, 16]`, i.e. remove the `12,14` part.
408
				added = true;
409
				// Note: we cannot `return` just yet.
410
			}
411

    
412
			else if (rangeStart <= start && rangeEnd + 1 >= end) {
413
				// The new range is a superset of the old range.
414
				data[index] = rangeStart;
415
				data[index + 1] = rangeEnd + 1;
416
				added = true;
417
			}
418

    
419
			index += 2;
420
		}
421
		// The loop has finished without doing anything; add the new pair to the end
422
		// of the data set.
423
		if (!added) {
424
			data.push(rangeStart, rangeEnd + 1);
425
		}
426
		return data;
427
	};
428

    
429
	var dataContains = function(data, codePoint) {
430
		var index = 0;
431
		var length = data.length;
432
		// Exit early if `codePoint` is not within `data`’s overall range.
433
		var start = data[index];
434
		var end = data[length - 1];
435
		if (length >= 2) {
436
			if (codePoint < start || codePoint > end) {
437
				return false;
438
			}
439
		}
440
		// Iterate over the data per `(start, end)` pair.
441
		while (index < length) {
442
			start = data[index];
443
			end = data[index + 1];
444
			if (codePoint >= start && codePoint < end) {
445
				return true;
446
			}
447
			index += 2;
448
		}
449
		return false;
450
	};
451

    
452
	var dataIntersection = function(data, codePoints) {
453
		var index = 0;
454
		var length = codePoints.length;
455
		var codePoint;
456
		var result = [];
457
		while (index < length) {
458
			codePoint = codePoints[index];
459
			if (dataContains(data, codePoint)) {
460
				result.push(codePoint);
461
			}
462
			++index;
463
		}
464
		return dataFromCodePoints(result);
465
	};
466

    
467
	var dataIsEmpty = function(data) {
468
		return !data.length;
469
	};
470

    
471
	var dataIsSingleton = function(data) {
472
		// Check if the set only represents a single code point.
473
		return data.length == 2 && data[0] + 1 == data[1];
474
	};
475

    
476
	var dataToArray = function(data) {
477
		// Iterate over the data per `(start, end)` pair.
478
		var index = 0;
479
		var start;
480
		var end;
481
		var result = [];
482
		var length = data.length;
483
		while (index < length) {
484
			start = data[index];
485
			end = data[index + 1];
486
			while (start < end) {
487
				result.push(start);
488
				++start;
489
			}
490
			index += 2;
491
		}
492
		return result;
493
	};
494

    
495
	/*--------------------------------------------------------------------------*/
496

    
497
	// https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
498
	var floor = Math.floor;
499
	var highSurrogate = function(codePoint) {
500
		return parseInt(
501
			floor((codePoint - 0x10000) / 0x400) + HIGH_SURROGATE_MIN,
502
			10
503
		);
504
	};
505

    
506
	var lowSurrogate = function(codePoint) {
507
		return parseInt(
508
			(codePoint - 0x10000) % 0x400 + LOW_SURROGATE_MIN,
509
			10
510
		);
511
	};
512

    
513
	var stringFromCharCode = String.fromCharCode;
514
	var codePointToString = function(codePoint) {
515
		var string;
516
		// https://mathiasbynens.be/notes/javascript-escapes#single
517
		// Note: the `\b` escape sequence for U+0008 BACKSPACE in strings has a
518
		// different meaning in regular expressions (word boundary), so it cannot
519
		// be used here.
520
		if (codePoint == 0x09) {
521
			string = '\\t';
522
		}
523
		// Note: IE < 9 treats `'\v'` as `'v'`, so avoid using it.
524
		// else if (codePoint == 0x0B) {
525
		// 	string = '\\v';
526
		// }
527
		else if (codePoint == 0x0A) {
528
			string = '\\n';
529
		}
530
		else if (codePoint == 0x0C) {
531
			string = '\\f';
532
		}
533
		else if (codePoint == 0x0D) {
534
			string = '\\r';
535
		}
536
		else if (codePoint == 0x2D) {
537
			// https://mathiasbynens.be/notes/javascript-escapes#hexadecimal
538
			// Note: `-` (U+002D HYPHEN-MINUS) is escaped in this way rather
539
			// than by backslash-escaping, in case the output is used outside
540
			// of a character class in a `u` RegExp. /\-/u throws, but
541
			// /\x2D/u is fine.
542
			string = '\\x2D';
543
		}
544
		else if (codePoint == 0x5C) {
545
			string = '\\\\';
546
		}
547
		else if (
548
			codePoint == 0x24 ||
549
			(codePoint >= 0x28 && codePoint <= 0x2B) ||
550
			codePoint == 0x2E || codePoint == 0x2F ||
551
			codePoint == 0x3F ||
552
			(codePoint >= 0x5B && codePoint <= 0x5E) ||
553
			(codePoint >= 0x7B && codePoint <= 0x7D)
554
		) {
555
			// The code point maps to an unsafe printable ASCII character;
556
			// backslash-escape it. Here’s the list of those symbols:
557
			//
558
			//     $()*+./?[\]^{|}
559
			//
560
			// This matches SyntaxCharacters as well as `/` (U+002F SOLIDUS).
561
			// https://tc39.github.io/ecma262/#prod-SyntaxCharacter
562
			string = '\\' + stringFromCharCode(codePoint);
563
		}
564
		else if (codePoint >= 0x20 && codePoint <= 0x7E) {
565
			// The code point maps to one of these printable ASCII symbols
566
			// (including the space character):
567
			//
568
			//      !"#%&',/0123456789:;<=>@ABCDEFGHIJKLMNO
569
			//     PQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~
570
			//
571
			// These can safely be used directly.
572
			string = stringFromCharCode(codePoint);
573
		}
574
		else if (codePoint <= 0xFF) {
575
			string = '\\x' + pad(hex(codePoint), 2);
576
		}
577
		else { // `codePoint <= 0xFFFF` holds true.
578
			// https://mathiasbynens.be/notes/javascript-escapes#unicode
579
			string = '\\u' + pad(hex(codePoint), 4);
580
		}
581

    
582
		// There’s no need to account for astral symbols / surrogate pairs here,
583
		// since `codePointToString` is private and only used for BMP code points.
584
		// But if that’s what you need, just add an `else` block with this code:
585
		//
586
		//     string = '\\u' + pad(hex(highSurrogate(codePoint)), 4)
587
		//     	+ '\\u' + pad(hex(lowSurrogate(codePoint)), 4);
588

    
589
		return string;
590
	};
591

    
592
	var codePointToStringUnicode = function(codePoint) {
593
		if (codePoint <= 0xFFFF) {
594
			return codePointToString(codePoint);
595
		}
596
		return '\\u{' + codePoint.toString(16).toUpperCase() + '}';
597
	};
598

    
599
	var symbolToCodePoint = function(symbol) {
600
		var length = symbol.length;
601
		var first = symbol.charCodeAt(0);
602
		var second;
603
		if (
604
			first >= HIGH_SURROGATE_MIN && first <= HIGH_SURROGATE_MAX &&
605
			length > 1 // There is a next code unit.
606
		) {
607
			// `first` is a high surrogate, and there is a next character. Assume
608
			// it’s a low surrogate (else it’s invalid usage of Regenerate anyway).
609
			second = symbol.charCodeAt(1);
610
			// https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
611
			return (first - HIGH_SURROGATE_MIN) * 0x400 +
612
				second - LOW_SURROGATE_MIN + 0x10000;
613
		}
614
		return first;
615
	};
616

    
617
	var createBMPCharacterClasses = function(data) {
618
		// Iterate over the data per `(start, end)` pair.
619
		var result = '';
620
		var index = 0;
621
		var start;
622
		var end;
623
		var length = data.length;
624
		if (dataIsSingleton(data)) {
625
			return codePointToString(data[0]);
626
		}
627
		while (index < length) {
628
			start = data[index];
629
			end = data[index + 1] - 1; // Note: the `- 1` makes `end` inclusive.
630
			if (start == end) {
631
				result += codePointToString(start);
632
			} else if (start + 1 == end) {
633
				result += codePointToString(start) + codePointToString(end);
634
			} else {
635
				result += codePointToString(start) + '-' + codePointToString(end);
636
			}
637
			index += 2;
638
		}
639
		return '[' + result + ']';
640
	};
641

    
642
	var createUnicodeCharacterClasses = function(data) {
643
		// Iterate over the data per `(start, end)` pair.
644
		var result = '';
645
		var index = 0;
646
		var start;
647
		var end;
648
		var length = data.length;
649
		if (dataIsSingleton(data)) {
650
			return codePointToStringUnicode(data[0]);
651
		}
652
		while (index < length) {
653
			start = data[index];
654
			end = data[index + 1] - 1; // Note: the `- 1` makes `end` inclusive.
655
			if (start == end) {
656
				result += codePointToStringUnicode(start);
657
			} else if (start + 1 == end) {
658
				result += codePointToStringUnicode(start) + codePointToStringUnicode(end);
659
			} else {
660
				result += codePointToStringUnicode(start) + '-' + codePointToStringUnicode(end);
661
			}
662
			index += 2;
663
		}
664
		return '[' + result + ']';
665
	};
666

    
667
	var splitAtBMP = function(data) {
668
		// Iterate over the data per `(start, end)` pair.
669
		var loneHighSurrogates = [];
670
		var loneLowSurrogates = [];
671
		var bmp = [];
672
		var astral = [];
673
		var index = 0;
674
		var start;
675
		var end;
676
		var length = data.length;
677
		while (index < length) {
678
			start = data[index];
679
			end = data[index + 1] - 1; // Note: the `- 1` makes `end` inclusive.
680

    
681
			if (start < HIGH_SURROGATE_MIN) {
682

    
683
				// The range starts and ends before the high surrogate range.
684
				// E.g. (0, 0x10).
685
				if (end < HIGH_SURROGATE_MIN) {
686
					bmp.push(start, end + 1);
687
				}
688

    
689
				// The range starts before the high surrogate range and ends within it.
690
				// E.g. (0, 0xD855).
691
				if (end >= HIGH_SURROGATE_MIN && end <= HIGH_SURROGATE_MAX) {
692
					bmp.push(start, HIGH_SURROGATE_MIN);
693
					loneHighSurrogates.push(HIGH_SURROGATE_MIN, end + 1);
694
				}
695

    
696
				// The range starts before the high surrogate range and ends in the low
697
				// surrogate range. E.g. (0, 0xDCFF).
698
				if (end >= LOW_SURROGATE_MIN && end <= LOW_SURROGATE_MAX) {
699
					bmp.push(start, HIGH_SURROGATE_MIN);
700
					loneHighSurrogates.push(HIGH_SURROGATE_MIN, HIGH_SURROGATE_MAX + 1);
701
					loneLowSurrogates.push(LOW_SURROGATE_MIN, end + 1);
702
				}
703

    
704
				// The range starts before the high surrogate range and ends after the
705
				// low surrogate range. E.g. (0, 0x10FFFF).
706
				if (end > LOW_SURROGATE_MAX) {
707
					bmp.push(start, HIGH_SURROGATE_MIN);
708
					loneHighSurrogates.push(HIGH_SURROGATE_MIN, HIGH_SURROGATE_MAX + 1);
709
					loneLowSurrogates.push(LOW_SURROGATE_MIN, LOW_SURROGATE_MAX + 1);
710
					if (end <= 0xFFFF) {
711
						bmp.push(LOW_SURROGATE_MAX + 1, end + 1);
712
					} else {
713
						bmp.push(LOW_SURROGATE_MAX + 1, 0xFFFF + 1);
714
						astral.push(0xFFFF + 1, end + 1);
715
					}
716
				}
717

    
718
			} else if (start >= HIGH_SURROGATE_MIN && start <= HIGH_SURROGATE_MAX) {
719

    
720
				// The range starts and ends in the high surrogate range.
721
				// E.g. (0xD855, 0xD866).
722
				if (end >= HIGH_SURROGATE_MIN && end <= HIGH_SURROGATE_MAX) {
723
					loneHighSurrogates.push(start, end + 1);
724
				}
725

    
726
				// The range starts in the high surrogate range and ends in the low
727
				// surrogate range. E.g. (0xD855, 0xDCFF).
728
				if (end >= LOW_SURROGATE_MIN && end <= LOW_SURROGATE_MAX) {
729
					loneHighSurrogates.push(start, HIGH_SURROGATE_MAX + 1);
730
					loneLowSurrogates.push(LOW_SURROGATE_MIN, end + 1);
731
				}
732

    
733
				// The range starts in the high surrogate range and ends after the low
734
				// surrogate range. E.g. (0xD855, 0x10FFFF).
735
				if (end > LOW_SURROGATE_MAX) {
736
					loneHighSurrogates.push(start, HIGH_SURROGATE_MAX + 1);
737
					loneLowSurrogates.push(LOW_SURROGATE_MIN, LOW_SURROGATE_MAX + 1);
738
					if (end <= 0xFFFF) {
739
						bmp.push(LOW_SURROGATE_MAX + 1, end + 1);
740
					} else {
741
						bmp.push(LOW_SURROGATE_MAX + 1, 0xFFFF + 1);
742
						astral.push(0xFFFF + 1, end + 1);
743
					}
744
				}
745

    
746
			} else if (start >= LOW_SURROGATE_MIN && start <= LOW_SURROGATE_MAX) {
747

    
748
				// The range starts and ends in the low surrogate range.
749
				// E.g. (0xDCFF, 0xDDFF).
750
				if (end >= LOW_SURROGATE_MIN && end <= LOW_SURROGATE_MAX) {
751
					loneLowSurrogates.push(start, end + 1);
752
				}
753

    
754
				// The range starts in the low surrogate range and ends after the low
755
				// surrogate range. E.g. (0xDCFF, 0x10FFFF).
756
				if (end > LOW_SURROGATE_MAX) {
757
					loneLowSurrogates.push(start, LOW_SURROGATE_MAX + 1);
758
					if (end <= 0xFFFF) {
759
						bmp.push(LOW_SURROGATE_MAX + 1, end + 1);
760
					} else {
761
						bmp.push(LOW_SURROGATE_MAX + 1, 0xFFFF + 1);
762
						astral.push(0xFFFF + 1, end + 1);
763
					}
764
				}
765

    
766
			} else if (start > LOW_SURROGATE_MAX && start <= 0xFFFF) {
767

    
768
				// The range starts and ends after the low surrogate range.
769
				// E.g. (0xFFAA, 0x10FFFF).
770
				if (end <= 0xFFFF) {
771
					bmp.push(start, end + 1);
772
				} else {
773
					bmp.push(start, 0xFFFF + 1);
774
					astral.push(0xFFFF + 1, end + 1);
775
				}
776

    
777
			} else {
778

    
779
				// The range starts and ends in the astral range.
780
				astral.push(start, end + 1);
781

    
782
			}
783

    
784
			index += 2;
785
		}
786
		return {
787
			'loneHighSurrogates': loneHighSurrogates,
788
			'loneLowSurrogates': loneLowSurrogates,
789
			'bmp': bmp,
790
			'astral': astral
791
		};
792
	};
793

    
794
	var optimizeSurrogateMappings = function(surrogateMappings) {
795
		var result = [];
796
		var tmpLow = [];
797
		var addLow = false;
798
		var mapping;
799
		var nextMapping;
800
		var highSurrogates;
801
		var lowSurrogates;
802
		var nextHighSurrogates;
803
		var nextLowSurrogates;
804
		var index = -1;
805
		var length = surrogateMappings.length;
806
		while (++index < length) {
807
			mapping = surrogateMappings[index];
808
			nextMapping = surrogateMappings[index + 1];
809
			if (!nextMapping) {
810
				result.push(mapping);
811
				continue;
812
			}
813
			highSurrogates = mapping[0];
814
			lowSurrogates = mapping[1];
815
			nextHighSurrogates = nextMapping[0];
816
			nextLowSurrogates = nextMapping[1];
817

    
818
			// Check for identical high surrogate ranges.
819
			tmpLow = lowSurrogates;
820
			while (
821
				nextHighSurrogates &&
822
				highSurrogates[0] == nextHighSurrogates[0] &&
823
				highSurrogates[1] == nextHighSurrogates[1]
824
			) {
825
				// Merge with the next item.
826
				if (dataIsSingleton(nextLowSurrogates)) {
827
					tmpLow = dataAdd(tmpLow, nextLowSurrogates[0]);
828
				} else {
829
					tmpLow = dataAddRange(
830
						tmpLow,
831
						nextLowSurrogates[0],
832
						nextLowSurrogates[1] - 1
833
					);
834
				}
835
				++index;
836
				mapping = surrogateMappings[index];
837
				highSurrogates = mapping[0];
838
				lowSurrogates = mapping[1];
839
				nextMapping = surrogateMappings[index + 1];
840
				nextHighSurrogates = nextMapping && nextMapping[0];
841
				nextLowSurrogates = nextMapping && nextMapping[1];
842
				addLow = true;
843
			}
844
			result.push([
845
				highSurrogates,
846
				addLow ? tmpLow : lowSurrogates
847
			]);
848
			addLow = false;
849
		}
850
		return optimizeByLowSurrogates(result);
851
	};
852

    
853
	var optimizeByLowSurrogates = function(surrogateMappings) {
854
		if (surrogateMappings.length == 1) {
855
			return surrogateMappings;
856
		}
857
		var index = -1;
858
		var innerIndex = -1;
859
		while (++index < surrogateMappings.length) {
860
			var mapping = surrogateMappings[index];
861
			var lowSurrogates = mapping[1];
862
			var lowSurrogateStart = lowSurrogates[0];
863
			var lowSurrogateEnd = lowSurrogates[1];
864
			innerIndex = index; // Note: the loop starts at the next index.
865
			while (++innerIndex < surrogateMappings.length) {
866
				var otherMapping = surrogateMappings[innerIndex];
867
				var otherLowSurrogates = otherMapping[1];
868
				var otherLowSurrogateStart = otherLowSurrogates[0];
869
				var otherLowSurrogateEnd = otherLowSurrogates[1];
870
				if (
871
					lowSurrogateStart == otherLowSurrogateStart &&
872
					lowSurrogateEnd == otherLowSurrogateEnd
873
				) {
874
					// Add the code points in the other item to this one.
875
					if (dataIsSingleton(otherMapping[0])) {
876
						mapping[0] = dataAdd(mapping[0], otherMapping[0][0]);
877
					} else {
878
						mapping[0] = dataAddRange(
879
							mapping[0],
880
							otherMapping[0][0],
881
							otherMapping[0][1] - 1
882
						);
883
					}
884
					// Remove the other, now redundant, item.
885
					surrogateMappings.splice(innerIndex, 1);
886
					--innerIndex;
887
				}
888
			}
889
		}
890
		return surrogateMappings;
891
	};
892

    
893
	var surrogateSet = function(data) {
894
		// Exit early if `data` is an empty set.
895
		if (!data.length) {
896
			return [];
897
		}
898

    
899
		// Iterate over the data per `(start, end)` pair.
900
		var index = 0;
901
		var start;
902
		var end;
903
		var startHigh;
904
		var startLow;
905
		var endHigh;
906
		var endLow;
907
		var surrogateMappings = [];
908
		var length = data.length;
909
		while (index < length) {
910
			start = data[index];
911
			end = data[index + 1] - 1;
912

    
913
			startHigh = highSurrogate(start);
914
			startLow = lowSurrogate(start);
915
			endHigh = highSurrogate(end);
916
			endLow = lowSurrogate(end);
917

    
918
			var startsWithLowestLowSurrogate = startLow == LOW_SURROGATE_MIN;
919
			var endsWithHighestLowSurrogate = endLow == LOW_SURROGATE_MAX;
920
			var complete = false;
921

    
922
			// Append the previous high-surrogate-to-low-surrogate mappings.
923
			// Step 1: `(startHigh, startLow)` to `(startHigh, LOW_SURROGATE_MAX)`.
924
			if (
925
				startHigh == endHigh ||
926
				startsWithLowestLowSurrogate && endsWithHighestLowSurrogate
927
			) {
928
				surrogateMappings.push([
929
					[startHigh, endHigh + 1],
930
					[startLow, endLow + 1]
931
				]);
932
				complete = true;
933
			} else {
934
				surrogateMappings.push([
935
					[startHigh, startHigh + 1],
936
					[startLow, LOW_SURROGATE_MAX + 1]
937
				]);
938
			}
939

    
940
			// Step 2: `(startHigh + 1, LOW_SURROGATE_MIN)` to
941
			// `(endHigh - 1, LOW_SURROGATE_MAX)`.
942
			if (!complete && startHigh + 1 < endHigh) {
943
				if (endsWithHighestLowSurrogate) {
944
					// Combine step 2 and step 3.
945
					surrogateMappings.push([
946
						[startHigh + 1, endHigh + 1],
947
						[LOW_SURROGATE_MIN, endLow + 1]
948
					]);
949
					complete = true;
950
				} else {
951
					surrogateMappings.push([
952
						[startHigh + 1, endHigh],
953
						[LOW_SURROGATE_MIN, LOW_SURROGATE_MAX + 1]
954
					]);
955
				}
956
			}
957

    
958
			// Step 3. `(endHigh, LOW_SURROGATE_MIN)` to `(endHigh, endLow)`.
959
			if (!complete) {
960
				surrogateMappings.push([
961
					[endHigh, endHigh + 1],
962
					[LOW_SURROGATE_MIN, endLow + 1]
963
				]);
964
			}
965

    
966
			index += 2;
967
		}
968

    
969
		// The format of `surrogateMappings` is as follows:
970
		//
971
		//     [ surrogateMapping1, surrogateMapping2 ]
972
		//
973
		// i.e.:
974
		//
975
		//     [
976
		//       [ highSurrogates1, lowSurrogates1 ],
977
		//       [ highSurrogates2, lowSurrogates2 ]
978
		//     ]
979
		return optimizeSurrogateMappings(surrogateMappings);
980
	};
981

    
982
	var createSurrogateCharacterClasses = function(surrogateMappings) {
983
		var result = [];
984
		forEach(surrogateMappings, function(surrogateMapping) {
985
			var highSurrogates = surrogateMapping[0];
986
			var lowSurrogates = surrogateMapping[1];
987
			result.push(
988
				createBMPCharacterClasses(highSurrogates) +
989
				createBMPCharacterClasses(lowSurrogates)
990
			);
991
		});
992
		return result.join('|');
993
	};
994

    
995
	var createCharacterClassesFromData = function(data, bmpOnly, hasUnicodeFlag) {
996
		if (hasUnicodeFlag) {
997
			return createUnicodeCharacterClasses(data);
998
		}
999
		var result = [];
1000

    
1001
		var parts = splitAtBMP(data);
1002
		var loneHighSurrogates = parts.loneHighSurrogates;
1003
		var loneLowSurrogates = parts.loneLowSurrogates;
1004
		var bmp = parts.bmp;
1005
		var astral = parts.astral;
1006
		var hasLoneHighSurrogates = !dataIsEmpty(loneHighSurrogates);
1007
		var hasLoneLowSurrogates = !dataIsEmpty(loneLowSurrogates);
1008

    
1009
		var surrogateMappings = surrogateSet(astral);
1010

    
1011
		if (bmpOnly) {
1012
			bmp = dataAddData(bmp, loneHighSurrogates);
1013
			hasLoneHighSurrogates = false;
1014
			bmp = dataAddData(bmp, loneLowSurrogates);
1015
			hasLoneLowSurrogates = false;
1016
		}
1017

    
1018
		if (!dataIsEmpty(bmp)) {
1019
			// The data set contains BMP code points that are not high surrogates
1020
			// needed for astral code points in the set.
1021
			result.push(createBMPCharacterClasses(bmp));
1022
		}
1023
		if (surrogateMappings.length) {
1024
			// The data set contains astral code points; append character classes
1025
			// based on their surrogate pairs.
1026
			result.push(createSurrogateCharacterClasses(surrogateMappings));
1027
		}
1028
		// https://gist.github.com/mathiasbynens/bbe7f870208abcfec860
1029
		if (hasLoneHighSurrogates) {
1030
			result.push(
1031
				createBMPCharacterClasses(loneHighSurrogates) +
1032
				// Make sure the high surrogates aren’t part of a surrogate pair.
1033
				'(?![\\uDC00-\\uDFFF])'
1034
			);
1035
		}
1036
		if (hasLoneLowSurrogates) {
1037
			result.push(
1038
				// It is not possible to accurately assert the low surrogates aren’t
1039
				// part of a surrogate pair, since JavaScript regular expressions do
1040
				// not support lookbehind.
1041
				'(?:[^\\uD800-\\uDBFF]|^)' +
1042
				createBMPCharacterClasses(loneLowSurrogates)
1043
			);
1044
		}
1045
		return result.join('|');
1046
	};
1047

    
1048
	/*--------------------------------------------------------------------------*/
1049

    
1050
	// `regenerate` can be used as a constructor (and new methods can be added to
1051
	// its prototype) but also as a regular function, the latter of which is the
1052
	// documented and most common usage. For that reason, it’s not capitalized.
1053
	var regenerate = function(value) {
1054
		if (arguments.length > 1) {
1055
			value = slice.call(arguments);
1056
		}
1057
		if (this instanceof regenerate) {
1058
			this.data = [];
1059
			return value ? this.add(value) : this;
1060
		}
1061
		return (new regenerate).add(value);
1062
	};
1063

    
1064
	regenerate.version = '1.3.3';
1065

    
1066
	var proto = regenerate.prototype;
1067
	extend(proto, {
1068
		'add': function(value) {
1069
			var $this = this;
1070
			if (value == null) {
1071
				return $this;
1072
			}
1073
			if (value instanceof regenerate) {
1074
				// Allow passing other Regenerate instances.
1075
				$this.data = dataAddData($this.data, value.data);
1076
				return $this;
1077
			}
1078
			if (arguments.length > 1) {
1079
				value = slice.call(arguments);
1080
			}
1081
			if (isArray(value)) {
1082
				forEach(value, function(item) {
1083
					$this.add(item);
1084
				});
1085
				return $this;
1086
			}
1087
			$this.data = dataAdd(
1088
				$this.data,
1089
				isNumber(value) ? value : symbolToCodePoint(value)
1090
			);
1091
			return $this;
1092
		},
1093
		'remove': function(value) {
1094
			var $this = this;
1095
			if (value == null) {
1096
				return $this;
1097
			}
1098
			if (value instanceof regenerate) {
1099
				// Allow passing other Regenerate instances.
1100
				$this.data = dataRemoveData($this.data, value.data);
1101
				return $this;
1102
			}
1103
			if (arguments.length > 1) {
1104
				value = slice.call(arguments);
1105
			}
1106
			if (isArray(value)) {
1107
				forEach(value, function(item) {
1108
					$this.remove(item);
1109
				});
1110
				return $this;
1111
			}
1112
			$this.data = dataRemove(
1113
				$this.data,
1114
				isNumber(value) ? value : symbolToCodePoint(value)
1115
			);
1116
			return $this;
1117
		},
1118
		'addRange': function(start, end) {
1119
			var $this = this;
1120
			$this.data = dataAddRange($this.data,
1121
				isNumber(start) ? start : symbolToCodePoint(start),
1122
				isNumber(end) ? end : symbolToCodePoint(end)
1123
			);
1124
			return $this;
1125
		},
1126
		'removeRange': function(start, end) {
1127
			var $this = this;
1128
			var startCodePoint = isNumber(start) ? start : symbolToCodePoint(start);
1129
			var endCodePoint = isNumber(end) ? end : symbolToCodePoint(end);
1130
			$this.data = dataRemoveRange(
1131
				$this.data,
1132
				startCodePoint,
1133
				endCodePoint
1134
			);
1135
			return $this;
1136
		},
1137
		'intersection': function(argument) {
1138
			var $this = this;
1139
			// Allow passing other Regenerate instances.
1140
			// TODO: Optimize this by writing and using `dataIntersectionData()`.
1141
			var array = argument instanceof regenerate ?
1142
				dataToArray(argument.data) :
1143
				argument;
1144
			$this.data = dataIntersection($this.data, array);
1145
			return $this;
1146
		},
1147
		'contains': function(codePoint) {
1148
			return dataContains(
1149
				this.data,
1150
				isNumber(codePoint) ? codePoint : symbolToCodePoint(codePoint)
1151
			);
1152
		},
1153
		'clone': function() {
1154
			var set = new regenerate;
1155
			set.data = this.data.slice(0);
1156
			return set;
1157
		},
1158
		'toString': function(options) {
1159
			var result = createCharacterClassesFromData(
1160
				this.data,
1161
				options ? options.bmpOnly : false,
1162
				options ? options.hasUnicodeFlag : false
1163
			);
1164
			if (!result) {
1165
				// For an empty set, return something that can be inserted `/here/` to
1166
				// form a valid regular expression. Avoid `(?:)` since that matches the
1167
				// empty string.
1168
				return '[]';
1169
			}
1170
			// Use `\0` instead of `\x00` where possible.
1171
			return result.replace(regexNull, '\\0$1');
1172
		},
1173
		'toRegExp': function(flags) {
1174
			var pattern = this.toString(
1175
				flags && flags.indexOf('u') != -1 ?
1176
					{ 'hasUnicodeFlag': true } :
1177
					null
1178
			);
1179
			return RegExp(pattern, flags || '');
1180
		},
1181
		'valueOf': function() { // Note: `valueOf` is aliased as `toArray`.
1182
			return dataToArray(this.data);
1183
		}
1184
	});
1185

    
1186
	proto.toArray = proto.valueOf;
1187

    
1188
	// Some AMD build optimizers, like r.js, check for specific condition patterns
1189
	// like the following:
1190
	if (
1191
		typeof define == 'function' &&
1192
		typeof define.amd == 'object' &&
1193
		define.amd
1194
	) {
1195
		define(function() {
1196
			return regenerate;
1197
		});
1198
	}	else if (freeExports && !freeExports.nodeType) {
1199
		if (freeModule) { // in Node.js, io.js, or RingoJS v0.8.0+
1200
			freeModule.exports = regenerate;
1201
		} else { // in Narwhal or RingoJS v0.7.0-
1202
			freeExports.regenerate = regenerate;
1203
		}
1204
	} else { // in Rhino or a web browser
1205
		root.regenerate = regenerate;
1206
	}
1207

    
1208
}(this));
(3-3/3)