openapi3_parser 0.4.0 → 0.5.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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/CHANGELOG.md +8 -0
  4. data/README.md +1 -1
  5. data/TODO.md +4 -4
  6. data/lib/openapi3_parser/array_sentence.rb +12 -0
  7. data/lib/openapi3_parser/cautious_dig.rb +39 -0
  8. data/lib/openapi3_parser/context.rb +53 -1
  9. data/lib/openapi3_parser/context/location.rb +1 -0
  10. data/lib/openapi3_parser/context/pointer.rb +67 -5
  11. data/lib/openapi3_parser/document.rb +45 -4
  12. data/lib/openapi3_parser/error.rb +9 -0
  13. data/lib/openapi3_parser/node/array.rb +14 -4
  14. data/lib/openapi3_parser/node/map.rb +45 -3
  15. data/lib/openapi3_parser/node/object.rb +25 -5
  16. data/lib/openapi3_parser/node_factory.rb +0 -150
  17. data/lib/openapi3_parser/node_factory/array.rb +198 -0
  18. data/lib/openapi3_parser/node_factory/callback.rb +24 -0
  19. data/lib/openapi3_parser/{node_factories → node_factory}/components.rb +24 -25
  20. data/lib/openapi3_parser/{node_factories → node_factory}/contact.rb +5 -6
  21. data/lib/openapi3_parser/{node_factories → node_factory}/discriminator.rb +6 -7
  22. data/lib/openapi3_parser/{node_factories → node_factory}/encoding.rb +6 -8
  23. data/lib/openapi3_parser/{node_factories → node_factory}/example.rb +4 -5
  24. data/lib/openapi3_parser/{node_factories → node_factory}/external_documentation.rb +4 -5
  25. data/lib/openapi3_parser/node_factory/field.rb +129 -0
  26. data/lib/openapi3_parser/node_factory/fields/reference.rb +54 -18
  27. data/lib/openapi3_parser/{node_factories → node_factory}/header.rb +4 -5
  28. data/lib/openapi3_parser/{node_factories → node_factory}/info.rb +6 -7
  29. data/lib/openapi3_parser/{node_factories → node_factory}/license.rb +4 -5
  30. data/lib/openapi3_parser/{node_factories → node_factory}/link.rb +6 -8
  31. data/lib/openapi3_parser/node_factory/map.rb +206 -21
  32. data/lib/openapi3_parser/{node_factories → node_factory}/media_type.rb +17 -16
  33. data/lib/openapi3_parser/{node_factories → node_factory}/oauth_flow.rb +2 -4
  34. data/lib/openapi3_parser/{node_factories → node_factory}/oauth_flows.rb +4 -6
  35. data/lib/openapi3_parser/node_factory/object.rb +66 -63
  36. data/lib/openapi3_parser/node_factory/object_factory/dsl.rb +50 -0
  37. data/lib/openapi3_parser/node_factory/object_factory/field_config.rb +88 -0
  38. data/lib/openapi3_parser/node_factory/object_factory/node_builder.rb +96 -0
  39. data/lib/openapi3_parser/node_factory/object_factory/validator.rb +172 -0
  40. data/lib/openapi3_parser/node_factory/openapi.rb +65 -0
  41. data/lib/openapi3_parser/node_factory/operation.rb +87 -0
  42. data/lib/openapi3_parser/node_factory/optional_reference.rb +7 -3
  43. data/lib/openapi3_parser/{node_factories → node_factory}/parameter.rb +16 -22
  44. data/lib/openapi3_parser/node_factory/parameter_like.rb +42 -0
  45. data/lib/openapi3_parser/{node_factories → node_factory}/path_item.rb +27 -29
  46. data/lib/openapi3_parser/{node_factories → node_factory}/paths.rb +21 -27
  47. data/lib/openapi3_parser/node_factory/recursive_pointer.rb +17 -0
  48. data/lib/openapi3_parser/node_factory/reference.rb +48 -0
  49. data/lib/openapi3_parser/{node_factories → node_factory}/request_body.rb +15 -19
  50. data/lib/openapi3_parser/{node_factories → node_factory}/response.rb +18 -21
  51. data/lib/openapi3_parser/node_factory/responses.rb +51 -0
  52. data/lib/openapi3_parser/{node_factories → node_factory}/schema.rb +33 -33
  53. data/lib/openapi3_parser/node_factory/security_requirement.rb +21 -0
  54. data/lib/openapi3_parser/{node_factories → node_factory}/security_scheme.rb +4 -6
  55. data/lib/openapi3_parser/{node_factories → node_factory}/server.rb +6 -8
  56. data/lib/openapi3_parser/{node_factories → node_factory}/server_variable.rb +10 -12
  57. data/lib/openapi3_parser/{node_factories → node_factory}/tag.rb +4 -6
  58. data/lib/openapi3_parser/node_factory/type_checker.rb +103 -0
  59. data/lib/openapi3_parser/{node_factories → node_factory}/xml.rb +4 -5
  60. data/lib/openapi3_parser/source/reference_resolver.rb +3 -3
  61. data/lib/openapi3_parser/validation/error.rb +9 -0
  62. data/lib/openapi3_parser/validation/input_validator.rb +18 -0
  63. data/lib/openapi3_parser/validation/validatable.rb +44 -0
  64. data/lib/openapi3_parser/validators/mutually_exclusive_fields.rb +121 -0
  65. data/lib/openapi3_parser/validators/required_fields.rb +37 -0
  66. data/lib/openapi3_parser/validators/unexpected_fields.rb +52 -0
  67. data/lib/openapi3_parser/version.rb +1 -1
  68. metadata +48 -38
  69. data/lib/openapi3_parser/node_factories/array.rb +0 -114
  70. data/lib/openapi3_parser/node_factories/callback.rb +0 -27
  71. data/lib/openapi3_parser/node_factories/map.rb +0 -120
  72. data/lib/openapi3_parser/node_factories/openapi.rb +0 -62
  73. data/lib/openapi3_parser/node_factories/operation.rb +0 -84
  74. data/lib/openapi3_parser/node_factories/parameter/parameter_like.rb +0 -41
  75. data/lib/openapi3_parser/node_factories/reference.rb +0 -35
  76. data/lib/openapi3_parser/node_factories/responses.rb +0 -60
  77. data/lib/openapi3_parser/node_factories/security_requirement.rb +0 -26
  78. data/lib/openapi3_parser/node_factory/field_config.rb +0 -88
  79. data/lib/openapi3_parser/node_factory/object/node_builder.rb +0 -97
  80. data/lib/openapi3_parser/node_factory/object/validator.rb +0 -176
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openapi3Parser
4
+ module NodeFactory
5
+ class RecursivePointer
6
+ attr_reader :reference_context
7
+
8
+ def initialize(reference_context)
9
+ @reference_context = reference_context
10
+ end
11
+
12
+ def node
13
+ reference_context.node
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/error"
4
+ require "openapi3_parser/node_factory/fields/reference"
5
+ require "openapi3_parser/node_factory/object"
6
+ require "openapi3_parser/node_factory/recursive_pointer"
7
+
8
+ module Openapi3Parser
9
+ module NodeFactory
10
+ class Reference < NodeFactory::Object
11
+ field "$ref", input_type: String, required: true, factory: :ref_factory
12
+
13
+ attr_reader :factory
14
+
15
+ def initialize(context, factory)
16
+ @factory = factory
17
+ super(context)
18
+ end
19
+
20
+ def in_recursive_loop?
21
+ data["$ref"].in_recursive_loop?
22
+ end
23
+
24
+ def recursive_pointer
25
+ NodeFactory::RecursivePointer.new(data["$ref"].reference_context)
26
+ end
27
+
28
+ private
29
+
30
+ def build_node
31
+ if in_recursive_loop?
32
+ raise Error::InRecursiveStructure,
33
+ "Can't build node as it references itself, use "\
34
+ "recursive_pointer"
35
+ end
36
+ data["$ref"].node
37
+ end
38
+
39
+ def ref_factory(context)
40
+ NodeFactory::Fields::Reference.new(context, factory)
41
+ end
42
+
43
+ def build_resolved_input
44
+ data["$ref"].resolved_input
45
+ end
46
+ end
47
+ end
48
+ end
@@ -2,17 +2,15 @@
2
2
 
3
3
  require "openapi3_parser/context"
4
4
  require "openapi3_parser/node/request_body"
5
+ require "openapi3_parser/node_factory/map"
5
6
  require "openapi3_parser/node_factory/object"
6
- require "openapi3_parser/node_factories/media_type"
7
- require "openapi3_parser/node_factories/map"
7
+ require "openapi3_parser/node_factory/media_type"
8
8
  require "openapi3_parser/validation/error"
9
9
  require "openapi3_parser/validators/media_type"
10
10
 
11
11
  module Openapi3Parser
12
- module NodeFactories
13
- class RequestBody
14
- include NodeFactory::Object
15
-
12
+ module NodeFactory
13
+ class RequestBody < NodeFactory::Object
16
14
  allow_extensions
17
15
  field "description", input_type: String
18
16
  field "content", factory: :content_factory, required: true
@@ -25,9 +23,9 @@ module Openapi3Parser
25
23
  end
26
24
 
27
25
  def content_factory(context)
28
- NodeFactories::Map.new(
26
+ NodeFactory::Map.new(
29
27
  context,
30
- value_factory: NodeFactories::MediaType,
28
+ value_factory: NodeFactory::MediaType,
31
29
  validate: ContentValidator
32
30
  )
33
31
  end
@@ -37,22 +35,20 @@ module Openapi3Parser
37
35
  new.call(*args)
38
36
  end
39
37
 
40
- def call(input, context)
38
+ def call(validatable)
41
39
  # This validation isn't actually mentioned in the spec, but it
42
40
  # doesn't seem to make sense if this is an empty hash.
43
- return "Expected to have at least 1 item" if input.size.zero?
44
-
45
- input.keys.each_with_object([]) do |key, memo|
46
- message = Validators::MediaType.call(key)
47
- memo << create_error(key, context, message) if message
41
+ if validatable.input.size.zero?
42
+ return validatable.add_error("Expected to have at least 1 item")
48
43
  end
49
- end
50
44
 
51
- private
45
+ validatable.input.keys.each do |key|
46
+ message = Validators::MediaType.call(key)
47
+ next unless message
52
48
 
53
- def create_error(key, parent_context, message)
54
- context = Context.next_field(parent_context, key)
55
- Validation::Error.new(message, context)
49
+ context = Context.next_field(validatable.context, key)
50
+ validatable.add_error(message, context)
51
+ end
56
52
  end
57
53
  end
58
54
  end
@@ -2,21 +2,19 @@
2
2
 
3
3
  require "openapi3_parser/context"
4
4
  require "openapi3_parser/node/response"
5
+ require "openapi3_parser/node_factory/map"
5
6
  require "openapi3_parser/node_factory/object"
6
7
  require "openapi3_parser/node_factory/optional_reference"
7
- require "openapi3_parser/node_factories/map"
8
- require "openapi3_parser/node_factories/header"
9
- require "openapi3_parser/node_factories/media_type"
10
- require "openapi3_parser/node_factories/link"
11
- require "openapi3_parser/validation/error"
8
+ require "openapi3_parser/node_factory/header"
9
+ require "openapi3_parser/node_factory/media_type"
10
+ require "openapi3_parser/node_factory/link"
11
+ require "openapi3_parser/validation/input_validator"
12
12
  require "openapi3_parser/validators/media_type"
13
13
  require "openapi3_parser/validators/component_keys"
14
14
 
15
15
  module Openapi3Parser
16
- module NodeFactories
17
- class Response
18
- include NodeFactory::Object
19
-
16
+ module NodeFactory
17
+ class Response < NodeFactory::Object
20
18
  allow_extensions
21
19
  field "description", input_type: String, required: true
22
20
  field "headers", factory: :headers_factory
@@ -30,34 +28,33 @@ module Openapi3Parser
30
28
  end
31
29
 
32
30
  def headers_factory(context)
33
- factory = NodeFactory::OptionalReference.new(NodeFactories::Header)
34
- NodeFactories::Map.new(context, value_factory: factory)
31
+ factory = NodeFactory::OptionalReference.new(NodeFactory::Header)
32
+ NodeFactory::Map.new(context, value_factory: factory)
35
33
  end
36
34
 
37
35
  def content_factory(context)
38
- NodeFactories::Map.new(
36
+ NodeFactory::Map.new(
39
37
  context,
40
38
  validate: method(:validate_content),
41
- value_factory: NodeFactories::MediaType
39
+ value_factory: NodeFactory::MediaType
42
40
  )
43
41
  end
44
42
 
45
43
  def links_factory(context)
46
- factory = NodeFactory::OptionalReference.new(NodeFactories::Link)
47
- NodeFactories::Map.new(
44
+ factory = NodeFactory::OptionalReference.new(NodeFactory::Link)
45
+ NodeFactory::Map.new(
48
46
  context,
49
- validate: ->(input, _) { Validators::ComponentKeys.call(input) },
47
+ validate: Validation::InputValidator.new(Validators::ComponentKeys),
50
48
  value_factory: factory
51
49
  )
52
50
  end
53
51
 
54
- def validate_content(input, context)
55
- input.keys.each_with_object([]) do |key, memo|
52
+ def validate_content(validatable)
53
+ validatable.input.each_key do |key|
56
54
  message = Validators::MediaType.call(key)
57
55
  next unless message
58
- memo << Validation::Error.new(
59
- message, Context.next_field(context, key)
60
- )
56
+ validatable.add_error(message,
57
+ Context.next_field(validatable.context, key))
61
58
  end
62
59
  end
63
60
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/context"
4
+ require "openapi3_parser/node_factory/map"
5
+ require "openapi3_parser/node_factory/response"
6
+ require "openapi3_parser/node_factory/optional_reference"
7
+ require "openapi3_parser/node/responses"
8
+
9
+ module Openapi3Parser
10
+ module NodeFactory
11
+ class Responses < NodeFactory::Map
12
+ KEY_REGEX = /
13
+ \A
14
+ (
15
+ default
16
+ |
17
+ [1-5]([0-9][0-9]|XX)
18
+ )
19
+ \Z
20
+ /x
21
+
22
+ def initialize(context)
23
+ factory = NodeFactory::OptionalReference.new(NodeFactory::Response)
24
+
25
+ super(context,
26
+ allow_extensions: true,
27
+ value_factory: factory,
28
+ validate: :validate_keys)
29
+ end
30
+
31
+ private
32
+
33
+ def build_node(data)
34
+ Node::Responses.new(data, context)
35
+ end
36
+
37
+ def validate_keys(validatable)
38
+ invalid = validatable.input.keys.reject do |key|
39
+ NodeFactory::EXTENSION_REGEX.match(key) ||
40
+ KEY_REGEX.match(key)
41
+ end
42
+
43
+ return if invalid.empty?
44
+
45
+ codes = invalid.map { |k| "'#{k}'" }.join(", ")
46
+ validatable.add_error("Invalid responses keys: #{codes} - default, "\
47
+ "status codes and status code ranges allowed")
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,19 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "openapi3_parser/node/schema"
4
+ require "openapi3_parser/node_factory/map"
4
5
  require "openapi3_parser/node_factory/object"
5
6
  require "openapi3_parser/node_factory/optional_reference"
6
- require "openapi3_parser/node_factories/map"
7
- require "openapi3_parser/node_factories/array"
8
- require "openapi3_parser/node_factories/external_documentation"
9
- require "openapi3_parser/node_factories/discriminator"
10
- require "openapi3_parser/node_factories/xml"
7
+ require "openapi3_parser/node_factory/array"
8
+ require "openapi3_parser/node_factory/external_documentation"
9
+ require "openapi3_parser/node_factory/discriminator"
10
+ require "openapi3_parser/node_factory/xml"
11
11
 
12
12
  module Openapi3Parser
13
- module NodeFactories
14
- class Schema
15
- include NodeFactory::Object
16
-
13
+ module NodeFactory
14
+ class Schema < NodeFactory::Object
17
15
  allow_extensions
18
16
  field "title", input_type: String
19
17
  field "multipleOf", input_type: Numeric
@@ -40,7 +38,7 @@ module Openapi3Parser
40
38
  field "items", factory: :referenceable_schema
41
39
  field "properties", factory: :properties_factory
42
40
  field "additionalProperties",
43
- input_type: :additional_properties_input_type,
41
+ validate: :additional_properties_input_type,
44
42
  factory: :additional_properties_factory,
45
43
  default: false
46
44
  field "description", input_type: String
@@ -56,28 +54,29 @@ module Openapi3Parser
56
54
  field "example"
57
55
  field "deprecated", input_type: :boolean, default: false
58
56
 
59
- private
57
+ validate :items_for_array, :read_only_or_write_only
60
58
 
61
- def build_object(data, context)
62
- Node::Schema.new(data, context)
63
- end
59
+ private
64
60
 
65
- def validate(input, _context)
66
- errors = []
61
+ def items_for_array(validatable)
62
+ return unless validatable.input["type"] == "array"
63
+ return unless validatable.factory.resolved_input["items"].nil?
67
64
 
68
- if input["type"] == "array" && resolved_input["items"].nil?
69
- errors << "items must be defined for a type of array"
70
- end
65
+ validatable.add_error("items must be defined for a type of array")
66
+ end
71
67
 
72
- if input["readOnly"] == true && input["writeOnly"] == true
73
- errors << "readOnly and writeOnly cannot both be true"
74
- end
68
+ def read_only_or_write_only(validatable)
69
+ input = validatable.input
70
+ return if [input["readOnly"], input["writeOnly"]].uniq != [true]
71
+ validatable.add_error("readOnly and writeOnly cannot both be true")
72
+ end
75
73
 
76
- errors
74
+ def build_object(data, context)
75
+ Node::Schema.new(data, context)
77
76
  end
78
77
 
79
78
  def required_factory(context)
80
- NodeFactories::Array.new(
79
+ NodeFactory::Array.new(
81
80
  context,
82
81
  default: nil,
83
82
  value_input_type: String
@@ -85,25 +84,25 @@ module Openapi3Parser
85
84
  end
86
85
 
87
86
  def enum_factory(context)
88
- NodeFactories::Array.new(context, default: nil)
87
+ NodeFactory::Array.new(context, default: nil)
89
88
  end
90
89
 
91
90
  def disciminator_factory(context)
92
- NodeFactories::Discriminator.new(context)
91
+ NodeFactory::Discriminator.new(context)
93
92
  end
94
93
 
95
94
  def xml_factory(context)
96
- NodeFactories::Xml.new(context)
95
+ NodeFactory::Xml.new(context)
97
96
  end
98
97
 
99
98
  def external_docs_factory(context)
100
- NodeFactories::ExternalDocumentation.new(context)
99
+ NodeFactory::ExternalDocumentation.new(context)
101
100
  end
102
101
 
103
102
  def properties_factory(context)
104
- NodeFactories::Map.new(
103
+ NodeFactory::Map.new(
105
104
  context,
106
- value_factory: NodeFactories::Schema
105
+ value_factory: NodeFactory::OptionalReference.new(self.class)
107
106
  )
108
107
  end
109
108
 
@@ -112,16 +111,17 @@ module Openapi3Parser
112
111
  end
113
112
 
114
113
  def referenceable_schema_array(context)
115
- NodeFactories::Array.new(
114
+ NodeFactory::Array.new(
116
115
  context,
117
116
  default: nil,
118
117
  value_factory: NodeFactory::OptionalReference.new(self.class)
119
118
  )
120
119
  end
121
120
 
122
- def additional_properties_input_type(input)
121
+ def additional_properties_input_type(validatable)
122
+ input = validatable.input
123
123
  return if [true, false].include?(input) || input.is_a?(Hash)
124
- "Expected a boolean or an object"
124
+ validatable.add_error("Expected a Boolean or an Object")
125
125
  end
126
126
 
127
127
  def additional_properties_factory(context)
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/security_requirement"
4
+ require "openapi3_parser/node_factory/array"
5
+ require "openapi3_parser/node_factory/map"
6
+
7
+ module Openapi3Parser
8
+ module NodeFactory
9
+ class SecurityRequirement < NodeFactory::Map
10
+ def initialize(context)
11
+ super(context, value_factory: NodeFactory::Array)
12
+ end
13
+
14
+ private
15
+
16
+ def build_node(data)
17
+ Node::SecurityRequirement.new(data, context)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,15 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "openapi3_parser/node/security_scheme"
4
- require "openapi3_parser/node_factories/oauth_flows"
4
+ require "openapi3_parser/node_factory/oauth_flows"
5
5
  require "openapi3_parser/node_factory/object"
6
6
  require "openapi3_parser/node_factory/optional_reference"
7
7
 
8
8
  module Openapi3Parser
9
- module NodeFactories
10
- class SecurityScheme
11
- include NodeFactory::Object
12
-
9
+ module NodeFactory
10
+ class SecurityScheme < NodeFactory::Object
13
11
  allow_extensions
14
12
 
15
13
  field "type", input_type: String, required: true
@@ -28,7 +26,7 @@ module Openapi3Parser
28
26
  end
29
27
 
30
28
  def flows_factory(context)
31
- NodeFactories::OauthFlows.new(context)
29
+ NodeFactory::OauthFlows.new(context)
32
30
  end
33
31
  end
34
32
  end
@@ -1,15 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "openapi3_parser/node/server"
4
+ require "openapi3_parser/node_factory/map"
4
5
  require "openapi3_parser/node_factory/object"
5
- require "openapi3_parser/node_factories/server_variable"
6
- require "openapi3_parser/node_factories/map"
6
+ require "openapi3_parser/node_factory/server_variable"
7
7
 
8
8
  module Openapi3Parser
9
- module NodeFactories
10
- class Server
11
- include NodeFactory::Object
12
-
9
+ module NodeFactory
10
+ class Server < NodeFactory::Object
13
11
  allow_extensions
14
12
  field "url", input_type: String, required: true
15
13
  field "description", input_type: String
@@ -22,9 +20,9 @@ module Openapi3Parser
22
20
  end
23
21
 
24
22
  def variables_factory(context)
25
- NodeFactories::Map.new(
23
+ NodeFactory::Map.new(
26
24
  context,
27
- value_factory: NodeFactories::ServerVariable
25
+ value_factory: NodeFactory::ServerVariable
28
26
  )
29
27
  end
30
28
  end