Skip to content

Commit 53cfd51

Browse files
committed
Hooks up the rest of the parsers and consolidates border
Border is becoming a pain in the ass, and while this is uber ugly, it works
1 parent 999eb2d commit 53cfd51

File tree

6 files changed

+143
-33
lines changed

6 files changed

+143
-33
lines changed

lib/csscss/parser/base.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module Csscss
22
module Parser
33
module Base
4-
def parse(inputs)
4+
def parse(_, inputs)
55
input = Array(inputs).join(" ")
66

77
if parsed = self::Parser.new.try_parse(input)

lib/csscss/parser/border_side.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
11
module Csscss
22
module Parser
33
module BorderSide
4-
extend Parser::Base
4+
class << self
5+
def parse(property, inputs)
6+
input = Array(inputs).join(" ")
7+
side = find_side(property)
8+
9+
if parsed = self::Parser.new(side).try_parse(input)
10+
self::Transformer.new.apply(parsed)
11+
end
12+
end
13+
14+
def find_side(property)
15+
case property
16+
when "border-top" then :top
17+
when "border-right" then :right
18+
when "border-bottom" then :bottom
19+
when "border-left" then :left
20+
else raise "Unknown property #{property}"
21+
end
22+
end
23+
end
524

625
class Parser < Parslet::Parser
726
include Common

lib/csscss/redundancy_analyzer.rb

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,43 @@ def initialize(raw_css)
77
def redundancies(minimum = nil)
88
rule_sets = CSSPool.CSS(@raw_css).rule_sets
99
matches = {}
10+
parents = {}
1011
rule_sets.each do |rule_set|
1112
rule_set.declarations.each do |dec|
12-
dec.property.downcase!
13-
dec.expressions do |exp|
14-
exp.value.downcase!
15-
end
16-
1713
sel = Selector.new(rule_set.selectors.map(&:to_s))
18-
1914
original_dec = Declaration.from_csspool(dec)
2015

2116
if parser = shorthand_parser(dec.property)
22-
if new_decs = parser.parse(dec.expressions)
17+
if new_decs = parser.parse(dec.property, dec.expressions)
18+
if original_dec.property == "border"
19+
%w(border-top border-right border-bottom border-left).each do |property|
20+
border_dec = Declaration.new(property, original_dec.value)
21+
parents[border_dec] ||= []
22+
(parents[border_dec] << original_dec).uniq!
23+
border_dec.parents = parents[border_dec]
24+
25+
matches[border_dec] ||= []
26+
matches[border_dec] << sel
27+
matches[border_dec].uniq!
28+
end
29+
end
30+
2331
new_decs.each do |new_dec|
2432
# replace any non-derivatives with derivatives
2533
existing = matches.delete(new_dec) || []
2634
existing << sel
27-
new_dec.parent = original_dec
35+
parents[new_dec] ||= []
36+
(parents[new_dec] << original_dec).uniq!
37+
new_dec.parents = parents[new_dec]
2838
matches[new_dec] = existing
39+
matches[new_dec].uniq!
2940
end
3041
end
3142
end
3243

3344
matches[original_dec] ||= []
3445
matches[original_dec] << sel
46+
matches[original_dec].uniq!
3547
end
3648
end
3749

@@ -68,13 +80,25 @@ def redundancies(minimum = nil)
6880
# trims any derivative declarations alongside shorthand
6981
final_inverted_matches.each do |selectors, declarations|
7082
redundant_derivatives = declarations.select do |dec|
71-
dec.derivative? && declarations.include?(dec.parent)
83+
dec.derivative? && declarations.detect {|dec2| dec2 > dec }
7284
end
7385
unless redundant_derivatives.empty?
7486
final_inverted_matches[selectors] = declarations - redundant_derivatives
7587
end
88+
89+
# border needs to be reduced even more
90+
%w(width style color).each do |property|
91+
decs = final_inverted_matches[selectors].select do |dec|
92+
dec.derivative? && dec.property =~ /border-\w+-#{property}/
93+
end
94+
if decs.size == 4 && decs.map(&:value).uniq.size == 1
95+
final_inverted_matches[selectors] -= decs
96+
final_inverted_matches[selectors] << Declaration.new("border-#{property}", decs.first.value)
97+
end
98+
end
7699
end
77100

101+
78102
# sort hash by number of matches
79103
sorted_array = final_inverted_matches.sort {|(_, v1), (_, v2)| v2.size <=> v1.size }
80104
{}.tap do |sorted_hash|
@@ -86,10 +110,16 @@ def redundancies(minimum = nil)
86110

87111
def shorthand_parser(property)
88112
case property
89-
when "background" then Parser::Background
90-
when "list-style" then Parser::ListStyle
91-
when "margin" then Parser::Margin
92-
when "padding" then Parser::Padding
113+
when "background" then Parser::Background
114+
when "list-style" then Parser::ListStyle
115+
when "margin" then Parser::Margin
116+
when "padding" then Parser::Padding
117+
when "border" then Parser::Border
118+
when "border-width" then Parser::BorderWidth
119+
when "border-style" then Parser::BorderStyle
120+
when "border-color" then Parser::BorderColor
121+
when "border-top", "border-right", "border-bottom", "border-left"
122+
Parser::BorderSide
93123
end
94124
end
95125
end

lib/csscss/types.rb

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
module Csscss
2-
class Declaration < Struct.new(:property, :value, :parent)
2+
class Declaration < Struct.new(:property, :value, :parents)
33
def self.from_csspool(dec)
4-
new(dec.property.to_s, dec.expressions.join(" "))
4+
new(dec.property.to_s.downcase, dec.expressions.join(" ").downcase)
55
end
66

77
def self.from_parser(property, value)
88
new(property.to_s, value.to_s.downcase.strip)
99
end
1010

1111
def derivative?
12-
!parent.nil?
12+
!parents.nil?
1313
end
1414

15-
def without_parent
15+
def without_parents
1616
if derivative?
1717
dup.tap do |duped|
18-
duped.parent = nil
18+
duped.parents = nil
1919
end
2020
else
2121
self
@@ -24,14 +24,14 @@ def without_parent
2424

2525
def ==(other)
2626
if derivative?
27-
without_parent == other
27+
without_parents == other
2828
else
29-
super(other.respond_to?(:without_parent) ? other.without_parent : other)
29+
super(other.respond_to?(:without_parents) ? other.without_parents : other)
3030
end
3131
end
3232

3333
def hash
34-
derivative? ? without_parent.hash : super
34+
derivative? ? without_parents.hash : super
3535
end
3636

3737
def eql?(other)
@@ -43,7 +43,7 @@ def <=>(other)
4343
end
4444

4545
def >(other)
46-
self == other.parent
46+
other.derivative? && other.parents.include?(self)
4747
end
4848

4949
def <(other)
@@ -52,8 +52,8 @@ def <(other)
5252

5353
def to_s
5454
base = "#{property}: #{value}"
55-
if parent
56-
"#{base} (parent: #{parent})"
55+
if parents
56+
"#{base} (parents: #{parents})"
5757
else
5858
base
5959
end

test/csscss/redundancy_analyzer_test.rb

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,5 +135,52 @@ module Csscss
135135
[sel(".bar"), sel(".baz"), sel(".foo")] => [dec("background-color", "#fff")]
136136
})
137137
end
138+
139+
it "handles border and border-top matches appropriately" do
140+
css = %$
141+
.bar { border: 1px solid #fff }
142+
.baz { border-top: 1px solid #fff }
143+
.foo { border-top-width: 1px }
144+
$
145+
146+
RedundancyAnalyzer.new(css).redundancies.must_equal({
147+
[sel(".bar"), sel(".baz")] => [dec("border-top", "1px solid #fff")],
148+
[sel(".bar"), sel(".baz"), sel(".foo")] => [dec("border-top-width", "1px")]
149+
})
150+
end
151+
152+
it "reduces border matches appropriately" do
153+
#css = %$
154+
#.bar { border: 1px solid #FFF }
155+
#.baz { border: 1px solid #FFF }
156+
#$
157+
158+
#RedundancyAnalyzer.new(css).redundancies.must_equal({
159+
#[sel(".bar"), sel(".baz")] => [dec("border", "1px solid #fff")]
160+
#})
161+
162+
css = %$
163+
.bar { border: 4px solid #4F4F4F }
164+
.baz { border: 4px solid #4F4F4F }
165+
.foo { border: 4px solid #3A86CE }
166+
$
167+
168+
RedundancyAnalyzer.new(css).redundancies.must_equal({
169+
[sel(".bar"), sel(".baz")] => [dec("border", "4px solid #4f4f4f")],
170+
[sel(".bar"), sel(".baz"), sel(".foo")] => [dec("border-style", "solid"), dec("border-width", "4px")]
171+
})
172+
end
173+
174+
# TODO: someday
175+
# it "reports duplication within the same selector" do
176+
# css = %$
177+
# .bar { background: #fff top; background-color: #fff }
178+
# $
179+
180+
# # TODO: need to update the reporter for this
181+
# RedundancyAnalyzer.new(css).redundancies.must_equal({
182+
# [sel(".bar")] => [dec("background-color", "#fff")]
183+
# })
184+
# end
138185
end
139186
end

test/csscss/types_test.rb

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,43 @@
22

33
module Csscss
44
describe Declaration do
5-
it "< and > checks parent" do
5+
it "< and > checks parents" do
66
dec1 = Declaration.new("background", "#fff")
77
dec2 = Declaration.new("background", "#fff")
8-
dec3 = Declaration.new("background-color", "#fff", dec1)
8+
dec3 = Declaration.new("background-color", "#fff", [dec1])
99
dec4 = Declaration.new("background-color", "#fff", nil)
1010

1111
dec1.must_be :>, dec3
1212
dec3.must_be :<, dec1
1313

14-
dec1.wont_be :>, dec2
1514
dec1.wont_be :>, dec4
15+
dec1.wont_be :>, dec2
1616
dec4.wont_be :>, dec1
1717
end
1818

19-
it "is a derivative if it has parent" do
19+
it "checks ancestory against all parents" do
20+
dec1 = Declaration.new("border", "#fff")
21+
dec2 = Declaration.new("border", "#fff top")
22+
dec3 = Declaration.new("border-top", "#fff", [dec1, dec2])
23+
24+
dec1.must_be :>, dec3
25+
dec2.must_be :>, dec3
26+
27+
dec1.wont_be :>, dec1
28+
dec2.wont_be :>, dec1
29+
dec1.wont_be :>, dec2
30+
dec3.wont_be :>, dec1
31+
end
32+
33+
it "is a derivative if it has parents" do
2034
dec1 = Declaration.new("background", "#fff")
2135
dec1.wont_be :derivative?
22-
Declaration.new("background-color", "#fff", dec1).must_be :derivative?
36+
Declaration.new("background-color", "#fff", [dec1]).must_be :derivative?
2337
end
2438

2539
it "ignores parents when checking equality" do
2640
dec1 = Declaration.new("background", "#fff")
27-
dec2 = Declaration.new("background-color", "#fff", dec1)
41+
dec2 = Declaration.new("background-color", "#fff", [dec1])
2842
dec3 = Declaration.new("background-color", "#fff", nil)
2943

3044
dec1.wont_equal dec2
@@ -44,7 +58,7 @@ module Csscss
4458

4559
it "derivatives are handled correctly in a hash" do
4660
dec1 = Declaration.new("background", "#fff")
47-
dec2 = Declaration.new("background-color", "#fff", dec1)
61+
dec2 = Declaration.new("background-color", "#fff", [dec1])
4862
dec3 = Declaration.new("background-color", "#fff", nil)
4963

5064
h = {}

0 commit comments

Comments
 (0)