==================
* Fixed issue [#781](https://github.com/jakubpawlowicz/clean-css/issues/781) - regression in override compacting.
+* Fixed issue [#782](https://github.com/jakubpawlowicz/clean-css/issues/782) - regression in processing data URIs.
[3.4.15 / 2016-06-01](https://github.com/jakubpawlowicz/clean-css/compare/v3.4.14...v3.4.15)
==================
+var split = require('../utils/split');
+
var URL_PREFIX = 'url(';
var UPPERCASE_URL_PREFIX = 'URL(';
var URL_SUFFIX = ')';
var DATA_URI_PREFIX_PATTERN = /^\s*['"]?\s*data:/;
-var DATA_URI_END_FUZZY_PATTERN = /^\)[\s\{\};]/;
+var DATA_URI_TRAILER_PATTERN = /[\s\};,\/]/;
var IMPORT_URL_PREFIX = '@import';
var UPPERCASE_IMPORT_URL_PREFIX = '@IMPORT';
var nextStart = 0;
var nextStartUpperCase = 0;
var nextEnd = 0;
- var nextEndAhead = 0;
+ var firstMatch;
var isDataURI = false;
var cursor = 0;
var tempData = [];
isDataURI = DATA_URI_PREFIX_PATTERN.test(data.substring(nextStart + URL_PREFIX.length));
if (isDataURI) {
- nextEnd = data.indexOf(URL_SUFFIX, nextStart);
-
- // this is a fuzzy matching logic for unqoted data URIs
- while (true) {
- nextEndAhead = data.indexOf(URL_SUFFIX, nextEnd + 1);
- // if it has whitespace, curly braces, or semicolon then we should be out of URL,
- // otherwise keep iterating if it has not but content is not escaped,
- // it has to be quoted so it will be captured by either of two clauses above
- if (nextEndAhead == -1 || DATA_URI_END_FUZZY_PATTERN.test(data.substring(nextEnd, nextEndAhead)))
- break;
-
- nextEnd = nextEndAhead;
+ firstMatch = split(data.substring(nextStart), DATA_URI_TRAILER_PATTERN, false, '(', ')', true).pop();
+
+ if (firstMatch && firstMatch[firstMatch.length - 1] == URL_SUFFIX) {
+ nextEnd = nextStart + firstMatch.length - URL_SUFFIX.length;
+ } else {
+ nextEnd = -1;
}
} else {
if (data[nextStart + URL_PREFIX.length] == '"') {
-function split(value, separator, includeSeparator, openLevel, closeLevel) {
+function split(value, separator, includeSeparator, openLevel, closeLevel, firstOnly) {
var withRegex = typeof separator != 'string';
var hasSeparator = withRegex ?
separator.test(value) :
openLevel = openLevel || '(';
closeLevel = closeLevel || ')';
- if (value.indexOf(openLevel) == -1 && !includeSeparator)
+ if (value.indexOf(openLevel) == -1 && !includeSeparator && !firstOnly)
return value.split(separator);
var level = 0;
if (level === 0 && cursor > 0 && cursor + 1 < len && (withRegex ? separator.test(value[cursor]) : value[cursor] == separator)) {
tokens.push(value.substring(lastStart, cursor + (includeSeparator ? 1 : 0)));
lastStart = cursor + 1;
+
+ if (firstOnly && tokens.length == 1) {
+ break;
+ }
}
cursor++;
'a{background:__ESCAPED_URL_CLEAN_CSS0__}div:not([test]){color:red}',
'a{background:url(url)}div:not([test]){color:red}'
],
- 'data URI with single brackets': [
+ 'data URI wrapped in single quotes': [
'a{background-image:url(\'data:image/svg+xml;charset=utf-8,<svg viewBox=\'0 0 120 120\'><g transform=\'rotate(30 60,60)\'></g></svg>\')}',
'a{background-image:__ESCAPED_URL_CLEAN_CSS0__}',
'a{background-image:url(\'data:image/svg+xml;charset=utf-8,<svg viewBox=\'0 0 120 120\'><g transform=\'rotate(30 60,60)\'></g></svg>\')}'
],
- 'data URI with double brackets': [
+ 'data URI wrapped in double quotes': [
'a{background-image:url("data:image/svg+xml;charset=utf-8,<svg viewBox=\'0 0 120 120\'><g transform=\'rotate(30 60,60)\'></g></svg>")}',
'a{background-image:__ESCAPED_URL_CLEAN_CSS0__}',
'a{background-image:url("data:image/svg+xml;charset=utf-8,<svg viewBox=\'0 0 120 120\'><g transform=\'rotate(30 60,60)\'></g></svg>")}'
+ ],
+ 'two quoted data URIs with closing brackets': [
+ '.a{cursor:url("data:application/octet-stream;base64,A...rotate(30 60,60)...="),move!important}.b{cursor:url("data:application/octet-stream;base64,A...rotate(30 60,60)...=")}',
+ '.a{cursor:__ESCAPED_URL_CLEAN_CSS0__,move!important}.b{cursor:__ESCAPED_URL_CLEAN_CSS0__}',
+ '.a{cursor:url("data:application/octet-stream;base64,A...rotate(30 60,60)...="),move!important}.b{cursor:url("data:application/octet-stream;base64,A...rotate(30 60,60)...=")}',
]
})
)
}
}
})
+ .addBatch({
+ 'just first one': {
+ topic: 'linear-gradient(0, #fff, rgba(0, 0, 0)) red',
+ split: function (input) {
+ assert.deepEqual(split(input, ' ', false, '(', ')', true), ['linear-gradient(0, #fff, rgba(0, 0, 0))']);
+ }
+ },
+ 'just first one when no opening token': {
+ topic: 'red blue',
+ split: function (input) {
+ assert.deepEqual(split(input, ' ', false, '(', ')', true), ['red']);
+ }
+ },
+ 'just first one when no closing token in last token': {
+ topic: 'red linear-gradient(0 0',
+ split: function (input) {
+ assert.deepEqual(split(input, ' ', false, '(', ')', true), ['red']);
+ }
+ }
+ })
.export(module);