From 07ea7189100182f48e58969648fa1f12c9ed9682 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Wed, 15 Mar 2017 16:40:55 -0500 Subject: [PATCH 1/2] Match parens recursively on URLs to not fix embeded calls --- fixUrls.js | 3 ++- test/fixUrlsTest.js | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/fixUrls.js b/fixUrls.js index 148384d4..410f274c 100644 --- a/fixUrls.js +++ b/fixUrls.js @@ -29,8 +29,9 @@ module.exports = function (css) { var currentDir = baseUrl + location.pathname.replace(/\/[^\/]*$/, "/"); // convert each url(...) - var fixedCss = css.replace(/url *\( *(.+?) *\)/g, function(fullMatch, origUrl) { + var fixedCss = css.replace(/url\(((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*)\)/g, function(fullMatch, origUrl) { // strip quotes (if they exist) + var unquotedOrigUrl = origUrl .replace(/^"(.*)"$/, function(o, $1){ return $1; }) .replace(/^'(.*)'$/, function(o, $1){ return $1; }); diff --git a/test/fixUrlsTest.js b/test/fixUrlsTest.js index d41da4cd..5fabcb9c 100644 --- a/test/fixUrlsTest.js +++ b/test/fixUrlsTest.js @@ -180,4 +180,12 @@ describe("fix urls tests", function() { "http://x.y.z" ); }); + + it("Doesn't break inline SVG", function() { + const svg = "url('data:image/svg+xml;charset=utf-8,')"; + + assertUrl( + "body: { background: " + svg + " }" + ); + }); }); From ba6c154a558b451255e403c3d58b8d6c8d5f7873 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 16 Mar 2017 03:30:08 -0500 Subject: [PATCH 2/2] add docs and more tests --- fixUrls.js | 29 +++++++++++++++++++++++++++-- test/fixUrlsTest.js | 11 +++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/fixUrls.js b/fixUrls.js index 410f274c..d215ae84 100644 --- a/fixUrls.js +++ b/fixUrls.js @@ -29,10 +29,35 @@ module.exports = function (css) { var currentDir = baseUrl + location.pathname.replace(/\/[^\/]*$/, "/"); // convert each url(...) - var fixedCss = css.replace(/url\(((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*)\)/g, function(fullMatch, origUrl) { - // strip quotes (if they exist) + /* + This regular expression is just a way to recursively match brackets within + a string. + + /url\s*\( = Match on the word "url" with any whitespace after it and then a parens + ( = Start a capturing group + (?: = Start a non-capturing group + [^)(] = Match anything that isn't a parentheses + | = OR + \( = Match a start parentheses + (?: = Start another non-capturing groups + [^)(]+ = Match anything that isn't a parentheses + | = OR + \( = Match a start parentheses + [^)(]* = Match anything that isn't a parentheses + \) = Match a end parentheses + ) = End Group + *\) = Match anything and then a close parens + ) = Close non-capturing group + * = Match anything + ) = Close capturing group + \) = Match a close parens + /gi = Get all matches, not the first. Be case insensitive. + */ + var fixedCss = css.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi, function(fullMatch, origUrl) { + // strip quotes (if they exist) var unquotedOrigUrl = origUrl + .trim() .replace(/^"(.*)"$/, function(o, $1){ return $1; }) .replace(/^'(.*)'$/, function(o, $1){ return $1; }); diff --git a/test/fixUrlsTest.js b/test/fixUrlsTest.js index 5fabcb9c..f8fa7fbf 100644 --- a/test/fixUrlsTest.js +++ b/test/fixUrlsTest.js @@ -22,7 +22,7 @@ describe("fix urls tests", function() { var resultCss = fixUrls(origCss, specialUrl || defaultUrl); expectedCss = expectedCss || origCss; - assert.equal(resultCss, expectedCss); + assert.equal(expectedCss, resultCss); }; // no change @@ -100,11 +100,18 @@ describe("fix urls tests", function() { // relative urls it("Relative url", function() { assertUrl( - "body { background-image:url(bg.jpg); }", + "body { background-image:url (bg.jpg); }", "body { background-image:url(\"https://x.y.z/a/bg.jpg\"); }" ); }); + it("Relative url case sensitivity", function() { + assertUrl( + "body { background-image:URL (bg.jpg); }", + "body { background-image:url(\"https://x.y.z/a/bg.jpg\"); }" + ); + }); + it("Relative url with path", function() { assertUrl( "body { background-image:url(c/d/bg.jpg); }",