yard-lint 1.3.0 → 1.5.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/.ruby-version +1 -0
- data/CHANGELOG.md +73 -3
- data/README.md +154 -527
- data/Rakefile +11 -8
- data/bin/yard-lint +64 -5
- data/lib/yard/lint/config.rb +4 -0
- data/lib/yard/lint/config_validator.rb +230 -0
- data/lib/yard/lint/errors.rb +6 -0
- data/lib/yard/lint/executor/in_process_registry.rb +9 -0
- data/lib/yard/lint/path_grouper.rb +70 -0
- data/lib/yard/lint/result_builder.rb +19 -5
- data/lib/yard/lint/results/base.rb +3 -3
- data/lib/yard/lint/templates/default_config.yml +31 -0
- data/lib/yard/lint/templates/strict_config.yml +31 -0
- data/lib/yard/lint/todo_generator.rb +261 -0
- data/lib/yard/lint/validators/base.rb +1 -1
- data/lib/yard/lint/validators/documentation/missing_return/config.rb +23 -0
- data/lib/yard/lint/validators/documentation/missing_return/messages_builder.rb +23 -0
- data/lib/yard/lint/validators/documentation/missing_return/parser.rb +128 -0
- data/lib/yard/lint/validators/documentation/missing_return/result.rb +25 -0
- data/lib/yard/lint/validators/documentation/missing_return/validator.rb +40 -0
- data/lib/yard/lint/validators/documentation/missing_return.rb +49 -0
- data/lib/yard/lint/validators/documentation/undocumented_boolean_methods/parser.rb +1 -1
- data/lib/yard/lint/validators/documentation/undocumented_method_arguments/parser.rb +1 -1
- data/lib/yard/lint/validators/documentation/undocumented_method_arguments/validator.rb +3 -0
- data/lib/yard/lint/validators/documentation/undocumented_objects/parser.rb +1 -1
- data/lib/yard/lint/validators/tags/collection_type/messages_builder.rb +8 -2
- data/lib/yard/lint/validators/tags/collection_type/validator.rb +33 -14
- data/lib/yard/lint/validators/tags/example_style/config.rb +33 -0
- data/lib/yard/lint/validators/tags/example_style/linter_detector.rb +71 -0
- data/lib/yard/lint/validators/tags/example_style/messages_builder.rb +29 -0
- data/lib/yard/lint/validators/tags/example_style/parser.rb +88 -0
- data/lib/yard/lint/validators/tags/example_style/result.rb +42 -0
- data/lib/yard/lint/validators/tags/example_style/rubocop_runner.rb +210 -0
- data/lib/yard/lint/validators/tags/example_style/validator.rb +87 -0
- data/lib/yard/lint/validators/tags/example_style.rb +61 -0
- data/lib/yard/lint/validators/tags/forbidden_tags/config.rb +21 -0
- data/lib/yard/lint/validators/tags/forbidden_tags/messages_builder.rb +34 -0
- data/lib/yard/lint/validators/tags/forbidden_tags/parser.rb +51 -0
- data/lib/yard/lint/validators/tags/forbidden_tags/result.rb +28 -0
- data/lib/yard/lint/validators/tags/forbidden_tags/validator.rb +66 -0
- data/lib/yard/lint/validators/tags/forbidden_tags.rb +68 -0
- data/lib/yard/lint/validators/tags/invalid_types/validator.rb +1 -1
- data/lib/yard/lint/validators/tags/tag_group_separator/parser.rb +1 -1
- data/lib/yard/lint/validators/tags/type_syntax/validator.rb +19 -0
- data/lib/yard/lint/validators/warnings/unknown_tag/parser.rb +1 -1
- data/lib/yard/lint/version.rb +1 -1
- data/mise.toml +2 -0
- data/package-lock.json +329 -0
- data/package.json +7 -0
- data/proxy_types +0 -0
- data/renovate.json +18 -1
- metadata +30 -3
- data/.coditsu/ci.yml +0 -3
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Lint
|
|
5
|
+
module Validators
|
|
6
|
+
module Tags
|
|
7
|
+
# ExampleStyle validator
|
|
8
|
+
#
|
|
9
|
+
# Validates code style in `@example` tags using RuboCop or StandardRB.
|
|
10
|
+
# This validator ensures that code examples follow the same style guidelines
|
|
11
|
+
# as the project codebase for consistency.
|
|
12
|
+
#
|
|
13
|
+
# ## Requirements
|
|
14
|
+
#
|
|
15
|
+
# - RuboCop or StandardRB gem must be installed
|
|
16
|
+
# - Validator auto-detects which linter to use based on project setup
|
|
17
|
+
#
|
|
18
|
+
# ## Configuration
|
|
19
|
+
#
|
|
20
|
+
# Basic usage:
|
|
21
|
+
#
|
|
22
|
+
# Tags/ExampleStyle:
|
|
23
|
+
# Enabled: true
|
|
24
|
+
#
|
|
25
|
+
# Advanced configuration:
|
|
26
|
+
#
|
|
27
|
+
# Tags/ExampleStyle:
|
|
28
|
+
# Enabled: true
|
|
29
|
+
# Linter: auto # 'auto', 'rubocop', 'standard', or 'none'
|
|
30
|
+
# SkipPatterns:
|
|
31
|
+
# - '/skip-lint/i'
|
|
32
|
+
# - '/bad code/i'
|
|
33
|
+
# DisabledCops:
|
|
34
|
+
# - 'Metrics/MethodLength'
|
|
35
|
+
#
|
|
36
|
+
# ## Skipping Examples
|
|
37
|
+
#
|
|
38
|
+
# Skip linting for specific examples (negative examples):
|
|
39
|
+
#
|
|
40
|
+
# # @example Bad code (skip-lint)
|
|
41
|
+
# # user = User.new("invalid")
|
|
42
|
+
#
|
|
43
|
+
# Or use inline RuboCop directives:
|
|
44
|
+
#
|
|
45
|
+
# # @example
|
|
46
|
+
# # # rubocop:disable all
|
|
47
|
+
# # user = User.new("invalid")
|
|
48
|
+
# # # rubocop:enable all
|
|
49
|
+
module ExampleStyle
|
|
50
|
+
autoload :Validator, 'yard/lint/validators/tags/example_style/validator'
|
|
51
|
+
autoload :Config, 'yard/lint/validators/tags/example_style/config'
|
|
52
|
+
autoload :Parser, 'yard/lint/validators/tags/example_style/parser'
|
|
53
|
+
autoload :Result, 'yard/lint/validators/tags/example_style/result'
|
|
54
|
+
autoload :MessagesBuilder, 'yard/lint/validators/tags/example_style/messages_builder'
|
|
55
|
+
autoload :LinterDetector, 'yard/lint/validators/tags/example_style/linter_detector'
|
|
56
|
+
autoload :RubocopRunner, 'yard/lint/validators/tags/example_style/rubocop_runner'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Lint
|
|
5
|
+
module Validators
|
|
6
|
+
module Tags
|
|
7
|
+
module ForbiddenTags
|
|
8
|
+
# Configuration for ForbiddenTags validator
|
|
9
|
+
class Config < ::Yard::Lint::Validators::Config
|
|
10
|
+
self.id = :forbidden_tags
|
|
11
|
+
self.defaults = {
|
|
12
|
+
'Enabled' => false,
|
|
13
|
+
'Severity' => 'convention',
|
|
14
|
+
'ForbiddenPatterns' => []
|
|
15
|
+
}.freeze
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Lint
|
|
5
|
+
module Validators
|
|
6
|
+
module Tags
|
|
7
|
+
module ForbiddenTags
|
|
8
|
+
# Builds human-readable messages for ForbiddenTags violations
|
|
9
|
+
class MessagesBuilder
|
|
10
|
+
class << self
|
|
11
|
+
# Formats a forbidden tag violation message
|
|
12
|
+
# @param offense [Hash] offense details with :tag_name, :types_text, :pattern_types
|
|
13
|
+
# @return [String] formatted message
|
|
14
|
+
def call(offense)
|
|
15
|
+
tag_name = offense[:tag_name]
|
|
16
|
+
types_text = offense[:types_text]
|
|
17
|
+
pattern_types = offense[:pattern_types]
|
|
18
|
+
|
|
19
|
+
if pattern_types.nil? || pattern_types.empty?
|
|
20
|
+
"Forbidden tag detected: @#{tag_name}. " \
|
|
21
|
+
'This tag is not allowed by project configuration.'
|
|
22
|
+
else
|
|
23
|
+
type_display = types_text.empty? ? '' : " [#{types_text}]"
|
|
24
|
+
"Forbidden tag pattern detected: @#{tag_name}#{type_display}. " \
|
|
25
|
+
"Type(s) '#{pattern_types}' are not allowed for @#{tag_name}."
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Lint
|
|
5
|
+
module Validators
|
|
6
|
+
module Tags
|
|
7
|
+
module ForbiddenTags
|
|
8
|
+
# Parser for ForbiddenTags validator output
|
|
9
|
+
# Parses in-process output that reports forbidden tag patterns
|
|
10
|
+
class Parser < ::Yard::Lint::Parsers::Base
|
|
11
|
+
# Parses validator output and extracts forbidden tag violations
|
|
12
|
+
# Expected format (two lines per violation):
|
|
13
|
+
# file.rb:LINE: ObjectName
|
|
14
|
+
# tag_name|types_text|pattern_types
|
|
15
|
+
# @param yard_output [String] raw validator output
|
|
16
|
+
# @return [Array<Hash>] array with violation details
|
|
17
|
+
def call(yard_output, **)
|
|
18
|
+
return [] if yard_output.nil? || yard_output.strip.empty?
|
|
19
|
+
|
|
20
|
+
lines = yard_output.split("\n").map(&:strip).reject(&:empty?)
|
|
21
|
+
violations = []
|
|
22
|
+
|
|
23
|
+
lines.each_slice(2) do |location_line, details_line|
|
|
24
|
+
next unless location_line && details_line
|
|
25
|
+
|
|
26
|
+
location_match = location_line.match(/^(.+):(\d+): (.+)$/)
|
|
27
|
+
next unless location_match
|
|
28
|
+
|
|
29
|
+
details = details_line.split('|', 3)
|
|
30
|
+
next if details.empty?
|
|
31
|
+
|
|
32
|
+
tag_name, types_text, pattern_types = details
|
|
33
|
+
|
|
34
|
+
violations << {
|
|
35
|
+
location: location_match[1],
|
|
36
|
+
line: location_match[2].to_i,
|
|
37
|
+
object_name: location_match[3],
|
|
38
|
+
tag_name: tag_name,
|
|
39
|
+
types_text: types_text || '',
|
|
40
|
+
pattern_types: pattern_types || ''
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
violations
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Lint
|
|
5
|
+
module Validators
|
|
6
|
+
module Tags
|
|
7
|
+
module ForbiddenTags
|
|
8
|
+
# Result wrapper for ForbiddenTags validator
|
|
9
|
+
# Formats parsed violations into offense objects
|
|
10
|
+
class Result < Results::Base
|
|
11
|
+
self.default_severity = 'convention'
|
|
12
|
+
self.offense_type = 'tag'
|
|
13
|
+
self.offense_name = 'ForbiddenTags'
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
# Builds a human-readable message for the offense
|
|
18
|
+
# @param offense [Hash] offense details
|
|
19
|
+
# @return [String] formatted message
|
|
20
|
+
def build_message(offense)
|
|
21
|
+
MessagesBuilder.call(offense)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Lint
|
|
5
|
+
module Validators
|
|
6
|
+
module Tags
|
|
7
|
+
module ForbiddenTags
|
|
8
|
+
# Validates that forbidden tag/type combinations are not used
|
|
9
|
+
class Validator < Base
|
|
10
|
+
# Enable in-process execution with all visibility
|
|
11
|
+
in_process visibility: :all
|
|
12
|
+
|
|
13
|
+
# Execute query for a single object during in-process execution.
|
|
14
|
+
# Checks for forbidden tag/type combinations in docstrings.
|
|
15
|
+
# @param object [YARD::CodeObjects::Base] the code object to query
|
|
16
|
+
# @param collector [Executor::ResultCollector] collector for output
|
|
17
|
+
def in_process_query(object, collector)
|
|
18
|
+
patterns = forbidden_patterns
|
|
19
|
+
return if patterns.empty?
|
|
20
|
+
|
|
21
|
+
object.docstring.tags.each do |tag|
|
|
22
|
+
patterns.each do |pattern|
|
|
23
|
+
next unless matches_pattern?(tag, pattern)
|
|
24
|
+
|
|
25
|
+
collector.puts "#{object.file}:#{object.line}: #{object.title}"
|
|
26
|
+
collector.puts build_details(tag, pattern)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
# @return [Array<Hash>] configured forbidden patterns
|
|
34
|
+
def forbidden_patterns
|
|
35
|
+
config_or_default('ForbiddenPatterns')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Check if a tag matches a forbidden pattern
|
|
39
|
+
# @param tag [YARD::Tags::Tag] the tag to check
|
|
40
|
+
# @param pattern [Hash] the forbidden pattern with 'Tag' and optional 'Types'
|
|
41
|
+
# @return [Boolean] true if tag matches the pattern
|
|
42
|
+
def matches_pattern?(tag, pattern)
|
|
43
|
+
return false unless tag.tag_name == pattern['Tag']
|
|
44
|
+
|
|
45
|
+
pattern_types = pattern['Types']
|
|
46
|
+
return true if pattern_types.nil? || pattern_types.empty?
|
|
47
|
+
|
|
48
|
+
tag_types = tag.types || []
|
|
49
|
+
(tag_types & pattern_types).any?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Build details string for output
|
|
53
|
+
# @param tag [YARD::Tags::Tag] the matched tag
|
|
54
|
+
# @param pattern [Hash] the matched pattern
|
|
55
|
+
# @return [String] details line for parser
|
|
56
|
+
def build_details(tag, pattern)
|
|
57
|
+
types_text = (tag.types || []).join(',')
|
|
58
|
+
pattern_types = (pattern['Types'] || []).join(',')
|
|
59
|
+
"#{tag.tag_name}|#{types_text}|#{pattern_types}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Lint
|
|
5
|
+
module Validators
|
|
6
|
+
module Tags
|
|
7
|
+
# ForbiddenTags validator
|
|
8
|
+
#
|
|
9
|
+
# Detects forbidden YARD tag and type combinations. This is useful for
|
|
10
|
+
# enforcing project-specific documentation conventions, such as:
|
|
11
|
+
# - Disallowing `@return [void]` (prefer documenting side effects)
|
|
12
|
+
# - Forbidding overly generic types like `@param [Object]`
|
|
13
|
+
# - Preventing use of certain tags entirely
|
|
14
|
+
#
|
|
15
|
+
# This validator is disabled by default (opt-in).
|
|
16
|
+
#
|
|
17
|
+
# ## Configuration
|
|
18
|
+
#
|
|
19
|
+
# To enable and configure forbidden patterns:
|
|
20
|
+
#
|
|
21
|
+
# Tags/ForbiddenTags:
|
|
22
|
+
# Enabled: true
|
|
23
|
+
# Severity: convention
|
|
24
|
+
# ForbiddenPatterns:
|
|
25
|
+
# # Forbid @return [void]
|
|
26
|
+
# - Tag: return
|
|
27
|
+
# Types:
|
|
28
|
+
# - void
|
|
29
|
+
# # Forbid @param [Object]
|
|
30
|
+
# - Tag: param
|
|
31
|
+
# Types:
|
|
32
|
+
# - Object
|
|
33
|
+
# # Forbid @api tag entirely
|
|
34
|
+
# - Tag: api
|
|
35
|
+
#
|
|
36
|
+
# @example Bad - @return [void] (when configured as forbidden)
|
|
37
|
+
# # Does something
|
|
38
|
+
# # @return [void]
|
|
39
|
+
# def do_something
|
|
40
|
+
# puts "done"
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# @example Good - Document side effects instead
|
|
44
|
+
# # Prints 'done' to stdout
|
|
45
|
+
# # @return [nil] always returns nil after printing
|
|
46
|
+
# def do_something
|
|
47
|
+
# puts "done"
|
|
48
|
+
# end
|
|
49
|
+
#
|
|
50
|
+
# @example Bad - @param [Object] (when configured as forbidden)
|
|
51
|
+
# # Process data
|
|
52
|
+
# # @param data [Object] the data
|
|
53
|
+
# def process(data)
|
|
54
|
+
# data.to_s
|
|
55
|
+
# end
|
|
56
|
+
#
|
|
57
|
+
# @example Good - Use specific type
|
|
58
|
+
# # Process data
|
|
59
|
+
# # @param data [String, Integer] the data to process
|
|
60
|
+
# def process(data)
|
|
61
|
+
# data.to_s
|
|
62
|
+
# end
|
|
63
|
+
module ForbiddenTags
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -34,7 +34,7 @@ module Yard
|
|
|
34
34
|
allowed_types = ALLOWED_DEFAULTS + extra_types
|
|
35
35
|
|
|
36
36
|
# Sanitize type string (remove type syntax characters)
|
|
37
|
-
sanitize = ->(type) { type.tr('=><>,{} ', '') }
|
|
37
|
+
sanitize = ->(type) { type.tr('=><>,{} ()', '') }
|
|
38
38
|
|
|
39
39
|
# Check for invalid types
|
|
40
40
|
invalid_types = object.docstring.tags
|
|
@@ -7,7 +7,7 @@ module Yard
|
|
|
7
7
|
module TagGroupSeparator
|
|
8
8
|
# Parser for extracting tag group separator violations from raw validator output.
|
|
9
9
|
#
|
|
10
|
-
# @example Output format
|
|
10
|
+
# @example Output format (skip-lint)
|
|
11
11
|
# /path/to/file.rb:10: ClassName#method_name
|
|
12
12
|
# param->return,return->error
|
|
13
13
|
class Parser < Parsers::Base
|
|
@@ -7,6 +7,18 @@ module Yard
|
|
|
7
7
|
module TypeSyntax
|
|
8
8
|
# Runs YARD to validate type syntax using TypesExplainer::Parser
|
|
9
9
|
class Validator < Base
|
|
10
|
+
# Matches valid Ruby symbol literals: :foo, :foo?, :foo!, :foo=
|
|
11
|
+
SYMBOL_LITERAL = /\A:[a-zA-Z_]\w*[?!=]?\z/
|
|
12
|
+
# Matches valid quoted symbol literals: :"foo", :'foo' (quotes must match)
|
|
13
|
+
QUOTED_SYMBOL_LITERAL = /\A:("[^"]*"|'[^']*')\z/
|
|
14
|
+
# Matches string literals: "foo", 'foo' (quotes must match)
|
|
15
|
+
STRING_LITERAL = /\A("[^"]*"|'[^']*')\z/
|
|
16
|
+
# Matches numeric literals: 1, -1, 1.0, -2.5
|
|
17
|
+
NUMERIC_LITERAL = /\A-?\d+(\.\d+)?\z/
|
|
18
|
+
|
|
19
|
+
private_constant :SYMBOL_LITERAL, :QUOTED_SYMBOL_LITERAL, :STRING_LITERAL,
|
|
20
|
+
:NUMERIC_LITERAL
|
|
21
|
+
|
|
10
22
|
# Enable in-process execution
|
|
11
23
|
in_process visibility: :public
|
|
12
24
|
|
|
@@ -25,6 +37,13 @@ module Yard
|
|
|
25
37
|
next unless tag.types
|
|
26
38
|
|
|
27
39
|
tag.types.each do |type_str|
|
|
40
|
+
# Skip literal types that YARD accepts but TypesExplainer::Parser doesn't
|
|
41
|
+
# See: https://github.com/mensfeld/yard-lint/issues/109
|
|
42
|
+
next if type_str.match?(SYMBOL_LITERAL)
|
|
43
|
+
next if type_str.match?(QUOTED_SYMBOL_LITERAL)
|
|
44
|
+
next if type_str.match?(STRING_LITERAL)
|
|
45
|
+
next if type_str.match?(NUMERIC_LITERAL)
|
|
46
|
+
|
|
28
47
|
begin
|
|
29
48
|
YARD::Tags::TypesExplainer::Parser.parse(type_str)
|
|
30
49
|
rescue SyntaxError => e
|
|
@@ -6,7 +6,7 @@ module Yard
|
|
|
6
6
|
module Warnings
|
|
7
7
|
module UnknownTag
|
|
8
8
|
# Parser used to extract warnings details that are related to yard unknown tags
|
|
9
|
-
# @example
|
|
9
|
+
# @example Output format (skip-lint)
|
|
10
10
|
# [warn]: Unknown tag @example1 in file `/builds/path/engine.rb` near line 32
|
|
11
11
|
class Parser < ::Yard::Lint::Parsers::OneLineBase
|
|
12
12
|
# Set of regexps for detecting warnings reported by YARD stats
|
data/lib/yard/lint/version.rb
CHANGED
data/mise.toml
ADDED