rubocop-yard 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cc400612d09ab5ddf92d7361573854c7338a9601a3c1ed253fee7affb4b56de
4
- data.tar.gz: 79b066ad6cf601e2d3eac583333cda1f2f56873dad13d7cc19ee30238e2e9d16
3
+ metadata.gz: b41b5e256726136d4cd8bfc96fabd2ab0fbc37e69a84c9f29a76456f464cf519
4
+ data.tar.gz: 678da6e808f7b844e4bd94ab061dbf8176c1aba9c3b279a211bf040f7cba907b
5
5
  SHA512:
6
- metadata.gz: 03c33163563d342329b62d989beb3dd4635cfa09a26b4ad3b13b7802ebf3c6286d3ebda9a4f28b7453fc42aa9bcfbafa4c6579703b90636e7d1a5ce608262312
7
- data.tar.gz: f82f34bf6a182f595669b9c0ef46567b4e86b22d73d17cc672baa297f3dbeb5cdc81aa544abedbf9787fece7aca0632f7e780e811a628d96112e9a095e206f49
6
+ metadata.gz: c14be7ae06b265ef9396bd3b2c494db30e7165cdcebd74884633053ca24a2007e367dc44bc7e8a17deec4a4c62f83eeabd3ae55bd9065ccc3b89633cf4052aee
7
+ data.tar.gz: f4fd229b29630192b24036fb59bc145704904a2f9142c26738a71815212fa1bf60a725a7c5b984c63a75c05ac75e31d8a6d55b238cdefce1384a4f69d449c315
data/CHANGELOG.md CHANGED
@@ -1,7 +1,17 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2023-09-16
4
+
5
+ - Add `YARD/MismatchName`
6
+ - Check `@param` and `@option` name with method definition
7
+
8
+ ## [0.2.0] - 2023-09-14
9
+
10
+ - `YARD/TagType`
11
+ - Check collection tag type syntax
12
+
3
13
  ## [0.1.0] - 2023-09-13
4
14
 
5
- - Add new `YARD/TagTypeSyntax` cop
15
+ - Add new `YARD/TagType` cop
6
16
 
7
17
  - Initial release
data/README.md CHANGED
@@ -1,24 +1,46 @@
1
- # Rubocop::YARD
1
+ # RuboCop::YARD
2
2
 
3
3
  You can check YARD format in Ruby code comment by RuboCop.
4
4
 
5
+ <img src="https://github.com/ksss/rubocop-yard/blob/main/demo.png?raw=true" width=700 />
6
+
5
7
  ## Features
6
8
 
7
- ### `YARD/TagTypeSyntax`
9
+ ### `YARD/TagType`
8
10
 
9
11
  Check tag type syntax error.
10
12
 
11
- ## Installation
13
+ ```
14
+ # @param [Symbol|String]
15
+ # ^^^^^^^^^^^^^ SyntaxError as YARD tag type
16
+ ```
17
+
18
+ ```
19
+ # @param [Hash<Symbol, String>]
20
+ # ^^^^^^^^^^^^^^^^^^^^ `<Type>` is the collection type syntax. Did you mean `{KeyType => ValueType}` or `Hash{KeyType => ValueType}`
21
+ ```
22
+
23
+ ### `YARD/MismatchName`
24
+
25
+ Check `@param` and `@option` name with method definition.
12
26
 
13
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
27
+ ```rb
28
+ # @param [String] string
29
+ # ^^^^^^ `string` is not found in method arguments
30
+ # @option opt bar [String]
31
+ # ^^^ `opt` is not found in method arguments
32
+ def foo(strings, opts = {})
33
+ ```
34
+
35
+ ## Installation
14
36
 
15
37
  Install the gem and add to the application's Gemfile by executing:
16
38
 
17
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG --require=false
39
+ $ bundle add rubocop-yard --require=false
18
40
 
19
41
  If bundler is not being used to manage dependencies, install the gem by executing:
20
42
 
21
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
43
+ $ gem install rubocop-yard
22
44
 
23
45
  ## Usage
24
46
 
@@ -44,4 +66,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
44
66
 
45
67
  ## Code of Conduct
46
68
 
47
- Everyone interacting in the Rubocop::YARD project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ksss/rubocop-yard/blob/main/CODE_OF_CONDUCT.md).
69
+ Everyone interacting in the RuboCop::YARD project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ksss/rubocop-yard/blob/main/CODE_OF_CONDUCT.md).
data/config/default.yml CHANGED
@@ -1,4 +1,9 @@
1
- YARD/TagTypeSyntax:
1
+ YARD/TagType:
2
2
  Description: 'Check syntax for yard tag type'
3
3
  Enabled: true
4
- VersionAdded: '0.1.0'
4
+ VersionAdded: '0.2.0'
5
+
6
+ YARD/MismatchName
7
+ Description: 'Check @param and @option name and method parameters'
8
+ Enabled: true
9
+ VersionAdded: '0.3.0'
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module YARD
6
+ # @example
7
+ # # bad
8
+ # # @param [void] baz
9
+ # # @option opt aaa [void]
10
+ # def foo(bar, opts = {})
11
+ # end
12
+ #
13
+ # # good
14
+ # # @param [void] bar
15
+ # # @param [Array] argsa
16
+ # # @option opts aaa [void]
17
+ # def foo(bar, opts = {}, *arg)
18
+ # end
19
+ class MismatchName < Base
20
+ include RangeHelp
21
+ include DocumentationComment
22
+
23
+ def on_def(node)
24
+ return unless node.arguments?
25
+
26
+ preceding_lines = preceding_lines(node)
27
+ return false unless preceding_comment?(node, preceding_lines.last)
28
+
29
+ yard_docstring = preceding_lines.map { |line| line.text.gsub(/\A#\s*/, '') }.join("\n")
30
+ docstring = ::YARD::DocstringParser.new.parse(yard_docstring)
31
+ docstring.tags.each do |tag|
32
+ next unless tag.tag_name == 'param' || tag.tag_name == 'option'
33
+ next unless node.arguments.none? { |arg_node| tag.name.to_sym == arg_node.name }
34
+
35
+ tag_name_regexp = Regexp.new("\\b#{Regexp.escape(tag.name)}\\b")
36
+ comment = preceding_lines.find { |line| line.text.match?(tag_name_regexp) && line.text.include?("@#{tag.tag_name}") }
37
+ next unless comment
38
+
39
+ start_column = comment.source.index(tag_name_regexp)
40
+ offense_start = comment.location.column + start_column
41
+ offense_end = offense_start + tag.name.length - 1
42
+ range = source_range(processed_source.buffer, comment.location.line, offense_start..offense_end)
43
+ add_offense(range, message: "`#{tag.name}` is not found in method arguments")
44
+ end
45
+ end
46
+ alias on_defs on_def
47
+ end
48
+
49
+ private
50
+
51
+ # @param [void] aaa
52
+ # @option opts bbb [void]
53
+ def dummy(aaa, opts = {}, *)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module YARD
6
+ # @example
7
+ # # bad
8
+ # @param [Integer String]
9
+ #
10
+ # # bad
11
+ # @param [Hash<Symbol, String>]
12
+ #
13
+ # # bad
14
+ # @param [Hash(String)]
15
+ #
16
+ # # bad
17
+ # @param [Array{Symbol => String}]
18
+ #
19
+ # # good
20
+ # @param [Integer, String]
21
+ #
22
+ # # good
23
+ # @param [<String>]
24
+ # @param [Array<String>]
25
+ # @param [List<String>]
26
+ # @param [Array<(String, Fixnum, Hash)>]
27
+ #
28
+ # # good
29
+ # @param [(String)]
30
+ # @param [Array(String)]
31
+ #
32
+ # # good
33
+ # @param [{KeyType => ValueType}]
34
+ # @param [Hash{KeyType => ValueType}]
35
+ class TagType < Base
36
+ MSG = ''
37
+ include RangeHelp # @return [void,]
38
+
39
+ def on_new_investigation
40
+ processed_source.comments.each do |comment|
41
+ next if inline_comment?(comment)
42
+ next unless include_yard_tag?(comment)
43
+
44
+ check(comment)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def check(comment)
51
+ docstring = comment.text.gsub(/\A#\s*/, '')
52
+ ::YARD::DocstringParser.new.parse(docstring).tags.each do |tag|
53
+ next unless tag.types
54
+
55
+ ::YARD::Tags::TypesExplainer::Parser.parse(tag.types.join(', ')).each do |types_explainer|
56
+ check_mismatch_collection_type(comment, types_explainer)
57
+ end
58
+ rescue SyntaxError
59
+ add_offense(tag_range_for_comment(comment), message: 'SyntaxError as YARD tag type')
60
+ end
61
+ end
62
+
63
+ def check_mismatch_collection_type(comment, types_explainer)
64
+ case types_explainer
65
+ when ::YARD::Tags::TypesExplainer::HashCollectionType
66
+ if types_explainer.name == 'Hash'
67
+ types_explainer.key_types.each { |t| check_mismatch_collection_type(comment, t) }
68
+ types_explainer.value_types.each { |t| check_mismatch_collection_type(comment, t) }
69
+ else
70
+ did_you_mean = types_explainer.name == 'Array' ? 'Did you mean `<Type>` or `Array<Type>`' : ''
71
+ message = "`{KeyType => ValueType}` is the hash collection type syntax. #{did_you_mean}"
72
+ add_offense(tag_range_for_comment(comment), message: message)
73
+ end
74
+ when ::YARD::Tags::TypesExplainer::FixedCollectionType
75
+ if types_explainer.name == 'Hash'
76
+ message = "`(Type)` is the fixed collection type syntax. Did you mean `{KeyType => ValueType}` or `Hash{KeyType => ValueType}`"
77
+ add_offense(tag_range_for_comment(comment), message: message)
78
+ else
79
+ types_explainer.types.each { |t| check_mismatch_collection_type(comment, t) }
80
+ end
81
+ when ::YARD::Tags::TypesExplainer::CollectionType
82
+ if types_explainer.name == 'Hash'
83
+ message = "`<Type>` is the collection type syntax. `{KeyType => ValueType}` or `Hash{KeyType => ValueType}` is more good"
84
+ add_offense(tag_range_for_comment(comment), message: message)
85
+ else
86
+ types_explainer.types.each { |t| check_mismatch_collection_type(comment, t) }
87
+ end
88
+ end
89
+ end
90
+
91
+ def inline_comment?(comment)
92
+ !comment_line?(comment.source_range.source_line)
93
+ end
94
+
95
+ def include_yard_tag?(comment)
96
+ comment.source.match?(/@(?:param|return|option|raise|yieldparam|yieldreturn)\s+\[.*\]/)
97
+ end
98
+
99
+ def tag_range_for_comment(comment)
100
+ start_column = comment.source.index(/\[/) + 1
101
+ end_column = comment.source.index(/\]/)
102
+ offense_start = comment.location.column + start_column
103
+ offense_end = comment.location.column + end_column
104
+ source_range(processed_source.buffer, comment.location.line, offense_start..offense_end)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -1,3 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'yard'
3
- require_relative 'yard/tag_type_syntax'
4
+ require_relative 'yard/tag_type'
5
+ require_relative 'yard/mismatch_name'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module YARD
5
- VERSION = "0.1.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
data/sig/rubocop/yard.rbs CHANGED
@@ -1,6 +1,17 @@
1
- module Rubocop
1
+ module RuboCop
2
2
  module YARD
3
3
  VERSION: String
4
4
  # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
5
  end
6
+ module Cop
7
+ module YARD
8
+ class TagType
9
+ type t = YARD::Tags::TypesExplainer::Type
10
+ | ::YARD::Tags::TypesExplainer::CollectionType
11
+ | ::YARD::Tags::TypesExplainer::FixedCollectionType
12
+ | ::YARD::Tags::TypesExplainer::HashCollectionType
13
+ private def check_mismatch_collection_type: (untyped comment, t types_explainer) -> void
14
+ end
15
+ end
16
+ end
6
17
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-yard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ksss
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-14 00:00:00.000000000 Z
11
+ date: 2023-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -51,19 +51,20 @@ files:
51
51
  - README.md
52
52
  - config/default.yml
53
53
  - lib/rubocop-yard.rb
54
- - lib/rubocop/cop/yard/tag_type_syntax.rb
54
+ - lib/rubocop/cop/yard/mismatch_name.rb
55
+ - lib/rubocop/cop/yard/tag_type.rb
55
56
  - lib/rubocop/cop/yard_cops.rb
56
57
  - lib/rubocop/yard.rb
57
58
  - lib/rubocop/yard/inject.rb
58
59
  - lib/rubocop/yard/version.rb
59
60
  - sig/rubocop/yard.rbs
60
- homepage: https://ksss.ink/
61
+ homepage: https://github.com/ksss/rubocop-yard
61
62
  licenses:
62
63
  - MIT
63
64
  metadata:
64
- homepage_uri: https://ksss.ink/
65
- source_code_uri: https://ksss.ink/
66
- changelog_uri: https://ksss.ink/
65
+ homepage_uri: https://github.com/ksss/rubocop-yard
66
+ source_code_uri: https://github.com/ksss/rubocop-yard
67
+ changelog_uri: https://github.com/ksss/rubocop-yard
67
68
  rubygems_mfa_required: 'true'
68
69
  post_install_message:
69
70
  rdoc_options: []
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module YARD
6
- # @example
7
- # # bad
8
- # @param [Integer String]
9
- #
10
- # # bad
11
- # @return [TrueClass|FalseClass]
12
- #
13
- # # good
14
- # @param [Integer, String]
15
- #
16
- # # good
17
- # @return [Boolean]
18
- class TagTypeSyntax < Base
19
- MSG = 'SyntaxError as YARD tag type'
20
- include RangeHelp # @return [void,]
21
-
22
- def on_new_investigation
23
- processed_source.comments.each do |comment|
24
- next if inline_comment?(comment)
25
- next unless include_yard_tag?(comment)
26
-
27
- check(comment)
28
- end
29
- end
30
-
31
- private
32
-
33
- def check(comment)
34
- docstring = comment.text.gsub(/\A#\s*/, '')
35
- ::YARD::DocstringParser.new.parse(docstring).tags.each do |tag|
36
- ::YARD::Tags::TypesExplainer::Parser.parse(tag.types.join(', '))
37
- rescue SyntaxError
38
- add_offense(tag_range(comment))
39
- end
40
- end
41
-
42
- def inline_comment?(comment)
43
- !comment_line?(comment.source_range.source_line)
44
- end
45
-
46
- def include_yard_tag?(comment)
47
- comment.source.match?(/@(?:param|return)\s+\[.*\]/)
48
- end
49
-
50
- def tag_range(comment)
51
- start_column = comment.source.index(/\[/) + 1
52
- end_column = comment.source.index(/\]/)
53
- offense_start = comment.location.column + start_column
54
- offense_end = comment.location.column + end_column
55
- source_range(processed_source.buffer, comment.location.line, offense_start..offense_end)
56
- end
57
- end
58
- end
59
- end
60
- end