openapi_parser 0.11.0 → 0.13.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c94d0bbb5e44314e9cde71c23587355496214b1fdf6ca2e3bf43f404087b6220
4
- data.tar.gz: be8205b97559da91e85613df31c2ac0e060116046532e4285eb01127c0303eae
3
+ metadata.gz: 9afe7e0164ddcad6c8a8fbb6d57e0514e32df10d014bc642b88fa3473f1f8d74
4
+ data.tar.gz: cefb18a632f4a16dd948fe2e82fadfc0236a159af2406fdcb52db50ef6dc980e
5
5
  SHA512:
6
- metadata.gz: a844336ca5d80573478d7e35d6978881c8d0581e2757584e227781c5b523e1f181f5403c4efb4047df3a9c519043ab0513bbaf5df83acff12d54f0d2c19874a2
7
- data.tar.gz: 406ad0fc2ad51af48b56ba1bf2ace1cac8b920adb85615e160e901aacbacf58c94a02cf4c737cf0601a6bab120bc2c51b3d7cd3f9da0295138edbc63bf7cf8ae
6
+ metadata.gz: fb0397b9251edac7e3bfb15e30041d5945a466c21b6671183eaec8491a372730e2f76101af71efbc7c07c66345353c260983acfb69d80f2b066c35c71207a076
7
+ data.tar.gz: 5a58f4b47946ca9c376dcce3c5be34de998a2bc3d59ee4321e2e7f0425c7cdf6b809ff9eb3a103fe099a849210def6c362431628610fdde137b3b79157a32849
data/.gitignore CHANGED
@@ -7,6 +7,9 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
 
10
+ # RubyMine
11
+ .idea
12
+
10
13
  # rspec failure tracking
11
14
  .rspec_status
12
- Gemfile.lock
15
+ Gemfile.lock
data/.travis.yml CHANGED
@@ -7,9 +7,10 @@ language: ruby
7
7
  rvm:
8
8
  - 2.3.8
9
9
  - 2.4.10
10
- - 2.5.8
11
- - 2.6.6
12
- - 2.7.1
10
+ - 2.5.9
11
+ - 2.6.7
12
+ - 2.7.3
13
+ - 3.0.1
13
14
  - ruby-head
14
15
 
15
16
  cache: bundler
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 0.13.0 (2021-05-01)
4
+ * Fix a problem with remote reference to path items which have path parameters #95
5
+ * Support enum for booleans. #104
6
+
7
+ ## 0.12.1 (2020-08-27)
8
+ * Use CGI.unescape (warning fix) #92
9
+
10
+ ## 0.12.0 (2020-08-26)
11
+ * Find path by extracted params than path length #84
12
+ * Unescape ref URI before lookup in OpenAPIParser::Findable #85
13
+ * Improved path parameter matching code to allow file extensions, multiple parameters inside one path element, etc #90
14
+
15
+ ## 0.11.2 (2020-05-23)
16
+ * Allow date and time content in YAML #81
17
+
18
+ ## 0.11.1 (2020-05-09)
19
+ * fix too many warning
20
+
3
21
  ## 0.11.0 (2020-05-09)
4
22
  * Add committee friendly interface to use remote references. #74
5
23
  * Prevent SystemStackError on recursive schema reference #76
@@ -78,7 +78,10 @@ module OpenAPIParser
78
78
  end
79
79
 
80
80
  def parse_yaml(content)
81
- Psych.safe_load(content)
81
+ # FIXME: when drop ruby 2.5, we should use permitted_classes
82
+ (Gem::Version.create(RUBY_VERSION) < Gem::Version.create("2.6.0")) ?
83
+ Psych.safe_load(content, [Date, Time]) :
84
+ Psych.safe_load(content, permitted_classes: [Date, Time])
82
85
  end
83
86
 
84
87
  def parse_json(content)
@@ -1,3 +1,4 @@
1
+ require 'cgi'
1
2
  require 'uri'
2
3
 
3
4
  module OpenAPIParser::Findable
@@ -9,19 +10,21 @@ module OpenAPIParser::Findable
9
10
  return find_remote_object(reference) if remote_reference
10
11
  return nil unless reference.start_with?(object_reference)
11
12
 
13
+ unescaped_reference = CGI.unescape(reference)
14
+
12
15
  @find_object_cache = {} unless defined? @find_object_cache
13
- if (obj = @find_object_cache[reference])
16
+ if (obj = @find_object_cache[unescaped_reference])
14
17
  return obj
15
18
  end
16
19
 
17
- if (child = _openapi_all_child_objects[reference])
18
- @find_object_cache[reference] = child
20
+ if (child = _openapi_all_child_objects[unescaped_reference])
21
+ @find_object_cache[unescaped_reference] = child
19
22
  return child
20
23
  end
21
24
 
22
25
  _openapi_all_child_objects.values.each do |c|
23
- if (obj = c.find_object(reference))
24
- @find_object_cache[reference] = obj
26
+ if (obj = c.find_object(unescaped_reference))
27
+ @find_object_cache[unescaped_reference] = obj
25
28
  return obj
26
29
  end
27
30
  end
@@ -30,6 +33,8 @@ module OpenAPIParser::Findable
30
33
  end
31
34
 
32
35
  def purge_object_cache
36
+ @purged = false unless defined? @purged
37
+
33
38
  return if @purged
34
39
 
35
40
  @find_object_cache = {}
@@ -13,7 +13,7 @@ module OpenAPIParser
13
13
  end
14
14
 
15
15
  def message
16
- "#{@reference} expected #{@type}, but received #{@data.class}: #{@data}"
16
+ "#{@reference} expected #{@type}, but received #{@data.class}: #{@data.inspect}"
17
17
  end
18
18
 
19
19
  class << self
@@ -73,7 +73,7 @@ module OpenAPIParser
73
73
  end
74
74
 
75
75
  def message
76
- "discriminator propertyName #{@key} does not exist in value #{@value} in #{@reference}"
76
+ "discriminator propertyName #{@key} does not exist in value #{@value.inspect} in #{@reference}"
77
77
  end
78
78
  end
79
79
 
@@ -84,7 +84,7 @@ module OpenAPIParser
84
84
  end
85
85
 
86
86
  def message
87
- "#{@value} isn't one of in #{@reference}"
87
+ "#{@value.inspect} isn't one of in #{@reference}"
88
88
  end
89
89
  end
90
90
 
@@ -95,7 +95,7 @@ module OpenAPIParser
95
95
  end
96
96
 
97
97
  def message
98
- "#{@value} isn't any of in #{@reference}"
98
+ "#{@value.inspect} isn't any of in #{@reference}"
99
99
  end
100
100
  end
101
101
 
@@ -106,7 +106,7 @@ module OpenAPIParser
106
106
  end
107
107
 
108
108
  def message
109
- "#{@value} isn't include enum in #{@reference}"
109
+ "#{@value.inspect} isn't part of the enum in #{@reference}"
110
110
  end
111
111
  end
112
112
 
@@ -117,7 +117,7 @@ module OpenAPIParser
117
117
  end
118
118
 
119
119
  def message
120
- "#{@reference} #{@value} is less than minimum value"
120
+ "#{@reference} #{@value.inspect} is less than minimum value"
121
121
  end
122
122
  end
123
123
 
@@ -128,7 +128,7 @@ module OpenAPIParser
128
128
  end
129
129
 
130
130
  def message
131
- "#{@reference} #{@value} cannot be less than or equal to exclusive minimum value"
131
+ "#{@reference} #{@value.inspect} cannot be less than or equal to exclusive minimum value"
132
132
  end
133
133
  end
134
134
 
@@ -139,7 +139,7 @@ module OpenAPIParser
139
139
  end
140
140
 
141
141
  def message
142
- "#{@reference} #{@value} is more than maximum value"
142
+ "#{@reference} #{@value.inspect} is more than maximum value"
143
143
  end
144
144
  end
145
145
 
@@ -150,7 +150,7 @@ module OpenAPIParser
150
150
  end
151
151
 
152
152
  def message
153
- "#{@reference} #{@value} cannot be more than or equal to exclusive maximum value"
153
+ "#{@reference} #{@value.inspect} cannot be more than or equal to exclusive maximum value"
154
154
  end
155
155
  end
156
156
 
@@ -163,7 +163,7 @@ module OpenAPIParser
163
163
  end
164
164
 
165
165
  def message
166
- "#{@reference} pattern #{@pattern} does not match value: #{@value}#{@example ? ", example: #{@example}" : ""}"
166
+ "#{@reference} pattern #{@pattern} does not match value: #{@value.inspect}#{@example ? ", example: #{@example}" : ""}"
167
167
  end
168
168
  end
169
169
 
@@ -174,7 +174,7 @@ module OpenAPIParser
174
174
  end
175
175
 
176
176
  def message
177
- "#{@reference} email address format does not match value: #{@value}"
177
+ "#{@reference} email address format does not match value: #{@value.inspect}"
178
178
  end
179
179
  end
180
180
 
@@ -185,7 +185,7 @@ module OpenAPIParser
185
185
  end
186
186
 
187
187
  def message
188
- "#{@reference} Value: #{@value} is not conformant with UUID format"
188
+ "#{@reference} Value: #{@value.inspect} is not conformant with UUID format"
189
189
  end
190
190
  end
191
191
 
@@ -208,7 +208,7 @@ module OpenAPIParser
208
208
  end
209
209
 
210
210
  def message
211
- "#{@reference} #{@value} is longer than max length"
211
+ "#{@reference} #{@value.inspect} is longer than max length"
212
212
  end
213
213
  end
214
214
 
@@ -219,7 +219,7 @@ module OpenAPIParser
219
219
  end
220
220
 
221
221
  def message
222
- "#{@reference} #{@value} is shorter than min length"
222
+ "#{@reference} #{@value.inspect} is shorter than min length"
223
223
  end
224
224
  end
225
225
 
@@ -230,7 +230,7 @@ module OpenAPIParser
230
230
  end
231
231
 
232
232
  def message
233
- "#{@reference} #{@value} contains more than max items"
233
+ "#{@reference} #{@value.inspect} contains more than max items"
234
234
  end
235
235
  end
236
236
 
@@ -241,7 +241,7 @@ module OpenAPIParser
241
241
  end
242
242
 
243
243
  def message
244
- "#{@reference} #{@value} contains fewer than min items"
244
+ "#{@reference} #{@value.inspect} contains fewer than min items"
245
245
  end
246
246
  end
247
247
  end
@@ -38,7 +38,41 @@ class OpenAPIParser::PathItemFinder
38
38
  end
39
39
  end
40
40
 
41
+ def parse_path_parameters(schema_path, request_path)
42
+ parameters = path_parameters(schema_path)
43
+ return nil if parameters.empty?
44
+
45
+ # If there are regex special characters in the path, the regex will
46
+ # be too permissive, so escape the non-parameter parts.
47
+ components = []
48
+ unprocessed = schema_path.dup
49
+ parameters.each do |parameter|
50
+ parts = unprocessed.partition(parameter)
51
+ components << Regexp.escape(parts[0]) unless parts[0] == ''
52
+ components << "(?<#{param_name(parameter)}>.+)"
53
+ unprocessed = parts[2]
54
+ end
55
+ components << Regexp.escape(unprocessed) unless unprocessed == ''
56
+
57
+ regex = components.join('')
58
+ matches = request_path.match(regex)
59
+ return nil unless matches
60
+
61
+ # Match up the captured names with the captured values as a hash
62
+ matches.names.zip(matches.captures).to_h
63
+ end
64
+
41
65
  private
66
+ def path_parameters(schema_path)
67
+ # OAS3 follows a RFC6570 subset for URL templates
68
+ # https://swagger.io/docs/specification/serialization/#uri-templates
69
+ # A URL template param can be preceded optionally by a "." or ";", and can be succeeded optionally by a "*";
70
+ # this regex returns a match of the full parameter name with all of these modifiers. Ex: {;id*}
71
+ parameters = schema_path.scan(/(\{[\.;]*[^\{\*\}]+\**\})/)
72
+ # The `String#scan` method returns an array of arrays; we want an array of strings
73
+ parameters.collect { |param| param[0] }
74
+ end
75
+
42
76
  # check if there is a identical path in the schema (without any param)
43
77
  def matches_directly?(request_path, http_method)
44
78
  @paths.path[request_path]&.operation(http_method)
@@ -70,8 +104,9 @@ class OpenAPIParser::PathItemFinder
70
104
  splitted_request_path.zip(splitted_schema_path).reduce({}) do |result, zip_item|
71
105
  request_path_item, schema_path_item = zip_item
72
106
 
73
- if path_template?(schema_path_item)
74
- result[param_name(schema_path_item)] = request_path_item
107
+ params = parse_path_parameters(schema_path_item, request_path_item)
108
+ if params
109
+ result.merge!(params)
75
110
  else
76
111
  return if schema_path_item != request_path_item
77
112
  end
@@ -80,7 +115,7 @@ class OpenAPIParser::PathItemFinder
80
115
  end
81
116
  end
82
117
 
83
- # find all matching patchs with parameters extracted
118
+ # find all matching paths with parameters extracted
84
119
  # EXAMPLE:
85
120
  # [
86
121
  # ['/user/{id}/edit', { 'id' => 1 }],
@@ -94,23 +129,23 @@ class OpenAPIParser::PathItemFinder
94
129
  splitted_schema_path = path.split('/')
95
130
 
96
131
  next result if different_depth_or_method?(splitted_schema_path, splitted_request_path, path_item, http_method)
97
-
132
+
98
133
  extracted_params = extract_params(splitted_request_path, splitted_schema_path)
99
134
  result << [path, extracted_params] if extracted_params
100
135
  result
101
136
  end
102
137
  end
103
138
 
104
- # find mathing path and extract params
139
+ # find matching path and extract params
105
140
  # EXAMPLE: find_path_and_params('get', '/user/1') => ['/user/{id}', { 'id' => 1 }]
106
141
  def find_path_and_params(http_method, request_path)
107
142
  return [request_path, {}] if matches_directly?(request_path, http_method)
108
-
143
+
109
144
  matching = matching_paths_with_params(request_path, http_method)
110
145
 
111
146
  # if there are many matching paths, return the one with the smallest number of params
112
147
  # (prefer /user/{id}/action over /user/{param_1}/{param_2} )
113
- matching.min_by { |match| match[0].size }
148
+ matching.min_by { |match| match[1].size }
114
149
  end
115
150
 
116
151
  def parse_request_path(http_method, request_path)
@@ -1,5 +1,7 @@
1
1
  class OpenAPIParser::SchemaValidator
2
2
  class BooleanValidator < Base
3
+ include ::OpenAPIParser::SchemaValidator::Enumable
4
+
3
5
  TRUE_VALUES = ['true', '1'].freeze
4
6
  FALSE_VALUES = ['false', '0'].freeze
5
7
 
@@ -8,6 +10,9 @@ class OpenAPIParser::SchemaValidator
8
10
 
9
11
  return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(TrueClass) || value.kind_of?(FalseClass)
10
12
 
13
+ value, err = check_enum_include(value, schema)
14
+ return [nil, err] if err
15
+
11
16
  [value, nil]
12
17
  end
13
18
 
@@ -1,3 +1,3 @@
1
1
  module OpenAPIParser
2
- VERSION = '0.11.0'.freeze
2
+ VERSION = '0.13.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ota42y
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-09 00:00:00.000000000 Z
11
+ date: 2021-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -207,7 +207,7 @@ homepage: https://github.com/ota42y/openapi_parser
207
207
  licenses:
208
208
  - MIT
209
209
  metadata: {}
210
- post_install_message:
210
+ post_install_message:
211
211
  rdoc_options: []
212
212
  require_paths:
213
213
  - lib
@@ -222,8 +222,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
222
  - !ruby/object:Gem::Version
223
223
  version: '0'
224
224
  requirements: []
225
- rubygems_version: 3.1.2
226
- signing_key:
225
+ rubygems_version: 3.2.3
226
+ signing_key:
227
227
  specification_version: 4
228
228
  summary: OpenAPI3 parser
229
229
  test_files: []