Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: clean-css/clean-css
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v4.2.1
Choose a base ref
...
head repository: clean-css/clean-css
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v4.2.2
Choose a head ref
  • 7 commits
  • 11 files changed
  • 5 contributors

Commits on Aug 7, 2018

  1. Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    jakubpawlowicz Jakub Pawlowicz
    Copy the full SHA
    b01dd75 View commit details

Commits on Jan 25, 2020

  1. Prevent error if property block has no value (level 0) (#1061)

    The tokenizer will parse a property like `width: ;`, but the property
    helper for level 0 (i.e. minification only) was not accounting for
    properties without a value and would throw a TypeError if the value
    was missing
    
    With this change, the property helper now checks for a missing property
    value before trying to access it
    clarkdave authored and jakubpawlowicz committed Jan 25, 2020

    Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    jakubpawlowicz Jakub Pawlowicz
    Copy the full SHA
    da25f4f View commit details
  2. Fix local fonts with colors in name (#1077)

    * fix(optimizer): do not convert colors inside local font names
    Sirius-A authored and jakubpawlowicz committed Jan 25, 2020

    Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    jakubpawlowicz Jakub Pawlowicz
    Copy the full SHA
    31379cd View commit details
  3. Prevent unquoting on grid elements (#1085)

    * Prevent unquoting on grid elements
    
    Add "grid" element to list of elements ignored by removeQuotes.
    This prevents required quotes from being removed from single column grids.
    
    * Update optimize.js
    veleek authored and jakubpawlowicz committed Jan 25, 2020

    Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    jakubpawlowicz Jakub Pawlowicz
    Copy the full SHA
    9b1ed5b View commit details
  4. Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    jakubpawlowicz Jakub Pawlowicz
    Copy the full SHA
    e1410e4 View commit details
  5. Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    jakubpawlowicz Jakub Pawlowicz
    Copy the full SHA
    e79454c View commit details
  6. Version 4.2.2.

    jakubpawlowicz committed Jan 25, 2020

    Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    jakubpawlowicz Jakub Pawlowicz
    Copy the full SHA
    58d80f8 View commit details
8 changes: 8 additions & 0 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
[4.2.2 / 2020-01-25](https://github.com/jakubpawlowicz/clean-css/compare/v4.2.1...v4.2.2)
==================

* Fixed error when property block has no value.
* Fixed issue [#1077](https://github.com/jakubpawlowicz/clean-css/issues/1077) - local fonts with color in name.
* Fixed issue [#1082](https://github.com/jakubpawlowicz/clean-css/issues/1082) - correctly convert colors if alpha >= 1.
* Fixed issue [#1085](https://github.com/jakubpawlowicz/clean-css/issues/1085) - prevent unquoting of grid elements.

[4.2.1 / 2018-08-07](https://github.com/jakubpawlowicz/clean-css/compare/v4.2.0...v4.2.1)
==================

2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ <h1 class="logo">
<form class="settings settings--collapsed js-settings">
<fieldset class="settings__group">
<select class="settings__option settings__option--version" name="version">
<option value="v4.2.0" selected>4.2.0 (latest)</option>
<option value="v4.2.1" selected>4.2.1 (latest)</option>
</select>
</fieldset>
<fieldset class="settings__group settings__group--advanced">
2 changes: 1 addition & 1 deletion docs/js/optimizer-worker.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ onmessage = function(event) {
case 'initialize':
if (!initialized) {
initialized = true
importScripts('//jakubpawlowicz.github.io/clean-css-builds/v4.2.0.js')
importScripts('//jakubpawlowicz.github.io/clean-css-builds/v4.2.1.js')
}
break
case 'optimize':
35 changes: 25 additions & 10 deletions lib/optimizer/level-1/optimize.js
Original file line number Diff line number Diff line change
@@ -37,8 +37,13 @@ var IMPORT_PREFIX_PATTERN = /^@import/i;
var QUOTED_PATTERN = /^('.*'|".*")$/;
var QUOTED_BUT_SAFE_PATTERN = /^['"][a-zA-Z][a-zA-Z\d\-_]+['"]$/;
var URL_PREFIX_PATTERN = /^url\(/i;
var LOCAL_PREFIX_PATTERN = /^local\(/i;
var VARIABLE_NAME_PATTERN = /^--\S+$/;

function isLocal(value){
return LOCAL_PREFIX_PATTERN.test(value);
}

function isNegative(value) {
return value && value[1][0] == '-' && parseFloat(value[1]) < 0;
}
@@ -89,16 +94,25 @@ function optimizeBorderRadius(property) {
}
}

/**
* @param {string} name
* @param {string} value
* @param {Object} compatibility
* @return {string}
*/
function optimizeColors(name, value, compatibility) {
if (value.indexOf('#') === -1 && value.indexOf('rgb') == -1 && value.indexOf('hsl') == -1) {
if (!value.match(/#|rgb|hsl/gi)) {
return shortenHex(value);
}

value = value
.replace(/rgb\((\-?\d+),(\-?\d+),(\-?\d+)\)/g, function (match, red, green, blue) {
.replace(/(rgb|hsl)a?\((\-?\d+),(\-?\d+\%?),(\-?\d+\%?),(0*[1-9]+[0-9]*(.?\d*)?)\)/gi, function (match, colorFn, p1, p2, p3, alpha) {
return (parseInt(alpha, 10) >= 1 ? colorFn + '(' + [p1,p2,p3].join(',') + ')' : match);
})
.replace(/rgb\((\-?\d+),(\-?\d+),(\-?\d+)\)/gi, function (match, red, green, blue) {
return shortenRgb(red, green, blue);
})
.replace(/hsl\((-?\d+),(-?\d+)%?,(-?\d+)%?\)/g, function (match, hue, saturation, lightness) {
.replace(/hsl\((-?\d+),(-?\d+)%?,(-?\d+)%?\)/gi, function (match, hue, saturation, lightness) {
return shortenHsl(hue, saturation, lightness);
})
.replace(/(^|[^='"])#([0-9a-f]{6})/gi, function (match, prefix, color, at, inputValue) {
@@ -115,12 +129,13 @@ function optimizeColors(name, value, compatibility) {
.replace(/(^|[^='"])#([0-9a-f]{3})/gi, function (match, prefix, color) {
return prefix + '#' + color.toLowerCase();
})
.replace(/(rgb|rgba|hsl|hsla)\(([^\)]+)\)/g, function (match, colorFunction, colorDef) {
.replace(/(rgb|rgba|hsl|hsla)\(([^\)]+)\)/gi, function (match, colorFunction, colorDef) {
var tokens = colorDef.split(',');
var applies = (colorFunction == 'hsl' && tokens.length == 3) ||
(colorFunction == 'hsla' && tokens.length == 4) ||
(colorFunction == 'rgb' && tokens.length == 3 && colorDef.indexOf('%') > 0) ||
(colorFunction == 'rgba' && tokens.length == 4 && colorDef.indexOf('%') > 0);
var colorFnLowercase = colorFunction && colorFunction.toLowerCase();
var applies = (colorFnLowercase == 'hsl' && tokens.length == 3) ||
(colorFnLowercase == 'hsla' && tokens.length == 4) ||
(colorFnLowercase == 'rgb' && tokens.length === 3 && colorDef.indexOf('%') > 0) ||
(colorFnLowercase == 'rgba' && tokens.length == 4 && colorDef.indexOf('%') > 0);

if (!applies) {
return match;
@@ -336,7 +351,7 @@ function optimizeZeroUnits(name, value) {
}

function removeQuotes(name, value) {
if (name == 'content' || name.indexOf('font-variation-settings') > -1 || name.indexOf('font-feature-settings') > -1 || name.indexOf('grid-') > -1) {
if (name == 'content' || name.indexOf('font-variation-settings') > -1 || name.indexOf('font-feature-settings') > -1 || name == 'grid' || name.indexOf('grid-') > -1) {
return value;
}

@@ -443,7 +458,7 @@ function optimizeBody(rule, properties, context) {
value = !options.compatibility.properties.urlQuotes ?
removeUrlQuotes(value) :
value;
} else if (isQuoted(value)) {
} else if (isQuoted(value) || isLocal(value)) {
value = levelOptions.removeQuotes ?
removeQuotes(name, value) :
value;
4 changes: 2 additions & 2 deletions lib/optimizer/validator.js
Original file line number Diff line number Diff line change
@@ -6,11 +6,11 @@ var functionAnyRegexStr = '(' + variableRegexStr + '|' + functionNoVendorRegexSt
var calcRegex = new RegExp('^(\\-moz\\-|\\-webkit\\-)?calc\\([^\\)]+\\)$', 'i');
var decimalRegex = /[0-9]/;
var functionAnyRegex = new RegExp('^' + functionAnyRegexStr + '$', 'i');
var hslColorRegex = /^hsl\(\s{0,31}[\-\.]?\d+\s{0,31},\s{0,31}\.?\d+%\s{0,31},\s{0,31}\.?\d+%\s{0,31}\)|hsla\(\s{0,31}[\-\.]?\d+\s{0,31},\s{0,31}\.?\d+%\s{0,31},\s{0,31}\.?\d+%\s{0,31},\s{0,31}\.?\d+\s{0,31}\)$/;
var hslColorRegex = /^hsl\(\s{0,31}[\-\.]?\d+\s{0,31},\s{0,31}\.?\d+%\s{0,31},\s{0,31}\.?\d+%\s{0,31}\)|hsla\(\s{0,31}[\-\.]?\d+\s{0,31},\s{0,31}\.?\d+%\s{0,31},\s{0,31}\.?\d+%\s{0,31},\s{0,31}\.?\d+\s{0,31}\)$/i;
var identifierRegex = /^(\-[a-z0-9_][a-z0-9\-_]*|[a-z][a-z0-9\-_]*)$/i;
var namedEntityRegex = /^[a-z]+$/i;
var prefixRegex = /^-([a-z0-9]|-)*$/i;
var rgbColorRegex = /^rgb\(\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31}\)|rgba\(\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\.\d]+\s{0,31}\)$/;
var rgbColorRegex = /^rgb\(\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31}\)|rgba\(\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\.\d]+\s{0,31}\)$/i;
var timingFunctionRegex = /^(cubic\-bezier|steps)\([^\)]+\)$/;
var validTimeUnits = ['ms', 's'];
var urlRegex = /^url\([\s\S]+\)$/i;
8 changes: 6 additions & 2 deletions lib/writer/helpers.js
Original file line number Diff line number Diff line change
@@ -77,7 +77,9 @@ function lastPropertyIndex(tokens) {
function property(context, tokens, position, lastPropertyAt) {
var store = context.store;
var token = tokens[position];
var isPropertyBlock = token[2][0] == Token.PROPERTY_BLOCK;

var propertyValue = token[2];
var isPropertyBlock = propertyValue && propertyValue[0] === Token.PROPERTY_BLOCK;

var needsSemicolon;
if ( context.format ) {
@@ -111,7 +113,9 @@ function property(context, tokens, position, lastPropertyAt) {
case Token.PROPERTY:
store(context, token[1]);
store(context, colon(context));
value(context, token);
if (propertyValue) {
value(context, token);
}
store(context, needsSemicolon ? semicolon(context, Breaks.AfterProperty, isLast) : emptyCharacter);
break;
case Token.RAW:
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clean-css",
"version": "4.2.1",
"version": "4.2.2",
"author": "Jakub Pawlowicz <contact@jakubpawlowicz.com> (http://twitter.com/jakubpawlowicz)",
"description": "A well-tested CSS minifier",
"license": "MIT",
2 changes: 1 addition & 1 deletion test/fixtures/big-min.css
Original file line number Diff line number Diff line change
@@ -189,7 +189,7 @@ body{font-size:13px;line-height:140%;color:#16212c;background:#e9edf0}
.global{width:1000px;margin:0 auto;padding:20px 0 10px;background:#fff}
.lmd-header{position:relative;z-index:15}
.lmd-header #header{margin-bottom:16px}
.deroule_edito,.deroule_fleuve,.ombre_section,.une_edito{-webkit-box-shadow:0 6px 6px -6px rgba(202,205,209,1);-moz-box-shadow:0 6px 6px -6px rgba(202,205,209,1);box-shadow:0 6px 6px -6px rgba(202,205,209,1);padding-top:0;margin-bottom:16px;margin-top:16px;overflow:hidden}
.deroule_edito,.deroule_fleuve,.ombre_section,.une_edito{-webkit-box-shadow:0 6px 6px -6px #cacdd1;-moz-box-shadow:0 6px 6px -6px #cacdd1;box-shadow:0 6px 6px -6px #cacdd1;padding-top:0;margin-bottom:16px;margin-top:16px;overflow:hidden}
a{color:#036;text-decoration:none;cursor:pointer}
.bg_fonce a{opacity:.85}
.obf{cursor:pointer;color:#036}
16 changes: 10 additions & 6 deletions test/integration-test.js
Original file line number Diff line number Diff line change
@@ -158,9 +158,13 @@ vows.describe('integration tests')
'a{text-shadow:rgb(255,0,1) 1px 1px}',
'a{text-shadow:#ff0001 1px 1px}'
],
'after rgba': [
'after rgba #1': [
'a{text-shadow:rgba(255,0,0,.1) 0 1px}',
'a{text-shadow:rgba(255,0,0,.1) 0 1px}'
],
'after rgba #2': [
'a{text-shadow:rgba(255,0,0,1) 0 1px}',
'a{text-shadow:rgba(255,0,0,1) 0 1px}'
'a{text-shadow:red 0 1px}'
],
'after hsl': [
'a{text-shadow:hsl(240,100%,40%) -1px 1px}',
@@ -215,8 +219,8 @@ vows.describe('integration tests')
'a{text-shadow:#ff0001 1px 1px}'
],
'after rgba': [
'a{text-shadow:rgba(255,0,0,1) 0 1px}',
'a{text-shadow:rgba(255,0,0,1) 0 1px}'
'a{text-shadow:rgba(255,0,0,.1) 0 1px}',
'a{text-shadow:rgba(255,0,0,.1) 0 1px}'
],
'after hsl': [
'a{text-shadow:hsl(240,100%,40%) -1px 1px}',
@@ -695,8 +699,8 @@ vows.describe('integration tests')
'a{-webkit-box-shadow:0 0;-moz-box-shadow:0 0}'
],
'zero as .0 #1': [
'a{color:rgba(0,0,.0,1)}',
'a{color:rgba(0,0,0,1)}'
'a{color:rgba(0,0,.0,.1)}',
'a{color:rgba(0,0,0,.1)}'
],
'zero as .0 #2': [
'body{margin:.0}',
8 changes: 8 additions & 0 deletions test/optimizer/level-0/optimizations-test.js
Original file line number Diff line number Diff line change
@@ -11,4 +11,12 @@ vows.describe('level 0')
]
}, { level: 0 })
)
.addBatch(
optimizerContext('empty properties', {
'are written': [
'a{color:#f00;font-weight:;background:red}',
'a{color:#f00;font-weight:;background:red}'
]
}, { level: 0 })
)
.export(module);
8 changes: 8 additions & 0 deletions test/optimizer/level-1/optimize-test.js
Original file line number Diff line number Diff line change
@@ -540,6 +540,10 @@ vows.describe('level 1 optimizations')
'with mixed bold weight and variant #2': [
'a{font:bold normal 17px sans-serif}',
'a{font:bold normal 17px sans-serif}'
],
'with color in local font name': [
'@font-face{src:local("Sans Black Italic")}',
'@font-face{src:local("Sans Black Italic")}',
]
}, { level: 1 })
)
@@ -1225,6 +1229,10 @@ vows.describe('level 1 optimizations')
'.block{-webkit-font-feature-settings:"scmp","swsh" 2}',
'.block{-webkit-font-feature-settings:"scmp","swsh" 2}'
],
'grid': [
'.block{grid:"header" 20% "nav" auto/auto}',
'.block{grid:"header" 20% "nav" auto/auto}'
],
'grid-template': [
'.block{grid-template:"header" 20% "nav" auto}',
'.block{grid-template:"header" 20% "nav" auto}'