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,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/openapi"
4
+ require "openapi3_parser/node_factory/object"
5
+ require "openapi3_parser/node_factory/info"
6
+ require "openapi3_parser/node_factory/array"
7
+ require "openapi3_parser/node_factory/server"
8
+ require "openapi3_parser/node_factory/paths"
9
+ require "openapi3_parser/node_factory/components"
10
+ require "openapi3_parser/node_factory/security_requirement"
11
+ require "openapi3_parser/node_factory/tag"
12
+ require "openapi3_parser/node_factory/external_documentation"
13
+
14
+ module Openapi3Parser
15
+ module NodeFactory
16
+ class Openapi < NodeFactory::Object
17
+ allow_extensions
18
+
19
+ field "openapi", input_type: String, required: true
20
+ field "info", factory: NodeFactory::Info, required: true
21
+ field "servers", factory: :servers_factory
22
+ field "paths", factory: NodeFactory::Paths, required: true
23
+ field "components", factory: NodeFactory::Components
24
+ field "security", factory: :security_factory
25
+ field "tags", factory: :tags_factory
26
+ field "externalDocs", factory: NodeFactory::ExternalDocumentation
27
+
28
+ def can_use_default?
29
+ false
30
+ end
31
+
32
+ private
33
+
34
+ def build_object(data, context)
35
+ Node::Openapi.new(data, context)
36
+ end
37
+
38
+ def servers_factory(context)
39
+ NodeFactory::Array.new(context,
40
+ value_factory: NodeFactory::Server)
41
+ end
42
+
43
+ def security_factory(context)
44
+ NodeFactory::Array.new(context,
45
+ value_factory: NodeFactory::SecurityRequirement)
46
+ end
47
+
48
+ def tags_factory(context)
49
+ validate_unique_tags = lambda do |validatable|
50
+ names = validatable.factory.context.input.map { |i| i["name"] }
51
+ return if names.uniq.count == names.count
52
+
53
+ dupes = names.find_all { |name| names.count(name) > 1 }
54
+ validatable.add_error(
55
+ "Duplicate tag names: #{dupes.uniq.join(', ')}"
56
+ )
57
+ end
58
+
59
+ NodeFactory::Array.new(context,
60
+ value_factory: NodeFactory::Tag,
61
+ validate: validate_unique_tags)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/operation"
4
+ require "openapi3_parser/node_factory/map"
5
+ require "openapi3_parser/node_factory/object"
6
+ require "openapi3_parser/node_factory/optional_reference"
7
+ require "openapi3_parser/node_factory/array"
8
+ require "openapi3_parser/node_factory/external_documentation"
9
+ require "openapi3_parser/node_factory/parameter"
10
+ require "openapi3_parser/node_factory/request_body"
11
+ require "openapi3_parser/node_factory/responses"
12
+ require "openapi3_parser/node_factory/callback"
13
+ require "openapi3_parser/node_factory/server"
14
+ require "openapi3_parser/node_factory/security_requirement"
15
+ require "openapi3_parser/validators/duplicate_parameters"
16
+
17
+ module Openapi3Parser
18
+ module NodeFactory
19
+ class Operation < NodeFactory::Object
20
+ allow_extensions
21
+ field "tags", factory: :tags_factory
22
+ field "summary", input_type: String
23
+ field "description", input_type: String
24
+ field "externalDocs", factory: NodeFactory::ExternalDocumentation
25
+ field "operationId", input_type: String
26
+ field "parameters", factory: :parameters_factory
27
+ field "requestBody", factory: :request_body_factory
28
+ field "responses", factory: NodeFactory::Responses,
29
+ required: true
30
+ field "callbacks", factory: :callbacks_factory
31
+ field "deprecated", input_type: :boolean, default: false
32
+ field "security", factory: :security_factory
33
+ field "servers", factory: :servers_factory
34
+
35
+ private
36
+
37
+ def build_object(data, context)
38
+ Node::Operation.new(data, context)
39
+ end
40
+
41
+ def tags_factory(context)
42
+ NodeFactory::Array.new(context, value_input_type: String)
43
+ end
44
+
45
+ def parameters_factory(context)
46
+ factory = NodeFactory::OptionalReference.new(NodeFactory::Parameter)
47
+
48
+ validate_parameters = lambda do |validatable|
49
+ validatable.add_error(
50
+ Validators::DuplicateParameters.call(
51
+ validatable.factory.resolved_input
52
+ )
53
+ )
54
+ end
55
+
56
+ NodeFactory::Array.new(context,
57
+ value_factory: factory,
58
+ validate: validate_parameters)
59
+ end
60
+
61
+ def request_body_factory(context)
62
+ factory = NodeFactory::RequestBody
63
+ NodeFactory::OptionalReference.new(factory).call(context)
64
+ end
65
+
66
+ def callbacks_factory(context)
67
+ factory = NodeFactory::OptionalReference.new(NodeFactory::Callback)
68
+ NodeFactory::Map.new(context, value_factory: factory)
69
+ end
70
+
71
+ def responses_factory(context)
72
+ factory = NodeFactory::RequestBody
73
+ NodeFactory::OptionalReference.new(factory).call(context)
74
+ end
75
+
76
+ def security_factory(context)
77
+ NodeFactory::Array.new(context,
78
+ value_factory: NodeFactory::SecurityRequirement)
79
+ end
80
+
81
+ def servers_factory(context)
82
+ NodeFactory::Array.new(context,
83
+ value_factory: NodeFactory::Server)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "openapi3_parser/node_factories/reference"
3
+ require "openapi3_parser/node_factory/reference"
4
4
 
5
5
  module Openapi3Parser
6
6
  module NodeFactory
@@ -11,8 +11,12 @@ module Openapi3Parser
11
11
 
12
12
  def call(context)
13
13
  reference = context.input.is_a?(Hash) && context.input["$ref"]
14
- return NodeFactories::Reference.new(context, self) if reference
15
- factory.new(context)
14
+
15
+ if reference
16
+ NodeFactory::Reference.new(context, self)
17
+ else
18
+ factory.new(context)
19
+ end
16
20
  end
17
21
 
18
22
  private
@@ -2,15 +2,14 @@
2
2
 
3
3
  require "openapi3_parser/context"
4
4
  require "openapi3_parser/node/parameter"
5
- require "openapi3_parser/node_factories/parameter/parameter_like"
5
+ require "openapi3_parser/node_factory/parameter_like"
6
6
  require "openapi3_parser/node_factory/object"
7
7
  require "openapi3_parser/validation/error"
8
8
 
9
9
  module Openapi3Parser
10
- module NodeFactories
11
- class Parameter
12
- include NodeFactory::Object
13
- include Parameter::ParameterLike
10
+ module NodeFactory
11
+ class Parameter < NodeFactory::Object
12
+ include ParameterLike
14
13
 
15
14
  allow_extensions
16
15
 
@@ -34,24 +33,19 @@ module Openapi3Parser
34
33
 
35
34
  mutually_exclusive "example", "examples"
36
35
 
37
- private
38
-
39
- def build_object(data, context)
40
- Node::Parameter.new(data, context)
41
- end
42
-
43
- def validate(input, context)
44
- errors = []
45
-
46
- if input["in"] == "path" && !input["required"]
47
- errors << Validation::Error.new(
36
+ validate do |validatable|
37
+ if validatable.input["in"] == "path" && !validatable.input["required"]
38
+ validatable.add_error(
48
39
  "Must be included and true for a path parameter",
49
- Context.next_field(context, "required"),
50
- self.class
40
+ Context.next_field(validatable.context, "required")
51
41
  )
52
42
  end
43
+ end
44
+
45
+ private
53
46
 
54
- errors
47
+ def build_object(data, context)
48
+ Node::Parameter.new(data, context)
55
49
  end
56
50
 
57
51
  def default_style
@@ -59,9 +53,9 @@ module Openapi3Parser
59
53
  "form"
60
54
  end
61
55
 
62
- def validate_in(input)
63
- valid = %w[header query cookie path].include?(input)
64
- "in can only be header, query, cookie, or path" unless valid
56
+ def validate_in(validatable)
57
+ return if %w[header query cookie path].include?(validatable.input)
58
+ validatable.add_error("in can only be header, query, cookie, or path")
65
59
  end
66
60
  end
67
61
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openapi3Parser
4
+ module NodeFactory
5
+ module ParameterLike
6
+ def default_explode
7
+ context.input["style"] == "form"
8
+ end
9
+
10
+ def schema_factory(context)
11
+ factory = NodeFactory::OptionalReference.new(NodeFactory::Schema)
12
+ factory.call(context)
13
+ end
14
+
15
+ def examples_factory(context)
16
+ factory = NodeFactory::OptionalReference.new(NodeFactory::Schema)
17
+ NodeFactory::Map.new(context,
18
+ default: nil,
19
+ value_factory: factory)
20
+ end
21
+
22
+ def content_factory(context)
23
+ NodeFactory::Map.new(context,
24
+ default: nil,
25
+ value_factory: NodeFactory::MediaType,
26
+ validate: method(:validate_content))
27
+ end
28
+
29
+ def validate_content(validatable)
30
+ return if validatable.input.size == 1
31
+ validatable.add_error("Must only have one item")
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ # These are in the footer as a cyclic dependency can stop this module loading
38
+ require "openapi3_parser/node_factory/optional_reference"
39
+ require "openapi3_parser/node_factory/map"
40
+ require "openapi3_parser/node_factory/schema"
41
+ require "openapi3_parser/node_factory/example"
42
+ require "openapi3_parser/node_factory/media_type"
@@ -3,19 +3,17 @@
3
3
  require "openapi3_parser/node/path_item"
4
4
  require "openapi3_parser/node_factory/fields/reference"
5
5
  require "openapi3_parser/node_factory/object"
6
- require "openapi3_parser/node_factory/object/node_builder"
6
+ require "openapi3_parser/node_factory/object_factory/node_builder"
7
7
  require "openapi3_parser/node_factory/optional_reference"
8
- require "openapi3_parser/node_factories/array"
9
- require "openapi3_parser/node_factories/server"
10
- require "openapi3_parser/node_factories/operation"
11
- require "openapi3_parser/node_factories/parameter"
8
+ require "openapi3_parser/node_factory/array"
9
+ require "openapi3_parser/node_factory/server"
10
+ require "openapi3_parser/node_factory/operation"
11
+ require "openapi3_parser/node_factory/parameter"
12
12
  require "openapi3_parser/validators/duplicate_parameters"
13
13
 
14
14
  module Openapi3Parser
15
- module NodeFactories
16
- class PathItem
17
- include NodeFactory::Object
18
-
15
+ module NodeFactory
16
+ class PathItem < NodeFactory::Object
19
17
  allow_extensions
20
18
  field "$ref", input_type: String, factory: :ref_factory
21
19
  field "summary", input_type: String
@@ -31,10 +29,6 @@ module Openapi3Parser
31
29
  field "servers", factory: :servers_factory
32
30
  field "parameters", factory: :parameters_factory
33
31
 
34
- def node_data
35
- NodeBuilder.new(processed_input, self).data
36
- end
37
-
38
32
  private
39
33
 
40
34
  def build_object(data, context)
@@ -45,44 +39,48 @@ module Openapi3Parser
45
39
  end
46
40
 
47
41
  def ref_factory(context)
48
- Fields::Reference.new(context, self.class)
42
+ NodeFactory::Fields::Reference.new(context, self.class)
49
43
  end
50
44
 
51
45
  def operation_factory(context)
52
- NodeFactories::Operation.new(context)
46
+ NodeFactory::Operation.new(context)
53
47
  end
54
48
 
55
49
  def servers_factory(context)
56
- NodeFactories::Array.new(
50
+ NodeFactory::Array.new(
57
51
  context,
58
- value_factory: NodeFactories::Server
52
+ value_factory: NodeFactory::Server
59
53
  )
60
54
  end
61
55
 
62
56
  def build_resolved_input
63
- ref = processed_input["$ref"]
64
- data = super.tap { |d| d.delete("$ref") }
65
- return data unless ref
57
+ ref = data["$ref"]
58
+ data_without_ref = super.tap { |d| d.delete("$ref") }
59
+ return data_without_ref unless ref
66
60
 
67
- merge_data(ref.data || {}, data)
61
+ merge_data(ref.resolved_input || {}, data_without_ref)
68
62
  end
69
63
 
70
64
  def merge_data(base, priority)
71
- base.merge(priority) do |_, new, old|
65
+ base.merge(priority) do |_, old, new|
72
66
  new.nil? ? old : new
73
67
  end
74
68
  end
75
69
 
76
70
  def parameters_factory(context)
77
- factory = NodeFactory::OptionalReference.new(NodeFactories::Parameter)
78
-
79
- validate = lambda do |_input, array_factory|
80
- Validators::DuplicateParameters.call(array_factory.resolved_input)
71
+ factory = NodeFactory::OptionalReference.new(NodeFactory::Parameter)
72
+
73
+ validate_parameters = lambda do |validatable|
74
+ validatable.add_error(
75
+ Validators::DuplicateParameters.call(
76
+ validatable.factory.resolved_input
77
+ )
78
+ )
81
79
  end
82
80
 
83
- NodeFactories::Array.new(context,
84
- value_factory: factory,
85
- validate: validate)
81
+ NodeFactory::Array.new(context,
82
+ value_factory: factory,
83
+ validate: validate_parameters)
86
84
  end
87
85
  end
88
86
  end
@@ -2,13 +2,12 @@
2
2
 
3
3
  require "openapi3_parser/node_factory/map"
4
4
  require "openapi3_parser/node_factory/optional_reference"
5
- require "openapi3_parser/node_factories/path_item"
5
+ require "openapi3_parser/node_factory/path_item"
6
6
  require "openapi3_parser/node/paths"
7
7
 
8
8
  module Openapi3Parser
9
- module NodeFactories
10
- class Paths
11
- include NodeFactory::Map
9
+ module NodeFactory
10
+ class Paths < NodeFactory::Map
12
11
  PATH_REGEX = %r{
13
12
  \A
14
13
  # required prefix slash
@@ -24,46 +23,41 @@ module Openapi3Parser
24
23
  \Z
25
24
  }x
26
25
 
27
- private
26
+ def initialize(context)
27
+ factory = NodeFactory::OptionalReference.new(NodeFactory::PathItem)
28
28
 
29
- def process_input(input)
30
- input.each_with_object({}) do |(key, value), memo|
31
- memo[key] = value if extension?(key)
32
- next_context = Context.next_field(context, key)
33
- memo[key] = child_factory(next_context)
34
- end
29
+ super(context,
30
+ allow_extensions: true,
31
+ value_factory: factory,
32
+ validate: :validate)
35
33
  end
36
34
 
37
- def child_factory(child_context)
38
- NodeFactory::OptionalReference.new(NodeFactories::PathItem)
39
- .call(child_context)
40
- end
35
+ private
41
36
 
42
- def build_map(data, context)
37
+ def build_node(data)
43
38
  Node::Paths.new(data, context)
44
39
  end
45
40
 
46
- def validate(input, _context)
47
- paths = input.keys.reject { |key| extension?(key) }
48
- validate_paths(paths)
41
+ def validate(validatable)
42
+ paths = validatable.input.keys.reject do |key|
43
+ NodeFactory::EXTENSION_REGEX =~ key
44
+ end
45
+ validate_paths(validatable, paths)
49
46
  end
50
47
 
51
- def validate_paths(paths)
48
+ def validate_paths(validatable, paths)
52
49
  invalid_paths = paths.reject { |p| PATH_REGEX.match(p) }
53
- errors = []
54
50
  unless invalid_paths.empty?
55
51
  joined = invalid_paths.map { |p| "'#{p}'" }.join(", ")
56
- errors << %(There are invalid paths: #{joined})
52
+ validatable.add_error("There are invalid paths: #{joined}")
57
53
  end
58
54
 
59
55
  conflicts = conflicting_paths(paths)
60
56
 
61
- unless conflicts.empty?
62
- joined = conflicts.map { |p| "'#{p}'" }.join(", ")
63
- errors << %(There are paths that conflict: #{joined})
64
- end
57
+ return if conflicts.empty?
65
58
 
66
- errors
59
+ joined = conflicts.map { |p| "'#{p}'" }.join(", ")
60
+ validatable.add_error("There are paths that conflict: #{joined}")
67
61
  end
68
62
 
69
63
  def conflicting_paths(paths)