p_css 0.2.0.beta1-x86_64-darwin

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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +282 -0
  3. data/Cargo.toml +3 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +357 -0
  6. data/ext/css_native/Cargo.toml +12 -0
  7. data/ext/css_native/extconf.rb +4 -0
  8. data/ext/css_native/src/lib.rs +117 -0
  9. data/ext/css_native/src/matcher.rs +356 -0
  10. data/ext/css_native/src/selectors.rs +411 -0
  11. data/ext/css_native/src/snapshot.rs +370 -0
  12. data/ext/css_native/src/state.rs +174 -0
  13. data/ext/css_native/src/tokenizer.rs +596 -0
  14. data/lib/css/3.3/css_native.bundle +0 -0
  15. data/lib/css/3.4/css_native.bundle +0 -0
  16. data/lib/css/4.0/css_native.bundle +0 -0
  17. data/lib/css/cascade.rb +277 -0
  18. data/lib/css/code_points.rb +59 -0
  19. data/lib/css/escape.rb +82 -0
  20. data/lib/css/media_queries/context.rb +60 -0
  21. data/lib/css/media_queries/evaluator.rb +157 -0
  22. data/lib/css/media_queries/nodes.rb +41 -0
  23. data/lib/css/media_queries/parser.rb +374 -0
  24. data/lib/css/media_queries.rb +9 -0
  25. data/lib/css/native.rb +179 -0
  26. data/lib/css/nesting.rb +229 -0
  27. data/lib/css/nodes.rb +42 -0
  28. data/lib/css/parser.rb +429 -0
  29. data/lib/css/selectors/anb_parser.rb +174 -0
  30. data/lib/css/selectors/matcher.rb +545 -0
  31. data/lib/css/selectors/nodes.rb +61 -0
  32. data/lib/css/selectors/parser.rb +395 -0
  33. data/lib/css/selectors/serializer.rb +102 -0
  34. data/lib/css/selectors/specificity.rb +81 -0
  35. data/lib/css/selectors.rb +11 -0
  36. data/lib/css/serializer.rb +167 -0
  37. data/lib/css/token.rb +107 -0
  38. data/lib/css/token_cursor.rb +49 -0
  39. data/lib/css/tokenizer.rb +447 -0
  40. data/lib/css/urange.rb +45 -0
  41. data/lib/css/version.rb +3 -0
  42. data/lib/css.rb +73 -0
  43. data/lib/p_css.rb +1 -0
  44. data/sig/css/cascade.rbs +22 -0
  45. data/sig/css/media_queries.rbs +107 -0
  46. data/sig/css/nodes.rbs +76 -0
  47. data/sig/css/selectors.rbs +164 -0
  48. data/sig/css/token.rbs +33 -0
  49. data/sig/css.rbs +99 -0
  50. metadata +113 -0
@@ -0,0 +1,174 @@
1
+ module CSS
2
+ module Selectors
3
+ # Parser for the An+B microsyntax used by `:nth-child(...)` and friends.
4
+ # https://drafts.csswg.org/css-syntax/#anb-microsyntax
5
+ module AnBParser
6
+ TRAILING_DASH_INT = /\A-(\d+)\z/.freeze
7
+ N_TRAILING_INT = /\An(-\d+)?\z/i.freeze
8
+ DASH_N_TRAILING = /\A-n(-\d+)?\z/i.freeze
9
+
10
+ module_function
11
+
12
+ def parse(input)
13
+ tokens = input.is_a?(String) ? Tokenizer.new(input).tokenize : input.to_a
14
+ Impl.new(tokens).parse
15
+ end
16
+
17
+ class Impl
18
+ include CSS::TokenCursor
19
+
20
+ def initialize(tokens)
21
+ init_cursor(tokens)
22
+ end
23
+
24
+ def parse
25
+ skip_whitespace
26
+
27
+ result = parse_value
28
+
29
+ skip_whitespace
30
+
31
+ unless peek.type == :eof
32
+ raise ParseError, "trailing tokens in AnB: #{peek.type}"
33
+ end
34
+
35
+ result
36
+ end
37
+
38
+ private
39
+
40
+ def parse_value
41
+ t = peek
42
+
43
+ case t.type
44
+ when :ident then parse_ident_form(t)
45
+ when :number then parse_pure_number(t)
46
+ when :dimension then parse_dimension_form(t)
47
+ when :delim then parse_signed_form(t)
48
+ else
49
+ raise ParseError, "expected An+B, got #{t.type}"
50
+ end
51
+ end
52
+
53
+ def parse_ident_form(t)
54
+ consume
55
+
56
+ case t.value.downcase
57
+ when 'even'
58
+ AnB.new(step: 2, offset: 0)
59
+ when 'odd'
60
+ AnB.new(step: 2, offset: 1)
61
+ when 'n'
62
+ parse_offset(step: 1)
63
+ when '-n'
64
+ parse_offset(step: -1)
65
+ when N_TRAILING_INT
66
+ AnB.new(step: 1, offset: -extract_dash_int(t.value, prefix: 'n'))
67
+ when DASH_N_TRAILING
68
+ AnB.new(step: -1, offset: -extract_dash_int(t.value, prefix: '-n'))
69
+ else
70
+ raise ParseError, "invalid AnB identifier: #{t.value}"
71
+ end
72
+ end
73
+
74
+ def parse_pure_number(t)
75
+ consume
76
+
77
+ raise ParseError, 'AnB integer must be an integer' unless t.flag == :integer
78
+
79
+ AnB.new(step: 0, offset: t.value)
80
+ end
81
+
82
+ def parse_dimension_form(t)
83
+ consume
84
+
85
+ raise ParseError, 'AnB step coefficient must be an integer' unless t.flag == :integer
86
+
87
+ unit = t.unit.downcase
88
+
89
+ if unit == 'n'
90
+ parse_offset(step: t.value)
91
+ elsif unit.start_with?('n') && (m = TRAILING_DASH_INT.match(unit[1..]))
92
+ AnB.new(step: t.value, offset: -m[1].to_i)
93
+ else
94
+ raise ParseError, "invalid AnB dimension unit: #{unit}"
95
+ end
96
+ end
97
+
98
+ # `+n`, `+n+1`, `+n-1`, `+n-3` (where `+n-3` lexes as delim '+' then
99
+ # ident "n-3"): consume the leading `+` and re-enter the ident path.
100
+ def parse_signed_form(t)
101
+ raise ParseError, "unexpected delim #{t.value}" unless t.value == '+'
102
+
103
+ consume
104
+
105
+ ident = peek
106
+
107
+ unless ident.type == :ident
108
+ raise ParseError, "expected ident after '+', got #{ident.type}"
109
+ end
110
+
111
+ consume
112
+
113
+ case ident.value.downcase
114
+ when 'n'
115
+ parse_offset(step: 1)
116
+ when N_TRAILING_INT
117
+ AnB.new(step: 1, offset: -extract_dash_int(ident.value, prefix: 'n'))
118
+ else
119
+ raise ParseError, "invalid AnB after '+': #{ident.value}"
120
+ end
121
+ end
122
+
123
+ def parse_offset(step:)
124
+ skip_whitespace
125
+
126
+ t = peek
127
+
128
+ case t.type
129
+ when :eof
130
+ AnB.new(step:, offset: 0)
131
+ when :number
132
+ consume
133
+
134
+ raise ParseError, 'AnB offset must be an integer' unless t.flag == :integer
135
+
136
+ AnB.new(step:, offset: t.value)
137
+ when :delim
138
+ unless t.value == '+' || t.value == '-'
139
+ raise ParseError, "expected +/- in AnB offset, got delim #{t.value}"
140
+ end
141
+
142
+ sign = t.value
143
+ consume
144
+
145
+ skip_whitespace
146
+
147
+ n = peek
148
+
149
+ unless n.type == :number && n.flag == :integer
150
+ raise ParseError, "expected integer after #{sign}"
151
+ end
152
+
153
+ consume
154
+
155
+ AnB.new(step:, offset: sign == '-' ? -n.value.abs : n.value.abs)
156
+ else
157
+ AnB.new(step:, offset: 0)
158
+ end
159
+ end
160
+
161
+ def extract_dash_int(s, prefix:)
162
+ rest = s.sub(/\A#{prefix}/i, '')
163
+ return 0 if rest.empty?
164
+
165
+ m = TRAILING_DASH_INT.match(rest)
166
+
167
+ raise ParseError, "invalid AnB suffix: #{s}" unless m
168
+
169
+ m[1].to_i
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end