lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb



# typed: strict
# frozen_string_literal: true

return unless defined?(ActiveModel::Validations)

module Tapioca
  module Dsl
    module Compilers
      # `Tapioca::Dsl::Compilers::ActiveModelValidationsConfirmation` decorates RBI files for all
      # classes that use [`ActiveModel::Validates::Confirmation`](https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_confirmation_of).
      #
      # For example, with the following class:
      #
      # ~~~rb
      # class User
      #   include ActiveModel::Validations
      #
      #   validates_confirmation_of :password
      #
      #   validates :email, confirmation: true
      # end
      # ~~~
      #
      # this compiler will produce an RBI file with the following content:
      # ~~~rbi
      # # typed: true
      #
      # class User
      #
      #   sig { returns(T.untyped) }
      #   def email_confirmation; end
      #
      #   sig { params(email_confirmation=: T.untyped).returns(T.untyped) }
      #   def email_confirmation=(email_confirmation); end
      #
      #   sig { returns(T.untyped) }
      #   def password_confirmation; end
      #
      #   sig { params(password_confirmation=: T.untyped).returns(T.untyped) }
      #   def password_confirmation=(password_confirmation); end
      # end
      # ~~~
      #: [ConstantType = (Class[ActiveModel::Validations] & ActiveModel::Validations::HelperMethods & ActiveModel::Validations::ClassMethods)]
      class ActiveModelValidationsConfirmation < Compiler
        extend T::Sig

        class << self
          # @override
          #: -> T::Enumerable[Module]
          def gather_constants
            # Collect all the classes that include ActiveModel::Validations
            all_classes.select { |c| ActiveModel::Validations > c }
          end
        end

        # @override
        #: -> void
        def decorate
          confirmation_validators = constant.validators.grep(ActiveModel::Validations::ConfirmationValidator)

          return if confirmation_validators.empty?

          # Create a RBI definition for each class that includes Active::Model::Validations
          root.create_path(constant) do |klass|
            # Create RBI definitions for all the attributes that use confirmation validation
            confirmation_validators.each do |validator|
              validator.attributes.each do |attr_name|
                klass.create_method("#{attr_name}_confirmation", return_type: "T.untyped")
                klass.create_method(
                  "#{attr_name}_confirmation=",
                  parameters: [create_param("#{attr_name}_confirmation", type: "T.untyped")],
                  return_type: "T.untyped",
                )
              end
            end
          end
        end
      end
    end
  end
end