* Adds unit compatibility switches to disable length optimizations.
* Adds inferring proxy settings from HTTP_PROXY environment variable.
* Adds support for Polymer / Web Components special selectors.
+* Adds support for Polymer mixins.
* Unifies wrappers for simple & advanced optimizations.
* Fixed issue [#596](https://github.com/jakubpawlowicz/clean-css/issues/596) - support for !ie IE<8 hack.
* Fixed issue [#599](https://github.com/jakubpawlowicz/clean-css/issues/599) - support for inlined source maps.
populateComponents(_properties, validator);
_optimize(_properties, mergeAdjacent, options.aggressiveMerging, validator);
+ for (var i = 0, l = _properties.length; i < l; i++) {
+ var _property = _properties[i];
+ if (_property.variable && _property.block)
+ optimize(selector, _property.value[0], mergeAdjacent, withCompacting, options, validator);
+ }
+
if (withCompacting && options.shorthandCompacting) {
compactOverrides(_properties, options.compatibility, validator);
compactShorthands(_properties, options.sourceMap, validator);
if (!isCompactable(right))
continue;
+ if (right.variable)
+ continue;
+
mayOverride = compactable[right.name].canOverride || canOverride.sameValue;
for (j = i - 1; j >= 0; j--) {
if (!isCompactable(left))
continue;
+ if (left.variable)
+ continue;
+
if (left.unused || right.unused)
continue;
if (property.hack)
continue;
+ if (property.variable)
+ continue;
+
var descriptor = compactable[property.name];
if (!descriptor || !descriptor.componentOf)
continue;
else if (_hackType == 'backslash' || _hackType == 'bang')
stripSuffixHack(property, _hackType);
+ var isVariable = property[0][0].indexOf('--') === 0;
+
return {
+ block: isVariable && property[1] && Array.isArray(property[1][0][0]),
components: [],
dirty: false,
hack: _hackType,
position: 0,
shorthand: false,
unused: property.length < 2,
- value: property.slice(1)
+ value: property.slice(1),
+ variable: isVariable
};
}
if (name.length === 0)
continue;
+ if (name.indexOf('--') === 0)
+ continue;
+
var value = stringifyValue(token[2], i);
properties.push([
if (property.unused)
continue;
+ if (property.variable) {
+ if (property.block)
+ optimizeBody(property.value[0], options);
+ continue;
+ }
+
for (var j = 0, m = property.value.length; j < m; j++) {
value = property.value[j][0];
function value(tokens, position, isLast, context) {
var store = context.store;
var token = tokens[position];
+ var isVariableDeclaration = token[0][0].indexOf('--') === 0;
+
+ if (isVariableDeclaration && Array.isArray(token[1][0][0])) {
+ store('{', context);
+ body(token[1], context);
+ store('};', context);
+ return;
+ }
for (var j = 1, m = token.length; j < m; j++) {
store(token[j], context);
if (string.indexOf('ESCAPED_URL_CLEAN_CSS') > -1)
string = string.replace(/(ESCAPED_URL_CLEAN_CSS[^_]+?__)/g, context.sourceMap ? '$1 __ESCAPED_COMMENT_CLEAN_CSS(0,-1)__ ' : '$1 ');
- var candidates = string.split(';');
+ var candidates = split(string, ';', false, '{', '}');
for (var i = 0, l = candidates.length; i < l; i++) {
var candidate = candidates[i];
continue;
}
- if (candidate.indexOf('{') > 0) {
+ if (candidate.indexOf('{') > 0 && candidate.indexOf('{') < firstColonAt) {
context.track(candidate);
continue;
}
trackComments(innerComments, list, context);
+ var firstBraceAt = candidate.indexOf('{');
+ var isVariable = name.trim().indexOf('--') === 0;
+ if (isVariable && firstBraceAt > 0) {
+ var blockPrefix = candidate.substring(firstColonAt + 1, firstBraceAt + 1);
+ var blockSuffix = candidate.substring(candidate.indexOf('}'));
+ var blockContent = candidate.substring(firstBraceAt + 1, candidate.length - blockSuffix.length);
+
+ context.track(blockPrefix);
+ body.push(extractProperties(blockContent, selectors, context));
+ list.push(body);
+ context.track(blockSuffix);
+ context.track(i < l - 1 ? ';' : '');
+
+ continue;
+ }
+
var values = split(candidate.substring(firstColonAt + 1), valueSeparator, true);
if (values.length == 1 && values[0] === '') {
var extractProperties = require('./extract-properties');
var extractSelectors = require('./extract-selectors');
var track = require('../source-maps/track');
+var split = require('../utils/split');
var path = require('path');
}
if (mode == 'body') {
- closest = chunk.indexOf('}', context.cursor);
- return closest > -1 ?
- [closest, 'bodyEnd'] :
- null;
+ if (chunk[context.cursor] == '}')
+ return [context.cursor, 'bodyEnd'];
+
+ if (chunk.indexOf('}', context.cursor) == -1)
+ return null;
+
+ closest = context.cursor + split(chunk.substring(context.cursor - 1), '}', true, '{', '}')[0].length - 2;
+ return [closest, 'bodyEnd'];
}
var nextSpecial = chunk.indexOf('@', context.cursor);
)
.addBatch(
optimizerContext('IE 7 hacks', {
- 'keeps !ie hack 123': [
+ 'keeps !ie hack': [
'a{list-style-type:none;list-style-type:decimal !ie}',
'a{list-style-type:none;list-style-type:decimal !ie}'
]
'all values': [
'a{--width:1px;--style:solid;--color:#000}.one{border:var(--width)var(--style)var(--color)}',
'a{--width:1px;--style:solid;--color:#000}.one{border:var(--width)var(--style)var(--color)}'
+ ],
+ 'Polymer mixins - simple optimizations': [
+ 'a{ display:block; --my-toolbar: { color:#f00; width:96px }; color:blue}',
+ 'a{display:block;--my-toolbar:{color:red;width:1in};color:#00f}'
+ ],
+ 'Polymer mixins - override optimizations': [
+ 'a{--my-toolbar: { margin:15px!important; margin:10px};}',
+ 'a{--my-toolbar:{margin:15px!important};}'
+ ],
+ 'Polymer mixins - shorthand optimizations': [
+ 'a{--my-toolbar: { margin:10px; margin-top:10px };}',
+ 'a{--my-toolbar:{margin:10px};}'
+ ],
+ 'Polymer mixins - not fitting into a single chunk of 128 bytes': [
+ ':host{--live-head-theme: { line-height: 40px !important; vertical-align: middle; background: transparent; height: 40px; z-index: 999; }; }',
+ ':host{--live-head-theme:{line-height:40px!important;vertical-align:middle;background:0 0;height:40px;z-index:999};}'
]
})
)
'has value': function (wrapped) {
assert.deepEqual(wrapped[0].value, [['0'], ['0']]);
},
+ 'is not a block': function (wrapped) {
+ assert.isFalse(wrapped[0].block);
+ },
'has no components': function (wrapped) {
assert.lengthOf(wrapped[0].components, 0);
},
assert.isTrue(wrapped[0].multiplex);
}
},
+ 'variable': {
+ 'topic': function () {
+ return wrapForOptimizing([[['--color'], ['red']]]);
+ },
+ 'has one wrap': function (wrapped) {
+ assert.lengthOf(wrapped, 1);
+ },
+ 'has name': function (wrapped) {
+ assert.deepEqual(wrapped[0].name, '--color');
+ },
+ 'has value': function (wrapped) {
+ assert.deepEqual(wrapped[0].value, [['red']]);
+ },
+ 'is not a block': function (wrapped) {
+ assert.isFalse(wrapped[0].block);
+ },
+ 'is variable': function (wrapped) {
+ assert.isTrue(wrapped[0].variable);
+ }
+ },
+ 'variable block': {
+ 'topic': function () {
+ return wrapForOptimizing([[['--color'], [ [['color'], ['red']], [['text-color'], ['red']] ]]]);
+ },
+ 'has one wrap': function (wrapped) {
+ assert.lengthOf(wrapped, 1);
+ },
+ 'has name': function (wrapped) {
+ assert.deepEqual(wrapped[0].name, '--color');
+ },
+ 'has value': function (wrapped) {
+ assert.deepEqual(wrapped[0].value, [[ [['color'], ['red']], [['text-color'], ['red']] ]]);
+ },
+ 'is not a block': function (wrapped) {
+ assert.isTrue(wrapped[0].block);
+ },
+ 'is variable': function (wrapped) {
+ assert.isTrue(wrapped[0].variable);
+ }
+ },
'without value': {
'topic': function () {
return wrapForOptimizing([[['margin']]]);
assert.deepEqual(tokens, [['color', 'red', 'color', [['color'], ['red']], 'color:red', [['#one span']], true]]);
}
},
+ 'one property - variable': {
+ 'topic': extractor(buildToken('#one span{--color:red}')),
+ 'has no properties': function (tokens) {
+ assert.deepEqual(tokens, []);
+ }
+ },
+ 'one property - block variable': {
+ 'topic': extractor(buildToken('#one span{--color:{color:red;display:block};}')),
+ 'has no properties': function (tokens) {
+ assert.deepEqual(tokens, []);
+ }
+ },
'one property - complex selector': {
'topic': extractor(buildToken('.one{color:red}')),
'has no properties': function (tokens) {
]
]
]
+ ],
+ 'variable blocks': [
+ '\ndiv {\n--test1:{\n color:red}; --test2:{ color: blue };}',
+ [
+ [
+ 'selector',
+ [['div', [[2, 0, undefined]]]],
+ [
+ [['--test1', [[3, 0, undefined]]], [[['color', [[4, 1, undefined]]], ['red', [[4, 7, undefined]] ]]]],
+ [['--test2', [[4, 13, undefined]]], [[['color', [[4, 23, undefined]]], ['blue', [[4, 30, undefined]] ]]]]
+ ]
+ ]
+ ]
]
})
)
]
})
)
+ .addBatch(
+ tokenizerContext('Polymer mixins', {
+ 'flat value': [
+ 'a{--my-toolbar-color:red}',
+ [
+ ['selector', [['a']], [[['--my-toolbar-color'], ['red']]]]
+ ]
+ ],
+ 'block value': [
+ 'a{--my-toolbar:{color:red;width:100%}}',
+ [
+ [
+ 'selector',
+ [['a']],
+ [[['--my-toolbar'], [
+ [['color'], ['red']],
+ [['width'], ['100%']]
+ ]]]
+ ]
+ ]
+ ],
+ 'mixed block value': [
+ 'a{display:block;--my-toolbar:{color:red;width:100%};color:blue}',
+ [
+ [
+ 'selector',
+ [['a']],
+ [
+ [['display'], ['block']],
+ [['--my-toolbar'], [[['color'], ['red']], [['width'], ['100%']]]],
+ [['color'], ['blue']]
+ ]
+ ]
+ ]
+ ]
+ })
+ )
.addBatch(
tokenizerContext('multiple values', {
'comma - no spaces': [