css_parser 1.9.0 → 1.16.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecd734b97658689e087ca19039ea51377c23d9e1c4be6099b084006150255fce
4
- data.tar.gz: d5a326fac6e3b57fe75fa3bc664ae8511a0e0dcf34f80dd5736ee8cc9709f5ee
3
+ metadata.gz: 36f35091b57e726d3e9b528b6f3357232343c075af962f61a402f2bb111aadd1
4
+ data.tar.gz: ee8dbf61a3a6f396e8d383f0334cfee91ad483b192bfbffb4e5c5d9294f89859
5
5
  SHA512:
6
- metadata.gz: ca0d59324036c9071c5f957235f10022d3db4841d4e4782e147f30e2cde1a1cd46873ede55db01b260676fc7289c0e7c4ad7e0e6ac7dbd0b38a1de8aa13333a1
7
- data.tar.gz: da5fb20229ecfac93b0436a0ed6954c109908429628cd635751c58fd9b3d029227da06a60bb80f5f4bd2fac55851ac258e7ff59d09fea59e93157f38d21c0fac
6
+ metadata.gz: ba19471cdbeed2daf719a2e1b238bff145bd748abbc760b64cd5ba40ba3e0ed03de8f6550b44b114bcbdbd577cd415b8f5c609def6c53a25699d3ca71f6e06d7
7
+ data.tar.gz: 72d71760da086f403c0d404c97d6bd6476e330376b56ce91b8ebfc51cdd27fc89932a066397b38799c15fb9f9a8a8b625d30728656dc0e8cfc24ec61a168e8e7
@@ -39,6 +39,7 @@ module CssParser
39
39
  @options = {absolute_paths: false,
40
40
  import: true,
41
41
  io_exceptions: true,
42
+ rule_set_exceptions: true,
42
43
  capture_offsets: false}.merge(options)
43
44
 
44
45
  # array of RuleSets
@@ -167,6 +168,8 @@ module CssParser
167
168
  def add_rule!(selectors, declarations, media_types = :all)
168
169
  rule_set = RuleSet.new(selectors, declarations)
169
170
  add_rule_set!(rule_set, media_types)
171
+ rescue ArgumentError => e
172
+ raise e if @options[:rule_set_exceptions]
170
173
  end
171
174
 
172
175
  # Add a CSS rule by setting the +selectors+, +declarations+, +filename+, +offset+ and +media_types+.
@@ -326,7 +329,7 @@ module CssParser
326
329
  rule_start = nil
327
330
  offset = nil
328
331
 
329
- block.scan(/\s+|\\{2,}|\\?[{}\s"]|.[^\s"{}\\]*/) do |token|
332
+ block.scan(/\s+|\\{2,}|\\?[{}\s"]|[()]|.[^\s"{}()\\]*/) do |token|
330
333
  # save the regex offset so that we know where in the file we are
331
334
  offset = Regexp.last_match.offset(0) if options[:capture_offsets]
332
335
 
@@ -388,7 +391,16 @@ module CssParser
388
391
  current_media_query = String.new
389
392
  else
390
393
  token.strip!
391
- current_media_query << token << ' '
394
+ # special-case the ( and ) tokens to remove inner-whitespace
395
+ # (eg we'd prefer '(width: 500px)' to '( width: 500px )' )
396
+ case token
397
+ when '('
398
+ current_media_query << token
399
+ when ')'
400
+ current_media_query.sub!(/ ?$/, token)
401
+ else
402
+ current_media_query << token << ' '
403
+ end
392
404
  end
393
405
  elsif in_charset or token =~ /@charset/i
394
406
  # iterate until we are out of the charset declaration
@@ -8,10 +8,10 @@ module CssParser
8
8
  # :stopdoc:
9
9
  # Base types
10
10
  RE_NL = Regexp.new('(\n|\r\n|\r|\f)')
11
- RE_NON_ASCII = Regexp.new('([\x00-\xFF])', Regexp::IGNORECASE, 'n') # [^\0-\177]
12
- RE_UNICODE = Regexp.new('(\\\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])*)', Regexp::IGNORECASE | Regexp::EXTENDED | Regexp::MULTILINE, 'n')
11
+ RE_NON_ASCII = Regexp.new('([\x00-\xFF])', Regexp::IGNORECASE | Regexp::NOENCODING) # [^\0-\177]
12
+ RE_UNICODE = Regexp.new('(\\\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])*)', Regexp::IGNORECASE | Regexp::EXTENDED | Regexp::MULTILINE | Regexp::NOENCODING)
13
13
  RE_ESCAPE = Regexp.union(RE_UNICODE, '|(\\\\[^\n\r\f0-9a-f])')
14
- RE_IDENT = Regexp.new("[\-]?([_a-z]|#{RE_NON_ASCII}|#{RE_ESCAPE})([_a-z0-9\-]|#{RE_NON_ASCII}|#{RE_ESCAPE})*", Regexp::IGNORECASE, 'n')
14
+ RE_IDENT = Regexp.new("[\-]?([_a-z]|#{RE_NON_ASCII}|#{RE_ESCAPE})([_a-z0-9\-]|#{RE_NON_ASCII}|#{RE_ESCAPE})*", Regexp::IGNORECASE | Regexp::NOENCODING)
15
15
 
16
16
  # General strings
17
17
  RE_STRING1 = /("(.[^\n\r\f"]*|\\#{RE_NL}|#{RE_ESCAPE})*")/.freeze
@@ -52,12 +52,30 @@ module CssParser
52
52
  # Special units
53
53
  BOX_MODEL_UNITS_RX = /(auto|inherit|0|(-*([0-9]+|[0-9]*\.[0-9]+)(rem|vw|vh|vm|vmin|vmax|e[mx]+|px|[cm]+m|p[tc+]|in|%)))([\s;]|\Z)/imx.freeze
54
54
  RE_LENGTH_OR_PERCENTAGE = Regexp.new('([\-]*(([0-9]*\.[0-9]+)|[0-9]+)(e[mx]+|px|[cm]+m|p[tc+]|in|\%))', Regexp::IGNORECASE)
55
- RE_BACKGROUND_POSITION = Regexp.new("((((#{RE_LENGTH_OR_PERCENTAGE})|left|center|right|top|bottom)[\s]*){1,2})", Regexp::IGNORECASE | Regexp::EXTENDED)
56
- RE_BACKGROUND_SIZE = Regexp.new("\\s*/\\s*((((#{RE_LENGTH_OR_PERCENTAGE})|auto|cover|contain|initial|inherit)[\\s]*){1,2})", Regexp::IGNORECASE | Regexp::EXTENDED)
55
+ RE_SINGLE_BACKGROUND_POSITION = /#{RE_LENGTH_OR_PERCENTAGE}|left|center|right|top|bottom/i.freeze
56
+ RE_SINGLE_BACKGROUND_SIZE = /#{RE_LENGTH_OR_PERCENTAGE}|auto|cover|contain|initial|inherit/i.freeze
57
+ RE_BACKGROUND_POSITION = /#{RE_SINGLE_BACKGROUND_POSITION}\s+#{RE_SINGLE_BACKGROUND_POSITION}|#{RE_SINGLE_BACKGROUND_POSITION}/.freeze
58
+ RE_BACKGROUND_SIZE = %r{\s*/\s*(#{RE_SINGLE_BACKGROUND_SIZE}\s+#{RE_SINGLE_BACKGROUND_SIZE}|#{RE_SINGLE_BACKGROUND_SIZE})}.freeze
57
59
  FONT_UNITS_RX = /((x+-)*small|medium|larger*|auto|inherit|([0-9]+|[0-9]*\.[0-9]+)(e[mx]+|px|[cm]+m|p[tc+]|in|%)*)/i.freeze
58
60
  RE_BORDER_STYLE = /(\s*^)?(none|hidden|dotted|dashed|solid|double|dot-dash|dot-dot-dash|wave|groove|ridge|inset|outset)(\s*$)?/imx.freeze
59
61
  RE_BORDER_UNITS = Regexp.union(BOX_MODEL_UNITS_RX, /(thin|medium|thick)/i)
60
62
 
63
+ # Functions like calc, var, clamp, etc.
64
+ RE_FUNCTIONS = /
65
+ (
66
+ [a-z0-9-]+ # function name
67
+ )
68
+ (?>
69
+ \( # opening parenthesis
70
+ (?:
71
+ ([^()]+)
72
+ | # recursion via subexpression
73
+ \g<0>
74
+ )*
75
+ \) # closing parenthesis
76
+ )
77
+ /imx.freeze
78
+
61
79
  # Patterns for specificity calculations
62
80
  NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX_NC = /
63
81
  (?:\.\w+) # classes
@@ -24,6 +24,8 @@ module CssParser
24
24
  ['border-width', %w[border-top-width border-right-width border-bottom-width border-left-width]]
25
25
  ].freeze
26
26
 
27
+ WHITESPACE_REPLACEMENT = '___SPACE___'
28
+
27
29
  class Declarations
28
30
  class Value
29
31
  attr_reader :value
@@ -91,6 +93,8 @@ module CssParser
91
93
  else
92
94
  declarations[property] = Value.new(value)
93
95
  end
96
+ rescue ArgumentError => e
97
+ raise e.exception, "#{property} #{e.message}"
94
98
  end
95
99
  alias add_declaration! []=
96
100
 
@@ -358,7 +362,7 @@ module CssParser
358
362
  # TODO: rgba, hsl, hsla
359
363
  value.gsub!(RE_COLOUR) { |c| c.gsub(/(\s*,\s*)/, ',') }
360
364
 
361
- matches = value.strip.split(/\s+/)
365
+ matches = split_value_preserving_function_whitespace(value)
362
366
 
363
367
  case matches.length
364
368
  when 1
@@ -374,8 +378,7 @@ module CssParser
374
378
  raise ArgumentError, "Cannot parse #{value}"
375
379
  end
376
380
 
377
- t, r, b, l = values
378
- replacement = {top => t, right => r, bottom => b, left => l}
381
+ replacement = [top, right, bottom, left].zip(values).to_h
379
382
 
380
383
  declarations.replace_declaration!(property, replacement, preserve_importance: true)
381
384
  end
@@ -510,23 +513,22 @@ module CssParser
510
513
  #
511
514
  # TODO: this is extremely similar to create_background_shorthand! and should be combined
512
515
  def create_border_shorthand! # :nodoc:
513
- values = []
514
-
515
- BORDER_STYLE_PROPERTIES.each do |property|
516
+ values = BORDER_STYLE_PROPERTIES.map do |property|
516
517
  next unless (declaration = declarations[property])
517
518
  next if declaration.important
518
-
519
519
  # can't merge if any value contains a space (i.e. has multiple values)
520
520
  # we temporarily remove any spaces after commas for the check (inside rgba, etc...)
521
- return nil if declaration.value.gsub(/,\s/, ',').strip =~ /\s/
521
+ next if declaration.value.gsub(/,\s/, ',').strip =~ /\s/
522
522
 
523
- values << declaration.value
523
+ declaration.value
524
+ end.compact
524
525
 
526
+ return if values.size != BORDER_STYLE_PROPERTIES.size
527
+
528
+ BORDER_STYLE_PROPERTIES.each do |property|
525
529
  declarations.delete(property)
526
530
  end
527
531
 
528
- return if values.empty?
529
-
530
532
  declarations['border'] = values.join(' ')
531
533
  end
532
534
 
@@ -614,7 +616,7 @@ module CssParser
614
616
  decs = (continuation ? continuation + decs : decs)
615
617
  if decs =~ /\([^)]*\Z/ # if it has an unmatched parenthesis
616
618
  continuation = "#{decs};"
617
- elsif (matches = decs.match(/\s*(.[^:]*)\s*:\s*(.+?)(?:;?\s*\Z)/i))
619
+ elsif (matches = decs.match(/\s*(.[^:]*)\s*:\s*(?m:(.+))(?:;?\s*\Z)/i))
618
620
  # skip end_of_declaration
619
621
  property = matches[1]
620
622
  value = matches[2]
@@ -634,6 +636,19 @@ module CssParser
634
636
  s
635
637
  end
636
638
  end
639
+
640
+ def split_value_preserving_function_whitespace(value)
641
+ split_value = value.gsub(RE_FUNCTIONS) do |c|
642
+ c.gsub!(/\s+/, WHITESPACE_REPLACEMENT)
643
+ c
644
+ end
645
+
646
+ matches = split_value.strip.split(/\s+/)
647
+
648
+ matches.each do |c|
649
+ c.gsub!(WHITESPACE_REPLACEMENT, ' ')
650
+ end
651
+ end
637
652
  end
638
653
 
639
654
  class OffsetAwareRuleSet < RuleSet
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CssParser
4
- VERSION = '1.9.0'.freeze
4
+ VERSION = '1.16.0'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: css_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Dunae
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-04 00:00:00.000000000 Z
11
+ date: 2023-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -163,14 +163,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
- version: '2.4'
166
+ version: '2.7'
167
167
  required_rubygems_version: !ruby/object:Gem::Requirement
168
168
  requirements:
169
169
  - - ">="
170
170
  - !ruby/object:Gem::Version
171
171
  version: '0'
172
172
  requirements: []
173
- rubygems_version: 3.1.3
173
+ rubygems_version: 3.1.6
174
174
  signing_key:
175
175
  specification_version: 4
176
176
  summary: Ruby CSS parser.