Permalink
Browse files

build.js: check for start anchor in subpatterns and add tests (closes #…

…35); misc code cleanup
  • Loading branch information...
1 parent 9253f99 commit 0f822768a5bb1f3138d385f9761e84974b2ab7c9 @slevithan committed Jun 24, 2012
Showing with 81 additions and 49 deletions.
  1. +36 −24 src/addons/build.js
  2. +9 −1 tests/tests.js
  3. +36 −24 xregexp-all.js
View
@@ -1,15 +1,15 @@
/*!
- * XRegExp.build 0.1.0
+ * XRegExp.build 0.1.1-dev
* (c) 2012 Steven Levithan <http://xregexp.com/>
* MIT License
* Inspired by RegExp.create by Lea Verou <http://lea.verou.me/>
*/
(function (XRegExp) {
- "use strict";
+ 'use strict';
var subparts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*]/g,
- parts = XRegExp.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/, subparts], "g");
+ parts = XRegExp.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/, subparts], 'g');
/**
* Strips a leading `^` and trailing unescaped `$`, if both are present.
@@ -20,8 +20,9 @@
function deanchor(pattern) {
var startAnchor = /^(?:\(\?:\))?\^/, // Leading `^` or `(?:)^` (handles /x cruft)
endAnchor = /\$(?:\(\?:\))?$/; // Trailing `$` or `$(?:)` (handles /x cruft)
- if (endAnchor.test(pattern.replace(/\\[\s\S]/g, ""))) { // Ensure trailing `$` isn't escaped
- return pattern.replace(startAnchor, "").replace(endAnchor, "");
+ // Ensure that the trailing `$` isn't escaped
+ if (startAnchor.test(pattern) && endAnchor.test(pattern.replace(/\\[\s\S]/g, ''))) {
+ return pattern.replace(startAnchor, '').replace(endAnchor, '');
}
return pattern;
}
@@ -65,7 +66,7 @@
XRegExp.build = function (pattern, subs, flags) {
var inlineFlags = /^\(\?([\w$]+)\)/.exec(pattern),
data = {},
- numCaps = 0, // Caps is short for captures
+ numCaps = 0, // 'Caps' is short for captures
numPriorCaps,
numOuterCaps = 0,
outerCapsMap = [0],
@@ -75,9 +76,10 @@
// Add flags within a leading mode modifier to the overall pattern's flags
if (inlineFlags) {
- flags = flags || "";
+ flags = flags || '';
inlineFlags[1].replace(/./g, function (flag) {
- flags += (flags.indexOf(flag) > -1 ? "" : flag); // Don't add duplicates
+ // Don't add duplicates
+ flags += (flags.indexOf(flag) > -1 ? '' : flag);
});
}
@@ -100,41 +102,51 @@
outerCapNames = pattern.xregexp.captureNames || [];
pattern = pattern.source.replace(parts, function ($0, $1, $2, $3, $4) {
var subName = $1 || $2, capName, intro;
- if (subName) { // Named subpattern
+ // Named subpattern
+ if (subName) {
if (!data.hasOwnProperty(subName)) {
- throw new ReferenceError("undefined property " + $0);
+ throw new ReferenceError('Undefined property ' + $0);
}
- if ($1) { // Named subpattern was wrapped in a capturing group
+ // 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) + ">";
+ intro = '(?<' + (capName || subName) + '>';
} else {
- intro = "(?:";
+ intro = '(?:';
}
numPriorCaps = numCaps;
return intro + data[subName].pattern.replace(subparts, function (match, paren, backref) {
- if (paren) { // Capturing group
+ // Capturing group
+ if (paren) {
capName = data[subName].names[numCaps - numPriorCaps];
++numCaps;
- if (capName) { // If the current capture has a name, preserve the name
- return "(?<" + capName + ">";
+ // If the current capture has a name, preserve the name
+ if (capName) {
+ return '(?<' + capName + '>';
}
- } else if (backref) { // Backreference
- return "\\" + (+backref + numPriorCaps); // Rewrite the backreference
+ // Backreference
+ } else if (backref) {
+ // Rewrite the backreference
+ return '\\' + (+backref + numPriorCaps);
}
return match;
- }) + ")";
+ }) + ')';
}
- if ($3) { // Capturing group
+ // Capturing group
+ if ($3) {
capName = outerCapNames[numOuterCaps];
outerCapsMap[++numOuterCaps] = ++numCaps;
- if (capName) { // If the current capture has a name, preserve the name
- return "(?<" + capName + ">";
+ // If the current capture has a name, preserve the name
+ if (capName) {
+ return '(?<' + capName + '>';
}
- } else if ($4) { // Backreference
- return "\\" + outerCapsMap[+$4]; // Rewrite the backreference
+ // Backreference
+ } else if ($4) {
+ // Rewrite the backreference
+ return '\\' + outerCapsMap[+$4];
}
return $0;
});
View
@@ -1010,10 +1010,18 @@ test("XRegExp.build", function () {
raises(function () {XRegExp.build("(?x)({{a}})", {a: /#/});}, Error, "Mode modifier in outer pattern applies to full regex with interpolated values (test 1)");
equal(XRegExp.build("(?x){{a}}", {a: /1 2/}).test("12"), true, "Mode modifier in outer pattern applies to full regex with interpolated values (test 2)");
equal(XRegExp.build("(?m){{a}}", {a: /a/}).multiline, true, "Mode modifier with native flag in outer pattern is applied to the final result");
-
equal(XRegExp.build("^[{{a}}]$", {a: "x"}).test("x"), false, "Named subpattern not interpolated within character class (test 1)");
equal(XRegExp.build("^{{a}}[{{a}}]$", {a: "x"}).test("x{"), true, "Named subpattern not interpolated within character class (test 2)");
+ ok(XRegExp.build("{{x}}", {x: "^123$"}).test("123"), "Leading ^ and trailing unescaped $ in subpattern (test 1)");
+ ok(XRegExp.build("{{x}}", {x: "^123$"}).test("01234"), "Leading ^ and trailing unescaped $ in subpattern (test 2)");
+ ok(XRegExp.build("{{x}}", {x: "^123\\$"}).test("123$"), "Leading ^ and trailing escaped $ in subpattern (test 1)");
+ ok(!XRegExp.build("{{x}}", {x: "^123\\$"}).test("0123$4"), "Leading ^ and trailing escaped $ in subpattern (test 2)");
+ ok(XRegExp.build("{{x}}", {x: "^123"}).test("123"), "Leading ^ without trailing unescaped $ in subpattern (test 1)");
+ ok(!XRegExp.build("{{x}}", {x: "^123"}).test("01234"), "Leading ^ without trailing unescaped $ in subpattern (test 2)");
+ ok(XRegExp.build("{{x}}", {x: "123$"}).test("123"), "Trailing unescaped $ without leading ^ in subpattern (test 1)");
+ ok(!XRegExp.build("{{x}}", {x: "123$"}).test("01234"), "Trailing unescaped $ without leading ^ in subpattern (test 2)");
+
// TODO: Add tests
});
View
@@ -3471,17 +3471,17 @@ var XRegExp = (function (undefined) {
/*---- build.js ----*/
/*!
- * XRegExp.build 0.1.0
+ * XRegExp.build 0.1.1-dev
* (c) 2012 Steven Levithan <http://xregexp.com/>
* MIT License
* Inspired by RegExp.create by Lea Verou <http://lea.verou.me/>
*/
(function (XRegExp) {
- "use strict";
+ 'use strict';
var subparts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*]/g,
- parts = XRegExp.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/, subparts], "g");
+ parts = XRegExp.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/, subparts], 'g');
/**
* Strips a leading `^` and trailing unescaped `$`, if both are present.
@@ -3492,8 +3492,9 @@ var XRegExp = (function (undefined) {
function deanchor(pattern) {
var startAnchor = /^(?:\(\?:\))?\^/, // Leading `^` or `(?:)^` (handles /x cruft)
endAnchor = /\$(?:\(\?:\))?$/; // Trailing `$` or `$(?:)` (handles /x cruft)
- if (endAnchor.test(pattern.replace(/\\[\s\S]/g, ""))) { // Ensure trailing `$` isn't escaped
- return pattern.replace(startAnchor, "").replace(endAnchor, "");
+ // Ensure that the trailing `$` isn't escaped
+ if (startAnchor.test(pattern) && endAnchor.test(pattern.replace(/\\[\s\S]/g, ''))) {
+ return pattern.replace(startAnchor, '').replace(endAnchor, '');
}
return pattern;
}
@@ -3537,7 +3538,7 @@ var XRegExp = (function (undefined) {
XRegExp.build = function (pattern, subs, flags) {
var inlineFlags = /^\(\?([\w$]+)\)/.exec(pattern),
data = {},
- numCaps = 0, // Caps is short for captures
+ numCaps = 0, // 'Caps' is short for captures
numPriorCaps,
numOuterCaps = 0,
outerCapsMap = [0],
@@ -3547,9 +3548,10 @@ var XRegExp = (function (undefined) {
// Add flags within a leading mode modifier to the overall pattern's flags
if (inlineFlags) {
- flags = flags || "";
+ flags = flags || '';
inlineFlags[1].replace(/./g, function (flag) {
- flags += (flags.indexOf(flag) > -1 ? "" : flag); // Don't add duplicates
+ // Don't add duplicates
+ flags += (flags.indexOf(flag) > -1 ? '' : flag);
});
}
@@ -3572,41 +3574,51 @@ var XRegExp = (function (undefined) {
outerCapNames = pattern.xregexp.captureNames || [];
pattern = pattern.source.replace(parts, function ($0, $1, $2, $3, $4) {
var subName = $1 || $2, capName, intro;
- if (subName) { // Named subpattern
+ // Named subpattern
+ if (subName) {
if (!data.hasOwnProperty(subName)) {
- throw new ReferenceError("undefined property " + $0);
+ throw new ReferenceError('Undefined property ' + $0);
}
- if ($1) { // Named subpattern was wrapped in a capturing group
+ // 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) + ">";
+ intro = '(?<' + (capName || subName) + '>';
} else {
- intro = "(?:";
+ intro = '(?:';
}
numPriorCaps = numCaps;
return intro + data[subName].pattern.replace(subparts, function (match, paren, backref) {
- if (paren) { // Capturing group
+ // Capturing group
+ if (paren) {
capName = data[subName].names[numCaps - numPriorCaps];
++numCaps;
- if (capName) { // If the current capture has a name, preserve the name
- return "(?<" + capName + ">";
+ // If the current capture has a name, preserve the name
+ if (capName) {
+ return '(?<' + capName + '>';
}
- } else if (backref) { // Backreference
- return "\\" + (+backref + numPriorCaps); // Rewrite the backreference
+ // Backreference
+ } else if (backref) {
+ // Rewrite the backreference
+ return '\\' + (+backref + numPriorCaps);
}
return match;
- }) + ")";
+ }) + ')';
}
- if ($3) { // Capturing group
+ // Capturing group
+ if ($3) {
capName = outerCapNames[numOuterCaps];
outerCapsMap[++numOuterCaps] = ++numCaps;
- if (capName) { // If the current capture has a name, preserve the name
- return "(?<" + capName + ">";
+ // If the current capture has a name, preserve the name
+ if (capName) {
+ return '(?<' + capName + '>';
}
- } else if ($4) { // Backreference
- return "\\" + outerCapsMap[+$4]; // Rewrite the backreference
+ // Backreference
+ } else if ($4) {
+ // Rewrite the backreference
+ return '\\' + outerCapsMap[+$4];
}
return $0;
});

0 comments on commit 0f82276

Please sign in to comment.