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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -2
- data/README.md +165 -7
- data/bin/yard-lint +45 -11
- data/lib/yard/lint/executor/in_process_registry.rb +38 -12
- data/lib/yard/lint/results/base.rb +3 -0
- data/lib/yard/lint/runner.rb +4 -2
- data/lib/yard/lint/templates/default_config.yml +40 -0
- data/lib/yard/lint/templates/strict_config.yml +39 -0
- data/lib/yard/lint/validators/base.rb +107 -1
- data/lib/yard/lint/validators/documentation/line_length/config.rb +21 -0
- data/lib/yard/lint/validators/documentation/line_length/messages_builder.rb +26 -0
- data/lib/yard/lint/validators/documentation/line_length/parser.rb +65 -0
- data/lib/yard/lint/validators/documentation/line_length/result.rb +26 -0
- data/lib/yard/lint/validators/documentation/line_length/validator.rb +59 -0
- data/lib/yard/lint/validators/documentation/line_length.rb +43 -0
- data/lib/yard/lint/validators/documentation/missing_return/config.rb +2 -1
- data/lib/yard/lint/validators/documentation/missing_return/parser.rb +0 -1
- data/lib/yard/lint/validators/documentation/missing_return/validator.rb +1 -0
- data/lib/yard/lint/validators/documentation/orphaned_doc_comment/config.rb +20 -0
- data/lib/yard/lint/validators/documentation/orphaned_doc_comment/messages_builder.rb +23 -0
- data/lib/yard/lint/validators/documentation/orphaned_doc_comment/parser.rb +38 -0
- data/lib/yard/lint/validators/documentation/orphaned_doc_comment/result.rb +24 -0
- data/lib/yard/lint/validators/documentation/orphaned_doc_comment/validator.rb +121 -0
- data/lib/yard/lint/validators/documentation/orphaned_doc_comment.rb +53 -0
- data/lib/yard/lint/validators/documentation/text_substitution/config.rb +24 -0
- data/lib/yard/lint/validators/documentation/text_substitution/messages_builder.rb +33 -0
- data/lib/yard/lint/validators/documentation/text_substitution/parser.rb +57 -0
- data/lib/yard/lint/validators/documentation/text_substitution/result.rb +24 -0
- data/lib/yard/lint/validators/documentation/text_substitution/validator.rb +72 -0
- data/lib/yard/lint/validators/documentation/text_substitution.rb +55 -0
- data/lib/yard/lint/validators/documentation/undocumented_boolean_methods/config.rb +2 -1
- data/lib/yard/lint/validators/documentation/undocumented_boolean_methods/validator.rb +1 -0
- data/lib/yard/lint/validators/documentation/undocumented_method_arguments/config.rb +3 -1
- data/lib/yard/lint/validators/documentation/undocumented_method_arguments/validator.rb +3 -1
- data/lib/yard/lint/validators/documentation/undocumented_method_arguments.rb +1 -2
- data/lib/yard/lint/validators/documentation/undocumented_objects/config.rb +2 -1
- data/lib/yard/lint/validators/documentation/undocumented_objects/validator.rb +1 -0
- data/lib/yard/lint/validators/documentation/undocumented_options/config.rb +2 -1
- data/lib/yard/lint/validators/documentation/undocumented_options/validator.rb +1 -0
- data/lib/yard/lint/validators/documentation/undocumented_options.rb +1 -2
- data/lib/yard/lint/validators/tags/api_tags/result.rb +1 -0
- data/lib/yard/lint/validators/tags/api_tags/validator.rb +1 -1
- data/lib/yard/lint/validators/tags/example_style/result.rb +1 -0
- data/lib/yard/lint/validators/tags/example_syntax/result.rb +1 -0
- data/lib/yard/lint/validators/tags/invalid_types/validator.rb +1 -1
- data/lib/yard/lint/validators/tags/meaningless_tag/validator.rb +1 -1
- data/lib/yard/lint/validators/tags/missing_yield/config.rb +20 -0
- data/lib/yard/lint/validators/tags/missing_yield/messages_builder.rb +22 -0
- data/lib/yard/lint/validators/tags/missing_yield/parser.rb +39 -0
- data/lib/yard/lint/validators/tags/missing_yield/result.rb +24 -0
- data/lib/yard/lint/validators/tags/missing_yield/validator.rb +76 -0
- data/lib/yard/lint/validators/tags/missing_yield.rb +56 -0
- data/lib/yard/lint/validators/tags/redundant_param_description/validator.rb +4 -2
- data/lib/yard/lint/validators/tags/redundant_param_description.rb +2 -1
- data/lib/yard/lint/validators/tags/type_syntax.rb +1 -2
- data/lib/yard/lint/validators/warnings/duplicated_parameter_name.rb +1 -2
- data/lib/yard/lint/validators/warnings/invalid_directive_format.rb +1 -2
- data/lib/yard/lint/version.rb +1 -1
- data/lib/yard/lint.rb +14 -4
- metadata +25 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef1425a1be17cac04595b6558a742eb4036fc1cc66891e1d8f31eb46094c8914
|
|
4
|
+
data.tar.gz: d5ba0ef812eb0261718d7259d2da0b0f0b2fa37a1674893f6d7d3178be3bf551
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 23d60c91521b5afbadd0a43380682686f7b10aa68a968f5091da2de425f477f71ce3b8a6477ca5d0197d7138979dffc4a0aebe2582b3a64cd4092b18b6222c95
|
|
7
|
+
data.tar.gz: 966fe65d5e72ba1dbf225fe8802f2259dcdb436a66b2571d6caf7aff7d59491e1b337c7fe4db0e68354bceebb192c89d40ed6c1229b5e2bd2f75d2f5cbde456a
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# YARD-Lint Changelog
|
|
2
2
|
|
|
3
|
+
## 1.6.0 (2026-06-11)
|
|
4
|
+
- **[Feature]** New `--format quickfix` output mode emits one offense per line in the standard `file:line: S: Validator: message` format. Vim users can set `makeprg=yard-lint\ --format\ quickfix\ --no-progress\ %` and navigate offenses with `:cnext`/`:cprev`; Emacs users can use it as their `compile-command` and navigate with `M-g n`/`M-g p`. Produces no output (and exits 0) when there are no offenses.
|
|
5
|
+
- **[Feature]** New opt-in validator `Documentation/LineLength` detects documentation comment lines that exceed a configurable maximum length (#176). Disabled by default (`Enabled: false`) to avoid breaking existing projects; enable with `Documentation/LineLength: Enabled: true` and tune with `MaxLength: 120` (default). Uses YARD's already-parsed docstring to determine which source lines belong to the comment block, avoiding fragile backwards-scanning. Each over-length line produces a separate offense at its exact file location.
|
|
6
|
+
- **[Feature]** `Yard::Lint.run` now accepts an optional `source:` keyword argument for linting in-memory source without reading from disk. `path:` is still required and governs config resolution, exclusion matching, and offense location reporting — only the source bytes come from the caller. The CLI gains a corresponding `--stdin` flag (`cat lib/foo.rb | yard-lint --stdin lib/foo.rb`). Enables LSP/editor integration tools (e.g. `solargraph-yard-lint`) to lint unsaved buffers without waiting for a save. (#173)
|
|
7
|
+
- **[Feature]** `Documentation/UndocumentedMethodArguments` now supports an `AllowedMethods` config option. Methods listed there are silently skipped for `@param` documentation checks. Three pattern forms are supported: exact name (`call`), arity notation (`initialize/1` — matches only that parameter count, with `*` and `&` params excluded from the count), and regex (`/^perform/`). Invalid regex patterns are silently ignored; the empty regex `//` is always rejected. Useful for idiomatic Ruby conventions like service objects where `call(args)` is self-documenting, or `respond_to_missing?` / `method_missing` whose arguments are rarely worth documenting.
|
|
8
|
+
- **[Feature]** All Documentation validators (`Documentation/UndocumentedObjects`, `Documentation/UndocumentedMethodArguments`, `Documentation/UndocumentedBooleanMethods`, `Documentation/UndocumentedOptions`, `Documentation/MissingReturn`) now support an `AllowedParentClasses` config option. When set, any class or method whose enclosing class directly inherits from one of the listed base classes is silently skipped by that validator. Useful for exempting exception hierarchies (`StandardError`), ORM model methods (`ActiveRecord::Base`, `ApplicationRecord`), or any framework base class whose subclasses don't need YARD coverage. Uses exact full-path matching (`"ActiveRecord::Base"`, not `"Base"`). `Object` and `BasicObject` are never matched to avoid accidentally exempting all classes.
|
|
9
|
+
- **[Feature]** New opt-in validator `Tags/MissingYield` detects methods that call `yield` in their body but do not document the block with a `@yield`, `@yieldparam`, or `@yieldreturn` tag. Callers need to know a method yields in order to pass a block; the validator checks raw docstring text rather than YARD's inferred tag list, so YARD's automatic `@yield` inference for bare `yield expr` statements does not suppress the offense. Method calls like `Fiber.yield` and `yielder.yield` are not flagged. Disabled by default - enable with `Tags/MissingYield: Enabled: true`.
|
|
10
|
+
- **[Feature]** New opt-in validator `Documentation/TextSubstitution` detects forbidden characters or strings in YARD documentation and suggests user-defined replacements. Ships with em-dash (—, U+2014) and en-dash (–, U+2013) → hyphen as built-in defaults to catch AI-generated punctuation that projects prefer as plain ASCII hyphens. Fully generic — configure any string-to-string rules via `Substitutions`. Content inside fenced code blocks is skipped. Disabled by default. (#182)
|
|
11
|
+
- **[Feature]** New validator `Documentation/OrphanedDocComment` detects YARD comment blocks with tags (`@param`, `@return`, etc.) that are not attached to any documentable Ruby construct and will be silently dropped by YARD. Triggered when a tagged comment is immediately followed by a non-documentable statement (variable assignment, `require`, `include`, etc.) or sits at end-of-file. Enabled by default. Complementary to `Documentation/BlankLineBeforeDefinition` which handles the blank-lines-before-def case.
|
|
12
|
+
- **[Enhancement]** Each offense now includes a `validator` field with the full config key (e.g. `"Documentation/MissingReturn"`, `"Tags/Order"`) identifying which validator produced it. The text formatter also now displays this path instead of the short offense name, making it easier to locate the right `.yard-lint.yml` setting to adjust.
|
|
13
|
+
- **[Fix]** `Tags/InvalidTypes` no longer reports false positives for YARD's semicolon shorthand in multi-pair fixed-shape Hash types (#171)
|
|
14
|
+
- Types like `Hash{:range => Hash; :severity => Integer; :source, :code, :message => String}` were incorrectly flagged because `;` was not included in the type-name splitter's delimiter set, leaving fragments such as `Hash;` and `Integer;` as tokens that appeared invalid
|
|
15
|
+
- Added `;` to the `extract_type_names` regex so each component is extracted cleanly; invalid types genuinely nested inside semicolon-delimited pairs are still caught
|
|
16
|
+
- **[Enhancement]** Add Ruby warning category opt-in to test helpers
|
|
17
|
+
- **[Fix]** Use `remove_method` instead of `define_singleton_method` to restore `warn` in `InProcessRegistry#capture_warnings`, eliminating a spurious method redefinition warning
|
|
18
|
+
|
|
3
19
|
## 1.5.2 (2026-06-02)
|
|
4
20
|
- **[Fix]** `Tags/InvalidTypes` no longer reports false positives for YARD pseudo-types `undefined`, `unspecified`, and `unknown` (#152)
|
|
5
21
|
- These lowercase pseudo-types are used in real-world YARD docs (e.g. Solargraph uses `Hash{String => undefined}` extensively) to signal that a type is intentionally unspecified
|
|
@@ -11,7 +27,7 @@
|
|
|
11
27
|
- Invalid types genuinely nested inside hash values (e.g. `Hash{String => bad_type}`) are still caught and surfaced correctly
|
|
12
28
|
- **[Enhancement]** `Tags/InvalidTypes` offense messages now name the invalid type(s) and the tag they appear in (#151)
|
|
13
29
|
- Previously reported a generic `"has at least one tag with an invalid type definition"` message with no further detail
|
|
14
|
-
- Now reports `"has invalid type(s): @param body: \`bad_type\`; @return: \`wrong_type\`"`
|
|
30
|
+
- Now reports `"has invalid type(s): @param body: \`bad_type\`; @return: \`wrong_type\`"` - the exact offending type and the tag (including param name for `@param`) where it was found
|
|
15
31
|
- **[Fix]** Do not flag `@param` on `Struct.new` / `Data.define` constants in `Tags/MeaninglessTag` (#152)
|
|
16
32
|
- Solargraph uses `@param` annotations on these constants to type the synthesised accessors; flagging them was a false positive
|
|
17
33
|
- `@option` on these constants is still reported as meaningless
|
|
@@ -32,7 +48,7 @@
|
|
|
32
48
|
- Both tags are now validated consistently across `Tags/InvalidTypes`, `Tags/TypeSyntax`, `Tags/CollectionType`, and `Tags/NonAsciiType`
|
|
33
49
|
- **[Fix]** Skip attribute methods in `Tags/ApiTags` validator (#128)
|
|
34
50
|
- Methods generated by `attr_*`, `@!attribute` directives, `Struct.new`, and `Data.define` are no longer flagged for missing `@api` tags
|
|
35
|
-
- YARD's `Data.define` and `Struct.new` handlers hard-replace the generated methods' docstrings, stripping any `@api` tag inherited from the enclosing class, and `@!attribute` directives written above a `Data.define` constant attach to the wrong namespace
|
|
51
|
+
- YARD's `Data.define` and `Struct.new` handlers hard-replace the generated methods' docstrings, stripping any `@api` tag inherited from the enclosing class, and `@!attribute` directives written above a `Data.define` constant attach to the wrong namespace - leaving users with no way to attach per-method `@api` tags to those accessors
|
|
36
52
|
- Matches the approach taken for `UndocumentedMethodArguments` in #115
|
|
37
53
|
|
|
38
54
|
## 1.5.1 (2026-04-09)
|
data/README.md
CHANGED
|
@@ -19,18 +19,18 @@ Accurate documentation isn't just for human developers anymore. [Research shows]
|
|
|
19
19
|
|
|
20
20
|
YARD-Lint validates your YARD documentation for:
|
|
21
21
|
|
|
22
|
-
- **Documentation Completeness** - Undocumented classes, modules, methods, parameters, boolean return values, and missing `@return` tags
|
|
22
|
+
- **Documentation Completeness** - Undocumented classes, modules, methods, parameters, boolean return values, and missing `@return` tags; orphaned doc comments with YARD tags that YARD silently drops
|
|
23
23
|
- **Type Accuracy** - Invalid type definitions, malformed type syntax, non-ASCII characters in types, tuple types, and literal types (symbols, strings, numbers)
|
|
24
|
-
- **Tag Validation** - Incorrect tag ordering, meaningless tags, invalid tag positions, unknown tags with suggestions, forbidden tag patterns
|
|
24
|
+
- **Tag Validation** - Incorrect tag ordering, meaningless tags, invalid tag positions, unknown tags with suggestions, forbidden tag patterns, undocumented `yield` calls (opt-in)
|
|
25
25
|
- **Code Examples** - Syntax validation in `@example` tags, optional style validation with RuboCop/StandardRB
|
|
26
26
|
- **Semantic Correctness** - Abstract methods with implementations, redundant descriptions
|
|
27
|
-
- **Style & Formatting** - Empty comment lines, blank lines before definitions, informal notation patterns, tag group separators
|
|
27
|
+
- **Style & Formatting** - Empty comment lines, blank lines before definitions, informal notation patterns, tag group separators, configurable documentation line length (opt-in)
|
|
28
28
|
- **Smart Suggestions** - "Did you mean" suggestions for typos in parameter names, tags, and configuration settings
|
|
29
29
|
- **Configuration Safety** - Validates `.yard-lint.yml` for typos and invalid settings before processing
|
|
30
30
|
- **Performance** - In-process YARD execution with shared registry (~10x faster than shell-based execution)
|
|
31
31
|
- **Incremental Adoption** - `--auto-gen-config` generates a baseline todo file to adopt on legacy codebases without fixing everything first
|
|
32
32
|
|
|
33
|
-
**See the complete list:** [All Features](https://github.com/mensfeld/yard-lint/wiki/Features) | [
|
|
33
|
+
**See the complete list:** [All Features](https://github.com/mensfeld/yard-lint/wiki/Features) | [34 Validators](https://github.com/mensfeld/yard-lint/wiki/Validators)
|
|
34
34
|
|
|
35
35
|
## Installation
|
|
36
36
|
|
|
@@ -142,6 +142,63 @@ yard-lint lib/ --only Tags/Order,Documentation/UndocumentedObjects
|
|
|
142
142
|
|
|
143
143
|
**Learn more:** [Advanced Usage Guide](https://github.com/mensfeld/yard-lint/wiki/Advanced-Usage)
|
|
144
144
|
|
|
145
|
+
### Lint from stdin (LSP / Editor Integration)
|
|
146
|
+
|
|
147
|
+
Pass source bytes directly without reading from disk. The `path` argument is still required - it governs config resolution, exclusion matching, and offense location reporting.
|
|
148
|
+
|
|
149
|
+
**CLI:**
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Lint source piped through stdin - path is used for config/reporting only
|
|
153
|
+
cat lib/foo.rb | yard-lint --stdin lib/foo.rb
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Ruby API:**
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
# Lint an in-memory buffer - file does not need to exist on disk
|
|
160
|
+
result = Yard::Lint.run(
|
|
161
|
+
path: 'lib/foo.rb', # used for config, exclusions, and offense locations
|
|
162
|
+
source: editor_buffer_content, # actual source bytes to lint
|
|
163
|
+
progress: false
|
|
164
|
+
)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
This is how [solargraph-yard-lint](https://github.com/lekemula/solargraph-yard-lint) surfaces yard-lint offenses on unsaved editor buffers - the file path provides context while the live buffer content is linted directly, matching the behaviour of RuboCop's `--stdin` flag.
|
|
168
|
+
|
|
169
|
+
### Quickfix Output (Vim / Emacs)
|
|
170
|
+
|
|
171
|
+
Use `--format quickfix` to get one offense per line in the standard `file:line: S: Validator: message` format that editors parse natively for their quickfix/error lists:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
yard-lint --format quickfix lib/
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Example output:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
lib/foo.rb:42: E: Documentation/UndocumentedObjects: Class Foo is not documented
|
|
181
|
+
lib/foo.rb:57: W: Tags/InvalidTypes: has invalid type(s): @return: `Sting`
|
|
182
|
+
lib/bar.rb:12: C: Tags/Order: Tags are not in the correct order
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Vim** — set `makeprg` and use `:make` to populate the quickfix list:
|
|
186
|
+
|
|
187
|
+
```vim
|
|
188
|
+
set makeprg=yard-lint\ --format\ quickfix\ --no-progress\ %
|
|
189
|
+
set errorformat=%f:%l:\ %t:\ %m
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Then `:make` lints the current file and `:cnext` / `:cprev` jump between offenses. Note: Vim only recognises `E` and `W` as named types for `:clist E`/`:clist W` filtering — `C` (convention) offenses are stored and navigable but appear without a named type in filtered views.
|
|
193
|
+
|
|
194
|
+
**Emacs** — set `compile-command`:
|
|
195
|
+
|
|
196
|
+
```elisp
|
|
197
|
+
(setq compile-command "yard-lint --format quickfix --no-progress lib/")
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Then `M-x compile` and `M-g n` / `M-g p` navigate between offenses.
|
|
201
|
+
|
|
145
202
|
## Configuration Basics
|
|
146
203
|
|
|
147
204
|
Create a `.yard-lint.yml` file in your project root:
|
|
@@ -173,10 +230,19 @@ Documentation/UndocumentedObjects:
|
|
|
173
230
|
ExcludedMethods:
|
|
174
231
|
- 'initialize/0'
|
|
175
232
|
- '/^_/'
|
|
233
|
+
# Skip classes inheriting from these base classes (exact full-path match)
|
|
234
|
+
AllowedParentClasses:
|
|
235
|
+
- StandardError
|
|
236
|
+
- ActiveRecord::Base
|
|
176
237
|
|
|
177
238
|
Documentation/UndocumentedMethodArguments:
|
|
178
239
|
Enabled: true
|
|
179
240
|
Severity: warning
|
|
241
|
+
# Skip @param checks for specific methods (exact name, name/arity, /regex/)
|
|
242
|
+
AllowedMethods:
|
|
243
|
+
- call # service objects: call(args) is self-documenting
|
|
244
|
+
- perform # background jobs
|
|
245
|
+
- initialize/1 # only this specific arity of initialize
|
|
180
246
|
|
|
181
247
|
Tags/Order:
|
|
182
248
|
Enabled: true
|
|
@@ -215,6 +281,11 @@ Documentation/MissingReturn:
|
|
|
215
281
|
Tags/ExampleStyle:
|
|
216
282
|
Enabled: true
|
|
217
283
|
Severity: convention
|
|
284
|
+
|
|
285
|
+
# Opt-in: Enforce max line length in documentation comments
|
|
286
|
+
Documentation/LineLength:
|
|
287
|
+
Enabled: true
|
|
288
|
+
MaxLength: 100
|
|
218
289
|
```
|
|
219
290
|
|
|
220
291
|
**Key features:**
|
|
@@ -225,6 +296,75 @@ Tags/ExampleStyle:
|
|
|
225
296
|
|
|
226
297
|
**Learn more:** [Complete Configuration Guide](https://github.com/mensfeld/yard-lint/wiki/Configuration)
|
|
227
298
|
|
|
299
|
+
## Catching Orphaned Documentation Comments
|
|
300
|
+
|
|
301
|
+
YARD silently ignores comment blocks that contain YARD tags (`@param`, `@return`, etc.) when they are not immediately followed by a documentable construct (method, class, module, constant, attribute). This happens with local variable assignments, `require` calls, `include`/`extend` statements, bare `private`/`public` keywords, or comments at the end of a file - the documentation is simply lost with no warning.
|
|
302
|
+
|
|
303
|
+
The `Documentation/OrphanedDocComment` validator (enabled by default) catches this:
|
|
304
|
+
|
|
305
|
+
```ruby
|
|
306
|
+
# Bad - YARD drops this silently; local variable is not documentable
|
|
307
|
+
# @param name [String] the name
|
|
308
|
+
# @return [void]
|
|
309
|
+
local_var = "value"
|
|
310
|
+
|
|
311
|
+
# Bad - require is not documentable
|
|
312
|
+
# @param id [Integer] user id
|
|
313
|
+
# @return [User]
|
|
314
|
+
require 'some_gem'
|
|
315
|
+
|
|
316
|
+
# Bad - orphaned at end of file
|
|
317
|
+
# @param id [Integer] user id
|
|
318
|
+
# @return [User]
|
|
319
|
+
|
|
320
|
+
# Good - properly attached to a method
|
|
321
|
+
# @param name [String] the name
|
|
322
|
+
# @return [void]
|
|
323
|
+
def greet(name); end
|
|
324
|
+
|
|
325
|
+
# Good - constant assignments are documentable, not flagged
|
|
326
|
+
# @return [Integer] the answer
|
|
327
|
+
ANSWER = 42
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
This validator is complementary to `Documentation/BlankLineBeforeDefinition` (which handles the case where blank lines separate a doc comment from a `def` - YARD still attaches it despite the gap).
|
|
331
|
+
|
|
332
|
+
## Documenting yield (opt-in)
|
|
333
|
+
|
|
334
|
+
The `Tags/MissingYield` validator (opt-in, disabled by default) detects methods that call `yield` in their body but do not document the block with a `@yield`, `@yieldparam`, or `@yieldreturn` tag. Callers need to know a method yields in order to pass a block.
|
|
335
|
+
|
|
336
|
+
Enable it in `.yard-lint.yml`:
|
|
337
|
+
|
|
338
|
+
```yaml
|
|
339
|
+
Tags/MissingYield:
|
|
340
|
+
Enabled: true
|
|
341
|
+
Severity: warning
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
```ruby
|
|
345
|
+
# Bad - method yields but block is not documented
|
|
346
|
+
# @param items [Array] the items to process
|
|
347
|
+
def each(items)
|
|
348
|
+
items.each { |item| yield item }
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# Good - block documented with @yield
|
|
352
|
+
# @param items [Array] the items to process
|
|
353
|
+
# @yield [item] each item in the collection
|
|
354
|
+
def each(items)
|
|
355
|
+
items.each { |item| yield item }
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# Good - @yieldparam is also accepted
|
|
359
|
+
# @param items [Array] the items to process
|
|
360
|
+
# @yieldparam item [Object] each item
|
|
361
|
+
def each(items)
|
|
362
|
+
items.each { |item| yield item }
|
|
363
|
+
end
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Method calls like `Fiber.yield` and `yielder.yield` (Enumerator::Yielder) are not flagged - only the `yield` keyword triggers the check.
|
|
367
|
+
|
|
228
368
|
## Handling Non-Standard Types
|
|
229
369
|
|
|
230
370
|
By default `Tags/InvalidTypes` accepts all built-in Ruby classes, constants, and a set of YARD pseudo-types (`nil`, `true`, `false`, `self`, `void`, `undefined`, `unspecified`, `unknown`). If your project uses additional type names that are not real Ruby classes - project-specific aliases, LSP extensions, or informal conventions - you can declare them via `ExtraTypes` so yard-lint does not report them as `InvalidTagType` offenses.
|
|
@@ -294,7 +434,7 @@ jobs:
|
|
|
294
434
|
```bash
|
|
295
435
|
#!/bin/bash
|
|
296
436
|
# .git/hooks/pre-commit
|
|
297
|
-
bundle exec yard-lint lib/ --staged
|
|
437
|
+
bundle exec yard-lint lib/ --staged
|
|
298
438
|
```
|
|
299
439
|
|
|
300
440
|
### GitLab CI
|
|
@@ -320,10 +460,11 @@ Configuration:
|
|
|
320
460
|
-c, --config FILE Path to config file (default: .yard-lint.yml)
|
|
321
461
|
|
|
322
462
|
Output:
|
|
323
|
-
-f, --format FORMAT Output format (text, json)
|
|
463
|
+
-f, --format FORMAT Output format (text, json, quickfix)
|
|
324
464
|
-q, --quiet Quiet mode (only show summary)
|
|
325
465
|
--stats Show documentation coverage statistics
|
|
326
466
|
--[no-]progress Show progress indicator (default: auto-detect TTY)
|
|
467
|
+
--stdin Read source from stdin; PATH still required for config/reporting
|
|
327
468
|
|
|
328
469
|
Coverage:
|
|
329
470
|
--min-coverage N Minimum documentation coverage required (0-100)
|
|
@@ -352,6 +493,23 @@ Information:
|
|
|
352
493
|
|
|
353
494
|
**Learn more:** [Advanced Usage](https://github.com/mensfeld/yard-lint/wiki/Advanced-Usage) - CLI reference, JSON output, coverage
|
|
354
495
|
|
|
496
|
+
## Offense Structure
|
|
497
|
+
|
|
498
|
+
Every offense (in text, JSON, and quickfix output) includes a `validator` field with the full config key that produced it, making it easy to find the right `.yard-lint.yml` setting to adjust:
|
|
499
|
+
|
|
500
|
+
```json
|
|
501
|
+
{
|
|
502
|
+
"name": "OrphanedDocComment",
|
|
503
|
+
"validator": "Documentation/OrphanedDocComment",
|
|
504
|
+
"severity": "warning",
|
|
505
|
+
"message": "Documentation comment with @param, @return is orphaned - YARD will ignore it",
|
|
506
|
+
"location": "lib/my_class.rb",
|
|
507
|
+
"location_line": 42
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
The text formatter also shows the validator path (e.g., `[Documentation/OrphanedDocComment]`) instead of just the short offense name.
|
|
512
|
+
|
|
355
513
|
## Documentation
|
|
356
514
|
|
|
357
515
|
### Quick Links
|
|
@@ -359,7 +517,7 @@ Information:
|
|
|
359
517
|
- **[Wiki Home](https://github.com/mensfeld/yard-lint/wiki)** - Full documentation
|
|
360
518
|
- **[Installation](https://github.com/mensfeld/yard-lint/wiki/Installation)** - Installation guide
|
|
361
519
|
- **[Configuration](https://github.com/mensfeld/yard-lint/wiki/Configuration)** - Complete configuration reference
|
|
362
|
-
- **[Validators](https://github.com/mensfeld/yard-lint/wiki/Validators)** - All
|
|
520
|
+
- **[Validators](https://github.com/mensfeld/yard-lint/wiki/Validators)** - All 34 validators documented
|
|
363
521
|
- **[Features](https://github.com/mensfeld/yard-lint/wiki/Features)** - All features explained
|
|
364
522
|
|
|
365
523
|
### Workflows
|
data/bin/yard-lint
CHANGED
|
@@ -17,7 +17,7 @@ OptionParser.new do |opts|
|
|
|
17
17
|
config_file = file
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
opts.on('-f', '--format FORMAT', 'Output format (text, json)') do |format|
|
|
20
|
+
opts.on('-f', '--format FORMAT', 'Output format (text, json, quickfix)') do |format|
|
|
21
21
|
options[:format] = format
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -37,6 +37,10 @@ OptionParser.new do |opts|
|
|
|
37
37
|
options[:progress] = value
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
opts.on('--stdin', 'Read source from stdin; PATH argument is required for config/reporting') do
|
|
41
|
+
options[:stdin] = true
|
|
42
|
+
end
|
|
43
|
+
|
|
40
44
|
opts.separator ''
|
|
41
45
|
opts.separator 'Diff mode options (mutually exclusive):'
|
|
42
46
|
|
|
@@ -111,12 +115,14 @@ OptionParser.new do |opts|
|
|
|
111
115
|
puts ' yard-lint --staged # Lint only staged files'
|
|
112
116
|
puts ' yard-lint --changed # Lint only uncommitted files'
|
|
113
117
|
puts ' yard-lint --format json lib/ # Output in JSON format'
|
|
118
|
+
puts ' yard-lint --format quickfix lib/ # Output in quickfix format (Vim/Emacs)'
|
|
114
119
|
puts ' yard-lint --init # Generate default config'
|
|
115
120
|
puts ' yard-lint --init --strict # Generate strict config'
|
|
116
121
|
puts ' yard-lint --update # Update config with new validators'
|
|
117
122
|
puts ' yard-lint --auto-gen-config # Generate todo file for existing violations'
|
|
118
123
|
puts ' yard-lint --regenerate-todo # Regenerate todo file'
|
|
119
124
|
puts ' yard-lint --auto-gen-config --exclude-limit 10 # Custom grouping threshold'
|
|
125
|
+
puts ' cat lib/foo.rb | yard-lint --stdin lib/foo.rb # Lint source piped from stdin'
|
|
120
126
|
exit
|
|
121
127
|
end
|
|
122
128
|
end.parse!
|
|
@@ -199,6 +205,16 @@ end
|
|
|
199
205
|
# Get path argument (defaults to current directory)
|
|
200
206
|
path = ARGV[0] || '.'
|
|
201
207
|
|
|
208
|
+
# Read stdin source when --stdin flag is given
|
|
209
|
+
stdin_source = nil
|
|
210
|
+
if options[:stdin]
|
|
211
|
+
if path == '.' || File.directory?(path)
|
|
212
|
+
puts 'Error: --stdin requires an explicit file path argument (e.g. yard-lint --stdin lib/foo.rb)'
|
|
213
|
+
exit 1
|
|
214
|
+
end
|
|
215
|
+
stdin_source = $stdin.read
|
|
216
|
+
end
|
|
217
|
+
|
|
202
218
|
# Clear YARD registry to ensure fresh run on each CLI invocation
|
|
203
219
|
YARD::Registry.clear
|
|
204
220
|
|
|
@@ -235,14 +251,21 @@ if options[:only]
|
|
|
235
251
|
config.only_validators = options[:only]
|
|
236
252
|
end
|
|
237
253
|
|
|
254
|
+
# Suppress progress for quickfix to avoid contaminating machine-readable output
|
|
255
|
+
options[:progress] = false if options[:format] == 'quickfix' && options[:progress].nil?
|
|
256
|
+
|
|
238
257
|
# Run the linter
|
|
239
258
|
begin
|
|
240
259
|
result = Yard::Lint.run(
|
|
241
260
|
path: path,
|
|
242
261
|
config: config,
|
|
243
262
|
progress: options[:progress],
|
|
244
|
-
diff: diff_mode
|
|
263
|
+
diff: diff_mode,
|
|
264
|
+
source: stdin_source
|
|
245
265
|
)
|
|
266
|
+
rescue ArgumentError => e
|
|
267
|
+
puts "Error: #{e.message}"
|
|
268
|
+
exit 1
|
|
246
269
|
rescue Yard::Lint::Git::Error => e
|
|
247
270
|
puts "Git error: #{e.message}"
|
|
248
271
|
exit 1
|
|
@@ -251,6 +274,11 @@ rescue Yard::Lint::Errors::FileNotFoundError => e
|
|
|
251
274
|
exit 1
|
|
252
275
|
end
|
|
253
276
|
|
|
277
|
+
# Maps a severity string to its single-character quickfix/display code
|
|
278
|
+
severity_char = lambda do |s|
|
|
279
|
+
{ 'error' => 'E', 'warning' => 'W', 'convention' => 'C', 'never' => 'C' }.fetch(s.to_s, '?')
|
|
280
|
+
end
|
|
281
|
+
|
|
254
282
|
# Format and display results
|
|
255
283
|
case options[:format]
|
|
256
284
|
when 'json'
|
|
@@ -260,6 +288,19 @@ when 'json'
|
|
|
260
288
|
offenses: result.offenses
|
|
261
289
|
})
|
|
262
290
|
exit result.exit_code
|
|
291
|
+
when 'quickfix'
|
|
292
|
+
if config.min_coverage
|
|
293
|
+
coverage = result.documentation_coverage
|
|
294
|
+
if coverage && coverage[:coverage] < config.min_coverage
|
|
295
|
+
warn "Error: Documentation coverage #{coverage[:coverage].round(2)}% is below minimum #{config.min_coverage}%"
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
result.offenses.each do |offense|
|
|
299
|
+
char = severity_char.call(offense[:severity])
|
|
300
|
+
message = offense[:message].to_s.gsub(/\n/, ' ')
|
|
301
|
+
puts "#{offense[:location]}:#{offense[:location_line]}: #{char}: #{offense[:validator]}: #{message}"
|
|
302
|
+
end
|
|
303
|
+
exit result.exit_code
|
|
263
304
|
when 'text', nil
|
|
264
305
|
# Calculate coverage stats if requested or configured
|
|
265
306
|
coverage = result.documentation_coverage if options[:stats] || options[:min_coverage] || config.min_coverage
|
|
@@ -306,15 +347,8 @@ when 'text', nil
|
|
|
306
347
|
puts "Found #{result.count} offense(s):\n\n"
|
|
307
348
|
|
|
308
349
|
result.offenses.each do |offense|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
when 'warning' then 'W'
|
|
312
|
-
when 'convention' then 'C'
|
|
313
|
-
else '?'
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
puts "[#{severity_symbol}] #{offense[:location]}:#{offense[:location_line]}"
|
|
317
|
-
puts " #{offense[:name]}: #{offense[:message]}"
|
|
350
|
+
puts "[#{severity_char.call(offense[:severity])}] #{offense[:location]}:#{offense[:location_line]}"
|
|
351
|
+
puts " #{offense[:validator]}: #{offense[:message]}"
|
|
318
352
|
puts
|
|
319
353
|
end
|
|
320
354
|
end
|
|
@@ -21,8 +21,10 @@ module Yard
|
|
|
21
21
|
# Parse Ruby source files and populate the YARD registry.
|
|
22
22
|
# Captures any warnings emitted by YARD during parsing for later dispatch.
|
|
23
23
|
# @param files [Array<String>] absolute or relative paths to Ruby source files
|
|
24
|
+
# @param source [String, nil] in-memory source; when given, `files.first` is used
|
|
25
|
+
# as the virtual filename for registry/location reporting only
|
|
24
26
|
# @return [void]
|
|
25
|
-
def parse(files)
|
|
27
|
+
def parse(files, source: nil)
|
|
26
28
|
@mutex.synchronize do
|
|
27
29
|
return if @parsed
|
|
28
30
|
|
|
@@ -33,16 +35,28 @@ module Yard
|
|
|
33
35
|
original_level = YARD::Logger.instance.level
|
|
34
36
|
YARD::Logger.instance.level = 4 # Only show fatal errors
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
if source
|
|
39
|
+
virtual_path = files.first
|
|
40
|
+
# First pass: register directive/macro definitions from the in-memory source.
|
|
41
|
+
# We set parser.file manually so registered objects carry the virtual path.
|
|
42
|
+
parse_source_string(source, virtual_path)
|
|
43
|
+
# Clear checksums so the second pass is not skipped
|
|
44
|
+
YARD::Registry.checksums.clear
|
|
45
|
+
# Second pass: full parse with all directives available
|
|
46
|
+
@warnings = capture_warnings { parse_source_string(source, virtual_path) }
|
|
47
|
+
else
|
|
48
|
+
# First pass: parse all files to process directive definitions
|
|
49
|
+
YARD.parse(files)
|
|
50
|
+
|
|
51
|
+
# Clear checksums to force reparsing without clearing the registry.
|
|
52
|
+
# This allows macro definitions from the first pass to be available
|
|
53
|
+
# during the second pass, enabling proper directive expansion regardless of parse order.
|
|
54
|
+
YARD::Registry.checksums.clear
|
|
55
|
+
|
|
56
|
+
# Second pass: reparse files now that all directive definitions are available
|
|
57
|
+
@warnings = capture_warnings { YARD.parse(files) }
|
|
58
|
+
end
|
|
43
59
|
|
|
44
|
-
# Second pass: reparse files now that all directive definitions are available
|
|
45
|
-
@warnings = capture_warnings { YARD.parse(files) }
|
|
46
60
|
@parsed = true
|
|
47
61
|
|
|
48
62
|
YARD::Logger.instance.level = original_level
|
|
@@ -110,6 +124,18 @@ module Yard
|
|
|
110
124
|
|
|
111
125
|
private
|
|
112
126
|
|
|
127
|
+
# Parse Ruby source from a string and register objects under a virtual path.
|
|
128
|
+
# YARD::Parser::SourceParser#parse accepts a StringIO but keeps @file as '(stdin)'
|
|
129
|
+
# unless we set it explicitly before parsing.
|
|
130
|
+
# @param source [String] Ruby source code to parse
|
|
131
|
+
# @param virtual_path [String] filename to assign to registered objects
|
|
132
|
+
# @return [void]
|
|
133
|
+
def parse_source_string(source, virtual_path)
|
|
134
|
+
parser = YARD::Parser::SourceParser.new(:ruby)
|
|
135
|
+
parser.file = virtual_path
|
|
136
|
+
parser.parse(StringIO.new(source))
|
|
137
|
+
end
|
|
138
|
+
|
|
113
139
|
# Capture warnings during a block execution
|
|
114
140
|
# @yield Block to execute while capturing warnings
|
|
115
141
|
# @return [Array<String>] captured warnings
|
|
@@ -130,8 +156,8 @@ module Yard
|
|
|
130
156
|
|
|
131
157
|
captured
|
|
132
158
|
ensure
|
|
133
|
-
|
|
134
|
-
|
|
159
|
+
sc = YARD::Logger.instance.singleton_class
|
|
160
|
+
sc.remove_method(:warn) if sc.public_instance_methods(false).include?(:warn)
|
|
135
161
|
end
|
|
136
162
|
end
|
|
137
163
|
end
|
|
@@ -96,6 +96,8 @@ module Yard
|
|
|
96
96
|
# @return [String] validator name for config lookup
|
|
97
97
|
def validator_name
|
|
98
98
|
# Extract from class path: Validators::Tags::Order::Result => 'Tags/Order'
|
|
99
|
+
return '' unless self.class.name
|
|
100
|
+
|
|
99
101
|
parts = self.class.name.split('::')
|
|
100
102
|
validators_index = parts.index('Validators')
|
|
101
103
|
return '' unless validators_index
|
|
@@ -125,6 +127,7 @@ module Yard
|
|
|
125
127
|
severity: configured_severity,
|
|
126
128
|
type: self.class.offense_type,
|
|
127
129
|
name: computed_offense_name,
|
|
130
|
+
validator: validator_name,
|
|
128
131
|
message: build_message(offense_data),
|
|
129
132
|
location: offense_data[:location] || offense_data[:file],
|
|
130
133
|
location_line: offense_data[:line] || offense_data[:location_line] || 0
|
data/lib/yard/lint/runner.rb
CHANGED
|
@@ -15,9 +15,11 @@ module Yard
|
|
|
15
15
|
|
|
16
16
|
# @param selection [Array<String>] array with ruby files to check
|
|
17
17
|
# @param config [Yard::Lint::Config] configuration object
|
|
18
|
-
|
|
18
|
+
# @param source [String, nil] in-memory source content (overrides disk reads)
|
|
19
|
+
def initialize(selection, config = Config.new, source: nil)
|
|
19
20
|
@selection = Array(selection).flatten
|
|
20
21
|
@config = config
|
|
22
|
+
@source = source
|
|
21
23
|
@result_builder = ResultBuilder.new(config)
|
|
22
24
|
@progress_formatter = nil
|
|
23
25
|
end
|
|
@@ -45,7 +47,7 @@ module Yard
|
|
|
45
47
|
|
|
46
48
|
# Initialize in-process infrastructure
|
|
47
49
|
registry = Executor::InProcessRegistry.new
|
|
48
|
-
registry.parse(selection)
|
|
50
|
+
registry.parse(selection, source: @source)
|
|
49
51
|
|
|
50
52
|
query_executor = Executor::QueryExecutor.new(registry)
|
|
51
53
|
warning_dispatcher = Executor::WarningDispatcher.new
|
|
@@ -36,21 +36,34 @@ Documentation/UndocumentedObjects:
|
|
|
36
36
|
ExcludedMethods:
|
|
37
37
|
- 'initialize/0' # Exclude parameter-less initialize
|
|
38
38
|
- '/^_/' # Exclude private methods (by convention)
|
|
39
|
+
# AllowedParentClasses:
|
|
40
|
+
# - StandardError # Skip error subclasses
|
|
41
|
+
# - ApplicationRecord # Skip Rails model subclasses
|
|
39
42
|
|
|
40
43
|
Documentation/UndocumentedMethodArguments:
|
|
41
44
|
Description: 'Checks for method parameters without @param tags.'
|
|
42
45
|
Enabled: true
|
|
43
46
|
Severity: warning
|
|
47
|
+
# AllowedParentClasses:
|
|
48
|
+
# - StandardError
|
|
49
|
+
# AllowedMethods: skip @param checks for specific methods (exact name, name/arity, /regex/)
|
|
50
|
+
# - call
|
|
51
|
+
# - perform
|
|
52
|
+
# - initialize/1
|
|
44
53
|
|
|
45
54
|
Documentation/UndocumentedBooleanMethods:
|
|
46
55
|
Description: 'Checks that question mark methods document their boolean return.'
|
|
47
56
|
Enabled: true
|
|
48
57
|
Severity: warning
|
|
58
|
+
# AllowedParentClasses:
|
|
59
|
+
# - StandardError
|
|
49
60
|
|
|
50
61
|
Documentation/UndocumentedOptions:
|
|
51
62
|
Description: 'Detects methods with options hash parameters but no @option tags.'
|
|
52
63
|
Enabled: true
|
|
53
64
|
Severity: warning
|
|
65
|
+
# AllowedParentClasses:
|
|
66
|
+
# - StandardError
|
|
54
67
|
|
|
55
68
|
Documentation/MissingReturn:
|
|
56
69
|
Description: 'Requires @return tags on all methods (opt-in for strict documentation).'
|
|
@@ -59,6 +72,13 @@ Documentation/MissingReturn:
|
|
|
59
72
|
ExcludedMethods:
|
|
60
73
|
- 'initialize' # Exclude all initialize methods
|
|
61
74
|
# - '/^_/' # Uncomment to exclude private methods (by convention)
|
|
75
|
+
# AllowedParentClasses:
|
|
76
|
+
# - StandardError
|
|
77
|
+
|
|
78
|
+
Documentation/OrphanedDocComment:
|
|
79
|
+
Description: 'Detects YARD comment blocks with tags not attached to any documentable construct.'
|
|
80
|
+
Enabled: true
|
|
81
|
+
Severity: warning
|
|
62
82
|
|
|
63
83
|
Documentation/MarkdownSyntax:
|
|
64
84
|
Description: 'Detects common markdown syntax errors in documentation.'
|
|
@@ -82,6 +102,20 @@ Documentation/BlankLineBeforeDefinition:
|
|
|
82
102
|
SingleBlankLine: true
|
|
83
103
|
OrphanedDocs: true
|
|
84
104
|
|
|
105
|
+
Documentation/LineLength:
|
|
106
|
+
Description: 'Detects documentation comment lines that exceed the configured maximum length.'
|
|
107
|
+
Enabled: false # Opt-in validator
|
|
108
|
+
Severity: convention
|
|
109
|
+
MaxLength: 120
|
|
110
|
+
|
|
111
|
+
Documentation/TextSubstitution:
|
|
112
|
+
Description: 'Detects forbidden characters or strings in documentation and suggests replacements.'
|
|
113
|
+
Enabled: false # Opt-in validator
|
|
114
|
+
Severity: warning
|
|
115
|
+
Substitutions:
|
|
116
|
+
"—": "-" # em-dash (U+2014)
|
|
117
|
+
"–": "-" # en-dash (U+2013)
|
|
118
|
+
|
|
85
119
|
# Tags validators
|
|
86
120
|
Tags/Order:
|
|
87
121
|
Description: 'Enforces consistent ordering of YARD tags.'
|
|
@@ -131,6 +165,11 @@ Tags/MeaninglessTag:
|
|
|
131
165
|
- module
|
|
132
166
|
- constant
|
|
133
167
|
|
|
168
|
+
Tags/MissingYield:
|
|
169
|
+
Description: 'Detects methods that yield to a block without a @yield, @yieldparam, or @yieldreturn tag.'
|
|
170
|
+
Enabled: false # Opt-in validator
|
|
171
|
+
Severity: warning
|
|
172
|
+
|
|
134
173
|
Tags/CollectionType:
|
|
135
174
|
Description: 'Validates Hash collection syntax consistency.'
|
|
136
175
|
Enabled: true
|
|
@@ -205,6 +244,7 @@ Tags/RedundantParamDescription:
|
|
|
205
244
|
- element
|
|
206
245
|
EnabledPatterns:
|
|
207
246
|
ArticleParam: true
|
|
247
|
+
ArticleParamPhrase: true
|
|
208
248
|
PossessiveParam: true
|
|
209
249
|
TypeRestatement: true
|
|
210
250
|
ParamToVerb: true
|