@@ -19,6 +19,7 @@ import {
19
19
GraphQLEnumType ,
20
20
GraphQLList ,
21
21
GraphQLNonNull ,
22
+ GraphQLSemanticNonNull ,
22
23
GraphQLObjectType ,
23
24
isAbstractType ,
24
25
isEnumType ,
@@ -205,6 +206,40 @@ export const __DirectiveLocation: GraphQLEnumType = new GraphQLEnumType({
205
206
} ,
206
207
} ) ;
207
208
209
+ // TODO: rename enum and options
210
+ enum TypeNullability {
211
+ AUTO = 'AUTO' ,
212
+ TRADITIONAL = 'TRADITIONAL' ,
213
+ SEMANTIC = 'SEMANTIC' ,
214
+ FULL = 'FULL' ,
215
+ }
216
+
217
+ // TODO: rename
218
+ export const __TypeNullability : GraphQLEnumType = new GraphQLEnumType ( {
219
+ name : '__TypeNullability' ,
220
+ description : 'TODO' ,
221
+ values : {
222
+ AUTO : {
223
+ value : TypeNullability . AUTO ,
224
+ description :
225
+ 'Determines nullability mode based on errorPropagation mode.' ,
226
+ } ,
227
+ TRADITIONAL : {
228
+ value : TypeNullability . TRADITIONAL ,
229
+ description : 'Turn semantic-non-null types into nullable types.' ,
230
+ } ,
231
+ SEMANTIC : {
232
+ value : TypeNullability . SEMANTIC ,
233
+ description : 'Turn non-null types into semantic-non-null types.' ,
234
+ } ,
235
+ FULL : {
236
+ value : TypeNullability . FULL ,
237
+ description :
238
+ 'Render the true nullability in the schema; be prepared for new types of nullability in future!' ,
239
+ } ,
240
+ } ,
241
+ } ) ;
242
+
208
243
export const __Type : GraphQLObjectType = new GraphQLObjectType ( {
209
244
name : '__Type' ,
210
245
description :
@@ -370,7 +405,25 @@ export const __Field: GraphQLObjectType = new GraphQLObjectType({
370
405
} ,
371
406
type : {
372
407
type : new GraphQLNonNull ( __Type ) ,
373
- resolve : ( field ) => field . type ,
408
+ args : {
409
+ nullability : {
410
+ type : __TypeNullability ,
411
+ defaultValue : 'AUTO' ,
412
+ } ,
413
+ } ,
414
+ resolve : ( field , { nullability } , _context , info ) => {
415
+ if ( nullability === TypeNullability . FULL ) {
416
+ return field . type ;
417
+ } else {
418
+ const mode =
419
+ nullability === TypeNullability . AUTO
420
+ ? info . errorPropagation
421
+ ? TypeNullability . TRADITIONAL
422
+ : TypeNullability . SEMANTIC
423
+ : nullability ;
424
+ return convertOutputTypeToNullabilityMode ( field . type , mode ) ;
425
+ }
426
+ } ,
374
427
} ,
375
428
isDeprecated : {
376
429
type : new GraphQLNonNull ( GraphQLBoolean ) ,
@@ -383,6 +436,40 @@ export const __Field: GraphQLObjectType = new GraphQLObjectType({
383
436
} as GraphQLFieldConfigMap < GraphQLField < unknown , unknown > , unknown > ) ,
384
437
} ) ;
385
438
439
+ // TODO: move this elsewhere, rename, memoize
440
+ function convertOutputTypeToNullabilityMode (
441
+ type : GraphQLType ,
442
+ mode : TypeNullability . TRADITIONAL | TypeNullability . SEMANTIC ,
443
+ ) : GraphQLType {
444
+ if ( mode === TypeNullability . TRADITIONAL ) {
445
+ if ( isNonNullType ( type ) ) {
446
+ return new GraphQLNonNull (
447
+ convertOutputTypeToNullabilityMode ( type . ofType , mode ) ,
448
+ ) ;
449
+ } else if ( isSemanticNonNullType ( type ) ) {
450
+ return convertOutputTypeToNullabilityMode ( type . ofType , mode ) ;
451
+ } else if ( isListType ( type ) ) {
452
+ return new GraphQLList (
453
+ convertOutputTypeToNullabilityMode ( type . ofType , mode ) ,
454
+ ) ;
455
+ } else {
456
+ return type ;
457
+ }
458
+ } else {
459
+ if ( isNonNullType ( type ) || isSemanticNonNullType ( type ) ) {
460
+ return new GraphQLSemanticNonNull (
461
+ convertOutputTypeToNullabilityMode ( type . ofType , mode ) ,
462
+ ) ;
463
+ } else if ( isListType ( type ) ) {
464
+ return new GraphQLList (
465
+ convertOutputTypeToNullabilityMode ( type . ofType , mode ) ,
466
+ ) ;
467
+ } else {
468
+ return type ;
469
+ }
470
+ }
471
+ }
472
+
386
473
export const __InputValue : GraphQLObjectType = new GraphQLObjectType ( {
387
474
name : '__InputValue' ,
388
475
description :
0 commit comments