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 +4 -4
- data/lib/css_parser/parser.rb +14 -2
- data/lib/css_parser/regexps.rb +23 -5
- data/lib/css_parser/rule_set.rb +27 -12
- data/lib/css_parser/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36f35091b57e726d3e9b528b6f3357232343c075af962f61a402f2bb111aadd1
|
4
|
+
data.tar.gz: ee8dbf61a3a6f396e8d383f0334cfee91ad483b192bfbffb4e5c5d9294f89859
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba19471cdbeed2daf719a2e1b238bff145bd748abbc760b64cd5ba40ba3e0ed03de8f6550b44b114bcbdbd577cd415b8f5c609def6c53a25699d3ca71f6e06d7
|
7
|
+
data.tar.gz: 72d71760da086f403c0d404c97d6bd6476e330376b56ce91b8ebfc51cdd27fc89932a066397b38799c15fb9f9a8a8b625d30728656dc0e8cfc24ec61a168e8e7
|
data/lib/css_parser/parser.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/css_parser/regexps.rb
CHANGED
@@ -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
|
12
|
-
RE_UNICODE = Regexp.new('(\\\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])*)', Regexp::IGNORECASE | Regexp::EXTENDED | Regexp::MULTILINE
|
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
|
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
|
-
|
56
|
-
|
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
|
data/lib/css_parser/rule_set.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
521
|
+
next if declaration.value.gsub(/,\s/, ',').strip =~ /\s/
|
522
522
|
|
523
|
-
|
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*(
|
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
|
data/lib/css_parser/version.rb
CHANGED
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.
|
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:
|
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.
|
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.
|
173
|
+
rubygems_version: 3.1.6
|
174
174
|
signing_key:
|
175
175
|
specification_version: 4
|
176
176
|
summary: Ruby CSS parser.
|