yard-lint 1.5.2 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -2
  3. data/README.md +165 -7
  4. data/bin/yard-lint +45 -11
  5. data/lib/yard/lint/executor/in_process_registry.rb +38 -12
  6. data/lib/yard/lint/results/base.rb +3 -0
  7. data/lib/yard/lint/runner.rb +4 -2
  8. data/lib/yard/lint/templates/default_config.yml +40 -0
  9. data/lib/yard/lint/templates/strict_config.yml +39 -0
  10. data/lib/yard/lint/validators/base.rb +107 -1
  11. data/lib/yard/lint/validators/documentation/line_length/config.rb +21 -0
  12. data/lib/yard/lint/validators/documentation/line_length/messages_builder.rb +26 -0
  13. data/lib/yard/lint/validators/documentation/line_length/parser.rb +65 -0
  14. data/lib/yard/lint/validators/documentation/line_length/result.rb +26 -0
  15. data/lib/yard/lint/validators/documentation/line_length/validator.rb +59 -0
  16. data/lib/yard/lint/validators/documentation/line_length.rb +43 -0
  17. data/lib/yard/lint/validators/documentation/missing_return/config.rb +2 -1
  18. data/lib/yard/lint/validators/documentation/missing_return/parser.rb +0 -1
  19. data/lib/yard/lint/validators/documentation/missing_return/validator.rb +1 -0
  20. data/lib/yard/lint/validators/documentation/orphaned_doc_comment/config.rb +20 -0
  21. data/lib/yard/lint/validators/documentation/orphaned_doc_comment/messages_builder.rb +23 -0
  22. data/lib/yard/lint/validators/documentation/orphaned_doc_comment/parser.rb +38 -0
  23. data/lib/yard/lint/validators/documentation/orphaned_doc_comment/result.rb +24 -0
  24. data/lib/yard/lint/validators/documentation/orphaned_doc_comment/validator.rb +121 -0
  25. data/lib/yard/lint/validators/documentation/orphaned_doc_comment.rb +53 -0
  26. data/lib/yard/lint/validators/documentation/text_substitution/config.rb +24 -0
  27. data/lib/yard/lint/validators/documentation/text_substitution/messages_builder.rb +33 -0
  28. data/lib/yard/lint/validators/documentation/text_substitution/parser.rb +57 -0
  29. data/lib/yard/lint/validators/documentation/text_substitution/result.rb +24 -0
  30. data/lib/yard/lint/validators/documentation/text_substitution/validator.rb +72 -0
  31. data/lib/yard/lint/validators/documentation/text_substitution.rb +55 -0
  32. data/lib/yard/lint/validators/documentation/undocumented_boolean_methods/config.rb +2 -1
  33. data/lib/yard/lint/validators/documentation/undocumented_boolean_methods/validator.rb +1 -0
  34. data/lib/yard/lint/validators/documentation/undocumented_method_arguments/config.rb +3 -1
  35. data/lib/yard/lint/validators/documentation/undocumented_method_arguments/validator.rb +3 -1
  36. data/lib/yard/lint/validators/documentation/undocumented_method_arguments.rb +1 -2
  37. data/lib/yard/lint/validators/documentation/undocumented_objects/config.rb +2 -1
  38. data/lib/yard/lint/validators/documentation/undocumented_objects/validator.rb +1 -0
  39. data/lib/yard/lint/validators/documentation/undocumented_options/config.rb +2 -1
  40. data/lib/yard/lint/validators/documentation/undocumented_options/validator.rb +1 -0
  41. data/lib/yard/lint/validators/documentation/undocumented_options.rb +1 -2
  42. data/lib/yard/lint/validators/tags/api_tags/result.rb +1 -0
  43. data/lib/yard/lint/validators/tags/api_tags/validator.rb +1 -1
  44. data/lib/yard/lint/validators/tags/example_style/result.rb +1 -0
  45. data/lib/yard/lint/validators/tags/example_syntax/result.rb +1 -0
  46. data/lib/yard/lint/validators/tags/invalid_types/validator.rb +1 -1
  47. data/lib/yard/lint/validators/tags/meaningless_tag/validator.rb +1 -1
  48. data/lib/yard/lint/validators/tags/missing_yield/config.rb +20 -0
  49. data/lib/yard/lint/validators/tags/missing_yield/messages_builder.rb +22 -0
  50. data/lib/yard/lint/validators/tags/missing_yield/parser.rb +39 -0
  51. data/lib/yard/lint/validators/tags/missing_yield/result.rb +24 -0
  52. data/lib/yard/lint/validators/tags/missing_yield/validator.rb +76 -0
  53. data/lib/yard/lint/validators/tags/missing_yield.rb +56 -0
  54. data/lib/yard/lint/validators/tags/redundant_param_description/validator.rb +4 -2
  55. data/lib/yard/lint/validators/tags/redundant_param_description.rb +2 -1
  56. data/lib/yard/lint/validators/tags/type_syntax.rb +1 -2
  57. data/lib/yard/lint/validators/warnings/duplicated_parameter_name.rb +1 -2
  58. data/lib/yard/lint/validators/warnings/invalid_directive_format.rb +1 -2
  59. data/lib/yard/lint/version.rb +1 -1
  60. data/lib/yard/lint.rb +14 -4
  61. metadata +25 -1
@@ -40,21 +40,34 @@ Documentation/UndocumentedObjects:
40
40
  ExcludedMethods:
41
41
  - 'initialize/0' # Exclude parameter-less initialize
42
42
  - '/^_/' # Exclude private methods (by convention)
43
+ # AllowedParentClasses:
44
+ # - StandardError # Skip error subclasses
45
+ # - ApplicationRecord # Skip Rails model subclasses
43
46
 
44
47
  Documentation/UndocumentedMethodArguments:
45
48
  Description: 'Checks for method parameters without @param tags.'
46
49
  Enabled: true
47
50
  Severity: error
51
+ # AllowedParentClasses:
52
+ # - StandardError
53
+ # AllowedMethods: skip @param checks for specific methods (exact name, name/arity, /regex/)
54
+ # - call
55
+ # - perform
56
+ # - initialize/1
48
57
 
49
58
  Documentation/UndocumentedBooleanMethods:
50
59
  Description: 'Checks that question mark methods document their boolean return.'
51
60
  Enabled: true
52
61
  Severity: error
62
+ # AllowedParentClasses:
63
+ # - StandardError
53
64
 
54
65
  Documentation/UndocumentedOptions:
55
66
  Description: 'Detects methods with options hash parameters but no @option tags.'
56
67
  Enabled: true
57
68
  Severity: error
69
+ # AllowedParentClasses:
70
+ # - StandardError
58
71
 
59
72
  Documentation/MissingReturn:
60
73
  Description: 'Requires @return tags on all methods (opt-in for strict documentation).'
@@ -63,6 +76,13 @@ Documentation/MissingReturn:
63
76
  ExcludedMethods:
64
77
  - 'initialize' # Exclude all initialize methods
65
78
  # - '/^_/' # Uncomment to exclude private methods (by convention)
79
+ # AllowedParentClasses:
80
+ # - StandardError
81
+
82
+ Documentation/OrphanedDocComment:
83
+ Description: 'Detects YARD comment blocks with tags not attached to any documentable construct.'
84
+ Enabled: true # Enabled in strict mode
85
+ Severity: error
66
86
 
67
87
  Documentation/MarkdownSyntax:
68
88
  Description: 'Detects common markdown syntax errors in documentation.'
@@ -86,6 +106,20 @@ Documentation/BlankLineBeforeDefinition:
86
106
  SingleBlankLine: true
87
107
  OrphanedDocs: true
88
108
 
109
+ Documentation/LineLength:
110
+ Description: 'Detects documentation comment lines that exceed the configured maximum length.'
111
+ Enabled: false # Opt-in validator
112
+ Severity: error
113
+ MaxLength: 120
114
+
115
+ Documentation/TextSubstitution:
116
+ Description: 'Detects forbidden characters or strings in documentation and suggests replacements.'
117
+ Enabled: true
118
+ Severity: warning
119
+ Substitutions:
120
+ "—": "-" # em-dash (U+2014)
121
+ "–": "-" # en-dash (U+2013)
122
+
89
123
  # Tags validators
90
124
  Tags/Order:
91
125
  Description: 'Enforces consistent ordering of YARD tags.'
@@ -135,6 +169,11 @@ Tags/MeaninglessTag:
135
169
  - module
136
170
  - constant
137
171
 
172
+ Tags/MissingYield:
173
+ Description: 'Detects methods that yield to a block without a @yield, @yieldparam, or @yieldreturn tag.'
174
+ Enabled: true # Enabled in strict mode
175
+ Severity: error
176
+
138
177
  Tags/CollectionType:
139
178
  Description: 'Validates Hash collection syntax consistency.'
140
179
  Enabled: true
@@ -81,7 +81,7 @@ module Yard
81
81
  # Collect tags matching the given tag names from a docstring, including
82
82
  # tags nested inside @overload blocks. YARD stores @overload inner tags
83
83
  # on the overload's own docstring, so they are invisible to
84
- # `docstring.tags` this helper traverses them.
84
+ # `docstring.tags` - this helper traverses them.
85
85
  # @param docstring [YARD::Docstring] the docstring to search
86
86
  # @param tag_names [Array<String>] tag names to collect (e.g., %w[param return])
87
87
  # @return [Array<YARD::Tags::Tag>] matching tags from the docstring and any overloads
@@ -97,6 +97,112 @@ module Yard
97
97
  tags
98
98
  end
99
99
 
100
+ # Checks whether the object's enclosing class (or the object itself if it is
101
+ # a class) has a superclass that appears in the validator's AllowedParentClasses
102
+ # configuration list. When true, validators skip the object so that classes
103
+ # inheriting from common base classes (e.g. StandardError, ApplicationRecord)
104
+ # are not flagged.
105
+ #
106
+ # Matching is done on YARD's resolved superclass path, which is always the
107
+ # fully-qualified name (e.g. "ActiveRecord::Base"). Entries in
108
+ # AllowedParentClasses are matched exactly, so callers must use the same form
109
+ # (e.g. "ActiveRecord::Base", not "Base").
110
+ #
111
+ # For method objects the enclosing namespace's superclass is checked. For
112
+ # class objects the class itself is checked. Other object types always return
113
+ # false so that modules and constants are unaffected.
114
+ #
115
+ # @param object [YARD::CodeObjects::Base] the code object to check
116
+ # @return [Boolean] true if the object should be skipped
117
+ def parent_class_allowed?(object)
118
+ allowed = Array(config_or_default('AllowedParentClasses'))
119
+ return false if allowed.empty?
120
+
121
+ klasses = case object.type
122
+ when :class
123
+ # Check the class's own superclass; also check the enclosing class's
124
+ # superclass so that nested classes and constants inside an allowed
125
+ # parent class are exempted as well.
126
+ [object, object.namespace].select { |k| k.respond_to?(:superclass) }
127
+ when :method, :constant
128
+ ns = object.namespace
129
+ ns.respond_to?(:superclass) ? [ns] : []
130
+ else
131
+ []
132
+ end
133
+
134
+ return false if klasses.empty?
135
+
136
+ klasses.any? do |klass|
137
+ superclass = klass.superclass
138
+ next false if superclass.nil?
139
+
140
+ superclass_path = superclass.respond_to?(:path) ? superclass.path.to_s : superclass.to_s
141
+ next false if superclass_path.empty?
142
+ # Every Ruby class without an explicit parent implicitly inherits from Object,
143
+ # so matching it would exempt all classes — never the intent.
144
+ # BasicObject is the root of the hierarchy and is guarded for the same reason.
145
+ next false if superclass_path == 'Object' || superclass_path == 'BasicObject'
146
+
147
+ allowed.any? { |a| superclass_path == a.to_s }
148
+ end
149
+ end
150
+
151
+ # Checks whether the method object's name matches any entry in the validator's
152
+ # AllowedMethods configuration list. When true, the validator should skip the
153
+ # object without reporting an offense.
154
+ #
155
+ # Three pattern forms are supported (matching ExcludedMethods convention):
156
+ # - Exact name: 'call' — matches any arity
157
+ # - Arity: 'initialize/1' — matches only the given parameter count
158
+ # (required + optional, excluding * and &)
159
+ # - Regex: '/^perform/' — matches against the bare method name
160
+ #
161
+ # Invalid regex patterns are silently ignored. The empty regex '//' is always
162
+ # rejected (it would match every method, making the option useless).
163
+ #
164
+ # @param object [YARD::CodeObjects::Base] the code object to check
165
+ # @return [Boolean] true if the method should be skipped
166
+ def method_allowed?(object)
167
+ return false unless object.type == :method
168
+
169
+ allowed = Array(config_or_default('AllowedMethods'))
170
+ .compact
171
+ .map { |p| p.to_s.strip }
172
+ .reject(&:empty?)
173
+ .reject { |p| p == '//' }
174
+ return false if allowed.empty?
175
+
176
+ method_name = object.name.to_s
177
+ arity = object.parameters.reject { |p| p[0].to_s.start_with?('*', '&') }.size
178
+
179
+ allowed.any? { |pattern| matches_method_pattern?(method_name, arity, pattern) }
180
+ end
181
+
182
+ # Matches a single AllowedMethods/ExcludedMethods pattern against a method.
183
+ # @param method_name [String] bare method name (e.g. "call")
184
+ # @param arity [Integer] parameter count (required + optional, no * or &)
185
+ # @param pattern [String] one entry from the AllowedMethods list
186
+ # @return [Boolean]
187
+ def matches_method_pattern?(method_name, arity, pattern)
188
+ case pattern
189
+ when %r{^/(.+)/$}
190
+ regex_str = Regexp.last_match(1)
191
+ return false if regex_str.empty?
192
+
193
+ begin
194
+ Regexp.new(regex_str).match?(method_name)
195
+ rescue RegexpError
196
+ false
197
+ end
198
+ when %r{^[^/]+/\d+$}
199
+ pattern_name, pattern_arity_str = pattern.split('/', 2)
200
+ method_name == pattern_name && arity == pattern_arity_str.to_i
201
+ else
202
+ method_name == pattern
203
+ end
204
+ end
205
+
100
206
  # Retrieves configuration value with fallback to default
101
207
  # Automatically determines the validator name from the class namespace
102
208
  #
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module LineLength
8
+ # Configuration for LineLength validator
9
+ class Config < ::Yard::Lint::Validators::Config
10
+ self.id = :line_length
11
+ self.defaults = {
12
+ 'Enabled' => false,
13
+ 'Severity' => 'convention',
14
+ 'MaxLength' => 120
15
+ }.freeze
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module LineLength
8
+ # Builds human-readable messages for LineLength violations.
9
+ class MessagesBuilder
10
+ class << self
11
+ # @param offense [Hash] offense details with :length, :object_name, and config :max_length
12
+ # @return [String] formatted message
13
+ def call(offense)
14
+ length = offense[:length]
15
+ object_name = offense[:object_name]
16
+ max_length = offense[:max_length]
17
+
18
+ "Documentation line is too long [#{length} > #{max_length}] for '#{object_name}'"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module LineLength
8
+ # Parses LineLength validator output into structured violation hashes.
9
+ #
10
+ # Expected format (two lines per object with violations):
11
+ # file.rb:OBJECT_LINE: ObjectName
12
+ # MAX_LENGTH|LINE_NO:LENGTH|LINE_NO:LENGTH|...
13
+ class Parser < Parsers::Base
14
+ # @param output [String] raw validator output
15
+ # @return [Array<Hash>] array of violation hashes
16
+ def call(output, **)
17
+ return [] if output.nil? || output.empty?
18
+
19
+ violations = []
20
+ lines = output.lines.map(&:chomp)
21
+
22
+ i = 0
23
+ while i < lines.size
24
+ line = lines[i]
25
+
26
+ if (location_match = line.match(/^(.+):(\d+): (.+)$/))
27
+ file_path = location_match[1]
28
+ object_line = location_match[2].to_i
29
+ object_name = location_match[3]
30
+
31
+ i += 1
32
+ next unless i < lines.size
33
+
34
+ parts = lines[i].split('|')
35
+ next if parts.empty?
36
+
37
+ # First token is max_length, remainder are line_no:length pairs
38
+ max_length = parts.shift.to_i
39
+
40
+ parts.each do |part|
41
+ line_no, length = part.split(':', 2)
42
+ next unless line_no && length
43
+
44
+ violations << {
45
+ location: file_path,
46
+ line: line_no.to_i,
47
+ object_line: object_line,
48
+ object_name: object_name,
49
+ length: length.to_i,
50
+ max_length: max_length
51
+ }
52
+ end
53
+ end
54
+
55
+ i += 1
56
+ end
57
+
58
+ violations
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module LineLength
8
+ # Result wrapper for LineLength validator.
9
+ class Result < Results::Base
10
+ self.default_severity = 'convention'
11
+ self.offense_type = 'line'
12
+ self.offense_name = 'LineLength'
13
+
14
+ private
15
+
16
+ # @param offense [Hash] offense details including :max_length from the validator
17
+ # @return [String] formatted message
18
+ def build_message(offense)
19
+ MessagesBuilder.call(offense)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module LineLength
8
+ # Validates that documentation comment lines do not exceed the configured maximum length.
9
+ #
10
+ # Uses YARD's `docstring.line_range` to locate the exact source lines belonging to
11
+ # each docstring block. This handles block comments, wrapped tag descriptions, and
12
+ # macro expansion correctly — no arithmetic reconstruction needed.
13
+ class Validator < Validators::Base
14
+ in_process visibility: :all
15
+
16
+ # Execute query for a single object during in-process execution.
17
+ # @param object [YARD::CodeObjects::Base] the code object to query
18
+ # @param collector [Executor::ResultCollector] collector for output
19
+ # @return [void]
20
+ def in_process_query(object, collector)
21
+ return unless object.file && File.exist?(object.file)
22
+ return if object.docstring.all.empty?
23
+
24
+ line_range = object.docstring.line_range
25
+ return unless line_range
26
+
27
+ max_length = config_or_default('MaxLength').to_i
28
+ source_lines = cached_lines(object.file)
29
+
30
+ violations = []
31
+ line_range.each do |line_no|
32
+ raw_line = source_lines[line_no - 1].to_s.rstrip
33
+ next if raw_line.length <= max_length
34
+
35
+ violations << "#{line_no}:#{raw_line.length}"
36
+ end
37
+
38
+ return if violations.empty?
39
+
40
+ collector.puts "#{object.file}:#{object.line}: #{object.title}"
41
+ collector.puts "#{max_length}|#{violations.join('|')}"
42
+ end
43
+
44
+ private
45
+
46
+ # Returns the lines of a source file, reading from disk only on the first call
47
+ # for each unique path.
48
+ # @param file [String] absolute path to the source file
49
+ # @return [Array<String>] lines of the file, memoized per path
50
+ def cached_lines(file)
51
+ @file_cache ||= {}
52
+ @file_cache[file] ||= File.readlines(file)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ # LineLength validator
8
+ #
9
+ # Detects documentation comment lines that exceed a configured maximum length.
10
+ # Only checks lines belonging to YARD docstring blocks (comment lines directly
11
+ # above a documentable Ruby construct). YARD's parsed docstring is used to
12
+ # determine which lines belong to a docstring, avoiding fragile backwards-scanning.
13
+ #
14
+ # Disabled by default — enable it and set MaxLength to taste.
15
+ #
16
+ # @example Bad - line exceeds MaxLength (120)
17
+ # # This documentation line is too long and exceeds the configured maximum length.
18
+ # def process(value)
19
+ # end
20
+ #
21
+ # @example Good - line within MaxLength
22
+ # # Process the given value.
23
+ # def process(value)
24
+ # end
25
+ #
26
+ # ## Configuration
27
+ #
28
+ # To enable with a custom limit:
29
+ #
30
+ # Documentation/LineLength:
31
+ # Enabled: true
32
+ # MaxLength: 100
33
+ #
34
+ # To disable:
35
+ #
36
+ # Documentation/LineLength:
37
+ # Enabled: false
38
+ module LineLength
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -13,7 +13,8 @@ module Yard
13
13
  'Severity' => 'warning',
14
14
  'ExcludedMethods' => [
15
15
  'initialize' # Exclude all initialize methods by default
16
- ]
16
+ ],
17
+ 'AllowedParentClasses' => []
17
18
  }.freeze
18
19
  end
19
20
  end
@@ -101,7 +101,6 @@ module Yard
101
101
 
102
102
  Regexp.new(regex_pattern).match?(method_name)
103
103
  rescue RegexpError
104
- # Invalid regex - skip this pattern
105
104
  false
106
105
  end
107
106
 
@@ -21,6 +21,7 @@ module Yard
21
21
  # Skip aliases and implicit methods
22
22
  return if object.is_alias?
23
23
  return unless object.is_explicit?
24
+ return if parent_class_allowed?(object)
24
25
 
25
26
  # Check if @return tag is missing
26
27
  return_tag = object.tag(:return)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module OrphanedDocComment
8
+ # Configuration for OrphanedDocComment validator
9
+ class Config < ::Yard::Lint::Validators::Config
10
+ self.id = :orphaned_doc_comment
11
+ self.defaults = {
12
+ 'Enabled' => true,
13
+ 'Severity' => 'warning'
14
+ }.freeze
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module OrphanedDocComment
8
+ # Builds messages for orphaned documentation comment offenses
9
+ class MessagesBuilder
10
+ class << self
11
+ # @param offense [Hash] offense data with :tags key
12
+ # @return [String] formatted message
13
+ def call(offense)
14
+ tags = Array(offense[:tags]).join(', ')
15
+ "Documentation comment with #{tags} is orphaned - YARD will ignore it"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module OrphanedDocComment
8
+ # Parses validator output into structured offense hashes.
9
+ # @example Output format (one line per orphaned block)
10
+ # # "path/to/file.rb:10: @param,@return"
11
+ class Parser < ::Yard::Lint::Parsers::Base
12
+ # @return [Regexp] parses "file:line: @tag1,@tag2" collector output lines
13
+ LINE_REGEX = /^(.+):(\d+): ([@a-z,_]+)$/.freeze
14
+
15
+ # @param validator_output [String] raw validator results string
16
+ # @return [Array<Hash>] array of orphaned comment offense hashes
17
+ def call(validator_output)
18
+ validator_output
19
+ .split("\n")
20
+ .map(&:strip)
21
+ .reject(&:empty?)
22
+ .filter_map do |line|
23
+ match = line.match(LINE_REGEX)
24
+ next unless match
25
+
26
+ {
27
+ location: match[1],
28
+ line: match[2].to_i,
29
+ tags: match[3].split(',')
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module OrphanedDocComment
8
+ # Result object for orphaned documentation comment offenses
9
+ class Result < Results::Base
10
+ self.default_severity = 'warning'
11
+ self.offense_type = 'line'
12
+ self.offense_name = 'OrphanedDocComment'
13
+
14
+ # @param offense [Hash] offense data
15
+ # @return [String] formatted message
16
+ def build_message(offense)
17
+ MessagesBuilder.call(offense)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end