ruby-clean-css 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](https://badge.fury.io/js/clean-css)
|
|
2
|
+
[](https://travis-ci.org/GoalSmashers/clean-css)
|
|
3
|
+
[](https://david-dm.org/GoalSmashers/clean-css)
|
|
4
|
+
[](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
|
+
};
|