ruby-clean-css 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
+ };