From ef4c2c9c233c68830f10eb4c167c7cceead27122 Mon Sep 17 00:00:00 2001 From: Levin Rickert Date: Tue, 15 Nov 2022 14:52:18 +0100 Subject: [PATCH] Fix @oneOf support broken with declaration kind other than type (#8586) Fixes https://github.com/dotansimha/graphql-code-generator/issues/7938 --- .changeset/afraid-maps-complain.md | 6 +++ .../src/base-types-visitor.ts | 5 ++- .../typescript/tests/typescript.spec.ts | 45 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 .changeset/afraid-maps-complain.md diff --git a/.changeset/afraid-maps-complain.md b/.changeset/afraid-maps-complain.md new file mode 100644 index 00000000000..b418393a505 --- /dev/null +++ b/.changeset/afraid-maps-complain.md @@ -0,0 +1,6 @@ +--- +'@graphql-codegen/visitor-plugin-common': patch +'@graphql-codegen/typescript': patch +--- + +Fix incompatibility between `@oneOf` input types and declaration kind other than `type` diff --git a/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts index c991d3351ca..624ceab739f 100644 --- a/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts @@ -624,9 +624,12 @@ export class BaseTypesVisitor< } getInputObjectOneOfDeclarationBlock(node: InputObjectTypeDefinitionNode): DeclarationBlock { + // As multiple fields always result in a union, we have + // to force a declaration kind of `type` in this case + const declarationKind = node.fields.length === 1 ? this._parsedConfig.declarationKind.input : 'type'; return new DeclarationBlock(this._declarationBlockConfig) .export() - .asKind(this._parsedConfig.declarationKind.input) + .asKind(declarationKind) .withName(this.convertName(node)) .withComment(node.description as any as string) .withContent(`\n` + node.fields.join('\n |')); diff --git a/packages/plugins/typescript/typescript/tests/typescript.spec.ts b/packages/plugins/typescript/typescript/tests/typescript.spec.ts index e7360b70daf..eb71b656c52 100644 --- a/packages/plugins/typescript/typescript/tests/typescript.spec.ts +++ b/packages/plugins/typescript/typescript/tests/typescript.spec.ts @@ -2635,6 +2635,51 @@ describe('TypeScript', () => { `); }); + it('respects configured declaration kind with single field', async () => { + const schema = buildSchema( + /* GraphQL */ ` + input Input @oneOf { + int: Int + } + + type Query { + foo(input: Input!): Boolean! + } + `.concat(oneOfDirectiveDefinition) + ); + + const result = await plugin(schema, [], { declarationKind: 'interface' }, { outputFile: '' }); + + expect(result.content).toBeSimilarStringTo(` + export interface Input { + int: Scalars['Int']; + } + `); + }); + + it('forces declaration kind of type with multiple fields', async () => { + const schema = buildSchema( + /* GraphQL */ ` + input Input @oneOf { + int: Int + boolean: Boolean + } + + type Query { + foo(input: Input!): Boolean! + } + `.concat(oneOfDirectiveDefinition) + ); + + const result = await plugin(schema, [], { declarationKind: 'interface' }, { outputFile: '' }); + + expect(result.content).toBeSimilarStringTo(` + export type Input = + { int: Scalars['Int']; boolean?: never; } + | { int?: never; boolean: Scalars['Boolean']; }; + `); + }); + it('raises exception for type with non-optional fields', async () => { const schema = buildSchema( /* GraphQL */ `