openapi3_parser 0.2.0 → 0.3.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +10 -1
  3. data/CHANGELOG.md +5 -0
  4. data/README.md +13 -0
  5. data/TODO.md +11 -8
  6. data/lib/openapi3_parser.rb +16 -28
  7. data/lib/openapi3_parser/context.rb +92 -34
  8. data/lib/openapi3_parser/context/location.rb +37 -0
  9. data/lib/openapi3_parser/context/pointer.rb +34 -0
  10. data/lib/openapi3_parser/document.rb +115 -15
  11. data/lib/openapi3_parser/document/reference_register.rb +50 -0
  12. data/lib/openapi3_parser/error.rb +27 -1
  13. data/lib/openapi3_parser/node/object.rb +26 -1
  14. data/lib/openapi3_parser/node_factories/array.rb +15 -14
  15. data/lib/openapi3_parser/node_factories/callback.rb +2 -1
  16. data/lib/openapi3_parser/node_factories/link.rb +1 -1
  17. data/lib/openapi3_parser/node_factories/map.rb +13 -11
  18. data/lib/openapi3_parser/node_factories/openapi.rb +2 -0
  19. data/lib/openapi3_parser/node_factories/path_item.rb +13 -18
  20. data/lib/openapi3_parser/node_factories/paths.rb +2 -1
  21. data/lib/openapi3_parser/node_factories/reference.rb +7 -9
  22. data/lib/openapi3_parser/node_factories/responses.rb +4 -2
  23. data/lib/openapi3_parser/node_factories/security_requirement.rb +2 -1
  24. data/lib/openapi3_parser/node_factory.rb +39 -30
  25. data/lib/openapi3_parser/node_factory/fields/reference.rb +44 -0
  26. data/lib/openapi3_parser/node_factory/map.rb +5 -5
  27. data/lib/openapi3_parser/node_factory/object.rb +6 -5
  28. data/lib/openapi3_parser/node_factory/object/node_builder.rb +12 -11
  29. data/lib/openapi3_parser/node_factory/object/validator.rb +25 -14
  30. data/lib/openapi3_parser/nodes/components.rb +9 -11
  31. data/lib/openapi3_parser/nodes/discriminator.rb +1 -1
  32. data/lib/openapi3_parser/nodes/encoding.rb +1 -1
  33. data/lib/openapi3_parser/nodes/link.rb +1 -1
  34. data/lib/openapi3_parser/nodes/media_type.rb +2 -2
  35. data/lib/openapi3_parser/nodes/oauth_flow.rb +1 -1
  36. data/lib/openapi3_parser/nodes/openapi.rb +3 -4
  37. data/lib/openapi3_parser/nodes/operation.rb +5 -8
  38. data/lib/openapi3_parser/nodes/parameter/parameter_like.rb +2 -2
  39. data/lib/openapi3_parser/nodes/path_item.rb +2 -3
  40. data/lib/openapi3_parser/nodes/request_body.rb +1 -1
  41. data/lib/openapi3_parser/nodes/response.rb +3 -3
  42. data/lib/openapi3_parser/nodes/schema.rb +6 -7
  43. data/lib/openapi3_parser/nodes/server.rb +1 -2
  44. data/lib/openapi3_parser/nodes/server_variable.rb +1 -1
  45. data/lib/openapi3_parser/source.rb +136 -0
  46. data/lib/openapi3_parser/source/reference.rb +68 -0
  47. data/lib/openapi3_parser/source/reference_resolver.rb +81 -0
  48. data/lib/openapi3_parser/source_input.rb +71 -0
  49. data/lib/openapi3_parser/source_input/file.rb +102 -0
  50. data/lib/openapi3_parser/source_input/raw.rb +90 -0
  51. data/lib/openapi3_parser/source_input/resolve_next.rb +62 -0
  52. data/lib/openapi3_parser/source_input/string_parser.rb +43 -0
  53. data/lib/openapi3_parser/source_input/url.rb +123 -0
  54. data/lib/openapi3_parser/validation/error.rb +36 -3
  55. data/lib/openapi3_parser/validation/error_collection.rb +57 -15
  56. data/lib/openapi3_parser/validators/reference.rb +40 -0
  57. data/lib/openapi3_parser/version.rb +1 -1
  58. data/openapi3_parser.gemspec +10 -5
  59. metadata +34 -20
  60. data/lib/openapi3_parser/fields/map.rb +0 -83
  61. data/lib/openapi3_parser/node.rb +0 -115
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node_factory"
4
+ require "openapi3_parser/validators/reference"
5
+
6
+ module Openapi3Parser
7
+ module NodeFactory
8
+ module Fields
9
+ class Reference
10
+ include NodeFactory
11
+ input_type ::String
12
+
13
+ def initialize(context, factory)
14
+ super(context)
15
+ @factory = factory
16
+ @given_reference = context.input
17
+ @reference_resolver = create_reference_resolver
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :given_reference, :factory, :reference_resolver
23
+
24
+ def validate(_, _)
25
+ return reference_validator.errors unless reference_validator.valid?
26
+ reference_resolver&.errors
27
+ end
28
+
29
+ def build_node(_)
30
+ reference_resolver&.node
31
+ end
32
+
33
+ def reference_validator
34
+ @reference_validator ||= Validators::Reference.new(given_reference)
35
+ end
36
+
37
+ def create_reference_resolver
38
+ return unless given_reference
39
+ context.register_reference(given_reference, factory)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "openapi3_parser/node_factory"
4
+ require "openapi3_parser/validation/error_collection"
4
5
 
5
6
  module Openapi3Parser
6
7
  module NodeFactory
@@ -23,11 +24,10 @@ module Openapi3Parser
23
24
  build_map(data, context)
24
25
  end
25
26
 
26
- def validate_input(error_collection)
27
- super(error_collection)
28
- processed_input.each_value do |value|
29
- next unless value.respond_to?(:errors)
30
- error_collection.merge(value.errors)
27
+ def validate_input
28
+ processed_input.each_value.inject(super) do |memo, value|
29
+ errors = value.respond_to?(:errors) ? value.errors : []
30
+ Validation::ErrorCollection.combine(memo, errors)
31
31
  end
32
32
  end
33
33
 
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "openapi3_parser/context"
3
4
  require "openapi3_parser/node_factory"
4
5
  require "openapi3_parser/node_factory/field_config"
5
6
  require "openapi3_parser/node_factory/object/node_builder"
6
7
  require "openapi3_parser/node_factory/object/validator"
8
+ require "openapi3_parser/validation/error_collection"
7
9
 
8
10
  module Openapi3Parser
9
11
  module NodeFactory
@@ -54,15 +56,14 @@ module Openapi3Parser
54
56
  def process_input(input)
55
57
  field_configs.each_with_object(input.dup) do |(field, config), memo|
56
58
  next unless config.factory?
57
- next_context = context.next_namespace(field)
59
+ next_context = Context.next_field(context, field)
58
60
  memo[field] = config.initialize_factory(next_context, self)
59
61
  end
60
62
  end
61
63
 
62
- def validate_input(error_collection)
63
- super(error_collection)
64
- validator = Validator.new(context.input, self)
65
- error_collection.tap { |ec| ec.append(*validator.errors) }
64
+ def validate_input
65
+ validator = Validator.new(processed_input, self)
66
+ Validation::ErrorCollection.combine(super, validator.errors)
66
67
  end
67
68
 
68
69
  def build_node(input)
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "openapi3_parser/node_factory/object/validator"
3
+ require "openapi3_parser/context"
4
4
  require "openapi3_parser/error"
5
+ require "openapi3_parser/node_factory/object/validator"
5
6
 
6
7
  module Openapi3Parser
7
8
  module NodeFactory
@@ -32,16 +33,16 @@ module Openapi3Parser
32
33
  def check_required_fields
33
34
  fields = Validator.missing_required_fields(input, factory)
34
35
  return if fields.empty?
35
- raise Openapi3Parser::Error,
36
+ raise Openapi3Parser::Error::MissingFields,
36
37
  "Missing required fields for "\
37
- "#{context.stringify_namespace}: #{fields.join(', ')}"
38
+ "#{context.location_summary}: #{fields.join(', ')}"
38
39
  end
39
40
 
40
41
  def check_unexpected_fields
41
42
  fields = Validator.unexpected_fields(input, factory)
42
43
  return if fields.empty?
43
- raise Openapi3Parser::Error,
44
- "Unexpected fields for #{context.stringify_namespace}: "\
44
+ raise Openapi3Parser::Error::UnexpectedFields,
45
+ "Unexpected fields for #{context.location_summary}: "\
45
46
  "#{fields.join(', ')}"
46
47
  end
47
48
 
@@ -53,23 +54,23 @@ module Openapi3Parser
53
54
  end
54
55
 
55
56
  def check_type_error(name, field_config)
56
- field_context = context.next_namespace(name)
57
+ field_context = Context.next_field(context, name)
57
58
  input = context.input.nil? ? nil : context.input[name]
58
59
  error = field_config.input_type_error(input, factory)
59
60
 
60
61
  return unless error
61
- raise Openapi3Parser::Error,
62
+ raise Openapi3Parser::Error::InvalidType,
62
63
  "Invalid type for "\
63
- "#{field_context.stringify_namespace}: #{error}"
64
+ "#{field_context.location_summary}: #{error}"
64
65
  end
65
66
 
66
67
  def check_validation_errors(name, field_config)
67
- field_context = context.next_namespace(name)
68
+ field_context = Context.next_field(context, name)
68
69
  errors = field_config.validation_errors(field_context.input, factory)
69
70
 
70
71
  return unless errors.any?
71
- raise Openapi3Parser::Error,
72
- "Invalid field for #{field_context.stringify_namespace}: "\
72
+ raise Openapi3Parser::Error::InvalidData,
73
+ "Invalid field for #{field_context.location_summary}: "\
73
74
  "#{errors.join(', ')}"
74
75
  end
75
76
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "openapi3_parser/context"
3
4
  require "openapi3_parser/node_factory"
4
5
  require "openapi3_parser/validation/error"
5
6
 
@@ -10,7 +11,9 @@ module Openapi3Parser
10
11
  def self.missing_required_fields(input, factory)
11
12
  configs = factory.field_configs
12
13
  configs.each_with_object([]) do |(name, field_config), memo|
13
- memo << name if field_config.required?(factory) && input[name].nil?
14
+ f = input[name]
15
+ is_nil = f.respond_to?(:nil_input?) ? f.nil_input? : f.nil?
16
+ memo << name if field_config.required?(factory) && is_nil
14
17
  end
15
18
  end
16
19
 
@@ -44,12 +47,17 @@ module Openapi3Parser
44
47
  factory.context
45
48
  end
46
49
 
50
+ def raw_input
51
+ context.input
52
+ end
53
+
47
54
  def missing_required_fields_error
48
55
  fields = self.class.missing_required_fields(input, factory)
49
56
  return unless fields.any?
50
57
  Validation::Error.new(
51
- context.namespace,
52
- "Missing required fields: #{fields.join(', ')}"
58
+ "Missing required fields: #{fields.join(', ')}",
59
+ context,
60
+ factory.class
53
61
  )
54
62
  end
55
63
 
@@ -57,42 +65,45 @@ module Openapi3Parser
57
65
  fields = self.class.unexpected_fields(input, factory)
58
66
  return unless fields.any?
59
67
  Validation::Error.new(
60
- context.namespace,
61
- "Unexpected fields: #{fields.join(', ')}"
68
+ "Unexpected fields: #{fields.join(', ')}",
69
+ context,
70
+ factory.class
62
71
  )
63
72
  end
64
73
 
65
74
  def invalid_field_errors
66
75
  factory.field_configs.inject([]) do |memo, (name, field_config)|
67
- memo + field_errors(name, field_config)
76
+ memo + Array(field_errors(name, field_config))
68
77
  end
69
78
  end
70
79
 
71
80
  def field_errors(name, field_config)
72
81
  field = input[name]
73
- return [] if field.nil?
82
+ return if field.nil?
74
83
  return field.errors.to_a if field.respond_to?(:errors)
75
84
  type_error = build_type_error(name, field_config)
76
- return [type_error] if type_error
85
+ return type_error if type_error
77
86
  build_validation_errors(name, field_config)
78
87
  end
79
88
 
80
89
  def build_type_error(name, field_config)
81
- type_error = field_config.input_type_error(input[name], factory)
90
+ type_error = field_config.input_type_error(raw_input[name], factory)
82
91
  return unless type_error
83
92
  Validation::Error.new(
84
- context.next_namespace(name),
85
- "Invalid type: #{type_error}"
93
+ "Invalid type: #{type_error}",
94
+ Context.next_field(context, name),
95
+ factory.class
86
96
  )
87
97
  end
88
98
 
89
99
  def build_validation_errors(name, field_config)
90
100
  field_config.validation_errors(
91
- input[name], factory
101
+ raw_input[name], factory
92
102
  ).map do |error|
93
103
  Validation::Error.new(
94
- context.next_namespace(name),
95
- "Invalid field: #{error}"
104
+ "Invalid field: #{error}",
105
+ Context.next_field(context, name),
106
+ factory.class
96
107
  )
97
108
  end
98
109
  end
@@ -8,49 +8,47 @@ module Openapi3Parser
8
8
  class Components
9
9
  include Node::Object
10
10
 
11
- # @return [Map] a map of String: {Schema}[../Schema.html] objects
11
+ # @return [Map<String, Schema>]
12
12
  def schemas
13
13
  node_data["schemas"]
14
14
  end
15
15
 
16
- # @return [Map] a map of String: {Response}[./Response.html] objects
16
+ # @return [Map<String, Response>]
17
17
  def responses
18
18
  node_data["responses"]
19
19
  end
20
20
 
21
- # @return [Map] a map of String: {Parameter}[./Parameter.html] objects
21
+ # @return [Map<String, Parameter>]
22
22
  def parameters
23
23
  node_data["parameters"]
24
24
  end
25
25
 
26
- # @return [Map] a map of String: {Example}[../Example.html] objects
26
+ # @return [Map<String, Example>]
27
27
  def examples
28
28
  node_data["examples"]
29
29
  end
30
30
 
31
- # @return [Map] a map of String: {RequestBody}[./RequestBody.html]
32
- # objects
31
+ # @return [Map<String, RequestBody>]
33
32
  def request_bodies
34
33
  node_data["requestBodies"]
35
34
  end
36
35
 
37
- # @return [Map] a map of String: {Header}[./Header.html] objects
36
+ # @return [Map<String, Header>]
38
37
  def headers
39
38
  node_data["headers"]
40
39
  end
41
40
 
42
- # @return [Map] a map of String: {SecurityScheme}[./SecurityScheme.html]
43
- # objects
41
+ # @return [Map<String, SecurityScheme>]
44
42
  def security_schemes
45
43
  node_data["securitySchemes"]
46
44
  end
47
45
 
48
- # @return [Map] a map of String: {Link}[./Link.html] objects
46
+ # @return [Map<String, Link>]
49
47
  def links
50
48
  node_data["links"]
51
49
  end
52
50
 
53
- # @return [Map] a map of String: {Callback}[./Callback.html] objects
51
+ # @return [Map<String, Callback>]
54
52
  def callbacks
55
53
  node_data["callbacks"]
56
54
  end
@@ -13,7 +13,7 @@ module Openapi3Parser
13
13
  node_data["propertyName"]
14
14
  end
15
15
 
16
- # @return [Map] a map of String: String objects
16
+ # @return [Map<String, String>]
17
17
  def mapping
18
18
  node_data["mapping"]
19
19
  end
@@ -13,7 +13,7 @@ module Openapi3Parser
13
13
  node_data["contentType"]
14
14
  end
15
15
 
16
- # @return [Map] a map of String: {Header}[./Header.html] objects
16
+ # @return [Map<String, Header>]
17
17
  def headers
18
18
  node_data["headers"]
19
19
  end
@@ -18,7 +18,7 @@ module Openapi3Parser
18
18
  node_data["operationId"]
19
19
  end
20
20
 
21
- # @return [Map] a map of String: {Parameter}[./Parameter.html] objects
21
+ # @return [Map<String, Parameter>]
22
22
  def parameters
23
23
  node_data["parameters"]
24
24
  end
@@ -18,12 +18,12 @@ module Openapi3Parser
18
18
  node_data["example"]
19
19
  end
20
20
 
21
- # @return [Map] a map of String: {Example}[./Example.html] objects
21
+ # @return [Map<String, Example>]
22
22
  def examples
23
23
  node_data["examples"]
24
24
  end
25
25
 
26
- # @return [Map] a map of String: {Encoding}[./Encoding.html] objects
26
+ # @return [Map<String, Encoding>]
27
27
  def encoding
28
28
  node_data["encoding"]
29
29
  end
@@ -23,7 +23,7 @@ module Openapi3Parser
23
23
  node_data["refreshUrl"]
24
24
  end
25
25
 
26
- # @return [Map] a map of String: String objects
26
+ # @return [Map<String, String>]
27
27
  def scopes
28
28
  node_data["scopes"]
29
29
  end
@@ -20,7 +20,7 @@ module Openapi3Parser
20
20
  node_data["info"]
21
21
  end
22
22
 
23
- # @return [Nodes::Array] A collection of {Server}[./Server.html] objects
23
+ # @return [Nodes::Array<Server>]
24
24
  def servers
25
25
  node_data["servers"]
26
26
  end
@@ -35,13 +35,12 @@ module Openapi3Parser
35
35
  node_data["components"]
36
36
  end
37
37
 
38
- # @return [Nodes::Array] a collection of
39
- # {SecurityRequirement}[./SecurityRequirement.html] objects
38
+ # @return [Nodes::Array<SecurityRequirement>]
40
39
  def security
41
40
  node_data["security"]
42
41
  end
43
42
 
44
- # @return [Nodes::Array] A collection of {Tag}[./Tag.html] objects
43
+ # @return [Nodes::Array<Tag>]
45
44
  def tags
46
45
  node_data["tags"]
47
46
  end
@@ -8,7 +8,7 @@ module Openapi3Parser
8
8
  class Operation
9
9
  include Node::Object
10
10
 
11
- # @return [Nodes::Array] a collection of String objects
11
+ # @return [Nodes::Array<String>]
12
12
  def tags
13
13
  node_data["tags"]
14
14
  end
@@ -33,8 +33,7 @@ module Openapi3Parser
33
33
  node_data["operationId"]
34
34
  end
35
35
 
36
- # @return [Nodes::Array] a collection of {Parameter}[./Parameter.html]
37
- # objects
36
+ # @return [Nodes::Array<Parameter>]
38
37
  def parameters
39
38
  node_data["parameters"]
40
39
  end
@@ -49,8 +48,7 @@ module Openapi3Parser
49
48
  node_data["responses"]
50
49
  end
51
50
 
52
- # @return [Map] a collection of String: {Callback}[./Callback.html]
53
- # objects
51
+ # @return [Map<String, Callback>]
54
52
  def callbacks
55
53
  node_data["callbacks"]
56
54
  end
@@ -60,13 +58,12 @@ module Openapi3Parser
60
58
  node_data["deprecated"]
61
59
  end
62
60
 
63
- # @return [Nodes::Array] a collection of
64
- # {SecurityRequirement}[./SecurityRequirement.html] objects
61
+ # @return [Nodes::Array<SecurityRequirement>]
65
62
  def security
66
63
  node_data["security"]
67
64
  end
68
65
 
69
- # @return [Nodes::Array] a collection of {Server}[./Server.html] objects
66
+ # @return [Nodes::Array<Server>]
70
67
  def servers
71
68
  node_data["servers"]
72
69
  end
@@ -52,12 +52,12 @@ module Openapi3Parser
52
52
  node_data["example"]
53
53
  end
54
54
 
55
- # @return [Map] a map of String: {Example}[../Example.html] objects
55
+ # @return [Map<String, Example>]
56
56
  def examples
57
57
  node_data["examples"]
58
58
  end
59
59
 
60
- # @return [Map] a map of String: {MediaType}[../MediaType.html] objects
60
+ # @return [Map<String, MediaType>]
61
61
  def content
62
62
  node_data["content"]
63
63
  end