Class: Rubydex::Linter::Rules::RuleStructure

Inherits:
CustomRule show all
Includes:
Helpers::SourceAccessHelpers
Defined in:
lib/rubydex_linter/rules/rule_structure.rb

Overview

Ensures discovered workspace linter rules follow these conventions:

  • A rule file does not define more than one linter rule.
  • Each rule subclass outside a test directory is in a rule directory.
  • Each checked rule subclass is in the Rubydex::Linter::Rules namespace.

The rule directories are rubydex_linter/rules/ and lib/rubydex_linter/rules/, including lib/rubydex_linter/rules/ directories in nested gems. This rule does not report files in those directories that define no rule subclass.

Constant Summary collapse

BASE_RULE_NAME =

: String

"Rubydex::Linter::CustomRule"
RULE_NAMESPACE =

: String

"Rubydex::Linter::Rules"
RULE_FILE_PATTERNS =
[
  "rubydex_linter/rules/**/*.rb",
  "**/lib/rubydex_linter/rules/**/*.rb",
].freeze
TEST_FILE_PATTERNS =

: Array

["test/**/*", "**/test/**/*"].freeze

Instance Attribute Summary

Attributes inherited from CustomRule

#config, #diagnostics, #graph

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers::SourceAccessHelpers

#file_location, #path_for_uri

Methods inherited from CustomRule

#child_classes, #diagnostic_location, #initialize, #required_method, #required_namespace, #rule_name

Methods inherited from Rule

rule_name, severity

Constructor Details

This class inherits a constructor from Rubydex::Linter::CustomRule

Class Method Details

.default_severityObject

: -> singleton(Severity::Base)



29
30
31
# File 'lib/rubydex_linter/rules/rule_structure.rb', line 29

def default_severity
  Severity::Error
end

Instance Method Details

#lintObject

: -> void



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/rubydex_linter/rules/rule_structure.rb', line 36

def lint
  rules = child_classes(BASE_RULE_NAME)
  rule_definitions_by_file = {} #: Hash[String, Hash[Rubydex::Class, Definition]]


  rules.each do |rule|
    rule_docs = []

    rule.definitions.each do |rule_definition|
      uri = rule_definition.document.uri
      path = path_for_uri(uri)
      next unless path_in_workspace?(path)

      if rule_file?(path)
        rule_definitions = (rule_definitions_by_file[uri] ||= {}) #: Hash[Rubydex::Class, Definition]

        rule_definitions[rule] ||= rule_definition
      elsif !test_file?(path)
        report_wrong_rule_directory(rule.name, rule_definition)
      end

      rule_docs.concat(rule_definition.comments)
    end

    rule_definition = rule.definitions.find do |definition|
      path = path_for_uri(definition.document.uri)
      path_in_workspace?(path) && (rule_file?(path) || !test_file?(path))
    end
    next unless rule_definition

    rule_name = rule.name

    if rule_docs.empty?
      add_diagnostic(
        "`#{rule_name}` is missing documentation.",
        diagnostic_location(rule_definition),
      )
    end

    next if rule_name.start_with?("#{RULE_NAMESPACE}::")

    report_wrong_rule_namespace(rule_name, rule_definition)
  end

  rule_definitions_by_file.each do |uri, rule_definitions|
    next if rule_definitions.length <= 1

    add_diagnostic(
      "Each rule file must define only one linter rule; found #{rule_definitions.length}.",
      file_location(uri),
      related_information: rule_definitions.map do |rule, rule_definition|
        RelatedInformation.new(
          "`#{rule.name}` is defined here.",
          diagnostic_location(rule_definition),
        )
      end,
    )
  end
end