This commit is contained in:
189
node_modules/xregexp/src/addons/build.js
generated
vendored
Normal file
189
node_modules/xregexp/src/addons/build.js
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
/*!
|
||||
* XRegExp.build 3.1.0
|
||||
* <xregexp.com>
|
||||
* Steven Levithan (c) 2012-2016 MIT License
|
||||
* Inspired by Lea Verou's RegExp.create <lea.verou.me>
|
||||
*/
|
||||
|
||||
module.exports = function(XRegExp) {
|
||||
'use strict';
|
||||
|
||||
var REGEX_DATA = 'xregexp',
|
||||
subParts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*]/g,
|
||||
parts = XRegExp.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/, subParts], 'g');
|
||||
|
||||
/**
|
||||
* Strips a leading `^` and trailing unescaped `$`, if both are present.
|
||||
*
|
||||
* @private
|
||||
* @param {String} pattern Pattern to process.
|
||||
* @returns {String} Pattern with edge anchors removed.
|
||||
*/
|
||||
function deanchor(pattern) {
|
||||
// Allow any number of empty noncapturing groups before/after anchors, because regexes
|
||||
// built/generated by XRegExp sometimes include them
|
||||
var leadingAnchor = /^(?:\(\?:\))*\^/,
|
||||
trailingAnchor = /\$(?:\(\?:\))*$/;
|
||||
|
||||
if (
|
||||
leadingAnchor.test(pattern) &&
|
||||
trailingAnchor.test(pattern) &&
|
||||
// Ensure that the trailing `$` isn't escaped
|
||||
trailingAnchor.test(pattern.replace(/\\[\s\S]/g, ''))
|
||||
) {
|
||||
return pattern.replace(leadingAnchor, '').replace(trailingAnchor, '');
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the provided value to an XRegExp. Native RegExp flags are not preserved.
|
||||
*
|
||||
* @private
|
||||
* @param {String|RegExp} value Value to convert.
|
||||
* @returns {RegExp} XRegExp object with XRegExp syntax applied.
|
||||
*/
|
||||
function asXRegExp(value) {
|
||||
return XRegExp.isRegExp(value) ?
|
||||
(value[REGEX_DATA] && value[REGEX_DATA].captureNames ?
|
||||
// Don't recompile, to preserve capture names
|
||||
value :
|
||||
// Recompile as XRegExp
|
||||
XRegExp(value.source)
|
||||
) :
|
||||
// Compile string as XRegExp
|
||||
XRegExp(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds regexes using named subpatterns, for readability and pattern reuse. Backreferences in the
|
||||
* outer pattern and provided subpatterns are automatically renumbered to work correctly. Native
|
||||
* flags used by provided subpatterns are ignored in favor of the `flags` argument.
|
||||
*
|
||||
* @memberOf XRegExp
|
||||
* @param {String} pattern XRegExp pattern using `{{name}}` for embedded subpatterns. Allows
|
||||
* `({{name}})` as shorthand for `(?<name>{{name}})`. Patterns cannot be embedded within
|
||||
* character classes.
|
||||
* @param {Object} subs Lookup object for named subpatterns. Values can be strings or regexes. A
|
||||
* leading `^` and trailing unescaped `$` are stripped from subpatterns, if both are present.
|
||||
* @param {String} [flags] Any combination of XRegExp flags.
|
||||
* @returns {RegExp} Regex with interpolated subpatterns.
|
||||
* @example
|
||||
*
|
||||
* var time = XRegExp.build('(?x)^ {{hours}} ({{minutes}}) $', {
|
||||
* hours: XRegExp.build('{{h12}} : | {{h24}}', {
|
||||
* h12: /1[0-2]|0?[1-9]/,
|
||||
* h24: /2[0-3]|[01][0-9]/
|
||||
* }, 'x'),
|
||||
* minutes: /^[0-5][0-9]$/
|
||||
* });
|
||||
* time.test('10:59'); // -> true
|
||||
* XRegExp.exec('10:59', time).minutes; // -> '59'
|
||||
*/
|
||||
XRegExp.build = function(pattern, subs, flags) {
|
||||
var inlineFlags = /^\(\?([\w$]+)\)/.exec(pattern),
|
||||
data = {},
|
||||
numCaps = 0, // 'Caps' is short for captures
|
||||
numPriorCaps,
|
||||
numOuterCaps = 0,
|
||||
outerCapsMap = [0],
|
||||
outerCapNames,
|
||||
sub,
|
||||
p;
|
||||
|
||||
// Add flags within a leading mode modifier to the overall pattern's flags
|
||||
if (inlineFlags) {
|
||||
flags = flags || '';
|
||||
inlineFlags[1].replace(/./g, function(flag) {
|
||||
// Don't add duplicates
|
||||
flags += (flags.indexOf(flag) > -1 ? '' : flag);
|
||||
});
|
||||
}
|
||||
|
||||
for (p in subs) {
|
||||
if (subs.hasOwnProperty(p)) {
|
||||
// Passing to XRegExp enables extended syntax and ensures independent validity,
|
||||
// lest an unescaped `(`, `)`, `[`, or trailing `\` breaks the `(?:)` wrapper. For
|
||||
// subpatterns provided as native regexes, it dies on octals and adds the property
|
||||
// used to hold extended regex instance data, for simplicity
|
||||
sub = asXRegExp(subs[p]);
|
||||
data[p] = {
|
||||
// Deanchoring allows embedding independently useful anchored regexes. If you
|
||||
// really need to keep your anchors, double them (i.e., `^^...$$`)
|
||||
pattern: deanchor(sub.source),
|
||||
names: sub[REGEX_DATA].captureNames || []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Passing to XRegExp dies on octals and ensures the outer pattern is independently valid;
|
||||
// helps keep this simple. Named captures will be put back
|
||||
pattern = asXRegExp(pattern);
|
||||
outerCapNames = pattern[REGEX_DATA].captureNames || [];
|
||||
pattern = pattern.source.replace(parts, function($0, $1, $2, $3, $4) {
|
||||
var subName = $1 || $2,
|
||||
capName,
|
||||
intro,
|
||||
localCapIndex;
|
||||
// Named subpattern
|
||||
if (subName) {
|
||||
if (!data.hasOwnProperty(subName)) {
|
||||
throw new ReferenceError('Undefined property ' + $0);
|
||||
}
|
||||
// Named subpattern was wrapped in a capturing group
|
||||
if ($1) {
|
||||
capName = outerCapNames[numOuterCaps];
|
||||
outerCapsMap[++numOuterCaps] = ++numCaps;
|
||||
// If it's a named group, preserve the name. Otherwise, use the subpattern name
|
||||
// as the capture name
|
||||
intro = '(?<' + (capName || subName) + '>';
|
||||
} else {
|
||||
intro = '(?:';
|
||||
}
|
||||
numPriorCaps = numCaps;
|
||||
return intro + data[subName].pattern.replace(subParts, function(match, paren, backref) {
|
||||
// Capturing group
|
||||
if (paren) {
|
||||
capName = data[subName].names[numCaps - numPriorCaps];
|
||||
++numCaps;
|
||||
// If the current capture has a name, preserve the name
|
||||
if (capName) {
|
||||
return '(?<' + capName + '>';
|
||||
}
|
||||
// Backreference
|
||||
} else if (backref) {
|
||||
localCapIndex = +backref - 1;
|
||||
// Rewrite the backreference
|
||||
return data[subName].names[localCapIndex] ?
|
||||
// Need to preserve the backreference name in case using flag `n`
|
||||
'\\k<' + data[subName].names[localCapIndex] + '>' :
|
||||
'\\' + (+backref + numPriorCaps);
|
||||
}
|
||||
return match;
|
||||
}) + ')';
|
||||
}
|
||||
// Capturing group
|
||||
if ($3) {
|
||||
capName = outerCapNames[numOuterCaps];
|
||||
outerCapsMap[++numOuterCaps] = ++numCaps;
|
||||
// If the current capture has a name, preserve the name
|
||||
if (capName) {
|
||||
return '(?<' + capName + '>';
|
||||
}
|
||||
// Backreference
|
||||
} else if ($4) {
|
||||
localCapIndex = +$4 - 1;
|
||||
// Rewrite the backreference
|
||||
return outerCapNames[localCapIndex] ?
|
||||
// Need to preserve the backreference name in case using flag `n`
|
||||
'\\k<' + outerCapNames[localCapIndex] + '>' :
|
||||
'\\' + outerCapsMap[+$4];
|
||||
}
|
||||
return $0;
|
||||
});
|
||||
|
||||
return XRegExp(pattern, flags);
|
||||
};
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user