docjs 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/README.md +7 -5
  2. data/bin/docjs +33 -8
  3. data/bin/docjs.rb +239 -0
  4. data/docjs.gemspec +2 -2
  5. data/lib/boot.rb +5 -3
  6. data/lib/code_object/base.rb +1 -0
  7. data/lib/code_object/function.rb +21 -37
  8. data/lib/code_object/object.rb +1 -1
  9. data/lib/helper/helper.rb +16 -3
  10. data/lib/helper/linker.rb +5 -2
  11. data/lib/parser/parser.rb +20 -6
  12. data/lib/token/container.rb +0 -1
  13. data/lib/token/handler.rb +46 -6
  14. data/lib/token/token.rb +3 -2
  15. data/templates/helpers/template.rb +15 -5
  16. data/templates/resources/css/application.css +65 -14
  17. data/templates/resources/js/application.js +33 -11
  18. data/templates/resources/js/regexpx.js +652 -0
  19. data/templates/resources/js/shBrushJScript.js +55 -0
  20. data/templates/resources/js/shCore.js +1596 -0
  21. data/templates/resources/scss/_header.scss +2 -1
  22. data/templates/resources/scss/_helpers.scss +6 -6
  23. data/templates/resources/scss/_highlighter.scss +70 -0
  24. data/templates/resources/scss/application.scss +8 -8
  25. data/templates/tokens/tokens.rb +55 -4
  26. data/templates/views/function/_detail.html.erb +1 -1
  27. data/templates/views/function/index.html.erb +16 -4
  28. data/templates/views/layout/application.html.erb +5 -5
  29. data/templates/views/layout/json.html.erb +3 -3
  30. data/templates/views/object/index.html.erb +3 -3
  31. data/templates/views/tokens/_default.html.erb +4 -2
  32. data/templates/views/tokens/_default_token.html.erb +2 -1
  33. data/templates/views/tokens/_example.html.erb +1 -1
  34. data/templates/views/tokens/_overload.html.erb +12 -0
  35. data/test/interactive.rb +5 -2
  36. data/test/js-files/core-doc.js +20 -12
  37. data/test/parser/intelligent_skip_until.rb +1 -1
  38. data/test/parser/parser.rb +3 -6
  39. metadata +8 -2
@@ -0,0 +1,652 @@
1
+ // XRegExp 1.5.0
2
+ // (c) 2007-2010 Steven Levithan
3
+ // MIT License
4
+ // <http://xregexp.com>
5
+ // Provides an augmented, extensible, cross-browser implementation of regular expressions,
6
+ // including support for additional syntax, flags, and methods
7
+
8
+ var XRegExp;
9
+
10
+ if (XRegExp) {
11
+ // Avoid running twice, since that would break references to native globals
12
+ throw Error("can't load XRegExp twice in the same frame");
13
+ }
14
+
15
+ // Run within an anonymous function to protect variables and avoid new globals
16
+ (function () {
17
+
18
+ //---------------------------------
19
+ // Constructor
20
+ //---------------------------------
21
+
22
+ // Accepts a pattern and flags; returns a new, extended `RegExp` object. Differs from a native
23
+ // regular expression in that additional syntax and flags are supported and cross-browser
24
+ // syntax inconsistencies are ameliorated
25
+ XRegExp = function (pattern, flags) {
26
+ var output = [],
27
+ currScope = XRegExp.OUTSIDE_CLASS,
28
+ pos = 0,
29
+ context, tokenResult, match, chr, regex;
30
+
31
+ if (XRegExp.isRegExp(pattern)) {
32
+ if (flags !== undefined)
33
+ throw TypeError("can't supply flags when constructing one RegExp from another");
34
+ return clone(pattern);
35
+ }
36
+ // Tokens become part of the regex construction process, so protect against infinite
37
+ // recursion when an XRegExp is constructed within a token handler or trigger
38
+ if (isInsideConstructor)
39
+ throw Error("can't call the XRegExp constructor within token definition functions");
40
+
41
+ flags = flags || "";
42
+ context = { // `this` object for custom tokens
43
+ hasNamedCapture: false,
44
+ captureNames: [],
45
+ hasFlag: function (flag) {return flags.indexOf(flag) > -1;},
46
+ setFlag: function (flag) {flags += flag;}
47
+ };
48
+
49
+ while (pos < pattern.length) {
50
+ // Check for custom tokens at the current position
51
+ tokenResult = runTokens(pattern, pos, currScope, context);
52
+
53
+ if (tokenResult) {
54
+ output.push(tokenResult.output);
55
+ pos += (tokenResult.match[0].length || 1);
56
+ } else {
57
+ // Check for native multicharacter metasequences (excluding character classes) at
58
+ // the current position
59
+ if (match = real.exec.call(nativeTokens[currScope], pattern.slice(pos))) {
60
+ output.push(match[0]);
61
+ pos += match[0].length;
62
+ } else {
63
+ chr = pattern.charAt(pos);
64
+ if (chr === "[")
65
+ currScope = XRegExp.INSIDE_CLASS;
66
+ else if (chr === "]")
67
+ currScope = XRegExp.OUTSIDE_CLASS;
68
+ // Advance position one character
69
+ output.push(chr);
70
+ pos++;
71
+ }
72
+ }
73
+ }
74
+
75
+ regex = RegExp(output.join(""), real.replace.call(flags, flagClip, ""));
76
+ regex._xregexp = {
77
+ source: pattern,
78
+ captureNames: context.hasNamedCapture ? context.captureNames : null
79
+ };
80
+ return regex;
81
+ };
82
+
83
+
84
+ //---------------------------------
85
+ // Public properties
86
+ //---------------------------------
87
+
88
+ XRegExp.version = "1.5.0";
89
+
90
+ // Token scope bitflags
91
+ XRegExp.INSIDE_CLASS = 1;
92
+ XRegExp.OUTSIDE_CLASS = 2;
93
+
94
+
95
+ //---------------------------------
96
+ // Private variables
97
+ //---------------------------------
98
+
99
+ var replacementToken = /\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g,
100
+ flagClip = /[^gimy]+|([\s\S])(?=[\s\S]*\1)/g, // Nonnative and duplicate flags
101
+ quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/,
102
+ isInsideConstructor = false,
103
+ tokens = [],
104
+ // Copy native globals for reference ("native" is an ES3 reserved keyword)
105
+ real = {
106
+ exec: RegExp.prototype.exec,
107
+ test: RegExp.prototype.test,
108
+ match: String.prototype.match,
109
+ replace: String.prototype.replace,
110
+ split: String.prototype.split
111
+ },
112
+ compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
113
+ compliantLastIndexIncrement = function () {
114
+ var x = /^/g;
115
+ real.test.call(x, "");
116
+ return !x.lastIndex;
117
+ }(),
118
+ compliantLastIndexReset = function () {
119
+ var x = /x/g;
120
+ real.replace.call("x", x, "");
121
+ return !x.lastIndex;
122
+ }(),
123
+ hasNativeY = RegExp.prototype.sticky !== undefined,
124
+ nativeTokens = {};
125
+
126
+ // `nativeTokens` match native multicharacter metasequences only (including deprecated octals,
127
+ // excluding character classes)
128
+ nativeTokens[XRegExp.INSIDE_CLASS] = /^(?:\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S]))/;
129
+ nativeTokens[XRegExp.OUTSIDE_CLASS] = /^(?:\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??)/;
130
+
131
+
132
+ //---------------------------------
133
+ // Public methods
134
+ //---------------------------------
135
+
136
+ // Lets you extend or change XRegExp syntax and create custom flags. This is used internally by
137
+ // the XRegExp library and can be used to create XRegExp plugins. This function is intended for
138
+ // users with advanced knowledge of JavaScript's regular expression syntax and behavior. It can
139
+ // be disabled by `XRegExp.freezeTokens`
140
+ XRegExp.addToken = function (regex, handler, scope, trigger) {
141
+ tokens.push({
142
+ pattern: clone(regex, "g" + (hasNativeY ? "y" : "")),
143
+ handler: handler,
144
+ scope: scope || XRegExp.OUTSIDE_CLASS,
145
+ trigger: trigger || null
146
+ });
147
+ };
148
+
149
+ // Accepts a pattern and flags; returns an extended `RegExp` object. If the pattern and flag
150
+ // combination has previously been cached, the cached copy is returned; otherwise the newly
151
+ // created regex is cached
152
+ XRegExp.cache = function (pattern, flags) {
153
+ var key = pattern + "/" + (flags || "");
154
+ return XRegExp.cache[key] || (XRegExp.cache[key] = XRegExp(pattern, flags));
155
+ };
156
+
157
+ // Accepts a `RegExp` instance; returns a copy with the `/g` flag set. The copy has a fresh
158
+ // `lastIndex` (set to zero). If you want to copy a regex without forcing the `global`
159
+ // property, use `XRegExp(regex)`. Do not use `RegExp(regex)` because it will not preserve
160
+ // special properties required for named capture
161
+ XRegExp.copyAsGlobal = function (regex) {
162
+ return clone(regex, "g");
163
+ };
164
+
165
+ // Accepts a string; returns the string with regex metacharacters escaped. The returned string
166
+ // can safely be used at any point within a regex to match the provided literal string. Escaped
167
+ // characters are [ ] { } ( ) * + ? - . , \ ^ $ | # and whitespace
168
+ XRegExp.escape = function (str) {
169
+ return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
170
+ };
171
+
172
+ // Accepts a string to search, regex to search with, position to start the search within the
173
+ // string (default: 0), and an optional Boolean indicating whether matches must start at-or-
174
+ // after the position or at the specified position only. This function ignores the `lastIndex`
175
+ // property of the provided regex
176
+ XRegExp.execAt = function (str, regex, pos, anchored) {
177
+ regex = clone(regex, "g" + ((anchored && hasNativeY) ? "y" : ""));
178
+ regex.lastIndex = pos = pos || 0;
179
+ var match = regex.exec(str);
180
+ if (anchored)
181
+ return (match && match.index === pos) ? match : null;
182
+ else
183
+ return match;
184
+ };
185
+
186
+ // Breaks the unrestorable link to XRegExp's private list of tokens, thereby preventing
187
+ // syntax and flag changes. Should be run after XRegExp and any plugins are loaded
188
+ XRegExp.freezeTokens = function () {
189
+ XRegExp.addToken = function () {
190
+ throw Error("can't run addToken after freezeTokens");
191
+ };
192
+ };
193
+
194
+ // Accepts any value; returns a Boolean indicating whether the argument is a `RegExp` object.
195
+ // Note that this is also `true` for regex literals and regexes created by the `XRegExp`
196
+ // constructor. This works correctly for variables created in another frame, when `instanceof`
197
+ // and `constructor` checks would fail to work as intended
198
+ XRegExp.isRegExp = function (o) {
199
+ return Object.prototype.toString.call(o) === "[object RegExp]";
200
+ };
201
+
202
+ // Executes `callback` once per match within `str`. Provides a simpler and cleaner way to
203
+ // iterate over regex matches compared to the traditional approaches of subverting
204
+ // `String.prototype.replace` or repeatedly calling `exec` within a `while` loop
205
+ XRegExp.iterate = function (str, origRegex, callback, context) {
206
+ var regex = clone(origRegex, "g"),
207
+ i = -1, match;
208
+ while (match = regex.exec(str)) {
209
+ callback.call(context, match, ++i, str, regex);
210
+ if (regex.lastIndex === match.index)
211
+ regex.lastIndex++;
212
+ }
213
+ if (origRegex.global)
214
+ origRegex.lastIndex = 0;
215
+ };
216
+
217
+ // Accepts a string and an array of regexes; returns the result of using each successive regex
218
+ // to search within the matches of the previous regex. The array of regexes can also contain
219
+ // objects with `regex` and `backref` properties, in which case the named or numbered back-
220
+ // references specified are passed forward to the next regex or returned. E.g.:
221
+ // var xregexpImgFileNames = XRegExp.matchChain(html, [
222
+ // {regex: /<img\b([^>]+)>/i, backref: 1}, // <img> tag attributes
223
+ // {regex: XRegExp('(?ix) \\s src=" (?<src> [^"]+ )'), backref: "src"}, // src attribute values
224
+ // {regex: XRegExp("^http://xregexp\\.com(/[^#?]+)", "i"), backref: 1}, // xregexp.com paths
225
+ // /[^\/]+$/ // filenames (strip directory paths)
226
+ // ]);
227
+ XRegExp.matchChain = function (str, chain) {
228
+ return function recurseChain (values, level) {
229
+ var item = chain[level].regex ? chain[level] : {regex: chain[level]},
230
+ regex = clone(item.regex, "g"),
231
+ matches = [], i;
232
+ for (i = 0; i < values.length; i++) {
233
+ XRegExp.iterate(values[i], regex, function (match) {
234
+ matches.push(item.backref ? (match[item.backref] || "") : match[0]);
235
+ });
236
+ }
237
+ return ((level === chain.length - 1) || !matches.length) ?
238
+ matches : recurseChain(matches, level + 1);
239
+ }([str], 0);
240
+ };
241
+
242
+
243
+ //---------------------------------
244
+ // New RegExp prototype methods
245
+ //---------------------------------
246
+
247
+ // Accepts a context object and arguments array; returns the result of calling `exec` with the
248
+ // first value in the arguments array. the context is ignored but is accepted for congruity
249
+ // with `Function.prototype.apply`
250
+ RegExp.prototype.apply = function (context, args) {
251
+ return this.exec(args[0]);
252
+ };
253
+
254
+ // Accepts a context object and string; returns the result of calling `exec` with the provided
255
+ // string. the context is ignored but is accepted for congruity with `Function.prototype.call`
256
+ RegExp.prototype.call = function (context, str) {
257
+ return this.exec(str);
258
+ };
259
+
260
+
261
+ //---------------------------------
262
+ // Overriden native methods
263
+ //---------------------------------
264
+
265
+ // Adds named capture support (with backreferences returned as `result.name`), and fixes two
266
+ // cross-browser issues per ES3:
267
+ // - Captured values for nonparticipating capturing groups should be returned as `undefined`,
268
+ // rather than the empty string.
269
+ // - `lastIndex` should not be incremented after zero-length matches.
270
+ RegExp.prototype.exec = function (str) {
271
+ var match = real.exec.apply(this, arguments),
272
+ name, r2;
273
+ if (match) {
274
+ // Fix browsers whose `exec` methods don't consistently return `undefined` for
275
+ // nonparticipating capturing groups
276
+ if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
277
+ r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", ""));
278
+ // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed
279
+ // matching due to characters outside the match
280
+ real.replace.call(str.slice(match.index), r2, function () {
281
+ for (var i = 1; i < arguments.length - 2; i++) {
282
+ if (arguments[i] === undefined)
283
+ match[i] = undefined;
284
+ }
285
+ });
286
+ }
287
+ // Attach named capture properties
288
+ if (this._xregexp && this._xregexp.captureNames) {
289
+ for (var i = 1; i < match.length; i++) {
290
+ name = this._xregexp.captureNames[i - 1];
291
+ if (name)
292
+ match[name] = match[i];
293
+ }
294
+ }
295
+ // Fix browsers that increment `lastIndex` after zero-length matches
296
+ if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
297
+ this.lastIndex--;
298
+ }
299
+ return match;
300
+ };
301
+
302
+ // Don't override `test` if it won't change anything
303
+ if (!compliantLastIndexIncrement) {
304
+ // Fix browser bug in native method
305
+ RegExp.prototype.test = function (str) {
306
+ // Use the native `exec` to skip some processing overhead, even though the overriden
307
+ // `exec` would take care of the `lastIndex` fix
308
+ var match = real.exec.call(this, str);
309
+ // Fix browsers that increment `lastIndex` after zero-length matches
310
+ if (match && this.global && !match[0].length && (this.lastIndex > match.index))
311
+ this.lastIndex--;
312
+ return !!match;
313
+ };
314
+ }
315
+
316
+ // Adds named capture support and fixes browser bugs in native method
317
+ String.prototype.match = function (regex) {
318
+ if (!XRegExp.isRegExp(regex))
319
+ regex = RegExp(regex); // Native `RegExp`
320
+ if (regex.global) {
321
+ var result = real.match.apply(this, arguments);
322
+ regex.lastIndex = 0; // Fix IE bug
323
+ return result;
324
+ }
325
+ return regex.exec(this); // Run the altered `exec`
326
+ };
327
+
328
+ // Adds support for `${n}` tokens for named and numbered backreferences in replacement text,
329
+ // and provides named backreferences to replacement functions as `arguments[0].name`. Also
330
+ // fixes cross-browser differences in replacement text syntax when performing a replacement
331
+ // using a nonregex search value, and the value of replacement regexes' `lastIndex` property
332
+ // during replacement iterations. Note that this doesn't support SpiderMonkey's proprietary
333
+ // third (`flags`) parameter
334
+ String.prototype.replace = function (search, replacement) {
335
+ var isRegex = XRegExp.isRegExp(search),
336
+ captureNames, result, str;
337
+
338
+ // There are many combinations of search/replacement types/values and browser bugs that
339
+ // preclude passing to native `replace`, so just keep this check relatively simple
340
+ if (isRegex && typeof replacement.valueOf() === "string" && replacement.indexOf("${") === -1 && compliantLastIndexReset)
341
+ return real.replace.apply(this, arguments);
342
+
343
+ if (!isRegex)
344
+ search = search + ""; // Type conversion
345
+ else if (search._xregexp)
346
+ captureNames = search._xregexp.captureNames; // Array or `null`
347
+
348
+ if (typeof replacement === "function") {
349
+ result = real.replace.call(this, search, function () {
350
+ if (captureNames) {
351
+ // Change the `arguments[0]` string primitive to a String object which can store properties
352
+ arguments[0] = new String(arguments[0]);
353
+ // Store named backreferences on `arguments[0]`
354
+ for (var i = 0; i < captureNames.length; i++) {
355
+ if (captureNames[i])
356
+ arguments[0][captureNames[i]] = arguments[i + 1];
357
+ }
358
+ }
359
+ // Update `lastIndex` before calling `replacement`
360
+ if (isRegex && search.global)
361
+ search.lastIndex = arguments[arguments.length - 2] + arguments[0].length;
362
+ return replacement.apply(null, arguments);
363
+ });
364
+ } else {
365
+ str = this + ""; // Type conversion, so `args[args.length - 1]` will be a string (given nonstring `this`)
366
+ result = real.replace.call(str, search, function () {
367
+ var args = arguments; // Keep this function's `arguments` available through closure
368
+ return real.replace.call(replacement, replacementToken, function ($0, $1, $2) {
369
+ // Numbered backreference (without delimiters) or special variable
370
+ if ($1) {
371
+ switch ($1) {
372
+ case "$": return "$";
373
+ case "&": return args[0];
374
+ case "`": return args[args.length - 1].slice(0, args[args.length - 2]);
375
+ case "'": return args[args.length - 1].slice(args[args.length - 2] + args[0].length);
376
+ // Numbered backreference
377
+ default:
378
+ // What does "$10" mean?
379
+ // - Backreference 10, if 10 or more capturing groups exist
380
+ // - Backreference 1 followed by "0", if 1-9 capturing groups exist
381
+ // - Otherwise, it's the string "$10"
382
+ // Also note:
383
+ // - Backreferences cannot be more than two digits (enforced by `replacementToken`)
384
+ // - "$01" is equivalent to "$1" if a capturing group exists, otherwise it's the string "$01"
385
+ // - There is no "$0" token ("$&" is the entire match)
386
+ var literalNumbers = "";
387
+ $1 = +$1; // Type conversion; drop leading zero
388
+ if (!$1) // `$1` was "0" or "00"
389
+ return $0;
390
+ while ($1 > args.length - 3) {
391
+ literalNumbers = String.prototype.slice.call($1, -1) + literalNumbers;
392
+ $1 = Math.floor($1 / 10); // Drop the last digit
393
+ }
394
+ return ($1 ? args[$1] || "" : "$") + literalNumbers;
395
+ }
396
+ // Named backreference or delimited numbered backreference
397
+ } else {
398
+ // What does "${n}" mean?
399
+ // - Backreference to numbered capture n. Two differences from "$n":
400
+ // - n can be more than two digits
401
+ // - Backreference 0 is allowed, and is the entire match
402
+ // - Backreference to named capture n, if it exists and is not a number overridden by numbered capture
403
+ // - Otherwise, it's the string "${n}"
404
+ var n = +$2; // Type conversion; drop leading zeros
405
+ if (n <= args.length - 3)
406
+ return args[n];
407
+ n = captureNames ? indexOf(captureNames, $2) : -1;
408
+ return n > -1 ? args[n + 1] : $0;
409
+ }
410
+ });
411
+ });
412
+ }
413
+
414
+ if (isRegex && search.global)
415
+ search.lastIndex = 0; // Fix IE bug
416
+
417
+ return result;
418
+ };
419
+
420
+ // A consistent cross-browser, ES3 compliant `split`
421
+ String.prototype.split = function (s /* separator */, limit) {
422
+ // If separator `s` is not a regex, use the native `split`
423
+ if (!XRegExp.isRegExp(s))
424
+ return real.split.apply(this, arguments);
425
+
426
+ var str = this + "", // Type conversion
427
+ output = [],
428
+ lastLastIndex = 0,
429
+ match, lastLength;
430
+
431
+ // Behavior for `limit`: if it's...
432
+ // - `undefined`: No limit
433
+ // - `NaN` or zero: Return an empty array
434
+ // - A positive number: Use `Math.floor(limit)`
435
+ // - A negative number: No limit
436
+ // - Other: Type-convert, then use the above rules
437
+ if (limit === undefined || +limit < 0) {
438
+ limit = Infinity;
439
+ } else {
440
+ limit = Math.floor(+limit);
441
+ if (!limit)
442
+ return [];
443
+ }
444
+
445
+ // This is required if not `s.global`, and it avoids needing to set `s.lastIndex` to zero
446
+ // and restore it to its original value when we're done using the regex
447
+ s = XRegExp.copyAsGlobal(s);
448
+
449
+ while (match = s.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.)
450
+ if (s.lastIndex > lastLastIndex) {
451
+ output.push(str.slice(lastLastIndex, match.index));
452
+
453
+ if (match.length > 1 && match.index < str.length)
454
+ Array.prototype.push.apply(output, match.slice(1));
455
+
456
+ lastLength = match[0].length;
457
+ lastLastIndex = s.lastIndex;
458
+
459
+ if (output.length >= limit)
460
+ break;
461
+ }
462
+
463
+ if (s.lastIndex === match.index)
464
+ s.lastIndex++;
465
+ }
466
+
467
+ if (lastLastIndex === str.length) {
468
+ if (!real.test.call(s, "") || lastLength)
469
+ output.push("");
470
+ } else {
471
+ output.push(str.slice(lastLastIndex));
472
+ }
473
+
474
+ return output.length > limit ? output.slice(0, limit) : output;
475
+ };
476
+
477
+
478
+ //---------------------------------
479
+ // Private helper functions
480
+ //---------------------------------
481
+
482
+ // Supporting function for `XRegExp`, `XRegExp.copyAsGlobal`, etc. Returns a copy of a `RegExp`
483
+ // instance with a fresh `lastIndex` (set to zero), preserving properties required for named
484
+ // capture. Also allows adding new flags in the process of copying the regex
485
+ function clone (regex, additionalFlags) {
486
+ if (!XRegExp.isRegExp(regex))
487
+ throw TypeError("type RegExp expected");
488
+ var x = regex._xregexp;
489
+ regex = XRegExp(regex.source, getNativeFlags(regex) + (additionalFlags || ""));
490
+ if (x) {
491
+ regex._xregexp = {
492
+ source: x.source,
493
+ captureNames: x.captureNames ? x.captureNames.slice(0) : null
494
+ };
495
+ }
496
+ return regex;
497
+ };
498
+
499
+ function getNativeFlags (regex) {
500
+ return (regex.global ? "g" : "") +
501
+ (regex.ignoreCase ? "i" : "") +
502
+ (regex.multiline ? "m" : "") +
503
+ (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
504
+ (regex.sticky ? "y" : "");
505
+ };
506
+
507
+ function runTokens (pattern, index, scope, context) {
508
+ var i = tokens.length,
509
+ result, match, t;
510
+ // Protect against constructing XRegExps within token handler and trigger functions
511
+ isInsideConstructor = true;
512
+ // Must reset `isInsideConstructor`, even if a `trigger` or `handler` throws
513
+ try {
514
+ while (i--) { // Run in reverse order
515
+ t = tokens[i];
516
+ if ((scope & t.scope) && (!t.trigger || t.trigger.call(context))) {
517
+ t.pattern.lastIndex = index;
518
+ match = t.pattern.exec(pattern); // Running the altered `exec` here allows use of named backreferences, etc.
519
+ if (match && match.index === index) {
520
+ result = {
521
+ output: t.handler.call(context, match, scope),
522
+ match: match
523
+ };
524
+ break;
525
+ }
526
+ }
527
+ }
528
+ } catch (err) {
529
+ throw err;
530
+ } finally {
531
+ isInsideConstructor = false;
532
+ }
533
+ return result;
534
+ };
535
+
536
+ function indexOf (array, item, from) {
537
+ if (Array.prototype.indexOf) // Use the native array method if available
538
+ return array.indexOf(item, from);
539
+ for (var i = from || 0; i < array.length; i++) {
540
+ if (array[i] === item)
541
+ return i;
542
+ }
543
+ return -1;
544
+ };
545
+
546
+
547
+ //---------------------------------
548
+ // Built-in tokens
549
+ //---------------------------------
550
+
551
+ // Augment XRegExp's regular expression syntax and flags. Note that when adding tokens, the
552
+ // third (`scope`) argument defaults to `XRegExp.OUTSIDE_CLASS`
553
+
554
+ // Comment pattern: (?# )
555
+ XRegExp.addToken(
556
+ /\(\?#[^)]*\)/,
557
+ function (match) {
558
+ // Keep tokens separated unless the following token is a quantifier
559
+ return real.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
560
+ }
561
+ );
562
+
563
+ // Capturing group (match the opening parenthesis only).
564
+ // Required for support of named capturing groups
565
+ XRegExp.addToken(
566
+ /\((?!\?)/,
567
+ function () {
568
+ this.captureNames.push(null);
569
+ return "(";
570
+ }
571
+ );
572
+
573
+ // Named capturing group (match the opening delimiter only): (?<name>
574
+ XRegExp.addToken(
575
+ /\(\?<([$\w]+)>/,
576
+ function (match) {
577
+ this.captureNames.push(match[1]);
578
+ this.hasNamedCapture = true;
579
+ return "(";
580
+ }
581
+ );
582
+
583
+ // Named backreference: \k<name>
584
+ XRegExp.addToken(
585
+ /\\k<([\w$]+)>/,
586
+ function (match) {
587
+ var index = indexOf(this.captureNames, match[1]);
588
+ // Keep backreferences separate from subsequent literal numbers. Preserve back-
589
+ // references to named groups that are undefined at this point as literal strings
590
+ return index > -1 ?
591
+ "\\" + (index + 1) + (isNaN(match.input.charAt(match.index + match[0].length)) ? "" : "(?:)") :
592
+ match[0];
593
+ }
594
+ );
595
+
596
+ // Empty character class: [] or [^]
597
+ XRegExp.addToken(
598
+ /\[\^?]/,
599
+ function (match) {
600
+ // For cross-browser compatibility with ES3, convert [] to \b\B and [^] to [\s\S].
601
+ // (?!) should work like \b\B, but is unreliable in Firefox
602
+ return match[0] === "[]" ? "\\b\\B" : "[\\s\\S]";
603
+ }
604
+ );
605
+
606
+ // Mode modifier at the start of the pattern only, with any combination of flags imsx: (?imsx)
607
+ // Does not support x(?i), (?-i), (?i-m), (?i: ), (?i)(?m), etc.
608
+ XRegExp.addToken(
609
+ /^\(\?([imsx]+)\)/,
610
+ function (match) {
611
+ this.setFlag(match[1]);
612
+ return "";
613
+ }
614
+ );
615
+
616
+ // Whitespace and comments, in free-spacing (aka extended) mode only
617
+ XRegExp.addToken(
618
+ /(?:\s+|#.*)+/,
619
+ function (match) {
620
+ // Keep tokens separated unless the following token is a quantifier
621
+ return real.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
622
+ },
623
+ XRegExp.OUTSIDE_CLASS,
624
+ function () {return this.hasFlag("x");}
625
+ );
626
+
627
+ // Dot, in dotall (aka singleline) mode only
628
+ XRegExp.addToken(
629
+ /\./,
630
+ function () {return "[\\s\\S]";},
631
+ XRegExp.OUTSIDE_CLASS,
632
+ function () {return this.hasFlag("s");}
633
+ );
634
+
635
+
636
+ //---------------------------------
637
+ // Backward compatibility
638
+ //---------------------------------
639
+
640
+ // Uncomment the following block for compatibility with XRegExp 1.0-1.2:
641
+ /*
642
+ XRegExp.matchWithinChain = XRegExp.matchChain;
643
+ RegExp.prototype.addFlags = function (s) {return clone(this, s);};
644
+ RegExp.prototype.execAll = function (s) {var r = []; XRegExp.iterate(s, this, function (m) {r.push(m);}); return r;};
645
+ RegExp.prototype.forEachExec = function (s, f, c) {return XRegExp.iterate(s, this, f, c);};
646
+ RegExp.prototype.validate = function (s) {var r = RegExp("^(?:" + this.source + ")$(?!\\s)", getNativeFlags(this)); if (this.global) this.lastIndex = 0; return s.search(r) === 0;};
647
+ */
648
+
649
+ })();
650
+
651
+ // CommonJS
652
+ typeof(exports) != 'undefined' ? exports.XRegExp = XRegExp : null;