yard-lint 1.2.3 → 1.3.0.rc1
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 +150 -1
- data/README.md +98 -4
- data/Rakefile +20 -0
- data/bin/yard-lint +71 -38
- data/lib/yard/lint/config.rb +5 -0
- data/lib/yard/lint/config_updater.rb +222 -0
- data/lib/yard/lint/errors.rb +6 -0
- data/lib/yard/lint/executor/in_process_registry.rb +130 -0
- data/lib/yard/lint/executor/query_executor.rb +109 -0
- data/lib/yard/lint/executor/result_collector.rb +55 -0
- data/lib/yard/lint/executor/warning_dispatcher.rb +79 -0
- data/lib/yard/lint/results/base.rb +2 -1
- data/lib/yard/lint/runner.rb +50 -38
- data/lib/yard/lint/templates/default_config.yml +105 -0
- data/lib/yard/lint/templates/strict_config.yml +105 -0
- data/lib/yard/lint/validators/base.rb +52 -118
- data/lib/yard/lint/validators/documentation/blank_line_before_definition/config.rb +25 -0
- data/lib/yard/lint/validators/documentation/blank_line_before_definition/messages_builder.rb +39 -0
- data/lib/yard/lint/validators/documentation/blank_line_before_definition/parser.rb +59 -0
- data/lib/yard/lint/validators/documentation/blank_line_before_definition/result.rb +61 -0
- data/lib/yard/lint/validators/documentation/blank_line_before_definition/validator.rb +94 -0
- data/lib/yard/lint/validators/documentation/blank_line_before_definition.rb +63 -0
- data/lib/yard/lint/validators/documentation/empty_comment_line/config.rb +24 -0
- data/lib/yard/lint/validators/documentation/empty_comment_line/messages_builder.rb +34 -0
- data/lib/yard/lint/validators/documentation/empty_comment_line/parser.rb +60 -0
- data/lib/yard/lint/validators/documentation/empty_comment_line/result.rb +25 -0
- data/lib/yard/lint/validators/documentation/empty_comment_line/validator.rb +109 -0
- data/lib/yard/lint/validators/documentation/empty_comment_line.rb +58 -0
- data/lib/yard/lint/validators/documentation/markdown_syntax/validator.rb +36 -21
- data/lib/yard/lint/validators/documentation/markdown_syntax.rb +0 -1
- data/lib/yard/lint/validators/documentation/undocumented_boolean_methods/validator.rb +19 -29
- data/lib/yard/lint/validators/documentation/undocumented_boolean_methods.rb +0 -1
- data/lib/yard/lint/validators/documentation/undocumented_method_arguments/validator.rb +18 -34
- data/lib/yard/lint/validators/documentation/undocumented_method_arguments.rb +0 -1
- data/lib/yard/lint/validators/documentation/undocumented_objects/validator.rb +17 -25
- data/lib/yard/lint/validators/documentation/undocumented_objects.rb +4 -5
- data/lib/yard/lint/validators/documentation/undocumented_options/validator.rb +30 -21
- data/lib/yard/lint/validators/documentation/undocumented_options.rb +0 -1
- data/lib/yard/lint/validators/semantic/abstract_methods/result.rb +2 -2
- data/lib/yard/lint/validators/semantic/abstract_methods/validator.rb +31 -43
- data/lib/yard/lint/validators/semantic/abstract_methods.rb +0 -1
- data/lib/yard/lint/validators/tags/api_tags/validator.rb +24 -39
- data/lib/yard/lint/validators/tags/api_tags.rb +0 -1
- data/lib/yard/lint/validators/tags/collection_type/validator.rb +37 -66
- data/lib/yard/lint/validators/tags/collection_type.rb +0 -1
- data/lib/yard/lint/validators/tags/example_syntax/validator.rb +51 -64
- data/lib/yard/lint/validators/tags/example_syntax.rb +0 -1
- data/lib/yard/lint/validators/tags/informal_notation/config.rb +40 -0
- data/lib/yard/lint/validators/tags/informal_notation/messages_builder.rb +35 -0
- data/lib/yard/lint/validators/tags/informal_notation/parser.rb +55 -0
- data/lib/yard/lint/validators/tags/informal_notation/result.rb +26 -0
- data/lib/yard/lint/validators/tags/informal_notation/validator.rb +133 -0
- data/lib/yard/lint/validators/tags/informal_notation.rb +45 -0
- data/lib/yard/lint/validators/tags/invalid_types/validator.rb +57 -70
- data/lib/yard/lint/validators/tags/invalid_types.rb +0 -1
- data/lib/yard/lint/validators/tags/meaningless_tag/validator.rb +22 -54
- data/lib/yard/lint/validators/tags/meaningless_tag.rb +0 -1
- data/lib/yard/lint/validators/tags/non_ascii_type/config.rb +21 -0
- data/lib/yard/lint/validators/tags/non_ascii_type/messages_builder.rb +29 -0
- data/lib/yard/lint/validators/tags/non_ascii_type/parser.rb +59 -0
- data/lib/yard/lint/validators/tags/non_ascii_type/result.rb +25 -0
- data/lib/yard/lint/validators/tags/non_ascii_type/validator.rb +50 -0
- data/lib/yard/lint/validators/tags/non_ascii_type.rb +39 -0
- data/lib/yard/lint/validators/tags/option_tags/result.rb +2 -2
- data/lib/yard/lint/validators/tags/option_tags/validator.rb +25 -40
- data/lib/yard/lint/validators/tags/option_tags.rb +0 -1
- data/lib/yard/lint/validators/tags/order/validator.rb +28 -55
- data/lib/yard/lint/validators/tags/order.rb +0 -1
- data/lib/yard/lint/validators/tags/redundant_param_description/config.rb +15 -1
- data/lib/yard/lint/validators/tags/redundant_param_description/messages_builder.rb +5 -0
- data/lib/yard/lint/validators/tags/redundant_param_description/validator.rb +134 -100
- data/lib/yard/lint/validators/tags/redundant_param_description.rb +0 -1
- data/lib/yard/lint/validators/tags/tag_group_separator/config.rb +29 -0
- data/lib/yard/lint/validators/tags/tag_group_separator/messages_builder.rb +49 -0
- data/lib/yard/lint/validators/tags/tag_group_separator/parser.rb +67 -0
- data/lib/yard/lint/validators/tags/tag_group_separator/result.rb +28 -0
- data/lib/yard/lint/validators/tags/tag_group_separator/validator.rb +117 -0
- data/lib/yard/lint/validators/tags/tag_group_separator.rb +49 -0
- data/lib/yard/lint/validators/tags/tag_type_position/validator.rb +53 -84
- data/lib/yard/lint/validators/tags/tag_type_position.rb +0 -1
- data/lib/yard/lint/validators/tags/type_syntax/parser.rb +7 -2
- data/lib/yard/lint/validators/tags/type_syntax/validator.rb +29 -59
- data/lib/yard/lint/validators/tags/type_syntax.rb +0 -1
- data/lib/yard/lint/validators/warnings/duplicated_parameter_name/validator.rb +1 -18
- data/lib/yard/lint/validators/warnings/invalid_directive_format/validator.rb +1 -18
- data/lib/yard/lint/validators/warnings/invalid_tag_format/validator.rb +1 -18
- data/lib/yard/lint/validators/warnings/unknown_directive/validator.rb +1 -18
- data/lib/yard/lint/validators/warnings/unknown_parameter_name/messages_builder.rb +243 -0
- data/lib/yard/lint/validators/warnings/unknown_parameter_name/result.rb +4 -3
- data/lib/yard/lint/validators/warnings/unknown_parameter_name/validator.rb +1 -18
- data/lib/yard/lint/validators/warnings/unknown_tag/messages_builder.rb +144 -0
- data/lib/yard/lint/validators/warnings/unknown_tag/result.rb +4 -3
- data/lib/yard/lint/validators/warnings/unknown_tag/validator.rb +1 -18
- data/lib/yard/lint/validators/warnings/unknown_tag.rb +10 -0
- data/lib/yard/lint/version.rb +1 -1
- data/lib/yard/lint.rb +81 -13
- data/renovate.json +1 -8
- metadata +38 -2
- data/lib/yard/lint/command_cache.rb +0 -93
data/lib/yard/lint/runner.rb
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Require executor components for in-process execution
|
|
4
|
+
require_relative 'executor/in_process_registry'
|
|
5
|
+
require_relative 'executor/result_collector'
|
|
6
|
+
require_relative 'executor/query_executor'
|
|
7
|
+
require_relative 'executor/warning_dispatcher'
|
|
8
|
+
|
|
3
9
|
module Yard
|
|
4
10
|
module Lint
|
|
5
11
|
# Main runner class that orchestrates the YARD validation process
|
|
@@ -26,8 +32,8 @@ module Yard
|
|
|
26
32
|
|
|
27
33
|
private
|
|
28
34
|
|
|
29
|
-
# Run all validators
|
|
30
|
-
#
|
|
35
|
+
# Run all validators using in-process YARD execution.
|
|
36
|
+
# Parses files once and shares the registry across all validators.
|
|
31
37
|
# @return [Hash] hash with raw results from all validators
|
|
32
38
|
def run_validators
|
|
33
39
|
results = {}
|
|
@@ -37,50 +43,55 @@ module Yard
|
|
|
37
43
|
|
|
38
44
|
@progress_formatter&.start(enabled_validators.size)
|
|
39
45
|
|
|
40
|
-
#
|
|
46
|
+
# Initialize in-process infrastructure
|
|
47
|
+
registry = Executor::InProcessRegistry.new
|
|
48
|
+
registry.parse(selection)
|
|
49
|
+
|
|
50
|
+
query_executor = Executor::QueryExecutor.new(registry)
|
|
51
|
+
warning_dispatcher = Executor::WarningDispatcher.new
|
|
52
|
+
dispatched_warnings = warning_dispatcher.dispatch(registry.warnings)
|
|
53
|
+
|
|
54
|
+
# Process each enabled validator
|
|
41
55
|
enabled_validators.each_with_index do |validator_name, index|
|
|
42
|
-
# Get the validator namespace and config
|
|
43
56
|
validator_namespace = ConfigLoader.validator_module(validator_name)
|
|
44
57
|
validator_cfg = ConfigLoader.validator_config(validator_name)
|
|
45
58
|
|
|
46
|
-
# Show progress before running validator
|
|
47
59
|
@progress_formatter&.update(index + 1, validator_name)
|
|
48
60
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
next unless validator_namespace
|
|
62
|
+
|
|
63
|
+
validator_class = validator_namespace::Validator
|
|
64
|
+
validator_selection = filter_files_for_validator(validator_name, selection)
|
|
65
|
+
|
|
66
|
+
result = if warning_dispatcher.warning_validator?(validator_name)
|
|
67
|
+
# Use dispatched warnings for warning validators
|
|
68
|
+
warning_dispatcher.format_for_validator(
|
|
69
|
+
dispatched_warnings[validator_name] || []
|
|
70
|
+
)
|
|
71
|
+
else
|
|
72
|
+
# Use in-process execution
|
|
73
|
+
validator = validator_class.new(config, validator_selection)
|
|
74
|
+
in_process_result = query_executor.execute(validator, file_selection: validator_selection)
|
|
75
|
+
|
|
76
|
+
# Tags/Order requires special result wrapping for its parser
|
|
77
|
+
if validator_name == 'Tags/Order'
|
|
78
|
+
tags_order = config.validator_config('Tags/Order', 'EnforcedOrder')
|
|
79
|
+
in_process_result[:stdout] = {
|
|
80
|
+
result: in_process_result[:stdout],
|
|
81
|
+
tags_order: tags_order
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
in_process_result
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
results[validator_cfg.id] = result
|
|
54
89
|
end
|
|
55
90
|
|
|
56
91
|
@progress_formatter&.finish
|
|
57
|
-
|
|
58
92
|
results
|
|
59
93
|
end
|
|
60
94
|
|
|
61
|
-
# Run a validator and store its result using the module's ID
|
|
62
|
-
# @param validator_namespace [Module] validator namespace module (e.g., Validators::Tags::Order)
|
|
63
|
-
# @param validator_config [Class] validator config class
|
|
64
|
-
# @param results [Hash] hash to store results in
|
|
65
|
-
# @param validator_name [String] full validator name for per-validator exclusions
|
|
66
|
-
def run_and_store_validator(
|
|
67
|
-
validator_namespace, validator_config, results, validator_name
|
|
68
|
-
)
|
|
69
|
-
results[validator_config.id] = run_validator(
|
|
70
|
-
validator_namespace::Validator,
|
|
71
|
-
validator_name
|
|
72
|
-
)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Run a single validator with per-validator file filtering
|
|
76
|
-
# @param validator_class [Class] validator class to instantiate and run
|
|
77
|
-
# @param validator_name [String] full validator name for exclusions
|
|
78
|
-
# @return [Hash] hash with stdout, stderr and exit_code keys
|
|
79
|
-
def run_validator(validator_class, validator_name)
|
|
80
|
-
validator_selection = filter_files_for_validator(validator_name, selection)
|
|
81
|
-
validator_class.new(config, validator_selection).call
|
|
82
|
-
end
|
|
83
|
-
|
|
84
95
|
# Filter files for a specific validator based on per-validator exclusions
|
|
85
96
|
# @param validator_name [String] full validator name
|
|
86
97
|
# @param files [Array<String>] array of file paths
|
|
@@ -106,7 +117,6 @@ module Yard
|
|
|
106
117
|
return result if validator_excludes.empty?
|
|
107
118
|
|
|
108
119
|
working_dir = Dir.pwd
|
|
109
|
-
filtered_keys = %i[severity type name message location_line]
|
|
110
120
|
|
|
111
121
|
filtered_offenses = result.offenses.reject do |offense|
|
|
112
122
|
file_path = offense[:location] || offense[:file]
|
|
@@ -128,9 +138,11 @@ module Yard
|
|
|
128
138
|
# Return nil if no offenses remain after filtering
|
|
129
139
|
return nil if filtered_offenses.empty?
|
|
130
140
|
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
|
|
141
|
+
# Instead of creating a new Result object (which would rebuild messages),
|
|
142
|
+
# just modify the existing result object's offenses array
|
|
143
|
+
# This preserves all the processed offense data including enhanced messages
|
|
144
|
+
result.offenses = filtered_offenses
|
|
145
|
+
result
|
|
134
146
|
end
|
|
135
147
|
|
|
136
148
|
# Parse raw results from validators and create Result objects
|
|
@@ -57,6 +57,23 @@ Documentation/MarkdownSyntax:
|
|
|
57
57
|
Enabled: true
|
|
58
58
|
Severity: warning
|
|
59
59
|
|
|
60
|
+
Documentation/EmptyCommentLine:
|
|
61
|
+
Description: 'Detects empty comment lines at the start or end of documentation blocks.'
|
|
62
|
+
Enabled: true
|
|
63
|
+
Severity: convention
|
|
64
|
+
EnabledPatterns:
|
|
65
|
+
Leading: true
|
|
66
|
+
Trailing: true
|
|
67
|
+
|
|
68
|
+
Documentation/BlankLineBeforeDefinition:
|
|
69
|
+
Description: 'Detects blank lines between YARD documentation and method definition.'
|
|
70
|
+
Enabled: true
|
|
71
|
+
Severity: convention
|
|
72
|
+
OrphanedSeverity: convention
|
|
73
|
+
EnabledPatterns:
|
|
74
|
+
SingleBlankLine: true
|
|
75
|
+
OrphanedDocs: true
|
|
76
|
+
|
|
60
77
|
# Tags validators
|
|
61
78
|
Tags/Order:
|
|
62
79
|
Description: 'Enforces consistent ordering of YARD tags.'
|
|
@@ -65,9 +82,15 @@ Tags/Order:
|
|
|
65
82
|
EnforcedOrder:
|
|
66
83
|
- param
|
|
67
84
|
- option
|
|
85
|
+
- yield
|
|
86
|
+
- yieldparam
|
|
87
|
+
- yieldreturn
|
|
68
88
|
- return
|
|
69
89
|
- raise
|
|
90
|
+
- see
|
|
70
91
|
- example
|
|
92
|
+
- note
|
|
93
|
+
- todo
|
|
71
94
|
|
|
72
95
|
Tags/InvalidTypes:
|
|
73
96
|
Description: 'Validates type definitions in @param, @return, @option tags.'
|
|
@@ -136,6 +159,88 @@ Tags/OptionTags:
|
|
|
136
159
|
Enabled: true
|
|
137
160
|
Severity: warning
|
|
138
161
|
|
|
162
|
+
Tags/ExampleSyntax:
|
|
163
|
+
Description: 'Validates Ruby syntax in @example tags.'
|
|
164
|
+
Enabled: true
|
|
165
|
+
Severity: warning
|
|
166
|
+
|
|
167
|
+
Tags/RedundantParamDescription:
|
|
168
|
+
Description: 'Detects meaningless parameter descriptions that add no value.'
|
|
169
|
+
Enabled: true
|
|
170
|
+
Severity: convention
|
|
171
|
+
CheckedTags:
|
|
172
|
+
- param
|
|
173
|
+
- option
|
|
174
|
+
Articles:
|
|
175
|
+
- The
|
|
176
|
+
- the
|
|
177
|
+
- A
|
|
178
|
+
- a
|
|
179
|
+
- An
|
|
180
|
+
- an
|
|
181
|
+
MaxRedundantWords: 6
|
|
182
|
+
GenericTerms:
|
|
183
|
+
- object
|
|
184
|
+
- instance
|
|
185
|
+
- value
|
|
186
|
+
- data
|
|
187
|
+
- item
|
|
188
|
+
- element
|
|
189
|
+
EnabledPatterns:
|
|
190
|
+
ArticleParam: true
|
|
191
|
+
PossessiveParam: true
|
|
192
|
+
TypeRestatement: true
|
|
193
|
+
ParamToVerb: true
|
|
194
|
+
IdPattern: true
|
|
195
|
+
DirectionalDate: true
|
|
196
|
+
TypeGeneric: true
|
|
197
|
+
|
|
198
|
+
Tags/InformalNotation:
|
|
199
|
+
Description: 'Detects informal tag notation patterns like "Note:" instead of @note.'
|
|
200
|
+
Enabled: true
|
|
201
|
+
Severity: warning
|
|
202
|
+
CaseSensitive: false
|
|
203
|
+
RequireStartOfLine: true
|
|
204
|
+
Patterns:
|
|
205
|
+
Note: '@note'
|
|
206
|
+
Todo: '@todo'
|
|
207
|
+
TODO: '@todo'
|
|
208
|
+
FIXME: '@todo'
|
|
209
|
+
See: '@see'
|
|
210
|
+
See also: '@see'
|
|
211
|
+
Warning: '@deprecated'
|
|
212
|
+
Deprecated: '@deprecated'
|
|
213
|
+
Author: '@author'
|
|
214
|
+
Version: '@version'
|
|
215
|
+
Since: '@since'
|
|
216
|
+
Returns: '@return'
|
|
217
|
+
Raises: '@raise'
|
|
218
|
+
Example: '@example'
|
|
219
|
+
|
|
220
|
+
Tags/NonAsciiType:
|
|
221
|
+
Description: 'Detects non-ASCII characters in type annotations.'
|
|
222
|
+
Enabled: true
|
|
223
|
+
Severity: warning
|
|
224
|
+
ValidatedTags:
|
|
225
|
+
- param
|
|
226
|
+
- option
|
|
227
|
+
- return
|
|
228
|
+
- yieldreturn
|
|
229
|
+
- yieldparam
|
|
230
|
+
|
|
231
|
+
Tags/TagGroupSeparator:
|
|
232
|
+
Description: 'Enforces blank line separators between different YARD tag groups.'
|
|
233
|
+
Enabled: false # Opt-in validator
|
|
234
|
+
Severity: convention
|
|
235
|
+
TagGroups:
|
|
236
|
+
param: [param, option]
|
|
237
|
+
return: [return]
|
|
238
|
+
error: [raise, throws]
|
|
239
|
+
example: [example]
|
|
240
|
+
meta: [see, note, todo, deprecated, since, version, api]
|
|
241
|
+
yield: [yield, yieldparam, yieldreturn]
|
|
242
|
+
RequireAfterDescription: false
|
|
243
|
+
|
|
139
244
|
# Warnings validators - catches YARD parser errors
|
|
140
245
|
Warnings/UnknownTag:
|
|
141
246
|
Description: 'Detects unknown YARD tags.'
|
|
@@ -61,6 +61,23 @@ Documentation/MarkdownSyntax:
|
|
|
61
61
|
Enabled: true
|
|
62
62
|
Severity: error
|
|
63
63
|
|
|
64
|
+
Documentation/EmptyCommentLine:
|
|
65
|
+
Description: 'Detects empty comment lines at the start or end of documentation blocks.'
|
|
66
|
+
Enabled: true
|
|
67
|
+
Severity: error
|
|
68
|
+
EnabledPatterns:
|
|
69
|
+
Leading: true
|
|
70
|
+
Trailing: true
|
|
71
|
+
|
|
72
|
+
Documentation/BlankLineBeforeDefinition:
|
|
73
|
+
Description: 'Detects blank lines between YARD documentation and method definition.'
|
|
74
|
+
Enabled: true
|
|
75
|
+
Severity: error
|
|
76
|
+
OrphanedSeverity: error
|
|
77
|
+
EnabledPatterns:
|
|
78
|
+
SingleBlankLine: true
|
|
79
|
+
OrphanedDocs: true
|
|
80
|
+
|
|
64
81
|
# Tags validators
|
|
65
82
|
Tags/Order:
|
|
66
83
|
Description: 'Enforces consistent ordering of YARD tags.'
|
|
@@ -69,9 +86,15 @@ Tags/Order:
|
|
|
69
86
|
EnforcedOrder:
|
|
70
87
|
- param
|
|
71
88
|
- option
|
|
89
|
+
- yield
|
|
90
|
+
- yieldparam
|
|
91
|
+
- yieldreturn
|
|
72
92
|
- return
|
|
73
93
|
- raise
|
|
94
|
+
- see
|
|
74
95
|
- example
|
|
96
|
+
- note
|
|
97
|
+
- todo
|
|
75
98
|
|
|
76
99
|
Tags/InvalidTypes:
|
|
77
100
|
Description: 'Validates type definitions in @param, @return, @option tags.'
|
|
@@ -140,6 +163,88 @@ Tags/OptionTags:
|
|
|
140
163
|
Enabled: true
|
|
141
164
|
Severity: error
|
|
142
165
|
|
|
166
|
+
Tags/ExampleSyntax:
|
|
167
|
+
Description: 'Validates Ruby syntax in @example tags.'
|
|
168
|
+
Enabled: true
|
|
169
|
+
Severity: error
|
|
170
|
+
|
|
171
|
+
Tags/RedundantParamDescription:
|
|
172
|
+
Description: 'Detects meaningless parameter descriptions that add no value.'
|
|
173
|
+
Enabled: true
|
|
174
|
+
Severity: error
|
|
175
|
+
CheckedTags:
|
|
176
|
+
- param
|
|
177
|
+
- option
|
|
178
|
+
Articles:
|
|
179
|
+
- The
|
|
180
|
+
- the
|
|
181
|
+
- A
|
|
182
|
+
- a
|
|
183
|
+
- An
|
|
184
|
+
- an
|
|
185
|
+
MaxRedundantWords: 6
|
|
186
|
+
GenericTerms:
|
|
187
|
+
- object
|
|
188
|
+
- instance
|
|
189
|
+
- value
|
|
190
|
+
- data
|
|
191
|
+
- item
|
|
192
|
+
- element
|
|
193
|
+
EnabledPatterns:
|
|
194
|
+
ArticleParam: true
|
|
195
|
+
PossessiveParam: true
|
|
196
|
+
TypeRestatement: true
|
|
197
|
+
ParamToVerb: true
|
|
198
|
+
IdPattern: true
|
|
199
|
+
DirectionalDate: true
|
|
200
|
+
TypeGeneric: true
|
|
201
|
+
|
|
202
|
+
Tags/InformalNotation:
|
|
203
|
+
Description: 'Detects informal tag notation patterns like "Note:" instead of @note.'
|
|
204
|
+
Enabled: true
|
|
205
|
+
Severity: error
|
|
206
|
+
CaseSensitive: false
|
|
207
|
+
RequireStartOfLine: true
|
|
208
|
+
Patterns:
|
|
209
|
+
Note: '@note'
|
|
210
|
+
Todo: '@todo'
|
|
211
|
+
TODO: '@todo'
|
|
212
|
+
FIXME: '@todo'
|
|
213
|
+
See: '@see'
|
|
214
|
+
See also: '@see'
|
|
215
|
+
Warning: '@deprecated'
|
|
216
|
+
Deprecated: '@deprecated'
|
|
217
|
+
Author: '@author'
|
|
218
|
+
Version: '@version'
|
|
219
|
+
Since: '@since'
|
|
220
|
+
Returns: '@return'
|
|
221
|
+
Raises: '@raise'
|
|
222
|
+
Example: '@example'
|
|
223
|
+
|
|
224
|
+
Tags/NonAsciiType:
|
|
225
|
+
Description: 'Detects non-ASCII characters in type annotations.'
|
|
226
|
+
Enabled: true
|
|
227
|
+
Severity: error
|
|
228
|
+
ValidatedTags:
|
|
229
|
+
- param
|
|
230
|
+
- option
|
|
231
|
+
- return
|
|
232
|
+
- yieldreturn
|
|
233
|
+
- yieldparam
|
|
234
|
+
|
|
235
|
+
Tags/TagGroupSeparator:
|
|
236
|
+
Description: 'Enforces blank line separators between different YARD tag groups.'
|
|
237
|
+
Enabled: false # Opt-in validator
|
|
238
|
+
Severity: error
|
|
239
|
+
TagGroups:
|
|
240
|
+
param: [param, option]
|
|
241
|
+
return: [return]
|
|
242
|
+
error: [raise, throws]
|
|
243
|
+
example: [example]
|
|
244
|
+
meta: [see, note, todo, deprecated, since, version, api]
|
|
245
|
+
yield: [yield, yieldparam, yieldreturn]
|
|
246
|
+
RequireAfterDescription: false
|
|
247
|
+
|
|
143
248
|
# Warnings validators - catches YARD parser errors
|
|
144
249
|
Warnings/UnknownTag:
|
|
145
250
|
Description: 'Detects unknown YARD tags.'
|
|
@@ -6,47 +6,52 @@ module Yard
|
|
|
6
6
|
module Validators
|
|
7
7
|
# Base YARD validator class
|
|
8
8
|
class Base
|
|
9
|
-
# Class-level
|
|
10
|
-
#
|
|
11
|
-
@
|
|
12
|
-
|
|
13
|
-
# Default YARD command options that we need to use
|
|
14
|
-
DEFAULT_OPTIONS = [
|
|
15
|
-
'--charset utf-8',
|
|
16
|
-
'--markup markdown',
|
|
17
|
-
'--no-progress'
|
|
18
|
-
].freeze
|
|
19
|
-
|
|
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
|
|
23
|
-
|
|
24
|
-
private_constant :YARDOC_BASE_TEMP_DIR
|
|
9
|
+
# Class-level settings for in-process execution
|
|
10
|
+
# These must be set on each subclass, not on Base
|
|
11
|
+
@in_process_enabled = nil
|
|
12
|
+
@in_process_visibility = nil
|
|
25
13
|
|
|
26
14
|
attr_reader :config, :selection
|
|
27
15
|
|
|
28
16
|
class << self
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
17
|
+
# Declare that this validator supports in-process execution
|
|
18
|
+
# @param visibility [Symbol] visibility filter for objects (:public or :all)
|
|
19
|
+
# :public - only include public methods (default, no --private/--protected)
|
|
20
|
+
# :all - include all methods (equivalent to --private --protected)
|
|
21
|
+
# @return [void]
|
|
22
|
+
# @example
|
|
23
|
+
# class Validator < Base
|
|
24
|
+
# in_process visibility: :all
|
|
25
|
+
# end
|
|
26
|
+
def in_process(visibility: :public)
|
|
27
|
+
@in_process_enabled = true
|
|
28
|
+
@in_process_visibility = visibility
|
|
36
29
|
end
|
|
37
30
|
|
|
38
|
-
#
|
|
39
|
-
# @return [
|
|
40
|
-
def
|
|
41
|
-
|
|
31
|
+
# Check if this validator supports in-process execution
|
|
32
|
+
# @return [Boolean]
|
|
33
|
+
def in_process?
|
|
34
|
+
@in_process_enabled == true
|
|
42
35
|
end
|
|
43
36
|
|
|
44
|
-
#
|
|
45
|
-
# @return [
|
|
46
|
-
def
|
|
47
|
-
|
|
37
|
+
# Get the visibility setting for in-process execution
|
|
38
|
+
# @return [Symbol, nil] :public, :all, or nil if not set
|
|
39
|
+
def in_process_visibility
|
|
40
|
+
@in_process_visibility
|
|
41
|
+
end
|
|
48
42
|
|
|
49
|
-
|
|
43
|
+
# Get the validator name from the class namespace
|
|
44
|
+
# @return [String, nil] validator name like 'Tags/Order' or nil
|
|
45
|
+
# @example
|
|
46
|
+
# Yard::Lint::Validators::Tags::Order::Validator.validator_name
|
|
47
|
+
# # => 'Tags/Order'
|
|
48
|
+
def validator_name
|
|
49
|
+
name&.split('::')&.then do |parts|
|
|
50
|
+
idx = parts.index('Validators')
|
|
51
|
+
return nil unless idx && parts[idx + 1] && parts[idx + 2]
|
|
52
|
+
|
|
53
|
+
"#{parts[idx + 1]}/#{parts[idx + 2]}"
|
|
54
|
+
end
|
|
50
55
|
end
|
|
51
56
|
end
|
|
52
57
|
|
|
@@ -57,105 +62,34 @@ module Yard
|
|
|
57
62
|
@selection = selection
|
|
58
63
|
end
|
|
59
64
|
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
|
65
|
+
# Execute query for a single object during in-process execution.
|
|
66
|
+
# Override this method in validators that support in-process execution.
|
|
67
|
+
# @param object [YARD::CodeObjects::Base] the code object to query
|
|
68
|
+
# @param collector [Executor::ResultCollector] collector for output
|
|
69
|
+
# @return [void]
|
|
70
|
+
# @example
|
|
71
|
+
# def in_process_query(object, collector)
|
|
72
|
+
# return unless object.docstring.all.empty?
|
|
73
|
+
# collector.puts "#{object.file}:#{object.line}: #{object.title}"
|
|
74
|
+
# end
|
|
75
|
+
def in_process_query(object, collector)
|
|
76
|
+
raise NotImplementedError, "#{self.class} must implement in_process_query for in-process execution"
|
|
82
77
|
end
|
|
83
78
|
|
|
84
79
|
private
|
|
85
80
|
|
|
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
|
-
|
|
105
|
-
# @return [String] all arguments with which YARD command should be executed
|
|
106
|
-
def shell_arguments
|
|
107
|
-
validator_name = self.class.name&.split('::')&.then do |parts|
|
|
108
|
-
idx = parts.index('Validators')
|
|
109
|
-
next config.options unless idx && parts[idx + 1] && parts[idx + 2]
|
|
110
|
-
|
|
111
|
-
"#{parts[idx + 1]}/#{parts[idx + 2]}"
|
|
112
|
-
end || config.options
|
|
113
|
-
|
|
114
|
-
yard_options = config.validator_yard_options(validator_name)
|
|
115
|
-
args = escape(yard_options).join(' ')
|
|
116
|
-
"#{args} #{DEFAULT_OPTIONS.join(' ')}"
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# @param array [Array] escape all elements in an array
|
|
120
|
-
# @return [Array] array with escaped elements
|
|
121
|
-
def escape(array)
|
|
122
|
-
array.map { |cmd| Shellwords.escape(cmd) }
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# Builds a raw hash that can be used for further processing
|
|
126
|
-
# @param stdout [String, Hash, Array] anything that we want to return as stdout
|
|
127
|
-
# @param stderr [String, Hash, Array] any errors that occurred
|
|
128
|
-
# @param exit_code [Integer, false] result exit code or false if we want to decide it based
|
|
129
|
-
# on the stderr content
|
|
130
|
-
# @return [Hash] hash with stdout, stderr and exit_code keys
|
|
131
|
-
def raw(stdout = '', stderr = '', exit_code = false)
|
|
132
|
-
{
|
|
133
|
-
stdout: stdout,
|
|
134
|
-
stderr: stderr,
|
|
135
|
-
exit_code: exit_code || (stderr.empty? ? 0 : 1)
|
|
136
|
-
}
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# Executes a shell command and returns the result
|
|
140
|
-
# Routes through command cache to avoid duplicate executions
|
|
141
|
-
# @param cmd [String] shell command to execute
|
|
142
|
-
# @return [Hash] hash with stdout, stderr and exit_code keys
|
|
143
|
-
def shell(cmd)
|
|
144
|
-
self.class.command_cache.execute(cmd)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
81
|
# Retrieves configuration value with fallback to default
|
|
148
82
|
# Automatically determines the validator name from the class namespace
|
|
149
83
|
#
|
|
150
84
|
# @param key [String] the configuration key to retrieve
|
|
151
85
|
# @return [Object] the configured value or default value from the validator's Config.defaults
|
|
152
|
-
# @note The validator name is automatically extracted from the class namespace.
|
|
153
|
-
# For example, Yard::Lint::Validators::Tags::RedundantParamDescription::Validator
|
|
154
|
-
# becomes 'Tags/RedundantParamDescription'
|
|
155
86
|
# @example Usage in a validator (e.g., Tags::RedundantParamDescription)
|
|
156
87
|
# def config_articles
|
|
157
88
|
# config_or_default('Articles')
|
|
158
89
|
# end
|
|
90
|
+
# @note The validator name is automatically extracted from the class namespace.
|
|
91
|
+
# For example, Yard::Lint::Validators::Tags::RedundantParamDescription::Validator
|
|
92
|
+
# becomes 'Tags/RedundantParamDescription'
|
|
159
93
|
def config_or_default(key)
|
|
160
94
|
validator_name = self.class.name&.split('::')&.then do |parts|
|
|
161
95
|
idx = parts.index('Validators')
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Lint
|
|
5
|
+
module Validators
|
|
6
|
+
module Documentation
|
|
7
|
+
module BlankLineBeforeDefinition
|
|
8
|
+
# Configuration for BlankLineBeforeDefinition validator
|
|
9
|
+
class Config < ::Yard::Lint::Validators::Config
|
|
10
|
+
self.id = :blank_line_before_definition
|
|
11
|
+
self.defaults = {
|
|
12
|
+
'Enabled' => true,
|
|
13
|
+
'Severity' => 'convention',
|
|
14
|
+
'OrphanedSeverity' => 'convention',
|
|
15
|
+
'EnabledPatterns' => {
|
|
16
|
+
'SingleBlankLine' => true,
|
|
17
|
+
'OrphanedDocs' => true
|
|
18
|
+
}
|
|
19
|
+
}.freeze
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Lint
|
|
5
|
+
module Validators
|
|
6
|
+
module Documentation
|
|
7
|
+
module BlankLineBeforeDefinition
|
|
8
|
+
# Builds human-readable messages for blank line before definition violations
|
|
9
|
+
class MessagesBuilder
|
|
10
|
+
# Maps violation types to human-readable descriptions
|
|
11
|
+
ERROR_DESCRIPTIONS = {
|
|
12
|
+
'single' => 'Blank line between documentation and definition',
|
|
13
|
+
'orphaned' => 'Documentation is orphaned (YARD ignores it due to blank lines)'
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
# Formats a violation message
|
|
18
|
+
# @param offense [Hash] the offense details
|
|
19
|
+
# @return [String] formatted message
|
|
20
|
+
def call(offense)
|
|
21
|
+
type = offense[:violation_type]
|
|
22
|
+
object_name = offense[:object_name]
|
|
23
|
+
blank_count = offense[:blank_count]
|
|
24
|
+
|
|
25
|
+
description = ERROR_DESCRIPTIONS[type] || 'Blank line before definition'
|
|
26
|
+
|
|
27
|
+
if type == 'orphaned'
|
|
28
|
+
"#{description} for '#{object_name}' (#{blank_count} blank lines)"
|
|
29
|
+
else
|
|
30
|
+
"#{description} for '#{object_name}'"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|