rubocop-yard 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -1
- data/README.md +29 -7
- data/config/default.yml +7 -2
- data/lib/rubocop/cop/yard/mismatch_name.rb +57 -0
- data/lib/rubocop/cop/yard/tag_type.rb +109 -0
- data/lib/rubocop/cop/yard_cops.rb +3 -1
- data/lib/rubocop/yard/version.rb +1 -1
- data/sig/rubocop/yard.rbs +12 -1
- metadata +8 -7
- data/lib/rubocop/cop/yard/tag_type_syntax.rb +0 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b41b5e256726136d4cd8bfc96fabd2ab0fbc37e69a84c9f29a76456f464cf519
|
4
|
+
data.tar.gz: 678da6e808f7b844e4bd94ab061dbf8176c1aba9c3b279a211bf040f7cba907b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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/
|
15
|
+
- Add new `YARD/TagType` cop
|
6
16
|
|
7
17
|
- Initial release
|
data/README.md
CHANGED
@@ -1,24 +1,46 @@
|
|
1
|
-
#
|
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/
|
9
|
+
### `YARD/TagType`
|
8
10
|
|
9
11
|
Check tag type syntax error.
|
10
12
|
|
11
|
-
|
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
|
-
|
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
|
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
|
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
|
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/
|
1
|
+
YARD/TagType:
|
2
2
|
Description: 'Check syntax for yard tag type'
|
3
3
|
Enabled: true
|
4
|
-
VersionAdded: '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
|
data/lib/rubocop/yard/version.rb
CHANGED
data/sig/rubocop/yard.rbs
CHANGED
@@ -1,6 +1,17 @@
|
|
1
|
-
module
|
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.
|
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-
|
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/
|
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://
|
61
|
+
homepage: https://github.com/ksss/rubocop-yard
|
61
62
|
licenses:
|
62
63
|
- MIT
|
63
64
|
metadata:
|
64
|
-
homepage_uri: https://
|
65
|
-
source_code_uri: https://
|
66
|
-
changelog_uri: https://
|
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
|