cssminify2 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +10 -5
  3. data/CHANGELOG.md +121 -0
  4. data/Dockerfile +16 -0
  5. data/Gemfile +1 -1
  6. data/README.md +501 -42
  7. data/cssminify2.gemspec +6 -2
  8. data/docs/ADVANCED_USAGE.md +616 -0
  9. data/docs/API_REFERENCE.md +464 -0
  10. data/docs/EXAMPLES.md +844 -0
  11. data/docs/MIGRATION_GUIDE.md +586 -0
  12. data/lib/cssminify2/cssmin.rb +89 -7
  13. data/lib/cssminify2/cssmin_enhanced.rb +424 -0
  14. data/lib/cssminify2/enhanced.rb +818 -0
  15. data/lib/cssminify2/version.rb +1 -1
  16. data/lib/cssminify2.rb +53 -4
  17. data/spec/cssminify_spec.rb +49 -34
  18. data/spec/tests/README +6 -0
  19. data/spec/tests/_munge.js +8 -0
  20. data/spec/tests/_munge.js.min +1 -0
  21. data/spec/tests/_string_combo.js +5 -0
  22. data/spec/tests/_string_combo.js.min +1 -0
  23. data/spec/tests/_string_combo2.js +4 -0
  24. data/spec/tests/_string_combo2.js.min +1 -0
  25. data/spec/tests/_string_combo3.js +5 -0
  26. data/spec/tests/_string_combo3.js.min +1 -0
  27. data/spec/tests/_syntax_error.js +73 -0
  28. data/spec/tests/_syntax_error.js.min +1 -0
  29. data/spec/tests/border-none.css +6 -1
  30. data/spec/tests/border-none.css.min +1 -1
  31. data/spec/tests/bug-flex.css +3 -0
  32. data/spec/tests/bug-flex.css.min +1 -0
  33. data/spec/tests/bug-nested-pseudoclass.css +3 -0
  34. data/spec/tests/bug-nested-pseudoclass.css.min +1 -0
  35. data/spec/tests/bug-preservetoken-calc.css +8 -0
  36. data/spec/tests/bug-preservetoken-calc.css.min +1 -0
  37. data/spec/tests/color-keyword.css +1 -0
  38. data/spec/tests/color-keyword.css.min +1 -0
  39. data/spec/tests/color.css +2 -0
  40. data/spec/tests/color.css.min +1 -1
  41. data/spec/tests/concat-charset.css +2 -2
  42. data/spec/tests/concat-charset.css.min +1 -1
  43. data/spec/tests/dataurl-singlequote-font.css +1 -1
  44. data/spec/tests/dataurl-validity.html +29 -0
  45. data/spec/tests/float.js +2 -0
  46. data/spec/tests/float.js.min +1 -0
  47. data/spec/tests/hsla-issue81.css.FAIL +4 -0
  48. data/spec/tests/hsla-issue81.css.min +1 -0
  49. data/spec/tests/ie-backslash9-hack.css +2 -0
  50. data/spec/tests/ie-backslash9-hack.css.min +1 -0
  51. data/spec/tests/issue-59.css +7 -0
  52. data/spec/tests/issue-59.css.min +1 -0
  53. data/spec/tests/issue151.css +8 -0
  54. data/spec/tests/issue151.css.min +1 -0
  55. data/spec/tests/issue172.css.FAIL +4 -0
  56. data/spec/tests/issue172.css.min +1 -0
  57. data/spec/tests/issue180.css +16 -0
  58. data/spec/tests/issue180.css.min +1 -0
  59. data/spec/tests/issue205.css +2 -0
  60. data/spec/tests/issue205.css.min +1 -0
  61. data/spec/tests/issue221.css +1 -1
  62. data/spec/tests/issue221.css.min +1 -1
  63. data/spec/tests/issue222.css +2 -2
  64. data/spec/tests/issue222.css.min +1 -1
  65. data/spec/tests/issue71.js.FAIL +4 -0
  66. data/spec/tests/issue71.js.min +1 -0
  67. data/spec/tests/issue86.js +2 -0
  68. data/spec/tests/issue86.js.min +1 -0
  69. data/spec/tests/jquery-1.6.4.js +9046 -0
  70. data/spec/tests/jquery-1.6.4.js.min +23 -0
  71. data/spec/tests/lowercasing.css +63 -0
  72. data/spec/tests/lowercasing.css.min +1 -0
  73. data/spec/tests/media-test.css +2 -2
  74. data/spec/tests/old-ie-filter-matrix.css +8 -0
  75. data/spec/tests/old-ie-filter-matrix.css.min +1 -0
  76. data/spec/tests/opera-pixel-ratio.css +14 -0
  77. data/spec/tests/opera-pixel-ratio.css.min +1 -0
  78. data/spec/tests/pointzeros.css +6 -0
  79. data/spec/tests/pointzeros.css.min +1 -0
  80. data/spec/tests/preserve-important.css +1 -0
  81. data/spec/tests/preserve-important.css.min +1 -0
  82. data/spec/tests/promise-catch-finally-issue203.js +4 -0
  83. data/spec/tests/promise-catch-finally-issue203.js.min +1 -0
  84. data/spec/tests/pseudo-first.css +2 -2
  85. data/spec/tests/rgb-issue81.css.FAIL +4 -0
  86. data/spec/tests/rgb-issue81.css.min +1 -0
  87. data/spec/tests/suite.rhino +3 -0
  88. data/spec/tests/suite.sh +49 -0
  89. data/spec/tests/zeros.css +2 -2
  90. data/spec/tests/zeros.css.min +1 -1
  91. metadata +129 -14
  92. data/spec/tests/bug2528093.css +0 -3
  93. data/spec/tests/bug2528093.css.min +0 -1
  94. data/spec/tests/keyframe.css +0 -4
  95. data/spec/tests/keyframe.css.min +0 -1
@@ -0,0 +1,464 @@
1
+ # API Reference
2
+
3
+ Complete API documentation for CSSminify2 with examples and detailed parameter descriptions.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Core API (Original)](#core-api-original)
8
+ - [Enhanced API (New Features)](#enhanced-api-new-features)
9
+ - [Configuration Classes](#configuration-classes)
10
+ - [Error Classes](#error-classes)
11
+ - [Examples](#examples)
12
+
13
+ ## Core API (Original)
14
+
15
+ ### CSSminify2.compress(source, line_length = 5000)
16
+
17
+ Basic CSS compression using YUI compressor algorithm.
18
+
19
+ **Parameters:**
20
+ - `source` (String|IO): CSS content to compress. Can be a string or any object that responds to `.read`
21
+ - `line_length` (Integer, optional): Maximum line length for output. Default: 5000
22
+
23
+ **Returns:** String - Compressed CSS
24
+
25
+ **Examples:**
26
+ ```ruby
27
+ # String input
28
+ CSSminify2.compress('body { margin: 0; padding: 0; }')
29
+ # => "body{margin:0;padding:0}"
30
+
31
+ # File input
32
+ CSSminify2.compress(File.open('styles.css'))
33
+
34
+ # Custom line length
35
+ CSSminify2.compress(css_string, 200)
36
+ ```
37
+
38
+ ### CSSminify2#compress(source, line_length = 5000)
39
+
40
+ Instance method equivalent of the class method.
41
+
42
+ **Examples:**
43
+ ```ruby
44
+ compressor = CSSminify2.new
45
+ compressor.compress('body { margin: 0; }')
46
+ # => "body{margin:0}"
47
+ ```
48
+
49
+ ## Enhanced API (New Features)
50
+
51
+ ### CSSminify2.compress_enhanced(source, options = {})
52
+
53
+ Advanced CSS compression with configurable optimization features.
54
+
55
+ **Parameters:**
56
+ - `source` (String|IO): CSS content to compress
57
+ - `options` (Hash): Configuration options
58
+
59
+ **Options:**
60
+ - `merge_duplicate_selectors` (Boolean): Merge duplicate CSS selectors. Default: false
61
+ - `optimize_shorthand_properties` (Boolean): Optimize margin, padding, and other shorthand properties. Default: false
62
+ - `compress_css_variables` (Boolean): Optimize CSS custom properties (variables). Default: false
63
+ - `advanced_color_optimization` (Boolean): Enhanced color optimization with IE filter protection. Default: false
64
+ - `strict_error_handling` (Boolean): Enable strict CSS validation with detailed errors. Default: false
65
+ - `linebreakpos` (Integer): Maximum line length. Default: 5000
66
+
67
+ **Returns:** String - Compressed CSS
68
+
69
+ **Examples:**
70
+ ```ruby
71
+ # Basic enhanced compression
72
+ CSSminify2.compress_enhanced(css, {
73
+ optimize_shorthand_properties: true
74
+ })
75
+
76
+ # Full optimization
77
+ CSSminify2.compress_enhanced(css, {
78
+ merge_duplicate_selectors: true,
79
+ optimize_shorthand_properties: true,
80
+ compress_css_variables: true,
81
+ advanced_color_optimization: true
82
+ })
83
+
84
+ # With strict error handling
85
+ CSSminify2.compress_enhanced(css, {
86
+ optimize_shorthand_properties: true,
87
+ strict_error_handling: true
88
+ })
89
+ ```
90
+
91
+ ### CSSminify2.compress_with_stats(source, options = {})
92
+
93
+ Enhanced compression that returns detailed statistics about the compression process.
94
+
95
+ **Parameters:**
96
+ - `source` (String|IO): CSS content to compress
97
+ - `options` (Hash): Same options as `compress_enhanced`
98
+
99
+ **Returns:** Hash with keys:
100
+ - `compressed_css` (String): The compressed CSS result
101
+ - `statistics` (Hash): Detailed compression statistics
102
+
103
+ **Statistics Hash:**
104
+ - `original_size` (Integer): Original CSS size in characters
105
+ - `compressed_size` (Integer): Compressed CSS size in characters
106
+ - `compression_ratio` (Float): Compression ratio as percentage
107
+ - `selectors_merged` (Integer): Number of duplicate selectors merged
108
+ - `properties_optimized` (Integer): Number of properties optimized
109
+ - `colors_converted` (Integer): Number of colors converted
110
+ - `fallback_used` (Boolean): Whether fallback compression was used
111
+
112
+ **Examples:**
113
+ ```ruby
114
+ stats = CSSminify2.compress_with_stats(css, {
115
+ merge_duplicate_selectors: true,
116
+ optimize_shorthand_properties: true
117
+ })
118
+
119
+ puts "Compressed: #{stats[:compressed_css]}"
120
+ puts "Original: #{stats[:statistics][:original_size]} chars"
121
+ puts "Compressed: #{stats[:statistics][:compressed_size]} chars"
122
+ puts "Ratio: #{stats[:statistics][:compression_ratio]}%"
123
+ puts "Selectors merged: #{stats[:statistics][:selectors_merged]}"
124
+ ```
125
+
126
+ ## Configuration Classes
127
+
128
+ ### CSSminify2Enhanced::Configuration
129
+
130
+ Configuration object for enhanced compression features.
131
+
132
+ **Attributes:**
133
+ - `merge_duplicate_selectors` (Boolean)
134
+ - `optimize_shorthand_properties` (Boolean)
135
+ - `advanced_color_optimization` (Boolean)
136
+ - `preserve_ie_hacks` (Boolean)
137
+ - `compress_css_variables` (Boolean)
138
+ - `strict_error_handling` (Boolean)
139
+ - `generate_source_map` (Boolean)
140
+ - `statistics_enabled` (Boolean)
141
+
142
+ **Class Methods:**
143
+
144
+ #### Configuration.conservative
145
+ Returns a configuration with all enhanced features disabled (default behavior).
146
+
147
+ ```ruby
148
+ config = CSSminify2Enhanced::Configuration.conservative
149
+ # All enhanced features disabled
150
+ ```
151
+
152
+ #### Configuration.aggressive
153
+ Returns a configuration with all optimization features enabled.
154
+
155
+ ```ruby
156
+ config = CSSminify2Enhanced::Configuration.aggressive
157
+ # merge_duplicate_selectors: true
158
+ # optimize_shorthand_properties: true
159
+ # advanced_color_optimization: true
160
+ # compress_css_variables: true
161
+ ```
162
+
163
+ #### Configuration.modern
164
+ Returns aggressive configuration plus additional modern features.
165
+
166
+ ```ruby
167
+ config = CSSminify2Enhanced::Configuration.modern
168
+ # All aggressive features plus:
169
+ # generate_source_map: true
170
+ # statistics_enabled: true
171
+ ```
172
+
173
+ **Examples:**
174
+ ```ruby
175
+ # Custom configuration
176
+ config = CSSminify2Enhanced::Configuration.new
177
+ config.merge_duplicate_selectors = true
178
+ config.optimize_shorthand_properties = true
179
+ config.strict_error_handling = true
180
+
181
+ compressor = CSSminify2Enhanced::Compressor.new(config)
182
+ result = compressor.compress(css)
183
+ ```
184
+
185
+ ### CSSminify2Enhanced::Compressor
186
+
187
+ Enhanced compressor class with configuration support.
188
+
189
+ #### Constructor
190
+ ```ruby
191
+ compressor = CSSminify2Enhanced::Compressor.new(configuration)
192
+ ```
193
+
194
+ **Parameters:**
195
+ - `configuration` (Configuration): Configuration object. Default: Conservative configuration
196
+
197
+ #### Methods
198
+
199
+ ##### #compress(css, linebreakpos = 5000)
200
+ Compress CSS with the configured options.
201
+
202
+ **Parameters:**
203
+ - `css` (String): CSS to compress
204
+ - `linebreakpos` (Integer): Maximum line length
205
+
206
+ **Returns:** String - Compressed CSS
207
+
208
+ ##### #statistics
209
+ Access compression statistics after calling `#compress`.
210
+
211
+ **Returns:** Hash - Statistics about the last compression
212
+
213
+ **Examples:**
214
+ ```ruby
215
+ config = CSSminify2Enhanced::Configuration.aggressive
216
+ compressor = CSSminify2Enhanced::Compressor.new(config)
217
+
218
+ result = compressor.compress(css)
219
+ stats = compressor.statistics
220
+
221
+ puts "Compression ratio: #{stats[:compression_ratio]}%"
222
+ puts "Selectors merged: #{stats[:selectors_merged]}"
223
+ ```
224
+
225
+ ## Error Classes
226
+
227
+ ### CSSminify2Enhanced::EnhancedCompressionError
228
+
229
+ Raised when enhanced compression fails in strict mode.
230
+
231
+ **Attributes:**
232
+ - `original_error` - The underlying error that caused the failure
233
+
234
+ **Example:**
235
+ ```ruby
236
+ begin
237
+ CSSminify2.compress_enhanced(malformed_css, {
238
+ strict_error_handling: true
239
+ })
240
+ rescue CSSminify2Enhanced::EnhancedCompressionError => e
241
+ puts "Compression failed: #{e.message}"
242
+ puts "Original error: #{e.original_error}"
243
+ end
244
+ ```
245
+
246
+ ### CSSminify2Enhanced::MalformedCSSError
247
+
248
+ Raised when CSS validation fails in strict mode.
249
+
250
+ **Attributes:**
251
+ - `css_errors` - Array of specific validation errors found
252
+
253
+ **Example:**
254
+ ```ruby
255
+ begin
256
+ CSSminify2.compress_enhanced(invalid_css, {
257
+ strict_error_handling: true
258
+ })
259
+ rescue CSSminify2Enhanced::MalformedCSSError => e
260
+ puts "CSS validation failed: #{e.message}"
261
+ e.css_errors.each { |error| puts "- #{error}" }
262
+ end
263
+ ```
264
+
265
+ ## Examples
266
+
267
+ ### Basic Usage
268
+
269
+ ```ruby
270
+ require 'cssminify2'
271
+
272
+ # Simple compression
273
+ css = "body { margin: 0; padding: 0; }"
274
+ compressed = CSSminify2.compress(css)
275
+ puts compressed # => "body{margin:0;padding:0}"
276
+
277
+ # File compression
278
+ File.write('output.min.css', CSSminify2.compress(File.read('input.css')))
279
+ ```
280
+
281
+ ### Enhanced Features
282
+
283
+ ```ruby
284
+ require 'cssminify2'
285
+
286
+ css = <<-CSS
287
+ .btn { color: red; }
288
+ .btn { background: blue; }
289
+ .container {
290
+ margin: 10px 10px 10px 10px;
291
+ padding: 0.0px 0rem 0vh;
292
+ }
293
+ CSS
294
+
295
+ # Use enhanced features
296
+ result = CSSminify2.compress_enhanced(css, {
297
+ merge_duplicate_selectors: true,
298
+ optimize_shorthand_properties: true,
299
+ advanced_color_optimization: true
300
+ })
301
+
302
+ puts result
303
+ # => ".btn{color:red;background:blue}.container{margin:10px;padding:0}"
304
+ ```
305
+
306
+ ### CSS Variables Optimization
307
+
308
+ ```ruby
309
+ css_with_vars = <<-CSS
310
+ :root {
311
+ --primary-color: #FF0000;
312
+ --unused-var: blue;
313
+ --single-use: 10px;
314
+ }
315
+
316
+ .component {
317
+ color: var(--primary-color);
318
+ margin: var(--single-use);
319
+ padding: var(--primary-color);
320
+ }
321
+ CSS
322
+
323
+ result = CSSminify2.compress_enhanced(css_with_vars, {
324
+ compress_css_variables: true,
325
+ advanced_color_optimization: true
326
+ })
327
+
328
+ puts result
329
+ # Variables optimized: unused removed, single-use inlined, colors optimized
330
+ ```
331
+
332
+ ### Error Handling
333
+
334
+ ```ruby
335
+ malformed_css = ".test { color: red .broken { }"
336
+
337
+ # Non-strict mode (default) - always succeeds with fallback
338
+ result = CSSminify2.compress_enhanced(malformed_css, {
339
+ strict_error_handling: false
340
+ })
341
+ puts "Result: #{result}" # Gets some result, possibly with warnings
342
+
343
+ # Strict mode - validates and throws errors
344
+ begin
345
+ result = CSSminify2.compress_enhanced(malformed_css, {
346
+ strict_error_handling: true
347
+ })
348
+ rescue CSSminify2Enhanced::MalformedCSSError => e
349
+ puts "Validation failed: #{e.message}"
350
+ puts "Errors: #{e.css_errors.join(', ')}"
351
+ end
352
+ ```
353
+
354
+ ### Configuration Presets
355
+
356
+ ```ruby
357
+ # Conservative (default) - no enhanced features
358
+ conservative_result = CSSminify2.compress_enhanced(css,
359
+ CSSminify2Enhanced::Configuration.conservative
360
+ )
361
+
362
+ # Aggressive - all optimizations enabled
363
+ aggressive_result = CSSminify2.compress_enhanced(css,
364
+ CSSminify2Enhanced::Configuration.aggressive
365
+ )
366
+
367
+ # Modern - aggressive plus additional features
368
+ modern_config = CSSminify2Enhanced::Configuration.modern
369
+ compressor = CSSminify2Enhanced::Compressor.new(modern_config)
370
+ modern_result = compressor.compress(css)
371
+ statistics = compressor.statistics
372
+ ```
373
+
374
+ ### Statistics and Monitoring
375
+
376
+ ```ruby
377
+ stats = CSSminify2.compress_with_stats(large_css_file, {
378
+ merge_duplicate_selectors: true,
379
+ optimize_shorthand_properties: true,
380
+ compress_css_variables: true
381
+ })
382
+
383
+ puts "=== Compression Report ==="
384
+ puts "Original size: #{stats[:statistics][:original_size]} chars"
385
+ puts "Compressed size: #{stats[:statistics][:compressed_size]} chars"
386
+ puts "Compression ratio: #{stats[:statistics][:compression_ratio].round(2)}%"
387
+ puts "Selectors merged: #{stats[:statistics][:selectors_merged]}"
388
+ puts "Properties optimized: #{stats[:statistics][:properties_optimized]}"
389
+ puts "Colors converted: #{stats[:statistics][:colors_converted]}"
390
+
391
+ if stats[:statistics][:fallback_used]
392
+ puts "⚠️ Fallback compression was used"
393
+ end
394
+
395
+ # Save the compressed CSS
396
+ File.write('compressed.css', stats[:compressed_css])
397
+ ```
398
+
399
+ ### Integration with Build Tools
400
+
401
+ ```ruby
402
+ # Rails Asset Pipeline
403
+ class EnhancedCSSCompressor
404
+ def initialize(options = {})
405
+ @config = CSSminify2Enhanced::Configuration.aggressive
406
+ @config.strict_error_handling = false # Graceful fallbacks in production
407
+ end
408
+
409
+ def compress(css)
410
+ CSSminify2Enhanced::Compressor.new(@config).compress(css)
411
+ rescue => e
412
+ Rails.logger.warn "Enhanced CSS compression failed: #{e.message}"
413
+ CSSminify2.compress(css) # Fallback to basic compression
414
+ end
415
+ end
416
+
417
+ # In config/application.rb
418
+ config.assets.css_compressor = EnhancedCSSCompressor.new
419
+ ```
420
+
421
+ ### Batch Processing
422
+
423
+ ```ruby
424
+ class BatchProcessor
425
+ def self.process_directory(input_dir, output_dir)
426
+ Dir.glob("#{input_dir}/**/*.css").each do |file|
427
+ css = File.read(file)
428
+
429
+ stats = CSSminify2.compress_with_stats(css, {
430
+ merge_duplicate_selectors: true,
431
+ optimize_shorthand_properties: true,
432
+ compress_css_variables: true
433
+ })
434
+
435
+ output_file = file.gsub(input_dir, output_dir).gsub('.css', '.min.css')
436
+ FileUtils.mkdir_p(File.dirname(output_file))
437
+ File.write(output_file, stats[:compressed_css])
438
+
439
+ puts "#{file}: #{stats[:statistics][:compression_ratio].round(1)}% compression"
440
+ end
441
+ end
442
+ end
443
+
444
+ BatchProcessor.process_directory('src/css', 'dist/css')
445
+ ```
446
+
447
+ ## Performance Considerations
448
+
449
+ ### Memory Usage
450
+ - Basic compression: Minimal memory overhead
451
+ - Enhanced features: ~2-3x memory usage during processing
452
+ - Large files (>1MB): Consider processing in chunks for memory efficiency
453
+
454
+ ### Processing Speed
455
+ - Basic compression: ~2ms per 100KB
456
+ - Enhanced compression: ~5-8ms per 100KB
457
+ - Batch processing: Use persistent Compressor instances to avoid configuration overhead
458
+
459
+ ### Best Practices
460
+ 1. Start with conservative settings and gradually enable features
461
+ 2. Use statistics to monitor compression effectiveness
462
+ 3. Enable strict error handling in development, disable in production
463
+ 4. Cache compressed results when possible
464
+ 5. Test compression results thoroughly in your target browsers