diff --git a/benchmarks/GraphQL.Benchmarks/GraphQL.Benchmarks.csproj b/benchmarks/GraphQL.Benchmarks/GraphQL.Benchmarks.csproj index e80878ea6..6f7bf4127 100644 --- a/benchmarks/GraphQL.Benchmarks/GraphQL.Benchmarks.csproj +++ b/benchmarks/GraphQL.Benchmarks/GraphQL.Benchmarks.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/GraphQL.Server.SourceGenerators/GraphQL.Server.SourceGenerators.csproj b/src/GraphQL.Server.SourceGenerators/GraphQL.Server.SourceGenerators.csproj index bc3336db0..f3ce8ee64 100644 --- a/src/GraphQL.Server.SourceGenerators/GraphQL.Server.SourceGenerators.csproj +++ b/src/GraphQL.Server.SourceGenerators/GraphQL.Server.SourceGenerators.csproj @@ -10,10 +10,11 @@ NU5100 false false + true - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -22,7 +23,7 @@ - + diff --git a/src/GraphQL.Server.SourceGenerators/InputTypeDefinition.cs b/src/GraphQL.Server.SourceGenerators/InputTypeDefinition.cs index 29e681c61..1d0d4cad2 100644 --- a/src/GraphQL.Server.SourceGenerators/InputTypeDefinition.cs +++ b/src/GraphQL.Server.SourceGenerators/InputTypeDefinition.cs @@ -6,11 +6,7 @@ namespace Tanka.GraphQL.Server.SourceGenerators; public class InputTypeDefinition: TypeDefinition, IEquatable { - public string? Namespace { get; init; } - - public string TargetType { get; init; } - - public List Properties { get; set; } = new List(); + public List Properties { get; set; } = new(); public ParentClass? ParentClass { get; set; } diff --git a/src/GraphQL.Server.SourceGenerators/InputTypeEmitter.cs b/src/GraphQL.Server.SourceGenerators/InputTypeEmitter.cs index 1302dbebf..a67099a27 100644 --- a/src/GraphQL.Server.SourceGenerators/InputTypeEmitter.cs +++ b/src/GraphQL.Server.SourceGenerators/InputTypeEmitter.cs @@ -30,6 +30,7 @@ public static class {{name}}InputTypeExtensions return builder; } } + """; public SourceProductionContext Context { get; } @@ -69,6 +70,7 @@ private string BuildTypeSdl(InputTypeDefinition definition) { var fieldName = JsonNamingPolicy.CamelCase.ConvertName(field.Name); var fieldType = field.ClosestMatchingGraphQLTypeName; + builder.AppendLine($"{fieldName}: {fieldType}"); } } diff --git a/src/GraphQL.Server.SourceGenerators/InputTypeParser.cs b/src/GraphQL.Server.SourceGenerators/InputTypeParser.cs index dba7b81bd..175dca6ea 100644 --- a/src/GraphQL.Server.SourceGenerators/InputTypeParser.cs +++ b/src/GraphQL.Server.SourceGenerators/InputTypeParser.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -54,13 +55,25 @@ private List ParseMembers(ClassDeclarationSyntax clas return properties; } + + private string GetClosestMatchingGraphQLTypeName(TypeSyntax typeSyntax) { - var typeSymbol = Context.SemanticModel.GetTypeInfo(typeSyntax).Type; + TypeInfo typeInfo = Context.SemanticModel.GetTypeInfo(typeSyntax); + + var typeSymbol = typeInfo.Type; if (typeSymbol is null) return typeSyntax.ToString(); - return TypeHelper.GetGraphQLTypeName(typeSymbol); + var typeName = TypeHelper.GetGraphQLTypeName(typeSymbol); + + // dirty hack until we have a better way to handle this + if (typeSyntax is NullableTypeSyntax && typeName.AsSpan().EndsWith("!")) + { + return typeName.AsSpan().Slice(0, typeName.Length - 1).ToString(); + } + + return typeName; } } \ No newline at end of file diff --git a/src/GraphQL.Server.SourceGenerators/ObjectControllerDefinition.cs b/src/GraphQL.Server.SourceGenerators/ObjectControllerDefinition.cs index 9d9d272ed..4d8d88be3 100644 --- a/src/GraphQL.Server.SourceGenerators/ObjectControllerDefinition.cs +++ b/src/GraphQL.Server.SourceGenerators/ObjectControllerDefinition.cs @@ -6,10 +6,6 @@ namespace Tanka.GraphQL.Server.SourceGenerators; public class ObjectControllerDefinition: TypeDefinition, IEquatable { - public string? Namespace { get; init; } - - public string TargetType { get; init; } - public List Properties { get; set; } = new List(); public List Methods { get; set; } = new List(); @@ -18,7 +14,7 @@ public class ObjectControllerDefinition: TypeDefinition, IEquatable Usings { get; init; } + public IReadOnlyList Usings { get; init; } = []; public virtual bool Equals(ObjectControllerDefinition? other) { diff --git a/src/GraphQL.Server.SourceGenerators/ObjectTypeParser.cs b/src/GraphQL.Server.SourceGenerators/ObjectTypeParser.cs index beb13d5f7..80818f1b2 100644 --- a/src/GraphQL.Server.SourceGenerators/ObjectTypeParser.cs +++ b/src/GraphQL.Server.SourceGenerators/ObjectTypeParser.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using System; namespace Tanka.GraphQL.Server.SourceGenerators { @@ -94,7 +95,15 @@ private static string GetClosestMatchingGraphQLTypeName(SemanticModel model, Typ if (typeSymbol is null) return typeSyntax.ToString(); - return TypeHelper.GetGraphQLTypeName(typeSymbol); + var typeName = TypeHelper.GetGraphQLTypeName(typeSymbol); + + // dirty hack until we have a better way to handle this + if (typeSyntax is NullableTypeSyntax && typeName.AsSpan().EndsWith("!")) + { + return typeName.AsSpan().Slice(0, typeName.Length - 1).ToString(); + } + + return typeName; } } } diff --git a/src/GraphQL.Server.SourceGenerators/TypeHelper.cs b/src/GraphQL.Server.SourceGenerators/TypeHelper.cs index 5b89a9336..91b003f62 100644 --- a/src/GraphQL.Server.SourceGenerators/TypeHelper.cs +++ b/src/GraphQL.Server.SourceGenerators/TypeHelper.cs @@ -10,6 +10,11 @@ namespace Tanka.GraphQL.Server.SourceGenerators; public class TypeHelper { + public static string GetGraphQLTypeName(TypeSyntax typeSyntax) + { + return null; + } + public static string GetGraphQLTypeName(ITypeSymbol typeSymbol) { // Handle arrays @@ -18,10 +23,24 @@ public static string GetGraphQLTypeName(ITypeSymbol typeSymbol) return $"[{GetGraphQLTypeName(arrayTypeSymbol.ElementType)}]"; } - // Handle IEnumerable - if (typeSymbol is INamedTypeSymbol { IsGenericType: true, ConstructedFrom.Name: "IEnumerable" } namedType) + if (typeSymbol is not { SpecialType: SpecialType.System_String }) { - return $"[{GetGraphQLTypeName(namedType.TypeArguments[0])}]"; + var ienumerableT = typeSymbol + .AllInterfaces + .FirstOrDefault(i => + i.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T); + + if (ienumerableT is not null) + { + var innerType = ienumerableT.TypeArguments[0]; + return $"[{GetGraphQLTypeName(innerType)}]"; + } + + // Handle IEnumerable + if (typeSymbol is INamedTypeSymbol { IsGenericType: true, ConstructedFrom.Name: "IEnumerable" } namedType) + { + return $"[{GetGraphQLTypeName(namedType.TypeArguments[0])}]"; + } } bool isNullable = IsNullable(typeSymbol, out typeSymbol); @@ -74,6 +93,7 @@ public static string GetGraphQLTypeName(ITypeSymbol typeSymbol) public static bool IsNullable(ITypeSymbol typeSymbol, out ITypeSymbol innerType) { + if (typeSymbol is INamedTypeSymbol { OriginalDefinition.SpecialType: SpecialType.System_Nullable_T @@ -82,7 +102,7 @@ public static bool IsNullable(ITypeSymbol typeSymbol, out ITypeSymbol innerType) innerType = namedTypeSymbol.TypeArguments[0]; return true; } - + innerType = typeSymbol; return typeSymbol.NullableAnnotation == NullableAnnotation.Annotated; } @@ -412,4 +432,6 @@ public static IReadOnlyList GetUsings(ClassDeclarationSyntax classDeclar .Select(u => u.ToString()) .ToList(); } + + } \ No newline at end of file diff --git a/src/GraphQL.Server/GraphQL.Server.csproj b/src/GraphQL.Server/GraphQL.Server.csproj index 14ca60448..dd5bb519f 100644 --- a/src/GraphQL.Server/GraphQL.Server.csproj +++ b/src/GraphQL.Server/GraphQL.Server.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/GraphQL/GraphQL.csproj b/src/GraphQL/GraphQL.csproj index 19f1fe2c3..fa87cc14d 100644 --- a/src/GraphQL/GraphQL.csproj +++ b/src/GraphQL/GraphQL.csproj @@ -11,8 +11,8 @@ - + - + \ No newline at end of file diff --git a/tests/GraphQL.Extensions.ApolloFederation.Tests/GraphQL.Extensions.ApolloFederation.Tests.csproj b/tests/GraphQL.Extensions.ApolloFederation.Tests/GraphQL.Extensions.ApolloFederation.Tests.csproj index 457422d46..b5d845884 100644 --- a/tests/GraphQL.Extensions.ApolloFederation.Tests/GraphQL.Extensions.ApolloFederation.Tests.csproj +++ b/tests/GraphQL.Extensions.ApolloFederation.Tests/GraphQL.Extensions.ApolloFederation.Tests.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/GraphQL.Extensions.Experimental.Tests/GraphQL.Extensions.Experimental.Tests.csproj b/tests/GraphQL.Extensions.Experimental.Tests/GraphQL.Extensions.Experimental.Tests.csproj index 1200debea..80359e498 100644 --- a/tests/GraphQL.Extensions.Experimental.Tests/GraphQL.Extensions.Experimental.Tests.csproj +++ b/tests/GraphQL.Extensions.Experimental.Tests/GraphQL.Extensions.Experimental.Tests.csproj @@ -10,9 +10,9 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/GraphQL.Extensions.Tracing.Tests/GraphQL.Extensions.Tracing.Tests.csproj b/tests/GraphQL.Extensions.Tracing.Tests/GraphQL.Extensions.Tracing.Tests.csproj index 7b5c24979..eaa7f307f 100644 --- a/tests/GraphQL.Extensions.Tracing.Tests/GraphQL.Extensions.Tracing.Tests.csproj +++ b/tests/GraphQL.Extensions.Tracing.Tests/GraphQL.Extensions.Tracing.Tests.csproj @@ -10,7 +10,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/GraphQL.Language.Tests/GraphQL.Language.Tests.csproj b/tests/GraphQL.Language.Tests/GraphQL.Language.Tests.csproj index 7c7311773..767314230 100644 --- a/tests/GraphQL.Language.Tests/GraphQL.Language.Tests.csproj +++ b/tests/GraphQL.Language.Tests/GraphQL.Language.Tests.csproj @@ -18,7 +18,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/GraphQL.Server.SourceGenerators.Tests.csproj b/tests/GraphQL.Server.SourceGenerators.Tests/GraphQL.Server.SourceGenerators.Tests.csproj index 4a36514d7..f9606a52a 100644 --- a/tests/GraphQL.Server.SourceGenerators.Tests/GraphQL.Server.SourceGenerators.Tests.csproj +++ b/tests/GraphQL.Server.SourceGenerators.Tests/GraphQL.Server.SourceGenerators.Tests.csproj @@ -10,7 +10,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -19,7 +19,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/InputTypeFacts.cs b/tests/GraphQL.Server.SourceGenerators.Tests/InputTypeFacts.cs index 39b5f99b8..5e5edc1a2 100644 --- a/tests/GraphQL.Server.SourceGenerators.Tests/InputTypeFacts.cs +++ b/tests/GraphQL.Server.SourceGenerators.Tests/InputTypeFacts.cs @@ -20,4 +20,56 @@ public class InputMessage return TestHelper.Verify(source); } + [Fact] + public Task Generate_InputType_with_nullable_string() + { + var source = """ + using Tanka.GraphQL.Server; + + [InputType] + public class InputMessage + { + public string? Content { get; set; } + } + """; + + return TestHelper.Verify(source); + } + + [Fact] + public Task Generate_InputType_with_nullable_int() + { + var source = """ + using Tanka.GraphQL.Server; + + [InputType] + public class InputMessage + { + public int? Content { get; set; } + } + """; + + return TestHelper.Verify(source); + } + + [Fact] + public Task Generate_InputType_with_listof_nullable_class() + { + var source = """ + using Tanka.GraphQL.Server; + using System.Collections.Generic; + + [InputType] + public class InputMessage + { + public List Content { get; set; } + } + + public class Person + { + } + """; + + return TestHelper.Verify(source); + } } \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType#InputMessageInputType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType#InputMessageInputType.g.verified.cs index 67aea8547..ea3358fd0 100644 --- a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType#InputMessageInputType.g.verified.cs +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType#InputMessageInputType.g.verified.cs @@ -28,3 +28,4 @@ input InputMessage return builder; } } + diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#Global.SourceGeneratedTypesExtensions.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#Global.SourceGeneratedTypesExtensions.verified.cs new file mode 100644 index 000000000..460802b12 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#Global.SourceGeneratedTypesExtensions.verified.cs @@ -0,0 +1,17 @@ +//HintName: Global.SourceGeneratedTypesExtensions.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Server; +using Tanka.GraphQL.Executable; +using Tanka.GraphQL.ValueResolution; +using Tanka.GraphQL.Fields; + +public static class GlobalSourceGeneratedTypesExtensions +{ + public static SourceGeneratedTypesBuilder AddGlobalTypes(this SourceGeneratedTypesBuilder builder) + { + builder.AddInputMessageInputType(); + return builder; + } +} diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#InputMessageInputType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#InputMessageInputType.g.verified.cs new file mode 100644 index 000000000..386a3de9f --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#InputMessageInputType.g.verified.cs @@ -0,0 +1,30 @@ +//HintName: InputMessageInputType.g.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Server; +using Tanka.GraphQL.Executable; +using Tanka.GraphQL.ValueResolution; +using Tanka.GraphQL.Fields; + + + +public static class InputMessageInputTypeExtensions +{ + public static SourceGeneratedTypesBuilder AddInputMessageInputType( + this SourceGeneratedTypesBuilder builder) + { + builder.Builder.Configure(options => options.Builder.Add( + """ + input InputMessage + { + content: [Person] + } + """ + ) + ); + + return builder; + } +} + diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#InputType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#InputType.g.verified.cs new file mode 100644 index 000000000..7f21cfdc9 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#InputType.g.verified.cs @@ -0,0 +1,12 @@ +//HintName: InputType.g.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Executable; + +namespace Tanka.GraphQL.Server; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class InputTypeAttribute: Attribute +{ +} \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#ObjectType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#ObjectType.g.verified.cs new file mode 100644 index 000000000..c39935439 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_listof_nullable_class#ObjectType.g.verified.cs @@ -0,0 +1,39 @@ +//HintName: ObjectType.g.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Executable; + +namespace Tanka.GraphQL.Server; + +public static class SourceGeneratedExecutableSchemaExtensions +{ + public static OptionsBuilder AddGeneratedTypes( + this OptionsBuilder builder, + Action configureTypes) + { + var typesBuilder = new SourceGeneratedTypesBuilder(builder); + configureTypes(typesBuilder); + return builder; + } +} + +public class SourceGeneratedTypesBuilder +{ + public OptionsBuilder Builder { get; } + + public SourceGeneratedTypesBuilder(OptionsBuilder builder) + { + Builder = builder; + } +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class ObjectTypeAttribute: Attribute +{ +} + +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class FromArgumentsAttribute: Attribute +{ +} \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#Global.SourceGeneratedTypesExtensions.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#Global.SourceGeneratedTypesExtensions.verified.cs new file mode 100644 index 000000000..240626493 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#Global.SourceGeneratedTypesExtensions.verified.cs @@ -0,0 +1,17 @@ +//HintName: Global.SourceGeneratedTypesExtensions.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Server; +using Tanka.GraphQL.Executable; +using Tanka.GraphQL.ValueResolution; +using Tanka.GraphQL.Fields; + +public static class GlobalSourceGeneratedTypesExtensions +{ + public static SourceGeneratedTypesBuilder AddGlobalTypes(this SourceGeneratedTypesBuilder builder) + { + builder.AddInputMessageInputType(); + return builder; + } +} \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#InputMessageInputType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#InputMessageInputType.g.verified.cs new file mode 100644 index 000000000..307faba0b --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#InputMessageInputType.g.verified.cs @@ -0,0 +1,30 @@ +//HintName: InputMessageInputType.g.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Server; +using Tanka.GraphQL.Executable; +using Tanka.GraphQL.ValueResolution; +using Tanka.GraphQL.Fields; + + + +public static class InputMessageInputTypeExtensions +{ + public static SourceGeneratedTypesBuilder AddInputMessageInputType( + this SourceGeneratedTypesBuilder builder) + { + builder.Builder.Configure(options => options.Builder.Add( + """ + input InputMessage + { + id: String! + content: String + } + """ + ) + ); + + return builder; + } +} \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#InputType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#InputType.g.verified.cs new file mode 100644 index 000000000..d283e1378 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#InputType.g.verified.cs @@ -0,0 +1,14 @@ +//HintName: InputType.g.cs +using System; +using System.Threading.Tasks; + +using Microsoft.Extensions.Options; + +using Tanka.GraphQL.Executable; + +namespace Tanka.GraphQL.Server; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class InputTypeAttribute : Attribute +{ +} \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#ObjectType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#ObjectType.g.verified.cs new file mode 100644 index 000000000..82fec1aac --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable#ObjectType.g.verified.cs @@ -0,0 +1,41 @@ +//HintName: ObjectType.g.cs +using System; +using System.Threading.Tasks; + +using Microsoft.Extensions.Options; + +using Tanka.GraphQL.Executable; + +namespace Tanka.GraphQL.Server; + +public static class SourceGeneratedExecutableSchemaExtensions +{ + public static OptionsBuilder AddGeneratedTypes( + this OptionsBuilder builder, + Action configureTypes) + { + var typesBuilder = new SourceGeneratedTypesBuilder(builder); + configureTypes(typesBuilder); + return builder; + } +} + +public class SourceGeneratedTypesBuilder +{ + public OptionsBuilder Builder { get; } + + public SourceGeneratedTypesBuilder(OptionsBuilder builder) + { + Builder = builder; + } +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class ObjectTypeAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class FromArgumentsAttribute : Attribute +{ +} \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#Global.SourceGeneratedTypesExtensions.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#Global.SourceGeneratedTypesExtensions.verified.cs new file mode 100644 index 000000000..460802b12 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#Global.SourceGeneratedTypesExtensions.verified.cs @@ -0,0 +1,17 @@ +//HintName: Global.SourceGeneratedTypesExtensions.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Server; +using Tanka.GraphQL.Executable; +using Tanka.GraphQL.ValueResolution; +using Tanka.GraphQL.Fields; + +public static class GlobalSourceGeneratedTypesExtensions +{ + public static SourceGeneratedTypesBuilder AddGlobalTypes(this SourceGeneratedTypesBuilder builder) + { + builder.AddInputMessageInputType(); + return builder; + } +} diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#InputMessageInputType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#InputMessageInputType.g.verified.cs new file mode 100644 index 000000000..80e74f531 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#InputMessageInputType.g.verified.cs @@ -0,0 +1,30 @@ +//HintName: InputMessageInputType.g.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Server; +using Tanka.GraphQL.Executable; +using Tanka.GraphQL.ValueResolution; +using Tanka.GraphQL.Fields; + + + +public static class InputMessageInputTypeExtensions +{ + public static SourceGeneratedTypesBuilder AddInputMessageInputType( + this SourceGeneratedTypesBuilder builder) + { + builder.Builder.Configure(options => options.Builder.Add( + """ + input InputMessage + { + content: Int + } + """ + ) + ); + + return builder; + } +} + diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#InputType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#InputType.g.verified.cs new file mode 100644 index 000000000..7f21cfdc9 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#InputType.g.verified.cs @@ -0,0 +1,12 @@ +//HintName: InputType.g.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Executable; + +namespace Tanka.GraphQL.Server; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class InputTypeAttribute: Attribute +{ +} \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#ObjectType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#ObjectType.g.verified.cs new file mode 100644 index 000000000..c39935439 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_int#ObjectType.g.verified.cs @@ -0,0 +1,39 @@ +//HintName: ObjectType.g.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Executable; + +namespace Tanka.GraphQL.Server; + +public static class SourceGeneratedExecutableSchemaExtensions +{ + public static OptionsBuilder AddGeneratedTypes( + this OptionsBuilder builder, + Action configureTypes) + { + var typesBuilder = new SourceGeneratedTypesBuilder(builder); + configureTypes(typesBuilder); + return builder; + } +} + +public class SourceGeneratedTypesBuilder +{ + public OptionsBuilder Builder { get; } + + public SourceGeneratedTypesBuilder(OptionsBuilder builder) + { + Builder = builder; + } +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class ObjectTypeAttribute: Attribute +{ +} + +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class FromArgumentsAttribute: Attribute +{ +} \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#Global.SourceGeneratedTypesExtensions.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#Global.SourceGeneratedTypesExtensions.verified.cs new file mode 100644 index 000000000..460802b12 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#Global.SourceGeneratedTypesExtensions.verified.cs @@ -0,0 +1,17 @@ +//HintName: Global.SourceGeneratedTypesExtensions.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Server; +using Tanka.GraphQL.Executable; +using Tanka.GraphQL.ValueResolution; +using Tanka.GraphQL.Fields; + +public static class GlobalSourceGeneratedTypesExtensions +{ + public static SourceGeneratedTypesBuilder AddGlobalTypes(this SourceGeneratedTypesBuilder builder) + { + builder.AddInputMessageInputType(); + return builder; + } +} diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#InputMessageInputType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#InputMessageInputType.g.verified.cs new file mode 100644 index 000000000..2fe70dd0f --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#InputMessageInputType.g.verified.cs @@ -0,0 +1,30 @@ +//HintName: InputMessageInputType.g.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Server; +using Tanka.GraphQL.Executable; +using Tanka.GraphQL.ValueResolution; +using Tanka.GraphQL.Fields; + + + +public static class InputMessageInputTypeExtensions +{ + public static SourceGeneratedTypesBuilder AddInputMessageInputType( + this SourceGeneratedTypesBuilder builder) + { + builder.Builder.Configure(options => options.Builder.Add( + """ + input InputMessage + { + content: String + } + """ + ) + ); + + return builder; + } +} + diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#InputType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#InputType.g.verified.cs new file mode 100644 index 000000000..7f21cfdc9 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#InputType.g.verified.cs @@ -0,0 +1,12 @@ +//HintName: InputType.g.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Executable; + +namespace Tanka.GraphQL.Server; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class InputTypeAttribute: Attribute +{ +} \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#ObjectType.g.verified.cs b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#ObjectType.g.verified.cs new file mode 100644 index 000000000..c39935439 --- /dev/null +++ b/tests/GraphQL.Server.SourceGenerators.Tests/Snapshots/InputTypeFacts.Generate_InputType_with_nullable_string#ObjectType.g.verified.cs @@ -0,0 +1,39 @@ +//HintName: ObjectType.g.cs +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Tanka.GraphQL.Executable; + +namespace Tanka.GraphQL.Server; + +public static class SourceGeneratedExecutableSchemaExtensions +{ + public static OptionsBuilder AddGeneratedTypes( + this OptionsBuilder builder, + Action configureTypes) + { + var typesBuilder = new SourceGeneratedTypesBuilder(builder); + configureTypes(typesBuilder); + return builder; + } +} + +public class SourceGeneratedTypesBuilder +{ + public OptionsBuilder Builder { get; } + + public SourceGeneratedTypesBuilder(OptionsBuilder builder) + { + Builder = builder; + } +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class ObjectTypeAttribute: Attribute +{ +} + +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class FromArgumentsAttribute: Attribute +{ +} \ No newline at end of file diff --git a/tests/GraphQL.Server.SourceGenerators.Tests/TestHelper.cs b/tests/GraphQL.Server.SourceGenerators.Tests/TestHelper.cs index 30e900fb4..8d2a1024d 100644 --- a/tests/GraphQL.Server.SourceGenerators.Tests/TestHelper.cs +++ b/tests/GraphQL.Server.SourceGenerators.Tests/TestHelper.cs @@ -1,5 +1,7 @@ using System.Reflection; using System.Runtime.CompilerServices; +using System.Text; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -9,7 +11,13 @@ namespace Tanka.GraphQL.Server.SourceGenerators.Tests; { public static Task Verify(string source, [CallerFilePath] string sourceFile = "") { - SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source); + source = new StringBuilder() + .AppendLine("#nullable enable") + .AppendLine(source) + .AppendLine("#nullable restore") + .ToString(); + + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp12)); var assemblyReferences = typeof(TGenerator).Assembly .GetReferencedAssemblies() @@ -27,14 +35,17 @@ public static Task Verify(string source, [CallerFilePath] string sourceFile = "" CSharpCompilation compilation = CSharpCompilation.Create( assemblyName: $"{typeof(TGenerator).Name}.GeneratedSources", syntaxTrees: new[] { syntaxTree }, - references: references); + references: references, + new CSharpCompilationOptions( + OutputKind.DynamicallyLinkedLibrary, + nullableContextOptions: NullableContextOptions.Enable)); var generator = new TGenerator(); GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); driver = driver.RunGenerators(compilation); - + var diagnostics = driver.GetRunResult().Diagnostics; return Verifier // ReSharper disable once ExplicitCallerInfoArgument .Verify(driver, sourceFile: sourceFile) diff --git a/tests/GraphQL.Server.Tests/GraphQL.Server.Tests.csproj b/tests/GraphQL.Server.Tests/GraphQL.Server.Tests.csproj index 1d705bd1f..1912e9000 100644 --- a/tests/GraphQL.Server.Tests/GraphQL.Server.Tests.csproj +++ b/tests/GraphQL.Server.Tests/GraphQL.Server.Tests.csproj @@ -9,7 +9,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -18,7 +18,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/tests/GraphQL.Tests.Data/GraphQL.Mock.Data.csproj b/tests/GraphQL.Tests.Data/GraphQL.Mock.Data.csproj index 173ab20ba..afa14c919 100644 --- a/tests/GraphQL.Tests.Data/GraphQL.Mock.Data.csproj +++ b/tests/GraphQL.Tests.Data/GraphQL.Mock.Data.csproj @@ -8,7 +8,7 @@ - + diff --git a/tests/GraphQL.Tests/GraphQL.Tests.csproj b/tests/GraphQL.Tests/GraphQL.Tests.csproj index a636d4d55..9ce241959 100644 --- a/tests/GraphQL.Tests/GraphQL.Tests.csproj +++ b/tests/GraphQL.Tests/GraphQL.Tests.csproj @@ -17,8 +17,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tutorials/GraphQL.Tutorials.Getting-Started/GraphQL.Tutorials.GettingStarted.csproj b/tutorials/GraphQL.Tutorials.Getting-Started/GraphQL.Tutorials.GettingStarted.csproj index 2595ba9cd..dec8eb24f 100644 --- a/tutorials/GraphQL.Tutorials.Getting-Started/GraphQL.Tutorials.GettingStarted.csproj +++ b/tutorials/GraphQL.Tutorials.Getting-Started/GraphQL.Tutorials.GettingStarted.csproj @@ -9,12 +9,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - +