rebase relative urls in inlined imports
authorbanderson <bluej100@gmail.com>
Thu, 23 May 2013 06:34:20 +0000 (00:34 -0600)
committerbanderson <bluej100@gmail.com>
Thu, 23 May 2013 06:34:20 +0000 (00:34 -0600)
lib/clean.js
test/data/partials/extra/down.gif [new file with mode: 0755]
test/data/partials/four.css [new file with mode: 0644]
test/data/partials/three.css [new file with mode: 0644]
test/unit-test.js

index 1b89755..e0cd5b6 100644 (file)
@@ -361,6 +361,7 @@ var CleanCSS = {
     var cursor = 0;
 
     options.relativeTo = options.relativeTo || options.root;
+    options._baseRelativeTo = options._baseRelativeTo || options.relativeTo;
     options.visited = options.visited || [];
 
     var inlinedFile = function() {
@@ -383,9 +384,12 @@ var CleanCSS = {
         options.visited.push(fullPath);
 
         var importedData = fs.readFileSync(fullPath, 'utf8');
+        var importRelativeTo = path.dirname(fullPath);
+        importedData = CleanCSS._rebaseRelativeURLs(importedData, importRelativeTo, options._baseRelativeTo);
         return CleanCSS._inlineImports(importedData, {
           root: options.root,
-          relativeTo: path.dirname(fullPath),
+          relativeTo: importRelativeTo,
+          _baseRelativeTo: options.baseRelativeTo,
           visited: options.visited
         });
       } else {
@@ -412,6 +416,34 @@ var CleanCSS = {
       data;
   },
 
+  _rebaseRelativeURLs: function(data, fromBase, toBase) {
+    var tempData = [];
+    var nextStart = 0;
+    var nextEnd = 0;
+    var cursor = 0;
+
+    for (; nextEnd < data.length; ) {
+      nextStart = data.indexOf('url(', nextEnd);
+      if (nextStart == -1)
+        break;
+      nextEnd = data.indexOf(')', nextStart + 4);
+      if (nextEnd == -1)
+        break;
+
+      tempData.push(data.substring(cursor, nextStart));
+      var url = data.substring(nextStart + 4, nextEnd).replace(/['"]/g, '');
+      if (url[0] != '/' && url.substring(url.length - 4) != '.css') {
+        url = path.relative(toBase, path.join(fromBase, url)).replace(/\\/g, '/');
+      }
+      tempData.push('url(' + url + ')');
+      cursor = nextEnd + 1;
+    }
+
+    return tempData.length > 0 ?
+      tempData.join('') + data.substring(cursor, data.length) :
+      data;
+  },
+
   // Strip special comments (/*! ... */) by replacing them by __CSSCOMMENT__ marker
   // for further restoring. Plain comments are removed. It's done by scanning datq using
   // String#indexOf scanning instead of regexps to speed up the process.
diff --git a/test/data/partials/extra/down.gif b/test/data/partials/extra/down.gif
new file mode 100755 (executable)
index 0000000..9bd9447
Binary files /dev/null and b/test/data/partials/extra/down.gif differ
diff --git a/test/data/partials/four.css b/test/data/partials/four.css
new file mode 100644 (file)
index 0000000..581c1ef
--- /dev/null
@@ -0,0 +1 @@
+.four {background-image: url(/partials/extra/down.gif);}
diff --git a/test/data/partials/three.css b/test/data/partials/three.css
new file mode 100644 (file)
index 0000000..d2d4006
--- /dev/null
@@ -0,0 +1 @@
+.three {background-image: url(extra/down.gif);}
index bda5be7..99611cb 100644 (file)
@@ -808,6 +808,14 @@ title']",
     'of multi-level, circular dependency file': [
       "@import url(test/data/partials/two.css);",
       ".one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}"
+    ],
+    'of a file with a relative resource path': [
+      "@import url(test/data/partials/three.css);",
+      ".three{background-image:url(test/data/partials/extra/down.gif)}",
+    ],
+    'of a file with an absolute resource path': [
+      "@import url(test/data/partials/four.css);",
+      ".four{background-image:url(/partials/extra/down.gif)}",
     ]
   }),
   '@import with absolute paths': cssContext({