Adds `--source-map` switch for building input's source map.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 9 Nov 2014 16:06:40 +0000 (16:06 +0000)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 8 Dec 2014 09:39:15 +0000 (09:39 +0000)
* It's enabled in CLI only if output file is given.

History.md
README.md
bin/cleancss
test/binary-test.js

index 0a5199e..4a08d60 100644 (file)
@@ -3,6 +3,7 @@
 
 * Adds more granular control over compatibility settings.
 * Adds support for @counter-style at-rule.
+* Adds `--source-map`/`sourceMap` switch for building input's source map.
 * Adds `--skip-shorthand-compacting`/`shorthandComacting` option for disabling shorthand compacting.
 * Allows `target` option to be a path to a folder instead of a file.
 * Allows disabling rounding precision. By [@superlukas](https://github.com/superlukas).
index e9efb27..4705230 100644 (file)
--- a/README.md
+++ b/README.md
@@ -89,6 +89,7 @@ cleancss [options] source-file, [source-file, ...]
 --skip-shorthand-compacting     Disable shorthand compacting
 --rounding-precision [N]        Rounds to `N` decimal places. Defaults to 2. -1 disables rounding.
 -c, --compatibility [ie7|ie8]   Force compatibility mode (see Readme for advanced examples)
+--source-map                    Enables building input's source map
 -d, --debug                     Shows debug information (minification time & compression efficiency)
 ```
 
index 19df3f0..1424a36 100755 (executable)
@@ -28,6 +28,7 @@ commands
   .option('--skip-shorthand-compacting', 'Disable shorthand compacting')
   .option('--rounding-precision [n]', 'Rounds to `N` decimal places. Defaults to 2. -1 disables rounding.', parseInt)
   .option('-c, --compatibility [ie7|ie8]', 'Force compatibility mode (see Readme for advanced examples)')
+  .option('--source-map', 'Enables building input\'s source map')
   .option('-t, --timeout [seconds]', 'Per connection timeout when fetching remote @imports (defaults to 5 seconds)')
   .option('-d, --debug', 'Shows debug information (minification time & compression efficiency)');
 
@@ -83,6 +84,8 @@ if (commands.skipShorthandCompacting)
   cleanOptions.shorthandCompacting = false;
 if (commands.compatibility)
   cleanOptions.compatibility = commands.compatibility;
+if (commands.sourceMap)
+  cleanOptions.sourceMap = true;
 if (commands.roundingPrecision !== undefined)
   cleanOptions.roundingPrecision = commands.roundingPrecision;
 if (commands.debug)
@@ -140,7 +143,13 @@ function minify(data) {
     if (this.errors.length > 0)
       process.exit(1);
 
-    output(minified.styles);
+    if (minified.sourceMap && options.target) {
+      var mapFilename = path.basename(options.target) + '.map';
+      output(minified.styles + '/*# sourceMappingURL=' + mapFilename + ' */');
+      outputMap(minified.sourceMap, mapFilename);
+    } else {
+      output(minified.styles);
+    }
   });
 }
 
@@ -151,6 +160,11 @@ function output(minified) {
     process.stdout.write(minified);
 }
 
+function outputMap(sourceMap, mapFilename) {
+  var mapPath = path.join(path.dirname(options.target), mapFilename);
+  fs.writeFileSync(mapPath, sourceMap.toString(), 'utf-8');
+}
+
 function outputFeedback(messages, isError) {
   var prefix = isError ? '\x1B[31mERROR\x1B[39m:' : 'WARNING:';
 
index fd87631..f1ea693 100644 (file)
@@ -4,6 +4,7 @@ var exec = require('child_process').exec;
 var fs = require('fs');
 var http = require('http');
 var path = require('path');
+var SourceMapConsumer = require('source-map').SourceMapConsumer;
 
 var isWindows = process.platform == 'win32';
 var lineBreakRegExp = new RegExp(require('os').EOL, 'g');
@@ -336,5 +337,31 @@ exports.commandsSuite = vows.describe('binary commands').addBatch({
         assert.equal(stdout, 'a{background:url(image.png);background-color:red}');
       }
     })
+  },
+  'source maps': {
+    'output file': binaryContext('--source-map -o ./reset.min.css ./test/data/reset.css', {
+      'includes map in minified file': function() {
+        assert.include(readFile('./reset.min.css'), '/*# sourceMappingURL=reset.min.css.map */');
+      },
+      'creates a map file': function () {
+        assert.isTrue(fs.existsSync('./reset.min.css.map'));
+      },
+      'includes right content in map file': function () {
+        var sourceMap = new SourceMapConsumer(readFile('./reset.min.css.map'));
+        assert.deepEqual(
+          sourceMap.originalPositionFor({ line: 1, column: 1 }),
+          {
+            source: 'test/data/reset.css',
+            line: 4,
+            column: 1,
+            name: 'a'
+          }
+        );
+      },
+      'teardown': function () {
+        deleteFile('reset.min.css');
+        deleteFile('reset.min.css.map');
+      }
+    })
   }
 });