1import {
2 ResultOf,
3 DocumentTypeDecoration,
4 TypedDocumentNode,
5} from '@graphql-typed-document-node/core';
6import { FragmentDefinitionNode } from 'graphql';
7import { Incremental } from './graphql';
8
9export type FragmentType<
10 TDocumentType extends DocumentTypeDecoration<any, any>
11> = TDocumentType extends DocumentTypeDecoration<infer TType, any>
12 ? [TType] extends [{ ' $fragmentName'?: infer TKey }]
13 ? TKey extends string
14 ? { ' $fragmentRefs'?: { [key in TKey]: TType } }
15 : never
16 : never
17 : never;
18
19// return non-nullable if `fragmentType` is non-nullable
20export function useFragment<TType>(
21 _documentNode: DocumentTypeDecoration<TType, any>,
22 fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>
23): TType;
24// return nullable if `fragmentType` is nullable
25export function useFragment<TType>(
26 _documentNode: DocumentTypeDecoration<TType, any>,
27 fragmentType:
28 | FragmentType<DocumentTypeDecoration<TType, any>>
29 | null
30 | undefined
31): TType | null | undefined;
32// return array of non-nullable if `fragmentType` is array of non-nullable
33export function useFragment<TType>(
34 _documentNode: DocumentTypeDecoration<TType, any>,
35 fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
36): ReadonlyArray<TType>;
37// return array of nullable if `fragmentType` is array of nullable
38export function useFragment<TType>(
39 _documentNode: DocumentTypeDecoration<TType, any>,
40 fragmentType:
41 | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
42 | null
43 | undefined
44): ReadonlyArray<TType> | null | undefined;
45export function useFragment<TType>(
46 _documentNode: DocumentTypeDecoration<TType, any>,
47 fragmentType:
48 | FragmentType<DocumentTypeDecoration<TType, any>>
49 | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
50 | null
51 | undefined
52): TType | ReadonlyArray<TType> | null | undefined {
53 return fragmentType as any;
54}
55
56export function makeFragmentData<
57 F extends DocumentTypeDecoration<any, any>,
58 FT extends ResultOf<F>
59>(data: FT, _fragment: F): FragmentType<F> {
60 return data as FragmentType<F>;
61}
62export function isFragmentReady<TQuery, TFrag>(
63 queryNode: DocumentTypeDecoration<TQuery, any>,
64 fragmentNode: TypedDocumentNode<TFrag>,
65 data:
66 | FragmentType<TypedDocumentNode<Incremental<TFrag>, any>>
67 | null
68 | undefined
69): data is FragmentType<typeof fragmentNode> {
70 const deferredFields = (
71 queryNode as {
72 __meta__?: { deferredFields: Record<string, (keyof TFrag)[]> };
73 }
74 ).__meta__?.deferredFields;
75
76 if (!deferredFields) return true;
77
78 const fragDef = fragmentNode.definitions[0] as
79 | FragmentDefinitionNode
80 | undefined;
81 const fragName = fragDef?.name?.value;
82
83 const fields = (fragName && deferredFields[fragName]) || [];
84 return fields.length > 0 && fields.every(field => data && field in data);
85}