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,409 @@
1
+ /* jshint unused: false */
2
+
3
+ var vows = require('vows');
4
+ var assert = require('assert');
5
+ var http = require('http');
6
+ var nock = require('nock');
7
+ var CleanCSS = require('../index');
8
+
9
+ var port = 24682;
10
+
11
+ if (process.platform == 'win32')
12
+ return;
13
+
14
+ vows.describe('protocol imports').addBatch({
15
+ 'of a missing file': {
16
+ topic: function() {
17
+ this.reqMocks = nock('http://127.0.0.1')
18
+ .get('/missing.css')
19
+ .reply(404);
20
+
21
+ new CleanCSS().minify('@import url(http://127.0.0.1/missing.css);a{color:red}', this.callback);
22
+ },
23
+ 'should raise error': function(errors, minified) {
24
+ assert.equal(errors.length, 1);
25
+ },
26
+ 'should ignore @import': function(errors, minified) {
27
+ assert.equal(minified, '@import url(http://127.0.0.1/missing.css);a{color:red}');
28
+ },
29
+ teardown: function() {
30
+ assert.equal(this.reqMocks.isDone(), true);
31
+ nock.restore();
32
+ }
33
+ },
34
+ 'of an existing file': {
35
+ topic: function() {
36
+ this.reqMocks = nock('http://127.0.0.1')
37
+ .get('/present.css')
38
+ .reply(200, 'p{font-size:13px}');
39
+
40
+ new CleanCSS().minify('@import url(http://127.0.0.1/present.css);a{color:red}', this.callback);
41
+ },
42
+ 'should not raise errors': function(errors, minified) {
43
+ assert.isNull(errors);
44
+ },
45
+ 'should process @import': function(errors, minified) {
46
+ assert.equal(minified, 'p{font-size:13px}a{color:red}');
47
+ },
48
+ teardown: function() {
49
+ assert.equal(this.reqMocks.isDone(), true);
50
+ nock.restore();
51
+ }
52
+ },
53
+ 'of an existing file with spaces in path': {
54
+ topic: function() {
55
+ this.reqMocks = nock('http://fonts.googleapis.com')
56
+ .get('/css?family=Oleo%20Script%20Swash%20Caps')
57
+ .reply(200, 'p{font-size:13px}');
58
+
59
+ new CleanCSS().minify('@import url(\'//fonts.googleapis.com/css?family=Oleo Script Swash Caps\');', this.callback);
60
+ },
61
+ 'should not raise errors': function(errors, minified) {
62
+ assert.isNull(errors);
63
+ },
64
+ 'should process @import': function(errors, minified) {
65
+ assert.equal(minified, 'p{font-size:13px}');
66
+ },
67
+ teardown: function() {
68
+ assert.equal(this.reqMocks.isDone(), true);
69
+ nock.restore();
70
+ }
71
+ },
72
+ 'of an existing file via HTTPS': {
73
+ topic: function() {
74
+ this.reqMocks = nock('https://127.0.0.1')
75
+ .get('/present.css')
76
+ .reply(200, 'p{font-size:13px}');
77
+
78
+ new CleanCSS().minify('@import url(https://127.0.0.1/present.css);a{color:red}', this.callback);
79
+ },
80
+ 'should not raise errors': function(errors, minified) {
81
+ assert.isNull(errors);
82
+ },
83
+ 'should process @import': function(errors, minified) {
84
+ assert.equal(minified, 'p{font-size:13px}a{color:red}');
85
+ },
86
+ teardown: function() {
87
+ assert.equal(this.reqMocks.isDone(), true);
88
+ nock.restore();
89
+ }
90
+ },
91
+ 'of an existing file with media': {
92
+ topic: function() {
93
+ this.reqMocks = nock('http://127.0.0.1')
94
+ .get('/present.css')
95
+ .reply(200, 'p{font-size:13px}');
96
+
97
+ new CleanCSS().minify('@import url(http://127.0.0.1/present.css) screen;a{color:red}', this.callback);
98
+ },
99
+ 'should not raise errors': function(errors, minified) {
100
+ assert.isNull(errors);
101
+ },
102
+ 'should process @import': function(errors, minified) {
103
+ assert.equal(minified, '@media screen{p{font-size:13px}}a{color:red}');
104
+ },
105
+ teardown: function() {
106
+ assert.equal(this.reqMocks.isDone(), true);
107
+ nock.restore();
108
+ }
109
+ },
110
+ 'of an existing file with dependencies': {
111
+ topic: function() {
112
+ this.reqMocks1 = nock('http://127.0.0.1')
113
+ .get('/present.css')
114
+ .reply(200, '@import url(/vendor/reset.css);@import url(https://assets.127.0.0.1/base.css);p{font-size:13px}')
115
+ .get('/vendor/reset.css')
116
+ .reply(200, 'body{margin:0}');
117
+ this.reqMocks2 = nock('https://assets.127.0.0.1')
118
+ .get('/base.css')
119
+ .reply(200, 'div{padding:0}');
120
+
121
+ new CleanCSS().minify('@import url(http://127.0.0.1/present.css);a{color:red}', this.callback);
122
+ },
123
+ 'should not raise errors': function(errors, minified) {
124
+ assert.isNull(errors);
125
+ },
126
+ 'should process @import': function(errors, minified) {
127
+ assert.equal(minified, 'body{margin:0}div{padding:0}p{font-size:13px}a{color:red}');
128
+ },
129
+ teardown: function() {
130
+ assert.equal(this.reqMocks1.isDone(), true);
131
+ assert.equal(this.reqMocks2.isDone(), true);
132
+ nock.restore();
133
+ }
134
+ },
135
+ 'of an existing file with relative dependencies': {
136
+ topic: function() {
137
+ this.reqMocks = nock('http://127.0.0.1')
138
+ .get('/nested/present.css')
139
+ .reply(200, '@import url(../vendor/reset.css);p{font-size:13px}')
140
+ .get('/vendor/reset.css')
141
+ .reply(200, 'body{margin:0}');
142
+
143
+ new CleanCSS().minify('@import url(http://127.0.0.1/nested/present.css);a{color:red}', this.callback);
144
+ },
145
+ 'should not raise errors': function(errors, minified) {
146
+ assert.isNull(errors);
147
+ },
148
+ 'should process @import': function(errors, minified) {
149
+ assert.equal(minified, 'body{margin:0}p{font-size:13px}a{color:red}');
150
+ },
151
+ teardown: function() {
152
+ assert.equal(this.reqMocks.isDone(), true);
153
+ nock.restore();
154
+ }
155
+ },
156
+ 'of an existing file missing relative dependency': {
157
+ topic: function() {
158
+ this.reqMocks = nock('http://127.0.0.1')
159
+ .get('/nested/present.css')
160
+ .reply(200, '@import url(../missing.css);p{font-size:13px}')
161
+ .get('/missing.css')
162
+ .reply(404);
163
+
164
+ new CleanCSS().minify('@import url(http://127.0.0.1/nested/present.css);a{color:red}', this.callback);
165
+ },
166
+ 'should not raise errors': function(errors, minified) {
167
+ assert.equal(errors.length, 1);
168
+ assert.equal(errors[0], 'Broken @import declaration of "http://127.0.0.1/missing.css" - error 404');
169
+ },
170
+ 'should process @import': function(errors, minified) {
171
+ assert.equal(minified, '@import url(http://127.0.0.1/missing.css);p{font-size:13px}a{color:red}');
172
+ },
173
+ teardown: function() {
174
+ assert.equal(this.reqMocks.isDone(), true);
175
+ nock.restore();
176
+ }
177
+ },
178
+ 'of an existing file with URLs to rebase': {
179
+ topic: function() {
180
+ this.reqMocks = nock('http://127.0.0.1')
181
+ .get('/urls.css')
182
+ .reply(200, 'a{background:url(test.png)}');
183
+
184
+ new CleanCSS().minify('@import url(http://127.0.0.1/urls.css);', this.callback);
185
+ },
186
+ 'should not raise errors': function(errors, minified) {
187
+ assert.isNull(errors);
188
+ },
189
+ 'should process @import': function(errors, minified) {
190
+ assert.equal(minified, 'a{background:url(http://127.0.0.1/test.png)}');
191
+ },
192
+ teardown: function() {
193
+ assert.equal(this.reqMocks.isDone(), true);
194
+ nock.restore();
195
+ }
196
+ },
197
+ 'of an existing file with relative URLs to rebase': {
198
+ topic: function() {
199
+ this.reqMocks = nock('http://127.0.0.1')
200
+ .get('/base.css')
201
+ .reply(200, '@import url(deeply/nested/urls.css);')
202
+ .get('/deeply/nested/urls.css')
203
+ .reply(200, 'a{background:url(../images/test.png)}');
204
+
205
+ new CleanCSS().minify('@import url(http://127.0.0.1/base.css);', this.callback);
206
+ },
207
+ 'should not raise errors': function(errors, minified) {
208
+ assert.isNull(errors);
209
+ },
210
+ 'should process @import': function(errors, minified) {
211
+ assert.equal(minified, 'a{background:url(http://127.0.0.1/deeply/images/test.png)}');
212
+ },
213
+ teardown: function() {
214
+ assert.equal(this.reqMocks.isDone(), true);
215
+ nock.restore();
216
+ }
217
+ },
218
+ 'of a non-resolvable domain': {
219
+ topic: function() {
220
+ new CleanCSS().minify('@import url(http://notdefined.127.0.0.1/custom.css);a{color:red}', this.callback);
221
+ },
222
+ 'should not raise errors': function(errors, minified) {
223
+ assert.equal(errors.length, 1);
224
+ assert.equal(errors[0], 'Broken @import declaration of "http://notdefined.127.0.0.1/custom.css" - getaddrinfo ENOTFOUND');
225
+ },
226
+ 'should process @import': function(errors, minified) {
227
+ assert.equal(minified, '@import url(http://notdefined.127.0.0.1/custom.css);a{color:red}');
228
+ }
229
+ },
230
+ 'of a 30x response with absolute URL': {
231
+ topic: function() {
232
+ this.reqMocks = nock('http://127.0.0.1')
233
+ .get('/moved.css')
234
+ .reply(301, '', { 'Location': 'http://127.0.0.1/present.css' })
235
+ .get('/present.css')
236
+ .reply(200, 'body{margin:0}');
237
+
238
+ new CleanCSS().minify('@import url(http://127.0.0.1/moved.css);a{color:red}', this.callback);
239
+ },
240
+ 'should not raise errors': function(errors, minified) {
241
+ assert.isNull(errors);
242
+ },
243
+ 'should process @import': function(errors, minified) {
244
+ assert.equal(minified, 'body{margin:0}a{color:red}');
245
+ },
246
+ teardown: function() {
247
+ assert.equal(this.reqMocks.isDone(), true);
248
+ nock.restore();
249
+ }
250
+ },
251
+ 'of a 30x response with relative URL': {
252
+ topic: function() {
253
+ this.reqMocks = nock('http://127.0.0.1')
254
+ .get('/moved.css')
255
+ .reply(301, '', { 'Location': '/present.css' })
256
+ .get('/present.css')
257
+ .reply(200, 'body{margin:0}');
258
+
259
+ new CleanCSS().minify('@import url(http://127.0.0.1/moved.css);a{color:red}', this.callback);
260
+ },
261
+ 'should not raise errors': function(errors, minified) {
262
+ assert.isNull(errors);
263
+ },
264
+ 'should process @import': function(errors, minified) {
265
+ assert.equal(minified, 'body{margin:0}a{color:red}');
266
+ },
267
+ teardown: function() {
268
+ assert.equal(this.reqMocks.isDone(), true);
269
+ nock.restore();
270
+ }
271
+ },
272
+ 'of a timed out response': {
273
+ topic: function() {
274
+ var self = this;
275
+ var timeout = 100;
276
+ this.server = http.createServer(function(req, res) {
277
+ setTimeout(function() {}, timeout * 2);
278
+ });
279
+ this.server.listen(port, function() {
280
+ new CleanCSS({
281
+ inliner: {
282
+ timeout: timeout
283
+ }
284
+ }).minify('@import url(http://localhost:' + port + '/timeout.css);a{color:red}', self.callback);
285
+ });
286
+ },
287
+ 'should not raise errors': function(errors, minified) {
288
+ assert.equal(errors.length, 1);
289
+ assert.equal(errors[0], 'Broken @import declaration of "http://localhost:' + port + '/timeout.css" - timeout');
290
+ },
291
+ 'should process @import': function(errors, minified) {
292
+ assert.equal(minified, '@import url(http://localhost:' + port + '/timeout.css);a{color:red}');
293
+ },
294
+ teardown: function() {
295
+ this.server.close();
296
+ }
297
+ },
298
+ 'of a cyclical reference response': {
299
+ topic: function() {
300
+ this.reqMocks = nock('http://127.0.0.1')
301
+ .get('/one.css')
302
+ .reply(200, '@import url(/two.css);div{padding:0}')
303
+ .get('/two.css')
304
+ .reply(200, '@import url(http://127.0.0.1/two.css);body{margin:0}');
305
+
306
+ new CleanCSS().minify('@import url(http://127.0.0.1/one.css);a{color:red}', this.callback);
307
+ },
308
+ 'should not raise errors': function(errors, minified) {
309
+ assert.isNull(errors);
310
+ },
311
+ 'should process @import': function(errors, minified) {
312
+ assert.equal(minified, 'body{margin:0}div{padding:0}a{color:red}');
313
+ },
314
+ teardown: function() {
315
+ assert.equal(this.reqMocks.isDone(), true);
316
+ nock.restore();
317
+ }
318
+ },
319
+ 'of a resource without protocol': {
320
+ topic: function() {
321
+ this.reqMocks = nock('http://127.0.0.1')
322
+ .get('/no-protocol.css')
323
+ .reply(200, 'div{padding:0}');
324
+
325
+ new CleanCSS().minify('@import url(//127.0.0.1/no-protocol.css);a{color:red}', this.callback);
326
+ },
327
+ 'should not raise errors': function(errors, minified) {
328
+ assert.isNull(errors);
329
+ },
330
+ 'should process @import': function(errors, minified) {
331
+ assert.equal(minified, 'div{padding:0}a{color:red}');
332
+ },
333
+ teardown: function() {
334
+ assert.equal(this.reqMocks.isDone(), true);
335
+ nock.restore();
336
+ }
337
+ },
338
+ 'of a resource available via POST only': {
339
+ topic: function() {
340
+ this.reqMocks = nock('http://127.0.0.1')
341
+ .post('/computed.css')
342
+ .reply(200, 'div{padding:0}');
343
+
344
+ new CleanCSS({
345
+ inliner: {
346
+ request: {
347
+ method: 'POST'
348
+ }
349
+ }
350
+ }).minify('@import url(http://127.0.0.1/computed.css);a{color:red}', this.callback);
351
+ },
352
+ 'should not raise errors': function(errors, minified) {
353
+ assert.isNull(errors);
354
+ },
355
+ 'should process @import': function(errors, minified) {
356
+ assert.equal(minified, 'div{padding:0}a{color:red}');
357
+ },
358
+ teardown: function() {
359
+ assert.equal(this.reqMocks.isDone(), true);
360
+ nock.restore();
361
+ }
362
+ },
363
+ 'of a remote resource mixed with local ones': {
364
+ topic: function() {
365
+ var source = '@import url(http://127.0.0.1/remote.css);@import url(test/data/partials/one.css);';
366
+ this.reqMocks = nock('http://127.0.0.1')
367
+ .get('/remote.css')
368
+ .reply(200, 'div{padding:0}');
369
+
370
+ new CleanCSS().minify(source, this.callback);
371
+ },
372
+ 'should not raise errors': function(errors, minified) {
373
+ assert.isNull(errors);
374
+ },
375
+ 'should process @import': function(errors, minified) {
376
+ assert.equal(minified, 'div{padding:0}.one{color:red}');
377
+ },
378
+ teardown: function() {
379
+ assert.equal(this.reqMocks.isDone(), true);
380
+ nock.restore();
381
+ }
382
+ },
383
+ 'of a remote resource mixed with local ones but no callback': {
384
+ topic: function() {
385
+ var source = '@import url(http://127.0.0.1/remote.css);@import url(test/data/partials/one.css);';
386
+ this.reqMocks = nock('http://127.0.0.1')
387
+ .get('/remote.css')
388
+ .reply(200, 'div{padding:0}');
389
+
390
+ var minifier = new CleanCSS();
391
+ var minified = minifier.minify(source);
392
+ this.callback(null, minifier, minified);
393
+ },
394
+ 'should not raise errors': function(error, minifier) {
395
+ assert.isEmpty(minifier.errors);
396
+ },
397
+ 'should raise warnings': function(error, minifier) {
398
+ assert.equal(minifier.warnings.length, 1);
399
+ assert.match(minifier.warnings[0], /no callback given/);
400
+ },
401
+ 'should process @import': function(error, minifier, minified) {
402
+ assert.equal(minified, '@import url(http://127.0.0.1/remote.css);.one{color:red}');
403
+ },
404
+ teardown: function() {
405
+ assert.equal(this.reqMocks.isDone(), false);
406
+ nock.restore();
407
+ }
408
+ }
409
+ }).export(module);
@@ -0,0 +1,20 @@
1
+ var vows = require('vows');
2
+ var assert = require('assert');
3
+ var Splitter = require('../../lib/text/splitter');
4
+
5
+ var split = function (value, expectedValue, separator) {
6
+ return function () {
7
+ assert.deepEqual(new Splitter(separator).split(value), expectedValue);
8
+ };
9
+ };
10
+
11
+ vows.describe('splitter').addBatch({
12
+ 'empty': split('', [''], ','),
13
+ 'simple': split('none', ['none'], ','),
14
+ 'comma separated - level 0': split('#000,#fff,#0f0', ['#000', '#fff', '#0f0'], ','),
15
+ 'comma separated - level 1': split('rgb(0,0,0),#fff', ['rgb(0,0,0)', '#fff'], ','),
16
+ 'comma separated - level 2': split('linear-gradient(0,#fff,rgba(0,0,0)),red', ['linear-gradient(0,#fff,rgba(0,0,0))', 'red'], ','),
17
+ 'space separated - level 0': split('#000 #fff #0f0', ['#000', '#fff', '#0f0'], ' '),
18
+ 'space separated - level 1': split('rgb(0, 0, 0) #fff', ['rgb(0, 0, 0)', '#fff'], ' '),
19
+ 'space separated - level 2': split('linear-gradient(0, #fff, rgba(0, 0, 0)) red', ['linear-gradient(0, #fff, rgba(0, 0, 0))', 'red'], ' ')
20
+ }).export(module);
@@ -0,0 +1,2071 @@
1
+ /* jshint indent: false, multistr: true, quotmark: false */
2
+
3
+ var vows = require('vows');
4
+ var assert = require('assert');
5
+ var path = require('path');
6
+ var CleanCSS = require('../index');
7
+ var ColorShortener = require('../lib/colors/shortener');
8
+
9
+ var lineBreak = process.platform == 'win32' ? '\r\n' : '\n';
10
+ var cssContext = function(groups, options) {
11
+ var context = {};
12
+ var clean = function(expectedCss) {
13
+ return function(css) {
14
+ var minifiedCss = new CleanCSS(options).minify(css);
15
+ assert.equal(minifiedCss, expectedCss);
16
+ };
17
+ };
18
+
19
+ for (var g in groups) {
20
+ var transformation = groups[g];
21
+ if (typeof transformation == 'string')
22
+ transformation = [transformation, transformation];
23
+
24
+ context[g] = {
25
+ topic: transformation[0],
26
+ clean: clean(transformation[1])
27
+ };
28
+ }
29
+
30
+ return context;
31
+ };
32
+
33
+ var colorShorteningContext = function() {
34
+ var shortenerContext = {};
35
+ var shortener = new ColorShortener();
36
+
37
+ ['toName', 'toHex'].forEach(function(type) {
38
+ for (var from in shortener[type]) {
39
+ var to = shortener[type][from];
40
+ shortenerContext['should turn ' + from + ' into ' + to] = [
41
+ 'a{color:' + from + '}',
42
+ 'a{color:' + to + '}'
43
+ ];
44
+ }
45
+ });
46
+
47
+ return cssContext(shortenerContext);
48
+ };
49
+
50
+ var redefineContext = function(redefinitions, options) {
51
+ var context = {};
52
+ var vendorPrefixes = ['', '-moz-', '-o-', '-webkit-']; // there is no -ms-animation nor -ms-transition.
53
+
54
+ for (var property in redefinitions) {
55
+ for (var i = 0; i < redefinitions[property].length; i++) {
56
+ var by = redefinitions[property][i];
57
+ var prefixes = options.vendorPrefixes.indexOf(by) > -1 ? vendorPrefixes : [''];
58
+
59
+ for (var j = 0, m = prefixes.length; j < m; j++) {
60
+ var prefixedProperty = prefixes[j] + property;
61
+ var prefixedBy = prefixes[j] + by;
62
+ var zeroValue = options.noneFor.indexOf(prefixedProperty) > -1 ? 'none' : '0';
63
+
64
+ context['should override ' + prefixedProperty + ' by ' + prefixedBy] = [
65
+ 'a{' + prefixedProperty + ':inherit;' + prefixedBy + ':' + zeroValue + '}',
66
+ 'a{' + prefixedBy + ':' + zeroValue + '}'
67
+ ];
68
+ context['should not override ' + prefixedBy + ' by ' + prefixedProperty] =
69
+ 'a{' + prefixedBy + ':' + zeroValue + ';' + prefixedProperty + ':inherit}';
70
+ }
71
+ }
72
+ }
73
+
74
+ return cssContext(context);
75
+ };
76
+
77
+ vows.describe('clean-units').addBatch({
78
+ 'identity': cssContext({
79
+ 'preserve minified content': 'a{color:#f10}'
80
+ }),
81
+ 'semicolons': cssContext({
82
+ 'multiple semicolons': [
83
+ 'a{color:#fff;;;width:0; ;}',
84
+ 'a{color:#fff;width:0}'
85
+ ],
86
+ 'trailing semicolon': [
87
+ 'a{color:#fff;}',
88
+ 'a{color:#fff}'
89
+ ],
90
+ 'trailing semicolon and space': [
91
+ 'a{color:#fff ; }',
92
+ 'a{color:#fff}'
93
+ ],
94
+ 'comma and space': [
95
+ 'a{color:rgba(0, 0, 5, .5)}',
96
+ 'a{color:rgba(0,0,5,.5)}'
97
+ ]
98
+ }),
99
+ 'whitespace': cssContext({
100
+ 'one argument': [
101
+ 'div a { color:#fff }',
102
+ 'div a{color:#fff}'
103
+ ],
104
+ 'tabs': [
105
+ 'div\t\ta{display:block}\tp{color:red}',
106
+ 'div a{display:block}p{color:red}'
107
+ ],
108
+ 'line breaks #1': [
109
+ 'div \na\r\n { width:500px }',
110
+ 'div a{width:500px}'
111
+ ],
112
+ 'line breaks #2': [
113
+ 'div \na\r\n, p { width:500px }',
114
+ 'div a,p{width:500px}'
115
+ ],
116
+ 'line breaks #3': [
117
+ 'div a{width:500px\r\n}',
118
+ 'div a{width:500px}'
119
+ ],
120
+ 'line breaks with whitespace lines': [
121
+ 'div \n \t\n \na\r\n, p { width:500px }',
122
+ 'div a,p{width:500px}'
123
+ ],
124
+ 'multiple arguments': [
125
+ 'a{color:#fff ; font-weight: bolder }',
126
+ 'a{color:#fff;font-weight:bolder}'
127
+ ],
128
+ 'space delimited arguments': [
129
+ 'a {border: 1px solid #f10; margin: 0 auto }',
130
+ 'a{border:1px solid #f10;margin:0 auto}'
131
+ ],
132
+ 'at beginning': [
133
+ ' a {color:#fff}',
134
+ 'a{color:#fff}'
135
+ ],
136
+ 'at end': [
137
+ 'a{color:#fff } ',
138
+ 'a{color:#fff}'
139
+ ],
140
+ 'not inside calc method #1': [
141
+ 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}',
142
+ 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}'
143
+ ],
144
+ 'not inside calc method #2': [
145
+ 'div{margin:-moz-calc(50% + 15px) -moz-calc(50% + 15px);margin:calc(50% + .5rem) calc(50% + .5rem)}',
146
+ 'div{margin:-moz-calc(50% + 15px);margin:calc(50% + .5rem)}'
147
+ ],
148
+ 'not inside calc method with more parentheses': [
149
+ 'div{height:-moz-calc((10% + 12px)/2 + 10em)}',
150
+ 'div{height:-moz-calc((10% + 12px)/2 + 10em)}'
151
+ ],
152
+ 'not inside calc method with multiplication': [
153
+ 'div{height:-moz-calc(3 * 2em + 10px)}',
154
+ 'div{height:-moz-calc(3 * 2em + 10px)}'
155
+ ],
156
+ 'before colon': [
157
+ '#test{padding-left :0}',
158
+ '#test{padding-left:0}'
159
+ ],
160
+ 'before colon but not selectors #1': 'div :before{display:block}',
161
+ 'before colon but not selectors #2': 'div ::-webkit-search-decoration{display:block}',
162
+ 'before colon but not selectors #3': 'div :after{color:red}',
163
+ 'windows breaks': [
164
+ 'div>a{color:red\r\n }',
165
+ 'div>a{color:red}'
166
+ ],
167
+ 'whitespace in media queries': [
168
+ '@media ( min-width: 980px ) {\n#page .span4 {\nwidth: 250px;\n}\n\n.row {\nmargin-left: -10px;\n}\n}',
169
+ '@media (min-width:980px){#page .span4{width:250px}.row{margin-left:-10px}}'
170
+ ],
171
+ 'line breaks in media queries': [
172
+ '@media\nonly screen and (max-width: 1319px) and (min--moz-device-pixel-ratio: 1.5),\nonly screen and (max-width: 1319px) and (-moz-min-device-pixel-ratio: 1.5)\n{ a { color:#000 } }',
173
+ '@media only screen and (max-width:1319px) and (min--moz-device-pixel-ratio:1.5),only screen and (max-width:1319px) and (-moz-min-device-pixel-ratio:1.5){a{color:#000}}'
174
+ ],
175
+ 'in content preceded by #content': '#content{display:block}#foo{content:"\0BB "}',
176
+ 'in content preceded by .content': '.content{display:block}#foo{content:"\0BB "}',
177
+ 'in content preceded by line break': [
178
+ '.content{display:block}#foo{' + lineBreak + 'content:"x"}',
179
+ '.content{display:block}#foo{content:"x"}'
180
+ ],
181
+ 'after rgb': [
182
+ 'a{text-shadow:rgb(255,0,1) 1px 1px}',
183
+ 'a{text-shadow:#ff0001 1px 1px}'
184
+ ],
185
+ 'after rgba': 'a{text-shadow:rgba(255,0,0,1) 0 1px}',
186
+ 'after hsl': [
187
+ 'a{text-shadow:hsl(240,100%,40%) -1px 1px}',
188
+ 'a{text-shadow:#00c -1px 1px}'
189
+ ],
190
+ 'after hsla': 'a{text-shadow:hsla(240,100%,40%,.5) -1px 1px}'
191
+ }),
192
+ 'line breaks': cssContext({
193
+ 'line breaks': [
194
+ 'div\na\r\n{width:500px}',
195
+ 'div a{width:500px}'
196
+ ],
197
+ 'line breaks #2': [
198
+ 'div\na\r\n,p{width:500px}',
199
+ 'div a,p{width:500px}'
200
+ ],
201
+ 'multiple line breaks #2': [
202
+ 'div \r\n\r\na\r\n,p{width:500px}',
203
+ 'div a,p{width:500px}'
204
+ ],
205
+ 'line breaks with whitespace lines': [
206
+ 'div \n \t\n \na\r\n, p { width:500px }',
207
+ 'div a,p{width:500px}'
208
+ ],
209
+ 'line breaks with multiple selectors': [
210
+ 'p{width:500px}a{color:red}span{font-style:italic}',
211
+ 'p{width:500px}' + lineBreak + 'a{color:red}' + lineBreak + 'span{font-style:italic}'
212
+ ],
213
+ 'charset not at beginning': [
214
+ "a{ color: #f10; }\n@charset 'utf-8';\nb { font-weight: bolder}",
215
+ "@charset 'utf-8';" + lineBreak + "a{color:#f10}" + lineBreak + "b{font-weight:bolder}"
216
+ ],
217
+ 'charset multiple charsets': [
218
+ "@charset 'utf-8';\ndiv :before { display: block }\n@charset 'utf-8';\na { color: #f10 }",
219
+ "@charset 'utf-8';" + lineBreak + "div :before{display:block}" + lineBreak + "a{color:#f10}"
220
+ ],
221
+ 'charset with double line break': [
222
+ "@charset 'utf-8';" + lineBreak + lineBreak + "a{display:block}",
223
+ "@charset 'utf-8';" + lineBreak + "a{display:block}"
224
+ ],
225
+ 'uppercase charset': [
226
+ "@CHARSET 'utf-8';h1{color:red}",
227
+ 'h1{color:red}'
228
+ ],
229
+ 'mixed case charset': [
230
+ "@chArSET 'utf-8';h1{color:red}",
231
+ 'h1{color:red}'
232
+ ]
233
+ }, { keepBreaks: true }),
234
+ 'line breaks and important comments': cssContext({
235
+ 'charset to beginning with comment removal': [
236
+ "/*! some comment */" + lineBreak + lineBreak + "@charset 'utf-8';" + lineBreak + lineBreak + "a{display:block}",
237
+ "@charset 'utf-8';" + lineBreak + "a{display:block}"
238
+ ]
239
+ }, { keepBreaks: true, keepSpecialComments: 0 }),
240
+ 'selectors': cssContext({
241
+ 'remove spaces around selectors': [
242
+ 'div + span > em{display:block}',
243
+ 'div+span>em{display:block}'
244
+ ],
245
+ 'not remove spaces for pseudo-classes': [
246
+ 'div :first-child{display:block}',
247
+ 'div :first-child{display:block}'
248
+ ],
249
+ 'strip universal selector from id and class selectors': [
250
+ '* > *#id > *.class{display:block}',
251
+ '*>#id>.class{display:block}'
252
+ ],
253
+ 'strip universal selector from attribute selectors': [
254
+ '*:first-child > *[data-id]{display:block}',
255
+ ':first-child>[data-id]{display:block}'
256
+ ],
257
+ 'not strip standalone universal selector': [
258
+ 'label ~ * + span{display:block}',
259
+ 'label~*+span{display:block}'
260
+ ],
261
+ 'not expand + in selectors mixed with calc methods': [
262
+ 'div{width:calc(50% + 3em)}div + div{width:100%}div:hover{width:calc(50% + 4em)}* > div {border:1px solid #f0f}',
263
+ 'div{width:calc(50% + 3em)}div+div{width:100%}div:hover{width:calc(50% + 4em)}*>div{border:1px solid #f0f}'
264
+ ],
265
+ 'process selectors ending with -0 correctly': '.selector-0,a{display:block}',
266
+ 'process selectors ending with -1 correctly': '.selector-1,a{display:block}'
267
+ }),
268
+ 'comments': cssContext({
269
+ 'single line': [
270
+ 'a{color:#fff}/* some comment*/p{height:10px/* other comment */}',
271
+ 'a{color:#fff}p{height:10px}'
272
+ ],
273
+ 'multiline': [
274
+ '/* \r\n multiline \n comment */a{color:rgba(0,0,0,0.8)}',
275
+ 'a{color:rgba(0,0,0,.8)}'
276
+ ],
277
+ 'comment chars in comments': [
278
+ '/* \r\n comment chars * inside / comments */a{color:#fff}',
279
+ 'a{color:#fff}'
280
+ ],
281
+ 'comment inside block': [
282
+ 'a{/* \r\n some comments */color:#fff}',
283
+ 'a{color:#fff}'
284
+ ],
285
+ 'special comments': [
286
+ '/*! special comment */a{color:#f10} /* normal comment */',
287
+ '/*! special comment */a{color:#f10}'
288
+ ],
289
+ 'should keep exact structure': [
290
+ '/*! \n a > span { } with some content */',
291
+ '/*! \n a > span { } with some content */'
292
+ ],
293
+ 'should remove comments with forward slashes inside': [
294
+ '/*////*/a{color:red}',
295
+ 'a{color:red}'
296
+ ],
297
+ 'should properly handle line breaks and ** characters inside comments': [
298
+ '/**====**\\\n/**2nd comment line/**===**/a{color:red}',
299
+ 'a{color:red}'
300
+ ],
301
+ 'selector between comments': [
302
+ '/*comment*/*/*comment*/{color:red}',
303
+ '*{color:red}'
304
+ ],
305
+ 'inside url': [
306
+ "p{background-image:url('/*')}/* */",
307
+ "p{background-image:url(/*)}"
308
+ ],
309
+ 'inside url twice': [
310
+ "p{background-image:url('/* */\" /*')}/* */",
311
+ "p{background-image:url('/* */\" /*')}"
312
+ ],
313
+ 'inside url with more quotation': [
314
+ "p{background-image:url('/*');content:\"\"/* */}",
315
+ "p{background-image:url(/*);content:\"\"}"
316
+ ],
317
+ 'with quote marks': [
318
+ '/*"*//* */',
319
+ ''
320
+ ]
321
+ }),
322
+ 'escaping': cssContext({
323
+ 'escaped @ symbol in class name': '.pad--all0\\@sm{padding:0}',
324
+ 'escaped @ symbol in id': '#id\\@sm{padding:0}'
325
+ }),
326
+ 'important comments - one': cssContext({
327
+ 'strip all but first': [
328
+ '/*! important comment */a{color:red}/* some comment *//*! important comment */',
329
+ '/*! important comment */a{color:red}'
330
+ ]
331
+ }, { keepSpecialComments: 1 }),
332
+ 'important comments - none': cssContext({
333
+ 'strip all': [
334
+ '/*! important comment */a{color:red}/* some comment *//*! important comment */',
335
+ 'a{color:red}'
336
+ ],
337
+ 'move charset before': [
338
+ "/*! some comment */" + lineBreak + lineBreak + "@charset 'utf-8';" + lineBreak + lineBreak + "a{display:block}",
339
+ "@charset 'utf-8';a{display:block}"
340
+ ]
341
+ }, { keepSpecialComments: 0 }),
342
+ 'important comments - keepSpecialComments when a string': cssContext({
343
+ 'strip all': [
344
+ '/*! important comment */a{color:red}/* some comment *//*! important comment */',
345
+ 'a{color:red}'
346
+ ]
347
+ }, { keepSpecialComments: '0' }),
348
+ 'expressions': cssContext({
349
+ 'empty': 'a{color:expression()}',
350
+ 'method call': 'a{color:expression(this.parentNode.currentStyle.color)}',
351
+ 'multiple call': 'a{color:expression(x = 0 , this.parentNode.currentStyle.color)}',
352
+ 'mixed content': "a{zoom:expression(this.runtimeStyle[\"zoom\"] = '1', this.innerHTML = '&#xf187;')}",
353
+ 'in comment': "/*! expression(this.runtimeStyle['zoom']) */",
354
+ 'complex': 'a{width:expression((this.parentNode.innerWidth + this.parentNode.innerHeight) / 2 )}',
355
+ 'with parentheses': "a{width:expression(this.parentNode.innerText == ')' ? '5px' : '10px' )}",
356
+ 'open ended (broken)': "a{width:expression(this.parentNode.innerText == }",
357
+ 'function call & advanced': 'a{zoom:expression(function(el){el.style.zoom="1"}(this))}'
358
+ }),
359
+ 'text content': cssContext({
360
+ 'normal #1': 'a{content:"."}',
361
+ 'normal #2': [
362
+ 'a:before{content : "test\'s test"; }',
363
+ 'a:before{content:"test\'s test"}'
364
+ ],
365
+ 'open quote': [
366
+ 'a{content : open-quote;opacity:1}',
367
+ 'a{content:open-quote;opacity:1}'
368
+ ],
369
+ 'close quote': [
370
+ 'a{content: close-quote;clear:left}',
371
+ 'a{content:close-quote;clear:left}'
372
+ ],
373
+ 'special characters': [
374
+ 'a{content : " a > div { } "}',
375
+ 'a{content:" a > div { } "}'
376
+ ],
377
+ 'with JSON': 'body::before{content:\'{ "current" : "small", "all" : ["small"], "position" : 0 }\'}'
378
+ }),
379
+ 'zero values': cssContext({
380
+ 'with units': [
381
+ 'a{margin:0px 0pt 0em 0%;padding: 0in 0cm 0mm 0pc;border-top-width:0ex}',
382
+ 'a{margin:0;padding:0;border-top-width:0}'
383
+ ],
384
+ 'multiple into one': [
385
+ 'a{margin:0 0 0 0;padding:0 0 0 0;border-width:0 0 0 0}',
386
+ 'a{margin:0;padding:0;border-width:0}'
387
+ ],
388
+ 'background\'s none to zero': [
389
+ 'a{background:none}',
390
+ 'a{background:0 0}'
391
+ ],
392
+ 'border\'s none to none': 'a{border:none}p{border-top:none}',
393
+ 'background:transparent to zero': [
394
+ 'a{background:transparent}p{background:transparent url(logo.png)}',
395
+ 'a{background:0 0}p{background:url(logo.png)}'
396
+ ],
397
+ 'outline:none to outline:0': [
398
+ 'a{outline:none}',
399
+ 'a{outline:0}'
400
+ ],
401
+ 'display:none not changed': 'a{display:none}',
402
+ 'mixed zeros not changed': 'div{margin:0 0 1px 2px}',
403
+ 'mixed zeros not changed #2': 'div{padding:0 1px 0 3px}',
404
+ 'mixed zeros not changed #3': 'div{padding:10px 0 0 1px}',
405
+ 'multiple zeros with fractions #1': [
406
+ 'div{padding:0 0 0 0.5em}',
407
+ 'div{padding:0 0 0 .5em}'
408
+ ],
409
+ 'multiple zeros with fractions #2': [
410
+ 'div{padding:0 0 0 .5em}',
411
+ 'div{padding:0 0 0 .5em}'
412
+ ],
413
+ 'rect zeros #1': 'div{clip:rect(0 0 0 0)}',
414
+ 'rect zeros #2': [
415
+ 'div{clip:rect(0px 0px 0px 0px)}',
416
+ 'div{clip:rect(0 0 0 0)}'
417
+ ],
418
+ 'rect zeros #3': [
419
+ 'div{clip:rect( 0px 0px 0px 0px )}',
420
+ 'div{clip:rect(0 0 0 0)}'
421
+ ],
422
+ 'rect zeros #4': [
423
+ 'div{clip:rect(0px, 0px, 0px, 0px)}',
424
+ 'div{clip:rect(0,0,0,0)}'
425
+ ],
426
+ 'rect zeros #5': [
427
+ 'div{clip:rect(0.5% 0px 0px 0px)}',
428
+ 'div{clip:rect(0.5% 0 0 0)}'
429
+ ],
430
+ 'rect zeros #6': [
431
+ 'div{clip:rect(0px 0px 0px 10px)}',
432
+ 'div{clip:rect(0 0 0 10px)}'
433
+ ],
434
+ 'box shadow zeros with four zeros': [
435
+ 'a{box-shadow:0 0 0 0}',
436
+ 'a{box-shadow:0 0}'
437
+ ],
438
+ 'box shadow with two zeros': 'a{box-shadow:0 0}',
439
+ 'box shadow with three zeros and a fraction': [
440
+ 'a{box-shadow:0 0 0 0.15em #EBEBEB}',
441
+ 'a{box-shadow:0 0 0 .15em #EBEBEB}'
442
+ ],
443
+ 'box shadow with three zeros and a value': 'a{box-shadow:0 0 0 15px #EBEBEB}',
444
+ 'rems': [
445
+ 'div{width:0rem;height:0rem}',
446
+ 'div{width:0;height:0}'
447
+ ],
448
+ 'prefixed box shadow zeros': [
449
+ 'a{-webkit-box-shadow:0 0 0 0; -moz-box-shadow:0 0 0 0}',
450
+ 'a{-webkit-box-shadow:0 0;-moz-box-shadow:0 0}'
451
+ ],
452
+ 'zero as .0 #1': [
453
+ 'a{color:rgba(0,0,.0,1)}',
454
+ 'a{color:rgba(0,0,0,1)}'
455
+ ],
456
+ 'zero as .0 #2': [
457
+ 'body{margin:.0}',
458
+ 'body{margin:0}'
459
+ ],
460
+ 'zero as .0 #3': [
461
+ 'body{margin:.0em}',
462
+ 'body{margin:0}'
463
+ ],
464
+ 'zero as .0 #4': [
465
+ 'body{margin:.0 1em .0 .0}',
466
+ 'body{margin:0 1em 0 0}'
467
+ ],
468
+ 'missing #1': [
469
+ 'body{margin:2.em}',
470
+ 'body{margin:2em}'
471
+ ],
472
+ 'missing #2': [
473
+ 'p{opacity:1.}',
474
+ 'p{opacity:1}'
475
+ ],
476
+ 'missing #3': [
477
+ 'p{opacity:11.px}',
478
+ 'p{opacity:11px}'
479
+ ],
480
+ 'minus zero as value to zero': [
481
+ 'body{margin:-0}',
482
+ 'body{margin:0}'
483
+ ],
484
+ 'minus zero in function to zero': [
485
+ 'body{color:rgba(-0,-0,-0,-0)}',
486
+ 'body{color:transparent}'
487
+ ],
488
+ 'minus zero px to zero': [
489
+ 'body{margin:-0px}',
490
+ 'body{margin:0}'
491
+ ],
492
+ 'zero em to zero': [
493
+ 'body{margin:0.0em}',
494
+ 'body{margin:0}'
495
+ ]
496
+ }),
497
+ 'zero values in ie8 compatibility mode': cssContext({
498
+ 'rems': 'div{width:0rem;height:0rem}'
499
+ }, { compatibility: 'ie8' }),
500
+ 'zero values in any other compatibility mode': cssContext({
501
+ 'rems': [
502
+ 'div{width:0rem;height:0rem}',
503
+ 'div{width:0;height:0}'
504
+ ]
505
+ }, { compatibility: '*' }),
506
+ 'shorthands': cssContext({
507
+ 'padding - same 4 values': [
508
+ 'div{padding:1px 1px 1px 1px}',
509
+ 'div{padding:1px}'
510
+ ],
511
+ 'margin - same 4 values': [
512
+ 'div{margin:1% 1% 1% 1%}',
513
+ 'div{margin:1%}'
514
+ ],
515
+ 'border-width - same 4 values': [
516
+ 'div{border-width:1em 1em 1em 1em}',
517
+ 'div{border-width:1em}'
518
+ ],
519
+ 'border-style - same 4 values': [
520
+ 'div{border-style:solid solid solid solid}',
521
+ 'div{border-style:solid}'
522
+ ],
523
+ 'border-color - same 4 values': [
524
+ 'div{border-color:red red red red}',
525
+ 'div{border-color:red}'
526
+ ],
527
+ 'border-color - same 4 values as hex': [
528
+ 'div{border-color:#f0f #f0f #f0f #f0f}',
529
+ 'div{border-color:#f0f}'
530
+ ],
531
+ 'border-color - same 4 values as rgb': [
532
+ 'div{border-color:rgb(0,0,0) rgb(0,0,0) rgb(0,0,0) rgb(0,0,0)}',
533
+ 'div{border-color:#000}'
534
+ ],
535
+ 'border-color - same 4 values as rgba': [
536
+ 'div{border-color:rgba(0,0,0,.5) rgba(0,0,0,.5) rgba(0,0,0,.5) rgba(0,0,0,.5)}',
537
+ 'div{border-color:rgba(0,0,0,.5)}'
538
+ ],
539
+ 'border-radius - same 4 values': [
540
+ 'div{border-radius:3px 3px 3px 3px}',
541
+ 'div{border-radius:3px}'
542
+ ],
543
+ 'border-radius - same 4 values with vendor prefixes': [
544
+ 'div{-moz-border-radius:3px 3px 3px 3px;-o-border-radius:3px 3px 3px 3px;-webkit-border-radius:3px 3px 3px 3px;border-radius:3px 3px 3px 3px}',
545
+ 'div{-moz-border-radius:3px;-o-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}'
546
+ ],
547
+ 'padding - same pairs': [
548
+ 'div{padding:15.5em 10.5em 15.5em 10.5em}',
549
+ 'div{padding:15.5em 10.5em}'
550
+ ],
551
+ 'margin - same 2nd and 4th value': [
552
+ 'div{margin:1px 2px 3px 2px}',
553
+ 'div{margin:1px 2px 3px}'
554
+ ],
555
+ 'padding - same 3 values': [
556
+ 'div{padding:1px 1px 1px}',
557
+ 'div{padding:1px}'
558
+ ],
559
+ 'padding - different 3 values': 'div{padding:1px 1em 1%}',
560
+ 'margin - 3 callapsible values': [
561
+ 'div{margin:1ex 2ex 1ex}',
562
+ 'div{margin:1ex 2ex}'
563
+ ],
564
+ 'border-radius - same 3 values with one vendor prefixe': [
565
+ 'div{-webkit-border-radius:3px 3px 3px;border-radius:3px 3px 3px}',
566
+ 'div{-webkit-border-radius:3px;border-radius:3px}'
567
+ ],
568
+ 'border-color - same 2nd and 4th value as rgb': [
569
+ 'div{border-color:rgb(0,0,0) rgb(34,0,0) rgb(255,0,0) rgb(34,0,0)}',
570
+ 'div{border-color:#000 #200 red}'
571
+ ],
572
+ 'margin - 3 different values': 'div{margin:1px 1px 3px}',
573
+ 'border width - 3 different values': 'div{border-width:1px 2px 3px}',
574
+ 'padding - same 2 values': [
575
+ 'div{padding:1px 1px}',
576
+ 'div{padding:1px}'
577
+ ],
578
+ 'margin - same 2 values': [
579
+ 'div{margin:5% 5%}',
580
+ 'div{margin:5%}'
581
+ ],
582
+ 'border-width - same 2 values': [
583
+ 'div{border-width:.5em .5em}',
584
+ 'div{border-width:.5em}'
585
+ ],
586
+ 'different units': 'div{padding:1px 1em 1% 1rem}',
587
+ 'fractions': [
588
+ 'div{margin:.1em .1em .1em .1em}',
589
+ 'div{margin:.1em}'
590
+ ],
591
+ 'preceeding value': [
592
+ 'div{padding:010px 00015px}',
593
+ 'div{padding:10px 15px}'
594
+ ],
595
+ 'preceeding value with fraction zeros': [
596
+ 'div{padding:010.0em .05rem}',
597
+ 'div{padding:10em .05rem}'
598
+ ]
599
+ }),
600
+ 'floats': cssContext({
601
+ 'strips zero in fractions': [
602
+ 'a{ margin-bottom: 0.5em}',
603
+ 'a{margin-bottom:.5em}'
604
+ ],
605
+ 'not strips zero in fractions of numbers greater than zero': [
606
+ 'a{ margin-bottom: 20.5em}',
607
+ 'a{margin-bottom:20.5em}'
608
+ ],
609
+ 'strip fraction zero #1': [
610
+ 'a{opacity:1.0}',
611
+ 'a{opacity:1}'
612
+ ],
613
+ 'strip fraction zero #2': [
614
+ 'a{opacity:15.000%}',
615
+ 'a{opacity:15%}'
616
+ ],
617
+ 'strip fraction zero #3': [
618
+ 'a{padding:15.55000em}',
619
+ 'a{padding:15.55em}'
620
+ ],
621
+ 'strip fraction zero #4': 'a{padding:15.101em}',
622
+ 'strip fraction zero #5': [
623
+ 'a{border-width:0.20em 20.30em}',
624
+ 'a{border-width:.2em 20.3em}'
625
+ ],
626
+ 'strip fraction zeros': [
627
+ 'div{margin:1.000em 2.00em 3.100em 4.01em}',
628
+ 'div{margin:1em 2em 3.1em 4.01em}'
629
+ ],
630
+ 'round pixels up to 2nd decimal place': [
631
+ 'div{transform:translateY(-418.505123px)}',
632
+ 'div{transform:translateY(-418.51px)}'
633
+ ],
634
+ 'round pixels down to 2nd decimal place': [
635
+ 'div{transform:translateY(0.504123px)}',
636
+ 'div{transform:translateY(0.5px)}'
637
+ ],
638
+ 'do not round 2nd decimal place pixels': 'div{transform:translateY(20.55px)}',
639
+ 'do not round percentages': 'div{left:20.505%}',
640
+ 'do not round ems': 'div{font-size:1.505em}'
641
+ }),
642
+ 'floats custom rounding': cssContext({
643
+ 'rounds to 4 values': [
644
+ 'div{transform:translateY(-418.505123px)}',
645
+ 'div{transform:translateY(-418.5051px)}'
646
+ ]
647
+ }, { roundingPrecision: 4 }),
648
+ 'colors': cssContext({
649
+ 'shorten rgb to standard hexadecimal format': [
650
+ 'a{ color:rgb(5, 10, 15) }',
651
+ 'a{color:#050a0f}'
652
+ ],
653
+ 'skip rgba shortening': [
654
+ 'a{ color:rgba(5, 10, 15, 0.5)}',
655
+ 'a{color:rgba(5,10,15,.5)}'
656
+ ],
657
+ 'shorten colors to 3 digit hex instead of 6 digit': [
658
+ 'a{ background-color: #aa0000; color:rgb(0, 17, 255)}',
659
+ 'a{background-color:#a00;color:#01f}'
660
+ ],
661
+ 'skip shortening IE filter colors': [
662
+ 'a{ filter: chroma(color = "#ff0000")}',
663
+ 'a{filter:chroma(color="#ff0000")}'
664
+ ],
665
+ 'color names to hex values': [
666
+ 'a{color:white;border-color:black;background-color:fuchsia}p{background:yellow}',
667
+ 'a{color:#fff;border-color:#000;background-color:#f0f}p{background:#ff0}'
668
+ ],
669
+ 'keep selectors with color name #1': ".black-and-white .foo{color:#fff;background-color:#000}",
670
+ 'keep selectors with color name #2': ".go-blues{background:#000}",
671
+ 'keep selectors with color name #3': "#top_white{background:#000}",
672
+ 'keep selectors with color name #4': "a[data-sth=white]{background:#000}",
673
+ 'color names to hex values with important': [
674
+ 'a{color:white !important}',
675
+ 'a{color:#fff!important}'
676
+ ],
677
+ 'color names to hex values in gradients': [
678
+ 'p{background:linear-gradient(-90deg,black,white)}',
679
+ 'p{background:linear-gradient(-90deg,#000,#fff)}'
680
+ ],
681
+ 'hex value to color name if shorter': [
682
+ 'p{color:#f00}',
683
+ 'p{color:red}'
684
+ ],
685
+ 'upper case hex value to color name if shorter': [
686
+ 'p{color:#F00}',
687
+ 'p{color:red}'
688
+ ],
689
+ 'upper case long hex value to color name if shorter': [
690
+ 'p{color:#FF0000}',
691
+ 'p{color:red}'
692
+ ],
693
+ 'hex value to color name in borders': [
694
+ 'p{border:1px solid #f00}',
695
+ 'p{border:1px solid red}'
696
+ ],
697
+ 'hex value to color name in gradients': [
698
+ 'p{background:-moz-linear-gradient(-90deg,#000,#f00)}',
699
+ 'p{background:-moz-linear-gradient(-90deg,#000,red)}'
700
+ ],
701
+ 'hex value to color name in gradients #2': [
702
+ 'p{background:-webkit-gradient(linear, left top, left bottom, from(#000), to(#f00))}',
703
+ 'p{background:-webkit-gradient(linear,left top,left bottom,from(#000),to(red))}'
704
+ ],
705
+ 'border color - keep unchanged': 'p{border:1px solid #f94311}',
706
+ 'border color - hex to name': [
707
+ 'p{border:1em dotted #f00}',
708
+ 'p{border:1em dotted red}'
709
+ ],
710
+ 'border color - name to hex': [
711
+ 'p{border:1em dotted white}',
712
+ 'p{border:1em dotted #fff}'
713
+ ],
714
+ 'border color - rgb': [
715
+ 'p{border:1em dotted rgb(255,0,0)}',
716
+ 'p{border:1em dotted red}'
717
+ ],
718
+ 'colors and colons': 'a{background-image:linear-gradient(top,red,#e6e6e6)}',
719
+ 'colors and parentheses': 'a{background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6))}',
720
+ 'colors in ie filters': 'a{filter:chroma(color=#ffffff)}',
721
+ 'colors in ie filters 2': "a{progid:DXImageTransform.Microsoft.gradient(startColorstr='#cccccc', endColorstr='#000000')}",
722
+ 'colors in ie filters 3': "a{progid:DXImageTransform.Microsoft.gradient(startColorstr='#DDDDDD', endColorstr='#333333')}",
723
+ 'rgb percents': 'a{color:rgb(100%,0%,0%)}',
724
+ 'rgba percents': 'a{color:rgba(100%,0%,0%,.5)}',
725
+ 'hsla percents': 'a{color:hsla(1,0%,0%,.5)}',
726
+ 'hsla custom ': 'a{color:hsl(80,30%,50%,.5)}',
727
+ 'hsl to hex #1': [
728
+ 'a{color:hsl(0,0%,0%)}',
729
+ 'a{color:#000}'
730
+ ],
731
+ 'hsl to hex #2': [
732
+ 'a{color:hsl(0,100%,100%)}',
733
+ 'a{color:#fff}'
734
+ ],
735
+ 'hsl to hex #3': [
736
+ 'a{color:hsl(240,100%,50%)}',
737
+ 'a{color:#00f}'
738
+ ],
739
+ 'hsl to hex #4': [
740
+ 'a{color:hsl(240,100%,50%)}',
741
+ 'a{color:#00f}'
742
+ ],
743
+ 'hsl to hex #5': [
744
+ 'a{color:hsl(120,100%,25%)}',
745
+ 'a{color:#007f00}'
746
+ ],
747
+ 'hsl to hex #6': [
748
+ 'a{color:hsl(99,66%,33%)}',
749
+ 'a{color:#438b1c}'
750
+ ],
751
+ 'hsl to hex #7': [
752
+ 'a{color:hsl(360,100%,50%)}',
753
+ 'a{color:red}'
754
+ ],
755
+ 'hsla not to hex': 'a{color:hsl(99,66%,33%,.5)}',
756
+ 'hsl out of bounds #1': [
757
+ 'a{color:hsl(120,200%,50%)}',
758
+ 'a{color:#0f0}'
759
+ ],
760
+ 'hsl out of bounds #2': [
761
+ 'a{color:hsl(120,-100%,50%)}',
762
+ 'a{color:#7f7f7f}'
763
+ ],
764
+ 'hsl out of bounds #3': [
765
+ 'a{color:hsl(480,100%,25%)}',
766
+ 'a{color:#007f00}'
767
+ ],
768
+ 'hsl out of bounds #4': [
769
+ 'a{color:hsl(-240,100%,75%)}',
770
+ 'a{color:#7fff7f}'
771
+ ],
772
+ 'hsl out of bounds #5': [
773
+ 'a{color:hsl(-600,100%,75%)}',
774
+ 'a{color:#7fff7f}'
775
+ ],
776
+ 'hsl out of bounds #6': [
777
+ 'a{color:hsl(0,0%,122%)}',
778
+ 'a{color:#fff}'
779
+ ],
780
+ 'hsl out of bounds #7': [
781
+ 'a{color:hsl(0,0%,-10%)}',
782
+ 'a{color:#000}'
783
+ ],
784
+ 'rgb out of a lower bound': [
785
+ 'a{color:rgb(-1,-1,-1)}',
786
+ 'a{color:#000}'
787
+ ],
788
+ 'rgb out of an upper bound': [
789
+ 'a{color:rgb(256,256,256)}',
790
+ 'a{color:#fff}'
791
+ ],
792
+ 'turns rgba(0,0,0,0) to transparent': [
793
+ 'a{color:rgba(0,0,0,0)}',
794
+ 'a{color:transparent}'
795
+ ],
796
+ 'turns rgba(0.0,0.0,.0,0) to transparent': [
797
+ 'a{color:rgba(0.0,0.0,.0,0)}',
798
+ 'a{color:transparent}'
799
+ ],
800
+ 'turns rgba(255,255,255,0) to transparent': [
801
+ 'a{color:rgba(255,255,255,0)}',
802
+ 'a{color:transparent}'
803
+ ],
804
+ 'turns rgba(255,0,255,0) to transparent': [
805
+ 'a{color:rgba(255,0,255,0)}',
806
+ 'a{color:transparent}'
807
+ ],
808
+ 'turns hsla(120,100%,50%,0) to transparent': [
809
+ 'a{color:hsla(120,100%,50%,0)}',
810
+ 'a{color:transparent}'
811
+ ],
812
+ 'keeps rgba(0,0,0,.5)': 'a{color:rgba(0,0,0,.5)}',
813
+ 'keeps rgba(0,255,0,.5)': 'a{color:rgba(0,255,0,.5)}',
814
+ 'keeps hsla(120,100%,50%,.5)': 'a{color:hsla(120,100%,50%,.5)}',
815
+ 'keeps rgba(0,0,0,0) when inside a gradient': 'a{background:linear-gradient(0,#000,rgba(0,0,0,0))}',
816
+ 'keeps hsla(120,100%,50%,0) when inside a gradient': 'a{background:linear-gradient(0,#000,hsla(120,100%,50%,0))}',
817
+ 'removes only right transparent colors': [
818
+ 'a{background-color:linear-gradient(0,#000,hsla(120,100%,50%,0)),rgba(0,0,0,0)}',
819
+ 'a{background-color:linear-gradient(0,#000,hsla(120,100%,50%,0)),transparent}'
820
+ ]
821
+ }),
822
+ 'border-radius': cssContext({
823
+ 'border radius H+V 0/0': [
824
+ 'a{border-radius:0 / 0}',
825
+ 'a{border-radius:0}'
826
+ ],
827
+ 'border radius side H+V 0/0': [
828
+ 'a{border-top-left-radius:0 / 0}',
829
+ 'a{border-top-left-radius:0}'
830
+ ],
831
+ 'border radius H+V same values': [
832
+ 'a{border-radius:5px / 5px}',
833
+ 'a{border-radius:5px}'
834
+ ],
835
+ 'border radius side H+V same values': [
836
+ 'a{border-top-left-radius:1em / 1em}',
837
+ 'a{border-top-left-radius:1em}'
838
+ ],
839
+ 'border radius H+V same expanded values': [
840
+ 'a{border-radius:5px 5px 5px 5px / 5px 5px}',
841
+ 'a{border-radius:5px}'
842
+ ]
843
+ }),
844
+ 'shortening colors': colorShorteningContext(),
845
+ 'font weights': cssContext({
846
+ 'font-weight:normal to 400': [
847
+ 'p{font-weight:normal}',
848
+ 'p{font-weight:400}'
849
+ ],
850
+ 'font-weight:bold to 700': [
851
+ 'p{font-weight:bold}',
852
+ 'p{font-weight:700}'
853
+ ],
854
+ 'font weight in font declarations': [
855
+ 'body{font:normal 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif}',
856
+ 'body{font:400 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif}'
857
+ ],
858
+ 'font weight in font declarations with fraction units': [
859
+ 'p{font:bold .9rem Helvetica}',
860
+ 'p{font:700 .9rem Helvetica}'
861
+ ],
862
+ 'multiple changes': [
863
+ 'p{font-weight:bold!important;width:100%;font:normal 12px Helvetica}',
864
+ 'p{font-weight:700!important;width:100%;font:400 12px Helvetica}'
865
+ ],
866
+ 'font weight in extended font declarations': 'a{font:normal normal normal 13px/20px Helvetica}',
867
+ 'font weight where style and weight are declared': 'a{font:normal 300 100%/1.5 sans-serif}'
868
+ }),
869
+ 'unicode': cssContext({
870
+ 'font-names': 'body{font-family:\\5FAE\\8F6F\\96C5\\9ED1,\\5B8B\\4F53,sans-serif}'
871
+ }),
872
+ 'urls': cssContext({
873
+ 'keep urls without parentheses unchanged': 'a{background:url(/images/blank.png)}',
874
+ 'keep non-encoded data URI unchanged': ".icon-logo{background-image:url('data:image/svg+xml;charset=US-ASCII')}",
875
+ 'strip quotes from base64 encoded PNG data URI': [
876
+ ".icon-logo{background-image:url('data:image/png;base64,iVBORw0')}",
877
+ ".icon-logo{background-image:url(data:image/png;base64,iVBORw0)}"
878
+ ],
879
+ 'strip quotes from base64 encoded ICO data URI': [
880
+ '.icon-logo{background-image:url("data:image/x-icon;base64,AAABAAEAEBA")}',
881
+ '.icon-logo{background-image:url(data:image/x-icon;base64,AAABAAEAEBA)}'
882
+ ],
883
+ 'strip single parentheses': [
884
+ "a{background:url('/images/blank.png')}",
885
+ "a{background:url(/images/blank.png)}"
886
+ ],
887
+ 'strip double parentheses': [
888
+ 'a{background:url("/images/blank.png")}',
889
+ 'a{background:url(/images/blank.png)}'
890
+ ],
891
+ 'strip more': [
892
+ 'p{background:url("/images/blank.png")}b{display:block}a{background:url("/images/blank2.png")}',
893
+ 'p{background:url(/images/blank.png)}b{display:block}a{background:url(/images/blank2.png)}'
894
+ ],
895
+ 'not strip comments if spaces inside': [
896
+ 'p{background:url("/images/long image name.png")}b{display:block}a{background:url("/images/no-spaces.png")}',
897
+ 'p{background:url("/images/long image name.png")}b{display:block}a{background:url(/images/no-spaces.png)}'
898
+ ],
899
+ 'not add a space before url\'s hash': "a{background:url(/fonts/d90b3358-e1e2-4abb-ba96-356983a54c22.svg#d90b3358-e1e2-4abb-ba96-356983a54c22)}",
900
+ 'keep urls from being stripped down #1': 'a{background:url(/image-1.0.png)}',
901
+ 'keep urls from being stripped down #2': "a{background:url(/image-white.png)}",
902
+ 'keep urls from being stripped down #3': "a{background:url(/libraries/jquery-ui-1.10.1.custom/images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top #eee}",
903
+ 'keep special markers in comments (so order is important)': '/*! __ESCAPED_URL_CLEAN_CSS0__ */a{display:block}',
904
+ 'strip new line in urls': [
905
+ 'a{background:url(/very/long/\
906
+ path)}',
907
+ 'a{background:url(/very/long/path)}'
908
+ ],
909
+ 'strip new line in urls which could be unquoted': [
910
+ 'a{background:url("/very/long/\
911
+ path")}',
912
+ 'a{background:url(/very/long/path)}'
913
+ ]
914
+ }),
915
+ 'urls rewriting - no root or target': cssContext({
916
+ 'no @import': 'a{background:url(test/data/partials/extra/down.gif) no-repeat}',
917
+ 'relative @import': [
918
+ '@import url(test/data/partials-relative/base.css);',
919
+ 'a{background:url(test/data/partials/extra/down.gif) no-repeat}'
920
+ ],
921
+ 'relative @import twice': [
922
+ '@import url(test/data/partials-relative/extra/included.css);',
923
+ 'a{background:url(test/data/partials/extra/down.gif) no-repeat}'
924
+ ],
925
+ 'absolute @import': [
926
+ '@import url(/test/data/partials-relative/base.css);',
927
+ 'a{background:url(test/data/partials/extra/down.gif) no-repeat}'
928
+ ]
929
+ }),
930
+ 'urls rewriting - root but no target': cssContext({
931
+ 'no @import': [
932
+ 'a{background:url(../partials/extra/down.gif) no-repeat}',
933
+ 'a{background:url(/test/data/partials/extra/down.gif) no-repeat}'
934
+ ],
935
+ 'relative @import': [
936
+ '@import url(base.css);',
937
+ 'a{background:url(/test/data/partials/extra/down.gif) no-repeat}'
938
+ ],
939
+ 'absolute @import': [
940
+ '@import url(/test/data/partials-relative/base.css);',
941
+ 'a{background:url(/test/data/partials/extra/down.gif) no-repeat}'
942
+ ]
943
+ }, {
944
+ root: process.cwd(),
945
+ relativeTo: path.join('test', 'data', 'partials-relative')
946
+ }),
947
+ 'urls rewriting - no root but target': cssContext({
948
+ 'no @import': [
949
+ 'a{background:url(../partials/extra/down.gif) no-repeat}',
950
+ 'a{background:url(test/data/partials/extra/down.gif) no-repeat}'
951
+ ],
952
+ 'relative @import': [
953
+ '@import url(base.css);',
954
+ 'a{background:url(test/data/partials/extra/down.gif) no-repeat}'
955
+ ],
956
+ 'absolute @import': [
957
+ '@import url(/test/data/partials-relative/base.css);',
958
+ 'a{background:url(test/data/partials/extra/down.gif) no-repeat}'
959
+ ]
960
+ }, {
961
+ target: path.join(process.cwd(), 'test.css'),
962
+ relativeTo: path.join('test', 'data', 'partials-relative')
963
+ }),
964
+ 'urls rewriting - root and target': cssContext({
965
+ 'no @import': [
966
+ 'a{background:url(../partials/extra/down.gif) no-repeat}',
967
+ 'a{background:url(/test/data/partials/extra/down.gif) no-repeat}'
968
+ ],
969
+ 'relative @import': [
970
+ '@import url(base.css);',
971
+ 'a{background:url(/test/data/partials/extra/down.gif) no-repeat}'
972
+ ],
973
+ 'absolute @import': [
974
+ '@import url(/test/data/partials-relative/base.css);',
975
+ 'a{background:url(/test/data/partials/extra/down.gif) no-repeat}'
976
+ ]
977
+ }, {
978
+ root: process.cwd(),
979
+ target: path.join(process.cwd(), 'test.css'),
980
+ relativeTo: path.join('test', 'data', 'partials-relative')
981
+ }),
982
+ 'fonts': cssContext({
983
+ 'keep format quotation': "@font-face{font-family:PublicVintage;src:url(/PublicVintage.otf) format('opentype')}",
984
+ 'remove font family quotation': [
985
+ "a{font-family:\"Helvetica\",'Arial'}",
986
+ "a{font-family:Helvetica,Arial}"
987
+ ],
988
+ 'do not remove font family double quotation if space inside': 'a{font-family:"Courier New"}',
989
+ 'do not remove font quotation if starts with a number': 'a{font:\'123font\'}',
990
+ 'do not remove font family quotation if starts with a number': 'a{font-family:\'123font\'}',
991
+ 'remove font quotation': [
992
+ "a{font:12px/16px \"Helvetica\",'Arial'}",
993
+ "a{font:12px/16px Helvetica,Arial}"
994
+ ],
995
+ 'remove font quotation #2': [
996
+ "a{font:12px/16px \"Helvetica1_12\",'Arial_1451'}",
997
+ "a{font:12px/16px Helvetica1_12,Arial_1451}"
998
+ ],
999
+ 'remove font quotation #3': [
1000
+ "a{font:12px/16px \"Helvetica-Regular\",'Arial-Bold'}",
1001
+ "a{font:12px/16px Helvetica-Regular,Arial-Bold}"
1002
+ ],
1003
+ 'do not remove quotation from enclosed JSON (weird, I know)': "p{font-family:'{ \"current\" : \"large\", \"all\" : [\"small\", \"medium\", \"large\"], \"position\" : 2 }'}"
1004
+ }),
1005
+ 'IE hacks': cssContext({
1006
+ 'star': 'a{*color:#fff}',
1007
+ 'unserscore': 'a{_color:#fff}',
1008
+ 'backslash': 'a{color:#fff\\9}',
1009
+ 'overriding by a star': 'a{color:red;display:block;*color:#fff}',
1010
+ 'overriding by a unserscore': 'a{color:red;display:block;_color:#fff}',
1011
+ 'overriding by a backslash': 'a{color:red;display:block;color:#fff\\9}',
1012
+ 'overriding !important by a star': 'a{color:red!important;display:block;*color:#fff}',
1013
+ 'overriding !important by a unserscore': 'a{color:red!important;display:block;_color:#fff}',
1014
+ 'overriding !important by a backslash': [
1015
+ 'a{color:red!important;display:block;color:#fff\\9}',
1016
+ 'a{color:red!important;display:block}'
1017
+ ],
1018
+ 'overriding a star': [
1019
+ 'a{*color:red;display:block;*color:#fff}',
1020
+ 'a{display:block;*color:#fff}'
1021
+ ],
1022
+ 'overriding a unserscore': [
1023
+ 'a{_color:red;display:block;_color:#fff}',
1024
+ 'a{display:block;_color:#fff}'
1025
+ ],
1026
+ 'overriding a backslash': [
1027
+ 'a{color:red\\9;display:block;color:#fff\\9}',
1028
+ 'a{display:block;color:#fff\\9}'
1029
+ ],
1030
+ 'overriding a star by a non-ajacent selector': 'a{color:red}.one{display:block}a{*color:#fff}',
1031
+ 'overriding a unserscore by a non-ajacent selector': 'a{color:red}.one{display:block}a{_color:#fff}',
1032
+ 'overriding a backslash by a non-ajacent selector': 'a{color:red}.one{display:block}a{color:#fff\\9}',
1033
+ 'keeps rgba(0,0,0,0)': 'a{color:rgba(0,0,0,0)}',
1034
+ 'keeps rgba(255,255,255,0)': 'a{color:rgba(255,255,255,0)}',
1035
+ 'keeps hsla(120,100%,50%,0)': 'a{color:hsla(120,100%,50%,0)}'
1036
+ }, { compatibility: 'ie8' }),
1037
+ 'IE hacks without IE compatibility': cssContext({
1038
+ 'star': [
1039
+ 'a{*color:#fff}',
1040
+ ''
1041
+ ],
1042
+ 'unserscore': [
1043
+ 'a{_color:#fff}',
1044
+ ''
1045
+ ],
1046
+ 'two in a row': [
1047
+ 'a{padding:0;*height:13px;*width:13px}',
1048
+ 'a{padding:0}'
1049
+ ],
1050
+ 'two in a row mixed': [
1051
+ 'a{padding:0;*height:13px;_width:13px}',
1052
+ 'a{padding:0}'
1053
+ ],
1054
+ 'backslash': [
1055
+ 'a{color:#fff\\9}',
1056
+ ''
1057
+ ]
1058
+ }),
1059
+ 'animations': cssContext({
1060
+ 'shorten': [
1061
+ '@keyframes test\n{ from\n { width:100px; }\n to { width:200px; }\n}',
1062
+ '@keyframes test{from{width:100px}to{width:200px}}'
1063
+ ],
1064
+ 'remove name quotes': [
1065
+ "@keyframes \"test1\"{a{display:block}}@keyframes 'test2'{a{display:block}}",
1066
+ "@keyframes test1{a{display:block}}@keyframes test2{a{display:block}}"
1067
+ ],
1068
+ 'not remove name quotes if whitespace inside': "@keyframes \"test 1\"{a{display:block}}@keyframes 'test 2'{a{display:block}}",
1069
+ 'remove name quotes for vendor prefixes': [
1070
+ "@-moz-keyframes 'test'{a{display:block}}@-o-keyframes 'test'{a{display:block}}@-webkit-keyframes 'test'{a{display:block}}",
1071
+ "@-moz-keyframes test{a{display:block}}@-o-keyframes test{a{display:block}}@-webkit-keyframes test{a{display:block}}"
1072
+ ],
1073
+ 'remove quotes in animation': [
1074
+ "div{animation:'test' 2s ease-in .5s 3}",
1075
+ "div{animation:test 2s ease-in .5s 3}"
1076
+ ],
1077
+ 'not remove quotes in animation when name with space inside': "div{animation:'test 1' 2s ease-in .5s 3}",
1078
+ 'remove quotes in vendor prefixed animation': [
1079
+ "div{-moz-animation:'test' 2s ease-in;-o-animation:'test' 2s ease-in;-webkit-animation:'test' 2s ease-in}",
1080
+ "div{-moz-animation:test 2s ease-in;-o-animation:test 2s ease-in;-webkit-animation:test 2s ease-in}"
1081
+ ],
1082
+ 'remove quotes in animation-name': [
1083
+ "div{animation-name:'test'}",
1084
+ "div{animation-name:test}"
1085
+ ],
1086
+ 'not remove quotes in animation-name when name with space inside': "div{animation-name:'test 1'}",
1087
+ 'remove quotes in vendor prefixed animation-name': [
1088
+ "div{-moz-animation-name:'test';-o-animation-name:'test';-webkit-animation-name:'test'}",
1089
+ "div{-moz-animation-name:test;-o-animation-name:test;-webkit-animation-name:test}"
1090
+ ]
1091
+ }),
1092
+ 'attributes': cssContext({
1093
+ 'should keep selector if no value': 'div[data-type]{border-color:red}',
1094
+ 'should keep selector if no quotation': 'div[data-type=something]{border-color:red}',
1095
+ 'should keep selector if equals in value': 'div[data-type="stupid=value"]{border-color:red}',
1096
+ 'should keep quotation if whitespace inside': 'div[data-type^=\'object 1\']{border-color:red}',
1097
+ 'should keep quotations if special characters inside': 'a[data-type="object+1"]{color:red}p[data-target="#some-place"]{color:#0f0}',
1098
+ 'should keep quotation if is a number': 'div[data-number=\'1\']{border-color:red}',
1099
+ 'should keep quotation if starts with a number': 'div[data-type^=\'1something\']{border-color:red}',
1100
+ 'should keep quotation if starts with a hyphen': 'div[data-type$=\'-something\']{border-color:red}',
1101
+ 'should keep quotation if key only (which is invalid)': 'div["data-type"]{color:red}',
1102
+ 'should strip quotation if is a word': [
1103
+ 'a[data-href=\'object\']{border-color:red}',
1104
+ 'a[data-href=object]{border-color:red}'
1105
+ ],
1106
+ 'should strip quotation if is a hyphen separated words': [
1107
+ 'a[data-href=\'object-1-two\']{border-color:red}',
1108
+ 'a[data-href=object-1-two]{border-color:red}'
1109
+ ],
1110
+ 'should strip quotations if is less specific selectors': [
1111
+ 'a[data-href*=\'object1\']{border-color:red}a[data-href|=\'object2\']{border-color:#0f0}',
1112
+ 'a[data-href*=object1]{border-color:red}a[data-href|=object2]{border-color:#0f0}'
1113
+ ],
1114
+ 'should keep special characters inside attributes #1': "a[data-css='color:white']{display:block}",
1115
+ 'should keep special characters inside attributes #2': 'a[href="/version-0.01.html"]{display:block}',
1116
+ 'should strip new lines inside attributes': [
1117
+ ".test[title='my very long \
1118
+ title']{display:block}",
1119
+ ".test[title='my very long title']{display:block}"
1120
+ ],
1121
+ 'should strip new lines inside attributes which can be unquoted': [
1122
+ ".test[title='my_very_long_\
1123
+ title']{display:block}",
1124
+ ".test[title=my_very_long_title]{display:block}"
1125
+ ],
1126
+ 'should strip whitespace between square brackets': [
1127
+ 'body[ data-title ]{color:red}',
1128
+ 'body[data-title]{color:red}'
1129
+ ],
1130
+ 'should strip whitespace inside square brackets': [
1131
+ 'body[ data-title = x ]{color:red}',
1132
+ 'body[data-title=x]{color:red}'
1133
+ ]
1134
+ }),
1135
+ 'ie filters': cssContext({
1136
+ 'short alpha': [
1137
+ "a{ filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80); -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)';}",
1138
+ "a{filter:alpha(Opacity=80);-ms-filter:'alpha(Opacity=50)'}"
1139
+ ],
1140
+ 'short chroma': [
1141
+ 'a{filter:progid:DXImageTransform.Microsoft.Chroma(color=#919191)}',
1142
+ 'a{filter:chroma(color=#919191)}'
1143
+ ],
1144
+ 'matrix filter spaces': [
1145
+ "a{filter:progid:DXImageTransform.Microsoft.Matrix(M11=0.984, M22=0.984, M12=0.17, M21=-0.17, SizingMethod='auto expand')}",
1146
+ "a{filter:progid:DXImageTransform.Microsoft.Matrix(M11=.984, M22=.984, M12=.17, M21=-.17, SizingMethod='auto expand')}"
1147
+ ],
1148
+ 'multiple filters (IE7 issue)': [
1149
+ "a{filter:progid:DXImageTransform.Microsoft.Chroma(color=#919191) progid:DXImageTransform.Microsoft.Matrix(M11=0.984, M22=0.984, M12=0.17, M21=-0.17, SizingMethod='auto expand')}",
1150
+ "a{filter:progid:DXImageTransform.Microsoft.Chroma(color=#919191) progid:DXImageTransform.Microsoft.Matrix(M11=.984, M22=.984, M12=.17, M21=-.17, SizingMethod='auto expand')}"
1151
+ ]
1152
+ }),
1153
+ 'charsets': cssContext({
1154
+ 'not at beginning': [
1155
+ "a{ color: #f10; }@charset 'utf-8';b { font-weight: bolder}",
1156
+ "@charset 'utf-8';a{color:#f10}b{font-weight:bolder}"
1157
+ ],
1158
+ 'multiple charsets': [
1159
+ "@charset 'utf-8';div :before { display: block }@charset 'utf-8';a { color: #f10 }",
1160
+ "@charset 'utf-8';div :before{display:block}a{color:#f10}"
1161
+ ],
1162
+ 'charset and space after': [
1163
+ "@charset 'utf-8';" + lineBreak + lineBreak + "a{display:block}",
1164
+ "@charset 'utf-8';a{display:block}"
1165
+ ]
1166
+ }),
1167
+ 'important': cssContext({
1168
+ 'space before': [
1169
+ "body{background-color:#fff !important}",
1170
+ "body{background-color:#fff!important}"
1171
+ ],
1172
+ 'space between ! and important': [
1173
+ "body{background-color:#fff ! important}",
1174
+ "body{background-color:#fff!important}"
1175
+ ]
1176
+ }),
1177
+ 'empty elements': cssContext({
1178
+ 'single': [
1179
+ ' div p { \n}',
1180
+ ''
1181
+ ],
1182
+ 'between non-empty': [
1183
+ 'div {color:#fff} a{ } p{ line-height:1.35em}',
1184
+ 'div{color:#fff}p{line-height:1.35em}'
1185
+ ],
1186
+ 'just a semicolon': [
1187
+ 'div { ; }',
1188
+ ''
1189
+ ],
1190
+ 'inside @media': [
1191
+ "@media screen { .test {} } .test1 { color: green; }",
1192
+ ".test1{color:green}"
1193
+ ],
1194
+ 'inside nested @media': [
1195
+ '@media screen { @media (orientation:landscape) { @media (max-width:999px) { .test {} } } }',
1196
+ ''
1197
+ ],
1198
+ 'inside not empty @media': [
1199
+ "@media screen { .test {} .some { display:none } }",
1200
+ "@media screen{.some{display:none}}"
1201
+ ],
1202
+ 'inside nested not empty @media': [
1203
+ '@media screen { @media (orientation:landscape) { @media (max-width:999px) { .test {} } a {color:red} } }',
1204
+ '@media screen{@media (orientation:landscape){a{color:red}}}'
1205
+ ]
1206
+ }),
1207
+ 'empty @media': cssContext({
1208
+ 'simple': [
1209
+ '@media print{}',
1210
+ ''
1211
+ ],
1212
+ 'simple with and': [
1213
+ '@media print and screen{}',
1214
+ ''
1215
+ ],
1216
+ 'complex': [
1217
+ '@media print, (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {\n}',
1218
+ ''
1219
+ ]
1220
+ }),
1221
+ 'empty with disabled advanced optimizations': cssContext({
1222
+ 'selector': [
1223
+ 'a{}p{}',
1224
+ ''
1225
+ ],
1226
+ 'media': [
1227
+ '@media screen{}',
1228
+ ''
1229
+ ]
1230
+ }, { noAdvanced: true }),
1231
+ '@import': cssContext({
1232
+ 'empty': [
1233
+ "@import url();",
1234
+ ''
1235
+ ],
1236
+ 'of an unknown file': [
1237
+ "@import url('fake.css');",
1238
+ ''
1239
+ ],
1240
+ 'of an unknown file with a missing trailing semicolon': [
1241
+ "@import url(fake.css)",
1242
+ ''
1243
+ ],
1244
+ 'of a directory': [
1245
+ "@import url(test/data/partials);",
1246
+ ''
1247
+ ],
1248
+ 'of a real file': [
1249
+ "@import url(test/data/partials/one.css);",
1250
+ ".one{color:red}"
1251
+ ],
1252
+ 'of a real file twice': [
1253
+ "@import url(test/data/partials/one.css);@import url(test/data/partials/one.css);",
1254
+ ".one{color:red}"
1255
+ ],
1256
+ 'of a real file with current path prefix': [
1257
+ "@import url(./test/data/partials/one.css);",
1258
+ ".one{color:red}"
1259
+ ],
1260
+ 'of a real file with quoted path': [
1261
+ "@import url('test/data/partials/one.css');",
1262
+ ".one{color:red}"
1263
+ ],
1264
+ 'of a real file with double-quoted path': [
1265
+ '@import url("test/data/partials/one.css");',
1266
+ ".one{color:red}"
1267
+ ],
1268
+ 'of a real file with bare path': [
1269
+ "@import test/data/partials/one.css;",
1270
+ ".one{color:red}"
1271
+ ],
1272
+ 'of a real file with bare quoted path': [
1273
+ "@import 'test/data/partials/one.css';",
1274
+ ".one{color:red}"
1275
+ ],
1276
+ 'of a real file with bare double-quoted path': [
1277
+ '@import "test/data/partials/one.css";',
1278
+ ".one{color:red}"
1279
+ ],
1280
+ 'of a real file with single simple media': [
1281
+ '@import url(test/data/partials/one.css) screen;',
1282
+ "@media screen{.one{color:red}}"
1283
+ ],
1284
+ 'of a real file with multiple simple media': [
1285
+ '@import "test/data/partials/one.css" screen, tv, print;',
1286
+ "@media screen,tv,print{.one{color:red}}"
1287
+ ],
1288
+ 'of a real file with complex media': [
1289
+ '@import \'test/data/partials/one.css\' screen and (orientation:landscape);',
1290
+ "@media screen and (orientation:landscape){.one{color:red}}"
1291
+ ],
1292
+ 'of a real file with a missing trailing semicolon': [
1293
+ "@import url(test/data/partials/one.css)",
1294
+ ''
1295
+ ],
1296
+ 'of a real files with a missing trailing semicolon': [
1297
+ "@import url(test/data/partials/one.css)@import url(test/data/partials/two.css)",
1298
+ ''
1299
+ ],
1300
+ 'of more files': [
1301
+ "@import url(test/data/partials/one.css);\n\n@import url(test/data/partials/extra/three.css);\n\na{display:block}",
1302
+ ".one{color:red}.three{color:#0f0}a{display:block}"
1303
+ ],
1304
+ 'of more files with media': [
1305
+ "@import url(test/data/partials/one.css) screen;@import url(test/data/partials/extra/three.css) tv;",
1306
+ "@media screen{.one{color:red}}@media tv{.three{color:#0f0}}"
1307
+ ],
1308
+ 'of multi-level, circular dependency file': [
1309
+ "@import url(test/data/partials/two.css);",
1310
+ ".one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}"
1311
+ ],
1312
+ 'of a file with a relative resource path': [
1313
+ "@import url(test/data/partials/three.css);",
1314
+ ".three{background-image:url(test/data/partials/extra/down.gif)}"
1315
+ ],
1316
+ 'of a file with an absolute resource path': [
1317
+ "@import url(test/data/partials/four.css);",
1318
+ ".four{background-image:url(/partials/extra/down.gif)}"
1319
+ ],
1320
+ 'of a file with a resource URI': [
1321
+ "@import url(test/data/partials/five.css);",
1322
+ ".five{background:url(data:image/jpeg;base64,/9j/)}"
1323
+ ],
1324
+ 'inside a comment': [
1325
+ '/* @import url(test/data/partials/five.css); */a { color: red; }',
1326
+ 'a{color:red}'
1327
+ ],
1328
+ 'after a comment': [
1329
+ '/* @import url(test/data/partials/one.css); */@import url(test/data/partials/one.css);a { color: red; }',
1330
+ '.one,a{color:red}'
1331
+ ],
1332
+ 'used arbitrarily in comment': [
1333
+ '/* @import foo */a { color: red; }',
1334
+ 'a{color:red}'
1335
+ ],
1336
+ 'used arbitrarily in comment multiple times': [
1337
+ '/* @import foo */a { color: red; }\n/* @import bar */p { color: #fff; }',
1338
+ 'a{color:red}p{color:#fff}'
1339
+ ],
1340
+ 'used arbitrarily in comment including unrelated comment': [
1341
+ '/* foo */a { color: red; }/* bar *//* @import */',
1342
+ 'a{color:red}'
1343
+ ],
1344
+ 'of a file with a comment': [
1345
+ '@import url(test/data/partials/comment.css);',
1346
+ 'a{display:block}'
1347
+ ],
1348
+ 'of a file (with media) with a comment': [
1349
+ '@import url(test/data/partials/comment.css) screen and (device-height: 600px);',
1350
+ '@media screen and (device-height:600px){a{display:block}}'
1351
+ ],
1352
+ 'after standard content': [
1353
+ "a{display:block}@import url(test/data/partials/one.css);body{margin:0}",
1354
+ "a{display:block}body{margin:0}"
1355
+ ],
1356
+ 'after quoted content': [
1357
+ "/*a{display:block}*/@import url(test/data/partials/one.css);",
1358
+ ".one{color:red}"
1359
+ ]
1360
+ }, { root: process.cwd() }),
1361
+ '@import with absolute paths': cssContext({
1362
+ 'of an unknown file': [
1363
+ "@import url(/fake.css);",
1364
+ ''
1365
+ ],
1366
+ 'of a real file': [
1367
+ "@import url(/partials/one.css);",
1368
+ ".one{color:red}"
1369
+ ],
1370
+ 'of a real file with quoted paths': [
1371
+ "@import url(\"/partials/one.css\");",
1372
+ ".one{color:red}"
1373
+ ],
1374
+ 'of two files with mixed paths': [
1375
+ "@import url(/partials/one.css);@import url(partials/extra/three.css);a{display:block}",
1376
+ ".one{color:red}.three{color:#0f0}a{display:block}"
1377
+ ],
1378
+ 'of a multi-level, circular dependency file': [
1379
+ "@import url(/partials/two.css);",
1380
+ ".one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}"
1381
+ ],
1382
+ 'of a multi-level, circular dependency file with mixed paths': [
1383
+ "@import url(/partials-absolute/base.css);",
1384
+ ".base2{border-width:0}.sub{padding:0}.base{margin:0}"
1385
+ ]
1386
+ }, { root: path.join(process.cwd(), 'test', 'data') }),
1387
+ '@import with option processImport': cssContext({
1388
+ 'of an unknown file': [
1389
+ "@import url(/fake.css);",
1390
+ "@import url(/fake.css);"
1391
+ ],
1392
+ 'of an unknown file with extra whitespace': [
1393
+ "@import url( /fake.css );",
1394
+ "@import url(/fake.css);"
1395
+ ],
1396
+ 'of comment chars within import url': "@import 'necolas/normalize.css@*/normalize.css';"
1397
+ }, { processImport: false }),
1398
+ '@import with no import and no advanced': cssContext({
1399
+ 'empty body': [
1400
+ '@import url(//fonts.googleapis.com/css?family=Domine:700);body{/* comment */}body h1{font-family:Domine}',
1401
+ '@import url(//fonts.googleapis.com/css?family=Domine:700);body h1{font-family:Domine}'
1402
+ ],
1403
+ 'no empty body': '@import url(//fonts.googleapis.com/css?family=Domine:700);body{color:red}body h1{font-family:Domine}'
1404
+ }, { processImport: false, noAdvanced: true }),
1405
+ 'duplicate selectors with disabled advanced processing': cssContext({
1406
+ 'of a duplicate selector': 'a,a{color:red}'
1407
+ }, { noAdvanced: true }),
1408
+ 'line breaks with disabled advanced processing': cssContext({
1409
+ 'should be applied': [
1410
+ 'a{color:red}p{display:block}',
1411
+ 'a{color:red}' + lineBreak + 'p{display:block}'
1412
+ ]
1413
+ }, { noAdvanced: true, keepBreaks: true }),
1414
+ 'invalid data tokenization': cssContext({
1415
+ 'extra top-level closing brace': [
1416
+ 'a{color:red}}p{width:auto}',
1417
+ 'a{color:red}p{width:auto}'
1418
+ ],
1419
+ 'extra top-level closing braces': [
1420
+ 'a{color:red}}}}p{width:auto}',
1421
+ 'a{color:red}p{width:auto}'
1422
+ ]
1423
+ }),
1424
+ 'duplicate selectors in a list': cssContext({
1425
+ 'of a duplicate selector': [
1426
+ 'a,a{color:red}',
1427
+ 'a{color:red}'
1428
+ ],
1429
+ 'of an unordered multiply repeated selector': [
1430
+ 'a,b,p,a{color:red}',
1431
+ 'a,b,p{color:red}'
1432
+ ],
1433
+ 'of an unordered multiply repeated selector within a block': [
1434
+ '@media screen{a,b,p,a{color:red}}',
1435
+ '@media screen{a,b,p{color:red}}'
1436
+ ],
1437
+ 'of an unordered multiply repeated complex selector within a block #1': [
1438
+ '@media screen{.link[data-path],a,p,.link[data-path]{color:red}}',
1439
+ '@media screen{.link[data-path],a,p{color:red}}'
1440
+ ],
1441
+ 'of an unordered multiply repeated complex selector within a block #2': [
1442
+ '@media screen{#foo[data-path^="bar bar"],a,p,#foo[data-path^="bar bar"]{color:red}}',
1443
+ '@media screen{#foo[data-path^="bar bar"],a,p{color:red}}'
1444
+ ]
1445
+ }),
1446
+ 'duplicate selectors in a scope': cssContext({
1447
+ 'of two successive selectors': [
1448
+ 'a{color:red}a{color:red}',
1449
+ 'a{color:red}'
1450
+ ],
1451
+ 'of two successive selectors with different body': [
1452
+ 'a{color:red}a{display:block}',
1453
+ 'a{color:red;display:block}'
1454
+ ],
1455
+ 'of many successive selectors': [
1456
+ 'a{color:red}a{color:red}a{color:red}a{color:red}',
1457
+ 'a{color:red}'
1458
+ ],
1459
+ 'of two non-successive selectors': [
1460
+ 'a{color:red}p{color:#fff}a{color:red}',
1461
+ 'p{color:#fff}a{color:red}'
1462
+ ],
1463
+ 'of many non-successive selectors': [
1464
+ 'div{width:100%}a{color:red}a{color:red}p{color:#fff}div{width:100%}ol{margin:0}p{color:#fff}',
1465
+ 'a{color:red}div{width:100%}ol{margin:0}p{color:#fff}'
1466
+ ],
1467
+ 'with global and media scope': [
1468
+ 'a{color:red}@media screen{a{color:red}p{width:100px}a{color:red}}',
1469
+ 'a{color:red}@media screen{p{width:100px}a{color:red}}'
1470
+ ],
1471
+ 'with two media scopes': [
1472
+ '@media (min-width:100px){a{color:red}}@media screen{a{color:red}p{width:100px}a{color:red}}',
1473
+ '@media (min-width:100px){a{color:red}}@media screen{p{width:100px}a{color:red}}'
1474
+ ]
1475
+ }),
1476
+ 'duplicate properties': cssContext({
1477
+ 'of two properties one after another': 'a{display:-moz-inline-box;display:inline-block}',
1478
+ 'of two properties in one declaration': [
1479
+ 'a{display:inline-block;color:red;display:block}',
1480
+ 'a{color:red;display:block}'
1481
+ ],
1482
+ 'of two properties in one declaration with former as !important': [
1483
+ 'a{display:inline-block!important;color:red;display:block}',
1484
+ 'a{display:inline-block!important;color:red}'
1485
+ ],
1486
+ 'of two properties in one declaration with latter as !important': [
1487
+ 'a{display:inline-block;color:red;display:block!important}',
1488
+ 'a{color:red;display:block!important}'
1489
+ ],
1490
+ 'of two properties in one declaration with both as !important': [
1491
+ 'a{display:inline-block!important;color:red;display:block!important}',
1492
+ 'a{color:red;display:block!important}'
1493
+ ],
1494
+ 'of many properties in one declaration': [
1495
+ 'a{display:inline-block;color:red;font-weight:bolder;font-weight:700;display:block!important;color:#fff}',
1496
+ 'a{font-weight:bolder;font-weight:700;display:block!important;color:#fff}'
1497
+ ],
1498
+ 'both redefined and overridden': [
1499
+ 'p{display:block;display:-moz-inline-box;color:red;display:table-cell}',
1500
+ 'p{color:red;display:table-cell}'
1501
+ ],
1502
+ 'background redefined with merging': [
1503
+ '.one{display:block}.one{background:#fff;background:-webkit-gradient();background:-moz-linear-gradient();filter:progid:DXImageTransform}',
1504
+ '.one{display:block;background:#fff;background:-webkit-gradient();background:-moz-linear-gradient();filter:progid:DXImageTransform}'
1505
+ ],
1506
+ 'filter treated as background': 'p{background:-moz-linear-gradient();background:-webkit-linear-gradient();filter:"progid:DXImageTransform";background:linear-gradient()}',
1507
+ 'filter treated as background-image': 'p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();filter:"progid:DXImageTransform";background-image:linear-gradient()}',
1508
+ '-ms-filter treated as background': 'p{background:-moz-linear-gradient();background:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background:linear-gradient()}',
1509
+ '-ms-filter treated as background-image': 'p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background-image:linear-gradient()}',
1510
+ '-ms-transform with different values #1': 'div{-ms-transform:translate(0,0);-ms-transform:translate3d(0,0,0)}',
1511
+ '-ms-transform with different values #2': 'div{-ms-transform:translate(0,0);-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0)}',
1512
+ 'transform with different values #1': 'div{transform:translate(0,0);transform:translate3d(0,0,0)}',
1513
+ 'transform with different values #2': 'div{transform:translate(0,0);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}',
1514
+ 'border(hex) with border(rgba)': 'a{border:1px solid #fff;display:none;border:1px solid rgba(1,0,0,.5)}',
1515
+ 'border(hex !important) with border(hex)': [
1516
+ 'a{border:1px solid #fff!important;display:none;border:1px solid #fff}',
1517
+ 'a{border:1px solid #fff!important;display:none}'
1518
+ ],
1519
+ 'border(hex) with border(hex !important)': [
1520
+ 'a{border:1px solid #fff;display:none;border:1px solid #fff!important}',
1521
+ 'a{display:none;border:1px solid #fff!important}'
1522
+ ]
1523
+ }),
1524
+ 'duplicate properties with aggressive merging disabled': cssContext({
1525
+ 'of (yet) unmergeable properties': 'a{display:inline-block;color:red;display:-moz-block}',
1526
+ 'of mergeable properties': [
1527
+ 'a{background:red;display:block;background:white}',
1528
+ 'a{display:block;background:#fff}'
1529
+ ]
1530
+ }, { noAggressiveMerging: true }),
1531
+ 'same selectors': cssContext({
1532
+ 'of two non-adjacent selectors': '.one{color:red}.two{color:#00f}.one{font-weight:700}',
1533
+ 'of two adjacent single selectors': [
1534
+ '.one{color:red}.one{font-weight:700}',
1535
+ '.one{color:red;font-weight:700}'
1536
+ ],
1537
+ 'of three adjacent single selectors': [
1538
+ '.one{color:red}.one{font-weight:700}.one{font-size:12px}',
1539
+ '.one{color:red;font-weight:700;font-size:12px}'
1540
+ ],
1541
+ 'of two adjacent single, complex selectors': [
1542
+ '#box>.one{color:red}#box>.one{font-weight:700}',
1543
+ '#box>.one{color:red;font-weight:700}'
1544
+ ],
1545
+ 'of two adjacent multiple, complex selectors': [
1546
+ '#box>.one,.zero{color:red}#box>.one,.zero{font-weight:700}',
1547
+ '#box>.one,.zero{color:red;font-weight:700}'
1548
+ ],
1549
+ 'of two adjacent selectors with duplicate properties #1': [
1550
+ '.one{color:red}.one{color:#fff}',
1551
+ '.one{color:#fff}'
1552
+ ],
1553
+ 'of two adjacent selectors with duplicate properties #2': [
1554
+ '.one{color:red;font-weight:bold}.one{color:#fff;font-weight:400}',
1555
+ '.one{color:#fff;font-weight:400}'
1556
+ ],
1557
+ 'of two adjacent complex selectors with different selector order': [
1558
+ '.one,.two{color:red}.two,.one{line-height:1em}',
1559
+ '.one,.two{color:red;line-height:1em}'
1560
+ ],
1561
+ 'two adjacent with hex color definitions': [
1562
+ 'a:link,a:visited{color:#fff}.one{display:block}a:link,a:visited{color:red}',
1563
+ '.one{display:block}a:link,a:visited{color:red}'
1564
+ ],
1565
+ 'in two passes': [
1566
+ 'a{color:red}a{background:red}b{color:red}b{background:red}',
1567
+ 'a,b{color:red;background:red}'
1568
+ ],
1569
+ 'when overriden with a browser specific selector': 'a{color:red}::-webkit-scrollbar,a{color:#fff}'
1570
+ }),
1571
+ 'same non-adjacent selectors': cssContext({
1572
+ 'with different properties': 'a{color:red;display:block}.one{font-size:12px}a{margin:2px}',
1573
+ 'with one redefined property': [
1574
+ 'a{color:red;display:block}.one{font-size:12px}a{color:#fff;margin:2px}',
1575
+ 'a{display:block}.one{font-size:12px}a{color:#fff;margin:2px}'
1576
+ ],
1577
+ 'with intentionally redefined properties on joins': [
1578
+ 'a{display:inline-block;display:-moz-inline-box;color:red}.one{font-size:12px}a{color:#fff;margin:2px}',
1579
+ 'a{display:inline-block;display:-moz-inline-box}.one{font-size:12px}a{color:#fff;margin:2px}'
1580
+ ],
1581
+ 'with intentionally redefined properties on nultiple joins': [
1582
+ 'a{color:red}.one{font-size:12px}a{color:#fff;margin:2px}.two{font-weight:400}a{margin:0}',
1583
+ '.one{font-size:12px}a{color:#fff}.two{font-weight:400}a{margin:0}'
1584
+ ],
1585
+ 'with all redefined properties': [
1586
+ 'a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}',
1587
+ '.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}'
1588
+ ],
1589
+ 'many with all redefined properties': [
1590
+ 'a{padding:10px}.zero{color:transparent}a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}',
1591
+ 'a{padding:10px}.zero{color:transparent}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}'
1592
+ ],
1593
+ 'when overriden by an empty selector': [
1594
+ 'a{padding:10px}.one{color:red}a{}',
1595
+ 'a{padding:10px}.one{color:red}'
1596
+ ],
1597
+ 'when overriden by a complex selector': [
1598
+ 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}',
1599
+ 'a{margin:0}.one{color:red}a,p{color:red;padding:0}'
1600
+ ],
1601
+ 'when overriden by complex selectors': [
1602
+ 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}.one,a{color:#fff}',
1603
+ 'a{margin:0}a,p{color:red;padding:0}.one,a{color:#fff}'
1604
+ ],
1605
+ 'when complex selector overriden by simple selectors': 'a,p{margin:0;color:red}a{color:#fff}',
1606
+ // Pending re-run selectors merge - see #160
1607
+ 'when complex selector overriden by complex and simple selectors': [
1608
+ 'a,p{margin:0;color:red}a{color:#fff}a,p{color:#00f}p{color:#0f0}',
1609
+ 'a,p{margin:0}a,p{color:#00f}p{color:#0f0}'
1610
+ ],
1611
+ 'when complex selector overriden by complex selectors': [
1612
+ '.one>.two,.three{color:red;line-height:1rem}#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}',
1613
+ '#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}'
1614
+ ],
1615
+ 'when undefined is used as a value': '.one{text-shadow:undefined}p{color:red}.one{font-size:12px}',
1616
+ 'when undefined is used as a value with reduction': [
1617
+ '.one{text-shadow:undefined}p{color:red}.one{font-size:12px;text-shadow:none}',
1618
+ 'p{color:red}.one{font-size:12px;text-shadow:none}'
1619
+ ],
1620
+ 'when overriden with a browser specific selector': 'a{color:red}p{display:block}::-moz-selection,a{color:#fff}',
1621
+ 'when same browser specific selector more than once': [
1622
+ 'a,::-moz-selection{color:red}p{display:block}a,::-moz-selection{color:#fff}',
1623
+ 'p{display:block}::-moz-selection,a{color:#fff}'
1624
+ ],
1625
+ 'with full property comparison': '.one{height:7rem}.two{height:auto}.one{line-height:7rem;color:red}'
1626
+ }),
1627
+ 'rerun optimizers': cssContext({
1628
+ 'selectors reducible once': [
1629
+ '.one{color:red;margin:0}.two{color:red}.one{margin:0}',
1630
+ '.one,.two{color:red}.one{margin:0}'
1631
+ ]
1632
+ }),
1633
+ 'same bodies': cssContext({
1634
+ 'of two non-adjacent selectors': '.one{color:red}.two{color:#00f}.three{color:red}',
1635
+ 'of two adjacent single selectors': [
1636
+ '.one{color:red}.two{color:red}',
1637
+ '.one,.two{color:red}'
1638
+ ],
1639
+ 'of three adjacent complex, multiple selectors': [
1640
+ '.one{color:red}#two.three{color:red}.four>.five{color:red}',
1641
+ '#two.three,.four>.five,.one{color:red}'
1642
+ ],
1643
+ 'with repeated selectors': [
1644
+ '#zero>p,.one,.two{color:red}.two,#zero>p,.three{color:red}',
1645
+ '#zero>p,.one,.three,.two{color:red}'
1646
+ ]
1647
+ }),
1648
+ 'same bodies - IE8 compat': cssContext({
1649
+ 'of two supported selectors': [
1650
+ '.one:first-child{color:red}.two>.three{color:red}',
1651
+ '.one:first-child,.two>.three{color:red}'
1652
+ ],
1653
+ 'of supported and unsupported selector': '.one:first-child{color:red}.two:last-child{color:red}',
1654
+ 'of two unsupported selectors': '.one:nth-child(5){color:red}.two:last-child{color:red}'
1655
+ }, { compatibility: 'ie8' }),
1656
+ 'same bodies - IE7 compat': cssContext({
1657
+ 'of two supported selectors': [
1658
+ '.one{color:red}.two>.three{color:red}',
1659
+ '.one,.two>.three{color:red}'
1660
+ ],
1661
+ 'of supported and unsupported selector': '.one{color:red}.two:last-child{color:red}',
1662
+ 'of two unsupported selectors': '.one:before{color:red}.two:last-child{color:red}'
1663
+ }, { compatibility: 'ie7' }),
1664
+ 'redefined more granular properties': redefineContext({
1665
+ 'animation-delay': ['animation'],
1666
+ 'animation-direction': ['animation'],
1667
+ 'animation-duration': ['animation'],
1668
+ 'animation-fill-mode': ['animation'],
1669
+ 'animation-iteration-count': ['animation'],
1670
+ 'animation-name': ['animation'],
1671
+ 'animation-play-state': ['animation'],
1672
+ 'animation-timing-function': ['animation'],
1673
+ 'background-attachment': ['background'],
1674
+ 'background-clip': ['background'],
1675
+ 'background-color': ['background'],
1676
+ 'background-image': ['background'],
1677
+ 'background-origin': ['background'],
1678
+ 'background-position': ['background'],
1679
+ 'background-repeat': ['background'],
1680
+ 'background-size': ['background'],
1681
+ 'border-color': ['border'],
1682
+ 'border-style': ['border'],
1683
+ 'border-width': ['border'],
1684
+ 'border-bottom': ['border'],
1685
+ 'border-bottom-color': ['border-bottom', 'border-color', 'border'],
1686
+ 'border-bottom-style': ['border-bottom', 'border-style', 'border'],
1687
+ 'border-bottom-width': ['border-bottom', 'border-width', 'border'],
1688
+ 'border-left': ['border'],
1689
+ 'border-left-color': ['border-left', 'border-color', 'border'],
1690
+ 'border-left-style': ['border-left', 'border-style', 'border'],
1691
+ 'border-left-width': ['border-left', 'border-width', 'border'],
1692
+ 'border-right': ['border'],
1693
+ 'border-right-color': ['border-right', 'border-color', 'border'],
1694
+ 'border-right-style': ['border-right', 'border-style', 'border'],
1695
+ 'border-right-width': ['border-right', 'border-width', 'border'],
1696
+ 'border-top': ['border'],
1697
+ 'border-top-color': ['border-top', 'border-color', 'border'],
1698
+ 'border-top-style': ['border-top', 'border-style', 'border'],
1699
+ 'border-top-width': ['border-top', 'border-width', 'border'],
1700
+ 'font-family': ['font'],
1701
+ 'font-size': ['font'],
1702
+ 'font-style': ['font'],
1703
+ 'font-variant': ['font'],
1704
+ 'font-weight': ['font'],
1705
+ 'list-style-image': ['list-style'],
1706
+ 'list-style-position': ['list-style'],
1707
+ 'list-style-type': ['list-style'],
1708
+ 'margin-bottom': ['margin'],
1709
+ 'margin-left': ['margin'],
1710
+ 'margin-right': ['margin'],
1711
+ 'margin-top': ['margin'],
1712
+ 'outline-color': ['outline'],
1713
+ 'outline-style': ['outline'],
1714
+ 'outline-width': ['outline'],
1715
+ 'padding-bottom': ['padding'],
1716
+ 'padding-left': ['padding'],
1717
+ 'padding-right': ['padding'],
1718
+ 'padding-top': ['padding'],
1719
+ 'transition-delay': ['transition'],
1720
+ 'transition-duration': ['transition'],
1721
+ 'transition-property': ['transition'],
1722
+ 'transition-timing-function': ['transition']
1723
+ }, { vendorPrefixes: ['animation', 'transition'], noneFor: ['list-style-image'] }),
1724
+ 'redefined more granular properties with property merging': cssContext({
1725
+ 'should merge background with background-attachment': [
1726
+ 'a{background:0;background-attachment:fixed}',
1727
+ 'a{background:0 fixed}'
1728
+ ],
1729
+ 'should NOT merge background with inherited background-attachment': [
1730
+ 'a{background:0;background-attachment:inherit}',
1731
+ 'a{background:0;background-attachment:inherit}'
1732
+ ],
1733
+ 'should merge background with background-color': [
1734
+ 'a{background:0;background-color:#9fce00}',
1735
+ 'a{background:0 #9fce00}'
1736
+ ],
1737
+ 'should NOT merge background with inherited background-color': [
1738
+ 'a{background:0;background-color:inherit}',
1739
+ 'a{background:0;background-color:inherit}'
1740
+ ],
1741
+ 'should merge background with background-image': [
1742
+ 'a{background:0;background-image:url(hello_world)}',
1743
+ 'a{background:url(hello_world) 0}'
1744
+ ],
1745
+ 'should NOT merge background with inherited background-image': [
1746
+ 'a{background:0;background-image:inherit}',
1747
+ 'a{background:0;background-image:inherit}'
1748
+ ],
1749
+ 'should merge background with background-position': [
1750
+ 'a{background:0;background-position:3px 4px}',
1751
+ 'a{background:3px 4px}'
1752
+ ],
1753
+ 'should NOT merge background with inherited background-position': [
1754
+ 'a{background:0;background-position:inherit}',
1755
+ 'a{background:0;background-position:inherit}'
1756
+ ],
1757
+ 'should merge background with background-repeat': [
1758
+ 'a{background:0;background-repeat:repeat-y}',
1759
+ 'a{background:0 repeat-y}'
1760
+ ],
1761
+ 'should NOT merge background with inherited background-repeat': [
1762
+ 'a{background:0;background-repeat:inherit}',
1763
+ 'a{background:0;background-repeat:inherit}'
1764
+ ],
1765
+ 'should merge outline with outline-color': [
1766
+ 'a{outline:1px;outline-color:#9fce00}',
1767
+ 'a{outline:#9fce00 1px}'
1768
+ ],
1769
+ 'should NOT merge outline with inherited outline-color': [
1770
+ 'a{outline:0;outline-color:inherit}',
1771
+ 'a{outline:0;outline-color:inherit}'
1772
+ ],
1773
+ 'should merge outline with outline-style': [
1774
+ 'a{outline:0;outline-style:dashed}',
1775
+ 'a{outline:dashed 0}'
1776
+ ],
1777
+ 'should NOT merge outline with inherited outline-style': [
1778
+ 'a{outline:0;outline-style:inherit}',
1779
+ 'a{outline:0;outline-style:inherit}'
1780
+ ],
1781
+ 'should merge outline with outline-width': [
1782
+ 'a{outline:0;outline-width:5px}',
1783
+ 'a{outline:5px}'
1784
+ ],
1785
+ 'should NOT merge outline with inherited outline-width': [
1786
+ 'a{outline:0;outline-width:inherit}',
1787
+ 'a{outline:0;outline-width:inherit}'
1788
+ ],
1789
+ 'should merge list-style with list-style-type': [
1790
+ 'li{list-style-type:disc;list-style:inside}',
1791
+ 'li{list-style:inside}'
1792
+ ]
1793
+ }),
1794
+ 'shorthand properties': cssContext({
1795
+ 'shorthand background #1' : [
1796
+ 'div{background-color:#111;background-image:url(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto}',
1797
+ 'div{background:url(aaa) #111}'
1798
+ ],
1799
+ 'shorthand background #2' : [
1800
+ 'div{background-color:#111;background-image:url(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll;background-size:auto}',
1801
+ 'div{background:url(aaa) no-repeat #111}'
1802
+ ],
1803
+ 'shorthand important background' : [
1804
+ 'div{background-color:#111!important;background-image:url(aaa)!important;background-repeat:repeat!important;background-position:0 0!important;background-attachment:scroll!important;background-size:auto!important}',
1805
+ 'div{background:url(aaa) #111!important}'
1806
+ ],
1807
+ 'shorthand border-width': [
1808
+ '.t{border-top-width:7px;border-bottom-width:7px;border-left-width:4px;border-right-width:4px}',
1809
+ '.t{border-width:7px 4px}'
1810
+ ],
1811
+ 'shorthand border-color #1': [
1812
+ '.t{border-top-color:#9fce00;border-bottom-color:#9fce00;border-left-color:#9fce00;border-right-color:#9fce00}',
1813
+ '.t{border-color:#9fce00}'
1814
+ ],
1815
+ 'shorthand border-color #2': [
1816
+ '.t{border-right-color:#002;border-bottom-color:#003;border-top-color:#001;border-left-color:#004}',
1817
+ '.t{border-color:#001 #002 #003 #004}'
1818
+ ],
1819
+ 'shorthand border-radius': [
1820
+ '.t{border-top-left-radius:7px;border-bottom-right-radius:6px;border-bottom-left-radius:5px;border-top-right-radius:3px}',
1821
+ '.t{border-radius:7px 3px 6px 5px}'
1822
+ ],
1823
+ 'shorthand border-radius none': 'li{border-radius:none}',
1824
+ 'shorthand list-style #1': [
1825
+ '.t{list-style-type:circle;list-style-position:outside;list-style-image:url(aaa)}',
1826
+ '.t{list-style:circle url(aaa)}'
1827
+ ],
1828
+ 'shorthand list-style #2': [
1829
+ '.t{list-style-image:url(aaa);list-style-type:circle;list-style-position:inside}',
1830
+ '.t{list-style:circle inside url(aaa)}'
1831
+ ]
1832
+ }),
1833
+ 'care about understandability of shorthand components': cssContext({
1834
+ 'linear-gradient should NOT clear out background with color only' : [
1835
+ 'div{background:#fff;background:linear-gradient(whatever)}',
1836
+ 'div{background:#fff;background:linear-gradient(whatever)}'
1837
+ ],
1838
+ 'linear-gradient should NOT clear out background with color only, even if it has a color' : [
1839
+ 'div{background:#fff;background:linear-gradient(whatever) #222}',
1840
+ 'div{background:#fff;background:linear-gradient(whatever) #222}'
1841
+ ],
1842
+ 'a background-image with just a linear-gradient should not be compacted to a shorthand' : [
1843
+ 'div{background-color:#111;background-image:linear-gradient(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll}',
1844
+ 'div{background-color:#111;background-image:linear-gradient(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll}'
1845
+ ],
1846
+ 'a background-image with a none and a linear-gradient should result in two shorthands' : [
1847
+ 'div{background-color:#111;background-image:none;background-image:linear-gradient(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto}',
1848
+ 'div{background:#111;background:linear-gradient(aaa) #111}'
1849
+ ]
1850
+ }),
1851
+ 'cares about understandability of border components': cssContext({
1852
+ 'border(none) with border(rgba)': 'a{border:none;border:1px solid rgba(1,0,0,.5)}',
1853
+ 'border(rgba) with border(none)': 'a{border:1px solid rgba(1,0,0,.5);border:none}',
1854
+ 'border(hex) with border(rgba)': 'a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)}'
1855
+ }),
1856
+ 'merge same properties sensibly': cssContext({
1857
+ 'should merge color values with same understandability #1': [
1858
+ 'p{color:red;color:#fff;color:blue}',
1859
+ 'p{color:#00f}'
1860
+ ],
1861
+ 'should merge color values with same understandability #2': [
1862
+ 'p{color:red;color:#fff;color:blue;color:transparent}',
1863
+ 'p{color:transparent}'
1864
+ ],
1865
+ 'should NOT destroy less understandable values': [
1866
+ 'p{color:red;color:#fff;color:blue;color:rgba(1,2,3,.4)}',
1867
+ 'p{color:#00f;color:rgba(1,2,3,.4)}'
1868
+ ],
1869
+ 'should destroy even less understandable values if a more understandable one comes after them': [
1870
+ 'p{color:red;color:#fff;color:blue;color:rgba(1,2,3,.4);color:#9fce00}',
1871
+ 'p{color:#9fce00}'
1872
+ ],
1873
+ 'should merge functions with the same name but keep different functions intact': [
1874
+ 'p{background:-webkit-linear-gradient(aaa);background:-webkit-linear-gradient(bbb);background:linear-gradient(aaa);}',
1875
+ 'p{background:-webkit-linear-gradient(bbb);background:linear-gradient(aaa)}'
1876
+ ],
1877
+ 'should merge nonimportant + important into one important': [
1878
+ 'a{color:#aaa;color:#bbb!important}',
1879
+ 'a{color:#bbb!important}'
1880
+ ],
1881
+ 'should merge important + nonimportant into one important': [
1882
+ 'a{color:#aaa!important;color:#bbb}',
1883
+ 'a{color:#aaa!important}'
1884
+ ],
1885
+ 'should merge importants just like nonimportants while also overriding them': [
1886
+ 'p{color:red!important;color:#fff!important;color:blue!important;color:rgba(1,2,3,.4)}',
1887
+ 'p{color:#00f!important}'
1888
+ ]
1889
+ }),
1890
+ 'shorthand granular properties when other granular properties are already covered by the shorthand': cssContext({
1891
+ 'should consider the already existing margin to shorthand margin-top and margin-bottom': [
1892
+ 'p{margin:5px;margin-top:foo(1);margin-left:foo(2)}',
1893
+ 'p{margin:5px;margin:foo(1) 5px 5px foo(2)}'
1894
+ ],
1895
+ 'should merge margin-top and margin-left with shorthand if their understandability is the same': [
1896
+ 'p{margin:5px;margin-top:1px;margin-left:2px}',
1897
+ 'p{margin:1px 5px 5px 2px}'
1898
+ ],
1899
+ 'should NOT shorthand to margin-top if the result would be longer than the input': [
1900
+ 'p{margin:5px;margin-top:foo(1)}',
1901
+ 'p{margin:5px;margin-top:foo(1)}'
1902
+ ],
1903
+ 'should consider the already existing background to shorthand background-color': [
1904
+ 'p{background:#9fce00;background-color:rgba(1,2,3,.4)}',
1905
+ 'p{background:#9fce00;background:rgba(1,2,3,.4)}'
1906
+ ],
1907
+ 'should NOT touch important outline-color but should minify default value of outline to 0': [
1908
+ 'p{outline:medium;outline-color:#9fce00!important}',
1909
+ 'p{outline:0;outline-color:#9fce00!important}'
1910
+ ]
1911
+ }),
1912
+ 'take advantage of importants for optimalization opportunities': cssContext({
1913
+ 'should take into account important margin-left to shorthand non-important margin-top, margin-right and margin-bottom': [
1914
+ 'p{margin-top:1px;margin-right:2px;margin-bottom:3px;margin-left:4px !important}',
1915
+ 'p{margin:1px 2px 3px;margin-left:4px!important}'
1916
+ ],
1917
+ 'should take into account important margin-bottom and margin-left to shorten shorthanded non-important margin-top and margin-bottom': [
1918
+ 'p{margin-top:1px;margin-right:2px;margin-bottom:3px!important;margin-left:4px !important}',
1919
+ 'p{margin:1px 2px;margin-bottom:3px!important;margin-left:4px!important}'
1920
+ ],
1921
+ 'should take into account important margin-right and margin-left to shorten shorthanded non-important margin-top and margin-bottom': [
1922
+ 'p{margin-top:1px;margin-bottom:3px;margin-right:2px!important;margin-left:4px !important}',
1923
+ 'p{margin:1px 0 3px;margin-right:2px!important;margin-left:4px!important}'
1924
+ ],
1925
+ 'should take into account important margin-right and margin-left to shorten shorthanded non-important margin-top and margin-bottom #2': [
1926
+ 'p{margin-top:1px;margin-bottom:1px;margin-right:2px!important;margin-left:4px !important}',
1927
+ 'p{margin:1px;margin-right:2px!important;margin-left:4px!important}'
1928
+ ],
1929
+ 'should take into account important background-color and shorthand others into background': [
1930
+ 'p{background-color:#9fce00!important;background-image:url(hello);background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y;background-size:auto}',
1931
+ 'p{background-color:#9fce00!important;background:url(hello) 1px 2px repeat-y}'
1932
+ ],
1933
+ 'should take into account important outline-color and default value of outline-width': [
1934
+ 'p{outline:inset medium;outline-color:#9fce00!important;outline-style:inset!important}',
1935
+ 'p{outline:0;outline-color:#9fce00!important;outline-style:inset!important}'
1936
+ ],
1937
+ 'should take into account important background-position remove its irrelevant counterpart': [
1938
+ 'p{background:#9fce00 url(hello) 4px 5px;background-position:5px 3px!important}',
1939
+ 'p{background:url(hello) #9fce00;background-position:5px 3px!important}'
1940
+ ],
1941
+ 'should take into account important background-position and assign the shortest possible value for its irrelevant counterpart': [
1942
+ 'p{background:transparent;background-position:5px 3px!important}',
1943
+ 'p{background:0;background-position:5px 3px!important}'
1944
+ ]
1945
+ }),
1946
+ 'properly care about inherit': cssContext({
1947
+ 'merge multiple inherited margin granular properties into one inherited shorthand': [
1948
+ 'p{margin-top:inherit;margin-right:inherit;margin-bottom:inherit;margin-left:inherit}',
1949
+ 'p{margin:inherit}'
1950
+ ],
1951
+ 'merge multiple inherited background granular properties into one inherited shorthand': [
1952
+ 'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:inherit;;background-size:inherit}',
1953
+ 'p{background:inherit}'
1954
+ ],
1955
+ 'when shorter, optimize inherited/non-inherited background granular properties into an inherited shorthand and some non-inherited granular properties': [
1956
+ 'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:repeat-y;background-size:inherit}',
1957
+ 'p{background:inherit;background-repeat:repeat-y}'
1958
+ ],
1959
+ 'when shorter, optimize inherited/non-inherited background granular properties into a non-inherited shorthand and some inherited granular properties': [
1960
+ 'p{background-color:#9fce00;background-image:inherit;background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y;background-size:auto}',
1961
+ 'p{background:1px 2px repeat-y #9fce00;background-image:inherit}'
1962
+ ],
1963
+ 'put inherit to the place where it consumes the least space': [
1964
+ 'div{padding:0;padding-bottom:inherit;padding-right:inherit}',
1965
+ 'div{padding:inherit;padding-top:0;padding-left:0}'
1966
+ ]
1967
+ }),
1968
+ 'remove defaults from shorthands': cssContext({
1969
+ 'all-default background should be changed to shortest possible default value': [
1970
+ 'div{background:transparent none repeat 0 0 scroll}',
1971
+ 'div{background:0 0}'
1972
+ ],
1973
+ 'default background components should be removed #1': [
1974
+ 'body{background:#9fce00 none repeat scroll}',
1975
+ 'body{background:#9fce00}'
1976
+ ],
1977
+ 'default background components should be removed #2': [
1978
+ 'body{background:transparent none 1px 5px scroll}',
1979
+ 'body{background:1px 5px}'
1980
+ ],
1981
+ 'default background components should be removed #3': [
1982
+ 'body{background:none repeat scroll 0 0 #000}',
1983
+ 'body{background:#000}'
1984
+ ]
1985
+ }),
1986
+ 'complex granular properties': cssContext({
1987
+ 'two granular properties': 'a{border-bottom:1px solid red;border-color:red}',
1988
+ 'more understandable granular property should override less understandable': [
1989
+ 'a{border-color:rgba(0,0,0,.5);border-color:red}',
1990
+ 'a{border-color:red}'
1991
+ ],
1992
+ 'less understandable granular property should NOT override more understandable': [
1993
+ 'a{border-color:red;border-color:rgba(0,0,0,.5)}',
1994
+ 'a{border-color:red;border-color:rgba(0,0,0,.5)}'
1995
+ ],
1996
+ 'two same granular properties redefined': [
1997
+ 'a{border-color:rgba(0,0,0,.5);border-color:red;border:0}',
1998
+ 'a{border:0}'
1999
+ ],
2000
+ 'important granular property redefined': 'a{border-color:red!important;border:0}',
2001
+ 'important granular property redefined with important': [
2002
+ 'a{border-color:red!important;border:0!important}',
2003
+ 'a{border:0!important}'
2004
+ ],
2005
+ 'mix of border properties': [
2006
+ 'a{border-top:1px solid red;border-top-color:#0f0;color:red;border-top-width:2px;border-bottom-width:1px;border:0;border-left:1px solid red}',
2007
+ 'a{color:red;border:0;border-left:1px solid red}'
2008
+ ]
2009
+ }),
2010
+ 'grouping with advanced optimizations': cssContext({
2011
+ '@-moz-document': '@-moz-document domain(mozilla.org){a{color:red}}',
2012
+ '@media': '@media{a{color:red}}',
2013
+ '@page': '@page{margin:.5em}',
2014
+ '@supports': '@supports (display:flexbox){.flex{display:flexbox}}',
2015
+ '@-ms-viewport': '@-ms-viewport{width:device-width}',
2016
+ '@-o-viewport': '@-o-viewport{width:device-width}',
2017
+ '@viewport': '@viewport{width:device-width}'
2018
+ }),
2019
+ 'background size': cssContext({
2020
+ 'with background-position': 'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}',
2021
+ 'with background-position and spaces': [
2022
+ 'a{background:url(top.jpg) 50% 0 / auto 25% no-repeat}',
2023
+ 'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}'
2024
+ ],
2025
+ 'with background-position shorthands': 'a{background:url(top.jpg) 50px/25% no-repeat}',
2026
+ 'with background-position shorthands and spaces': [
2027
+ 'a{background:url(top.jpg) 0 / cover no-repeat}',
2028
+ 'a{background:url(top.jpg) 0/cover no-repeat}'
2029
+ ],
2030
+ 'with background-size property': [
2031
+ 'a{background:none;background-image:url(1.png);background-size:28px 28px}',
2032
+ 'a{background:url(1.png) 0 0/28px 28px}'
2033
+ ]
2034
+ }),
2035
+ 'misc advanced': cssContext({
2036
+ 'outline auto': [
2037
+ 'a{outline:5px auto -webkit-focus-ring-color}',
2038
+ 'a{outline:-webkit-focus-ring-color auto 5px}'
2039
+ ],
2040
+ 'border radius side H+V': [
2041
+ 'a{border-top-left-radius:2em / 1em}',
2042
+ 'a{border-top-left-radius:2em/1em}'
2043
+ ],
2044
+ 'border radius expanded H+V': [
2045
+ 'a{border-radius:1em 1em 1em 1em / 2em 2em 2em 2em}',
2046
+ 'a{border-radius:1em/2em}'
2047
+ ],
2048
+ 'border radius expanded H+V with mixed values #1': [
2049
+ 'a{border-radius:1em 2em 1em 2em / 1em 2em 3em 2em}',
2050
+ 'a{border-radius:1em 2em/1em 2em 3em}'
2051
+ ],
2052
+ 'border radius expanded H+V with mixed values #2': 'a{border-radius:1em/1em 1em 1em 2em}',
2053
+ 'border radius H+V': 'a{border-radius:50%/100%}',
2054
+ 'lost background position': [
2055
+ '.one{background:50% no-repeat}.one{background-image:url(/img.png)}',
2056
+ '.one{background:url(/img.png) 50% no-repeat}'
2057
+ ],
2058
+ 'merging color with backgrounds': [
2059
+ 'p{background:red;background-image:url(1.png),url(2.png)}',
2060
+ 'p{background:url(1.png),url(2.png) red}'
2061
+ ],
2062
+ 'unknown @ rule': '@unknown "test";h1{color:red}'
2063
+ }),
2064
+ 'viewport units': cssContext({
2065
+ 'shorthand margin with viewport width not changed': 'div{margin:5vw}'
2066
+ }),
2067
+ 'variables': cssContext({
2068
+ 'stripping': 'a{--border:#000}.one{border:1px solid var(--border)}',
2069
+ 'all values': 'a{--width:1px;--style:solid;--color:#000}.one{border:var(--width) var(--style) var(--color)}'
2070
+ })
2071
+ }).export(module);