Class: Rails::CssUnused::ViewScanner

Inherits:
Object
  • Object
show all
Defined in:
lib/rails/css_unused/view_scanner.rb

Overview

Scans Rails view templates, ViewComponent files, Phlex components, Stimulus controllers, and Ruby files for referenced CSS class names.

Handles:

ERB:       class="foo bar",  class: "foo",  class: ["foo", "bar"]
HAML:      .foo.bar,  %div.foo
Slim:      div.foo,  .foo
Ruby:      html_class: "foo",  css_classes("foo bar"),  "foo bar"
Stimulus:  this.element.classList.add("foo"),  "foo" string literals
Dynamic:   class="<%= cond ? 'foo' : 'bar' %>" — literal parts extracted

Constant Summary collapse

HTML_CLASS_ATTR =

── ERB / HTML patterns ──────────────────────────────────────────────class=“foo bar baz” or class=‘foo bar’

/class\s*=\s*["']([^"'<>]+)["']/i
RUBY_CLASS_KV =

class: “foo bar” or class: ‘foo’

/class:\s*["']([^"']+)["']/
RUBY_CLASS_ARRAY =

class: [“foo”, “bar”] or class: %w[foo bar]

/class:\s*(?:\[|%w\[)\s*([^\]\n]+)/
TAG_HELPER =

tag.div(class: “foo”) content_tag(:div, class: “foo”)

/(?:content_tag|tag\.\w+)\s*[({][^)}\n]*class:\s*["']([^"']+)["']/
HAML_IMPLICIT =

── HAML patterns ───────────────────────────────────────────────────.foo, %div.foo.bar, %span.foo#id

/^[ \t]*(?:%[\w:-]+)?(\.[a-zA-Z][a-zA-Z0-9_-]*(?:\.[a-zA-Z][a-zA-Z0-9_-]*)*)/
HAML_HASH_CLASS =

Inline { class: “foo” }

/class:\s*["']([^"']+)["']/
SLIM_CLASS =

── Slim patterns ───────────────────────────────────────────────────div.foo.bar or .foo.bar on its own line

/^[ \t]*(?:[\w-]*)(\.[a-zA-Z][a-zA-Z0-9_-]*(?:\.[a-zA-Z][a-zA-Z0-9_-]*)*)/
ERB_DYNAMIC_CLASS =

── ERB dynamic interpolation ────────────────────────────────────────class=“<%= expr %>”, class=“prefix-<%= var %>” — extracts static parts

/class\s*=\s*["'][^"']*<%=[^%]+%>[^"']*["']/m
JS_ADD_CLASS =

── Ruby / Stimulus string literals ─────────────────────────────────Any double-quoted string that looks like a space-separated class list Used when scan_javascript_for_classes or scan_ruby_components is on.

/(?:classList\.add|classList\.toggle|classList\.replace)\s*\(\s*["']([^"']+)["']/
JS_REMOVE_CLASS =

these ARE used

/(?:classList\.remove)\s*\(\s*["']([^"']+)["']/
RUBY_STRING_CLASSES =
/["']([a-zA-Z][a-zA-Z0-9_-]*(?:\s+[a-zA-Z][a-zA-Z0-9_-]*)*)["']/

Instance Method Summary collapse

Constructor Details

#initialize(root:, config: CssUnused.configuration) ⇒ ViewScanner

Returns a new instance of ViewScanner.



47
48
49
50
# File 'lib/rails/css_unused/view_scanner.rb', line 47

def initialize(root:, config: CssUnused.configuration)
  @root   = Pathname(root)
  @config = config
end

Instance Method Details

#used_classesObject

Returns a Set of class name strings referenced across all view files.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rails/css_unused/view_scanner.rb', line 53

def used_classes
  classes     = Set.new
  ignore_set  = @config.ignore_classes.map(&:to_s).to_set
  ignore_pats = Array(@config.ignore_patterns)

  each_view_file do |path, content|
    extract_from(content, path).each do |cls|
      next if ignore_set.include?(cls)
      next if ignore_pats.any? { |p| cls.match?(p) }
      classes << cls
    end
  end

  if @config.scan_javascript_for_classes
    each_js_file do |path, content|
      extract_js_classes(content).each { |cls| classes << cls }
    end
  end

  classes
end