* Fixed issue [#159](https://github.com/GoalSmashers/clean-css/issues/159) - escaped quotes inside content.
* Fixed issue [#162](https://github.com/GoalSmashers/clean-css/issues/162) - strip quotes from base64 encoded URLs.
* Adds CSS tokenizer which will make it possible to optimize content by reordering and/or merging selectors.
+* Adds basic optimizer removing duplicate selectors from a list.
1.1.7 / 2013-10-28
==================
var FreeTextProcessor = require('./text/free');
var UrlsProcessor = require('./text/urls');
-var SelectorsTokenizer = require('./selectors/tokenizer');
+var SelectorsOptimizer = require('./selectors/optimizer');
var CleanCSS = {
process: function(data, options) {
});
replace(function optimizeSelectors() {
- data = new SelectorsTokenizer(data).process();
+ data = new SelectorsOptimizer(data).process();
});
replace(function restoreUrls() {
--- /dev/null
+var Tokenizer = require('./tokenizer');
+
+module.exports = function Optimizer(data) {
+ var stripRepeats = function(selectors) {
+ var plain = [];
+ selectors = selectors.split(',');
+
+ for (var i = 0, l = selectors.length; i < l; i++) {
+ var sel = selectors[i];
+
+ if (plain.indexOf(sel) == -1)
+ plain.push(sel);
+ }
+
+ return plain.join(',');
+ };
+
+ var optimize = function(tokens) {
+ tokens = (Array.isArray(tokens) ? tokens : [tokens]);
+ for (var i = 0, l = tokens.length; i < l; i++) {
+ var token = tokens[i];
+
+ if (token.selector)
+ token.selector = stripRepeats(token.selector);
+ if (token.block)
+ optimize(token.body);
+ }
+ };
+
+ var rebuild = function(tokens) {
+ return (Array.isArray(tokens) ? tokens : [tokens])
+ .map(function(token) {
+ if (typeof token == 'string')
+ return token;
+
+ if (token.block)
+ return token.block + '{' + rebuild(token.body) + '}';
+ else
+ return token.selector + '{' + token.body + '}';
+ })
+ .join('');
+ };
+
+ return {
+ process: function() {
+ var tokenized = new Tokenizer(data).process();
+ optimize(tokenized);
+ return rebuild(tokenized);
+ }
+ };
+};
return tokenized;
};
- var rebuild = function(tokens) {
- return (Array.isArray(tokens) ? tokens : [tokens])
- .map(function(token) {
- if (typeof token == 'string')
- return token;
-
- if (token.block)
- return token.block + '{' + rebuild(token.body) + '}';
- else
- return token.selector + '{' + token.body + '}';
- })
- .join('');
- };
-
return {
process: function() {
- return rebuild(tokenize());
+ return tokenize();
}
};
};
"@import url(/fake.css);",
"@import url(/fake.css);"
]
- }, { processImport: false })
+ }, { processImport: false }),
+ 'duplicate selectors in a list': cssContext({
+ 'of a duplicate selector': [
+ 'a,a{color:red}',
+ 'a{color:red}'
+ ],
+ 'of an unordered multiply repeated selector': [
+ 'a,b,p,a{color:red}',
+ 'a,b,p{color:red}'
+ ],
+ 'of an unordered multiply repeated selector within a block': [
+ '@media screen{a,b,p,a{color:red}}',
+ '@media screen{a,b,p{color:red}}'
+ ],
+ 'of an unordered multiply repeated complex selector within a block #1': [
+ '@media screen{a,.link[data-path],p,.link[data-path]{color:red}}',
+ '@media screen{a,.link[data-path],p{color:red}}'
+ ],
+ 'of an unordered multiply repeated complex selector within a block #2': [
+ '@media screen{a,#foo[data-path^="bar bar"],p,#foo[data-path^="bar bar"]{color:red}}',
+ '@media screen{a,#foo[data-path^="bar bar"],p{color:red}}'
+ ]
+ })
}).export(module);