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
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "openapi3_parser/node/openapi"
4
- require "openapi3_parser/node_factory/object"
5
- require "openapi3_parser/node_factories/info"
6
- require "openapi3_parser/node_factories/array"
7
- require "openapi3_parser/node_factories/server"
8
- require "openapi3_parser/node_factories/paths"
9
- require "openapi3_parser/node_factories/components"
10
- require "openapi3_parser/node_factories/security_requirement"
11
- require "openapi3_parser/node_factories/tag"
12
- require "openapi3_parser/node_factories/external_documentation"
13
-
14
- module Openapi3Parser
15
- module NodeFactories
16
- class Openapi
17
- include NodeFactory::Object
18
-
19
- allow_extensions
20
- disallow_default
21
-
22
- field "openapi", input_type: String, required: true
23
- field "info", factory: NodeFactories::Info, required: true
24
- field "servers", factory: :servers_factory
25
- field "paths", factory: NodeFactories::Paths, required: true
26
- field "components", factory: NodeFactories::Components
27
- field "security", factory: :security_factory
28
- field "tags", factory: :tags_factory
29
- field "externalDocs", factory: NodeFactories::ExternalDocumentation
30
-
31
- private
32
-
33
- def build_object(data, context)
34
- Node::Openapi.new(data, context)
35
- end
36
-
37
- def servers_factory(context)
38
- NodeFactories::Array.new(context, value_factory: NodeFactories::Server)
39
- end
40
-
41
- def security_factory(context)
42
- NodeFactories::Array.new(
43
- context, value_factory: NodeFactories::SecurityRequirement
44
- )
45
- end
46
-
47
- def tags_factory(context)
48
- validate_unique_tags = lambda do |input, _context|
49
- names = input.map { |i| i["name"] }
50
- return if names.uniq.count == names.count
51
-
52
- dupes = names.find_all { |name| names.count(name) > 1 }
53
- "Duplicate tag names: #{dupes.uniq.join(', ')}"
54
- end
55
-
56
- NodeFactories::Array.new(context,
57
- value_factory: NodeFactories::Tag,
58
- validate: validate_unique_tags)
59
- end
60
- end
61
- end
62
- end
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "openapi3_parser/node/operation"
4
- require "openapi3_parser/node_factory/object"
5
- require "openapi3_parser/node_factory/optional_reference"
6
- require "openapi3_parser/node_factories/array"
7
- require "openapi3_parser/node_factories/external_documentation"
8
- require "openapi3_parser/node_factories/parameter"
9
- require "openapi3_parser/node_factories/request_body"
10
- require "openapi3_parser/node_factories/responses"
11
- require "openapi3_parser/node_factories/callback"
12
- require "openapi3_parser/node_factories/server"
13
- require "openapi3_parser/node_factories/security_requirement"
14
- require "openapi3_parser/validators/duplicate_parameters"
15
-
16
- module Openapi3Parser
17
- module NodeFactories
18
- class Operation
19
- include NodeFactory::Object
20
-
21
- allow_extensions
22
- field "tags", factory: :tags_factory
23
- field "summary", input_type: String
24
- field "description", input_type: String
25
- field "externalDocs", factory: NodeFactories::ExternalDocumentation
26
- field "operationId", input_type: String
27
- field "parameters", factory: :parameters_factory
28
- field "requestBody", factory: :request_body_factory
29
- field "responses", factory: NodeFactories::Responses,
30
- required: true
31
- field "callbacks", factory: :callbacks_factory
32
- field "deprecated", input_type: :boolean, default: false
33
- field "security", factory: :security_factory
34
- field "servers", factory: :servers_factory
35
-
36
- private
37
-
38
- def build_object(data, context)
39
- Node::Operation.new(data, context)
40
- end
41
-
42
- def tags_factory(context)
43
- NodeFactories::Array.new(context, value_input_type: String)
44
- end
45
-
46
- def parameters_factory(context)
47
- factory = NodeFactory::OptionalReference.new(NodeFactories::Parameter)
48
-
49
- validate = lambda do |_input, array_factory|
50
- Validators::DuplicateParameters.call(array_factory.resolved_input)
51
- end
52
-
53
- NodeFactories::Array.new(context,
54
- value_factory: factory,
55
- validate: validate)
56
- end
57
-
58
- def request_body_factory(context)
59
- factory = NodeFactories::RequestBody
60
- NodeFactory::OptionalReference.new(factory).call(context)
61
- end
62
-
63
- def callbacks_factory(context)
64
- factory = NodeFactory::OptionalReference.new(NodeFactories::Callback)
65
- NodeFactories::Map.new(context, value_factory: factory)
66
- end
67
-
68
- def responses_factory(context)
69
- factory = NodeFactories::RequestBody
70
- NodeFactory::OptionalReference.new(factory).call(context)
71
- end
72
-
73
- def security_factory(context)
74
- NodeFactories::Array.new(
75
- context, value_factory: NodeFactories::SecurityRequirement
76
- )
77
- end
78
-
79
- def servers_factory(context)
80
- NodeFactories::Array.new(context, value_factory: NodeFactories::Server)
81
- end
82
- end
83
- end
84
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Openapi3Parser
4
- module NodeFactories
5
- class Parameter
6
- module ParameterLike
7
- def default_explode
8
- context.input["style"] == "form"
9
- end
10
-
11
- def schema_factory(context)
12
- factory = NodeFactory::OptionalReference.new(NodeFactories::Schema)
13
- factory.call(context)
14
- end
15
-
16
- def examples_factory(context)
17
- factory = NodeFactory::OptionalReference.new(NodeFactories::Schema)
18
- NodeFactories::Map.new(context, default: nil, value_factory: factory)
19
- end
20
-
21
- def content_factory(context)
22
- NodeFactories::Map.new(context,
23
- default: nil,
24
- value_factory: NodeFactories::MediaType,
25
- validate: method(:validate_content).to_proc)
26
- end
27
-
28
- def validate_content(input, _context)
29
- "Must only have one item" unless input.size == 1
30
- end
31
- end
32
- end
33
- end
34
- end
35
-
36
- # These are in the footer as a cyclic dependency can stop this module loading
37
- require "openapi3_parser/node_factory/optional_reference"
38
- require "openapi3_parser/node_factories/schema"
39
- require "openapi3_parser/node_factories/map"
40
- require "openapi3_parser/node_factories/example"
41
- require "openapi3_parser/node_factories/media_type"
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "openapi3_parser/node_factory/object"
4
- require "openapi3_parser/node_factory/fields/reference"
5
-
6
- module Openapi3Parser
7
- module NodeFactories
8
- class Reference
9
- include NodeFactory::Object
10
-
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
- private
21
-
22
- def build_node(input)
23
- input["$ref"].node
24
- end
25
-
26
- def ref_factory(context)
27
- Fields::Reference.new(context, factory)
28
- end
29
-
30
- def build_resolved_input
31
- processed_input["$ref"].data
32
- end
33
- end
34
- end
35
- end
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "openapi3_parser/context"
4
- require "openapi3_parser/node_factories/response"
5
- require "openapi3_parser/node_factory/map"
6
- require "openapi3_parser/node_factory/optional_reference"
7
- require "openapi3_parser/node/responses"
8
-
9
- module Openapi3Parser
10
- module NodeFactories
11
- class Responses
12
- include NodeFactory::Map
13
-
14
- KEY_REGEX = /
15
- \A
16
- (
17
- default
18
- |
19
- [1-5]([0-9][0-9]|XX)
20
- )
21
- \Z
22
- /x
23
-
24
- private
25
-
26
- def process_input(input)
27
- input.each_with_object({}) do |(key, value), memo|
28
- memo[key] = value if extension?(key)
29
- next_context = Context.next_field(context, key)
30
- memo[key] = child_factory(next_context)
31
- end
32
- end
33
-
34
- def child_factory(child_context)
35
- NodeFactory::OptionalReference.new(NodeFactories::Response)
36
- .call(child_context)
37
- end
38
-
39
- def build_map(data, context)
40
- Node::Responses.new(data, context)
41
- end
42
-
43
- def validate(input, _context)
44
- validate_keys(input.keys)
45
- end
46
-
47
- def validate_keys(keys)
48
- invalid = keys.reject do |key|
49
- extension?(key) || KEY_REGEX.match(key)
50
- end
51
-
52
- return if invalid.empty?
53
-
54
- codes = invalid.map { |k| "'#{k}'" }.join(", ")
55
- "Invalid responses keys: #{codes} - default, status codes and status "\
56
- "code ranges allowed"
57
- end
58
- end
59
- end
60
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "openapi3_parser/node/security_requirement"
4
- require "openapi3_parser/node_factory/map"
5
- require "openapi3_parser/node_factories/array"
6
-
7
- module Openapi3Parser
8
- module NodeFactories
9
- class SecurityRequirement
10
- include NodeFactory::Map
11
-
12
- private
13
-
14
- def process_input(input)
15
- input.keys.each_with_object({}) do |key, memo|
16
- next_context = Context.next_field(context, key)
17
- memo[key] = NodeFactories::Array.new(next_context)
18
- end
19
- end
20
-
21
- def build_map(data, context)
22
- Node::SecurityRequirement.new(data, context)
23
- end
24
- end
25
- end
26
- end
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "openapi3_parser/error"
4
-
5
- module Openapi3Parser
6
- module NodeFactory
7
- class FieldConfig
8
- attr_reader :given_input_type, :given_factory, :given_required,
9
- :given_default, :given_validate
10
-
11
- def initialize(
12
- input_type: nil,
13
- factory: nil,
14
- required: false,
15
- default: nil,
16
- validate: nil
17
- )
18
- @given_input_type = input_type
19
- @given_factory = factory
20
- @given_required = required
21
- @given_default = default
22
- @given_validate = validate
23
- end
24
-
25
- def factory?
26
- !given_factory.nil?
27
- end
28
-
29
- def initialize_factory(context, factory)
30
- if given_factory.is_a?(Class)
31
- given_factory.new(context)
32
- elsif given_factory.is_a?(Symbol)
33
- factory.send(given_factory, context)
34
- else
35
- given_factory.call(context)
36
- end
37
- end
38
-
39
- def required?(_factory)
40
- given_required
41
- end
42
-
43
- def input_type_error(input, factory)
44
- return if !given_input_type || input.nil?
45
- return boolean_error(input) if given_input_type == :boolean
46
- resolve_type_error(input, factory)
47
- end
48
-
49
- def validation_errors(input, factory)
50
- return [] if !given_validate || input.nil?
51
- errors = resolve_validation_errors(input, factory)
52
- Array(errors)
53
- end
54
-
55
- def default(factory)
56
- return given_default.call if given_default.is_a?(Proc)
57
- return factory.send(given_default) if given_default.is_a?(Symbol)
58
- given_default
59
- end
60
-
61
- private
62
-
63
- def boolean_error(input)
64
- "Expected a boolean" unless [true, false].include?(input)
65
- end
66
-
67
- def resolve_type_error(input, factory)
68
- if given_input_type.is_a?(Proc)
69
- given_input_type.call(input)
70
- elsif given_input_type.is_a?(Symbol)
71
- factory.send(given_input_type, input)
72
- elsif !input.is_a?(given_input_type)
73
- "Expected a #{given_input_type}"
74
- end
75
- end
76
-
77
- def resolve_validation_errors(input, factory)
78
- if given_validate.is_a?(Proc)
79
- given_validate.call(input)
80
- elsif given_validate.is_a?(Symbol)
81
- factory.send(given_validate, input)
82
- else
83
- raise Error, "Expected a Proc or Symbol for validate"
84
- end
85
- end
86
- end
87
- end
88
- end
@@ -1,97 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "openapi3_parser/context"
4
- require "openapi3_parser/error"
5
- require "openapi3_parser/node_factory/object/validator"
6
-
7
- module Openapi3Parser
8
- module NodeFactory
9
- module Object
10
- class NodeBuilder
11
- def initialize(input, factory)
12
- @input = input
13
- @factory = factory
14
- end
15
-
16
- def data
17
- check_required_fields
18
- check_unexpected_fields
19
- check_fields_valid
20
- input.each_with_object({}) do |(key, value), memo|
21
- memo[key] = resolve_value(key, value)
22
- end
23
- end
24
-
25
- private
26
-
27
- attr_reader :input, :factory
28
-
29
- def context
30
- factory.context
31
- end
32
-
33
- def check_required_fields
34
- fields = Validator.missing_required_fields(input, factory)
35
- return if fields.empty?
36
- raise Openapi3Parser::Error::MissingFields,
37
- "Missing required fields for "\
38
- "#{context.location_summary}: #{fields.join(', ')}"
39
- end
40
-
41
- def check_unexpected_fields
42
- fields = Validator.unexpected_fields(input, factory)
43
- return if fields.empty?
44
- raise Openapi3Parser::Error::UnexpectedFields,
45
- "Unexpected fields for #{context.location_summary}: "\
46
- "#{fields.join(', ')}"
47
- end
48
-
49
- def check_fields_valid
50
- factory.field_configs.each do |name, field_config|
51
- check_type_error(name, field_config)
52
- check_validation_errors(name, field_config)
53
- end
54
- end
55
-
56
- def check_type_error(name, field_config)
57
- field_context = Context.next_field(context, name)
58
- input = context.input.nil? ? nil : context.input[name]
59
- error = field_config.input_type_error(input, factory)
60
-
61
- return unless error
62
- raise Openapi3Parser::Error::InvalidType,
63
- "Invalid type for "\
64
- "#{field_context.location_summary}: #{error}"
65
- end
66
-
67
- def check_validation_errors(name, field_config)
68
- field_context = Context.next_field(context, name)
69
- errors = field_config.validation_errors(field_context.input, factory)
70
-
71
- return unless errors.any?
72
- raise Openapi3Parser::Error::InvalidData,
73
- "Invalid field for #{field_context.location_summary}: "\
74
- "#{errors.join(', ')}"
75
- end
76
-
77
- def resolve_value(key, value)
78
- configs = factory.field_configs
79
- return configs[key]&.default(factory) if value.nil?
80
- default_value(configs[key], value)
81
- end
82
-
83
- def default_value(config, value)
84
- resolved_value = value.respond_to?(:node) ? value.node : value
85
-
86
- # let a field config default take precedence if value is a nil_input?
87
- if value.respond_to?(:nil_input?) && value.nil_input?
88
- default = config&.default(factory)
89
- default.nil? ? resolved_value : default
90
- else
91
- resolved_value
92
- end
93
- end
94
- end
95
- end
96
- end
97
- end