openapi3_parser 0.7.0 → 0.8.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.
- checksums.yaml +4 -4
 - data/.gitignore +1 -0
 - data/.rubocop.yml +2 -4
 - data/.travis.yml +11 -0
 - data/CHANGELOG.md +13 -0
 - data/README.md +4 -1
 - data/TODO.md +1 -1
 - data/lib/openapi3_parser.rb +2 -3
 - data/lib/openapi3_parser/array_sentence.rb +1 -0
 - data/lib/openapi3_parser/document.rb +2 -1
 - data/lib/openapi3_parser/node/array.rb +1 -1
 - data/lib/openapi3_parser/node/context.rb +23 -0
 - data/lib/openapi3_parser/node/map.rb +1 -1
 - data/lib/openapi3_parser/node/object.rb +1 -0
 - data/lib/openapi3_parser/node/operation.rb +8 -0
 - data/lib/openapi3_parser/node/path_item.rb +8 -0
 - data/lib/openapi3_parser/node/placeholder.rb +8 -5
 - data/lib/openapi3_parser/node/schema.rb +3 -2
 - data/lib/openapi3_parser/node_factory.rb +1 -1
 - data/lib/openapi3_parser/node_factory/array.rb +34 -26
 - data/lib/openapi3_parser/node_factory/context.rb +9 -2
 - data/lib/openapi3_parser/node_factory/discriminator.rb +2 -0
 - data/lib/openapi3_parser/node_factory/field.rb +2 -0
 - data/lib/openapi3_parser/node_factory/fields/reference.rb +1 -0
 - data/lib/openapi3_parser/node_factory/map.rb +6 -4
 - data/lib/openapi3_parser/node_factory/media_type.rb +1 -0
 - data/lib/openapi3_parser/node_factory/object.rb +4 -1
 - data/lib/openapi3_parser/node_factory/object_factory/dsl.rb +1 -1
 - data/lib/openapi3_parser/node_factory/object_factory/field_config.rb +1 -0
 - data/lib/openapi3_parser/node_factory/object_factory/node_builder.rb +1 -0
 - data/lib/openapi3_parser/node_factory/object_factory/validator.rb +6 -4
 - data/lib/openapi3_parser/node_factory/openapi.rb +2 -0
 - data/lib/openapi3_parser/node_factory/operation.rb +11 -0
 - data/lib/openapi3_parser/node_factory/parameter.rb +2 -0
 - data/lib/openapi3_parser/node_factory/parameter_like.rb +1 -0
 - data/lib/openapi3_parser/node_factory/path_item.rb +27 -5
 - data/lib/openapi3_parser/node_factory/paths.rb +1 -1
 - data/lib/openapi3_parser/node_factory/response.rb +1 -0
 - data/lib/openapi3_parser/node_factory/responses.rb +1 -1
 - data/lib/openapi3_parser/node_factory/schema.rb +3 -0
 - data/lib/openapi3_parser/node_factory/server_variable.rb +1 -0
 - data/lib/openapi3_parser/node_factory/type_checker.rb +6 -0
 - data/lib/openapi3_parser/source.rb +2 -0
 - data/lib/openapi3_parser/source/location.rb +6 -0
 - data/lib/openapi3_parser/source/pointer.rb +5 -0
 - data/lib/openapi3_parser/source_input.rb +2 -0
 - data/lib/openapi3_parser/source_input/file.rb +2 -0
 - data/lib/openapi3_parser/source_input/raw.rb +3 -0
 - data/lib/openapi3_parser/source_input/resolve_next.rb +1 -0
 - data/lib/openapi3_parser/source_input/string_parser.rb +3 -2
 - data/lib/openapi3_parser/source_input/url.rb +2 -0
 - data/lib/openapi3_parser/validation/error.rb +2 -0
 - data/lib/openapi3_parser/validators/component_keys.rb +1 -1
 - data/lib/openapi3_parser/validators/duplicate_parameters.rb +1 -0
 - data/lib/openapi3_parser/validators/email.rb +1 -1
 - data/lib/openapi3_parser/validators/media_type.rb +1 -1
 - data/lib/openapi3_parser/validators/mutually_exclusive_fields.rb +2 -2
 - data/lib/openapi3_parser/validators/reference.rb +2 -0
 - data/lib/openapi3_parser/validators/required_fields.rb +2 -2
 - data/lib/openapi3_parser/validators/unexpected_fields.rb +3 -2
 - data/lib/openapi3_parser/version.rb +1 -1
 - data/openapi3_parser.gemspec +9 -7
 - metadata +44 -16
 
| 
         @@ -19,9 +19,11 @@ module Openapi3Parser 
     | 
|
| 
       19 
19 
     | 
    
         
             
                  def validate_mapping(validatable)
         
     | 
| 
       20 
20 
     | 
    
         
             
                    input = validatable.input
         
     | 
| 
       21 
21 
     | 
    
         
             
                    return if input.empty?
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
       22 
23 
     | 
    
         
             
                    string_keys = input.keys.map(&:class).uniq == [String]
         
     | 
| 
       23 
24 
     | 
    
         
             
                    string_values = input.values.map(&:class).uniq == [String]
         
     | 
| 
       24 
25 
     | 
    
         
             
                    return if string_keys && string_values
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
       25 
27 
     | 
    
         
             
                    validatable.add_error("Expected string keys and string values")
         
     | 
| 
       26 
28 
     | 
    
         
             
                  end
         
     | 
| 
       27 
29 
     | 
    
         
             
                end
         
     | 
| 
         @@ -70,8 +70,10 @@ module Openapi3Parser 
     | 
|
| 
       70 
70 
     | 
    
         | 
| 
       71 
71 
     | 
    
         
             
                    def errors
         
     | 
| 
       72 
72 
     | 
    
         
             
                      return validatable.collection if factory.nil_input?
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
       73 
74 
     | 
    
         
             
                      TypeChecker.validate_type(validatable, type: factory.input_type)
         
     | 
| 
       74 
75 
     | 
    
         
             
                      return validatable.collection if validatable.errors.any?
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
       75 
77 
     | 
    
         
             
                      validate(raise_on_invalid: false)
         
     | 
| 
       76 
78 
     | 
    
         
             
                      validatable.collection
         
     | 
| 
       77 
79 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -60,6 +60,7 @@ module Openapi3Parser 
     | 
|
| 
       60 
60 
     | 
    
         
             
                  def build_data(raw_input)
         
     | 
| 
       61 
61 
     | 
    
         
             
                    use_default = nil_input? || !raw_input.is_a?(::Hash)
         
     | 
| 
       62 
62 
     | 
    
         
             
                    return if use_default && default.nil?
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
       63 
64 
     | 
    
         
             
                    process_data(use_default ? default : raw_input)
         
     | 
| 
       64 
65 
     | 
    
         
             
                  end
         
     | 
| 
       65 
66 
     | 
    
         | 
| 
         @@ -114,8 +115,10 @@ module Openapi3Parser 
     | 
|
| 
       114 
115 
     | 
    
         | 
| 
       115 
116 
     | 
    
         
             
                    def errors
         
     | 
| 
       116 
117 
     | 
    
         
             
                      return validatable.collection if factory.nil_input?
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
       117 
119 
     | 
    
         
             
                      TypeChecker.validate_type(validatable, type: ::Hash)
         
     | 
| 
       118 
120 
     | 
    
         
             
                      return validatable.collection if validatable.errors.any?
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
       119 
122 
     | 
    
         
             
                      collate_errors
         
     | 
| 
       120 
123 
     | 
    
         
             
                      validatable.collection
         
     | 
| 
       121 
124 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -175,12 +178,11 @@ module Openapi3Parser 
     | 
|
| 
       175 
178 
     | 
    
         
             
                    def check_values(raise_on_invalid: false)
         
     | 
| 
       176 
179 
     | 
    
         
             
                      return unless factory.value_input_type
         
     | 
| 
       177 
180 
     | 
    
         | 
| 
       178 
     | 
    
         
            -
                      factory.context.input. 
     | 
| 
      
 181 
     | 
    
         
            +
                      factory.context.input.each do |key, value|
         
     | 
| 
       179 
182 
     | 
    
         
             
                        next if factory.allow_extensions && key.to_s =~ EXTENSION_REGEX
         
     | 
| 
       180 
183 
     | 
    
         | 
| 
       181 
     | 
    
         
            -
                        check_field_type(
         
     | 
| 
       182 
     | 
    
         
            -
             
     | 
| 
       183 
     | 
    
         
            -
                        )
         
     | 
| 
      
 184 
     | 
    
         
            +
                        check_field_type(Context.next_field(factory.context, key, value),
         
     | 
| 
      
 185 
     | 
    
         
            +
                                         raise_on_invalid)
         
     | 
| 
       184 
186 
     | 
    
         
             
                      end
         
     | 
| 
       185 
187 
     | 
    
         
             
                    end
         
     | 
| 
       186 
188 
     | 
    
         | 
| 
         @@ -78,6 +78,7 @@ module Openapi3Parser 
     | 
|
| 
       78 
78 
     | 
    
         
             
                  def build_data(raw_input)
         
     | 
| 
       79 
79 
     | 
    
         
             
                    use_default = nil_input? || !raw_input.is_a?(::Hash)
         
     | 
| 
       80 
80 
     | 
    
         
             
                    return if use_default && default.nil?
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
       81 
82 
     | 
    
         
             
                    process_data(use_default ? default : raw_input)
         
     | 
| 
       82 
83 
     | 
    
         
             
                  end
         
     | 
| 
       83 
84 
     | 
    
         | 
| 
         @@ -85,7 +86,8 @@ module Openapi3Parser 
     | 
|
| 
       85 
86 
     | 
    
         
             
                    field_configs.each_with_object(raw_data.dup) do |(field, config), memo|
         
     | 
| 
       86 
87 
     | 
    
         
             
                      memo[field] = nil unless memo[field]
         
     | 
| 
       87 
88 
     | 
    
         
             
                      next unless config.factory?
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                      next_context = Context.next_field(context, field, memo[field])
         
     | 
| 
       89 
91 
     | 
    
         
             
                      memo[field] = config.initialize_factory(next_context, self)
         
     | 
| 
       90 
92 
     | 
    
         
             
                    end
         
     | 
| 
       91 
93 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -95,6 +97,7 @@ module Openapi3Parser 
     | 
|
| 
       95 
97 
     | 
    
         | 
| 
       96 
98 
     | 
    
         
             
                    data.each_with_object({}) do |(key, value), memo|
         
     | 
| 
       97 
99 
     | 
    
         
             
                      next if value.respond_to?(:nil_input?) && value.nil_input?
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
       98 
101 
     | 
    
         
             
                      memo[key] = if value.respond_to?(:resolved_input)
         
     | 
| 
       99 
102 
     | 
    
         
             
                                    value.resolved_input
         
     | 
| 
       100 
103 
     | 
    
         
             
                                  else
         
     | 
| 
         @@ -31,6 +31,7 @@ module Openapi3Parser 
     | 
|
| 
       31 
31 
     | 
    
         | 
| 
       32 
32 
     | 
    
         
             
                    def node_data(parent_context)
         
     | 
| 
       33 
33 
     | 
    
         
             
                      return build_node_data(parent_context) if empty_and_allowed_to_be?
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
       34 
35 
     | 
    
         
             
                      TypeChecker.raise_on_invalid_type(factory.context, type: ::Hash)
         
     | 
| 
       35 
36 
     | 
    
         
             
                      validate(raise_on_invalid: true)
         
     | 
| 
       36 
37 
     | 
    
         
             
                      build_node_data(parent_context)
         
     | 
| 
         @@ -81,6 +81,7 @@ module Openapi3Parser 
     | 
|
| 
       81 
81 
     | 
    
         
             
                        factory.data.each do |name, field|
         
     | 
| 
       82 
82 
     | 
    
         
             
                          # references can reference themselves and become in a loop
         
     | 
| 
       83 
83 
     | 
    
         
             
                          next if in_recursive_loop?(field)
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
       84 
85 
     | 
    
         
             
                          has_factory_errors = handle_factory_checks(name)
         
     | 
| 
       85 
86 
     | 
    
         | 
| 
       86 
87 
     | 
    
         
             
                          next if has_factory_errors || !field.respond_to?(:errors)
         
     | 
| 
         @@ -108,10 +109,11 @@ module Openapi3Parser 
     | 
|
| 
       108 
109 
     | 
    
         
             
                      def check_field(name, field_config)
         
     | 
| 
       109 
110 
     | 
    
         
             
                        return if factory.raw_input[name].nil?
         
     | 
| 
       110 
111 
     | 
    
         | 
| 
       111 
     | 
    
         
            -
                         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                         
     | 
| 
      
 112 
     | 
    
         
            +
                        context = Context.next_field(factory.context,
         
     | 
| 
      
 113 
     | 
    
         
            +
                                                     name,
         
     | 
| 
      
 114 
     | 
    
         
            +
                                                     factory.raw_input[name])
         
     | 
| 
      
 115 
     | 
    
         
            +
                        field_validatable = Validation::Validatable.new(factory,
         
     | 
| 
      
 116 
     | 
    
         
            +
                                                                        context: context)
         
     | 
| 
       115 
117 
     | 
    
         | 
| 
       116 
118 
     | 
    
         
             
                        valid_input_type = field_config.check_input_type(field_validatable,
         
     | 
| 
       117 
119 
     | 
    
         
             
                                                                         building_node)
         
     | 
| 
         @@ -25,6 +25,10 @@ module Openapi3Parser 
     | 
|
| 
       25 
25 
     | 
    
         
             
                  private
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                  def build_object(data, context)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    if data["servers"].node.empty?
         
     | 
| 
      
 29 
     | 
    
         
            +
                      data["servers"] = path_item_server_data(context)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
       28 
32 
     | 
    
         
             
                    Node::Operation.new(data, context)
         
     | 
| 
       29 
33 
     | 
    
         
             
                  end
         
     | 
| 
       30 
34 
     | 
    
         | 
| 
         @@ -72,6 +76,13 @@ module Openapi3Parser 
     | 
|
| 
       72 
76 
     | 
    
         
             
                    NodeFactory::Array.new(context,
         
     | 
| 
       73 
77 
     | 
    
         
             
                                           value_factory: NodeFactory::Server)
         
     | 
| 
       74 
78 
     | 
    
         
             
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  def path_item_server_data(node_context)
         
     | 
| 
      
 81 
     | 
    
         
            +
                    path_item_servers = node_context.parent_node.node_data["servers"]
         
     | 
| 
      
 82 
     | 
    
         
            +
                    Node::Placeholder.new(path_item_servers.node_factory,
         
     | 
| 
      
 83 
     | 
    
         
            +
                                          "servers",
         
     | 
| 
      
 84 
     | 
    
         
            +
                                          node_context)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
       75 
86 
     | 
    
         
             
                end
         
     | 
| 
       76 
87 
     | 
    
         
             
              end
         
     | 
| 
       77 
88 
     | 
    
         
             
            end
         
     | 
| 
         @@ -47,11 +47,13 @@ module Openapi3Parser 
     | 
|
| 
       47 
47 
     | 
    
         | 
| 
       48 
48 
     | 
    
         
             
                  def default_style
         
     | 
| 
       49 
49 
     | 
    
         
             
                    return "simple" if %w[path header].include?(context.input["in"])
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
       50 
51 
     | 
    
         
             
                    "form"
         
     | 
| 
       51 
52 
     | 
    
         
             
                  end
         
     | 
| 
       52 
53 
     | 
    
         | 
| 
       53 
54 
     | 
    
         
             
                  def validate_in(validatable)
         
     | 
| 
       54 
55 
     | 
    
         
             
                    return if %w[header query cookie path].include?(validatable.input)
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
       55 
57 
     | 
    
         
             
                    validatable.add_error("in can only be header, query, cookie, or path")
         
     | 
| 
       56 
58 
     | 
    
         
             
                  end
         
     | 
| 
       57 
59 
     | 
    
         
             
                end
         
     | 
| 
         @@ -23,11 +23,22 @@ module Openapi3Parser 
     | 
|
| 
       23 
23 
     | 
    
         
             
                  private
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                  def build_object(data, node_context)
         
     | 
| 
       26 
     | 
    
         
            -
                    ref = data.delete("$ref") 
     | 
| 
       27 
     | 
    
         
            -
                     
     | 
| 
      
 26 
     | 
    
         
            +
                    ref = data.delete("$ref")
         
     | 
| 
      
 27 
     | 
    
         
            +
                    context = if node_context.input.keys == %w[$ref]
         
     | 
| 
      
 28 
     | 
    
         
            +
                                referenced_factory = ref.node_factory.referenced_factory
         
     | 
| 
      
 29 
     | 
    
         
            +
                                Node::Context.resolved_reference(
         
     | 
| 
      
 30 
     | 
    
         
            +
                                  node_context,
         
     | 
| 
      
 31 
     | 
    
         
            +
                                  referenced_factory.context
         
     | 
| 
      
 32 
     | 
    
         
            +
                                )
         
     | 
| 
      
 33 
     | 
    
         
            +
                              else
         
     | 
| 
      
 34 
     | 
    
         
            +
                                node_context
         
     | 
| 
      
 35 
     | 
    
         
            +
                              end
         
     | 
| 
       28 
36 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                     
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
      
 37 
     | 
    
         
            +
                    reference_data = ref.nil_input? ? {} : ref.node.node_data
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    data = merge_data(reference_data, data).tap do |d|
         
     | 
| 
      
 40 
     | 
    
         
            +
                      d["servers"] = root_server_data(context) if d["servers"].node.empty?
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
       31 
42 
     | 
    
         | 
| 
       32 
43 
     | 
    
         
             
                    Node::PathItem.new(data, context)
         
     | 
| 
       33 
44 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -57,7 +68,11 @@ module Openapi3Parser 
     | 
|
| 
       57 
68 
     | 
    
         | 
| 
       58 
69 
     | 
    
         
             
                  def merge_data(base, priority)
         
     | 
| 
       59 
70 
     | 
    
         
             
                    base.merge(priority) do |_, old, new|
         
     | 
| 
       60 
     | 
    
         
            -
                      new.nil? ?  
     | 
| 
      
 71 
     | 
    
         
            +
                      if new.nil? || new.respond_to?(:nil_input?) && new.nil_input?
         
     | 
| 
      
 72 
     | 
    
         
            +
                        old
         
     | 
| 
      
 73 
     | 
    
         
            +
                      else
         
     | 
| 
      
 74 
     | 
    
         
            +
                        new
         
     | 
| 
      
 75 
     | 
    
         
            +
                      end
         
     | 
| 
       61 
76 
     | 
    
         
             
                    end
         
     | 
| 
       62 
77 
     | 
    
         
             
                  end
         
     | 
| 
       63 
78 
     | 
    
         | 
| 
         @@ -76,6 +91,13 @@ module Openapi3Parser 
     | 
|
| 
       76 
91 
     | 
    
         
             
                                           value_factory: factory,
         
     | 
| 
       77 
92 
     | 
    
         
             
                                           validate: validate_parameters)
         
     | 
| 
       78 
93 
     | 
    
         
             
                  end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                  def root_server_data(node_context)
         
     | 
| 
      
 96 
     | 
    
         
            +
                    root_servers = node_context.document.root.node_data["servers"]
         
     | 
| 
      
 97 
     | 
    
         
            +
                    Node::Placeholder.new(root_servers.node_factory,
         
     | 
| 
      
 98 
     | 
    
         
            +
                                          "servers",
         
     | 
| 
      
 99 
     | 
    
         
            +
                                          node_context)
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
       79 
101 
     | 
    
         
             
                end
         
     | 
| 
       80 
102 
     | 
    
         
             
              end
         
     | 
| 
       81 
103 
     | 
    
         
             
            end
         
     | 
| 
         @@ -61,6 +61,7 @@ module Openapi3Parser 
     | 
|
| 
       61 
61 
     | 
    
         
             
                  def read_only_or_write_only(validatable)
         
     | 
| 
       62 
62 
     | 
    
         
             
                    input = validatable.input
         
     | 
| 
       63 
63 
     | 
    
         
             
                    return if [input["readOnly"], input["writeOnly"]].uniq != [true]
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
       64 
65 
     | 
    
         
             
                    validatable.add_error("readOnly and writeOnly cannot both be true")
         
     | 
| 
       65 
66 
     | 
    
         
             
                  end
         
     | 
| 
       66 
67 
     | 
    
         | 
| 
         @@ -114,11 +115,13 @@ module Openapi3Parser 
     | 
|
| 
       114 
115 
     | 
    
         
             
                  def additional_properties_input_type(validatable)
         
     | 
| 
       115 
116 
     | 
    
         
             
                    input = validatable.input
         
     | 
| 
       116 
117 
     | 
    
         
             
                    return if [true, false].include?(input) || input.is_a?(Hash)
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
       117 
119 
     | 
    
         
             
                    validatable.add_error("Expected a Boolean or an Object")
         
     | 
| 
       118 
120 
     | 
    
         
             
                  end
         
     | 
| 
       119 
121 
     | 
    
         | 
| 
       120 
122 
     | 
    
         
             
                  def additional_properties_factory(context)
         
     | 
| 
       121 
123 
     | 
    
         
             
                    return context.input if [true, false].include?(context.input)
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
       122 
125 
     | 
    
         
             
                    referenceable_schema(context)
         
     | 
| 
       123 
126 
     | 
    
         
             
                  end
         
     | 
| 
       124 
127 
     | 
    
         
             
                end
         
     | 
| 
         @@ -27,9 +27,11 @@ module Openapi3Parser 
     | 
|
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
                  def validate_type(validatable, context)
         
     | 
| 
       29 
29 
     | 
    
         
             
                    return true unless type
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
       30 
31 
     | 
    
         
             
                    context ||= validatable.context
         
     | 
| 
       31 
32 
     | 
    
         
             
                    valid_type?(context.input).tap do |valid|
         
     | 
| 
       32 
33 
     | 
    
         
             
                      next if valid
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
       33 
35 
     | 
    
         
             
                      validatable.add_error("Invalid type. #{field_error_message}",
         
     | 
| 
       34 
36 
     | 
    
         
             
                                            context)
         
     | 
| 
       35 
37 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -37,9 +39,11 @@ module Openapi3Parser 
     | 
|
| 
       37 
39 
     | 
    
         | 
| 
       38 
40 
     | 
    
         
             
                  def validate_keys(validatable, context)
         
     | 
| 
       39 
41 
     | 
    
         
             
                    return true unless type
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
       40 
43 
     | 
    
         
             
                    context ||= validatable.context
         
     | 
| 
       41 
44 
     | 
    
         
             
                    valid_keys?(context.input).tap do |valid|
         
     | 
| 
       42 
45 
     | 
    
         
             
                      next if valid
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
       43 
47 
     | 
    
         
             
                      validatable.add_error("Invalid keys. #{keys_error_message}",
         
     | 
| 
       44 
48 
     | 
    
         
             
                                            context)
         
     | 
| 
       45 
49 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -47,6 +51,7 @@ module Openapi3Parser 
     | 
|
| 
       47 
51 
     | 
    
         | 
| 
       48 
52 
     | 
    
         
             
                  def raise_on_invalid_type(context)
         
     | 
| 
       49 
53 
     | 
    
         
             
                    return true if !type || valid_type?(context.input)
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
       50 
55 
     | 
    
         
             
                    raise Error::InvalidType,
         
     | 
| 
       51 
56 
     | 
    
         
             
                          "Invalid type for #{context.location_summary}: "\
         
     | 
| 
       52 
57 
     | 
    
         
             
                          "#{field_error_message}"
         
     | 
| 
         @@ -54,6 +59,7 @@ module Openapi3Parser 
     | 
|
| 
       54 
59 
     | 
    
         | 
| 
       55 
60 
     | 
    
         
             
                  def raise_on_invalid_keys(context)
         
     | 
| 
       56 
61 
     | 
    
         
             
                    return true if !type || valid_keys?(context.input)
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
       57 
63 
     | 
    
         
             
                    raise Error::InvalidType,
         
     | 
| 
       58 
64 
     | 
    
         
             
                          "Invalid keys for #{context.location_summary}: "\
         
     | 
| 
       59 
65 
     | 
    
         
             
                          "#{keys_error_message}"
         
     | 
| 
         @@ -93,6 +93,7 @@ module Openapi3Parser 
     | 
|
| 
       93 
93 
     | 
    
         
             
                # @return [Object]
         
     | 
| 
       94 
94 
     | 
    
         
             
                def data_at_pointer(json_pointer)
         
     | 
| 
       95 
95 
     | 
    
         
             
                  return data if json_pointer.empty?
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
       96 
97 
     | 
    
         
             
                  data.dig(*json_pointer) if data.respond_to?(:dig)
         
     | 
| 
       97 
98 
     | 
    
         
             
                end
         
     | 
| 
       98 
99 
     | 
    
         | 
| 
         @@ -104,6 +105,7 @@ module Openapi3Parser 
     | 
|
| 
       104 
105 
     | 
    
         
             
                # @return [String]
         
     | 
| 
       105 
106 
     | 
    
         
             
                def relative_to_root
         
     | 
| 
       106 
107 
     | 
    
         
             
                  return "" if root?
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
       107 
109 
     | 
    
         
             
                  source_input.relative_to(document.root_source.source_input)
         
     | 
| 
       108 
110 
     | 
    
         
             
                end
         
     | 
| 
       109 
111 
     | 
    
         | 
| 
         @@ -1,15 +1,20 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            require "forwardable"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       3 
5 
     | 
    
         
             
            module Openapi3Parser
         
     | 
| 
       4 
6 
     | 
    
         
             
              class Source
         
     | 
| 
       5 
7 
     | 
    
         
             
                # Class used to represent a location within an OpenAPI document.
         
     | 
| 
       6 
8 
     | 
    
         
             
                # It contains a source, which is the source file/data used for the contents
         
     | 
| 
       7 
9 
     | 
    
         
             
                # and the pointer which indicates where in the object like file the data is
         
     | 
| 
       8 
10 
     | 
    
         
             
                class Location
         
     | 
| 
      
 11 
     | 
    
         
            +
                  extend Forwardable
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
       9 
13 
     | 
    
         
             
                  def self.next_field(location, field)
         
     | 
| 
       10 
14 
     | 
    
         
             
                    new(location.source, location.pointer.segments + [field])
         
     | 
| 
       11 
15 
     | 
    
         
             
                  end
         
     | 
| 
       12 
16 
     | 
    
         | 
| 
      
 17 
     | 
    
         
            +
                  def_delegators :pointer, :root?
         
     | 
| 
       13 
18 
     | 
    
         
             
                  attr_reader :source, :pointer
         
     | 
| 
       14 
19 
     | 
    
         | 
| 
       15 
20 
     | 
    
         
             
                  # @param [Openapi3Parser::Source] source
         
     | 
| 
         @@ -21,6 +26,7 @@ module Openapi3Parser 
     | 
|
| 
       21 
26 
     | 
    
         | 
| 
       22 
27 
     | 
    
         
             
                  def ==(other)
         
     | 
| 
       23 
28 
     | 
    
         
             
                    return false unless other.instance_of?(self.class)
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
       24 
30 
     | 
    
         
             
                    source == other.source && pointer == other.pointer
         
     | 
| 
       25 
31 
     | 
    
         
             
                  end
         
     | 
| 
       26 
32 
     | 
    
         | 
| 
         @@ -12,6 +12,7 @@ module Openapi3Parser 
     | 
|
| 
       12 
12 
     | 
    
         
             
                    absolute = fragment[0] == "/"
         
     | 
| 
       13 
13 
     | 
    
         
             
                    segments = fragment.split("/").map do |part|
         
     | 
| 
       14 
14 
     | 
    
         
             
                      next if part == ""
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
       15 
16 
     | 
    
         
             
                      unescaped = CGI.unescape(part.gsub("%20", "+"))
         
     | 
| 
       16 
17 
     | 
    
         
             
                      unescaped.match?(/\A\d+\z/) ? unescaped.to_i : unescaped
         
     | 
| 
       17 
18 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -49,6 +50,10 @@ module Openapi3Parser 
     | 
|
| 
       49 
50 
     | 
    
         
             
                    %{#{self.class.name}(segments: #{segments}, fragment: "#{fragment}")}
         
     | 
| 
       50 
51 
     | 
    
         
             
                  end
         
     | 
| 
       51 
52 
     | 
    
         | 
| 
      
 53 
     | 
    
         
            +
                  def root?
         
     | 
| 
      
 54 
     | 
    
         
            +
                    segments.empty?
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
       52 
57 
     | 
    
         
             
                  class MergePointers
         
     | 
| 
       53 
58 
     | 
    
         
             
                    private_class_method :new
         
     | 
| 
       54 
59 
     | 
    
         | 
| 
         @@ -45,6 +45,7 @@ module Openapi3Parser 
     | 
|
| 
       45 
45 
     | 
    
         
             
                def contents
         
     | 
| 
       46 
46 
     | 
    
         
             
                  raise access_error if access_error
         
     | 
| 
       47 
47 
     | 
    
         
             
                  raise parse_error if parse_error
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
       48 
49 
     | 
    
         
             
                  @contents
         
     | 
| 
       49 
50 
     | 
    
         
             
                end
         
     | 
| 
       50 
51 
     | 
    
         | 
| 
         @@ -61,6 +62,7 @@ module Openapi3Parser 
     | 
|
| 
       61 
62 
     | 
    
         | 
| 
       62 
63 
     | 
    
         
             
                def initialize_contents
         
     | 
| 
       63 
64 
     | 
    
         
             
                  return if access_error
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
       64 
66 
     | 
    
         
             
                  @contents = parse_contents
         
     | 
| 
       65 
67 
     | 
    
         
             
                rescue ::StandardError => e
         
     | 
| 
       66 
68 
     | 
    
         
             
                  @parse_error = Error::UnparsableInput.new(e.message)
         
     |