diff --git a/packages/plugins/other/visitor-plugin-common/src/selection-set-to-object.ts b/packages/plugins/other/visitor-plugin-common/src/selection-set-to-object.ts index 74e3d588080..06a6aa6ef09 100644 --- a/packages/plugins/other/visitor-plugin-common/src/selection-set-to-object.ts +++ b/packages/plugins/other/visitor-plugin-common/src/selection-set-to-object.ts @@ -51,6 +51,11 @@ type FragmentSpreadUsage = { selectionNodes: Array; }; +type TypenameField = { + name: string; + type: string; +}; + function isMetadataFieldName(name: string) { return ['__schema', '__type'].includes(name); } @@ -434,7 +439,7 @@ export class SelectionSetToObject typeName)); } else if (this._config.inlineFragmentTypes === 'mask') { - fields.push(`{ ' $fragmentRefs'?: { ${fragmentsSpreadUsages.map(name => `'${name}': ${name}`).join(`;`)} } }`); + fields.push( + `{ ' $fragmentRefs'?: { ${fragmentsSpreadUsages + .map(({ typeName }) => `'${typeName}': ${typeName}`) + .join(`;`)} } }` + ); } } return { typeInfo: typeInfoField, fields }; } + /** + * When masking the fragments, typename will always be added. + * When combining the fragments, typename will be added only if there + * are no fragments. + * When merging fragments, we need to wait until we know all the involved + * typenames, so we don't add the typename field. + */ + private needsTypenameField(fragmentsSpreadUsages: FragmentSpreadUsage[]) { + if (this._config.inlineFragmentTypes === 'combine' && fragmentsSpreadUsages.length > 0) { + return false; + } + + return !this._config.mergeFragmentTypes || this._config.inlineFragmentTypes === 'mask'; + } + protected buildTypeNameField( type: GraphQLObjectType, nonOptionalTypename: boolean = this._config.nonOptionalTypename, addTypename: boolean = this._config.addTypename, queriedForTypename: boolean = this._queriedForTypename, skipTypeNameForRoot: boolean = this._config.skipTypeNameForRoot - ): { name: string; type: string } { + ): TypenameField | null { const rootTypes = getRootTypes(this._schema); if (rootTypes.has(type) && skipTypeNameForRoot && !queriedForTypename) { return null; diff --git a/packages/plugins/typescript/operations/tests/ts-documents.spec.ts b/packages/plugins/typescript/operations/tests/ts-documents.spec.ts index 3a5ab87b87a..c0913da9eb8 100644 --- a/packages/plugins/typescript/operations/tests/ts-documents.spec.ts +++ b/packages/plugins/typescript/operations/tests/ts-documents.spec.ts @@ -6364,6 +6364,23 @@ function test(q: GetEntityBrandDataQuery): void { fragment UserFragment on User { id } + + query { + me { + id + } + } + + query { + search(term: "test") { + ...UserFragment + ...NotifFragment + } + } + fragment NotifFragment on TextNotification { + id + text + } `); const result = await plugin( schema, @@ -6375,12 +6392,21 @@ function test(q: GetEntityBrandDataQuery): void { export type Unnamed_1_QueryVariables = Exact<{ [key: string]: never; }>; - export type Unnamed_1_Query = { __typename?: 'Query', me?: ( - { __typename?: 'User' } - & UserFragmentFragment - ) | null }; + export type Unnamed_1_Query = { __typename?: 'Query', me?: UserFragmentFragment | null }; export type UserFragmentFragment = { __typename?: 'User', id: string }; + + export type Unnamed_2_QueryVariables = Exact<{ [key: string]: never; }>; + + + export type Unnamed_2_Query = { __typename?: 'Query', me?: { __typename?: 'User', id: string } | null }; + + export type Unnamed_3_QueryVariables = Exact<{ [key: string]: never; }>; + + + export type Unnamed_3_Query = { __typename?: 'Query', search: Array }; + + export type NotifFragmentFragment = { __typename?: 'TextNotification', id: string, text: string }; `); });