yard-lint 1.9.0 → 1.10.1

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +2 -2
  4. data/lib/yard/lint/config.rb +0 -1
  5. data/lib/yard/lint/config_validator.rb +0 -2
  6. data/lib/yard/lint/templates/default_config.yml +5 -0
  7. data/lib/yard/lint/templates/strict_config.yml +5 -0
  8. data/lib/yard/lint/validators/documentation/blank_line_before_definition/validator.rb +67 -7
  9. data/lib/yard/lint/validators/documentation/duplicate_namespace_comment/config.rb +20 -0
  10. data/lib/yard/lint/validators/documentation/duplicate_namespace_comment/messages_builder.rb +51 -0
  11. data/lib/yard/lint/validators/documentation/duplicate_namespace_comment/parser.rb +44 -0
  12. data/lib/yard/lint/validators/documentation/duplicate_namespace_comment/result.rb +26 -0
  13. data/lib/yard/lint/validators/documentation/duplicate_namespace_comment/validator.rb +118 -0
  14. data/lib/yard/lint/validators/documentation/duplicate_namespace_comment.rb +50 -0
  15. data/lib/yard/lint/validators/tags/example_syntax.rb +0 -1
  16. data/lib/yard/lint/validators/tags/redundant_param_description.rb +0 -1
  17. data/lib/yard/lint/validators/warnings/duplicated_parameter_name/config.rb +0 -1
  18. data/lib/yard/lint/validators/warnings/duplicated_parameter_name.rb +0 -2
  19. data/lib/yard/lint/validators/warnings/invalid_directive_format/config.rb +0 -2
  20. data/lib/yard/lint/validators/warnings/invalid_directive_format.rb +0 -2
  21. data/lib/yard/lint/validators/warnings/invalid_tag_format/config.rb +0 -2
  22. data/lib/yard/lint/validators/warnings/invalid_tag_format.rb +0 -2
  23. data/lib/yard/lint/validators/warnings/syntax_error/config.rb +0 -2
  24. data/lib/yard/lint/validators/warnings/syntax_error.rb +0 -2
  25. data/lib/yard/lint/validators/warnings/unknown_directive/config.rb +0 -2
  26. data/lib/yard/lint/validators/warnings/unknown_directive.rb +0 -2
  27. data/lib/yard/lint/validators/warnings/unknown_parameter_name/config.rb +0 -2
  28. data/lib/yard/lint/validators/warnings/unknown_parameter_name.rb +0 -2
  29. data/lib/yard/lint/validators/warnings/unknown_tag/config.rb +0 -2
  30. data/lib/yard/lint/validators/warnings/unknown_tag.rb +0 -2
  31. data/lib/yard/lint/version.rb +1 -1
  32. data/lib/yard/lint.rb +1 -0
  33. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba0156cdfc89e9d83eb44c650fc7577e68256717646470736a1a5051d45c8830
4
- data.tar.gz: f12452f074b35d19f8edaf2fe4d4e28dcda832e0b355b500980e21e97b96c71b
3
+ metadata.gz: 0c63ea819ad85e3c0878e26d37ea3b59bb61598804d3963425ff5882931b1a22
4
+ data.tar.gz: 5b613e3ba58f6773abd4b47b23c64e94d223ddecde10a743db5de1525b0f5ec2
5
5
  SHA512:
6
- metadata.gz: 1d453260f7016fcdb0f678d22349ffd922eb941f7daec2393bde3c81798bee88669cd003134f72c8a85fc44c700953e72c10d3ca930df96b33d15efbff1cbaf9
7
- data.tar.gz: 5b0f7a4c24095a2db9d5c584029a23e2ff49dfcdd01c534ce5ac9922d2d8c5206f0137046815d5b9bfbffb3be4dff908df9409a99842db9234dd81c1471dceb6
6
+ metadata.gz: 608923c037bde8d53573ae6f7d3487d1b156ba04ae94c143675c5c5f6c541ccb6266df7acf1748e7fd54e9e3bb92942a28fd2d62d560b92b6ee6e5373f60c822
7
+ data.tar.gz: 91863e353c9be138fa4bd93db36ce4cdf85209a85863dca25f6d7c1f3a794673018946d7e8160fedf801a4c80cf7377359f675462d87c7955aaf4b80fcffa68f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 1.10.1 (2026-07-24)
2
+ - **[Bugfix]** `Documentation/BlankLineBeforeDefinition` no longer reports a foreign comment block above a definition as documentation that was accidentally detached from it. When the object is documented (non-empty docstring) but that docstring did not come from the comment block sitting above this definition, the block is not a detached docstring - it is a file-level license/copyright banner, an encoding note, or an unrelated comment above a namespace reopening whose documentation lives in another file. The check compares the object's docstring against the block's text, so it recognizes any such banner without hardcoding its wording. Definitions whose documentation was genuinely lost (an undocumented object with a comment block detached above it) are still reported.
3
+
4
+ ## 1.10.0 (2026-07-24)
5
+ - **[Feature]** Added `Documentation/DuplicateNamespaceComment` (enabled by default, severity `warning`) - detects namespaces (modules and classes) that carry a YARD documentation comment in more than one file. When a namespace is reopened across files and documented in several of them, YARD merges the reopenings into a single object and keeps only one docstring, silently discarding the rest (the last documented reopening wins, with no warning), so competing descriptions are lost. This is a common accident for shared namespaces (e.g. `Users` or `Users::Operations`) spread across many files; it does not affect a leaf object such as `Users::Operations::Create` that lives in a single file. Because YARD does not record which reopening carried a comment, the validator re-reads each definition site to detect the documented ones (ignoring blank-line-detached comments and directive/magic comments), and reports one offense per namespace documented in two or more files, listing every documented location and noting when the docstrings differ (meaning content is actually lost). Configurable via the standard `Enabled` and `Severity` keys.
6
+
1
7
  ## 1.9.0 (2026-07-01)
2
8
  - **[Breaking]** Dropped support for Ruby 3.2. The minimum required Ruby version is now 3.3.0. This change was necessary because the `parallel` gem no longer supports Ruby 3.2.
3
9
 
data/README.md CHANGED
@@ -31,7 +31,7 @@ YARD-Lint validates your YARD documentation for:
31
31
  - **Performance** - In-process YARD execution with shared registry (~10x faster than shell-based execution)
32
32
  - **Incremental Adoption** - `--auto-gen-config` generates a baseline todo file to adopt on legacy codebases without fixing everything first
33
33
 
34
- **See the complete list:** [All Features](https://github.com/mensfeld/yard-lint/wiki/Features) | [36 Validators](https://github.com/mensfeld/yard-lint/wiki/Validators)
34
+ **See the complete list:** [All Features](https://github.com/mensfeld/yard-lint/wiki/Features) | [37 Validators](https://github.com/mensfeld/yard-lint/wiki/Validators)
35
35
 
36
36
  ## Installation
37
37
 
@@ -569,7 +569,7 @@ The text formatter also shows the validator path (e.g., `[Documentation/Orphaned
569
569
  - **[Wiki Home](https://github.com/mensfeld/yard-lint/wiki)** - Full documentation
570
570
  - **[Installation](https://github.com/mensfeld/yard-lint/wiki/Installation)** - Installation guide
571
571
  - **[Configuration](https://github.com/mensfeld/yard-lint/wiki/Configuration)** - Complete configuration reference
572
- - **[Validators](https://github.com/mensfeld/yard-lint/wiki/Validators)** - All 35 validators documented
572
+ - **[Validators](https://github.com/mensfeld/yard-lint/wiki/Validators)** - All 37 validators documented
573
573
  - **[Features](https://github.com/mensfeld/yard-lint/wiki/Features)** - All features explained
574
574
 
575
575
  ### Workflows
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # YARD Lint - comprehensive linter for YARD documentation
4
3
  module Yard
5
4
  module Lint
6
5
  # Configuration object for YARD Lint
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # YARD Lint - comprehensive linter for YARD documentation
4
3
  module Yard
5
- # YARD Lint module providing linting functionality for YARD documentation
6
4
  module Lint
7
5
  # Validates configuration structure and values to catch typos and invalid settings
8
6
  class ConfigValidator
@@ -137,6 +137,11 @@ Documentation/TextSubstitution:
137
137
  "—": "-" # em-dash (U+2014)
138
138
  "–": "-" # en-dash (U+2013)
139
139
 
140
+ Documentation/DuplicateNamespaceComment:
141
+ Description: 'Detects namespaces (modules and classes) documented in more than one file.'
142
+ Enabled: true
143
+ Severity: warning
144
+
140
145
  # Tags validators
141
146
  Tags/Order:
142
147
  Description: 'Enforces consistent ordering of YARD tags.'
@@ -135,6 +135,11 @@ Documentation/TextSubstitution:
135
135
  "—": "-" # em-dash (U+2014)
136
136
  "–": "-" # en-dash (U+2013)
137
137
 
138
+ Documentation/DuplicateNamespaceComment:
139
+ Description: 'Detects namespaces (modules and classes) documented in more than one file.'
140
+ Enabled: true
141
+ Severity: error
142
+
138
143
  # Tags validators
139
144
  Tags/Order:
140
145
  Description: 'Enforces consistent ordering of YARD tags.'
@@ -21,9 +21,19 @@ module Yard
21
21
  source_lines = File.readlines(object.file)
22
22
  definition_line = object.line - 1
23
23
 
24
- blank_count, has_doc_block = analyze_spacing(source_lines, definition_line)
24
+ blank_count, doc_block_line = analyze_spacing(source_lines, definition_line)
25
25
 
26
- return if blank_count.zero? || !has_doc_block
26
+ return if blank_count.zero? || doc_block_line.nil?
27
+
28
+ # Only a comment block that is genuinely THIS object's documentation can have
29
+ # been detached from it by the blank line. When the object is documented (its
30
+ # docstring is non-empty) but that docstring did not come from the comment block
31
+ # sitting above this definition, the block is a foreign comment - a file-level
32
+ # license/copyright banner, an encoding note, or an unrelated comment above a
33
+ # namespace reopening that is documented in another file - and the blank line is
34
+ # intentional. This is decided by comparing the object's docstring against the
35
+ # block's text, so it covers any such banner without hardcoding its wording.
36
+ return if foreign_comment_block?(object, source_lines, doc_block_line)
27
37
 
28
38
  violation_type = blank_count >= 2 ? 'orphaned' : 'single'
29
39
 
@@ -38,10 +48,10 @@ module Yard
38
48
  # Analyze spacing between documentation and definition
39
49
  # @param source_lines [Array<String>] lines of source file
40
50
  # @param definition_line [Integer] 0-indexed line of definition
41
- # @return [Array<Integer, Boolean>] blank count and whether doc block exists
51
+ # @return [Array<Integer, Integer, nil>] blank count and the 0-indexed line of the
52
+ # nearest documentation comment above the definition (nil when there is none)
42
53
  def analyze_spacing(source_lines, definition_line)
43
54
  blank_count = 0
44
- has_doc_block = false
45
55
 
46
56
  (definition_line - 1).downto(0) do |i|
47
57
  line = source_lines[i].to_s.rstrip
@@ -56,15 +66,65 @@ module Yard
56
66
  # spurious blank-line offenses for undocumented definitions.
57
67
  next if non_documentation_comment?(stripped)
58
68
 
59
- has_doc_block = true
60
- break
69
+ return [blank_count, i]
61
70
  else
62
71
  # Non-comment, non-blank line - no documentation above
63
72
  break
64
73
  end
65
74
  end
66
75
 
67
- [blank_count, has_doc_block]
76
+ [blank_count, nil]
77
+ end
78
+
79
+ # Whether the comment block above the definition is NOT the source of the object's
80
+ # documentation - a file banner or an unrelated comment rather than a docstring
81
+ # this definition lost to the blank line.
82
+ #
83
+ # An object with no docstring at all has genuinely orphaned documentation, so the
84
+ # block above is still reported. When the object IS documented, the block only
85
+ # counts as detached documentation if the docstring's text actually came from it;
86
+ # a license header or a comment above a reopening documented elsewhere carries
87
+ # different text and is left alone.
88
+ # @param object [YARD::CodeObjects::Base] the code object being checked
89
+ # @param source_lines [Array<String>] lines of source file
90
+ # @param doc_line [Integer] 0-indexed line of the nearest comment above the definition
91
+ # @return [Boolean]
92
+ def foreign_comment_block?(object, source_lines, doc_line)
93
+ docstring = object.docstring.to_s.strip
94
+ return false if docstring.empty?
95
+
96
+ block = comment_block_text(source_lines, doc_line)
97
+ first_line = normalize(docstring.lines.first.to_s)
98
+ return false if first_line.empty?
99
+
100
+ !normalize(block).include?(first_line)
101
+ end
102
+
103
+ # Text of the contiguous comment block that contains `doc_line`, stripped of the
104
+ # comment markers and joined into a single string.
105
+ # @param source_lines [Array<String>] lines of source file
106
+ # @param doc_line [Integer] 0-indexed line within the comment block
107
+ # @return [String]
108
+ def comment_block_text(source_lines, doc_line)
109
+ first = doc_line
110
+ first -= 1 while first.positive? && comment_line?(source_lines[first - 1])
111
+ last = doc_line
112
+ last += 1 while last + 1 < source_lines.length && comment_line?(source_lines[last + 1])
113
+
114
+ source_lines[first..last].map { |line| line.sub(/\A\s*#+\s?/, '').strip }.join(' ')
115
+ end
116
+
117
+ # @param line [String, nil] a source line
118
+ # @return [Boolean] whether the line is a comment line
119
+ def comment_line?(line)
120
+ line.to_s.strip.start_with?('#')
121
+ end
122
+
123
+ # Collapse whitespace so wrapped docstrings and their source comments compare equal.
124
+ # @param text [String]
125
+ # @return [String]
126
+ def normalize(text)
127
+ text.strip.gsub(/\s+/, ' ')
68
128
  end
69
129
 
70
130
  # Check if a comment line is a Ruby magic comment
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module DuplicateNamespaceComment
8
+ # Configuration for DuplicateNamespaceComment validator
9
+ class Config < ::Yard::Lint::Validators::Config
10
+ self.id = :duplicate_namespace_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,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module DuplicateNamespaceComment
8
+ # Builds messages for duplicate namespace comment offenses
9
+ class MessagesBuilder
10
+ # Maximum number of documented locations listed inline in the message
11
+ MAX_LISTED_SITES = 5
12
+
13
+ class << self
14
+ # Build message for a namespace documented in multiple files
15
+ # @param offense [Hash] offense data with :namespace, :sites and :conflict keys
16
+ # @return [String] formatted message
17
+ def call(offense)
18
+ sites = Array(offense[:sites])
19
+ listed = sites.first(MAX_LISTED_SITES).map { |site| relativize(site) }
20
+ remainder = sites.size - listed.size
21
+ located = listed.join(', ')
22
+ located += " (+#{remainder} more)" if remainder.positive?
23
+
24
+ differ = offense[:conflict] == 'differ' ? ' The docstrings differ, so content is lost.' : ''
25
+
26
+ "Namespace `#{offense[:namespace]}` is documented in #{sites.size} files; " \
27
+ "YARD keeps only one docstring and discards the rest.#{differ} " \
28
+ "Documented at: #{located}. " \
29
+ 'Consolidate the documentation into a single location.'
30
+ end
31
+
32
+ private
33
+
34
+ # Shortens an absolute "path:line" site to a path relative to the working
35
+ # directory for readability, leaving already-relative paths untouched.
36
+ # @param site [String] a "path:line" location
37
+ # @return [String] a display-friendly location
38
+ def relativize(site)
39
+ path, _, line = site.rpartition(':')
40
+ return site if path.empty?
41
+
42
+ relative = path.start_with?("#{Dir.pwd}/") ? path.sub("#{Dir.pwd}/", '') : path
43
+ "#{relative}:#{line}"
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module DuplicateNamespaceComment
8
+ # Extracts duplicate namespace documentation offenses from raw collector output.
9
+ # Each line has the form "file:line: Namespace\tsite|site|...\tconflict" where
10
+ # conflict is either 'same' or 'differ'.
11
+ # @example Output format (skip-lint)
12
+ # /a.rb:6: Foo::Bar\t/a.rb:6|/b.rb:6\tsame
13
+ class Parser < ::Yard::Lint::Parsers::Base
14
+ # Parses the "file:line: Namespace" head of an offense line. The namespace
15
+ # path uses '::' and never ': ', so the final ": " is an unambiguous separator.
16
+ LINE_REGEX = /\A(.+):(\d+): (.+)\z/
17
+
18
+ # @param output [String] raw collector output, one offense per line
19
+ # @return [Array<Hash>] offense hashes with location/line/namespace/sites/conflict
20
+ def call(output)
21
+ return [] if output.nil? || output.empty?
22
+
23
+ output.split("\n").filter_map do |line|
24
+ head, sites, conflict = line.split("\t")
25
+ next unless head
26
+
27
+ match = head.match(LINE_REGEX)
28
+ next unless match
29
+
30
+ {
31
+ location: match[1],
32
+ line: match[2].to_i,
33
+ namespace: match[3],
34
+ sites: (sites || '').split('|'),
35
+ conflict: conflict
36
+ }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ 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 DuplicateNamespaceComment
8
+ # Result object for duplicate namespace comment validation
9
+ # Transforms parsed offenses into offense objects
10
+ class Result < Results::Base
11
+ self.default_severity = 'warning'
12
+ self.offense_type = 'line'
13
+ self.offense_name = 'DuplicateNamespaceComment'
14
+
15
+ # Build human-readable message for a duplicate namespace comment offense
16
+ # @param offense [Hash] offense data with :namespace, :sites and :conflict keys
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,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module DuplicateNamespaceComment
8
+ # Flags namespaces (modules and classes) that carry a documentation comment in
9
+ # more than one file. YARD keeps only one docstring per object, so documenting
10
+ # the same reopened namespace in several files silently discards all but one of
11
+ # those comments. Because YARD does not record which reopening carried a comment,
12
+ # the source is re-read at each definition site to detect the documented ones.
13
+ class Validator < Base
14
+ # Enable in-process execution including private/protected objects
15
+ in_process visibility: :all
16
+
17
+ # Comment lines that are directives or magic comments rather than
18
+ # documentation. A definition preceded only by these is not "documented".
19
+ IGNORED_COMMENT = /
20
+ \A\#! # shebang
21
+ |\A\#\s*frozen_string_literal: # frozen_string_literal magic comment
22
+ |\A\#\s*-\*- # editor modeline, e.g. -*- coding: utf-8 -*-
23
+ |\A\#\s*(en)?coding[:=] # encoding magic comment
24
+ |\A\#\s*warn_indent: # warn_indent magic comment
25
+ |\A\#\s*rubocop: # rubocop directive
26
+ |\A\#\s*:nodoc: # nodoc directive
27
+ |\A\#\s*yard-lint: # yard-lint inline directive
28
+ /x
29
+
30
+ private_constant :IGNORED_COMMENT
31
+
32
+ # Execute query for a single object during in-process execution.
33
+ # Emits one line per namespace documented in two or more files.
34
+ # @param object [YARD::CodeObjects::Base] the code object to query
35
+ # @param collector [Executor::ResultCollector] collector for output
36
+ # @return [void]
37
+ def in_process_query(object, collector)
38
+ # Only namespaces (modules and classes) get reopened across files.
39
+ # NamespaceObject excludes methods, constants, and the like.
40
+ return unless object.is_a?(YARD::CodeObjects::NamespaceObject)
41
+ # A namespace defined in a single file can only be documented once.
42
+ return if object.files.size < 2
43
+
44
+ documented = object.files.select do |file, line|
45
+ line && documented_site?(file, line)
46
+ end
47
+
48
+ return if documented.size < 2
49
+
50
+ primary_file, primary_line = documented.first
51
+ sites = documented.map { |file, line| "#{file}:#{line}" }.join('|')
52
+ texts = documented.map { |file, line| doc_text(file, line) }
53
+ conflict = texts.uniq.size > 1 ? 'differ' : 'same'
54
+
55
+ collector.puts "#{primary_file}:#{primary_line}: #{object.title}\t#{sites}\t#{conflict}"
56
+ end
57
+
58
+ private
59
+
60
+ # Whether the definition at a location is preceded by a real doc comment,
61
+ # as opposed to no comment, a blank-separated (detached) comment, or only
62
+ # directive/magic comments.
63
+ # @param file [String] path to the source file
64
+ # @param line [Integer] 1-based line of the namespace definition
65
+ # @return [Boolean] true when the site carries documentation
66
+ def documented_site?(file, line)
67
+ !comment_lines(file, line).empty?
68
+ end
69
+
70
+ # Joins the documentation text at a location so identical and differing
71
+ # documentation across sites can be told apart.
72
+ # @param file [String] path to the source file
73
+ # @param line [Integer] 1-based line of the namespace definition
74
+ # @return [String] normalized comment text ('' when undocumented)
75
+ def doc_text(file, line)
76
+ comment_lines(file, line).join("\n")
77
+ end
78
+
79
+ # Collects the contiguous block of documentation comment lines directly
80
+ # above a definition, dropping directive/magic comments. A blank line
81
+ # between the comment and the definition detaches it (YARD behaviour), so
82
+ # scanning stops at the first blank or non-comment line.
83
+ # @param file [String] path to the source file
84
+ # @param line [Integer] 1-based line of the namespace definition
85
+ # @return [Array<String>] normalized documentation lines
86
+ def comment_lines(file, line)
87
+ lines = source_lines(file)
88
+ return [] if lines.empty?
89
+
90
+ collected = []
91
+ index = line - 2 # zero-based line directly above the definition
92
+
93
+ while index >= 0
94
+ text = lines[index].strip
95
+ break if text.empty? || !text.start_with?('#')
96
+
97
+ collected << text unless text.match?(IGNORED_COMMENT)
98
+ index -= 1
99
+ end
100
+
101
+ collected
102
+ end
103
+
104
+ # Reads source lines for a file, tolerating unreadable paths so a single
105
+ # bad location drops only its own site instead of hiding the whole object.
106
+ # @param file [String] path to the source file
107
+ # @return [Array<String>] file lines, or an empty array when unreadable
108
+ def source_lines(file)
109
+ cached_lines(file)
110
+ rescue SystemCallError, IOError
111
+ []
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ # DuplicateNamespaceComment validator
8
+ #
9
+ # Detects namespaces (modules and classes) that carry a YARD documentation
10
+ # comment in more than one file. When a namespace is reopened across several
11
+ # files, YARD merges every reopening into a single object and keeps only one
12
+ # docstring - the last documented reopening wins and all the other comments are
13
+ # silently discarded, with no warning. This is a common accident for shared
14
+ # namespaces (e.g. `Users` or `Users::Operations`) that are spread across many
15
+ # files. It is not a concern for a leaf object such as `Users::Operations::Create`
16
+ # which is normally defined in a single file and can only be documented once.
17
+ #
18
+ # The validator reports one offense per namespace that is documented in two or
19
+ # more files, listing every documented location so the duplicates can be
20
+ # consolidated into a single canonical spot.
21
+ #
22
+ # @example Bad - the same namespace documented in two files
23
+ # # a.rb
24
+ # # Handles user operations
25
+ # module Users; end
26
+ #
27
+ # # b.rb
28
+ # # User-related helpers # &lt;- silently discarded by YARD
29
+ # module Users; end
30
+ #
31
+ # @example Good - document the namespace in exactly one place
32
+ # # a.rb
33
+ # # Handles user operations
34
+ # module Users; end
35
+ #
36
+ # # b.rb
37
+ # module Users; end # &lt;- reopened without a comment
38
+ #
39
+ # ## Configuration
40
+ #
41
+ # To disable this validator:
42
+ #
43
+ # Documentation/DuplicateNamespaceComment:
44
+ # Enabled: false
45
+ module DuplicateNamespaceComment
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -3,7 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Tags validators - validate YARD tag quality and consistency
7
6
  module Tags
8
7
  # ExampleSyntax validator
9
8
  #
@@ -3,7 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Tags validators - validate YARD tag quality and consistency
7
6
  module Tags
8
7
  # RedundantParamDescription validator
9
8
  #
@@ -5,7 +5,6 @@ module Yard
5
5
  module Validators
6
6
  # Validators for checking YARD warnings
7
7
  module Warnings
8
- # Validator for detecting duplicated parameter names in @param tags
9
8
  module DuplicatedParameterName
10
9
  # Configuration for DuplicatedParameterName validator
11
10
  class Config < ::Yard::Lint::Validators::Config
@@ -3,7 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
7
  # DuplicatedParameterName validator
9
8
  #
@@ -29,7 +28,6 @@ module Yard
29
28
  #
30
29
  # Warnings/DuplicatedParameterName:
31
30
  # Enabled: false
32
- #
33
31
  module DuplicatedParameterName
34
32
  end
35
33
  end
@@ -3,9 +3,7 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
- # Validator for detecting invalid directive formats
9
7
  module InvalidDirectiveFormat
10
8
  # Configuration for InvalidDirectiveFormat validator
11
9
  class Config < ::Yard::Lint::Validators::Config
@@ -3,7 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
7
  # InvalidDirectiveFormat validator
9
8
  #
@@ -29,7 +28,6 @@ module Yard
29
28
  #
30
29
  # Warnings/InvalidDirectiveFormat:
31
30
  # Enabled: false
32
- #
33
31
  module InvalidDirectiveFormat
34
32
  end
35
33
  end
@@ -3,9 +3,7 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
- # Validator for detecting invalid tag formats
9
7
  module InvalidTagFormat
10
8
  # Configuration for InvalidTagFormat validator
11
9
  class Config < ::Yard::Lint::Validators::Config
@@ -3,7 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
7
  # InvalidTagFormat validator
9
8
  #
@@ -29,7 +28,6 @@ module Yard
29
28
  #
30
29
  # Warnings/InvalidTagFormat:
31
30
  # Enabled: false
32
- #
33
31
  module InvalidTagFormat
34
32
  end
35
33
  end
@@ -3,9 +3,7 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
- # Validator for detecting files YARD could not parse
9
7
  module SyntaxError
10
8
  # Configuration for SyntaxError validator
11
9
  class Config < ::Yard::Lint::Validators::Config
@@ -3,7 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
7
  # SyntaxError validator
9
8
  #
@@ -25,7 +24,6 @@ module Yard
25
24
  #
26
25
  # Warnings/SyntaxError:
27
26
  # Enabled: false
28
- #
29
27
  module SyntaxError
30
28
  end
31
29
  end
@@ -3,9 +3,7 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
- # Validator for detecting unknown directives
9
7
  module UnknownDirective
10
8
  # Configuration for UnknownDirective validator
11
9
  class Config < ::Yard::Lint::Validators::Config
@@ -3,7 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
7
  # UnknownDirective validator
9
8
  #
@@ -30,7 +29,6 @@ module Yard
30
29
  #
31
30
  # Warnings/UnknownDirective:
32
31
  # Enabled: false
33
- #
34
32
  module UnknownDirective
35
33
  end
36
34
  end
@@ -3,9 +3,7 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
- # Validator for detecting unknown parameter names in @param tags
9
7
  module UnknownParameterName
10
8
  # Configuration for UnknownParameterName validator
11
9
  class Config < ::Yard::Lint::Validators::Config
@@ -3,7 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
7
  # UnknownParameterName validator
9
8
  #
@@ -27,7 +26,6 @@ module Yard
27
26
  #
28
27
  # Warnings/UnknownParameterName:
29
28
  # Enabled: false
30
- #
31
29
  module UnknownParameterName
32
30
  end
33
31
  end
@@ -3,9 +3,7 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
- # Validator for detecting unknown tags in documentation
9
7
  module UnknownTag
10
8
  # Configuration for UnknownTag validator
11
9
  class Config < ::Yard::Lint::Validators::Config
@@ -3,7 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  module Validators
6
- # Validators for checking YARD warnings
7
6
  module Warnings
8
7
  # UnknownTag validator
9
8
  #
@@ -40,7 +39,6 @@ module Yard
40
39
  #
41
40
  # Warnings/UnknownTag:
42
41
  # Enabled: false
43
- #
44
42
  module UnknownTag
45
43
  end
46
44
  end
@@ -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.9.0'
6
+ VERSION = '1.10.1'
7
7
  end
8
8
  end
data/lib/yard/lint.rb CHANGED
@@ -10,6 +10,7 @@ require 'did_you_mean'
10
10
  require 'yard'
11
11
  require 'set'
12
12
 
13
+ # YARD Lint - comprehensive linter for YARD documentation
13
14
  module Yard
14
15
  # YARD Lint module providing linting functionality for YARD documentation
15
16
  module Lint
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.9.0
4
+ version: 1.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld
@@ -85,6 +85,12 @@ files:
85
85
  - lib/yard/lint/validators/documentation/blank_line_before_definition/parser.rb
86
86
  - lib/yard/lint/validators/documentation/blank_line_before_definition/result.rb
87
87
  - lib/yard/lint/validators/documentation/blank_line_before_definition/validator.rb
88
+ - lib/yard/lint/validators/documentation/duplicate_namespace_comment.rb
89
+ - lib/yard/lint/validators/documentation/duplicate_namespace_comment/config.rb
90
+ - lib/yard/lint/validators/documentation/duplicate_namespace_comment/messages_builder.rb
91
+ - lib/yard/lint/validators/documentation/duplicate_namespace_comment/parser.rb
92
+ - lib/yard/lint/validators/documentation/duplicate_namespace_comment/result.rb
93
+ - lib/yard/lint/validators/documentation/duplicate_namespace_comment/validator.rb
88
94
  - lib/yard/lint/validators/documentation/empty_comment_line.rb
89
95
  - lib/yard/lint/validators/documentation/empty_comment_line/config.rb
90
96
  - lib/yard/lint/validators/documentation/empty_comment_line/messages_builder.rb
@@ -313,7 +319,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
313
319
  - !ruby/object:Gem::Version
314
320
  version: '0'
315
321
  requirements: []
316
- rubygems_version: 4.0.10
322
+ rubygems_version: 4.0.16
317
323
  specification_version: 4
318
324
  summary: YARD documentation linter and validator
319
325
  test_files: []