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.
Files changed (124) hide show
  1. data/.gitmodules +3 -0
  2. data/EXAMPLE.md +25 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +30 -0
  5. data/LICENSE +19 -0
  6. data/README.md +106 -0
  7. data/lib/javascript/clean-css/.gitignore +4 -0
  8. data/lib/javascript/clean-css/.jshintignore +3 -0
  9. data/lib/javascript/clean-css/.jshintrc +14 -0
  10. data/lib/javascript/clean-css/.travis.yml +11 -0
  11. data/lib/javascript/clean-css/History.md +556 -0
  12. data/lib/javascript/clean-css/LICENSE +19 -0
  13. data/lib/javascript/clean-css/README.md +218 -0
  14. data/lib/javascript/clean-css/bin/cleancss +157 -0
  15. data/lib/javascript/clean-css/index.js +1 -0
  16. data/lib/javascript/clean-css/lib/clean.js +426 -0
  17. data/lib/javascript/clean-css/lib/colors/hsl-to-hex.js +64 -0
  18. data/lib/javascript/clean-css/lib/colors/long-to-short-hex.js +12 -0
  19. data/lib/javascript/clean-css/lib/colors/rgb-to-hex.js +14 -0
  20. data/lib/javascript/clean-css/lib/colors/shortener.js +174 -0
  21. data/lib/javascript/clean-css/lib/images/url-rebase.js +32 -0
  22. data/lib/javascript/clean-css/lib/images/url-rewriter.js +60 -0
  23. data/lib/javascript/clean-css/lib/imports/inliner.js +319 -0
  24. data/lib/javascript/clean-css/lib/properties/optimizer.js +276 -0
  25. data/lib/javascript/clean-css/lib/properties/override-compactor.js +116 -0
  26. data/lib/javascript/clean-css/lib/properties/processable.js +859 -0
  27. data/lib/javascript/clean-css/lib/properties/scanner.js +20 -0
  28. data/lib/javascript/clean-css/lib/properties/shorthand-compactor.js +244 -0
  29. data/lib/javascript/clean-css/lib/properties/token.js +184 -0
  30. data/lib/javascript/clean-css/lib/properties/validator.js +140 -0
  31. data/lib/javascript/clean-css/lib/selectors/empty-removal.js +30 -0
  32. data/lib/javascript/clean-css/lib/selectors/optimizer.js +341 -0
  33. data/lib/javascript/clean-css/lib/selectors/tokenizer.js +168 -0
  34. data/lib/javascript/clean-css/lib/text/comments.js +83 -0
  35. data/lib/javascript/clean-css/lib/text/escape-store.js +32 -0
  36. data/lib/javascript/clean-css/lib/text/expressions.js +73 -0
  37. data/lib/javascript/clean-css/lib/text/free.js +26 -0
  38. data/lib/javascript/clean-css/lib/text/name-quotes.js +37 -0
  39. data/lib/javascript/clean-css/lib/text/quote-scanner.js +91 -0
  40. data/lib/javascript/clean-css/lib/text/splitter.js +35 -0
  41. data/lib/javascript/clean-css/lib/text/urls.js +41 -0
  42. data/lib/javascript/clean-css/package.json +50 -0
  43. data/lib/javascript/clean-css/test/batch-test.js +56 -0
  44. data/lib/javascript/clean-css/test/bench.js +11 -0
  45. data/lib/javascript/clean-css/test/binary-test.js +323 -0
  46. data/lib/javascript/clean-css/test/data-bench/_partial.css +1 -0
  47. data/lib/javascript/clean-css/test/data-bench/complex.css +4 -0
  48. data/lib/javascript/clean-css/test/data/129-assets/assets/ui.css +2 -0
  49. data/lib/javascript/clean-css/test/data/129-assets/components/bootstrap/css/bootstrap.css +3 -0
  50. data/lib/javascript/clean-css/test/data/129-assets/components/bootstrap/images/glyphs.gif +0 -0
  51. data/lib/javascript/clean-css/test/data/129-assets/components/jquery-ui/css/style.css +6 -0
  52. data/lib/javascript/clean-css/test/data/129-assets/components/jquery-ui/images/next.gif +0 -0
  53. data/lib/javascript/clean-css/test/data/129-assets/components/jquery-ui/images/prev.gif +0 -0
  54. data/lib/javascript/clean-css/test/data/960-min.css +125 -0
  55. data/lib/javascript/clean-css/test/data/960.css +602 -0
  56. data/lib/javascript/clean-css/test/data/big-min.css +2984 -0
  57. data/lib/javascript/clean-css/test/data/big.css +13794 -0
  58. data/lib/javascript/clean-css/test/data/blueprint-min.css +245 -0
  59. data/lib/javascript/clean-css/test/data/blueprint.css +556 -0
  60. data/lib/javascript/clean-css/test/data/charset-mixed-with-fonts-min.css +3 -0
  61. data/lib/javascript/clean-css/test/data/charset-mixed-with-fonts.css +14 -0
  62. data/lib/javascript/clean-css/test/data/font-awesome-ie7-min.css +392 -0
  63. data/lib/javascript/clean-css/test/data/font-awesome-ie7.css +1203 -0
  64. data/lib/javascript/clean-css/test/data/font-awesome-min.css +319 -0
  65. data/lib/javascript/clean-css/test/data/font-awesome.css +540 -0
  66. data/lib/javascript/clean-css/test/data/imports-min.css +5 -0
  67. data/lib/javascript/clean-css/test/data/imports.css +4 -0
  68. data/lib/javascript/clean-css/test/data/issue-117-snippet-min.css +3 -0
  69. data/lib/javascript/clean-css/test/data/issue-117-snippet.css +19 -0
  70. data/lib/javascript/clean-css/test/data/issue-159-snippet-min.css +7 -0
  71. data/lib/javascript/clean-css/test/data/issue-159-snippet.css +7 -0
  72. data/lib/javascript/clean-css/test/data/issue-192-min.css +1 -0
  73. data/lib/javascript/clean-css/test/data/issue-192.css +8 -0
  74. data/lib/javascript/clean-css/test/data/issue-198-min.css +3 -0
  75. data/lib/javascript/clean-css/test/data/issue-198.css +4 -0
  76. data/lib/javascript/clean-css/test/data/issue-232-min.css +2 -0
  77. data/lib/javascript/clean-css/test/data/issue-232.css +17 -0
  78. data/lib/javascript/clean-css/test/data/issue-241-min.css +2 -0
  79. data/lib/javascript/clean-css/test/data/issue-241.css +2 -0
  80. data/lib/javascript/clean-css/test/data/issue-304-min.css +1 -0
  81. data/lib/javascript/clean-css/test/data/issue-304.css +4 -0
  82. data/lib/javascript/clean-css/test/data/issue-305-min.css +1 -0
  83. data/lib/javascript/clean-css/test/data/issue-305.css +3 -0
  84. data/lib/javascript/clean-css/test/data/issue-308-min.css +1 -0
  85. data/lib/javascript/clean-css/test/data/issue-308.css +5 -0
  86. data/lib/javascript/clean-css/test/data/issue-312-min.css +1 -0
  87. data/lib/javascript/clean-css/test/data/issue-312.css +7 -0
  88. data/lib/javascript/clean-css/test/data/issue-337-min.css +1 -0
  89. data/lib/javascript/clean-css/test/data/issue-337.css +4 -0
  90. data/lib/javascript/clean-css/test/data/line-breaks-in-attributes-min.css +2 -0
  91. data/lib/javascript/clean-css/test/data/line-breaks-in-attributes.css +8 -0
  92. data/lib/javascript/clean-css/test/data/partials-absolute/base.css +3 -0
  93. data/lib/javascript/clean-css/test/data/partials-absolute/base2.css +1 -0
  94. data/lib/javascript/clean-css/test/data/partials-absolute/extra/sub.css +3 -0
  95. data/lib/javascript/clean-css/test/data/partials-relative/base.css +3 -0
  96. data/lib/javascript/clean-css/test/data/partials-relative/extra/included.css +1 -0
  97. data/lib/javascript/clean-css/test/data/partials/comment.css +2 -0
  98. data/lib/javascript/clean-css/test/data/partials/extra/down.gif +0 -0
  99. data/lib/javascript/clean-css/test/data/partials/extra/four.css +3 -0
  100. data/lib/javascript/clean-css/test/data/partials/extra/three.css +1 -0
  101. data/lib/javascript/clean-css/test/data/partials/five.css +1 -0
  102. data/lib/javascript/clean-css/test/data/partials/four.css +1 -0
  103. data/lib/javascript/clean-css/test/data/partials/one.css +1 -0
  104. data/lib/javascript/clean-css/test/data/partials/three.css +1 -0
  105. data/lib/javascript/clean-css/test/data/partials/two.css +5 -0
  106. data/lib/javascript/clean-css/test/data/reset-min.css +12 -0
  107. data/lib/javascript/clean-css/test/data/reset.css +64 -0
  108. data/lib/javascript/clean-css/test/data/sample1-min.css +4 -0
  109. data/lib/javascript/clean-css/test/data/sample1.css +12 -0
  110. data/lib/javascript/clean-css/test/data/unsupported/selectors-ie7.css +20 -0
  111. data/lib/javascript/clean-css/test/data/unsupported/selectors-ie8.css +17 -0
  112. data/lib/javascript/clean-css/test/module-test.js +185 -0
  113. data/lib/javascript/clean-css/test/protocol-imports-test.js +409 -0
  114. data/lib/javascript/clean-css/test/text/splitter-test.js +20 -0
  115. data/lib/javascript/clean-css/test/unit-test.js +2071 -0
  116. data/lib/ruby-clean-css.rb +6 -0
  117. data/lib/ruby-clean-css/compressor.rb +142 -0
  118. data/lib/ruby-clean-css/exports.rb +258 -0
  119. data/lib/ruby-clean-css/railtie.rb +27 -0
  120. data/lib/ruby-clean-css/sprockets.rb +19 -0
  121. data/lib/ruby-clean-css/version.rb +5 -0
  122. data/ruby-clean-css.gemspec +30 -0
  123. data/test/test_compressor.rb +84 -0
  124. 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
+ };