From 5867f34793c1beaa8a84ea15d9c0ee18e0ee966c Mon Sep 17 00:00:00 2001 From: Jovi De Croock Date: Wed, 12 Feb 2025 03:54:43 +0100 Subject: [PATCH] Cleanup and code coverage --- .../__tests__/semantic-nullability-test.ts | 26 ---------- src/type/__tests__/introspection-test.ts | 12 +---- src/type/directives.ts | 11 +++++ src/type/introspection.ts | 47 ++++++------------- src/utilities/__tests__/printSchema-test.ts | 16 ++----- src/utilities/getIntrospectionQuery.ts | 6 +-- 6 files changed, 33 insertions(+), 85 deletions(-) diff --git a/src/execution/__tests__/semantic-nullability-test.ts b/src/execution/__tests__/semantic-nullability-test.ts index 6d9098d016..613ab91d1c 100644 --- a/src/execution/__tests__/semantic-nullability-test.ts +++ b/src/execution/__tests__/semantic-nullability-test.ts @@ -165,32 +165,6 @@ describe('Execute: Handles Semantic Nullability', () => { }); }); - it('SemanticNullable allows null values', async () => { - const data = { - a: () => null, - b: () => null, - c: () => 'Cookie', - }; - - const document = parse(` - query { - a - } - `); - - const result = await execute({ - schema: new GraphQLSchema({ query: DataType }), - document, - rootValue: data, - }); - - expect(result).to.deep.equal({ - data: { - a: null, - }, - }); - }); - it('SemanticNullable allows non-null values', async () => { const data = { a: () => 'Apple', diff --git a/src/type/__tests__/introspection-test.ts b/src/type/__tests__/introspection-test.ts index 9b0eaa11a4..e12e7fc464 100644 --- a/src/type/__tests__/introspection-test.ts +++ b/src/type/__tests__/introspection-test.ts @@ -523,7 +523,7 @@ describe('Introspection', () => { ofType: null, }, }, - defaultValue: 'AUTO', + defaultValue: 'TRADITIONAL', }, ], type: { @@ -667,21 +667,11 @@ describe('Introspection', () => { inputFields: null, interfaces: null, enumValues: [ - { - name: 'AUTO', - isDeprecated: false, - deprecationReason: null, - }, { name: 'TRADITIONAL', isDeprecated: false, deprecationReason: null, }, - { - name: 'SEMANTIC', - isDeprecated: false, - deprecationReason: null, - }, { name: 'FULL', isDeprecated: false, diff --git a/src/type/directives.ts b/src/type/directives.ts index 6881f20532..276eb38aa7 100644 --- a/src/type/directives.ts +++ b/src/type/directives.ts @@ -165,6 +165,17 @@ export const GraphQLSkipDirective: GraphQLDirective = new GraphQLDirective({ }, }); +/** + * Used to indicate that the nullability of the document will be parsed as semantic-non-null types. + */ +export const GraphQLSemanticNullabilityDirective: GraphQLDirective = + new GraphQLDirective({ + name: 'SemanticNullability', + description: + 'Indicates that the nullability of the document will be parsed as semantic-non-null types.', + locations: [DirectiveLocation.SCHEMA], + }); + /** * Constant string used for default reason for a deprecation. */ diff --git a/src/type/introspection.ts b/src/type/introspection.ts index b77ea37380..950cf8958e 100644 --- a/src/type/introspection.ts +++ b/src/type/introspection.ts @@ -206,36 +206,23 @@ export const __DirectiveLocation: GraphQLEnumType = new GraphQLEnumType({ }, }); -// TODO: rename enum and options enum TypeNullability { - AUTO = 'AUTO', TRADITIONAL = 'TRADITIONAL', - SEMANTIC = 'SEMANTIC', FULL = 'FULL', } -// TODO: rename export const __TypeNullability: GraphQLEnumType = new GraphQLEnumType({ name: '__TypeNullability', - description: 'TODO', + description: + 'This represents the type of nullability we want to return as part of the introspection.', values: { - AUTO: { - value: TypeNullability.AUTO, - description: - 'Determines nullability mode based on errorPropagation mode.', - }, TRADITIONAL: { value: TypeNullability.TRADITIONAL, description: 'Turn semantic-non-null types into nullable types.', }, - SEMANTIC: { - value: TypeNullability.SEMANTIC, - description: 'Turn non-null types into semantic-non-null types.', - }, FULL: { value: TypeNullability.FULL, - description: - 'Render the true nullability in the schema; be prepared for new types of nullability in future!', + description: 'Allow for returning semantic-non-null types.', }, }, }); @@ -408,22 +395,11 @@ export const __Field: GraphQLObjectType = new GraphQLObjectType({ args: { nullability: { type: new GraphQLNonNull(__TypeNullability), - defaultValue: TypeNullability.AUTO, + defaultValue: TypeNullability.TRADITIONAL, }, }, - resolve: (field, { nullability }, _context, info) => { - if (nullability === TypeNullability.FULL) { - return field.type; - } - - const mode = - nullability === TypeNullability.AUTO - ? info.errorPropagation - ? TypeNullability.TRADITIONAL - : TypeNullability.SEMANTIC - : nullability; - return convertOutputTypeToNullabilityMode(field.type, mode); - }, + resolve: (field, { nullability }, _context) => + convertOutputTypeToNullabilityMode(field.type, nullability), }, isDeprecated: { type: new GraphQLNonNull(GraphQLBoolean), @@ -436,10 +412,9 @@ export const __Field: GraphQLObjectType = new GraphQLObjectType({ } as GraphQLFieldConfigMap, unknown>), }); -// TODO: move this elsewhere, rename, memoize function convertOutputTypeToNullabilityMode( type: GraphQLType, - mode: TypeNullability.TRADITIONAL | TypeNullability.SEMANTIC, + mode: TypeNullability, ): GraphQLType { if (mode === TypeNullability.TRADITIONAL) { if (isNonNullType(type)) { @@ -455,7 +430,12 @@ function convertOutputTypeToNullabilityMode( } return type; } - if (isNonNullType(type) || isSemanticNonNullType(type)) { + + if (isNonNullType(type)) { + return new GraphQLNonNull( + convertOutputTypeToNullabilityMode(type.ofType, mode), + ); + } else if (isSemanticNonNullType(type)) { return new GraphQLSemanticNonNull( convertOutputTypeToNullabilityMode(type.ofType, mode), ); @@ -464,6 +444,7 @@ function convertOutputTypeToNullabilityMode( convertOutputTypeToNullabilityMode(type.ofType, mode), ); } + return type; } diff --git a/src/utilities/__tests__/printSchema-test.ts b/src/utilities/__tests__/printSchema-test.ts index b651bf16a8..e94bd2fb79 100644 --- a/src/utilities/__tests__/printSchema-test.ts +++ b/src/utilities/__tests__/printSchema-test.ts @@ -782,7 +782,7 @@ describe('Type System Printer', () => { name: String! description: String args(includeDeprecated: Boolean = false): [__InputValue!]! - type(nullability: __TypeNullability! = AUTO): __Type! + type(nullability: __TypeNullability! = TRADITIONAL): __Type! isDeprecated: Boolean! deprecationReason: String } @@ -803,20 +803,14 @@ describe('Type System Printer', () => { deprecationReason: String } - """TODO""" + """ + This represents the type of nullability we want to return as part of the introspection. + """ enum __TypeNullability { - """Determines nullability mode based on errorPropagation mode.""" - AUTO - """Turn semantic-non-null types into nullable types.""" TRADITIONAL - """Turn non-null types into semantic-non-null types.""" - SEMANTIC - - """ - Render the true nullability in the schema; be prepared for new types of nullability in future! - """ + """Allow for returning semantic-non-null types.""" FULL } diff --git a/src/utilities/getIntrospectionQuery.ts b/src/utilities/getIntrospectionQuery.ts index dda0e7f19a..e9a8a796df 100644 --- a/src/utilities/getIntrospectionQuery.ts +++ b/src/utilities/getIntrospectionQuery.ts @@ -42,13 +42,11 @@ export interface IntrospectionOptions { /** * Choose the type of nullability you would like to see. * - * - AUTO: SEMANTIC if errorPropagation is set to false, otherwise TRADITIONAL * - TRADITIONAL: all GraphQLSemanticNonNull will be unwrapped - * - SEMANTIC: all GraphQLNonNull will be converted to GraphQLSemanticNonNull * - FULL: the true nullability will be returned * */ - nullability?: 'AUTO' | 'TRADITIONAL' | 'SEMANTIC' | 'FULL'; + nullability?: 'TRADITIONAL' | 'FULL'; } /** @@ -63,7 +61,7 @@ export function getIntrospectionQuery(options?: IntrospectionOptions): string { schemaDescription: false, inputValueDeprecation: false, oneOf: false, - nullability: null, + nullability: 'TRADITIONAL', ...options, };