yard-lint 0.2.1 → 1.0.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 +33 -1
- data/README.md +256 -1
- data/bin/yard-lint +24 -0
- data/lib/yard/lint/config.rb +35 -1
- data/lib/yard/lint/config_loader.rb +1 -1
- data/lib/yard/lint/result_builder.rb +10 -1
- data/lib/yard/lint/validators/base.rb +41 -12
- data/lib/yard/lint/validators/documentation/undocumented_boolean_methods/validator.rb +7 -6
- data/lib/yard/lint/validators/documentation/undocumented_method_arguments/validator.rb +4 -5
- data/lib/yard/lint/validators/documentation/undocumented_objects/config.rb +2 -1
- data/lib/yard/lint/validators/documentation/undocumented_objects/parser.rb +95 -5
- data/lib/yard/lint/validators/documentation/undocumented_objects/validator.rb +15 -11
- data/lib/yard/lint/validators/semantic/abstract_methods/validator.rb +4 -5
- data/lib/yard/lint/validators/tags/api_tags/validator.rb +4 -5
- data/lib/yard/lint/validators/tags/collection_type/config.rb +21 -0
- data/lib/yard/lint/validators/tags/collection_type/messages_builder.rb +44 -0
- data/lib/yard/lint/validators/tags/collection_type/parser.rb +49 -0
- data/lib/yard/lint/validators/tags/collection_type/result.rb +25 -0
- data/lib/yard/lint/validators/tags/collection_type/validator.rb +73 -0
- data/lib/yard/lint/validators/tags/collection_type.rb +14 -0
- data/lib/yard/lint/validators/tags/invalid_types/validator.rb +6 -6
- data/lib/yard/lint/validators/tags/meaningless_tag/config.rb +22 -0
- data/lib/yard/lint/validators/tags/meaningless_tag/messages_builder.rb +28 -0
- data/lib/yard/lint/validators/tags/meaningless_tag/parser.rb +53 -0
- data/lib/yard/lint/validators/tags/meaningless_tag/result.rb +26 -0
- data/lib/yard/lint/validators/tags/meaningless_tag/validator.rb +84 -0
- data/lib/yard/lint/validators/tags/meaningless_tag.rb +15 -0
- data/lib/yard/lint/validators/tags/option_tags/validator.rb +4 -5
- data/lib/yard/lint/validators/tags/order/validator.rb +4 -5
- data/lib/yard/lint/validators/tags/tag_type_position/config.rb +22 -0
- data/lib/yard/lint/validators/tags/tag_type_position/messages_builder.rb +38 -0
- data/lib/yard/lint/validators/tags/tag_type_position/parser.rb +51 -0
- data/lib/yard/lint/validators/tags/tag_type_position/result.rb +25 -0
- data/lib/yard/lint/validators/tags/tag_type_position/validator.rb +113 -0
- data/lib/yard/lint/validators/tags/tag_type_position.rb +14 -0
- data/lib/yard/lint/validators/tags/type_syntax/config.rb +21 -0
- data/lib/yard/lint/validators/tags/type_syntax/messages_builder.rb +27 -0
- data/lib/yard/lint/validators/tags/type_syntax/parser.rb +54 -0
- data/lib/yard/lint/validators/tags/type_syntax/result.rb +25 -0
- data/lib/yard/lint/validators/tags/type_syntax/validator.rb +76 -0
- data/lib/yard/lint/validators/tags/type_syntax.rb +14 -0
- data/lib/yard/lint/validators/warnings/duplicated_parameter_name/validator.rb +4 -5
- data/lib/yard/lint/validators/warnings/invalid_directive_format/validator.rb +4 -5
- data/lib/yard/lint/validators/warnings/invalid_tag_format/validator.rb +4 -5
- data/lib/yard/lint/validators/warnings/unknown_directive/validator.rb +4 -5
- data/lib/yard/lint/validators/warnings/unknown_parameter_name/parser.rb +4 -1
- data/lib/yard/lint/validators/warnings/unknown_parameter_name/validator.rb +4 -5
- data/lib/yard/lint/validators/warnings/unknown_tag/validator.rb +4 -5
- data/lib/yard/lint/version.rb +1 -1
- data/lib/yard/lint.rb +1 -0
- data/misc/logo.png +0 -0
- metadata +26 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 312a8649c021c9df03d03240a80da73a5985b692f784bbe1143cf6f7138dbb78
|
|
4
|
+
data.tar.gz: ba230c3af103171163396ccc31ac2b4b8fb400b98faba25705072558ee9b71bb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d14c94827a3b20f08c283aff9e60f82473dd91522e35f434012cf7b90bd23f7aeaaa3e4f95788d3e7fd32870ac96ee75c953b2bf176c4f38cc44ef9d0cb2e874
|
|
7
|
+
data.tar.gz: b8d9bdf4583ea0553b8badd02266d03b402a50926f26492ba1d5c956ee275d2e9fab97bcc773e9d7d160acae76e10746a8103937fa5ea01aeb46e0480fd0a0e2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,36 @@
|
|
|
1
|
-
# Changelog
|
|
1
|
+
# YARD-Lint Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0 (2025-11-09)
|
|
4
|
+
- [Fix] Fix "Argument list too long" error on large codebases by using xargs pattern with temporary file lists
|
|
5
|
+
- [Enhancement] Expand default exclusion patterns to include typical Ruby/Rails directories (test/, log/, coverage/, db/migrate/, etc.)
|
|
6
|
+
- **[Feature]** Add `Tags/TypeSyntax` validator to detect malformed YARD type syntax using YARD's built-in parser
|
|
7
|
+
- Detects unclosed brackets: `Array<`, `Hash{Symbol =>`
|
|
8
|
+
- Detects empty generics: `Array<>`
|
|
9
|
+
- Detects malformed hash syntax: `Hash{Symbol}`
|
|
10
|
+
- Configurable `ValidatedTags` option (default: param, option, return, yieldreturn)
|
|
11
|
+
- **[Feature]** Add `Tags/MeaninglessTag` validator to detect `@param` and `@option` tags on non-method objects
|
|
12
|
+
- Prevents meaningless tags on classes, modules, and constants
|
|
13
|
+
- Configurable `CheckedTags` (default: param, option) and `InvalidObjectTypes` (default: class, module, constant)
|
|
14
|
+
- **[Feature]** Add `Tags/CollectionType` validator to enforce YARD's Hash collection syntax
|
|
15
|
+
- Enforces `Hash{K => V}` over `Hash<K, V>` (generic syntax from other languages)
|
|
16
|
+
- Configurable `ValidatedTags` (default: param, option, return, yieldreturn)
|
|
17
|
+
- Provides automatic correction suggestions
|
|
18
|
+
- **[Feature]** Add `Tags/TagTypePosition` validator to validate type annotation position in tags
|
|
19
|
+
- Configurable style: `type_after_name` (YARD standard: `@param name [Type]`) or `type_first` (`@param [Type] name`)
|
|
20
|
+
- Only validates `@param` and `@option` tags (excludes `@return` as it has no parameter name)
|
|
21
|
+
- Reads source code directly to avoid false positives from YARD's internal docstring normalization
|
|
22
|
+
- [Fix] Fix `Warnings/UnknownParameterName` validator showing only line number instead of full file path by correcting regex pattern
|
|
23
|
+
- [Enhancement] Add comprehensive integration tests for `UnknownParameterName` validator
|
|
24
|
+
- [Documentation] Add inline documentation explaining cache clearing in bin/yard-lint
|
|
25
|
+
- [Documentation] Expand README with troubleshooting section for ExcludedMethods patterns
|
|
26
|
+
|
|
27
|
+
## 0.2.2 (2025-11-07)
|
|
28
|
+
- **[Feature]** Add `ExcludedMethods` configuration option to exclude methods from validation using simple names, regex patterns, or arity notation (default excludes parameter-less `initialize/0` methods).
|
|
29
|
+
- [Fix] Fix `UndocumentedObjects` validator incorrectly flagging methods with `@return [Boolean]` tags as undocumented by using `docstring.all.empty?` instead of `docstring.blank?`.
|
|
30
|
+
- [Fix] Fix `UndocumentedBooleanMethods` validator incorrectly flagging methods with `@return [Boolean]` (type without description text) by checking for return types instead of description text.
|
|
31
|
+
- [Enhancement] Implement per-arguments YARD database isolation using SHA256 hash of arguments to prevent contamination between validators with different file selections.
|
|
32
|
+
- [Refactoring] Remove file filtering workaround as database isolation eliminates the need for it.
|
|
33
|
+
- [Change] YARD database directories are now created under a base temp directory with unique subdirectories per argument set.
|
|
2
34
|
|
|
3
35
|
## 0.2.1 (2025-11-07)
|
|
4
36
|
- Release to validate Trusted Publishing flow.
|
data/README.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
[](https://github.com/mensfeld/yard-lint/actions/workflows/ci.yml)
|
|
4
|
+
[](http://badge.fury.io/rb/yard-lint)
|
|
5
|
+
|
|
1
6
|
# YARD-Lint
|
|
2
7
|
|
|
3
8
|
A comprehensive linter for YARD documentation that helps you maintain clean, consistent, and complete documentation in your Ruby and Ruby on Rails projects.
|
|
@@ -17,7 +22,11 @@ YARD-Lint validates your YARD documentation for:
|
|
|
17
22
|
- **Undocumented code**: Classes, modules, methods, and constants without documentation
|
|
18
23
|
- **Missing parameter documentation**: Methods with undocumented parameters
|
|
19
24
|
- **Invalid tag types**: Type definitions that aren't valid Ruby classes or allowed defaults
|
|
25
|
+
- **Invalid type syntax**: Malformed YARD type syntax (unclosed brackets, empty generics, etc.)
|
|
20
26
|
- **Invalid tag ordering**: Tags that don't follow your specified order
|
|
27
|
+
- **Meaningless tags**: `@param` or `@option` tags on classes, modules, or constants (only valid on methods)
|
|
28
|
+
- **Collection type syntax**: Enforces `Hash{K => V}` over `Hash<K, V>` (YARD standard)
|
|
29
|
+
- **Type annotation position**: Validates whether types appear before or after parameter names (configurable)
|
|
21
30
|
- **Boolean method documentation**: Question mark methods missing return type documentation
|
|
22
31
|
- **API tag validation**: Enforce @api tags on public objects and validate API values
|
|
23
32
|
- **Abstract method validation**: Ensure @abstract methods don't have real implementations
|
|
@@ -96,6 +105,14 @@ Documentation/UndocumentedObjects:
|
|
|
96
105
|
Description: 'Checks for classes, modules, and methods without documentation.'
|
|
97
106
|
Enabled: true
|
|
98
107
|
Severity: warning
|
|
108
|
+
# List of methods to exclude from validation
|
|
109
|
+
# Supports three patterns:
|
|
110
|
+
# - Exact names: 'method_name' (excludes all methods with this name)
|
|
111
|
+
# - Arity notation: 'method_name/N' (excludes only if method has N parameters)
|
|
112
|
+
# - Regex patterns: '/pattern/' (excludes methods matching the regex)
|
|
113
|
+
ExcludedMethods:
|
|
114
|
+
- 'initialize/0' # Exclude only parameter-less initialize (default)
|
|
115
|
+
- '/^_/' # Exclude private methods (by convention)
|
|
99
116
|
|
|
100
117
|
Documentation/UndocumentedMethodArguments:
|
|
101
118
|
Description: 'Checks for method parameters without @param tags.'
|
|
@@ -130,6 +147,49 @@ Tags/InvalidTypes:
|
|
|
130
147
|
- CustomType
|
|
131
148
|
- MyType
|
|
132
149
|
|
|
150
|
+
Tags/TypeSyntax:
|
|
151
|
+
Description: 'Validates YARD type syntax using YARD parser.'
|
|
152
|
+
Enabled: true
|
|
153
|
+
Severity: warning
|
|
154
|
+
ValidatedTags:
|
|
155
|
+
- param
|
|
156
|
+
- option
|
|
157
|
+
- return
|
|
158
|
+
- yieldreturn
|
|
159
|
+
|
|
160
|
+
Tags/MeaninglessTag:
|
|
161
|
+
Description: 'Detects @param/@option tags on classes, modules, or constants.'
|
|
162
|
+
Enabled: true
|
|
163
|
+
Severity: warning
|
|
164
|
+
CheckedTags:
|
|
165
|
+
- param
|
|
166
|
+
- option
|
|
167
|
+
InvalidObjectTypes:
|
|
168
|
+
- class
|
|
169
|
+
- module
|
|
170
|
+
- constant
|
|
171
|
+
|
|
172
|
+
Tags/CollectionType:
|
|
173
|
+
Description: 'Validates Hash collection syntax (enforces Hash{K => V} over Hash<K, V>).'
|
|
174
|
+
Enabled: true
|
|
175
|
+
Severity: convention
|
|
176
|
+
ValidatedTags:
|
|
177
|
+
- param
|
|
178
|
+
- option
|
|
179
|
+
- return
|
|
180
|
+
- yieldreturn
|
|
181
|
+
|
|
182
|
+
Tags/TagTypePosition:
|
|
183
|
+
Description: 'Validates type annotation position in tags.'
|
|
184
|
+
Enabled: true
|
|
185
|
+
Severity: convention
|
|
186
|
+
CheckedTags:
|
|
187
|
+
- param
|
|
188
|
+
- option
|
|
189
|
+
# EnforcedStyle: 'type_after_name' (YARD standard: @param name [Type])
|
|
190
|
+
# or 'type_first' (@param [Type] name)
|
|
191
|
+
EnforcedStyle: type_after_name
|
|
192
|
+
|
|
133
193
|
Tags/ApiTags:
|
|
134
194
|
Description: 'Enforces @api tags on public objects.'
|
|
135
195
|
Enabled: false # Opt-in validator
|
|
@@ -297,12 +357,16 @@ Supported glob patterns:
|
|
|
297
357
|
| Validator | Description | Default | Configuration Options |
|
|
298
358
|
|-----------|-------------|---------|----------------------|
|
|
299
359
|
| **Documentation Validators** |
|
|
300
|
-
| `Documentation/UndocumentedObjects` | Checks for classes, modules, and methods without documentation | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
|
|
360
|
+
| `Documentation/UndocumentedObjects` | Checks for classes, modules, and methods without documentation | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `ExcludedMethods` |
|
|
301
361
|
| `Documentation/UndocumentedMethodArguments` | Checks for method parameters without `@param` tags | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
|
|
302
362
|
| `Documentation/UndocumentedBooleanMethods` | Checks that question mark methods document their boolean return | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
|
|
303
363
|
| **Tags Validators** |
|
|
304
364
|
| `Tags/Order` | Enforces consistent ordering of YARD tags | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `EnforcedOrder` |
|
|
305
365
|
| `Tags/InvalidTypes` | Validates type definitions in `@param`, `@return`, `@option` tags | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `ValidatedTags`, `ExtraTypes` |
|
|
366
|
+
| `Tags/TypeSyntax` | Validates YARD type syntax (detects unclosed brackets, empty generics, etc.) | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `ValidatedTags` |
|
|
367
|
+
| `Tags/MeaninglessTag` | Detects `@param`/`@option` tags on classes, modules, or constants (only valid on methods) | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `CheckedTags`, `InvalidObjectTypes` |
|
|
368
|
+
| `Tags/CollectionType` | Enforces `Hash{K => V}` over `Hash<K, V>` (YARD standard collection syntax) | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `ValidatedTags` |
|
|
369
|
+
| `Tags/TagTypePosition` | Validates type annotation position (`@param name [Type]` vs `@param [Type] name`) | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `CheckedTags`, `EnforcedStyle` |
|
|
306
370
|
| `Tags/ApiTags` | Enforces `@api` tags on public objects | Disabled (opt-in) | `Enabled`, `Severity`, `Exclude`, `AllowedApis` |
|
|
307
371
|
| `Tags/OptionTags` | Requires `@option` tags for methods with options parameters | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
|
|
308
372
|
| **Warnings Validators** |
|
|
@@ -315,6 +379,118 @@ Supported glob patterns:
|
|
|
315
379
|
| **Semantic Validators** |
|
|
316
380
|
| `Semantic/AbstractMethods` | Ensures `@abstract` methods don't have real implementations | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
|
|
317
381
|
|
|
382
|
+
### Excluding Methods from Documentation Validation
|
|
383
|
+
|
|
384
|
+
The `Documentation/UndocumentedObjects` validator supports a flexible `ExcludedMethods` configuration option that allows you to exclude specific methods from documentation requirements. This supports three pattern types:
|
|
385
|
+
|
|
386
|
+
#### Pattern Types
|
|
387
|
+
|
|
388
|
+
1. **Exact Name Matching**
|
|
389
|
+
```yaml
|
|
390
|
+
ExcludedMethods:
|
|
391
|
+
- 'to_s' # Excludes ALL to_s methods regardless of parameters
|
|
392
|
+
- 'inspect' # Excludes ALL inspect methods
|
|
393
|
+
```
|
|
394
|
+
Note: Exact name matching excludes the method with **any arity**. If you need arity-specific exclusions, use arity notation instead.
|
|
395
|
+
|
|
396
|
+
2. **Arity Notation** (method_name/N)
|
|
397
|
+
```yaml
|
|
398
|
+
ExcludedMethods:
|
|
399
|
+
- 'initialize/0' # Only excludes initialize with NO parameters (default)
|
|
400
|
+
- 'call/1' # Only excludes call methods with exactly 1 parameter
|
|
401
|
+
- 'initialize/2' # Only excludes initialize with exactly 2 parameters
|
|
402
|
+
```
|
|
403
|
+
Note: Arity counts total parameters (required + optional) excluding splat (*) and block (&) parameters.
|
|
404
|
+
|
|
405
|
+
3. **Regex Patterns**
|
|
406
|
+
```yaml
|
|
407
|
+
ExcludedMethods:
|
|
408
|
+
- '/^_/' # Excludes all methods starting with underscore (private convention)
|
|
409
|
+
- '/^test_/' # Excludes all test methods
|
|
410
|
+
- '/_(helper|util)$/' # Excludes methods ending with _helper or _util
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
#### Examples
|
|
414
|
+
|
|
415
|
+
```yaml
|
|
416
|
+
# Minimal setup: only exclude parameter-less initialize
|
|
417
|
+
Documentation/UndocumentedObjects:
|
|
418
|
+
ExcludedMethods:
|
|
419
|
+
- 'initialize/0'
|
|
420
|
+
|
|
421
|
+
# Common Rails/Ruby patterns
|
|
422
|
+
Documentation/UndocumentedObjects:
|
|
423
|
+
ExcludedMethods:
|
|
424
|
+
- 'initialize/0' # Parameter-less constructors
|
|
425
|
+
- '/^_/' # Private methods (by convention)
|
|
426
|
+
- 'to_s' # String conversion
|
|
427
|
+
- 'inspect' # Object inspection
|
|
428
|
+
- 'hash' # Hash code generation
|
|
429
|
+
- 'eql?' # Equality comparison
|
|
430
|
+
- '==' # Binary equality operator
|
|
431
|
+
- '<=>' # Spaceship operator (comparison)
|
|
432
|
+
- '+' # Addition operator
|
|
433
|
+
- '-' # Subtraction operator
|
|
434
|
+
- '+@' # Unary plus operator
|
|
435
|
+
- '-@' # Unary minus operator
|
|
436
|
+
|
|
437
|
+
# Test framework exclusions
|
|
438
|
+
Documentation/UndocumentedObjects:
|
|
439
|
+
ExcludedMethods:
|
|
440
|
+
- '/^test_/' # Minitest methods
|
|
441
|
+
- '/^should_/' # Shoulda methods
|
|
442
|
+
- 'setup/0' # Setup with no params
|
|
443
|
+
- 'teardown/0' # Teardown with no params
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
#### Pattern Validation & Edge Cases
|
|
447
|
+
|
|
448
|
+
The `ExcludedMethods` feature includes robust validation and error handling:
|
|
449
|
+
|
|
450
|
+
**Automatic Pattern Sanitization:**
|
|
451
|
+
- **Nil values** are automatically removed
|
|
452
|
+
- **Empty strings** and whitespace-only patterns are filtered out
|
|
453
|
+
- **Whitespace trimming** is applied to all patterns
|
|
454
|
+
- **Empty regex patterns** (`//`) are rejected (would match everything)
|
|
455
|
+
- **Non-array values** are automatically converted to arrays
|
|
456
|
+
|
|
457
|
+
**Invalid Pattern Handling:**
|
|
458
|
+
- **Invalid regex patterns** (e.g., `/[/`, `/(unclosed`) are silently skipped without crashing
|
|
459
|
+
- **Invalid arity notation** (e.g., `method/abc`, `method/`) is silently skipped
|
|
460
|
+
- **Pattern matching is case-sensitive** for both exact names and regex
|
|
461
|
+
|
|
462
|
+
**Operator Method Support:**
|
|
463
|
+
YARD-Lint fully supports Ruby operator methods including:
|
|
464
|
+
- Binary operators: `+`, `-`, `*`, `/`, `%`, `**`, `==`, `!=`, `===`, `<`, `>`, `<=`, `>=`, `<=>`, `&`, `|`, `^`, `<<`, `>>`
|
|
465
|
+
- Unary operators: `+@`, `-@`, `!`, `~`
|
|
466
|
+
- Other special methods: `[]`, `[]=`, `=~`
|
|
467
|
+
|
|
468
|
+
**Pattern Matching Behavior:**
|
|
469
|
+
- **Any match excludes**: If a method matches any pattern, it is excluded from validation
|
|
470
|
+
- **Patterns are evaluated in order** as defined in the configuration
|
|
471
|
+
- **Exact names have no arity restriction**: `'initialize'` excludes all initialize methods, regardless of parameters
|
|
472
|
+
- **Arity notation is strict**: `'initialize/0'` only excludes initialize with exactly 0 parameters
|
|
473
|
+
|
|
474
|
+
#### Troubleshooting ExcludedMethods
|
|
475
|
+
|
|
476
|
+
**Methods still showing as undocumented:**
|
|
477
|
+
1. Verify the method name matches exactly (case-sensitive)
|
|
478
|
+
2. Check if you're using arity notation - ensure the arity count is correct
|
|
479
|
+
3. For regex patterns, test your regex independently to ensure it matches
|
|
480
|
+
4. Remember: Arity counts `required + optional` parameters, **excluding** splat (`*args`) and block (`&block`)
|
|
481
|
+
|
|
482
|
+
**Regex patterns not working:**
|
|
483
|
+
1. Ensure you're using `/pattern/` format with forward slashes
|
|
484
|
+
2. Test the regex in Ruby: `Regexp.new('your_pattern').match?('method_name')`
|
|
485
|
+
3. Escape special regex characters: `\.`, `\(`, `\)`, `\[`, `\]`, etc.
|
|
486
|
+
4. Invalid regex patterns are silently skipped - check for syntax errors
|
|
487
|
+
|
|
488
|
+
**Arity not matching:**
|
|
489
|
+
1. Count parameters correctly: `def method(a, b = 1)` has arity 2 (required + optional)
|
|
490
|
+
2. Splat parameters don't count: `def method(a, *rest)` has arity 1
|
|
491
|
+
3. Block parameters don't count: `def method(a, &block)` has arity 1
|
|
492
|
+
4. Keyword arguments count as individual parameters: `def method(a:, b:)` has arity 2
|
|
493
|
+
|
|
318
494
|
### Global Configuration
|
|
319
495
|
|
|
320
496
|
| Option | Description | Default | Type |
|
|
@@ -449,6 +625,85 @@ def configure(name, options = {})
|
|
|
449
625
|
end
|
|
450
626
|
```
|
|
451
627
|
|
|
628
|
+
### Meaningless tag validation (enabled by default)
|
|
629
|
+
|
|
630
|
+
This validator prevents `@param` and `@option` tags from being used on classes, modules, or constants, where they make no sense (these tags are only valid on methods).
|
|
631
|
+
|
|
632
|
+
```ruby
|
|
633
|
+
# Bad - @param on a class
|
|
634
|
+
# @param name [String] this makes no sense on a class
|
|
635
|
+
class User
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
# Bad - @option on a module
|
|
639
|
+
# @option config [Boolean] :enabled modules don't have parameters
|
|
640
|
+
module Authentication
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
# Good - @param on a method
|
|
644
|
+
class User
|
|
645
|
+
# @param name [String] the user's name
|
|
646
|
+
def initialize(name)
|
|
647
|
+
@name = name
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
To disable this validator:
|
|
653
|
+
|
|
654
|
+
```yaml
|
|
655
|
+
Tags/MeaninglessTag:
|
|
656
|
+
Enabled: false
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### Collection type syntax validation (enabled by default)
|
|
660
|
+
|
|
661
|
+
YARD uses `Hash{K => V}` syntax for hashes, not `Hash<K, V>` (which is generic syntax from other languages). This validator enforces the correct YARD syntax.
|
|
662
|
+
|
|
663
|
+
```ruby
|
|
664
|
+
# Bad - using generic syntax
|
|
665
|
+
# @param options [Hash<Symbol, String>] configuration
|
|
666
|
+
def configure(options)
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
# Good - using YARD syntax
|
|
670
|
+
# @param options [Hash{Symbol => String}] configuration
|
|
671
|
+
def configure(options)
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
# Also good - Array uses angle brackets
|
|
675
|
+
# @param items [Array<String>] list of items
|
|
676
|
+
def process(items)
|
|
677
|
+
end
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
To disable this validator:
|
|
681
|
+
|
|
682
|
+
```yaml
|
|
683
|
+
Tags/CollectionType:
|
|
684
|
+
Enabled: false
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### Type annotation position validation (enabled by default)
|
|
688
|
+
|
|
689
|
+
This validator ensures consistent type annotation positioning. By default, it enforces YARD standard (`@param name [Type]`), but you can configure it to enforce `type_first` style if your team prefers it.
|
|
690
|
+
|
|
691
|
+
```ruby
|
|
692
|
+
# Good - type after parameter name (YARD standard)
|
|
693
|
+
# @param name [String] the user's name
|
|
694
|
+
# @param age [Integer] the user's age
|
|
695
|
+
def create_user(name, age)
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
# Bad - type before parameter name
|
|
699
|
+
# @param [String] name the user's name
|
|
700
|
+
# @param [Integer] age the user's age
|
|
701
|
+
def create_user(name, age)
|
|
702
|
+
end
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
To use `type_first` style instead, set `EnforcedStyle: type_first` in your `.yard-lint.yml`.
|
|
706
|
+
|
|
452
707
|
## License
|
|
453
708
|
|
|
454
709
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/bin/yard-lint
CHANGED
|
@@ -52,6 +52,30 @@ unless path
|
|
|
52
52
|
exit 1
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
# Clear YARD database and command cache to ensure fresh run on each CLI invocation
|
|
56
|
+
#
|
|
57
|
+
# Why this is necessary:
|
|
58
|
+
#
|
|
59
|
+
# 1. **Command Cache Reset** (`reset_command_cache!`)
|
|
60
|
+
# - The command cache stores results from YARD commands across validator instances
|
|
61
|
+
# - This cache is shared at the class level (Base.@shared_command_cache)
|
|
62
|
+
# - Without reset: Results from a previous CLI run could leak into the current run
|
|
63
|
+
# - Critical for CLI: Each `yard-lint` invocation should start with clean state
|
|
64
|
+
# - Not needed in-process: Within a single run, caching YARD results is beneficial
|
|
65
|
+
#
|
|
66
|
+
# 2. **YARD Database Clear** (`clear_yard_database!`)
|
|
67
|
+
# - YARD creates temp database directories for parsing documentation
|
|
68
|
+
# - Directories are isolated per-argument-set using SHA256 hash (see base.rb:84-97)
|
|
69
|
+
# - Base temp dir (YARDOC_BASE_TEMP_DIR) persists across CLI invocations
|
|
70
|
+
# - Without clear: Old databases accumulate in /tmp, wasting disk space
|
|
71
|
+
# - Database isolation prevents contamination within a single run, but doesn't
|
|
72
|
+
# clean up between runs
|
|
73
|
+
#
|
|
74
|
+
# In summary: These ensure each CLI invocation is independent and doesn't leak state
|
|
75
|
+
# from previous runs, while also preventing temp directory accumulation.
|
|
76
|
+
Yard::Lint::Validators::Base.reset_command_cache!
|
|
77
|
+
Yard::Lint::Validators::Base.clear_yard_database!
|
|
78
|
+
|
|
55
79
|
# Run the linter with config_file (it will be loaded internally)
|
|
56
80
|
result = Yard::Lint.run(
|
|
57
81
|
path: path,
|
data/lib/yard/lint/config.rb
CHANGED
|
@@ -86,7 +86,41 @@ module Yard
|
|
|
86
86
|
# Global file exclusion patterns
|
|
87
87
|
# @return [Array<String>] exclusion patterns
|
|
88
88
|
def exclude
|
|
89
|
-
all_validators['Exclude'] ||
|
|
89
|
+
all_validators['Exclude'] || default_exclusions
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Default exclusion patterns for typical Ruby/Rails projects
|
|
93
|
+
# @return [Array<String>] default exclusion patterns
|
|
94
|
+
def default_exclusions
|
|
95
|
+
[
|
|
96
|
+
# Version control
|
|
97
|
+
'\.git',
|
|
98
|
+
# Dependencies
|
|
99
|
+
'vendor/**/*',
|
|
100
|
+
'node_modules/**/*',
|
|
101
|
+
# Test directories
|
|
102
|
+
'spec/**/*',
|
|
103
|
+
'test/**/*',
|
|
104
|
+
'features/**/*',
|
|
105
|
+
# Temporary and cache directories
|
|
106
|
+
'tmp/**/*',
|
|
107
|
+
'log/**/*',
|
|
108
|
+
'coverage/**/*',
|
|
109
|
+
'.bundle/**/*',
|
|
110
|
+
# Rails-specific
|
|
111
|
+
'db/schema.rb',
|
|
112
|
+
'db/migrate/**/*',
|
|
113
|
+
'public/assets/**/*',
|
|
114
|
+
'public/packs/**/*',
|
|
115
|
+
'public/system/**/*',
|
|
116
|
+
# Build artifacts
|
|
117
|
+
'pkg/**/*',
|
|
118
|
+
'doc/**/*',
|
|
119
|
+
'.yardoc/**/*',
|
|
120
|
+
# Configuration that doesn't need docs
|
|
121
|
+
'config/initializers/**/*',
|
|
122
|
+
'config/environments/**/*'
|
|
123
|
+
]
|
|
90
124
|
end
|
|
91
125
|
|
|
92
126
|
# Minimum severity level to fail on
|
|
@@ -37,7 +37,7 @@ module Yard
|
|
|
37
37
|
# Auto-discover validators from the codebase
|
|
38
38
|
# Scans the validators directory and loads all validator modules that have
|
|
39
39
|
# an .id method and .defaults method (indicating they're valid validators)
|
|
40
|
-
# @return [Hash
|
|
40
|
+
# @return [Hash{String => Array<String>}] hash of category names to validator names
|
|
41
41
|
def discover_validators
|
|
42
42
|
categories = Hash.new { |h, k| h[k] = [] }
|
|
43
43
|
|
|
@@ -109,7 +109,16 @@ module Yard
|
|
|
109
109
|
return [] unless stdout
|
|
110
110
|
|
|
111
111
|
parsers = discover_parsers(validator_module)
|
|
112
|
-
parsers.flat_map
|
|
112
|
+
parsers.flat_map do |parser|
|
|
113
|
+
parser_instance = parser.new
|
|
114
|
+
# Try passing config to parser if it accepts it (for filtering)
|
|
115
|
+
# Otherwise, call without config for backwards compatibility
|
|
116
|
+
begin
|
|
117
|
+
parser_instance.call(stdout, config: config)
|
|
118
|
+
rescue ArgumentError
|
|
119
|
+
parser_instance.call(stdout)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
113
122
|
end
|
|
114
123
|
|
|
115
124
|
# Auto-discover parser classes in a validator module
|
|
@@ -17,12 +17,11 @@ module Yard
|
|
|
17
17
|
'--no-progress'
|
|
18
18
|
].freeze
|
|
19
19
|
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
|
|
23
|
-
YARDOC_TEMP_DIR = Dir.mktmpdir.freeze
|
|
20
|
+
# Base temp directory for YARD databases
|
|
21
|
+
# Each unique set of arguments gets its own subdirectory to prevent contamination
|
|
22
|
+
YARDOC_BASE_TEMP_DIR = Dir.mktmpdir.freeze
|
|
24
23
|
|
|
25
|
-
private_constant :
|
|
24
|
+
private_constant :YARDOC_BASE_TEMP_DIR
|
|
26
25
|
|
|
27
26
|
attr_reader :config, :selection
|
|
28
27
|
|
|
@@ -42,12 +41,12 @@ module Yard
|
|
|
42
41
|
Base.instance_variable_set(:@shared_command_cache, nil)
|
|
43
42
|
end
|
|
44
43
|
|
|
45
|
-
# Clear
|
|
44
|
+
# Clear all YARD databases (primarily for testing)
|
|
46
45
|
# @return [void]
|
|
47
46
|
def clear_yard_database!
|
|
48
|
-
return unless defined?(
|
|
47
|
+
return unless defined?(YARDOC_BASE_TEMP_DIR)
|
|
49
48
|
|
|
50
|
-
FileUtils.rm_rf(Dir.glob(File.join(
|
|
49
|
+
FileUtils.rm_rf(Dir.glob(File.join(YARDOC_BASE_TEMP_DIR, '*')))
|
|
51
50
|
end
|
|
52
51
|
end
|
|
53
52
|
|
|
@@ -66,21 +65,51 @@ module Yard
|
|
|
66
65
|
return raw if selection.nil? || selection.empty?
|
|
67
66
|
|
|
68
67
|
# Anything that goes to shell needs to be escaped
|
|
69
|
-
escaped_file_names = escape(selection)
|
|
68
|
+
escaped_file_names = escape(selection)
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
# Use a unique YARD database per set of arguments to prevent contamination
|
|
71
|
+
# between validators with different file selections or options
|
|
72
|
+
yardoc_dir = yardoc_temp_dir_for_arguments(escaped_file_names.join(' '))
|
|
73
|
+
|
|
74
|
+
# For large file lists, use a temporary file to avoid ARG_MAX limits
|
|
75
|
+
# Write file paths to temp file, one per line
|
|
76
|
+
Tempfile.create(['yard_files', '.txt']) do |f|
|
|
77
|
+
escaped_file_names.each { |file| f.puts(file) }
|
|
78
|
+
f.flush
|
|
79
|
+
|
|
80
|
+
yard_cmd(yardoc_dir, f.path)
|
|
81
|
+
end
|
|
72
82
|
end
|
|
73
83
|
|
|
74
84
|
private
|
|
75
85
|
|
|
86
|
+
# Returns a unique YARD database directory for the given arguments
|
|
87
|
+
# Uses SHA256 hash of the normalized arguments to ensure different file sets
|
|
88
|
+
# get separate databases, preventing contamination
|
|
89
|
+
# @param escaped_file_names [String] escaped file names to process
|
|
90
|
+
# @return [String] path to the YARD database directory
|
|
91
|
+
def yardoc_temp_dir_for_arguments(escaped_file_names)
|
|
92
|
+
# Combine all arguments that affect YARD output
|
|
93
|
+
all_args = "#{shell_arguments} #{escaped_file_names}"
|
|
94
|
+
|
|
95
|
+
# Create a hash of the arguments for a unique directory name
|
|
96
|
+
args_hash = Digest::SHA256.hexdigest(all_args)
|
|
97
|
+
|
|
98
|
+
# Create subdirectory under base temp dir
|
|
99
|
+
dir = File.join(YARDOC_BASE_TEMP_DIR, args_hash)
|
|
100
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
|
101
|
+
|
|
102
|
+
dir
|
|
103
|
+
end
|
|
104
|
+
|
|
76
105
|
# @return [String] all arguments with which YARD command should be executed
|
|
77
106
|
def shell_arguments
|
|
78
|
-
validator_name = self.class.name
|
|
107
|
+
validator_name = self.class.name&.split('::')&.then do |parts|
|
|
79
108
|
idx = parts.index('Validators')
|
|
80
109
|
next config.options unless idx && parts[idx + 1] && parts[idx + 2]
|
|
81
110
|
|
|
82
111
|
"#{parts[idx + 1]}/#{parts[idx + 2]}"
|
|
83
|
-
end
|
|
112
|
+
end || config.options
|
|
84
113
|
|
|
85
114
|
yard_options = config.validator_yard_options(validator_name)
|
|
86
115
|
args = escape(yard_options).join(' ')
|
|
@@ -9,13 +9,15 @@ module Yard
|
|
|
9
9
|
# do not have a return type or return description documented
|
|
10
10
|
class Validator < Base
|
|
11
11
|
# Query to find all the boolean methods without proper return documentation
|
|
12
|
+
# Requires either: no @return tag, OR @return tag with no types specified
|
|
13
|
+
# Accepts @return [Boolean] without description text as valid documentation
|
|
12
14
|
QUERY = <<~QUERY.tr("\n", ' ')
|
|
13
15
|
'
|
|
14
16
|
type == :method &&
|
|
15
17
|
!is_alias? &&
|
|
16
18
|
is_explicit? &&
|
|
17
19
|
name.to_s.end_with?("?") &&
|
|
18
|
-
(tag("return").nil? || tag("return").
|
|
20
|
+
(tag("return").nil? || tag("return").types.to_a.empty?)
|
|
19
21
|
'
|
|
20
22
|
QUERY
|
|
21
23
|
|
|
@@ -25,16 +27,15 @@ module Yard
|
|
|
25
27
|
|
|
26
28
|
# Runs yard list query with proper settings on a given dir and files
|
|
27
29
|
# @param dir [String] dir where we should generate the temp docs
|
|
28
|
-
# @param
|
|
30
|
+
# @param file_list_path [String] path to temp file containing file paths (one per line)
|
|
29
31
|
# @return [Hash] shell command execution hash results
|
|
30
|
-
def yard_cmd(dir,
|
|
32
|
+
def yard_cmd(dir, file_list_path)
|
|
31
33
|
cmd = <<~CMD
|
|
32
|
-
yard list \
|
|
34
|
+
cat #{Shellwords.escape(file_list_path)} | xargs yard list \
|
|
33
35
|
#{shell_arguments} \
|
|
34
36
|
--query #{QUERY} \
|
|
35
37
|
-q \
|
|
36
|
-
-b #{Shellwords.escape(dir)}
|
|
37
|
-
#{escaped_file_names}
|
|
38
|
+
-b #{Shellwords.escape(dir)}
|
|
38
39
|
CMD
|
|
39
40
|
cmd = cmd.tr("\n", ' ')
|
|
40
41
|
|
|
@@ -29,19 +29,18 @@ module Yard
|
|
|
29
29
|
|
|
30
30
|
# Runs yard list query with proper settings on a given dir and files
|
|
31
31
|
# @param dir [String] dir where we should generate the temp docs
|
|
32
|
-
# @param
|
|
32
|
+
# @param file_list_path [String] path to temp file containing file paths (one per line)
|
|
33
33
|
# @return [Hash] shell command execution hash results
|
|
34
|
-
def yard_cmd(dir,
|
|
34
|
+
def yard_cmd(dir, file_list_path)
|
|
35
35
|
shell_args = shell_arguments
|
|
36
36
|
UNWANTED_OPTIONS.each { |opt| shell_args.gsub!(opt, '') }
|
|
37
37
|
|
|
38
38
|
cmd = <<~CMD
|
|
39
|
-
yard list \
|
|
39
|
+
cat #{Shellwords.escape(file_list_path)} | xargs yard list \
|
|
40
40
|
#{shell_args} \
|
|
41
41
|
--query #{QUERY} \
|
|
42
42
|
-q \
|
|
43
|
-
-b #{Shellwords.escape(dir)}
|
|
44
|
-
#{escaped_file_names}
|
|
43
|
+
-b #{Shellwords.escape(dir)}
|
|
45
44
|
CMD
|
|
46
45
|
cmd = cmd.tr("\n", ' ')
|
|
47
46
|
|
|
@@ -10,7 +10,8 @@ module Yard
|
|
|
10
10
|
self.id = :undocumented_objects
|
|
11
11
|
self.defaults = {
|
|
12
12
|
'Enabled' => true,
|
|
13
|
-
'Severity' => 'warning'
|
|
13
|
+
'Severity' => 'warning',
|
|
14
|
+
'ExcludedMethods' => ['initialize/0']
|
|
14
15
|
}.freeze
|
|
15
16
|
self.combines_with = ['Documentation/UndocumentedBooleanMethods'].freeze
|
|
16
17
|
end
|