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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d0d7b568c5726071030b7e7726c8b23c03a6169e717faf47112d76b6c375fc5
4
- data.tar.gz: 229e07f5b7b072d3fcaca91b735227c2e639814f3efc949c135b2c47f8df3d8f
3
+ metadata.gz: 8b8a1f840812e93ae9174569844d2aa5d0f76aa7992bb3644d952c062e6182df
4
+ data.tar.gz: 3991d6ec7f5d7ffce8ac15f6f774b1693ffaa793cee07c2fc6928acfbf78bf49
5
5
  SHA512:
6
- metadata.gz: 8c79b83a2cb794ffe161438753b0e161e09afec8b9b845b54d62affe8ed25189efc2932932fd56eee60575c98f0631f944502f55853bed59c52a70fe76e2cde0
7
- data.tar.gz: cc8f99a6df08bab9d5351aee184403086d6466727b66df22624187ebae6ff2d226f65f82dc2e17289bb18dc96b27f1b5d762b0183f50adc82ea702deb2fa460a
6
+ metadata.gz: 03cd8ba07eff16ae6291f202f3f9de70e8eead68bcfe15623edcdaf9a832ae370f4d3b4a316282162b2a5ee3db92adc636a68058a18c37318a11303548dbdbb3
7
+ data.tar.gz: 77de6184ef30e9ccd0473c16e5e9a75ad618df38bf57eb3c7a779f853c8bd8989499fb3ce12daccd64477eb5f6f7e1208f354fe43f9049189acd96a759197de3
data/.rubocop.yml CHANGED
@@ -15,6 +15,9 @@ Metrics/BlockLength:
15
15
  - '**/spec/**/*'
16
16
  - 'rubocop-iotventure.gemspec'
17
17
 
18
+ Metrics/ClassLength:
19
+ CountAsOne: ['array', 'hash', 'heredoc']
20
+
18
21
  Naming/FileName:
19
22
  Exclude:
20
23
  - lib/rubocop-iotventure.rb
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubocop-iotventure (0.1.1)
4
+ rubocop-iotventure (0.2.1)
5
5
  rubocop (~> 1.0)
6
6
  rubocop-rake (~> 0.6.0)
7
7
 
@@ -71,4 +71,4 @@ DEPENDENCIES
71
71
  simplecov
72
72
 
73
73
  BUNDLED WITH
74
- 2.2.32
74
+ 2.3.13
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Rubocop::Iotventure
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rubocop/iotventure`. To experiment with that code, run `bin/console` for an interactive prompt.
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
- $ bundle install
15
+ ```shell
16
+ bundle install
17
+ ```
18
18
 
19
- Or install it yourself as:
19
+ Or install it yourself using:
20
20
 
21
- $ gem install rubocop-iotventure
21
+ ```shell
22
+ gem install rubocop-iotventure
23
+ ```
22
24
 
23
25
  ## Usage
24
26
 
25
- ### Rswag/DuplicateResponseCode
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
- ### Rswag/SaveRequestExample
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. 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).
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
@@ -2,3 +2,4 @@
2
2
 
3
3
  require_relative 'iotventure/duplicate_response_code'
4
4
  require_relative 'iotventure/save_request_example'
5
+ require_relative 'iotventure/schema_definition_per_response'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Iotventure
5
- VERSION = '0.1.1'
5
+ VERSION = '0.2.1'
6
6
  end
7
7
  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.1.1
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: 2022-04-18 00:00:00.000000000 Z
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.32
162
+ rubygems_version: 3.2.3
162
163
  signing_key:
163
164
  specification_version: 4
164
165
  summary: Rswag cops.