1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Linq ;
4
+ using Microsoft . CodeAnalysis ;
5
+ using Microsoft . CodeAnalysis . CSharp ;
6
+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
7
+ using Tanka . GraphQL . SchemaBuilding ;
8
+ using Tanka . GraphQL . TypeSystem ;
9
+ using static Microsoft . CodeAnalysis . CSharp . SyntaxFactory ;
10
+
11
+ namespace Tanka . GraphQL . Generator . Core
12
+ {
13
+ public class CodeModel
14
+ {
15
+ public static bool IsNullable ( IType type )
16
+ {
17
+ if ( type is NonNull )
18
+ return false ;
19
+
20
+ if ( type is List list )
21
+ return IsNullable ( list . OfType ) ;
22
+
23
+ return true ;
24
+ }
25
+
26
+ public static string SelectFieldTypeName ( SchemaBuilder schema , ComplexType ownerType , KeyValuePair < string , IField > field )
27
+ {
28
+ if ( schema . TryGetDirective ( "gen" , out _ ) )
29
+ {
30
+ if ( field . Value . HasDirective ( "gen" ) )
31
+ {
32
+ var gen = field . Value . GetDirective ( "gen" ) ;
33
+
34
+ var clrType = gen . GetArgument < string > ( "clrType" ) ;
35
+ if ( ! string . IsNullOrEmpty ( clrType ) )
36
+ return clrType ;
37
+ }
38
+ }
39
+
40
+ return SelectTypeName ( field . Value . Type ) ;
41
+ }
42
+
43
+ public static string SelectTypeName ( IType type , bool nullable = true )
44
+ {
45
+ if ( type is NonNull nonNull )
46
+ {
47
+ return SelectTypeName ( nonNull . OfType , false ) ;
48
+ }
49
+
50
+ if ( type is List list )
51
+ {
52
+ var ofType = SelectTypeName ( list . OfType ) ;
53
+
54
+ if ( nullable )
55
+ return $ "IEnumerable<{ ofType } >?";
56
+
57
+ return $ "IEnumerable<{ ofType } >";
58
+ }
59
+
60
+ var typeName = SelectTypeName ( ( INamedType ) type ) ;
61
+
62
+ if ( nullable )
63
+ return $ "{ typeName } ?";
64
+
65
+ return typeName ;
66
+ }
67
+
68
+ public static string SelectTypeName ( INamedType namedType )
69
+ {
70
+ return namedType switch
71
+ {
72
+ ScalarType scalar => SelectScalarTypeName ( scalar ) ,
73
+ ObjectType objectType => SelectObjectTypeName ( objectType ) ,
74
+ EnumType enumType => SelectEnumTypeName ( enumType ) ,
75
+ InputObjectType inputObjectType => SelectInputObjectTypeName ( inputObjectType ) ,
76
+ InterfaceType interfaceType => SelectInterfaceTypeName ( interfaceType ) ,
77
+ UnionType unionType => SelectUnionTypeName ( unionType ) ,
78
+ _ => "object"
79
+ } ;
80
+ }
81
+
82
+ private static string SelectUnionTypeName ( UnionType unionType )
83
+ {
84
+ return unionType . Name . ToModelInterfaceName ( ) ;
85
+ }
86
+
87
+ private static string SelectInterfaceTypeName ( InterfaceType interfaceType )
88
+ {
89
+ return interfaceType . Name . ToModelInterfaceName ( ) ;
90
+ }
91
+
92
+ public static string SelectFieldTypeName ( SchemaBuilder schema , InputObjectType inputObjectType , KeyValuePair < string , InputObjectField > fieldDefinition )
93
+ {
94
+ if ( schema . TryGetDirective ( "gen" , out _ ) )
95
+ {
96
+ if ( fieldDefinition . Value . HasDirective ( "gen" ) )
97
+ {
98
+ var gen = fieldDefinition . Value . GetDirective ( "gen" ) ;
99
+
100
+ var clrType = gen . GetArgument < string > ( "clrType" ) ;
101
+ if ( ! string . IsNullOrEmpty ( clrType ) )
102
+ return clrType ;
103
+ }
104
+ }
105
+
106
+ return SelectTypeName ( fieldDefinition . Value . Type ) ;
107
+ }
108
+
109
+ private static string SelectEnumTypeName ( EnumType objectType )
110
+ {
111
+ return objectType . Name . ToModelName ( ) ;
112
+ }
113
+
114
+ private static string SelectObjectTypeName ( ObjectType objectType )
115
+ {
116
+ return objectType . Name . ToModelName ( ) ;
117
+ }
118
+
119
+ private static string SelectScalarTypeName ( ScalarType scalar )
120
+ {
121
+ if ( StandardScalarToClrType . TryGetValue ( scalar . Name , out var value ) )
122
+ {
123
+ return value ;
124
+ }
125
+
126
+ return "object" ;
127
+ }
128
+
129
+ private static string SelectInputObjectTypeName ( InputObjectType inputObjectType )
130
+ {
131
+ return inputObjectType . Name . ToModelName ( ) ;
132
+ }
133
+
134
+ private static readonly Dictionary < string , string > StandardScalarToClrType = new Dictionary < string , string > ( )
135
+ {
136
+ [ ScalarType . Float . Name ] = "double" ,
137
+ [ ScalarType . Boolean . Name ] = "bool" ,
138
+ [ ScalarType . ID . Name ] = "string" ,
139
+ [ ScalarType . Int . Name ] = "int" ,
140
+ [ ScalarType . String . Name ] = "string"
141
+ } ;
142
+
143
+ public static SyntaxTriviaList ToXmlComment ( string text )
144
+ {
145
+ if ( string . IsNullOrWhiteSpace ( text ) )
146
+ return SyntaxTriviaList . Empty ;
147
+
148
+ var comment = $ "/// <summary>{ Environment . NewLine } "
149
+ + string . Join ( Environment . NewLine , text . Select ( line => $ "/// { line } ") )
150
+ + $ "/// </summary>{ Environment . NewLine } ";
151
+ return SyntaxFactory . ParseLeadingTrivia ( comment ) ;
152
+ }
153
+
154
+ public static bool IsAbstract ( SchemaBuilder schema , ComplexType ownerType , KeyValuePair < string , IField > field )
155
+ {
156
+ // Check for gen override directive
157
+ if ( schema . TryGetDirective ( "gen" , out _ ) )
158
+ {
159
+ if ( field . Value . HasDirective ( "gen" ) )
160
+ {
161
+ var gen = field . Value . GetDirective ( "gen" ) ;
162
+
163
+ var asAbstract = gen . GetArgument < bool > ( "asAbstract" ) ;
164
+
165
+ if ( asAbstract )
166
+ return true ;
167
+
168
+ var asProperty = gen . GetArgument < bool > ( "asProperty" ) ;
169
+
170
+ if ( asProperty )
171
+ return false ;
172
+ }
173
+ }
174
+
175
+ var args = field . Value . Arguments ;
176
+
177
+ // if field has arguments then automatically require implementation for it
178
+ if ( args . Any ( ) )
179
+ return true ;
180
+
181
+ var type = field . Value . Type ;
182
+
183
+ // if complex type (Object, Interface) then requires implementation
184
+ if ( type . Unwrap ( ) is ComplexType )
185
+ return true ;
186
+
187
+ // unions require implementation as they require the actual graph type to be
188
+ // given
189
+ if ( type . Unwrap ( ) is UnionType )
190
+ return true ;
191
+
192
+ if ( schema . IsSubscriptionType ( ownerType ) )
193
+ return true ;
194
+
195
+ return false ;
196
+ }
197
+
198
+ public static MemberDeclarationSyntax TypenameProperty ( string name )
199
+ {
200
+ return PropertyDeclaration (
201
+ PredefinedType (
202
+ Token ( SyntaxKind . StringKeyword ) ) ,
203
+ Identifier ( "__Typename" ) )
204
+ . WithModifiers (
205
+ TokenList (
206
+ Token ( SyntaxKind . PublicKeyword ) ) )
207
+ . WithExpressionBody (
208
+ ArrowExpressionClause (
209
+ LiteralExpression (
210
+ SyntaxKind . StringLiteralExpression ,
211
+ Literal ( name ) ) ) )
212
+ . WithSemicolonToken (
213
+ Token ( SyntaxKind . SemicolonToken ) ) ;
214
+ }
215
+ }
216
+ }
0 commit comments