def validate(type, options, attrs, required, opts)
        validator_class = Validations.require_validator(type)
        validator_instance = validator_class.new(
          attrs,
          options,
          required,
          self,
          opts
        )
        @api.inheritable_setting.namespace_stackable[:validations] = validator_instance
      end


# frozen_string_literal: true

module Grape
  module Validations
    class ParamsScope
      attr_reader :parent, :type, :nearest_array_ancestor, :full_path

      def qualifying_params
        ParamScopeTracker.current&.qualifying_params(self)
      end

      include Grape::DSL::Parameters
      include Grape::Validations::ParamsDocumentation

      # There are a number of documentation options on entities that don't have
      # corresponding validators. Since there is nowhere that enumerates them all,
      # we maintain a list of them here and skip looking up validators for them.
      RESERVED_DOCUMENTATION_KEYWORDS = %i[as required param_type is_array format example].freeze

      SPECIAL_JSON = [JSON, Array[JSON]].freeze

      class Attr
        attr_reader :key, :scope

        # Open up a new ParamsScope::Attr
        # @param key [Hash, Symbol] key of attr
        # @param scope [Grape::Validations::ParamsScope] scope of attr
        def initialize(key, scope)
          @key = key
          @scope = scope
        end

        # @return Array[Symbol, Hash[Symbol => Array]] declared_params with symbol instead of Attr
        def self.attrs_keys(declared_params)
          declared_params.map do |declared_param_attr|
            attr_key(declared_param_attr)
          end
        end

        def self.attr_key(declared_param_attr)
          case declared_param_attr
          when self
            attr_key(declared_param_attr.key)
          when Hash
            declared_param_attr.transform_values { |value| attrs_keys(value) }
          else
            declared_param_attr
          end
        end
      end

      # Open up a new ParamsScope, allowing parameter definitions per
      #   Grape::DSL::Params.
      # @param api [API] the API endpoint to modify
      # @param element [Symbol] the element that contains this scope; for
      #   this to be relevant, parent must be set
      # @param element_renamed [Symbol, nil] whenever this scope should
      #   be renamed and to what, given +nil+ no renaming is done
      # @param parent [ParamsScope] the scope containing this scope
      # @param optional [Boolean] whether or not this scope needs to have
      #   any parameters set or not
      # @param type [Class] a type meant to govern this scope (deprecated)
      # @param type [Hash] group options for this scope
      # @param dependent_on [Symbol] if present, this scope should only
      #   validate if this param is present in the parent scope
      # @yield the instance context, open for parameter definitions
      def initialize(api:, element: nil, element_renamed: nil, parent: nil, optional: false, type: nil, group: nil, dependent_on: nil, &block)
        @element          = element
        @element_renamed  = element_renamed
        @parent           = parent
        @api              = api
        @optional         = optional
        @type             = type
        @group            = group
        @dependent_on     = dependent_on
        # Must be an ivar: push_declared_params is dispatched on self during
        # instance_eval, so local variables from initialize are unreachable.
        # configure_declared_params consumes it and clears @declared_params to nil.
        @declared_params = []
        @full_path = build_full_path

        instance_eval(&block) if block

        configure_declared_params
        @nearest_array_ancestor = find_nearest_array_ancestor
        freeze
      end

      def configuration
        config = @api.configuration
        config.is_a?(Grape::Util::Lazy::Base) ? config.evaluate : config
      end

      # @return [Boolean] whether or not this entire scope needs to be
      #   validated
      def should_validate?(parameters)
        scoped_params = params(parameters)

        return false if @optional && (scoped_params.blank? || all_element_blank?(scoped_params))
        return false unless meets_dependency?(scoped_params, parameters)
        return true if @parent.nil?

        @parent.should_validate?(parameters)
      end

      def meets_dependency?(params, request_params)
        return true unless @dependent_on
        return false if @parent.present? && !@parent.meets_dependency?(@parent.params(request_params), request_params)

        if params.is_a?(Array)
          filtered = params.flatten.filter { |param| meets_dependency?(param, request_params) }
          ParamScopeTracker.current&.store_qualifying_params(self, filtered)
          return filtered.present?
        end

        meets_hash_dependency?(params)
      end

      def attr_meets_dependency?(params)
        return true unless @dependent_on
        return false if @parent.present? && !@parent.attr_meets_dependency?(params)

        meets_hash_dependency?(params)
      end

      def meets_hash_dependency?(params)
        # params might be anything what looks like a hash, so it must implement a `key?` method
        return false unless params.respond_to?(:key?)

        @dependent_on.all? do |dependency|
          if dependency.is_a?(Hash)
            key, callable = dependency.first
            callable.call(params[key])
          else
            params[dependency].present?
          end
        end
      end

      # @return [String] the proper attribute name, with nesting considered.
      def full_name(name, index: nil)
        tracker = ParamScopeTracker.current
        if nested?
          # Find our containing element's name, and append ours.
          resolved_index = index || tracker&.index_for(self)
          "#{@parent.full_name(@element)}#{brackets(resolved_index)}#{brackets(name)}"
        elsif lateral?
          # Find the name of the element as if it was at the same nesting level
          # as our parent. We need to forward our index upward to achieve this.
          @parent.full_name(name, index: tracker&.index_for(self))
        else
          # We must be the root scope, so no prefix needed.
          name.to_s
        end
      end

      def brackets(val)
        "[#{val}]" if val
      end

      # @return [Boolean] whether or not this scope is the root-level scope
      def root?
        !@parent
      end

      # A nested scope is contained in one of its parent's elements.
      # @return [Boolean] whether or not this scope is nested
      def nested?
        @parent && @element
      end

      # A lateral scope is subordinate to its parent, but its keys are at the
      # same level as its parent and thus is not contained within an element.
      # @return [Boolean] whether or not this scope is lateral
      def lateral?
        @parent && !@element
      end

      # @return [Boolean] whether or not this scope needs to be present, or can
      #   be blank
      def required?
        !@optional
      end

      protected

      # Adds a parameter declaration to our list of validations.
      # @param attrs [Array] (see Grape::DSL::Parameters#requires)
      def push_declared_params(attrs, **opts)
        opts[:declared_params_scope] = self unless opts.key?(:declared_params_scope)
        return @parent.push_declared_params(attrs, **opts) if lateral?

        push_renamed_param(full_path + [attrs.first], opts[:as]) if opts[:as]
        @declared_params.concat(attrs.map { |attr| ::Grape::Validations::ParamsScope::Attr.new(attr, opts[:declared_params_scope]) })
      end

      private

      def build_full_path
        if nested?
          @parent.full_path + [@element]
        elsif lateral?
          @parent.full_path
        else
          []
        end
      end

      # Add a new parameter which should be renamed when using the +#declared+
      # method.
      #
      # @param path [Array<String, Symbol>] the full path of the parameter
      #   (including the parameter name as last array element)
      # @param new_name [String, Symbol] the new name of the parameter (the
      #   renamed name, with the +as: ...+ semantic)
      def push_renamed_param(path, new_name)
        api_route_setting = @api.inheritable_setting.route
        base = api_route_setting[:renamed_params] || {}
        base[Array(path).map(&:to_s)] = new_name.to_s
        api_route_setting[:renamed_params] = base
      end

      def require_required_and_optional_fields(context, using:, except: nil)
        except_fields = Array.wrap(except)
        using_fields = using.keys.delete_if { |f| except_fields.include?(f) }

        if context == :all
          optional_fields = except_fields
          required_fields = using_fields
        else # context == :none
          required_fields = except_fields
          optional_fields = using_fields
        end
        required_fields.each do |field|
          field_opts = using[field]
          raise ArgumentError, "required field not exist: #{field}" unless field_opts

          requires(field, **field_opts)
        end
        optional_fields.each do |field|
          field_opts = using[field]
          optional(field, **field_opts) if field_opts
        end
      end

      def require_optional_fields(context, using:, except: nil)
        optional_fields = using.keys
        unless context == :all
          except_fields = Array.wrap(except)
          optional_fields.delete_if { |f| except_fields.include?(f) }
        end
        optional_fields.each do |field|
          field_opts = using[field]
          optional(field, **field_opts) if field_opts
        end
      end

      def validate_attributes(attrs, **opts, &block)
        opts[:type] ||= Array if block
        validates(attrs, opts)
      end

      # Returns a new parameter scope, subordinate to the current one and nested
      # under the given element.
      # @param element [Symbol] the parameter name under which this scope is nested
      # @param type [Class] the type governing this scope
      # @param as [Symbol, nil] optional renamed name for the element
      # @param optional [Boolean] whether the parameter this scope is nested under
      #   is optional or not (and hence, whether this block's params will be).
      # @yield parameter scope
      def new_scope(element, type:, as:, optional: false, &)
        # if required params are grouped and no type or unsupported type is provided, raise an error
        if element && !optional
          raise Grape::Exceptions::MissingGroupType if type.nil?
          raise Grape::Exceptions::UnsupportedGroupType unless Grape::Validations::Types.group?(type)
        end

        self.class.new(
          api: @api,
          element:,
          element_renamed: as,
          parent: self,
          optional:,
          type: type || Array,
          group: @group,
          &
        )
      end

      # Returns a new parameter scope, not nested under any current-level param
      # but instead at the same level as the current scope.
      # @param dependent_on [Symbol] if given, specifies that this scope should
      #   only validate if this parameter from the above scope is present
      # @yield parameter scope
      def new_lateral_scope(dependent_on:, &)
        self.class.new(
          api: @api,
          parent: self,
          optional: @optional,
          type: type == Array ? Array : Hash,
          dependent_on:,
          &
        )
      end

      # Returns a new parameter scope, subordinate to the current one, sharing
      # the given group options with all parameters defined within.
      # @param group [Hash] common options to merge into each parameter in the scope
      # @yield parameter scope
      def new_group_scope(group, &)
        self.class.new(api: @api, parent: self, group:, &)
      end

      # Pushes declared params to parent or settings, then clears @declared_params.
      # Clearing here (rather than in initialize) keeps the lifecycle ownership in
      # one place: this method both consumes and invalidates the ivar so that
      # push_declared_params cannot be called on the frozen scope later.
      def configure_declared_params
        push_renamed_param(full_path, @element_renamed) if @element_renamed

        if nested?
          @parent.push_declared_params [{ @element => @declared_params }]
        else
          @api.inheritable_setting.namespace_stackable[:declared_params] = @declared_params
        end
      ensure
        @declared_params = nil
      end

      def find_nearest_array_ancestor
        scope = @parent
        scope = scope.parent while scope && scope.type != Array
        scope
      end

      def validates(attrs, validations)
        coerce_type = infer_coercion(validations)
        required = validations.key?(:presence)
        default = validations[:default]
        values = validations[:values].is_a?(Hash) ? validations.dig(:values, :value) : validations[:values]
        except_values = validations[:except_values].is_a?(Hash) ? validations.dig(:except_values, :value) : validations[:except_values]

        # NB. values and excepts should be nil, Proc, Array, or Range.
        # Specifically, values should NOT be a Hash
        # use values or excepts to guess coerce type when stated type is Array
        coerce_type = guess_coerce_type(coerce_type, values, except_values)

        # default value should be present in values array, if both exist and are not procs
        check_incompatible_option_values(default, values, except_values)

        # type should be compatible with values array, if both exist
        validate_value_coercion(coerce_type, values, except_values)

        document_params attrs, validations, coerce_type, values, except_values

        opts = derive_validator_options(validations).freeze

        # Validate for presence before any other validators
        validates_presence(validations, attrs, opts)

        # Before we run the rest of the validators, let's handle
        # whatever coercion so that we are working with correctly
        # type casted values
        coerce_type validations.extract!(:coerce, :coerce_with, :coerce_message), attrs, required, opts

        validations.each do |type, options|
          # Don't try to look up validators for documentation params that don't have one.
          next if RESERVED_DOCUMENTATION_KEYWORDS.include?(type)

          validate(type, options, attrs, required, opts)
        end
      end

      # Validate and comprehend the +:type+, +:types+, and +:coerce_with+
      # options that have been supplied to the parameter declaration.
      # The +:type+ and +:types+ options will be removed from the
      # validations list, replaced appropriately with +:coerce+ and
      # +:coerce_with+ options that will later be passed to
      # {Validators::CoerceValidator}. The type that is returned may be
      # used for documentation and further validation of parameter
      # options.
      #
      # @param validations [Hash] list of validations supplied to the
      #   parameter declaration
      # @return [class-like] type to which the parameter will be coerced
      # @raise [ArgumentError] if the given type options are invalid
      def infer_coercion(validations)
        raise ArgumentError, ':type may not be supplied with :types' if validations.key?(:type) && validations.key?(:types)

        validations[:coerce] = (options_key?(:type, :value, validations) ? validations[:type][:value] : validations[:type]) if validations.key?(:type)
        validations[:coerce_message] = (options_key?(:type, :message, validations) ? validations[:type][:message] : nil) if validations.key?(:type)
        validations[:coerce] = (options_key?(:types, :value, validations) ? validations[:types][:value] : validations[:types]) if validations.key?(:types)
        validations[:coerce_message] = (options_key?(:types, :message, validations) ? validations[:types][:message] : nil) if validations.key?(:types)

        validations.delete(:types) if validations.key?(:types)

        coerce_type = validations[:coerce]

        # Special case - when the argument is a single type that is a
        # variant-type collection.
        if Types.multiple?(coerce_type) && validations.key?(:type)
          validations[:coerce] = Types::VariantCollectionCoercer.new(
            coerce_type,
            validations.delete(:coerce_with)
          )
        end
        validations.delete(:type)

        coerce_type
      end

      # Enforce correct usage of :coerce_with parameter.
      # We do not allow coercion without a type, nor with
      # +JSON+ as a type since this defines its own coercion
      # method.
      def check_coerce_with(validations)
        return unless validations.key?(:coerce_with)
        # type must be supplied for coerce_with..
        raise ArgumentError, 'must supply type for coerce_with' unless validations.key?(:coerce)

        # but not special JSON types, which
        # already imply coercion method
        return unless SPECIAL_JSON.include?(validations[:coerce])

        raise ArgumentError, 'coerce_with disallowed for type: JSON'
      end

      # Add type coercion validation to this scope,
      # if any has been specified.
      # This validation has special handling since it is
      # composited from more than one +requires+/+optional+
      # parameter, and needs to be run before most other
      # validations.
      def coerce_type(validations, attrs, required, opts)
        check_coerce_with(validations)

        # Falsy check (not key?) is intentional: when a remountable API is first
        # evaluated on its base instance (no configuration supplied yet),
        # configuration[:some_type] evaluates to nil. Skipping instantiation
        # here is correct — the real mounted instance will replay this step with
        # the actual type value.
        return unless validations[:coerce]

        coerce_options = {
          type: validations[:coerce],
          method: validations[:coerce_with],
          message: validations[:coerce_message]
        }
        validate('coerce', coerce_options, attrs, required, opts)
      end

      def guess_coerce_type(coerce_type, *values_list)
        return coerce_type unless coerce_type == Array

        values_list.each do |values|
          next if !values || values.is_a?(Proc)
          return values.first.class if values.is_a?(Range) || !values.empty?
        end
        coerce_type
      end

      def check_incompatible_option_values(default, values, except_values)
        return unless default && !default.is_a?(Proc)

        raise Grape::Exceptions::IncompatibleOptionValues.new(:default, default, :values, values) if values && !values.is_a?(Proc) && !Array(default).all? { |def_val| values.include?(def_val) }

        return unless except_values && !except_values.is_a?(Proc) && Array(default).any? { |def_val| except_values.include?(def_val) }

        raise Grape::Exceptions::IncompatibleOptionValues.new(:default, default, :except, except_values)
      end

      def validate(type, options, attrs, required, opts)
        validator_class = Validations.require_validator(type)
        validator_instance = validator_class.new(
          attrs,
          options,
          required,
          self,
          opts
        )
        @api.inheritable_setting.namespace_stackable[:validations] = validator_instance
      end

      def validate_value_coercion(coerce_type, *values_list)
        return unless coerce_type

        coerce_type = coerce_type.first if coerce_type.is_a?(Enumerable)
        values_list.each do |values|
          next if !values || values.is_a?(Proc)

          value_types = values.is_a?(Range) ? [values.begin, values.end].compact : values
          value_types = value_types.map { |type| Grape::API::Boolean.build(type) } if coerce_type == Grape::API::Boolean
          raise Grape::Exceptions::IncompatibleOptionValues.new(:type, coerce_type, :values, values) unless value_types.all?(coerce_type)
        end
      end

      def options_key?(type, key, validations)
        validations[type].respond_to?(:key?) && validations[type].key?(key) && !validations[type][key].nil?
      end

      def all_element_blank?(scoped_params)
        scoped_params.respond_to?(:all?) && scoped_params.all?(&:blank?)
      end

      # Validators don't have access to each other and they don't need, however,
      # some validators might influence others, so their options should be shared
      def derive_validator_options(validations)
        allow_blank = validations[:allow_blank]

        {
          allow_blank: allow_blank.is_a?(Hash) ? allow_blank[:value] : allow_blank,
          fail_fast: validations.delete(:fail_fast) || false
        }
      end

      def validates_presence(validations, attrs, opts)
        return unless validations.key?(:presence) && validations[:presence]

        validate('presence', validations.delete(:presence), attrs, true, opts)
        validations.delete(:message) if validations.key?(:message)
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Validations
    class AttributesIterator
      include Enumerable

      attr_reader :scope

      def initialize(attrs, scope, params)
        @attrs = attrs
        @scope = scope
        @original_params = scope.params(params)
        @params = Array.wrap(@original_params)
      end

      def each(&)
        do_each(@params, &) # because we need recursion for nested arrays
      end

      private

      def do_each(params_to_process, parent_indices = [], &block)
        params_to_process.each_with_index do |resource_params, index|
          # when we get arrays of arrays it means that target element located inside array
          # we need this because we want to know parent arrays indices
          if resource_params.is_a?(Array)
            do_each(resource_params, [index] + parent_indices, &block)
            next
          end

          if @scope.type == Array
            next unless @original_params.is_a?(Array) # do not validate content of array if it isn't array

            store_indices(@scope, index, parent_indices)
          elsif @original_params.is_a?(Array)
            # Lateral scope (no @element) whose params resolved to an array —
            # delegate index tracking to the nearest array-typed ancestor so
            # that full_name produces the correct bracketed index.
            target = @scope.nearest_array_ancestor
            store_indices(target, index, parent_indices) if target
          end

          yield_attributes(resource_params, &block)
        end
      end

      def store_indices(target_scope, index, parent_indices)
        # No tracker means we're outside a ParamScopeTracker.track block (e.g.
        # a unit test that invokes a validator directly). Index tracking is
        # skipped — full_name will produce bracket-less names — but validation
        # continues rather than crashing.
        tracker = ParamScopeTracker.current or return
        parent_scope = target_scope.parent
        parent_indices.each do |parent_index|
          break unless parent_scope

          tracker.store_index(parent_scope, parent_index)
          parent_scope = parent_scope.parent
        end
        tracker.store_index(target_scope, index)
      end

      def yield_attributes(_resource_params)
        raise NotImplementedError
      end

      # This is a special case so that we can ignore trees where option
      # values are missing lower down. Unfortunately we can't remove this
      # at the parameter parsing stage as they are required to ensure
      # the correct indexing is maintained
      def skip?(val)
        val == Grape::DSL::Parameters::EmptyOptionalValue
      end
    end
  end
end


def store_indices(target_scope, index, parent_indices)
        # No tracker means we're outside a ParamScopeTracker.track block (e.g.
        # a unit test that invokes a validator directly). Index tracking is
        # skipped — full_name will produce bracket-less names — but validation
        # continues rather than crashing.
        tracker = ParamScopeTracker.current or return
        parent_scope = target_scope.parent
        parent_indices.each do |parent_index|
          break unless parent_scope

          tracker.store_index(parent_scope, parent_index)
          parent_scope = parent_scope.parent
        end
        tracker.store_index(target_scope, index)
      end


# frozen_string_literal: true

module Grape
  module Middleware
    # Class to handle the stack of middlewares based on ActionDispatch::MiddlewareStack
    # It allows to insert and insert after
    class Stack
      extend Forwardable

      class Middleware
        attr_reader :args, :block, :klass

        def initialize(klass, args, block)
          @klass = klass
          @args = args
          @block = block
        end

        def name
          klass.name
        end

        def ==(other)
          case other
          when Middleware
            klass == other.klass
          when Class
            klass == other || (name.nil? && klass.superclass == other)
          end
        end

        def inspect
          klass.to_s
        end

        def build(builder)
          # we need to force the ruby2_keywords_hash for middlewares that initialize contains keywords
          # like ActionDispatch::RequestId since middleware arguments are serialized
          # https://rubyapi.org/3.4/o/hash#method-c-ruby2_keywords_hash
          args[-1] = Hash.ruby2_keywords_hash(args[-1]) if args.last.is_a?(Hash) && Hash.respond_to?(:ruby2_keywords_hash)
          builder.use(klass, *args, &block)
        end
      end

      include Enumerable

      attr_accessor :middlewares, :others

      def_delegators :middlewares, :each, :size, :last, :[]

      def initialize
        @middlewares = []
        @others = []
      end

      def insert(index, klass, *args, &block)
        index = assert_index(index, :before)
        middlewares.insert(index, self.class::Middleware.new(klass, args, block))
      end

      alias insert_before insert

      def insert_after(index, ...)
        index = assert_index(index, :after)
        insert(index + 1, ...)
      end

      def use(klass, *args, &block)
        middleware = self.class::Middleware.new(klass, args, block)
        middlewares.push(middleware)
      end

      def merge_with(middleware_specs)
        middleware_specs.each do |operation, klass, *args|
          if args.last.is_a?(Proc)
            last_proc = args.pop
            public_send(operation, klass, *args, &last_proc)
          else
            public_send(operation, klass, *args)
          end
        end
      end

      # @return [Rack::Builder] the builder object with our middlewares applied
      def build
        Rack::Builder.new.tap do |builder|
          others.shift(others.size).each { |m| merge_with(m) }
          middlewares.each do |m|
            m.build(builder)
          end
        end
      end

      # @description Add middlewares with :use operation to the stack. Store others with :insert_* operation for later
      # @param [Array] other_specs An array of middleware specifications (e.g. [[:use, klass], [:insert_before, *args]])
      def concat(other_specs)
        use, not_use = other_specs.partition { |o| o.first == :use }
        others << not_use
        merge_with(use)
      end

      protected

      def assert_index(index, where)
        i = index.is_a?(Integer) ? index : middlewares.index(index)
        i || raise("No such middleware to insert #{where}: #{index.inspect}")
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Middleware
    class Formatter < Base
      include PrecomputedContentTypes

      DEFAULT_OPTIONS = {
        default_format: :txt
      }.freeze

      ALL_MEDIA_TYPES = '*/*'

      def before
        negotiate_content_type
        read_body_input
      end

      def after
        return unless @app_response

        status, headers, bodies = *@app_response

        if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status)
          [status, headers, []]
        else
          build_formatted_response(status, headers, bodies)
        end
      end

      private

      def build_formatted_response(status, headers, bodies)
        headers = ensure_content_type(headers)

        if bodies.is_a?(Grape::ServeStream::StreamResponse)
          Grape::ServeStream::SendfileResponse.new([], status, headers) do |resp|
            resp.body = bodies.stream
          end
        else
          # Allow content-type to be explicitly overwritten
          formatter = fetch_formatter(headers, options)
          bodymap = ActiveSupport::Notifications.instrument('format_response.grape', formatter:, env:) do
            bodies.map { |body| formatter.call(body, env) }
          end
          Rack::Response.new(bodymap, status, headers)
        end
      rescue Grape::Exceptions::InvalidFormatter => e
        throw :error, status: 500, message: e.message, backtrace: e.backtrace, original_exception: e
      end

      def fetch_formatter(headers, options)
        api_format = env.fetch(Grape::Env::API_FORMAT) { mime_types[headers[Rack::CONTENT_TYPE]] }
        Grape::Formatter.formatter_for(api_format, options[:formatters])
      end

      # Set the content type header for the API format if it is not already present.
      #
      # @param headers [Hash]
      # @return [Hash]
      def ensure_content_type(headers)
        return headers if headers[Rack::CONTENT_TYPE]

        headers.merge(Rack::CONTENT_TYPE => content_type_for(env[Grape::Env::API_FORMAT]))
      end

      def read_body_input
        input = rack_request.body # reads RACK_INPUT
        return if input.nil?
        return unless read_body_input?

        rewind = input.respond_to?(:rewind)

        input.rewind if rewind
        body = env[Grape::Env::API_REQUEST_INPUT] = input.read
        begin
          read_rack_input(body)
        ensure
          input.rewind if rewind
        end
      end

      def read_rack_input(body)
        return if body.empty?

        media_type = rack_request.media_type
        fmt = media_type ? mime_types[media_type] : options[:default_format]

        throw :error, status: 415, message: "The provided content-type '#{media_type}' is not supported." unless content_type_for(fmt)
        parser = Grape::Parser.parser_for fmt, options[:parsers]
        return env[Grape::Env::API_REQUEST_BODY] = body unless parser

        begin
          body = (env[Grape::Env::API_REQUEST_BODY] = parser.call(body, env))
          if body.is_a?(Hash)
            env[Rack::RACK_REQUEST_FORM_HASH] = if env.key?(Rack::RACK_REQUEST_FORM_HASH)
                                                  env[Rack::RACK_REQUEST_FORM_HASH].merge(body)
                                                else
                                                  body
                                                end
            env[Rack::RACK_REQUEST_FORM_INPUT] = env[Rack::RACK_INPUT]
          end
        rescue Grape::Exceptions::Base => e
          raise e
        rescue StandardError => e
          throw :error, status: 400, message: e.message, backtrace: e.backtrace, original_exception: e
        end
      end

      # this middleware will not try to format the following content-types since Rack already handles them
      # when calling Rack's `params` function
      # - application/x-www-form-urlencoded
      # - multipart/form-data
      # - multipart/related
      # - multipart/mixed
      def read_body_input?
        (rack_request.post? || rack_request.put? || rack_request.patch? || rack_request.delete?) &&
          !(rack_request.form_data? && rack_request.content_type) &&
          !rack_request.parseable_data? &&
          (rack_request.content_length.to_i.positive? || rack_request.env['HTTP_TRANSFER_ENCODING'] == 'chunked')
      end

      def negotiate_content_type
        fmt = format_from_extension || query_params['format'] || options[:format] || format_from_header || options[:default_format]
        if content_type_for(fmt)
          env[Grape::Env::API_FORMAT] = fmt.to_sym
        else
          throw :error, status: 406, message: "The requested format '#{fmt}' is not supported."
        end
      end

      def format_from_extension
        request_path = try_scrub(rack_request.path)
        dot_pos = request_path.rindex('.')
        return unless dot_pos

        extension = request_path[(dot_pos + 1)..]
        extension if content_type_for(extension)
      end

      def format_from_header
        accept_header = try_scrub(env['HTTP_ACCEPT'])
        return if accept_header.blank? || accept_header == ALL_MEDIA_TYPES

        media_type = Rack::Utils.best_q_match(accept_header, mime_types.keys)
        mime_types[media_type] if media_type
      end
    end
  end
end


def read_body_input
        input = rack_request.body # reads RACK_INPUT
        return if input.nil?
        return unless read_body_input?

        rewind = input.respond_to?(:rewind)

        input.rewind if rewind
        body = env[Grape::Env::API_REQUEST_INPUT] = input.read
        begin
          read_rack_input(body)
        ensure
          input.rewind if rewind
        end
      end


def read_rack_input(body)
        return if body.empty?

        media_type = rack_request.media_type
        fmt = media_type ? mime_types[media_type] : options[:default_format]

        throw :error, status: 415, message: "The provided content-type '#{media_type}' is not supported." unless content_type_for(fmt)
        parser = Grape::Parser.parser_for fmt, options[:parsers]
        return env[Grape::Env::API_REQUEST_BODY] = body unless parser

        begin
          body = (env[Grape::Env::API_REQUEST_BODY] = parser.call(body, env))
          if body.is_a?(Hash)
            env[Rack::RACK_REQUEST_FORM_HASH] = if env.key?(Rack::RACK_REQUEST_FORM_HASH)
                                                  env[Rack::RACK_REQUEST_FORM_HASH].merge(body)
                                                else
                                                  body
                                                end
            env[Rack::RACK_REQUEST_FORM_INPUT] = env[Rack::RACK_INPUT]
          end
        rescue Grape::Exceptions::Base => e
          raise e
        rescue StandardError => e
          throw :error, status: 400, message: e.message, backtrace: e.backtrace, original_exception: e
        end
      end


# frozen_string_literal: true

module Grape
  module Middleware
    class Error < Base
      include PrecomputedContentTypes

      DEFAULT_OPTIONS = {
        default_status: 500,
        default_message: '',
        format: :txt,
        rescue_all: false,
        rescue_grape_exceptions: false,
        rescue_subclasses: true,
        rescue_options: {
          backtrace: false,
          original_exception: false
        }.freeze
      }.freeze

      def call!(env)
        @env = env
        error_response(catch(:error) { return @app.call(@env) })
      rescue Exception => e # rubocop:disable Lint/RescueException
        run_rescue_handler(find_handler(e.class), e, @env[Grape::Env::API_ENDPOINT])
      end

      private

      def rack_response(status, headers, message)
        message = Rack::Utils.escape_html(message) if headers[Rack::CONTENT_TYPE] == 'text/html'
        Rack::Response.new(Array.wrap(message), Rack::Utils.status_code(status), Grape::Util::Header.new.merge(headers))
      end

      def format_message(message, backtrace, original_exception = nil)
        format = env[Grape::Env::API_FORMAT] || options[:format]
        formatter = Grape::ErrorFormatter.formatter_for(format, options[:error_formatters], options[:default_error_formatter])
        return formatter.call(message, backtrace, options, env, original_exception) if formatter

        throw :error,
              status: 406,
              message: "The requested format '#{format}' is not supported.",
              backtrace:,
              original_exception:
      end

      def find_handler(klass)
        registered_rescue_handler(klass) ||
          rescue_handler_for_grape_exception(klass) ||
          rescue_handler_for_any_class(klass) ||
          raise
      end

      def error_response(error = {})
        status = error[:status] || options[:default_status]
        env[Grape::Env::API_ENDPOINT].status(status) # error! may not have been called
        message = error[:message] || options[:default_message]
        headers = { Rack::CONTENT_TYPE => content_type }.tap do |h|
          h.merge!(error[:headers]) if error[:headers].is_a?(Hash)
        end
        backtrace = error[:backtrace] || error[:original_exception]&.backtrace || []
        original_exception = error.is_a?(Exception) ? error : error[:original_exception]
        rack_response(status, headers, format_message(message, backtrace, original_exception))
      end

      def default_rescue_handler(exception)
        error_response(message: exception.message, backtrace: exception.backtrace, original_exception: exception)
      end

      def registered_rescue_handler(klass)
        rescue_handler_from(:base_only_rescue_handlers) { |err| klass == err } ||
          rescue_handler_from(:rescue_handlers) { |err| klass <= err }
      end

      def rescue_handler_from(key)
        error, handler = options[key]&.find { |err, _handler| yield(err) }

        return unless error

        handler || method(:default_rescue_handler)
      end

      def rescue_handler_for_grape_exception(klass)
        return unless klass <= Grape::Exceptions::Base
        return method(:error_response) if klass == Grape::Exceptions::InvalidVersionHeader
        return unless options[:rescue_grape_exceptions] || !options[:rescue_all]

        options[:grape_exceptions_rescue_handler] || method(:error_response)
      end

      def rescue_handler_for_any_class(klass)
        return unless klass <= StandardError
        return unless options[:rescue_all] || options[:rescue_grape_exceptions]

        options[:all_rescue_handler] || method(:default_rescue_handler)
      end

      def run_rescue_handler(handler, error, endpoint)
        handler = endpoint.public_method(handler) if handler.instance_of?(Symbol)
        response = catch(:error) do
          handler.arity.zero? ? endpoint.instance_exec(&handler) : endpoint.instance_exec(error, &handler)
        end

        if error?(response)
          error_response(response)
        elsif response.is_a?(Rack::Response)
          response
        else
          run_rescue_handler(method(:default_rescue_handler), Grape::Exceptions::InvalidResponse.new, endpoint)
        end
      end

      def error!(message, status = options[:default_status], headers = {}, backtrace = [], original_exception = nil)
        env[Grape::Env::API_ENDPOINT].status(status) # not error! inside route
        rack_response(
          status, headers.reverse_merge(Rack::CONTENT_TYPE => content_type),
          format_message(message, backtrace, original_exception)
        )
      end

      def error?(response)
        return false unless response.is_a?(Hash)

        response.key?(:message) && response.key?(:status) && response.key?(:headers)
      end
    end
  end
end


def error_response(error = {})
        status = error[:status] || options[:default_status]
        env[Grape::Env::API_ENDPOINT].status(status) # error! may not have been called
        message = error[:message] || options[:default_message]
        headers = { Rack::CONTENT_TYPE => content_type }.tap do |h|
          h.merge!(error[:headers]) if error[:headers].is_a?(Hash)
        end
        backtrace = error[:backtrace] || error[:original_exception]&.backtrace || []
        original_exception = error.is_a?(Exception) ? error : error[:original_exception]
        rack_response(status, headers, format_message(message, backtrace, original_exception))
      end


def run_rescue_handler(handler, error, endpoint)
        handler = endpoint.public_method(handler) if handler.instance_of?(Symbol)
        response = catch(:error) do
          handler.arity.zero? ? endpoint.instance_exec(&handler) : endpoint.instance_exec(error, &handler)
        end

        if error?(response)
          error_response(response)
        elsif response.is_a?(Rack::Response)
          response
        else
          run_rescue_handler(method(:default_rescue_handler), Grape::Exceptions::InvalidResponse.new, endpoint)
        end
      end


# frozen_string_literal: true

module Grape
  module Middleware
    class Base
      include Grape::DSL::Headers

      attr_reader :app, :env, :options

      # @param [Rack Application] app The standard argument for a Rack middleware.
      # @param [Hash] options A hash of options, simply stored for use by subclasses.
      def initialize(app, **options)
        @app = app
        @options = merge_default_options(options)
        @app_response = nil
      end

      def call(env)
        dup.call!(env).to_a
      end

      def call!(env)
        @env = env
        before
        begin
          @app_response = @app.call(@env)
        ensure
          begin
            after_response = after
          rescue StandardError => e
            warn "caught error of type #{e.class} in after callback inside #{self.class.name} : #{e.message}"
            raise e
          end
        end

        response = after_response || @app_response
        merge_headers response
        response
      end

      # @abstract
      # Called before the application is called in the middleware lifecycle.
      def before; end

      # @abstract
      # Called after the application is called in the middleware lifecycle.
      # @return [Response, nil] a Rack SPEC response or nil to call the application afterwards.
      def after; end

      def rack_request
        @rack_request ||= Rack::Request.new(env)
      end

      def context
        env[Grape::Env::API_ENDPOINT]
      end

      def response
        return @app_response if @app_response.is_a?(Rack::Response)

        @app_response = Rack::Response[*@app_response]
      end

      def content_types
        @content_types ||= Grape::ContentTypes.content_types_for(options[:content_types])
      end

      def mime_types
        @mime_types ||= Grape::ContentTypes.mime_types_for(content_types)
      end

      def content_type_for(format)
        content_types_indifferent_access[format]
      end

      def content_type
        content_type_for(env[Grape::Env::API_FORMAT] || options[:format]) || 'text/html'
      end

      def query_params
        rack_request.GET
      rescue *Grape::RACK_ERRORS
        raise Grape::Exceptions::RequestError
      end

      private

      def content_types_indifferent_access
        @content_types_indifferent_access ||= content_types.with_indifferent_access
      end

      def merge_headers(response)
        return if @header.blank?

        case response
        when Rack::Response then response.headers.merge!(@header)
        when Array          then response[1].merge!(@header)
        end
      end

      def merge_default_options(options)
        if respond_to?(:default_options)
          default_options.deep_merge(options)
        elsif self.class.const_defined?(:DEFAULT_OPTIONS)
          self.class::DEFAULT_OPTIONS.deep_merge(options)
        else
          options
        end
      end

      def try_scrub(obj)
        obj.respond_to?(:valid_encoding?) && !obj.valid_encoding? ? obj.scrub : obj
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Formatter
    class SerializableHash < Base
      class << self
        def call(object, _env)
          return object if object.is_a?(String)
          return ::Grape::Json.dump(serialize(object)) if serializable?(object)
          return object.to_json if object.respond_to?(:to_json)

          ::Grape::Json.dump(object)
        end

        private

        def serializable?(object)
          object.respond_to?(:serializable_hash) || array_serializable?(object) || object.is_a?(Hash)
        end

        def serialize(object)
          if object.respond_to? :serializable_hash
            object.serializable_hash
          elsif array_serializable?(object)
            object.map(&:serializable_hash)
          elsif object.is_a?(Hash)
            object.transform_values { |v| serialize(v) }
          else
            object
          end
        end

        def array_serializable?(object)
          object.is_a?(Array) && object.all? { |o| o.respond_to? :serializable_hash }
        end
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Exceptions
    class Base < StandardError
      include Grape::Util::Translation

      MESSAGE_STEPS = %w[problem summary resolution].to_h { |s| [s, s.capitalize] }.freeze

      attr_reader :status, :headers

      def initialize(status: nil, message: nil, headers: nil)
        super(message)

        @status  = status
        @headers = headers
      end

      def [](index)
        __send__ index
      end

      private

      def compose_message(key, **)
        short_message = translate_message(key, **)
        return short_message unless short_message.is_a?(Hash)

        MESSAGE_STEPS.filter_map do |step, label|
          detail = translate_message(:"#{key}.#{step}", **)
          "\n#{label}:\n  #{detail}" if detail.present?
        end.join
      end

      def translate_message(translation_key, **)
        case translation_key
        when Symbol
          translate(translation_key, **)
        when Hash
          translation_key => { key:, **opts }
          translate(key, **opts)
        when Proc
          translation_key.call
        else
          translation_key
        end
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Exceptions
    class ValidationErrors < Base
      include Enumerable

      attr_reader :errors

      def initialize(errors: [], headers: {})
        @errors = errors.group_by(&:params)
        super(message: full_messages.join(', '), status: 400, headers:)
      end

      def each
        errors.each_pair do |attribute, errors|
          errors.each do |error|
            yield attribute, error
          end
        end
      end

      def as_json(**_opts)
        errors.map do |k, v|
          {
            params: k,
            messages: v.map(&:to_s)
          }
        end
      end

      def to_json(*_opts)
        as_json.to_json
      end

      def full_messages
        messages = map do |attributes, error|
          translate(
            :format,
            scope: 'grape.errors',
            default: '%<attributes>s %<message>s',
            attributes: translate_attributes(attributes),
            message: error.message
          )
        end
        messages.uniq!
        messages
      end

      private

      def translate_attributes(keys)
        keys.map do |key|
          translate(key, scope: 'grape.errors.attributes', default: key.to_s)
        end.join(', ')
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Exceptions
    class Validation < Base
      EMPTY_BACKTRACE = [].freeze

      attr_reader :params, :message_key

      def initialize(params:, message: nil, status: nil, headers: nil)
        @params = Array(params)
        if message
          @message_key = case message
                         when Symbol then message
                         when Hash then message[:key]
                         end
          message = translate_message(message)
        end

        super(status:, message:, headers:)
        # Pre-seed the backtrace so Ruby's raise skips capture. Validation errors are
        # a hot path (raised per bad attribute) and end up as 400 Bad Request responses;
        # backtraces here point into Grape internals and have no diagnostic value.
        set_backtrace(EMPTY_BACKTRACE)
      end

      # Remove all the unnecessary stuff from Grape::Exceptions::Base like status
      # and headers when converting a validation error to json or string
      def as_json(*_args)
        to_s
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module DSL
    # Keeps track of settings (implemented as key-value pairs, grouped by
    # types), in two contexts: top-level settings which apply globally no
    # matter where they're defined, and inheritable settings which apply only
    # in the current scope and scopes nested under it.
    module Settings
      attr_writer :inheritable_setting

      # Fetch our top-level settings, which apply to all endpoints in the API.
      def top_level_setting
        @top_level_setting ||= Grape::Util::InheritableSetting.new.tap do |setting|
          # Doesn't try to inherit settings from +Grape::API::Instance+ which also responds to
          # +inheritable_setting+, however, it doesn't contain any user-defined settings.
          # Otherwise, it would lead to an extra instance of +Grape::Util::InheritableSetting+
          # in the chain for every endpoint.
          setting.inherit_from superclass.inheritable_setting if defined?(superclass) && superclass.respond_to?(:inheritable_setting) && superclass != Grape::API::Instance
        end
      end

      # Fetch our current inheritable settings, which are inherited by
      # nested scopes but not shared across siblings.
      def inheritable_setting
        @inheritable_setting ||= Grape::Util::InheritableSetting.new.tap { |new_settings| new_settings.inherit_from top_level_setting }
      end

      def global_setting(key, value = nil)
        get_or_set(inheritable_setting.global, key, value)
      end

      def route_setting(key, value = nil)
        get_or_set(inheritable_setting.route, key, value)
      end

      def namespace_setting(key, value = nil)
        get_or_set(inheritable_setting.namespace, key, value)
      end

      private

      # Execute the block within a context where our inheritable settings are forked
      # to a new copy (see #namespace_start).
      def within_namespace
        new_inheritable_settings = Grape::Util::InheritableSetting.new
        new_inheritable_settings.inherit_from inheritable_setting

        @inheritable_setting = new_inheritable_settings

        result = yield

        inheritable_setting.route_end
        @inheritable_setting = inheritable_setting.parent
        reset_validations!

        result
      end

      def get_or_set(setting, key, value)
        return setting[key] if value.nil?

        setting[key] = value
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module DSL
    module Routing
      attr_reader :endpoints

      def given(conditional_option, &)
        return unless conditional_option

        mounted(&)
      end

      def mounted(&block)
        evaluate_as_instance_with_configuration(block, lazy: true)
      end

      def cascade(value = nil)
        return inheritable_setting.namespace_inheritable.key?(:cascade) ? !inheritable_setting.namespace_inheritable[:cascade].nil? : true if value.nil?

        inheritable_setting.namespace_inheritable[:cascade] = value
      end

      # Specify an API version.
      #
      # @example API with legacy support.
      #   class MyAPI < Grape::API
      #     version 'v2'
      #
      #     get '/main' do
      #       {some: 'data'}
      #     end
      #
      #     version 'v1' do
      #       get '/main' do
      #         {legacy: 'data'}
      #       end
      #     end
      #   end
      #
      def version(*args, **options, &block)
        if args.any?
          options = options.reverse_merge(using: :path)
          requested_versions = args.flatten.map(&:to_s)

          raise Grape::Exceptions::MissingVendorOption.new if options[:using] == :header && !options.key?(:vendor)

          @versions = versions | requested_versions

          if block
            within_namespace do
              inheritable_setting.namespace_inheritable[:version] = requested_versions
              inheritable_setting.namespace_inheritable[:version_options] = options

              instance_eval(&block)
            end
          else
            inheritable_setting.namespace_inheritable[:version] = requested_versions
            inheritable_setting.namespace_inheritable[:version_options] = options
          end
        end

        @versions&.last
      end

      # Define a root URL prefix for your entire API.
      def prefix(prefix = nil)
        return inheritable_setting.namespace_inheritable[:root_prefix] if prefix.nil?

        inheritable_setting.namespace_inheritable[:root_prefix] = prefix.to_s
      end

      # Create a scope without affecting the URL.
      #
      # @param _name [Symbol] Purely placebo, just allows to name the scope to
      # make the code more readable.
      def scope(_name = nil, &block)
        within_namespace do
          nest(block)
        end
      end

      def build_with(build_with)
        inheritable_setting.namespace_inheritable[:build_params_with] = build_with
      end

      # Do not route HEAD requests to GET requests automatically.
      def do_not_route_head!
        inheritable_setting.namespace_inheritable[:do_not_route_head] = true
      end

      # Do not automatically route OPTIONS.
      def do_not_route_options!
        inheritable_setting.namespace_inheritable[:do_not_route_options] = true
      end

      def lint!
        inheritable_setting.namespace_inheritable[:lint] = true
      end

      def do_not_document!
        inheritable_setting.namespace_inheritable[:do_not_document] = true
      end

      def mount(mounts, *opts)
        mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
        mounts.each_pair do |app, path|
          if app.respond_to?(:mount_instance)
            opts_with = opts.any? ? opts.first[:with] : {}
            mount({ app.mount_instance(configuration: opts_with) => path }, *opts)
            next
          end
          in_setting = inheritable_setting

          if app.respond_to?(:inheritable_setting, true)
            mount_path = Grape::Router.normalize_path(path)
            app.top_level_setting.namespace_stackable[:mount_path] = mount_path

            app.inherit_settings(inheritable_setting)

            in_setting = app.top_level_setting

            app.change!
            change!
          end

          # When trying to mount multiple times the same endpoint, remove the previous ones
          # from the list of endpoints if refresh_already_mounted parameter is true
          refresh_already_mounted = opts.any? ? opts.first[:refresh_already_mounted] : false
          if refresh_already_mounted && !endpoints.empty?
            endpoints.delete_if do |endpoint|
              endpoint.options[:app].to_s == app.to_s
            end
          end

          endpoints << Grape::Endpoint.new(
            in_setting,
            method: :any,
            path:,
            app:,
            route_options: { anchor: false },
            forward_match: !app.respond_to?(:inheritable_setting),
            for: self
          )
        end
      end

      # Defines a route that will be recognized
      # by the Grape API.
      #
      # @param methods [HTTP Verb] One or more HTTP verbs that are accepted by this route. Set to `:any` if you want any verb to be accepted.
      # @param paths [String] One or more strings representing the URL segment(s) for this route.
      #
      # @example Defining a basic route.
      #   class MyAPI < Grape::API
      #     route(:any, '/hello') do
      #       {hello: 'world'}
      #     end
      #   end
      def route(methods, paths = ['/'], route_options = {}, &)
        method = methods == :any ? '*' : methods
        endpoint_params = inheritable_setting.namespace_stackable_with_hash(:params) || {}
        endpoint_description = inheritable_setting.route[:description]
        all_route_options = { params: endpoint_params }
        all_route_options.deep_merge!(endpoint_description) if endpoint_description
        all_route_options.deep_merge!(route_options) if route_options&.any?

        new_endpoint = Grape::Endpoint.new(
          inheritable_setting,
          method:,
          path: paths,
          for: self,
          route_options: all_route_options,
          &
        )
        endpoints << new_endpoint unless endpoints.include?(new_endpoint)

        inheritable_setting.route_end
        reset_validations!
      end

      Grape::HTTP_SUPPORTED_METHODS.each do |supported_method|
        define_method supported_method.downcase do |*args, **options, &block|
          paths = args.first || ['/']
          route(supported_method, paths, options, &block)
        end
      end

      # Declare a "namespace", which prefixes all subordinate routes with its
      # name. Any endpoints within a namespace, group, resource or segment,
      # etc., will share their parent context as well as any configuration
      # done in the namespace context.
      #
      # @example
      #
      #     namespace :foo do
      #       get 'bar' do
      #         # defines the endpoint: GET /foo/bar
      #       end
      #     end
      def namespace(space = nil, requirements: nil, **options, &block)
        return Namespace.joined_space_path(inheritable_setting.namespace_stackable[:namespace]) unless space || block

        within_namespace do
          nest(block) do
            inheritable_setting.namespace_stackable[:namespace] = Grape::Namespace.new(space, requirements:, **options) if space
          end
        end
      end

      alias group namespace
      alias resource namespace
      alias resources namespace
      alias segment namespace

      # An array of API routes.
      def routes
        @routes ||= endpoints.map(&:routes).flatten
      end

      # This method allows you to quickly define a parameter route segment
      # in your API.
      #
      # @param param [Symbol] The name of the parameter you wish to declare.
      # @option options [Regexp] You may supply a regular expression that the declared parameter must meet.
      def route_param(param, requirements: nil, type: nil, **, &)
        requirements = { param.to_sym => requirements } if requirements.is_a?(Regexp)

        Grape::Validations::ParamsScope.new(api: self) do
          requires param, type: type
        end if type

        namespace(":#{param}", requirements:, **, &)
      end

      # @return array of defined versions
      def versions
        @versions ||= []
      end

      private

      # Remove all defined routes.
      def reset_routes!
        endpoints.each(&:reset_routes!)
        @routes = nil
      end

      def reset_endpoints!
        @endpoints = []
      end

      def refresh_mounted_api(mounts, *opts)
        opts << { refresh_already_mounted: true }
        mount(mounts, *opts)
      end

      # Execute first the provided block, then each of the
      # block passed in. Allows for simple 'before' setups
      # of settings stack pushes.
      def nest(*blocks, &block)
        blocks.compact!
        return instance_eval(&block) if blocks.empty?

        evaluate_as_instance_with_configuration(block) if block
        blocks.each { |b| evaluate_as_instance_with_configuration(b) }
        reset_validations!
      end

      def evaluate_as_instance_with_configuration(block, lazy: false)
        lazy_block = Grape::Util::Lazy::Block.new do |configuration|
          value_for_configuration = configuration
          self.configuration = value_for_configuration.evaluate if value_for_configuration.is_a?(Grape::Util::Lazy::Base)
          response = instance_eval(&block)
          self.configuration = value_for_configuration
          response
        end
        return lazy_block if @base && base_instance? && lazy

        lazy_block.evaluate_from(configuration)
      end
    end
  end
end


def mount(mounts, *opts)
        mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
        mounts.each_pair do |app, path|
          if app.respond_to?(:mount_instance)
            opts_with = opts.any? ? opts.first[:with] : {}
            mount({ app.mount_instance(configuration: opts_with) => path }, *opts)
            next
          end
          in_setting = inheritable_setting

          if app.respond_to?(:inheritable_setting, true)
            mount_path = Grape::Router.normalize_path(path)
            app.top_level_setting.namespace_stackable[:mount_path] = mount_path

            app.inherit_settings(inheritable_setting)

            in_setting = app.top_level_setting

            app.change!
            change!
          end

          # When trying to mount multiple times the same endpoint, remove the previous ones
          # from the list of endpoints if refresh_already_mounted parameter is true
          refresh_already_mounted = opts.any? ? opts.first[:refresh_already_mounted] : false
          if refresh_already_mounted && !endpoints.empty?
            endpoints.delete_if do |endpoint|
              endpoint.options[:app].to_s == app.to_s
            end
          end

          endpoints << Grape::Endpoint.new(
            in_setting,
            method: :any,
            path:,
            app:,
            route_options: { anchor: false },
            forward_match: !app.respond_to?(:inheritable_setting),
            for: self
          )
        end
      end


def route(methods, paths = ['/'], route_options = {}, &)
        method = methods == :any ? '*' : methods
        endpoint_params = inheritable_setting.namespace_stackable_with_hash(:params) || {}
        endpoint_description = inheritable_setting.route[:description]
        all_route_options = { params: endpoint_params }
        all_route_options.deep_merge!(endpoint_description) if endpoint_description
        all_route_options.deep_merge!(route_options) if route_options&.any?

        new_endpoint = Grape::Endpoint.new(
          inheritable_setting,
          method:,
          path: paths,
          for: self,
          route_options: all_route_options,
          &
        )
        endpoints << new_endpoint unless endpoints.include?(new_endpoint)

        inheritable_setting.route_end
        reset_validations!
      end


def evaluate_as_instance_with_configuration(block, lazy: false)
        lazy_block = Grape::Util::Lazy::Block.new do |configuration|
          value_for_configuration = configuration
          self.configuration = value_for_configuration.evaluate if value_for_configuration.is_a?(Grape::Util::Lazy::Base)
          response = instance_eval(&block)
          self.configuration = value_for_configuration
          response
        end
        return lazy_block if @base && base_instance? && lazy

        lazy_block.evaluate_from(configuration)
      end


# frozen_string_literal: true

module Grape
  module DSL
    module Entity
      # Allows you to make use of Grape Entities by setting
      # the response body to the serializable hash of the
      # entity provided in the `:with` option. This has the
      # added benefit of automatically passing along environment
      # and version information to the serialization, making it
      # very easy to do conditional exposures. See Entity docs
      # for more info.
      #
      # @param args [Array] either `(object)` or `(key, object)` where key is a Symbol
      #   used to nest the representation under that key in the response body.
      # @param root [Symbol, String, nil] wraps the representation under this root key.
      # @param with [Class, nil] the entity class to use for representation.
      #   If omitted, the entity class is inferred from the object via {#entity_class_for_obj}.
      # @param options [Hash] additional options forwarded to the entity's `represent` call.
      #
      # @example
      #
      #   get '/users/:id' do
      #     present User.find(params[:id]),
      #       with: API::Entities::User,
      #       admin: current_user.admin?
      #   end
      def present(*args, root: nil, with: nil, **options)
        key, object = args.count == 2 && args.first.is_a?(Symbol) ? args : [nil, args.first]
        entity_class = with || entity_class_for_obj(object)
        representation = entity_class ? entity_representation_for(entity_class, object, options) : object
        representation = { root => representation } if root

        if key
          representation = body&.merge(key => representation) || { key => representation }
        elsif entity_class.present? && body
          raise ArgumentError, "Representation of type #{representation.class} cannot be merged." unless representation.respond_to?(:merge)

          representation = body.merge(representation)
        end

        body representation
      end

      # Attempt to locate the Entity class for a given object, if not given
      # explicitly. This is done by looking for the presence of Klass::Entity,
      # where Klass is the class of the `object` parameter, or one of its
      # ancestors.
      # @param object [Object] the object to locate the Entity class for
      # @return [Class] the located Entity class, or nil if none is found
      def entity_class_for_obj(object)
        object_class =
          if object.respond_to?(:klass)
            object.klass
          elsif object.respond_to?(:first)
            object.first.class
          else
            object.class
          end

        representations = inheritable_setting.namespace_stackable_with_hash(:representations)
        if representations
          potential = object_class.ancestors.detect { |potential| representations.key?(potential) }
          return representations[potential] if potential && representations[potential]
        end

        return unless object_class.const_defined?(:Entity)

        entity = object_class.const_get(:Entity)
        entity if entity.respond_to?(:represent)
      end

      private

      # @param entity_class [Class] the entity class to use for representation.
      # @param object [Object] the object to represent.
      # @param options [Hash] additional options forwarded to the entity's `represent` call.
      # @return the representation of the given object as done through the given entity_class.
      def entity_representation_for(entity_class, object, options)
        embeds = env.key?(Grape::Env::API_VERSION) ? { env:, version: env[Grape::Env::API_VERSION] } : { env: }
        entity_class.represent(object, **embeds, **options)
      end
    end
  end
end


def entity_class_for_obj(object)
        object_class =
          if object.respond_to?(:klass)
            object.klass
          elsif object.respond_to?(:first)
            object.first.class
          else
            object.class
          end

        representations = inheritable_setting.namespace_stackable_with_hash(:representations)
        if representations
          potential = object_class.ancestors.detect { |potential| representations.key?(potential) }
          return representations[potential] if potential && representations[potential]
        end

        return unless object_class.const_defined?(:Entity)

        entity = object_class.const_get(:Entity)
        entity if entity.respond_to?(:represent)
      end


# frozen_string_literal: true

module Grape
  module DSL
    module RequestResponse
      # Specify the default format for the API's serializers.
      # May be `:json` or `:txt` (default).
      def default_format(new_format = nil)
        return inheritable_setting.namespace_inheritable[:default_format] if new_format.nil?

        inheritable_setting.namespace_inheritable[:default_format] = new_format.to_sym
      end

      # Specify the format for the API's serializers.
      # May be `:json`, `:xml`, `:txt`, etc.
      def format(new_format = nil)
        return inheritable_setting.namespace_inheritable[:format] if new_format.nil?

        symbolic_new_format = new_format.to_sym
        inheritable_setting.namespace_inheritable[:format] = symbolic_new_format
        inheritable_setting.namespace_inheritable[:default_error_formatter] = Grape::ErrorFormatter.formatter_for(symbolic_new_format)

        content_type = content_types[symbolic_new_format]
        raise Grape::Exceptions::MissingMimeType.new(new_format) unless content_type

        inheritable_setting.namespace_stackable[:content_types] = { symbolic_new_format => content_type }
      end

      # Specify a custom formatter for a content-type.
      def formatter(content_type, new_formatter)
        inheritable_setting.namespace_stackable[:formatters] = { content_type.to_sym => new_formatter }
      end

      # Specify a custom parser for a content-type.
      def parser(content_type, new_parser)
        inheritable_setting.namespace_stackable[:parsers] = { content_type.to_sym => new_parser }
      end

      # Specify a default error formatter.
      def default_error_formatter(new_formatter_name = nil)
        return inheritable_setting.namespace_inheritable[:default_error_formatter] if new_formatter_name.nil?

        new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name)
        inheritable_setting.namespace_inheritable[:default_error_formatter] = new_formatter
      end

      def error_formatter(format, options = nil, with: nil)
        formatter = with || options
        inheritable_setting.namespace_stackable[:error_formatters] = { format.to_sym => formatter }
      end

      # Specify additional content-types, e.g.:
      #   content_type :xls, 'application/vnd.ms-excel'
      def content_type(key, val)
        inheritable_setting.namespace_stackable[:content_types] = { key.to_sym => val }
      end

      # All available content types.
      def content_types
        c_types = inheritable_setting.namespace_stackable_with_hash(:content_types)
        Grape::ContentTypes.content_types_for c_types
      end

      # Specify the default status code for errors.
      def default_error_status(new_status = nil)
        return inheritable_setting.namespace_inheritable[:default_error_status] if new_status.nil?

        inheritable_setting.namespace_inheritable[:default_error_status] = new_status
      end

      # Allows you to rescue certain exceptions that occur to return
      # a grape error rather than raising all the way to the
      # server level.
      #
      # @example Rescue from custom exceptions
      #     class ExampleAPI < Grape::API
      #       class CustomError < StandardError; end
      #
      #       rescue_from CustomError
      #     end
      #
      # @overload rescue_from(*exception_classes, **options)
      #   @param [Array] exception_classes A list of classes that you want to rescue, or
      #     the symbol :all to rescue from all exceptions.
      #   @param [Block] block Execution block to handle the given exception.
      #   @param [Hash] options Options for the rescue usage.
      #   @option options [Boolean] :backtrace Include a backtrace in the rescue response.
      #   @option options [Boolean] :rescue_subclasses Also rescue subclasses of exception classes
      #   @param [Proc] handler Execution proc to handle the given exception as an
      #     alternative to passing a block.
      def rescue_from(*args, with: nil, **options, &block)
        handler = extract_handler(args, with:, block:)

        if args.include?(:all)
          inheritable_setting.namespace_inheritable[:rescue_all] = true
          inheritable_setting.namespace_inheritable[:all_rescue_handler] = handler
        elsif args.include?(:grape_exceptions)
          inheritable_setting.namespace_inheritable[:rescue_all] = true
          inheritable_setting.namespace_inheritable[:rescue_grape_exceptions] = true
          inheritable_setting.namespace_inheritable[:grape_exceptions_rescue_handler] = handler
        else
          handler_type =
            case options[:rescue_subclasses]
            when nil, true
              :rescue_handlers
            else
              :base_only_rescue_handlers
            end

          inheritable_setting.namespace_reverse_stackable[handler_type] = args.to_h { |arg| [arg, handler] }
        end

        inheritable_setting.namespace_stackable[:rescue_options] = options
      end

      # Allows you to specify a default representation entity for a
      # class. This allows you to map your models to their respective
      # entities once and then simply call `present` with the model.
      #
      # @example
      #   class ExampleAPI < Grape::API
      #     represent User, with: Entity::User
      #
      #     get '/me' do
      #       present current_user # with: Entity::User is assumed
      #     end
      #   end
      #
      # Note that Grape will automatically go up the class ancestry to
      # try to find a representing entity, so if you, for example, define
      # an entity to represent `Object` then all presented objects will
      # bubble up and utilize the entity provided on that `represent` call.
      #
      # @param model_class [Class] The model class that will be represented.
      # @option options [Class] :with The entity class that will represent the model.
      def represent(model_class, with:)
        raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless with.is_a?(Class)

        inheritable_setting.namespace_stackable[:representations] = { model_class => with }
      end

      private

      def extract_handler(args, with:, block:)
        raise ArgumentError, 'both :with option and block cannot be passed' if block && with

        return args.pop if args.last.is_a?(Proc)
        return block if block
        return with if with.instance_of?(Proc) || with.instance_of?(Symbol)
        return with.to_sym if with.instance_of?(String)

        raise ArgumentError, "with: #{with.class}, expected Symbol, String or Proc" if with
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module DSL
    module InsideRoute
      include Declared
      include Entity

      # Backward compatibility: alias exception class to previous location
      MethodNotYetAvailable = Declared::MethodNotYetAvailable

      # The API version as specified in the URL.
      def version
        env[Grape::Env::API_VERSION]
      end

      def configuration
        options[:for].configuration.evaluate
      end

      # End the request and display an error to the
      # end user with the specified message.
      #
      # @param message [String] The message to display.
      # @param status [Integer] The HTTP Status Code. Defaults to default_error_status, 500 if not set.
      # @param additional_headers [Hash] Addtional headers for the response.
      # @param backtrace [Array<String>] The backtrace of the exception that caused the error.
      # @param original_exception [Exception] The original exception that caused the error.
      def error!(message, status = nil, additional_headers = nil, backtrace = nil, original_exception = nil)
        status = self.status(status || inheritable_setting.namespace_inheritable[:default_error_status])
        headers = additional_headers.present? ? header.merge(additional_headers) : header
        throw :error,
              message:,
              status:,
              headers:,
              backtrace:,
              original_exception:
      end

      # Redirect to a new url.
      #
      # @param url [String] The url to be redirect.
      # @param permanent [Boolean] default false.
      # @param body default a short message including the URL.
      def redirect(url, permanent: false, body: nil)
        body_message = body
        if permanent
          status 301
          body_message ||= "This resource has been moved permanently to #{url}."
        elsif http_version == 'HTTP/1.1' && !request.get?
          status 303
          body_message ||= "An alternate resource is located at #{url}."
        else
          status 302
          body_message ||= "This resource has been moved temporarily to #{url}."
        end
        header 'Location', url
        content_type 'text/plain'
        body body_message
      end

      # Set or retrieve the HTTP status code.
      #
      # @param status [Integer] The HTTP Status Code to return for this request.
      def status(status = nil)
        case status
        when Symbol
          raise ArgumentError, "Status code :#{status} is invalid." unless Rack::Utils::SYMBOL_TO_STATUS_CODE.key?(status)

          @status = Rack::Utils.status_code(status)
        when Integer
          @status = status
        when nil
          return @status if @status

          if request.post?
            201
          elsif request.delete?
            if @body.present?
              200
            else
              204
            end
          else
            200
          end
        else
          raise ArgumentError, 'Status code must be Integer or Symbol.'
        end
      end

      # Set response content-type
      def content_type(val = nil)
        if val
          header(Rack::CONTENT_TYPE, val)
        else
          header[Rack::CONTENT_TYPE]
        end
      end

      # Allows you to define the response body as something other than the
      # return value.
      #
      # @example
      #   get '/body' do
      #     body "Body"
      #     "Not the Body"
      #   end
      #
      #   GET /body # => "Body"
      def body(value = nil)
        if value
          @body = value
        elsif value == false
          @body = ''
          status 204
        else
          @body
        end
      end

      # Allows you to explicitly return no content.
      #
      # @example
      #   delete :id do
      #     return_no_content
      #     "not returned"
      #   end
      #
      #   DELETE /12 # => 204 No Content, ""
      def return_no_content
        status 204
        body false
      end

      # Allows you to send a file to the client via sendfile.
      #
      # @example
      #   get '/file' do
      #     sendfile FileStreamer.new(...)
      #   end
      #
      #   GET /file # => "contents of file"
      def sendfile(value = nil)
        return stream if value.nil?

        raise ArgumentError, 'Argument must be a file path' unless value.is_a?(String)

        file_body = Grape::ServeStream::FileBody.new(value)
        @stream = Grape::ServeStream::StreamResponse.new(file_body)
      end

      # Allows you to define the response as a streamable object.
      #
      # If Content-Length and Transfer-Encoding are blank (among other conditions),
      # Rack assumes this response can be streamed in chunks.
      #
      # @example
      #   get '/stream' do
      #     stream FileStreamer.new(...)
      #   end
      #
      #   GET /stream # => "chunked contents of file"
      #
      # See:
      # * https://github.com/rack/rack/blob/99293fa13d86cd48021630fcc4bd5acc9de5bdc3/lib/rack/chunked.rb
      # * https://github.com/rack/rack/blob/99293fa13d86cd48021630fcc4bd5acc9de5bdc3/lib/rack/etag.rb
      def stream(value = nil)
        return if value.nil? && @stream.nil?

        header Rack::CONTENT_LENGTH, nil
        header 'Transfer-Encoding', nil
        header Rack::CACHE_CONTROL, 'no-cache' # Skips ETag generation (reading the response up front)

        return @stream if value.nil?

        stream_body =
          if value.is_a?(String)
            Grape::ServeStream::FileBody.new(value)
          elsif value.respond_to?(:each)
            value
          else
            raise ArgumentError, 'Stream object must respond to :each.'
          end

        @stream = Grape::ServeStream::StreamResponse.new(stream_body)
      end

      # Returns route information for the current request.
      #
      # @example
      #
      #   desc "Returns the route description."
      #   get '/' do
      #     route.description
      #   end
      def route
        env[Grape::Env::GRAPE_ROUTING_ARGS][:route_info]
      end

      def http_version
        env.fetch('HTTP_VERSION') { env[Rack::SERVER_PROTOCOL] }
      end

      def api_format(format)
        env[Grape::Env::API_FORMAT] = format
      end

      def context
        self
      end
    end
  end
end


def redirect(url, permanent: false, body: nil)
        body_message = body
        if permanent
          status 301
          body_message ||= "This resource has been moved permanently to #{url}."
        elsif http_version == 'HTTP/1.1' && !request.get?
          status 303
          body_message ||= "An alternate resource is located at #{url}."
        else
          status 302
          body_message ||= "This resource has been moved temporarily to #{url}."
        end
        header 'Location', url
        content_type 'text/plain'
        body body_message
      end


def status(status = nil)
        case status
        when Symbol
          raise ArgumentError, "Status code :#{status} is invalid." unless Rack::Utils::SYMBOL_TO_STATUS_CODE.key?(status)

          @status = Rack::Utils.status_code(status)
        when Integer
          @status = status
        when nil
          return @status if @status

          if request.post?
            201
          elsif request.delete?
            if @body.present?
              200
            else
              204
            end
          else
            200
          end
        else
          raise ArgumentError, 'Status code must be Integer or Symbol.'
        end
      end


def body(value = nil)
        if value
          @body = value
        elsif value == false
          @body = ''
          status 204
        else
          @body
        end
      end


def stream(value = nil)
        return if value.nil? && @stream.nil?

        header Rack::CONTENT_LENGTH, nil
        header 'Transfer-Encoding', nil
        header Rack::CACHE_CONTROL, 'no-cache' # Skips ETag generation (reading the response up front)

        return @stream if value.nil?

        stream_body =
          if value.is_a?(String)
            Grape::ServeStream::FileBody.new(value)
          elsif value.respond_to?(:each)
            value
          else
            raise ArgumentError, 'Stream object must respond to :each.'
          end

        @stream = Grape::ServeStream::StreamResponse.new(stream_body)
      end


# frozen_string_literal: true

module Grape
  module DSL
    module Desc
      extend Grape::DSL::Settings

      # Add a description to the next namespace or function.
      # @param description [String] descriptive string for this endpoint
      #   or namespace
      # @param options [Hash] other properties you can set to describe the
      #   endpoint or namespace. Optional.
      # @option options :detail [String] additional detail about this endpoint
      # @option options :summary [String] summary for this endpoint
      # @option options :params [Hash] param types and info. normally, you set
      #   these via the `params` dsl method.
      # @option options :entity [Grape::Entity] the entity returned upon a
      #   successful call to this action
      # @option options :http_codes [Array[Array]] possible HTTP codes this
      #   endpoint may return, with their meanings, in a 2d array
      # @option options :named [String] a specific name to help find this route
      # @option options :body_name [String] override the autogenerated body name param
      # @option options :headers [Hash] HTTP headers this method can accept
      # @option options :hidden [Boolean] hide the endpoint or not
      # @option options :deprecated [Boolean] deprecate the endpoint or not
      # @option options :is_array [Boolean] response entity is array or not
      # @option options :nickname [String] nickname of the endpoint
      # @option options :produces [Array[String]] a list of MIME types the endpoint produce
      # @option options :consumes [Array[String]] a list of MIME types the endpoint consume
      # @option options :security [Array[Hash]] a list of security schemes
      # @option options :tags [Array[String]] a list of tags
      # @yield a block yielding an instance context with methods mapping to
      #   each of the above, except that :entity is also aliased as #success
      #   and :http_codes is aliased as #failure.
      #
      # @example
      #
      #     desc 'create a user'
      #     post '/users' do
      #       # ...
      #     end
      #
      #     desc 'find a user' do
      #       detail 'locates the user from the given user ID'
      #       failure [ [404, 'Couldn\'t find the given user' ] ]
      #       success User::Entity
      #     end
      #     get '/user/:id' do
      #       # ...
      #     end
      #
      def desc(description, options = {}, &config_block)
        settings =
          if config_block
            endpoint_config = defined?(configuration) ? configuration : nil
            Grape::Util::ApiDescription.new(description, endpoint_config, &config_block).settings
          else
            options.merge(description:)
          end
        inheritable_setting.namespace[:description] = settings
        inheritable_setting.route[:description] = settings
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module DSL
    # Defines DSL methods, meant to be applied to a ParamsScope, which define
    # and describe the parameters accepted by an endpoint, or all endpoints
    # within a namespace.
    module Parameters
      # Set the module used to build the request.params.
      #
      # @param build_with the ParamBuilder module to use when building request.params
      #   Available builders are:
      #
      #     * Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder (default)
      #     * Grape::Extensions::Hash::ParamBuilder
      #     * Grape::Extensions::Hashie::Mash::ParamBuilder
      #
      # @example
      #
      #     require 'grape/extenstions/hashie_mash'
      #     class API < Grape::API
      #       desc "Get collection"
      #       params do
      #         build_with :hashie_mash
      #         requires :user_id, type: Integer
      #       end
      #       get do
      #         params['user_id']
      #       end
      #     end
      def build_with(build_with)
        @api.inheritable_setting.namespace_inheritable[:build_params_with] = build_with
      end

      # Include reusable params rules among current.
      # You can define reusable params with helpers method.
      #
      # @example
      #
      #     class API < Grape::API
      #       helpers do
      #         params :pagination do
      #           optional :page, type: Integer
      #           optional :per_page, type: Integer
      #         end
      #       end
      #
      #       desc "Get collection"
      #       params do
      #         use :pagination
      #       end
      #       get do
      #         Collection.page(params[:page]).per(params[:per_page])
      #       end
      #     end
      def use(*names, **options)
        named_params = @api.inheritable_setting.namespace_stackable_with_hash(:named_params) || {}
        names.each do |name|
          params_block = named_params.fetch(name) do
            raise "Params :#{name} not found!"
          end

          if options.empty?
            instance_exec(options, &params_block)
          else
            instance_exec(**options, &params_block)
          end
        end
      end
      alias use_scope use
      alias includes use

      # Require one or more parameters for the current endpoint.
      #
      # @param attrs list of parameters names, or, if :using is
      #   passed as an option, which keys to include (:all or :none) from
      #   the :using hash. The last key can be a hash, which specifies
      #   options for the parameters
      # @option attrs :type [Class] the type to coerce this parameter to before
      #   passing it to the endpoint. See {Grape::Validations::Types} for a list of
      #   types that are supported automatically. Custom classes may be used
      #   where they define a class-level `::parse` method, or in conjunction
      #   with the `:coerce_with` parameter. `JSON` may be supplied to denote
      #   `JSON`-formatted objects or arrays of objects. `Array[JSON]` accepts
      #   the same values as `JSON` but will wrap single objects in an `Array`.
      # @option attrs :types [Array<Class>] may be supplied in place of +:type+
      #   to declare an attribute that has multiple allowed types. See
      #   {Validations::Types::MultipleTypeCoercer} for more details on coercion
      #   and validation rules for variant-type parameters.
      # @option attrs :desc [String] description to document this parameter
      # @option attrs :default [Object] default value, if parameter is optional
      # @option attrs :values [Array] permissable values for this field. If any
      #   other value is given, it will be handled as a validation error
      # @option attrs :using [Hash[Symbol => Hash]] a hash defining keys and
      #   options, like that returned by {Grape::Entity#documentation}. The value
      #   of each key is an options hash accepting the same parameters
      # @option attrs :except [Array[Symbol]] a list of keys to exclude from
      #   the :using Hash. The meaning of this depends on if :all or :none was
      #   passed; :all + :except will make the :except fields optional, whereas
      #   :none + :except will make the :except fields required
      # @option attrs :coerce_with [#parse, #call] method to be used when coercing
      #   the parameter to the type named by `attrs[:type]`. Any class or object
      #   that defines `::parse` or `::call` may be used.
      #
      # @example
      #
      #     params do
      #       # Basic usage: require a parameter of a certain type
      #       requires :user_id, type: Integer
      #
      #       # You don't need to specify type; String is default
      #       requires :foo
      #
      #       # Multiple params can be specified at once if they share
      #       # the same options.
      #       requires :x, :y, :z, type: Date
      #
      #       # Nested parameters can be handled as hashes. You must
      #       # pass in a block, within which you can use any of the
      #       # parameters DSL methods.
      #       requires :user, type: Hash do
      #         requires :name, type: String
      #       end
      #     end
      def requires(*attrs, **opts, &block)
        opts[:presence] = { value: true, message: opts[:message] }
        opts = @group.deep_merge(opts) if @group

        if opts[:using]
          require_required_and_optional_fields(attrs.first, using: opts[:using], except: opts[:except])
        else
          validate_attributes(attrs, **opts, &block)
          block ? new_scope(attrs.first, type: opts[:type], as: opts[:as], &block) : push_declared_params(attrs, as: opts[:as])
        end
      end

      # Allow, but don't require, one or more parameters for the current
      #   endpoint.
      # @param (see #requires)
      # @option (see #requires)
      def optional(*attrs, **opts, &block)
        type = opts[:type]
        opts = @group.deep_merge(opts) if @group

        # check type for optional parameter group
        if attrs && block
          raise Grape::Exceptions::MissingGroupType if type.nil?
          raise Grape::Exceptions::UnsupportedGroupType unless Grape::Validations::Types.group?(type)
        end

        if opts[:using]
          require_optional_fields(attrs.first, using: opts[:using], except: opts[:except])
        else
          validate_attributes(attrs, **opts, &block)

          block ? new_scope(attrs.first, type: opts[:type], as: opts[:as], optional: true, &block) : push_declared_params(attrs, as: opts[:as])
        end
      end

      # Define common settings for one or more parameters
      # @param (see #requires)
      # @option (see #requires)
      def with(**opts, &)
        new_group_attrs = @group&.deep_merge(opts) || opts
        new_group_scope(new_group_attrs, &)
      end

      %i[mutually_exclusive exactly_one_of at_least_one_of all_or_none_of].each do |validator|
        define_method validator do |*attrs, message: nil|
          validates(attrs, validator => { value: true, message: })
        end
      end

      # Define a block of validations which should be applied if and only if
      # the given parameter is present. The parameters are not nested.
      # @param attr [Symbol] the parameter which, if present, triggers the
      #   validations
      # @raise Grape::Exceptions::UnknownParameter if `attr` has not been
      #   defined in this scope yet
      # @yield a parameter definition DSL
      def given(*attrs, &)
        attrs.each do |attr|
          proxy_attr = first_hash_key_or_param(attr)
          raise Grape::Exceptions::UnknownParameter.new(proxy_attr) unless declared_param?(proxy_attr)
        end
        new_lateral_scope(dependent_on: attrs, &)
      end

      # Test for whether a certain parameter has been defined in this params
      # block yet.
      # @return [Boolean] whether the parameter has been defined
      def declared_param?(param)
        if lateral?
          # Elements of @declared_params of lateral scope are pushed in @parent. So check them in @parent.
          @parent.declared_param?(param)
        else
          # @declared_params also includes hashes of options and such, but those
          # won't be flattened out.
          @declared_params.flatten.any? do |declared_param_attr|
            first_hash_key_or_param(declared_param_attr.key) == param
          end
        end
      end

      alias group requires

      EmptyOptionalValue = Object.new.freeze

      # @param params [Hash] initial hash of parameters
      # @return hash of parameters relevant for the current scope
      # @api private
      def params(params)
        params = @parent.qualifying_params.presence || @parent.params(params) if @parent
        params = map_params(params, @element) if @element
        params
      end

      private

      def first_hash_key_or_param(parameter)
        parameter.is_a?(Hash) ? parameter.keys.first : parameter
      end

      def map_params(params, element, is_array: false)
        case params
        when Array
          params.map do |el|
            map_params(el, element, is_array: true)
          end
        when Hash
          params[element] || (@optional && is_array ? EmptyOptionalValue : {})
        when EmptyOptionalValue
          EmptyOptionalValue
        else
          {}
        end
      end
    end
  end
end


def requires(*attrs, **opts, &block)
        opts[:presence] = { value: true, message: opts[:message] }
        opts = @group.deep_merge(opts) if @group

        if opts[:using]
          require_required_and_optional_fields(attrs.first, using: opts[:using], except: opts[:except])
        else
          validate_attributes(attrs, **opts, &block)
          block ? new_scope(attrs.first, type: opts[:type], as: opts[:as], &block) : push_declared_params(attrs, as: opts[:as])
        end
      end


def optional(*attrs, **opts, &block)
        type = opts[:type]
        opts = @group.deep_merge(opts) if @group

        # check type for optional parameter group
        if attrs && block
          raise Grape::Exceptions::MissingGroupType if type.nil?
          raise Grape::Exceptions::UnsupportedGroupType unless Grape::Validations::Types.group?(type)
        end

        if opts[:using]
          require_optional_fields(attrs.first, using: opts[:using], except: opts[:except])
        else
          validate_attributes(attrs, **opts, &block)

          block ? new_scope(attrs.first, type: opts[:type], as: opts[:as], optional: true, &block) : push_declared_params(attrs, as: opts[:as])
        end
      end


def map_params(params, element, is_array: false)
        case params
        when Array
          params.map do |el|
            map_params(el, element, is_array: true)
          end
        when Hash
          params[element] || (@optional && is_array ? EmptyOptionalValue : {})
        when EmptyOptionalValue
          EmptyOptionalValue
        else
          {}
        end
      end