Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

additional CSS selector formatting #59

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions lib/syntax_tree/css/format.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ def visit_ident_token(node)
q.text(node.value)
end

# Visit a HashToken node.
def visit_hash_token(node)
q.text(node.value)
end

# Visit a StyleRule node.
def visit_style_rule(node)
q.group do
Expand Down Expand Up @@ -77,12 +82,30 @@ def visit_type_selector(node)
end
end

# Visit a Selectors::IdSelector node.
def visit_id_selector(node)
q.text("#")
node.value.format(q)
end

# Visit a Selectors::ClassSelector node.
def visit_class_selector(node)
q.text(".")
node.value.format(q)
end

# Visit a Selectors::PseudoClassSelector node.
def visit_pseudo_class_selector(node)
q.text(":")
node.value.format(q)
end

# Visit a Selectors::PseudoElementSelector node.
def visit_pseudo_element_selector(node)
q.text(":")
node.value.format(q)
end

# Visit a Selectors::Combinator node.
def visit_combinator(node)
node.value.format(q)
Expand All @@ -101,9 +124,8 @@ def visit_complex_selector(node)
# Visit a Selectors::CompoundSelector node.
def visit_compound_selector(node)
q.group do
node.type.format(q) if node.type
node.subclasses.each do |subclass|
subclass.format(q)
node.child_nodes.each do |node_|
node_.format(q)
end
# TODO: pseudo-elements
end
Expand Down
2 changes: 1 addition & 1 deletion lib/syntax_tree/css/selectors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def accept(visitor)
end

def child_nodes
[type, subclasses, pseudo_elements].flatten
[type, subclasses, pseudo_elements].compact.flatten
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to you, but you could make this:

Suggested change
[type, subclasses, pseudo_elements].compact.flatten
[type, *subclasses, *pseudo_elements]

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately that change doesn't account for a) type being nil and needing to be removed, and b) pseudo_elements contains nested arrays.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we're here, I don't really like the fact that pseudo_elements contains nested arrays (see the test "parses a compound selector with pseudo-elements and pseudo-classes" to see what it looks like), but regardless I think child_nodes should flatten it all.

end

alias deconstruct child_nodes
Expand Down
108 changes: 102 additions & 6 deletions test/selectors_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ class SelectorsTest < Minitest::Spec
]
]
end

assert_pattern do
actual => [
Selectors::CompoundSelector[
Selectors::ClassSelector[value: { value: "flex" }],
Selectors::ClassSelector[value: { value: "text-xl" }]
]
]
end
end

it "parses a compound selector" do
Expand All @@ -41,6 +50,15 @@ class SelectorsTest < Minitest::Spec
]
]
end

assert_pattern do
actual => [
Selectors::CompoundSelector[
Selectors::TypeSelector[value: { name: { value: "div" } } ],
Selectors::ClassSelector[value: { value: "flex" }],
]
]
end
end

it "parses a compound selector with a pseudo-element" do
Expand All @@ -54,9 +72,7 @@ class SelectorsTest < Minitest::Spec
pseudo_elements: [
[
Selectors::PseudoElementSelector[
Selectors::PseudoClassSelector[
value: { value: "first-line" }
]
value: { value: { value: "first-line" } }
],
[]
]
Expand All @@ -66,6 +82,51 @@ class SelectorsTest < Minitest::Spec
end
end

it "parses a compound selector with a pseudo-class" do
actual = parse_selectors("div.flex:hover")

assert_pattern do
actual => [
Selectors::CompoundSelector[
type: { value: { name: { value: "div" } } },
subclasses: [
Selectors::ClassSelector[value: { value: "flex" }],
Selectors::PseudoClassSelector[value: { value: "hover" }],
],
]
]
end
end

it "parses a compound selector with pseudo-elements and pseudo-classes" do
actual = parse_selectors("div.flex:hover::first-line:last-child:active::first-letter")

assert_pattern do
actual => [
Selectors::CompoundSelector[
type: { value: { name: { value: "div" } } },
subclasses: [
Selectors::ClassSelector[value: { value: "flex" }],
Selectors::PseudoClassSelector[value: { value: "hover" }],
],
pseudo_elements: [
[
Selectors::PseudoElementSelector[value: { value: { value: "first-line" } }],
[
Selectors::PseudoClassSelector[value: { value: "last-child" }],
Selectors::PseudoClassSelector[value: { value: "active" }],
],
],
[
Selectors::PseudoElementSelector[value: { value: { value: "first-letter" } }],
[],
]
]
]
]
end
end

it "parses a complex selector" do
actual = parse_selectors("section>table")

Expand Down Expand Up @@ -151,8 +212,43 @@ class SelectorsTest < Minitest::Spec
end

describe "formatting" do
it "formats complex selectors" do
assert_selector_format(".outer section.foo>table.bar tr", ".outer section.foo > table.bar tr")
describe Selectors::CompoundSelector do
it "with an id selector" do
assert_selector_format(
"div#foo",
"div#foo",
)
end

it "with a pseudo-class selector" do
assert_selector_format(
"div:hover",
"div:hover",
)
end

it "with class selectors" do
assert_selector_format(
"div.flex.text-xl",
"div.flex.text-xl",
)
end

it "with pseudo-elements" do
assert_selector_format(
"div.flex:hover::first-line:last-child:active::first-letter",
"div.flex:hover::first-line:last-child:active::first-letter",
)
end
end

describe Selectors::ComplexSelector do
it "with whitespace" do
assert_selector_format(
".outer section.foo>table.bar tr",
".outer section.foo > table.bar tr",
)
end
end

private
Expand All @@ -162,7 +258,7 @@ def assert_selector_format(selectors, expected)

io = StringIO.new
selectors.each do |selector|
selector.format(::PrettyPrint.new(io))
selector.format(::PP.new(io))
assert_equal(expected, io.string)
end
end
Expand Down