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
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Tags
7
+ module MissingYield
8
+ # Parses validator output into structured offense hashes.
9
+ # @example Output format (one offense per line)
10
+ # # "path/to/file.rb:10: ClassName#method_name"
11
+ class Parser < ::Yard::Lint::Parsers::Base
12
+ # @return [Regexp] parses "file:line: element" collector output lines
13
+ LINE_REGEX = /^(.+):(\d+): (.+)$/.freeze
14
+
15
+ # @param validator_output [String] raw collector output
16
+ # @param config [Yard::Lint::Config, nil] configuration (unused)
17
+ # @return [Array<Hash>] parsed offense hashes
18
+ def call(validator_output, config: nil)
19
+ validator_output
20
+ .split("\n")
21
+ .map(&:strip)
22
+ .reject(&:empty?)
23
+ .filter_map do |line|
24
+ match = line.match(LINE_REGEX)
25
+ next unless match
26
+
27
+ {
28
+ location: match[1],
29
+ line: match[2].to_i,
30
+ element: match[3]
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Tags
7
+ module MissingYield
8
+ # Result object for missing yield tag validation
9
+ class Result < Results::Base
10
+ self.default_severity = 'warning'
11
+ self.offense_type = 'line'
12
+ self.offense_name = 'MissingYield'
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
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Tags
7
+ module MissingYield
8
+ # Detects methods that call `yield` but lack @yield/@yieldparam/@yieldreturn documentation
9
+ class Validator < Base
10
+ # Enable in-process execution with all visibility (private methods can yield too)
11
+ in_process visibility: :all
12
+
13
+ # Matches the `yield` keyword. The negative lookbehind `(?<![:.])`
14
+ # prevents matching method calls like `Fiber.yield` or `yielder.yield`
15
+ # and symbol literals like `:yield`. Word boundaries ensure `yield_self`
16
+ # and similar identifiers are not matched.
17
+ # Known limitation: `yield` inside regex literals (e.g. /yield/) is
18
+ # not stripped before scanning; it is rare enough to be acceptable.
19
+ YIELD_PATTERN = /(?<![:.])\byield\b/.freeze
20
+
21
+ # @return [Regexp] matches full-line Ruby comments
22
+ COMMENT_LINE_PATTERN = /\A\s*#/.freeze
23
+
24
+ # Matches simple single- and double-quoted string literals to strip before
25
+ # scanning for the yield keyword, reducing false positives from strings
26
+ # that contain the word "yield".
27
+ STRING_LITERAL_PATTERN = /("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/.freeze
28
+
29
+ # Matches user-written @yield, @yieldparam, or @yieldreturn tags in raw
30
+ # docstring text. YARD infers @yield automatically for bare `yield expr`
31
+ # statements and adds it to object.tags(), so we check docstring.all (the
32
+ # raw source text) rather than the parsed tag list to avoid counting
33
+ # YARD-inferred tags as explicit documentation.
34
+ YIELD_TAG_PATTERN = /^\s*@yield(?:param|return)?(?:\s|$)/.freeze
35
+
36
+ # Execute query for a single object during in-process execution.
37
+ # Flags methods that yield without a @yield, @yieldparam, or @yieldreturn tag.
38
+ # @param object [YARD::CodeObjects::Base] the code object to query
39
+ # @param collector [Executor::ResultCollector] collector for output
40
+ # @return [void]
41
+ def in_process_query(object, collector)
42
+ return unless object.type == :method
43
+ return if object.is_alias?
44
+ return unless object.is_explicit?
45
+ return unless object.source
46
+ return if yield_documented?(object)
47
+ return unless source_contains_yield?(object.source)
48
+
49
+ collector.puts "#{object.file}:#{object.line}: #{object.title}"
50
+ end
51
+
52
+ private
53
+
54
+ # @param object [YARD::CodeObjects::MethodObject] the method to check
55
+ # @return [Boolean] true if the user explicitly wrote a yield-related tag
56
+ def yield_documented?(object)
57
+ object.docstring.all.match?(YIELD_TAG_PATTERN)
58
+ end
59
+
60
+ # @param source [String] raw method source code
61
+ # @return [Boolean] true if the source contains the `yield` keyword
62
+ def source_contains_yield?(source)
63
+ source.each_line.any? do |line|
64
+ next false if line.match?(COMMENT_LINE_PATTERN)
65
+
66
+ sanitized = line.gsub(STRING_LITERAL_PATTERN, '""')
67
+ sanitized = sanitized.sub(/#.*$/, '')
68
+ sanitized.match?(YIELD_PATTERN)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Tags
7
+ # MissingYield validator
8
+ #
9
+ # Detects methods that call `yield` in their body but do not document
10
+ # the block with a `@yield`, `@yieldparam`, or `@yieldreturn` tag.
11
+ # Callers need to know a method yields so they can pass a block;
12
+ # undocumented yield is a silent API contract that only source readers discover.
13
+ #
14
+ # This validator is disabled by default (opt-in).
15
+ #
16
+ # @note Does not flag the inverse case (has `@yield` tag but no actual
17
+ # `yield` in source) - that is intentional for abstract/overridable methods.
18
+ #
19
+ # @note Known limitation: `yield` appearing inside heredoc bodies or
20
+ # multi-line string literals may produce false positives. These cases
21
+ # are rare enough in practice that the validator does not attempt to
22
+ # handle them.
23
+ #
24
+ # @example Bad - method yields but block is undocumented
25
+ # # Iterates over items
26
+ # # @param items [Array] the items
27
+ # def each(items)
28
+ # items.each { |item| yield item }
29
+ # end
30
+ #
31
+ # @example Good - block documented with @yield
32
+ # # Iterates over items
33
+ # # @param items [Array] the items
34
+ # # @yield [item] each item in the collection
35
+ # def each(items)
36
+ # items.each { |item| yield item }
37
+ # end
38
+ #
39
+ # @example Good - block documented with @yieldparam
40
+ # # @param items [Array] the items
41
+ # # @yieldparam item [Object] each item
42
+ # def each(items)
43
+ # items.each { |item| yield item }
44
+ # end
45
+ #
46
+ # ## Configuration
47
+ #
48
+ # Tags/MissingYield:
49
+ # Enabled: true
50
+ # Severity: warning
51
+ module MissingYield
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -64,7 +64,8 @@ module Yard
64
64
  # @param low_value_verbs [Array<String>] low-value verbs
65
65
  # @param patterns [Hash] enabled pattern flags
66
66
  # @return [String, nil] pattern type or nil
67
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/ParameterLists
67
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
68
+ # rubocop:disable Metrics/AbcSize, Metrics/ParameterLists
68
69
  def detect_pattern(param_name, description, type_name, word_count, articles, generic_terms, connectors, low_value_verbs, patterns)
69
70
  desc_parts = description.split
70
71
  articles_re = /^(#{articles.join('|')})/i
@@ -136,7 +137,8 @@ module Yard
136
137
 
137
138
  nil
138
139
  end
139
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/ParameterLists
140
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
141
+ # rubocop:enable Metrics/AbcSize, Metrics/ParameterLists
140
142
 
141
143
  private
142
144
 
@@ -68,7 +68,8 @@ module Yard
68
68
  # end
69
69
  #
70
70
  # @example Good - Long, meaningful descriptions with context
71
- # # @param date [Date, nil] the date that can describe the event starting information or nil if event did not yet start
71
+ # # @param date [Date, nil] the date describing when the event starts,
72
+ # # or nil if the event has not yet started
72
73
  # # @param user [User] the user who initiated the request and will receive notifications
73
74
  # # @param data [Hash] configuration options for the API endpoint including timeout and retry settings
74
75
  # def configure(date, user, data)
@@ -8,8 +8,7 @@ module Yard
8
8
  #
9
9
  # Validates YARD type syntax using YARD's TypesExplainer::Parser. This
10
10
  # validator ensures that type annotations can be properly parsed by YARD
11
- # and follow YARD's type specification format. This validator is enabled
12
- # by default.
11
+ # and follow YARD's type specification format. This validator is enabled by default.
13
12
  #
14
13
  # @example Bad - Invalid type syntax that YARD cannot parse
15
14
  # # @param data [{String, Integer}] invalid hash syntax
@@ -9,8 +9,7 @@ module Yard
9
9
  #
10
10
  # Detects duplicate `@param` tags for the same parameter name. If a parameter
11
11
  # is documented multiple times, it's unclear which documentation is correct
12
- # and can confuse both readers and YARD's parser. This validator is enabled
13
- # by default.
12
+ # and can confuse both readers and YARD's parser. This validator is enabled by default.
14
13
  #
15
14
  # @example Bad - Duplicate @param tags
16
15
  # # @param name [String] the name
@@ -9,8 +9,7 @@ module Yard
9
9
  #
10
10
  # Detects malformed YARD directive syntax. Directives have specific format
11
11
  # requirements (like `@!attribute [r] name` for read-only attributes), and
12
- # this validator ensures those requirements are met. This validator is
13
- # enabled by default.
12
+ # this validator ensures those requirements are met. This validator is enabled by default.
14
13
  #
15
14
  # @example Bad - Malformed directive syntax
16
15
  # # @!attribute name missing brackets
@@ -3,6 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  # @return [String] version of the YARD Lint gem
6
- VERSION = '1.5.2'
6
+ VERSION = '1.6.0'
7
7
  end
8
8
  end
data/lib/yard/lint.rb CHANGED
@@ -23,18 +23,28 @@ module Yard
23
23
  # @param diff [Hash, nil] diff mode options
24
24
  # - :mode [Symbol] one of :ref, :staged, :changed
25
25
  # - :base_ref [String, nil] base ref for :ref mode (auto-detects main/master if nil)
26
+ # @param source [String, nil] in-memory source content; when given, the file is not
27
+ # read from disk — `path` must be a single .rb file path (used for config/exclusion
28
+ # resolution and offense location reporting only)
26
29
  # @return [Yard::Lint::Result] result object with offenses
27
- def run(path:, config: nil, config_file: nil, progress: nil, diff: nil)
30
+ def run(path:, config: nil, config_file: nil, progress: nil, diff: nil, source: nil)
31
+ if source
32
+ raise ArgumentError, '`source:` requires `path:` to be a single .rb file, not a directory or glob' \
33
+ if path.is_a?(Array) || path.to_s.include?('*') || File.directory?(path.to_s)
34
+ end
35
+
28
36
  config ||= load_config(config_file)
29
37
 
30
- # Determine files to lint based on diff mode or normal path expansion
31
- files = if diff
38
+ # Determine files to lint based on source, diff mode, or normal path expansion
39
+ files = if source
40
+ [File.expand_path(path)]
41
+ elsif diff
32
42
  get_diff_files(diff, path, config)
33
43
  else
34
44
  expand_path(path, config)
35
45
  end
36
46
 
37
- runner = Runner.new(files, config)
47
+ runner = Runner.new(files, config, source: source)
38
48
 
39
49
  # Enable progress by default if output is a TTY
40
50
  show_progress = progress.nil? ? $stdout.tty? : progress
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yard-lint
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld
@@ -91,6 +91,12 @@ files:
91
91
  - lib/yard/lint/validators/documentation/empty_comment_line/parser.rb
92
92
  - lib/yard/lint/validators/documentation/empty_comment_line/result.rb
93
93
  - lib/yard/lint/validators/documentation/empty_comment_line/validator.rb
94
+ - lib/yard/lint/validators/documentation/line_length.rb
95
+ - lib/yard/lint/validators/documentation/line_length/config.rb
96
+ - lib/yard/lint/validators/documentation/line_length/messages_builder.rb
97
+ - lib/yard/lint/validators/documentation/line_length/parser.rb
98
+ - lib/yard/lint/validators/documentation/line_length/result.rb
99
+ - lib/yard/lint/validators/documentation/line_length/validator.rb
94
100
  - lib/yard/lint/validators/documentation/markdown_syntax.rb
95
101
  - lib/yard/lint/validators/documentation/markdown_syntax/config.rb
96
102
  - lib/yard/lint/validators/documentation/markdown_syntax/messages_builder.rb
@@ -103,6 +109,18 @@ files:
103
109
  - lib/yard/lint/validators/documentation/missing_return/parser.rb
104
110
  - lib/yard/lint/validators/documentation/missing_return/result.rb
105
111
  - lib/yard/lint/validators/documentation/missing_return/validator.rb
112
+ - lib/yard/lint/validators/documentation/orphaned_doc_comment.rb
113
+ - lib/yard/lint/validators/documentation/orphaned_doc_comment/config.rb
114
+ - lib/yard/lint/validators/documentation/orphaned_doc_comment/messages_builder.rb
115
+ - lib/yard/lint/validators/documentation/orphaned_doc_comment/parser.rb
116
+ - lib/yard/lint/validators/documentation/orphaned_doc_comment/result.rb
117
+ - lib/yard/lint/validators/documentation/orphaned_doc_comment/validator.rb
118
+ - lib/yard/lint/validators/documentation/text_substitution.rb
119
+ - lib/yard/lint/validators/documentation/text_substitution/config.rb
120
+ - lib/yard/lint/validators/documentation/text_substitution/messages_builder.rb
121
+ - lib/yard/lint/validators/documentation/text_substitution/parser.rb
122
+ - lib/yard/lint/validators/documentation/text_substitution/result.rb
123
+ - lib/yard/lint/validators/documentation/text_substitution/validator.rb
106
124
  - lib/yard/lint/validators/documentation/undocumented_boolean_methods.rb
107
125
  - lib/yard/lint/validators/documentation/undocumented_boolean_methods/config.rb
108
126
  - lib/yard/lint/validators/documentation/undocumented_boolean_methods/parser.rb
@@ -181,6 +199,12 @@ files:
181
199
  - lib/yard/lint/validators/tags/meaningless_tag/parser.rb
182
200
  - lib/yard/lint/validators/tags/meaningless_tag/result.rb
183
201
  - lib/yard/lint/validators/tags/meaningless_tag/validator.rb
202
+ - lib/yard/lint/validators/tags/missing_yield.rb
203
+ - lib/yard/lint/validators/tags/missing_yield/config.rb
204
+ - lib/yard/lint/validators/tags/missing_yield/messages_builder.rb
205
+ - lib/yard/lint/validators/tags/missing_yield/parser.rb
206
+ - lib/yard/lint/validators/tags/missing_yield/result.rb
207
+ - lib/yard/lint/validators/tags/missing_yield/validator.rb
184
208
  - lib/yard/lint/validators/tags/non_ascii_type.rb
185
209
  - lib/yard/lint/validators/tags/non_ascii_type/config.rb
186
210
  - lib/yard/lint/validators/tags/non_ascii_type/messages_builder.rb