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.
Files changed (100) 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/results/base.rb +2 -1
  14. data/lib/yard/lint/runner.rb +50 -38
  15. data/lib/yard/lint/templates/default_config.yml +105 -0
  16. data/lib/yard/lint/templates/strict_config.yml +105 -0
  17. data/lib/yard/lint/validators/base.rb +52 -118
  18. data/lib/yard/lint/validators/documentation/blank_line_before_definition/config.rb +25 -0
  19. data/lib/yard/lint/validators/documentation/blank_line_before_definition/messages_builder.rb +39 -0
  20. data/lib/yard/lint/validators/documentation/blank_line_before_definition/parser.rb +59 -0
  21. data/lib/yard/lint/validators/documentation/blank_line_before_definition/result.rb +61 -0
  22. data/lib/yard/lint/validators/documentation/blank_line_before_definition/validator.rb +94 -0
  23. data/lib/yard/lint/validators/documentation/blank_line_before_definition.rb +63 -0
  24. data/lib/yard/lint/validators/documentation/empty_comment_line/config.rb +24 -0
  25. data/lib/yard/lint/validators/documentation/empty_comment_line/messages_builder.rb +34 -0
  26. data/lib/yard/lint/validators/documentation/empty_comment_line/parser.rb +60 -0
  27. data/lib/yard/lint/validators/documentation/empty_comment_line/result.rb +25 -0
  28. data/lib/yard/lint/validators/documentation/empty_comment_line/validator.rb +109 -0
  29. data/lib/yard/lint/validators/documentation/empty_comment_line.rb +58 -0
  30. data/lib/yard/lint/validators/documentation/markdown_syntax/validator.rb +36 -21
  31. data/lib/yard/lint/validators/documentation/markdown_syntax.rb +0 -1
  32. data/lib/yard/lint/validators/documentation/undocumented_boolean_methods/validator.rb +19 -29
  33. data/lib/yard/lint/validators/documentation/undocumented_boolean_methods.rb +0 -1
  34. data/lib/yard/lint/validators/documentation/undocumented_method_arguments/validator.rb +18 -34
  35. data/lib/yard/lint/validators/documentation/undocumented_method_arguments.rb +0 -1
  36. data/lib/yard/lint/validators/documentation/undocumented_objects/validator.rb +17 -25
  37. data/lib/yard/lint/validators/documentation/undocumented_objects.rb +4 -5
  38. data/lib/yard/lint/validators/documentation/undocumented_options/validator.rb +30 -21
  39. data/lib/yard/lint/validators/documentation/undocumented_options.rb +0 -1
  40. data/lib/yard/lint/validators/semantic/abstract_methods/result.rb +2 -2
  41. data/lib/yard/lint/validators/semantic/abstract_methods/validator.rb +31 -43
  42. data/lib/yard/lint/validators/semantic/abstract_methods.rb +0 -1
  43. data/lib/yard/lint/validators/tags/api_tags/validator.rb +24 -39
  44. data/lib/yard/lint/validators/tags/api_tags.rb +0 -1
  45. data/lib/yard/lint/validators/tags/collection_type/validator.rb +37 -66
  46. data/lib/yard/lint/validators/tags/collection_type.rb +0 -1
  47. data/lib/yard/lint/validators/tags/example_syntax/validator.rb +51 -64
  48. data/lib/yard/lint/validators/tags/example_syntax.rb +0 -1
  49. data/lib/yard/lint/validators/tags/informal_notation/config.rb +40 -0
  50. data/lib/yard/lint/validators/tags/informal_notation/messages_builder.rb +35 -0
  51. data/lib/yard/lint/validators/tags/informal_notation/parser.rb +55 -0
  52. data/lib/yard/lint/validators/tags/informal_notation/result.rb +26 -0
  53. data/lib/yard/lint/validators/tags/informal_notation/validator.rb +133 -0
  54. data/lib/yard/lint/validators/tags/informal_notation.rb +45 -0
  55. data/lib/yard/lint/validators/tags/invalid_types/validator.rb +57 -70
  56. data/lib/yard/lint/validators/tags/invalid_types.rb +0 -1
  57. data/lib/yard/lint/validators/tags/meaningless_tag/validator.rb +22 -54
  58. data/lib/yard/lint/validators/tags/meaningless_tag.rb +0 -1
  59. data/lib/yard/lint/validators/tags/non_ascii_type/config.rb +21 -0
  60. data/lib/yard/lint/validators/tags/non_ascii_type/messages_builder.rb +29 -0
  61. data/lib/yard/lint/validators/tags/non_ascii_type/parser.rb +59 -0
  62. data/lib/yard/lint/validators/tags/non_ascii_type/result.rb +25 -0
  63. data/lib/yard/lint/validators/tags/non_ascii_type/validator.rb +50 -0
  64. data/lib/yard/lint/validators/tags/non_ascii_type.rb +39 -0
  65. data/lib/yard/lint/validators/tags/option_tags/result.rb +2 -2
  66. data/lib/yard/lint/validators/tags/option_tags/validator.rb +25 -40
  67. data/lib/yard/lint/validators/tags/option_tags.rb +0 -1
  68. data/lib/yard/lint/validators/tags/order/validator.rb +28 -55
  69. data/lib/yard/lint/validators/tags/order.rb +0 -1
  70. data/lib/yard/lint/validators/tags/redundant_param_description/config.rb +15 -1
  71. data/lib/yard/lint/validators/tags/redundant_param_description/messages_builder.rb +5 -0
  72. data/lib/yard/lint/validators/tags/redundant_param_description/validator.rb +134 -100
  73. data/lib/yard/lint/validators/tags/redundant_param_description.rb +0 -1
  74. data/lib/yard/lint/validators/tags/tag_group_separator/config.rb +29 -0
  75. data/lib/yard/lint/validators/tags/tag_group_separator/messages_builder.rb +49 -0
  76. data/lib/yard/lint/validators/tags/tag_group_separator/parser.rb +67 -0
  77. data/lib/yard/lint/validators/tags/tag_group_separator/result.rb +28 -0
  78. data/lib/yard/lint/validators/tags/tag_group_separator/validator.rb +117 -0
  79. data/lib/yard/lint/validators/tags/tag_group_separator.rb +49 -0
  80. data/lib/yard/lint/validators/tags/tag_type_position/validator.rb +53 -84
  81. data/lib/yard/lint/validators/tags/tag_type_position.rb +0 -1
  82. data/lib/yard/lint/validators/tags/type_syntax/parser.rb +7 -2
  83. data/lib/yard/lint/validators/tags/type_syntax/validator.rb +29 -59
  84. data/lib/yard/lint/validators/tags/type_syntax.rb +0 -1
  85. data/lib/yard/lint/validators/warnings/duplicated_parameter_name/validator.rb +1 -18
  86. data/lib/yard/lint/validators/warnings/invalid_directive_format/validator.rb +1 -18
  87. data/lib/yard/lint/validators/warnings/invalid_tag_format/validator.rb +1 -18
  88. data/lib/yard/lint/validators/warnings/unknown_directive/validator.rb +1 -18
  89. data/lib/yard/lint/validators/warnings/unknown_parameter_name/messages_builder.rb +243 -0
  90. data/lib/yard/lint/validators/warnings/unknown_parameter_name/result.rb +4 -3
  91. data/lib/yard/lint/validators/warnings/unknown_parameter_name/validator.rb +1 -18
  92. data/lib/yard/lint/validators/warnings/unknown_tag/messages_builder.rb +144 -0
  93. data/lib/yard/lint/validators/warnings/unknown_tag/result.rb +4 -3
  94. data/lib/yard/lint/validators/warnings/unknown_tag/validator.rb +1 -18
  95. data/lib/yard/lint/validators/warnings/unknown_tag.rb +10 -0
  96. data/lib/yard/lint/version.rb +1 -1
  97. data/lib/yard/lint.rb +81 -13
  98. data/renovate.json +1 -8
  99. metadata +38 -2
  100. data/lib/yard/lint/command_cache.rb +0 -93
@@ -5,25 +5,8 @@ module Yard
5
5
  module Validators
6
6
  module Warnings
7
7
  module UnknownParameterName
8
- # Runs YARD stats command to check for unknownparametername
8
+ # Validator for detecting unknown parameter name warnings from YARD
9
9
  class Validator < Base
10
- private
11
-
12
- # Runs YARD stats command with proper settings on a given dir and files
13
- # @param dir [String] dir where we should generate the temp docs
14
- # @param file_list_path [String] path to temp file containing file paths (one per line)
15
- # @return [Hash] shell command execution hash results
16
- def yard_cmd(dir, file_list_path)
17
- cmd = <<~CMD
18
- cat #{Shellwords.escape(file_list_path)} | xargs yard stats \
19
- #{shell_arguments} \
20
- --compact \
21
- -b #{Shellwords.escape(dir)}
22
- CMD
23
- cmd = cmd.tr("\n", ' ')
24
-
25
- shell(cmd)
26
- end
27
10
  end
28
11
  end
29
12
  end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Warnings
7
+ module UnknownTag
8
+ # Builds enhanced messages with "did you mean" suggestions for unknown tags
9
+ class MessagesBuilder
10
+ class << self
11
+ # Dynamically fetch list of valid YARD meta-data tags from YARD::Tags::Library
12
+ # This ensures we're always in sync with the installed YARD version
13
+ # @return [Array<String>] array of tag names (without @ prefix)
14
+ def known_tags
15
+ @known_tags ||= begin
16
+ lib = ::YARD::Tags::Library.instance
17
+ lib.methods
18
+ .grep(/_tag$/)
19
+ .map { |m| m.to_s.sub(/_tag$/, '') }
20
+ .sort
21
+ .freeze
22
+ end
23
+ end
24
+
25
+ # Dynamically fetch list of valid YARD directives from YARD::Tags::Library
26
+ # This ensures we're always in sync with the installed YARD version
27
+ # @return [Array<String>] array of directive names (without @! prefix)
28
+ def known_directives
29
+ @known_directives ||= begin
30
+ lib = ::YARD::Tags::Library.instance
31
+ lib.methods
32
+ .grep(/_directive$/)
33
+ .map { |m| m.to_s.sub(/_directive$/, '') }
34
+ .sort
35
+ .freeze
36
+ end
37
+ end
38
+
39
+ # Combined list of all known tags and directives
40
+ # @return [Array<String>] array of all valid tag and directive names
41
+ def all_known_tags
42
+ @all_known_tags ||= (known_tags + known_directives).freeze
43
+ end
44
+ # Build message with suggestion for unknown tag
45
+ # @param offense [Hash] offense data with :message, :location (file), :line keys
46
+ # @return [String] formatted message with suggestion if available
47
+ def call(offense)
48
+ message = offense[:message] || 'Unknown tag detected'
49
+
50
+ # Extract the unknown tag name from the message
51
+ # Format: "Unknown tag @tagname in file..."
52
+ match = message.match(/Unknown tag @(\w+)/)
53
+ return message unless match
54
+
55
+ unknown_tag = match[1]
56
+
57
+ # Find best suggestion using did_you_mean
58
+ suggestion = find_suggestion(unknown_tag)
59
+
60
+ if suggestion
61
+ # Replace just the descriptive part before "in file"
62
+ message.sub(/Unknown tag @\w+/, "Unknown tag @#{unknown_tag} (did you mean '@#{suggestion}'?)")
63
+ else
64
+ message
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ # Find the best suggestion using DidYouMean spell checker
71
+ # @param unknown_tag [String] the unknown tag name (without @ prefix)
72
+ # @return [String, nil] suggested tag name or nil
73
+ def find_suggestion(unknown_tag)
74
+ return nil if unknown_tag.nil? || unknown_tag.empty?
75
+
76
+ # Use DidYouMean::SpellChecker for smart suggestions
77
+ spell_checker = DidYouMean::SpellChecker.new(dictionary: all_known_tags)
78
+ suggestions = spell_checker.correct(unknown_tag)
79
+
80
+ # If DidYouMean found suggestions, return the best one
81
+ return suggestions.first unless suggestions.empty?
82
+
83
+ # Otherwise, fallback to Levenshtein distance
84
+ find_suggestion_fallback(unknown_tag)
85
+ rescue StandardError => e
86
+ # Fallback to simple Levenshtein distance if DidYouMean fails
87
+ warn "DidYouMean failed: #{e.message}, using fallback" if ENV['DEBUG']
88
+ find_suggestion_fallback(unknown_tag)
89
+ end
90
+
91
+ # Fallback suggestion finder using simple Levenshtein distance
92
+ # @param unknown_tag [String] the unknown tag name
93
+ # @return [String, nil] suggested tag name or nil
94
+ def find_suggestion_fallback(unknown_tag)
95
+ # Calculate Levenshtein distance for each tag
96
+ distances = all_known_tags.map do |tag|
97
+ [tag, levenshtein_distance(unknown_tag, tag)]
98
+ end
99
+
100
+ # Sort by distance and get the closest match
101
+ best_match = distances.min_by { |_tag, distance| distance }
102
+
103
+ # Only suggest if the distance is reasonable (less than half the length)
104
+ return nil unless best_match
105
+
106
+ tag, distance = best_match
107
+ max_distance = [unknown_tag.length, tag.length].max / 2
108
+
109
+ distance <= max_distance ? tag : nil
110
+ end
111
+
112
+ # Calculate Levenshtein distance between two strings
113
+ # @param str1 [String] first string
114
+ # @param str2 [String] second string
115
+ # @return [Integer] Levenshtein distance
116
+ def levenshtein_distance(str1, str2)
117
+ return str2.length if str1.empty?
118
+ return str1.length if str2.empty?
119
+
120
+ matrix = Array.new(str1.length + 1) { Array.new(str2.length + 1) }
121
+
122
+ (0..str1.length).each { |i| matrix[i][0] = i }
123
+ (0..str2.length).each { |j| matrix[0][j] = j }
124
+
125
+ (1..str1.length).each do |i|
126
+ (1..str2.length).each do |j|
127
+ cost = str1[i - 1] == str2[j - 1] ? 0 : 1
128
+ matrix[i][j] = [
129
+ matrix[i - 1][j] + 1, # deletion
130
+ matrix[i][j - 1] + 1, # insertion
131
+ matrix[i - 1][j - 1] + cost # substitution
132
+ ].min
133
+ end
134
+ end
135
+
136
+ matrix[str1.length][str2.length]
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -12,10 +12,11 @@ module Yard
12
12
  self.offense_name = 'UnknownTag'
13
13
 
14
14
  # Build human-readable message for unknown tag offense
15
- # @param offense [Hash] offense data with :message key
16
- # @return [String] formatted message
15
+ # Uses MessagesBuilder to add "did you mean" suggestions
16
+ # @param offense [Hash] offense data with :message, :location, :line keys
17
+ # @return [String] formatted message with suggestion if available
17
18
  def build_message(offense)
18
- offense[:message] || 'Unknown tag detected'
19
+ MessagesBuilder.call(offense)
19
20
  end
20
21
  end
21
22
  end
@@ -5,25 +5,8 @@ module Yard
5
5
  module Validators
6
6
  module Warnings
7
7
  module UnknownTag
8
- # Runs YARD stats command to check for unknown YARD tags
8
+ # Validator for detecting unknown YARD tag warnings
9
9
  class Validator < Base
10
- private
11
-
12
- # Runs YARD stats command with proper settings on a given dir and files
13
- # @param dir [String] dir where we should generate the temp docs
14
- # @param file_list_path [String] path to temp file containing file paths (one per line)
15
- # @return [Hash] shell command execution hash results
16
- def yard_cmd(dir, file_list_path)
17
- cmd = <<~CMD
18
- cat #{Shellwords.escape(file_list_path)} | xargs yard stats \
19
- #{shell_arguments} \
20
- --compact \
21
- -b #{Shellwords.escape(dir)}
22
- CMD
23
- cmd = cmd.tr("\n", ' ')
24
-
25
- shell(cmd)
26
- end
27
10
  end
28
11
  end
29
12
  end
@@ -12,18 +12,28 @@ module Yard
12
12
  # doesn't recognize, which could indicate typos or unsupported tags.
13
13
  # This validator is enabled by default.
14
14
  #
15
+ # Provides intelligent "did you mean" suggestions for common typos using
16
+ # Ruby's did_you_mean gem with Levenshtein distance fallback.
17
+ #
15
18
  # @example Bad - Misspelled or non-existent tags
16
19
  # # @param name [String] typo in param tag
17
20
  # # @returns [String] should be @return not @returns
21
+ # # @raises [Error] should be @raise not @raises
18
22
  # def process(name)
19
23
  # end
20
24
  #
21
25
  # @example Good - Standard YARD tags
22
26
  # # @param name [String] the name
23
27
  # # @return [String] the result
28
+ # # @raise [Error] the error
24
29
  # def process(name)
25
30
  # end
26
31
  #
32
+ # **Output with suggestions:**
33
+ #
34
+ # lib/foo.rb:10: [error] Unknown tag @returns (did you mean '@return'?)
35
+ # lib/foo.rb:11: [error] Unknown tag @raises (did you mean '@raise'?)
36
+ #
27
37
  # ## Configuration
28
38
  #
29
39
  # To disable this validator:
@@ -3,6 +3,6 @@
3
3
  module Yard
4
4
  module Lint
5
5
  # @return [String] version of the YARD Lint gem
6
- VERSION = '1.2.3'
6
+ VERSION = '1.3.0.rc1'
7
7
  end
8
8
  end
data/lib/yard/lint.rb CHANGED
@@ -6,6 +6,9 @@ require 'open3'
6
6
  require 'tempfile'
7
7
  require 'tmpdir'
8
8
  require 'digest'
9
+ require 'did_you_mean'
10
+ require 'yard'
11
+ require 'set'
9
12
 
10
13
  module Yard
11
14
  # YARD Lint module providing linting functionality for YARD documentation
@@ -59,6 +62,9 @@ module Yard
59
62
  # @param config [Yard::Lint::Config] configuration object
60
63
  # @return [Array<String>] array of absolute file paths
61
64
  def get_diff_files(diff, path, config)
65
+ # Determine the base directory for relative path calculations
66
+ base_dir = determine_base_dir(path)
67
+
62
68
  # Get changed files from git based on mode
63
69
  git_files = case diff[:mode]
64
70
  when :ref
@@ -72,11 +78,7 @@ module Yard
72
78
  end
73
79
 
74
80
  # Apply exclusion patterns
75
- git_files.reject do |file|
76
- config.exclude.any? do |pattern|
77
- File.fnmatch(pattern, file, File::FNM_PATHNAME | File::FNM_EXTGLOB)
78
- end
79
- end
81
+ git_files.reject { |file| excluded_file?(file, config.exclude, base_dir) }
80
82
  end
81
83
 
82
84
  # Expand path/glob patterns into an array of files
@@ -84,28 +86,94 @@ module Yard
84
86
  # @param config [Yard::Lint::Config] configuration object
85
87
  # @return [Array<String>] array of absolute file paths
86
88
  def expand_path(path, config)
89
+ # Determine the base directory for relative path calculations
90
+ base_dir = determine_base_dir(path)
91
+
92
+ files = discover_ruby_files(path)
93
+
94
+ # Convert to absolute paths for YARD
95
+ files = files.map { |file| File.expand_path(file) }
96
+
97
+ # Filter out excluded files
98
+ files.reject { |file| excluded_file?(file, config.exclude, base_dir) }
99
+ end
100
+
101
+ # Discover Ruby files from path/glob patterns
102
+ # @param path [String, Array<String>] path or array of paths
103
+ # @return [Array<String>] array of discovered Ruby file paths
104
+ # @raise [Errors::FileNotFoundError] if a specified path does not exist
105
+ def discover_ruby_files(path)
87
106
  files = Array(path).flat_map do |p|
88
107
  if p.include?('*')
89
108
  Dir.glob(p)
90
109
  elsif File.directory?(p)
91
110
  Dir.glob(File.join(p, '**/*.rb'))
92
111
  else
112
+ validate_path_exists!(p)
93
113
  p
94
114
  end
95
115
  end
96
116
 
97
- files = files.select { |f| File.file?(f) && f.end_with?('.rb') }
117
+ files.select { |file| File.file?(file) && file.end_with?('.rb') }
118
+ end
98
119
 
99
- # Convert to absolute paths for YARD
100
- files = files.map { |f| File.expand_path(f) }
120
+ # Validate that a path exists
121
+ # @param path [String] file or directory path to check for existence
122
+ # @raise [Errors::FileNotFoundError] if path does not exist
123
+ def validate_path_exists!(path)
124
+ return if File.exist?(path)
101
125
 
102
- # Filter out excluded files
103
- files.reject do |file|
104
- config.exclude.any? do |pattern|
105
- File.fnmatch(pattern, file, File::FNM_PATHNAME | File::FNM_EXTGLOB)
106
- end
126
+ raise Errors::FileNotFoundError, "No such file or directory: #{path}"
127
+ end
128
+
129
+ # Determine base directory for relative path calculations
130
+ # @param path [String, Array<String>] path or array of paths
131
+ # @return [String] absolute base directory path
132
+ def determine_base_dir(path)
133
+ first_path = Array(path).first
134
+ return Dir.pwd unless first_path
135
+
136
+ absolute_path = File.expand_path(first_path)
137
+ File.directory?(absolute_path) ? absolute_path : File.dirname(absolute_path)
138
+ end
139
+
140
+ # Check if a file matches any exclusion pattern
141
+ # Patterns are matched against both absolute and relative paths
142
+ # @param file [String] absolute file path
143
+ # @param patterns [Array<String>] exclusion patterns
144
+ # @param base_dir [String] base directory for relative path calculation
145
+ # @return [Boolean] true if file should be excluded
146
+ def excluded_file?(file, patterns, base_dir)
147
+ relative_path = relative_path_from(file, base_dir)
148
+
149
+ patterns.any? do |pattern|
150
+ match_path?(pattern, file, relative_path)
107
151
  end
108
152
  end
153
+
154
+ # Calculate relative path from base directory
155
+ # @param file [String] absolute file path
156
+ # @param base_dir [String] base directory
157
+ # @return [String] relative path
158
+ def relative_path_from(file, base_dir)
159
+ if file.start_with?("#{base_dir}/")
160
+ file.sub("#{base_dir}/", '')
161
+ else
162
+ file
163
+ end
164
+ end
165
+
166
+ # Check if a pattern matches a file path
167
+ # Tries matching against both relative and absolute paths
168
+ # @param pattern [String] glob pattern
169
+ # @param absolute_path [String] absolute file path
170
+ # @param relative_path [String] relative file path
171
+ # @return [Boolean] true if pattern matches
172
+ def match_path?(pattern, absolute_path, relative_path)
173
+ flags = File::FNM_PATHNAME | File::FNM_EXTGLOB
174
+
175
+ File.fnmatch(pattern, relative_path, flags) || File.fnmatch(pattern, absolute_path, flags)
176
+ end
109
177
  end
110
178
  end
111
179
  end
data/renovate.json CHANGED
@@ -3,6 +3,7 @@
3
3
  "extends": [
4
4
  "config:recommended"
5
5
  ],
6
+ "minimumReleaseAge": "7 days",
6
7
  "github-actions": {
7
8
  "enabled": true,
8
9
  "pinDigests": true
@@ -10,13 +11,5 @@
10
11
  "includePaths": [
11
12
  "Gemfile",
12
13
  "yard-lint.gemspec"
13
- ],
14
- "packageRules": [
15
- {
16
- "matchManagers": [
17
- "github-actions"
18
- ],
19
- "minimumReleaseAge": "7 days"
20
- }
21
14
  ]
22
15
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yard-lint
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.3.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld
@@ -54,11 +54,15 @@ files:
54
54
  - bin/yard-lint
55
55
  - lib/yard-lint.rb
56
56
  - lib/yard/lint.rb
57
- - lib/yard/lint/command_cache.rb
58
57
  - lib/yard/lint/config.rb
59
58
  - lib/yard/lint/config_generator.rb
60
59
  - lib/yard/lint/config_loader.rb
60
+ - lib/yard/lint/config_updater.rb
61
61
  - lib/yard/lint/errors.rb
62
+ - lib/yard/lint/executor/in_process_registry.rb
63
+ - lib/yard/lint/executor/query_executor.rb
64
+ - lib/yard/lint/executor/result_collector.rb
65
+ - lib/yard/lint/executor/warning_dispatcher.rb
62
66
  - lib/yard/lint/ext/irb_notifier_shim.rb
63
67
  - lib/yard/lint/formatters/progress.rb
64
68
  - lib/yard/lint/git.rb
@@ -74,6 +78,18 @@ files:
74
78
  - lib/yard/lint/templates/strict_config.yml
75
79
  - lib/yard/lint/validators/base.rb
76
80
  - lib/yard/lint/validators/config.rb
81
+ - lib/yard/lint/validators/documentation/blank_line_before_definition.rb
82
+ - lib/yard/lint/validators/documentation/blank_line_before_definition/config.rb
83
+ - lib/yard/lint/validators/documentation/blank_line_before_definition/messages_builder.rb
84
+ - lib/yard/lint/validators/documentation/blank_line_before_definition/parser.rb
85
+ - lib/yard/lint/validators/documentation/blank_line_before_definition/result.rb
86
+ - lib/yard/lint/validators/documentation/blank_line_before_definition/validator.rb
87
+ - lib/yard/lint/validators/documentation/empty_comment_line.rb
88
+ - lib/yard/lint/validators/documentation/empty_comment_line/config.rb
89
+ - lib/yard/lint/validators/documentation/empty_comment_line/messages_builder.rb
90
+ - lib/yard/lint/validators/documentation/empty_comment_line/parser.rb
91
+ - lib/yard/lint/validators/documentation/empty_comment_line/result.rb
92
+ - lib/yard/lint/validators/documentation/empty_comment_line/validator.rb
77
93
  - lib/yard/lint/validators/documentation/markdown_syntax.rb
78
94
  - lib/yard/lint/validators/documentation/markdown_syntax/config.rb
79
95
  - lib/yard/lint/validators/documentation/markdown_syntax/messages_builder.rb
@@ -126,6 +142,12 @@ files:
126
142
  - lib/yard/lint/validators/tags/example_syntax/parser.rb
127
143
  - lib/yard/lint/validators/tags/example_syntax/result.rb
128
144
  - lib/yard/lint/validators/tags/example_syntax/validator.rb
145
+ - lib/yard/lint/validators/tags/informal_notation.rb
146
+ - lib/yard/lint/validators/tags/informal_notation/config.rb
147
+ - lib/yard/lint/validators/tags/informal_notation/messages_builder.rb
148
+ - lib/yard/lint/validators/tags/informal_notation/parser.rb
149
+ - lib/yard/lint/validators/tags/informal_notation/result.rb
150
+ - lib/yard/lint/validators/tags/informal_notation/validator.rb
129
151
  - lib/yard/lint/validators/tags/invalid_types.rb
130
152
  - lib/yard/lint/validators/tags/invalid_types/config.rb
131
153
  - lib/yard/lint/validators/tags/invalid_types/messages_builder.rb
@@ -138,6 +160,12 @@ files:
138
160
  - lib/yard/lint/validators/tags/meaningless_tag/parser.rb
139
161
  - lib/yard/lint/validators/tags/meaningless_tag/result.rb
140
162
  - lib/yard/lint/validators/tags/meaningless_tag/validator.rb
163
+ - lib/yard/lint/validators/tags/non_ascii_type.rb
164
+ - lib/yard/lint/validators/tags/non_ascii_type/config.rb
165
+ - lib/yard/lint/validators/tags/non_ascii_type/messages_builder.rb
166
+ - lib/yard/lint/validators/tags/non_ascii_type/parser.rb
167
+ - lib/yard/lint/validators/tags/non_ascii_type/result.rb
168
+ - lib/yard/lint/validators/tags/non_ascii_type/validator.rb
141
169
  - lib/yard/lint/validators/tags/option_tags.rb
142
170
  - lib/yard/lint/validators/tags/option_tags/config.rb
143
171
  - lib/yard/lint/validators/tags/option_tags/messages_builder.rb
@@ -156,6 +184,12 @@ files:
156
184
  - lib/yard/lint/validators/tags/redundant_param_description/parser.rb
157
185
  - lib/yard/lint/validators/tags/redundant_param_description/result.rb
158
186
  - lib/yard/lint/validators/tags/redundant_param_description/validator.rb
187
+ - lib/yard/lint/validators/tags/tag_group_separator.rb
188
+ - lib/yard/lint/validators/tags/tag_group_separator/config.rb
189
+ - lib/yard/lint/validators/tags/tag_group_separator/messages_builder.rb
190
+ - lib/yard/lint/validators/tags/tag_group_separator/parser.rb
191
+ - lib/yard/lint/validators/tags/tag_group_separator/result.rb
192
+ - lib/yard/lint/validators/tags/tag_group_separator/validator.rb
159
193
  - lib/yard/lint/validators/tags/tag_type_position.rb
160
194
  - lib/yard/lint/validators/tags/tag_type_position/config.rb
161
195
  - lib/yard/lint/validators/tags/tag_type_position/messages_builder.rb
@@ -190,11 +224,13 @@ files:
190
224
  - lib/yard/lint/validators/warnings/unknown_directive/validator.rb
191
225
  - lib/yard/lint/validators/warnings/unknown_parameter_name.rb
192
226
  - lib/yard/lint/validators/warnings/unknown_parameter_name/config.rb
227
+ - lib/yard/lint/validators/warnings/unknown_parameter_name/messages_builder.rb
193
228
  - lib/yard/lint/validators/warnings/unknown_parameter_name/parser.rb
194
229
  - lib/yard/lint/validators/warnings/unknown_parameter_name/result.rb
195
230
  - lib/yard/lint/validators/warnings/unknown_parameter_name/validator.rb
196
231
  - lib/yard/lint/validators/warnings/unknown_tag.rb
197
232
  - lib/yard/lint/validators/warnings/unknown_tag/config.rb
233
+ - lib/yard/lint/validators/warnings/unknown_tag/messages_builder.rb
198
234
  - lib/yard/lint/validators/warnings/unknown_tag/parser.rb
199
235
  - lib/yard/lint/validators/warnings/unknown_tag/result.rb
200
236
  - lib/yard/lint/validators/warnings/unknown_tag/validator.rb
@@ -1,93 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Yard
4
- module Lint
5
- # Cache for YARD command executions to avoid running identical commands multiple times
6
- # This provides a transparent optimization layer - validators don't need to know about it
7
- class CommandCache
8
- def initialize
9
- @cache = {}
10
- @hits = 0
11
- @misses = 0
12
- end
13
-
14
- # Execute a command through the cache
15
- # If the command has been executed before, return cached result
16
- # Otherwise execute and cache the result
17
- # @param command_string [String] the shell command to execute
18
- # @return [Hash] hash with stdout, stderr, exit_code keys
19
- # @note Returns a deep clone to prevent validators from modifying cached data
20
- def execute(command_string)
21
- cache_key = generate_cache_key(command_string)
22
-
23
- if @cache.key?(cache_key)
24
- @hits += 1
25
- deep_clone(@cache[cache_key])
26
- else
27
- @misses += 1
28
- result = execute_command(command_string)
29
- @cache[cache_key] = deep_clone(result)
30
- result
31
- end
32
- end
33
-
34
- # Get cache statistics
35
- # @return [Hash] hash with hits, misses, and total executions
36
- def stats
37
- {
38
- hits: @hits,
39
- misses: @misses,
40
- total: @hits + @misses,
41
- saved_executions: @hits
42
- }
43
- end
44
-
45
- private
46
-
47
- # Generate a cache key for the command
48
- # Normalizes the command to handle whitespace differences
49
- # @param command_string [String] the command to generate key for
50
- # @return [String] SHA256 hash of normalized command
51
- def generate_cache_key(command_string)
52
- # Normalize whitespace: collapse multiple spaces/newlines into single spaces
53
- normalized = command_string.strip.gsub(/\s+/, ' ')
54
- Digest::SHA256.hexdigest(normalized)
55
- end
56
-
57
- # Actually execute the command
58
- # @param command_string [String] the command to execute
59
- # @return [Hash] hash with stdout, stderr, exit_code keys
60
- def execute_command(command_string)
61
- # Set up environment to load IRB shim before YARD (Ruby 3.5+ compatibility)
62
- env = build_environment_with_shim
63
-
64
- stdout, stderr, status = Open3.capture3(env, command_string)
65
- {
66
- stdout: stdout,
67
- stderr: stderr,
68
- exit_code: status.exitstatus
69
- }
70
- end
71
-
72
- # Build environment hash with RUBYOPT to load IRB shim
73
- # This ensures the shim is loaded in subprocesses (like yard list commands)
74
- # @return [Hash] environment variables for command execution
75
- def build_environment_with_shim
76
- shim_path = File.expand_path('ext/irb_notifier_shim.rb', __dir__)
77
- rubyopt = "-r#{shim_path}"
78
-
79
- # Preserve existing RUBYOPT if present
80
- rubyopt = "#{ENV['RUBYOPT'].strip} #{rubyopt}" if ENV['RUBYOPT']
81
-
82
- { 'RUBYOPT' => rubyopt }
83
- end
84
-
85
- # Deep clone a hash to prevent modifications to cached data
86
- # @param hash [Hash] the hash to clone
87
- # @return [Hash] deep cloned hash
88
- def deep_clone(hash)
89
- Marshal.load(Marshal.dump(hash))
90
- end
91
- end
92
- end
93
- end