* Fixed issue [#751](https://github.com/jakubpawlowicz/clean-css/issues/751) - stringifying CSS variables.
* Fixed issue [#763](https://github.com/jakubpawlowicz/clean-css/issues/763) - data URI SVG and quoting.
* Fixed issue [#765](https://github.com/jakubpawlowicz/clean-css/issues/765) - two values of border-radius.
+* Fixed issue [#768](https://github.com/jakubpawlowicz/clean-css/issues/768) - invalid border-radius property.
[3.4.13 / 2016-05-23](https://github.com/jakubpawlowicz/clean-css/compare/v3.4.12...v3.4.13)
==================
simpleOptimize(tokens, options);
if (options.advanced)
- advancedOptimize(tokens, options, context.validator, true);
+ advancedOptimize(tokens, options, context, true);
return stringify(tokens, options, restoreEscapes, context.inputSourceMapTracker);
}
var wrapSingle = require('./wrap-for-optimizing').single;
+var InvalidPropertyError = require('./invalid-property-error');
var split = require('../utils/split');
var MULTIPLEX_SEPARATOR = ',';
}
}
+ if (splitAt === 0 || splitAt === values.length - 1) {
+ throw new InvalidPropertyError('Invalid border-radius value.');
+ }
+
var target = _wrapDefault(property.name, property, compactable);
target.value = splitAt > -1 ?
values.slice(0, splitAt) :
--- /dev/null
+function InvalidPropertyError(message) {
+ this.name = 'InvalidPropertyError';
+ this.message = message;
+ this.stack = (new Error()).stack;
+}
+
+InvalidPropertyError.prototype = Object.create(Error.prototype);
+InvalidPropertyError.prototype.constructor = InvalidPropertyError;
+
+module.exports = InvalidPropertyError;
}
}
-function optimize(selector, properties, mergeAdjacent, withCompacting, options, validator) {
+function optimize(selector, properties, mergeAdjacent, withCompacting, options, context) {
+ var validator = context.validator;
+ var warnings = context.warnings;
+
var _properties = wrapForOptimizing(properties);
- populateComponents(_properties, validator);
+ populateComponents(_properties, validator, warnings);
_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);
+ optimize(selector, _property.value[0], mergeAdjacent, withCompacting, options, context);
}
if (withCompacting && options.shorthandCompacting) {
var compactable = require('./compactable');
+var InvalidPropertyError = require('./invalid-property-error');
-function populateComponents(properties, validator) {
+function populateComponents(properties, validator, warnings) {
for (var i = properties.length - 1; i >= 0; i--) {
var property = properties[i];
var descriptor = compactable[property.name];
if (descriptor && descriptor.shorthand) {
property.shorthand = true;
property.dirty = true;
- property.components = descriptor.breakUp(property, compactable, validator);
+
+ try {
+ property.components = descriptor.breakUp(property, compactable, validator);
+ } catch (e) {
+ if (e instanceof InvalidPropertyError) {
+ property.components = []; // this will set property.unused to true below
+ warnings.push(e.message);
+ } else {
+ throw e;
+ }
+ }
if (property.components.length > 0)
property.multiplex = property.components[0].multiplex;
newProperty.shorthand = true;
newProperty.dirty = true;
- populateComponents([newProperty], validator);
+ populateComponents([newProperty], validator, []);
for (var i = 0, l = descriptor.components.length; i < l; i++) {
var component = candidateComponents[descriptor.components[i]];
}
}
-function recursivelyOptimizeBlocks(tokens, options, validator) {
+function recursivelyOptimizeBlocks(tokens, options, context) {
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (token[0] == 'block') {
var isKeyframes = /@(-moz-|-o-|-webkit-)?keyframes/.test(token[1][0]);
- optimize(token[2], options, validator, !isKeyframes);
+ optimize(token[2], options, context, !isKeyframes);
}
}
}
-function recursivelyOptimizeProperties(tokens, options, validator) {
+function recursivelyOptimizeProperties(tokens, options, context) {
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
switch (token[0]) {
case 'selector':
- optimizeProperties(token[1], token[2], false, true, options, validator);
+ optimizeProperties(token[1], token[2], false, true, options, context);
break;
case 'block':
- recursivelyOptimizeProperties(token[2], options, validator);
+ recursivelyOptimizeProperties(token[2], options, context);
}
}
}
-function optimize(tokens, options, validator, withRestructuring) {
- recursivelyOptimizeBlocks(tokens, options, validator);
- recursivelyOptimizeProperties(tokens, options, validator);
+function optimize(tokens, options, context, withRestructuring) {
+ recursivelyOptimizeBlocks(tokens, options, context);
+ recursivelyOptimizeProperties(tokens, options, context);
removeDuplicates(tokens);
- mergeAdjacent(tokens, options, validator);
- reduceNonAdjacent(tokens, options, validator);
+ mergeAdjacent(tokens, options, context);
+ reduceNonAdjacent(tokens, options, context);
- mergeNonAdjacentBySelector(tokens, options, validator);
+ mergeNonAdjacentBySelector(tokens, options, context);
mergeNonAdjacentByBody(tokens, options);
if (options.restructuring && withRestructuring) {
restructure(tokens, options);
- mergeAdjacent(tokens, options, validator);
+ mergeAdjacent(tokens, options, context);
}
if (options.mediaMerging) {
removeDuplicateMediaQueries(tokens);
var reduced = mergeMediaQueries(tokens);
for (var i = reduced.length - 1; i >= 0; i--) {
- optimize(reduced[i][2], options, validator, false);
+ optimize(reduced[i][2], options, context, false);
}
}
var cleanUpSelectors = require('./clean-up').selectors;
var isSpecial = require('./is-special');
-function mergeAdjacent(tokens, options, validator) {
+function mergeAdjacent(tokens, options, context) {
var lastToken = [null, [], []];
var adjacentSpace = options.compatibility.selectors.adjacentSpace;
if (lastToken[0] == 'selector' && stringifySelectors(token[1]) == stringifySelectors(lastToken[1])) {
var joinAt = [lastToken[2].length];
Array.prototype.push.apply(lastToken[2], token[2]);
- optimizeProperties(token[1], lastToken[2], joinAt, true, options, validator);
+ optimizeProperties(token[1], lastToken[2], joinAt, true, options, context);
token[2] = [];
} else if (lastToken[0] == 'selector' && stringifyBody(token[2]) == stringifyBody(lastToken[2]) &&
!isSpecial(options, stringifySelectors(token[1])) && !isSpecial(options, stringifySelectors(lastToken[1]))) {
var extractProperties = require('./extractor');
var canReorder = require('./reorderable').canReorder;
-function mergeNonAdjacentBySelector(tokens, options, validator) {
+function mergeNonAdjacentBySelector(tokens, options, context) {
var allSelectors = {};
var repeatedSelectors = [];
var i;
Array.prototype.push.apply(target[2], moved[2]);
}
- optimizeProperties(target[1], target[2], joinAt, true, options, validator);
+ optimizeProperties(target[1], target[2], joinAt, true, options, context);
moved[2] = [];
}
}
var isSpecial = require('./is-special');
var cloneArray = require('../utils/clone-array');
-function reduceNonAdjacent(tokens, options, validator) {
+function reduceNonAdjacent(tokens, options, context) {
var candidates = {};
var repeated = [];
}
}
- reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, validator);
- reduceComplexNonAdjacentCases(tokens, candidates, options, validator);
+ reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, context);
+ reduceComplexNonAdjacentCases(tokens, candidates, options, context);
}
function wrappedSelectorsFrom(list) {
return wrapped;
}
-function reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, validator) {
+function reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, context) {
function filterOut(idx, bodies) {
return data[idx].isPartial && bodies.length === 0;
}
reduceSelector(tokens, selector, data, {
filterOut: filterOut,
callback: reduceBody
- }, options, validator);
+ }, options, context);
}
}
-function reduceComplexNonAdjacentCases(tokens, candidates, options, validator) {
+function reduceComplexNonAdjacentCases(tokens, candidates, options, context) {
var localContext = {};
function filterOut(idx) {
reduceSelector(tokens, selector, data, {
filterOut: filterOut,
callback: collectReducedBodies
- }, options, validator);
+ }, options, context);
if (stringifyBody(reducedBodies[reducedBodies.length - 1]) != stringifyBody(reducedBodies[0]))
continue allSelectors;
}
}
-function reduceSelector(tokens, selector, data, context, options, validator) {
+function reduceSelector(tokens, selector, data, context, options, outerContext) {
var bodies = [];
var bodiesAsList = [];
var joinsAt = [];
joinsAt.push((joinsAt[j - 1] || 0) + bodiesAsList[j].length);
}
- optimizeProperties(selector, bodies, joinsAt, false, options, validator);
+ optimizeProperties(selector, bodies, joinsAt, false, options, outerContext);
var processedCount = processedTokens.length;
var propertyIdx = bodies.length - 1;
function _breakUp(properties) {
var validator = new Validator(new Compatibility().toOptions());
var wrapped = wrapForOptimizing(properties);
- populateComponents(wrapped, validator);
+ populateComponents(wrapped, validator, []);
return wrapped[0].components;
}
assert.equal(components[3].name, '-webkit-border-bottom-left-radius');
assert.deepEqual(components[3].value, [['1px'], ['4px']]);
}
+ },
+ 'with missing vertical value': {
+ 'topic': function () {
+ return _breakUp([[['border-radius'], ['0px'], ['/']]]);
+ },
+ 'has no components': function (components) {
+ assert.lengthOf(components, 0);
+ }
+ },
+ 'with missing horizontal value': {
+ 'topic': function () {
+ return _breakUp([[['border-radius'], ['/'], ['0px']]]);
+ },
+ 'has no components': function (components) {
+ assert.lengthOf(components, 0);
+ }
}
},
'four values': {
var compatibility = new Compatibility().toOptions();
var validator = new Validator(compatibility);
- optimize(tokens[0][1], tokens[0][2], false, true, { compatibility: compatibility, aggressiveMerging: true, shorthandCompacting: true }, validator);
+ optimize(tokens[0][1], tokens[0][2], false, true, { compatibility: compatibility, aggressiveMerging: true, shorthandCompacting: true }, { validator: validator });
return tokens[0][2];
}
warnings: []
});
- optimize(tokens[0][1], tokens[0][2], mergeAdjacent, true, { compatibility: compatibility, aggressiveMerging: aggressiveMerging }, validator);
+ optimize(tokens[0][1], tokens[0][2], mergeAdjacent, true, { compatibility: compatibility, aggressiveMerging: aggressiveMerging }, { validator: validator });
return tokens[0][2];
}
compatibility: compatibility,
shorthandCompacting: true
};
- optimize(tokens[0][1], tokens[0][2], false, true, options, validator);
+ optimize(tokens[0][1], tokens[0][2], false, true, options, { validator: validator });
return tokens[0][2];
}
sourceMap: true,
shorthandCompacting: true
};
- optimize(tokens[0][1], tokens[0][2], false, true, options, validator);
+ optimize(tokens[0][1], tokens[0][2], false, true, options, { validator: validator });
return tokens[0][2];
}
compatibility: compatibility,
shorthandCompacting: true
};
- optimize(tokens[0][1], tokens[0][2], false, true, options, validator);
+ optimize(tokens[0][1], tokens[0][2], false, true, options, { validator: validator });
return tokens[0][2];
}