', start: 8, end: 13},
- * // {name: 'match', value: '
an
', start: 13, end: 27},
- * // {name: 'right', value: '
', start: 27, end: 33},
- * // {name: 'between', value: ' example', start: 33, end: 41}
- * // ]
- *
- * // Omitting unneeded parts with null valueNames, and using escapeChar
- * str = '...{1}\\{{function(x,y){return y+x;}}';
- * XRegExp.matchRecursive(str, '{', '}', 'g', {
- * valueNames: ['literal', null, 'value', null],
- * escapeChar: '\\'
- * });
- * // -> [
- * // {name: 'literal', value: '...', start: 0, end: 3},
- * // {name: 'value', value: '1', start: 4, end: 5},
- * // {name: 'literal', value: '\\{', start: 6, end: 8},
- * // {name: 'value', value: 'function(x,y){return y+x;}', start: 9, end: 35}
- * // ]
- *
- * // Sticky mode via flag y
- * str = '<1><<<2>>><3>4<5>';
- * XRegExp.matchRecursive(str, '<', '>', 'gy');
- * // -> ['1', '<<2>>', '3']
- */
- XRegExp.matchRecursive = function (str, left, right, flags, options) {
- flags = flags || "";
+ /**
+ * Returns an array of match strings between outermost left and right delimiters, or an array of
+ * objects with detailed match parts and position data. An error is thrown if delimiters are
+ * unbalanced within the data.
+ *
+ * @memberOf XRegExp
+ * @param {String} str String to search.
+ * @param {String} left Left delimiter as an XRegExp pattern.
+ * @param {String} right Right delimiter as an XRegExp pattern.
+ * @param {String} [flags] Any native or XRegExp flags, used for the left and right delimiters.
+ * @param {Object} [options] Lets you specify `valueNames` and `escapeChar` options.
+ * @returns {Array} Array of matches, or an empty array.
+ * @example
+ *
+ * // Basic usage
+ * var str = '(t((e))s)t()(ing)';
+ * XRegExp.matchRecursive(str, '\\(', '\\)', 'g');
+ * // -> ['t((e))s', '', 'ing']
+ *
+ * // Extended information mode with valueNames
+ * str = 'Here is ', start: 8, end: 13},
+ * // {name: 'match', value: '
an
', start: 13, end: 27},
+ * // {name: 'right', value: '
', start: 27, end: 33},
+ * // {name: 'between', value: ' example', start: 33, end: 41}
+ * // ]
+ *
+ * // Omitting unneeded parts with null valueNames, and using escapeChar
+ * str = '...{1}.\\{{function(x,y){return {y:x}}}';
+ * XRegExp.matchRecursive(str, '{', '}', 'g', {
+ * valueNames: ['literal', null, 'value', null],
+ * escapeChar: '\\'
+ * });
+ * // -> [
+ * // {name: 'literal', value: '...', start: 0, end: 3},
+ * // {name: 'value', value: '1', start: 4, end: 5},
+ * // {name: 'literal', value: '.\\{', start: 6, end: 9},
+ * // {name: 'value', value: 'function(x,y){return {y:x}}', start: 10, end: 37}
+ * // ]
+ *
+ * // Sticky mode via flag y
+ * str = '<1><<<2>>><3>4<5>';
+ * XRegExp.matchRecursive(str, '<', '>', 'gy');
+ * // -> ['1', '<<2>>', '3']
+ */
+ XRegExp.matchRecursive = function(str, left, right, flags, options) {
+ flags = flags || '';
options = options || {};
- var global = flags.indexOf("g") > -1,
- sticky = flags.indexOf("y") > -1,
- basicFlags = flags.replace(/y/g, ""), // Flag y controlled internally
- escapeChar = options.escapeChar,
- vN = options.valueNames,
- output = [],
- openTokens = 0,
- delimStart = 0,
- delimEnd = 0,
- lastOuterEnd = 0,
- outerStart,
- innerStart,
- leftMatch,
- rightMatch,
- esc;
+ var global = flags.indexOf('g') > -1;
+ var sticky = flags.indexOf('y') > -1;
+ // Flag `y` is controlled internally
+ var basicFlags = flags.replace(/y/g, '');
+ var escapeChar = options.escapeChar;
+ var vN = options.valueNames;
+ var output = [];
+ var openTokens = 0;
+ var delimStart = 0;
+ var delimEnd = 0;
+ var lastOuterEnd = 0;
+ var outerStart;
+ var innerStart;
+ var leftMatch;
+ var rightMatch;
+ var esc;
left = XRegExp(left, basicFlags);
right = XRegExp(right, basicFlags);
if (escapeChar) {
if (escapeChar.length > 1) {
- throw new SyntaxError("can't use more than one escape character");
+ throw new Error('Cannot use more than one escape character');
}
escapeChar = XRegExp.escape(escapeChar);
- // Using XRegExp.union safely rewrites backreferences in `left` and `right`
+ // Example of concatenated `esc` regex:
+ // `escapeChar`: '%'
+ // `left`: '<'
+ // `right`: '>'
+ // Regex is: /(?:%[\S\s]|(?:(?!<|>)[^%])+)+/
esc = new RegExp(
- "(?:" + escapeChar + "[\\S\\s]|(?:(?!" + XRegExp.union([left, right]).source + ")[^" + escapeChar + "])+)+",
- flags.replace(/[^im]+/g, "") // Flags gy not needed here; flags nsx handled by XRegExp
+ '(?:' + escapeChar + '[\\S\\s]|(?:(?!' +
+ // Using `XRegExp.union` safely rewrites backreferences in `left` and `right`.
+ // Intentionally not passing `basicFlags` to `XRegExp.union` since any syntax
+ // transformation resulting from those flags was already applied to `left` and
+ // `right` when they were passed through the XRegExp constructor above.
+ XRegExp.union([left, right], '', {conjunction: 'or'}).source +
+ ')[^' + escapeChar + '])+)+',
+ // Flags `gy` not needed here
+ flags.replace(/[^imu]+/g, '')
);
}
@@ -1961,7 +316,7 @@ XRegExp = XRegExp || (function (undef) {
// If using an escape character, advance to the delimiter's next starting position,
// skipping any escaped characters in between
if (escapeChar) {
- delimEnd += (XRegExp.exec(str, esc, delimEnd, "sticky") || [""])[0].length;
+ delimEnd += (XRegExp.exec(str, esc, delimEnd, 'sticky') || [''])[0].length;
}
leftMatch = XRegExp.exec(str, left, delimEnd);
rightMatch = XRegExp.exec(str, right, delimEnd);
@@ -1973,16 +328,16 @@ XRegExp = XRegExp || (function (undef) {
leftMatch = null;
}
}
- /* Paths (LM:leftMatch, RM:rightMatch, OT:openTokens):
- LM | RM | OT | Result
- 1 | 0 | 1 | loop
- 1 | 0 | 0 | loop
- 0 | 1 | 1 | loop
- 0 | 1 | 0 | throw
- 0 | 0 | 1 | throw
- 0 | 0 | 0 | break
- * Doesn't include the sticky mode special case
- * Loop ends after the first completed match if `!global` */
+ // Paths (LM: leftMatch, RM: rightMatch, OT: openTokens):
+ // LM | RM | OT | Result
+ // 1 | 0 | 1 | loop
+ // 1 | 0 | 0 | loop
+ // 0 | 1 | 1 | loop
+ // 0 | 1 | 0 | throw
+ // 0 | 0 | 1 | throw
+ // 0 | 0 | 0 | break
+ // The paths above don't include the sticky mode special case. The loop ends after the
+ // first completed match if not `global`.
if (leftMatch || rightMatch) {
delimStart = (leftMatch || rightMatch).index;
delimEnd = delimStart + (leftMatch || rightMatch)[0].length;
@@ -2022,7 +377,7 @@ XRegExp = XRegExp || (function (undef) {
}
}
} else {
- throw new Error("string contains unbalanced delimiters");
+ throw new Error('Unbalanced delimiter found in string');
}
// If the delimiter matched an empty string, avoid an infinite loop
if (delimStart === delimEnd) {
@@ -2037,272 +392,4261 @@ XRegExp = XRegExp || (function (undef) {
return output;
};
-}(XRegExp));
-
-
-/***** build.js *****/
+};
+},{}],3:[function(require,module,exports){
/*!
- * XRegExp.build v0.1.0
- * (c) 2012 Steven Levithan