squoosh 0.2.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65d794e4fa97573f5ffe9fbc8339df1fcd8ef91908d743be565345a0e5a7b92f
4
- data.tar.gz: 857fb11296b5e4a3989a06d660e44a4c6536780f21d85092e2ab5b11f82bcceb
3
+ metadata.gz: 5629b74c30885ffe74552245300726730050c5b08be3a0ae3270d87d26940b3b
4
+ data.tar.gz: e10c8aa994b60e7ad192da3b0c0f5ef27346827c7e777f30a5b828d5c891a718
5
5
  SHA512:
6
- metadata.gz: 6487482bb47b8c43b7215ca3d901128fe39abc33044c7ac9cd0d8b2b9f09ac90f9b9ff1d7750bea6ea907b31c4044b0c05e19231871bb9306cb54b508de0dd34
7
- data.tar.gz: 3693641100489cc0128c5f0569eca44607ddac2c126b265b0a837653b6e847e04887034dea3a648049a3841e8d6e368f9d628e375b16eb33c22402328c42d0b2
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
+ [![Actions
2
+ Status](https://github.com/stevecheckoway/squoosh/workflows/CI%20Test/badge.svg)](https://github.com/stevecheckoway/squoosh/actions)
3
+ [![Coverage
4
+ Status](https://coveralls.io/repos/github/stevecheckoway/squoosh/badge.svg?branch=master)](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
- [![Travis-CI Build
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 Sass and Uglifier.
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/github/stevecheckoway/squoosh/v0.2.0).
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
- require 'squoosh'
74
-
75
- Jekyll::Hooks.register [:documents, :pages], :post_render, priority: :high do |doc|
76
- case File.extname(doc.destination('./'))
77
- when '.html', '.htm'
78
- doc.output = Squoosh::minify_html doc.output
79
- when '.js'
80
- doc.output = Squoosh::minify_js doc.output
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 'nokogumbo'
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 Sass.
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 = minify_js 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
- # Remove leading newline in pre and textarea tags unless there are two
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.attributes.each do |name, attr|
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]+)/, '&amp;\1')
333
348
  value = (attr.value || '').gsub('&', '&amp;')
334
349
  if value.empty?
335
- output << ' ' + name
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 node_is_self_closing? node
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 node_is_self_closing?(node)
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
- return false if node.children.empty?
404
- return false unless node.children[0].name == 'col'
499
+ child = first_child_content_node(node)
500
+ return false if child.nil? || !child.element? || child.name != 'col'
405
501
 
406
- prev_elm = node.previous_element
407
- return prev_elm.nil? ||
408
- prev_elm.name != 'col' ||
409
- !omit_end_tag?(prev_elm)
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
- return false if node.children.empty?
417
- return false unless node.children[0].name == 'tr'
512
+ child = first_child_content_node(node)
513
+ return false if child.nil? || !child.element? || child.name != 'tr'
418
514
 
419
- prev_elm = node.previous_element
420
- return prev_elm.nil? ||
421
- !%w[tbody thead tfoot].include?(prev_elm.name) ||
422
- !omit_end_tag?(prev_elm)
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 next_elm&.name == 'li' || !parent_contains_more_content?(node)
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].include? next_elm&.name
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].include?(next_elm&.name) ||
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 may be omitted if the p element is immediately
483
- # followed by an address, article, aside, blockquote, div, dl,
484
- # fieldset, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr,
485
- # main, nav, ol, p, pre, section, table, or ul, element, or if there
486
- # is no more content in the parent element and the parent element is
487
- # not an a element.
488
- return true if %w[address article aside blockquote div dl
489
- fieldset footer form h1 h2 h3 h4
490
- h5 h6 header hgroup hr main nav ol
491
- p pre section table ul].include? next_elm&.name
492
-
493
- return node.parent.name != 'a' && !parent_contains_more_content?(node)
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].include?(next_elm&.name) ||
508
- !parent_contains_more_content?(node)
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].include?(next_elm&.name) ||
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 next_elm&.name == 'optgroup' ||
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].include?(next_elm&.name) ||
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
- (next_node.text? && !next_node.content.start_with(' ')) ||
536
- !next_node.comment?
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].include? next_elm&.name
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].include?(next_elm&.name) ||
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 may be omitted if the tfoot element is
552
- # immediately followed by a tbody element, or if there is no more
553
- # content in the parent element.
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 next_elm&.name == 'tr' ||
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].include?(next_elm&.name) ||
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Squoosh
4
4
  # The version of squoosh.
5
- VERSION = '0.2.1'
5
+ VERSION = '0.4.0'
6
6
  end
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.2.1
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: 2019-03-28 00:00:00.000000000 Z
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: nokogumbo
112
+ name: nokogiri
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: '2.0'
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: '2.0'
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.0'
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.0'
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: '2.3'
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.0.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: []