@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/dist/cache.d.ts +3 -19
- package/dist/cache.js +29 -44
- package/dist/componentCache.d.ts +3 -3
- package/dist/componentCache.js +2 -2
- package/dist/context.d.ts +34 -0
- package/dist/context.js +48 -0
- package/dist/index.d.ts +7 -6
- package/dist/index.js +35 -37
- package/package.json +3 -3
- package/src/{cache.ts → cache.tsx} +72 -79
- package/src/componentCache.ts +10 -3
- package/src/context.tsx +90 -0
- package/src/index.tsx +141 -59
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
|
-
|
24
|
-
} from './
|
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<
|
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<
|
46
|
+
readerArtifact: ReaderArtifact<
|
47
|
+
TReadFromStore,
|
48
|
+
TResolverProps,
|
49
|
+
TResolverResult
|
50
|
+
>;
|
34
51
|
nestedRefetchQueries: RefetchQueryArtifactWrapper[];
|
35
52
|
};
|
36
53
|
|
37
|
-
export type ReaderArtifact<
|
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 =
|
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<
|
165
|
+
export type FragmentReference<
|
166
|
+
TReadFromStore extends Object,
|
167
|
+
TResolverProps,
|
168
|
+
TResolverResult,
|
169
|
+
> = {
|
143
170
|
kind: 'FragmentReference';
|
144
|
-
readerArtifact: ReaderArtifact<
|
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<
|
152
|
-
|
153
|
-
|
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> =
|
158
|
-
|
159
|
-
type
|
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 =
|
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
|
202
|
-
|
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 =
|
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(
|
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(
|
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(
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
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
|
-
|
501
|
-
|
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');
|