Fixes #570 - rebasing "no-url()" imports.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 20 May 2015 19:25:12 +0000 (20:25 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 20 May 2015 19:25:12 +0000 (20:25 +0100)
`@import '...';` should be treated the same as `@import url(...);`.

History.md
lib/text/urls-processor.js
lib/urls/reduce.js
lib/urls/rewrite.js
test/module-test.js

index c9677d4..04421f8 100644 (file)
@@ -13,6 +13,7 @@
 * Fixed issue [#517](https://github.com/jakubpawlowicz/clean-css/issues/517) - turning off color optimizations.
 * Fixed issue [#542](https://github.com/jakubpawlowicz/clean-css/issues/542) - space after closing brace in IE.
 * Fixed issue [#563](https://github.com/jakubpawlowicz/clean-css/issues/563) - `background:inherit` restoring.
+* Fixed issue [#570](https://github.com/jakubpawlowicz/clean-css/issues/570) - rebasing "no-url()" imports.
 * Fixed issue [#574](https://github.com/jakubpawlowicz/clean-css/issues/574) - rewriting internal URLs.
 * Fixed issue [#575](https://github.com/jakubpawlowicz/clean-css/issues/575) - missing directory as a `target`.
 
index 784b0fe..7e4a530 100644 (file)
@@ -42,7 +42,7 @@ function normalize(url, keepUrlQuotes) {
     .replace(/^url\((['"])? /, 'url($1')
     .replace(/ (['"])?\)$/, '$1)');
 
-  if (!keepUrlQuotes && !/url\(.*[\s\(\)].*\)/.test(url) && !/url\(['"]data:[^;]+;charset/.test(url))
+  if (!keepUrlQuotes && !/^['"].+['"]$/.test(url) && !/url\(.*[\s\(\)].*\)/.test(url) && !/url\(['"]data:[^;]+;charset/.test(url))
     url = url.replace(/["']/g, '');
 
   return url;
index 067e6f4..84555c8 100644 (file)
@@ -2,7 +2,10 @@ var URL_PREFIX = 'url(';
 var UPPERCASE_URL_PREFIX = 'URL(';
 var URL_SUFFIX = ')';
 
-function reduceUrls(data, context, callback) {
+var IMPORT_URL_PREFIX = '@import';
+var UPPERCASE_IMPORT_URL_PREFIX = '@IMPORT';
+
+function byUrl(data, context, callback) {
   var nextStart = 0;
   var nextStartUpperCase = 0;
   var nextEnd = 0;
@@ -55,4 +58,65 @@ function reduceUrls(data, context, callback) {
     data;
 }
 
-module.exports = reduceUrls;
+function byImport(data, context, callback) {
+  var nextStart = 0;
+  var nextStartUpperCase = 0;
+  var nextEnd = 0;
+  var cursor = 0;
+  var tempData = [];
+  var nextSingleQuote = 0;
+  var nextDoubleQuote = 0;
+  var withQuote;
+  var SINGLE_QUOTE = '\'';
+  var DOUBLE_QUOTE = '"';
+
+  for (; nextEnd < data.length;) {
+    nextStart = data.indexOf(IMPORT_URL_PREFIX, nextEnd);
+    nextStartUpperCase = data.indexOf(UPPERCASE_IMPORT_URL_PREFIX, nextEnd);
+    if (nextStart == -1 && nextStartUpperCase == -1)
+      break;
+
+    if (nextStart > -1 && nextStartUpperCase > -1 && nextStartUpperCase < nextStart)
+      nextStart = nextStartUpperCase;
+
+    nextSingleQuote = data.indexOf(SINGLE_QUOTE, nextStart);
+    nextDoubleQuote = data.indexOf(DOUBLE_QUOTE, nextStart);
+
+    if (nextSingleQuote > -1 && nextDoubleQuote > -1 && nextSingleQuote < nextDoubleQuote) {
+      nextStart = nextSingleQuote;
+      withQuote = SINGLE_QUOTE;
+    } else if (nextSingleQuote > -1 && nextDoubleQuote > -1 && nextSingleQuote > nextDoubleQuote) {
+      nextStart = nextDoubleQuote;
+      withQuote = DOUBLE_QUOTE;
+    } else if (nextSingleQuote > -1) {
+      nextStart = nextSingleQuote;
+      withQuote = SINGLE_QUOTE;
+    } else if (nextDoubleQuote > -1) {
+      nextStart = nextDoubleQuote;
+      withQuote = DOUBLE_QUOTE;
+    }
+
+    tempData.push(data.substring(cursor, nextStart));
+
+    nextEnd = data.indexOf(withQuote, nextStart + 1);
+    if (nextEnd == -1)
+      break;
+
+    var url = data.substring(nextStart, nextEnd + 1);
+    callback(url, tempData);
+
+    cursor = nextEnd + 1;
+  }
+
+  return tempData.length > 0 ?
+    tempData.join('') + data.substring(cursor, data.length) :
+    data;
+}
+
+function reduceAll(data, context, callback) {
+  data = byUrl(data, context, callback);
+  data = byImport(data, context, callback);
+  return data;
+}
+
+module.exports = reduceAll;
index 5413500..ef25130 100644 (file)
@@ -70,7 +70,7 @@ function rebase(uri, options) {
 
 function rewriteUrls(data, options, context) {
   return reduceUrls(data, context, function (url, tempData) {
-    url = url.replace(/^url\(\s*['"]?|['"]?\s*\)$/g, '');
+    url = url.replace(/^(url\()?\s*['"]?|['"]?\s*\)?$/g, '');
     tempData.push('url(' + rebase(url, options) + ')');
   });
 }
index 9b5da0e..0223987 100644 (file)
@@ -556,6 +556,28 @@ vows.describe('module tests').addBatch({
         'should give right output': function (minified) {
           assert.equal(minified.styles, '@import url(/partials/one.css);@import url(/partials/extra/three.css);@import url(/partials/extra/four.css);.two{color:#fff}');
         }
+      },
+      'with import URL as a string': {
+        'topic': function () {
+          var source = 'test/fixtures/partials/two.css';
+          var asHash = sourcesAsHash([source]);
+          asHash[source].styles = asHash[source].styles.replace(/url\(|\)/g, '');
+          return new CleanCSS().minify(asHash);
+        },
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}');
+        }
+      },
+      'with import URL as an uppercase string': {
+        'topic': function () {
+          var source = 'test/fixtures/partials/two.css';
+          var asHash = sourcesAsHash([source]);
+          asHash[source].styles = asHash[source].styles.replace(/url\(|\)/g, '').replace('@import', '@IMPORT');
+          return new CleanCSS().minify(asHash);
+        },
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}');
+        }
       }
     },
     'with remote paths': {