openapi3_parser 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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