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
@@ -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