@isograph/react 0.0.0-main-d319cfe5 → 0.0.0-main-b72868e3

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.
@@ -2,12 +2,13 @@ import { DataId } from './IsographEnvironment';
2
2
  import { RefetchQueryArtifactWrapper } from './entrypoint';
3
3
  import { ReaderArtifact } from './reader';
4
4
  export type Variable = any;
5
+ export type Variables = {
6
+ readonly [index: string]: Variable;
7
+ };
5
8
  export type FragmentReference<TReadFromStore extends Object, TClientFieldValue> = {
6
9
  kind: 'FragmentReference';
7
10
  readerArtifact: ReaderArtifact<TReadFromStore, TClientFieldValue>;
8
11
  root: DataId;
9
- variables: {
10
- [index: string]: Variable;
11
- } | null;
12
+ variables: Variables | null;
12
13
  nestedRefetchQueries: RefetchQueryArtifactWrapper[];
13
14
  };
@@ -1,24 +1,30 @@
1
1
  /// <reference types="react" />
2
2
  import { ParentCache } from '@isograph/react-disposable-state';
3
3
  import { RetainedQuery } from './garbageCollection';
4
+ import { WithEncounteredRecords } from './read';
5
+ import { FragmentReference } from './FragmentReference';
4
6
  export type ComponentOrFieldName = string;
5
- type StringifiedArgs = string;
6
- type ComponentAndEncounteredRecordsCache = {
7
+ export type StringifiedArgs = string;
8
+ type ComponentCache = {
7
9
  [key: DataId]: {
8
10
  [key: ComponentOrFieldName]: {
9
- [key: StringifiedArgs]: ComponentAndEncounteredRecords;
11
+ [key: StringifiedArgs]: React.FC<any>;
10
12
  };
11
13
  };
12
14
  };
13
- export type ComponentAndEncounteredRecords = {
14
- component: React.FC<any>;
15
- encounteredRecordsDuringLastRead: Set<DataId> | null;
15
+ type FragmentSubscription<TReadFromStore extends Object> = {
16
+ readonly kind: 'FragmentSubscription';
17
+ readonly callback: (newEncounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>) => void;
18
+ /** The value read out from the previous call to readButDoNotEvaluate */
19
+ readonly encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>;
20
+ readonly fragmentReference: FragmentReference<TReadFromStore, any>;
16
21
  };
17
- type CallbackAndRecords = {
18
- callback: () => void;
19
- records: Set<DataId> | null;
22
+ type AnyRecordSubscription = {
23
+ readonly kind: 'AnyRecords';
24
+ readonly callback: () => void;
20
25
  };
21
- type Subscriptions = Set<CallbackAndRecords>;
26
+ type Subscription = FragmentSubscription<Object> | AnyRecordSubscription;
27
+ type Subscriptions = Set<Subscription>;
22
28
  type SuspenseCache = {
23
29
  [index: string]: ParentCache<any>;
24
30
  };
@@ -26,12 +32,12 @@ export type IsographEnvironment = {
26
32
  store: IsographStore;
27
33
  networkFunction: IsographNetworkFunction;
28
34
  missingFieldHandler: MissingFieldHandler | null;
35
+ componentCache: ComponentCache;
29
36
  subscriptions: Subscriptions;
37
+ suspenseCache: SuspenseCache;
30
38
  retainedQueries: Set<RetainedQuery>;
31
39
  gcBuffer: Array<RetainedQuery>;
32
40
  gcBufferSize: number;
33
- componentAndEncounteredRecordsCache: ComponentAndEncounteredRecordsCache;
34
- suspenseCache: SuspenseCache;
35
41
  };
36
42
  export type MissingFieldHandler = (storeRecord: StoreRecord, root: DataId, fieldName: string, arguments_: {
37
43
  [index: string]: any;
@@ -8,7 +8,7 @@ function createIsographEnvironment(store, networkFunction, missingFieldHandler)
8
8
  store,
9
9
  networkFunction,
10
10
  missingFieldHandler: missingFieldHandler !== null && missingFieldHandler !== void 0 ? missingFieldHandler : null,
11
- componentAndEncounteredRecordsCache: {},
11
+ componentCache: {},
12
12
  subscriptions: new Set(),
13
13
  suspenseCache: {},
14
14
  retainedQueries: new Set(),
@@ -0,0 +1,3 @@
1
+ export declare function areEqualWithDeepComparison(oldItem: unknown, newItem: unknown): boolean;
2
+ export declare function areEqualArraysWithDeepComparison(oldItems: ReadonlyArray<unknown>, newItems: ReadonlyArray<unknown>): boolean;
3
+ export declare function areEqualObjectsWithDeepComparison(oldItemObject: object, newItemObject: object): boolean;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.areEqualObjectsWithDeepComparison = exports.areEqualArraysWithDeepComparison = exports.areEqualWithDeepComparison = void 0;
4
+ function areEqualWithDeepComparison(oldItem, newItem) {
5
+ if (newItem === null) {
6
+ return oldItem === null;
7
+ }
8
+ if (newItem === undefined) {
9
+ return oldItem === undefined;
10
+ }
11
+ if (Array.isArray(newItem)) {
12
+ if (!Array.isArray(oldItem)) {
13
+ return false;
14
+ }
15
+ return areEqualArraysWithDeepComparison(oldItem, newItem);
16
+ }
17
+ if (typeof newItem === 'object') {
18
+ if (typeof oldItem !== 'object') {
19
+ return false;
20
+ }
21
+ if (oldItem === null) {
22
+ return false;
23
+ }
24
+ return areEqualObjectsWithDeepComparison(oldItem, newItem);
25
+ }
26
+ return newItem === oldItem;
27
+ }
28
+ exports.areEqualWithDeepComparison = areEqualWithDeepComparison;
29
+ function areEqualArraysWithDeepComparison(oldItems, newItems) {
30
+ if (newItems.length !== oldItems.length) {
31
+ return false;
32
+ }
33
+ for (let i = 0; i < newItems.length; i++) {
34
+ if (!areEqualWithDeepComparison(oldItems[i], newItems[i])) {
35
+ return false;
36
+ }
37
+ }
38
+ return true;
39
+ }
40
+ exports.areEqualArraysWithDeepComparison = areEqualArraysWithDeepComparison;
41
+ function areEqualObjectsWithDeepComparison(oldItemObject, newItemObject) {
42
+ const oldKeys = Object.keys(oldItemObject);
43
+ const newKeys = Object.keys(newItemObject);
44
+ if (oldKeys.length !== newKeys.length) {
45
+ return false;
46
+ }
47
+ for (const oldKey of oldKeys) {
48
+ if (!(oldKey in newItemObject)) {
49
+ return false;
50
+ }
51
+ // @ts-expect-error
52
+ const oldValue = oldItemObject[oldKey];
53
+ // @ts-expect-error
54
+ const newValue = newItemObject[oldKey];
55
+ if (!areEqualWithDeepComparison(oldValue, newValue)) {
56
+ return false;
57
+ }
58
+ }
59
+ return true;
60
+ }
61
+ exports.areEqualObjectsWithDeepComparison = areEqualObjectsWithDeepComparison;
package/dist/cache.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { ItemCleanupPair, ParentCache } from '@isograph/react-disposable-state';
2
2
  import { PromiseWrapper } from './PromiseWrapper';
3
- import { DataId, type IsographEnvironment } from './IsographEnvironment';
3
+ import { type IsographEnvironment } from './IsographEnvironment';
4
4
  import { IsographEntrypoint, NormalizationLinkedField, NormalizationScalarField } from './entrypoint';
5
5
  import { ReaderLinkedField, ReaderScalarField } from './reader';
6
+ import { WithEncounteredRecords } from './read';
7
+ import { FragmentReference } from './FragmentReference';
6
8
  declare global {
7
9
  interface Window {
8
10
  __LOG: boolean;
@@ -17,7 +19,8 @@ export declare function stableCopy<T>(value: T): T;
17
19
  type IsoResolver = IsographEntrypoint<any, any>;
18
20
  export declare function getOrCreateCacheForArtifact<TReadFromStore extends Object, TClientFieldValue>(environment: IsographEnvironment, artifact: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: object): ParentCache<PromiseWrapper<TClientFieldValue>>;
19
21
  export declare function makeNetworkRequest<T>(environment: IsographEnvironment, artifact: IsoResolver, variables: object): ItemCleanupPair<PromiseWrapper<T>>;
20
- export declare function subscribe(environment: IsographEnvironment, encounteredRecords: Set<DataId> | null, callback: () => void): () => void;
22
+ export declare function subscribeToAnyChange(environment: IsographEnvironment, callback: () => void): () => void;
23
+ export declare function subscribe<TReadFromStore extends Object>(environment: IsographEnvironment, encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>, fragmentReference: FragmentReference<TReadFromStore, any>, callback: (newEncounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>) => void): () => void;
21
24
  export declare function onNextChange(environment: IsographEnvironment): Promise<void>;
22
25
  export declare function getParentRecordKey(astNode: NormalizationLinkedField | NormalizationScalarField | ReaderLinkedField | ReaderScalarField, variables: {
23
26
  [index: string]: string;
package/dist/cache.js CHANGED
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SECOND_SPLIT_KEY = exports.FIRST_SPLIT_KEY = exports.getParentRecordKey = exports.onNextChange = exports.subscribe = exports.makeNetworkRequest = exports.getOrCreateCacheForArtifact = exports.stableCopy = void 0;
3
+ exports.SECOND_SPLIT_KEY = exports.FIRST_SPLIT_KEY = exports.getParentRecordKey = exports.onNextChange = exports.subscribe = exports.subscribeToAnyChange = exports.makeNetworkRequest = exports.getOrCreateCacheForArtifact = exports.stableCopy = void 0;
4
4
  const react_disposable_state_1 = require("@isograph/react-disposable-state");
5
5
  const PromiseWrapper_1 = require("./PromiseWrapper");
6
6
  const IsographEnvironment_1 = require("./IsographEnvironment");
7
7
  const garbageCollection_1 = require("./garbageCollection");
8
+ const read_1 = require("./read");
9
+ const areEqualWithDeepComparison_1 = require("./areEqualWithDeepComparison");
8
10
  function getOrCreateCache(environment, index, factory) {
9
11
  if (typeof window !== 'undefined' && window.__LOG) {
10
12
  console.log('getting cache for', {
@@ -108,18 +110,31 @@ function normalizeData(environment, normalizationAst, networkResponse, variables
108
110
  callSubscriptions(environment, encounteredIds);
109
111
  return encounteredIds;
110
112
  }
111
- function subscribe(environment, encounteredRecords, callback) {
112
- const callbackAndRecords = {
113
+ function subscribeToAnyChange(environment, callback) {
114
+ const subscription = {
115
+ kind: 'AnyRecords',
113
116
  callback,
114
- records: encounteredRecords,
115
117
  };
116
- environment.subscriptions.add(callbackAndRecords);
117
- return () => environment.subscriptions.delete(callbackAndRecords);
118
+ environment.subscriptions.add(subscription);
119
+ return () => environment.subscriptions.delete(subscription);
120
+ }
121
+ exports.subscribeToAnyChange = subscribeToAnyChange;
122
+ function subscribe(environment, encounteredDataAndRecords, fragmentReference, callback) {
123
+ const fragmentSubscription = {
124
+ kind: 'FragmentSubscription',
125
+ callback,
126
+ encounteredDataAndRecords,
127
+ fragmentReference,
128
+ };
129
+ // @ts-expect-error
130
+ environment.subscriptions.add(fragmentSubscription);
131
+ // @ts-expect-error
132
+ return () => environment.subscriptions.delete(fragmentSubscription);
118
133
  }
119
134
  exports.subscribe = subscribe;
120
135
  function onNextChange(environment) {
121
136
  return new Promise((resolve) => {
122
- const unsubscribe = subscribe(environment, null, () => {
137
+ const unsubscribe = subscribeToAnyChange(environment, () => {
123
138
  unsubscribe();
124
139
  resolve();
125
140
  });
@@ -127,12 +142,44 @@ function onNextChange(environment) {
127
142
  }
128
143
  exports.onNextChange = onNextChange;
129
144
  function callSubscriptions(environment, recordsEncounteredWhenNormalizing) {
130
- environment.subscriptions.forEach(({ callback, records }) => {
131
- if (records === null) {
132
- callback();
133
- }
134
- else if (hasOverlappingIds(recordsEncounteredWhenNormalizing, records)) {
135
- callback();
145
+ environment.subscriptions.forEach((subscription) => {
146
+ switch (subscription.kind) {
147
+ case 'FragmentSubscription': {
148
+ // TODO if there are multiple components subscribed to the same
149
+ // fragment, we will call readButNotEvaluate multiple times. We
150
+ // should fix that.
151
+ if (hasOverlappingIds(recordsEncounteredWhenNormalizing, subscription.encounteredDataAndRecords.encounteredRecords)) {
152
+ const newEncounteredDataAndRecords = (0, read_1.readButDoNotEvaluate)(environment, subscription.fragmentReference);
153
+ if (!(0, areEqualWithDeepComparison_1.areEqualObjectsWithDeepComparison)(subscription.encounteredDataAndRecords.item, newEncounteredDataAndRecords.item)) {
154
+ if (typeof window !== 'undefined' && window.__LOG) {
155
+ console.log('Deep equality - No', {
156
+ fragmentReference: subscription.fragmentReference,
157
+ old: subscription.encounteredDataAndRecords.item,
158
+ new: newEncounteredDataAndRecords.item,
159
+ });
160
+ }
161
+ // TODO deep compare values
162
+ subscription.callback(newEncounteredDataAndRecords);
163
+ }
164
+ else {
165
+ if (typeof window !== 'undefined' && window.__LOG) {
166
+ console.log('Deep equality - Yes', {
167
+ fragmentReference: subscription.fragmentReference,
168
+ old: subscription.encounteredDataAndRecords.item,
169
+ });
170
+ }
171
+ }
172
+ }
173
+ return;
174
+ }
175
+ case 'AnyRecords': {
176
+ return subscription.callback();
177
+ }
178
+ default: {
179
+ // @ts-expect-error(6133)
180
+ const _ = subscription;
181
+ throw new Error('Unexpected case');
182
+ }
136
183
  }
137
184
  });
138
185
  }
@@ -1,7 +1,4 @@
1
1
  /// <reference types="react" />
2
- import { RefetchQueryArtifactWrapper } from './entrypoint';
3
- import { IsographEnvironment, DataId } from './IsographEnvironment';
4
- import { ReaderArtifact } from './reader';
5
- export declare function getOrCreateCachedComponent(environment: IsographEnvironment, rootId: DataId, componentName: string, readerArtifact: ReaderArtifact<any, any>, variables: {
6
- [key: string]: string;
7
- }, resolverRefetchQueries: RefetchQueryArtifactWrapper[]): React.FC<any>;
2
+ import { IsographEnvironment } from './IsographEnvironment';
3
+ import { FragmentReference } from './FragmentReference';
4
+ export declare function getOrCreateCachedComponent(environment: IsographEnvironment, componentName: string, fragmentReference: FragmentReference<any, any>): React.FC<any>;
@@ -2,38 +2,34 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getOrCreateCachedComponent = void 0;
4
4
  const cache_1 = require("./cache");
5
- const read_1 = require("./read");
6
- const useRerenderWhenEncounteredRecordChanges_1 = require("./useRerenderWhenEncounteredRecordChanges");
7
- function getOrCreateCachedComponent(environment, rootId, componentName, readerArtifact, variables, resolverRefetchQueries) {
5
+ const useReadAndSubscribe_1 = require("./useReadAndSubscribe");
6
+ function getOrCreateCachedComponent(environment, componentName, fragmentReference) {
8
7
  var _a, _b, _c;
9
- const cachedComponentsById = environment.componentAndEncounteredRecordsCache;
10
- const stringifiedArgs = JSON.stringify((0, cache_1.stableCopy)(variables));
11
- cachedComponentsById[rootId] = (_a = cachedComponentsById[rootId]) !== null && _a !== void 0 ? _a : {};
12
- const componentsByName = cachedComponentsById[rootId];
8
+ // cachedComponentsById is a three layer cache: id, then component name, then
9
+ // stringified args. These three, together, uniquely identify a read at a given
10
+ // time.
11
+ const cachedComponentsById = environment.componentCache;
12
+ cachedComponentsById[fragmentReference.root] =
13
+ (_a = cachedComponentsById[fragmentReference.root]) !== null && _a !== void 0 ? _a : {};
14
+ const componentsByName = cachedComponentsById[fragmentReference.root];
13
15
  componentsByName[componentName] = (_b = componentsByName[componentName]) !== null && _b !== void 0 ? _b : {};
14
16
  const byArgs = componentsByName[componentName];
17
+ const stringifiedArgs = JSON.stringify((0, cache_1.stableCopy)(fragmentReference.variables));
15
18
  byArgs[stringifiedArgs] =
16
19
  (_c = byArgs[stringifiedArgs]) !== null && _c !== void 0 ? _c : (() => {
17
20
  function Component(additionalRuntimeProps) {
18
- const { item: data, encounteredRecords } = (0, read_1.readButDoNotEvaluate)(environment, {
19
- kind: 'FragmentReference',
20
- readerArtifact: readerArtifact,
21
- root: rootId,
22
- variables,
23
- nestedRefetchQueries: resolverRefetchQueries,
24
- }, byArgs[stringifiedArgs]);
25
- (0, useRerenderWhenEncounteredRecordChanges_1.useRerenderWhenEncounteredRecordChanges)(environment, encounteredRecords);
21
+ const data = (0, useReadAndSubscribe_1.useReadAndSubscribe)(environment, fragmentReference);
26
22
  if (typeof window !== 'undefined' && window.__LOG) {
27
- console.log('Component re-rendered: ' + componentName + ' ' + rootId);
23
+ console.log('Component re-rendered: ' +
24
+ componentName +
25
+ ' ' +
26
+ fragmentReference.root);
28
27
  }
29
- return readerArtifact.resolver(data, additionalRuntimeProps);
28
+ return fragmentReference.readerArtifact.resolver(data, additionalRuntimeProps);
30
29
  }
31
- Component.displayName = `${componentName} (id: ${rootId}) @component`;
32
- return {
33
- component: Component,
34
- encounteredRecordsDuringLastRead: null,
35
- };
30
+ Component.displayName = `${componentName} (id: ${fragmentReference.root}) @component`;
31
+ return Component;
36
32
  })();
37
- return byArgs[stringifiedArgs].component;
33
+ return byArgs[stringifiedArgs];
38
34
  }
39
35
  exports.getOrCreateCachedComponent = getOrCreateCachedComponent;
package/dist/index.d.ts CHANGED
@@ -7,9 +7,9 @@ export { useImperativeReference } from './useImperativeReference';
7
7
  export { EntrypointReader } from './EntrypointReader';
8
8
  export { type ReaderArtifact, ReaderAst, ReaderAstNode, ReaderLinkedField, ReaderMutationField, ReaderRefetchField, ReaderResolverField, ReaderResolverVariant, ReaderScalarField, } from './reader';
9
9
  export { NormalizationAst, NormalizationAstNode, NormalizationLinkedField, NormalizationScalarField, IsographEntrypoint, assertIsEntrypoint, RefetchQueryArtifact, RefetchQueryArtifactWrapper, } from './entrypoint';
10
- export { read, readButDoNotEvaluate } from './read';
10
+ export { readButDoNotEvaluate } from './read';
11
11
  export { useResult } from './useResult';
12
12
  export { type FragmentReference } from './FragmentReference';
13
13
  export { useLazyReference } from './useLazyReference';
14
14
  export { ExtractSecondParam, Argument, ArgumentName, ArgumentValue, Arguments, } from './util';
15
- export { useRerenderWhenEncounteredRecordChanges } from './useRerenderWhenEncounteredRecordChanges';
15
+ export { useRerenderOnChange } from './useRerenderOnChange';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useRerenderWhenEncounteredRecordChanges = exports.useLazyReference = exports.useResult = exports.readButDoNotEvaluate = exports.read = exports.assertIsEntrypoint = exports.EntrypointReader = exports.useImperativeReference = exports.useIsographEnvironment = exports.IsographEnvironmentProvider = exports.defaultMissingFieldHandler = exports.createIsographStore = exports.createIsographEnvironment = exports.ROOT_ID = exports.subscribe = exports.makeNetworkRequest = exports.garbageCollectEnvironment = exports.unretainQuery = exports.retainQuery = void 0;
3
+ exports.useRerenderOnChange = exports.useLazyReference = exports.useResult = exports.readButDoNotEvaluate = exports.assertIsEntrypoint = exports.EntrypointReader = exports.useImperativeReference = exports.useIsographEnvironment = exports.IsographEnvironmentProvider = exports.defaultMissingFieldHandler = exports.createIsographStore = exports.createIsographEnvironment = exports.ROOT_ID = exports.subscribe = exports.makeNetworkRequest = exports.garbageCollectEnvironment = exports.unretainQuery = exports.retainQuery = void 0;
4
4
  var garbageCollection_1 = require("./garbageCollection");
5
5
  Object.defineProperty(exports, "retainQuery", { enumerable: true, get: function () { return garbageCollection_1.retainQuery; } });
6
6
  Object.defineProperty(exports, "unretainQuery", { enumerable: true, get: function () { return garbageCollection_1.unretainQuery; } });
@@ -23,11 +23,10 @@ Object.defineProperty(exports, "EntrypointReader", { enumerable: true, get: func
23
23
  var entrypoint_1 = require("./entrypoint");
24
24
  Object.defineProperty(exports, "assertIsEntrypoint", { enumerable: true, get: function () { return entrypoint_1.assertIsEntrypoint; } });
25
25
  var read_1 = require("./read");
26
- Object.defineProperty(exports, "read", { enumerable: true, get: function () { return read_1.read; } });
27
26
  Object.defineProperty(exports, "readButDoNotEvaluate", { enumerable: true, get: function () { return read_1.readButDoNotEvaluate; } });
28
27
  var useResult_1 = require("./useResult");
29
28
  Object.defineProperty(exports, "useResult", { enumerable: true, get: function () { return useResult_1.useResult; } });
30
29
  var useLazyReference_1 = require("./useLazyReference");
31
30
  Object.defineProperty(exports, "useLazyReference", { enumerable: true, get: function () { return useLazyReference_1.useLazyReference; } });
32
- var useRerenderWhenEncounteredRecordChanges_1 = require("./useRerenderWhenEncounteredRecordChanges");
33
- Object.defineProperty(exports, "useRerenderWhenEncounteredRecordChanges", { enumerable: true, get: function () { return useRerenderWhenEncounteredRecordChanges_1.useRerenderWhenEncounteredRecordChanges; } });
31
+ var useRerenderOnChange_1 = require("./useRerenderOnChange");
32
+ Object.defineProperty(exports, "useRerenderOnChange", { enumerable: true, get: function () { return useRerenderOnChange_1.useRerenderOnChange; } });
package/dist/read.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { FragmentReference } from './FragmentReference';
2
- import { ComponentAndEncounteredRecords, DataId, IsographEnvironment } from './IsographEnvironment';
2
+ import { DataId, IsographEnvironment } from './IsographEnvironment';
3
3
  export type WithEncounteredRecords<T> = {
4
4
  encounteredRecords: Set<DataId>;
5
5
  item: T;
6
6
  };
7
- export declare function read<TReadFromStore extends Object, TClientFieldValue>(environment: IsographEnvironment, fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>): WithEncounteredRecords<TClientFieldValue>;
8
- export declare function readButDoNotEvaluate<TReadFromStore extends Object>(environment: IsographEnvironment, reference: FragmentReference<TReadFromStore, unknown>, encounteredRecordCache: ComponentAndEncounteredRecords): WithEncounteredRecords<TReadFromStore>;
7
+ export declare function readButDoNotEvaluate<TReadFromStore extends Object>(environment: IsographEnvironment, reference: FragmentReference<TReadFromStore, unknown>): WithEncounteredRecords<TReadFromStore>;
package/dist/read.js CHANGED
@@ -1,38 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.readButDoNotEvaluate = exports.read = void 0;
3
+ exports.readButDoNotEvaluate = void 0;
4
4
  const cache_1 = require("./cache");
5
5
  const componentCache_1 = require("./componentCache");
6
6
  const IsographEnvironment_1 = require("./IsographEnvironment");
7
- function read(environment, fragmentReference) {
8
- var _a, _b;
9
- const variant = fragmentReference.readerArtifact.variant;
10
- if (variant.kind === 'Eager') {
11
- const mutableEncounteredRecords = new Set();
12
- const data = readData(environment, fragmentReference.readerArtifact.readerAst, fragmentReference.root, (_a = fragmentReference.variables) !== null && _a !== void 0 ? _a : {}, fragmentReference.nestedRefetchQueries, mutableEncounteredRecords);
13
- if (data.kind === 'MissingData') {
14
- throw (0, cache_1.onNextChange)(environment);
15
- }
16
- else {
17
- return {
18
- encounteredRecords: mutableEncounteredRecords,
19
- // @ts-expect-error This not properly typed yet
20
- item: fragmentReference.readerArtifact.resolver(data.data),
21
- };
22
- }
23
- }
24
- else if (variant.kind === 'Component') {
25
- return {
26
- // @ts-ignore
27
- item: (0, componentCache_1.getOrCreateCachedComponent)(environment, fragmentReference.root, variant.componentName, fragmentReference.readerArtifact, (_b = fragmentReference.variables) !== null && _b !== void 0 ? _b : {}, fragmentReference.nestedRefetchQueries),
28
- encounteredRecords: new Set(),
29
- };
30
- }
31
- // Why can't Typescript realize that this is unreachable??
32
- throw new Error('This is unreachable');
33
- }
34
- exports.read = read;
35
- function readButDoNotEvaluate(environment, reference, encounteredRecordCache) {
7
+ function readButDoNotEvaluate(environment, reference) {
36
8
  var _a;
37
9
  const mutableEncounteredRecords = new Set();
38
10
  const response = readData(environment, reference.readerArtifact.readerAst, reference.root, (_a = reference.variables) !== null && _a !== void 0 ? _a : {}, reference.nestedRefetchQueries, mutableEncounteredRecords);
@@ -43,33 +15,13 @@ function readButDoNotEvaluate(environment, reference, encounteredRecordCache) {
43
15
  throw (0, cache_1.onNextChange)(environment);
44
16
  }
45
17
  else {
46
- const encounteredRecords = compareAndUpdateEncounteredRecords(encounteredRecordCache, mutableEncounteredRecords);
47
18
  return {
48
- encounteredRecords,
19
+ encounteredRecords: mutableEncounteredRecords,
49
20
  item: response.data,
50
21
  };
51
22
  }
52
23
  }
53
24
  exports.readButDoNotEvaluate = readButDoNotEvaluate;
54
- function compareAndUpdateEncounteredRecords(encounteredRecordCache, newEncounteredRecords) {
55
- const { encounteredRecordsDuringLastRead } = encounteredRecordCache;
56
- if (encounteredRecordsDuringLastRead == null ||
57
- encounteredRecordsDuringLastRead.size != newEncounteredRecords.size) {
58
- encounteredRecordCache.encounteredRecordsDuringLastRead =
59
- newEncounteredRecords;
60
- return newEncounteredRecords;
61
- }
62
- else {
63
- for (const item of newEncounteredRecords) {
64
- if (!encounteredRecordsDuringLastRead.has(item)) {
65
- encounteredRecordCache.encounteredRecordsDuringLastRead =
66
- newEncounteredRecords;
67
- return newEncounteredRecords;
68
- }
69
- }
70
- return encounteredRecordsDuringLastRead;
71
- }
72
- }
73
25
  function readData(environment, ast, root, variables, nestedRefetchQueries, mutableEncounteredRecords) {
74
26
  var _a, _b, _c, _d, _e;
75
27
  mutableEncounteredRecords.add(root);
@@ -184,9 +136,6 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, mutab
184
136
  const data = readData(environment, field.readerArtifact.readerAst, root, variables,
185
137
  // Refetch fields just read the id, and don't need refetch query artifacts
186
138
  [], mutableEncounteredRecords);
187
- if (typeof window !== 'undefined' && window.__LOG) {
188
- console.log('refetch field data', data, field);
189
- }
190
139
  if (data.kind === 'MissingData') {
191
140
  return {
192
141
  kind: 'MissingData',
@@ -212,9 +161,6 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, mutab
212
161
  const data = readData(environment, field.readerArtifact.readerAst, root, variables,
213
162
  // Mutation don't need refetch query artifacts
214
163
  [], mutableEncounteredRecords);
215
- if (typeof window !== 'undefined' && window.__LOG) {
216
- console.log('refetch field data', data, field);
217
- }
218
164
  if (data.kind === 'MissingData') {
219
165
  return {
220
166
  kind: 'MissingData',
@@ -255,7 +201,13 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, mutab
255
201
  }
256
202
  }
257
203
  else if (variant.kind === 'Component') {
258
- target[field.alias] = (0, componentCache_1.getOrCreateCachedComponent)(environment, root, variant.componentName, field.readerArtifact, variables, resolverRefetchQueries);
204
+ target[field.alias] = (0, componentCache_1.getOrCreateCachedComponent)(environment, variant.componentName, {
205
+ kind: 'FragmentReference',
206
+ readerArtifact: field.readerArtifact,
207
+ root,
208
+ variables,
209
+ nestedRefetchQueries: resolverRefetchQueries,
210
+ });
259
211
  }
260
212
  break;
261
213
  }
@@ -0,0 +1,7 @@
1
+ import { FragmentReference } from './FragmentReference';
2
+ import { IsographEnvironment } from './IsographEnvironment';
3
+ /**
4
+ * Read the data from a fragment reference and subscribe to updates.
5
+ * Does not pass the data to the fragment reference's resolver function.
6
+ */
7
+ export declare function useReadAndSubscribe<TReadFromStore extends Object>(environment: IsographEnvironment, fragmentReference: FragmentReference<TReadFromStore, any>): TReadFromStore;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useReadAndSubscribe = void 0;
4
+ const react_1 = require("react");
5
+ const read_1 = require("./read");
6
+ const useRerenderOnChange_1 = require("./useRerenderOnChange");
7
+ /**
8
+ * Read the data from a fragment reference and subscribe to updates.
9
+ * Does not pass the data to the fragment reference's resolver function.
10
+ */
11
+ function useReadAndSubscribe(environment, fragmentReference) {
12
+ const [readOutDataAndRecords, setReadOutDataAndRecords] = (0, react_1.useState)(() => (0, read_1.readButDoNotEvaluate)(environment, fragmentReference));
13
+ (0, useRerenderOnChange_1.useRerenderOnChange)(environment, readOutDataAndRecords, fragmentReference, setReadOutDataAndRecords);
14
+ return readOutDataAndRecords.item;
15
+ }
16
+ exports.useReadAndSubscribe = useReadAndSubscribe;
@@ -0,0 +1,4 @@
1
+ import { IsographEnvironment } from './IsographEnvironment';
2
+ import { WithEncounteredRecords } from './read';
3
+ import { FragmentReference } from './FragmentReference';
4
+ export declare function useRerenderOnChange<TReadFromStore extends Object>(environment: IsographEnvironment, encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>, fragmentReference: FragmentReference<any, any>, setEncounteredDataAndRecords: (data: WithEncounteredRecords<TReadFromStore>) => void): void;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useRerenderOnChange = void 0;
4
+ const react_1 = require("react");
5
+ const cache_1 = require("./cache");
6
+ // TODO add unit tests for this. Add integration tests that test
7
+ // behavior when the encounteredRecords underneath a fragment change.
8
+ function useRerenderOnChange(environment, encounteredDataAndRecords, fragmentReference, setEncounteredDataAndRecords) {
9
+ (0, react_1.useEffect)(() => {
10
+ return (0, cache_1.subscribe)(environment, encounteredDataAndRecords, fragmentReference, (newEncounteredDataAndRecords) => {
11
+ setEncounteredDataAndRecords(newEncounteredDataAndRecords);
12
+ });
13
+ // Note: this is an empty array on purpose:
14
+ // - the fragment reference is stable for the life of the component
15
+ // - ownership of encounteredDataAndRecords is transferred into the
16
+ // environment
17
+ // - though maybe we need to include setEncounteredDataAndRecords in
18
+ // the dependency array
19
+ }, []);
20
+ }
21
+ exports.useRerenderOnChange = useRerenderOnChange;
package/dist/useResult.js CHANGED
@@ -2,12 +2,20 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useResult = void 0;
4
4
  const IsographEnvironmentProvider_1 = require("./IsographEnvironmentProvider");
5
- const read_1 = require("./read");
6
- const useRerenderWhenEncounteredRecordChanges_1 = require("./useRerenderWhenEncounteredRecordChanges");
5
+ const componentCache_1 = require("./componentCache");
6
+ const useReadAndSubscribe_1 = require("./useReadAndSubscribe");
7
7
  function useResult(fragmentReference) {
8
8
  const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
9
- const { item: data, encounteredRecords } = (0, read_1.read)(environment, fragmentReference);
10
- (0, useRerenderWhenEncounteredRecordChanges_1.useRerenderWhenEncounteredRecordChanges)(environment, encounteredRecords);
11
- return data;
9
+ switch (fragmentReference.readerArtifact.variant.kind) {
10
+ case 'Component': {
11
+ // @ts-expect-error
12
+ return (0, componentCache_1.getOrCreateCachedComponent)(environment, fragmentReference.readerArtifact.variant.componentName, fragmentReference);
13
+ }
14
+ case 'Eager': {
15
+ const data = (0, useReadAndSubscribe_1.useReadAndSubscribe)(environment, fragmentReference);
16
+ // @ts-expect-error resolver is incorrectly typed in ReaderArtifact
17
+ return fragmentReference.readerArtifact.resolver(data);
18
+ }
19
+ }
12
20
  }
13
21
  exports.useResult = useResult;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isograph/react",
3
- "version": "0.0.0-main-d319cfe5",
3
+ "version": "0.0.0-main-b72868e3",
4
4
  "description": "Use Isograph with React",
5
5
  "homepage": "https://isograph.dev",
6
6
  "main": "dist/index.js",
@@ -16,8 +16,8 @@
16
16
  "prepack": "yarn run test && yarn run compile"
17
17
  },
18
18
  "dependencies": {
19
- "@isograph/disposable-types": "0.0.0-main-d319cfe5",
20
- "@isograph/react-disposable-state": "0.0.0-main-d319cfe5",
19
+ "@isograph/disposable-types": "0.0.0-main-b72868e3",
20
+ "@isograph/react-disposable-state": "0.0.0-main-b72868e3",
21
21
  "react": "^18.2.0"
22
22
  },
23
23
  "devDependencies": {
@@ -5,6 +5,8 @@ import { ReaderArtifact } from './reader';
5
5
  // TODO type this better
6
6
  export type Variable = any;
7
7
 
8
+ export type Variables = { readonly [index: string]: Variable };
9
+
8
10
  export type FragmentReference<
9
11
  TReadFromStore extends Object,
10
12
  TClientFieldValue,
@@ -12,7 +14,7 @@ export type FragmentReference<
12
14
  kind: 'FragmentReference';
13
15
  readerArtifact: ReaderArtifact<TReadFromStore, TClientFieldValue>;
14
16
  root: DataId;
15
- variables: { [index: string]: Variable } | null;
17
+ variables: Variables | null;
16
18
  // TODO: We should instead have ReaderAst<TClientFieldProps>
17
19
  nestedRefetchQueries: RefetchQueryArtifactWrapper[];
18
20
  };