| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 | 
							- var fs = require('fs');
 
- var path = require('path');
 
- var cli = require('clap');
 
- var SourceMapConsumer = require('source-map').SourceMapConsumer;
 
- var csso = require('./index.js');
 
- function readFromStream(stream, minify) {
 
-     var buffer = [];
 
-     // FIXME: don't chain until node.js 0.10 drop, since setEncoding isn't chainable in 0.10
 
-     stream.setEncoding('utf8');
 
-     stream
 
-         .on('data', function(chunk) {
 
-             buffer.push(chunk);
 
-         })
 
-         .on('end', function() {
 
-             minify(buffer.join(''));
 
-         });
 
- }
 
- function showStat(filename, source, result, inputMap, map, time, mem) {
 
-     function fmt(size) {
 
-         return String(size).split('').reverse().reduce(function(size, digit, idx) {
 
-             if (idx && idx % 3 === 0) {
 
-                 size = ' ' + size;
 
-             }
 
-             return digit + size;
 
-         }, '');
 
-     }
 
-     map = map || 0;
 
-     result -= map;
 
-     console.error('Source:    ', filename === '<stdin>' ? filename : path.relative(process.cwd(), filename));
 
-     if (inputMap) {
 
-         console.error('Map source:', inputMap);
 
-     }
 
-     console.error('Original:  ', fmt(source), 'bytes');
 
-     console.error('Compressed:', fmt(result), 'bytes', '(' + (100 * result / source).toFixed(2) + '%)');
 
-     console.error('Saving:    ', fmt(source - result), 'bytes', '(' + (100 * (source - result) / source).toFixed(2) + '%)');
 
-     if (map) {
 
-         console.error('Source map:', fmt(map), 'bytes', '(' + (100 * map / (result + map)).toFixed(2) + '% of total)');
 
-         console.error('Total:     ', fmt(map + result), 'bytes');
 
-     }
 
-     console.error('Time:      ', time, 'ms');
 
-     console.error('Memory:    ', (mem / (1024 * 1024)).toFixed(3), 'MB');
 
- }
 
- function showParseError(source, filename, details, message) {
 
-     function processLines(start, end) {
 
-         return lines.slice(start, end).map(function(line, idx) {
 
-             var num = String(start + idx + 1);
 
-             while (num.length < maxNumLength) {
 
-                 num = ' ' + num;
 
-             }
 
-             return num + ' |' + line;
 
-         }).join('\n');
 
-     }
 
-     var lines = source.split(/\n|\r\n?|\f/);
 
-     var column = details.column;
 
-     var line = details.line;
 
-     var startLine = Math.max(1, line - 2);
 
-     var endLine = Math.min(line + 2, lines.length + 1);
 
-     var maxNumLength = Math.max(4, String(endLine).length) + 1;
 
-     console.error('\nParse error ' + filename + ': ' + message);
 
-     console.error(processLines(startLine - 1, line));
 
-     console.error(new Array(column + maxNumLength + 2).join('-') + '^');
 
-     console.error(processLines(line, endLine));
 
-     console.error();
 
- }
 
- function debugLevel(level) {
 
-     // level is undefined when no param -> 1
 
-     return isNaN(level) ? 1 : Math.max(Number(level), 0);
 
- }
 
- function resolveSourceMap(source, inputMap, map, inputFile, outputFile) {
 
-     var inputMapContent = null;
 
-     var inputMapFile = null;
 
-     var outputMapFile = null;
 
-     switch (map) {
 
-         case 'none':
 
-             // don't generate source map
 
-             map = false;
 
-             inputMap = 'none';
 
-             break;
 
-         case 'inline':
 
-             // nothing to do
 
-             break;
 
-         case 'file':
 
-             if (!outputFile) {
 
-                 console.error('Output filename should be specified when `--map file` is used');
 
-                 process.exit(2);
 
-             }
 
-             outputMapFile = outputFile + '.map';
 
-             break;
 
-         default:
 
-             // process filename
 
-             if (map) {
 
-                 // check path is reachable
 
-                 if (!fs.existsSync(path.dirname(map))) {
 
-                     console.error('Directory for map file should exists:', path.dirname(path.resolve(map)));
 
-                     process.exit(2);
 
-                 }
 
-                 // resolve to absolute path
 
-                 outputMapFile = path.resolve(process.cwd(), map);
 
-             }
 
-     }
 
-     switch (inputMap) {
 
-         case 'none':
 
-             // nothing to do
 
-             break;
 
-         case 'auto':
 
-             if (map) {
 
-                 // try fetch source map from source
 
-                 var inputMapComment = source.match(/\/\*# sourceMappingURL=(\S+)\s*\*\/\s*$/);
 
-                 if (inputFile === '<stdin>') {
 
-                     inputFile = false;
 
-                 }
 
-                 if (inputMapComment) {
 
-                     // if comment found – value is filename or base64-encoded source map
 
-                     inputMapComment = inputMapComment[1];
 
-                     if (inputMapComment.substr(0, 5) === 'data:') {
 
-                         // decode source map content from comment
 
-                         inputMapContent = new Buffer(inputMapComment.substr(inputMapComment.indexOf('base64,') + 7), 'base64').toString();
 
-                     } else {
 
-                         // value is filename – resolve it as absolute path
 
-                         if (inputFile) {
 
-                             inputMapFile = path.resolve(path.dirname(inputFile), inputMapComment);
 
-                         }
 
-                     }
 
-                 } else {
 
-                     // comment doesn't found - look up file with `.map` extension nearby input file
 
-                     if (inputFile && fs.existsSync(inputFile + '.map')) {
 
-                         inputMapFile = inputFile + '.map';
 
-                     }
 
-                 }
 
-             }
 
-             break;
 
-         default:
 
-             if (inputMap) {
 
-                 inputMapFile = inputMap;
 
-             }
 
-     }
 
-     // source map placed in external file
 
-     if (inputMapFile) {
 
-         inputMapContent = fs.readFileSync(inputMapFile, 'utf8');
 
-     }
 
-     return {
 
-         input: inputMapContent,
 
-         inputFile: inputMapFile || (inputMapContent ? '<inline>' : false),
 
-         output: map,
 
-         outputFile: outputMapFile
 
-     };
 
- }
 
- function processCommentsOption(value) {
 
-     switch (value) {
 
-         case 'exclamation':
 
-         case 'first-exclamation':
 
-         case 'none':
 
-             return value;
 
-     }
 
-     console.error('Wrong value for `comments` option: %s', value);
 
-     process.exit(2);
 
- }
 
- var command = cli.create('csso', '[input] [output]')
 
-     .version(require('../package.json').version)
 
-     .option('-i, --input <filename>', 'Input file')
 
-     .option('-o, --output <filename>', 'Output file (result outputs to stdout if not set)')
 
-     .option('-m, --map <destination>', 'Generate source map: none (default), inline, file or <filename>', 'none')
 
-     .option('-u, --usage <filenane>', 'Usage data file')
 
-     .option('--input-map <source>', 'Input source map: none, auto (default) or <filename>', 'auto')
 
-     .option('--restructure-off', 'Turns structure minimization off')
 
-     .option('--comments <value>', 'Comments to keep: exclamation (default), first-exclamation or none', 'exclamation')
 
-     .option('--stat', 'Output statistics in stderr')
 
-     .option('--debug [level]', 'Output intermediate state of CSS during compression', debugLevel, 0)
 
-     .action(function(args) {
 
-         var options = this.values;
 
-         var inputFile = options.input || args[0];
 
-         var outputFile = options.output || args[1];
 
-         var usageFile = options.usage;
 
-         var usageData = false;
 
-         var map = options.map;
 
-         var inputMap = options.inputMap;
 
-         var structureOptimisationOff = options.restructureOff;
 
-         var comments = processCommentsOption(options.comments);
 
-         var debug = options.debug;
 
-         var statistics = options.stat;
 
-         var inputStream;
 
-         if (process.stdin.isTTY && !inputFile && !outputFile) {
 
-             this.showHelp();
 
-             return;
 
-         }
 
-         if (!inputFile) {
 
-             inputFile = '<stdin>';
 
-             inputStream = process.stdin;
 
-         } else {
 
-             inputFile = path.resolve(process.cwd(), inputFile);
 
-             inputStream = fs.createReadStream(inputFile);
 
-         }
 
-         if (outputFile) {
 
-             outputFile = path.resolve(process.cwd(), outputFile);
 
-         }
 
-         if (usageFile) {
 
-             if (!fs.existsSync(usageFile)) {
 
-                 console.error('Usage data file doesn\'t found (%s)', usageFile);
 
-                 process.exit(2);
 
-             }
 
-             usageData = fs.readFileSync(usageFile, 'utf-8');
 
-             try {
 
-                 usageData = JSON.parse(usageData);
 
-             } catch (e) {
 
-                 console.error('Usage data parse error (%s)', usageFile);
 
-                 process.exit(2);
 
-             }
 
-         }
 
-         readFromStream(inputStream, function(source) {
 
-             var time = process.hrtime();
 
-             var mem = process.memoryUsage().heapUsed;
 
-             var sourceMap = resolveSourceMap(source, inputMap, map, inputFile, outputFile);
 
-             var sourceMapAnnotation = '';
 
-             var result;
 
-             // main action
 
-             try {
 
-                 result = csso.minify(source, {
 
-                     filename: inputFile,
 
-                     sourceMap: sourceMap.output,
 
-                     usage: usageData,
 
-                     restructure: !structureOptimisationOff,
 
-                     comments: comments,
 
-                     debug: debug
 
-                 });
 
-                 // for backward capability minify returns a string
 
-                 if (typeof result === 'string') {
 
-                     result = {
 
-                         css: result,
 
-                         map: null
 
-                     };
 
-                 }
 
-             } catch (e) {
 
-                 if (e.parseError) {
 
-                     showParseError(source, inputFile, e.parseError, e.message);
 
-                     if (!debug) {
 
-                         process.exit(2);
 
-                     }
 
-                 }
 
-                 throw e;
 
-             }
 
-             if (sourceMap.output && result.map) {
 
-                 // apply input map
 
-                 if (sourceMap.input) {
 
-                     result.map.applySourceMap(
 
-                         new SourceMapConsumer(sourceMap.input),
 
-                         inputFile
 
-                     );
 
-                 }
 
-                 // add source map to result
 
-                 if (sourceMap.outputFile) {
 
-                     // write source map to file
 
-                     fs.writeFileSync(sourceMap.outputFile, result.map.toString(), 'utf-8');
 
-                     sourceMapAnnotation = '\n' +
 
-                         '/*# sourceMappingURL=' +
 
-                         path.relative(outputFile ? path.dirname(outputFile) : process.cwd(), sourceMap.outputFile) +
 
-                         ' */';
 
-                 } else {
 
-                     // inline source map
 
-                     sourceMapAnnotation = '\n' +
 
-                         '/*# sourceMappingURL=data:application/json;base64,' +
 
-                         new Buffer(result.map.toString()).toString('base64') +
 
-                         ' */';
 
-                 }
 
-                 result.css += sourceMapAnnotation;
 
-             }
 
-             // output result
 
-             if (outputFile) {
 
-                 fs.writeFileSync(outputFile, result.css, 'utf-8');
 
-             } else {
 
-                 console.log(result.css);
 
-             }
 
-             // output statistics
 
-             if (statistics) {
 
-                 var timeDiff = process.hrtime(time);
 
-                 showStat(
 
-                     path.relative(process.cwd(), inputFile),
 
-                     source.length,
 
-                     result.css.length,
 
-                     sourceMap.inputFile,
 
-                     sourceMapAnnotation.length,
 
-                     parseInt(timeDiff[0] * 1e3 + timeDiff[1] / 1e6),
 
-                     process.memoryUsage().heapUsed - mem
 
-                 );
 
-             }
 
-         });
 
-     });
 
- module.exports = {
 
-     run: command.run.bind(command),
 
-     isCliError: function(err) {
 
-         return err instanceof cli.Error;
 
-     }
 
- };
 
 
  |