Skip to content

Commit 4ee952e

Browse files
committed
Introduce a distinct Combinator subclass for each combinator
Where the AST was previously ``` Selectors::ComplexSelector[ child_nodes: [ Selectors::TypeSelector[value: { name: { value: "section" } }], Selectors::Combinator[value: { value: ">" }], Selectors::TypeSelector[value: { name: { value: "table" } }] ] ] ``` it's now ``` Selectors::ComplexSelector[ child_nodes: [ Selectors::TypeSelector[value: { name: { value: "a" } }], Selectors::DescendantCombinator, Selectors::TypeSelector[value: { name: { value: "b" } }], Selectors::ChildCombinator, Selectors::TypeSelector[value: { name: { value: "c" } }], Selectors::NextSiblingCombinator, Selectors::TypeSelector[value: { name: { value: "d" } }], Selectors::SubsequentSiblingCombinator, Selectors::TypeSelector[value: { name: { value: "e" } }], Selectors::ColumnSiblingCombinator, Selectors::TypeSelector[value: { name: { value: "f" } }], ] ] ```
1 parent 27a9bb5 commit 4ee952e

File tree

3 files changed

+58
-20
lines changed

3 files changed

+58
-20
lines changed

lib/syntax_tree/css/pretty_print.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ def visit_wqname(node)
423423

424424
# Visit a Selectors::Combinator node.
425425
def visit_combinator(node)
426-
token("combinator") do
426+
token(node.class::PP_NAME) do
427427
q.breakable
428428
q.pp(node.value)
429429
end

lib/syntax_tree/css/selectors.rb

+45-15
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,36 @@ def deconstruct_keys(keys)
9393
end
9494
end
9595

96+
# §15.1 https://www.w3.org/TR/selectors-4/#descendant-combinators
97+
class DescendantCombinator < Combinator
98+
TOKEN = WhitespaceToken
99+
PP_NAME = "descendant-combinator"
100+
end
101+
102+
# §15.2 https://www.w3.org/TR/selectors-4/#child-combinators
103+
class ChildCombinator < Combinator
104+
TOKEN = ">"
105+
PP_NAME = "child-combinator"
106+
end
107+
108+
# §15.3 https://www.w3.org/TR/selectors-4/#adjacent-sibling-combinators
109+
class NextSiblingCombinator < Combinator
110+
TOKEN = "+"
111+
PP_NAME = "next-sibling-combinator"
112+
end
113+
114+
# §15.4 https://www.w3.org/TR/selectors-4/#general-sibling-combinators
115+
class SubsequentSiblingCombinator < Combinator
116+
TOKEN = "~"
117+
PP_NAME = "subsequent-sibling-combinator"
118+
end
119+
120+
# §16.1 https://www.w3.org/TR/selectors-4/#the-column-combinator
121+
class ColumnSiblingCombinator < Combinator
122+
TOKEN = ["|", "|"]
123+
PP_NAME = "column-sibling-combinator"
124+
end
125+
96126
class ComplexSelector < Node
97127
attr_reader :child_nodes
98128

@@ -399,16 +429,13 @@ def simple_selector
399429

400430
# <combinator> = '>' | '+' | '~' | [ '|' '|' ]
401431
def combinator
402-
value =
403-
options do
404-
maybe { consume_combinator(">") } ||
405-
maybe { consume_combinator("+") } ||
406-
maybe { consume_combinator("~") } ||
407-
maybe { consume_combinator("|", "|") } ||
408-
maybe { consume(WhitespaceToken) }
409-
end
410-
411-
Combinator.new(value: value)
432+
options do
433+
maybe { consume_combinator(ChildCombinator) } ||
434+
maybe { consume_combinator(NextSiblingCombinator) } ||
435+
maybe { consume_combinator(SubsequentSiblingCombinator) } ||
436+
maybe { consume_combinator(ColumnSiblingCombinator) } ||
437+
maybe { consume_combinator(DescendantCombinator) }
438+
end
412439
end
413440

414441
# <type-selector> = <wq-name> | <ns-prefix>? '*'
@@ -551,11 +578,14 @@ def one_or_more
551578
end
552579
end
553580

554-
def consume_combinator(*values)
555-
consume_whitespace
556-
result = consume(*values)
557-
consume_whitespace
558-
result
581+
def consume_combinator(combinator_class)
582+
eat_whitespace = (combinator_class::TOKEN != WhitespaceToken)
583+
584+
consume_whitespace if eat_whitespace
585+
result = consume(*combinator_class::TOKEN)
586+
consume_whitespace if eat_whitespace
587+
588+
combinator_class.new(value: result)
559589
end
560590

561591
def consume(*values)

test/selectors_test.rb

+12-4
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,23 @@ class SelectorsTest < Minitest::Spec
128128
end
129129

130130
it "parses a complex selector" do
131-
actual = parse_selectors("section>table")
131+
actual = parse_selectors("a b > c + d ~ e || f")
132132

133133
assert_pattern do
134134
actual => [
135135
Selectors::ComplexSelector[
136136
child_nodes: [
137-
Selectors::TypeSelector[value: { name: { value: "section" } }],
138-
Selectors::Combinator[value: { value: ">" }],
139-
Selectors::TypeSelector[value: { name: { value: "table" } }]
137+
Selectors::TypeSelector[value: { name: { value: "a" } }],
138+
Selectors::DescendantCombinator,
139+
Selectors::TypeSelector[value: { name: { value: "b" } }],
140+
Selectors::ChildCombinator,
141+
Selectors::TypeSelector[value: { name: { value: "c" } }],
142+
Selectors::NextSiblingCombinator,
143+
Selectors::TypeSelector[value: { name: { value: "d" } }],
144+
Selectors::SubsequentSiblingCombinator,
145+
Selectors::TypeSelector[value: { name: { value: "e" } }],
146+
Selectors::ColumnSiblingCombinator,
147+
Selectors::TypeSelector[value: { name: { value: "f" } }],
140148
]
141149
]
142150
]

0 commit comments

Comments
 (0)