Fixes #400 - CleanCSS#minify accepts an array of filenames.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 14 Dec 2014 18:50:39 +0000 (18:50 +0000)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 14 Dec 2014 18:53:45 +0000 (18:53 +0000)
* Both relative and absolute paths are supported - see test/module-test.js.

History.md
README.md
bin/cleancss
lib/clean.js
lib/utils/source-reader.js [new file with mode: 0644]
test/module-test.js

index 4f6e085..91578be 100644 (file)
@@ -23,6 +23,7 @@
 * Fixed issue [#363](https://github.com/GoalSmashers/clean-css/issues/363) - `rem` units overriding `px`.
 * Fixed issue [#373](https://github.com/GoalSmashers/clean-css/issues/373) - proper background shorthand merging.
 * Fixed issue [#395](https://github.com/GoalSmashers/clean-css/issues/395) - unescaped brackets in data URIs.
+* Fixed issue [#400](https://github.com/GoalSmashers/clean-css/issues/400) - API to accept an array of filenames.
 * Fixed issue [#403](https://github.com/GoalSmashers/clean-css/issues/403) - tracking input files in source maps.
 * Fixed issue [#404](https://github.com/GoalSmashers/clean-css/issues/404) - no state sharing in API.
 * Refixed issue [#304](https://github.com/GoalSmashers/clean-css/issues/304) - background position merging.
index 6fc3b4d..f50a156 100644 (file)
--- a/README.md
+++ b/README.md
@@ -242,7 +242,7 @@ To generate a source map, use `sourceMap: true` option, e.g.:
 new CleanCSS({ sourceMap: true, target: pathToOutputDirectory }).minify(source, function (minified) {
   // access minified.sourceMap for SourceMapGenerator object
   // see https://github.com/mozilla/source-map/#sourcemapgenerator for more details
-  // see https://github.com/jakubpawlowicz/clean-css/blob/master/bin/cleancss#L132 on how it's used in clean-css' CLI
+  // see https://github.com/jakubpawlowicz/clean-css/blob/master/bin/cleancss#L114 on how it's used in clean-css' CLI
 });
 ```
 
@@ -252,7 +252,7 @@ Using API you can also pass an input source map directly:
 new CleanCSS({ sourceMap: inputSourceMapAsString, target: pathToOutputDirectory }).minify(source, function (minified) {
   // access minified.sourceMap to access SourceMapGenerator object
   // see https://github.com/mozilla/source-map/#sourcemapgenerator for more details
-  // see https://github.com/jakubpawlowicz/clean-css/blob/master/bin/cleancss#L132 on how it's used in clean-css' CLI
+  // see https://github.com/jakubpawlowicz/clean-css/blob/master/bin/cleancss#L114 on how it's used in clean-css' CLI
 });
 ```
 
index d726c53..8100306 100755 (executable)
@@ -73,21 +73,8 @@ var options = {
   target: commands.output
 };
 
-if (commands.args.length > 0) {
-  var relativeTo = (options.rebase ? options.root : false) || commands.args[0];
-  options.relativeTo = path.dirname(path.resolve(relativeTo));
-
-  options.sources = commands.args.map(function(source) {
-    var isRemote = /^https?:\/\//.test(source);
-
-    if (options.processImport === false)
-      source += '@shallow';
-
-    return isRemote ?
-      source :
-      path.relative(options.relativeTo, path.resolve(source));
-  });
-}
+if (options.root || commands.args.length > 0)
+  options.relativeTo = path.dirname(path.resolve(options.root || commands.args[0]));
 
 if (options.sourceMap && !options.target) {
   outputFeedback(['Source maps will not be built because you have not specified an output file.'], true);
@@ -95,13 +82,8 @@ if (options.sourceMap && !options.target) {
 }
 
 // ... and do the magic!
-if (options.sources) {
-  var data = options.sources
-    .map(function(source) {
-      return '@import url(' + source + ');';
-    })
-    .join('');
-  minify(data);
+if (commands.args.length > 0) {
+  minify(commands.args);
 } else {
   var stdin = process.openStdin();
   stdin.setEncoding('utf-8');
index 7498c13..116ad8d 100644 (file)
@@ -19,6 +19,7 @@ var UrlsProcessor = require('./text/urls-processor');
 var Compatibility = require('./utils/compatibility');
 var InputSourceMapTracker = require('./utils/input-source-map-tracker');
 var SourceTracker = require('./utils/source-tracker');
+var SourceReader = require('./utils/source-reader');
 
 var DEFAULT_TIMEOUT = 5000;
 
@@ -58,8 +59,7 @@ CleanCSS.prototype.minify = function(data, callback) {
     sourceTracker: new SourceTracker()
   };
 
-  if (Buffer.isBuffer(data))
-    data = data.toString();
+  data = new SourceReader(context, data).toString();
 
   if (context.options.processImport || data.indexOf('@shallow') > 0) {
     // inline all imports
diff --git a/lib/utils/source-reader.js b/lib/utils/source-reader.js
new file mode 100644 (file)
index 0000000..c98eb0b
--- /dev/null
@@ -0,0 +1,35 @@
+var path = require('path');
+
+function SourceReader(context, data) {
+  this.outerContext = context;
+  this.data = data;
+}
+
+SourceReader.prototype.toString = function () {
+  if (typeof this.data == 'string')
+    return this.data;
+  if (Buffer.isBuffer(this.data))
+    return this.data.toString();
+  if (Array.isArray(this.data))
+    return fromArray(this.outerContext, this.data);
+
+  return this.data;
+};
+
+function fromArray(outerContext, sources) {
+  return sources
+    .map(function (source) {
+      return outerContext.options.processImport === false ?
+        source + '@shallow' :
+        source;
+    })
+    .map(function (source) {
+      return !outerContext.options.relativeTo || /^https?:\/\//.test(source) ?
+        source :
+        path.relative(outerContext.options.relativeTo, source);
+    })
+    .map(function (source) { return '@import url(' + source + ');'; })
+    .join('');
+}
+
+module.exports = SourceReader;
index 64dc0a7..14a5f86 100644 (file)
@@ -233,5 +233,55 @@ vows.describe('module tests').addBatch({
     'should include source map': function (minified) {
       assert.instanceOf(minified.sourceMap, SourceMapGenerator);
     }
+  },
+  'accepts a list of source files as array': {
+    'rebased to the current dir': {
+      'relative': {
+        'topic': new CleanCSS().minify(['test/data/partials/one.css', 'test/data/partials/three.css']),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/data/partials/extra/down.gif)}');
+        }
+      },
+      'absolute': {
+        'topic': new CleanCSS({ relativeTo: process.cwd() }).minify([path.resolve('test/data/partials/one.css'), path.resolve('test/data/partials/three.css')]),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/data/partials/extra/down.gif)}');
+        }
+      }
+    },
+    'rebased to a path': {
+      'relative': {
+        'topic': new CleanCSS({ relativeTo: 'test/data' }).minify(['test/data/partials/one.css', 'test/data/partials/three.css']),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(partials/extra/down.gif)}');
+        }
+      },
+      'absolute': {
+        'topic': new CleanCSS({ relativeTo: 'test/data' }).minify([path.resolve('test/data/partials/one.css'), path.resolve('test/data/partials/three.css')]),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(partials/extra/down.gif)}');
+        }
+      }
+    },
+    'rebased to root': {
+      'relative': {
+        'topic': new CleanCSS({ root: 'test/data', relativeTo: 'test/data' }).minify(['test/data/partials/one.css', 'test/data/partials/three.css']),
+        'should give right output': function (minified) {
+          assert.equal(minified.styles, '.one{color:red}.three{background-image:url(/partials/extra/down.gif)}');
+        }
+      },
+      'absolute': {
+        'topic': new CleanCSS({ root: 'test/data', relativeTo: 'test/data' }).minify([path.resolve('test/data/partials/one.css'), path.resolve('test/data/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 imports off': {
+      'topic': new CleanCSS({ processImport: false }).minify(['./test/data/partials/two.css']),
+      'should give right output': function (minified) {
+        assert.equal(minified.styles, '@import url(one.css);@import url(extra/three.css);@import url(./extra/four.css);.two{color:#fff}');
+      }
+    }
   }
 }).export(module);