Sha256: 019bd4223b4c5579c1f06f7981e43a526e9dc4ddcc0ccd2a46244036e642e3bc

Contents?: true

Size: 1.51 KB

Versions: 1

Compression:

Stored size: 1.51 KB

Contents

# frozen_string_literal: true

require "dry/initializer"
require "dry/schema/constants"

module Dry
  module Schema
    # @api private
    class KeyValidator
      extend Dry::Initializer

      INDEX_REGEX = /\[\d+\]/.freeze
      DIGIT_REGEX = /\A\d+\z/.freeze
      BRACKETS = "[]"

      # @api private
      option :key_map

      # @api private
      def call(result)
        input = result.to_h

        input_paths = key_paths(input)
        key_paths = key_map.to_dot_notation

        input_paths.each do |path|
          error_path =
            if path[INDEX_REGEX]
              key = path.gsub(INDEX_REGEX, BRACKETS)

              unless key_paths.include?(key)
                arr = path.gsub(INDEX_REGEX) { |m| ".#{m[1]}" }
                arr.split(DOT).map { |s| DIGIT_REGEX.match?(s) ? s.to_i : s.to_sym }
              end
            elsif !key_paths.include?(path)
              path
            end

          next unless error_path

          result.add_error([:unexpected_key, [error_path, input]])
        end

        result
      end

      private

      # @api private
      def key_paths(hash)
        hash.flat_map { |key, _|
          case (value = hash[key])
          when Hash
            [key].product(key_paths(hash[key])).map { |keys| keys.join(DOT) }
          when Array
            value.flat_map.with_index { |el, idx|
              key_paths(el).map { |path| ["#{key}[#{idx}]", *path].join(DOT) }
            }
          else
            key.to_s
          end
        }
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
dry-schema-1.5.0 lib/dry/schema/key_validator.rb