@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/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
- Factory,
3
- ItemCleanupPair,
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 "./index";
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
- index: string,
27
- factory: Factory<T>
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 !== "object") {
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 !== "undefined" && window.__LOG) {
89
- console.log("make network request", artifact, variables);
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("Network must be set before makeNetworkRequest is called");
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
- (networkResponse) => {
97
- if (typeof window !== "undefined" && window.__LOG) {
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 & "__ROOT" = "__ROOT";
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 !== "undefined" && window.__LOG) {
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 !== "undefined" && window.__LOG) {
200
- console.log("after normalization", { store });
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 "Scalar": {
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 "Linked": {
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("Unexpected object array when normalizing scalar");
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 === "string" ||
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 === "string" ||
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
- const { argumentName, variableName } = fieldParameter;
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 { argumentName, variableName } = fieldParameter;
432
- networkResponseKey += `${FIRST_SPLIT_KEY}${argumentName}${SECOND_SPLIT_KEY}${variableName}`;
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
- const { argumentName, variableName } = fieldParameter;
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
  }
@@ -1,9 +1,5 @@
1
- import {
2
- ReaderArtifact,
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: "FragmentReference",
28
+ kind: 'FragmentReference',
33
29
  readerArtifact: readerArtifact,
34
30
  root,
35
31
  variables,