Class: SCSSLint::Linter::Bliss::Module

Inherits:
SCSSLint::Linter::Bliss show all
Includes:
SCSSLint::LinterRegistry
Defined in:
lib/scss_lint/linter/bliss/module.rb

Overview

Checks that selectors in CSS Modules (github.com/gilbox/css-bliss#module) use a specified convention

Constant Summary

Constants included from Utils

Utils::COLOR_REGEX

Instance Attribute Summary

Attributes inherited from SCSSLint::Linter

#config, #engine, #lints

Instance Method Summary collapse

Methods included from SCSSLint::LinterRegistry

extract_linters_from, included

Methods inherited from SCSSLint::Linter

#initialize, #name, #run

Methods included from Utils

#color?, #color_hex?, #color_keyword?, #color_keyword_to_code, #extract_string_selectors, #node_ancestor, #node_siblings, #pluralize, #previous_node, #remove_quoted_strings, #same_position?

Methods included from SelectorVisitor

#visit_selector

Constructor Details

This class inherits a constructor from SCSSLint::Linter

Instance Method Details

#visit_attribute(attribute) ⇒ Object



26
27
28
29
30
31
# File 'lib/scss_lint/linter/bliss/module.rb', line 26

def visit_attribute(attribute)
  return if config['allow_attribute_selector_in_module']
  return unless is_module

  add_lint(attribute, 'Avoid using attribute selectors. https://github.com/gilbox/css-bliss/blob/master/solving-complexity.md#7-breaking-isolation')
end

#visit_class(klass) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/scss_lint/linter/bliss/module.rb', line 33

def visit_class(klass)
  return unless is_module

  unless config['allow_utility_classes_in_module']
    if /^[a-z]/.match(klass.name)
      unless @ignored_utility_class_prefixes.any? { |prefix| klass.name.start_with?(prefix) }
        add_lint(klass, "Class `#{klass.name}` is not allowed in the #{@module_name} module (use a module-namespaced class)")
      end
    end
  end

  if /^[A-Z]/.match(klass.name) && ! klass.name.start_with?(@module_name)
    add_lint(klass, "Class selector `#{klass.name}` is not allowed in the #{@module_name} module https://github.com/gilbox/css-bliss#encapsulation")
  end
end

#visit_element(element) ⇒ Object



49
50
51
52
53
54
# File 'lib/scss_lint/linter/bliss/module.rb', line 49

def visit_element(element)
  return if config['allow_element_selector_in_module']
  return unless is_module

  add_lint(element, 'Avoid using element selectors. https://github.com/gilbox/css-bliss/blob/master/solving-complexity.md#7-breaking-isolation')
end

#visit_id(id) ⇒ Object



56
57
58
59
60
61
# File 'lib/scss_lint/linter/bliss/module.rb', line 56

def visit_id(id)
  return if config['allow_id_selector_in_module']
  return unless is_module

  add_lint(id, 'Don\'t use id selectors in CSS Modules.')
end

#visit_prop(node) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/scss_lint/linter/bliss/module.rb', line 63

def visit_prop(node)
  return unless is_module

  if node.node_parent.rule.include?(".#{@module_name}")
    name = node.name[0]
    unless config['allow_module_margin']
      if name.start_with?('margin')
        add_lint(node, 'A module should not define it\'s own margin, instead the parent element should define padding. https://github.com/gilbox/css-bliss#module')
      end
    end

    unless config['allow_module_width']
      if name == 'width'
        value = node.value
        if value.is_a?(Sass::Script::Tree::Literal) && /\d/.match("#{value.value}") && ! ['100%', '100vw'].include?("#{value.value}")
          add_lint(node, 'A module should not define it\'s own bespoke width, it should take up the full width of it\'s parent element. https://github.com/gilbox/css-bliss#module')
        end
      end
    end
  end
end

#visit_root(_node) ⇒ Object



6
7
8
9
# File 'lib/scss_lint/linter/bliss/module.rb', line 6

def visit_root(_node)
  @ignored_utility_class_prefixes = Array(config['ignored_utility_class_prefixes']).to_set
  yield
end

#visit_rule(node) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/scss_lint/linter/bliss/module.rb', line 11

def visit_rule(node)
  return if config['allow_utility_direct_styling']
  return unless is_module

  node.parsed_rules.members.each { |rule|
    match = /(^|\s)\.([a-z]\S*)$/.match(rule.to_s)

    if match
      add_lint(node, "Class `#{match.captures[1]}` is used at the end of a descendant selector. Avoid styling utility or state classes directly from within a Module. https://github.com/gilbox/css-bliss/blob/master/solving-complexity.md#7-breaking-isolation")
    end
  }

  yield
end