@isograph/react 0.0.0-main-55364d41 → 0.0.0-main-2c275831
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/PromiseWrapper.js +1 -1
- package/dist/cache.d.ts +4 -4
- package/dist/cache.js +62 -35
- package/dist/componentCache.d.ts +2 -2
- package/dist/componentCache.js +1 -1
- package/dist/index.d.ts +29 -21
- package/dist/index.js +62 -58
- package/package.json +3 -3
- package/src/PromiseWrapper.ts +1 -1
- package/src/cache.ts +102 -87
- package/src/componentCache.ts +4 -8
- package/src/index.tsx +151 -206
package/src/cache.ts
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
+
import { Factory, ItemCleanupPair, ParentCache } from '@isograph/react-disposable-state';
|
2
|
+
import { PromiseWrapper, wrapPromise } from './PromiseWrapper';
|
1
3
|
import {
|
2
|
-
|
3
|
-
|
4
|
-
ParentCache,
|
5
|
-
} from "@isograph/react-disposable-state";
|
6
|
-
import { PromiseWrapper, wrapPromise } from "./PromiseWrapper";
|
7
|
-
import {
|
4
|
+
Argument,
|
5
|
+
ArgumentValue,
|
8
6
|
IsographEntrypoint,
|
9
7
|
NormalizationAst,
|
10
8
|
NormalizationLinkedField,
|
@@ -12,7 +10,7 @@ import {
|
|
12
10
|
ReaderLinkedField,
|
13
11
|
ReaderScalarField,
|
14
12
|
RefetchQueryArtifactWrapper,
|
15
|
-
} from
|
13
|
+
} from './index';
|
16
14
|
|
17
15
|
declare global {
|
18
16
|
interface Window {
|
@@ -22,12 +20,9 @@ declare global {
|
|
22
20
|
|
23
21
|
const cache: { [index: string]: ParentCache<any> } = {};
|
24
22
|
|
25
|
-
function getOrCreateCache<T>(
|
26
|
-
|
27
|
-
|
28
|
-
): ParentCache<T> {
|
29
|
-
if (typeof window !== "undefined" && window.__LOG) {
|
30
|
-
console.log("getting cache for", {
|
23
|
+
function getOrCreateCache<T>(index: string, factory: Factory<T>): ParentCache<T> {
|
24
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
25
|
+
console.log('getting cache for', {
|
31
26
|
index,
|
32
27
|
cache: Object.keys(cache),
|
33
28
|
found: !!cache[index],
|
@@ -46,7 +41,7 @@ function getOrCreateCache<T>(
|
|
46
41
|
* results.
|
47
42
|
*/
|
48
43
|
export function stableCopy<T>(value: T): T {
|
49
|
-
if (!value || typeof value !==
|
44
|
+
if (!value || typeof value !== 'object') {
|
50
45
|
return value;
|
51
46
|
}
|
52
47
|
if (Array.isArray(value)) {
|
@@ -66,11 +61,10 @@ type IsoResolver = IsographEntrypoint<any, any, any>;
|
|
66
61
|
|
67
62
|
export function getOrCreateCacheForArtifact<T>(
|
68
63
|
artifact: IsographEntrypoint<any, any, T>,
|
69
|
-
variables: object
|
64
|
+
variables: object,
|
70
65
|
): ParentCache<PromiseWrapper<T>> {
|
71
66
|
const cacheKey = artifact.queryText + JSON.stringify(stableCopy(variables));
|
72
|
-
const factory: Factory<PromiseWrapper<T>> = () =>
|
73
|
-
makeNetworkRequest<T>(artifact, variables);
|
67
|
+
const factory: Factory<PromiseWrapper<T>> = () => makeNetworkRequest<T>(artifact, variables);
|
74
68
|
return getOrCreateCache<PromiseWrapper<T>>(cacheKey, factory);
|
75
69
|
}
|
76
70
|
|
@@ -83,29 +77,27 @@ export function setNetwork(newNetwork: typeof network) {
|
|
83
77
|
|
84
78
|
export function makeNetworkRequest<T>(
|
85
79
|
artifact: IsoResolver,
|
86
|
-
variables: object
|
80
|
+
variables: object,
|
87
81
|
): ItemCleanupPair<PromiseWrapper<T>> {
|
88
|
-
if (typeof window !==
|
89
|
-
console.log(
|
82
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
83
|
+
console.log('make network request', artifact, variables);
|
90
84
|
}
|
91
85
|
if (network == null) {
|
92
|
-
throw new Error(
|
86
|
+
throw new Error('Network must be set before makeNetworkRequest is called');
|
93
87
|
}
|
94
88
|
|
95
|
-
const promise = network(artifact.queryText, variables).then(
|
96
|
-
(
|
97
|
-
|
98
|
-
console.log("network response", artifact);
|
99
|
-
}
|
100
|
-
normalizeData(
|
101
|
-
artifact.normalizationAst,
|
102
|
-
networkResponse.data,
|
103
|
-
variables,
|
104
|
-
artifact.nestedRefetchQueries
|
105
|
-
);
|
106
|
-
return networkResponse.data;
|
89
|
+
const promise = network(artifact.queryText, variables).then((networkResponse) => {
|
90
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
91
|
+
console.log('network response', artifact);
|
107
92
|
}
|
108
|
-
|
93
|
+
normalizeData(
|
94
|
+
artifact.normalizationAst,
|
95
|
+
networkResponse.data,
|
96
|
+
variables,
|
97
|
+
artifact.nestedRefetchQueries,
|
98
|
+
);
|
99
|
+
return networkResponse.data;
|
100
|
+
});
|
109
101
|
|
110
102
|
const wrapper = wrapPromise(promise);
|
111
103
|
|
@@ -144,7 +136,7 @@ export type StoreRecord = {
|
|
144
136
|
|
145
137
|
export type DataId = string;
|
146
138
|
|
147
|
-
export const ROOT_ID: DataId &
|
139
|
+
export const ROOT_ID: DataId & '__ROOT' = '__ROOT';
|
148
140
|
let store: {
|
149
141
|
[index: DataId]: StoreRecord | null;
|
150
142
|
__ROOT: StoreRecord;
|
@@ -178,15 +170,10 @@ function normalizeData(
|
|
178
170
|
normalizationAst: NormalizationAst,
|
179
171
|
networkResponse: NetworkResponseObject,
|
180
172
|
variables: Object,
|
181
|
-
nestedRefetchQueries: RefetchQueryArtifactWrapper[]
|
173
|
+
nestedRefetchQueries: RefetchQueryArtifactWrapper[],
|
182
174
|
) {
|
183
|
-
if (typeof window !==
|
184
|
-
console.log(
|
185
|
-
"about to normalize",
|
186
|
-
normalizationAst,
|
187
|
-
networkResponse,
|
188
|
-
variables
|
189
|
-
);
|
175
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
176
|
+
console.log('about to normalize', normalizationAst, networkResponse, variables);
|
190
177
|
}
|
191
178
|
normalizeDataIntoRecord(
|
192
179
|
normalizationAst,
|
@@ -194,10 +181,10 @@ function normalizeData(
|
|
194
181
|
store.__ROOT,
|
195
182
|
ROOT_ID,
|
196
183
|
variables as any,
|
197
|
-
nestedRefetchQueries
|
184
|
+
nestedRefetchQueries,
|
198
185
|
);
|
199
|
-
if (typeof window !==
|
200
|
-
console.log(
|
186
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
187
|
+
console.log('after normalization', { store });
|
201
188
|
}
|
202
189
|
callSubscriptions();
|
203
190
|
}
|
@@ -231,27 +218,27 @@ function normalizeDataIntoRecord(
|
|
231
218
|
targetParentRecord: StoreRecord,
|
232
219
|
targetParentRecordId: DataId,
|
233
220
|
variables: { [index: string]: string },
|
234
|
-
nestedRefetchQueries: RefetchQueryArtifactWrapper[]
|
221
|
+
nestedRefetchQueries: RefetchQueryArtifactWrapper[],
|
235
222
|
) {
|
236
223
|
for (const normalizationNode of normalizationAst) {
|
237
224
|
switch (normalizationNode.kind) {
|
238
|
-
case
|
225
|
+
case 'Scalar': {
|
239
226
|
normalizeScalarField(
|
240
227
|
normalizationNode,
|
241
228
|
networkResponseParentRecord,
|
242
229
|
targetParentRecord,
|
243
|
-
variables
|
230
|
+
variables,
|
244
231
|
);
|
245
232
|
break;
|
246
233
|
}
|
247
|
-
case
|
234
|
+
case 'Linked': {
|
248
235
|
normalizeLinkedField(
|
249
236
|
normalizationNode,
|
250
237
|
networkResponseParentRecord,
|
251
238
|
targetParentRecord,
|
252
239
|
targetParentRecordId,
|
253
240
|
variables,
|
254
|
-
nestedRefetchQueries
|
241
|
+
nestedRefetchQueries,
|
255
242
|
);
|
256
243
|
break;
|
257
244
|
}
|
@@ -263,19 +250,16 @@ function normalizeScalarField(
|
|
263
250
|
astNode: NormalizationScalarField,
|
264
251
|
networkResponseParentRecord: NetworkResponseObject,
|
265
252
|
targetStoreRecord: StoreRecord,
|
266
|
-
variables: { [index: string]: string }
|
253
|
+
variables: { [index: string]: string },
|
267
254
|
) {
|
268
255
|
const networkResponseKey = getNetworkResponseKey(astNode);
|
269
256
|
const networkResponseData = networkResponseParentRecord[networkResponseKey];
|
270
257
|
const parentRecordKey = getParentRecordKey(astNode, variables);
|
271
258
|
|
272
|
-
if (
|
273
|
-
networkResponseData == null ||
|
274
|
-
isScalarOrEmptyArray(networkResponseData)
|
275
|
-
) {
|
259
|
+
if (networkResponseData == null || isScalarOrEmptyArray(networkResponseData)) {
|
276
260
|
targetStoreRecord[parentRecordKey] = networkResponseData;
|
277
261
|
} else {
|
278
|
-
throw new Error(
|
262
|
+
throw new Error('Unexpected object array when normalizing scalar');
|
279
263
|
}
|
280
264
|
}
|
281
265
|
|
@@ -288,7 +272,7 @@ function normalizeLinkedField(
|
|
288
272
|
targetParentRecord: StoreRecord,
|
289
273
|
targetParentRecordId: DataId,
|
290
274
|
variables: { [index: string]: string },
|
291
|
-
nestedRefetchQueries: RefetchQueryArtifactWrapper[]
|
275
|
+
nestedRefetchQueries: RefetchQueryArtifactWrapper[],
|
292
276
|
) {
|
293
277
|
const networkResponseKey = getNetworkResponseKey(astNode);
|
294
278
|
const networkResponseData = networkResponseParentRecord[networkResponseKey];
|
@@ -300,9 +284,7 @@ function normalizeLinkedField(
|
|
300
284
|
}
|
301
285
|
|
302
286
|
if (isScalarButNotEmptyArray(networkResponseData)) {
|
303
|
-
throw new Error(
|
304
|
-
"Unexpected scalar network response when normalizing a linked field"
|
305
|
-
);
|
287
|
+
throw new Error('Unexpected scalar network response when normalizing a linked field');
|
306
288
|
}
|
307
289
|
|
308
290
|
if (Array.isArray(networkResponseData)) {
|
@@ -316,7 +298,7 @@ function normalizeLinkedField(
|
|
316
298
|
targetParentRecordId,
|
317
299
|
variables,
|
318
300
|
i,
|
319
|
-
nestedRefetchQueries
|
301
|
+
nestedRefetchQueries,
|
320
302
|
);
|
321
303
|
dataIds.push({ __link: newStoreRecordId });
|
322
304
|
}
|
@@ -328,7 +310,7 @@ function normalizeLinkedField(
|
|
328
310
|
targetParentRecordId,
|
329
311
|
variables,
|
330
312
|
null,
|
331
|
-
nestedRefetchQueries
|
313
|
+
nestedRefetchQueries,
|
332
314
|
);
|
333
315
|
targetParentRecord[parentRecordKey] = {
|
334
316
|
__link: newStoreRecordId,
|
@@ -342,14 +324,14 @@ function normalizeNetworkResponseObject(
|
|
342
324
|
targetParentRecordId: string,
|
343
325
|
variables: { [index: string]: string },
|
344
326
|
index: number | null,
|
345
|
-
nestedRefetchQueries: RefetchQueryArtifactWrapper[]
|
327
|
+
nestedRefetchQueries: RefetchQueryArtifactWrapper[],
|
346
328
|
): DataId /* The id of the modified or newly created item */ {
|
347
329
|
const newStoreRecordId = getDataIdOfNetworkResponse(
|
348
330
|
targetParentRecordId,
|
349
331
|
networkResponseData,
|
350
332
|
astNode,
|
351
333
|
variables,
|
352
|
-
index
|
334
|
+
index,
|
353
335
|
);
|
354
336
|
|
355
337
|
const newStoreRecord = store[newStoreRecordId] ?? {};
|
@@ -361,14 +343,14 @@ function normalizeNetworkResponseObject(
|
|
361
343
|
newStoreRecord,
|
362
344
|
newStoreRecordId,
|
363
345
|
variables,
|
364
|
-
nestedRefetchQueries
|
346
|
+
nestedRefetchQueries,
|
365
347
|
);
|
366
348
|
|
367
349
|
return newStoreRecordId;
|
368
350
|
}
|
369
351
|
|
370
352
|
function isScalarOrEmptyArray(
|
371
|
-
data: NonNullable<NetworkResponseValue
|
353
|
+
data: NonNullable<NetworkResponseValue>,
|
372
354
|
): data is NetworkResponseScalarValue | NetworkResponseScalarValue[] {
|
373
355
|
// N.B. empty arrays count as empty arrays of scalar fields.
|
374
356
|
if (Array.isArray(data)) {
|
@@ -376,14 +358,12 @@ function isScalarOrEmptyArray(
|
|
376
358
|
return (data as any).every((x: any) => isScalarOrEmptyArray(x));
|
377
359
|
}
|
378
360
|
const isScalarValue =
|
379
|
-
typeof data ===
|
380
|
-
typeof data === "number" ||
|
381
|
-
typeof data === "boolean";
|
361
|
+
typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean';
|
382
362
|
return isScalarValue;
|
383
363
|
}
|
384
364
|
|
385
365
|
function isScalarButNotEmptyArray(
|
386
|
-
data: NonNullable<NetworkResponseValue
|
366
|
+
data: NonNullable<NetworkResponseValue>,
|
387
367
|
): data is NetworkResponseScalarValue | NetworkResponseScalarValue[] {
|
388
368
|
// N.B. empty arrays count as empty arrays of linked fields.
|
389
369
|
if (Array.isArray(data)) {
|
@@ -394,9 +374,7 @@ function isScalarButNotEmptyArray(
|
|
394
374
|
return (data as any).every((x: any) => isScalarOrEmptyArray(x));
|
395
375
|
}
|
396
376
|
const isScalarValue =
|
397
|
-
typeof data ===
|
398
|
-
typeof data === "number" ||
|
399
|
-
typeof data === "boolean";
|
377
|
+
typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean';
|
400
378
|
return isScalarValue;
|
401
379
|
}
|
402
380
|
|
@@ -406,38 +384,77 @@ export function getParentRecordKey(
|
|
406
384
|
| NormalizationScalarField
|
407
385
|
| ReaderLinkedField
|
408
386
|
| ReaderScalarField,
|
409
|
-
variables: { [index: string]: string }
|
387
|
+
variables: { [index: string]: string },
|
410
388
|
): string {
|
411
389
|
let parentRecordKey = astNode.fieldName;
|
412
390
|
const fieldParameters = astNode.arguments;
|
413
391
|
if (fieldParameters != null) {
|
414
392
|
for (const fieldParameter of fieldParameters) {
|
415
|
-
|
416
|
-
const valueToUse = variables[variableName];
|
417
|
-
parentRecordKey += `${FIRST_SPLIT_KEY}${argumentName}${SECOND_SPLIT_KEY}${valueToUse}`;
|
393
|
+
parentRecordKey += getStoreKeyChunkForArgument(fieldParameter, variables);
|
418
394
|
}
|
419
395
|
}
|
420
396
|
|
421
397
|
return parentRecordKey;
|
422
398
|
}
|
423
399
|
|
400
|
+
function getStoreKeyChunkForArgumentValue(
|
401
|
+
argumentValue: ArgumentValue,
|
402
|
+
variables: { [index: string]: string },
|
403
|
+
) {
|
404
|
+
switch (argumentValue.kind) {
|
405
|
+
case 'Literal': {
|
406
|
+
return argumentValue.value;
|
407
|
+
break;
|
408
|
+
}
|
409
|
+
case 'Variable': {
|
410
|
+
return variables[argumentValue.name];
|
411
|
+
break;
|
412
|
+
}
|
413
|
+
default: {
|
414
|
+
// TODO configure eslint to allow unused vars starting with _
|
415
|
+
let _: never = argumentValue;
|
416
|
+
throw new Error('Unexpected case');
|
417
|
+
}
|
418
|
+
}
|
419
|
+
}
|
420
|
+
|
421
|
+
function getStoreKeyChunkForArgument(argument: Argument, variables: { [index: string]: string }) {
|
422
|
+
const chunk = getStoreKeyChunkForArgumentValue(argument[1], variables);
|
423
|
+
return `${FIRST_SPLIT_KEY}${argument[0]}${SECOND_SPLIT_KEY}${chunk}`;
|
424
|
+
}
|
425
|
+
|
424
426
|
function getNetworkResponseKey(
|
425
|
-
astNode: NormalizationLinkedField | NormalizationScalarField
|
427
|
+
astNode: NormalizationLinkedField | NormalizationScalarField,
|
426
428
|
): string {
|
427
429
|
let networkResponseKey = astNode.fieldName;
|
428
430
|
const fieldParameters = astNode.arguments;
|
429
431
|
if (fieldParameters != null) {
|
430
432
|
for (const fieldParameter of fieldParameters) {
|
431
|
-
const
|
432
|
-
|
433
|
+
const [argumentName, argumentValue] = fieldParameter;
|
434
|
+
let argumentValueChunk;
|
435
|
+
switch (argumentValue.kind) {
|
436
|
+
case 'Literal': {
|
437
|
+
argumentValueChunk = 'l_' + argumentValue.value;
|
438
|
+
break;
|
439
|
+
}
|
440
|
+
case 'Variable': {
|
441
|
+
argumentValueChunk = 'v_' + argumentValue.name;
|
442
|
+
break;
|
443
|
+
}
|
444
|
+
default: {
|
445
|
+
let _: never = argumentValue;
|
446
|
+
throw new Error('Unexpected case');
|
447
|
+
}
|
448
|
+
}
|
449
|
+
networkResponseKey += `${FIRST_SPLIT_KEY}${argumentName}${SECOND_SPLIT_KEY}${argumentValueChunk}`;
|
433
450
|
}
|
434
451
|
}
|
435
452
|
return networkResponseKey;
|
436
453
|
}
|
437
454
|
|
438
455
|
// an alias might be pullRequests____first___first____after___cursor
|
439
|
-
export const FIRST_SPLIT_KEY =
|
440
|
-
export const SECOND_SPLIT_KEY =
|
456
|
+
export const FIRST_SPLIT_KEY = '____';
|
457
|
+
export const SECOND_SPLIT_KEY = '___';
|
441
458
|
|
442
459
|
// Returns a key to look up an item in the store
|
443
460
|
function getDataIdOfNetworkResponse(
|
@@ -445,7 +462,7 @@ function getDataIdOfNetworkResponse(
|
|
445
462
|
dataToNormalize: NetworkResponseObject,
|
446
463
|
astNode: NormalizationLinkedField | NormalizationScalarField,
|
447
464
|
variables: { [index: string]: string },
|
448
|
-
index: number | null
|
465
|
+
index: number | null,
|
449
466
|
): DataId {
|
450
467
|
// Check whether the dataToNormalize has an id field. If so, that is the key.
|
451
468
|
// If not, we construct an id from the parentRecordId and the field parameters.
|
@@ -466,9 +483,7 @@ function getDataIdOfNetworkResponse(
|
|
466
483
|
}
|
467
484
|
|
468
485
|
for (const fieldParameter of fieldParameters) {
|
469
|
-
|
470
|
-
const valueToUse = variables[variableName];
|
471
|
-
storeKey += `${FIRST_SPLIT_KEY}${argumentName}${SECOND_SPLIT_KEY}${valueToUse}`;
|
486
|
+
storeKey += getStoreKeyChunkForArgument(fieldParameter, variables);
|
472
487
|
}
|
473
488
|
return storeKey;
|
474
489
|
}
|
package/src/componentCache.ts
CHANGED
@@ -1,9 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
|
3
|
-
RefetchQueryArtifactWrapper,
|
4
|
-
readButDoNotEvaluate,
|
5
|
-
} from "./index";
|
6
|
-
import { DataId, stableCopy } from "./cache";
|
1
|
+
import { ReaderArtifact, RefetchQueryArtifactWrapper, readButDoNotEvaluate } from './index';
|
2
|
+
import { DataId, stableCopy } from './cache';
|
7
3
|
|
8
4
|
type ComponentName = string;
|
9
5
|
type StringifiedArgs = string;
|
@@ -17,7 +13,7 @@ export function getOrCreateCachedComponent(
|
|
17
13
|
componentName: string,
|
18
14
|
readerArtifact: ReaderArtifact<any, any, any>,
|
19
15
|
variables: { [key: string]: string },
|
20
|
-
resolverRefetchQueries: RefetchQueryArtifactWrapper[]
|
16
|
+
resolverRefetchQueries: RefetchQueryArtifactWrapper[],
|
21
17
|
) {
|
22
18
|
const stringifiedArgs = JSON.stringify(stableCopy(variables));
|
23
19
|
cachedComponentsById[root] = cachedComponentsById[root] ?? {};
|
@@ -29,7 +25,7 @@ export function getOrCreateCachedComponent(
|
|
29
25
|
(() => {
|
30
26
|
function Component(additionalRuntimeProps) {
|
31
27
|
const data = readButDoNotEvaluate({
|
32
|
-
kind:
|
28
|
+
kind: 'FragmentReference',
|
33
29
|
readerArtifact: readerArtifact,
|
34
30
|
root,
|
35
31
|
variables,
|