css_parser 1.2.2 → 3.0.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.
@@ -1,65 +1,88 @@
1
- module CssParser
2
-
1
+ # frozen_string_literal: true
3
2
 
4
- def self.regex_possible_values *values
3
+ module CssParser
4
+ def self.regex_possible_values(*values)
5
5
  Regexp.new("([\s]*^)?(#{values.join('|')})([\s]*$)?", 'i')
6
6
  end
7
7
 
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
- RE_STRING1 = Regexp.new('(\"(.[^\n\r\f\\"]*|\\\\' + RE_NL.to_s + '|' + RE_ESCAPE.to_s + ')*\")')
18
- RE_STRING2 = Regexp.new('(\'(.[^\n\r\f\\\']*|\\\\' + RE_NL.to_s + '|' + RE_ESCAPE.to_s + ')*\')')
17
+ RE_STRING1 = /("(.[^\n\r\f"]*|\\#{RE_NL}|#{RE_ESCAPE})*")/.freeze
18
+ RE_STRING2 = /('(.[^\n\r\f']*|\\#{RE_NL}|#{RE_ESCAPE})*')/.freeze
19
19
  RE_STRING = Regexp.union(RE_STRING1, RE_STRING2)
20
20
 
21
21
  RE_INHERIT = regex_possible_values 'inherit'
22
22
 
23
- RE_URI = Regexp.new('(url\([\s]*([\s]*' + RE_STRING.to_s + '[\s]*)[\s]*\))|(url\([\s]*([!#$%&*\-~]|' + RE_NON_ASCII.to_s + '|' + RE_ESCAPE.to_s + ')*[\s]*)\)', Regexp::IGNORECASE | Regexp::EXTENDED | Regexp::MULTILINE, 'n')
24
- URI_RX = /url\(("([^"]*)"|'([^']*)'|([^)]*))\)/im
23
+ RE_URI = /(url\(\s*(\s*#{RE_STRING}\s*)\s*\))|(url\(\s*([!#$%&*\-~]|#{RE_NON_ASCII}|#{RE_ESCAPE})*\s*)\)/ixm.freeze
24
+ URI_RX = /url\(("([^"]*)"|'([^']*)'|([^)]*))\)/im.freeze
25
+ URI_RX_OR_NONE = Regexp.union(URI_RX, /none/i)
26
+ RE_GRADIENT = /[-a-z]*gradient\([-a-z0-9 .,#%()]*\)/im.freeze
25
27
 
26
28
  # Initial parsing
27
- RE_AT_IMPORT_RULE = /\@import[\s]+(url\()?["''"]?(.[^'"\s"']*)["''"]?\)?([\w\s\,^\])]*)\)?;?/
28
-
29
+ RE_AT_IMPORT_RULE = /@import\s+(url\()?["']?(.[^'"\s]*)["']?\)?([\w\s,^\])]*)\)?;?/.freeze
30
+
29
31
  #--
30
- #RE_AT_MEDIA_RULE = Regexp.new('(\"(.[^\n\r\f\\"]*|\\\\' + RE_NL.to_s + '|' + RE_ESCAPE.to_s + ')*\")')
31
-
32
- #RE_AT_IMPORT_RULE = Regexp.new('@import[\s]*(' + RE_STRING.to_s + ')([\w\s\,]*)[;]?', Regexp::IGNORECASE) -- should handle url() even though it is not allowed
32
+ # RE_AT_MEDIA_RULE = Regexp.new('(\"(.[^\n\r\f\\"]*|\\\\' + RE_NL.to_s + '|' + RE_ESCAPE.to_s + ')*\")')
33
+
34
+ # RE_AT_IMPORT_RULE = Regexp.new('@import[\s]*(' + RE_STRING.to_s + ')([\w\s\,]*)[;]?', Regexp::IGNORECASE) -- should handle url() even though it is not allowed
33
35
  #++
34
- IMPORTANT_IN_PROPERTY_RX = /[\s]*!important[\s]*/i
36
+ IMPORTANT_IN_PROPERTY_RX = /\s*!important\b\s*/i.freeze
35
37
 
36
38
  RE_INSIDE_OUTSIDE = regex_possible_values 'inside', 'outside'
37
39
  RE_SCROLL_FIXED = regex_possible_values 'scroll', 'fixed'
38
40
  RE_REPEAT = regex_possible_values 'repeat(\-x|\-y)*|no\-repeat'
39
- RE_LIST_STYLE_TYPE = regex_possible_values 'disc', 'circle', 'square', 'decimal-leading-zero', 'decimal', 'lower-roman',
40
- 'upper-roman', 'lower-greek', 'lower-alpha', 'lower-latin', 'upper-alpha',
41
- 'upper-latin', 'hebrew', 'armenian', 'georgian', 'cjk-ideographic', 'hiragana',
42
- 'hira-gana-iroha', 'katakana-iroha', 'katakana', 'none'
41
+ RE_LIST_STYLE_TYPE = regex_possible_values(
42
+ 'disc', 'circle', 'square', 'decimal-leading-zero', 'decimal', 'lower-roman',
43
+ 'upper-roman', 'lower-greek', 'lower-alpha', 'lower-latin', 'upper-alpha',
44
+ 'upper-latin', 'hebrew', 'armenian', 'georgian', 'cjk-ideographic', 'hiragana',
45
+ 'hira-gana-iroha', 'katakana-iroha', 'katakana', 'none'
46
+ )
47
+ RE_IMAGE = Regexp.union(CssParser::URI_RX, CssParser::RE_GRADIENT, /none/i)
43
48
 
44
- STRIP_CSS_COMMENTS_RX = /\/\*.*?\*\//m
45
- STRIP_HTML_COMMENTS_RX = /\<\!\-\-|\-\-\>/m
49
+ STRIP_CSS_COMMENTS_RX = %r{/\*.*?\*/}m.freeze
50
+ STRIP_HTML_COMMENTS_RX = /<!--|-->/m.freeze
46
51
 
47
52
  # Special units
48
- BOX_MODEL_UNITS_RX = /(auto|inherit|0|([\-]*([0-9]+|[0-9]*\.[0-9]+)(e[mx]+|px|[cm]+m|p[tc+]|in|\%)))([\s;]|\Z)/imx
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
49
54
  RE_LENGTH_OR_PERCENTAGE = Regexp.new('([\-]*(([0-9]*\.[0-9]+)|[0-9]+)(e[mx]+|px|[cm]+m|p[tc+]|in|\%))', Regexp::IGNORECASE)
50
- RE_BACKGROUND_POSITION = Regexp.new("((((#{RE_LENGTH_OR_PERCENTAGE})|left|center|right|top|bottom)[\s]*){1,2})", Regexp::IGNORECASE | Regexp::EXTENDED)
51
- FONT_UNITS_RX = /(([x]+\-)*small|medium|large[r]*|auto|inherit|([0-9]+|[0-9]*\.[0-9]+)(e[mx]+|px|[cm]+m|p[tc+]|in|\%)*)/i
52
- RE_BORDER_STYLE = /([\s]*^)?(none|hidden|dotted|dashed|solid|double|dot-dash|dot-dot-dash|wave|groove|ridge|inset|outset)([\s]*$)?/imx
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
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
60
+ RE_BORDER_STYLE = /(\s*^)?(none|hidden|dotted|dashed|solid|double|dot-dash|dot-dot-dash|wave|groove|ridge|inset|outset)(\s*$)?/imx.freeze
53
61
  RE_BORDER_UNITS = Regexp.union(BOX_MODEL_UNITS_RX, /(thin|medium|thick)/i)
54
-
55
-
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
+
56
79
  # Patterns for specificity calculations
57
- NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX= /
58
- (\.[\w]+) # classes
80
+ NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX_NC = /
81
+ (?:\.\w+) # classes
59
82
  |
60
- \[(\w+) # attributes
83
+ \[(?:\w+) # attributes
61
84
  |
62
- (\:( # pseudo classes
85
+ (?::(?: # pseudo classes
63
86
  link|visited|active
64
87
  |hover|focus
65
88
  |lang
@@ -71,22 +94,177 @@ module CssParser
71
94
  |only-child|only-of-type
72
95
  |empty|contains
73
96
  ))
74
- /ix
75
- ELEMENTS_AND_PSEUDO_ELEMENTS_RX = /
76
- ((^|[\s\+\>\~]+)[\w]+ # elements
77
- |
78
- \:{1,2}( # pseudo-elements
97
+ /ix.freeze
98
+ ELEMENTS_AND_PSEUDO_ELEMENTS_RX_NC = /
99
+ (?:(?:^|[\s+>~]+)\w+ # elements
100
+ |
101
+ :{1,2}(?: # pseudo-elements
79
102
  after|before
80
103
  |first-letter|first-line
81
104
  |selection
82
105
  )
83
- )/ix
106
+ )/ix.freeze
84
107
 
85
108
  # Colours
86
- RE_COLOUR_NUMERIC = Regexp.new('((hsl|rgb)[\s]*\([\s-]*[\d]+(\.[\d]+)?[%\s]*,[\s-]*[\d]+(\.[\d]+)?[%\s]*,[\s-]*[\d]+(\.[\d]+)?[%\s]*\))', Regexp::IGNORECASE)
87
- RE_COLOUR_NUMERIC_ALPHA = Regexp.new('((hsla|rgba)[\s]*\([\s-]*[\d]+(\.[\d]+)?[%\s]*,[\s-]*[\d]+(\.[\d]+)?[%\s]*,[\s-]*[\d]+(\.[\d]+)?[%\s]*,[\s-]*[\d]+(\.[\d]+)?[%\s]*\))', Regexp::IGNORECASE)
88
- RE_COLOUR_HEX = /(#([0-9a-f]{6}|[0-9a-f]{3})([\s;]|$))/i
89
- RE_COLOUR_NAMED = /([\s]*^)?(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|transparent)([\s]*$)?/i
109
+ NAMED_COLOURS = %w[
110
+ aliceblue
111
+ antiquewhite
112
+ aqua
113
+ aquamarine
114
+ azure
115
+ beige
116
+ bisque
117
+ black
118
+ blanchedalmond
119
+ blue
120
+ blueviolet
121
+ brown
122
+ burlywood
123
+ cadetblue
124
+ chartreuse
125
+ chocolate
126
+ coral
127
+ cornflowerblue
128
+ cornsilk
129
+ crimson
130
+ cyan
131
+ darkblue
132
+ darkcyan
133
+ darkgoldenrod
134
+ darkgray
135
+ darkgreen
136
+ darkgrey
137
+ darkkhaki
138
+ darkmagenta
139
+ darkolivegreen
140
+ darkorange
141
+ darkorchid
142
+ darkred
143
+ darksalmon
144
+ darkseagreen
145
+ darkslateblue
146
+ darkslategray
147
+ darkslategrey
148
+ darkturquoise
149
+ darkviolet
150
+ deeppink
151
+ deepskyblue
152
+ dimgray
153
+ dimgrey
154
+ dodgerblue
155
+ firebrick
156
+ floralwhite
157
+ forestgreen
158
+ fuchsia
159
+ gainsboro
160
+ ghostwhite
161
+ gold
162
+ goldenrod
163
+ gray
164
+ green
165
+ greenyellow
166
+ grey
167
+ honeydew
168
+ hotpink
169
+ indianred
170
+ indigo
171
+ ivory
172
+ khaki
173
+ lavender
174
+ lavenderblush
175
+ lawngreen
176
+ lemonchiffon
177
+ lightblue
178
+ lightcoral
179
+ lightcyan
180
+ lightgoldenrodyellow
181
+ lightgray
182
+ lightgreen
183
+ lightgrey
184
+ lightpink
185
+ lightsalmon
186
+ lightseagreen
187
+ lightskyblue
188
+ lightslategray
189
+ lightslategrey
190
+ lightsteelblue
191
+ lightyellow
192
+ lime
193
+ limegreen
194
+ linen
195
+ magenta
196
+ maroon
197
+ mediumaquamarine
198
+ mediumblue
199
+ mediumorchid
200
+ mediumpurple
201
+ mediumseagreen
202
+ mediumslateblue
203
+ mediumspringgreen
204
+ mediumturquoise
205
+ mediumvioletred
206
+ midnightblue
207
+ mintcream
208
+ mistyrose
209
+ moccasin
210
+ navajowhite
211
+ navy
212
+ oldlace
213
+ olive
214
+ olivedrab
215
+ orange
216
+ orangered
217
+ orchid
218
+ palegoldenrod
219
+ palegreen
220
+ paleturquoise
221
+ palevioletred
222
+ papayawhip
223
+ peachpuff
224
+ peru
225
+ pink
226
+ plum
227
+ powderblue
228
+ purple
229
+ red
230
+ rosybrown
231
+ royalblue
232
+ saddlebrown
233
+ salmon
234
+ sandybrown
235
+ seagreen
236
+ seashell
237
+ sienna
238
+ silver
239
+ skyblue
240
+ slateblue
241
+ slategray
242
+ slategrey
243
+ snow
244
+ springgreen
245
+ steelblue
246
+ tan
247
+ teal
248
+ thistle
249
+ tomato
250
+ turquoise
251
+ violet
252
+ wheat
253
+ white
254
+ whitesmoke
255
+ yellow
256
+ yellowgreen
257
+
258
+ transparent
259
+ inherit
260
+ currentColor
261
+ ].freeze
262
+ # CSS <number> allows the integer part to be omitted (e.g. `.1`), per CSS Values & Units.
263
+ # `(?:\d*\.)?\d+` accepts `1`, `1.5`, and `.5` while still rejecting bare `1.`.
264
+ RE_COLOUR_NUMERIC = /\b(hsl|rgb)\s*\(-?\s*-?(?:\d*\.)?\d+%?\s*%?,-?\s*-?(?:\d*\.)?\d+%?\s*%?,-?\s*-?(?:\d*\.)?\d+%?\s*%?\)/i.freeze
265
+ RE_COLOUR_NUMERIC_ALPHA = /\b(hsla|rgba)\s*\(-?\s*-?(?:\d*\.)?\d+%?\s*%?,-?\s*-?(?:\d*\.)?\d+%?\s*%?,-?\s*-?(?:\d*\.)?\d+%?\s*%?,-?\s*-?(?:\d*\.)?\d+%?\s*%?\)/i.freeze
266
+ RE_COLOUR_HEX = /\s*#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})\b/.freeze
267
+ RE_COLOUR_NAMED = /\s*\b(#{NAMED_COLOURS.join('|')})\b/i.freeze
90
268
  RE_COLOUR = Regexp.union(RE_COLOUR_NUMERIC, RE_COLOUR_NUMERIC_ALPHA, RE_COLOUR_HEX, RE_COLOUR_NAMED)
91
269
  # :startdoc:
92
270
  end