Fixes #416 - accepts hash as a list of arguments.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 12 Jan 2015 23:12:53 +0000 (23:12 +0000)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 14 Jan 2015 20:01:46 +0000 (20:01 +0000)
Such a hash is now accepted as the first argument to `minify` method:

```javascript
{
  'path/to/file/one': {
    styles: 'contents of file one'
  },
  'path/to/file/two': {
    styles: 'contents of file two'
  }
}
```

This is also prepares us to implement #419 - merging input source maps.

History.md
README.md
lib/images/url-rewriter.js
lib/utils/source-reader.js
test/module-test.js

index 47e9bd5..1568cee 100644 (file)
@@ -6,6 +6,7 @@
 * Fixed issue [#158](https://github.com/GoalSmashers/clean-css/issues/158) - adds body-based selectors reduction.
 * Fixed issue [#182](https://github.com/GoalSmashers/clean-css/issues/182) - removing space after closing brace.
 * Fixed issue [#357](https://github.com/GoalSmashers/clean-css/issues/357) - non-standard but valid URLs.
+* Fixed issue [#416](https://github.com/GoalSmashers/clean-css/issues/416) - accepts hash as `minify` argument.
 
 [3.0.4 / 2015-01-11](https://github.com/jakubpawlowicz/clean-css/compare/v3.0.3...v3.0.4)
 ==================
index 20950b0..8e86dd4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -247,6 +247,21 @@ new CleanCSS({ sourceMap: inputSourceMapAsString, target: pathToOutputDirectory
 * Shorthand compacting is currently disabled when source maps are enabled, see [#399](https://github.com/GoalSmashers/clean-css/issues/399)
 * Sources inlined in source maps are not supported, see [#397](https://github.com/GoalSmashers/clean-css/issues/397)
 
+### How to minify multiple files with API
+
+#### Passing a hash
+
+```javascript
+new CleanCSS().minify({
+  'path/to/file/one': {
+    styles: 'contents of file one'
+  },
+  'path/to/file/two': {
+    styles: 'contents of file two'
+  }
+});
+```
+
 ### How to set compatibility mode
 
 Compatibility settings are controlled by `--compatibility` switch (CLI) and `compatibility` option (library mode).
index 69c2443..955ea0c 100644 (file)
@@ -35,14 +35,23 @@ UrlRewriter.prototype.process = function (data) {
 };
 
 function rebase(resource, options) {
+  // TODO: this is getting insane now - pending refactor in #436
+  var importUrl = resource.substring(resource.length - 4) == '.css';
   var specialUrl = resource[0] == '/' ||
     resource[0] == '#' ||
-    resource.substring(resource.length - 4) == '.css' ||
+    (!options.imports && importUrl) ||
     resource.indexOf('data:') === 0 ||
     /^https?:\/\//.exec(resource) !== null ||
     /__\w+__/.exec(resource) !== null;
   var rebased;
 
+  if (false === options.urls) {
+    if (options.imports && importUrl)
+      specialUrl = false;
+    else
+      specialUrl = true;
+  }
+
   if (specialUrl)
     return resource;
 
index c98eb0b..4bc31f3 100644 (file)
@@ -1,4 +1,5 @@
 var path = require('path');
+var UrlRewriter = require('../images/url-rewriter');
 
 function SourceReader(context, data) {
   this.outerContext = context;
@@ -13,7 +14,7 @@ SourceReader.prototype.toString = function () {
   if (Array.isArray(this.data))
     return fromArray(this.outerContext, this.data);
 
-  return this.data;
+  return fromHash(this.outerContext, this.data);
 };
 
 function fromArray(outerContext, sources) {
@@ -32,4 +33,26 @@ function fromArray(outerContext, sources) {
     .join('');
 }
 
+function fromHash(outerContext, sources) {
+  var data = [];
+  var toBase = path.resolve(outerContext.options.target || process.cwd());
+
+  for (var source in sources) {
+    var styles = sources[source].styles;
+    var rewriter = new UrlRewriter({
+      absolute: !!outerContext.options.root,
+      relative: !outerContext.options.root,
+      imports: true,
+      urls: outerContext.options.rebase,
+      fromBase: path.dirname(path.resolve(source)),
+      toBase: toBase
+    });
+
+    styles = rewriter.process(styles);
+    data.push(styles);
+  }
+
+  return data.join('');
+}
+
 module.exports = SourceReader;
index df76624..28ae768 100644 (file)
@@ -1,9 +1,23 @@
 var vows = require('vows');
 var assert = require('assert');
 var path = require('path');
+var fs = require('fs');
 var CleanCSS = require('../index');
 var SourceMapGenerator = require('source-map').SourceMapGenerator;
 
+function sourcesAsHash(sources, resolve) {
+  var inputHash = {};
+
+  sources.forEach(function (source) {
+    source = resolve ? path.resolve(source) : source;
+    inputHash[source] = {
+      styles: fs.readFileSync(source, 'utf-8')
+    };
+  });
+
+  return inputHash;
+}
+
 vows.describe('module tests').addBatch({
   'imported as a function': {
     topic: function() {
@@ -287,5 +301,95 @@ vows.describe('module tests').addBatch({
         assert.equal(minified.styles, '@import url(one.css);@import url(extra/three.css);@import url(./extra/four.css);.two{color:#fff}');
       }
     }
+  },
+  'accepts a list of source files as hash': {
+    'rebased to the current dir': {
+      'with relative paths': {
+        'topic': new CleanCSS().minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'])),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/fixtures/partials/extra/down.gif)}');
+        }
+      },
+      'with absolute paths': {
+        'topic': new CleanCSS().minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'], true)),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/fixtures/partials/extra/down.gif)}');
+        }
+      }
+    },
+    'rebased to a relative path': {
+      'with relative paths': {
+        'topic': new CleanCSS({ target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'])),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(partials/extra/down.gif)}');
+        }
+      },
+      'with absolute paths': {
+        'topic': new CleanCSS({ target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'], true)),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(partials/extra/down.gif)}');
+        }
+      }
+    },
+    'rebased to an absolute root': {
+      'with relative paths': {
+        'topic': new CleanCSS({ root: 'test/fixtures', target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'])),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(/partials/extra/down.gif)}');
+        }
+      },
+      'with absolute paths': {
+        'topic': new CleanCSS({ root: 'test/fixtures', target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'], true)),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(/partials/extra/down.gif)}');
+        }
+      }
+    },
+    'with rebasing off': {
+      'with relative paths': {
+        'topic': new CleanCSS({ rebase: false }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'])),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(extra/down.gif)}');
+        }
+      },
+      'with absolute paths': {
+        'topic': new CleanCSS({ rebase: false }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'], true)),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(extra/down.gif)}');
+        }
+      }
+    },
+    'with other imports': {
+      'topic': new CleanCSS().minify(sourcesAsHash(['test/fixtures/partials/two.css'])),
+      'should give right output': function (minified) {
+        assert.equal(minified.styles, '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}');
+      }
+    },
+    'with other imports and rebasing off': {
+      'topic': new CleanCSS({ rebase: false }).minify(sourcesAsHash(['test/fixtures/partials/two.css'])),
+      'should give right output': function (minified) {
+        assert.equal(minified.styles, '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}');
+      }
+    },
+    'with other imports and processing imports off': {
+      'relative to current path': {
+        'topic': new CleanCSS({ processImport: false }).minify(sourcesAsHash(['test/fixtures/partials/two.css'])),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/extra/three.css);@import url(test/fixtures/partials/extra/four.css);.two{color:#fff}');
+        }
+      },
+      'relative to different path': {
+        'topic': new CleanCSS({ processImport: false, target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/two.css'])),
+        '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}');
+        }
+      },
+      'absolute': {
+        'topic': new CleanCSS({ processImport: false, root: 'test/fixtures', target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/two.css'])),
+        '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}');
+        }
+      }
+    }
   }
 }).export(module);