@isograph/react 0.2.0 → 0.3.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.
- package/dist/core/FragmentReference.d.ts +14 -4
- package/dist/core/FragmentReference.d.ts.map +1 -0
- package/dist/core/FragmentReference.js +2 -3
- package/dist/core/IsographEnvironment.d.ts +28 -10
- package/dist/core/IsographEnvironment.d.ts.map +1 -0
- package/dist/core/IsographEnvironment.js +15 -22
- package/dist/core/PromiseWrapper.d.ts +1 -0
- package/dist/core/PromiseWrapper.d.ts.map +1 -0
- package/dist/core/PromiseWrapper.js +4 -5
- package/dist/core/areEqualWithDeepComparison.d.ts +5 -3
- package/dist/core/areEqualWithDeepComparison.d.ts.map +1 -0
- package/dist/core/areEqualWithDeepComparison.js +73 -39
- package/dist/core/cache.d.ts +26 -10
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +160 -98
- package/dist/core/check.d.ts +18 -0
- package/dist/core/check.d.ts.map +1 -0
- package/dist/core/check.js +127 -0
- package/dist/core/componentCache.d.ts +1 -1
- package/dist/core/componentCache.d.ts.map +1 -0
- package/dist/core/componentCache.js +14 -14
- package/dist/core/entrypoint.d.ts +27 -8
- package/dist/core/entrypoint.d.ts.map +1 -0
- package/dist/core/entrypoint.js +1 -2
- package/dist/core/garbageCollection.d.ts +3 -1
- package/dist/core/garbageCollection.d.ts.map +1 -0
- package/dist/core/garbageCollection.js +48 -15
- package/dist/core/logging.d.ts +69 -0
- package/dist/core/logging.d.ts.map +1 -0
- package/dist/core/logging.js +19 -0
- package/dist/core/makeNetworkRequest.d.ts +4 -1
- package/dist/core/makeNetworkRequest.d.ts.map +1 -0
- package/dist/core/makeNetworkRequest.js +71 -15
- package/dist/core/read.d.ts +20 -5
- package/dist/core/read.d.ts.map +1 -0
- package/dist/core/read.js +104 -41
- package/dist/core/reader.d.ts +34 -10
- package/dist/core/reader.d.ts.map +1 -0
- package/dist/core/util.d.ts +2 -0
- package/dist/core/util.d.ts.map +1 -0
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -2
- package/dist/loadable-hooks/useClientSideDefer.d.ts +15 -3
- package/dist/loadable-hooks/useClientSideDefer.d.ts.map +1 -0
- package/dist/loadable-hooks/useClientSideDefer.js +4 -6
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts +34 -0
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -0
- package/dist/loadable-hooks/useConnectionSpecPagination.js +160 -0
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +1 -0
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts.map +1 -0
- package/dist/loadable-hooks/useImperativeExposedMutationField.js +1 -2
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts +13 -5
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts.map +1 -0
- package/dist/loadable-hooks/useImperativeLoadableField.js +3 -4
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts +18 -24
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -0
- package/dist/loadable-hooks/useSkipLimitPagination.js +88 -44
- package/dist/react/FragmentReader.d.ts +7 -4
- package/dist/react/FragmentReader.d.ts.map +1 -0
- package/dist/react/FragmentReader.js +4 -2
- package/dist/react/IsographEnvironmentProvider.d.ts +1 -0
- package/dist/react/IsographEnvironmentProvider.d.ts.map +1 -0
- package/dist/react/IsographEnvironmentProvider.js +3 -3
- package/dist/react/RenderAfterCommit__DO_NOT_USE.d.ts +10 -0
- package/dist/react/RenderAfterCommit__DO_NOT_USE.d.ts.map +1 -0
- package/dist/react/RenderAfterCommit__DO_NOT_USE.js +15 -0
- package/dist/react/useImperativeReference.d.ts +8 -3
- package/dist/react/useImperativeReference.d.ts.map +1 -0
- package/dist/react/useImperativeReference.js +4 -5
- package/dist/react/useLazyReference.d.ts +7 -2
- package/dist/react/useLazyReference.d.ts.map +1 -0
- package/dist/react/useLazyReference.js +11 -4
- package/dist/react/useReadAndSubscribe.d.ts +12 -3
- package/dist/react/useReadAndSubscribe.d.ts.map +1 -0
- package/dist/react/useReadAndSubscribe.js +6 -7
- package/dist/react/useRerenderOnChange.d.ts +6 -1
- package/dist/react/useRerenderOnChange.d.ts.map +1 -0
- package/dist/react/useRerenderOnChange.js +3 -4
- package/dist/react/useResult.d.ts +5 -1
- package/dist/react/useResult.d.ts.map +1 -0
- package/dist/react/useResult.js +8 -5
- package/{src/tests/isograph.config.json → isograph.config.json} +1 -1
- package/package.json +12 -8
- package/{src/tests/schema.graphql → schema.graphql} +1 -0
- package/src/core/FragmentReference.ts +17 -5
- package/src/core/IsographEnvironment.ts +38 -29
- package/src/core/areEqualWithDeepComparison.ts +76 -42
- package/src/core/cache.ts +237 -123
- package/src/core/check.ts +207 -0
- package/src/core/componentCache.ts +18 -17
- package/src/core/entrypoint.ts +15 -8
- package/src/core/garbageCollection.ts +71 -20
- package/src/core/logging.ts +116 -0
- package/src/core/makeNetworkRequest.ts +89 -13
- package/src/core/read.ts +162 -55
- package/src/core/reader.ts +40 -13
- package/src/core/util.ts +4 -0
- package/src/index.ts +14 -1
- package/src/loadable-hooks/useClientSideDefer.ts +45 -15
- package/src/loadable-hooks/useConnectionSpecPagination.ts +331 -0
- package/src/loadable-hooks/useImperativeLoadableField.ts +36 -10
- package/src/loadable-hooks/useSkipLimitPagination.ts +231 -90
- package/src/react/FragmentReader.tsx +13 -4
- package/src/react/RenderAfterCommit__DO_NOT_USE.tsx +17 -0
- package/src/react/useImperativeReference.ts +18 -7
- package/src/react/useLazyReference.ts +24 -4
- package/src/react/useReadAndSubscribe.ts +20 -5
- package/src/react/useRerenderOnChange.ts +6 -1
- package/src/react/useResult.ts +10 -2
- package/src/tests/__isograph/Query/meName/entrypoint.ts +7 -2
- package/src/tests/__isograph/Query/meName/param_type.ts +5 -2
- package/src/tests/__isograph/Query/meName/resolver_reader.ts +1 -0
- package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +9 -2
- package/src/tests/__isograph/Query/meNameSuccessor/param_type.ts +9 -6
- package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +3 -0
- package/src/tests/__isograph/Query/nodeField/entrypoint.ts +13 -2
- package/src/tests/__isograph/Query/nodeField/param_type.ts +7 -3
- package/src/tests/__isograph/Query/nodeField/parameters_type.ts +3 -0
- package/src/tests/__isograph/Query/nodeField/resolver_reader.ts +1 -0
- package/src/tests/__isograph/Query/subquery/entrypoint.ts +67 -0
- package/src/tests/__isograph/Query/subquery/output_type.ts +3 -0
- package/src/tests/__isograph/Query/subquery/param_type.ts +12 -0
- package/src/tests/__isograph/Query/subquery/parameters_type.ts +3 -0
- package/src/tests/__isograph/Query/subquery/resolver_reader.ts +47 -0
- package/src/tests/__isograph/iso.ts +22 -11
- package/src/tests/garbageCollection.test.ts +45 -39
- package/src/tests/meNameSuccessor.ts +8 -3
- package/src/tests/nodeQuery.ts +6 -4
- package/src/tests/normalizeData.test.ts +120 -0
- package/src/tests/tsconfig.json +3 -3
- package/tsconfig.json +2 -2
- package/tsconfig.pkg.json +6 -1
- package/vitest.config.ts +20 -0
package/dist/core/cache.js
CHANGED
@@ -1,28 +1,37 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.SECOND_SPLIT_KEY = exports.FIRST_SPLIT_KEY = exports.
|
3
|
+
exports.SECOND_SPLIT_KEY = exports.FIRST_SPLIT_KEY = exports.TYPENAME_FIELD_NAME = void 0;
|
4
|
+
exports.getOrCreateItemInSuspenseCache = getOrCreateItemInSuspenseCache;
|
5
|
+
exports.stableCopy = stableCopy;
|
6
|
+
exports.getOrCreateCacheForArtifact = getOrCreateCacheForArtifact;
|
7
|
+
exports.normalizeData = normalizeData;
|
8
|
+
exports.subscribeToAnyChange = subscribeToAnyChange;
|
9
|
+
exports.subscribeToAnyChangesToRecord = subscribeToAnyChangesToRecord;
|
10
|
+
exports.subscribe = subscribe;
|
11
|
+
exports.onNextChangeToRecord = onNextChangeToRecord;
|
12
|
+
exports.insertIfNotExists = insertIfNotExists;
|
13
|
+
exports.getParentRecordKey = getParentRecordKey;
|
4
14
|
const react_disposable_state_1 = require("@isograph/react-disposable-state");
|
5
15
|
const IsographEnvironment_1 = require("./IsographEnvironment");
|
6
16
|
const read_1 = require("./read");
|
7
17
|
const areEqualWithDeepComparison_1 = require("./areEqualWithDeepComparison");
|
8
18
|
const makeNetworkRequest_1 = require("./makeNetworkRequest");
|
9
19
|
const PromiseWrapper_1 = require("./PromiseWrapper");
|
10
|
-
const
|
20
|
+
const logging_1 = require("./logging");
|
21
|
+
exports.TYPENAME_FIELD_NAME = '__typename';
|
11
22
|
function getOrCreateItemInSuspenseCache(environment, index, factory) {
|
12
|
-
//
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
}
|
23
|
+
// TODO this is probably a useless message, we should remove it
|
24
|
+
(0, logging_1.logMessage)(environment, {
|
25
|
+
kind: 'GettingSuspenseCacheItem',
|
26
|
+
index,
|
27
|
+
availableCacheItems: Object.keys(environment.fragmentCache),
|
28
|
+
found: !!environment.fragmentCache[index],
|
29
|
+
});
|
20
30
|
if (environment.fragmentCache[index] == null) {
|
21
31
|
environment.fragmentCache[index] = new react_disposable_state_1.ParentCache(factory);
|
22
32
|
}
|
23
33
|
return environment.fragmentCache[index];
|
24
34
|
}
|
25
|
-
exports.getOrCreateItemInSuspenseCache = getOrCreateItemInSuspenseCache;
|
26
35
|
/**
|
27
36
|
* Creates a copy of the provided value, ensuring any nested objects have their
|
28
37
|
* keys sorted such that equivalent values would have identical JSON.stringify
|
@@ -44,11 +53,11 @@ function stableCopy(value) {
|
|
44
53
|
}
|
45
54
|
return stable;
|
46
55
|
}
|
47
|
-
|
48
|
-
|
49
|
-
|
56
|
+
function getOrCreateCacheForArtifact(environment, entrypoint, variables, fetchOptions) {
|
57
|
+
const cacheKey = entrypoint.networkRequestInfo.queryText +
|
58
|
+
JSON.stringify(stableCopy(variables));
|
50
59
|
const factory = () => {
|
51
|
-
const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.
|
60
|
+
const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.maybeMakeNetworkRequest)(environment, entrypoint, variables, fetchOptions);
|
52
61
|
const itemCleanupPair = [
|
53
62
|
{
|
54
63
|
kind: 'FragmentReference',
|
@@ -57,7 +66,7 @@ function getOrCreateCacheForArtifact(environment, entrypoint, variables) {
|
|
57
66
|
readerArtifact: entrypoint.readerWithRefetchQueries.readerArtifact,
|
58
67
|
nestedRefetchQueries: entrypoint.readerWithRefetchQueries.nestedRefetchQueries,
|
59
68
|
}),
|
60
|
-
root: IsographEnvironment_1.ROOT_ID,
|
69
|
+
root: { __link: IsographEnvironment_1.ROOT_ID, __typename: entrypoint.concreteType },
|
61
70
|
variables,
|
62
71
|
networkRequest: networkRequest,
|
63
72
|
},
|
@@ -67,26 +76,27 @@ function getOrCreateCacheForArtifact(environment, entrypoint, variables) {
|
|
67
76
|
};
|
68
77
|
return getOrCreateItemInSuspenseCache(environment, cacheKey, factory);
|
69
78
|
}
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
79
|
+
function normalizeData(environment, normalizationAst, networkResponse, variables, nestedRefetchQueries, root) {
|
80
|
+
var _a, _b;
|
81
|
+
var _c, _d, _e;
|
82
|
+
const encounteredIds = new Map();
|
83
|
+
(0, logging_1.logMessage)(environment, {
|
84
|
+
kind: 'AboutToNormalize',
|
85
|
+
normalizationAst,
|
86
|
+
networkResponse,
|
87
|
+
variables,
|
88
|
+
});
|
89
|
+
const recordsById = ((_a = (_c = environment.store)[_d = root.__typename]) !== null && _a !== void 0 ? _a : (_c[_d] = {}));
|
90
|
+
const newStoreRecord = ((_b = recordsById[_e = root.__link]) !== null && _b !== void 0 ? _b : (recordsById[_e] = {}));
|
91
|
+
normalizeDataIntoRecord(environment, normalizationAst, networkResponse, newStoreRecord, root, variables, nestedRefetchQueries, encounteredIds);
|
92
|
+
(0, logging_1.logMessage)(environment, {
|
93
|
+
kind: 'AfterNormalization',
|
94
|
+
store: environment.store,
|
95
|
+
encounteredIds,
|
96
|
+
});
|
86
97
|
callSubscriptions(environment, encounteredIds);
|
87
98
|
return encounteredIds;
|
88
99
|
}
|
89
|
-
exports.normalizeData = normalizeData;
|
90
100
|
function subscribeToAnyChange(environment, callback) {
|
91
101
|
const subscription = {
|
92
102
|
kind: 'AnyRecords',
|
@@ -95,30 +105,35 @@ function subscribeToAnyChange(environment, callback) {
|
|
95
105
|
environment.subscriptions.add(subscription);
|
96
106
|
return () => environment.subscriptions.delete(subscription);
|
97
107
|
}
|
98
|
-
|
108
|
+
function subscribeToAnyChangesToRecord(environment, recordLink, callback) {
|
109
|
+
const subscription = {
|
110
|
+
kind: 'AnyChangesToRecord',
|
111
|
+
recordLink,
|
112
|
+
callback,
|
113
|
+
};
|
114
|
+
environment.subscriptions.add(subscription);
|
115
|
+
return () => environment.subscriptions.delete(subscription);
|
116
|
+
}
|
99
117
|
// TODO we should re-read and call callback if the value has changed
|
100
|
-
function subscribe(environment, encounteredDataAndRecords, fragmentReference, callback) {
|
118
|
+
function subscribe(environment, encounteredDataAndRecords, fragmentReference, callback, readerAst) {
|
101
119
|
const fragmentSubscription = {
|
102
120
|
kind: 'FragmentSubscription',
|
103
121
|
callback,
|
104
122
|
encounteredDataAndRecords,
|
105
123
|
fragmentReference,
|
124
|
+
readerAst,
|
106
125
|
};
|
107
|
-
// @ts-expect-error
|
108
126
|
environment.subscriptions.add(fragmentSubscription);
|
109
|
-
// @ts-expect-error
|
110
127
|
return () => environment.subscriptions.delete(fragmentSubscription);
|
111
128
|
}
|
112
|
-
|
113
|
-
function onNextChange(environment) {
|
129
|
+
function onNextChangeToRecord(environment, recordLink) {
|
114
130
|
return new Promise((resolve) => {
|
115
|
-
const unsubscribe =
|
131
|
+
const unsubscribe = subscribeToAnyChangesToRecord(environment, recordLink, () => {
|
116
132
|
unsubscribe();
|
117
133
|
resolve();
|
118
134
|
});
|
119
135
|
});
|
120
136
|
}
|
121
|
-
exports.onNextChange = onNextChange;
|
122
137
|
// Calls to readButDoNotEvaluate can suspend (i.e. throw a promise).
|
123
138
|
// Maybe in the future, they will be able to throw errors.
|
124
139
|
//
|
@@ -134,6 +149,7 @@ function withErrorHandling(f) {
|
|
134
149
|
}
|
135
150
|
function callSubscriptions(environment, recordsEncounteredWhenNormalizing) {
|
136
151
|
environment.subscriptions.forEach(withErrorHandling((subscription) => {
|
152
|
+
var _a;
|
137
153
|
switch (subscription.kind) {
|
138
154
|
case 'FragmentSubscription': {
|
139
155
|
// TODO if there are multiple components subscribed to the same
|
@@ -157,32 +173,30 @@ function callSubscriptions(environment, recordsEncounteredWhenNormalizing) {
|
|
157
173
|
suspendIfInFlight: false,
|
158
174
|
throwOnNetworkError: false,
|
159
175
|
});
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
// TODO deep compare values
|
176
|
+
const mergedItem = (0, areEqualWithDeepComparison_1.mergeObjectsUsingReaderAst)(subscription.readerAst, subscription.encounteredDataAndRecords.item, newEncounteredDataAndRecords.item);
|
177
|
+
(0, logging_1.logMessage)(environment, {
|
178
|
+
kind: 'DeepEqualityCheck',
|
179
|
+
fragmentReference: subscription.fragmentReference,
|
180
|
+
old: subscription.encounteredDataAndRecords.item,
|
181
|
+
new: newEncounteredDataAndRecords.item,
|
182
|
+
deeplyEqual: mergedItem === subscription.encounteredDataAndRecords.item,
|
183
|
+
});
|
184
|
+
if (mergedItem !== subscription.encounteredDataAndRecords.item) {
|
170
185
|
subscription.callback(newEncounteredDataAndRecords);
|
171
186
|
}
|
172
|
-
else {
|
173
|
-
// @ts-expect-error
|
174
|
-
if (typeof window !== 'undefined' && window.__LOG) {
|
175
|
-
console.log('Deep equality - Yes', {
|
176
|
-
fragmentReference: subscription.fragmentReference,
|
177
|
-
old: subscription.encounteredDataAndRecords.item,
|
178
|
-
});
|
179
|
-
}
|
180
|
-
}
|
181
187
|
}
|
182
188
|
return;
|
183
189
|
}
|
184
190
|
case 'AnyRecords': {
|
185
|
-
|
191
|
+
subscription.callback();
|
192
|
+
return;
|
193
|
+
}
|
194
|
+
case 'AnyChangesToRecord': {
|
195
|
+
if ((_a = recordsEncounteredWhenNormalizing
|
196
|
+
.get(subscription.recordLink.__typename)) === null || _a === void 0 ? void 0 : _a.has(subscription.recordLink.__link)) {
|
197
|
+
subscription.callback();
|
198
|
+
}
|
199
|
+
return;
|
186
200
|
}
|
187
201
|
default: {
|
188
202
|
// Ensure we have covered all variants
|
@@ -193,7 +207,20 @@ function callSubscriptions(environment, recordsEncounteredWhenNormalizing) {
|
|
193
207
|
}
|
194
208
|
}));
|
195
209
|
}
|
196
|
-
function hasOverlappingIds(
|
210
|
+
function hasOverlappingIds(ids1, ids2) {
|
211
|
+
for (const [typeName, set1] of ids1.entries()) {
|
212
|
+
const set2 = ids2.get(typeName);
|
213
|
+
if (set2 === undefined) {
|
214
|
+
continue;
|
215
|
+
}
|
216
|
+
if (isNotDisjointFrom(set1, set2)) {
|
217
|
+
return true;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
return false;
|
221
|
+
}
|
222
|
+
// TODO use a polyfill library
|
223
|
+
function isNotDisjointFrom(set1, set2) {
|
197
224
|
for (const id of set1) {
|
198
225
|
if (set2.has(id)) {
|
199
226
|
return true;
|
@@ -204,7 +231,7 @@ function hasOverlappingIds(set1, set2) {
|
|
204
231
|
/**
|
205
232
|
* Mutate targetParentRecord according to the normalizationAst and networkResponseParentRecord.
|
206
233
|
*/
|
207
|
-
function normalizeDataIntoRecord(environment, normalizationAst, networkResponseParentRecord, targetParentRecord,
|
234
|
+
function normalizeDataIntoRecord(environment, normalizationAst, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds) {
|
208
235
|
let recordHasBeenUpdated = false;
|
209
236
|
for (const normalizationNode of normalizationAst) {
|
210
237
|
switch (normalizationNode.kind) {
|
@@ -215,13 +242,13 @@ function normalizeDataIntoRecord(environment, normalizationAst, networkResponseP
|
|
215
242
|
break;
|
216
243
|
}
|
217
244
|
case 'Linked': {
|
218
|
-
const linkedFieldResultedInChange = normalizeLinkedField(environment, normalizationNode, networkResponseParentRecord, targetParentRecord,
|
245
|
+
const linkedFieldResultedInChange = normalizeLinkedField(environment, normalizationNode, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds);
|
219
246
|
recordHasBeenUpdated =
|
220
247
|
recordHasBeenUpdated || linkedFieldResultedInChange;
|
221
248
|
break;
|
222
249
|
}
|
223
250
|
case 'InlineFragment': {
|
224
|
-
const inlineFragmentResultedInChange = normalizeInlineFragment(environment, normalizationNode, networkResponseParentRecord, targetParentRecord,
|
251
|
+
const inlineFragmentResultedInChange = normalizeInlineFragment(environment, normalizationNode, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds);
|
225
252
|
recordHasBeenUpdated =
|
226
253
|
recordHasBeenUpdated || inlineFragmentResultedInChange;
|
227
254
|
break;
|
@@ -235,10 +262,19 @@ function normalizeDataIntoRecord(environment, normalizationAst, networkResponseP
|
|
235
262
|
}
|
236
263
|
}
|
237
264
|
if (recordHasBeenUpdated) {
|
238
|
-
mutableEncounteredIds.
|
265
|
+
let encounteredRecordsIds = insertIfNotExists(mutableEncounteredIds, targetParentRecordLink.__typename);
|
266
|
+
encounteredRecordsIds.add(targetParentRecordLink.__link);
|
239
267
|
}
|
240
268
|
return recordHasBeenUpdated;
|
241
269
|
}
|
270
|
+
function insertIfNotExists(map, key) {
|
271
|
+
let result = map.get(key);
|
272
|
+
if (result === undefined) {
|
273
|
+
result = new Set();
|
274
|
+
map.set(key, result);
|
275
|
+
}
|
276
|
+
return result;
|
277
|
+
}
|
242
278
|
function normalizeScalarField(astNode, networkResponseParentRecord, targetStoreRecord, variables) {
|
243
279
|
const networkResponseKey = getNetworkResponseKey(astNode);
|
244
280
|
const networkResponseData = networkResponseParentRecord[networkResponseKey];
|
@@ -256,7 +292,8 @@ function normalizeScalarField(astNode, networkResponseParentRecord, targetStoreR
|
|
256
292
|
/**
|
257
293
|
* Mutate targetParentRecord with a given linked field ast node.
|
258
294
|
*/
|
259
|
-
function normalizeLinkedField(environment, astNode, networkResponseParentRecord, targetParentRecord,
|
295
|
+
function normalizeLinkedField(environment, astNode, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds) {
|
296
|
+
var _a, _b;
|
260
297
|
const networkResponseKey = getNetworkResponseKey(astNode);
|
261
298
|
const networkResponseData = networkResponseParentRecord[networkResponseKey];
|
262
299
|
const parentRecordKey = getParentRecordKey(astNode, variables);
|
@@ -265,7 +302,8 @@ function normalizeLinkedField(environment, astNode, networkResponseParentRecord,
|
|
265
302
|
targetParentRecord[parentRecordKey] = null;
|
266
303
|
return existingValue !== null;
|
267
304
|
}
|
268
|
-
if (
|
305
|
+
if (isScalarOrEmptyArray(networkResponseData) &&
|
306
|
+
!isNullOrEmptyArray(networkResponseData)) {
|
269
307
|
throw new Error('Unexpected scalar network response when normalizing a linked field');
|
270
308
|
}
|
271
309
|
if (Array.isArray(networkResponseData)) {
|
@@ -273,43 +311,61 @@ function normalizeLinkedField(environment, astNode, networkResponseParentRecord,
|
|
273
311
|
const dataIds = [];
|
274
312
|
for (let i = 0; i < networkResponseData.length; i++) {
|
275
313
|
const networkResponseObject = networkResponseData[i];
|
276
|
-
|
277
|
-
|
314
|
+
if (networkResponseObject == null) {
|
315
|
+
dataIds.push(null);
|
316
|
+
continue;
|
317
|
+
}
|
318
|
+
const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseObject, targetParentRecordLink, variables, i, nestedRefetchQueries, mutableEncounteredIds);
|
319
|
+
const __typename = (_a = astNode.concreteType) !== null && _a !== void 0 ? _a : networkResponseObject[exports.TYPENAME_FIELD_NAME];
|
320
|
+
if (__typename == null) {
|
321
|
+
throw new Error('Unexpected missing __typename in network response when normalizing a linked field. ' +
|
322
|
+
'This is indicative of a bug in Isograph.');
|
323
|
+
}
|
324
|
+
dataIds.push({
|
325
|
+
__link: newStoreRecordId,
|
326
|
+
__typename,
|
327
|
+
});
|
278
328
|
}
|
279
329
|
targetParentRecord[parentRecordKey] = dataIds;
|
280
330
|
return !dataIdsAreTheSame(existingValue, dataIds);
|
281
331
|
}
|
282
332
|
else {
|
283
|
-
const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseData,
|
333
|
+
const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseData, targetParentRecordLink, variables, null, nestedRefetchQueries, mutableEncounteredIds);
|
334
|
+
let __typename = (_b = astNode.concreteType) !== null && _b !== void 0 ? _b : networkResponseData[exports.TYPENAME_FIELD_NAME];
|
335
|
+
if (__typename == null) {
|
336
|
+
throw new Error('Unexpected missing __typename in network response when normalizing a linked field. ' +
|
337
|
+
'This is indicative of a bug in Isograph.');
|
338
|
+
}
|
284
339
|
targetParentRecord[parentRecordKey] = {
|
285
340
|
__link: newStoreRecordId,
|
341
|
+
__typename,
|
286
342
|
};
|
287
343
|
const link = (0, IsographEnvironment_1.getLink)(existingValue);
|
288
|
-
return (link === null || link === void 0 ? void 0 : link.__link) !== newStoreRecordId;
|
344
|
+
return (link === null || link === void 0 ? void 0 : link.__link) !== newStoreRecordId || link.__typename !== __typename;
|
289
345
|
}
|
290
346
|
}
|
291
347
|
/**
|
292
348
|
* Mutate targetParentRecord with a given linked field ast node.
|
293
349
|
*/
|
294
|
-
function normalizeInlineFragment(environment, astNode, networkResponseParentRecord, targetParentRecord,
|
350
|
+
function normalizeInlineFragment(environment, astNode, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds) {
|
295
351
|
const typeToRefineTo = astNode.type;
|
296
|
-
if (networkResponseParentRecord[TYPENAME_FIELD_NAME] === typeToRefineTo) {
|
297
|
-
const hasBeenModified = normalizeDataIntoRecord(environment, astNode.selections, networkResponseParentRecord, targetParentRecord,
|
352
|
+
if (networkResponseParentRecord[exports.TYPENAME_FIELD_NAME] === typeToRefineTo) {
|
353
|
+
const hasBeenModified = normalizeDataIntoRecord(environment, astNode.selections, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds);
|
298
354
|
return hasBeenModified;
|
299
355
|
}
|
300
356
|
return false;
|
301
357
|
}
|
302
358
|
function dataIdsAreTheSame(existingValue, newDataIds) {
|
359
|
+
var _a, _b;
|
303
360
|
if (Array.isArray(existingValue)) {
|
304
361
|
if (newDataIds.length !== existingValue.length) {
|
305
362
|
return false;
|
306
363
|
}
|
307
364
|
for (let i = 0; i < newDataIds.length; i++) {
|
308
365
|
const maybeLink = (0, IsographEnvironment_1.getLink)(existingValue[i]);
|
309
|
-
if (
|
310
|
-
|
311
|
-
|
312
|
-
}
|
366
|
+
if (((_a = newDataIds[i]) === null || _a === void 0 ? void 0 : _a.__link) !== (maybeLink === null || maybeLink === void 0 ? void 0 : maybeLink.__link) ||
|
367
|
+
((_b = newDataIds[i]) === null || _b === void 0 ? void 0 : _b.__typename) !== (maybeLink === null || maybeLink === void 0 ? void 0 : maybeLink.__typename)) {
|
368
|
+
return false;
|
313
369
|
}
|
314
370
|
}
|
315
371
|
return true;
|
@@ -318,12 +374,18 @@ function dataIdsAreTheSame(existingValue, newDataIds) {
|
|
318
374
|
return false;
|
319
375
|
}
|
320
376
|
}
|
321
|
-
function normalizeNetworkResponseObject(environment, astNode, networkResponseData,
|
322
|
-
var _a;
|
323
|
-
|
324
|
-
const
|
325
|
-
|
326
|
-
|
377
|
+
function normalizeNetworkResponseObject(environment, astNode, networkResponseData, targetParentRecordLink, variables, index, nestedRefetchQueries, mutableEncounteredIds) {
|
378
|
+
var _a, _b, _c;
|
379
|
+
var _d;
|
380
|
+
const newStoreRecordId = getDataIdOfNetworkResponse(targetParentRecordLink, networkResponseData, astNode, variables, index);
|
381
|
+
const __typename = (_a = astNode.concreteType) !== null && _a !== void 0 ? _a : networkResponseData[exports.TYPENAME_FIELD_NAME];
|
382
|
+
if (__typename == null) {
|
383
|
+
throw new Error('Unexpected missing __typename in network response object. ' +
|
384
|
+
'This is indicative of a bug in Isograph.');
|
385
|
+
}
|
386
|
+
const recordsById = ((_b = (_d = environment.store)[__typename]) !== null && _b !== void 0 ? _b : (_d[__typename] = {}));
|
387
|
+
const newStoreRecord = ((_c = recordsById[newStoreRecordId]) !== null && _c !== void 0 ? _c : (recordsById[newStoreRecordId] = {}));
|
388
|
+
normalizeDataIntoRecord(environment, astNode.selections, networkResponseData, newStoreRecord, { __link: newStoreRecordId, __typename: __typename }, variables, nestedRefetchQueries, mutableEncounteredIds);
|
327
389
|
return newStoreRecordId;
|
328
390
|
}
|
329
391
|
function isScalarOrEmptyArray(data) {
|
@@ -332,24 +394,20 @@ function isScalarOrEmptyArray(data) {
|
|
332
394
|
// This is maybe fixed in a new version of Typescript??
|
333
395
|
return data.every((x) => isScalarOrEmptyArray(x));
|
334
396
|
}
|
335
|
-
const isScalarValue =
|
397
|
+
const isScalarValue = data === null ||
|
398
|
+
typeof data === 'string' ||
|
336
399
|
typeof data === 'number' ||
|
337
400
|
typeof data === 'boolean';
|
338
401
|
return isScalarValue;
|
339
402
|
}
|
340
|
-
function
|
341
|
-
// N.B. empty arrays count as empty arrays of linked fields.
|
403
|
+
function isNullOrEmptyArray(data) {
|
342
404
|
if (Array.isArray(data)) {
|
343
405
|
if (data.length === 0) {
|
344
|
-
return
|
406
|
+
return true;
|
345
407
|
}
|
346
|
-
|
347
|
-
return data.every((x) => isScalarOrEmptyArray(x));
|
408
|
+
return data.every((x) => isNullOrEmptyArray(x));
|
348
409
|
}
|
349
|
-
|
350
|
-
typeof data === 'number' ||
|
351
|
-
typeof data === 'boolean';
|
352
|
-
return isScalarValue;
|
410
|
+
return data === null;
|
353
411
|
}
|
354
412
|
function getParentRecordKey(astNode, variables) {
|
355
413
|
let parentRecordKey = astNode.fieldName;
|
@@ -361,7 +419,6 @@ function getParentRecordKey(astNode, variables) {
|
|
361
419
|
}
|
362
420
|
return parentRecordKey;
|
363
421
|
}
|
364
|
-
exports.getParentRecordKey = getParentRecordKey;
|
365
422
|
function getStoreKeyChunkForArgumentValue(argumentValue, variables) {
|
366
423
|
var _a;
|
367
424
|
switch (argumentValue.kind) {
|
@@ -430,14 +487,19 @@ function getNetworkResponseKey(astNode) {
|
|
430
487
|
exports.FIRST_SPLIT_KEY = '____';
|
431
488
|
exports.SECOND_SPLIT_KEY = '___';
|
432
489
|
// Returns a key to look up an item in the store
|
433
|
-
function getDataIdOfNetworkResponse(
|
490
|
+
function getDataIdOfNetworkResponse(parentRecordLink, dataToNormalize, astNode, variables, index) {
|
491
|
+
// If we are dealing with nested Query, use __ROOT as id
|
492
|
+
// TODO do not hard code this value here
|
493
|
+
if (astNode.concreteType === 'Query') {
|
494
|
+
return IsographEnvironment_1.ROOT_ID;
|
495
|
+
}
|
434
496
|
// Check whether the dataToNormalize has an id field. If so, that is the key.
|
435
497
|
// If not, we construct an id from the parentRecordId and the field parameters.
|
436
498
|
const dataId = dataToNormalize.id;
|
437
499
|
if (dataId != null) {
|
438
500
|
return dataId;
|
439
501
|
}
|
440
|
-
let storeKey = `${
|
502
|
+
let storeKey = `${parentRecordLink.__typename}:${parentRecordLink.__link}.${astNode.fieldName}`;
|
441
503
|
if (index != null) {
|
442
504
|
storeKey += `.${index}`;
|
443
505
|
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { NormalizationAst } from './entrypoint';
|
2
|
+
import { Variables } from './FragmentReference';
|
3
|
+
import { IsographEnvironment, Link } from './IsographEnvironment';
|
4
|
+
export type ShouldFetch = 'Yes' | 'No' | 'IfNecessary';
|
5
|
+
export declare const DEFAULT_SHOULD_FETCH_VALUE: ShouldFetch;
|
6
|
+
export type FetchOptions = {
|
7
|
+
shouldFetch?: ShouldFetch;
|
8
|
+
onComplete?: () => void;
|
9
|
+
onError?: () => void;
|
10
|
+
};
|
11
|
+
export type CheckResult = {
|
12
|
+
kind: 'EnoughData';
|
13
|
+
} | {
|
14
|
+
kind: 'MissingData';
|
15
|
+
record: Link;
|
16
|
+
};
|
17
|
+
export declare function check(environment: IsographEnvironment, normalizationAst: NormalizationAst, variables: Variables, root: Link): CheckResult;
|
18
|
+
//# sourceMappingURL=check.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/core/check.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAEL,mBAAmB,EACnB,IAAI,EAEL,MAAM,uBAAuB,CAAC;AAG/B,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,IAAI,GAAG,aAAa,CAAC;AAEvD,eAAO,MAAM,0BAA0B,EAAE,WAA2B,CAAC;AAErE,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IACE,IAAI,EAAE,YAAY,CAAC;CACpB,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,IAAI,CAAC;CACd,CAAC;AAEN,wBAAgB,KAAK,CACnB,WAAW,EAAE,mBAAmB,EAChC,gBAAgB,EAAE,gBAAgB,EAClC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,IAAI,GACT,WAAW,CAgBb"}
|
@@ -0,0 +1,127 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.DEFAULT_SHOULD_FETCH_VALUE = void 0;
|
4
|
+
exports.check = check;
|
5
|
+
const cache_1 = require("./cache");
|
6
|
+
const IsographEnvironment_1 = require("./IsographEnvironment");
|
7
|
+
const logging_1 = require("./logging");
|
8
|
+
exports.DEFAULT_SHOULD_FETCH_VALUE = 'IfNecessary';
|
9
|
+
function check(environment, normalizationAst, variables, root) {
|
10
|
+
var _a, _b;
|
11
|
+
var _c, _d, _e;
|
12
|
+
const recordsById = ((_a = (_c = environment.store)[_d = root.__typename]) !== null && _a !== void 0 ? _a : (_c[_d] = {}));
|
13
|
+
const newStoreRecord = ((_b = recordsById[_e = root.__link]) !== null && _b !== void 0 ? _b : (recordsById[_e] = {}));
|
14
|
+
const checkResult = checkFromRecord(environment, normalizationAst, variables, newStoreRecord, root);
|
15
|
+
(0, logging_1.logMessage)(environment, {
|
16
|
+
kind: 'EnvironmentCheck',
|
17
|
+
result: checkResult,
|
18
|
+
});
|
19
|
+
return checkResult;
|
20
|
+
}
|
21
|
+
function checkFromRecord(environment, normalizationAst, variables, record, recordLink) {
|
22
|
+
var _a, _b;
|
23
|
+
normalizationAstLoop: for (const normalizationAstNode of normalizationAst) {
|
24
|
+
switch (normalizationAstNode.kind) {
|
25
|
+
case 'Scalar': {
|
26
|
+
const parentRecordKey = (0, cache_1.getParentRecordKey)(normalizationAstNode, variables);
|
27
|
+
const scalarValue = record[parentRecordKey];
|
28
|
+
// null means the value is known to be missing, so it must
|
29
|
+
// be exactly undefined
|
30
|
+
if (scalarValue === undefined) {
|
31
|
+
return {
|
32
|
+
kind: 'MissingData',
|
33
|
+
record: recordLink,
|
34
|
+
};
|
35
|
+
}
|
36
|
+
continue normalizationAstLoop;
|
37
|
+
}
|
38
|
+
case 'Linked': {
|
39
|
+
const parentRecordKey = (0, cache_1.getParentRecordKey)(normalizationAstNode, variables);
|
40
|
+
const linkedValue = record[parentRecordKey];
|
41
|
+
if (linkedValue === undefined) {
|
42
|
+
return {
|
43
|
+
kind: 'MissingData',
|
44
|
+
record: recordLink,
|
45
|
+
};
|
46
|
+
}
|
47
|
+
else if (linkedValue === null) {
|
48
|
+
continue;
|
49
|
+
}
|
50
|
+
else if (Array.isArray(linkedValue)) {
|
51
|
+
arrayItemsLoop: for (const item of linkedValue) {
|
52
|
+
const link = (0, IsographEnvironment_1.getLink)(item);
|
53
|
+
if (link === null) {
|
54
|
+
throw new Error('Unexpected non-link in the Isograph store. ' +
|
55
|
+
'This is indicative of a bug in Isograph.');
|
56
|
+
}
|
57
|
+
const linkedRecord = (_a = environment.store[link.__typename]) === null || _a === void 0 ? void 0 : _a[link.__link];
|
58
|
+
if (linkedRecord === undefined) {
|
59
|
+
return {
|
60
|
+
kind: 'MissingData',
|
61
|
+
record: link,
|
62
|
+
};
|
63
|
+
}
|
64
|
+
else if (linkedRecord === null) {
|
65
|
+
continue arrayItemsLoop;
|
66
|
+
}
|
67
|
+
else {
|
68
|
+
// TODO in __DEV__ assert linkedRecord is an object
|
69
|
+
const result = checkFromRecord(environment, normalizationAstNode.selections, variables, linkedRecord, link);
|
70
|
+
if (result.kind === 'MissingData') {
|
71
|
+
return result;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
else {
|
77
|
+
const link = (0, IsographEnvironment_1.getLink)(linkedValue);
|
78
|
+
if (link === null) {
|
79
|
+
throw new Error('Unexpected non-link in the Isograph store. ' +
|
80
|
+
'This is indicative of a bug in Isograph.');
|
81
|
+
}
|
82
|
+
const linkedRecord = (_b = environment.store[link.__typename]) === null || _b === void 0 ? void 0 : _b[link.__link];
|
83
|
+
if (linkedRecord === undefined) {
|
84
|
+
return {
|
85
|
+
kind: 'MissingData',
|
86
|
+
record: link,
|
87
|
+
};
|
88
|
+
}
|
89
|
+
else if (linkedRecord === null) {
|
90
|
+
continue normalizationAstLoop;
|
91
|
+
}
|
92
|
+
else {
|
93
|
+
// TODO in __DEV__ assert linkedRecord is an object
|
94
|
+
const result = checkFromRecord(environment, normalizationAstNode.selections, variables, linkedRecord, link);
|
95
|
+
if (result.kind === 'MissingData') {
|
96
|
+
return result;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
continue normalizationAstLoop;
|
101
|
+
}
|
102
|
+
case 'InlineFragment': {
|
103
|
+
const existingRecordTypename = record['__typename'];
|
104
|
+
if (existingRecordTypename == null ||
|
105
|
+
existingRecordTypename !== normalizationAstNode.type) {
|
106
|
+
return {
|
107
|
+
kind: 'MissingData',
|
108
|
+
record: recordLink,
|
109
|
+
};
|
110
|
+
}
|
111
|
+
const result = checkFromRecord(environment, normalizationAstNode.selections, variables, record, recordLink);
|
112
|
+
if (result.kind === 'MissingData') {
|
113
|
+
return result;
|
114
|
+
}
|
115
|
+
continue normalizationAstLoop;
|
116
|
+
}
|
117
|
+
default: {
|
118
|
+
let _ = normalizationAstNode;
|
119
|
+
_;
|
120
|
+
throw new Error('Unexpected case. This is indicative of a bug in Isograph.');
|
121
|
+
}
|
122
|
+
}
|
123
|
+
}
|
124
|
+
return {
|
125
|
+
kind: 'EnoughData',
|
126
|
+
};
|
127
|
+
}
|
@@ -1,5 +1,5 @@
|
|
1
|
-
/// <reference types="react" />
|
2
1
|
import { IsographEnvironment } from './IsographEnvironment';
|
3
2
|
import { FragmentReference } from './FragmentReference';
|
4
3
|
import { NetworkRequestReaderOptions } from './read';
|
5
4
|
export declare function getOrCreateCachedComponent(environment: IsographEnvironment, componentName: string, fragmentReference: FragmentReference<any, any>, networkRequestOptions: NetworkRequestReaderOptions): React.FC<any>;
|
5
|
+
//# sourceMappingURL=componentCache.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"componentCache.d.ts","sourceRoot":"","sources":["../../src/core/componentCache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,2BAA2B,EAAE,MAAM,QAAQ,CAAC;AAIrD,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,mBAAmB,EAChC,aAAa,EAAE,MAAM,EACrB,iBAAiB,EAAE,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,EAC9C,qBAAqB,EAAE,2BAA2B,GACjD,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAgDf"}
|