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,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/context"
4
+ require "openapi3_parser/node_factory/map"
5
+ require "openapi3_parser/node_factory/path_item"
6
+ require "openapi3_parser/node/callback"
7
+
8
+ module Openapi3Parser
9
+ module NodeFactory
10
+ class Callback < NodeFactory::Map
11
+ def initialize(context)
12
+ super(context,
13
+ allow_extensions: true,
14
+ value_factory: NodeFactory::PathItem)
15
+ end
16
+
17
+ private
18
+
19
+ def build_node(data)
20
+ Node::Callback.new(data, context)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -3,23 +3,22 @@
3
3
  require "openapi3_parser/node/components"
4
4
  require "openapi3_parser/node_factory/object"
5
5
  require "openapi3_parser/node_factory/optional_reference"
6
- require "openapi3_parser/node_factories/map"
7
- require "openapi3_parser/node_factories/schema"
8
- require "openapi3_parser/node_factories/response"
9
- require "openapi3_parser/node_factories/parameter"
10
- require "openapi3_parser/node_factories/example"
11
- require "openapi3_parser/node_factories/request_body"
12
- require "openapi3_parser/node_factories/header"
13
- require "openapi3_parser/node_factories/security_scheme"
14
- require "openapi3_parser/node_factories/link"
15
- require "openapi3_parser/node_factories/callback"
6
+ require "openapi3_parser/node_factory/map"
7
+ require "openapi3_parser/node_factory/schema"
8
+ require "openapi3_parser/node_factory/response"
9
+ require "openapi3_parser/node_factory/parameter"
10
+ require "openapi3_parser/node_factory/example"
11
+ require "openapi3_parser/node_factory/request_body"
12
+ require "openapi3_parser/node_factory/header"
13
+ require "openapi3_parser/node_factory/security_scheme"
14
+ require "openapi3_parser/node_factory/link"
15
+ require "openapi3_parser/node_factory/callback"
16
+ require "openapi3_parser/validation/input_validator"
16
17
  require "openapi3_parser/validators/component_keys"
17
18
 
18
19
  module Openapi3Parser
19
- module NodeFactories
20
- class Components
21
- include NodeFactory::Object
22
-
20
+ module NodeFactory
21
+ class Components < NodeFactory::Object
23
22
  allow_extensions
24
23
  field "schemas", factory: :schemas_factory
25
24
  field "responses", factory: :responses_factory
@@ -38,46 +37,46 @@ module Openapi3Parser
38
37
  end
39
38
 
40
39
  def schemas_factory(context)
41
- referenceable_map_factory(context, NodeFactories::Schema)
40
+ referenceable_map_factory(context, NodeFactory::Schema)
42
41
  end
43
42
 
44
43
  def responses_factory(context)
45
- referenceable_map_factory(context, NodeFactories::Response)
44
+ referenceable_map_factory(context, NodeFactory::Response)
46
45
  end
47
46
 
48
47
  def parameters_factory(context)
49
- referenceable_map_factory(context, NodeFactories::Parameter)
48
+ referenceable_map_factory(context, NodeFactory::Parameter)
50
49
  end
51
50
 
52
51
  def examples_factory(context)
53
- referenceable_map_factory(context, NodeFactories::Example)
52
+ referenceable_map_factory(context, NodeFactory::Example)
54
53
  end
55
54
 
56
55
  def request_bodies_factory(context)
57
- referenceable_map_factory(context, NodeFactories::RequestBody)
56
+ referenceable_map_factory(context, NodeFactory::RequestBody)
58
57
  end
59
58
 
60
59
  def headers_factory(context)
61
- referenceable_map_factory(context, NodeFactories::Header)
60
+ referenceable_map_factory(context, NodeFactory::Header)
62
61
  end
63
62
 
64
63
  def security_schemes_factory(context)
65
- referenceable_map_factory(context, NodeFactories::SecurityScheme)
64
+ referenceable_map_factory(context, NodeFactory::SecurityScheme)
66
65
  end
67
66
 
68
67
  def links_factory(context)
69
- referenceable_map_factory(context, NodeFactories::Link)
68
+ referenceable_map_factory(context, NodeFactory::Link)
70
69
  end
71
70
 
72
71
  def callbacks_factory(context)
73
- referenceable_map_factory(context, NodeFactories::Callback)
72
+ referenceable_map_factory(context, NodeFactory::Callback)
74
73
  end
75
74
 
76
75
  def referenceable_map_factory(context, factory)
77
- NodeFactories::Map.new(
76
+ NodeFactory::Map.new(
78
77
  context,
79
78
  value_factory: NodeFactory::OptionalReference.new(factory),
80
- validate: ->(input, _) { Validators::ComponentKeys.call(input) }
79
+ validate: Validation::InputValidator.new(Validators::ComponentKeys)
81
80
  )
82
81
  end
83
82
 
@@ -4,21 +4,20 @@ require "openapi3_parser/node/contact"
4
4
  require "openapi3_parser/node_factory/object"
5
5
  require "openapi3_parser/validators/url"
6
6
  require "openapi3_parser/validators/email"
7
+ require "openapi3_parser/validation/input_validator"
7
8
 
8
9
  module Openapi3Parser
9
- module NodeFactories
10
- class Contact
11
- include NodeFactory::Object
12
-
10
+ module NodeFactory
11
+ class Contact < NodeFactory::Object
13
12
  allow_extensions
14
13
 
15
14
  field "name", input_type: String
16
15
  field "url",
17
16
  input_type: String,
18
- validate: ->(input) { Validators::Url.call(input) }
17
+ validate: Validation::InputValidator.new(Validators::Url)
19
18
  field "email",
20
19
  input_type: String,
21
- validate: ->(input) { Validators::Email.call(input) }
20
+ validate: Validation::InputValidator.new(Validators::Email)
22
21
 
23
22
  private
24
23
 
@@ -4,10 +4,8 @@ require "openapi3_parser/node/discriminator"
4
4
  require "openapi3_parser/node_factory/object"
5
5
 
6
6
  module Openapi3Parser
7
- module NodeFactories
8
- class Discriminator
9
- include NodeFactory::Object
10
-
7
+ module NodeFactory
8
+ class Discriminator < NodeFactory::Object
11
9
  field "propertyName", input_type: String, required: true
12
10
  field "mapping", input_type: Hash,
13
11
  validate: :validate_mapping,
@@ -19,12 +17,13 @@ module Openapi3Parser
19
17
  Node::Discriminator.new(data, context)
20
18
  end
21
19
 
22
- def validate_mapping(input)
20
+ def validate_mapping(validatable)
21
+ input = validatable.input
23
22
  return if input.empty?
24
23
  string_keys = input.keys.map(&:class).uniq == [String]
25
24
  string_values = input.values.map(&:class).uniq == [String]
26
- valid = string_keys && string_values
27
- return "Expected string keys and string values" unless valid
25
+ return if string_keys && string_values
26
+ validatable.add_error("Expected string keys and string values")
28
27
  end
29
28
  end
30
29
  end
@@ -1,16 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "openapi3_parser/node/encoding"
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/header"
7
+ require "openapi3_parser/node_factory/header"
8
8
 
9
9
  module Openapi3Parser
10
- module NodeFactories
11
- class Encoding
12
- include NodeFactory::Object
13
-
10
+ module NodeFactory
11
+ class Encoding < NodeFactory::Object
14
12
  allow_extensions
15
13
 
16
14
  field "contentType", input_type: String
@@ -26,8 +24,8 @@ module Openapi3Parser
26
24
  end
27
25
 
28
26
  def headers_factory(context)
29
- factory = NodeFactory::OptionalReference.new(NodeFactories::Header)
30
- NodeFactories::Map.new(context, value_factory: factory)
27
+ factory = NodeFactory::OptionalReference.new(NodeFactory::Header)
28
+ NodeFactory::Map.new(context, value_factory: factory)
31
29
  end
32
30
 
33
31
  def default_explode
@@ -3,12 +3,11 @@
3
3
  require "openapi3_parser/node/example"
4
4
  require "openapi3_parser/node_factory/object"
5
5
  require "openapi3_parser/validators/url"
6
+ require "openapi3_parser/validation/input_validator"
6
7
 
7
8
  module Openapi3Parser
8
- module NodeFactories
9
- class Example
10
- include NodeFactory::Object
11
-
9
+ module NodeFactory
10
+ class Example < NodeFactory::Object
12
11
  allow_extensions
13
12
 
14
13
  field "summary", input_type: String
@@ -16,7 +15,7 @@ module Openapi3Parser
16
15
  field "value"
17
16
  field "externalValue",
18
17
  input_type: String,
19
- validate: ->(input) { Validators::Url.call(input) }
18
+ validate: Validation::InputValidator.new(Validators::Url)
20
19
 
21
20
  mutually_exclusive "value", "externalValue"
22
21
 
@@ -2,20 +2,19 @@
2
2
 
3
3
  require "openapi3_parser/node/external_documentation"
4
4
  require "openapi3_parser/node_factory/object"
5
+ require "openapi3_parser/validation/input_validator"
5
6
  require "openapi3_parser/validators/url"
6
7
 
7
8
  module Openapi3Parser
8
- module NodeFactories
9
- class ExternalDocumentation
10
- include NodeFactory::Object
11
-
9
+ module NodeFactory
10
+ class ExternalDocumentation < NodeFactory::Object
12
11
  allow_extensions
13
12
 
14
13
  field "description", input_type: String
15
14
  field "url",
16
15
  required: true,
17
16
  input_type: String,
18
- validate: ->(input) { Validators::Url.call(input) }
17
+ validate: Validation::InputValidator.new(Validators::Url)
19
18
 
20
19
  private
21
20
 
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node_factory"
4
+ require "openapi3_parser/node_factory/type_checker"
5
+ require "openapi3_parser/validation/validatable"
6
+
7
+ module Openapi3Parser
8
+ module NodeFactory
9
+ class Field
10
+ attr_reader :context, :input_type, :validation
11
+
12
+ def initialize(context, input_type: nil, validate: nil)
13
+ @context = context
14
+ @input_type = input_type
15
+ @validation = validate
16
+ end
17
+
18
+ def data
19
+ context.input
20
+ end
21
+
22
+ def resolved_input
23
+ context.input
24
+ end
25
+
26
+ def raw_input
27
+ context.input
28
+ end
29
+
30
+ def nil_input?
31
+ context.input.nil?
32
+ end
33
+
34
+ def valid?
35
+ errors.empty?
36
+ end
37
+
38
+ def default
39
+ nil
40
+ end
41
+
42
+ def errors
43
+ @errors ||= ValidNodeBuilder.errors(self)
44
+ end
45
+
46
+ def node
47
+ @node ||= begin
48
+ data = ValidNodeBuilder.data(self)
49
+ data.nil? ? nil : build_node(data)
50
+ end
51
+ end
52
+
53
+ def inspect
54
+ %{#{self.class.name}(#{context.source_location.inspect})}
55
+ end
56
+
57
+ private
58
+
59
+ def build_node(data)
60
+ data
61
+ end
62
+
63
+ class ValidNodeBuilder
64
+ def self.errors(factory)
65
+ new(factory).errors
66
+ end
67
+
68
+ def self.data(factory)
69
+ new(factory).data
70
+ end
71
+
72
+ def initialize(factory)
73
+ @factory = factory
74
+ @validatable = Validation::Validatable.new(factory)
75
+ end
76
+
77
+ def errors
78
+ return validatable.collection if factory.nil_input?
79
+ TypeChecker.validate_type(validatable, type: factory.input_type)
80
+ return validatable.collection if validatable.errors.any?
81
+ validate(raise_on_invalid: false)
82
+ validatable.collection
83
+ end
84
+
85
+ def data
86
+ return default_value if factory.nil_input?
87
+
88
+ TypeChecker.raise_on_invalid_type(factory.context,
89
+ type: factory.input_type)
90
+ validate(raise_on_invalid: true)
91
+ factory.data
92
+ end
93
+
94
+ private_class_method :new
95
+
96
+ private
97
+
98
+ attr_reader :factory, :validatable
99
+
100
+ def default_value
101
+ if factory.nil_input? && factory.default.nil?
102
+ nil
103
+ else
104
+ factory.data
105
+ end
106
+ end
107
+
108
+ def validate(raise_on_invalid: false)
109
+ run_validation
110
+
111
+ return if !raise_on_invalid || validatable.errors.empty?
112
+
113
+ first_error = validatable.errors.first
114
+ raise Openapi3Parser::Error::InvalidData,
115
+ "Invalid data for #{first_error.context.location_summary}. "\
116
+ "#{first_error.message}"
117
+ end
118
+
119
+ def run_validation
120
+ if factory.validation.is_a?(Symbol)
121
+ factory.send(factory.validation, validatable)
122
+ else
123
+ factory.validation&.call(validatable)
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -1,46 +1,82 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "openapi3_parser/node_factory"
3
+ require "forwardable"
4
+
5
+ require "openapi3_parser/context"
6
+ require "openapi3_parser/node_factory/field"
4
7
  require "openapi3_parser/validators/reference"
5
8
 
6
9
  module Openapi3Parser
7
10
  module NodeFactory
8
11
  module Fields
9
- class Reference
10
- include NodeFactory
11
- input_type ::String
12
-
12
+ class Reference < NodeFactory::Field
13
13
  def initialize(context, factory)
14
- super(context)
14
+ context = Context.as_reference(context)
15
+ super(context, input_type: String, validate: :validate)
15
16
  @factory = factory
16
- @given_reference = context.input
17
+ @reference = context.input
17
18
  @reference_resolver = create_reference_resolver
18
19
  end
19
20
 
20
- def data
21
- reference_resolver&.data
21
+ def resolved_input
22
+ return unless reference_resolver
23
+
24
+ if in_recursive_loop?
25
+ RecursiveResolvedInput.new(reference_context)
26
+ else
27
+ reference_resolver.resolved_input
28
+ end
29
+ end
30
+
31
+ def in_recursive_loop?
32
+ context.source_location == reference_context&.source_location
33
+ end
34
+
35
+ def reference_context
36
+ context.referenced_by
22
37
  end
23
38
 
24
39
  private
25
40
 
26
- attr_reader :given_reference, :factory, :reference_resolver
41
+ attr_reader :reference, :factory, :reference_resolver
27
42
 
28
- def validate(_, _)
29
- return reference_validator.errors unless reference_validator.valid?
30
- reference_resolver&.errors
43
+ def build_node(_data)
44
+ reference_resolver&.node
31
45
  end
32
46
 
33
- def build_node(_)
34
- reference_resolver&.node
47
+ def validate(validatable)
48
+ if !reference_validator.valid?
49
+ validatable.add_errors(reference_validator.errors)
50
+ else
51
+ validatable.add_errors(reference_resolver&.errors)
52
+ end
35
53
  end
36
54
 
37
55
  def reference_validator
38
- @reference_validator ||= Validators::Reference.new(given_reference)
56
+ @reference_validator ||= Validators::Reference.new(reference)
39
57
  end
40
58
 
41
59
  def create_reference_resolver
42
- return unless given_reference
43
- context.register_reference(given_reference, factory)
60
+ return unless reference_validator.valid?
61
+ context.register_reference(reference, factory)
62
+ end
63
+
64
+ # Used in the place of a hash for resolved input so the value can
65
+ # be looked up at runtime avoiding a recursive loop.
66
+ class RecursiveResolvedInput
67
+ extend Forwardable
68
+ include Enumerable
69
+
70
+ def_delegators :resolved_input, :each, :[], :keys
71
+ attr_reader :context
72
+
73
+ def initialize(context)
74
+ @context = context
75
+ end
76
+
77
+ def resolved_input
78
+ context.resolved_input
79
+ end
44
80
  end
45
81
  end
46
82
  end