class Tapioca::Dsl::Compilers::Protobuf

def decorate

: -> void
@override
def decorate
  root.create_path(constant) do |klass|
    if constant == Google::Protobuf::RepeatedField
      create_type_members(klass, "Elem")
    elsif constant == Google::Protobuf::Map
      create_type_members(klass, "Key", "Value")
    else
      descriptor = T.unsafe(constant).descriptor
      case descriptor
      when Google::Protobuf::EnumDescriptor
        descriptor.to_h.each do |sym, val|
          # For each enum value, create a namespaced constant on the root rather than an un-namespaced
          # constant within the class. This is because un-namespaced constants might conflict with reserved
          # Ruby words, such as "BEGIN." By namespacing them, we avoid this problem.
          #
          # Invalid syntax:
          # class Foo
          #   BEGIN = 3
          # end
          #
          # Valid syntax:
          # Foo::BEGIN = 3
          root.create_constant("#{constant}::#{sym}", value: val.to_s)
        end
        klass.create_method(
          "lookup",
          parameters: [create_param("number", type: "Integer")],
          return_type: "T.nilable(Symbol)",
          class_method: true,
        )
        klass.create_method(
          "resolve",
          parameters: [create_param("symbol", type: "Symbol")],
          return_type: "T.nilable(Integer)",
          class_method: true,
        )
        klass.create_method(
          "descriptor",
          return_type: "Google::Protobuf::EnumDescriptor",
          class_method: true,
        )
      when Google::Protobuf::Descriptor
        raise "#{klass} is not a RBI::Class" unless klass.is_a?(RBI::Class)
        klass.superclass_name = "Google::Protobuf::AbstractMessage"
        descriptor.each_oneof { |oneof| create_oneof_method(klass, oneof) }
        fields = descriptor.map { |desc| create_descriptor_method(klass, desc) }
        fields.sort_by!(&:name)
        parameters = fields.map do |field|
          create_kw_opt_param(field.name, type: field.init_type, default: field.default)
        end
        if fields.all? { |field| FIELD_RE.match?(field.name) }
          klass.create_method("initialize", parameters: parameters, return_type: "void")
        else
          # One of the fields has an incorrect name for a named parameter so creating the default initialize for
          # it would create a RBI with a syntax error.
          # The workaround is to create an initialize that takes a **kwargs instead.
          kwargs_parameter = create_kw_rest_param("fields", type: "T.untyped")
          klass.create_method("initialize", parameters: [kwargs_parameter], return_type: "void")
        end
      else
        add_error(<<~MSG.strip)
          Unexpected descriptor class `#{descriptor.class.name}` for `#{constant}`
        MSG
      end
    end
  end
end