See #791 - normalizes stored paths.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 9 Jan 2017 09:44:51 +0000 (10:44 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 9 Jan 2017 10:05:48 +0000 (11:05 +0100)
Stores all paths internally as normalized to *nix format but
still outputs Windows friendly paths if needed.

`source-map` does it internally so there's no need to transform
paths in source maps.

lib/reader/normalize-path.js [new file with mode: 0644]
lib/reader/read-sources.js
lib/writer/source-maps.js
test/module-test.js
test/source-map-test.js

diff --git a/lib/reader/normalize-path.js b/lib/reader/normalize-path.js
new file mode 100644 (file)
index 0000000..a9eca38
--- /dev/null
@@ -0,0 +1,8 @@
+var UNIX_SEPARATOR = '/';
+var WINDOWS_SEPARATOR_PATTERN = /\\/g;
+
+function normalizePath(path) {
+  return path.replace(WINDOWS_SEPARATOR_PATTERN, UNIX_SEPARATOR);
+}
+
+module.exports = normalizePath;
index 1ccbdb2..82c34ec 100644 (file)
@@ -6,6 +6,7 @@ var extractImportUrlAndMedia = require('./extract-import-url-and-media');
 var isAllowedResource = require('./is-allowed-resource');
 var loadOriginalSources = require('./load-original-sources');
 var loadRemoteResource = require('./load-remote-resource');
+var normalizePath = require('./normalize-path');
 var rebase = require('./rebase');
 var rebaseLocalMap = require('./rebase-local-map');
 var rebaseRemoteMap = require('./rebase-remote-map');
@@ -57,7 +58,9 @@ function fromString(input, context, callback) {
 
 function fromArray(input, context, callback) {
   var inputAsImports = input.reduce(function (accumulator, uri) {
-    accumulator.push(restoreAsRelativeImport(uri));
+    var normalizedUri = isRemoteResource(uri) ? uri : normalizePath(uri);
+
+    accumulator.push(restoreAsRelativeImport(normalizedUri));
     return accumulator;
   }, []);
 
@@ -66,17 +69,20 @@ function fromArray(input, context, callback) {
 
 function fromHash(input, context, callback) {
   var uri;
+  var normalizedUri;
   var source;
   var inputAsImports = [];
 
   for (uri in input) {
     source = input[uri];
-    inputAsImports.push(restoreAsRelativeImport(uri));
+    normalizedUri = isRemoteResource(uri) ? uri : normalizePath(uri);
+
+    inputAsImports.push(restoreAsRelativeImport(normalizedUri));
 
-    context.sourcesContent[uri] = source.styles;
+    context.sourcesContent[normalizedUri] = source.styles;
 
     if (source.sourceMap) {
-      trackSourceMap(source.sourceMap, uri, context);
+      trackSourceMap(source.sourceMap, normalizedUri, context);
     }
   }
 
@@ -274,7 +280,8 @@ function inlineLocalStylesheet(uri, mediaQuery, metadata, inlinerContext) {
   var importedStyles;
   var importedTokens;
   var isAllowed = isAllowedResource(uri, false, inlinerContext.inline);
-  var isLoaded = relativeToCurrentPath in inlinerContext.externalContext.sourcesContent;
+  var normalizedPath = normalizePath(relativeToCurrentPath);
+  var isLoaded = normalizedPath in inlinerContext.externalContext.sourcesContent;
 
   if (inlinerContext.inlinedStylesheets.indexOf(absoluteUri) > -1) {
     inlinerContext.warnings.push('Ignoring local @import of "' + uri + '" as it has already been imported.');
@@ -289,14 +296,14 @@ function inlineLocalStylesheet(uri, mediaQuery, metadata, inlinerContext) {
     inlinerContext.outputTokens = inlinerContext.outputTokens.concat(inlinerContext.sourceTokens.slice(0, 1));
   } else {
     importedStyles = isLoaded ?
-      inlinerContext.externalContext.sourcesContent[relativeToCurrentPath] :
+      inlinerContext.externalContext.sourcesContent[normalizedPath] :
       fs.readFileSync(absoluteUri, 'utf-8');
 
     inlinerContext.inlinedStylesheets.push(absoluteUri);
     inlinerContext.inline = inlinerContext.externalContext.options.inline;
 
-    inlinerContext.externalContext.source = relativeToCurrentPath;
-    inlinerContext.externalContext.sourcesContent[relativeToCurrentPath] = importedStyles;
+    inlinerContext.externalContext.source = normalizedPath;
+    inlinerContext.externalContext.sourcesContent[normalizedPath] = importedStyles;
     inlinerContext.externalContext.stats.originalSize += importedStyles.length;
 
     importedTokens = fromStyles(importedStyles, inlinerContext.externalContext, inlinerContext, function (tokens) { return tokens; });
index c7374b2..54a0090 100644 (file)
@@ -4,7 +4,10 @@ var all = require('./helpers').all;
 var isRemoteResource = require('../utils/is-remote-resource');
 
 var isWindows = process.platform == 'win32';
+
+var NIX_SEPARATOR_PATTERN = /\//g;
 var UNKNOWN_SOURCE = '$stdin';
+var WINDOWS_SEPARATOR = '\\';
 
 function store(element, serializeContext) {
   var fromString = typeof element == 'string';
@@ -40,7 +43,7 @@ function trackMapping(mapping, serializeContext) {
   var storedSource = source || UNKNOWN_SOURCE;
 
   if (isWindows && source && !isRemoteResource(source)) {
-    source = source.replace(/\\/g, '/');
+    storedSource = source.replace(NIX_SEPARATOR_PATTERN, WINDOWS_SEPARATOR);
   }
 
   serializeContext.outputMap.addMapping({
index b15e548..f31e34f 100644 (file)
@@ -664,6 +664,24 @@ vows.describe('module tests').addBatch({
         assert.equal(minified.styles, '.one{background-color:red}.test{color:#000}');
       }
     },
+    'with mixed-style paths': {
+      'topic': function () {
+        new CleanCSS({ level: 1, inline: 'all' }).minify({
+          'main.css': {
+            styles: '@import url(test/fixtures/partials/one.css);\n@import url(http://127.0.0.1/test.css);'
+          },
+          'test\\fixtures\\partials\\one.css': {
+            styles: '.one { background-color:#f00; }'
+          },
+          'http://127.0.0.1/test.css': {
+            styles: '.test { color: #000 }'
+          }
+        }, this.callback);
+      },
+      'gives right output without reading resources': function (minified) {
+        assert.equal(minified.styles, '.one{background-color:red}.test{color:#000}');
+      }
+    },
     'with @import and rules after': {
       'topic': function () {
         return new CleanCSS().minify(sourcesAsHash(['./test/fixtures/partials/two.css', './test/fixtures/partials-absolute/base.css']));
index 0ae3c80..5ef05fe 100644 (file)
@@ -1410,9 +1410,9 @@ vows.describe('source-map')
         },
         'has embedded sources': function (minified) {
           assert.deepEqual(JSON.parse(minified.sourceMap.toString()).sources, [
-            'test/fixtures/source-maps/some.css',
-            'test/fixtures/source-maps/nested/once.css',
-            'test/fixtures/source-maps/styles.css'
+            path.join('test', 'fixtures', 'source-maps', 'some.css'),
+            path.join('test', 'fixtures', 'source-maps', 'nested', 'once.css'),
+            path.join('test', 'fixtures', 'source-maps', 'styles.css')
           ]);
         },
         'has embedded sources content': function (minified) {
@@ -1438,9 +1438,9 @@ vows.describe('source-map')
         },
         'has embedded sources': function (minified) {
           assert.deepEqual(JSON.parse(minified.sourceMap.toString()).sources, [
-            'test/fixtures/source-maps/some.css',
-            'test/fixtures/source-maps/nested/once.css',
-            'test/fixtures/source-maps/styles.css'
+            path.join('test', 'fixtures', 'source-maps', 'some.css'),
+            path.join('test', 'fixtures', 'source-maps', 'nested', 'once.css'),
+            path.join('test', 'fixtures', 'source-maps', 'styles.css')
           ]);
         },
         'has embedded sources content': function (minified) {