openapi3_parser 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +3 -3
- data/CHANGELOG.md +7 -1
- data/README.md +102 -15
- data/lib/openapi3_parser/document.rb +14 -14
- data/lib/openapi3_parser/document/reference_registry.rb +72 -0
- data/lib/openapi3_parser/node/array.rb +10 -2
- data/lib/openapi3_parser/node/components.rb +9 -9
- data/lib/openapi3_parser/node/contact.rb +3 -3
- data/lib/openapi3_parser/node/context.rb +129 -0
- data/lib/openapi3_parser/node/discriminator.rb +2 -2
- data/lib/openapi3_parser/node/encoding.rb +5 -5
- data/lib/openapi3_parser/node/example.rb +4 -4
- data/lib/openapi3_parser/node/external_documentation.rb +2 -2
- data/lib/openapi3_parser/node/info.rb +6 -6
- data/lib/openapi3_parser/node/license.rb +2 -2
- data/lib/openapi3_parser/node/link.rb +6 -6
- data/lib/openapi3_parser/node/map.rb +8 -4
- data/lib/openapi3_parser/node/media_type.rb +5 -5
- data/lib/openapi3_parser/node/oauth_flow.rb +4 -4
- data/lib/openapi3_parser/node/oauth_flows.rb +4 -4
- data/lib/openapi3_parser/node/object.rb +8 -4
- data/lib/openapi3_parser/node/openapi.rb +8 -8
- data/lib/openapi3_parser/node/operation.rb +12 -12
- data/lib/openapi3_parser/node/parameter.rb +2 -2
- data/lib/openapi3_parser/node/parameter_like.rb +11 -11
- data/lib/openapi3_parser/node/path_item.rb +12 -12
- data/lib/openapi3_parser/node/placeholder.rb +34 -0
- data/lib/openapi3_parser/node/request_body.rb +3 -3
- data/lib/openapi3_parser/node/response.rb +4 -4
- data/lib/openapi3_parser/node/responses.rb +1 -1
- data/lib/openapi3_parser/node/schema.rb +36 -36
- data/lib/openapi3_parser/node/security_scheme.rb +8 -8
- data/lib/openapi3_parser/node/server.rb +3 -3
- data/lib/openapi3_parser/node/server_variable.rb +3 -3
- data/lib/openapi3_parser/node/tag.rb +3 -3
- data/lib/openapi3_parser/node/xml.rb +5 -5
- data/lib/openapi3_parser/node_factory/array.rb +15 -13
- data/lib/openapi3_parser/node_factory/callback.rb +2 -2
- data/lib/openapi3_parser/node_factory/context.rb +111 -0
- data/lib/openapi3_parser/node_factory/field.rb +5 -7
- data/lib/openapi3_parser/node_factory/fields/reference.rb +43 -24
- data/lib/openapi3_parser/node_factory/link.rb +1 -1
- data/lib/openapi3_parser/node_factory/map.rb +14 -12
- data/lib/openapi3_parser/node_factory/object.rb +9 -5
- data/lib/openapi3_parser/node_factory/object_factory/node_builder.rb +21 -28
- data/lib/openapi3_parser/node_factory/optional_reference.rb +4 -0
- data/lib/openapi3_parser/node_factory/parameter_like.rb +0 -2
- data/lib/openapi3_parser/node_factory/path_item.rb +7 -4
- data/lib/openapi3_parser/node_factory/paths.rb +2 -2
- data/lib/openapi3_parser/node_factory/reference.rb +17 -10
- data/lib/openapi3_parser/node_factory/responses.rb +2 -2
- data/lib/openapi3_parser/node_factory/security_requirement.rb +2 -2
- data/lib/openapi3_parser/source.rb +27 -24
- data/lib/openapi3_parser/{context → source}/location.rb +13 -1
- data/lib/openapi3_parser/{context → source}/pointer.rb +2 -2
- data/lib/openapi3_parser/source/resolved_reference.rb +67 -0
- data/lib/openapi3_parser/validators/duplicate_parameters.rb +8 -4
- data/lib/openapi3_parser/validators/reference.rb +3 -3
- data/lib/openapi3_parser/version.rb +1 -1
- data/openapi3_parser.gemspec +1 -1
- metadata +11 -10
- data/lib/openapi3_parser/context.rb +0 -162
- data/lib/openapi3_parser/document/reference_register.rb +0 -48
- data/lib/openapi3_parser/node_factory/recursive_pointer.rb +0 -17
- data/lib/openapi3_parser/source/reference_resolver.rb +0 -82
@@ -8,12 +8,12 @@ module Openapi3Parser
|
|
8
8
|
class SecurityScheme < Node::Object
|
9
9
|
# @return [String, nil]
|
10
10
|
def type
|
11
|
-
|
11
|
+
self["type"]
|
12
12
|
end
|
13
13
|
|
14
14
|
# @return [String, nil]
|
15
15
|
def description
|
16
|
-
|
16
|
+
self["description"]
|
17
17
|
end
|
18
18
|
|
19
19
|
# @return [String, nil]
|
@@ -23,32 +23,32 @@ module Openapi3Parser
|
|
23
23
|
|
24
24
|
# @return [String, nil]
|
25
25
|
def name
|
26
|
-
|
26
|
+
self["name"]
|
27
27
|
end
|
28
28
|
|
29
29
|
# @return [String, nil]
|
30
30
|
def in
|
31
|
-
|
31
|
+
self["in"]
|
32
32
|
end
|
33
33
|
|
34
34
|
# @return [String, nil]
|
35
35
|
def scheme
|
36
|
-
|
36
|
+
self["scheme"]
|
37
37
|
end
|
38
38
|
|
39
39
|
# @return [String, nil]
|
40
40
|
def bearer_format
|
41
|
-
|
41
|
+
self["bearerFormat"]
|
42
42
|
end
|
43
43
|
|
44
44
|
# @return [OauthFlows, nil]
|
45
45
|
def flows
|
46
|
-
|
46
|
+
self["flows"]
|
47
47
|
end
|
48
48
|
|
49
49
|
# @return [String, nil]
|
50
50
|
def open_id_connect_url
|
51
|
-
|
51
|
+
self["openIdConnectUrl"]
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -8,12 +8,12 @@ module Openapi3Parser
|
|
8
8
|
class Server < Node::Object
|
9
9
|
# @return [String]
|
10
10
|
def url
|
11
|
-
|
11
|
+
self["url"]
|
12
12
|
end
|
13
13
|
|
14
14
|
# @return [String, nil]
|
15
15
|
def description
|
16
|
-
|
16
|
+
self["description"]
|
17
17
|
end
|
18
18
|
|
19
19
|
# @return [String, nil]
|
@@ -23,7 +23,7 @@ module Openapi3Parser
|
|
23
23
|
|
24
24
|
# @return [Map<String, ServerVariable>]
|
25
25
|
def variables
|
26
|
-
|
26
|
+
self["variables"]
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -8,17 +8,17 @@ module Openapi3Parser
|
|
8
8
|
class ServerVariable < Node::Object
|
9
9
|
# @return [Node::Array<String>, nil]
|
10
10
|
def enum
|
11
|
-
|
11
|
+
self["enum"]
|
12
12
|
end
|
13
13
|
|
14
14
|
# @return [String]
|
15
15
|
def default
|
16
|
-
|
16
|
+
self["default"]
|
17
17
|
end
|
18
18
|
|
19
19
|
# @return [String, nil]
|
20
20
|
def description
|
21
|
-
|
21
|
+
self["description"]
|
22
22
|
end
|
23
23
|
|
24
24
|
# @return [String, nil]
|
@@ -8,12 +8,12 @@ module Openapi3Parser
|
|
8
8
|
class Tag < Node::Object
|
9
9
|
# @return [String]
|
10
10
|
def name
|
11
|
-
|
11
|
+
self["name"]
|
12
12
|
end
|
13
13
|
|
14
14
|
# @return [String, nil]
|
15
15
|
def description
|
16
|
-
|
16
|
+
self["description"]
|
17
17
|
end
|
18
18
|
|
19
19
|
# @return [String, nil]
|
@@ -23,7 +23,7 @@ module Openapi3Parser
|
|
23
23
|
|
24
24
|
# @return [ExternalDocumentation, nil]
|
25
25
|
def external_docs
|
26
|
-
|
26
|
+
self["externalDocs"]
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -8,27 +8,27 @@ module Openapi3Parser
|
|
8
8
|
class Xml < Node::Object
|
9
9
|
# @return [String, nil]
|
10
10
|
def name
|
11
|
-
|
11
|
+
self["name"]
|
12
12
|
end
|
13
13
|
|
14
14
|
# @return [String, nil]
|
15
15
|
def namespace
|
16
|
-
|
16
|
+
self["namespace"]
|
17
17
|
end
|
18
18
|
|
19
19
|
# @return [String, nil]
|
20
20
|
def prefix
|
21
|
-
|
21
|
+
self["prefix"]
|
22
22
|
end
|
23
23
|
|
24
24
|
# @return [Boolean]
|
25
25
|
def attribute?
|
26
|
-
|
26
|
+
self["attribute"]
|
27
27
|
end
|
28
28
|
|
29
29
|
# @return [Boolean]
|
30
30
|
def wrapped?
|
31
|
-
|
31
|
+
self["wrapped"]
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -41,11 +41,9 @@ module Openapi3Parser
|
|
41
41
|
@errors ||= ValidNodeBuilder.errors(self)
|
42
42
|
end
|
43
43
|
|
44
|
-
def node
|
45
|
-
|
46
|
-
|
47
|
-
data.nil? ? nil : build_node(data)
|
48
|
-
end
|
44
|
+
def node(node_context)
|
45
|
+
data = ValidNodeBuilder.data(self, node_context)
|
46
|
+
data.nil? ? nil : build_node(data, node_context)
|
49
47
|
end
|
50
48
|
|
51
49
|
def inspect
|
@@ -78,8 +76,8 @@ module Openapi3Parser
|
|
78
76
|
end
|
79
77
|
end
|
80
78
|
|
81
|
-
def build_node(data)
|
82
|
-
Node::Array.new(data,
|
79
|
+
def build_node(data, node_context)
|
80
|
+
Node::Array.new(data, node_context) if data
|
83
81
|
end
|
84
82
|
|
85
83
|
def build_resolved_input
|
@@ -95,8 +93,8 @@ module Openapi3Parser
|
|
95
93
|
new(factory).errors
|
96
94
|
end
|
97
95
|
|
98
|
-
def self.data(factory)
|
99
|
-
new(factory).data
|
96
|
+
def self.data(factory, parent_context)
|
97
|
+
new(factory).data(parent_context)
|
100
98
|
end
|
101
99
|
|
102
100
|
def initialize(factory)
|
@@ -112,15 +110,19 @@ module Openapi3Parser
|
|
112
110
|
validatable.collection
|
113
111
|
end
|
114
112
|
|
115
|
-
def data
|
113
|
+
def data(parent_context)
|
116
114
|
return default_value if factory.nil_input?
|
117
115
|
|
118
116
|
TypeChecker.raise_on_invalid_type(factory.context, type: ::Array)
|
119
117
|
check_values(raise_on_invalid: true)
|
120
118
|
validate(raise_on_invalid: true)
|
121
119
|
|
122
|
-
factory.data.map do |value|
|
123
|
-
value.respond_to?(:node)
|
120
|
+
factory.data.each_with_index.map do |value, i|
|
121
|
+
if value.respond_to?(:node)
|
122
|
+
Node::Placeholder.new(value, i, parent_context)
|
123
|
+
else
|
124
|
+
value
|
125
|
+
end
|
124
126
|
end
|
125
127
|
end
|
126
128
|
|
@@ -175,7 +177,7 @@ module Openapi3Parser
|
|
175
177
|
|
176
178
|
first_error = validatable.errors.first
|
177
179
|
raise Openapi3Parser::Error::InvalidData,
|
178
|
-
"Invalid data for #{first_error.context.location_summary}
|
180
|
+
"Invalid data for #{first_error.context.location_summary}: "\
|
179
181
|
"#{first_error.message}"
|
180
182
|
end
|
181
183
|
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Openapi3Parser
|
4
|
+
module NodeFactory
|
5
|
+
# This class is used to specify the data and source information for a
|
6
|
+
# NodeFactory. The same NodeFactory can be used multiple times if the
|
7
|
+
# object is referenced so it is limited in data about it's location
|
8
|
+
# within the document.
|
9
|
+
#
|
10
|
+
# @attr_reader [Any] input
|
11
|
+
# @attr_reader [Source::Location] source_location
|
12
|
+
# @attr_reader [Array<Source::Location>] refernce_locations
|
13
|
+
#
|
14
|
+
class Context
|
15
|
+
# Create a context for the root of a document
|
16
|
+
#
|
17
|
+
# @param [Any] input
|
18
|
+
# @param [Source] source
|
19
|
+
# @return [Context]
|
20
|
+
def self.root(input, source)
|
21
|
+
new(input, source_location: Source::Location.new(source, []))
|
22
|
+
end
|
23
|
+
|
24
|
+
# Create a factory context for a field within the current contexts data
|
25
|
+
# eg for a context of:
|
26
|
+
# root = Context.root({ "test" => {} }, source)
|
27
|
+
# we can get the context of "test" with:
|
28
|
+
# test = Context.next_field(root, "test")
|
29
|
+
#
|
30
|
+
# @param [Context] parent_context
|
31
|
+
# @param [String] field
|
32
|
+
# @return [Context]
|
33
|
+
def self.next_field(parent_context, field)
|
34
|
+
pc = parent_context
|
35
|
+
input = pc.input.respond_to?(:[]) ? pc.input[field] : nil
|
36
|
+
source_location = Source::Location.next_field(pc.source_location, field)
|
37
|
+
new(input,
|
38
|
+
source_location: source_location,
|
39
|
+
reference_locations: pc.reference_locations)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Creates the context for a field that references another field
|
43
|
+
#
|
44
|
+
# @param [Context] reference_context
|
45
|
+
# @param [Source::Location] source_location
|
46
|
+
# @return [Context]
|
47
|
+
def self.resolved_reference(reference_context, source_location:)
|
48
|
+
reference_locations = [reference_context.source_location] +
|
49
|
+
reference_context.reference_locations
|
50
|
+
|
51
|
+
data = source_location.data if source_location.source_available?
|
52
|
+
new(data,
|
53
|
+
source_location: source_location,
|
54
|
+
reference_locations: reference_locations)
|
55
|
+
end
|
56
|
+
|
57
|
+
attr_reader :input, :source_location, :reference_locations
|
58
|
+
|
59
|
+
# @param [Any] input
|
60
|
+
# @param [Source::Location] source_location
|
61
|
+
# @param [Array<Source::Location>] reference_locations
|
62
|
+
def initialize(input,
|
63
|
+
source_location:,
|
64
|
+
reference_locations: [])
|
65
|
+
@input = input
|
66
|
+
@source_location = source_location
|
67
|
+
@reference_locations = reference_locations
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Boolean]
|
71
|
+
def ==(other)
|
72
|
+
input == other.input &&
|
73
|
+
source_location == other.source_location &&
|
74
|
+
reference_locations == other.reference_locations
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [Source]
|
78
|
+
def source
|
79
|
+
source_location.source
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param [String] reference
|
83
|
+
# @param [Object, Map, Array] factory
|
84
|
+
# @param [Boolean] recursive
|
85
|
+
# @return [Source::ResolvedReference]
|
86
|
+
def resolve_reference(reference, factory, recursive: false)
|
87
|
+
source.resolve_reference(reference, factory, self, recursive: recursive)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Used to show when an recursive reference loop has begun
|
91
|
+
#
|
92
|
+
# @return [Boolean]
|
93
|
+
def self_referencing?
|
94
|
+
reference_locations.include?(source_location)
|
95
|
+
end
|
96
|
+
|
97
|
+
def inspect
|
98
|
+
%{#{self.class.name}(source_location: #{source_location}, } +
|
99
|
+
%{referenced_by: #{reference_locations.map(&:to_s).join(', ')})}
|
100
|
+
end
|
101
|
+
|
102
|
+
def location_summary
|
103
|
+
source_location.to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_s
|
107
|
+
location_summary
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -39,11 +39,9 @@ module Openapi3Parser
|
|
39
39
|
@errors ||= ValidNodeBuilder.errors(self)
|
40
40
|
end
|
41
41
|
|
42
|
-
def node
|
43
|
-
|
44
|
-
|
45
|
-
data.nil? ? nil : build_node(data)
|
46
|
-
end
|
42
|
+
def node(node_context)
|
43
|
+
data = ValidNodeBuilder.data(self)
|
44
|
+
data.nil? ? nil : build_node(data, node_context)
|
47
45
|
end
|
48
46
|
|
49
47
|
def inspect
|
@@ -52,7 +50,7 @@ module Openapi3Parser
|
|
52
50
|
|
53
51
|
private
|
54
52
|
|
55
|
-
def build_node(data)
|
53
|
+
def build_node(data, _node_context)
|
56
54
|
data
|
57
55
|
end
|
58
56
|
|
@@ -108,7 +106,7 @@ module Openapi3Parser
|
|
108
106
|
|
109
107
|
first_error = validatable.errors.first
|
110
108
|
raise Openapi3Parser::Error::InvalidData,
|
111
|
-
"Invalid data for #{first_error.context.location_summary}
|
109
|
+
"Invalid data for #{first_error.context.location_summary}: "\
|
112
110
|
"#{first_error.message}"
|
113
111
|
end
|
114
112
|
|
@@ -7,55 +7,74 @@ module Openapi3Parser
|
|
7
7
|
module NodeFactory
|
8
8
|
module Fields
|
9
9
|
class Reference < NodeFactory::Field
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
def_delegator :context, :self_referencing?
|
13
|
+
|
10
14
|
def initialize(context, factory)
|
11
|
-
context = Context.as_reference(context)
|
12
15
|
super(context, input_type: String, validate: :validate)
|
13
16
|
@factory = factory
|
14
17
|
@reference = context.input
|
15
|
-
@
|
18
|
+
@resolved_reference = create_resolved_reference
|
16
19
|
end
|
17
20
|
|
18
21
|
def resolved_input
|
19
|
-
return unless
|
22
|
+
return unless resolved_reference
|
20
23
|
|
21
|
-
if
|
22
|
-
RecursiveResolvedInput.new(
|
24
|
+
if context.self_referencing?
|
25
|
+
RecursiveResolvedInput.new(resolved_reference.factory)
|
23
26
|
else
|
24
|
-
|
27
|
+
resolved_reference.resolved_input
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
28
|
-
def
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
def reference_context
|
33
|
-
context.referenced_by
|
31
|
+
def referenced_factory
|
32
|
+
resolved_reference&.factory
|
34
33
|
end
|
35
34
|
|
36
35
|
private
|
37
36
|
|
38
|
-
attr_reader :reference, :factory, :
|
37
|
+
attr_reader :reference, :factory, :resolved_reference
|
38
|
+
|
39
|
+
def build_node(_data, node_context)
|
40
|
+
if resolved_reference.nil?
|
41
|
+
# this shouldn't happen unless dependant code changes
|
42
|
+
raise Openapi3Parser::Error,
|
43
|
+
"can't build node without a resolved reference"
|
44
|
+
end
|
45
|
+
|
46
|
+
reference_context = Node::Context.resolved_reference(
|
47
|
+
node_context, resolved_reference.factory.context
|
48
|
+
)
|
39
49
|
|
40
|
-
|
41
|
-
reference_resolver&.node
|
50
|
+
resolved_reference.node(reference_context)
|
42
51
|
end
|
43
52
|
|
44
53
|
def validate(validatable)
|
45
54
|
if !reference_validator.valid?
|
46
55
|
validatable.add_errors(reference_validator.errors)
|
56
|
+
elsif !reference_resolves?
|
57
|
+
validatable.add_error("Reference doesn't resolve to an object")
|
47
58
|
else
|
48
|
-
validatable.add_errors(
|
59
|
+
validatable.add_errors(resolved_reference&.errors)
|
49
60
|
end
|
50
61
|
end
|
51
62
|
|
63
|
+
def reference_resolves?
|
64
|
+
return true unless referenced_factory.is_a?(NodeFactory::Reference)
|
65
|
+
|
66
|
+
referenced_factory.resolves?
|
67
|
+
end
|
68
|
+
|
52
69
|
def reference_validator
|
53
70
|
@reference_validator ||= Validators::Reference.new(reference)
|
54
71
|
end
|
55
72
|
|
56
|
-
def
|
73
|
+
def create_resolved_reference
|
57
74
|
return unless reference_validator.valid?
|
58
|
-
context.
|
75
|
+
context.resolve_reference(reference,
|
76
|
+
factory,
|
77
|
+
recursive: context.self_referencing?)
|
59
78
|
end
|
60
79
|
|
61
80
|
# Used in the place of a hash for resolved input so the value can
|
@@ -64,15 +83,15 @@ module Openapi3Parser
|
|
64
83
|
extend Forwardable
|
65
84
|
include Enumerable
|
66
85
|
|
67
|
-
def_delegators :
|
68
|
-
attr_reader :
|
86
|
+
def_delegators :value, :each, :[], :keys
|
87
|
+
attr_reader :factory
|
69
88
|
|
70
|
-
def initialize(
|
71
|
-
@
|
89
|
+
def initialize(factory)
|
90
|
+
@factory = factory
|
72
91
|
end
|
73
92
|
|
74
|
-
def
|
75
|
-
|
93
|
+
def value
|
94
|
+
@factory.resolved_input
|
76
95
|
end
|
77
96
|
end
|
78
97
|
end
|