ruby-clean-css 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitmodules +3 -0
- data/EXAMPLE.md +25 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +30 -0
- data/LICENSE +19 -0
- data/README.md +106 -0
- data/lib/javascript/clean-css/.gitignore +4 -0
- data/lib/javascript/clean-css/.jshintignore +3 -0
- data/lib/javascript/clean-css/.jshintrc +14 -0
- data/lib/javascript/clean-css/.travis.yml +11 -0
- data/lib/javascript/clean-css/History.md +556 -0
- data/lib/javascript/clean-css/LICENSE +19 -0
- data/lib/javascript/clean-css/README.md +218 -0
- data/lib/javascript/clean-css/bin/cleancss +157 -0
- data/lib/javascript/clean-css/index.js +1 -0
- data/lib/javascript/clean-css/lib/clean.js +426 -0
- data/lib/javascript/clean-css/lib/colors/hsl-to-hex.js +64 -0
- data/lib/javascript/clean-css/lib/colors/long-to-short-hex.js +12 -0
- data/lib/javascript/clean-css/lib/colors/rgb-to-hex.js +14 -0
- data/lib/javascript/clean-css/lib/colors/shortener.js +174 -0
- data/lib/javascript/clean-css/lib/images/url-rebase.js +32 -0
- data/lib/javascript/clean-css/lib/images/url-rewriter.js +60 -0
- data/lib/javascript/clean-css/lib/imports/inliner.js +319 -0
- data/lib/javascript/clean-css/lib/properties/optimizer.js +276 -0
- data/lib/javascript/clean-css/lib/properties/override-compactor.js +116 -0
- data/lib/javascript/clean-css/lib/properties/processable.js +859 -0
- data/lib/javascript/clean-css/lib/properties/scanner.js +20 -0
- data/lib/javascript/clean-css/lib/properties/shorthand-compactor.js +244 -0
- data/lib/javascript/clean-css/lib/properties/token.js +184 -0
- data/lib/javascript/clean-css/lib/properties/validator.js +140 -0
- data/lib/javascript/clean-css/lib/selectors/empty-removal.js +30 -0
- data/lib/javascript/clean-css/lib/selectors/optimizer.js +341 -0
- data/lib/javascript/clean-css/lib/selectors/tokenizer.js +168 -0
- data/lib/javascript/clean-css/lib/text/comments.js +83 -0
- data/lib/javascript/clean-css/lib/text/escape-store.js +32 -0
- data/lib/javascript/clean-css/lib/text/expressions.js +73 -0
- data/lib/javascript/clean-css/lib/text/free.js +26 -0
- data/lib/javascript/clean-css/lib/text/name-quotes.js +37 -0
- data/lib/javascript/clean-css/lib/text/quote-scanner.js +91 -0
- data/lib/javascript/clean-css/lib/text/splitter.js +35 -0
- data/lib/javascript/clean-css/lib/text/urls.js +41 -0
- data/lib/javascript/clean-css/package.json +50 -0
- data/lib/javascript/clean-css/test/batch-test.js +56 -0
- data/lib/javascript/clean-css/test/bench.js +11 -0
- data/lib/javascript/clean-css/test/binary-test.js +323 -0
- data/lib/javascript/clean-css/test/data-bench/_partial.css +1 -0
- data/lib/javascript/clean-css/test/data-bench/complex.css +4 -0
- data/lib/javascript/clean-css/test/data/129-assets/assets/ui.css +2 -0
- data/lib/javascript/clean-css/test/data/129-assets/components/bootstrap/css/bootstrap.css +3 -0
- data/lib/javascript/clean-css/test/data/129-assets/components/bootstrap/images/glyphs.gif +0 -0
- data/lib/javascript/clean-css/test/data/129-assets/components/jquery-ui/css/style.css +6 -0
- data/lib/javascript/clean-css/test/data/129-assets/components/jquery-ui/images/next.gif +0 -0
- data/lib/javascript/clean-css/test/data/129-assets/components/jquery-ui/images/prev.gif +0 -0
- data/lib/javascript/clean-css/test/data/960-min.css +125 -0
- data/lib/javascript/clean-css/test/data/960.css +602 -0
- data/lib/javascript/clean-css/test/data/big-min.css +2984 -0
- data/lib/javascript/clean-css/test/data/big.css +13794 -0
- data/lib/javascript/clean-css/test/data/blueprint-min.css +245 -0
- data/lib/javascript/clean-css/test/data/blueprint.css +556 -0
- data/lib/javascript/clean-css/test/data/charset-mixed-with-fonts-min.css +3 -0
- data/lib/javascript/clean-css/test/data/charset-mixed-with-fonts.css +14 -0
- data/lib/javascript/clean-css/test/data/font-awesome-ie7-min.css +392 -0
- data/lib/javascript/clean-css/test/data/font-awesome-ie7.css +1203 -0
- data/lib/javascript/clean-css/test/data/font-awesome-min.css +319 -0
- data/lib/javascript/clean-css/test/data/font-awesome.css +540 -0
- data/lib/javascript/clean-css/test/data/imports-min.css +5 -0
- data/lib/javascript/clean-css/test/data/imports.css +4 -0
- data/lib/javascript/clean-css/test/data/issue-117-snippet-min.css +3 -0
- data/lib/javascript/clean-css/test/data/issue-117-snippet.css +19 -0
- data/lib/javascript/clean-css/test/data/issue-159-snippet-min.css +7 -0
- data/lib/javascript/clean-css/test/data/issue-159-snippet.css +7 -0
- data/lib/javascript/clean-css/test/data/issue-192-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-192.css +8 -0
- data/lib/javascript/clean-css/test/data/issue-198-min.css +3 -0
- data/lib/javascript/clean-css/test/data/issue-198.css +4 -0
- data/lib/javascript/clean-css/test/data/issue-232-min.css +2 -0
- data/lib/javascript/clean-css/test/data/issue-232.css +17 -0
- data/lib/javascript/clean-css/test/data/issue-241-min.css +2 -0
- data/lib/javascript/clean-css/test/data/issue-241.css +2 -0
- data/lib/javascript/clean-css/test/data/issue-304-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-304.css +4 -0
- data/lib/javascript/clean-css/test/data/issue-305-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-305.css +3 -0
- data/lib/javascript/clean-css/test/data/issue-308-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-308.css +5 -0
- data/lib/javascript/clean-css/test/data/issue-312-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-312.css +7 -0
- data/lib/javascript/clean-css/test/data/issue-337-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-337.css +4 -0
- data/lib/javascript/clean-css/test/data/line-breaks-in-attributes-min.css +2 -0
- data/lib/javascript/clean-css/test/data/line-breaks-in-attributes.css +8 -0
- data/lib/javascript/clean-css/test/data/partials-absolute/base.css +3 -0
- data/lib/javascript/clean-css/test/data/partials-absolute/base2.css +1 -0
- data/lib/javascript/clean-css/test/data/partials-absolute/extra/sub.css +3 -0
- data/lib/javascript/clean-css/test/data/partials-relative/base.css +3 -0
- data/lib/javascript/clean-css/test/data/partials-relative/extra/included.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/comment.css +2 -0
- data/lib/javascript/clean-css/test/data/partials/extra/down.gif +0 -0
- data/lib/javascript/clean-css/test/data/partials/extra/four.css +3 -0
- data/lib/javascript/clean-css/test/data/partials/extra/three.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/five.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/four.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/one.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/three.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/two.css +5 -0
- data/lib/javascript/clean-css/test/data/reset-min.css +12 -0
- data/lib/javascript/clean-css/test/data/reset.css +64 -0
- data/lib/javascript/clean-css/test/data/sample1-min.css +4 -0
- data/lib/javascript/clean-css/test/data/sample1.css +12 -0
- data/lib/javascript/clean-css/test/data/unsupported/selectors-ie7.css +20 -0
- data/lib/javascript/clean-css/test/data/unsupported/selectors-ie8.css +17 -0
- data/lib/javascript/clean-css/test/module-test.js +185 -0
- data/lib/javascript/clean-css/test/protocol-imports-test.js +409 -0
- data/lib/javascript/clean-css/test/text/splitter-test.js +20 -0
- data/lib/javascript/clean-css/test/unit-test.js +2071 -0
- data/lib/ruby-clean-css.rb +6 -0
- data/lib/ruby-clean-css/compressor.rb +142 -0
- data/lib/ruby-clean-css/exports.rb +258 -0
- data/lib/ruby-clean-css/railtie.rb +27 -0
- data/lib/ruby-clean-css/sprockets.rb +19 -0
- data/lib/ruby-clean-css/version.rb +5 -0
- data/ruby-clean-css.gemspec +30 -0
- data/test/test_compressor.rb +84 -0
- metadata +203 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2011-2014 GoalSmashers.com
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is furnished
|
8
|
+
to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
14
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
15
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
16
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
17
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
18
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
19
|
+
DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,218 @@
|
|
1
|
+
[![NPM version](https://badge.fury.io/js/clean-css.svg)](https://badge.fury.io/js/clean-css)
|
2
|
+
[![Build Status](https://secure.travis-ci.org/GoalSmashers/clean-css.svg)](https://travis-ci.org/GoalSmashers/clean-css)
|
3
|
+
[![Dependency Status](https://david-dm.org/GoalSmashers/clean-css.svg?theme=shields.io)](https://david-dm.org/GoalSmashers/clean-css)
|
4
|
+
[![devDependency Status](https://david-dm.org/GoalSmashers/clean-css/dev-status.svg?theme=shields.io)](https://david-dm.org/GoalSmashers/clean-css#info=devDependencies)
|
5
|
+
|
6
|
+
## What is clean-css?
|
7
|
+
|
8
|
+
Clean-css is a fast and efficient [Node.js](http://nodejs.org/) library for minifying CSS files.
|
9
|
+
|
10
|
+
According to [tests](http://goalsmashers.github.io/css-minification-benchmark/) it is one of the best available.
|
11
|
+
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
### What are the requirements?
|
16
|
+
|
17
|
+
```
|
18
|
+
Node.js 0.8.0+ (tested on CentOS, Ubuntu, OS X 10.6+, and Windows 7+)
|
19
|
+
```
|
20
|
+
|
21
|
+
### How to install clean-css?
|
22
|
+
|
23
|
+
```
|
24
|
+
npm install clean-css
|
25
|
+
```
|
26
|
+
|
27
|
+
### How to upgrade clean-css from 1.x to 2.x?
|
28
|
+
|
29
|
+
#### Command-line interface (CLI)
|
30
|
+
|
31
|
+
```
|
32
|
+
npm update clean-css
|
33
|
+
```
|
34
|
+
|
35
|
+
or point `package.json` to version 2.x. That's it!
|
36
|
+
|
37
|
+
#### Node.js module
|
38
|
+
|
39
|
+
Update `clean-css` as for CLI above.
|
40
|
+
Then change your JavaScript code from:
|
41
|
+
|
42
|
+
```js
|
43
|
+
var minimized = CleanCSS.process(source, options);
|
44
|
+
```
|
45
|
+
|
46
|
+
into
|
47
|
+
|
48
|
+
```js
|
49
|
+
var minimized = new CleanCSS(options).minify(source);
|
50
|
+
```
|
51
|
+
|
52
|
+
And you are done.
|
53
|
+
|
54
|
+
### How to use clean-css CLI?
|
55
|
+
|
56
|
+
Clean-css accepts the following command line arguments (please make sure
|
57
|
+
you use `<source-file>` as the very last argument to avoid potential issues):
|
58
|
+
|
59
|
+
```
|
60
|
+
cleancss [options] source-file, [source-file, ...]
|
61
|
+
|
62
|
+
-h, --help Output usage information
|
63
|
+
-v, --version Output the version number
|
64
|
+
-b, --keep-line-breaks Keep line breaks
|
65
|
+
--s0 Remove all special comments, i.e. /*! comment */
|
66
|
+
--s1 Remove all special comments but the first one
|
67
|
+
-r, --root [root-path] A root path to which resolve absolute @import rules
|
68
|
+
and rebase relative URLs
|
69
|
+
-o, --output [output-file] Use [output-file] as output instead of STDOUT
|
70
|
+
-s, --skip-import Disable @import processing
|
71
|
+
--skip-rebase Disable URLs rebasing
|
72
|
+
--skip-advanced Disable advanced optimizations - selector & property merging,
|
73
|
+
reduction, etc.
|
74
|
+
--skip-aggressive-merging Disable properties merging based on their order
|
75
|
+
--rounding-precision [value] Rounding precision, defaults to 2
|
76
|
+
-c, --compatibility [ie7|ie8] Force compatibility mode
|
77
|
+
-d, --debug Shows debug information (minification time & compression efficiency)
|
78
|
+
```
|
79
|
+
|
80
|
+
#### Examples:
|
81
|
+
|
82
|
+
To minify a **public.css** file into **public-min.css** do:
|
83
|
+
|
84
|
+
```
|
85
|
+
cleancss -o public-min.css public.css
|
86
|
+
```
|
87
|
+
|
88
|
+
To minify the same **public.css** into the standard output skip the `-o` parameter:
|
89
|
+
|
90
|
+
```
|
91
|
+
cleancss public.css
|
92
|
+
```
|
93
|
+
|
94
|
+
More likely you would like to concatenate a couple of files.
|
95
|
+
If you are on a Unix-like system:
|
96
|
+
|
97
|
+
```bash
|
98
|
+
cat one.css two.css three.css | cleancss -o merged-and-minified.css
|
99
|
+
```
|
100
|
+
|
101
|
+
On Windows:
|
102
|
+
|
103
|
+
```bat
|
104
|
+
type one.css two.css three.css | cleancss -o merged-and-minified.css
|
105
|
+
```
|
106
|
+
|
107
|
+
Or even gzip the result at once:
|
108
|
+
|
109
|
+
```bash
|
110
|
+
cat one.css two.css three.css | cleancss | gzip -9 -c > merged-minified-and-gzipped.css.gz
|
111
|
+
```
|
112
|
+
|
113
|
+
### How to use clean-css programmatically?
|
114
|
+
|
115
|
+
```js
|
116
|
+
var CleanCSS = require('clean-css');
|
117
|
+
var source = 'a{font-weight:bold;}';
|
118
|
+
var minimized = new CleanCSS().minify(source);
|
119
|
+
```
|
120
|
+
|
121
|
+
CleanCSS constructor accepts a hash as a parameter, i.e.,
|
122
|
+
`new CleanCSS(options).minify(source)` with the following options available:
|
123
|
+
|
124
|
+
* `keepSpecialComments` - `*` for keeping all (default), `1` for keeping first one only, `0` for removing all
|
125
|
+
* `keepBreaks` - whether to keep line breaks (default is false)
|
126
|
+
* `benchmark` - turns on benchmarking mode measuring time spent on cleaning up
|
127
|
+
(run `npm run bench` to see example)
|
128
|
+
* `root` - path to resolve absolute `@import` rules and rebase relative URLs
|
129
|
+
* `relativeTo` - path with which to resolve relative `@import` rules and URLs
|
130
|
+
* `processImport` - whether to process `@import` rules
|
131
|
+
* `noRebase` - whether to skip URLs rebasing
|
132
|
+
* `noAdvanced` - set to true to disable advanced optimizations - selector & property merging, reduction, etc.
|
133
|
+
* `roundingPrecision` - Rounding precision, defaults to 2.
|
134
|
+
* `compatibility` - Force compatibility mode to `ie7` or `ie8`. Defaults to not set.
|
135
|
+
* `debug` - set to true to get minification statistics under `stats` property (see `test/custom-test.js` for examples)
|
136
|
+
|
137
|
+
### How to use clean-css with build tools?
|
138
|
+
|
139
|
+
* [Broccoli](https://github.com/broccolijs/broccoli#broccoli) : [broccoli-clean-css](https://github.com/shinnn/broccoli-clean-css)
|
140
|
+
* [Brunch](http://brunch.io/) : [clean-css-brunch](https://github.com/brunch/clean-css-brunch)
|
141
|
+
* [Grunt](http://gruntjs.com) : [grunt-contrib-cssmin](https://github.com/gruntjs/grunt-contrib-cssmin)
|
142
|
+
* [Gulp](http://gulpjs.com/) : [gulp-minify-css](https://github.com/jonathanepollack/gulp-minify-css)
|
143
|
+
* [component-builder2](https://github.com/component/builder2.js) : [builder-clean-css](https://github.com/poying/builder-clean-css)
|
144
|
+
* [Metalsmith](http://metalsmith.io) : [metalsmith-clean-css](https://github.com/aymericbeaumet/metalsmith-clean-css)
|
145
|
+
|
146
|
+
### What are the clean-css' dev commands?
|
147
|
+
|
148
|
+
First clone the source, then run:
|
149
|
+
|
150
|
+
* `npm run bench` for clean-css benchmarks (see [test/bench.js](https://github.com/GoalSmashers/clean-css/blob/master/test/bench.js) for details)
|
151
|
+
* `npm run check` to check JS sources with [JSHint](https://github.com/jshint/jshint/)
|
152
|
+
* `npm test` for the test suite
|
153
|
+
|
154
|
+
## How to contribute to clean-css?
|
155
|
+
|
156
|
+
1. Fork it.
|
157
|
+
2. Add test(s) veryfying the problem.
|
158
|
+
3. Fix the problem.
|
159
|
+
4. Make sure all tests still pass (`npm test`).
|
160
|
+
5. Make sure your code doesn't break style rules (`npm run check`) and follow all [other ones](https://github.com/GoalSmashers/clean-css/wiki/Style-Guide) too.
|
161
|
+
6. Send a PR.
|
162
|
+
|
163
|
+
If you wonder where to add tests, go for:
|
164
|
+
|
165
|
+
* `test/unit-test.js` if it's a simple scenario
|
166
|
+
* `test/data/...` if it's a complex scenario (just add two files, input and expected output)
|
167
|
+
* `test/binary-test.js` if it's related to `bin/cleancss` binary
|
168
|
+
* `test/module-test.js` if it's related to importing `clean-css` as a module
|
169
|
+
* `test/protocol-imports-test.js` if it fixes anything related to protocol `@import`s
|
170
|
+
|
171
|
+
## Tips & Tricks
|
172
|
+
|
173
|
+
### How to preserve a comment block?
|
174
|
+
|
175
|
+
Use the `/*!` notation instead of the standard one `/*`:
|
176
|
+
|
177
|
+
```css
|
178
|
+
/*!
|
179
|
+
Important comments included in minified output.
|
180
|
+
*/
|
181
|
+
```
|
182
|
+
|
183
|
+
### How to rebase relative image URLs
|
184
|
+
|
185
|
+
Clean-css will handle it automatically for you (since version 1.1) in the following cases:
|
186
|
+
|
187
|
+
* When using the CLI:
|
188
|
+
1. Use an output path via `-o`/`--output` to rebase URLs as relative to the output file.
|
189
|
+
2. Use a root path via `-r`/`--root` to rebase URLs as absolute from the given root path.
|
190
|
+
3. If you specify both then `-r`/`--root` takes precendence.
|
191
|
+
* When using clean-css as a library:
|
192
|
+
1. Use a combination of `relativeTo` and `target` options for relative rebase (same as 1 in CLI).
|
193
|
+
2. Use a combination of `relativeTo` and `root` options for absolute rebase (same as 2 in CLI).
|
194
|
+
3. `root` takes precendence over `target` as in CLI.
|
195
|
+
|
196
|
+
## Acknowledgments (sorted alphabetically)
|
197
|
+
|
198
|
+
* Anthony Barre ([@abarre](https://github.com/abarre)) for improvements to
|
199
|
+
`@import` processing, namely introducing the `--skip-import` /
|
200
|
+
`processImport` options.
|
201
|
+
* Simon Altschuler ([@altschuler](https://github.com/altschuler)) for fixing
|
202
|
+
`@import` processing inside comments.
|
203
|
+
* Isaac ([@facelessuser](https://github.com/facelessuser)) for pointing out
|
204
|
+
a flaw in clean-css' stateless mode.
|
205
|
+
* Jan Michael Alonzo ([@jmalonzo](https://github.com/jmalonzo)) for a patch
|
206
|
+
removing node.js' old `sys` package.
|
207
|
+
* Timur Kristóf ([@Venemo](https://github.com/Venemo)) for an outstanding
|
208
|
+
contribution of advanced property optimizer for 2.2 release.
|
209
|
+
* Vincent Voyer ([@vvo](https://github.com/vvo)) for a patch with better
|
210
|
+
empty element regex and for inspiring us to do many performance improvements
|
211
|
+
in 0.4 release.
|
212
|
+
* [@XhmikosR](https://github.com/XhmikosR) for suggesting new features
|
213
|
+
(option to remove special comments and strip out URLs quotation) and
|
214
|
+
pointing out numerous improvements (JSHint, media queries).
|
215
|
+
|
216
|
+
## License
|
217
|
+
|
218
|
+
Clean-css is released under the [MIT License](https://github.com/GoalSmashers/clean-css/blob/master/LICENSE).
|
@@ -0,0 +1,157 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
var util = require('util');
|
4
|
+
var fs = require('fs');
|
5
|
+
var path = require('path');
|
6
|
+
var CleanCSS = require('../index');
|
7
|
+
|
8
|
+
var commands = require('commander');
|
9
|
+
|
10
|
+
var packageConfig = fs.readFileSync(path.join(path.dirname(fs.realpathSync(process.argv[1])), '../package.json'));
|
11
|
+
var buildVersion = JSON.parse(packageConfig).version;
|
12
|
+
|
13
|
+
var isWindows = process.platform == 'win32';
|
14
|
+
|
15
|
+
// Specify commander options to parse command line params correctly
|
16
|
+
commands
|
17
|
+
.version(buildVersion, '-v, --version')
|
18
|
+
.usage('[options] source-file, [source-file, ...]')
|
19
|
+
.option('-b, --keep-line-breaks', 'Keep line breaks')
|
20
|
+
.option('--s0', 'Remove all special comments, i.e. /*! comment */')
|
21
|
+
.option('--s1', 'Remove all special comments but the first one')
|
22
|
+
.option('-r, --root [root-path]', 'Set a root path to which resolve absolute @import rules')
|
23
|
+
.option('-o, --output [output-file]', 'Use [output-file] as output instead of STDOUT')
|
24
|
+
.option('-s, --skip-import', 'Disable @import processing')
|
25
|
+
.option('--skip-rebase', 'Disable URLs rebasing')
|
26
|
+
.option('--skip-advanced', 'Disable advanced optimizations - selector & property merging, reduction, etc.')
|
27
|
+
.option('--skip-aggressive-merging', 'Disable properties merging based on their order')
|
28
|
+
.option('--rounding-precision [value]', 'Rounding precision, defaults to 2', parseInt)
|
29
|
+
.option('-c, --compatibility [ie7|ie8]', 'Force compatibility mode')
|
30
|
+
.option('-t, --timeout [seconds]', 'Per connection timeout when fetching remote @imports (defaults to 5 seconds)')
|
31
|
+
.option('-d, --debug', 'Shows debug information (minification time & compression efficiency)');
|
32
|
+
|
33
|
+
commands.on('--help', function() {
|
34
|
+
util.puts(' Examples:\n');
|
35
|
+
util.puts(' %> cleancss one.css');
|
36
|
+
util.puts(' %> cleancss -o one-min.css one.css');
|
37
|
+
if (isWindows) {
|
38
|
+
util.puts(' %> type one.css two.css three.css | cleancss -o merged-and-minified.css');
|
39
|
+
} else {
|
40
|
+
util.puts(' %> cat one.css two.css three.css | cleancss -o merged-and-minified.css');
|
41
|
+
util.puts(' %> cat one.css two.css three.css | cleancss | gzip -9 -c > merged-minified-and-gzipped.css.gz');
|
42
|
+
}
|
43
|
+
util.puts('');
|
44
|
+
process.exit();
|
45
|
+
});
|
46
|
+
|
47
|
+
commands.parse(process.argv);
|
48
|
+
|
49
|
+
var options = {
|
50
|
+
sources: null,
|
51
|
+
target: null
|
52
|
+
};
|
53
|
+
var cleanOptions = {};
|
54
|
+
var fromStdin = !process.env.__DIRECT__ && !process.stdin.isTTY;
|
55
|
+
|
56
|
+
// If no sensible data passed in just print help and exit
|
57
|
+
if (!fromStdin && commands.args.length === 0) {
|
58
|
+
commands.outputHelp();
|
59
|
+
return 0;
|
60
|
+
}
|
61
|
+
|
62
|
+
// Now coerce commands into CleanCSS configuration...
|
63
|
+
if (commands.output)
|
64
|
+
cleanOptions.target = options.target = commands.output;
|
65
|
+
if (commands.keepLineBreaks)
|
66
|
+
cleanOptions.keepBreaks = true;
|
67
|
+
if (commands.s1)
|
68
|
+
cleanOptions.keepSpecialComments = 1;
|
69
|
+
if (commands.s0)
|
70
|
+
cleanOptions.keepSpecialComments = 0;
|
71
|
+
if (commands.root)
|
72
|
+
cleanOptions.root = commands.root;
|
73
|
+
if (commands.skipImport)
|
74
|
+
cleanOptions.processImport = false;
|
75
|
+
if (commands.skipRebase)
|
76
|
+
cleanOptions.noRebase = true;
|
77
|
+
if (commands.skipAdvanced)
|
78
|
+
cleanOptions.noAdvanced = true;
|
79
|
+
if (commands.skipAggressiveMerging)
|
80
|
+
cleanOptions.noAggressiveMerging = true;
|
81
|
+
if (commands.compatibility)
|
82
|
+
cleanOptions.compatibility = commands.compatibility;
|
83
|
+
if (commands.roundingPrecision !== undefined)
|
84
|
+
cleanOptions.roundingPrecision = commands.roundingPrecision;
|
85
|
+
if (commands.debug)
|
86
|
+
cleanOptions.debug = true;
|
87
|
+
if (commands.timeout)
|
88
|
+
cleanOptions.inliner = { timeout: parseFloat(commands.timeout) * 1000 };
|
89
|
+
if (commands.args.length > 0) {
|
90
|
+
var relativeTo = (cleanOptions.noRebase ? false : cleanOptions.root) || commands.args[0];
|
91
|
+
cleanOptions.relativeTo = path.dirname(path.resolve(relativeTo));
|
92
|
+
|
93
|
+
options.sources = commands.args.map(function(source) {
|
94
|
+
var isRemote = /^https?:\/\//.test(source);
|
95
|
+
|
96
|
+
if (cleanOptions.processImport === false)
|
97
|
+
source += '@shallow';
|
98
|
+
|
99
|
+
return isRemote ?
|
100
|
+
source :
|
101
|
+
path.relative(cleanOptions.relativeTo, path.resolve(source));
|
102
|
+
});
|
103
|
+
}
|
104
|
+
|
105
|
+
// ... and do the magic!
|
106
|
+
if (options.sources) {
|
107
|
+
var data = options.sources
|
108
|
+
.map(function(source) {
|
109
|
+
return '@import url(' + source + ');';
|
110
|
+
})
|
111
|
+
.join('');
|
112
|
+
minify(data);
|
113
|
+
} else {
|
114
|
+
var stdin = process.openStdin();
|
115
|
+
stdin.setEncoding('utf-8');
|
116
|
+
var data = '';
|
117
|
+
stdin.on('data', function(chunk) {
|
118
|
+
data += chunk;
|
119
|
+
});
|
120
|
+
stdin.on('end', function() {
|
121
|
+
minify(data);
|
122
|
+
});
|
123
|
+
}
|
124
|
+
|
125
|
+
function minify(data) {
|
126
|
+
new CleanCSS(cleanOptions).minify(data, function(errors, minified) {
|
127
|
+
if (cleanOptions.debug) {
|
128
|
+
console.error('Original: %d bytes', this.stats.originalSize);
|
129
|
+
console.error('Minified: %d bytes', this.stats.minifiedSize);
|
130
|
+
console.error('Efficiency: %d%', ~~(this.stats.efficiency * 10000) / 100.0);
|
131
|
+
console.error('Time spent: %dms', this.stats.timeSpent);
|
132
|
+
}
|
133
|
+
|
134
|
+
outputFeedback(this.errors, true);
|
135
|
+
outputFeedback(this.warnings);
|
136
|
+
|
137
|
+
if (this.errors.length > 0)
|
138
|
+
process.exit(1);
|
139
|
+
|
140
|
+
output(minified);
|
141
|
+
});
|
142
|
+
}
|
143
|
+
|
144
|
+
function output(minified) {
|
145
|
+
if (options.target)
|
146
|
+
fs.writeFileSync(options.target, minified, 'utf8');
|
147
|
+
else
|
148
|
+
process.stdout.write(minified);
|
149
|
+
}
|
150
|
+
|
151
|
+
function outputFeedback(messages, isError) {
|
152
|
+
var prefix = isError ? '\x1B[31mERROR\x1B[39m:' : 'WARNING:';
|
153
|
+
|
154
|
+
messages.forEach(function(message) {
|
155
|
+
console.error('%s %s', prefix, message);
|
156
|
+
});
|
157
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
module.exports = require('./lib/clean');
|
@@ -0,0 +1,426 @@
|
|
1
|
+
/**
|
2
|
+
* Clean-css - https://github.com/GoalSmashers/clean-css
|
3
|
+
* Released under the terms of MIT license
|
4
|
+
*
|
5
|
+
* Copyright (C) 2011-2014 GoalSmashers.com
|
6
|
+
*/
|
7
|
+
|
8
|
+
var ColorShortener = require('./colors/shortener');
|
9
|
+
var ColorHSLToHex = require('./colors/hsl-to-hex');
|
10
|
+
var ColorRGBToHex = require('./colors/rgb-to-hex');
|
11
|
+
var ColorLongToShortHex = require('./colors/long-to-short-hex');
|
12
|
+
|
13
|
+
var ImportInliner = require('./imports/inliner');
|
14
|
+
var UrlRebase = require('./images/url-rebase');
|
15
|
+
var EmptyRemoval = require('./selectors/empty-removal');
|
16
|
+
|
17
|
+
var CommentsProcessor = require('./text/comments');
|
18
|
+
var ExpressionsProcessor = require('./text/expressions');
|
19
|
+
var FreeTextProcessor = require('./text/free');
|
20
|
+
var UrlsProcessor = require('./text/urls');
|
21
|
+
var NameQuotesProcessor = require('./text/name-quotes');
|
22
|
+
var Splitter = require('./text/splitter');
|
23
|
+
|
24
|
+
var SelectorsOptimizer = require('./selectors/optimizer');
|
25
|
+
|
26
|
+
var CleanCSS = module.exports = function CleanCSS(options) {
|
27
|
+
options = options || {};
|
28
|
+
|
29
|
+
// back compat
|
30
|
+
if (!(this instanceof CleanCSS))
|
31
|
+
return new CleanCSS(options);
|
32
|
+
|
33
|
+
options.keepBreaks = options.keepBreaks || false;
|
34
|
+
|
35
|
+
//active by default
|
36
|
+
if (undefined === options.processImport)
|
37
|
+
options.processImport = true;
|
38
|
+
|
39
|
+
this.options = options;
|
40
|
+
this.stats = {};
|
41
|
+
this.context = {
|
42
|
+
errors: [],
|
43
|
+
warnings: [],
|
44
|
+
debug: options.debug
|
45
|
+
};
|
46
|
+
this.errors = this.context.errors;
|
47
|
+
this.warnings = this.context.warnings;
|
48
|
+
this.lineBreak = process.platform == 'win32' ? '\r\n' : '\n';
|
49
|
+
};
|
50
|
+
|
51
|
+
CleanCSS.prototype.minify = function(data, callback) {
|
52
|
+
var options = this.options;
|
53
|
+
|
54
|
+
if (Buffer.isBuffer(data))
|
55
|
+
data = data.toString();
|
56
|
+
|
57
|
+
if (options.processImport || data.indexOf('@shallow') > 0) {
|
58
|
+
// inline all imports
|
59
|
+
var self = this;
|
60
|
+
var runner = callback ?
|
61
|
+
process.nextTick :
|
62
|
+
function(callback) { return callback(); };
|
63
|
+
|
64
|
+
return runner(function() {
|
65
|
+
return new ImportInliner(self.context, options.inliner).process(data, {
|
66
|
+
localOnly: !callback,
|
67
|
+
root: options.root || process.cwd(),
|
68
|
+
relativeTo: options.relativeTo,
|
69
|
+
whenDone: function(data) {
|
70
|
+
return minify.call(self, data, callback);
|
71
|
+
}
|
72
|
+
});
|
73
|
+
});
|
74
|
+
} else {
|
75
|
+
return minify.call(this, data, callback);
|
76
|
+
}
|
77
|
+
};
|
78
|
+
|
79
|
+
var minify = function(data, callback) {
|
80
|
+
var startedAt;
|
81
|
+
var stats = this.stats;
|
82
|
+
var options = this.options;
|
83
|
+
var context = this.context;
|
84
|
+
var lineBreak = this.lineBreak;
|
85
|
+
|
86
|
+
var commentsProcessor = new CommentsProcessor(
|
87
|
+
'keepSpecialComments' in options ? options.keepSpecialComments : '*',
|
88
|
+
options.keepBreaks,
|
89
|
+
lineBreak
|
90
|
+
);
|
91
|
+
var expressionsProcessor = new ExpressionsProcessor();
|
92
|
+
var freeTextProcessor = new FreeTextProcessor();
|
93
|
+
var urlsProcessor = new UrlsProcessor();
|
94
|
+
var nameQuotesProcessor = new NameQuotesProcessor();
|
95
|
+
|
96
|
+
if (options.debug) {
|
97
|
+
this.startedAt = process.hrtime();
|
98
|
+
this.stats.originalSize = data.length;
|
99
|
+
}
|
100
|
+
|
101
|
+
var replace = function() {
|
102
|
+
if (typeof arguments[0] == 'function')
|
103
|
+
arguments[0]();
|
104
|
+
else
|
105
|
+
data = data.replace.apply(data, arguments);
|
106
|
+
};
|
107
|
+
|
108
|
+
// replace function
|
109
|
+
if (options.benchmark) {
|
110
|
+
var originalReplace = replace;
|
111
|
+
replace = function(pattern, replacement) {
|
112
|
+
var name = typeof pattern == 'function' ?
|
113
|
+
/function (\w+)\(/.exec(pattern.toString())[1] :
|
114
|
+
pattern;
|
115
|
+
|
116
|
+
var start = process.hrtime();
|
117
|
+
originalReplace(pattern, replacement);
|
118
|
+
|
119
|
+
var itTook = process.hrtime(start);
|
120
|
+
console.log('%d ms: ' + name, 1000 * itTook[0] + itTook[1] / 1000000);
|
121
|
+
};
|
122
|
+
}
|
123
|
+
|
124
|
+
if (options.debug) {
|
125
|
+
startedAt = process.hrtime();
|
126
|
+
stats.originalSize = data.length;
|
127
|
+
}
|
128
|
+
|
129
|
+
replace(function escapeComments() {
|
130
|
+
data = commentsProcessor.escape(data);
|
131
|
+
});
|
132
|
+
|
133
|
+
// replace all escaped line breaks
|
134
|
+
replace(/\\(\r\n|\n)/gm, '');
|
135
|
+
|
136
|
+
// strip parentheses in urls if possible (no spaces inside)
|
137
|
+
replace(/url\((['"])([^\)]+)['"]\)/g, function(match, quote, url) {
|
138
|
+
var unsafeDataURI = url.indexOf('data:') === 0 && url.match(/data:\w+\/[^;]+;base64,/) === null;
|
139
|
+
if (url.match(/[ \t]/g) !== null || unsafeDataURI)
|
140
|
+
return 'url(' + quote + url + quote + ')';
|
141
|
+
else
|
142
|
+
return 'url(' + url + ')';
|
143
|
+
});
|
144
|
+
|
145
|
+
// strip parentheses in animation & font names
|
146
|
+
replace(function removeQuotes() {
|
147
|
+
data = nameQuotesProcessor.process(data);
|
148
|
+
});
|
149
|
+
|
150
|
+
// strip parentheses in @keyframes
|
151
|
+
replace(/@(\-moz\-|\-o\-|\-webkit\-)?keyframes ([^{]+)/g, function(match, prefix, name) {
|
152
|
+
prefix = prefix || '';
|
153
|
+
return '@' + prefix + 'keyframes ' + (name.indexOf(' ') > -1 ? name : name.replace(/['"]/g, ''));
|
154
|
+
});
|
155
|
+
|
156
|
+
// IE shorter filters, but only if single (IE 7 issue)
|
157
|
+
replace(/progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\([^\)]+\))([;}'"])/g, function(match, filter, args, suffix) {
|
158
|
+
return filter.toLowerCase() + args + suffix;
|
159
|
+
});
|
160
|
+
|
161
|
+
replace(function escapeExpressions() {
|
162
|
+
data = expressionsProcessor.escape(data);
|
163
|
+
});
|
164
|
+
|
165
|
+
// strip parentheses in attribute values
|
166
|
+
replace(/\[([^\]]+)\]/g, function(match, content) {
|
167
|
+
var eqIndex = content.indexOf('=');
|
168
|
+
var singleQuoteIndex = content.indexOf('\'');
|
169
|
+
var doubleQuoteIndex = content.indexOf('"');
|
170
|
+
if (eqIndex < 0 && singleQuoteIndex < 0 && doubleQuoteIndex < 0)
|
171
|
+
return match;
|
172
|
+
if (singleQuoteIndex === 0 || doubleQuoteIndex === 0)
|
173
|
+
return match;
|
174
|
+
|
175
|
+
var key = content.substring(0, eqIndex);
|
176
|
+
var value = content.substring(eqIndex + 1, content.length);
|
177
|
+
|
178
|
+
if (/^['"](?:[a-zA-Z][a-zA-Z\d\-_]+)['"]$/.test(value))
|
179
|
+
return '[' + key + '=' + value.substring(1, value.length - 1) + ']';
|
180
|
+
else
|
181
|
+
return match;
|
182
|
+
});
|
183
|
+
|
184
|
+
replace(function escapeFreeText() {
|
185
|
+
data = freeTextProcessor.escape(data);
|
186
|
+
});
|
187
|
+
|
188
|
+
replace(function escapeUrls() {
|
189
|
+
data = urlsProcessor.escape(data);
|
190
|
+
});
|
191
|
+
|
192
|
+
// remove invalid special declarations
|
193
|
+
replace(/@charset [^;]+;/ig, function (match) {
|
194
|
+
return match.indexOf('@charset') > -1 ? match : '';
|
195
|
+
});
|
196
|
+
|
197
|
+
// whitespace inside attribute selectors brackets
|
198
|
+
replace(/\[([^\]]+)\]/g, function(match) {
|
199
|
+
return match.replace(/\s/g, '');
|
200
|
+
});
|
201
|
+
|
202
|
+
// line breaks
|
203
|
+
replace(/[\r]?\n/g, ' ');
|
204
|
+
|
205
|
+
// multiple whitespace
|
206
|
+
replace(/[\t ]+/g, ' ');
|
207
|
+
|
208
|
+
// multiple semicolons (with optional whitespace)
|
209
|
+
replace(/;[ ]?;+/g, ';');
|
210
|
+
|
211
|
+
// multiple line breaks to one
|
212
|
+
replace(/ (?:\r\n|\n)/g, lineBreak);
|
213
|
+
replace(/(?:\r\n|\n)+/g, lineBreak);
|
214
|
+
|
215
|
+
// remove spaces around selectors
|
216
|
+
replace(/ ([+~>]) /g, '$1');
|
217
|
+
|
218
|
+
// remove extra spaces inside content
|
219
|
+
replace(/([!\(\{\}:;=,\n]) /g, '$1');
|
220
|
+
replace(/ ([!\)\{\};=,\n])/g, '$1');
|
221
|
+
replace(/(?:\r\n|\n)\}/g, '}');
|
222
|
+
replace(/([\{;,])(?:\r\n|\n)/g, '$1');
|
223
|
+
replace(/ :([^\{\};]+)([;}])/g, ':$1$2');
|
224
|
+
|
225
|
+
// restore spaces inside IE filters (IE 7 issue)
|
226
|
+
replace(/progid:[^(]+\(([^\)]+)/g, function(match) {
|
227
|
+
return match.replace(/,/g, ', ');
|
228
|
+
});
|
229
|
+
|
230
|
+
// trailing semicolons
|
231
|
+
replace(/;\}/g, '}');
|
232
|
+
|
233
|
+
replace(function hsl2Hex() {
|
234
|
+
data = new ColorHSLToHex(data).process();
|
235
|
+
});
|
236
|
+
|
237
|
+
replace(function rgb2Hex() {
|
238
|
+
data = new ColorRGBToHex(data).process();
|
239
|
+
});
|
240
|
+
|
241
|
+
replace(function longToShortHex() {
|
242
|
+
data = new ColorLongToShortHex(data).process();
|
243
|
+
});
|
244
|
+
|
245
|
+
replace(function shortenColors() {
|
246
|
+
data = new ColorShortener(data).process();
|
247
|
+
});
|
248
|
+
|
249
|
+
// replace font weight with numerical value
|
250
|
+
replace(/(font\-weight|font):(normal|bold)([ ;\}!])(\w*)/g, function(match, property, weight, suffix, next) {
|
251
|
+
if (suffix == ' ' && (next.indexOf('/') > -1 || next == 'normal' || /[1-9]00/.test(next)))
|
252
|
+
return match;
|
253
|
+
|
254
|
+
if (weight == 'normal')
|
255
|
+
return property + ':400' + suffix + next;
|
256
|
+
else if (weight == 'bold')
|
257
|
+
return property + ':700' + suffix + next;
|
258
|
+
else
|
259
|
+
return match;
|
260
|
+
});
|
261
|
+
|
262
|
+
// minus zero to zero
|
263
|
+
// repeated twice on purpose as if not it doesn't process rgba(-0,-0,-0,-0) correctly
|
264
|
+
var zerosRegexp = /(\s|:|,|\()\-0([^\.])/g;
|
265
|
+
replace(zerosRegexp, '$10$2');
|
266
|
+
replace(zerosRegexp, '$10$2');
|
267
|
+
|
268
|
+
// zero(s) + value to value
|
269
|
+
replace(/(\s|:|,)0+([1-9])/g, '$1$2');
|
270
|
+
|
271
|
+
// round pixels to 2nd decimal place
|
272
|
+
var precision = 'roundingPrecision' in options ? options.roundingPrecision : 2;
|
273
|
+
var decimalMultiplier = Math.pow(10, precision);
|
274
|
+
replace(new RegExp('\\.(\\d{' + (precision + 1) + ',})px', 'g'), function(match, decimalPlaces) {
|
275
|
+
return precision === 0 ?
|
276
|
+
'px' :
|
277
|
+
'.' + Math.round(parseFloat('.' + decimalPlaces) * decimalMultiplier) / decimalMultiplier + 'px';
|
278
|
+
});
|
279
|
+
|
280
|
+
// .0 to 0
|
281
|
+
// repeated twice on purpose as if not it doesn't process {padding: .0 .0 .0 .0} correctly
|
282
|
+
var leadingDecimalRegexp = /(\D)\.0+(\D)/g;
|
283
|
+
replace(leadingDecimalRegexp, '$10$2');
|
284
|
+
replace(leadingDecimalRegexp, '$10$2');
|
285
|
+
|
286
|
+
// fraction zeros removal
|
287
|
+
replace(/\.([1-9]*)0+(\D)/g, function(match, nonZeroPart, suffix) {
|
288
|
+
return (nonZeroPart.length > 0 ? '.' : '') + nonZeroPart + suffix;
|
289
|
+
});
|
290
|
+
|
291
|
+
// zero + unit to zero
|
292
|
+
var units = ['px', 'em', 'ex', 'cm', 'mm', 'in', 'pt', 'pc', '%'];
|
293
|
+
if (['ie7', 'ie8'].indexOf(options.compatibility) == -1)
|
294
|
+
units.push('rem');
|
295
|
+
|
296
|
+
replace(new RegExp('(\\s|:|,)\\-?0(?:' + units.join('|') + ')', 'g'), '$1' + '0');
|
297
|
+
replace(new RegExp('(\\s|:|,)\\-?(\\d+)\\.(\\D)', 'g'), '$1$2$3');
|
298
|
+
replace(new RegExp('rect\\(0(?:' + units.join('|') + ')', 'g'), 'rect(0');
|
299
|
+
|
300
|
+
// restore % in rgb/rgba and hsl/hsla
|
301
|
+
replace(/(rgb|rgba|hsl|hsla)\(([^\)]+)\)/g, function(match, colorFunction, colorDef) {
|
302
|
+
var tokens = colorDef.split(',');
|
303
|
+
var applies = colorFunction == 'hsl' || colorFunction == 'hsla' || tokens[0].indexOf('%') > -1;
|
304
|
+
if (!applies)
|
305
|
+
return match;
|
306
|
+
|
307
|
+
if (tokens[1].indexOf('%') == -1)
|
308
|
+
tokens[1] += '%';
|
309
|
+
if (tokens[2].indexOf('%') == -1)
|
310
|
+
tokens[2] += '%';
|
311
|
+
return colorFunction + '(' + tokens.join(',') + ')';
|
312
|
+
});
|
313
|
+
|
314
|
+
// transparent rgba/hsla to 'transparent' unless in compatibility mode
|
315
|
+
if (!options.compatibility) {
|
316
|
+
replace(/:([^;]*)(?:rgba|hsla)\(\d+,\d+%?,\d+%?,0\)/g, function (match, prefix) {
|
317
|
+
if (new Splitter(',').split(match).pop().indexOf('gradient(') > -1)
|
318
|
+
return match;
|
319
|
+
|
320
|
+
return ':' + prefix + 'transparent';
|
321
|
+
});
|
322
|
+
}
|
323
|
+
|
324
|
+
// none to 0
|
325
|
+
replace(/outline:none/g, 'outline:0');
|
326
|
+
|
327
|
+
// background:none to background:0 0
|
328
|
+
replace(/background:(?:none|transparent)([;}])/g, 'background:0 0$1');
|
329
|
+
|
330
|
+
// multiple zeros into one
|
331
|
+
replace(/box-shadow:0 0 0 0([^\.])/g, 'box-shadow:0 0$1');
|
332
|
+
replace(/:0 0 0 0([^\.])/g, ':0$1');
|
333
|
+
replace(/([: ,=\-])0\.(\d)/g, '$1.$2');
|
334
|
+
|
335
|
+
// restore rect(...) zeros syntax for 4 zeros
|
336
|
+
replace(/rect\(\s?0(\s|,)0[ ,]0[ ,]0\s?\)/g, 'rect(0$10$10$10)');
|
337
|
+
|
338
|
+
// remove universal selector when not needed (*#id, *.class etc)
|
339
|
+
replace(/\*([\.#:\[])/g, '$1');
|
340
|
+
|
341
|
+
// Restore spaces inside calc back
|
342
|
+
replace(/calc\([^\}]+\}/g, function(match) {
|
343
|
+
return match.replace(/\+/g, ' + ');
|
344
|
+
});
|
345
|
+
|
346
|
+
// get rid of IE hacks if not in compatibility mode
|
347
|
+
if (!options.compatibility)
|
348
|
+
replace(/([;\{])[\*_][\w\-]+:[^;\}]+/g, '$1');
|
349
|
+
|
350
|
+
if (options.noAdvanced) {
|
351
|
+
if (options.keepBreaks)
|
352
|
+
replace(/\}/g, '}' + lineBreak);
|
353
|
+
} else {
|
354
|
+
replace(function optimizeSelectors() {
|
355
|
+
data = new SelectorsOptimizer(data, context, {
|
356
|
+
keepBreaks: options.keepBreaks,
|
357
|
+
lineBreak: lineBreak,
|
358
|
+
compatibility: options.compatibility,
|
359
|
+
aggressiveMerging: !options.noAggressiveMerging
|
360
|
+
}).process();
|
361
|
+
});
|
362
|
+
}
|
363
|
+
|
364
|
+
// replace ' / ' in border-*-radius with '/'
|
365
|
+
replace(/(border-\w+-\w+-radius:\S+)\s+\/\s+/g, '$1/');
|
366
|
+
|
367
|
+
// replace same H/V values in border-radius
|
368
|
+
replace(/(border-\w+-\w+-radius):([^;\}]+)/g, function (match, property, value) {
|
369
|
+
var parts = value.split('/');
|
370
|
+
|
371
|
+
if (parts.length > 1 && parts[0] == parts[1])
|
372
|
+
return property + ':' + parts[0];
|
373
|
+
else
|
374
|
+
return match;
|
375
|
+
});
|
376
|
+
|
377
|
+
replace(function restoreUrls() {
|
378
|
+
data = urlsProcessor.restore(data);
|
379
|
+
});
|
380
|
+
replace(function rebaseUrls() {
|
381
|
+
data = options.noRebase ? data : new UrlRebase(options, context).process(data);
|
382
|
+
});
|
383
|
+
replace(function restoreFreeText() {
|
384
|
+
data = freeTextProcessor.restore(data);
|
385
|
+
});
|
386
|
+
replace(function restoreComments() {
|
387
|
+
data = commentsProcessor.restore(data);
|
388
|
+
});
|
389
|
+
replace(function restoreExpressions() {
|
390
|
+
data = expressionsProcessor.restore(data);
|
391
|
+
});
|
392
|
+
|
393
|
+
// move first charset to the beginning
|
394
|
+
replace(function moveCharset() {
|
395
|
+
// get first charset in stylesheet
|
396
|
+
var match = data.match(/@charset [^;]+;/);
|
397
|
+
var firstCharset = match ? match[0] : null;
|
398
|
+
if (!firstCharset)
|
399
|
+
return;
|
400
|
+
|
401
|
+
// reattach first charset and remove all subsequent
|
402
|
+
data = firstCharset +
|
403
|
+
(options.keepBreaks ? lineBreak : '') +
|
404
|
+
data.replace(new RegExp('@charset [^;]+;(' + lineBreak + ')?', 'g'), '').trim();
|
405
|
+
});
|
406
|
+
|
407
|
+
if (options.noAdvanced) {
|
408
|
+
replace(function removeEmptySelectors() {
|
409
|
+
data = new EmptyRemoval(data).process();
|
410
|
+
});
|
411
|
+
}
|
412
|
+
|
413
|
+
// trim spaces at beginning and end
|
414
|
+
data = data.trim();
|
415
|
+
|
416
|
+
if (options.debug) {
|
417
|
+
var elapsed = process.hrtime(startedAt);
|
418
|
+
stats.timeSpent = ~~(elapsed[0] * 1e3 + elapsed[1] / 1e6);
|
419
|
+
stats.efficiency = 1 - data.length / stats.originalSize;
|
420
|
+
stats.minifiedSize = data.length;
|
421
|
+
}
|
422
|
+
|
423
|
+
return callback ?
|
424
|
+
callback.call(this, this.context.errors.length > 0 ? this.context.errors : null, data) :
|
425
|
+
data;
|
426
|
+
};
|