#!/usr/bin/env node var util = require('util'); var fs = require('fs'); var path = require('path'); var CleanCSS = require('../index'); var commands = require('commander'); var packageConfig = fs.readFileSync(path.join(path.dirname(fs.realpathSync(process.argv[1])), '../package.json')); var buildVersion = JSON.parse(packageConfig).version; var isWindows = process.platform == 'win32'; // Specify commander options to parse command line params correctly commands .version(buildVersion, '-v, --version') .usage('[options] source-file, [source-file, ...]') .option('-b, --keep-line-breaks', 'Keep line breaks') .option('--s0', 'Remove all special comments, i.e. /*! comment */') .option('--s1', 'Remove all special comments but the first one') .option('-r, --root [root-path]', 'Set a root path to which resolve absolute @import rules') .option('-o, --output [output-file]', 'Use [output-file] as output instead of STDOUT') .option('-s, --skip-import', 'Disable @import processing') .option('--skip-rebase', 'Disable URLs rebasing') .option('--skip-advanced', 'Disable advanced optimizations - selector & property merging, reduction, etc.') .option('--skip-aggressive-merging', 'Disable properties merging based on their order') .option('--rounding-precision [value]', 'Rounding precision, defaults to 2', parseInt) .option('-c, --compatibility [ie7|ie8]', 'Force compatibility mode') .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)'); commands.on('--help', function() { util.puts(' Examples:\n'); util.puts(' %> cleancss one.css'); util.puts(' %> cleancss -o one-min.css one.css'); if (isWindows) { util.puts(' %> type one.css two.css three.css | cleancss -o merged-and-minified.css'); } else { util.puts(' %> cat one.css two.css three.css | cleancss -o merged-and-minified.css'); util.puts(' %> cat one.css two.css three.css | cleancss | gzip -9 -c > merged-minified-and-gzipped.css.gz'); } util.puts(''); process.exit(); }); commands.parse(process.argv); var options = { sources: null, target: null }; var cleanOptions = {}; var fromStdin = !process.env.__DIRECT__ && !process.stdin.isTTY; // If no sensible data passed in just print help and exit if (!fromStdin && commands.args.length === 0) { commands.outputHelp(); return 0; } // Now coerce commands into CleanCSS configuration... if (commands.output) cleanOptions.target = options.target = commands.output; if (commands.keepLineBreaks) cleanOptions.keepBreaks = true; if (commands.s1) cleanOptions.keepSpecialComments = 1; if (commands.s0) cleanOptions.keepSpecialComments = 0; if (commands.root) cleanOptions.root = commands.root; if (commands.skipImport) cleanOptions.processImport = false; if (commands.skipRebase) cleanOptions.noRebase = true; if (commands.skipAdvanced) cleanOptions.noAdvanced = true; if (commands.skipAggressiveMerging) cleanOptions.noAggressiveMerging = true; if (commands.compatibility) cleanOptions.compatibility = commands.compatibility; if (commands.roundingPrecision !== undefined) cleanOptions.roundingPrecision = commands.roundingPrecision; if (commands.debug) cleanOptions.debug = true; if (commands.timeout) cleanOptions.inliner = { timeout: parseFloat(commands.timeout) * 1000 }; if (commands.args.length > 0) { var relativeTo = (cleanOptions.noRebase ? false : cleanOptions.root) || commands.args[0]; cleanOptions.relativeTo = path.dirname(path.resolve(relativeTo)); options.sources = commands.args.map(function(source) { var isRemote = /^https?:\/\//.test(source); if (cleanOptions.processImport === false) source += '@shallow'; return isRemote ? source : path.relative(cleanOptions.relativeTo, path.resolve(source)); }); } // ... and do the magic! if (options.sources) { var data = options.sources .map(function(source) { return '@import url(' + source + ');'; }) .join(''); minify(data); } else { var stdin = process.openStdin(); stdin.setEncoding('utf-8'); var data = ''; stdin.on('data', function(chunk) { data += chunk; }); stdin.on('end', function() { minify(data); }); } function minify(data) { new CleanCSS(cleanOptions).minify(data, function(errors, minified) { if (cleanOptions.debug) { console.error('Original: %d bytes', this.stats.originalSize); console.error('Minified: %d bytes', this.stats.minifiedSize); console.error('Efficiency: %d%', ~~(this.stats.efficiency * 10000) / 100.0); console.error('Time spent: %dms', this.stats.timeSpent); } outputFeedback(this.errors, true); outputFeedback(this.warnings); if (this.errors.length > 0) process.exit(1); output(minified); }); } function output(minified) { if (options.target) fs.writeFileSync(options.target, minified, 'utf8'); else process.stdout.write(minified); } function outputFeedback(messages, isError) { var prefix = isError ? '\x1B[31mERROR\x1B[39m:' : 'WARNING:'; messages.forEach(function(message) { console.error('%s %s', prefix, message); }); }