var ImportInliner = require('./imports/inliner');
var rebaseUrls = require('./urls/rebase');
-var SelectorsOptimizer = require('./selectors/optimizer');
+
+var tokenize = require('./tokenizer/tokenize');
+var SimpleOptimizer = require('./selectors/simple');
+var AdvancedOptimizer = require('./selectors/advanced');
+var addOptimizationMetadata = require('./selectors/optimization-metadata');
var simpleStringify = require('./stringifier/simple');
var sourceMapStringify = require('./stringifier/source-maps');
function minify(context, data) {
var options = context.options;
- var sourceMapTracker = context.inputSourceMapTracker;
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 selectorsOptimizer = new SelectorsOptimizer(options, context);
var stringify = options.sourceMap ? sourceMapStringify : simpleStringify;
var run = function (processor, action) {
run(urlsProcessor, 'escape');
run(freeTextProcessor, 'escape');
- run(function () {
- return selectorsOptimizer.process(data, stringify, function (data) {
- data = freeTextProcessor.restore(data);
- data = urlsProcessor.restore(data);
- data = options.rebase ? rebaseUrls(data, context) : data;
- data = expressionsProcessor.restore(data);
- return commentsProcessor.restore(data);
- }, sourceMapTracker);
- });
+ function restoreEscapes(data) {
+ data = freeTextProcessor.restore(data);
+ data = urlsProcessor.restore(data);
+ data = options.rebase ? rebaseUrls(data, context) : data;
+ data = expressionsProcessor.restore(data);
+ return commentsProcessor.restore(data);
+ }
+
+ var tokens = tokenize(data, context);
- return data;
+ addOptimizationMetadata(tokens);
+
+ new SimpleOptimizer(options).optimize(tokens);
+
+ if (options.advanced)
+ new AdvancedOptimizer(options, context).optimize(tokens);
+
+ return stringify(tokens, options, restoreEscapes, context.inputSourceMapTracker);
}
-var optimizeProperties = require('../../properties/optimizer');
+var optimizeProperties = require('../properties/optimizer');
var CleanUp = require('./clean-up');
-var extractProperties = require('../extractor');
-var canReorder = require('../reorderable').canReorder;
-var canReorderSingle = require('../reorderable').canReorderSingle;
-var stringifyAll = require('../../stringifier/one-time').all;
-var stringifyBody = require('../../stringifier/one-time').body;
-var stringifySelectors = require('../../stringifier/one-time').selectors;
+var extractProperties = require('./extractor');
+var canReorder = require('./reorderable').canReorder;
+var canReorderSingle = require('./reorderable').canReorderSingle;
+var stringifyAll = require('../stringifier/one-time').all;
+var stringifyBody = require('../stringifier/one-time').body;
+var stringifySelectors = require('../stringifier/one-time').selectors;
function AdvancedOptimizer(options, context) {
this.options = options;
+++ /dev/null
-var tokenize = require('../tokenizer/tokenize');
-var SimpleOptimizer = require('./optimizers/simple');
-var AdvancedOptimizer = require('./optimizers/advanced');
-var addOptimizationMetadata = require('./optimization-metadata');
-
-function SelectorsOptimizer(options, context) {
- this.options = options || {};
- this.context = context || {};
-}
-
-SelectorsOptimizer.prototype.process = function (data, stringify, restoreCallback, sourceMapTracker) {
- var tokens = tokenize(data, this.context);
-
- addOptimizationMetadata(tokens);
-
- new SimpleOptimizer(this.options).optimize(tokens);
- if (this.options.advanced)
- new AdvancedOptimizer(this.options, this.context).optimize(tokens);
-
- return stringify(tokens, this.options, restoreCallback, sourceMapTracker);
-};
-
-module.exports = SelectorsOptimizer;
var CleanUp = require('./clean-up');
-var Splitter = require('../../utils/splitter');
+var Splitter = require('../utils/splitter');
-var RGB = require('../../colors/rgb');
-var HSL = require('../../colors/hsl');
-var HexNameShortener = require('../../colors/hex-name-shortener');
+var RGB = require('../colors/rgb');
+var HSL = require('../colors/hsl');
+var HexNameShortener = require('../colors/hex-name-shortener');
var DEFAULT_ROUNDING_PRECISION = 2;
var CHARSET_TOKEN = '@charset';
var vows = require('vows');
var assert = require('assert');
-var SelectorsOptimizer = require('../../lib/selectors/optimizer');
-var stringify = require('../../lib/stringifier/simple');
-var Compatibility = require('../../lib/utils/compatibility');
-var Validator = require('../../lib/properties/validator');
-var SourceTracker = require('../../lib/utils/source-tracker');
+var CleanCSS = require('../../lib/clean');
function optimizerContext(group, specs, options) {
- function restoreCallback(data) {
- return data;
- }
-
var context = {};
options = options || {};
options.shorthandCompacting = true;
options.restructuring = true;
- options.compatibility = new Compatibility(options.compatibility).toOptions();
- var outerContext = {
- options: {},
- sourceTracker: new SourceTracker(),
- validator: new Validator(options.compatibility)
- };
function optimized(target) {
return function (source) {
- assert.equal(new SelectorsOptimizer(options, outerContext).process(source, stringify, restoreCallback).styles, target);
+ assert.equal(new CleanCSS(options).minify(source).styles, target);
};
}
return context;
}
-vows.describe(SelectorsOptimizer)
- .addBatch(
- optimizerContext('selectors', {
- 'whitespace - heading & trailing': [
- ' a {color:red}',
- 'a{color:red}'
- ],
- 'whitespace - descendant selector': [
- 'div > a{color:red}',
- 'div>a{color:red}'
- ],
- 'whitespace - next selector': [
- 'div + a{color:red}',
- 'div+a{color:red}'
- ],
- 'whitespace - sibling selector': [
- 'div ~ a{color:red}',
- 'div~a{color:red}'
- ],
- 'whitespace - pseudo classes': [
- 'div :first-child{color:red}',
- 'div :first-child{color:red}'
- ],
- 'whitespace - line breaks': [
- '\r\ndiv\n{color:red}',
- 'div{color:red}'
- ],
- 'whitespace - tabs': [
- 'div\t\t{color:red}',
- 'div{color:red}'
- ],
- 'universal selector - id, class, and property': [
- '* > *#id > *.class > *[property]{color:red}',
- '*>#id>.class>[property]{color:red}'
- ],
- 'universal selector - pseudo': [
- '*:first-child{color:red}',
- ':first-child{color:red}'
- ],
- 'universal selector - standalone': [
- 'label ~ * + span{color:red}',
- 'label~*+span{color:red}'
- ],
- 'order': [
- 'b,div,a{color:red}',
- 'a,b,div{color:red}'
- ],
- 'duplicates': [
- 'a,div,.class,.class,a ,div > a{color:red}',
- '.class,a,div,div>a{color:red}'
- ],
- 'mixed': [
- ' label ~ \n* + span , div>*.class, section\n\n{color:red}',
- 'div>.class,label~*+span,section{color:red}'
- ],
- 'calc': [
- 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}',
- 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}'
- ]
- })
- )
+vows.describe('advanced optimizer')
.addBatch(
optimizerContext('selectors - restructuring', {
'up until changed': [
'@-moz-keyframes test{0%{transform:scale3d(1,1,1);opacity:1}100%{transform:scale3d(.5,.5,.5);opacity:1}}'
],
'with one important comment': [
- '__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0__a{width:100px}div{color:red}.one{display:block}.two{display:inline;color:red}',
- '__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0__.two,div{color:red}a{width:100px}.one{display:block}.two{display:inline}'
+ '/*! comment */a{width:100px}div{color:red}.one{display:block}.two{display:inline;color:red}',
+ '/*! comment */.two,div{color:red}a{width:100px}.one{display:block}.two{display:inline}'
],
'with many important comments': [
- '__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0____ESCAPED_COMMENT_SPECIAL_CLEAN_CSS1__a{width:100px}div{color:red}.one{display:block}.two{display:inline;color:red}',
- '__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0____ESCAPED_COMMENT_SPECIAL_CLEAN_CSS1__.two,div{color:red}a{width:100px}.one{display:block}.two{display:inline}'
+ '/*! comment 1 *//*! comment 2 */a{width:100px}div{color:red}.one{display:block}.two{display:inline;color:red}',
+ '/*! comment 1 *//*! comment 2 */.two,div{color:red}a{width:100px}.one{display:block}.two{display:inline}'
],
'with important comment and charset': [
- '@charset "utf-8";__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0__a{width:100px}div{color:red}.one{display:block}.two{display:inline;color:red}',
- '@charset "utf-8";__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0__.two,div{color:red}a{width:100px}.one{display:block}.two{display:inline}'
+ '@charset "utf-8";/*! comment */a{width:100px}div{color:red}.one{display:block}.two{display:inline;color:red}',
+ '@charset "utf-8";/*! comment */.two,div{color:red}a{width:100px}.one{display:block}.two{display:inline}'
],
'with charset and import': [
'@charset "UTF-8";@import url(http://fonts.googleapis.com/css?family=Lora:400,700);a{width:100px}div{color:red}.one{display:block}.two{display:inline;color:red}',
'@charset "UTF-8";@import url(http://fonts.googleapis.com/css?family=Lora:400,700);.two,div{color:red}a{width:100px}.one{display:block}.two{display:inline}'
],
'with charset and import and comments': [
- '@charset "UTF-8";@import url(http://fonts.googleapis.com/css?family=Lora:400,700);__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0__a{width:100px}div{color:red}.one{display:block}.two{display:inline;color:red}',
- '@charset "UTF-8";@import url(http://fonts.googleapis.com/css?family=Lora:400,700);__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0__.two,div{color:red}a{width:100px}.one{display:block}.two{display:inline}'
+ '@charset "UTF-8";@import url(http://fonts.googleapis.com/css?family=Lora:400,700);/*! comment */a{width:100px}div{color:red}.one{display:block}.two{display:inline;color:red}',
+ '@charset "UTF-8";@import url(http://fonts.googleapis.com/css?family=Lora:400,700);/*! comment */.two,div{color:red}a{width:100px}.one{display:block}.two{display:inline}'
],
'with vendor prefixed value group': [
'a{-moz-box-sizing:content-box;box-sizing:content-box}div{color:red}p{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}',
]
}, { advanced: true, semanticMerging: true })
)
- .addBatch(
- optimizerContext('properties', {
- 'empty body': [
- 'a{}',
- ''
- ],
- 'whitespace body': [
- 'a{ \n }',
- ''
- ],
- 'whitespace after calc()': [
- 'div{margin:calc(100% - 20px) 1px}',
- 'div{margin:calc(100% - 20px) 1px}'
- ]
- })
- )
.addBatch(
optimizerContext('@media', {
'empty': [
]
}, { advanced: false })
)
- .addBatch(
- optimizerContext('@charset', {
- 'multiple': [
- '@charset \'utf-8\';a{color:red}@charset \'utf-8\';',
- '@charset \'utf-8\';a{color:red}'
- ],
- 'not at beginning': [
- 'a{color:red}@charset \'utf-8\';',
- '@charset \'utf-8\';a{color:red}'
- ],
- 'different case': [
- 'a{color:red}@ChArSeT \'utf-8\';',
- 'a{color:red}'
- ]
- })
- )
.addBatch(
optimizerContext('@font-face', {
'rebuilding': [
var vows = require('vows');
var assert = require('assert');
-var tokenize = require('../../../lib/tokenizer/tokenize');
-var SimpleOptimizer = require('../../../lib/selectors/optimizers/simple');
-var Compatibility = require('../../../lib/utils/compatibility');
-var addOptimizationMetadata = require('../../../lib/selectors/optimization-metadata');
+var tokenize = require('../../lib/tokenizer/tokenize');
+var SimpleOptimizer = require('../../lib/selectors/simple');
+var Compatibility = require('../../lib/utils/compatibility');
+var addOptimizationMetadata = require('../../lib/selectors/optimization-metadata');
function selectorContext(group, specs, options) {
var context = {};
' div >\n\r\n span{color:red}',
[['div>span']]
],
+ 'more line breaks': [
+ '\r\ndiv\n{color:red}',
+ [['div']]
+ ],
'+html': [
'*+html .foo{display:inline}',
null
'adjacent nav': [
'div + nav{color:red}',
[['div+nav']]
+ ],
+ 'heading & trailing': [
+ ' a {color:red}',
+ [['a']]
+ ],
+ 'descendant selector': [
+ 'div > a{color:red}',
+ [['div>a']]
+ ],
+ 'next selector': [
+ 'div + a{color:red}',
+ [['div+a']]
+ ],
+ 'sibling selector': [
+ 'div ~ a{color:red}',
+ [['div~a']]
+ ],
+ 'pseudo classes': [
+ 'div :first-child{color:red}',
+ [['div :first-child']]
+ ],
+ 'tabs': [
+ 'div\t\t{color:red}',
+ [['div']]
+ ],
+ 'universal selector - id, class, and property': [
+ '* > *#id > *.class > *[property]{color:red}',
+ [['*>#id>.class>[property]']]
+ ],
+ 'universal selector - pseudo': [
+ '*:first-child{color:red}',
+ [[':first-child']]
+ ],
+ 'universal selector - standalone': [
+ 'label ~ * + span{color:red}',
+ [['label~*+span']]
+ ],
+ 'order': [
+ 'b,div,a{color:red}',
+ [['a'], ['b'], ['div']]
+ ],
+ 'duplicates': [
+ 'a,div,.class,.class,a ,div > a{color:red}',
+ [['.class'], ['a'], ['div'], ['div>a']]
+ ],
+ 'mixed': [
+ ' label ~ \n* + span , div>*.class, section\n\n{color:red}',
+ [['div>.class'], ['label~*+span'], ['section']]
]
})
)
'stripped spaces': [
'div{text-shadow:rgba(255,1,1,.5) 1px}',
[['text-shadow', 'rgba(255,1,1,.5)', '1px']]
+ ],
+ 'calc': [
+ 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}',
+ [['width', '-moz-calc(100% - 1em)'], ['width', 'calc(100% - 1em)']]
+ ],
+ 'empty body': [
+ 'a{}',
+ null
+ ],
+ 'in a body': [
+ 'a{ \n }',
+ null
+ ],
+ 'after calc()': [
+ 'div{margin:calc(100% - 20px) 1px}',
+ [['margin', 'calc(100% - 20px)', '1px']]
]
})
)