@isograph/react 0.1.0 → 0.2.0

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.
Files changed (107) hide show
  1. package/dist/core/FragmentReference.d.ts +15 -0
  2. package/dist/core/FragmentReference.js +17 -0
  3. package/dist/core/IsographEnvironment.d.ts +71 -0
  4. package/dist/core/IsographEnvironment.js +72 -0
  5. package/dist/core/PromiseWrapper.d.ts +27 -0
  6. package/dist/core/PromiseWrapper.js +58 -0
  7. package/dist/core/areEqualWithDeepComparison.d.ts +3 -0
  8. package/dist/core/areEqualWithDeepComparison.js +61 -0
  9. package/dist/core/cache.d.ts +28 -0
  10. package/dist/core/cache.js +452 -0
  11. package/dist/core/componentCache.d.ts +5 -0
  12. package/dist/core/componentCache.js +38 -0
  13. package/dist/core/entrypoint.d.ts +50 -0
  14. package/dist/core/entrypoint.js +8 -0
  15. package/dist/core/garbageCollection.d.ts +11 -0
  16. package/dist/core/garbageCollection.js +74 -0
  17. package/dist/core/makeNetworkRequest.d.ts +6 -0
  18. package/dist/core/makeNetworkRequest.js +62 -0
  19. package/dist/core/read.d.ts +12 -0
  20. package/dist/core/read.js +415 -0
  21. package/dist/core/reader.d.ts +63 -0
  22. package/dist/core/reader.js +2 -0
  23. package/dist/core/util.d.ts +17 -0
  24. package/dist/core/util.js +2 -0
  25. package/dist/index.d.ts +21 -118
  26. package/dist/index.js +50 -303
  27. package/dist/loadable-hooks/useClientSideDefer.d.ts +4 -0
  28. package/dist/loadable-hooks/useClientSideDefer.js +15 -0
  29. package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +5 -0
  30. package/dist/loadable-hooks/useImperativeExposedMutationField.js +15 -0
  31. package/dist/loadable-hooks/useImperativeLoadableField.d.ts +9 -0
  32. package/dist/loadable-hooks/useImperativeLoadableField.js +15 -0
  33. package/dist/loadable-hooks/useSkipLimitPagination.d.ts +33 -0
  34. package/dist/loadable-hooks/useSkipLimitPagination.js +118 -0
  35. package/dist/react/FragmentReader.d.ts +13 -0
  36. package/dist/react/FragmentReader.js +33 -0
  37. package/dist/react/IsographEnvironmentProvider.d.ts +10 -0
  38. package/dist/{IsographEnvironment.js → react/IsographEnvironmentProvider.js} +2 -20
  39. package/dist/react/useImperativeReference.d.ts +7 -0
  40. package/dist/react/useImperativeReference.js +36 -0
  41. package/dist/react/useLazyReference.d.ts +5 -0
  42. package/dist/react/useLazyReference.js +14 -0
  43. package/dist/react/useReadAndSubscribe.d.ts +11 -0
  44. package/dist/react/useReadAndSubscribe.js +41 -0
  45. package/dist/react/useRerenderOnChange.d.ts +3 -0
  46. package/dist/react/useRerenderOnChange.js +23 -0
  47. package/dist/react/useResult.d.ts +5 -0
  48. package/dist/react/useResult.js +36 -0
  49. package/docs/how-useLazyReference-works.md +117 -0
  50. package/package.json +12 -6
  51. package/src/core/FragmentReference.ts +37 -0
  52. package/src/core/IsographEnvironment.ts +183 -0
  53. package/src/core/PromiseWrapper.ts +86 -0
  54. package/src/core/areEqualWithDeepComparison.ts +78 -0
  55. package/src/core/cache.ts +721 -0
  56. package/src/core/componentCache.ts +61 -0
  57. package/src/core/entrypoint.ts +99 -0
  58. package/src/core/garbageCollection.ts +122 -0
  59. package/src/core/makeNetworkRequest.ts +99 -0
  60. package/src/core/read.ts +615 -0
  61. package/src/core/reader.ts +133 -0
  62. package/src/core/util.ts +23 -0
  63. package/src/index.ts +86 -0
  64. package/src/loadable-hooks/useClientSideDefer.ts +28 -0
  65. package/src/loadable-hooks/useImperativeExposedMutationField.ts +17 -0
  66. package/src/loadable-hooks/useImperativeLoadableField.ts +26 -0
  67. package/src/loadable-hooks/useSkipLimitPagination.ts +211 -0
  68. package/src/react/FragmentReader.tsx +34 -0
  69. package/src/react/IsographEnvironmentProvider.tsx +33 -0
  70. package/src/react/useImperativeReference.ts +57 -0
  71. package/src/react/useLazyReference.ts +22 -0
  72. package/src/react/useReadAndSubscribe.ts +66 -0
  73. package/src/react/useRerenderOnChange.ts +33 -0
  74. package/src/react/useResult.ts +65 -0
  75. package/src/tests/__isograph/Query/meName/entrypoint.ts +47 -0
  76. package/src/tests/__isograph/Query/meName/output_type.ts +3 -0
  77. package/src/tests/__isograph/Query/meName/param_type.ts +6 -0
  78. package/src/tests/__isograph/Query/meName/resolver_reader.ts +32 -0
  79. package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +83 -0
  80. package/src/tests/__isograph/Query/meNameSuccessor/output_type.ts +3 -0
  81. package/src/tests/__isograph/Query/meNameSuccessor/param_type.ts +11 -0
  82. package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +54 -0
  83. package/src/tests/__isograph/Query/nodeField/entrypoint.ts +46 -0
  84. package/src/tests/__isograph/Query/nodeField/output_type.ts +3 -0
  85. package/src/tests/__isograph/Query/nodeField/param_type.ts +6 -0
  86. package/src/tests/__isograph/Query/nodeField/resolver_reader.ts +37 -0
  87. package/src/tests/__isograph/iso.ts +88 -0
  88. package/src/tests/garbageCollection.test.ts +136 -0
  89. package/src/tests/isograph.config.json +7 -0
  90. package/src/tests/meNameSuccessor.ts +20 -0
  91. package/src/tests/nodeQuery.ts +17 -0
  92. package/src/tests/schema.graphql +16 -0
  93. package/src/tests/tsconfig.json +21 -0
  94. package/tsconfig.json +6 -0
  95. package/tsconfig.pkg.json +2 -1
  96. package/dist/IsographEnvironment.d.ts +0 -56
  97. package/dist/PromiseWrapper.d.ts +0 -13
  98. package/dist/PromiseWrapper.js +0 -22
  99. package/dist/cache.d.ts +0 -26
  100. package/dist/cache.js +0 -274
  101. package/dist/componentCache.d.ts +0 -6
  102. package/dist/componentCache.js +0 -31
  103. package/src/IsographEnvironment.tsx +0 -120
  104. package/src/PromiseWrapper.ts +0 -29
  105. package/src/cache.tsx +0 -484
  106. package/src/componentCache.ts +0 -44
  107. package/src/index.tsx +0 -651
@@ -1,120 +0,0 @@
1
- import { ReactNode, createContext, useContext } from 'react';
2
- import * as React from 'react';
3
- import { ParentCache } from '@isograph/isograph-react-disposable-state';
4
-
5
- export const IsographEnvironmentContext =
6
- createContext<IsographEnvironment | null>(null);
7
-
8
- type ComponentName = string;
9
- type StringifiedArgs = string;
10
- type ComponentCache = {
11
- [key: DataId]: {
12
- [key: ComponentName]: { [key: StringifiedArgs]: React.FC<any> };
13
- };
14
- };
15
-
16
- export type Subscriptions = Set<() => void>;
17
- type SuspenseCache = { [index: string]: ParentCache<any> };
18
-
19
- export type IsographEnvironment = {
20
- store: IsographStore;
21
- networkFunction: IsographNetworkFunction;
22
- missingFieldHandler: MissingFieldHandler | null;
23
- componentCache: ComponentCache;
24
- subscriptions: Subscriptions;
25
- suspenseCache: SuspenseCache;
26
- };
27
-
28
- export type MissingFieldHandler = (
29
- storeRecord: StoreRecord,
30
- root: DataId,
31
- fieldName: string,
32
- arguments_: { [index: string]: any } | null,
33
- variables: { [index: string]: any } | null,
34
- ) => Link | undefined;
35
-
36
- export type IsographNetworkFunction = (
37
- queryText: string,
38
- variables: object,
39
- ) => Promise<any>;
40
-
41
- export type Link = {
42
- __link: DataId;
43
- };
44
- export type DataTypeValue =
45
- // N.B. undefined is here to support optional id's, but
46
- // undefined should not *actually* be present in the store.
47
- | undefined
48
- // Singular scalar fields:
49
- | number
50
- | boolean
51
- | string
52
- | null
53
- // Singular linked fields:
54
- | Link
55
- // Plural scalar and linked fields:
56
- | DataTypeValue[];
57
-
58
- export type StoreRecord = {
59
- [index: DataId | string]: DataTypeValue;
60
- // TODO __typename?: T, which is restricted to being a concrete string
61
- // TODO this shouldn't always be named id
62
- id?: DataId;
63
- };
64
-
65
- export type DataId = string;
66
-
67
- export const ROOT_ID: DataId & '__ROOT' = '__ROOT';
68
-
69
- export type IsographStore = {
70
- [index: DataId]: StoreRecord | null;
71
- __ROOT: StoreRecord;
72
- };
73
-
74
- export type IsographEnvironmentProviderProps = {
75
- environment: IsographEnvironment;
76
- children: ReactNode;
77
- };
78
-
79
- export function IsographEnvironmentProvider({
80
- environment,
81
- children,
82
- }: IsographEnvironmentProviderProps) {
83
- return (
84
- <IsographEnvironmentContext.Provider value={environment}>
85
- {children}
86
- </IsographEnvironmentContext.Provider>
87
- );
88
- }
89
-
90
- export function useIsographEnvironment(): IsographEnvironment {
91
- const context = useContext(IsographEnvironmentContext);
92
- if (context == null) {
93
- throw new Error(
94
- 'Unexpected null environment context. Make sure to render ' +
95
- 'this component within an IsographEnvironmentProvider component',
96
- );
97
- }
98
- return context;
99
- }
100
-
101
- export function createIsographEnvironment(
102
- store: IsographStore,
103
- networkFunction: IsographNetworkFunction,
104
- missingFieldHandler?: MissingFieldHandler,
105
- ): IsographEnvironment {
106
- return {
107
- store,
108
- networkFunction,
109
- missingFieldHandler: missingFieldHandler ?? null,
110
- componentCache: {},
111
- subscriptions: new Set(),
112
- suspenseCache: {},
113
- };
114
- }
115
-
116
- export function createIsographStore() {
117
- return {
118
- [ROOT_ID]: {},
119
- };
120
- }
@@ -1,29 +0,0 @@
1
- const NOT_SET: Symbol = Symbol('NOT_SET');
2
- type NotSet = typeof NOT_SET;
3
-
4
- /**
5
- * Invariant:
6
- * Before the promise is resolved, value becomes non-null.
7
- */
8
- export type PromiseWrapper<T> = {
9
- promise: Promise<T>;
10
- value: Exclude<T, NotSet> | NotSet;
11
- };
12
-
13
- export function wrapPromise<T>(promise: Promise<T>): PromiseWrapper<T> {
14
- // TODO confirm suspense works if the promise is already resolved.
15
- const wrapper: PromiseWrapper<T> = { promise, value: NOT_SET };
16
- promise.then((v) => {
17
- // T is assignable to Exclude<T, Symbol> | Symbol
18
- wrapper.value = v as any;
19
- });
20
- return wrapper;
21
- }
22
-
23
- export function useReadPromise<T>(p: PromiseWrapper<T>): T {
24
- if (p.value !== NOT_SET) {
25
- // Safety: p.value is either NOT_SET or an actual value.
26
- return p.value as any;
27
- }
28
- throw p.promise;
29
- }
package/src/cache.tsx DELETED
@@ -1,484 +0,0 @@
1
- import {
2
- Factory,
3
- ItemCleanupPair,
4
- ParentCache,
5
- } from '@isograph/react-disposable-state';
6
- import { PromiseWrapper, wrapPromise } from './PromiseWrapper';
7
- import {
8
- Argument,
9
- ArgumentValue,
10
- IsographEntrypoint,
11
- NormalizationAst,
12
- NormalizationLinkedField,
13
- NormalizationScalarField,
14
- ReaderLinkedField,
15
- ReaderScalarField,
16
- RefetchQueryArtifactWrapper,
17
- } from './index';
18
- import {
19
- DataId,
20
- ROOT_ID,
21
- StoreRecord,
22
- Link,
23
- type IsographEnvironment,
24
- } from './IsographEnvironment';
25
-
26
- declare global {
27
- interface Window {
28
- __LOG: boolean;
29
- }
30
- }
31
-
32
- function getOrCreateCache<T>(
33
- environment: IsographEnvironment,
34
- index: string,
35
- factory: Factory<T>,
36
- ): ParentCache<T> {
37
- if (typeof window !== 'undefined' && window.__LOG) {
38
- console.log('getting cache for', {
39
- index,
40
- cache: Object.keys(environment.suspenseCache),
41
- found: !!environment.suspenseCache[index],
42
- });
43
- }
44
- if (environment.suspenseCache[index] == null) {
45
- environment.suspenseCache[index] = new ParentCache(factory);
46
- }
47
-
48
- return environment.suspenseCache[index];
49
- }
50
-
51
- /**
52
- * Creates a copy of the provided value, ensuring any nested objects have their
53
- * keys sorted such that equivalent values would have identical JSON.stringify
54
- * results.
55
- */
56
- export function stableCopy<T>(value: T): T {
57
- if (!value || typeof value !== 'object') {
58
- return value;
59
- }
60
- if (Array.isArray(value)) {
61
- // @ts-ignore
62
- return value.map(stableCopy);
63
- }
64
- const keys = Object.keys(value).sort();
65
- const stable: { [index: string]: any } = {};
66
- for (let i = 0; i < keys.length; i++) {
67
- // @ts-ignore
68
- stable[keys[i]] = stableCopy(value[keys[i]]);
69
- }
70
- return stable as any;
71
- }
72
-
73
- type IsoResolver = IsographEntrypoint<any, any, any>;
74
-
75
- export function getOrCreateCacheForArtifact<T>(
76
- environment: IsographEnvironment,
77
- artifact: IsographEntrypoint<any, any, T>,
78
- variables: object,
79
- ): ParentCache<PromiseWrapper<T>> {
80
- const cacheKey = artifact.queryText + JSON.stringify(stableCopy(variables));
81
- const factory: Factory<PromiseWrapper<T>> = () =>
82
- makeNetworkRequest<T>(environment, artifact, variables);
83
- return getOrCreateCache<PromiseWrapper<T>>(environment, cacheKey, factory);
84
- }
85
-
86
- export function makeNetworkRequest<T>(
87
- environment: IsographEnvironment,
88
- artifact: IsoResolver,
89
- variables: object,
90
- ): ItemCleanupPair<PromiseWrapper<T>> {
91
- if (typeof window !== 'undefined' && window.__LOG) {
92
- console.log('make network request', artifact, variables);
93
- }
94
- const promise = environment
95
- .networkFunction(artifact.queryText, variables)
96
- .then((networkResponse) => {
97
- if (typeof window !== 'undefined' && window.__LOG) {
98
- console.log('network response', artifact);
99
- }
100
- normalizeData(
101
- environment,
102
- artifact.normalizationAst,
103
- networkResponse.data,
104
- variables,
105
- artifact.nestedRefetchQueries,
106
- );
107
- return networkResponse.data;
108
- });
109
-
110
- const wrapper = wrapPromise(promise);
111
-
112
- const response: ItemCleanupPair<PromiseWrapper<T>> = [
113
- wrapper,
114
- () => {
115
- // delete from cache
116
- },
117
- ];
118
- return response;
119
- }
120
-
121
- type NetworkResponseScalarValue = string | number | boolean;
122
- type NetworkResponseValue =
123
- | NetworkResponseScalarValue
124
- | null
125
- | NetworkResponseObject
126
- | NetworkResponseObject[]
127
- | NetworkResponseScalarValue[];
128
- type NetworkResponseObject = {
129
- // N.B. undefined is here to support optional id's, but
130
- // undefined should not *actually* be present in the network response.
131
- [index: string]: undefined | NetworkResponseValue;
132
- id?: DataId;
133
- };
134
-
135
- function normalizeData(
136
- environment: IsographEnvironment,
137
- normalizationAst: NormalizationAst,
138
- networkResponse: NetworkResponseObject,
139
- variables: Object,
140
- nestedRefetchQueries: RefetchQueryArtifactWrapper[],
141
- ) {
142
- if (typeof window !== 'undefined' && window.__LOG) {
143
- console.log(
144
- 'about to normalize',
145
- normalizationAst,
146
- networkResponse,
147
- variables,
148
- );
149
- }
150
- normalizeDataIntoRecord(
151
- environment,
152
- normalizationAst,
153
- networkResponse,
154
- environment.store.__ROOT,
155
- ROOT_ID,
156
- variables as any,
157
- nestedRefetchQueries,
158
- );
159
- if (typeof window !== 'undefined' && window.__LOG) {
160
- console.log('after normalization', { store: environment.store });
161
- }
162
- callSubscriptions(environment);
163
- }
164
-
165
- export function subscribe(
166
- environment: IsographEnvironment,
167
- callback: () => void,
168
- ): () => void {
169
- environment.subscriptions.add(callback);
170
- return () => environment.subscriptions.delete(callback);
171
- }
172
-
173
- export function onNextChange(environment: IsographEnvironment): Promise<void> {
174
- return new Promise((resolve) => {
175
- const unsubscribe = subscribe(environment, () => {
176
- unsubscribe();
177
- resolve();
178
- });
179
- });
180
- }
181
-
182
- function callSubscriptions(environment: IsographEnvironment) {
183
- environment.subscriptions.forEach((callback) => callback());
184
- }
185
-
186
- /**
187
- * Mutate targetParentRecord according to the normalizationAst and networkResponseParentRecord.
188
- */
189
- function normalizeDataIntoRecord(
190
- environment: IsographEnvironment,
191
- normalizationAst: NormalizationAst,
192
- networkResponseParentRecord: NetworkResponseObject,
193
- targetParentRecord: StoreRecord,
194
- targetParentRecordId: DataId,
195
- variables: { [index: string]: string },
196
- nestedRefetchQueries: RefetchQueryArtifactWrapper[],
197
- ) {
198
- for (const normalizationNode of normalizationAst) {
199
- switch (normalizationNode.kind) {
200
- case 'Scalar': {
201
- normalizeScalarField(
202
- normalizationNode,
203
- networkResponseParentRecord,
204
- targetParentRecord,
205
- variables,
206
- );
207
- break;
208
- }
209
- case 'Linked': {
210
- normalizeLinkedField(
211
- environment,
212
- normalizationNode,
213
- networkResponseParentRecord,
214
- targetParentRecord,
215
- targetParentRecordId,
216
- variables,
217
- nestedRefetchQueries,
218
- );
219
- break;
220
- }
221
- }
222
- }
223
- }
224
-
225
- function normalizeScalarField(
226
- astNode: NormalizationScalarField,
227
- networkResponseParentRecord: NetworkResponseObject,
228
- targetStoreRecord: StoreRecord,
229
- variables: { [index: string]: string },
230
- ) {
231
- const networkResponseKey = getNetworkResponseKey(astNode);
232
- const networkResponseData = networkResponseParentRecord[networkResponseKey];
233
- const parentRecordKey = getParentRecordKey(astNode, variables);
234
-
235
- if (
236
- networkResponseData == null ||
237
- isScalarOrEmptyArray(networkResponseData)
238
- ) {
239
- targetStoreRecord[parentRecordKey] = networkResponseData;
240
- } else {
241
- throw new Error('Unexpected object array when normalizing scalar');
242
- }
243
- }
244
-
245
- /**
246
- * Mutate targetParentRecord with a given linked field ast node.
247
- */
248
- function normalizeLinkedField(
249
- environment: IsographEnvironment,
250
- astNode: NormalizationLinkedField,
251
- networkResponseParentRecord: NetworkResponseObject,
252
- targetParentRecord: StoreRecord,
253
- targetParentRecordId: DataId,
254
- variables: { [index: string]: string },
255
- nestedRefetchQueries: RefetchQueryArtifactWrapper[],
256
- ) {
257
- const networkResponseKey = getNetworkResponseKey(astNode);
258
- const networkResponseData = networkResponseParentRecord[networkResponseKey];
259
- const parentRecordKey = getParentRecordKey(astNode, variables);
260
-
261
- if (networkResponseData == null) {
262
- targetParentRecord[parentRecordKey] = null;
263
- return;
264
- }
265
-
266
- if (isScalarButNotEmptyArray(networkResponseData)) {
267
- throw new Error(
268
- 'Unexpected scalar network response when normalizing a linked field',
269
- );
270
- }
271
-
272
- if (Array.isArray(networkResponseData)) {
273
- // TODO check astNode.plural or the like
274
- const dataIds: Link[] = [];
275
- for (let i = 0; i < networkResponseData.length; i++) {
276
- const networkResponseObject = networkResponseData[i];
277
- const newStoreRecordId = normalizeNetworkResponseObject(
278
- environment,
279
- astNode,
280
- networkResponseObject,
281
- targetParentRecordId,
282
- variables,
283
- i,
284
- nestedRefetchQueries,
285
- );
286
- dataIds.push({ __link: newStoreRecordId });
287
- }
288
- targetParentRecord[parentRecordKey] = dataIds;
289
- } else {
290
- const newStoreRecordId = normalizeNetworkResponseObject(
291
- environment,
292
- astNode,
293
- networkResponseData,
294
- targetParentRecordId,
295
- variables,
296
- null,
297
- nestedRefetchQueries,
298
- );
299
- targetParentRecord[parentRecordKey] = {
300
- __link: newStoreRecordId,
301
- };
302
- }
303
- }
304
-
305
- function normalizeNetworkResponseObject(
306
- environment: IsographEnvironment,
307
- astNode: NormalizationLinkedField,
308
- networkResponseData: NetworkResponseObject,
309
- targetParentRecordId: string,
310
- variables: { [index: string]: string },
311
- index: number | null,
312
- nestedRefetchQueries: RefetchQueryArtifactWrapper[],
313
- ): DataId /* The id of the modified or newly created item */ {
314
- const newStoreRecordId = getDataIdOfNetworkResponse(
315
- targetParentRecordId,
316
- networkResponseData,
317
- astNode,
318
- variables,
319
- index,
320
- );
321
-
322
- const newStoreRecord = environment.store[newStoreRecordId] ?? {};
323
- environment.store[newStoreRecordId] = newStoreRecord;
324
-
325
- normalizeDataIntoRecord(
326
- environment,
327
- astNode.selections,
328
- networkResponseData,
329
- newStoreRecord,
330
- newStoreRecordId,
331
- variables,
332
- nestedRefetchQueries,
333
- );
334
-
335
- return newStoreRecordId;
336
- }
337
-
338
- function isScalarOrEmptyArray(
339
- data: NonNullable<NetworkResponseValue>,
340
- ): data is NetworkResponseScalarValue | NetworkResponseScalarValue[] {
341
- // N.B. empty arrays count as empty arrays of scalar fields.
342
- if (Array.isArray(data)) {
343
- // This is maybe fixed in a new version of Typescript??
344
- return (data as any).every((x: any) => isScalarOrEmptyArray(x));
345
- }
346
- const isScalarValue =
347
- typeof data === 'string' ||
348
- typeof data === 'number' ||
349
- typeof data === 'boolean';
350
- return isScalarValue;
351
- }
352
-
353
- function isScalarButNotEmptyArray(
354
- data: NonNullable<NetworkResponseValue>,
355
- ): data is NetworkResponseScalarValue | NetworkResponseScalarValue[] {
356
- // N.B. empty arrays count as empty arrays of linked fields.
357
- if (Array.isArray(data)) {
358
- if (data.length === 0) {
359
- return false;
360
- }
361
- // This is maybe fixed in a new version of Typescript??
362
- return (data as any).every((x: any) => isScalarOrEmptyArray(x));
363
- }
364
- const isScalarValue =
365
- typeof data === 'string' ||
366
- typeof data === 'number' ||
367
- typeof data === 'boolean';
368
- return isScalarValue;
369
- }
370
-
371
- export function getParentRecordKey(
372
- astNode:
373
- | NormalizationLinkedField
374
- | NormalizationScalarField
375
- | ReaderLinkedField
376
- | ReaderScalarField,
377
- variables: { [index: string]: string },
378
- ): string {
379
- let parentRecordKey = astNode.fieldName;
380
- const fieldParameters = astNode.arguments;
381
- if (fieldParameters != null) {
382
- for (const fieldParameter of fieldParameters) {
383
- parentRecordKey += getStoreKeyChunkForArgument(fieldParameter, variables);
384
- }
385
- }
386
-
387
- return parentRecordKey;
388
- }
389
-
390
- function getStoreKeyChunkForArgumentValue(
391
- argumentValue: ArgumentValue,
392
- variables: { [index: string]: string },
393
- ) {
394
- switch (argumentValue.kind) {
395
- case 'Literal': {
396
- return argumentValue.value;
397
- break;
398
- }
399
- case 'Variable': {
400
- return variables[argumentValue.name];
401
- break;
402
- }
403
- default: {
404
- // TODO configure eslint to allow unused vars starting with _
405
- // @ts-expect-error
406
- const _: never = argumentValue;
407
- throw new Error('Unexpected case');
408
- }
409
- }
410
- }
411
-
412
- function getStoreKeyChunkForArgument(
413
- argument: Argument,
414
- variables: { [index: string]: string },
415
- ) {
416
- const chunk = getStoreKeyChunkForArgumentValue(argument[1], variables);
417
- return `${FIRST_SPLIT_KEY}${argument[0]}${SECOND_SPLIT_KEY}${chunk}`;
418
- }
419
-
420
- function getNetworkResponseKey(
421
- astNode: NormalizationLinkedField | NormalizationScalarField,
422
- ): string {
423
- let networkResponseKey = astNode.fieldName;
424
- const fieldParameters = astNode.arguments;
425
- if (fieldParameters != null) {
426
- for (const fieldParameter of fieldParameters) {
427
- const [argumentName, argumentValue] = fieldParameter;
428
- let argumentValueChunk;
429
- switch (argumentValue.kind) {
430
- case 'Literal': {
431
- argumentValueChunk = 'l_' + argumentValue.value;
432
- break;
433
- }
434
- case 'Variable': {
435
- argumentValueChunk = 'v_' + argumentValue.name;
436
- break;
437
- }
438
- default: {
439
- // @ts-expect-error
440
- let _: never = argumentValue;
441
- throw new Error('Unexpected case');
442
- }
443
- }
444
- networkResponseKey += `${FIRST_SPLIT_KEY}${argumentName}${SECOND_SPLIT_KEY}${argumentValueChunk}`;
445
- }
446
- }
447
- return networkResponseKey;
448
- }
449
-
450
- // an alias might be pullRequests____first___first____after___cursor
451
- export const FIRST_SPLIT_KEY = '____';
452
- export const SECOND_SPLIT_KEY = '___';
453
-
454
- // Returns a key to look up an item in the store
455
- function getDataIdOfNetworkResponse(
456
- parentRecordId: DataId,
457
- dataToNormalize: NetworkResponseObject,
458
- astNode: NormalizationLinkedField | NormalizationScalarField,
459
- variables: { [index: string]: string },
460
- index: number | null,
461
- ): DataId {
462
- // Check whether the dataToNormalize has an id field. If so, that is the key.
463
- // If not, we construct an id from the parentRecordId and the field parameters.
464
-
465
- const dataId = dataToNormalize.id;
466
- if (dataId != null) {
467
- return dataId;
468
- }
469
-
470
- let storeKey = `${parentRecordId}.${astNode.fieldName}`;
471
- if (index != null) {
472
- storeKey += `.${index}`;
473
- }
474
-
475
- const fieldParameters = astNode.arguments;
476
- if (fieldParameters == null) {
477
- return storeKey;
478
- }
479
-
480
- for (const fieldParameter of fieldParameters) {
481
- storeKey += getStoreKeyChunkForArgument(fieldParameter, variables);
482
- }
483
- return storeKey;
484
- }
@@ -1,44 +0,0 @@
1
- import {
2
- ReaderArtifact,
3
- RefetchQueryArtifactWrapper,
4
- readButDoNotEvaluate,
5
- } from './index';
6
- import { stableCopy } from './cache';
7
- import { IsographEnvironment, DataId } from './IsographEnvironment';
8
-
9
- export function getOrCreateCachedComponent(
10
- environment: IsographEnvironment,
11
- root: DataId,
12
- componentName: string,
13
- readerArtifact: ReaderArtifact<any, any, any>,
14
- variables: { [key: string]: string },
15
- resolverRefetchQueries: RefetchQueryArtifactWrapper[],
16
- ) {
17
- const cachedComponentsById = environment.componentCache;
18
- const stringifiedArgs = JSON.stringify(stableCopy(variables));
19
- cachedComponentsById[root] = cachedComponentsById[root] ?? {};
20
- const componentsByName = cachedComponentsById[root];
21
- componentsByName[componentName] = componentsByName[componentName] ?? {};
22
- const byArgs = componentsByName[componentName];
23
- byArgs[stringifiedArgs] =
24
- byArgs[stringifiedArgs] ??
25
- (() => {
26
- function Component(additionalRuntimeProps: { [key: string]: any }) {
27
- const data = readButDoNotEvaluate(environment, {
28
- kind: 'FragmentReference',
29
- readerArtifact: readerArtifact,
30
- root,
31
- variables,
32
- nestedRefetchQueries: resolverRefetchQueries,
33
- });
34
-
35
- return readerArtifact.resolver({
36
- data,
37
- ...additionalRuntimeProps,
38
- });
39
- }
40
- Component.displayName = `${componentName} (id: ${root}) @component`;
41
- return Component;
42
- })();
43
- return byArgs[stringifiedArgs];
44
- }