diff --git a/.changeset/great-dancers-pump.md b/.changeset/great-dancers-pump.md new file mode 100644 index 00000000000..db87d0297d2 --- /dev/null +++ b/.changeset/great-dancers-pump.md @@ -0,0 +1,5 @@ +--- +'@graphql-codegen/client-preset': minor +--- + +Forward customDirectives to support Apollo unmask diff --git a/packages/presets/client/src/index.ts b/packages/presets/client/src/index.ts index d4217659043..8b60bc3fa4a 100644 --- a/packages/presets/client/src/index.ts +++ b/packages/presets/client/src/index.ts @@ -136,6 +136,7 @@ export const preset: Types.OutputPreset = { skipTypeNameForRoot: options.config.skipTypeNameForRoot, onlyOperationTypes: options.config.onlyOperationTypes, onlyEnumTypes: options.config.onlyEnumTypes, + customDirectives: options.config.customDirectives, }; const visitor = new ClientSideBaseVisitor(options.schemaAst!, [], options.config, options.config); diff --git a/packages/presets/client/tests/client-preset.spec.ts b/packages/presets/client/tests/client-preset.spec.ts index 03bce9c8949..75caa761540 100644 --- a/packages/presets/client/tests/client-preset.spec.ts +++ b/packages/presets/client/tests/client-preset.spec.ts @@ -517,6 +517,98 @@ export * from "./gql";`); expect(graphqlFile.content).toContain("__typename: 'Query';"); }); + it('supports Apollo fragment masking', async () => { + const result = await executeCodegen({ + schema: /* GraphQL */ ` + type Query { + me: User + } + + type User { + id: ID! + name: String! + age: Int! + } + `, + documents: /* GraphQL */ ` + query Me { + unmasked: me { + id + ...User_Me @unmask + } + masked: me { + id + ...User_Me + } + } + + fragment User_Me on User { + name + age + } + `, + generates: { + 'out1/': { + preset, + presetConfig: { fragmentMasking: false }, + config: { + inlineFragmentTypes: 'mask', + customDirectives: { apolloUnmask: true }, + }, + }, + }, + }); + + const graphqlFile = result.find(file => file.filename === 'out1/graphql.ts'); + expect(graphqlFile.content).toMatchInlineSnapshot(` + "/* eslint-disable */ + import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; + export type Maybe = T | null; + export type InputMaybe = Maybe; + export type Exact = { [K in keyof T]: T[K] }; + export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; + export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; + export type MakeEmpty = { [_ in K]?: never }; + export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; + /** All built-in and custom scalars, mapped to their actual values */ + export type Scalars = { + ID: { input: string; output: string; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + }; + + export type Query = { + __typename?: 'Query'; + me?: Maybe; + }; + + export type User = { + __typename?: 'User'; + age: Scalars['Int']['output']; + id: Scalars['ID']['output']; + name: Scalars['String']['output']; + }; + + export type MeQueryVariables = Exact<{ [key: string]: never; }>; + + + export type MeQuery = { __typename?: 'Query', unmasked?: ( + { __typename?: 'User', id: string, name: string, age: number } + & { ' $fragmentRefs'?: { 'User_MeFragment': User_MeFragment } } + ) | null, masked?: ( + { __typename?: 'User', id: string } + & { ' $fragmentRefs'?: { 'User_MeFragment': User_MeFragment } } + ) | null }; + + export type User_MeFragment = { __typename?: 'User', name: string, age: number } & { ' $fragmentName'?: 'User_MeFragment' }; + + export const User_MeFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"User_Me"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"age"}}]}}]} as unknown as DocumentNode; + export const MeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"unmasked"},"name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"User_Me"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"unmask"}}]}]}},{"kind":"Field","alias":{"kind":"Name","value":"masked"},"name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"User_Me"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"User_Me"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"age"}}]}}]} as unknown as DocumentNode;" + `); + }); + it('prevent duplicate operations', async () => { const result = await executeCodegen({ schema: [ @@ -2972,29 +3064,29 @@ export * from "./gql.js";`); Int: { input: number; output: number; } Float: { input: number; output: number; } }; - + export const Color = { Blue: 'BLUE', Red: 'RED' } as const; - + export type Color = typeof Color[keyof typeof Color]; export type Query = { __typename?: 'Query'; thing?: Maybe; }; - + export type Thing = { __typename?: 'Thing'; color: Color; }; - + export type FavoriteColorQueryVariables = Exact<{ [key: string]: never; }>; - - + + export type FavoriteColorQuery = { __typename?: 'Query', thing?: { __typename?: 'Thing', color: Color } | null }; - - + + export const FavoriteColorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FavoriteColor"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}}]} as unknown as DocumentNode; `); });