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);
- }
|