squoosh 0.2.1 → 0.4.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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +33 -16
- data/lib/squoosh.rb +167 -83
- data/lib/squoosh/version.rb +1 -1
- metadata +31 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5629b74c30885ffe74552245300726730050c5b08be3a0ae3270d87d26940b3b
|
4
|
+
data.tar.gz: e10c8aa994b60e7ad192da3b0c0f5ef27346827c7e777f30a5b828d5c891a718
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64cd4ba5c5c8ab4de943685546a0aef694489c1f68ab809383b21f2a1bc650e68b0c20d5a4eeafaa144a44e9f35978c44868b1bd27c857fa41442a26cae48db2
|
7
|
+
data.tar.gz: d3d0e28e5b4201552f7db683c97b6b5b7195dae718abf020869b180b23c6eab04b07ed5bc501310b88d8a4ba481247b78149ee45b31eb93e045cce215713b2dc
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2016, 2018 Stephen Checkoway
|
3
|
+
Copyright (c) 2016, 2018, 2019 Stephen Checkoway
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
[](https://github.com/stevecheckoway/squoosh/actions)
|
3
|
+
[](https://coveralls.io/github/stevecheckoway/squoosh?branch=master)
|
5
|
+
|
1
6
|
# Squoosh
|
2
7
|
|
3
8
|
Minifies HTML, JavaScript, and CSS, including inline JavaScript and CSS.
|
4
9
|
|
5
|
-
[
|
6
|
-
Status](https://travis-ci.org/stevecheckoway/squoosh.svg)](https://travis-ci.org/stevecheckoway/squoosh)
|
7
|
-
|
8
|
-
CSS minification is handled by [Sass](http://www.rubydoc.info/gems/sass)
|
10
|
+
CSS minification is handled by [Sassc](http://www.rubydoc.info/gems/sassc)
|
9
11
|
whereas JavaScript minification is handled by
|
10
12
|
[Uglifier](http://www.rubydoc.info/gems/uglifier) which requires node.js.
|
11
13
|
|
@@ -17,7 +19,7 @@ nodes](https://html.spec.whatwg.org/multipage/dom.html#inter-element-whitespace)
|
|
17
19
|
are removed from the DOM and semantically meaningfull runs of whitespace are
|
18
20
|
compressed to single spaces, except in `pre`, `textarea`, and
|
19
21
|
[foreign](https://html.spec.whatwg.org/multipage/syntax.html#elements-2) elements.
|
20
|
-
Then, inline JavaScript and CSS are compressed using
|
22
|
+
Then, inline JavaScript and CSS are compressed using Sassc and Uglifier.
|
21
23
|
Finally, the DOM is serialized, compressing
|
22
24
|
[attributes](https://html.spec.whatwg.org/multipage/syntax.html#attributes-2)
|
23
25
|
where possible and omitting [optional start and end
|
@@ -32,8 +34,17 @@ Squoosh will not minify
|
|
32
34
|
|
33
35
|
- HTML 4 and earlier;
|
34
36
|
- XHTML, any version;
|
35
|
-
- [MathML](https://www.w3.org/TR/MathML3/) elements; nor
|
36
|
-
- [SVG](https://www.w3.org/TR/SVG11/) elements.
|
37
|
+
- spaces in [MathML](https://www.w3.org/TR/MathML3/) elements; nor
|
38
|
+
- spaces in [SVG](https://www.w3.org/TR/SVG11/) elements.
|
39
|
+
|
40
|
+
HTML 4 and XHTML documents (more precisely, any document that does not have an
|
41
|
+
HTML 5 DOCTYPE, typically `<!DOCTYPE html>`) is returned unchanged by
|
42
|
+
`Squoosh::minify_html`.
|
43
|
+
|
44
|
+
MathML and SVG elements have their tags minified (including compressing
|
45
|
+
attributes and serializing empty elements as self-closing start tags) and
|
46
|
+
comments inside them are removed. White space is preserved (except for the
|
47
|
+
newline normalization performed by the HTML 5 parser).
|
37
48
|
|
38
49
|
## Installation
|
39
50
|
|
@@ -54,7 +65,7 @@ Or install it yourself as:
|
|
54
65
|
## Usage
|
55
66
|
|
56
67
|
You can read the documentation
|
57
|
-
[here](https://www.rubydoc.info/
|
68
|
+
[here](https://www.rubydoc.info/gems/squoosh/).
|
58
69
|
|
59
70
|
The three basic minification functions are
|
60
71
|
|
@@ -70,14 +81,20 @@ significantly speed up minifying HTML with repeated scripts and style sheets.
|
|
70
81
|
Create a `_plugins/squoosh.rb` file with the contents
|
71
82
|
|
72
83
|
```ruby
|
73
|
-
|
74
|
-
|
75
|
-
Jekyll
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
84
|
+
# frozen_string_literal: true
|
85
|
+
|
86
|
+
if Jekyll.env == 'deploy'
|
87
|
+
require 'squoosh'
|
88
|
+
|
89
|
+
squoosher = Squoosh::Squoosher.new
|
90
|
+
Jekyll::Hooks.register(%i[documents pages],
|
91
|
+
:post_render, priority: :high) do |doc|
|
92
|
+
case File.extname(doc.destination('./'))
|
93
|
+
when '.html', '.htm'
|
94
|
+
doc.output = squoosher.minify_html(doc.output)
|
95
|
+
when '.js'
|
96
|
+
doc.output = squoosher.minify_js(doc.output)
|
97
|
+
end
|
81
98
|
end
|
82
99
|
end
|
83
100
|
```
|
data/lib/squoosh.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'squoosh/version'
|
4
|
-
require '
|
4
|
+
require 'nokogiri'
|
5
5
|
require 'sassc'
|
6
6
|
require 'set'
|
7
7
|
require 'uglifier'
|
@@ -74,6 +74,7 @@ module Squoosh
|
|
74
74
|
end
|
75
75
|
@options = DEFAULT_OPTIONS.merge(options)
|
76
76
|
@js_cache = {}
|
77
|
+
@inline_script_cache = {}
|
77
78
|
@css_cache = {}
|
78
79
|
end
|
79
80
|
|
@@ -95,7 +96,7 @@ module Squoosh
|
|
95
96
|
doc.children.map { |node| stringify_node(node) }.join
|
96
97
|
end
|
97
98
|
|
98
|
-
# Minify CSS using
|
99
|
+
# Minify CSS using Sassc.
|
99
100
|
#
|
100
101
|
# @param content [String] the CSS to minify
|
101
102
|
# @return [String] the minified CSS
|
@@ -111,8 +112,7 @@ module Squoosh
|
|
111
112
|
# @param content [String] the JavaScript to minify
|
112
113
|
# @return [String] the minified JavaScript
|
113
114
|
def minify_js(content)
|
114
|
-
@js_cache[content] ||=
|
115
|
-
Uglifier.compile(content, @options[:uglifier_options])
|
115
|
+
@js_cache[content] ||= uglify(content, @options[:uglifier_options])
|
116
116
|
end
|
117
117
|
|
118
118
|
# Element kinds
|
@@ -124,6 +124,13 @@ module Squoosh
|
|
124
124
|
private_constant :VOID_ELEMENTS, :RAW_TEXT_ELEMENTS
|
125
125
|
private_constant :ESCAPABLE_RAW_TEXT_ELEMENTS, :FOREIGN_ELEMENTS
|
126
126
|
|
127
|
+
INLINE_SCRIPT_OPTIONS = {
|
128
|
+
output: {
|
129
|
+
inline_script: true
|
130
|
+
}
|
131
|
+
}.freeze
|
132
|
+
private_constant :INLINE_SCRIPT_OPTIONS
|
133
|
+
|
127
134
|
private
|
128
135
|
|
129
136
|
def void_element?(node)
|
@@ -197,6 +204,7 @@ module Squoosh
|
|
197
204
|
false
|
198
205
|
end
|
199
206
|
|
207
|
+
# rubocop:disable Style/StringConcatenation
|
200
208
|
EVENT_HANDLERS_XPATH = (
|
201
209
|
# Select all attribute nodes whose names start with "on";
|
202
210
|
'//@*[starts-with(name(),"on")]' +
|
@@ -224,17 +232,31 @@ module Squoosh
|
|
224
232
|
rejectionhandled storage unhandledrejection
|
225
233
|
unload].map { |n| "name()=\"on#{n}\"" }.join(' or ') +
|
226
234
|
')' \
|
227
|
-
|
235
|
+
']'
|
228
236
|
).freeze
|
237
|
+
# rubocop:enable Style/StringConcatenation
|
229
238
|
private_constant :EVENT_HANDLERS_XPATH
|
230
239
|
|
240
|
+
def uglify(content, options)
|
241
|
+
js = Uglifier.compile(content, options)
|
242
|
+
js.chomp!(';')
|
243
|
+
js
|
244
|
+
end
|
245
|
+
|
246
|
+
def compress_script(content)
|
247
|
+
@inline_script_cache[content] ||= begin
|
248
|
+
options = @options[:uglifier_options].merge(INLINE_SCRIPT_OPTIONS)
|
249
|
+
uglify(content, options)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
231
253
|
def compress_javascript(doc)
|
232
254
|
# Compress script elements.
|
233
255
|
doc.xpath('//script[not(ancestor::math or ancestor::svg)]').each do |node|
|
234
256
|
type = node['type']&.downcase
|
235
257
|
next unless type.nil? || type == 'text/javascript'
|
236
258
|
|
237
|
-
node.content =
|
259
|
+
node.content = compress_script(node.content)
|
238
260
|
end
|
239
261
|
# Compress event handlers.
|
240
262
|
doc.xpath(EVENT_HANDLERS_XPATH).each do |attr|
|
@@ -272,15 +294,7 @@ module Squoosh
|
|
272
294
|
end
|
273
295
|
elsif node.element? &&
|
274
296
|
(node.name == 'pre' || node.name == 'textarea')
|
275
|
-
#
|
276
|
-
# in a row.
|
277
|
-
if node.children[0]&.text?
|
278
|
-
content = node.children[0].content
|
279
|
-
if content.sub!(/\A\r\n?([^\r]|\z)/, '\1') ||
|
280
|
-
content.sub!(/\A\n([^\n]|\z)/, '\1')
|
281
|
-
node.children[0].content = content
|
282
|
-
end
|
283
|
-
end
|
297
|
+
# Leave the contents of these nodes alone.
|
284
298
|
elsif normal_element?(node) || node.name == 'title'
|
285
299
|
# Compress spaces in normal elements and title.
|
286
300
|
node.children.each { |c| compress_spaces c }
|
@@ -323,7 +337,8 @@ module Squoosh
|
|
323
337
|
|
324
338
|
# Add attributes. 8.1.2.3
|
325
339
|
last_attr_unquoted = false
|
326
|
-
node.
|
340
|
+
node.attribute_nodes.each do |attr|
|
341
|
+
name = qualified_attribute_name(attr)
|
327
342
|
last_attr_unquoted = false
|
328
343
|
# Make sure there are no character references.
|
329
344
|
# XXX: We should be able to compress a bit more by leaving bare & in
|
@@ -332,7 +347,7 @@ module Squoosh
|
|
332
347
|
# value.gsub!(/&([a-zA-Z0-9]+;|#[0-9]+|#[xX][a-fA-F0-9]+)/, '&\1')
|
333
348
|
value = (attr.value || '').gsub('&', '&')
|
334
349
|
if value.empty?
|
335
|
-
output <<
|
350
|
+
output << " #{name}"
|
336
351
|
elsif /[\t\n\f\r "'`=<>]/ !~ value
|
337
352
|
last_attr_unquoted = true
|
338
353
|
output << " #{name}=#{value}"
|
@@ -347,13 +362,23 @@ module Squoosh
|
|
347
362
|
end
|
348
363
|
|
349
364
|
# Close start tag.
|
350
|
-
if
|
365
|
+
if self_closing? node
|
351
366
|
output << ' ' if last_attr_unquoted
|
352
367
|
output << '/'
|
353
368
|
end
|
354
369
|
output << '>'
|
355
370
|
end
|
356
371
|
|
372
|
+
# If pre or textarea start with a newline, double it because the HTML
|
373
|
+
# parser strips leading newlines.
|
374
|
+
if (node.name == 'pre' || node.name == 'textarea') &&
|
375
|
+
!node.children.empty?
|
376
|
+
first_child = node.children[0]
|
377
|
+
if first_child.text? && first_child.content.start_with?("\n")
|
378
|
+
output << "\n"
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
357
382
|
# Add content.
|
358
383
|
output << node.children.map { |c| stringify_node c }.join
|
359
384
|
|
@@ -362,10 +387,81 @@ module Squoosh
|
|
362
387
|
output.string
|
363
388
|
end
|
364
389
|
|
365
|
-
def
|
390
|
+
def qualified_attribute_name(attr)
|
391
|
+
ns = attr.namespace
|
392
|
+
return attr.name if ns.nil?
|
393
|
+
|
394
|
+
uri = ns.href
|
395
|
+
if uri == Nokogiri::HTML5::XML_NAMESPACE
|
396
|
+
"xml:#{attr.name}"
|
397
|
+
elsif uri == Nokogiri::HTML5::XMLNS_NAMESPACE && attr.name == 'xmlns'
|
398
|
+
'xmlns'
|
399
|
+
elsif uri == Nokogiri::HTML5::XMLNS_NAMESPACE
|
400
|
+
"xmlns:#{attr.name}"
|
401
|
+
elsif uri == Nokogiri::HTML5::XLINK_NAMESPACE
|
402
|
+
"xlink:#{attr.name}"
|
403
|
+
else
|
404
|
+
# :nocov:
|
405
|
+
raise 'Unreachable!'
|
406
|
+
# :nocov:
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
def self_closing?(node)
|
411
|
+
# If we're not omitting end tags, then don't mark foreign elements as
|
412
|
+
# self closing.
|
413
|
+
return false unless @options[:omit_tags]
|
414
|
+
|
366
415
|
foreign_element?(node) && node.children.empty?
|
367
416
|
end
|
368
417
|
|
418
|
+
def content_node?(node)
|
419
|
+
# Inter-element whitespace, comment nodes, and processing instruction
|
420
|
+
# nodes must be ignored when establishing whether an element's contents
|
421
|
+
# match the element's content model or not, and must be ignored when
|
422
|
+
# following algorithms that define document and element semantics.
|
423
|
+
!(node.comment? ||
|
424
|
+
node.processing_instruction? ||
|
425
|
+
inter_element_whitespace?(node))
|
426
|
+
end
|
427
|
+
|
428
|
+
def previous_sibling_content_node(node)
|
429
|
+
while (node = node.previous_sibling)
|
430
|
+
return node if content_node?(node)
|
431
|
+
end
|
432
|
+
nil
|
433
|
+
end
|
434
|
+
|
435
|
+
def next_sibling_content_node(node)
|
436
|
+
while (node = node.next_sibling)
|
437
|
+
return node if content_node?(node)
|
438
|
+
end
|
439
|
+
nil
|
440
|
+
end
|
441
|
+
|
442
|
+
def first_child_content_node(node)
|
443
|
+
return nil if node.children.empty?
|
444
|
+
|
445
|
+
node = node.children[0]
|
446
|
+
return node if content_node?(node)
|
447
|
+
|
448
|
+
next_sibling_content_node(node)
|
449
|
+
end
|
450
|
+
|
451
|
+
def next_sibling_is_nil_or_one_of?(node, elements)
|
452
|
+
node = next_sibling_content_node(node)
|
453
|
+
node.nil? || (node.element? && elements.include?(node.name))
|
454
|
+
end
|
455
|
+
|
456
|
+
def next_sibling_is_one_of?(node, elements)
|
457
|
+
node = next_sibling_content_node(node)
|
458
|
+
node&.element? && elements.include?(node.name)
|
459
|
+
end
|
460
|
+
|
461
|
+
def parent_contains_more_content?(node)
|
462
|
+
!next_sibling_content_node(node).nil?
|
463
|
+
end
|
464
|
+
|
369
465
|
def omit_start_tag?(node)
|
370
466
|
return false unless @options[:omit_tags]
|
371
467
|
return false unless node.attributes.empty?
|
@@ -400,48 +496,36 @@ module Squoosh
|
|
400
496
|
# inside the colgroup element is a col element, and if the element is
|
401
497
|
# not immediately preceded by another colgroup element whose end tag
|
402
498
|
# has been omitted. (It can't be omitted if the element is empty.)
|
403
|
-
|
404
|
-
return false
|
499
|
+
child = first_child_content_node(node)
|
500
|
+
return false if child.nil? || !child.element? || child.name != 'col'
|
405
501
|
|
406
|
-
|
407
|
-
return
|
408
|
-
|
409
|
-
|
502
|
+
prev_node = previous_sibling_content_node(node)
|
503
|
+
return !(prev_node&.element? &&
|
504
|
+
prev_node.name == 'colgroup' &&
|
505
|
+
omit_end_tag?(prev_node))
|
410
506
|
|
411
507
|
when 'tbody'
|
412
508
|
# A tbody element's start tag may be omitted if the first thing inside
|
413
509
|
# the tbody element is a tr element, and if the element is not
|
414
510
|
# immediately preceded by a tbody, thead, or tfoot element whose end
|
415
511
|
# tag has been omitted. (It can't be omitted if the element is empty.)
|
416
|
-
|
417
|
-
return false
|
512
|
+
child = first_child_content_node(node)
|
513
|
+
return false if child.nil? || !child.element? || child.name != 'tr'
|
418
514
|
|
419
|
-
|
420
|
-
return
|
421
|
-
|
422
|
-
|
423
|
-
end
|
424
|
-
false
|
425
|
-
end
|
426
|
-
|
427
|
-
def parent_contains_more_content?(node)
|
428
|
-
while (node = node.next_sibling)
|
429
|
-
next if node.comment?
|
430
|
-
next if node.processing_instruction?
|
431
|
-
next if inter_element_whitespace? node
|
432
|
-
|
433
|
-
return true
|
515
|
+
prev_node = previous_sibling_content_node(node)
|
516
|
+
return !(prev_node&.element? &&
|
517
|
+
%w[tbody thead tfoot].include?(prev_node.name) &&
|
518
|
+
omit_end_tag?(prev_node))
|
434
519
|
end
|
435
520
|
false
|
436
521
|
end
|
437
522
|
|
438
523
|
def omit_end_tag?(node)
|
439
|
-
return true if void_element? node
|
524
|
+
return true if void_element?(node) || self_closing?(node)
|
440
525
|
return false unless @options[:omit_tags]
|
441
526
|
return false if node.parent.name == 'noscript'
|
442
527
|
|
443
528
|
next_node = node.next_sibling
|
444
|
-
next_elm = node.next_element
|
445
529
|
case node.name
|
446
530
|
when 'html'
|
447
531
|
# An html element's end tag may be omitted if the html element is not
|
@@ -464,33 +548,40 @@ module Squoosh
|
|
464
548
|
# An li element's end tag may be omitted if the li element is
|
465
549
|
# immediately followed by another li element or if there is no more
|
466
550
|
# content in the parent element.
|
467
|
-
return
|
551
|
+
return next_sibling_is_nil_or_one_of?(node, ['li'])
|
468
552
|
|
469
553
|
when 'dt'
|
470
554
|
# A dt element's end tag may be omitted if the dt element is immediately
|
471
555
|
# followed by another dt element or a dd element.
|
472
|
-
return %w[dt dd]
|
556
|
+
return next_sibling_is_one_of?(node, %w[dt dd])
|
473
557
|
|
474
558
|
when 'dd'
|
475
559
|
# A dd element's end tag may be omitted if the dd element is immediately
|
476
560
|
# followed by another dd element or a dt element, or if there is no more
|
477
561
|
# content in the parent element.
|
478
|
-
return %w[dt dd]
|
479
|
-
!parent_contains_more_content?(node)
|
562
|
+
return next_sibling_is_nil_or_one_of?(node, %w[dt dd])
|
480
563
|
|
481
564
|
when 'p'
|
482
|
-
# A p element's end tag
|
483
|
-
# followed by an address, article, aside, blockquote,
|
484
|
-
# fieldset, footer, form, h1, h2, h3, h4, h5,
|
485
|
-
# main, nav, ol, p, pre, section, table,
|
486
|
-
# is no more content in the parent element
|
487
|
-
# not an a
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
565
|
+
# A p element's end tag can be omitted if the p element is immediately
|
566
|
+
# followed by an address, article, aside, blockquote, details, div,
|
567
|
+
# dl, fieldset, figcaption, figure, footer, form, h1, h2, h3, h4, h5,
|
568
|
+
# h6, header, hgroup, hr, main, menu, nav, ol, p, pre, section, table,
|
569
|
+
# or ul element, or if there is no more content in the parent element
|
570
|
+
# and the parent element is an HTML element that is not an a, audio,
|
571
|
+
# del, ins, map, noscript, or video element, or an autonomous custom
|
572
|
+
# element.
|
573
|
+
return true if next_sibling_is_one_of?(
|
574
|
+
node,
|
575
|
+
%w[
|
576
|
+
address article aside blockquote details div dl fieldset figcaption
|
577
|
+
figure footer form h1 h2 h3 h4 h5 h6 header hgroup hr main menu nav
|
578
|
+
ol p pre section table ul
|
579
|
+
]
|
580
|
+
)
|
581
|
+
return false if foreign_element?(node.parent)
|
582
|
+
|
583
|
+
return !parent_contains_more_content?(node) &&
|
584
|
+
!%(a audio del ins map noscript video).include?(node.parent.name)
|
494
585
|
|
495
586
|
when 'rb', 'rt', 'rp'
|
496
587
|
# An rb element's end tag may be omitted if the rb element is
|
@@ -504,62 +595,56 @@ module Squoosh
|
|
504
595
|
# An rp element's end tag may be omitted if the rp element is
|
505
596
|
# immediately followed by an rb, rt, rtc or rp element, or if there is
|
506
597
|
# no more content in the parent element.
|
507
|
-
return %w[rb rt rtc rp]
|
508
|
-
|
598
|
+
return next_sibling_is_nil_or_one_of?(node, %w[rb rt rtc rp])
|
599
|
+
|
509
600
|
when 'rtc'
|
510
601
|
# An rtc element's end tag may be omitted if the rtc element is
|
511
602
|
# immediately followed by an rb, rtc or rp element, or if there is no
|
512
603
|
# more content in the parent element.
|
513
|
-
return %w[rb rtc rp]
|
514
|
-
!parent_contains_more_content?(node)
|
604
|
+
return next_sibling_is_nil_or_one_of?(node, %w[rb rtc rp])
|
515
605
|
|
516
606
|
when 'optgroup'
|
517
607
|
# An optgroup element's end tag may be omitted if the optgroup element
|
518
608
|
# is immediately followed by another optgroup element, or if there is
|
519
609
|
# no more content in the parent element.
|
520
|
-
return
|
521
|
-
!parent_contains_more_content?(node)
|
610
|
+
return next_sibling_is_nil_or_one_of?(node, ['optgroup'])
|
522
611
|
|
523
612
|
when 'option'
|
524
613
|
# An option element's end tag may be omitted if the option element is
|
525
614
|
# immediately followed by another option element, or if it is
|
526
615
|
# immediately followed by an optgroup element, or if there is no more
|
527
616
|
# content in the parent element.
|
528
|
-
return %w[option optgroup]
|
529
|
-
!parent_contains_more_content?(node)
|
617
|
+
return next_sibling_is_nil_or_one_of?(node, %w[option optgroup])
|
530
618
|
|
531
619
|
when 'colgroup'
|
532
620
|
# A colgroup element's end tag may be omitted if the colgroup element is
|
533
621
|
# not immediately followed by a space character or a comment.
|
534
|
-
return next_node.nil?
|
535
|
-
|
536
|
-
|
622
|
+
return true if next_node.nil?
|
623
|
+
return !next_node.content.start_with?(' ') if next_node.text?
|
624
|
+
|
625
|
+
return !next_node.comment?
|
537
626
|
|
538
627
|
when 'thead'
|
539
628
|
# A thead element's end tag may be omitted if the thead element is
|
540
629
|
# immediately followed by a tbody or tfoot element.
|
541
|
-
return %w[tbody tfoot]
|
630
|
+
return next_sibling_is_one_of?(node, %w[tbody tfoot])
|
542
631
|
|
543
632
|
when 'tbody'
|
544
633
|
# A tbody element's end tag may be omitted if the tbody element is
|
545
634
|
# immediately followed by a tbody or tfoot element, or if there is no
|
546
635
|
# more content in the parent element.
|
547
|
-
return %w[tbody tfoot]
|
548
|
-
!parent_contains_more_content?(node)
|
636
|
+
return next_sibling_is_nil_or_one_of?(node, %w[tbody tfoot])
|
549
637
|
|
550
638
|
when 'tfoot'
|
551
|
-
# A tfoot element's end tag
|
552
|
-
#
|
553
|
-
|
554
|
-
return next_elm&.name == 'tbody' ||
|
555
|
-
!parent_contains_more_content?(node)
|
639
|
+
# A tfoot element's end tag can be omitted if there is no more content
|
640
|
+
# in the parent element.
|
641
|
+
return !parent_contains_more_content?(node)
|
556
642
|
|
557
643
|
when 'tr'
|
558
644
|
# A tr element's end tag may be omitted if the tr element is immediately
|
559
645
|
# followed by another tr element, or if there is no more content in the
|
560
646
|
# parent element.
|
561
|
-
return
|
562
|
-
!parent_contains_more_content?(node)
|
647
|
+
return next_sibling_is_nil_or_one_of?(node, ['tr'])
|
563
648
|
|
564
649
|
when 'td', 'th'
|
565
650
|
# A td element's end tag may be omitted if the td element is immediately
|
@@ -569,8 +654,7 @@ module Squoosh
|
|
569
654
|
# A th element's end tag may be omitted if the th element is immediately
|
570
655
|
# followed by a td or th element, or if there is no more content in the
|
571
656
|
# parent element.
|
572
|
-
return %w[td th]
|
573
|
-
!parent_contains_more_content?(node)
|
657
|
+
return next_sibling_is_nil_or_one_of?(node, %w[td th])
|
574
658
|
end
|
575
659
|
false
|
576
660
|
end
|
data/lib/squoosh/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: squoosh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Checkoway
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov-lcov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: yard
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,33 +109,33 @@ dependencies:
|
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
112
|
+
name: nokogiri
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
117
|
+
version: '1.12'
|
104
118
|
type: :runtime
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
124
|
+
version: '1.12'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: sassc
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
114
128
|
requirements:
|
115
129
|
- - "~>"
|
116
130
|
- !ruby/object:Gem::Version
|
117
|
-
version: '2.
|
131
|
+
version: '2.1'
|
118
132
|
type: :runtime
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
135
|
requirements:
|
122
136
|
- - "~>"
|
123
137
|
- !ruby/object:Gem::Version
|
124
|
-
version: '2.
|
138
|
+
version: '2.1'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: uglifier
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,7 +150,7 @@ dependencies:
|
|
136
150
|
- - "~>"
|
137
151
|
- !ruby/object:Gem::Version
|
138
152
|
version: '4.1'
|
139
|
-
description:
|
153
|
+
description:
|
140
154
|
email:
|
141
155
|
- s@pahtak.org
|
142
156
|
executables: []
|
@@ -155,23 +169,26 @@ metadata:
|
|
155
169
|
changelog_uri: https://github.com/stevecheckoway/squoosh/blob/master/CHANGELOG.md
|
156
170
|
homepage_uri: https://github.com/stevecheckoway/squoosh
|
157
171
|
source_code_uri: https://github.com/stevecheckoway/squoosh
|
158
|
-
post_install_message:
|
172
|
+
post_install_message:
|
159
173
|
rdoc_options: []
|
160
174
|
require_paths:
|
161
175
|
- lib
|
162
176
|
required_ruby_version: !ruby/object:Gem::Requirement
|
163
177
|
requirements:
|
164
|
-
- - "
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '2.6'
|
181
|
+
- - "<"
|
165
182
|
- !ruby/object:Gem::Version
|
166
|
-
version: '
|
183
|
+
version: '4.0'
|
167
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
185
|
requirements:
|
169
186
|
- - ">="
|
170
187
|
- !ruby/object:Gem::Version
|
171
188
|
version: '0'
|
172
189
|
requirements: []
|
173
|
-
rubygems_version: 3.
|
174
|
-
signing_key:
|
190
|
+
rubygems_version: 3.1.6
|
191
|
+
signing_key:
|
175
192
|
specification_version: 4
|
176
193
|
summary: Minify HTML/CSS/JavaScript files.
|
177
194
|
test_files: []
|