# frozen_string_literal: true require 'css_parser' require 'singleton' module Cucumber module UnusedCss class Checker include Singleton def self.prepare(output_directory:) @output_directory = output_directory @used_selectors = [] @unused_selectors = [] @css_files = [] @ignored_selectors = [] @ignores = [ /^@(font-face|(-moz-|-webkit-)?keyframes)/, /^\*$/, /:active/, /:hover/, /::(before|after)/, ] end def self.ignore(list = []) @ignores += list end def self.load_css_in_page(html_string, current_url) html_page = Nokogiri::HTML(html_string) html_page.css('link[rel="stylesheet"]').each do |file_tag| if file_tag['href'].match?(/^https?:/) css_file_url = file_tag['href'] else uri = URI.parse(current_url) css_file_url = "#{uri.scheme}://#{uri.host}:#{uri.port}#{file_tag['href']}" end load_selectors css_file_url end end def self.check_selectors(page) new_used_selectors = [] @unused_selectors.each do |selector| new_used_selectors.push selector if page.has_css?(selector, wait: 0) end # Add newly used selectors @used_selectors += new_used_selectors # Remove from unused list @unused_selectors -= new_used_selectors end def self.save_and_summarize @unused_selectors.sort! @used_selectors.sort! @ignored_selectors.sort! write_files summarize end class << self attr_reader :unused_selectors, :used_selectors, :ignored_selectors private def load_selectors(url) return if @css_files.include? url parser = CssParser::Parser.new parser.load_uri! url parser.each_selector do |selector| # Ignore some CSS directive that are not selectors if ignore? selector @ignored_selectors.push selector next end @unused_selectors.push(selector) unless @used_selectors.include?(selector) || @unused_selectors.include?(selector) end @css_files.push url end def ignore?(selector) @ignores.each do |regexp| return true if selector.match? regexp end false end def write_files File.write @output_directory.join('css_unused_selectors.yml'), @unused_selectors.to_yaml File.write @output_directory.join('css_used_selectors.yml'), @used_selectors.to_yaml File.write @output_directory.join('css_ignored_selectors.yml'), @ignored_selectors.to_yaml end def summarize puts "\nCSS selectors summary" puts '---------------------' puts " > Ignored selectors: #{@ignored_selectors.count}" puts " > Used selectors: #{@used_selectors.count}" puts " > Unused selectors: #{@unused_selectors.count}" puts " > Total selectors: #{@used_selectors.count + @unused_selectors.count + @ignored_selectors.count}" puts "\nLists saved in tmp as css_*.yml" end end end end end