css_parser 1.9.0 → 1.16.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: 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.