From 30ee6e8509b07a79e1ad2317b1499426057a93ea Mon Sep 17 00:00:00 2001 From: Jonas Thelemann Date: Fri, 23 May 2025 06:45:59 +0200 Subject: [PATCH] fix(typescript-urql-graphcache): improve typing - resolve a duplicate import - improve typing for "empty object" - respect `defaultScalarType` --- .changeset/spicy-paths-lose.md | 5 +++ .../typescript/urql-graphcache/src/index.ts | 21 ++++------ .../tests/__snapshots__/urql.spec.ts.snap | 38 ++++++++----------- .../urql-graphcache/tests/urql.spec.ts | 38 ++++++++++++++++++- 4 files changed, 65 insertions(+), 37 deletions(-) create mode 100644 .changeset/spicy-paths-lose.md diff --git a/.changeset/spicy-paths-lose.md b/.changeset/spicy-paths-lose.md new file mode 100644 index 000000000..2e90f3879 --- /dev/null +++ b/.changeset/spicy-paths-lose.md @@ -0,0 +1,5 @@ +--- +'@graphql-codegen/typescript-urql-graphcache': patch +--- + +Resolve a duplicate import, improve typing for "empty object" and respect `defaultScalarType` diff --git a/packages/plugins/typescript/urql-graphcache/src/index.ts b/packages/plugins/typescript/urql-graphcache/src/index.ts index e3100c20b..50011c9c7 100644 --- a/packages/plugins/typescript/urql-graphcache/src/index.ts +++ b/packages/plugins/typescript/urql-graphcache/src/index.ts @@ -276,14 +276,9 @@ function getOptimisticUpdatersConfig( } function getImports(config: UrqlGraphCacheConfig): string { - return [ - `import { ${ - config.offlineExchange ? 'offlineExchange' : 'cacheExchange' - } } from '@urql/exchange-graphcache';`, - `${ - config.useTypeImports ? 'import type' : 'import' - } { Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache';\n`, - ].join('\n'); + return `${config.useTypeImports ? 'import type' : 'import'} { ${ + config.offlineExchange ? 'offlineExchange' : 'cacheExchange' + }, Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache';\n`; } export const plugin: PluginFunction = ( @@ -305,24 +300,24 @@ export const plugin: PluginFunction = Partial & { __typename: NonNullable };`, + `export type WithTypename = Partial & { __typename: NonNullable };`, keys, 'export type GraphCacheResolvers = {\n' + resolvers.join(',\n') + '\n};', 'export type GraphCacheOptimisticUpdaters = ' + - (optimisticUpdaters ? '{\n ' + optimisticUpdaters.join(',\n ') + '\n};' : '{};'), + (optimisticUpdaters ? '{\n ' + optimisticUpdaters.join(',\n ') + '\n};' : 'object;'), 'export type GraphCacheUpdaters = {\n' + ` ${(queryType && queryType.name) || 'Mutation'}?: ` + - (queryUpdaters ? `{\n ${queryUpdaters.join(',\n ')}\n }` : '{}') + + (queryUpdaters ? `{\n ${queryUpdaters.join(',\n ')}\n }` : 'object') + ',\n' + ` ${(mutationType && mutationType.name) || 'Mutation'}?: ` + - (mutationUpdaters ? `{\n ${mutationUpdaters.join(',\n ')}\n }` : '{}') + + (mutationUpdaters ? `{\n ${mutationUpdaters.join(',\n ')}\n }` : 'object') + ',\n' + ` ${(subscriptionType && subscriptionType.name) || 'Subscription'}?: ` + - (subscriptionUpdaters ? `{\n ${subscriptionUpdaters.join(',\n ')}\n }` : '{}') + + (subscriptionUpdaters ? `{\n ${subscriptionUpdaters.join(',\n ')}\n }` : 'object') + ',\n' + `${typeUpdateResolvers.join(',\n')}` + ',\n};', diff --git a/packages/plugins/typescript/urql-graphcache/tests/__snapshots__/urql.spec.ts.snap b/packages/plugins/typescript/urql-graphcache/tests/__snapshots__/urql.spec.ts.snap index 5b7523747..e4ce45b6c 100644 --- a/packages/plugins/typescript/urql-graphcache/tests/__snapshots__/urql.spec.ts.snap +++ b/packages/plugins/typescript/urql-graphcache/tests/__snapshots__/urql.spec.ts.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`urql graphcache Should correctly name GraphCacheResolvers & GraphCacheOptimisticUpdaters with nonstandard mutationType names 1`] = ` -"import { cacheExchange } from '@urql/exchange-graphcache'; -import { Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; +"import { cacheExchange, Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; export type WithTypename = Partial & { __typename: NonNullable }; @@ -32,7 +31,7 @@ export type GraphCacheUpdaters = { Mutation_Root?: { toggleTodo?: GraphCacheUpdateResolver<{ toggleTodo: WithTypename }, Mutation_RootToggleTodoArgs> }, - Subscription?: {}, + Subscription?: object, Todo?: { id?: GraphCacheUpdateResolver>, Record>, text?: GraphCacheUpdateResolver>, Record>, @@ -49,8 +48,7 @@ export type GraphCacheConfig = Parameters[0] & { `; exports[`urql graphcache Should correctly output GraphCacheOptimisticUpdaters when there are no mutations 1`] = ` -"import { cacheExchange } from '@urql/exchange-graphcache'; -import { Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; +"import { cacheExchange, Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; export type WithTypename = Partial & { __typename: NonNullable }; @@ -69,14 +67,14 @@ export type GraphCacheResolvers = { } }; -export type GraphCacheOptimisticUpdaters = {}; +export type GraphCacheOptimisticUpdaters = object; export type GraphCacheUpdaters = { Query_Root?: { todos?: GraphCacheUpdateResolver<{ todos: Maybe>> }, Record> }, - Mutation?: {}, - Subscription?: {}, + Mutation?: object, + Subscription?: object, Todo?: { id?: GraphCacheUpdateResolver>, Record>, text?: GraphCacheUpdateResolver>, Record>, @@ -93,8 +91,7 @@ export type GraphCacheConfig = Parameters[0] & { `; exports[`urql graphcache Should output the cache-generic correctly (with interfaces) 1`] = ` -"import { cacheExchange } from '@urql/exchange-graphcache'; -import { Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; +"import { cacheExchange, Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; export type WithTypename = Partial & { __typename: NonNullable }; @@ -128,14 +125,14 @@ export type GraphCacheResolvers = { } }; -export type GraphCacheOptimisticUpdaters = {}; +export type GraphCacheOptimisticUpdaters = object; export type GraphCacheUpdaters = { Query?: { schoolBooks?: GraphCacheUpdateResolver<{ schoolBooks: Maybe>> }, Record> }, - Mutation?: {}, - Subscription?: {}, + Mutation?: object, + Subscription?: object, Author?: { id?: GraphCacheUpdateResolver>, Record>, name?: GraphCacheUpdateResolver>, Record>, @@ -165,8 +162,7 @@ export type GraphCacheConfig = Parameters[0] & { `; exports[`urql graphcache Should output the cache-generic correctly (with typesPrefix and typesSuffix) 1`] = ` -"import { cacheExchange } from '@urql/exchange-graphcache'; -import { Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; +"import { cacheExchange, Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; export type WithTypename = Partial & { __typename: NonNullable }; @@ -212,7 +208,7 @@ export type GraphCacheUpdaters = { toggleTodosOptionalEntity?: GraphCacheUpdateResolver<{ toggleTodosOptionalEntity: Array> }, PrefixMutationToggleTodosOptionalEntityArgsSuffix>, toggleTodosOptional?: GraphCacheUpdateResolver<{ toggleTodosOptional: Maybe>> }, PrefixMutationToggleTodosOptionalArgsSuffix> }, - Subscription?: {}, + Subscription?: object, Author?: { id?: GraphCacheUpdateResolver>, Record>, name?: GraphCacheUpdateResolver>, Record>, @@ -236,8 +232,7 @@ export type GraphCacheConfig = Parameters[0] & { `; exports[`urql graphcache Should output the cache-generic correctly (with unions) 1`] = ` -"import { cacheExchange } from '@urql/exchange-graphcache'; -import { Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; +"import { cacheExchange, Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; export type WithTypename = Partial & { __typename: NonNullable }; @@ -273,7 +268,7 @@ export type GraphCacheUpdaters = { Mutation?: { updateMedia?: GraphCacheUpdateResolver<{ updateMedia: Maybe> }, MutationUpdateMediaArgs> }, - Subscription?: {}, + Subscription?: object, Book?: { id?: GraphCacheUpdateResolver>, Record>, title?: GraphCacheUpdateResolver>, Record>, @@ -295,8 +290,7 @@ export type GraphCacheConfig = Parameters[0] & { `; exports[`urql graphcache Should output the cache-generic correctly 1`] = ` -"import { cacheExchange } from '@urql/exchange-graphcache'; -import { Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; +"import { cacheExchange, Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; export type WithTypename = Partial & { __typename: NonNullable }; @@ -342,7 +336,7 @@ export type GraphCacheUpdaters = { toggleTodosOptionalEntity?: GraphCacheUpdateResolver<{ toggleTodosOptionalEntity: Array> }, MutationToggleTodosOptionalEntityArgs>, toggleTodosOptional?: GraphCacheUpdateResolver<{ toggleTodosOptional: Maybe>> }, MutationToggleTodosOptionalArgs> }, - Subscription?: {}, + Subscription?: object, Author?: { id?: GraphCacheUpdateResolver>, Record>, name?: GraphCacheUpdateResolver>, Record>, diff --git a/packages/plugins/typescript/urql-graphcache/tests/urql.spec.ts b/packages/plugins/typescript/urql-graphcache/tests/urql.spec.ts index a8efb3ae5..4afe60781 100644 --- a/packages/plugins/typescript/urql-graphcache/tests/urql.spec.ts +++ b/packages/plugins/typescript/urql-graphcache/tests/urql.spec.ts @@ -166,11 +166,45 @@ describe('urql graphcache', () => { const result = mergeOutputs([await plugin(schema, [], { useTypeImports: true })]); expect(result).toBeSimilarStringTo(`\ -import { cacheExchange } from '@urql/exchange-graphcache'; -import type { Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; +import type { cacheExchange, Resolver as GraphCacheResolver, UpdateResolver as GraphCacheUpdateResolver, OptimisticMutationResolver as GraphCacheOptimisticMutationResolver } from '@urql/exchange-graphcache'; `); }); + it('should emit default scalar type if defaultScalarType config value is used', async () => { + const schema = buildSchema(/* GraphQL */ ` + type Query { + todos: [Todo] + } + + type Mutation { + toggleTodo(id: ID!): Todo! + toggleTodos(id: [ID!]!): [Todo!]! + toggleTodosOptionalArray(id: [ID!]!): [Todo!] + toggleTodosOptionalEntity(id: [ID!]!): [Todo]! + toggleTodosOptional(id: [ID!]!): [Todo] + } + + type Author { + id: ID + name: String + friends: [Author] + friendsPaginated(from: Int!, limit: Int!): [Author] + } + + type Todo { + id: ID + text: String + complete: Boolean + author: Author + } + `); + const result = mergeOutputs([await plugin(schema, [], { defaultScalarType: 'unknown' })]); + + expect(result).toMatch( + `export type WithTypename = Partial & { __typename: NonNullable };`, + ); + }); + it('Should correctly name GraphCacheResolvers & GraphCacheOptimisticUpdaters with nonstandard mutationType names', async () => { const schema = buildSchema(/* GraphQL */ ` schema {