Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

clean-css

Package Overview
Dependencies
Maintainers
1
Versions
211
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

clean-css - npm Package Compare versions

Comparing version 0.10.2 to 1.0.0

bench/TP-bench.md

48

History.md

@@ -0,1 +1,13 @@

1.0.0 / 2013-03-30
==================
* Fixed issue [#2](https://github.com/GoalSmashers/clean-css/issues/2) - resolving `@import` rules.
* Fixed issue [#44](https://github.com/GoalSmashers/clean-css/issues/44) - examples in `--help`.
* Fixed issue [#46](https://github.com/GoalSmashers/clean-css/issues/46) - preserving special characters in URLs and attributes.
* Fixed issue [#80](https://github.com/GoalSmashers/clean-css/issues/80) - quotation in multi line strings.
* Fixed issue [#83](https://github.com/GoalSmashers/clean-css/issues/83) - HSL to hex color conversions.
* Fixed issue [#86](https://github.com/GoalSmashers/clean-css/issues/86) - broken `@charset` replacing.
* Fixed issue [#88](https://github.com/GoalSmashers/clean-css/issues/88) - removes space in `! important`.
* Fixed issue [#92](https://github.com/GoalSmashers/clean-css/issues/92) - uppercase hex to short versions.
0.10.2 / 2013-03-19

@@ -20,8 +32,8 @@ ==================

* Fixed issue [#49](https://github.com/GoalSmashers/clean-css/issues/49) - remove empty selectors from media query.
* Fixed issue [#52](https://github.com/GoalSmashers/clean-css/issues/49) - strip fraction zeros if not needed.
* Fixed issue [#59](https://github.com/GoalSmashers/clean-css/issues/49) - content property handling.
* Fixed issue [#58](https://github.com/GoalSmashers/clean-css/issues/49) - remove colon where possible.
* Fixed issue [#52](https://github.com/GoalSmashers/clean-css/issues/52) - strip fraction zeros if not needed.
* Fixed issue [#58](https://github.com/GoalSmashers/clean-css/issues/58) - remove colon where possible.
* Fixed issue [#59](https://github.com/GoalSmashers/clean-css/issues/59) - content property handling.
* Fixed performance issue with replacing multiple `@charset` declarations and issue
with line break after `@charset` when using `keepLineBreaks` option. By [@rrjaime](https://github.com/rrjamie).
* Removed Makefile in favor to npm run ... commands (e.g. `make check` -> `npm run check`).
* Removed Makefile in favor to `npm run` commands (e.g. `make check` -> `npm run check`).

@@ -38,7 +50,9 @@ 0.9.1 / 2012-12-19

* Added stripping quotation from font names (if possible).
* Added stripping quotation from `@keyframes` declaration, `animation` and `animation-name` property.
* Added stripping quotation from `@keyframes` declaration, `animation` and
`animation-name` property.
* Added stripping quotations from attributes' value (e.g. `[data-target='x']`).
* Added better hex->name and name->hex color shortening.
* Added `font: normal` and `font: bold` shortening the same way as `font-weight` is.
* Refactored shorthand selectors and added `border-radius`, `border-style` and `border-color` shortening.
* Refactored shorthand selectors and added `border-radius`, `border-style`
and `border-color` shortening.
* Added `margin`, `padding` and `border-width` shortening.

@@ -54,3 +68,3 @@ * Added removing line break after commas.

* Fixed hsl/hsla colors processing.
* Fixed HSL/HSLA colors processing.

@@ -74,3 +88,3 @@ 0.8.2 / 2012-10-31

* Added `keepBreaks`/`-b` option to keep line breaks in the minimized file.
* Reformatted lib/clean.js so it's easier to follow the rules.
* Reformatted [lib/clean.js](/lib/clean.js) so it's easier to follow the rules.
* Minimized test data is now minimized with line breaks so it's easier to

@@ -95,3 +109,3 @@ compare the changes line by line.

* Made path to vows local.
* Explicit node 0.6 requirement.
* Explicit node.js 0.6 requirement.

@@ -116,4 +130,4 @@ 0.4.2 / 2012-06-28

processing.
* Stripping empty CSS tags is now optional (see ./bin/cleancss for details).
* Improved debugging mode (see ./test/bench.js)
* Stripping empty CSS tags is now optional (see [bin/cleancss](/bin/cleancss) for details).
* Improved debugging mode (see [test/bench.js](/test/bench.js))
* Added `make bench` for a one-pass benchmark.

@@ -124,4 +138,4 @@

* Fixed tests, package.json for development, and regex for removing empty
declarations (thanks to [@vvo](https://github.com/vvo)).
* Fixed tests, [package.json](/package.json) for development, and regex
for removing empty declarations (thanks to [@vvo](https://github.com/vvo)).

@@ -131,3 +145,3 @@ 0.3.2 / 2012-01-17

* Fixed output method under node 0.6 which incorrectly tried to close
* Fixed output method under node.js 0.6 which incorrectly tried to close
`process.stdout`.

@@ -143,4 +157,4 @@

* Clean-css requires node 0.4.0+ to run.
* Removed node's 0.2.x 'sys' package dependency
* Clean-css requires node.js 0.4.0+ to run.
* Removed node.js's 0.2.x 'sys' package dependency
(thanks to [@jmalonzo](https://github.com/jmalonzo) for a patch).

@@ -181,3 +195,3 @@

* Added stripping space before `!important` keyword.
* Updated repository location and author information in package.json.
* Updated repository location and author information in [package.json](/package.json).

@@ -184,0 +198,0 @@ 0.2.0 / 2011-03-02

@@ -1,1 +0,1 @@

module.exports = require("./lib/clean");
module.exports = require('./lib/clean');

@@ -8,2 +8,6 @@ /**

var fs = require('fs');
var path = require('path');
var existsSync = fs.existsSync || path.existsSync;
var CleanCSS = {

@@ -35,3 +39,4 @@ colors: {

specialComments: [],
contentBlocks: []
freeTextBlocks: [],
urlBlocks: []
};

@@ -74,2 +79,13 @@ var replace = function() {

// replace all escaped line breaks
replace(/\\(\r\n|\n)/mg, '');
// inline all imports
replace(function inlineImports() {
data = CleanCSS._inlineImports(data, {
root: options.root || process.cwd(),
relativeTo: options.relativeTo
});
});
// strip comments one by one

@@ -80,15 +96,51 @@ replace(function stripComments() {

// replace content: with a placeholder
replace(function stripContent() {
data = CleanCSS._stripContent(context, data);
// strip parentheses in urls if possible (no spaces inside)
replace(/url\((['"])([^\)]+)['"]\)/g, function(match, quote, url) {
if (url.match(/[ \t]/g) !== null)
return 'url(' + quote + url + quote + ')';
else
return 'url(' + url + ')';
});
// strip url's parentheses if possible (no spaces inside)
replace(/url\(['"]([^\)]+)['"]\)/g, function(urlMatch) {
if (urlMatch.match(/\s/g) !== null)
return urlMatch;
// strip parentheses in animation & font names
replace(/(animation|animation\-name|font|font\-family):([^;}]+)/g, function(match, propertyName, fontDef) {
return propertyName + ':' + fontDef.replace(/['"]([\w\-]+)['"]/g, '$1');
});
// strip parentheses in @keyframes
replace(/@(\-moz\-|\-o\-|\-webkit\-)?keyframes ([^{]+)/g, function(match, prefix, name) {
prefix = prefix || '';
return '@' + prefix + 'keyframes ' + (name.indexOf(' ') > -1 ? name : name.replace(/['"]/g, ''));
});
// IE shorter filters, but only if single (IE 7 issue)
replace(/progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\([^\)]+\))([;}'"])/g, function(match, filter, args, suffix) {
return filter.toLowerCase() + args + suffix;
});
// strip parentheses in attribute values
replace(/\[([^\]]+)\]/g, function(match, content) {
var eqIndex = content.indexOf('=');
if (eqIndex < 0 && content.indexOf('\'') < 0 && content.indexOf('"') < 0)
return match;
var key = content.substring(0, eqIndex);
var value = content.substring(eqIndex + 1, content.length);
if (/^['"](?:[a-zA-Z][a-zA-Z\d\-_]+)['"]$/.test(value))
return '[' + key + '=' + value.substring(1, value.length - 1) + ']';
else
return urlMatch.replace(/\(['"]/, '(').replace(/['"]\)$/, ')');
return match;
});
// replace all free text content with a placeholder
replace(function stripFreeText() {
data = CleanCSS._stripFreeText(context, data);
});
// replace url(...) with a placeholder
replace(function stripUrls() {
data = CleanCSS._stripUrls(context, data);
});
// line breaks

@@ -112,3 +164,3 @@ if (!options.keepBreaks)

// remove extra spaces inside content
replace(/([\(\{\}:;=,\n]) /g, '$1');
replace(/([!\(\{\}:;=,\n]) /g, '$1');
replace(/ ([!\)\{\};=,\n])/g, '$1');

@@ -127,40 +179,28 @@ replace(/(?:\r\n|\n)\}/g, '}');

// strip quotation in animation & font names
replace(/(animation|animation\-name|font|font\-family):([^;}]+)/g, function(match, propertyName, fontDef) {
return propertyName + ':' + fontDef.replace(/['"]([\w\-]+)['"]/g, '$1');
});
// hsl to hex colors
replace(/hsl\((\d+),(\d+)%?,(\d+)%?\)/g, function(match, hue, saturation, lightness) {
var asRgb = CleanCSS._hslToRgb(hue, saturation, lightness);
var redAsHex = asRgb[0].toString(16);
var greenAsHex = asRgb[1].toString(16);
var blueAsHex = asRgb[2].toString(16);
// strip quotation in @keyframes
replace(/@(\-moz\-|\-o\-|\-webkit\-)?keyframes ([^{]+)/g, function(match, prefix, name) {
prefix = prefix || '';
return '@' + prefix + 'keyframes ' + (name.indexOf(' ') > -1 ? name : name.replace(/['"]/g, ''));
return '#' +
((redAsHex.length == 1 ? '0' : '') + redAsHex) +
((greenAsHex.length == 1 ? '0' : '') + greenAsHex) +
((blueAsHex.length == 1 ? '0' : '') + blueAsHex);
});
// strip quotation in attribute values
replace(/\[([^\]]+)\]/g, function(match, content) {
var eqIndex = content.indexOf('=');
if (eqIndex < 0 && content.indexOf('\'') < 0 && content.indexOf('"') < 0)
return match;
// rgb to hex colors
replace(/rgb\((\d+),(\d+),(\d+)\)/g, function(match, red, green, blue) {
var redAsHex = parseInt(red, 10).toString(16);
var greenAsHex = parseInt(green, 10).toString(16);
var blueAsHex = parseInt(blue, 10).toString(16);
var key = content.substring(0, eqIndex);
var value = content.substring(eqIndex + 1, content.length);
if (/^['"](?:[a-zA-Z][a-zA-Z\d\-]+)['"]$/.test(value))
return '[' + key + '=' + value.substring(1, value.length - 1) + ']';
else
return match;
return '#' +
((redAsHex.length == 1 ? '0' : '') + redAsHex) +
((greenAsHex.length == 1 ? '0' : '') + greenAsHex) +
((blueAsHex.length == 1 ? '0' : '') + blueAsHex);
});
// rgb to hex colors
replace(/rgb\s*\(([^\)]+)\)/g, function(match, color) {
var parts = color.split(',');
var encoded = '#';
for (var i = 0; i < 3; i++) {
var asHex = parseInt(parts[i], 10).toString(16);
encoded += asHex.length == 1 ? '0' + asHex : asHex;
}
return encoded;
});
// long color hex to short hex
// long hex to short hex colors
replace(/([,: \(])#([0-9a-f]{6})/gi, function(match, prefix, color) {

@@ -175,8 +215,8 @@ if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5])

['toHex', 'toName'].forEach(function(type) {
var pattern = "(" + Object.keys(CleanCSS.colors[type]).join('|') + ")";
var pattern = '(' + Object.keys(CleanCSS.colors[type]).join('|') + ')';
var colorSwitcher = function(match, prefix, colorValue, suffix) {
return prefix + CleanCSS.colors[type][colorValue] + suffix;
return prefix + CleanCSS.colors[type][colorValue.toLowerCase()] + suffix;
};
replace(new RegExp("([ :,\\(])" + pattern + "([;\\}!\\) ])", 'g'), colorSwitcher);
replace(new RegExp("(,)" + pattern + "(,)", 'g'), colorSwitcher);
replace(new RegExp('([ :,\\(])' + pattern + '([;\\}!\\) ])', 'ig'), colorSwitcher);
replace(new RegExp('(,)' + pattern + '(,)', 'ig'), colorSwitcher);
});

@@ -194,7 +234,2 @@

// IE shorter filters, but only if single (IE 7 issue)
replace(/progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\([^\)]+\))([;}'"])/g, function(match, filter, args, suffix) {
return filter.toLowerCase() + args + suffix;
});
// zero + unit to zero

@@ -212,5 +247,7 @@ replace(/(\s|:|,)0(?:px|em|ex|cm|mm|in|pt|pc|%)/g, '$1' + '0');

var tokens = colorDef.split(',');
if (tokens[1] == "0") tokens[1] = '0%';
if (tokens[2] == "0") tokens[2] = '0%';
return colorFunction + "(" + tokens.join(',') + ")";
if (tokens[1] == '0')
tokens[1] = '0%';
if (tokens[2] == '0')
tokens[2] = '0%';
return colorFunction + '(' + tokens.join(',') + ')';
});

@@ -230,5 +267,5 @@

var shorthandRegex = function(repeats, hasSuffix) {
var pattern = "(padding|margin|border\\-width|border\\-color|border\\-style|border\\-radius):";
var pattern = '(padding|margin|border\\-width|border\\-color|border\\-style|border\\-radius):';
for (var i = 0; i < repeats; i++) {
pattern += "([\\d\\w\\.%#\\(\\),]+)" + (i < repeats - 1 ? ' ' : '');
pattern += '([\\d\\w\\.%#\\(\\),]+)' + (i < repeats - 1 ? ' ' : '');
}

@@ -244,3 +281,3 @@ return new RegExp(pattern + (hasSuffix ? '([;}])' : ''), 'g');

return property + ':' + size1 + ' ' + size2;
else if (size2 == size4)
else if (size2 === size4)
return property + ':' + size1 + ' ' + size2 + ' ' + size3;

@@ -264,3 +301,3 @@ else

if (size1 === size2)
return property + ":" + size1 + suffix;
return property + ':' + size1 + suffix;
else

@@ -273,17 +310,2 @@ return match;

// move first charset to the beginning
replace(function moveCharset() {
// get first charset in stylesheet
var match = data.match(/@charset [^;]+;/);
var firstCharset = match ? match[0] : '';
// remove all charsets
data = data.replace(/@charset [^;]+;\n?/g, '');
// reattach first charset
if (firstCharset !== '') {
data = firstCharset + (options.keepBreaks ? lineBreak : '') + data;
}
});
if (options.removeEmpty) {

@@ -300,15 +322,25 @@ // empty elements

// Restore special comments, content content, and spaces inside calc back
var specialCommentsCount = context.specialComments.length;
// Restore spaces inside calc back
replace(/calc\([^\}]+\}/g, function(match) {
return match.replace(/\+/g, ' + ');
});
replace(/__CSSCOMMENT__/g, function() {
// Restore urls, content content, and special comments (in that order)
replace(/__URL__/g, function() {
return context.urlBlocks.shift();
});
replace(/__CSSFREETEXT__/g, function() {
return context.freeTextBlocks.shift();
});
var specialCommentsCount = context.specialComments.length;
var breakSuffix = options.keepBreaks ? lineBreak : '';
replace(new RegExp('__CSSCOMMENT__(' + lineBreak + '| )?', 'g'), function() {
switch (options.keepSpecialComments) {
case '*':
return context.specialComments.shift();
return context.specialComments.shift() + breakSuffix;
case 1:
return context.specialComments.length == specialCommentsCount ?
context.specialComments.shift() :
context.specialComments.shift() + breakSuffix :
'';

@@ -319,4 +351,15 @@ case 0:

});
replace(/__CSSCONTENT__/g, function() {
return context.contentBlocks.shift();
// move first charset to the beginning
replace(function moveCharset() {
// get first charset in stylesheet
var match = data.match(/@charset [^;]+;/);
var firstCharset = match ? match[0] : null;
if (!firstCharset)
return;
// reattach first charset and remove all subsequent
data = firstCharset +
(options.keepBreaks ? lineBreak : '') +
data.replace(new RegExp('@charset [^;]+;(' + lineBreak + ')?', 'g'), '');
});

@@ -328,2 +371,59 @@

// Inlines all imports taking care of repetitions, unknown files, and cilcular dependencies
_inlineImports: function(data, options) {
var tempData = [];
var nextStart = 0;
var nextEnd = 0;
var cursor = 0;
options.relativeTo = options.relativeTo || options.root;
options.visited = options.visited || [];
var inlinedFile = function() {
var importedFile = data
.substring(data.indexOf('(', nextStart) + 1, nextEnd)
.replace(/['"]/g, '');
if (/^(http|https):\/\//.test(importedFile))
return "@import url(" + importedFile + ");";
var relativeTo = importedFile[0] == '/' ?
options.root :
options.relativeTo;
var fullPath = path.resolve(path.join(relativeTo, importedFile));
if (existsSync(fullPath) && fs.statSync(fullPath).isFile() && options.visited.indexOf(fullPath) == -1) {
options.visited.push(fullPath);
var importedData = fs.readFileSync(fullPath, 'utf8');
return CleanCSS._inlineImports(importedData, {
root: options.root,
relativeTo: path.dirname(fullPath),
visited: options.visited
});
} else {
return '';
}
};
for (; nextEnd < data.length; ) {
nextStart = data.indexOf('@import url(', cursor);
if (nextStart == -1)
break;
nextEnd = data.indexOf(')', nextStart);
if (nextEnd == -1)
break;
tempData.push(data.substring(cursor, nextStart));
tempData.push(inlinedFile());
cursor = nextEnd + 2;
}
return tempData.length > 0 ?
tempData.join('') + data.substring(cursor, data.length) :
data;
},
// Strip special comments (/*! ... */) by replacing them by __CSSCOMMENT__ marker

@@ -333,6 +433,6 @@ // for further restoring. Plain comments are removed. It's done by scanning datq using

_stripComments: function(context, data) {
var tempData = [],
nextStart = 0,
nextEnd = 0,
cursor = 0;
var tempData = [];
var nextStart = 0;
var nextEnd = 0;
var cursor = 0;

@@ -359,71 +459,69 @@ for (; nextEnd < data.length; ) {

// Strip content tags by replacing them by the __CSSCONTENT__
// Strip content tags by replacing them by the __CSSFREETEXT__
// marker for further restoring. It's done via string scanning
// instead of regexps to speed up the process.
_stripContent: function(context, data) {
var tempData = [],
nextStart = 0,
nextEnd = 0,
cursor = 0,
matchedParenthesis = null;
var allowedPrefixes = [' ', '{', ';', this.lineBreak];
var skipBy = 'content'.length;
_stripFreeText: function(context, data) {
var tempData = [];
var nextStart = 0;
var nextEnd = 0;
var cursor = 0;
var matchedParenthesis = null;
var singleParenthesis = "'";
var doubleParenthesis = '"';
var dataLength = data.length;
// Find either first (matchedParenthesis == null) or second matching
// parenthesis so that we can determine boundaries of content block.
var nextParenthesis = function(pos) {
var min,
max = data.length;
for (; nextEnd < data.length; ) {
var nextStartSingle = data.indexOf(singleParenthesis, nextEnd + 1);
var nextStartDouble = data.indexOf(doubleParenthesis, nextEnd + 1);
if (matchedParenthesis) {
min = data.indexOf(matchedParenthesis, pos);
if (min == -1)
min = max;
if (nextStartSingle == -1)
nextStartSingle = dataLength;
if (nextStartDouble == -1)
nextStartDouble = dataLength;
if (nextStartSingle < nextStartDouble) {
nextStart = nextStartSingle;
matchedParenthesis = singleParenthesis;
} else {
var next1 = data.indexOf("'", pos);
var next2 = data.indexOf('"', pos);
if (next1 == -1)
next1 = max;
if (next2 == -1)
next2 = max;
min = next1 > next2 ? next2 : next1;
nextStart = nextStartDouble;
matchedParenthesis = doubleParenthesis;
}
if (min == max)
return -1;
if (nextStart == -1)
break;
if (matchedParenthesis) {
matchedParenthesis = null;
return min;
} else {
// check if there's anything else between pos and min
// that doesn't match ':' or whitespace
if (/[^:\s]/.test(data.substring(pos, min)))
return -1;
nextEnd = data.indexOf(matchedParenthesis, nextStart + 1);
if (nextStart == -1 || nextEnd == -1)
break;
matchedParenthesis = data.charAt(min);
return min + 1;
}
};
tempData.push(data.substring(cursor, nextStart));
tempData.push('__CSSFREETEXT__');
context.freeTextBlocks.push(data.substring(nextStart, nextEnd + 1));
cursor = nextEnd + 1;
}
return tempData.length > 0 ?
tempData.join('') + data.substring(cursor, data.length) :
data;
},
// Strip urls by replacing them by the __URL__
// marker for further restoring. It's done via string scanning
// instead of regexps to speed up the process.
_stripUrls: function(context, data) {
var nextStart = 0;
var nextEnd = 0;
var cursor = 0;
var tempData = [];
for (; nextEnd < data.length; ) {
nextStart = data.indexOf('content', nextEnd);
nextStart = data.indexOf('url(', nextEnd);
if (nextStart == -1)
break;
// skip by `skipBy` bytes if matched declaration is not a property but ID, class name or a some substring
if (allowedPrefixes.indexOf(data[nextStart - 1]) == -1) {
nextEnd += skipBy;
continue;
}
nextEnd = data.indexOf(')', nextStart);
nextStart = nextParenthesis(nextStart + skipBy);
nextEnd = nextParenthesis(nextStart);
if (nextStart == -1 || nextEnd == -1)
break;
tempData.push(data.substring(cursor, nextStart - 1));
tempData.push('__CSSCONTENT__');
context.contentBlocks.push(data.substring(nextStart - 1, nextEnd + 1));
tempData.push(data.substring(cursor, nextStart));
tempData.push('__URL__');
context.urlBlocks.push(data.substring(nextStart, nextEnd + 1));
cursor = nextEnd + 1;

@@ -435,2 +533,35 @@ }

data;
},
// HSL to RGB converter. Both methods taken and adapted from:
// http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
_hslToRgb: function(h, s, l) {
var r, g, b;
h = ~~h / 360;
s = ~~s / 100;
l = ~~l / 100;
if (s === 0) {
r = g = b = l; // achromatic
} else {
var q = l < 0.5 ?
l * (1 + s) :
l + s - l * s;
var p = 2 * l - q;
r = this._hueToRgb(p, q, h + 1/3);
g = this._hueToRgb(p, q, h);
b = this._hueToRgb(p, q, h - 1/3);
}
return [~~(r * 255), ~~(g * 255), ~~(b * 255)];
},
_hueToRgb: function(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}

@@ -437,0 +568,0 @@ };

{
"name": "clean-css",
"version": "1.0.0",
"author": "Jakub Pawlowicz <jakub@goalsmashers.com> (http://twitter.com/GoalSmashers)",
"description": "A well-tested CSS minifier",
"keywords": ["css", "minifier"],
"keywords": [
"css",
"minifier"
],
"homepage": "https://github.com/GoalSmashers/clean-css",
"repository": {
"type" : "git",
"url" : "https://github.com/GoalSmashers/clean-css.git"
"type": "git",
"url": "https://github.com/GoalSmashers/clean-css.git"
},
"version": "0.10.2",
"main": "index.js",
"bin": {
"cleancss": "./bin/cleancss"
},
"main": "index.js",
"scripts": {

@@ -27,7 +30,9 @@ "bench": "node test/bench.js",

"vows": "0.7.x",
"jshint": "0.9.x"
"jshint": "1.1.x"
},
"engines": {
"node": ">=0.6.0"
}
},
"readmeFilename": "README.md",
"license": "MIT"
}

@@ -1,2 +0,4 @@

[![build status](https://secure.travis-ci.org/GoalSmashers/clean-css.png)](http://travis-ci.org/GoalSmashers/clean-css)
[![NPM version](https://badge.fury.io/js/clean-css.png)](http://badge.fury.io/js/clean-css)
[![Build Status](https://secure.travis-ci.org/GoalSmashers/clean-css.png)](http://travis-ci.org/GoalSmashers/clean-css)
[![Dependency Status](https://gemnasium.com/GoalSmashers/clean-css.png)](https://gemnasium.com/GoalSmashers/clean-css)

@@ -15,4 +17,4 @@ ## What is clean-css?

```
node 0.6.0+ on UN*X (fully tested on OS X 10.6+ and CentOS)
node 0.8.0+ on Windows
node.js 0.6.0+ on UN*X (fully tested on OS X 10.6+ and CentOS)
node.js 0.8.0+ on Windows
```

@@ -28,15 +30,17 @@

Clean-css accepts the following command line arguments (please make sure you use `<source-file>` as the
very last argument to avoid potential issues):
Clean-css accepts the following command line arguments (please make sure
you use `<source-file>` as the very last argument to avoid potential issues):
```
cleancss [options] <source-file>
-h, --help Output usage information
-v, --version Output the version number
-e, --remove-empty Remove empty declarations (e.g. a{})
-b, --keep-line-breaks Keep line breaks
--s0 Remove all special comments (i.e. /*! special comment */)
--s1 Remove all special comments but the first one
-r, --root [root-path] Set a root path to which resolve absolute @import rules
-o, --output [output-file] Use [output-file] as output instead of STDOUT
```
* `-h`, `--help` output usage information
* `-v`, `--version` output the version number
* `-e`, `--remove-empty` Remove empty declarations (e.g. `a{}`)
* `-b`, `--keep-line-breaks` Keep line breaks
* `--s0` Remove all special comments (i.e. `/*! special comment */`)
* `--s1` Remove all special comments but the first one
* `-o`, `--output [output-file]` Use [output-file] as output instead of stdout

@@ -60,3 +64,3 @@ #### Examples:

```
```bash
cat one.css two.css three.css | cleancss -o merged-and-minified.css

@@ -67,3 +71,3 @@ ```

```
```bat
type one.css two.css three.css | cleancss -o merged-and-minified.css

@@ -74,3 +78,3 @@ ```

```
```bash
cat one.css two.css three.css | cleancss | gzip -9 -c > merged-minified-and-gzipped.css.gz

@@ -100,3 +104,3 @@ ```

* `npm run bench` for clean-css benchmarks (see test/bench.js for details)
* `npm run bench` for clean-css benchmarks (see [test/bench.js](/test/bench.js) for details)
* `npm run check` to check JS sources with [JSHint](https://github.com/jshint/jshint/)

@@ -124,3 +128,3 @@ * `npm test` for the test suite

* Jan Michael Alonzo ([@jmalonzo](https://github.com/jmalonzo)) for a patch
removing node's old 'sys' package.
removing node.js's old 'sys' package.
* [@XhmikosR](https://github.com/XhmikosR) for suggesting new features

@@ -132,2 +136,2 @@ (option to remove special comments and strip out URLs quotation) and pointing

Clean-css is released under the [MIT License](http://opensource.org/licenses/MIT).
Clean-css is released under the [MIT License](/LICENSE).

@@ -1,6 +0,6 @@

var vows = require('vows'),
path = require('path'),
fs = require('fs'),
assert = require('assert'),
cleanCSS = require('../index');
var vows = require('vows');
var path = require('path');
var fs = require('fs');
var assert = require('assert');
var cleanCSS = require('../index');

@@ -11,4 +11,6 @@ var lineBreak = process.platform == 'win32' ? /\r\n/g : /\n/g;

var context = {};
fs.readdirSync(path.join(__dirname, 'data')).forEach(function(filename) {
if (/min.css$/.exec(filename)) return;
var dir = path.join(__dirname, 'data');
fs.readdirSync(dir).forEach(function(filename) {
if (/min.css$/.exec(filename) || !fs.statSync(path.join(dir, filename)).isFile())
return;
var testName = filename.split('.')[0];

@@ -23,3 +25,4 @@

plain: fs.readFileSync(plainPath, 'utf-8'),
minimized: fs.readFileSync(minPath, 'utf-8')
minimized: fs.readFileSync(minPath, 'utf-8'),
root: path.dirname(plainPath)
};

@@ -31,3 +34,4 @@ }

removeEmpty: true,
keepBreaks: true
keepBreaks: true,
root: data.root
});

@@ -34,0 +38,0 @@

@@ -1,6 +0,6 @@

var cleanCSS = require('../index'),
bigcss = require('fs').readFileSync(require('path').join(__dirname, 'data', 'big.css'), 'utf8');
var cleanCSS = require('../index');
var bigcss = require('fs').readFileSync(require('path').join(__dirname, 'data', 'big.css'), 'utf8');
if (!process.hrtime) {
console.log("process.hrtime() (node > 0.7.6) is required for benchmarking");
console.log('process.hrtime() (node.js > 0.7.6) is required for benchmarking');
process.exit(1);

@@ -13,2 +13,2 @@ }

var itTook = process.hrtime(start);
console.log('complete minification: %d ms', 1000 * itTook[0] + itTook[1] / 1000000.0);
console.log('complete minification: %d ms', 1000 * itTook[0] + itTook[1] / 1000000.0);

@@ -15,3 +15,3 @@ var vows = require('vows'),

// We add __DIRECT__=1 to force binary into 'non-piped' mode
exec("__DIRECT__=1 ./bin/cleancss " + options, this.callback);
exec('__DIRECT__=1 ./bin/cleancss ' + options, this.callback);
};

@@ -26,3 +26,3 @@ return context;

context.topic = function() {
exec("echo \"" + css + "\" | ./bin/cleancss " + options, this.callback);
exec('echo "' + css + '" | ./bin/cleancss ' + options, this.callback);
};

@@ -41,3 +41,12 @@ return context;

assert.equal(/Usage:/.test(stdout), true);
}
},
'should output one file example': function(error, stdout) {
assert.equal(stdout.indexOf('cleancss -o one-min.css one.css') > -1, true);
},
'should output multiple files example': function(error, stdout) {
assert.equal(stdout.indexOf('cat one.css two.css three.css | cleancss -o merged-and-minified.css') > -1, true);
},
'should output gzipping multiple files example': function(error, stdout) {
assert.equal(stdout.indexOf('cat one.css two.css three.css | cleancss | gzip -9 -c > merged-minified-and-gzipped.css.gz') > -1, true);
},
}),

@@ -47,8 +56,8 @@ 'version': binaryContext('-v', {

var version = JSON.parse(fs.readFileSync('./package.json')).version;
assert.equal(stdout, version + "\n");
assert.equal(stdout, version + '\n');
}
}),
'stdin': pipedContext("a{color: #f00}", '', {
'stdin': pipedContext('a{color: #f00}', '', {
'should output data': function(error, stdout) {
assert.equal(stdout, "a{color:red}");
assert.equal(stdout, 'a{color:red}');
}

@@ -58,3 +67,3 @@ }),

'should preserve content': function(error, stdout) {
assert.equal(stdout, "a{}");
assert.equal(stdout, 'a{}');
}

@@ -64,3 +73,3 @@ }),

'should keep the 2nd comment': function(error, stdout) {
assert.equal(stdout, "/*!1st*/a{}");
assert.equal(stdout, '/*!1st*/a{}');
}

@@ -70,3 +79,3 @@ }),

'should keep the 2nd comment': function(error, stdout) {
assert.equal(stdout, "a{}");
assert.equal(stdout, 'a{}');
}

@@ -76,5 +85,15 @@ }),

'should preserve content': function(error, stdout) {
assert.equal(stdout, "");
assert.equal(stdout, '');
}
}),
'no relative to path': binaryContext('./test/data/partials-absolute/base.css', {
'should not be able to resolve it fully': function(error, stdout) {
assert.equal(stdout, '.sub{padding:0}.base{margin:0}');
}
}),
'relative to path': binaryContext('-r ./test/data ./test/data/partials-absolute/base.css', {
'should be able to resolve it': function(error, stdout) {
assert.equal(stdout, '.base2{border-width:0}.sub{padding:0}.base{margin:0}');
}
}),
'from source': binaryContext('./test/data/reset.css', {

@@ -86,3 +105,3 @@ 'should minimize': function(error, stdout) {

}),
'to file': binaryContext('-o reset-min.css ./test/data/reset.css', {
'to file': binaryContext('-o ./reset-min.css ./test/data/reset.css', {
'should give no output': function(error, stdout) {

@@ -98,7 +117,7 @@ assert.equal(stdout, '');

if (isWindows)
exec('del /q /f reset-min.css');
exec('del /q /f ./reset-min.css');
else
exec('rm reset-min.css');
exec('rm ./reset-min.css');
}
})
});
});

@@ -1,4 +0,4 @@

var vows = require('vows'),
assert = require('assert'),
CleanCSS = require('../index');
var vows = require('vows');
var assert = require('assert');
var CleanCSS = require('../index');

@@ -5,0 +5,0 @@ vows.describe('clean-custom')

@@ -1,4 +0,5 @@

var vows = require('vows'),
assert = require('assert'),
cleanCSS = require('../index');
var vows = require('vows');
var assert = require('assert');
var path = require('path');
var cleanCSS = require('../index');

@@ -16,6 +17,6 @@ var lineBreak = process.platform == 'win32' ? '\r\n' : '\n';

var transformation = groups[g];
if (typeof transformation == 'string') transformation = [transformation, transformation];
if (!transformation[0].push) {
if (typeof transformation == 'string')
transformation = [transformation, transformation];
if (!transformation[0].push)
transformation = [[transformation[0], transformation[1]]];
}

@@ -113,8 +114,8 @@ for (var i = 0, c = transformation.length; i < c; i++) {

'before colon': [
"#test{padding-left :0}",
"#test{padding-left:0}"
'#test{padding-left :0}',
'#test{padding-left:0}'
],
'before colon but not selectors #1': "div :before{}",
'before colon but not selectors #2': "div ::-webkit-search-decoration{}",
'before colon but not selectors #3': "div :after{color:red}",
'before colon but not selectors #1': 'div :before{}',
'before colon but not selectors #2': 'div ::-webkit-search-decoration{}',
'before colon but not selectors #3': 'div :after{color:red}',
'windows breaks': [

@@ -163,4 +164,14 @@ 'div>a{color:red\r\n }',

"@charset 'utf-8';" + lineBreak + "div :before{display:block}" + lineBreak + "a{color:#f10}"
],
'charset with double line break': [
"@charset 'utf-8';" + lineBreak + lineBreak + "a{}",
"@charset 'utf-8';" + lineBreak + "a{}"
]
}, { keepBreaks: true }),
'line breaks and important comments': cssContext({
'charset to beginning with comment removal': [
"/*! some comment */" + lineBreak + lineBreak + "@charset 'utf-8';" + lineBreak + lineBreak + "a{}",
"@charset 'utf-8';" + lineBreak + "a{}"
]
}, { keepBreaks: true, keepSpecialComments: 0 }),
'selectors': cssContext({

@@ -233,2 +244,6 @@ 'remove spaces around selectors': [

'a{color:red}'
],
'move charset before': [
"/*! some comment */" + lineBreak + lineBreak + "@charset 'utf-8';" + lineBreak + lineBreak + "a{}",
"@charset 'utf-8';a{}"
]

@@ -426,3 +441,3 @@ }, { keepSpecialComments: 0 }),

'shorten rgb to standard hexadecimal format': [
'a{ color:rgb (5, 10, 15) }',
'a{ color:rgb(5, 10, 15) }',
'a{color:#050a0f}'

@@ -462,2 +477,10 @@ ],

],
'upper case hex value to color name if shorter': [
'p{color:#F00}',
'p{color:red}'
],
'upper case long hex value to color name if shorter': [
'p{color:#FF0000}',
'p{color:red}'
],
'hex value to color name in borders': [

@@ -490,9 +513,36 @@ 'p{border:1px solid #f00}',

'colors and parentheses': 'a{background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6))}',
'hsl percents': 'a{color:hsl(1,0%,0%)}',
'hsla percents': 'a{color:hsl(1,0%,0%)}',
'hsl one percent': 'a{color:hsl(80,100%,0%)}',
'hsla custom ': 'a{color:hsl(80,30%,50%,.5)}',
'colors in ie filters': 'a{filter:chroma(color=#ffffff)}',
'colors in ie filters 2': "a{progid:DXImageTransform.Microsoft.gradient(startColorstr='#cccccc', endColorstr='#000000')}",
'colors in ie filters 3': "a{progid:DXImageTransform.Microsoft.gradient(startColorstr='#DDDDDD', endColorstr='#333333')}"
'colors in ie filters 3': "a{progid:DXImageTransform.Microsoft.gradient(startColorstr='#DDDDDD', endColorstr='#333333')}",
'hsla percents': 'a{color:hsla(1,0%,0%,.5)}',
'hsla custom ': 'a{color:hsl(80,30%,50%,.5)}',
'hsl to hex #1': [
'a{color:hsl(0,0%,0%)}',
'a{color:#000}'
],
'hsl to hex #2': [
'a{color:hsl(0,100%,100%)}',
'a{color:#fff}'
],
'hsl to hex #3': [
'a{color:hsl(240,100%,50%)}',
'a{color:#00f}'
],
'hsl to hex #4': [
'a{color:hsl(240,100%,50%)}',
'a{color:#00f}'
],
'hsl to hex #5': [
'a{color:hsl(120,100%,25%)}',
'a{color:#007f00}'
],
'hsl to hex #6': [
'a{color:hsl(99,66%,33%)}',
'a{color:#438b1c}'
],
'hsl to hex #7': [
'a{color:hsl(360,100%,50%)}',
'a{color:red}'
],
'hsla not to hex': 'a{color:hsl(99,66%,33%,.5)}'
}),

@@ -538,2 +588,16 @@ 'font weights': cssContext({

"url(../fonts/d90b3358-e1e2-4abb-ba96-356983a54c22.svg#d90b3358-e1e2-4abb-ba96-356983a54c22)"
],
'keep urls from being stripped down #1': 'a{background:url(/image-1.0.png)}',
'keep urls from being stripped down #2': "a{background:url(/image-white.png)}",
'keep urls from being stripped down #3': "a{background:#eee url(libraries/jquery-ui-1.10.1.custom/images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x}",
'keep __URL__ in comments (so order is important)': '/*! __URL__ */a{}',
'strip new line in urls': [
'a{background:url(/very/long/\
path)}',
'a{background:url(/very/long/path)}'
],
'strip new line in urls which could be unquoted': [
'a{background:url("/very/long/\
path")}',
'a{background:url(/very/long/path)}'
]

@@ -599,3 +663,3 @@ }),

'should keep quotation if whitespace inside': 'div[data-type^=\'object 1\']{border-color:red}',
'should keep quotations if special characters inside': 'a[data-type="object_1"]{color:red}a[data-target="#some-place"]{color:red}',
'should keep quotations if special characters inside': 'a[data-type="object+1"]{color:red}a[data-target="#some-place"]{color:red}',
'should keep quotation if is a number': 'div[data-number=\'1\']{border-color:red}',

@@ -615,2 +679,14 @@ 'should keep quotation if starts with a number': 'div[data-type^=\'1something\']{border-color:red}',

'a[data-href*=object1]{border-color:red}a[data-href|=object2]{border-color:#0f0}'
],
'should keep special characters inside attributes #1': "a[data-css='color:white']",
'should keep special characters inside attributes #2': 'a[href="/version-0.01.html"]',
'should strip new lines inside attributes': [
".test[title='my very long \
title']",
".test[title='my very long title']"
],
'should strip new lines inside attributes which can be unquoted': [
".test[title='my_very_long_\
title']",
".test[title=my_very_long_title]"
]

@@ -644,2 +720,6 @@ }),

"@charset 'utf-8';div :before{display:block}a{color:#f10}"
],
'charset and space after': [
"@charset 'utf-8';" + lineBreak + lineBreak + "a{}",
"@charset 'utf-8';a{}"
]

@@ -651,2 +731,6 @@ }),

"body{background-color:#fff!important}"
],
'space between ! and important': [
"body{background-color:#fff ! important}",
"body{background-color:#fff!important}"
]

@@ -681,3 +765,72 @@ }),

'empty #4': 'a{color:#fff}div{}p{line-height:2em}'
})
}).export(module);
}),
'@import': cssContext({
'empty': [
"@import url();",
""
],
'of an unknown file': [
"@import url('fake.css');",
""
],
'of a http file': "@import url(http://pro.goalsmashers.com/test.css);",
'of a https file': [
"@import url('https://pro.goalsmashers.com/test.css');",
"@import url(https://pro.goalsmashers.com/test.css);"
],
'of a directory': [
"@import url(test/data/partials);",
""
],
'of a real file': [
"@import url(test/data/partials/one.css);",
".one{color:red}"
],
'of a real file twice': [
"@import url(test/data/partials/one.css);@import url(test/data/partials/one.css);",
".one{color:red}"
],
'of a real file with current path prefix': [
"@import url(./test/data/partials/one.css);",
".one{color:red}"
],
'of a real file with quoted path': [
"@import url('test/data/partials/one.css');",
".one{color:red}"
],
'of more files': [
"@import url(test/data/partials/one.css);\n\na{}\n\n@import url(test/data/partials/extra/three.css);",
".one{color:red}a{}.three{color:#0f0}"
],
'of multi-level, circular dependency file': [
"@import url(test/data/partials/two.css);",
".one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}"
]
}),
'@import with absolute paths': cssContext({
'of an unknown file': [
"@import url(/fake.css);",
""
],
'of a real file': [
"@import url(/partials/one.css);",
".one{color:red}"
],
'of a real file with quoted paths': [
"@import url(\"/partials/one.css\");",
".one{color:red}"
],
'of two files with mixed paths': [
"@import url(/partials/one.css);a{}@import url(partials/extra/three.css);",
".one{color:red}a{}.three{color:#0f0}"
],
'of a multi-level, circular dependency file': [
"@import url(/partials/two.css);",
".one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}"
],
'of a multi-level, circular dependency file with mixed paths': [
"@import url(/partials-absolute/base.css);",
".base2{border-width:0}.sub{padding:0}.base{margin:0}"
]
}, { root: path.join(process.cwd(), 'test', 'data') })
}).export(module);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc