lib/scss_lint/linter/name_format.rb in scss-lint-0.19.0 vs lib/scss_lint/linter/name_format.rb in scss-lint-0.20.0

- old
+ new

@@ -3,40 +3,38 @@ # lowercase and use hyphens instead of underscores. class Linter::NameFormat < Linter include LinterRegistry def visit_extend(node) - if selector_has_bad_placeholder?(node.selector) - add_name_lint(node, node.selector.join, 'placeholder') - end + check_placeholder(node) end def visit_function(node) - check_declared_name(node, 'function') + check_name(node, 'function') yield # Continue into content block of this function definition end def visit_mixin(node) - check_name_use(node, 'mixin') + check_name(node, 'mixin') yield # Continue into content block of this mixin's block end def visit_mixindef(node) - check_declared_name(node, 'mixin') + check_name(node, 'mixin') yield # Continue into content block of this mixin definition end def visit_script_funcall(node) - check_name_use(node, 'function') unless FUNCTION_WHITELIST.include?(node.name) + check_name(node, 'function') unless FUNCTION_WHITELIST.include?(node.name) end def visit_script_variable(node) - check_name_use(node, 'variable') + check_name(node, 'variable') end def visit_variable(node) - check_declared_name(node, 'variable') + check_name(node, 'variable') yield # Continue into expression tree for this variable definition end private @@ -45,34 +43,42 @@ scaleX scaleY scaleZ skewX skewY translateX translateY translateZ ].to_set - def check_declared_name(node, node_type) - if node_has_bad_name?(node) - fixed_name = node.name.downcase.gsub(/_/, '-') - - add_lint(node, "Name of #{node_type} `#{node.name}` should " << - "be written in lowercase as `#{fixed_name}`") + def check_name(node, node_type, node_text = node.name) + if convention = violated_convention(node_text) + add_lint(node, "Name of #{node_type} `#{node_text}` should be " << + "written #{convention[:explanation]}") end end - def check_name_use(node, node_type) - add_name_lint(node, node.name, node_type) if node_has_bad_name?(node) + def check_placeholder(node) + extract_string_selectors(node.selector).any? do |selector_str| + check_name(node, 'placeholder', selector_str.gsub('%', '')) + end end - def add_name_lint(node, name, node_type) - fixed_name = name.downcase.gsub(/_/, '-') + CONVENTIONS = { + 'hyphenated_lowercase' => { + explanation: 'in lowercase with hyphens instead of underscores', + validator: ->(name) { name !~ /[_A-Z]/ }, + }, + 'BEM' => { + explanation: 'in BEM (Block Element Modifier) format', + validator: ->(name) { name !~ /[A-Z]|-{3}|_{3}|[^_]_[^_]/ }, + }, + } - add_lint(node, "All uses of #{node_type} `#{name}` should be written " << - "in lowercase as `#{fixed_name}`") - end + # Checks the given name and returns the violated convention if it failed. + def violated_convention(name_string) + convention_name = config['convention'] || 'hyphenated_lowercase' - # Given a selector array, returns whether it contains any placeholder - # selectors with invalid names. - def selector_has_bad_placeholder?(selector_array) - extract_string_selectors(selector_array).any? do |selector_str| - selector_str =~ /%\w*#{INVALID_NAME_CHARS}/ - end + convention = CONVENTIONS[convention_name] || { + explanation: "must match regex /#{convention_name}/", + validator: ->(name) { name =~ /#{convention_name}/ } + } + + convention unless convention[:validator].call(name_string) end end end