| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 | /** * Clean-css - https://github.com/jakubpawlowicz/clean-css * Released under the terms of MIT license * * Copyright (C) 2015 JakubPawlowicz.com */var ImportInliner = require('./imports/inliner');var rebaseUrls = require('./urls/rebase');var tokenize = require('./tokenizer/tokenize');var simpleOptimize = require('./selectors/simple');var advancedOptimize = require('./selectors/advanced');var simpleStringify = require('./stringifier/simple');var sourceMapStringify = require('./stringifier/source-maps');var CommentsProcessor = require('./text/comments-processor');var ExpressionsProcessor = require('./text/expressions-processor');var FreeTextProcessor = require('./text/free-text-processor');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 Validator = require('./properties/validator');var fs = require('fs');var path = require('path');var url = require('url');var override = require('./utils/object').override;var DEFAULT_TIMEOUT = 5000;var CleanCSS = module.exports = function CleanCSS(options) {  options = options || {};  this.options = {    advanced: undefined === options.advanced ? true : !!options.advanced,    aggressiveMerging: undefined === options.aggressiveMerging ? true : !!options.aggressiveMerging,    benchmark: options.benchmark,    compatibility: new Compatibility(options.compatibility).toOptions(),    debug: options.debug,    explicitRoot: !!options.root,    explicitTarget: !!options.target,    inliner: options.inliner || {},    keepBreaks: options.keepBreaks || false,    keepSpecialComments: 'keepSpecialComments' in options ? options.keepSpecialComments : '*',    mediaMerging: undefined === options.mediaMerging ? true : !!options.mediaMerging,    processImport: undefined === options.processImport ? true : !!options.processImport,    processImportFrom: importOptionsFrom(options.processImportFrom),    rebase: undefined === options.rebase ? true : !!options.rebase,    relativeTo: options.relativeTo,    restructuring: undefined === options.restructuring ? true : !!options.restructuring,    root: options.root || process.cwd(),    roundingPrecision: options.roundingPrecision,    semanticMerging: undefined === options.semanticMerging ? false : !!options.semanticMerging,    shorthandCompacting: undefined === options.shorthandCompacting ? true : !!options.shorthandCompacting,    sourceMap: options.sourceMap,    sourceMapInlineSources: !!options.sourceMapInlineSources,    target: !options.target || missingDirectory(options.target) || presentDirectory(options.target) ? options.target : path.dirname(options.target)  };  this.options.inliner.timeout = this.options.inliner.timeout || DEFAULT_TIMEOUT;  this.options.inliner.request = override(    /* jshint camelcase: false */    proxyOptionsFrom(process.env.HTTP_PROXY || process.env.http_proxy),    this.options.inliner.request || {}  );};function importOptionsFrom(rules) {  return undefined === rules ? ['all'] : rules;}function missingDirectory(filepath) {  return !fs.existsSync(filepath) && !/\.css$/.test(filepath);}function presentDirectory(filepath) {  return fs.existsSync(filepath) && fs.statSync(filepath).isDirectory();}function proxyOptionsFrom(httpProxy) {  return httpProxy ?    {      hostname: url.parse(httpProxy).hostname,      port: parseInt(url.parse(httpProxy).port)    } :    {};}CleanCSS.prototype.minify = function (data, callback) {  var context = {    stats: {},    errors: [],    warnings: [],    options: this.options,    debug: this.options.debug,    localOnly: !callback,    sourceTracker: new SourceTracker(),    validator: new Validator(this.options.compatibility)  };  if (context.options.sourceMap)    context.inputSourceMapTracker = new InputSourceMapTracker(context);  context.sourceReader = new SourceReader(context, data);  data = context.sourceReader.toString();  if (context.options.processImport || data.indexOf('@shallow') > 0) {    // inline all imports    var runner = callback ?      process.nextTick :      function (callback) { return callback(); };    return runner(function () {      return new ImportInliner(context).process(data, {        localOnly: context.localOnly,        imports: context.options.processImportFrom,        whenDone: runMinifier(callback, context)      });    });  } else {    return runMinifier(callback, context)(data);  }};function runMinifier(callback, context) {  function whenSourceMapReady (data) {    data = context.options.debug ?      minifyWithDebug(context, data) :      minify(context, data);    data = withMetadata(context, data);    return callback ?      callback.call(null, context.errors.length > 0 ? context.errors : null, data) :      data;  }  return function (data) {    if (context.options.sourceMap) {      return context.inputSourceMapTracker.track(data, function () {        if (context.options.sourceMapInlineSources) {          return context.inputSourceMapTracker.resolveSources(function () {            return whenSourceMapReady(data);          });        } else {          return whenSourceMapReady(data);        }      });    } else {      return whenSourceMapReady(data);    }  };}function withMetadata(context, data) {  data.stats = context.stats;  data.errors = context.errors;  data.warnings = context.warnings;  return data;}function minifyWithDebug(context, data) {  var startedAt = process.hrtime();  context.stats.originalSize = context.sourceTracker.removeAll(data).length;  data = minify(context, data);  var elapsed = process.hrtime(startedAt);  context.stats.timeSpent = ~~(elapsed[0] * 1e3 + elapsed[1] / 1e6);  context.stats.efficiency = 1 - data.styles.length / context.stats.originalSize;  context.stats.minifiedSize = data.styles.length;  return data;}function benchmark(runner) {  return function (processor, action) {    var name =  processor.constructor.name + '#' + action;    var start = process.hrtime();    runner(processor, action);    var itTook = process.hrtime(start);    console.log('%d ms: ' + name, 1000 * itTook[0] + itTook[1] / 1000000);  };}function minify(context, data) {  var options = context.options;  var commentsProcessor = new CommentsProcessor(context, options.keepSpecialComments, options.keepBreaks, options.sourceMap);  var expressionsProcessor = new ExpressionsProcessor(options.sourceMap);  var freeTextProcessor = new FreeTextProcessor(options.sourceMap);  var urlsProcessor = new UrlsProcessor(context, options.sourceMap, options.compatibility.properties.urlQuotes);  var stringify = options.sourceMap ? sourceMapStringify : simpleStringify;  var run = function (processor, action) {    data = typeof processor == 'function' ?      processor(data) :      processor[action](data);  };  if (options.benchmark)    run = benchmark(run);  run(commentsProcessor, 'escape');  run(expressionsProcessor, 'escape');  run(urlsProcessor, 'escape');  run(freeTextProcessor, 'escape');  function restoreEscapes(data, prefixContent) {    data = freeTextProcessor.restore(data, prefixContent);    data = urlsProcessor.restore(data);    data = options.rebase ? rebaseUrls(data, context) : data;    data = expressionsProcessor.restore(data);    return commentsProcessor.restore(data);  }  var tokens = tokenize(data, context);  simpleOptimize(tokens, options, context);  if (options.advanced)    advancedOptimize(tokens, options, context, true);  return stringify(tokens, options, restoreEscapes, context.inputSourceMapTracker);}
 |