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

mount

mount

    def self.normalize_path(path)
      return '/' unless path
      return path if path == '/'

      # Fast path for the overwhelming majority of paths that don't need to be normalized
      return path if path.start_with?('/') && !(path.end_with?('/') || path.match?(%r{%|//}))

      # Slow path
      encoding = path.encoding
      path = "/#{path}"
      path.squeeze!('/')

      unless path == '/'
        path.delete_suffix!('/')
        path.gsub!(/(%[a-f0-9]{2})/) { ::Regexp.last_match(1).upcase }
      end

      path.force_encoding(encoding)
    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 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

        def evaluate_from(configuration)
          @block.call(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

redirect

      def content_type(val = nil)
        if val
          header(Rack::CONTENT_TYPE, val)
        else
          header[Rack::CONTENT_TYPE]
        end
      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

optional

group?

      def group?(type)
        GROUPS.include? type
      end

opts[:using]
!(opts[:using])
!(attrs && block)


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


# frozen_string_literal: true

module Grape
  module Util
    # A branchable, inheritable settings object which can store both stackable
    # and inheritable values (see InheritableValues and StackableValues).
    class InheritableSetting
      attr_accessor :route, :api_class, :namespace, :namespace_inheritable, :namespace_stackable, :namespace_reverse_stackable, :parent, :point_in_time_copies

      # Retrieve global settings.
      def self.global
        @global ||= {}
      end

      # Clear all global settings.
      # @api private
      # @note only for testing
      def self.reset_global!
        @global = {}
      end

      # Instantiate a new settings instance, with blank values. The fresh
      # instance can then be set to inherit from an existing instance (see
      # #inherit_from).
      def initialize
        self.route = {}
        self.api_class = {}
        self.namespace = InheritableValues.new # only inheritable from a parent when
        # used with a mount, or should every API::Class be a separate namespace by default?
        self.namespace_inheritable = InheritableValues.new
        self.namespace_stackable = StackableValues.new
        self.namespace_reverse_stackable = ReverseStackableValues.new

        self.point_in_time_copies = []

        self.parent = nil
      end

      # Return the class-level global properties.
      def global
        self.class.global
      end

      # Set our inherited values to the given parent's current values. Also,
      # update the inherited values on any settings instances which were forked
      # from us.
      # @param parent [InheritableSetting]
      def inherit_from(parent)
        return if parent.nil?

        self.parent = parent

        namespace_inheritable.inherited_values = parent.namespace_inheritable
        namespace_stackable.inherited_values = parent.namespace_stackable
        namespace_reverse_stackable.inherited_values = parent.namespace_reverse_stackable
        self.route = parent.route.merge(route)

        point_in_time_copies.each { |cloned_one| cloned_one.inherit_from parent }
      end

      # Create a point-in-time copy of this settings instance, with clones of
      # all our values. Note that, should this instance's parent be set or
      # changed via #inherit_from, it will copy that inheritence to any copies
      # which were made.
      def point_in_time_copy
        self.class.new.tap do |new_setting|
          point_in_time_copies << new_setting
          new_setting.point_in_time_copies = []

          new_setting.namespace = namespace.clone
          new_setting.namespace_inheritable = namespace_inheritable.clone
          new_setting.namespace_stackable = namespace_stackable.clone
          new_setting.namespace_reverse_stackable = namespace_reverse_stackable.clone
          new_setting.route = route.clone
          new_setting.api_class = api_class

          new_setting.inherit_from(parent)
        end
      end

      # Resets the instance store of per-route settings.
      # @api private
      def route_end
        @route = {}
      end

      # Return a serializable hash of our values.
      def to_hash
        {
          global: global.clone,
          route: route.clone,
          namespace: namespace.to_hash,
          namespace_inheritable: namespace_inheritable.to_hash,
          namespace_stackable: namespace_stackable.to_hash,
          namespace_reverse_stackable: namespace_reverse_stackable.to_hash
        }
      end

      def namespace_stackable_with_hash(key)
        data = namespace_stackable[key]
        return if data.blank?

        data.each_with_object({}) { |value, result| result.deep_merge!(value) }
      end
    end
  end
end


def point_in_time_copy
        self.class.new.tap do |new_setting|
          point_in_time_copies << new_setting
          new_setting.point_in_time_copies = []

          new_setting.namespace = namespace.clone
          new_setting.namespace_inheritable = namespace_inheritable.clone
          new_setting.namespace_stackable = namespace_stackable.clone
          new_setting.namespace_reverse_stackable = namespace_reverse_stackable.clone
          new_setting.route = route.clone
          new_setting.api_class = api_class

          new_setting.inherit_from(parent)
        end
      end

      def inherit_from(parent)
        return if parent.nil?

        self.parent = parent

        namespace_inheritable.inherited_values = parent.namespace_inheritable
        namespace_stackable.inherited_values = parent.namespace_stackable
        namespace_reverse_stackable.inherited_values = parent.namespace_reverse_stackable
        self.route = parent.route.merge(route)

        point_in_time_copies.each { |cloned_one| cloned_one.inherit_from parent }
      end


def to_hash
        {
          global: global.clone,
          route: route.clone,
          namespace: namespace.to_hash,
          namespace_inheritable: namespace_inheritable.to_hash,
          namespace_stackable: namespace_stackable.to_hash,
          namespace_reverse_stackable: namespace_reverse_stackable.to_hash
        }
      end


# frozen_string_literal: true

module Grape
  module Util
    module DeepFreeze
      module_function

      # Recursively freezes Hash (keys and values), Array (elements), and String
      # objects. All other types are returned as-is.
      #
      # Intentionally left unfrozen:
      #   - Procs / lambdas — may be deferred DB-backed callables
      #   - Coercers (e.g. ArrayCoercer) — use lazy ivar memoization at request time
      #   - Classes / Modules — shared constants that must remain open
      #   - ParamsScope — self-freezes at the end of its own initialize
      def deep_freeze(obj)
        case obj
        when Hash
          obj.each do |k, v|
            deep_freeze(k)
            deep_freeze(v)
          end
          obj.freeze
        when Array
          obj.each { |v| deep_freeze(v) }
          obj.freeze
        when String
          obj.freeze
        else
          obj
        end
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Util
    # Base for classes which need to operate with own values kept
    # in the hash and inherited values kept in a Hash-like object.
    class BaseInheritable
      attr_accessor :inherited_values, :new_values

      # @param inherited_values [Object] An object implementing an interface
      #   of the Hash class.
      def initialize(inherited_values = nil)
        @inherited_values = inherited_values || {}
        @new_values = {}
      end

      def delete(*keys)
        keys.map do |key|
          # since delete returns the deleted value, seems natural to `map` the result
          new_values.delete key
        end
      end

      def initialize_copy(other)
        super
        self.inherited_values = other.inherited_values
        self.new_values = other.new_values.dup
      end

      def keys
        if new_values.any?
          inherited_values.keys.tap do |combined|
            combined.concat(new_values.keys)
            combined.uniq!
          end
        else
          inherited_values.keys
        end
      end

      def key?(name)
        inherited_values.key?(name) || new_values.key?(name)
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  class Router
    class Pattern
      extend Forwardable

      DEFAULT_CAPTURES = %w[format version].freeze

      attr_reader :origin, :path, :pattern, :to_regexp

      def_delegators :pattern, :params
      def_delegators :to_regexp, :===
      alias match? ===

      def initialize(origin:, suffix:, anchor:, params:, format:, version:, requirements:)
        @origin = origin
        @path = PatternCache[[build_path_from_pattern(@origin, anchor), suffix]]
        @pattern = Mustermann::Grape.new(@path, uri_decode: true, params:, capture: extract_capture(format, version, requirements))
        @to_regexp = @pattern.to_regexp
      end

      def captures_default
        to_regexp.names
                 .delete_if { |n| DEFAULT_CAPTURES.include?(n) }
                 .to_h { |k| [k, ''] }
      end

      private

      def extract_capture(format, version, requirements)
        capture = {}
        capture[:format] = map_str(format) if format.present?
        capture[:version] = map_str(version) if version.present?

        return capture if requirements.blank?

        requirements.merge(capture)
      end

      def build_path_from_pattern(pattern, anchor)
        if pattern.end_with?('*path')
          pattern.dup.insert(pattern.rindex('/') + 1, '?')
        elsif anchor
          pattern
        elsif pattern.end_with?('/')
          "#{pattern}?*path"
        else
          "#{pattern}/?*path"
        end
      end

      def map_str(value)
        Array.wrap(value).map(&:to_s)
      end

      class PatternCache < Grape::Util::Cache
        def initialize
          super
          @cache = Hash.new do |h, (pattern, suffix)|
            h[[pattern, suffix]] = -"#{pattern}#{suffix}"
          end
        end
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Validations
    module Validators
      class ValuesValidator < Base
        default_message_key :values

        def initialize(attrs, options, required, scope, opts)
          super
          values = option_value

          # Zero-arity procs return a collection per-request (e.g. DB-backed lists).
          # Non-zero-arity procs are per-element predicates, called directly at validation time.
          # Non-Proc values are wrapped in a zero-arity lambda for a uniform call interface.
          if values.is_a?(Proc)
            @values_call = values
            @values_is_predicate = !values.arity.zero?
          else
            @values_call = -> { values }
            @values_is_predicate = false
          end
        end

        def validate_param!(attr_name, params)
          return unless hash_like?(params)

          val = scrub(params[attr_name])

          return if val.nil? && !required_for_root_scope?
          return if val != false && val.blank? && @allow_blank
          return if check_values?(val, attr_name)

          validation_error!(attr_name)
        end

        private

        def check_values?(val, attr_name)
          param_array = val.nil? ? [nil] : Array.wrap(val)

          if @values_is_predicate
            begin
              param_array.all? { |param| @values_call.call(param) }
            rescue StandardError => e
              warn "Error '#{e}' raised while validating attribute '#{attr_name}'"
              false
            end
          else
            values = @values_call.call
            return true if values.nil?

            param_array.all? { |param| values.include?(param) }
          end
        end

        def required_for_root_scope?
          return false unless @required

          scope = @scope
          scope = scope.parent while scope.lateral?

          scope.root?
        end
      end
    end
  end
end


def check_values?(val, attr_name)
          param_array = val.nil? ? [nil] : Array.wrap(val)

          if @values_is_predicate
            begin
              param_array.all? { |param| @values_call.call(param) }
            rescue StandardError => e
              warn "Error '#{e}' raised while validating attribute '#{attr_name}'"
              false
            end
          else
            values = @values_call.call
            return true if values.nil?

            param_array.all? { |param| values.include?(param) }
          end
        end


# frozen_string_literal: true

module Grape
  module Validations
    module Validators
      class MultipleParamsBase < Base
        def validate!(params)
          attributes = MultipleAttributesIterator.new(@attrs, @scope, params)
          array_errors = []

          attributes.each do |resource_params|
            validate_params!(resource_params)
          rescue Grape::Exceptions::Validation => e
            array_errors << e
          end

          raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
        end

        private

        def keys_in_common(resource_params, known_keys = all_keys)
          return [] unless hash_like?(resource_params)

          known_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
        end

        def all_keys
          @attrs.map { |attr| @scope.full_name(attr) }
        end
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Validations
    module Validators
      class CoerceValidator < Base
        default_message_key :coerce

        def initialize(attrs, options, required, scope, opts)
          super

          raw_type = @options[:type]
          type = hash_like?(raw_type) ? raw_type[:value] : raw_type
          @converter =
            if type.is_a?(Grape::Validations::Types::VariantCollectionCoercer)
              type
            else
              Types.build_coercer(type, method: @options[:method])
            end
        end

        def validate_param!(attr_name, params)
          validation_error!(attr_name) unless hash_like?(params)

          new_value = coerce_value(params[attr_name])

          validation_error!(attr_name, new_value.message || @exception_message) if new_value.is_a?(Types::InvalidValue)

          # Don't assign a value if it is identical. It fixes a problem with Hashie::Mash
          # which looses wrappers for hashes and arrays after reassigning values
          #
          #     h = Hashie::Mash.new(list: [1, 2, 3, 4])
          #     => #<Hashie::Mash list=#<Hashie::Array [1, 2, 3, 4]>>
          #     list = h.list
          #     h[:list] = list
          #     h
          #     => #<Hashie::Mash list=[1, 2, 3, 4]>
          return if params[attr_name].instance_of?(new_value.class) && params[attr_name] == new_value

          params[attr_name] = new_value
        end

        private

        # Calls the converter built at definition time.
        # Custom coercers may raise; any StandardError is treated as an invalid value.
        def coerce_value(val)
          @converter.call(val)
        rescue StandardError
          Types::InvalidValue.new
        end
      end
    end
  end
end

        def hash_like?(obj)
          obj.respond_to?(:key?)
        end

      def build_coercer(type, method: nil, strict: false)
        # no cache since unique
        return create_coercer_instance(type, method, strict) if method.respond_to?(:call)

        CoercerCache[[type, method, strict]]
      end


# frozen_string_literal: true

module Grape
  module Validations
    module Validators
      class LengthValidator < Base
        def initialize(attrs, options, required, scope, opts)
          super

          @min, @max, @is = @options.values_at(:min, :max, :is)
          validate_boundary!(:min, @min)
          validate_boundary!(:max, @max)
          raise ArgumentError, "min #{@min} cannot be greater than max #{@max}" if @min && @max && @min > @max

          return if @is.nil?
          raise ArgumentError, 'is must be an integer greater than zero' unless @is.is_a?(Integer) && @is.positive?
          raise ArgumentError, 'is cannot be combined with min or max' unless @min.nil? && @max.nil?
        end

        def validate_param!(attr_name, params)
          param = params[attr_name]

          return unless param.respond_to?(:length)

          return unless (!@min.nil? && param.length < @min) || (!@max.nil? && param.length > @max) || (!@is.nil? && param.length != @is)

          validation_error!(attr_name, message do
            if @min && @max
              translate(:length, min: @min, max: @max)
            elsif @min
              translate(:length_min, min: @min)
            elsif @max
              translate(:length_max, max: @max)
            else
              translate(:length_is, is: @is)
            end
          end)
        end

        private

        def validate_boundary!(name, val)
          raise ArgumentError, "#{name} must be an integer greater than or equal to zero" if !val.nil? && (!val.is_a?(Integer) || val.negative?)
        end
      end
    end
  end
end


def validate_param!(attr_name, params)
          param = params[attr_name]

          return unless param.respond_to?(:length)

          return unless (!@min.nil? && param.length < @min) || (!@max.nil? && param.length > @max) || (!@is.nil? && param.length != @is)

          validation_error!(attr_name, message do
            if @min && @max
              translate(:length, min: @min, max: @max)
            elsif @min
              translate(:length_min, min: @min)
            elsif @max
              translate(:length_max, max: @max)
            else
              translate(:length_is, is: @is)
            end
          end)
        end

        def validation_error!(attr_name_or_params, message = @exception_message)
          params = attr_name_or_params.is_a?(Array) ? attr_name_or_params : @scope.full_name(attr_name_or_params)
          raise Grape::Exceptions::Validation.new(params:, message:)
        end

translate

      def translate(key, default: MISSING, scope: 'grape.errors.messages', locale: nil, **)
        i18n_opts = { default:, scope:, ** }
        i18n_opts[:locale] = locale if locale
        message = ::I18n.translate(key, **i18n_opts)
        return message unless message.equal?(MISSING)

        effective_default = default.equal?(MISSING) ? [*Array(scope), key].join('.') : default
        return effective_default if fallback_locale?(locale) || fallback_locale_unavailable?

        ::I18n.translate(key, default: effective_default, scope:, locale: FALLBACK_LOCALE, **)
      end


# frozen_string_literal: true

module Grape
  module Validations
    module Validators
      # Base class for all parameter validators.
      #
      # == Freeze contract
      # Validator instances are shared across requests and are frozen after
      # initialization (via +.new+). All inputs (+options+, +opts+, +attrs+)
      # arrive pre-frozen from the DSL boundary, so subclass ivars derived
      # from them are frozen by construction. Lazy ivar assignment
      # (e.g. +memoize+, <tt>||=</tt>) will raise +FrozenError+ at request time.
      class Base
        include Grape::Util::Translation

        attr_reader :attrs

        class << self
          # Declares the default I18n message key used by +validation_error!+.
          # Subclasses that only need a single fixed error message can declare it
          # at the class level instead of overriding +initialize+:
          #
          #   class MyValidator < Grape::Validations::Validators::Base
          #     default_message_key :my_error
          #   end
          #
          # The key is resolved through +message+, so a per-option +:message+
          # override still takes precedence.
          def default_message_key(key = nil)
            if key
              @default_message_key = key
            else
              @default_message_key || (superclass.respond_to?(:default_message_key) ? superclass.default_message_key : nil)
            end
          end

          def new(...)
            super.freeze
          end

          def inherited(klass)
            super
            Validations.register(klass)
          end
        end

        # Creates a new Validator from options specified
        # by a +requires+ or +optional+ directive during
        # parameter definition.
        # @param attrs [Array] names of attributes to which the Validator applies
        # @param options [Object] implementation-dependent Validator options; deep-frozen on assignment
        # @param required [Boolean] attribute(s) are required or optional
        # @param scope [ParamsScope] parent scope for this Validator
        # @param opts [Hash] additional validation options
        def initialize(attrs, options, required, scope, opts)
          @attrs = Array(attrs).freeze
          @options = Grape::Util::DeepFreeze.deep_freeze(options)
          @option = @options # TODO: remove in next major release
          @required = required
          @scope = scope
          @fail_fast, @allow_blank = opts.values_at(:fail_fast, :allow_blank)
          @exception_message = message(self.class.default_message_key) if self.class.default_message_key
        end

        # Validates a given request.
        # @note Override #validate! unless you need to access the entire request.
        # @param request [Grape::Request] the request currently being handled
        # @raise [Grape::Exceptions::Validation] if validation failed
        # @return [void]
        def validate(request)
          return unless @scope.should_validate?(request.params)

          validate!(request.params)
        end

        def fail_fast?
          @fail_fast
        end

        # Validates a given parameter hash.
        # @note Override #validate_param! for per-parameter validation,
        #   or #validate if you need access to the entire request.
        # @param params [Hash] parameters to validate
        # @raise [Grape::Exceptions::Validation] if validation failed
        # @return [void]
        def validate!(params)
          attributes = SingleAttributeIterator.new(@attrs, @scope, params)
          # we collect errors inside array because
          # there may be more than one error per field
          array_errors = []

          attributes.each do |val, attr_name, empty_val|
            next if !@scope.required? && empty_val
            next unless @scope.meets_dependency?(val, params)

            validate_param!(attr_name, val) if @required || (hash_like?(val) && val.key?(attr_name))
          rescue Grape::Exceptions::Validation => e
            array_errors << e
          end

          raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
        end

        protected

        # Validates a single attribute. Override in subclasses.
        # @param attr_name [Symbol, String] the attribute name
        # @param params [Hash] the parameter hash containing the attribute
        # @raise [Grape::Exceptions::Validation] if validation failed
        # @return [void]
        def validate_param!(attr_name, params)
          raise NotImplementedError
        end

        private

        def validation_error!(attr_name_or_params, message = @exception_message)
          params = attr_name_or_params.is_a?(Array) ? attr_name_or_params : @scope.full_name(attr_name_or_params)
          raise Grape::Exceptions::Validation.new(params:, message:)
        end

        def hash_like?(obj)
          obj.respond_to?(:key?)
        end

        def options_key?(key, options = nil)
          current_options = options || @options
          hash_like?(current_options) && current_options.key?(key) && !current_options[key].nil?
        end

        # Returns the effective message for a validation error.
        # Prefers an explicit +:message+ option, then +default_key+.
        # If both are nil, the block (if given) is called to compute a fallback —
        # useful for validators that build a message Hash for deferred i18n interpolation.
        # @example
        #   @exception_message = message(:presence)             # symbol key or custom message
        #   @exception_message = message { build_hash_message } # computed fallback
        def message(default_key = nil)
          key = options_key?(:message) ? @options[:message] : default_key
          return key unless key.nil?

          yield if block_given?
        end

        def option_value
          options_key?(:value) ? @options[:value] : @options
        end

        def scrub(value)
          return value unless value.respond_to?(:valid_encoding?) && !value.valid_encoding?

          value.scrub
        end
      end
    end
  end
end

validate!

      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


# frozen_string_literal: true

module Grape
  module Validations
    module Validators
      class DefaultValidator < Base
        def initialize(attrs, options, required, scope, opts)
          super
          # !important, lazy call at runtime
          @default_call =
            if @options.is_a?(Proc)
              @options.arity.zero? ? proc { @options.call } : @options
            elsif @options.duplicable?
              proc { @options.dup }
            else
              proc { @options }
            end
        end

        def validate!(params)
          attrs = SingleAttributeIterator.new(@attrs, @scope, params)
          attrs.each do |resource_params, attr_name|
            next unless @scope.meets_dependency?(resource_params, params)

            resource_params[attr_name] = @default_call.call(resource_params) if hash_like?(resource_params) && resource_params[attr_name].nil?
          end
        end
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Validations
    module Types
      # Coerces the given value to a type defined via a +type+ argument during
      # initialization. When +strict+ is true, it doesn't coerce a value but check
      # that it has the proper type.
      class PrimitiveCoercer < DryTypeCoercer
        def initialize(type, strict: false)
          super

          @coercer = cache_coercer[type]
        end

        def call(val)
          return InvalidValue.new if reject?(val)
          return nil if val.nil? || treat_as_nil?(val)

          super
        end

        protected

        attr_reader :type

        # This method maintains logic which was defined by Virtus. For example,
        # dry-types is ok to convert an array or a hash to a string, it is supported,
        # but Virtus wouldn't accept it. So, this method only exists to not introduce
        # breaking changes.
        def reject?(val)
          case val
          when Array, Hash
            type == String
          when String
            type == Hash
          else
            false
          end
        end

        # Dry-Types treats an empty string as invalid. However, Grape considers an empty string as
        # absence of a value and coerces it into nil. See a discussion there
        # https://github.com/ruby-grape/grape/pull/2045
        def treat_as_nil?(val)
          val == '' && type != String
        end
      end
    end
  end
end

class PrimitiveCoercer < < DryTypeCoercer


# frozen_string_literal: true

module Grape
  module Validations
    module Types
      # This class is intended for use with Grape endpoint parameters that
      # have been declared to be of variant-type using the +:types+ option.
      # +MultipleTypeCoercer+ will build a coercer for each type declared
      # in the array passed to +:types+ using {Types.build_coercer}. It will
      # apply these coercers to parameter values in the order given to
      # +:types+, and will return the value returned by the first coercer
      # to successfully coerce the parameter value. Therefore if +String+ is
      # an allowed type it should be declared last, since it will always
      # successfully "coerce" the value.
      class MultipleTypeCoercer
        # Construct a new coercer that will attempt to coerce
        # values to the given list of types in the given order.
        #
        # @param types [Array<Class>] list of allowed types
        # @param method [#call,#parse] method by which values should be
        #   coerced. See class docs for default behaviour.
        def initialize(types, method = nil)
          @method = method.respond_to?(:parse) ? method.method(:parse) : method

          @type_coercers = types.map do |type|
            if Types.multiple? type
              VariantCollectionCoercer.new type, @method
            else
              Types.build_coercer type, strict: !@method.nil?
            end
          end
        end

        # Coerces the given value.
        #
        # @param val [String] value to be coerced, in grape
        #   this should always be a string.
        # @return [Object,InvalidValue] the coerced result, or an instance
        #   of {InvalidValue} if the value could not be coerced.
        def call(val)
          # once the value is coerced by the custom method, its type should be checked
          val = @method.call(val) if @method

          coerced_val = InvalidValue.new

          @type_coercers.each do |coercer|
            coerced_val = coercer.call(val)

            return coerced_val unless coerced_val.is_a?(InvalidValue)
          end

          coerced_val
        end
      end
    end
  end
end

initialize

multiple?

      def multiple?(type)
        array_or_set?(type) && type.size > 1
      end


# frozen_string_literal: true

module Grape
  module Validations
    module Types
      # A base class for classes which must identify a coercer to be used.
      # If the +strict+ argument is true, it won't coerce the given value
      # but check its type. More information there
      # https://dry-rb.org/gems/dry-types/main/built-in-types/
      class DryTypeCoercer
        class << self
          # Returns a collection coercer which corresponds to a given type.
          # Example:
          #
          #    collection_coercer_for(Array)
          #    #=> Grape::Validations::Types::ArrayCoercer
          def collection_coercer_for(type)
            case type
            when Array
              ArrayCoercer
            when Set
              SetCoercer
            else
              raise ArgumentError, "Unknown type: #{type}"
            end
          end

          # Returns an instance of a coercer for a given type
          def coercer_instance_for(type, strict: false)
            klass = type.instance_of?(Class) ? PrimitiveCoercer : collection_coercer_for(type)
            klass.new(type, strict:)
          end
        end

        def initialize(type, strict: false)
          @type = type
          @strict = strict
          @cache_coercer = strict ? DryTypes::StrictCache : DryTypes::ParamsCache
        end

        # Coerces the given value to a type which was specified during
        # initialization as a type argument.
        #
        # @param val [Object]
        def call(val)
          return if val.nil?

          @coercer[val]
        rescue Dry::Types::CoercionError
          InvalidValue.new
        end

        protected

        attr_reader :type, :strict, :cache_coercer
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Validations
    module Types
      # This class will detect type classes that implement
      # a class-level +parse+ method. The method should accept one
      # +String+ argument and should return the value coerced to
      # the appropriate type. The method may raise an exception if
      # there are any problems parsing the string.
      #
      # Alternately an optional +method+ may be supplied (see the
      # +coerce_with+ option of {Grape::Dsl::Parameters#requires}).
      # This may be any class or object implementing +parse+ or +call+,
      # with the same contract as described above.
      #
      # Type Checking
      # -------------
      #
      # Calls to +coerced?+ will consult this class to check
      # that the coerced value produced above is in fact of the
      # expected type. By default this class performs a basic check
      # against the type supplied, but this behaviour will be
      # overridden if the class implements a class-level
      # +coerced?+ or +parsed?+ method. This method
      # will receive a single parameter that is the coerced value
      # and should return +true+ if the value meets type expectations.
      # Arbitrary assertions may be made here but the grape validation
      # system should be preferred.
      #
      # Alternately a proc or other object responding to +call+ may be
      # supplied in place of a type. This should implement the same
      # contract as +coerced?+, and must be supplied with a coercion
      # +method+.
      class CustomTypeCoercer
        # A new coercer for the given type specification
        # and coercion method.
        #
        # @param type [Class,#coerced?,#parsed?,#call?]
        #   specifier for the target type. See class docs.
        # @param method [#parse,#call]
        #   optional coercion method. See class docs.
        def initialize(type, method = nil)
          coercion_method = infer_coercion_method type, method
          @method = enforce_symbolized_keys type, coercion_method
          @type_check = infer_type_check(type)
        end

        # Coerces the given value.
        #
        # @param value [String] value to be coerced, in grape
        #   this should always be a string.
        # @return [Object] the coerced result
        def call(val)
          coerced_val = @method.call(val)

          return coerced_val if coerced_val.is_a?(InvalidValue)
          return InvalidValue.new unless coerced?(coerced_val)

          coerced_val
        end

        def coerced?(val)
          val.nil? || @type_check.call(val)
        end

        private

        # Determine the coercion method we're expected to use
        # based on the parameters given.
        #
        # @param type see #new
        # @param method see #new
        # @return [#call] coercion method
        def infer_coercion_method(type, method)
          if method
            if method.respond_to? :parse
              method.method :parse
            else
              method
            end
          else
            # Try to use parse() declared on the target type.
            # This may raise an exception, but we are out of ideas anyway.
            type.method :parse
          end
        end

        # Determine how the type validity of a coerced
        # value should be decided.
        #
        # @param type see #new
        # @return [#call] a procedure which accepts a single parameter
        #   and returns +true+ if the passed object is of the correct type.
        def infer_type_check(type)
          # First check for special class methods
          if type.respond_to? :coerced?
            type.method :coerced?
          elsif type.respond_to? :parsed?
            type.method :parsed?
          elsif type.respond_to? :call
            # Arbitrary proc passed for type validation.
            # Note that this will fail unless a method is also
            # passed, or if the type also implements a parse() method.
            type
          elsif type.is_a?(Enumerable)
            lambda do |value|
              value.is_a?(Enumerable) && value.all? do |val|
                recursive_type_check(type.first, val)
              end
            end
          else
            # By default, do a simple type check
            ->(value) { value.is_a? type }
          end
        end

        def recursive_type_check(type, value)
          if type.is_a?(Enumerable) && value.is_a?(Enumerable)
            value.all? { |val| recursive_type_check(type.first, val) }
          else
            !type.is_a?(Enumerable) && value.is_a?(type)
          end
        end

        # Enforce symbolized keys for complex types
        # by wrapping the coercion method such that
        # any Hash objects in the immediate heirarchy
        # have their keys recursively symbolized.
        # This helps common libs such as JSON to work easily.
        #
        # @param type see #new
        # @param method see #infer_coercion_method
        # @return [#call] +method+ wrapped in an additional
        #   key-conversion step, or just returns +method+
        #   itself if no conversion is deemed to be
        #   necessary.
        def enforce_symbolized_keys(type, method)
          # Collections have all values processed individually
          if [Array, Set].include?(type)
            lambda do |val|
              method.call(val).tap do |new_val|
                new_val.map do |item|
                  item.is_a?(Hash) ? item.deep_symbolize_keys : item
                end
              end
            end

          # Hash objects are processed directly
          elsif type == Hash
            lambda do |val|
              method.call(val).deep_symbolize_keys
            end

          # Simple types are not processed.
          # This includes Array<primitive> types.
          else
            method
          end
        end
      end
    end
  end
end

method

method
method.respond_to? :parse
!(method)
!(method.respond_to? :parse)


def infer_type_check(type)
          # First check for special class methods
          if type.respond_to? :coerced?
            type.method :coerced?
          elsif type.respond_to? :parsed?
            type.method :parsed?
          elsif type.respond_to? :call
            # Arbitrary proc passed for type validation.
            # Note that this will fail unless a method is also
            # passed, or if the type also implements a parse() method.
            type
          elsif type.is_a?(Enumerable)
            lambda do |value|
              value.is_a?(Enumerable) && value.all? do |val|
                recursive_type_check(type.first, val)
              end
            end
          else
            # By default, do a simple type check
            ->(value) { value.is_a? type }
          end
        end

type.respond_to? :coerced?
!(type.respond_to? :coerced?)


def enforce_symbolized_keys(type, method)
          # Collections have all values processed individually
          if [Array, Set].include?(type)
            lambda do |val|
              method.call(val).tap do |new_val|
                new_val.map do |item|
                  item.is_a?(Hash) ? item.deep_symbolize_keys : item
                end
              end
            end

          # Hash objects are processed directly
          elsif type == Hash
            lambda do |val|
              method.call(val).deep_symbolize_keys
            end

          # Simple types are not processed.
          # This includes Array<primitive> types.
          else
            method
          end
        end

[Array, Set].include?(type)
!([Array, Set].include?(type))


# frozen_string_literal: true

module Grape
  module Validations
    module Types
      # This class wraps {MultipleTypeCoercer}, for use with collections
      # that allow members of more than one type.
      class VariantCollectionCoercer
        # Construct a new coercer that will attempt to coerce
        # a list of values such that all members are of one of
        # the given types. The container may also optionally be
        # coerced to a +Set+. An arbitrary coercion +method+ may
        # be supplied, which will be passed the entire collection
        # as a parameter and should return a new collection, or
        # may return the same one if no coercion was required.
        #
        # @param types [Array<Class>,Set<Class>] list of allowed types,
        #   also specifying the container type
        # @param method [#call,#parse] method by which values should be coerced
        def initialize(types, method = nil)
          @types = types
          @method = method.respond_to?(:parse) ? method.method(:parse) : method

          # If we have a coercion method, pass it in here to save
          # building another one, even though we call it directly.
          @member_coercer = MultipleTypeCoercer.new types, method
        end

        # Coerce the given value.
        #
        # @param value [Array<String>] collection of values to be coerced
        # @return [Array<Object>,Set<Object>,InvalidValue]
        #   the coerced result, or an instance
        #   of {InvalidValue} if the value could not be coerced.
        def call(value)
          return unless value.is_a? Array

          value =
            if @method
              @method.call(value)
            else
              value.map { |v| @member_coercer.call(v) }
            end
          return Set.new value if @types.is_a? Set

          value
        end
      end
    end
  end
end

call

call

        def call(val)
          # once the value is coerced by the custom method, its type should be checked
          val = @method.call(val) if @method

          coerced_val = InvalidValue.new

          @type_coercers.each do |coercer|
            coerced_val = coercer.call(val)

            return coerced_val unless coerced_val.is_a?(InvalidValue)
          end

          coerced_val
        end


# frozen_string_literal: true

module Grape
  module Validations
    module Types
      # Coerces elements in an array. It might be an array of strings or integers or
      # an array of arrays of integers.
      #
      # It could've been possible to use an +of+
      # method (https://dry-rb.org/gems/dry-types/main/array-with-member/)
      # provided by dry-types. Unfortunately, it doesn't work for Grape because of
      # behavior of Virtus which was used earlier, a `Grape::Validations::Types::PrimitiveCoercer`
      # maintains Virtus behavior in coercing.
      class ArrayCoercer < DryTypeCoercer
        def initialize(type, strict: false)
          super
          @coercer = strict ? DryTypes::Strict::Array : DryTypes::Params::Array
          @subtype = type.first
        end

        def call(_val)
          collection = super
          return collection if collection.is_a?(InvalidValue)

          coerce_elements collection
        end

        protected

        attr_reader :subtype

        def coerce_elements(collection)
          return if collection.nil?

          collection.each_with_index do |elem, index|
            return InvalidValue.new if reject?(elem)

            coerced_elem = elem_coercer.call(elem)

            return coerced_elem if coerced_elem.is_a?(InvalidValue)

            collection[index] = coerced_elem
          end

          collection
        end

        # This method maintains logic which was defined by Virtus for arrays.
        # Virtus doesn't allow nil in arrays.
        def reject?(val)
          val.nil?
        end

        def elem_coercer
          @elem_coercer ||= DryTypeCoercer.coercer_instance_for(subtype, strict:)
        end
      end
    end
  end
end

reject?

        def reject?(val)
          val.nil?
        end

call

        def call(val)
          return InvalidValue.new if reject?(val)
          return nil if val.nil? || treat_as_nil?(val)

          super
        end


# frozen_string_literal: true

module Grape
  module Middleware
    module Versioner
      class Base < Grape::Middleware::Base
        include Grape::Middleware::PrecomputedContentTypes

        DEFAULT_OPTIONS = {
          pattern: /.*/i,
          prefix: nil,
          mount_path: nil,
          version_options: {
            strict: false,
            cascade: true,
            parameter: 'apiver',
            vendor: nil
          }.freeze
        }.freeze

        CASCADE_PASS_HEADER = { 'X-Cascade' => 'pass' }.freeze

        DEFAULT_OPTIONS.each_key do |key|
          define_method key do
            options[key]
          end
        end

        DEFAULT_OPTIONS[:version_options].each_key do |key|
          define_method key do
            options[:version_options][key]
          end
        end

        def self.inherited(klass)
          super
          Versioner.register(klass)
        end

        attr_reader :error_headers, :versions, :available_media_types

        def initialize(app, **options)
          super
          @error_headers = cascade ? CASCADE_PASS_HEADER : {}
          @versions = options[:versions]&.map(&:to_s) # making sure versions are strings to ease potential match
          @available_media_types = build_available_media_types
        end

        def potential_version_match?(potential_version)
          versions.blank? || versions.include?(potential_version)
        end

        def version_not_found!
          throw :error, status: 404, message: '404 API Version Not Found', headers: CASCADE_PASS_HEADER
        end

        private

        def build_available_media_types
          media_types = []
          base_media_type = "application/vnd.#{vendor}"
          content_types.each_key do |extension|
            versions&.reverse_each do |version|
              media_types << "#{base_media_type}-#{version}+#{extension}"
              media_types << "#{base_media_type}-#{version}"
            end
            media_types << "#{base_media_type}+#{extension}"
          end

          media_types << base_media_type
          media_types.concat(content_types.values.flatten)
          media_types
        end
      end
    end
  end
end


# frozen_string_literal: true

module Grape
  module Middleware
    module Versioner
      # This middleware sets various version related rack environment variables
      # based on the uri path and removes the version substring from the uri
      # path. If the version substring does not match any potential initialized
      # versions, a 404 error is thrown.
      #
      # Example: For a uri path
      #   /v1/resource
      #
      # The following rack env variables are set and path is rewritten to
      # '/resource':
      #
      #   env['api.version'] => 'v1'
      #
      class Path < Base
        def initialize(app, **options)
          super
          @prefixes = [mount_path, Grape::Router.normalize_path(prefix)].select { |p| p.present? && p != '/' }.freeze
        end

        def before
          path_info = Grape::Router.normalize_path(env[Rack::PATH_INFO])
          return if path_info == '/'

          path_info = @prefixes.reduce(path_info) do |pi, path|
            pi.start_with?(path) ? pi.delete_prefix(path) : pi
          end

          slash_position = path_info.index('/', 1) # omit the first one
          return unless slash_position

          potential_version = path_info[1..(slash_position - 1)]
          return unless potential_version.match?(pattern)

          version_not_found! unless potential_version_match?(potential_version)
          env[Grape::Env::API_VERSION] = potential_version
        end
      end
    end
  end
end

before

    def self.normalize_path(path)
      return '/' unless path
      return path if path == '/'

      # Fast path for the overwhelming majority of paths that don't need to be normalized
      return path if path.start_with?('/') && !(path.end_with?('/') || path.match?(%r{%|//}))

      # Slow path
      encoding = path.encoding
      path = "/#{path}"
      path.squeeze!('/')

      unless path == '/'
        path.delete_suffix!('/')
        path.gsub!(/(%[a-f0-9]{2})/) { ::Regexp.last_match(1).upcase }
      end

      path.force_encoding(encoding)
    end

        def potential_version_match?(potential_version)
          versions.blank? || versions.include?(potential_version)
        end


# frozen_string_literal: true

module Grape
  module Middleware
    module Versioner
      # This middleware sets various version related rack environment variables
      # based on the HTTP Accept header with the pattern:
      # application/vnd.:vendor-:version+:format
      #
      # Example: For request header
      #    Accept: application/vnd.mycompany.a-cool-resource-v1+json
      #
      # The following rack env variables are set:
      #
      #    env['api.type']    => 'application'
      #    env['api.subtype'] => 'vnd.mycompany.a-cool-resource-v1+json'
      #    env['api.vendor]   => 'mycompany.a-cool-resource'
      #    env['api.version]  => 'v1'
      #    env['api.format]   => 'json'
      #
      # If version does not match this route, then a 406 is raised with
      # X-Cascade header to alert Grape::Router to attempt the next matched
      # route.
      class Header < Base
        def before
          match_best_quality_media_type! do |media_type|
            env.update(
              Grape::Env::API_TYPE => media_type.type,
              Grape::Env::API_SUBTYPE => media_type.subtype,
              Grape::Env::API_VENDOR => media_type.vendor,
              Grape::Env::API_VERSION => media_type.version,
              Grape::Env::API_FORMAT => media_type.format
            )
          end
        end

        private

        def match_best_quality_media_type!
          return unless vendor

          strict_header_checks!
          media_type = Grape::Util::MediaType.best_quality(accept_header, available_media_types)
          if media_type
            yield media_type
          else
            fail!
          end
        end

        def accept_header
          env['HTTP_ACCEPT']
        end

        def strict_header_checks!
          return unless strict

          accept_header_check!
          version_and_vendor_check!
        end

        def accept_header_check!
          return if accept_header.present?

          invalid_accept_header!('Accept header must be set.')
        end

        def version_and_vendor_check!
          return if versions.blank? || version_and_vendor?

          invalid_accept_header!('API vendor or version not found.')
        end

        def q_values_mime_types
          @q_values_mime_types ||= Rack::Utils.q_values(accept_header).map(&:first)
        end

        def version_and_vendor?
          q_values_mime_types.any? { |mime_type| Grape::Util::MediaType.match?(mime_type) }
        end

        def invalid_accept_header!(message)
          raise Grape::Exceptions::InvalidAcceptHeader.new(message, error_headers)
        end

        def invalid_version_header!(message)
          raise Grape::Exceptions::InvalidVersionHeader.new(message, error_headers)
        end

        def fail!
          return if env[Grape::Env::GRAPE_ALLOWED_METHODS].present?

          media_types = q_values_mime_types.map { |mime_type| Grape::Util::MediaType.parse(mime_type) }
          vendor_not_found!(media_types) || version_not_found!(media_types)
        end

        def vendor_not_found!(media_types)
          return unless media_types.all? { |media_type| media_type&.vendor && media_type.vendor != vendor }

          invalid_accept_header!('API vendor not found.')
        end

        def version_not_found!(media_types)
          return unless media_types.all? { |media_type| media_type&.version && versions && !versions.include?(media_type.version) }

          invalid_version_header!('API version not found.')
        end
      end
    end
  end
end


def match_best_quality_media_type!
          return unless vendor

          strict_header_checks!
          media_type = Grape::Util::MediaType.best_quality(accept_header, available_media_types)
          if media_type
            yield media_type
          else
            fail!
          end
        end

        def best_quality(header, available_media_types)
          parse(best_quality_media_type(header, available_media_types))
        end


# frozen_string_literal: true

module Grape
  module Util
    module Lazy
      class ValueEnumerable < Value
        def [](key)
          if @value_hash[key].nil?
            Value.new(nil).reached_by(access_keys, key)
          else
            @value_hash[key].reached_by(access_keys, key)
          end
        end

        def fetch(access_keys)
          fetched_keys = access_keys.dup
          value = self[fetched_keys.shift]
          fetched_keys.any? ? value.fetch(fetched_keys) : value
        end

        def []=(key, value)
          @value_hash[key] = case value
                             when Hash
                               ValueHash.new(value)
                             when Array
                               ValueArray.new(value)
                             else
                               Value.new(value)
                             end
        end
      end
    end
  end
end