# Nick's web site: css_clean_selectors filter. Remove unnecessary whitespace # from CSS selectors as this improves compatibility with old versions of IE. # # Copyright © 2020 Nick Bowler # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . class CssCleanSelectorsFilter < Nanoc::Filter identifier :css_clean_selectors require 'crass' def run(content, params = {}) tree = Crass.parse(content, params) queue = Array.new(tree) while i = queue.shift do if i[:node] == :at_rule case i[:name] when "media", "supports" # Re-parse the block as a list of rules. s = Crass::Parser.stringify(i[:block]) i[:block] = Crass::Parser.parse_rules(s, params) queue += i[:block] end end if i[:selector] ts = i[:selector][:tokens] ts.each_index do |i| next if ts[i].nil? or ts[i][:node] != :delim next if ts[i][:value] == '*' if ts[i-1] # keep whitespace before class selectors next if ts[i][:value] == '.' and ts[i-1][:node] == :whitespace end ts[i-1] = nil if ts[i-1] and ts[i-1][:node] == :whitespace ts[i+1] = nil if ts[i+1] and ts[i+1][:node] == :whitespace end end end return Crass::Parser.stringify(tree) end end