diff --git a/lib/tapioca/dsl/helpers/graphql_type_helper.rb b/lib/tapioca/dsl/helpers/graphql_type_helper.rb index e38bf818c..36e554855 100644 --- a/lib/tapioca/dsl/helpers/graphql_type_helper.rb +++ b/lib/tapioca/dsl/helpers/graphql_type_helper.rb @@ -80,7 +80,9 @@ def type_for(type, ignore_nilable_wrapper: false, prepare_method: nil) signature = Runtime::Reflection.signature_of(method) return_type = signature&.return_type - valid_return_type?(return_type) ? return_type.to_s : "T.untyped" + # Wrap as non-nilable for required arguments. `coerce_input` supports both + # required and optional; optional arguments are re-wrapped below based on `type.non_null?` + valid_return_type?(return_type) ? RBIHelper.as_non_nilable_type(return_type.to_s) : "T.untyped" when GraphQL::Schema::InputObject.singleton_class type_for_constant(unwrapped_type) when Module diff --git a/spec/tapioca/dsl/compilers/graphql_mutation_spec.rb b/spec/tapioca/dsl/compilers/graphql_mutation_spec.rb index 1311f6ae2..4850770d1 100644 --- a/spec/tapioca/dsl/compilers/graphql_mutation_spec.rb +++ b/spec/tapioca/dsl/compilers/graphql_mutation_spec.rb @@ -361,6 +361,45 @@ def resolve(loaded_argument:, loaded_arguments:, custom_name:, optional_loaded_a assert_equal(expected, rbi_for(:CreateComment)) end + it "generates correct RBI for custom scalars whose coerce_input returns a nilable type" do + add_ruby_file("create_comment.rb", <<~RUBY) + class CustomScalar; end + + class NilableScalarType < GraphQL::Schema::Scalar + class << self + extend T::Sig + + sig { params(value: T.untyped, context: GraphQL::Query::Context).returns(T.nilable(CustomScalar)) } + def coerce_input(value, context) + return nil if value.nil? + CustomScalar.new + end + end + end + + class CreateComment < GraphQL::Schema::Mutation + argument :required_scalar, NilableScalarType, required: true + argument :required_scalar_array, [NilableScalarType], required: true + argument :optional_scalar, NilableScalarType, required: false + + def resolve(required_scalar:, required_scalar_array:, optional_scalar: nil) + # ... + end + end + RUBY + + expected = <<~RBI + # typed: strong + + class CreateComment + sig { params(required_scalar: ::CustomScalar, required_scalar_array: T::Array[::CustomScalar], optional_scalar: T.nilable(::CustomScalar)).returns(T.untyped) } + def resolve(required_scalar:, required_scalar_array:, optional_scalar: T.unsafe(nil)); end + end + RBI + + assert_equal(expected, rbi_for(:CreateComment)) + end + it "generates correct RBI for custom scalars with return types" do add_ruby_file("create_comment.rb", <<~RUBY) class CustomScalar; end