242 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * Clean-css - https://github.com/clean-css/clean-css
 | |
|  * Released under the terms of MIT license
 | |
|  */
 | |
| 
 | |
| var level0Optimize = require('./optimizer/level-0/optimize');
 | |
| var level1Optimize = require('./optimizer/level-1/optimize');
 | |
| var level2Optimize = require('./optimizer/level-2/optimize');
 | |
| var validator = require('./optimizer/validator');
 | |
| 
 | |
| var compatibilityFrom = require('./options/compatibility');
 | |
| var fetchFrom = require('./options/fetch');
 | |
| var formatFrom = require('./options/format').formatFrom;
 | |
| var inlineFrom = require('./options/inline');
 | |
| var inlineRequestFrom = require('./options/inline-request');
 | |
| var inlineTimeoutFrom = require('./options/inline-timeout');
 | |
| var OptimizationLevel = require('./options/optimization-level').OptimizationLevel;
 | |
| var optimizationLevelFrom = require('./options/optimization-level').optimizationLevelFrom;
 | |
| var pluginsFrom = require('./options/plugins');
 | |
| var rebaseFrom = require('./options/rebase');
 | |
| var rebaseToFrom = require('./options/rebase-to');
 | |
| 
 | |
| var inputSourceMapTracker = require('./reader/input-source-map-tracker');
 | |
| var readSources = require('./reader/read-sources');
 | |
| 
 | |
| var serializeStyles = require('./writer/simple');
 | |
| var serializeStylesAndSourceMap = require('./writer/source-maps');
 | |
| 
 | |
| var CleanCSS = module.exports = function CleanCSS(options) {
 | |
|   options = options || {};
 | |
| 
 | |
|   this.options = {
 | |
|     batch: !!options.batch,
 | |
|     compatibility: compatibilityFrom(options.compatibility),
 | |
|     explicitRebaseTo: 'rebaseTo' in options,
 | |
|     fetch: fetchFrom(options.fetch),
 | |
|     format: formatFrom(options.format),
 | |
|     inline: inlineFrom(options.inline),
 | |
|     inlineRequest: inlineRequestFrom(options.inlineRequest),
 | |
|     inlineTimeout: inlineTimeoutFrom(options.inlineTimeout),
 | |
|     level: optimizationLevelFrom(options.level),
 | |
|     plugins: pluginsFrom(options.plugins),
 | |
|     rebase: rebaseFrom(options.rebase, options.rebaseTo),
 | |
|     rebaseTo: rebaseToFrom(options.rebaseTo),
 | |
|     returnPromise: !!options.returnPromise,
 | |
|     sourceMap: !!options.sourceMap,
 | |
|     sourceMapInlineSources: !!options.sourceMapInlineSources
 | |
|   };
 | |
| };
 | |
| 
 | |
| // for compatibility with optimize-css-assets-webpack-plugin
 | |
| CleanCSS.process = function(input, opts) {
 | |
|   var cleanCss;
 | |
|   var optsTo = opts.to;
 | |
| 
 | |
|   delete opts.to;
 | |
|   cleanCss = new CleanCSS(Object.assign({
 | |
|     returnPromise: true, rebaseTo: optsTo
 | |
|   }, opts));
 | |
| 
 | |
|   return cleanCss.minify(input)
 | |
|     .then(function(output) {
 | |
|       return { css: output.styles };
 | |
|     });
 | |
| };
 | |
| 
 | |
| CleanCSS.prototype.minify = function(input, maybeSourceMap, maybeCallback) {
 | |
|   var options = this.options;
 | |
| 
 | |
|   if (options.returnPromise) {
 | |
|     return new Promise(function(resolve, reject) {
 | |
|       minifyAll(input, options, maybeSourceMap, function(errors, output) {
 | |
|         return errors
 | |
|           ? reject(errors)
 | |
|           : resolve(output);
 | |
|       });
 | |
|     });
 | |
|   }
 | |
|   return minifyAll(input, options, maybeSourceMap, maybeCallback);
 | |
| };
 | |
| 
 | |
| function minifyAll(input, options, maybeSourceMap, maybeCallback) {
 | |
|   if (options.batch && Array.isArray(input)) {
 | |
|     return minifyInBatchesFromArray(input, options, maybeSourceMap, maybeCallback);
 | |
|   } if (options.batch && (typeof input == 'object')) {
 | |
|     return minifyInBatchesFromHash(input, options, maybeSourceMap, maybeCallback);
 | |
|   }
 | |
|   return minify(input, options, maybeSourceMap, maybeCallback);
 | |
| }
 | |
| 
 | |
| function minifyInBatchesFromArray(input, options, maybeSourceMap, maybeCallback) {
 | |
|   var callback = typeof maybeCallback == 'function'
 | |
|     ? maybeCallback
 | |
|     : (typeof maybeSourceMap == 'function' ? maybeSourceMap : null);
 | |
|   var errors = [];
 | |
|   var outputAsHash = {};
 | |
|   var inputValue;
 | |
|   var i, l;
 | |
| 
 | |
|   function whenHashBatchDone(innerErrors, output) {
 | |
|     outputAsHash = Object.assign(outputAsHash, output);
 | |
| 
 | |
|     if (innerErrors !== null) {
 | |
|       errors = errors.concat(innerErrors);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (i = 0, l = input.length; i < l; i++) {
 | |
|     if (typeof input[i] == 'object') {
 | |
|       minifyInBatchesFromHash(input[i], options, whenHashBatchDone);
 | |
|     } else {
 | |
|       inputValue = input[i];
 | |
| 
 | |
|       outputAsHash[inputValue] = minify([inputValue], options);
 | |
|       errors = errors.concat(outputAsHash[inputValue].errors);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return callback
 | |
|     ? callback(errors.length > 0 ? errors : null, outputAsHash)
 | |
|     : outputAsHash;
 | |
| }
 | |
| 
 | |
| function minifyInBatchesFromHash(input, options, maybeSourceMap, maybeCallback) {
 | |
|   var callback = typeof maybeCallback == 'function'
 | |
|     ? maybeCallback
 | |
|     : (typeof maybeSourceMap == 'function' ? maybeSourceMap : null);
 | |
|   var errors = [];
 | |
|   var outputAsHash = {};
 | |
|   var inputKey;
 | |
|   var inputValue;
 | |
| 
 | |
|   for (inputKey in input) {
 | |
|     inputValue = input[inputKey];
 | |
| 
 | |
|     outputAsHash[inputKey] = minify(inputValue.styles, options, inputValue.sourceMap);
 | |
|     errors = errors.concat(outputAsHash[inputKey].errors);
 | |
|   }
 | |
| 
 | |
|   return callback
 | |
|     ? callback(errors.length > 0 ? errors : null, outputAsHash)
 | |
|     : outputAsHash;
 | |
| }
 | |
| 
 | |
| function minify(input, options, maybeSourceMap, maybeCallback) {
 | |
|   var sourceMap = typeof maybeSourceMap != 'function'
 | |
|     ? maybeSourceMap
 | |
|     : null;
 | |
|   var callback = typeof maybeCallback == 'function'
 | |
|     ? maybeCallback
 | |
|     : (typeof maybeSourceMap == 'function' ? maybeSourceMap : null);
 | |
|   var context = {
 | |
|     stats: {
 | |
|       efficiency: 0,
 | |
|       minifiedSize: 0,
 | |
|       originalSize: 0,
 | |
|       startedAt: Date.now(),
 | |
|       timeSpent: 0
 | |
|     },
 | |
|     cache: { specificity: {} },
 | |
|     errors: [],
 | |
|     inlinedStylesheets: [],
 | |
|     inputSourceMapTracker: inputSourceMapTracker(),
 | |
|     localOnly: !callback,
 | |
|     options: options,
 | |
|     source: null,
 | |
|     sourcesContent: {},
 | |
|     validator: validator(options.compatibility),
 | |
|     warnings: []
 | |
|   };
 | |
|   var implicitRebaseToWarning;
 | |
| 
 | |
|   if (sourceMap) {
 | |
|     context.inputSourceMapTracker.track(undefined, sourceMap);
 | |
|   }
 | |
| 
 | |
|   if (options.rebase && !options.explicitRebaseTo) {
 | |
|     implicitRebaseToWarning = 'You have set `rebase: true` without giving `rebaseTo` option, which, in this case, defaults to the current working directory. '
 | |
|       + 'You are then warned this can lead to unexpected URL rebasing (aka here be dragons)! '
 | |
|       + 'If you are OK with the clean-css output, then you can get rid of this warning by giving clean-css a `rebaseTo: process.cwd()` option.';
 | |
|     context.warnings.push(implicitRebaseToWarning);
 | |
|   }
 | |
| 
 | |
|   return runner(context.localOnly)(function() {
 | |
|     return readSources(input, context, function(tokens) {
 | |
|       var serialize = context.options.sourceMap
 | |
|         ? serializeStylesAndSourceMap
 | |
|         : serializeStyles;
 | |
| 
 | |
|       var optimizedTokens = optimize(tokens, context);
 | |
|       var optimizedStyles = serialize(optimizedTokens, context);
 | |
|       var output = withMetadata(optimizedStyles, context);
 | |
| 
 | |
|       return callback
 | |
|         ? callback(context.errors.length > 0 ? context.errors : null, output)
 | |
|         : output;
 | |
|     });
 | |
|   });
 | |
| }
 | |
| 
 | |
| function runner(localOnly) {
 | |
|   // to always execute code asynchronously when a callback is given
 | |
|   // more at blog.izs.me/post/59142742143/designing-apis-for-asynchrony
 | |
|   return localOnly
 | |
|     ? function(callback) { return callback(); }
 | |
|     : process.nextTick;
 | |
| }
 | |
| 
 | |
| function optimize(tokens, context) {
 | |
|   var optimized = level0Optimize(tokens, context);
 | |
| 
 | |
|   optimized = OptimizationLevel.One in context.options.level
 | |
|     ? level1Optimize(tokens, context)
 | |
|     : tokens;
 | |
|   optimized = OptimizationLevel.Two in context.options.level
 | |
|     ? level2Optimize(tokens, context, true)
 | |
|     : optimized;
 | |
| 
 | |
|   return optimized;
 | |
| }
 | |
| 
 | |
| function withMetadata(output, context) {
 | |
|   output.stats = calculateStatsFrom(output.styles, context);
 | |
|   output.errors = context.errors;
 | |
|   output.inlinedStylesheets = context.inlinedStylesheets;
 | |
|   output.warnings = context.warnings;
 | |
| 
 | |
|   return output;
 | |
| }
 | |
| 
 | |
| function calculateStatsFrom(styles, context) {
 | |
|   var finishedAt = Date.now();
 | |
|   var timeSpent = finishedAt - context.stats.startedAt;
 | |
| 
 | |
|   delete context.stats.startedAt;
 | |
|   context.stats.timeSpent = timeSpent;
 | |
|   context.stats.efficiency = 1 - styles.length / context.stats.originalSize;
 | |
|   context.stats.minifiedSize = styles.length;
 | |
| 
 | |
|   return context.stats;
 | |
| }
 |