openapi3_parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +9 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +4 -0
  7. data/Gemfile +5 -0
  8. data/LICENCE +19 -0
  9. data/README.md +32 -0
  10. data/Rakefile +10 -0
  11. data/TODO.md +30 -0
  12. data/lib/openapi3_parser.rb +39 -0
  13. data/lib/openapi3_parser/context.rb +54 -0
  14. data/lib/openapi3_parser/document.rb +48 -0
  15. data/lib/openapi3_parser/error.rb +5 -0
  16. data/lib/openapi3_parser/fields/map.rb +83 -0
  17. data/lib/openapi3_parser/node.rb +115 -0
  18. data/lib/openapi3_parser/node/map.rb +24 -0
  19. data/lib/openapi3_parser/node/object.rb +28 -0
  20. data/lib/openapi3_parser/node_factories/array.rb +105 -0
  21. data/lib/openapi3_parser/node_factories/callback.rb +26 -0
  22. data/lib/openapi3_parser/node_factories/components.rb +83 -0
  23. data/lib/openapi3_parser/node_factories/contact.rb +24 -0
  24. data/lib/openapi3_parser/node_factories/discriminator.rb +31 -0
  25. data/lib/openapi3_parser/node_factories/encoding.rb +34 -0
  26. data/lib/openapi3_parser/node_factories/example.rb +25 -0
  27. data/lib/openapi3_parser/node_factories/external_documentation.rb +23 -0
  28. data/lib/openapi3_parser/node_factories/header.rb +36 -0
  29. data/lib/openapi3_parser/node_factories/info.rb +28 -0
  30. data/lib/openapi3_parser/node_factories/license.rb +22 -0
  31. data/lib/openapi3_parser/node_factories/link.rb +40 -0
  32. data/lib/openapi3_parser/node_factories/map.rb +110 -0
  33. data/lib/openapi3_parser/node_factories/media_type.rb +44 -0
  34. data/lib/openapi3_parser/node_factories/oauth_flow.rb +24 -0
  35. data/lib/openapi3_parser/node_factories/oauth_flows.rb +31 -0
  36. data/lib/openapi3_parser/node_factories/openapi.rb +50 -0
  37. data/lib/openapi3_parser/node_factories/operation.rb +76 -0
  38. data/lib/openapi3_parser/node_factories/parameter.rb +43 -0
  39. data/lib/openapi3_parser/node_factories/parameter/parameter_like.rb +37 -0
  40. data/lib/openapi3_parser/node_factories/path_item.rb +75 -0
  41. data/lib/openapi3_parser/node_factories/paths.rb +32 -0
  42. data/lib/openapi3_parser/node_factories/reference.rb +33 -0
  43. data/lib/openapi3_parser/node_factories/request_body.rb +31 -0
  44. data/lib/openapi3_parser/node_factories/response.rb +45 -0
  45. data/lib/openapi3_parser/node_factories/responses.rb +32 -0
  46. data/lib/openapi3_parser/node_factories/schema.rb +106 -0
  47. data/lib/openapi3_parser/node_factories/security_requirement.rb +25 -0
  48. data/lib/openapi3_parser/node_factories/security_scheme.rb +35 -0
  49. data/lib/openapi3_parser/node_factories/server.rb +32 -0
  50. data/lib/openapi3_parser/node_factories/server_variable.rb +28 -0
  51. data/lib/openapi3_parser/node_factories/tag.rb +24 -0
  52. data/lib/openapi3_parser/node_factories/xml.rb +25 -0
  53. data/lib/openapi3_parser/node_factory.rb +126 -0
  54. data/lib/openapi3_parser/node_factory/field_config.rb +88 -0
  55. data/lib/openapi3_parser/node_factory/map.rb +39 -0
  56. data/lib/openapi3_parser/node_factory/object.rb +80 -0
  57. data/lib/openapi3_parser/node_factory/object/node_builder.rb +85 -0
  58. data/lib/openapi3_parser/node_factory/object/validator.rb +102 -0
  59. data/lib/openapi3_parser/node_factory/optional_reference.rb +23 -0
  60. data/lib/openapi3_parser/nodes/array.rb +26 -0
  61. data/lib/openapi3_parser/nodes/callback.rb +11 -0
  62. data/lib/openapi3_parser/nodes/components.rb +47 -0
  63. data/lib/openapi3_parser/nodes/contact.rb +23 -0
  64. data/lib/openapi3_parser/nodes/discriminator.rb +19 -0
  65. data/lib/openapi3_parser/nodes/encoding.rb +31 -0
  66. data/lib/openapi3_parser/nodes/example.rb +27 -0
  67. data/lib/openapi3_parser/nodes/external_documentation.rb +19 -0
  68. data/lib/openapi3_parser/nodes/header.rb +13 -0
  69. data/lib/openapi3_parser/nodes/info.rb +35 -0
  70. data/lib/openapi3_parser/nodes/license.rb +19 -0
  71. data/lib/openapi3_parser/nodes/link.rb +35 -0
  72. data/lib/openapi3_parser/nodes/map.rb +11 -0
  73. data/lib/openapi3_parser/nodes/media_type.rb +27 -0
  74. data/lib/openapi3_parser/nodes/oauth_flow.rb +27 -0
  75. data/lib/openapi3_parser/nodes/oauth_flows.rb +27 -0
  76. data/lib/openapi3_parser/nodes/openapi.rb +44 -0
  77. data/lib/openapi3_parser/nodes/operation.rb +59 -0
  78. data/lib/openapi3_parser/nodes/parameter.rb +21 -0
  79. data/lib/openapi3_parser/nodes/parameter/parameter_like.rb +53 -0
  80. data/lib/openapi3_parser/nodes/path_item.rb +59 -0
  81. data/lib/openapi3_parser/nodes/paths.rb +11 -0
  82. data/lib/openapi3_parser/nodes/request_body.rb +23 -0
  83. data/lib/openapi3_parser/nodes/response.rb +27 -0
  84. data/lib/openapi3_parser/nodes/responses.rb +15 -0
  85. data/lib/openapi3_parser/nodes/schema.rb +159 -0
  86. data/lib/openapi3_parser/nodes/security_requirement.rb +11 -0
  87. data/lib/openapi3_parser/nodes/security_scheme.rb +44 -0
  88. data/lib/openapi3_parser/nodes/server.rb +25 -0
  89. data/lib/openapi3_parser/nodes/server_variable.rb +23 -0
  90. data/lib/openapi3_parser/nodes/tag.rb +23 -0
  91. data/lib/openapi3_parser/nodes/xml.rb +31 -0
  92. data/lib/openapi3_parser/validation/error.rb +14 -0
  93. data/lib/openapi3_parser/validation/error_collection.rb +36 -0
  94. data/lib/openapi3_parser/version.rb +5 -0
  95. data/openapi3_parser.gemspec +28 -0
  96. metadata +208 -0
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/nodes/server"
4
+ require "openapi3_parser/node_factory/object"
5
+ require "openapi3_parser/node_factories/server_variable"
6
+ require "openapi3_parser/node_factories/map"
7
+
8
+ module Openapi3Parser
9
+ module NodeFactories
10
+ class Server
11
+ include NodeFactory::Object
12
+
13
+ allow_extensions
14
+ field "url", input_type: String, required: true
15
+ field "description", input_type: String
16
+ field "variables", factory: :variables_factory
17
+
18
+ private
19
+
20
+ def build_object(data, context)
21
+ Nodes::Server.new(data, context)
22
+ end
23
+
24
+ def variables_factory(context)
25
+ NodeFactories::Map.new(
26
+ context,
27
+ value_factory: NodeFactories::ServerVariable
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/nodes/server_variable"
4
+ require "openapi3_parser/node_factory/object"
5
+
6
+ module Openapi3Parser
7
+ module NodeFactories
8
+ class ServerVariable
9
+ include NodeFactory::Object
10
+
11
+ allow_extensions
12
+ field "enum", input_type: ::Array, validate: :validate_enum
13
+ field "default", input_type: String, required: true
14
+ field "description", input_type: String
15
+
16
+ private
17
+
18
+ def validate_enum(input)
19
+ return "Expected atleast one value" if input.empty?
20
+ "Expected String values" unless input.map(&:class).uniq == [String]
21
+ end
22
+
23
+ def build_object(data, context)
24
+ Nodes::ServerVariable.new(data, context)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/nodes/tag"
4
+ require "openapi3_parser/node_factory/object"
5
+ require "openapi3_parser/node_factories/external_documentation"
6
+
7
+ module Openapi3Parser
8
+ module NodeFactories
9
+ class Tag
10
+ include NodeFactory::Object
11
+
12
+ allow_extensions
13
+ field "name", input_type: String, required: true
14
+ field "description", input_type: String
15
+ field "externalDocs", factory: NodeFactories::ExternalDocumentation
16
+
17
+ private
18
+
19
+ def build_object(data, context)
20
+ Nodes::Tag.new(data, context)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/nodes/xml"
4
+ require "openapi3_parser/node_factory/object"
5
+
6
+ module Openapi3Parser
7
+ module NodeFactories
8
+ class Xml
9
+ include NodeFactory::Object
10
+
11
+ allow_extensions
12
+ field "name", input_type: String
13
+ field "namespace", input_type: String
14
+ field "prefix", input_type: String
15
+ field "attribute", input_type: :boolean, default: false
16
+ field "wrapped", input_type: :boolean, default: false
17
+
18
+ private
19
+
20
+ def build_object(data, context)
21
+ Nodes::Xml.new(data, context)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/error"
4
+ require "openapi3_parser/validation/error"
5
+ require "openapi3_parser/validation/error_collection"
6
+
7
+ module Openapi3Parser
8
+ module NodeFactory
9
+ module ClassMethods
10
+ def input_type(type)
11
+ @input_type = type
12
+ end
13
+
14
+ def valid_input_type?(type)
15
+ return true unless @input_type
16
+ type.is_a?(@input_type)
17
+ end
18
+
19
+ def expected_input_type
20
+ @input_type
21
+ end
22
+ end
23
+
24
+ def self.included(base)
25
+ base.extend(ClassMethods)
26
+ end
27
+
28
+ EXTENSION_REGEX = /^x-(.*)/
29
+
30
+ attr_reader :context
31
+
32
+ def initialize(context)
33
+ @context = context
34
+ end
35
+
36
+ def valid?
37
+ errors.empty?
38
+ end
39
+
40
+ def errors
41
+ @errors ||= build_errors
42
+ end
43
+
44
+ def node
45
+ @node ||= build_valid_node
46
+ end
47
+
48
+ private
49
+
50
+ def validate(_input, _context); end
51
+
52
+ def validate_input(error_collection)
53
+ add_validation_errors(
54
+ validate(context.input, context),
55
+ error_collection
56
+ )
57
+ end
58
+
59
+ def add_validation_errors(errors, error_collection)
60
+ errors = Array(errors)
61
+ errors.each do |error|
62
+ unless error.is_a?(Validation::Error)
63
+ error = Validation::Error.new(context.namespace, error)
64
+ end
65
+ error_collection.append(error)
66
+ end
67
+ error_collection
68
+ end
69
+
70
+ def build_errors
71
+ error_collection = Validation::ErrorCollection.new
72
+ unless valid_type?
73
+ error = Validation::Error.new(
74
+ context.namespace, "Invalid type. #{validate_type}"
75
+ )
76
+ return error_collection.tap { |ec| ec.append(error) }
77
+ end
78
+ validate_input(error_collection)
79
+ error_collection
80
+ end
81
+
82
+ def build_valid_node
83
+ unless valid_type?
84
+ raise Openapi3Parser::Error,
85
+ "Invalid type for #{context.stringify_namespace}. "\
86
+ "#{validate_type}"
87
+ end
88
+
89
+ validate_before_build
90
+ build_node(processed_input)
91
+ end
92
+
93
+ def validate_before_build
94
+ errors = Array(validate(context.input, context))
95
+ return unless errors.any?
96
+ raise Openapi3Parser::Error,
97
+ "Invalid data for #{context.stringify_namespace}. "\
98
+ "#{errors.join(', ')}"
99
+ end
100
+
101
+ def valid_type?
102
+ validate_type.nil?
103
+ end
104
+
105
+ def validate_type
106
+ valid_type = self.class.valid_input_type?(context.input)
107
+ return "Expected #{self.class.expected_input_type}" unless valid_type
108
+ end
109
+
110
+ def processed_input
111
+ @processed_input ||= process_input(context.input)
112
+ end
113
+
114
+ def process_input(input)
115
+ input
116
+ end
117
+
118
+ def build_node(input)
119
+ input
120
+ end
121
+
122
+ def extension?(key)
123
+ key.match(EXTENSION_REGEX)
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,88 @@
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
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node_factory"
4
+
5
+ module Openapi3Parser
6
+ module NodeFactory
7
+ module Map
8
+ include NodeFactory
9
+
10
+ def self.included(base)
11
+ base.extend(NodeFactory::ClassMethods)
12
+ base.class_eval do
13
+ input_type Hash
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def build_node(input)
20
+ data = input.each_with_object({}) do |(key, value), memo|
21
+ memo[key] = value.respond_to?(:node) ? value.node : value
22
+ end
23
+ build_map(data, context)
24
+ end
25
+
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)
31
+ end
32
+ end
33
+
34
+ def build_map(data, _)
35
+ data
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node_factory"
4
+ require "openapi3_parser/node_factory/field_config"
5
+ require "openapi3_parser/node_factory/object/node_builder"
6
+ require "openapi3_parser/node_factory/object/validator"
7
+
8
+ module Openapi3Parser
9
+ module NodeFactory
10
+ module Object
11
+ include NodeFactory
12
+
13
+ module ClassMethods
14
+ def field(name, **options)
15
+ @field_configs ||= {}
16
+ @field_configs[name] = FieldConfig.new(options)
17
+ end
18
+
19
+ def field_configs
20
+ @field_configs || {}
21
+ end
22
+
23
+ def allow_extensions
24
+ @allow_extensions = true
25
+ end
26
+
27
+ def disallow_extensions
28
+ @allow_extensions = false
29
+ end
30
+
31
+ def allowed_extensions?
32
+ @allow_extensions == true
33
+ end
34
+ end
35
+
36
+ def self.included(base)
37
+ base.extend(NodeFactory::ClassMethods)
38
+ base.extend(ClassMethods)
39
+ base.class_eval do
40
+ input_type Hash
41
+ end
42
+ end
43
+
44
+ def allowed_extensions?
45
+ self.class.allowed_extensions?
46
+ end
47
+
48
+ def field_configs
49
+ self.class.field_configs || {}
50
+ end
51
+
52
+ private
53
+
54
+ def process_input(input)
55
+ field_configs.each_with_object(input.dup) do |(field, config), memo|
56
+ next if !config.factory? || !memo[field]
57
+ next_context = context.next_namespace(field)
58
+ memo[field] = config.initialize_factory(
59
+ next_context, self
60
+ )
61
+ end
62
+ end
63
+
64
+ def validate_input(error_collection)
65
+ super(error_collection)
66
+ validator = Validator.new(processed_input, self)
67
+ error_collection.tap { |ec| ec.append(*validator.errors) }
68
+ end
69
+
70
+ def build_node(input)
71
+ data = NodeBuilder.new(input, self).data
72
+ build_object(data, context)
73
+ end
74
+
75
+ def build_object(data, _context)
76
+ data
77
+ end
78
+ end
79
+ end
80
+ end