openapi3_parser 0.8.2 → 0.9.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 +5 -5
- data/.github/workflows/ci.yml +23 -0
- data/.rubocop.yml +18 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +6 -0
- data/README.md +3 -3
- data/lib/openapi3_parser/array_sentence.rb +1 -1
- data/lib/openapi3_parser/error.rb +11 -1
- data/lib/openapi3_parser/node/context.rb +1 -3
- data/lib/openapi3_parser/node/placeholder.rb +8 -7
- data/lib/openapi3_parser/node_factory/map.rb +6 -6
- data/lib/openapi3_parser/node_factory/object_factory/dsl.rb +6 -4
- data/lib/openapi3_parser/node_factory/object_factory/field_config.rb +8 -7
- data/lib/openapi3_parser/node_factory/object_factory/node_builder.rb +11 -13
- data/lib/openapi3_parser/node_factory/object_factory/validator.rb +19 -17
- data/lib/openapi3_parser/node_factory/operation.rb +1 -3
- data/lib/openapi3_parser/node_factory/parameter_like.rb +1 -1
- data/lib/openapi3_parser/node_factory/reference.rb +1 -1
- data/lib/openapi3_parser/node_factory/request_body.rb +2 -4
- data/lib/openapi3_parser/source/pointer.rb +4 -4
- data/lib/openapi3_parser/source_input.rb +8 -10
- data/lib/openapi3_parser/source_input/file.rb +1 -1
- data/lib/openapi3_parser/source_input/raw.rb +1 -1
- data/lib/openapi3_parser/source_input/url.rb +1 -1
- data/lib/openapi3_parser/validation/error_collection.rb +1 -1
- data/lib/openapi3_parser/validation/input_validator.rb +1 -1
- data/lib/openapi3_parser/validators/component_keys.rb +1 -1
- data/lib/openapi3_parser/validators/email.rb +2 -2
- data/lib/openapi3_parser/validators/mutually_exclusive_fields.rb +6 -6
- data/lib/openapi3_parser/validators/url.rb +2 -7
- data/lib/openapi3_parser/version.rb +1 -1
- data/openapi3_parser.gemspec +6 -4
- metadata +45 -17
- data/.travis.yml +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 81001258de6af8c21c8a7db87520d9433e3acb878483a56a616fdcd804e92848
|
4
|
+
data.tar.gz: 496f3a02ebcb386e949eab7ec6607f360a0b2e755be6bb4f1df3cd6b260a6e0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d789d4ffe423f8854f961e902ffa6ef56b86d7dbcf506292106afa8548b72f2fbe968d98358ea7c80771a3c2e974c302096d43968c0663bdad40dc5f60a676e2
|
7
|
+
data.tar.gz: aea92fa77fbb4808872093b9149f8eb933f70a38336a0e415fa1fc9d4c15e691b8307abb0d70c0e51eee8eca89887cbc1a16b21e70f2d1812ae0fd77b75fe2a3
|
@@ -0,0 +1,23 @@
|
|
1
|
+
on: [push, pull_request]
|
2
|
+
jobs:
|
3
|
+
test:
|
4
|
+
strategy:
|
5
|
+
matrix:
|
6
|
+
ruby: [2.5, 2.6, 2.7, 3.0]
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
steps:
|
9
|
+
- uses: actions/checkout@v2
|
10
|
+
- uses: ruby/setup-ruby@v1
|
11
|
+
with:
|
12
|
+
bundler-cache: true
|
13
|
+
ruby-version: ${{ matrix.ruby }}
|
14
|
+
- name: Test Ruby ${{ matrix.ruby }}
|
15
|
+
run: bundle exec rake
|
16
|
+
if: matrix.ruby != '2.5'
|
17
|
+
- name: Test and publish coverage for Ruby ${{ matrix.ruby }}
|
18
|
+
uses: paambaati/codeclimate-action@v2.7.5
|
19
|
+
env:
|
20
|
+
CC_TEST_REPORTER_ID: 8bc2d8e54331569aeb442094c21cb64a58d6efa0670f65ff00d9ae887f63c0b4
|
21
|
+
with:
|
22
|
+
coverageCommand: bundle exec rake
|
23
|
+
if: matrix.ruby == '2.5'
|
data/.rubocop.yml
CHANGED
@@ -1,13 +1,30 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rake
|
3
|
+
- rubocop-rspec
|
4
|
+
AllCops:
|
5
|
+
NewCops: enable
|
1
6
|
Style/StringLiterals:
|
2
7
|
EnforcedStyle: double_quotes
|
3
8
|
Metrics/MethodLength:
|
4
9
|
Max: 30
|
5
10
|
Metrics/AbcSize:
|
6
11
|
Max: 30
|
12
|
+
RSpec/ExampleLength:
|
13
|
+
Max: 30
|
7
14
|
Style/Documentation:
|
8
15
|
Enabled: false
|
9
16
|
Metrics/BlockLength:
|
10
17
|
Exclude:
|
11
18
|
- 'spec/**/*.rb'
|
12
|
-
|
19
|
+
- '*.gemspec'
|
20
|
+
RSpec/DescribeClass:
|
21
|
+
Exclude:
|
22
|
+
- 'spec/integration/**/*.rb'
|
23
|
+
# I'd rather have multiple expectations than lots of duplicate tests
|
24
|
+
RSpec/MultipleExpectations:
|
25
|
+
Enabled: false
|
26
|
+
# The default arbitrary number (5) is a little painful
|
27
|
+
RSpec/MultipleMemoizedHelpers:
|
28
|
+
Enabled: false
|
29
|
+
RSpec/MessageSpies:
|
13
30
|
Enabled: false
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.5.8
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# OpenAPI 3 Parser
|
2
2
|
|
3
|
-
[](https://travis-ci.org/kevindew/openapi3_parser)
|
4
4
|
|
5
5
|
This a Ruby based parser/validator for [OpenAPI 3][openapi-3]. It is used to
|
6
6
|
convert an OpenAPI file (can be a local file, a URL, a string or even a Ruby
|
@@ -47,7 +47,7 @@ parser in [How to write an OpenAPI 3 parser][blog].
|
|
47
47
|
|
48
48
|
```ruby
|
49
49
|
# by URL
|
50
|
-
Openapi3Parser.load_url("https://raw.githubusercontent.com/kevindew/openapi3_parser/
|
50
|
+
Openapi3Parser.load_url("https://raw.githubusercontent.com/kevindew/openapi3_parser/main/spec/support/examples/petstore-expanded.yaml")
|
51
51
|
|
52
52
|
# by path to file
|
53
53
|
Openapi3Parser.load_file("spec/support/examples/uber.yaml")
|
@@ -76,7 +76,7 @@ document.errors
|
|
76
76
|
### Traversing
|
77
77
|
|
78
78
|
```ruby
|
79
|
-
document = Openapi3Parser.load_url("https://raw.githubusercontent.com/kevindew/openapi3_parser/
|
79
|
+
document = Openapi3Parser.load_url("https://raw.githubusercontent.com/kevindew/openapi3_parser/main/spec/support/examples/petstore-expanded.yaml")
|
80
80
|
|
81
81
|
# by objects
|
82
82
|
|
@@ -7,32 +7,42 @@ module Openapi3Parser
|
|
7
7
|
# at runtime when we have tried to access that resource it is not available
|
8
8
|
# for whatever reason.
|
9
9
|
class InaccessibleInput < Error; end
|
10
|
+
|
10
11
|
# Raised in cases where we provided data that we expected to be parsable
|
11
12
|
# (such as a string of JSON data) but when we tried to parse it an error
|
12
13
|
# is raised
|
13
14
|
class UnparsableInput < Error; end
|
15
|
+
|
14
16
|
# Raised in cases where an object that is in an immutable state is modified
|
15
17
|
#
|
16
18
|
# Typically this would occur when a component that is frozen is modififed.
|
17
19
|
# Some components are mutable during the construction of a document and
|
18
20
|
# then frozen afterwards.
|
19
21
|
class ImmutableObject < Error; end
|
20
|
-
|
22
|
+
|
23
|
+
# Raised when a node is provided data as a type that is outside the allowed
|
24
|
+
# list
|
21
25
|
class InvalidType < Error; end
|
26
|
+
|
22
27
|
# Raised when we have to abort creating an object due to invalid data
|
23
28
|
class InvalidData < Error; end
|
29
|
+
|
24
30
|
# Used when there are fields that are missing from an object which prevents
|
25
31
|
# us from creating a node
|
26
32
|
class MissingFields < Error; end
|
33
|
+
|
27
34
|
# Used when there are extra fields that are not expected in the data for
|
28
35
|
# a node
|
29
36
|
class UnexpectedFields < Error; end
|
37
|
+
|
30
38
|
# Used when a method we expect to be able to call (through symbol or proc)
|
31
39
|
# is not callable
|
32
40
|
class NotCallable < Error; end
|
41
|
+
|
33
42
|
# Raised when we in a recursive data structure and can't perform an
|
34
43
|
# operation
|
35
44
|
class InRecursiveStructure < Error; end
|
45
|
+
|
36
46
|
# Used when we're trying to validate that a type is something that is not
|
37
47
|
# validatable, most likely a sign that we're in a bug
|
38
48
|
class UnvalidatableType < Error; end
|
@@ -107,9 +107,7 @@ module Openapi3Parser
|
|
107
107
|
def location_summary
|
108
108
|
summary = document_location.to_s
|
109
109
|
|
110
|
-
if document_location != source_location
|
111
|
-
summary += " (#{source_location})"
|
112
|
-
end
|
110
|
+
summary += " (#{source_location})" if document_location != source_location
|
113
111
|
|
114
112
|
summary
|
115
113
|
end
|
@@ -21,8 +21,8 @@ module Openapi3Parser
|
|
21
21
|
def self.each(node_data, &block)
|
22
22
|
resolved =
|
23
23
|
if node_data.respond_to?(:keys)
|
24
|
-
node_data.
|
25
|
-
|
24
|
+
node_data.transform_values do |value|
|
25
|
+
resolve(value)
|
26
26
|
end
|
27
27
|
else
|
28
28
|
node_data.map { |item| resolve(item) }
|
@@ -32,6 +32,7 @@ module Openapi3Parser
|
|
32
32
|
end
|
33
33
|
|
34
34
|
attr_reader :node_factory, :field, :parent_context
|
35
|
+
|
35
36
|
def_delegators :node_factory, :nil_input?
|
36
37
|
|
37
38
|
def initialize(node_factory, field, parent_context)
|
@@ -42,11 +43,11 @@ module Openapi3Parser
|
|
42
43
|
|
43
44
|
def node
|
44
45
|
@node ||= begin
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
node_context = Context.next_field(parent_context,
|
47
|
+
field,
|
48
|
+
node_factory.context)
|
49
|
+
node_factory.node(node_context)
|
50
|
+
end
|
50
51
|
end
|
51
52
|
end
|
52
53
|
end
|
@@ -90,12 +90,12 @@ module Openapi3Parser
|
|
90
90
|
def build_resolved_input
|
91
91
|
return unless data
|
92
92
|
|
93
|
-
data.
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
93
|
+
data.transform_values do |value|
|
94
|
+
if value.respond_to?(:resolved_input)
|
95
|
+
value.resolved_input
|
96
|
+
else
|
97
|
+
value
|
98
|
+
end
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "ostruct"
|
4
3
|
require "openapi3_parser/node_factory/object_factory/field_config"
|
5
4
|
|
6
5
|
module Openapi3Parser
|
7
6
|
module NodeFactory
|
8
7
|
module ObjectFactory
|
9
8
|
module Dsl
|
9
|
+
MutuallyExclusiveField = Struct.new(:fields, :required, keyword_init: true)
|
10
|
+
|
10
11
|
def field(name, **options)
|
11
12
|
@field_configs ||= {}
|
12
13
|
@field_configs[name] = FieldConfig.new(**options)
|
@@ -30,8 +31,9 @@ module Openapi3Parser
|
|
30
31
|
|
31
32
|
def mutually_exclusive(*fields, required: false)
|
32
33
|
@mutually_exclusive_fields ||= []
|
33
|
-
@mutually_exclusive_fields <<
|
34
|
-
fields: fields,
|
34
|
+
@mutually_exclusive_fields << MutuallyExclusiveField.new(
|
35
|
+
fields: fields,
|
36
|
+
required: required
|
35
37
|
)
|
36
38
|
end
|
37
39
|
|
@@ -41,7 +43,7 @@ module Openapi3Parser
|
|
41
43
|
|
42
44
|
def validate(*items, &block)
|
43
45
|
@validations ||= []
|
44
|
-
@validations
|
46
|
+
@validations.concat(items)
|
45
47
|
@validations << block if block
|
46
48
|
end
|
47
49
|
|
@@ -22,10 +22,11 @@ module Openapi3Parser
|
|
22
22
|
!given_factory.nil?
|
23
23
|
end
|
24
24
|
|
25
|
-
def initialize_factory(context, parent_factory)
|
26
|
-
|
25
|
+
def initialize_factory(context, parent_factory = nil)
|
26
|
+
case given_factory
|
27
|
+
when Class
|
27
28
|
given_factory.new(context)
|
28
|
-
|
29
|
+
when Symbol
|
29
30
|
parent_factory.send(given_factory, context)
|
30
31
|
else
|
31
32
|
given_factory.call(context)
|
@@ -36,7 +37,7 @@ module Openapi3Parser
|
|
36
37
|
given_required
|
37
38
|
end
|
38
39
|
|
39
|
-
def check_input_type(validatable, building_node)
|
40
|
+
def check_input_type(validatable, building_node: false)
|
40
41
|
return true if !given_input_type || validatable.input.nil?
|
41
42
|
|
42
43
|
if building_node
|
@@ -47,7 +48,7 @@ module Openapi3Parser
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
def validate_field(validatable, building_node)
|
51
|
+
def validate_field(validatable, building_node: false)
|
51
52
|
return true if !given_validate || validatable.input.nil?
|
52
53
|
|
53
54
|
run_validation(validatable)
|
@@ -61,9 +62,9 @@ module Openapi3Parser
|
|
61
62
|
"Invalid data for #{location_summary}: #{error.message}"
|
62
63
|
end
|
63
64
|
|
64
|
-
def default(factory)
|
65
|
+
def default(factory = nil)
|
65
66
|
return given_default.call if given_default.is_a?(Proc)
|
66
|
-
return factory
|
67
|
+
return factory&.send(given_default) if given_default.is_a?(Symbol)
|
67
68
|
|
68
69
|
given_default
|
69
70
|
end
|
@@ -8,8 +8,8 @@ module Openapi3Parser
|
|
8
8
|
new(factory).errors
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.node_data(factory,
|
12
|
-
new(factory).node_data(
|
11
|
+
def self.node_data(factory, node_context)
|
12
|
+
new(factory).node_data(node_context)
|
13
13
|
end
|
14
14
|
|
15
15
|
def initialize(factory)
|
@@ -22,19 +22,17 @@ module Openapi3Parser
|
|
22
22
|
|
23
23
|
TypeChecker.validate_type(validatable, type: ::Hash)
|
24
24
|
|
25
|
-
if validatable.errors.empty?
|
26
|
-
validatable.add_errors(validate(raise_on_invalid: false))
|
27
|
-
end
|
25
|
+
validatable.add_errors(validate(raise_on_invalid: false)) if validatable.errors.empty?
|
28
26
|
|
29
27
|
validatable.collection
|
30
28
|
end
|
31
29
|
|
32
|
-
def node_data(
|
33
|
-
return build_node_data(
|
30
|
+
def node_data(node_context)
|
31
|
+
return build_node_data(node_context) if empty_and_allowed_to_be?
|
34
32
|
|
35
33
|
TypeChecker.raise_on_invalid_type(factory.context, type: ::Hash)
|
36
34
|
validate(raise_on_invalid: true)
|
37
|
-
build_node_data(
|
35
|
+
build_node_data(node_context)
|
38
36
|
end
|
39
37
|
|
40
38
|
private_class_method :new
|
@@ -48,22 +46,22 @@ module Openapi3Parser
|
|
48
46
|
end
|
49
47
|
|
50
48
|
def validate(raise_on_invalid:)
|
51
|
-
Validator.call(factory, raise_on_invalid)
|
49
|
+
Validator.call(factory, raise_on_invalid: raise_on_invalid)
|
52
50
|
end
|
53
51
|
|
54
|
-
def build_node_data(
|
52
|
+
def build_node_data(node_context)
|
55
53
|
return if factory.nil_input? && factory.data.nil?
|
56
54
|
|
57
55
|
factory.data.each_with_object({}) do |(key, value), memo|
|
58
|
-
memo[key] = resolve_value(key, value,
|
56
|
+
memo[key] = resolve_value(key, value, node_context)
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
62
|
-
def resolve_value(key, value,
|
60
|
+
def resolve_value(key, value, node_context)
|
63
61
|
resolved = determine_value_or_default(key, value)
|
64
62
|
|
65
63
|
if resolved.respond_to?(:node)
|
66
|
-
Node::Placeholder.new(value, key,
|
64
|
+
Node::Placeholder.new(value, key, node_context)
|
67
65
|
else
|
68
66
|
resolved
|
69
67
|
end
|
@@ -7,15 +7,15 @@ module Openapi3Parser
|
|
7
7
|
module ObjectFactory
|
8
8
|
class Validator
|
9
9
|
private_class_method :new
|
10
|
-
attr_reader :factory, :validatable, :
|
10
|
+
attr_reader :factory, :validatable, :raise_on_invalid
|
11
11
|
|
12
|
-
def self.call(*args)
|
13
|
-
new(*args).call
|
12
|
+
def self.call(*args, **kwargs)
|
13
|
+
new(*args, **kwargs).call
|
14
14
|
end
|
15
15
|
|
16
|
-
def initialize(factory,
|
16
|
+
def initialize(factory, raise_on_invalid: false)
|
17
17
|
@factory = factory
|
18
|
-
@
|
18
|
+
@raise_on_invalid = raise_on_invalid
|
19
19
|
@validatable = Validation::Validatable.new(factory)
|
20
20
|
end
|
21
21
|
|
@@ -34,7 +34,7 @@ module Openapi3Parser
|
|
34
34
|
Validators::RequiredFields.call(
|
35
35
|
validatable,
|
36
36
|
required_fields: factory.required_fields,
|
37
|
-
raise_on_invalid:
|
37
|
+
raise_on_invalid: raise_on_invalid
|
38
38
|
)
|
39
39
|
end
|
40
40
|
|
@@ -43,7 +43,7 @@ module Openapi3Parser
|
|
43
43
|
validatable,
|
44
44
|
allow_extensions: factory.allowed_extensions?,
|
45
45
|
allowed_fields: factory.allowed_fields,
|
46
|
-
raise_on_invalid:
|
46
|
+
raise_on_invalid: raise_on_invalid
|
47
47
|
)
|
48
48
|
end
|
49
49
|
|
@@ -51,7 +51,7 @@ module Openapi3Parser
|
|
51
51
|
Validators::MutuallyExclusiveFields.call(
|
52
52
|
validatable,
|
53
53
|
mutually_exclusive_fields: factory.mutually_exclusive_fields,
|
54
|
-
raise_on_invalid:
|
54
|
+
raise_on_invalid: raise_on_invalid
|
55
55
|
)
|
56
56
|
end
|
57
57
|
|
@@ -66,7 +66,8 @@ module Openapi3Parser
|
|
66
66
|
class CheckInvalidFields
|
67
67
|
extend Forwardable
|
68
68
|
attr_reader :validator
|
69
|
-
|
69
|
+
|
70
|
+
def_delegators :validator, :factory, :raise_on_invalid, :validatable
|
70
71
|
private_class_method :new
|
71
72
|
|
72
73
|
def self.call(validator)
|
@@ -88,16 +89,14 @@ module Openapi3Parser
|
|
88
89
|
|
89
90
|
# We don't add errors when we're building a node as they will
|
90
91
|
# be raised when that child node is built
|
91
|
-
validatable.add_errors(field.errors) unless
|
92
|
+
validatable.add_errors(field.errors) unless raise_on_invalid
|
92
93
|
end
|
93
94
|
end
|
94
95
|
|
95
96
|
private
|
96
97
|
|
97
98
|
def handle_factory_checks(name)
|
98
|
-
field_errors = if factory.field_configs[name]
|
99
|
-
check_field(name, factory.field_configs[name])
|
100
|
-
end
|
99
|
+
field_errors = (check_field(name, factory.field_configs[name]) if factory.field_configs[name])
|
101
100
|
|
102
101
|
(field_errors || []).any?
|
103
102
|
end
|
@@ -115,11 +114,14 @@ module Openapi3Parser
|
|
115
114
|
field_validatable = Validation::Validatable.new(factory,
|
116
115
|
context: context)
|
117
116
|
|
118
|
-
valid_input_type = field_config.check_input_type(
|
119
|
-
|
117
|
+
valid_input_type = field_config.check_input_type(
|
118
|
+
field_validatable,
|
119
|
+
building_node: raise_on_invalid
|
120
|
+
)
|
120
121
|
|
121
122
|
if valid_input_type
|
122
|
-
field_config.validate_field(field_validatable,
|
123
|
+
field_config.validate_field(field_validatable,
|
124
|
+
building_node: raise_on_invalid)
|
123
125
|
end
|
124
126
|
|
125
127
|
validatable.add_errors(field_validatable.errors)
|
@@ -139,7 +141,7 @@ module Openapi3Parser
|
|
139
141
|
|
140
142
|
errors = validator.validatable.errors
|
141
143
|
|
142
|
-
return if errors.empty? || !validator.
|
144
|
+
return if errors.empty? || !validator.raise_on_invalid
|
143
145
|
|
144
146
|
location_summary = errors.first.context.location_summary
|
145
147
|
raise Error::InvalidData,
|
@@ -25,9 +25,7 @@ module Openapi3Parser
|
|
25
25
|
private
|
26
26
|
|
27
27
|
def build_object(data, context)
|
28
|
-
if data["servers"].node.empty?
|
29
|
-
data["servers"] = path_item_server_data(context)
|
30
|
-
end
|
28
|
+
data["servers"] = path_item_server_data(context) if data["servers"].node.empty?
|
31
29
|
|
32
30
|
Node::Operation.new(data, context)
|
33
31
|
end
|
@@ -13,7 +13,7 @@ module Openapi3Parser
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def examples_factory(context)
|
16
|
-
factory = NodeFactory::OptionalReference.new(NodeFactory::
|
16
|
+
factory = NodeFactory::OptionalReference.new(NodeFactory::Example)
|
17
17
|
NodeFactory::Map.new(context,
|
18
18
|
default: nil,
|
19
19
|
value_factory: factory)
|
@@ -44,7 +44,7 @@ module Openapi3Parser
|
|
44
44
|
|
45
45
|
def build_node(node_context)
|
46
46
|
TypeChecker.raise_on_invalid_type(context, type: ::Hash)
|
47
|
-
ObjectFactory::Validator.call(self, true)
|
47
|
+
ObjectFactory::Validator.call(self, raise_on_invalid: true)
|
48
48
|
data["$ref"].node(node_context)
|
49
49
|
end
|
50
50
|
|
@@ -32,11 +32,9 @@ module Openapi3Parser
|
|
32
32
|
def call(validatable)
|
33
33
|
# This validation isn't actually mentioned in the spec, but it
|
34
34
|
# doesn't seem to make sense if this is an empty hash.
|
35
|
-
if validatable.input.size.zero?
|
36
|
-
return validatable.add_error("Expected to have at least 1 item")
|
37
|
-
end
|
35
|
+
return validatable.add_error("Expected to have at least 1 item") if validatable.input.size.zero?
|
38
36
|
|
39
|
-
validatable.input.
|
37
|
+
validatable.input.each_key do |key|
|
40
38
|
message = Validators::MediaType.call(key)
|
41
39
|
next unless message
|
42
40
|
|
@@ -16,7 +16,7 @@ module Openapi3Parser
|
|
16
16
|
unescaped = CGI.unescape(part.gsub("%20", "+"))
|
17
17
|
unescaped.match?(/\A\d+\z/) ? unescaped.to_i : unescaped
|
18
18
|
end
|
19
|
-
new(segments.compact, absolute)
|
19
|
+
new(segments.compact, absolute: absolute)
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.merge_pointers(base_pointer, new_pointer)
|
@@ -27,7 +27,7 @@ module Openapi3Parser
|
|
27
27
|
|
28
28
|
# @param [::Array] segments
|
29
29
|
# @param [Boolean] absolute
|
30
|
-
def initialize(segments, absolute
|
30
|
+
def initialize(segments, absolute: true)
|
31
31
|
@segments = segments.freeze
|
32
32
|
@absolute = absolute
|
33
33
|
end
|
@@ -39,7 +39,7 @@ module Openapi3Parser
|
|
39
39
|
def fragment
|
40
40
|
fragment = segments.map { |s| CGI.escape(s.to_s).gsub("+", "%20") }
|
41
41
|
.join("/")
|
42
|
-
"
|
42
|
+
"##{absolute ? fragment.prepend('/') : fragment}"
|
43
43
|
end
|
44
44
|
|
45
45
|
def to_s
|
@@ -80,7 +80,7 @@ module Openapi3Parser
|
|
80
80
|
def create_pointer(pointer_like)
|
81
81
|
case pointer_like
|
82
82
|
when Pointer then pointer_like
|
83
|
-
when ::Array then Pointer.new(pointer_like, false)
|
83
|
+
when ::Array then Pointer.new(pointer_like, absolute: false)
|
84
84
|
when ::String then Pointer.from_fragment(pointer_like)
|
85
85
|
when nil then nil
|
86
86
|
else raise Openapi3Parser::Error, "Unexpected type for pointer"
|
@@ -20,6 +20,14 @@ module Openapi3Parser
|
|
20
20
|
class SourceInput
|
21
21
|
attr_reader :access_error, :parse_error
|
22
22
|
|
23
|
+
def initialize
|
24
|
+
return if access_error
|
25
|
+
|
26
|
+
@contents = parse_contents
|
27
|
+
rescue ::StandardError => e
|
28
|
+
@parse_error = Error::UnparsableInput.new(e.message)
|
29
|
+
end
|
30
|
+
|
23
31
|
# Indicates that the data within this input is suitable (i.e. can parse
|
24
32
|
# underlying JSON or YAML) for trying to use as part of a Document
|
25
33
|
def available?
|
@@ -57,15 +65,5 @@ module Openapi3Parser
|
|
57
65
|
def relative_to(_source_input)
|
58
66
|
""
|
59
67
|
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
def initialize_contents
|
64
|
-
return if access_error
|
65
|
-
|
66
|
-
@contents = parse_contents
|
67
|
-
rescue ::StandardError => e
|
68
|
-
@parse_error = Error::UnparsableInput.new(e.message)
|
69
|
-
end
|
70
68
|
end
|
71
69
|
end
|
@@ -56,7 +56,7 @@ module Openapi3Parser
|
|
56
56
|
grouped.each_with_object({}) do |(_, items), memo|
|
57
57
|
items.each do |item|
|
58
58
|
key = item.location_summary(with_type: items.count > 1)
|
59
|
-
memo[key] = (
|
59
|
+
memo[key] = memo.fetch(key, []) + item.errors.map(&:to_s)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
@@ -6,7 +6,7 @@ module Openapi3Parser
|
|
6
6
|
# defined for a Components node.
|
7
7
|
# As defined: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#components-object
|
8
8
|
class ComponentKeys
|
9
|
-
REGEX = /\A[a-zA-Z0-9
|
9
|
+
REGEX = /\A[a-zA-Z0-9.\-_]+\Z/.freeze
|
10
10
|
|
11
11
|
def self.call(input)
|
12
12
|
invalid = input.keys.reject { |key| REGEX.match(key) }
|
@@ -7,10 +7,10 @@ module Openapi3Parser
|
|
7
7
|
# https://html.spec.whatwg.org/#e-mail-state-(type=email)
|
8
8
|
REGEX = %r{
|
9
9
|
\A
|
10
|
-
[a-zA-Z0-9.!#$%&'
|
10
|
+
[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+
|
11
11
|
@
|
12
12
|
[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?
|
13
|
-
(
|
13
|
+
(?:.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*
|
14
14
|
\Z
|
15
15
|
}x.freeze
|
16
16
|
|
@@ -78,12 +78,12 @@ module Openapi3Parser
|
|
78
78
|
|
79
79
|
def errors
|
80
80
|
@errors ||= begin
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
81
|
+
default = { required: [], exclusive: [] }
|
82
|
+
mutually_exclusive_fields
|
83
|
+
.each_with_object(default) do |exclusive, errors|
|
84
|
+
add_error(errors, exclusive)
|
85
|
+
end
|
86
|
+
end
|
87
87
|
end
|
88
88
|
|
89
89
|
private
|
@@ -4,14 +4,9 @@ module Openapi3Parser
|
|
4
4
|
module Validators
|
5
5
|
class Url
|
6
6
|
def self.call(input)
|
7
|
-
|
8
|
-
uri = URI.parse(input)
|
9
|
-
|
10
|
-
message if !uri.relative? &&
|
11
|
-
!uri.is_a?(URI::HTTP) &&
|
12
|
-
!uri.is_a?(URI::HTTPS)
|
7
|
+
URI.parse(input) && nil
|
13
8
|
rescue URI::InvalidURIError
|
14
|
-
|
9
|
+
%("#{input}" is not a valid URL)
|
15
10
|
end
|
16
11
|
end
|
17
12
|
end
|
data/openapi3_parser.gemspec
CHANGED
@@ -24,16 +24,18 @@ Gem::Specification.new do |spec|
|
|
24
24
|
f.match(%r{^spec/})
|
25
25
|
end
|
26
26
|
|
27
|
-
spec.required_ruby_version = ">= 2.
|
27
|
+
spec.required_ruby_version = ">= 2.5.0"
|
28
28
|
|
29
29
|
spec.add_dependency "commonmarker", "~> 0.17"
|
30
30
|
spec.add_dependency "psych", "~> 3.1"
|
31
31
|
|
32
32
|
spec.add_development_dependency "bundler"
|
33
33
|
spec.add_development_dependency "byebug", "~> 11.0"
|
34
|
-
spec.add_development_dependency "rake"
|
34
|
+
spec.add_development_dependency "rake"
|
35
35
|
spec.add_development_dependency "rspec", "~> 3.9"
|
36
|
-
spec.add_development_dependency "rubocop", "~>
|
37
|
-
spec.add_development_dependency "
|
36
|
+
spec.add_development_dependency "rubocop", "~> 1"
|
37
|
+
spec.add_development_dependency "rubocop-rake", "~> 0.5"
|
38
|
+
spec.add_development_dependency "rubocop-rspec", "~> 2"
|
39
|
+
spec.add_development_dependency "simplecov", "~> 0.19"
|
38
40
|
spec.add_development_dependency "webmock", "~> 3.8"
|
39
41
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openapi3_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Dew
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commonmarker
|
@@ -70,16 +70,16 @@ dependencies:
|
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,28 +100,56 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: '1'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop-rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.5'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.
|
124
|
+
version: '0.5'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop-rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '2'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '2'
|
111
139
|
- !ruby/object:Gem::Dependency
|
112
140
|
name: simplecov
|
113
141
|
requirement: !ruby/object:Gem::Requirement
|
114
142
|
requirements:
|
115
143
|
- - "~>"
|
116
144
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0.
|
145
|
+
version: '0.19'
|
118
146
|
type: :development
|
119
147
|
prerelease: false
|
120
148
|
version_requirements: !ruby/object:Gem::Requirement
|
121
149
|
requirements:
|
122
150
|
- - "~>"
|
123
151
|
- !ruby/object:Gem::Version
|
124
|
-
version: '0.
|
152
|
+
version: '0.19'
|
125
153
|
- !ruby/object:Gem::Dependency
|
126
154
|
name: webmock
|
127
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,11 +173,11 @@ executables: []
|
|
145
173
|
extensions: []
|
146
174
|
extra_rdoc_files: []
|
147
175
|
files:
|
176
|
+
- ".github/workflows/ci.yml"
|
148
177
|
- ".gitignore"
|
149
178
|
- ".rspec"
|
150
179
|
- ".rubocop.yml"
|
151
180
|
- ".ruby-version"
|
152
|
-
- ".travis.yml"
|
153
181
|
- CHANGELOG.md
|
154
182
|
- Gemfile
|
155
183
|
- LICENCE
|
@@ -273,7 +301,7 @@ homepage: https://github.com/kevindew/openapi_parser
|
|
273
301
|
licenses:
|
274
302
|
- MIT
|
275
303
|
metadata: {}
|
276
|
-
post_install_message:
|
304
|
+
post_install_message:
|
277
305
|
rdoc_options: []
|
278
306
|
require_paths:
|
279
307
|
- lib
|
@@ -281,16 +309,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
281
309
|
requirements:
|
282
310
|
- - ">="
|
283
311
|
- !ruby/object:Gem::Version
|
284
|
-
version: 2.
|
312
|
+
version: 2.5.0
|
285
313
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
286
314
|
requirements:
|
287
315
|
- - ">="
|
288
316
|
- !ruby/object:Gem::Version
|
289
317
|
version: '0'
|
290
318
|
requirements: []
|
291
|
-
rubyforge_project:
|
292
|
-
rubygems_version: 2.6.
|
293
|
-
signing_key:
|
319
|
+
rubyforge_project:
|
320
|
+
rubygems_version: 2.7.6.2
|
321
|
+
signing_key:
|
294
322
|
specification_version: 4
|
295
323
|
summary: An OpenAPI V3 parser for Ruby
|
296
324
|
test_files: []
|
data/.travis.yml
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
sudo: false
|
3
|
-
env:
|
4
|
-
global:
|
5
|
-
CC_TEST_REPORTER_ID=8bc2d8e54331569aeb442094c21cb64a58d6efa0670f65ff00d9ae887f63c0b4
|
6
|
-
CC_RUBY_VERSION=ruby-2.4.6
|
7
|
-
rvm:
|
8
|
-
- 2.4.6
|
9
|
-
- 2.5.5
|
10
|
-
- 2.6.4
|
11
|
-
- 2.7.0
|
12
|
-
- ruby-head
|
13
|
-
matrix:
|
14
|
-
allow_failures:
|
15
|
-
- rvm: ruby-head
|
16
|
-
fast_finish: true
|
17
|
-
before_script:
|
18
|
-
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
19
|
-
- chmod +x ./cc-test-reporter
|
20
|
-
- if [ $(rvm current) = $CC_RUBY_VERSION ]; then ./cc-test-reporter before-build; fi
|
21
|
-
after_script:
|
22
|
-
- if [ $(rvm current) = $CC_RUBY_VERSION ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi
|