From 9e8bd9d1039646217ef0e6007e3a349631bdd1a3 Mon Sep 17 00:00:00 2001 From: Eddy Nguyen Date: Tue, 23 May 2023 15:56:49 +1000 Subject: [PATCH] Fix scalar input/output object bug when given external file or module pattern (#9418) * Use mapper to ensure path and module cases work in input/output object case * Add test cases to capture scalars from modules * Add test case for scalar input/output for file/module cases * Add changeset * Update default tests to something more practical * Remove extraneous changeset since we haven't released feature * Mapped scalar types are now used as input and output instead of having to be an input/output object --- .../other/visitor-plugin-common/src/utils.ts | 35 ++--- .../typescript/tests/typescript.spec.ts | 124 +++++++++++++++++- 2 files changed, 130 insertions(+), 29 deletions(-) diff --git a/packages/plugins/other/visitor-plugin-common/src/utils.ts b/packages/plugins/other/visitor-plugin-common/src/utils.ts index 4d8d8db8253..f27d91183d2 100644 --- a/packages/plugins/other/visitor-plugin-common/src/utils.ts +++ b/packages/plugins/other/visitor-plugin-common/src/utils.ts @@ -325,39 +325,22 @@ export function buildScalars( outputMapper.type += "['output']"; } - result[name] = { - input: inputMapper, - output: outputMapper, - }; - } else if (scalarsMapping && typeof scalarsMapping[name] === 'string') { - const normalizedScalar = normalizeScalarType(scalarsMapping[name]); - - const inputMapper = parseMapper(normalizedScalar.input, name); - if (inputMapper.isExternal) { - inputMapper.type += "['input']"; - } - - const outputMapper = parseMapper(normalizedScalar.output, name); - if (outputMapper.isExternal) { - outputMapper.type += "['output']"; - } - result[name] = { input: inputMapper, output: outputMapper, }; } else if (scalarsMapping?.[name]) { const mappedScalar = scalarsMapping[name]; - if (typeof mappedScalar === 'object' && mappedScalar.input && mappedScalar.output) { + if (typeof mappedScalar === 'string') { + const normalizedScalar = normalizeScalarType(scalarsMapping[name]); result[name] = { - input: { - isExternal: false, - type: mappedScalar.input, - }, - output: { - isExternal: false, - type: mappedScalar.output, - }, + input: parseMapper(normalizedScalar.input, name), + output: parseMapper(normalizedScalar.output, name), + }; + } else if (typeof mappedScalar === 'object' && mappedScalar.input && mappedScalar.output) { + result[name] = { + input: parseMapper(mappedScalar.input, name), + output: parseMapper(mappedScalar.output, name), }; } else { result[name] = { diff --git a/packages/plugins/typescript/typescript/tests/typescript.spec.ts b/packages/plugins/typescript/typescript/tests/typescript.spec.ts index 732a4f6e1ea..15be990e1f1 100644 --- a/packages/plugins/typescript/typescript/tests/typescript.spec.ts +++ b/packages/plugins/typescript/typescript/tests/typescript.spec.ts @@ -1961,6 +1961,9 @@ describe('TypeScript', () => { scalar MyScalar scalar MyOtherScalar scalar MyAliasedScalar + scalar OrgScalar + scalar OrgOtherScalar + scalar OrgAliasedScalar type MyType { foo: String @@ -1968,6 +1971,9 @@ describe('TypeScript', () => { baz: MyOtherScalar! qux: MyAliasedScalar! tux(in: MyScalar!): MyScalar! + ay: OrgScalar! + bee: OrgOtherScalar! + ce: OrgAliasedScalar! } `); const result = (await plugin( @@ -1978,6 +1984,9 @@ describe('TypeScript', () => { MyScalar: '../../scalars#default', MyOtherScalar: '../../scalars#MyOtherScalar', MyAliasedScalar: '../../scalars#MyAliasedScalar as AliasedScalar', + OrgScalar: '@org/scalars#default', + OrgOtherScalar: '@org/scalars#OrgOtherScalar', + OrgAliasedScalar: '@org/scalars#OrgOtherScalar as OrgAliasedScalar', }, }, { outputFile: '' } @@ -1987,6 +1996,9 @@ describe('TypeScript', () => { expect(result.prepend).toContain(`import MyScalar from '../../scalars';`); expect(result.prepend).toContain(`import { MyOtherScalar } from '../../scalars';`); expect(result.prepend).toContain(`import { MyAliasedScalar as AliasedScalar } from '../../scalars';`); + expect(result.prepend).toContain(`import OrgScalar from '@org/scalars';`); + expect(result.prepend).toContain(`import { OrgOtherScalar } from '@org/scalars';`); + expect(result.prepend).toContain(`import { OrgOtherScalar as OrgAliasedScalar } from '@org/scalars';`); expect(result.content).toBeSimilarStringTo(` export type Scalars = { ID: { input: string | number; output: string; } @@ -1994,9 +2006,112 @@ describe('TypeScript', () => { Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } - MyScalar: { input: MyScalar['input']; output: MyScalar['output']; } - MyOtherScalar: { input: MyOtherScalar['input']; output: MyOtherScalar['output']; } - MyAliasedScalar: { input: AliasedScalar['input']; output: AliasedScalar['output']; } + MyScalar: { input: MyScalar; output: MyScalar; } + MyOtherScalar: { input: MyOtherScalar; output: MyOtherScalar; } + MyAliasedScalar: { input: AliasedScalar; output: AliasedScalar; } + OrgScalar: { input: OrgScalar; output: OrgScalar; } + OrgOtherScalar: { input: OrgOtherScalar; output: OrgOtherScalar; } + OrgAliasedScalar: { input: OrgAliasedScalar; output: OrgAliasedScalar; } + };`); + + expect(result.content).toBeSimilarStringTo(` + export type MyType = { + __typename?: 'MyType'; + foo?: Maybe; + bar: Scalars['MyScalar']['output']; + baz: Scalars['MyOtherScalar']['output']; + qux: Scalars['MyAliasedScalar']['output']; + tux: Scalars['MyScalar']['output']; + ay: Scalars['OrgScalar']['output']; + bee: Scalars['OrgOtherScalar']['output']; + ce: Scalars['OrgAliasedScalar']['output']; + };`); + expect(result.content).toBeSimilarStringTo(` + export type MyTypeTuxArgs = { + in: Scalars['MyScalar']['input']; + }`); + validateTs(result); + }); + + it('Should import a type of a mapped scalar for input/output mapping', async () => { + const schema = buildSchema(/* GraphQL */ ` + scalar MyScalar + scalar MyOtherScalar + scalar MyAliasedScalar + scalar OrgScalar + scalar OrgOtherScalar + scalar OrgAliasedScalar + + type MyType { + foo: String + bar: MyScalar! + baz: MyOtherScalar! + qux: MyAliasedScalar! + tux(in: MyScalar!): MyScalar! + ay: OrgScalar! + bee: OrgOtherScalar! + ce: OrgAliasedScalar! + } + `); + const result = (await plugin( + schema, + [], + { + scalars: { + MyScalar: { + input: '../../scalarsInput#default as MyScalarInput', + output: '../../scalarsOutput#default as MyScalarOutput', + }, + MyOtherScalar: { + input: '../../scalars#MyOtherScalarInput', + output: '../../scalars#MyOtherScalarOutput', + }, + MyAliasedScalar: { + input: '../../scalars#MyAliasedScalar as AliasedScalarInput', + output: '../../scalars#MyAliasedScalar as AliasedScalarOutput', + }, + OrgScalar: { + input: '@org/scalars-input#default as OrgScalarInput', + output: '@org/scalars-output#default as OrgScalarOutput', + }, + OrgOtherScalar: { + input: '@org/scalars#OrgOtherScalarInput', + output: '@org/scalars#OrgOtherScalarOutput', + }, + OrgAliasedScalar: { + input: '@org/scalars#OrgOtherScalar as OrgAliasedScalarInput', + output: '@org/scalars#OrgOtherScalar as OrgAliasedScalarOutput', + }, + }, + }, + { outputFile: '' } + )) as Types.ComplexPluginOutput; + + expect(result.prepend).toContain(`import MyScalarInput from '../../scalarsInput';`); + expect(result.prepend).toContain(`import MyScalarOutput from '../../scalarsOutput';`); + expect(result.prepend).toContain(`import { MyOtherScalarInput } from '../../scalars';`); + expect(result.prepend).toContain(`import { MyOtherScalarOutput } from '../../scalars';`); + expect(result.prepend).toContain(`import { MyAliasedScalar as AliasedScalarInput } from '../../scalars';`); + expect(result.prepend).toContain(`import { MyAliasedScalar as AliasedScalarOutput } from '../../scalars';`); + expect(result.prepend).toContain(`import OrgScalarInput from '@org/scalars-input';`); + expect(result.prepend).toContain(`import OrgScalarOutput from '@org/scalars-output';`); + expect(result.prepend).toContain(`import { OrgOtherScalarInput } from '@org/scalars';`); + expect(result.prepend).toContain(`import { OrgOtherScalarOutput } from '@org/scalars';`); + expect(result.prepend).toContain(`import { OrgOtherScalar as OrgAliasedScalarInput } from '@org/scalars';`); + expect(result.prepend).toContain(`import { OrgOtherScalar as OrgAliasedScalarOutput } from '@org/scalars';`); + expect(result.content).toBeSimilarStringTo(` + export type Scalars = { + ID: { input: string | number; output: string; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + MyScalar: { input: MyScalarInput; output: MyScalarOutput; } + MyOtherScalar: { input: MyOtherScalarInput; output: MyOtherScalarOutput; } + MyAliasedScalar: { input: AliasedScalarInput; output: AliasedScalarOutput; } + OrgScalar: { input: OrgScalarInput; output: OrgScalarOutput; } + OrgOtherScalar: { input: OrgOtherScalarInput; output: OrgOtherScalarOutput; } + OrgAliasedScalar: { input: OrgAliasedScalarInput; output: OrgAliasedScalarOutput; } };`); expect(result.content).toBeSimilarStringTo(` @@ -2007,6 +2122,9 @@ describe('TypeScript', () => { baz: Scalars['MyOtherScalar']['output']; qux: Scalars['MyAliasedScalar']['output']; tux: Scalars['MyScalar']['output']; + ay: Scalars['OrgScalar']['output']; + bee: Scalars['OrgOtherScalar']['output']; + ce: Scalars['OrgAliasedScalar']['output']; };`); expect(result.content).toBeSimilarStringTo(` export type MyTypeTuxArgs = {