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

Fix selectors :not(.a,.b) #161

Merged
merged 1 commit into from
Jun 12, 2024
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
21 changes: 19 additions & 2 deletions lib/css_parser/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ def self.create_declaration_from_properties(properties)

declarations
end

# it is expecting the selector tokens from node: :style_rule, not just
# from Crass::Tokenizer.tokenize(input)
def self.split_selectors(tokens)
tokens
.each_with_object([[]]) do |token, sum|
case token
in node: :comma
sum << []
else
sum.last << token
end
end
end
end

# == Parser class
Expand Down Expand Up @@ -107,7 +121,7 @@ def find_rule_sets(selectors, media_types = :all)
rule_sets = []

selectors.each do |selector|
selector = selector.gsub(/\s+/, ' ').strip
selector = selector.strip
each_rule_set(media_types) do |rule_set, _media_type|
if !rule_sets.member?(rule_set) && rule_set.selectors.member?(selector)
rule_sets << rule_set
Expand Down Expand Up @@ -157,9 +171,12 @@ def add_block!(block, options = {})
case node
in node: :style_rule
declarations = ParserFx.create_declaration_from_properties(node[:children])
selectors = ParserFx
.split_selectors(node[:selector][:tokens])
.map { Crass::Parser.stringify(_1).strip }

add_rule_options = {
selectors: node[:selector][:value],
selectors: selectors,
block: declarations,
media_types: current_media_queries
}
Expand Down
13 changes: 1 addition & 12 deletions lib/css_parser/rule_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def initialize(selectors: nil, block: nil, offset: nil, filename: nil, specifici
@offset = offset
@filename = filename

parse_selectors!(selectors) if selectors
@selectors = Array(selectors) if selectors
parse_declarations!(block)
end

Expand Down Expand Up @@ -522,17 +522,6 @@ def parse_declarations!(block) # :nodoc:
end
end

#--
# TODO: way too simplistic
#++
def parse_selectors!(selectors) # :nodoc:
@selectors = selectors.split(',').map do |s|
s.gsub!(/\s+/, ' ')
s.strip!
s
end
end

def split_value_preserving_function_whitespace(value)
split_value = value.gsub(RE_FUNCTIONS) do |c|
c.gsub!(/\s+/, WHITESPACE_REPLACEMENT)
Expand Down
52 changes: 42 additions & 10 deletions test/test_css_parser_misc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def test_multiline_declarations
end

def test_find_rule_sets
css = <<-CSS
css = <<~CSS
h1, h2 { color: blue; }
h1 { font-size: 10px; }
h2 { font-size: 5px; }
Expand All @@ -144,9 +144,37 @@ def test_find_rule_sets

@cp.add_block!(css)
assert_equal 2, @cp.find_rule_sets(["h2"]).size
assert_equal 2, @cp.find_rule_sets([" h2 "]).size
assert_equal 3, @cp.find_rule_sets(["h1", "h2"]).size
assert_equal 2, @cp.find_rule_sets(["article h3"]).size
assert_equal 2, @cp.find_rule_sets([" article \t \n h3 \n "]).size
assert_equal 1, @cp.find_rule_sets(["article h3"]).size
assert_equal 1, @cp.find_rule_sets(["article\nh3"]).size
assert_equal 0, @cp.find_rule_sets([" article \t \n h3 \n "]).size
end

def test_whitespace_in_selector_names
css = <<~CSS
h1 {}
h1 pre{}
.a.b.c
.d.e.f {}
h1 > pre {}
input[name="Joe"]{}
input[name="Joe Doe"]{}
input:not(a,b){}
CSS

@cp.add_block!(css)

assert_equal(
["h1",
"h1 pre",
".a.b.c\n.d.e.f",
"h1 > pre",
"input[name=\"Joe\"]",
"input[name=\"Joe Doe\"]",
"input:not(a,b)"],
@cp.rules_by_media_query[:all].flat_map(&:selectors)
)
end

def test_calculating_specificity
Expand All @@ -171,13 +199,17 @@ def test_calculating_specificity

def test_converting_uris
base_uri = 'http://www.example.org/style/basic.css'
["body { background: url(yellow) };", "body { background: url('yellow') };",
"body { background: url('/style/yellow') };",
"body { background: url(\"../style/yellow\") };",
"body { background: url(\"lib/../../style/yellow\") };"].each do |css|
converted_css = CssParser.convert_uris(css, base_uri)
assert_equal "body { background: url('http://www.example.org/style/yellow') };", converted_css
end
[
"body { background: url(yellow) };",
"body { background: url('yellow') };",
"body { background: url('/style/yellow') };",
"body { background: url(\"../style/yellow\") };",
"body { background: url(\"lib/../../style/yellow\") };"
]
.each do |css|
converted_css = CssParser.convert_uris(css, base_uri)
assert_equal "body { background: url('http://www.example.org/style/yellow') };", converted_css
end

converted_css = CssParser.convert_uris("body { background: url(../style/yellow-dot_symbol$.png?abc=123&amp;def=456&ghi=789#1011) };", base_uri)
assert_equal "body { background: url('http://www.example.org/style/yellow-dot_symbol$.png?abc=123&amp;def=456&ghi=789#1011') };", converted_css
Expand Down
8 changes: 1 addition & 7 deletions test/test_rule_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def test_each_selector
]

actual = []
rs = RuleSet.new(selectors: '#content p, a', block: 'color: #fff;')
rs = RuleSet.new(selectors: ['#content p', 'a'], block: 'color: #fff;')
rs.each_selector do |sel, decs, spec|
actual << {selector: sel, declarations: decs, specificity: spec}
end
Expand Down Expand Up @@ -78,12 +78,6 @@ def test_each_declaration_containing_semicolons
assert_equal('no-repeat;', rs['background-repeat'])
end

def test_selector_sanitization
selectors = "h1, h2,\nh3 "
rs = RuleSet.new(selectors: selectors, block: "color: #fff;")
assert rs.selectors.member?("h3")
end

def test_multiple_selectors_to_s
selectors = "#content p, a"
rs = RuleSet.new(selectors: selectors, block: "color: #fff;")
Expand Down