yard-lint 1.2.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +150 -1
  3. data/README.md +98 -4
  4. data/Rakefile +20 -0
  5. data/bin/yard-lint +71 -38
  6. data/lib/yard/lint/config.rb +5 -0
  7. data/lib/yard/lint/config_updater.rb +222 -0
  8. data/lib/yard/lint/errors.rb +6 -0
  9. data/lib/yard/lint/executor/in_process_registry.rb +130 -0
  10. data/lib/yard/lint/executor/query_executor.rb +109 -0
  11. data/lib/yard/lint/executor/result_collector.rb +55 -0
  12. data/lib/yard/lint/executor/warning_dispatcher.rb +79 -0
  13. data/lib/yard/lint/ext/irb_notifier_shim.rb +19 -6
  14. data/lib/yard/lint/results/base.rb +2 -1
  15. data/lib/yard/lint/runner.rb +50 -38
  16. data/lib/yard/lint/templates/default_config.yml +105 -0
  17. data/lib/yard/lint/templates/strict_config.yml +105 -0
  18. data/lib/yard/lint/validators/base.rb +52 -118
  19. data/lib/yard/lint/validators/documentation/blank_line_before_definition/config.rb +25 -0
  20. data/lib/yard/lint/validators/documentation/blank_line_before_definition/messages_builder.rb +39 -0
  21. data/lib/yard/lint/validators/documentation/blank_line_before_definition/parser.rb +59 -0
  22. data/lib/yard/lint/validators/documentation/blank_line_before_definition/result.rb +61 -0
  23. data/lib/yard/lint/validators/documentation/blank_line_before_definition/validator.rb +94 -0
  24. data/lib/yard/lint/validators/documentation/blank_line_before_definition.rb +63 -0
  25. data/lib/yard/lint/validators/documentation/empty_comment_line/config.rb +24 -0
  26. data/lib/yard/lint/validators/documentation/empty_comment_line/messages_builder.rb +34 -0
  27. data/lib/yard/lint/validators/documentation/empty_comment_line/parser.rb +60 -0
  28. data/lib/yard/lint/validators/documentation/empty_comment_line/result.rb +25 -0
  29. data/lib/yard/lint/validators/documentation/empty_comment_line/validator.rb +109 -0
  30. data/lib/yard/lint/validators/documentation/empty_comment_line.rb +58 -0
  31. data/lib/yard/lint/validators/documentation/markdown_syntax/validator.rb +36 -21
  32. data/lib/yard/lint/validators/documentation/markdown_syntax.rb +0 -1
  33. data/lib/yard/lint/validators/documentation/undocumented_boolean_methods/validator.rb +19 -29
  34. data/lib/yard/lint/validators/documentation/undocumented_boolean_methods.rb +0 -1
  35. data/lib/yard/lint/validators/documentation/undocumented_method_arguments/validator.rb +18 -34
  36. data/lib/yard/lint/validators/documentation/undocumented_method_arguments.rb +0 -1
  37. data/lib/yard/lint/validators/documentation/undocumented_objects/validator.rb +17 -25
  38. data/lib/yard/lint/validators/documentation/undocumented_objects.rb +4 -5
  39. data/lib/yard/lint/validators/documentation/undocumented_options/validator.rb +30 -21
  40. data/lib/yard/lint/validators/documentation/undocumented_options.rb +0 -1
  41. data/lib/yard/lint/validators/semantic/abstract_methods/result.rb +2 -2
  42. data/lib/yard/lint/validators/semantic/abstract_methods/validator.rb +31 -43
  43. data/lib/yard/lint/validators/semantic/abstract_methods.rb +0 -1
  44. data/lib/yard/lint/validators/tags/api_tags/validator.rb +24 -39
  45. data/lib/yard/lint/validators/tags/api_tags.rb +0 -1
  46. data/lib/yard/lint/validators/tags/collection_type/validator.rb +37 -66
  47. data/lib/yard/lint/validators/tags/collection_type.rb +0 -1
  48. data/lib/yard/lint/validators/tags/example_syntax/validator.rb +51 -64
  49. data/lib/yard/lint/validators/tags/example_syntax.rb +0 -1
  50. data/lib/yard/lint/validators/tags/informal_notation/config.rb +40 -0
  51. data/lib/yard/lint/validators/tags/informal_notation/messages_builder.rb +35 -0
  52. data/lib/yard/lint/validators/tags/informal_notation/parser.rb +55 -0
  53. data/lib/yard/lint/validators/tags/informal_notation/result.rb +26 -0
  54. data/lib/yard/lint/validators/tags/informal_notation/validator.rb +133 -0
  55. data/lib/yard/lint/validators/tags/informal_notation.rb +45 -0
  56. data/lib/yard/lint/validators/tags/invalid_types/validator.rb +57 -70
  57. data/lib/yard/lint/validators/tags/invalid_types.rb +0 -1
  58. data/lib/yard/lint/validators/tags/meaningless_tag/validator.rb +22 -54
  59. data/lib/yard/lint/validators/tags/meaningless_tag.rb +0 -1
  60. data/lib/yard/lint/validators/tags/non_ascii_type/config.rb +21 -0
  61. data/lib/yard/lint/validators/tags/non_ascii_type/messages_builder.rb +29 -0
  62. data/lib/yard/lint/validators/tags/non_ascii_type/parser.rb +59 -0
  63. data/lib/yard/lint/validators/tags/non_ascii_type/result.rb +25 -0
  64. data/lib/yard/lint/validators/tags/non_ascii_type/validator.rb +50 -0
  65. data/lib/yard/lint/validators/tags/non_ascii_type.rb +39 -0
  66. data/lib/yard/lint/validators/tags/option_tags/result.rb +2 -2
  67. data/lib/yard/lint/validators/tags/option_tags/validator.rb +25 -40
  68. data/lib/yard/lint/validators/tags/option_tags.rb +0 -1
  69. data/lib/yard/lint/validators/tags/order/validator.rb +28 -55
  70. data/lib/yard/lint/validators/tags/order.rb +0 -1
  71. data/lib/yard/lint/validators/tags/redundant_param_description/config.rb +15 -1
  72. data/lib/yard/lint/validators/tags/redundant_param_description/messages_builder.rb +5 -0
  73. data/lib/yard/lint/validators/tags/redundant_param_description/validator.rb +134 -100
  74. data/lib/yard/lint/validators/tags/redundant_param_description.rb +0 -1
  75. data/lib/yard/lint/validators/tags/tag_group_separator/config.rb +29 -0
  76. data/lib/yard/lint/validators/tags/tag_group_separator/messages_builder.rb +49 -0
  77. data/lib/yard/lint/validators/tags/tag_group_separator/parser.rb +67 -0
  78. data/lib/yard/lint/validators/tags/tag_group_separator/result.rb +28 -0
  79. data/lib/yard/lint/validators/tags/tag_group_separator/validator.rb +117 -0
  80. data/lib/yard/lint/validators/tags/tag_group_separator.rb +49 -0
  81. data/lib/yard/lint/validators/tags/tag_type_position/validator.rb +53 -84
  82. data/lib/yard/lint/validators/tags/tag_type_position.rb +0 -1
  83. data/lib/yard/lint/validators/tags/type_syntax/parser.rb +7 -2
  84. data/lib/yard/lint/validators/tags/type_syntax/validator.rb +29 -59
  85. data/lib/yard/lint/validators/tags/type_syntax.rb +0 -1
  86. data/lib/yard/lint/validators/warnings/duplicated_parameter_name/validator.rb +1 -18
  87. data/lib/yard/lint/validators/warnings/invalid_directive_format/validator.rb +1 -18
  88. data/lib/yard/lint/validators/warnings/invalid_tag_format/validator.rb +1 -18
  89. data/lib/yard/lint/validators/warnings/unknown_directive/validator.rb +1 -18
  90. data/lib/yard/lint/validators/warnings/unknown_parameter_name/messages_builder.rb +243 -0
  91. data/lib/yard/lint/validators/warnings/unknown_parameter_name/result.rb +4 -3
  92. data/lib/yard/lint/validators/warnings/unknown_parameter_name/validator.rb +1 -18
  93. data/lib/yard/lint/validators/warnings/unknown_tag/messages_builder.rb +144 -0
  94. data/lib/yard/lint/validators/warnings/unknown_tag/result.rb +4 -3
  95. data/lib/yard/lint/validators/warnings/unknown_tag/validator.rb +1 -18
  96. data/lib/yard/lint/validators/warnings/unknown_tag.rb +10 -0
  97. data/lib/yard/lint/version.rb +1 -1
  98. data/lib/yard/lint.rb +81 -13
  99. data/lib/yard-lint.rb +1 -1
  100. data/renovate.json +1 -8
  101. metadata +38 -2
  102. data/lib/yard/lint/command_cache.rb +0 -93
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21f921e879abc0fa9e4722a7731ca9a9cd2bf9ba80791be5de62e54c815dc64b
4
- data.tar.gz: 921d9ece14e2b400b31c46cce77546fb59967d52fd7c0edb9e2e38a4085fd76a
3
+ metadata.gz: 94fb689d34dd180a9dd434050717aff86bbb3a2eb386e61dc5f10c94927bd18b
4
+ data.tar.gz: d04b4e22866b4a688ec057251075ec4ec50aab43b81551a2f77559b8983296f6
5
5
  SHA512:
6
- metadata.gz: 83ee69985db1ad6ef6180e29a5a5b337f2e315616df2efabf8f954bad2940151bd55c79dd83fe872dbd10135250f571edc9010c5ce465f19fdc52508041a03b4
7
- data.tar.gz: 81a12c4ecdbebe8eb45987d2b8a5e5b6d75104640e8af225c3a005b1db6daa17ba0bfbb46256e463ed71587de424e7acf70318d6ba88d877a0aff581f878339c
6
+ metadata.gz: 964e60021c8c7d78308e3ceafa76f54b6f096fc65ff99e0adec51ef8620c1aa42c908d6fdef0f548ce96dbc9b0d1de380b59cd49816d7516ddf29cc337e426b3
7
+ data.tar.gz: e59e7924b6d7e823ca6a9146d040b3d5739360e1763afca3c966a0a885c0e6a8b782e33e48a9a0a0088b8c3ae0fa34cba64b12c2df33eac906b35c2052d318a3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,154 @@
1
1
  # YARD-Lint Changelog
2
2
 
3
+ ## 1.3.0 (2025-12-10)
4
+ - **[Fix]** Expand `Tags/Order` default `EnforcedOrder` to include all standard YARD tags
5
+ - Previous config only included: `param`, `option`, `return`, `raise`, `example`
6
+ - Now includes full order: `param`, `option`, `yield`, `yieldparam`, `yieldreturn`, `return`, `raise`, `see`, `example`, `note`, `todo`
7
+ - Tags not in the list were silently ignored, so `@note`, `@todo`, `@see`, and `@yield*` ordering was not validated
8
+ - Updated both `default_config.yml` and `strict_config.yml`
9
+ - **[Enhancement]** Add `IMPORTANT:` pattern detection to `Tags/InformalNotation` validator
10
+ - Detects `IMPORTANT:` and `Important:` informal notation and suggests using `@note` tag
11
+ - YARD does not have a dedicated `@important` tag; `@note` is the standard tag for emphasized notes
12
+ - **[Feature]** Add `Tags/TagGroupSeparator` validator to enforce blank line separators between different YARD tag groups (#29)
13
+ - Enforces visual separation between semantically different tag groups (e.g., `@param` tags should be separated from `@return` tags by a blank line)
14
+ - Configurable tag groups: param (param, option), return (return), error (raise, throws), example (example), meta (see, note, todo, deprecated, since, version, api), yield (yield, yieldparam, yieldreturn)
15
+ - Optional `RequireAfterDescription` setting to require blank line between description and first tag
16
+ - Unknown tags are treated as their own group (require separator from known groups)
17
+ - Disabled by default (opt-in validator) with 'convention' severity
18
+ - **[Feature]** Add `Tags/InformalNotation` validator to detect informal notation patterns in documentation (#33)
19
+ - Detects patterns like `Note:`, `TODO:`, `See:`, `Warning:`, `Deprecated:` and suggests proper YARD tags
20
+ - Suggests appropriate replacements: `@note`, `@todo`, `@see`, `@deprecated`, `@author`, `@version`, etc.
21
+ - Skips patterns inside fenced code blocks to avoid false positives
22
+ - Case-insensitive matching by default (configurable via `CaseSensitive`)
23
+ - Start-of-line matching by default (configurable via `RequireStartOfLine`)
24
+ - Fully configurable pattern mappings via `Patterns` option
25
+ - Enabled by default with 'warning' severity
26
+ - **[Feature]** Add `Tags/NonAsciiType` validator to detect non-ASCII characters in YARD type specifications (#39)
27
+ - Ruby type names must be valid Ruby identifiers (ASCII only)
28
+ - Detects characters like `…` (U+2026), `→` (U+2192), `—` (U+2014) in type specs
29
+ - Common cause: copy-paste from word processors with smart typography
30
+ - Reports specific character and Unicode code point in error message
31
+ - Example: `@param flags [Symbol, …]` → reports `'…' (U+2026)`
32
+ - Enabled by default with 'warning' severity
33
+ - Configurable `ValidatedTags` (default: param, option, return, yieldreturn, yieldparam)
34
+ - **[Fix]** Fix `Encoding::CompatibilityError` crash when YARD encounters non-ASCII characters in type specifications
35
+ - TypeSyntax validator now handles encoding issues gracefully
36
+ - Sanitizes YARD error messages that may contain invalid UTF-8 sequences
37
+ - **[Fix]** Fix relative exclusion patterns not matching files discovered with absolute paths
38
+ - Patterns like `vendor/**/*` were not being applied when running `yard-lint /path/to/project` or `yard-lint .`
39
+ - Root cause: `expand_path` converted files to absolute paths before filtering, but compared against relative patterns
40
+ - Now matches patterns against both relative and absolute paths (similar to RuboCop's `PathUtil#match_path?`)
41
+ - Extracted `discover_ruby_files` method for better separation of concerns
42
+ - Added `determine_base_dir`, `excluded_file?`, `relative_path_from`, and `match_path?` helper methods
43
+ - Comprehensive integration tests in `spec/integrations/global_exclusions_spec.rb`
44
+ - **[Enhancement]** Make PATH argument optional, defaulting to current directory (like RuboCop)
45
+ - Running `yard-lint` without arguments now lints the current directory
46
+ - Maintains backward compatibility with explicit path arguments
47
+ - Updated help text and examples to show default behavior
48
+ - **[Fix]** Respect per-validator `YardOptions` when filtering by visibility (#41)
49
+ - Executor was ignoring `YardOptions` defined on individual validators
50
+ - Specifying `YardOptions` on a specific validator now correctly overrides `AllValidators` defaults
51
+ - Enables use cases like validating tag order on private methods, but skipping documentation requirement
52
+ - Example: Set `--private` in `AllValidators.YardOptions`, then override with empty `YardOptions: []` on `Documentation/UndocumentedObjects` to skip private methods or constants
53
+ - **[Feature]** Add in-process YARD execution for ~10x faster performance
54
+ - Parses files once and shares the YARD registry across all validators
55
+ - Eliminates subprocess spawning overhead (previously spawned 17+ processes per run)
56
+ - Maintains identical detection results and output format
57
+ - All 17 validators migrated to in-process execution
58
+ - Warning validators (UnknownTag, UnknownParameterName, etc.) capture YARD warnings during parsing
59
+ - Respects `--private`/`--protected` YardOptions for visibility filtering
60
+ - Fixed `void` typo in allowed types (was `vold`)
61
+ - Properly handles symbol types (`:all`, `:public`) in type validation
62
+ - **[Change]** Remove shell mode execution (was deprecated fallback)
63
+ - In-process execution is now the only mode
64
+ - Shell mode fallback code and `YARD_LINT_SHELL_MODE` environment variable removed
65
+ - Simplifies codebase by removing ~1000 lines of shell-related code
66
+ - **[Feature]** Add `Documentation/EmptyCommentLine` validator to detect unnecessary empty comment lines in YARD documentation blocks
67
+ - Detects empty `#` lines at the start of documentation blocks (leading)
68
+ - Detects empty `#` lines at the end of documentation blocks (trailing)
69
+ - Correctly allows empty lines between sections (e.g., between description and @param tags)
70
+ - Configurable `EnabledPatterns` to check leading, trailing, or both
71
+ - Reads source files directly to detect comment block boundaries
72
+ - Enabled by default with 'convention' severity
73
+ - Comprehensive test coverage with 45 unit and integration tests
74
+ - **[Feature]** Add "did you mean" suggestions for UnknownParameterName validator
75
+ - Suggests correct parameter names when documentation mismatches are detected
76
+ - Uses Ruby's `did_you_mean` gem as primary suggestion engine
77
+ - Falls back to Levenshtein distance algorithm when DidYouMean doesn't find matches
78
+ - Parses Ruby source files directly to extract actual method parameters
79
+ - Handles all parameter types: regular, keyword, splat, block, with defaults
80
+ - Example: `@param user_nme [String] typo` → suggests "did you mean 'user_name'?"
81
+ - Only suggests when parameter names are similar enough (distance threshold)
82
+ - Comprehensive test coverage with 19 unit tests and 12 integration tests
83
+ - Inspired by yard-junk's helpful error messages
84
+ - **[Feature]** Add "did you mean" suggestions for UnknownTag validator
85
+ - Suggests correct YARD tag names when typos are detected
86
+ - Dynamically loads valid tags and directives from YARD::Tags::Library for automatic compatibility with any YARD version
87
+ - Checks against all 22 standard YARD meta-data tags and 8 directives (in YARD 0.9.x)
88
+ - Uses Ruby's `did_you_mean` gem as primary suggestion engine
89
+ - Falls back to Levenshtein distance algorithm when DidYouMean doesn't find matches
90
+ - Example: `@returns [String]` → suggests "did you mean '@return'?"
91
+ - Example: `@raises [Error]` → suggests "did you mean '@raise'?"
92
+ - Example: `@params value` → suggests "did you mean '@param'?"
93
+ - Only suggests when tag names are similar enough (within 50% edit distance)
94
+ - Comprehensive test coverage with 35 unit tests and 12 integration tests covering common typos
95
+ - Completes the "did you mean" feature set alongside UnknownParameterName validator
96
+ - Inspired by yard-junk's helpful suggestion system
97
+ - **[Fix]** Replace hard-coded `#!/bin/bash` with `#!/bin/sh` for BSD/macOS compatibility (#34)
98
+ - Scripts now use POSIX-compliant shell instead of Bash
99
+ - Fixes `Errno::ENOENT` errors on *BSD systems where `/bin/bash` doesn't exist
100
+ - Affects all validators that use temporary shell scripts: InvalidTypes, RedundantParamDescription, EmptyCommentLine, TypeSyntax, CollectionType, MeaninglessTag, TagTypePosition
101
+ - **[Fix]** Fix Runner bug where offense messages were lost during per-validator exclusion filtering
102
+ - `filter_result_offenses` was creating new Result objects with stripped offense data
103
+ - Enhanced messages (like "did you mean" suggestions) were being discarded
104
+ - Now modifies existing Result object's offenses array to preserve all data
105
+ - Fixes issue affecting all validators with custom message builders
106
+ - **[Change]** Update `.yard-lint.yml` to set `FailOnSeverity` to `convention` level
107
+ - Previously set to `error`, now fails on any severity including convention
108
+ - Ensures stricter enforcement of documentation style conventions
109
+ - **[CI]** Add macOS testing to CI workflow
110
+ - Tests Ruby 3.4 on macOS to validate BSD/POSIX compatibility
111
+ - **[CI]** Add parallel_tests gem to run specs in parallel for faster CI execution
112
+ - **[Feature]** Add `ArticleParamPhrase` pattern to `Tags/RedundantParamDescription` validator (#32)
113
+ - Detects filler phrases like "The action being performed" or "A callback to invoke"
114
+ - Matches pattern: `<Article> <param_name> <connector> [<low_value_verb>...]`
115
+ - Configurable `LowValueConnectors` list (default: being, to, that, which, for)
116
+ - Configurable `LowValueVerbs` list (default: perform, process, use, handle, act, pass, invoke, call, execute, run)
117
+ - Enabled by default via `EnabledPatterns.ArticleParamPhrase`
118
+ - Pattern-specific error message explaining the filler phrase adds no value
119
+ - Comprehensive test coverage with fixtures and integration tests
120
+ - **[Feature]** Add `--only` CLI option to run specific validators
121
+ - Run single validator: `yard-lint --only Tags/TypeSyntax`
122
+ - Run multiple validators: `yard-lint --only Tags/Order,Tags/TypeSyntax`
123
+ - Overrides `Enabled: false` in config for specified validators
124
+ - Provides "did you mean" suggestions for typos using Ruby's `did_you_mean` gem
125
+ - Lists all available validators when unknown validator is specified
126
+ - Requires exact validator names (case-sensitive, full path like `Tags/Order`)
127
+ - **[Feature]** Add `Documentation/BlankLineBeforeDefinition` validator to detect blank lines between YARD documentation and definitions (#30)
128
+ - Detects single blank line violations where YARD still associates docs but violates conventions
129
+ - Detects orphaned documentation (2+ blank lines) where YARD completely ignores the documentation
130
+ - Works with methods, classes, and modules
131
+ - Configurable `EnabledPatterns` to check only single blank lines, only orphaned docs, or both
132
+ - Separate `Severity` and `OrphanedSeverity` configuration options for different violation types
133
+ - Respects `--private` and `--protected` YardOptions for visibility filtering
134
+ - Enabled by default with 'convention' severity for both violation types
135
+ - **[Fix]** Fix yard-lint silently returning "No offenses found" for non-existent file paths
136
+ - Previously, specifying a non-existent path would silently succeed with empty results
137
+ - Now raises `Errors::FileNotFoundError` with clear message: "No such file or directory: /path"
138
+ - Matches behavior of similar tools like RuboCop
139
+ - Only validates explicit file paths (glob patterns and directories are not affected)
140
+ - **[Feature]** Add `--update` command to update existing `.yard-lint.yml` with new validators
141
+ - Adds new validators introduced in newer yard-lint versions with their template defaults
142
+ - Removes obsolete validators that no longer exist in yard-lint
143
+ - Preserves all existing user configuration (custom severities, exclusions, etc.)
144
+ - Reports added, removed, and preserved validator counts
145
+ - Supports `--strict` flag to use strict template defaults for new validators
146
+ - Example: `yard-lint --update` or `yard-lint --update --strict`
147
+ - **[Fix]** Fix integration specs failing in parallel test runs due to relative fixture paths
148
+ - Updated `MeaninglessTag`, `EmptyCommentLine`, `MultiValidatorComprehensive`, `InformalNotation`, `BlankLineBeforeDefinition`, `MagicComments`, `CollectionType`, `TagTypePosition` specs to use absolute paths
149
+ - Updated `ValidatorCoverage` spec to use absolute paths for config and template files
150
+ - Uses `File.expand_path` with `__dir__` for reliable path resolution regardless of working directory
151
+
3
152
  ## 1.2.3 (2025-11-13)
4
153
  - **[Feature]** Add per-validator exclusion support for fine-grained file filtering
5
154
  - Individual validators can now specify `Exclude` patterns in `.yard-lint.yml`
@@ -145,7 +294,7 @@
145
294
  - [Change] YARD database directories are now created under a base temp directory with unique subdirectories per argument set.
146
295
 
147
296
  ## 0.2.1 (2025-11-07)
148
- - Release to validate Trusted Publishing flow.
297
+ - Release to validate Trusted Publishing flow.
149
298
 
150
299
  ## 0.2.0 (2025-11-07)
151
300
 
data/README.md CHANGED
@@ -9,7 +9,7 @@ A comprehensive linter for YARD documentation that helps you maintain clean, con
9
9
 
10
10
  ## Why Documentation Quality Matters More Than Ever
11
11
 
12
- Accurate documentation isn't just for human developers anymore. [Research shows](https://arxiv.org/html/2404.03114) that incorrect documentation reduces AI assistant success rates up to 50% (from 44.7% to 22.1%). [Enterprise studies](https://arxiv.org/html/2501.13282v1) with 400+ developers found well-documented code achieves 30%+ AI acceptance rates versus 14-20% for poorly documented code.
12
+ Accurate documentation isn't just for human developers anymore. [Research shows](https://arxiv.org/html/2404.03114) that incorrect documentation reduces AI assistant success rates up to 50% (from 44.7% to 22.1%).
13
13
 
14
14
  **The problem:** Documentation drifts as code changes-parameters get renamed, return types change, but docs stay stale. This doesn't just confuse developers; it trains AI coding assistants to generate confidently wrong code.
15
15
 
@@ -23,6 +23,7 @@ YARD-Lint validates your YARD documentation for:
23
23
  - **Missing parameter documentation**: Methods with undocumented parameters
24
24
  - **Invalid tag types**: Type definitions that aren't valid Ruby classes or allowed defaults
25
25
  - **Invalid type syntax**: Malformed YARD type syntax (unclosed brackets, empty generics, etc.)
26
+ - **Non-ASCII type characters**: Detects Unicode characters in type specifications (e.g., `…`, `→`, `—`) that are invalid Ruby identifiers
26
27
  - **Invalid tag ordering**: Tags that don't follow your specified order
27
28
  - **Meaningless tags**: `@param` or `@option` tags on classes, modules, or constants (only valid on methods)
28
29
  - **Collection type syntax**: Enforces `Hash{K => V}` over `Hash<K, V>` (YARD standard)
@@ -33,7 +34,12 @@ YARD-Lint validates your YARD documentation for:
33
34
  - **Option hash documentation**: Validate that methods with options parameters have @option tags
34
35
  - **Example code syntax validation**: Validates Ruby syntax in `@example` tags to catch broken code examples
35
36
  - **Redundant parameter descriptions**: Detects meaningless parameter descriptions that add no value (e.g., `@param user [User] The user`)
37
+ - **Empty comment lines**: Detects unnecessary empty `#` lines at the start or end of documentation blocks
38
+ - **Blank lines before definitions**: Detects blank lines between YARD documentation and method/class/module definitions (single blank line = convention violation, 2+ blank lines = orphaned documentation that YARD ignores)
39
+ - **Informal notation patterns**: Detects `Note:`, `TODO:`, `See:` etc. and suggests proper YARD tags (`@note`, `@todo`, `@see`)
40
+ - **Tag group separation**: Enforces blank lines between different YARD tag groups (e.g., between `@param` and `@return` tags) for improved readability
36
41
  - **YARD warnings**: Unknown tags, invalid directives, duplicated parameter names, and more
42
+ - **Smart suggestions**: Provides "did you mean" suggestions for typos in parameter names using Ruby's `did_you_mean` gem with Levenshtein distance fallback
37
43
 
38
44
  ## Installation
39
45
 
@@ -78,6 +84,17 @@ This creates a strict configuration with:
78
84
  - Minimum documentation coverage set to 100%
79
85
  - Perfect for bootstrapping new repositories with high quality standards
80
86
 
87
+ After upgrading yard-lint, update your config to include any new validators:
88
+
89
+ ```bash
90
+ yard-lint --update
91
+ ```
92
+
93
+ This will:
94
+ - Add any new validators introduced in the latest version (with their default settings)
95
+ - Remove any obsolete validators that no longer exist
96
+ - Preserve all your existing configuration
97
+
81
98
  ### Command Line
82
99
 
83
100
  Basic usage:
@@ -211,6 +228,21 @@ jobs:
211
228
  - Works with diff mode to enforce coverage only on changed files
212
229
  - Performance optimized with auto-cleanup temp directories for large codebases
213
230
 
231
+ ### Running Specific Validators
232
+
233
+ Run only specific validators using the `--only` option - useful for debugging, gradual adoption, or focused CI checks:
234
+
235
+ ```bash
236
+ # Run only one validator
237
+ yard-lint --only Tags/TypeSyntax lib/
238
+
239
+ # Run multiple validators (comma-separated)
240
+ yard-lint --only Tags/Order,Tags/TypeSyntax lib/
241
+
242
+ # Combine with other options
243
+ yard-lint --only Documentation/UndocumentedObjects --diff main lib/
244
+ ```
245
+
214
246
  ## Configuration
215
247
 
216
248
  YARD-Lint is configured via a `.yard-lint.yml` configuration file (similar to `.rubocop.yml`).
@@ -507,10 +539,13 @@ Supported glob patterns:
507
539
  | `Documentation/UndocumentedBooleanMethods` | Checks that question mark methods document their boolean return | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
508
540
  | `Documentation/UndocumentedOptions` | Detects methods with options hash/kwargs parameters but no `@option` tags | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
509
541
  | `Documentation/MarkdownSyntax` | Detects common markdown syntax errors in documentation (unclosed backticks, invalid list markers, etc.) | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
542
+ | `Documentation/EmptyCommentLine` | Detects empty `#` lines at the start or end of documentation blocks | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `EnabledPatterns` |
543
+ | `Documentation/BlankLineBeforeDefinition` | Detects blank lines between documentation and definitions (single blank = convention violation, 2+ blank = orphaned docs) | Enabled (convention) | `Enabled`, `Severity`, `OrphanedSeverity`, `Exclude`, `EnabledPatterns` |
510
544
  | **Tags Validators** |
511
545
  | `Tags/Order` | Enforces consistent ordering of YARD tags | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `EnforcedOrder` |
512
546
  | `Tags/InvalidTypes` | Validates type definitions in `@param`, `@return`, `@option` tags | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `ValidatedTags`, `ExtraTypes` |
513
547
  | `Tags/TypeSyntax` | Validates YARD type syntax (detects unclosed brackets, empty generics, etc.) | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `ValidatedTags` |
548
+ | `Tags/NonAsciiType` | Detects non-ASCII characters in type specifications (e.g., `…`, `→`, `—`) | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `ValidatedTags` |
514
549
  | `Tags/MeaninglessTag` | Detects `@param`/`@option` tags on classes, modules, or constants (only valid on methods) | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `CheckedTags`, `InvalidObjectTypes` |
515
550
  | `Tags/CollectionType` | Enforces `Hash{K => V}` over `Hash<K, V>` (YARD standard collection syntax) | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `ValidatedTags` |
516
551
  | `Tags/TagTypePosition` | Validates type annotation position (`@param name [Type]` vs `@param [Type] name`) | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `CheckedTags`, `EnforcedStyle` |
@@ -518,13 +553,15 @@ Supported glob patterns:
518
553
  | `Tags/OptionTags` | Requires `@option` tags for methods with options parameters | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
519
554
  | `Tags/ExampleSyntax` | Validates Ruby syntax in `@example` tags to catch broken code examples | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
520
555
  | `Tags/RedundantParamDescription` | Detects meaningless parameter descriptions that add no value beyond the parameter name | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `CheckedTags`, `Articles`, `MaxRedundantWords`, `MinMeaningfulLength`, `GenericTerms`, `EnabledPatterns` |
556
+ | `Tags/InformalNotation` | Detects informal notation patterns (`Note:`, `TODO:`, etc.) and suggests proper YARD tags | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `CaseSensitive`, `RequireStartOfLine`, `Patterns` |
557
+ | `Tags/TagGroupSeparator` | Enforces blank line separators between different YARD tag groups (e.g., between `@param` and `@return` tags) | Disabled (opt-in) | `Enabled`, `Severity`, `Exclude`, `TagGroups`, `RequireAfterDescription` |
521
558
  | **Warnings Validators** |
522
- | `Warnings/UnknownTag` | Detects unknown YARD tags | Enabled (error) | `Enabled`, `Severity`, `Exclude` |
559
+ | `Warnings/UnknownTag` | Detects unknown YARD tags with "did you mean" suggestions | Enabled (error) | `Enabled`, `Severity`, `Exclude` |
523
560
  | `Warnings/UnknownDirective` | Detects unknown YARD directives | Enabled (error) | `Enabled`, `Severity`, `Exclude` |
524
561
  | `Warnings/InvalidTagFormat` | Detects malformed tag syntax | Enabled (error) | `Enabled`, `Severity`, `Exclude` |
525
562
  | `Warnings/InvalidDirectiveFormat` | Detects malformed directive syntax | Enabled (error) | `Enabled`, `Severity`, `Exclude` |
526
563
  | `Warnings/DuplicatedParameterName` | Detects duplicate `@param` tags | Enabled (error) | `Enabled`, `Severity`, `Exclude` |
527
- | `Warnings/UnknownParameterName` | Detects `@param` tags for non-existent parameters | Enabled (error) | `Enabled`, `Severity`, `Exclude` |
564
+ | `Warnings/UnknownParameterName` | Detects `@param` tags for non-existent parameters with "did you mean" suggestions | Enabled (error) | `Enabled`, `Severity`, `Exclude` |
528
565
  | **Semantic Validators** |
529
566
  | `Semantic/AbstractMethods` | Ensures `@abstract` methods don't have real implementations | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
530
567
 
@@ -542,6 +579,61 @@ yard server
542
579
 
543
580
  Then open http://localhost:8808 in your browser to browse the full validator documentation with examples.
544
581
 
582
+ ### Smart Suggestions with "Did You Mean"
583
+
584
+ YARD-Lint provides intelligent suggestions for common typos in both tag names and parameter names.
585
+
586
+ #### Unknown Tag Suggestions
587
+
588
+ The `Warnings/UnknownTag` validator suggests correct YARD tags for typos:
589
+
590
+ **Example:**
591
+
592
+ ```ruby
593
+ # @params value [String] should be @param
594
+ # @returns [String] should be @return
595
+ # @raises [Error] should be @raise
596
+ def process(value)
597
+ # ...
598
+ end
599
+ ```
600
+
601
+ **Output:**
602
+
603
+ ```
604
+ lib/processor.rb:10: [error] Unknown tag @params (did you mean '@param'?)
605
+ lib/processor.rb:11: [error] Unknown tag @returns (did you mean '@return'?)
606
+ lib/processor.rb:12: [error] Unknown tag @raises (did you mean '@raise'?)
607
+ ```
608
+
609
+ #### Unknown Parameter Suggestions
610
+
611
+ The `Warnings/UnknownParameterName` validator suggests correct parameter names:
612
+
613
+ **Example:**
614
+
615
+ ```ruby
616
+ # @param usr_name [String] the username
617
+ # @param usr_email [String] the email
618
+ def create_user(user_name, user_email)
619
+ # ...
620
+ end
621
+ ```
622
+
623
+ **Output:**
624
+
625
+ ```
626
+ lib/user.rb:123: [error] @param tag has unknown parameter name: usr_name (did you mean 'user_name'?)
627
+ lib/user.rb:124: [error] @param tag has unknown parameter name: usr_email (did you mean 'user_email'?)
628
+ ```
629
+
630
+ **How it works:**
631
+ - Uses Ruby's `did_you_mean` gem for intelligent suggestions
632
+ - Falls back to Levenshtein distance algorithm when needed
633
+ - For parameters: Parses method signatures directly from source files for accurate parameter detection
634
+ - Supports all parameter types: regular, keyword, splat, block, and default values
635
+ - For tags: Checks against all standard YARD tags and directives
636
+
545
637
  ### Quick Configuration Examples
546
638
 
547
639
  ```yaml
@@ -608,8 +700,10 @@ Options:
608
700
  --diff [REF] Lint only files changed since REF
609
701
  --staged Lint only staged files
610
702
  --changed Lint only uncommitted files
703
+ --only VALIDATORS Run only specified validators (comma-separated)
611
704
  --init Generate .yard-lint.yml config file
612
- --strict Generate strict config (use with --init)
705
+ --update Update .yard-lint.yml with new validators
706
+ --strict Generate strict config (use with --init or --update)
613
707
  --force Force overwrite when using --init
614
708
  -v, --version Show version
615
709
  -h, --help Show this help
data/Rakefile CHANGED
@@ -2,3 +2,23 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'bundler/gem_tasks'
5
+ require 'etc'
6
+
7
+ namespace :spec do
8
+ # Determine optimal number of parallel processes
9
+ # Use all CPUs if less than 8, otherwise cap at 8
10
+ def parallel_process_count
11
+ cpus = Etc.nprocessors
12
+ [cpus, 8].min
13
+ end
14
+
15
+ desc 'Run integration specs in parallel'
16
+ task :integrations do
17
+ sh "bundle exec parallel_rspec -n #{parallel_process_count} spec/integrations/"
18
+ end
19
+
20
+ desc 'Run all specs in parallel'
21
+ task :parallel do
22
+ sh "bundle exec parallel_rspec -n #{parallel_process_count} spec/"
23
+ end
24
+ end
data/bin/yard-lint CHANGED
@@ -11,7 +11,7 @@ config_file = nil
11
11
  diff_mode = nil
12
12
 
13
13
  OptionParser.new do |opts|
14
- opts.banner = 'Usage: yard-lint [options] PATH'
14
+ opts.banner = 'Usage: yard-lint [options] [PATH]'
15
15
 
16
16
  opts.on('-c', '--config FILE', 'Path to config file (default: .yard-lint.yml)') do |file|
17
17
  config_file = file
@@ -52,6 +52,13 @@ OptionParser.new do |opts|
52
52
  diff_mode = { mode: :changed }
53
53
  end
54
54
 
55
+ opts.separator ''
56
+ opts.separator 'Validator selection:'
57
+
58
+ opts.on('--only VALIDATORS', 'Run only specified validators (comma-separated)') do |validators|
59
+ options[:only] = validators.split(',').map(&:strip)
60
+ end
61
+
55
62
  opts.separator ''
56
63
  opts.separator 'Other options:'
57
64
 
@@ -59,7 +66,11 @@ OptionParser.new do |opts|
59
66
  options[:init] = true
60
67
  end
61
68
 
62
- opts.on('--strict', 'Generate strict config (all Error severity, 100% coverage). Use with --init') do
69
+ opts.on('--update', 'Update .yard-lint.yml to add new validators and remove obsolete ones') do
70
+ options[:update] = true
71
+ end
72
+
73
+ opts.on('--strict', 'Generate strict config (all Error severity, 100% coverage). Use with --init or --update') do
63
74
  options[:strict] = true
64
75
  end
65
76
 
@@ -76,13 +87,17 @@ OptionParser.new do |opts|
76
87
  puts opts
77
88
  puts
78
89
  puts 'Examples:'
79
- puts ' yard-lint lib/ # Lint all files in lib/'
80
- puts ' yard-lint lib/ --diff main # Lint only files changed since main branch'
81
- puts ' yard-lint lib/ --staged # Lint only staged files'
82
- puts ' yard-lint lib/ --changed # Lint only uncommitted files'
83
- puts ' yard-lint lib/ --format json # Output in JSON format'
84
- puts ' yard-lint --init # Generate default config'
85
- puts ' yard-lint --init --strict # Generate strict config (all errors, 100% coverage)'
90
+ puts ' yard-lint # Lint current directory'
91
+ puts ' yard-lint lib/ # Lint all files in lib/'
92
+ puts ' yard-lint --only Tags/TypeSyntax lib/ # Run only one validator on lib/'
93
+ puts ' yard-lint --only Tags/Order,Tags/TypeSyntax # Run specific validators'
94
+ puts ' yard-lint --diff main # Lint files changed since main branch'
95
+ puts ' yard-lint --staged # Lint only staged files'
96
+ puts ' yard-lint --changed # Lint only uncommitted files'
97
+ puts ' yard-lint --format json lib/ # Output in JSON format'
98
+ puts ' yard-lint --init # Generate default config'
99
+ puts ' yard-lint --init --strict # Generate strict config'
100
+ puts ' yard-lint --update # Update config with new validators'
86
101
  exit
87
102
  end
88
103
  end.parse!
@@ -103,38 +118,35 @@ if options[:init]
103
118
  end
104
119
  end
105
120
 
106
- # Get path argument
107
- path = ARGV[0]
121
+ # Handle --update flag
122
+ if options[:update]
123
+ begin
124
+ result = Yard::Lint::ConfigUpdater.update(strict: options[:strict])
108
125
 
109
- unless path
110
- puts 'Error: PATH argument is required'
111
- puts 'Usage: yard-lint [options] PATH'
112
- exit 1
126
+ if result[:added].any? || result[:removed].any?
127
+ puts 'Updated .yard-lint.yml:'
128
+ if result[:added].any?
129
+ puts " Added #{result[:added].size} new validator(s): #{result[:added].join(', ')}"
130
+ end
131
+ if result[:removed].any?
132
+ puts " Removed #{result[:removed].size} obsolete validator(s): #{result[:removed].join(', ')}"
133
+ end
134
+ puts " Preserved #{result[:preserved].size} existing validator(s)"
135
+ else
136
+ puts '.yard-lint.yml is already up to date'
137
+ end
138
+ exit 0
139
+ rescue Yard::Lint::Errors::ConfigFileNotFoundError => e
140
+ puts "Error: #{e.message}"
141
+ exit 1
142
+ end
113
143
  end
114
144
 
115
- # Clear YARD database and command cache to ensure fresh run on each CLI invocation
116
- #
117
- # Why this is necessary:
118
- #
119
- # 1. **Command Cache Reset** (`reset_command_cache!`)
120
- # - The command cache stores results from YARD commands across validator instances
121
- # - This cache is shared at the class level (Base.@shared_command_cache)
122
- # - Without reset: Results from a previous CLI run could leak into the current run
123
- # - Critical for CLI: Each `yard-lint` invocation should start with clean state
124
- # - Not needed in-process: Within a single run, caching YARD results is beneficial
125
- #
126
- # 2. **YARD Database Clear** (`clear_yard_database!`)
127
- # - YARD creates temp database directories for parsing documentation
128
- # - Directories are isolated per-argument-set using SHA256 hash (see base.rb:84-97)
129
- # - Base temp dir (YARDOC_BASE_TEMP_DIR) persists across CLI invocations
130
- # - Without clear: Old databases accumulate in /tmp, wasting disk space
131
- # - Database isolation prevents contamination within a single run, but doesn't
132
- # clean up between runs
133
- #
134
- # In summary: These ensure each CLI invocation is independent and doesn't leak state
135
- # from previous runs, while also preventing temp directory accumulation.
136
- Yard::Lint::Validators::Base.reset_command_cache!
137
- Yard::Lint::Validators::Base.clear_yard_database!
145
+ # Get path argument (defaults to current directory)
146
+ path = ARGV[0] || '.'
147
+
148
+ # Clear YARD registry to ensure fresh run on each CLI invocation
149
+ YARD::Registry.clear
138
150
 
139
151
  # Load config and apply CLI overrides
140
152
  config = if config_file
@@ -146,6 +158,24 @@ config = if config_file
146
158
  # Apply CLI min_coverage override if provided
147
159
  config.min_coverage = options[:min_coverage] if options[:min_coverage]
148
160
 
161
+ # Apply --only filter if provided
162
+ if options[:only]
163
+ unknown = options[:only] - Yard::Lint::ConfigLoader::ALL_VALIDATORS
164
+ if unknown.any?
165
+ checker = DidYouMean::SpellChecker.new(dictionary: Yard::Lint::ConfigLoader::ALL_VALIDATORS)
166
+ messages = unknown.map do |name|
167
+ suggestions = checker.correct(name)
168
+ suggestions.any? ? " #{name} (did you mean: #{suggestions.first}?)" : " #{name}"
169
+ end
170
+ puts "Error: Unknown validator(s):"
171
+ puts messages.join("\n")
172
+ puts "\nAvailable validators:"
173
+ Yard::Lint::ConfigLoader::ALL_VALIDATORS.each { |v| puts " #{v}" }
174
+ exit 1
175
+ end
176
+ config.only_validators = options[:only]
177
+ end
178
+
149
179
  # Run the linter
150
180
  begin
151
181
  result = Yard::Lint.run(
@@ -157,6 +187,9 @@ begin
157
187
  rescue Yard::Lint::Git::Error => e
158
188
  puts "Git error: #{e.message}"
159
189
  exit 1
190
+ rescue Yard::Lint::Errors::FileNotFoundError => e
191
+ puts "Error: #{e.message}"
192
+ exit 1
160
193
  end
161
194
 
162
195
  # Format and display results
@@ -6,6 +6,7 @@ module Yard
6
6
  # Configuration object for YARD Lint
7
7
  class Config
8
8
  attr_reader :raw_config, :validators
9
+ attr_accessor :only_validators
9
10
 
10
11
  # Default YAML config file name
11
12
  DEFAULT_CONFIG_FILE = '.yard-lint.yml'
@@ -20,6 +21,7 @@ module Yard
20
21
  def initialize(raw_config = {})
21
22
  @raw_config = raw_config
22
23
  @validators = build_validators_config
24
+ @only_validators = []
23
25
 
24
26
  yield self if block_given?
25
27
  end
@@ -146,6 +148,9 @@ module Yard
146
148
  # @param validator_name [String] full validator name (e.g., 'Tags/Order')
147
149
  # @return [Boolean] true if validator is enabled
148
150
  def validator_enabled?(validator_name)
151
+ # If --only is specified, it takes full control
152
+ return only_validators.include?(validator_name) if only_validators.any?
153
+
149
154
  validator_config = validators[validator_name] || {}
150
155
  validator_config['Enabled'] != false # Default to true
151
156
  end