import type { Fragment, FragmentArtifact, GraphQLObject } from 'houdini/runtime' import type { Readable } from 'svelte/store' import type { FragmentStore } from './stores/index.js' import type { BasePaginatedFragmentStore, FragmentStorePaginated, } from './stores/pagination/fragment.js' import type { FragmentStoreRefetchable } from './stores/refetchable.js' // Accepts both FragmentStore (non-paginated) and paginated variants (FragmentStoreCursor / // FragmentStoreOffset). The paginated classes extend BasePaginatedFragmentStore, not // FragmentStore, so they are missing the protected `context` member. Using a union here // avoids the class-hierarchy compatibility error TypeScript would otherwise emit. type AnyFragmentStoreFor<_Data extends GraphQLObject> = | FragmentStore<_Data, {}> | BasePaginatedFragmentStore<_Data, any, any> // @plural fragment overloads: the reference is a list of fragment references and the // resulting store holds an array of data (one entry per item in the list). export function fragment<_Data extends GraphQLObject, _Fragment extends Fragment<_Data>>( ref: ReadonlyArray<_Fragment>, fragment: FragmentStore<_Data, {}> ): Readable>> & { data: Readable> artifact: FragmentArtifact } export function fragment<_Data extends GraphQLObject, _Fragment extends Fragment<_Data>>( ref: ReadonlyArray<_Fragment> | null | undefined, fragment: FragmentStore<_Data, {}> ): Readable>> & { data: Readable> artifact: FragmentArtifact } // function overloads meant to only return a nullable value // if the reference type was nullable. // _Data is inferred from the store so that the return type is correct even when // the ref argument is a bare query-result type (e.g. { " $fragments": { Name: {} } }) // that has no `shape` property. export function fragment<_Data extends GraphQLObject, _Fragment extends Fragment<_Data>>( ref: _Fragment, fragment: FragmentStore<_Data, {}> ): Readable> & { data: Readable<_Fragment> artifact: FragmentArtifact } export function fragment<_Data extends GraphQLObject, _Fragment extends Fragment<_Data>>( ref: _Fragment | null | undefined, fragment: FragmentStore<_Data, {}> ): Readable | null> & { data: Readable<_Fragment | null> artifact: FragmentArtifact } export function fragment<_Data extends GraphQLObject>( ref: Fragment<_Data> | ReadonlyArray> | null | undefined, store: FragmentStore<_Data, {}> ) { // make sure we got a query document if (store.kind !== 'HoudiniFragment') { throw new Error(`fragment can only take fragment documents. Found: ${store.kind}`) } // store.get() handles both a single reference and a list of references (for @plural // fragments), and throws if a list is passed to a non-plural fragment. // @ts-expect-error: ref is Fragment<_Data> but store.get() expects _Data | { [fragmentKey]: _ReferenceType }; // Fragment<_Data> structurally satisfies the { [fragmentKey]: _ReferenceType } branch at runtime. const fragmentStore = store.get(ref) return { ...fragmentStore, artifact: store.artifact, data: { subscribe: fragmentStore.subscribe }, } } export function paginatedFragment<_Data extends GraphQLObject, _Fragment extends Fragment<_Data>>( initialValue: _Fragment | null | undefined, document: AnyFragmentStoreFor<_Data> ): FragmentStorePaginated<_Data, {}> export function paginatedFragment<_Data extends GraphQLObject, _Fragment extends Fragment<_Data>>( initialValue: _Fragment, document: AnyFragmentStoreFor<_Data> ): FragmentStorePaginated<_Data, {}> export function paginatedFragment<_Data extends GraphQLObject>( initialValue: Fragment<_Data> | null | undefined, store: AnyFragmentStoreFor<_Data> ): FragmentStorePaginated<_Data, {}> { // make sure we got a query document if (store.kind !== 'HoudiniFragment') { throw new Error(`paginatedFragment() must be passed a fragment document: ${store.kind}`) } // if we don't have a pagination fragment there is a problem if (!('paginated' in store)) { throw new Error('paginatedFragment() must be passed a fragment with @paginate') } // TODO: fix type checking paginated // @ts-expect-error: the query store will only include the methods when it needs to // and the userland type checking happens as part of the query type generation return fragment(initialValue, store) } // refetchableFragment is just like fragment but the fragment is marked with @refetchable. // it returns a store whose value is `{ data, variables }` plus a `refetch` method that // re-runs the fragment with new argument values. export function refetchableFragment<_Data extends GraphQLObject, _Fragment extends Fragment<_Data>>( initialValue: _Fragment | null | undefined, document: FragmentStoreRefetchable<_Data, {}, any> ): ReturnType['get']> export function refetchableFragment<_Data extends GraphQLObject>( initialValue: Fragment<_Data> | null | undefined, store: FragmentStoreRefetchable<_Data, {}, any> ): ReturnType['get']> { // make sure we got a fragment document if (store.kind !== 'HoudiniFragment') { throw new Error(`refetchableFragment() must be passed a fragment document: ${store.kind}`) } // if we don't have a refetchable fragment there is a problem if (!('refetchable' in store)) { throw new Error('refetchableFragment() must be passed a fragment with @refetchable') } // @ts-expect-error: ref is Fragment<_Data> but store.get() expects _Data | { [fragmentKey]: _ReferenceType } return store.get(initialValue) }