lib/csscss/redundancy_analyzer.rb in csscss-0.0.1 vs lib/csscss/redundancy_analyzer.rb in csscss-0.1.0
- old
+ new
@@ -3,23 +3,48 @@
def initialize(raw_css)
@raw_css = raw_css
end
def redundancies(minimum = nil)
- rule_sets = CSSPool.CSS(@raw_css).rule_sets
+ rule_sets = Parser::Css.parse(@raw_css)
matches = {}
+ parents = {}
rule_sets.each do |rule_set|
rule_set.declarations.each do |dec|
- dec.property.downcase!
- dec.expressions do |exp|
- exp.value.downcase!
+ sel = rule_set.selectors
+
+ if parser = shorthand_parser(dec.property)
+ if new_decs = parser.parse(dec.property, dec.value)
+ if dec.property == "border"
+ %w(border-top border-right border-bottom border-left).each do |property|
+ border_dec = Declaration.new(property, dec.value)
+ parents[border_dec] ||= []
+ (parents[border_dec] << dec).uniq!
+ border_dec.parents = parents[border_dec]
+
+ matches[border_dec] ||= []
+ matches[border_dec] << sel
+ matches[border_dec].uniq!
+ end
+ end
+
+ new_decs.each do |new_dec|
+ # replace any non-derivatives with derivatives
+ existing = matches.delete(new_dec) || []
+ existing << sel
+ parents[new_dec] ||= []
+ (parents[new_dec] << dec).uniq!
+ new_dec.parents = parents[new_dec]
+ matches[new_dec] = existing
+ matches[new_dec].uniq!
+ end
+ end
end
- dec_key = Declaration.from_csspool(dec)
- sel = Selector.new(rule_set.selectors.map(&:to_s))
- matches[dec_key] ||= []
- matches[dec_key] << sel
+ matches[dec] ||= []
+ matches[dec] << sel
+ matches[dec].uniq!
end
end
inverted_matches = {}
matches.each do |declaration, selector_groups|
@@ -29,16 +54,39 @@
inverted_matches[two_selectors] << declaration
end
end
end
+
+ # trims any derivative declarations alongside shorthand
+ inverted_matches.each do |selectors, declarations|
+ redundant_derivatives = declarations.select do |dec|
+ dec.derivative? && declarations.detect {|dec2| dec2 > dec }
+ end
+ unless redundant_derivatives.empty?
+ inverted_matches[selectors] = declarations - redundant_derivatives
+ end
+
+ # border needs to be reduced even more
+ %w(width style color).each do |property|
+ decs = inverted_matches[selectors].select do |dec|
+ dec.derivative? && dec.property =~ /border-\w+-#{property}/
+ end
+ if decs.size == 4 && decs.map(&:value).uniq.size == 1
+ inverted_matches[selectors] -= decs
+ inverted_matches[selectors] << Declaration.new("border-#{property}", decs.first.value)
+ end
+ end
+ end
+
if minimum
inverted_matches.delete_if do |key, declarations|
declarations.size < minimum
end
end
+ # combines selector keys by common declarations
final_inverted_matches = inverted_matches.dup
inverted_matches.to_a[0..-2].each_with_index do |(selector_group1, declarations1), index|
inverted_matches.to_a[(index + 1)..-1].each do |selector_group2, declarations2|
if declarations1 == declarations2
final_inverted_matches.delete(selector_group1)
@@ -48,14 +96,33 @@
final_inverted_matches[key].concat(declarations1 + declarations2).uniq!
end
end
end
+ # sort hash by number of matches
sorted_array = final_inverted_matches.sort {|(_, v1), (_, v2)| v2.size <=> v1.size }
{}.tap do |sorted_hash|
sorted_array.each do |key, value|
sorted_hash[key.sort] = value.sort
end
+ end
+ end
+
+ private
+ def shorthand_parser(property)
+ case property
+ when "background" then Parser::Background
+ when "list-style" then Parser::ListStyle
+ when "margin" then Parser::Margin
+ when "padding" then Parser::Padding
+ when "border" then Parser::Border
+ when "border-width" then Parser::BorderWidth
+ when "border-style" then Parser::BorderStyle
+ when "border-color" then Parser::BorderColor
+ when "outline" then Parser::Outline
+ when "font" then Parser::Font
+ when "border-top", "border-right", "border-bottom", "border-left"
+ Parser::BorderSide
end
end
end
end