@isograph/react 0.0.0-main-c88a0561 → 0.0.0-main-f49c67bb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.tsx CHANGED
@@ -1,40 +1,61 @@
1
1
  import {
2
- DataId,
3
- StoreRecord,
4
- DataTypeValue,
5
- Link,
6
- ROOT_ID,
7
2
  getOrCreateCacheForArtifact,
8
3
  onNextChange,
9
- getStore,
10
4
  getParentRecordKey,
11
5
  } from './cache';
12
6
  import { useLazyDisposableState } from '@isograph/react-disposable-state';
13
7
  import { type PromiseWrapper } from './PromiseWrapper';
14
8
  import { getOrCreateCachedComponent } from './componentCache';
15
-
16
- export {
17
- setNetwork,
18
- makeNetworkRequest,
19
- subscribe,
9
+ import {
20
10
  DataId,
11
+ DataTypeValue,
12
+ IsographEnvironment,
21
13
  Link,
14
+ ROOT_ID,
22
15
  StoreRecord,
23
- clearStore,
24
- } from './cache';
16
+ useIsographEnvironment,
17
+ } from './context';
18
+
19
+ export { makeNetworkRequest, subscribe } from './cache';
20
+ export {
21
+ IsographEnvironmentContext,
22
+ ROOT_ID,
23
+ type DataId,
24
+ type DataTypeValue,
25
+ type IsographEnvironment,
26
+ IsographEnvironmentProvider,
27
+ type IsographEnvironmentProviderProps,
28
+ type IsographNetworkFunction,
29
+ type IsographStore,
30
+ type Link,
31
+ type StoreRecord,
32
+ useIsographEnvironment,
33
+ } from './context';
25
34
 
26
35
  export { iso } from './iso';
27
36
 
28
37
  // This type should be treated as an opaque type.
29
- export type IsographEntrypoint<TReadFromStore extends Object, TResolverProps, TResolverResult> = {
38
+ export type IsographEntrypoint<
39
+ TReadFromStore extends Object,
40
+ TResolverProps,
41
+ TResolverResult,
42
+ > = {
30
43
  kind: 'Entrypoint';
31
44
  queryText: string;
32
45
  normalizationAst: NormalizationAst;
33
- readerArtifact: ReaderArtifact<TReadFromStore, TResolverProps, TResolverResult>;
46
+ readerArtifact: ReaderArtifact<
47
+ TReadFromStore,
48
+ TResolverProps,
49
+ TResolverResult
50
+ >;
34
51
  nestedRefetchQueries: RefetchQueryArtifactWrapper[];
35
52
  };
36
53
 
37
- export type ReaderArtifact<TReadFromStore extends Object, TResolverProps, TResolverResult> = {
54
+ export type ReaderArtifact<
55
+ TReadFromStore extends Object,
56
+ TResolverProps,
57
+ TResolverResult,
58
+ > = {
38
59
  kind: 'ReaderArtifact';
39
60
  readerAst: ReaderAst<TReadFromStore>;
40
61
  resolver: (data: TResolverProps) => TResolverResult;
@@ -96,7 +117,9 @@ export type ReaderMutationField = {
96
117
  allowedVariables: string[];
97
118
  };
98
119
 
99
- export type NormalizationAstNode = NormalizationScalarField | NormalizationLinkedField;
120
+ export type NormalizationAstNode =
121
+ | NormalizationScalarField
122
+ | NormalizationLinkedField;
100
123
  // @ts-ignore
101
124
  export type NormalizationAst = NormalizationAstNode[];
102
125
 
@@ -139,24 +162,48 @@ export type ArgumentValue =
139
162
  value: any;
140
163
  };
141
164
 
142
- export type FragmentReference<TReadFromStore extends Object, TResolverProps, TResolverResult> = {
165
+ export type FragmentReference<
166
+ TReadFromStore extends Object,
167
+ TResolverProps,
168
+ TResolverResult,
169
+ > = {
143
170
  kind: 'FragmentReference';
144
- readerArtifact: ReaderArtifact<TReadFromStore, TResolverProps, TResolverResult>;
171
+ readerArtifact: ReaderArtifact<
172
+ TReadFromStore,
173
+ TResolverProps,
174
+ TResolverResult
175
+ >;
145
176
  root: DataId;
146
177
  variables: { [index: string]: string } | null;
147
178
  // TODO: We should instead have ReaderAst<TResolverProps>
148
179
  nestedRefetchQueries: RefetchQueryArtifactWrapper[];
149
180
  };
150
181
 
151
- function assertIsEntrypoint<TReadFromStore extends Object, TResolverProps, TResolverResult>(
152
- value: IsographEntrypoint<TReadFromStore, TResolverProps, TResolverResult> | typeof iso,
153
- ): asserts value is IsographEntrypoint<TReadFromStore, TResolverProps, TResolverResult> {
182
+ function assertIsEntrypoint<
183
+ TReadFromStore extends Object,
184
+ TResolverProps,
185
+ TResolverResult,
186
+ >(
187
+ value:
188
+ | IsographEntrypoint<TReadFromStore, TResolverProps, TResolverResult>
189
+ | ((_: any) => any)
190
+ // Temporarily, allow any here. Once we automatically provide
191
+ // types to entrypoints, we probably don't need this.
192
+ | any,
193
+ ): asserts value is IsographEntrypoint<
194
+ TReadFromStore,
195
+ TResolverProps,
196
+ TResolverResult
197
+ > {
154
198
  if (typeof value === 'function') throw new Error('Not a string');
155
199
  }
156
200
 
157
- type ExtractTReadFromStore<Type> = Type extends IsographEntrypoint<infer X, any, any> ? X : never;
158
- type ExtractResolverProps<Type> = Type extends IsographEntrypoint<any, infer X, any> ? X : never;
159
- type ExtractResolverResult<Type> = Type extends IsographEntrypoint<any, any, infer X> ? X : never;
201
+ type ExtractTReadFromStore<Type> =
202
+ Type extends IsographEntrypoint<infer X, any, any> ? X : never;
203
+ type ExtractResolverProps<Type> =
204
+ Type extends IsographEntrypoint<any, infer X, any> ? X : never;
205
+ type ExtractResolverResult<Type> =
206
+ Type extends IsographEntrypoint<any, any, infer X> ? X : never;
160
207
  // Note: we cannot write TEntrypoint extends IsographEntrypoint<any, any, any>, or else
161
208
  // if we do not explicitly pass a type, the read out type will be any.
162
209
  // We cannot write TEntrypoint extends IsographEntrypoint<never, never, never>, or else
@@ -176,16 +223,19 @@ export function useLazyReference<TEntrypoint>(
176
223
  ExtractResolverResult<TEntrypoint>
177
224
  >;
178
225
  } {
226
+ const environment = useIsographEnvironment();
179
227
  assertIsEntrypoint(entrypoint);
180
228
  // Typechecking fails here... TODO investigate
181
229
  const cache = getOrCreateCacheForArtifact<ExtractResolverResult<TEntrypoint>>(
230
+ environment,
182
231
  entrypoint,
183
232
  variables,
184
233
  );
185
234
 
186
235
  // TODO add comment explaining why we never use this value
187
236
  // @ts-ignore
188
- const data = useLazyDisposableState<PromiseWrapper<TResolverResult>>(cache).state;
237
+ const data =
238
+ useLazyDisposableState<PromiseWrapper<TResolverResult>>(cache).state;
189
239
 
190
240
  return {
191
241
  queryReference: {
@@ -198,12 +248,37 @@ export function useLazyReference<TEntrypoint>(
198
248
  };
199
249
  }
200
250
 
201
- export function read<TReadFromStore extends Object, TResolverProps, TResolverResult>(
202
- fragmentReference: FragmentReference<TReadFromStore, TResolverProps, TResolverResult>,
251
+ export function useRead<
252
+ TReadFromStore extends Object,
253
+ TResolverProps,
254
+ TResolverResult,
255
+ >(
256
+ fragmentReference: FragmentReference<
257
+ TReadFromStore,
258
+ TResolverProps,
259
+ TResolverResult
260
+ >,
261
+ ): TResolverResult {
262
+ const environment = useIsographEnvironment();
263
+ return read(environment, fragmentReference);
264
+ }
265
+
266
+ export function read<
267
+ TReadFromStore extends Object,
268
+ TResolverProps,
269
+ TResolverResult,
270
+ >(
271
+ environment: IsographEnvironment,
272
+ fragmentReference: FragmentReference<
273
+ TReadFromStore,
274
+ TResolverProps,
275
+ TResolverResult
276
+ >,
203
277
  ): TResolverResult {
204
278
  const variant = fragmentReference.readerArtifact.variant;
205
279
  if (variant.kind === 'Eager') {
206
280
  const data = readData(
281
+ environment,
207
282
  fragmentReference.readerArtifact.readerAst,
208
283
  fragmentReference.root,
209
284
  fragmentReference.variables ?? {},
@@ -217,6 +292,7 @@ export function read<TReadFromStore extends Object, TResolverProps, TResolverRes
217
292
  } else if (variant.kind === 'Component') {
218
293
  // @ts-ignore
219
294
  return getOrCreateCachedComponent(
295
+ environment,
220
296
  fragmentReference.root,
221
297
  variant.componentName,
222
298
  fragmentReference.readerArtifact,
@@ -229,9 +305,11 @@ export function read<TReadFromStore extends Object, TResolverProps, TResolverRes
229
305
  }
230
306
 
231
307
  export function readButDoNotEvaluate<TReadFromStore extends Object>(
308
+ environment: IsographEnvironment,
232
309
  reference: FragmentReference<TReadFromStore, unknown, unknown>,
233
310
  ): TReadFromStore {
234
311
  const response = readData(
312
+ environment,
235
313
  reference.readerArtifact.readerAst,
236
314
  reference.root,
237
315
  reference.variables ?? {},
@@ -259,12 +337,13 @@ type ReadDataResult<TReadFromStore> =
259
337
  };
260
338
 
261
339
  function readData<TReadFromStore>(
340
+ environment: IsographEnvironment,
262
341
  ast: ReaderAst<TReadFromStore>,
263
342
  root: DataId,
264
343
  variables: { [index: string]: string },
265
344
  nestedRefetchQueries: RefetchQueryArtifactWrapper[],
266
345
  ): ReadDataResult<TReadFromStore> {
267
- let storeRecord = getStore()[root];
346
+ let storeRecord = environment.store[root];
268
347
  if (storeRecord === undefined) {
269
348
  return { kind: 'MissingData', reason: 'No record for root ' + root };
270
349
  }
@@ -313,7 +392,13 @@ function readData<TReadFromStore>(
313
392
  results.push(null);
314
393
  continue;
315
394
  }
316
- const result = readData(field.selections, link.__link, variables, nestedRefetchQueries);
395
+ const result = readData(
396
+ environment,
397
+ field.selections,
398
+ link.__link,
399
+ variables,
400
+ nestedRefetchQueries,
401
+ );
317
402
  if (result.kind === 'MissingData') {
318
403
  return {
319
404
  kind: 'MissingData',
@@ -335,6 +420,8 @@ function readData<TReadFromStore>(
335
420
  let link = assertLink(value);
336
421
  if (link === undefined) {
337
422
  // TODO make this configurable, and also generated and derived from the schema
423
+ const missingFieldHandler =
424
+ environment.missingFieldHandler ?? defaultMissingFieldHandler;
338
425
  const altLink = missingFieldHandler(
339
426
  storeRecord,
340
427
  root,
@@ -361,7 +448,13 @@ function readData<TReadFromStore>(
361
448
  break;
362
449
  }
363
450
  const targetId = link.__link;
364
- const data = readData(field.selections, targetId, variables, nestedRefetchQueries);
451
+ const data = readData(
452
+ environment,
453
+ field.selections,
454
+ targetId,
455
+ variables,
456
+ nestedRefetchQueries,
457
+ );
365
458
  if (data.kind === 'MissingData') {
366
459
  return {
367
460
  kind: 'MissingData',
@@ -374,6 +467,7 @@ function readData<TReadFromStore>(
374
467
  }
375
468
  case 'RefetchField': {
376
469
  const data = readData(
470
+ environment,
377
471
  field.readerArtifact.readerAst,
378
472
  root,
379
473
  variables,
@@ -398,17 +492,22 @@ function readData<TReadFromStore>(
398
492
  const refetchQueryArtifact = refetchQuery.artifact;
399
493
  const allowedVariables = refetchQuery.allowedVariables;
400
494
 
401
- target[field.alias] = field.readerArtifact.resolver(refetchQueryArtifact, {
402
- ...data.data,
403
- // TODO continue from here
404
- // variables need to be filtered for what we need just for the refetch query
405
- ...filterVariables(variables, allowedVariables),
406
- });
495
+ target[field.alias] = field.readerArtifact.resolver(
496
+ environment,
497
+ refetchQueryArtifact,
498
+ {
499
+ ...data.data,
500
+ // TODO continue from here
501
+ // variables need to be filtered for what we need just for the refetch query
502
+ ...filterVariables(variables, allowedVariables),
503
+ },
504
+ );
407
505
  }
408
506
  break;
409
507
  }
410
508
  case 'MutationField': {
411
509
  const data = readData(
510
+ environment,
412
511
  field.readerArtifact.readerAst,
413
512
  root,
414
513
  variables,
@@ -434,6 +533,7 @@ function readData<TReadFromStore>(
434
533
  const allowedVariables = refetchQuery.allowedVariables;
435
534
 
436
535
  target[field.alias] = field.readerArtifact.resolver(
536
+ environment,
437
537
  refetchQueryArtifact,
438
538
  data.data,
439
539
  filterVariables(variables, allowedVariables),
@@ -450,6 +550,7 @@ function readData<TReadFromStore>(
450
550
  const variant = field.readerArtifact.variant;
451
551
  if (variant.kind === 'Eager') {
452
552
  const data = readData(
553
+ environment,
453
554
  field.readerArtifact.readerAst,
454
555
  root,
455
556
  variables,
@@ -466,6 +567,7 @@ function readData<TReadFromStore>(
466
567
  }
467
568
  } else if (variant.kind === 'Component') {
468
569
  target[field.alias] = getOrCreateCachedComponent(
570
+ environment,
469
571
  root,
470
572
  variant.componentName,
471
573
  field.readerArtifact,
@@ -480,25 +582,9 @@ function readData<TReadFromStore>(
480
582
  return { kind: 'Success', data: target as any };
481
583
  }
482
584
 
483
- let customMissingFieldHandler: typeof defaultMissingFieldHandler | null = null;
484
-
485
- function missingFieldHandler(
486
- storeRecord: StoreRecord,
487
- root: DataId,
488
- fieldName: string,
489
- arguments_: { [index: string]: any } | null,
490
- variables: { [index: string]: any } | null,
491
- ): Link | undefined {
492
- if (customMissingFieldHandler != null) {
493
- return customMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables);
494
- } else {
495
- return defaultMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables);
496
- }
497
- }
498
-
499
585
  export function defaultMissingFieldHandler(
500
- storeRecord: StoreRecord,
501
- root: DataId,
586
+ _storeRecord: StoreRecord,
587
+ _root: DataId,
502
588
  fieldName: string,
503
589
  arguments_: { [index: string]: any } | null,
504
590
  variables: { [index: string]: any } | null,
@@ -514,10 +600,6 @@ export function defaultMissingFieldHandler(
514
600
  }
515
601
  }
516
602
 
517
- export function setMissingFieldHandler(handler: typeof defaultMissingFieldHandler) {
518
- customMissingFieldHandler = handler;
519
- }
520
-
521
603
  function assertLink(link: DataTypeValue): Link | undefined | null {
522
604
  if (Array.isArray(link)) {
523
605
  throw new Error('Unexpected array');