rubocop-iotventure 0.1.1 → 0.2.1
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/.rubocop.yml +3 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile.lock +2 -2
- data/README.md +34 -9
- data/lib/rubocop/cop/iotventure/schema_definition_per_response.rb +233 -0
- data/lib/rubocop/cop/iotventure_cops.rb +1 -0
- data/lib/rubocop/iotventure/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b8a1f840812e93ae9174569844d2aa5d0f76aa7992bb3644d952c062e6182df
|
4
|
+
data.tar.gz: 3991d6ec7f5d7ffce8ac15f6f774b1693ffaa793cee07c2fc6928acfbf78bf49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03cd8ba07eff16ae6291f202f3f9de70e8eead68bcfe15623edcdaf9a832ae370f4d3b4a316282162b2a5ee3db92adc636a68058a18c37318a11303548dbdbb3
|
7
|
+
data.tar.gz: 77de6184ef30e9ccd0473c16e5e9a75ad618df38bf57eb3c7a779f853c8bd8989499fb3ce12daccd64477eb5f6f7e1208f354fe43f9049189acd96a759197de3
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
1
3
|
## [Unreleased]
|
2
4
|
|
5
|
+
## [0.2.1] - 2023-04-21
|
6
|
+
|
7
|
+
- Fix SchemaDefinitionPerResponse cop for 204 No Content responses
|
8
|
+
|
9
|
+
## [0.2.0] - 2022-05-12
|
10
|
+
|
11
|
+
- FB-111 Add SchemaDefinitionPerResponse cop
|
12
|
+
|
13
|
+
## [0.1.1] - 2022-04-18
|
14
|
+
|
15
|
+
- Fix error for nonexistent response definition
|
16
|
+
|
3
17
|
## [0.1.0] - 2022-04-18
|
4
18
|
|
5
19
|
- Initial release
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# Rubocop::Iotventure
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
This is a gem running some internal checks for IoTVenture. All of the existing cops are for RSwag, but that might change in the future.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
@@ -14,15 +12,19 @@ gem 'rubocop-iotventure', require: false
|
|
14
12
|
|
15
13
|
And then execute:
|
16
14
|
|
17
|
-
|
15
|
+
```shell
|
16
|
+
bundle install
|
17
|
+
```
|
18
18
|
|
19
|
-
Or install it yourself
|
19
|
+
Or install it yourself using:
|
20
20
|
|
21
|
-
|
21
|
+
```shell
|
22
|
+
gem install rubocop-iotventure
|
23
|
+
```
|
22
24
|
|
23
25
|
## Usage
|
24
26
|
|
25
|
-
###
|
27
|
+
### Iotventure/DuplicateResponseCode
|
26
28
|
|
27
29
|
```ruby
|
28
30
|
# bad
|
@@ -36,7 +38,7 @@ response 401, 'response description 2' {}
|
|
36
38
|
|
37
39
|
This cop prevents duplicated response code blocks. Those would overwrite each other when generating the `swagger.yaml` file.
|
38
40
|
|
39
|
-
###
|
41
|
+
### Iotventure/SaveRequestExample
|
40
42
|
|
41
43
|
```ruby
|
42
44
|
# bad
|
@@ -50,6 +52,29 @@ response 200, 'response description', save_request_example: :param1 {}
|
|
50
52
|
|
51
53
|
This cop enforces usage of the `save_request_example` parameter in `api` files (saves the body parameter). This should only be enabled when there is custom logic reacting to this parameter.
|
52
54
|
|
55
|
+
### Iotventure/SchemaDefinitionPerResponse
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# bad
|
59
|
+
response 200, 'response description' do
|
60
|
+
context 'context' do
|
61
|
+
schema '$ref' => '#/components/schemas/object'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# bad
|
66
|
+
schema '$ref' => '#/components/schemas/object'
|
67
|
+
response 200, 'response description' {}
|
68
|
+
|
69
|
+
|
70
|
+
# good
|
71
|
+
response 200, 'response description' do
|
72
|
+
schema '$ref' => '#/components/schemas/object'
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
This cop checks that there is exactly one top-level schema definition per response block (except 204 No Content blocks, those should not have any schema definitions). Multiple or misplaced schema definitions might overwrite each other.
|
77
|
+
|
53
78
|
## Development
|
54
79
|
|
55
80
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -58,7 +83,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
58
83
|
|
59
84
|
## Contributing
|
60
85
|
|
61
|
-
Bug reports and pull requests are welcome on Bitbucket at https://bitbucket.org/iotventure/rubocop-iotventure
|
86
|
+
Bug reports and pull requests are welcome on Bitbucket at <https://bitbucket.org/iotventure/rubocop-iotventure>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://bitbucket.org/iotventure/rubocop-iotventure/src/master/CODE_OF_CONDUCT.md).
|
62
87
|
|
63
88
|
## License
|
64
89
|
|
@@ -0,0 +1,233 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Iotventure
|
6
|
+
# This cop checks that there is exactly one top-level schema definition per response declaration.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
#
|
12
|
+
# response 200, 'response description' {}
|
13
|
+
#
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
#
|
19
|
+
# response 200, 'response description' do
|
20
|
+
# context 'context' do
|
21
|
+
# schema '$ref' => '#/components/schemas/object'
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
#
|
28
|
+
# # bad
|
29
|
+
#
|
30
|
+
# response 200, 'response description' do
|
31
|
+
# schema '$ref' => '#/components/schemas/object1'
|
32
|
+
# schema '$ref' => '#/components/schemas/object2'
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
#
|
38
|
+
# # bad
|
39
|
+
#
|
40
|
+
# schema '$ref' => '#/components/schemas/object'
|
41
|
+
# response 200, 'response description' {}
|
42
|
+
#
|
43
|
+
#
|
44
|
+
# @example
|
45
|
+
#
|
46
|
+
# # bad
|
47
|
+
#
|
48
|
+
# response 204, 'response description' do
|
49
|
+
# schema '$ref' => '#/components/schemas/object'
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
#
|
55
|
+
# # good
|
56
|
+
#
|
57
|
+
# response 200, 'response description' do
|
58
|
+
# schema '$ref' => '#/components/schemas/object'
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
#
|
62
|
+
# @example
|
63
|
+
#
|
64
|
+
# # good
|
65
|
+
#
|
66
|
+
# response 204, 'response description' do
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
#
|
70
|
+
class SchemaDefinitionPerResponse < Base
|
71
|
+
MISSING_MSG = 'Schema definition is missing for response declaration at %<current>s.'
|
72
|
+
DUPLICATED_MSG = 'Schema definition is defined both at %<first>s and %<second>s '\
|
73
|
+
'for response declaration at %<current>s.'
|
74
|
+
MISPLACED_MSG = 'Schema definition for %<schema_name>s is defined at %<current>s, '\
|
75
|
+
'but should be defined immediately after response declaration at %<other>s.'
|
76
|
+
MISPLACED_WITHOUT_RESPONSE_DEFINITION_MSG = 'Schema definition for %<schema_name>s is '\
|
77
|
+
'outside of response declaration.'
|
78
|
+
NO_CONTENT_SCHEMA_MSG = 'Schema definition for %<schema_name>s is defined at %<current>s, '\
|
79
|
+
'but 204 response should not have schema.'
|
80
|
+
|
81
|
+
# @!method response_block?(node)
|
82
|
+
def_node_matcher :response_block, <<~PATTERN
|
83
|
+
(block
|
84
|
+
(send nil? :response
|
85
|
+
(int _)
|
86
|
+
...)
|
87
|
+
...
|
88
|
+
)
|
89
|
+
PATTERN
|
90
|
+
|
91
|
+
# @!method no_content_response(node)
|
92
|
+
def_node_matcher :no_content_response, <<~PATTERN
|
93
|
+
(block
|
94
|
+
(send nil? :response
|
95
|
+
(:int 204)
|
96
|
+
(:str _)
|
97
|
+
...
|
98
|
+
)
|
99
|
+
...
|
100
|
+
)
|
101
|
+
PATTERN
|
102
|
+
|
103
|
+
# @!method schema_definition?(node)
|
104
|
+
def_node_matcher :schema_definition, <<~PATTERN
|
105
|
+
(send nil? :schema
|
106
|
+
(hash
|
107
|
+
...
|
108
|
+
)
|
109
|
+
)
|
110
|
+
PATTERN
|
111
|
+
|
112
|
+
# @!method schema_name(node)
|
113
|
+
def_node_matcher :schema_name, <<~PATTERN
|
114
|
+
(send nil? :schema
|
115
|
+
(hash
|
116
|
+
(pair
|
117
|
+
(str "$ref")
|
118
|
+
(str $_)
|
119
|
+
)
|
120
|
+
)
|
121
|
+
)
|
122
|
+
PATTERN
|
123
|
+
|
124
|
+
# @!method schema_definition_by_child?(node)
|
125
|
+
def_node_matcher :schema_definition_by_child, <<~PATTERN
|
126
|
+
({block | begin}
|
127
|
+
<
|
128
|
+
$(send nil? :schema
|
129
|
+
(hash
|
130
|
+
...
|
131
|
+
)
|
132
|
+
)
|
133
|
+
...
|
134
|
+
>
|
135
|
+
)
|
136
|
+
PATTERN
|
137
|
+
|
138
|
+
def on_block(node)
|
139
|
+
return check_schema_definition_count(node) if response_block(node)
|
140
|
+
|
141
|
+
return if begin_inside_response_block?(node)
|
142
|
+
|
143
|
+
check_for_misplaced_schema(node)
|
144
|
+
end
|
145
|
+
alias on_begin on_block
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
# Checks that schema is missing completely. Does not check where schema is defined exactly,
|
150
|
+
# that will be picked up by check_for_misplaced_schema
|
151
|
+
def check_schema_definition_count(node)
|
152
|
+
schema_definitions = schema_definitions(node)
|
153
|
+
return check_no_schemas(schema_definitions) if no_content_response(node)
|
154
|
+
|
155
|
+
return if schema_definitions.count == 1
|
156
|
+
|
157
|
+
return add_missing_offense(node) if schema_definitions.empty?
|
158
|
+
|
159
|
+
add_duplicated_offense(node, schema_definitions)
|
160
|
+
end
|
161
|
+
|
162
|
+
def check_no_schemas(schema_definitions)
|
163
|
+
schema_definitions.each do |schema_definition|
|
164
|
+
message = format(NO_CONTENT_SCHEMA_MSG, schema_name: find_schema_name(schema_definition),
|
165
|
+
current: source_location(schema_definition))
|
166
|
+
add_offense(schema_definition.loc.expression, message: message)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def add_missing_offense(node)
|
171
|
+
message = format(MISSING_MSG, current: source_location(node))
|
172
|
+
add_offense(node.loc.expression, message: message)
|
173
|
+
end
|
174
|
+
|
175
|
+
def add_duplicated_offense(node, schema_definitions)
|
176
|
+
message = format(
|
177
|
+
DUPLICATED_MSG,
|
178
|
+
current: source_location(node),
|
179
|
+
first: source_location(schema_definitions[0]),
|
180
|
+
second: source_location(schema_definitions[1])
|
181
|
+
)
|
182
|
+
add_offense(node.loc.expression, message: message)
|
183
|
+
end
|
184
|
+
|
185
|
+
def check_for_misplaced_schema(node)
|
186
|
+
schema_definition = schema_definition_by_child(node)
|
187
|
+
return unless schema_definition
|
188
|
+
|
189
|
+
correct_node = response_definition_ancestor(node)
|
190
|
+
message = message_for_misplaced(schema_definition, correct_node)
|
191
|
+
add_offense(schema_definition.loc.expression, message: message)
|
192
|
+
end
|
193
|
+
|
194
|
+
def message_for_misplaced(schema_definition, correct_node)
|
195
|
+
if correct_node
|
196
|
+
return format(MISPLACED_MSG,
|
197
|
+
schema_name: find_schema_name(schema_definition),
|
198
|
+
other: source_location(correct_node),
|
199
|
+
current: source_location(schema_definition))
|
200
|
+
end
|
201
|
+
|
202
|
+
format(MISPLACED_WITHOUT_RESPONSE_DEFINITION_MSG, schema_name: find_schema_name(schema_definition))
|
203
|
+
end
|
204
|
+
|
205
|
+
def begin_inside_response_block?(node)
|
206
|
+
node.begin_type? && response_block(node.parent)
|
207
|
+
end
|
208
|
+
|
209
|
+
def schema_definitions(node)
|
210
|
+
node.each_descendant.filter do |d|
|
211
|
+
schema_definition(d)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def response_definition_ancestor(node)
|
216
|
+
ancestor = node.parent
|
217
|
+
ancestor = ancestor.parent until ancestor.nil? || response_block(ancestor)
|
218
|
+
ancestor
|
219
|
+
end
|
220
|
+
|
221
|
+
def find_schema_name(schema_definition)
|
222
|
+
schema_name(schema_definition) || 'composite schema declaration'
|
223
|
+
end
|
224
|
+
|
225
|
+
def source_location(node)
|
226
|
+
range = node.location.expression
|
227
|
+
path = smart_path(range.source_buffer.name)
|
228
|
+
"#{path}:#{range.line}"
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-iotventure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fynn Starke
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -130,6 +130,7 @@ files:
|
|
130
130
|
- lib/rubocop-iotventure.rb
|
131
131
|
- lib/rubocop/cop/iotventure/duplicate_response_code.rb
|
132
132
|
- lib/rubocop/cop/iotventure/save_request_example.rb
|
133
|
+
- lib/rubocop/cop/iotventure/schema_definition_per_response.rb
|
133
134
|
- lib/rubocop/cop/iotventure_cops.rb
|
134
135
|
- lib/rubocop/iotventure.rb
|
135
136
|
- lib/rubocop/iotventure/inject.rb
|
@@ -158,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
158
159
|
- !ruby/object:Gem::Version
|
159
160
|
version: '0'
|
160
161
|
requirements: []
|
161
|
-
rubygems_version: 3.2.
|
162
|
+
rubygems_version: 3.2.3
|
162
163
|
signing_key:
|
163
164
|
specification_version: 4
|
164
165
|
summary: Rswag cops.
|