* Fixed issue [#360](https://github.com/GoalSmashers/clean-css/issues/360) - adds 7 extra CSS colors.
* Fixed issue [#363](https://github.com/GoalSmashers/clean-css/issues/363) - `rem` units overriding `px`.
+[2.2.19 / 2014-11-20](https://github.com/jakubpawlowicz/clean-css/compare/v2.2.18...v2.2.19)
+==================
+
+* Fixed issue [#385](https://github.com/GoalSmashers/clean-css/issues/385) - edge cases in processing cut off data.
+
[2.2.18 / 2014-11-17](https://github.com/jakubpawlowicz/clean-css/compare/v2.2.17...v2.2.18)
==================
var options = this.options;
var context = this.context;
- var commentsProcessor = new CommentsProcessor(options.keepSpecialComments, options.keepBreaks);
+ var commentsProcessor = new CommentsProcessor(context, options.keepSpecialComments, options.keepBreaks);
var expressionsProcessor = new ExpressionsProcessor();
var freeTextProcessor = new FreeTextProcessor();
- var urlsProcessor = new UrlsProcessor();
+ var urlsProcessor = new UrlsProcessor(context);
var urlRebase = new UrlRebase(options, context);
var selectorsOptimizer = new SelectorsOptimizer(options, context);
var firstOpenBraceAt = chunk.indexOf('{', nextSpecial);
var firstSemicolonAt = chunk.indexOf(';', nextSpecial);
var isSingle = firstSemicolonAt > -1 && (firstOpenBraceAt == -1 || firstSemicolonAt < firstOpenBraceAt);
- if (isSingle) {
+ var isBroken = firstOpenBraceAt == -1 && firstSemicolonAt == -1;
+ if (isBroken) {
+ context.outer.warnings.push('Broken declaration: \'' + chunk.substring(context.cursor) + '\'.');
+ context.cursor = chunk.length;
+ } else if (isSingle) {
nextEnd = chunk.indexOf(';', nextSpecial + 1);
var single = extractBlock(chunk.substring(context.cursor, nextEnd + 1));
var lineBreak = require('os').EOL;
-var CommentsProcessor = function CommentsProcessor(keepSpecialComments, keepBreaks) {
+var CommentsProcessor = function CommentsProcessor(context, keepSpecialComments, keepBreaks) {
this.comments = new EscapeStore('COMMENT');
+ this.context = context;
this.keepAll = keepSpecialComments == '*';
this.keepOne = keepSpecialComments == '1' || keepSpecialComments === 1;
this.keepBreaks = keepBreaks;
}
nextEnd = data.indexOf(COMMENT_SUFFIX, nextStart + COMMENT_PREFIX.length);
- if (nextEnd == -1)
- break;
+ if (nextEnd == -1) {
+ this.context.warnings.push('Broken comment: \'' + data.substring(nextStart) + '\'.');
+ nextEnd = data.length - 2;
+ }
tempData.push(data.substring(cursor, nextStart));
var EscapeStore = require('./escape-store');
-var UrlsProcessor = function UrlsProcessor() {
+var UrlsProcessor = function UrlsProcessor(context) {
this.urls = new EscapeStore('URL');
+ this.context = context;
};
// Strip urls by replacing them by a special
break;
nextEnd = data.indexOf(')', nextStart);
+ // Following lines are a safety mechanism to ensure
+ // incorrectly terminated urls are processed correctly.
+ if (nextEnd == -1) {
+ nextEnd = data.indexOf('}', nextStart);
+
+ if (nextEnd == -1)
+ nextEnd = data.length;
+ else
+ nextEnd--;
+
+ this.context.warnings.push('Broken URL declaration: \'' + data.substring(nextStart, nextEnd + 1) + '\'.');
+ }
var url = data.substring(nextStart, nextEnd + 1);
var placeholder = this.urls.store(url);
'.icon-logo{background-image:url("data:image/x-icon;base64,AAABAAEAEBA")}',
'.icon-logo{background-image:url(data:image/x-icon;base64,AAABAAEAEBA)}'
],
+ 'cut off url content on selector level': 'a{background:url(image/}',
+ 'cut off url content on block level': [
+ '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA}',
+ '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA}'
+ ],
+ 'cut off url content on top level': [
+ '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA',
+ '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA}'
+ ],
'strip single parentheses': [
"a{background:url('/images/blank.png')}",
"a{background:url(/images/blank.png)}"
"@import url(test/data/partials/five.css);",
".five{background:url(data:image/jpeg;base64,/9j/)}"
],
+ 'cut off': [
+ '@impo',
+ ''
+ ],
+ 'cut off inside a comment': [
+ '/* @impo',
+ ''
+ ],
'inside a comment': [
'/* @import url(test/data/partials/five.css); */a { color: red; }',
'a{color:red}'
assert.equal(minifier.warnings[0], 'Empty property \'color\' inside \'a\' selector. Ignoring.');
}
},
+ 'warnings on broken urls': {
+ topic: function () {
+ var minifier = new CleanCSS();
+ var minified = minifier.minify('a{background:url(image/}');
+ this.callback(null, minified, minifier);
+ },
+ 'should output correct content': function(error, minified) {
+ assert.equal(minified, 'a{background:url(image/}');
+ },
+ 'should raise no errors': function(error, minified, minifier) {
+ assert.equal(minifier.errors.length, 0);
+ },
+ 'should raise one warning': function(error, minified, minifier) {
+ assert.equal(minifier.warnings.length, 1);
+ assert.equal(minifier.warnings[0], 'Broken URL declaration: \'url(image/\'.');
+ }
+ },
+ 'warnings on broken imports': {
+ topic: function () {
+ var minifier = new CleanCSS();
+ var minified = minifier.minify('@impor');
+ this.callback(null, minified, minifier);
+ },
+ 'should output correct content': function(error, minified) {
+ assert.equal(minified, '');
+ },
+ 'should raise no errors': function(error, minified, minifier) {
+ assert.equal(minifier.errors.length, 0);
+ },
+ 'should raise one warning': function(error, minified, minifier) {
+ assert.equal(minifier.warnings.length, 1);
+ assert.equal(minifier.warnings[0], 'Broken declaration: \'@impor\'.');
+ }
+ },
+ 'warnings on broken comments': {
+ topic: function () {
+ var minifier = new CleanCSS();
+ var minified = minifier.minify('a{}/* ');
+ this.callback(null, minified, minifier);
+ },
+ 'should output correct content': function(error, minified) {
+ assert.equal(minified, '');
+ },
+ 'should raise no errors': function(error, minified, minifier) {
+ assert.equal(minifier.errors.length, 0);
+ },
+ 'should raise one warning': function(error, minified, minifier) {
+ assert.equal(minifier.warnings.length, 1);
+ assert.equal(minifier.warnings[0], 'Broken comment: \'/* \'.');
+ }
+ },
'no errors': {
topic: function() {
var minifier = new CleanCSS();
function restored (targetCSS) {
return function (sourceCSS) {
- var processor = new CommentsProcessor(keepSpecialComments, keepBreaks);
+ var processor = new CommentsProcessor(null, keepSpecialComments, keepBreaks);
var result = processor.restore(processor.escape(sourceCSS));
assert.equal(result, targetCSS);
};