@isograph/react 0.0.0-main-f524690b → 0.0.0-main-f49c67bb
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/cache.d.ts +3 -19
- package/dist/cache.js +21 -41
- package/dist/componentCache.d.ts +3 -3
- package/dist/componentCache.js +2 -2
- package/dist/context.d.ts +34 -0
- package/dist/context.js +48 -0
- package/dist/index.d.ts +7 -6
- package/dist/index.js +35 -37
- package/package.json +3 -3
- package/src/{cache.ts → cache.tsx} +29 -63
- package/src/componentCache.ts +5 -2
- package/src/context.tsx +90 -0
- package/src/index.tsx +62 -51
package/dist/cache.d.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import { ItemCleanupPair, ParentCache } from '@isograph/react-disposable-state';
|
2
2
|
import { PromiseWrapper } from './PromiseWrapper';
|
3
3
|
import { IsographEntrypoint, NormalizationLinkedField, NormalizationScalarField, ReaderLinkedField, ReaderScalarField } from './index';
|
4
|
+
import { type IsographEnvironment } from './context';
|
4
5
|
declare global {
|
5
6
|
interface Window {
|
6
7
|
__LOG: boolean;
|
@@ -13,25 +14,8 @@ declare global {
|
|
13
14
|
*/
|
14
15
|
export declare function stableCopy<T>(value: T): T;
|
15
16
|
type IsoResolver = IsographEntrypoint<any, any, any>;
|
16
|
-
export declare function getOrCreateCacheForArtifact<T>(artifact: IsographEntrypoint<any, any, T>, variables: object): ParentCache<PromiseWrapper<T>>;
|
17
|
-
declare
|
18
|
-
export declare function setNetwork(newNetwork: typeof network): void;
|
19
|
-
export declare function makeNetworkRequest<T>(artifact: IsoResolver, variables: object): ItemCleanupPair<PromiseWrapper<T>>;
|
20
|
-
export type Link = {
|
21
|
-
__link: DataId;
|
22
|
-
};
|
23
|
-
export type DataTypeValue = undefined | number | boolean | string | null | Link | DataTypeValue[];
|
24
|
-
export type StoreRecord = {
|
25
|
-
[index: DataId | string]: DataTypeValue;
|
26
|
-
id?: DataId;
|
27
|
-
};
|
28
|
-
export type DataId = string;
|
29
|
-
export declare const ROOT_ID: DataId & '__ROOT';
|
30
|
-
export declare function getStore(): {
|
31
|
-
[index: string]: StoreRecord | null;
|
32
|
-
__ROOT: StoreRecord;
|
33
|
-
};
|
34
|
-
export declare function clearStore(): void;
|
17
|
+
export declare function getOrCreateCacheForArtifact<T>(environment: IsographEnvironment, artifact: IsographEntrypoint<any, any, T>, variables: object): ParentCache<PromiseWrapper<T>>;
|
18
|
+
export declare function makeNetworkRequest<T>(environment: IsographEnvironment, artifact: IsoResolver, variables: object): ItemCleanupPair<PromiseWrapper<T>>;
|
35
19
|
export declare function subscribe(callback: () => void): () => void;
|
36
20
|
export declare function onNextChange(): Promise<void>;
|
37
21
|
export declare function getParentRecordKey(astNode: NormalizationLinkedField | NormalizationScalarField | ReaderLinkedField | ReaderScalarField, variables: {
|
package/dist/cache.js
CHANGED
@@ -1,8 +1,9 @@
|
|
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.
|
3
|
+
exports.SECOND_SPLIT_KEY = exports.FIRST_SPLIT_KEY = exports.getParentRecordKey = exports.onNextChange = exports.subscribe = 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
|
+
const context_1 = require("./context");
|
6
7
|
const cache = {};
|
7
8
|
function getOrCreateCache(index, factory) {
|
8
9
|
if (typeof window !== 'undefined' && window.__LOG) {
|
@@ -39,30 +40,23 @@ function stableCopy(value) {
|
|
39
40
|
return stable;
|
40
41
|
}
|
41
42
|
exports.stableCopy = stableCopy;
|
42
|
-
function getOrCreateCacheForArtifact(artifact, variables) {
|
43
|
+
function getOrCreateCacheForArtifact(environment, artifact, variables) {
|
43
44
|
const cacheKey = artifact.queryText + JSON.stringify(stableCopy(variables));
|
44
|
-
const factory = () => makeNetworkRequest(artifact, variables);
|
45
|
+
const factory = () => makeNetworkRequest(environment, artifact, variables);
|
45
46
|
return getOrCreateCache(cacheKey, factory);
|
46
47
|
}
|
47
48
|
exports.getOrCreateCacheForArtifact = getOrCreateCacheForArtifact;
|
48
|
-
|
49
|
-
// This is a hack until we store this in context somehow
|
50
|
-
function setNetwork(newNetwork) {
|
51
|
-
network = newNetwork;
|
52
|
-
}
|
53
|
-
exports.setNetwork = setNetwork;
|
54
|
-
function makeNetworkRequest(artifact, variables) {
|
49
|
+
function makeNetworkRequest(environment, artifact, variables) {
|
55
50
|
if (typeof window !== 'undefined' && window.__LOG) {
|
56
51
|
console.log('make network request', artifact, variables);
|
57
52
|
}
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
const promise = network(artifact.queryText, variables).then((networkResponse) => {
|
53
|
+
const promise = environment
|
54
|
+
.networkFunction(artifact.queryText, variables)
|
55
|
+
.then((networkResponse) => {
|
62
56
|
if (typeof window !== 'undefined' && window.__LOG) {
|
63
57
|
console.log('network response', artifact);
|
64
58
|
}
|
65
|
-
normalizeData(artifact.normalizationAst, networkResponse.data, variables, artifact.nestedRefetchQueries);
|
59
|
+
normalizeData(environment, artifact.normalizationAst, networkResponse.data, variables, artifact.nestedRefetchQueries);
|
66
60
|
return networkResponse.data;
|
67
61
|
});
|
68
62
|
const wrapper = (0, PromiseWrapper_1.wrapPromise)(promise);
|
@@ -75,27 +69,13 @@ function makeNetworkRequest(artifact, variables) {
|
|
75
69
|
return response;
|
76
70
|
}
|
77
71
|
exports.makeNetworkRequest = makeNetworkRequest;
|
78
|
-
|
79
|
-
let store = {
|
80
|
-
__ROOT: {},
|
81
|
-
};
|
82
|
-
function getStore() {
|
83
|
-
return store;
|
84
|
-
}
|
85
|
-
exports.getStore = getStore;
|
86
|
-
function clearStore() {
|
87
|
-
store = {
|
88
|
-
__ROOT: {},
|
89
|
-
};
|
90
|
-
}
|
91
|
-
exports.clearStore = clearStore;
|
92
|
-
function normalizeData(normalizationAst, networkResponse, variables, nestedRefetchQueries) {
|
72
|
+
function normalizeData(environment, normalizationAst, networkResponse, variables, nestedRefetchQueries) {
|
93
73
|
if (typeof window !== 'undefined' && window.__LOG) {
|
94
74
|
console.log('about to normalize', normalizationAst, networkResponse, variables);
|
95
75
|
}
|
96
|
-
normalizeDataIntoRecord(normalizationAst, networkResponse, store.__ROOT,
|
76
|
+
normalizeDataIntoRecord(environment, normalizationAst, networkResponse, environment.store.__ROOT, context_1.ROOT_ID, variables, nestedRefetchQueries);
|
97
77
|
if (typeof window !== 'undefined' && window.__LOG) {
|
98
|
-
console.log('after normalization', { store });
|
78
|
+
console.log('after normalization', { store: environment.store });
|
99
79
|
}
|
100
80
|
callSubscriptions();
|
101
81
|
}
|
@@ -120,7 +100,7 @@ function callSubscriptions() {
|
|
120
100
|
/**
|
121
101
|
* Mutate targetParentRecord according to the normalizationAst and networkResponseParentRecord.
|
122
102
|
*/
|
123
|
-
function normalizeDataIntoRecord(normalizationAst, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries) {
|
103
|
+
function normalizeDataIntoRecord(environment, normalizationAst, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries) {
|
124
104
|
for (const normalizationNode of normalizationAst) {
|
125
105
|
switch (normalizationNode.kind) {
|
126
106
|
case 'Scalar': {
|
@@ -128,7 +108,7 @@ function normalizeDataIntoRecord(normalizationAst, networkResponseParentRecord,
|
|
128
108
|
break;
|
129
109
|
}
|
130
110
|
case 'Linked': {
|
131
|
-
normalizeLinkedField(normalizationNode, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries);
|
111
|
+
normalizeLinkedField(environment, normalizationNode, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries);
|
132
112
|
break;
|
133
113
|
}
|
134
114
|
}
|
@@ -149,7 +129,7 @@ function normalizeScalarField(astNode, networkResponseParentRecord, targetStoreR
|
|
149
129
|
/**
|
150
130
|
* Mutate targetParentRecord with a given linked field ast node.
|
151
131
|
*/
|
152
|
-
function normalizeLinkedField(astNode, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries) {
|
132
|
+
function normalizeLinkedField(environment, astNode, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries) {
|
153
133
|
const networkResponseKey = getNetworkResponseKey(astNode);
|
154
134
|
const networkResponseData = networkResponseParentRecord[networkResponseKey];
|
155
135
|
const parentRecordKey = getParentRecordKey(astNode, variables);
|
@@ -165,24 +145,24 @@ function normalizeLinkedField(astNode, networkResponseParentRecord, targetParent
|
|
165
145
|
const dataIds = [];
|
166
146
|
for (let i = 0; i < networkResponseData.length; i++) {
|
167
147
|
const networkResponseObject = networkResponseData[i];
|
168
|
-
const newStoreRecordId = normalizeNetworkResponseObject(astNode, networkResponseObject, targetParentRecordId, variables, i, nestedRefetchQueries);
|
148
|
+
const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseObject, targetParentRecordId, variables, i, nestedRefetchQueries);
|
169
149
|
dataIds.push({ __link: newStoreRecordId });
|
170
150
|
}
|
171
151
|
targetParentRecord[parentRecordKey] = dataIds;
|
172
152
|
}
|
173
153
|
else {
|
174
|
-
const newStoreRecordId = normalizeNetworkResponseObject(astNode, networkResponseData, targetParentRecordId, variables, null, nestedRefetchQueries);
|
154
|
+
const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseData, targetParentRecordId, variables, null, nestedRefetchQueries);
|
175
155
|
targetParentRecord[parentRecordKey] = {
|
176
156
|
__link: newStoreRecordId,
|
177
157
|
};
|
178
158
|
}
|
179
159
|
}
|
180
|
-
function normalizeNetworkResponseObject(astNode, networkResponseData, targetParentRecordId, variables, index, nestedRefetchQueries) {
|
160
|
+
function normalizeNetworkResponseObject(environment, astNode, networkResponseData, targetParentRecordId, variables, index, nestedRefetchQueries) {
|
181
161
|
var _a;
|
182
162
|
const newStoreRecordId = getDataIdOfNetworkResponse(targetParentRecordId, networkResponseData, astNode, variables, index);
|
183
|
-
const newStoreRecord = (_a = store[newStoreRecordId]) !== null && _a !== void 0 ? _a : {};
|
184
|
-
store[newStoreRecordId] = newStoreRecord;
|
185
|
-
normalizeDataIntoRecord(astNode.selections, networkResponseData, newStoreRecord, newStoreRecordId, variables, nestedRefetchQueries);
|
163
|
+
const newStoreRecord = (_a = environment.store[newStoreRecordId]) !== null && _a !== void 0 ? _a : {};
|
164
|
+
environment.store[newStoreRecordId] = newStoreRecord;
|
165
|
+
normalizeDataIntoRecord(environment, astNode.selections, networkResponseData, newStoreRecord, newStoreRecordId, variables, nestedRefetchQueries);
|
186
166
|
return newStoreRecordId;
|
187
167
|
}
|
188
168
|
function isScalarOrEmptyArray(data) {
|
package/dist/componentCache.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/// <reference types="react" />
|
2
|
-
import { ReaderArtifact, RefetchQueryArtifactWrapper } from './index';
|
3
|
-
import {
|
4
|
-
export declare function getOrCreateCachedComponent(root: DataId, componentName: string, readerArtifact: ReaderArtifact<any, any, any>, variables: {
|
2
|
+
import { DataId, ReaderArtifact, RefetchQueryArtifactWrapper } from './index';
|
3
|
+
import { IsographEnvironment } from '../dist';
|
4
|
+
export declare function getOrCreateCachedComponent(environment: IsographEnvironment, root: DataId, componentName: string, readerArtifact: ReaderArtifact<any, any, any>, variables: {
|
5
5
|
[key: string]: string;
|
6
6
|
}, resolverRefetchQueries: RefetchQueryArtifactWrapper[]): import("react").FC<any>;
|
package/dist/componentCache.js
CHANGED
@@ -4,7 +4,7 @@ exports.getOrCreateCachedComponent = void 0;
|
|
4
4
|
const index_1 = require("./index");
|
5
5
|
const cache_1 = require("./cache");
|
6
6
|
const cachedComponentsById = {};
|
7
|
-
function getOrCreateCachedComponent(root, componentName, readerArtifact, variables, resolverRefetchQueries) {
|
7
|
+
function getOrCreateCachedComponent(environment, root, componentName, readerArtifact, variables, resolverRefetchQueries) {
|
8
8
|
var _a, _b, _c;
|
9
9
|
const stringifiedArgs = JSON.stringify((0, cache_1.stableCopy)(variables));
|
10
10
|
cachedComponentsById[root] = (_a = cachedComponentsById[root]) !== null && _a !== void 0 ? _a : {};
|
@@ -14,7 +14,7 @@ function getOrCreateCachedComponent(root, componentName, readerArtifact, variabl
|
|
14
14
|
byArgs[stringifiedArgs] =
|
15
15
|
(_c = byArgs[stringifiedArgs]) !== null && _c !== void 0 ? _c : (() => {
|
16
16
|
function Component(additionalRuntimeProps) {
|
17
|
-
const data = (0, index_1.readButDoNotEvaluate)({
|
17
|
+
const data = (0, index_1.readButDoNotEvaluate)(environment, {
|
18
18
|
kind: 'FragmentReference',
|
19
19
|
readerArtifact: readerArtifact,
|
20
20
|
root,
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import { ReactNode } from 'react';
|
2
|
+
import * as React from 'react';
|
3
|
+
export declare const IsographEnvironmentContext: React.Context<IsographEnvironment | null>;
|
4
|
+
export type IsographEnvironment = {
|
5
|
+
store: IsographStore;
|
6
|
+
networkFunction: IsographNetworkFunction;
|
7
|
+
missingFieldHandler: MissingFieldHandler | null;
|
8
|
+
};
|
9
|
+
export type MissingFieldHandler = (storeRecord: StoreRecord, root: DataId, fieldName: string, arguments_: {
|
10
|
+
[index: string]: any;
|
11
|
+
} | null, variables: {
|
12
|
+
[index: string]: any;
|
13
|
+
} | null) => Link | undefined;
|
14
|
+
export type IsographNetworkFunction = (queryText: string, variables: object) => Promise<any>;
|
15
|
+
export type Link = {
|
16
|
+
__link: DataId;
|
17
|
+
};
|
18
|
+
export type DataTypeValue = undefined | number | boolean | string | null | Link | DataTypeValue[];
|
19
|
+
export type StoreRecord = {
|
20
|
+
[index: DataId | string]: DataTypeValue;
|
21
|
+
id?: DataId;
|
22
|
+
};
|
23
|
+
export type DataId = string;
|
24
|
+
export declare const ROOT_ID: DataId & '__ROOT';
|
25
|
+
export type IsographStore = {
|
26
|
+
[index: DataId]: StoreRecord | null;
|
27
|
+
__ROOT: StoreRecord;
|
28
|
+
};
|
29
|
+
export type IsographEnvironmentProviderProps = {
|
30
|
+
environment: IsographEnvironment;
|
31
|
+
children: ReactNode;
|
32
|
+
};
|
33
|
+
export declare function IsographEnvironmentProvider({ environment, children, }: IsographEnvironmentProviderProps): React.JSX.Element;
|
34
|
+
export declare function useIsographEnvironment(): IsographEnvironment;
|
package/dist/context.js
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
+
exports.useIsographEnvironment = exports.IsographEnvironmentProvider = exports.ROOT_ID = exports.IsographEnvironmentContext = void 0;
|
27
|
+
const react_1 = require("react");
|
28
|
+
const React = __importStar(require("react"));
|
29
|
+
const cache_1 = require("./cache");
|
30
|
+
exports.IsographEnvironmentContext = (0, react_1.createContext)(null);
|
31
|
+
exports.ROOT_ID = '__ROOT';
|
32
|
+
function IsographEnvironmentProvider({ environment, children, }) {
|
33
|
+
const [, setState] = React.useState();
|
34
|
+
React.useEffect(() => {
|
35
|
+
return (0, cache_1.subscribe)(() => setState({}));
|
36
|
+
}, []);
|
37
|
+
return (React.createElement(exports.IsographEnvironmentContext.Provider, { value: environment }, children));
|
38
|
+
}
|
39
|
+
exports.IsographEnvironmentProvider = IsographEnvironmentProvider;
|
40
|
+
function useIsographEnvironment() {
|
41
|
+
const context = (0, react_1.useContext)(exports.IsographEnvironmentContext);
|
42
|
+
if (context == null) {
|
43
|
+
throw new Error('Unexpected null environment context. Make sure to render ' +
|
44
|
+
'this component within an IsographEnvironmentProvider component');
|
45
|
+
}
|
46
|
+
return context;
|
47
|
+
}
|
48
|
+
exports.useIsographEnvironment = useIsographEnvironment;
|
package/dist/index.d.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
import { DataId,
|
2
|
-
export {
|
1
|
+
import { DataId, IsographEnvironment, Link, StoreRecord } from './context';
|
2
|
+
export { makeNetworkRequest, subscribe } from './cache';
|
3
|
+
export { IsographEnvironmentContext, ROOT_ID, type DataId, type DataTypeValue, type IsographEnvironment, IsographEnvironmentProvider, type IsographEnvironmentProviderProps, type IsographNetworkFunction, type IsographStore, type Link, type StoreRecord, useIsographEnvironment, } from './context';
|
3
4
|
export { iso } from './iso';
|
4
5
|
export type IsographEntrypoint<TReadFromStore extends Object, TResolverProps, TResolverResult> = {
|
5
6
|
kind: 'Entrypoint';
|
@@ -102,14 +103,14 @@ type ExtractResolverResult<Type> = Type extends IsographEntrypoint<any, any, inf
|
|
102
103
|
export declare function useLazyReference<TEntrypoint>(entrypoint: TEntrypoint | ((_: any) => any), variables: object): {
|
103
104
|
queryReference: FragmentReference<ExtractTReadFromStore<TEntrypoint>, ExtractResolverProps<TEntrypoint>, ExtractResolverResult<TEntrypoint>>;
|
104
105
|
};
|
105
|
-
export declare function
|
106
|
-
export declare function
|
107
|
-
export declare function
|
106
|
+
export declare function useRead<TReadFromStore extends Object, TResolverProps, TResolverResult>(fragmentReference: FragmentReference<TReadFromStore, TResolverProps, TResolverResult>): TResolverResult;
|
107
|
+
export declare function read<TReadFromStore extends Object, TResolverProps, TResolverResult>(environment: IsographEnvironment, fragmentReference: FragmentReference<TReadFromStore, TResolverProps, TResolverResult>): TResolverResult;
|
108
|
+
export declare function readButDoNotEvaluate<TReadFromStore extends Object>(environment: IsographEnvironment, reference: FragmentReference<TReadFromStore, unknown, unknown>): TReadFromStore;
|
109
|
+
export declare function defaultMissingFieldHandler(_storeRecord: StoreRecord, _root: DataId, fieldName: string, arguments_: {
|
108
110
|
[index: string]: any;
|
109
111
|
} | null, variables: {
|
110
112
|
[index: string]: any;
|
111
113
|
} | null): Link | undefined;
|
112
|
-
export declare function setMissingFieldHandler(handler: typeof defaultMissingFieldHandler): void;
|
113
114
|
export type IsographComponentProps<TDataType, TOtherProps = Object> = {
|
114
115
|
data: TDataType;
|
115
116
|
} & TOtherProps;
|
package/dist/index.js
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.
|
3
|
+
exports.defaultMissingFieldHandler = exports.readButDoNotEvaluate = exports.read = exports.useRead = exports.useLazyReference = exports.iso = exports.useIsographEnvironment = exports.IsographEnvironmentProvider = exports.ROOT_ID = exports.IsographEnvironmentContext = exports.subscribe = exports.makeNetworkRequest = void 0;
|
4
4
|
const cache_1 = require("./cache");
|
5
5
|
const react_disposable_state_1 = require("@isograph/react-disposable-state");
|
6
6
|
const componentCache_1 = require("./componentCache");
|
7
|
+
const context_1 = require("./context");
|
7
8
|
var cache_2 = require("./cache");
|
8
|
-
Object.defineProperty(exports, "setNetwork", { enumerable: true, get: function () { return cache_2.setNetwork; } });
|
9
9
|
Object.defineProperty(exports, "makeNetworkRequest", { enumerable: true, get: function () { return cache_2.makeNetworkRequest; } });
|
10
10
|
Object.defineProperty(exports, "subscribe", { enumerable: true, get: function () { return cache_2.subscribe; } });
|
11
|
-
|
11
|
+
var context_2 = require("./context");
|
12
|
+
Object.defineProperty(exports, "IsographEnvironmentContext", { enumerable: true, get: function () { return context_2.IsographEnvironmentContext; } });
|
13
|
+
Object.defineProperty(exports, "ROOT_ID", { enumerable: true, get: function () { return context_2.ROOT_ID; } });
|
14
|
+
Object.defineProperty(exports, "IsographEnvironmentProvider", { enumerable: true, get: function () { return context_2.IsographEnvironmentProvider; } });
|
15
|
+
Object.defineProperty(exports, "useIsographEnvironment", { enumerable: true, get: function () { return context_2.useIsographEnvironment; } });
|
12
16
|
var iso_1 = require("./iso");
|
13
17
|
Object.defineProperty(exports, "iso", { enumerable: true, get: function () { return iso_1.iso; } });
|
14
18
|
function assertIsEntrypoint(value) {
|
@@ -20,9 +24,10 @@ function assertIsEntrypoint(value) {
|
|
20
24
|
// We cannot write TEntrypoint extends IsographEntrypoint<never, never, never>, or else
|
21
25
|
// any actual Entrypoint we pass will not be valid.
|
22
26
|
function useLazyReference(entrypoint, variables) {
|
27
|
+
const environment = (0, context_1.useIsographEnvironment)();
|
23
28
|
assertIsEntrypoint(entrypoint);
|
24
29
|
// Typechecking fails here... TODO investigate
|
25
|
-
const cache = (0, cache_1.getOrCreateCacheForArtifact)(entrypoint, variables);
|
30
|
+
const cache = (0, cache_1.getOrCreateCacheForArtifact)(environment, entrypoint, variables);
|
26
31
|
// TODO add comment explaining why we never use this value
|
27
32
|
// @ts-ignore
|
28
33
|
const data = (0, react_disposable_state_1.useLazyDisposableState)(cache).state;
|
@@ -30,18 +35,23 @@ function useLazyReference(entrypoint, variables) {
|
|
30
35
|
queryReference: {
|
31
36
|
kind: 'FragmentReference',
|
32
37
|
readerArtifact: entrypoint.readerArtifact,
|
33
|
-
root:
|
38
|
+
root: context_1.ROOT_ID,
|
34
39
|
variables,
|
35
40
|
nestedRefetchQueries: entrypoint.nestedRefetchQueries,
|
36
41
|
},
|
37
42
|
};
|
38
43
|
}
|
39
44
|
exports.useLazyReference = useLazyReference;
|
40
|
-
function
|
45
|
+
function useRead(fragmentReference) {
|
46
|
+
const environment = (0, context_1.useIsographEnvironment)();
|
47
|
+
return read(environment, fragmentReference);
|
48
|
+
}
|
49
|
+
exports.useRead = useRead;
|
50
|
+
function read(environment, fragmentReference) {
|
41
51
|
var _a, _b;
|
42
52
|
const variant = fragmentReference.readerArtifact.variant;
|
43
53
|
if (variant.kind === 'Eager') {
|
44
|
-
const data = readData(fragmentReference.readerArtifact.readerAst, fragmentReference.root, (_a = fragmentReference.variables) !== null && _a !== void 0 ? _a : {}, fragmentReference.nestedRefetchQueries);
|
54
|
+
const data = readData(environment, fragmentReference.readerArtifact.readerAst, fragmentReference.root, (_a = fragmentReference.variables) !== null && _a !== void 0 ? _a : {}, fragmentReference.nestedRefetchQueries);
|
45
55
|
if (data.kind === 'MissingData') {
|
46
56
|
throw (0, cache_1.onNextChange)();
|
47
57
|
}
|
@@ -51,15 +61,15 @@ function read(fragmentReference) {
|
|
51
61
|
}
|
52
62
|
else if (variant.kind === 'Component') {
|
53
63
|
// @ts-ignore
|
54
|
-
return (0, componentCache_1.getOrCreateCachedComponent)(fragmentReference.root, variant.componentName, fragmentReference.readerArtifact, (_b = fragmentReference.variables) !== null && _b !== void 0 ? _b : {}, fragmentReference.nestedRefetchQueries);
|
64
|
+
return (0, componentCache_1.getOrCreateCachedComponent)(environment, fragmentReference.root, variant.componentName, fragmentReference.readerArtifact, (_b = fragmentReference.variables) !== null && _b !== void 0 ? _b : {}, fragmentReference.nestedRefetchQueries);
|
55
65
|
}
|
56
66
|
// Why can't Typescript realize that this is unreachable??
|
57
67
|
throw new Error('This is unreachable');
|
58
68
|
}
|
59
69
|
exports.read = read;
|
60
|
-
function readButDoNotEvaluate(reference) {
|
70
|
+
function readButDoNotEvaluate(environment, reference) {
|
61
71
|
var _a;
|
62
|
-
const response = readData(reference.readerArtifact.readerAst, reference.root, (_a = reference.variables) !== null && _a !== void 0 ? _a : {}, reference.nestedRefetchQueries);
|
72
|
+
const response = readData(environment, reference.readerArtifact.readerAst, reference.root, (_a = reference.variables) !== null && _a !== void 0 ? _a : {}, reference.nestedRefetchQueries);
|
63
73
|
if (typeof window !== 'undefined' && window.__LOG) {
|
64
74
|
console.log('done reading', { response });
|
65
75
|
}
|
@@ -71,9 +81,9 @@ function readButDoNotEvaluate(reference) {
|
|
71
81
|
}
|
72
82
|
}
|
73
83
|
exports.readButDoNotEvaluate = readButDoNotEvaluate;
|
74
|
-
function readData(ast, root, variables, nestedRefetchQueries) {
|
75
|
-
var _a, _b, _c, _d;
|
76
|
-
let storeRecord =
|
84
|
+
function readData(environment, ast, root, variables, nestedRefetchQueries) {
|
85
|
+
var _a, _b, _c, _d, _e;
|
86
|
+
let storeRecord = environment.store[root];
|
77
87
|
if (storeRecord === undefined) {
|
78
88
|
return { kind: 'MissingData', reason: 'No record for root ' + root };
|
79
89
|
}
|
@@ -119,7 +129,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
|
|
119
129
|
results.push(null);
|
120
130
|
continue;
|
121
131
|
}
|
122
|
-
const result = readData(field.selections, link.__link, variables, nestedRefetchQueries);
|
132
|
+
const result = readData(environment, field.selections, link.__link, variables, nestedRefetchQueries);
|
123
133
|
if (result.kind === 'MissingData') {
|
124
134
|
return {
|
125
135
|
kind: 'MissingData',
|
@@ -140,6 +150,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
|
|
140
150
|
let link = assertLink(value);
|
141
151
|
if (link === undefined) {
|
142
152
|
// TODO make this configurable, and also generated and derived from the schema
|
153
|
+
const missingFieldHandler = (_c = environment.missingFieldHandler) !== null && _c !== void 0 ? _c : defaultMissingFieldHandler;
|
143
154
|
const altLink = missingFieldHandler(storeRecord, root, field.fieldName, field.arguments, variables);
|
144
155
|
if (altLink === undefined) {
|
145
156
|
return {
|
@@ -157,11 +168,11 @@ function readData(ast, root, variables, nestedRefetchQueries) {
|
|
157
168
|
}
|
158
169
|
}
|
159
170
|
else if (link === null) {
|
160
|
-
target[(
|
171
|
+
target[(_d = field.alias) !== null && _d !== void 0 ? _d : field.fieldName] = null;
|
161
172
|
break;
|
162
173
|
}
|
163
174
|
const targetId = link.__link;
|
164
|
-
const data = readData(field.selections, targetId, variables, nestedRefetchQueries);
|
175
|
+
const data = readData(environment, field.selections, targetId, variables, nestedRefetchQueries);
|
165
176
|
if (data.kind === 'MissingData') {
|
166
177
|
return {
|
167
178
|
kind: 'MissingData',
|
@@ -169,11 +180,11 @@ function readData(ast, root, variables, nestedRefetchQueries) {
|
|
169
180
|
nestedReason: data,
|
170
181
|
};
|
171
182
|
}
|
172
|
-
target[(
|
183
|
+
target[(_e = field.alias) !== null && _e !== void 0 ? _e : field.fieldName] = data.data;
|
173
184
|
break;
|
174
185
|
}
|
175
186
|
case 'RefetchField': {
|
176
|
-
const data = readData(field.readerArtifact.readerAst, root, variables,
|
187
|
+
const data = readData(environment, field.readerArtifact.readerAst, root, variables,
|
177
188
|
// Refetch fields just read the id, and don't need refetch query artifacts
|
178
189
|
[]);
|
179
190
|
if (typeof window !== 'undefined' && window.__LOG) {
|
@@ -194,12 +205,12 @@ function readData(ast, root, variables, nestedRefetchQueries) {
|
|
194
205
|
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
195
206
|
const refetchQueryArtifact = refetchQuery.artifact;
|
196
207
|
const allowedVariables = refetchQuery.allowedVariables;
|
197
|
-
target[field.alias] = field.readerArtifact.resolver(refetchQueryArtifact, Object.assign(Object.assign({}, data.data), filterVariables(variables, allowedVariables)));
|
208
|
+
target[field.alias] = field.readerArtifact.resolver(environment, refetchQueryArtifact, Object.assign(Object.assign({}, data.data), filterVariables(variables, allowedVariables)));
|
198
209
|
}
|
199
210
|
break;
|
200
211
|
}
|
201
212
|
case 'MutationField': {
|
202
|
-
const data = readData(field.readerArtifact.readerAst, root, variables,
|
213
|
+
const data = readData(environment, field.readerArtifact.readerAst, root, variables,
|
203
214
|
// Refetch fields just read the id, and don't need refetch query artifacts
|
204
215
|
[]);
|
205
216
|
if (typeof window !== 'undefined' && window.__LOG) {
|
@@ -220,7 +231,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
|
|
220
231
|
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
221
232
|
const refetchQueryArtifact = refetchQuery.artifact;
|
222
233
|
const allowedVariables = refetchQuery.allowedVariables;
|
223
|
-
target[field.alias] = field.readerArtifact.resolver(refetchQueryArtifact, data.data, filterVariables(variables, allowedVariables));
|
234
|
+
target[field.alias] = field.readerArtifact.resolver(environment, refetchQueryArtifact, data.data, filterVariables(variables, allowedVariables));
|
224
235
|
}
|
225
236
|
break;
|
226
237
|
}
|
@@ -229,7 +240,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
|
|
229
240
|
const resolverRefetchQueries = usedRefetchQueries.map((index) => nestedRefetchQueries[index]);
|
230
241
|
const variant = field.readerArtifact.variant;
|
231
242
|
if (variant.kind === 'Eager') {
|
232
|
-
const data = readData(field.readerArtifact.readerAst, root, variables, resolverRefetchQueries);
|
243
|
+
const data = readData(environment, field.readerArtifact.readerAst, root, variables, resolverRefetchQueries);
|
233
244
|
if (data.kind === 'MissingData') {
|
234
245
|
return {
|
235
246
|
kind: 'MissingData',
|
@@ -242,7 +253,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
|
|
242
253
|
}
|
243
254
|
}
|
244
255
|
else if (variant.kind === 'Component') {
|
245
|
-
target[field.alias] = (0, componentCache_1.getOrCreateCachedComponent)(root, variant.componentName, field.readerArtifact, variables, resolverRefetchQueries);
|
256
|
+
target[field.alias] = (0, componentCache_1.getOrCreateCachedComponent)(environment, root, variant.componentName, field.readerArtifact, variables, resolverRefetchQueries);
|
246
257
|
}
|
247
258
|
break;
|
248
259
|
}
|
@@ -250,16 +261,7 @@ function readData(ast, root, variables, nestedRefetchQueries) {
|
|
250
261
|
}
|
251
262
|
return { kind: 'Success', data: target };
|
252
263
|
}
|
253
|
-
|
254
|
-
function missingFieldHandler(storeRecord, root, fieldName, arguments_, variables) {
|
255
|
-
if (customMissingFieldHandler != null) {
|
256
|
-
return customMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables);
|
257
|
-
}
|
258
|
-
else {
|
259
|
-
return defaultMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables);
|
260
|
-
}
|
261
|
-
}
|
262
|
-
function defaultMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables) {
|
264
|
+
function defaultMissingFieldHandler(_storeRecord, _root, fieldName, arguments_, variables) {
|
263
265
|
if (fieldName === 'node' || fieldName === 'user') {
|
264
266
|
const variable = arguments_ === null || arguments_ === void 0 ? void 0 : arguments_['id'];
|
265
267
|
const value = variables === null || variables === void 0 ? void 0 : variables[variable];
|
@@ -270,10 +272,6 @@ function defaultMissingFieldHandler(storeRecord, root, fieldName, arguments_, va
|
|
270
272
|
}
|
271
273
|
}
|
272
274
|
exports.defaultMissingFieldHandler = defaultMissingFieldHandler;
|
273
|
-
function setMissingFieldHandler(handler) {
|
274
|
-
customMissingFieldHandler = handler;
|
275
|
-
}
|
276
|
-
exports.setMissingFieldHandler = setMissingFieldHandler;
|
277
275
|
function assertLink(link) {
|
278
276
|
if (Array.isArray(link)) {
|
279
277
|
throw new Error('Unexpected array');
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@isograph/react",
|
3
|
-
"version": "0.0.0-main-
|
3
|
+
"version": "0.0.0-main-f49c67bb",
|
4
4
|
"description": "Use Isograph with React",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"types": "dist/index.d.ts",
|
@@ -15,8 +15,8 @@
|
|
15
15
|
"prepack": "yarn run test && yarn run compile"
|
16
16
|
},
|
17
17
|
"dependencies": {
|
18
|
-
"@isograph/disposable-types": "0.0.0-main-
|
19
|
-
"@isograph/react-disposable-state": "0.0.0-main-
|
18
|
+
"@isograph/disposable-types": "0.0.0-main-f49c67bb",
|
19
|
+
"@isograph/react-disposable-state": "0.0.0-main-f49c67bb",
|
20
20
|
"react": "^18.2.0"
|
21
21
|
},
|
22
22
|
"devDependencies": {
|
@@ -15,6 +15,13 @@ import {
|
|
15
15
|
ReaderScalarField,
|
16
16
|
RefetchQueryArtifactWrapper,
|
17
17
|
} from './index';
|
18
|
+
import {
|
19
|
+
DataId,
|
20
|
+
ROOT_ID,
|
21
|
+
StoreRecord,
|
22
|
+
Link,
|
23
|
+
type IsographEnvironment,
|
24
|
+
} from './context';
|
18
25
|
|
19
26
|
declare global {
|
20
27
|
interface Window {
|
@@ -67,47 +74,39 @@ export function stableCopy<T>(value: T): T {
|
|
67
74
|
type IsoResolver = IsographEntrypoint<any, any, any>;
|
68
75
|
|
69
76
|
export function getOrCreateCacheForArtifact<T>(
|
77
|
+
environment: IsographEnvironment,
|
70
78
|
artifact: IsographEntrypoint<any, any, T>,
|
71
79
|
variables: object,
|
72
80
|
): ParentCache<PromiseWrapper<T>> {
|
73
81
|
const cacheKey = artifact.queryText + JSON.stringify(stableCopy(variables));
|
74
82
|
const factory: Factory<PromiseWrapper<T>> = () =>
|
75
|
-
makeNetworkRequest<T>(artifact, variables);
|
83
|
+
makeNetworkRequest<T>(environment, artifact, variables);
|
76
84
|
return getOrCreateCache<PromiseWrapper<T>>(cacheKey, factory);
|
77
85
|
}
|
78
86
|
|
79
|
-
let network: ((queryText: string, variables: object) => Promise<any>) | null;
|
80
|
-
|
81
|
-
// This is a hack until we store this in context somehow
|
82
|
-
export function setNetwork(newNetwork: typeof network) {
|
83
|
-
network = newNetwork;
|
84
|
-
}
|
85
|
-
|
86
87
|
export function makeNetworkRequest<T>(
|
88
|
+
environment: IsographEnvironment,
|
87
89
|
artifact: IsoResolver,
|
88
90
|
variables: object,
|
89
91
|
): ItemCleanupPair<PromiseWrapper<T>> {
|
90
92
|
if (typeof window !== 'undefined' && window.__LOG) {
|
91
93
|
console.log('make network request', artifact, variables);
|
92
94
|
}
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
const promise = network(artifact.queryText, variables).then(
|
98
|
-
(networkResponse) => {
|
95
|
+
const promise = environment
|
96
|
+
.networkFunction(artifact.queryText, variables)
|
97
|
+
.then((networkResponse) => {
|
99
98
|
if (typeof window !== 'undefined' && window.__LOG) {
|
100
99
|
console.log('network response', artifact);
|
101
100
|
}
|
102
101
|
normalizeData(
|
102
|
+
environment,
|
103
103
|
artifact.normalizationAst,
|
104
104
|
networkResponse.data,
|
105
105
|
variables,
|
106
106
|
artifact.nestedRefetchQueries,
|
107
107
|
);
|
108
108
|
return networkResponse.data;
|
109
|
-
}
|
110
|
-
);
|
109
|
+
});
|
111
110
|
|
112
111
|
const wrapper = wrapPromise(promise);
|
113
112
|
|
@@ -120,48 +119,6 @@ export function makeNetworkRequest<T>(
|
|
120
119
|
return response;
|
121
120
|
}
|
122
121
|
|
123
|
-
export type Link = {
|
124
|
-
__link: DataId;
|
125
|
-
};
|
126
|
-
export type DataTypeValue =
|
127
|
-
// N.B. undefined is here to support optional id's, but
|
128
|
-
// undefined should not *actually* be present in the store.
|
129
|
-
| undefined
|
130
|
-
// Singular scalar fields:
|
131
|
-
| number
|
132
|
-
| boolean
|
133
|
-
| string
|
134
|
-
| null
|
135
|
-
// Singular linked fields:
|
136
|
-
| Link
|
137
|
-
// Plural scalar and linked fields:
|
138
|
-
| DataTypeValue[];
|
139
|
-
|
140
|
-
export type StoreRecord = {
|
141
|
-
[index: DataId | string]: DataTypeValue;
|
142
|
-
// TODO __typename?: T, which is restricted to being a concrete string
|
143
|
-
// TODO this shouldn't always be named id
|
144
|
-
id?: DataId;
|
145
|
-
};
|
146
|
-
|
147
|
-
export type DataId = string;
|
148
|
-
|
149
|
-
export const ROOT_ID: DataId & '__ROOT' = '__ROOT';
|
150
|
-
let store: {
|
151
|
-
[index: DataId]: StoreRecord | null;
|
152
|
-
__ROOT: StoreRecord;
|
153
|
-
} = {
|
154
|
-
__ROOT: {},
|
155
|
-
};
|
156
|
-
export function getStore() {
|
157
|
-
return store;
|
158
|
-
}
|
159
|
-
export function clearStore() {
|
160
|
-
store = {
|
161
|
-
__ROOT: {},
|
162
|
-
};
|
163
|
-
}
|
164
|
-
|
165
122
|
type NetworkResponseScalarValue = string | number | boolean;
|
166
123
|
type NetworkResponseValue =
|
167
124
|
| NetworkResponseScalarValue
|
@@ -177,6 +134,7 @@ type NetworkResponseObject = {
|
|
177
134
|
};
|
178
135
|
|
179
136
|
function normalizeData(
|
137
|
+
environment: IsographEnvironment,
|
180
138
|
normalizationAst: NormalizationAst,
|
181
139
|
networkResponse: NetworkResponseObject,
|
182
140
|
variables: Object,
|
@@ -191,15 +149,16 @@ function normalizeData(
|
|
191
149
|
);
|
192
150
|
}
|
193
151
|
normalizeDataIntoRecord(
|
152
|
+
environment,
|
194
153
|
normalizationAst,
|
195
154
|
networkResponse,
|
196
|
-
store.__ROOT,
|
155
|
+
environment.store.__ROOT,
|
197
156
|
ROOT_ID,
|
198
157
|
variables as any,
|
199
158
|
nestedRefetchQueries,
|
200
159
|
);
|
201
160
|
if (typeof window !== 'undefined' && window.__LOG) {
|
202
|
-
console.log('after normalization', { store });
|
161
|
+
console.log('after normalization', { store: environment.store });
|
203
162
|
}
|
204
163
|
callSubscriptions();
|
205
164
|
}
|
@@ -228,6 +187,7 @@ function callSubscriptions() {
|
|
228
187
|
* Mutate targetParentRecord according to the normalizationAst and networkResponseParentRecord.
|
229
188
|
*/
|
230
189
|
function normalizeDataIntoRecord(
|
190
|
+
environment: IsographEnvironment,
|
231
191
|
normalizationAst: NormalizationAst,
|
232
192
|
networkResponseParentRecord: NetworkResponseObject,
|
233
193
|
targetParentRecord: StoreRecord,
|
@@ -248,6 +208,7 @@ function normalizeDataIntoRecord(
|
|
248
208
|
}
|
249
209
|
case 'Linked': {
|
250
210
|
normalizeLinkedField(
|
211
|
+
environment,
|
251
212
|
normalizationNode,
|
252
213
|
networkResponseParentRecord,
|
253
214
|
targetParentRecord,
|
@@ -285,6 +246,7 @@ function normalizeScalarField(
|
|
285
246
|
* Mutate targetParentRecord with a given linked field ast node.
|
286
247
|
*/
|
287
248
|
function normalizeLinkedField(
|
249
|
+
environment: IsographEnvironment,
|
288
250
|
astNode: NormalizationLinkedField,
|
289
251
|
networkResponseParentRecord: NetworkResponseObject,
|
290
252
|
targetParentRecord: StoreRecord,
|
@@ -309,10 +271,11 @@ function normalizeLinkedField(
|
|
309
271
|
|
310
272
|
if (Array.isArray(networkResponseData)) {
|
311
273
|
// TODO check astNode.plural or the like
|
312
|
-
const dataIds = [];
|
274
|
+
const dataIds: Link[] = [];
|
313
275
|
for (let i = 0; i < networkResponseData.length; i++) {
|
314
276
|
const networkResponseObject = networkResponseData[i];
|
315
277
|
const newStoreRecordId = normalizeNetworkResponseObject(
|
278
|
+
environment,
|
316
279
|
astNode,
|
317
280
|
networkResponseObject,
|
318
281
|
targetParentRecordId,
|
@@ -325,6 +288,7 @@ function normalizeLinkedField(
|
|
325
288
|
targetParentRecord[parentRecordKey] = dataIds;
|
326
289
|
} else {
|
327
290
|
const newStoreRecordId = normalizeNetworkResponseObject(
|
291
|
+
environment,
|
328
292
|
astNode,
|
329
293
|
networkResponseData,
|
330
294
|
targetParentRecordId,
|
@@ -339,6 +303,7 @@ function normalizeLinkedField(
|
|
339
303
|
}
|
340
304
|
|
341
305
|
function normalizeNetworkResponseObject(
|
306
|
+
environment: IsographEnvironment,
|
342
307
|
astNode: NormalizationLinkedField,
|
343
308
|
networkResponseData: NetworkResponseObject,
|
344
309
|
targetParentRecordId: string,
|
@@ -354,10 +319,11 @@ function normalizeNetworkResponseObject(
|
|
354
319
|
index,
|
355
320
|
);
|
356
321
|
|
357
|
-
const newStoreRecord = store[newStoreRecordId] ?? {};
|
358
|
-
store[newStoreRecordId] = newStoreRecord;
|
322
|
+
const newStoreRecord = environment.store[newStoreRecordId] ?? {};
|
323
|
+
environment.store[newStoreRecordId] = newStoreRecord;
|
359
324
|
|
360
325
|
normalizeDataIntoRecord(
|
326
|
+
environment,
|
361
327
|
astNode.selections,
|
362
328
|
networkResponseData,
|
363
329
|
newStoreRecord,
|
package/src/componentCache.ts
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
import {
|
2
|
+
DataId,
|
2
3
|
ReaderArtifact,
|
3
4
|
RefetchQueryArtifactWrapper,
|
4
5
|
readButDoNotEvaluate,
|
5
6
|
} from './index';
|
6
|
-
import {
|
7
|
+
import { stableCopy } from './cache';
|
8
|
+
import { IsographEnvironment } from '../dist';
|
7
9
|
|
8
10
|
type ComponentName = string;
|
9
11
|
type StringifiedArgs = string;
|
@@ -13,6 +15,7 @@ const cachedComponentsById: {
|
|
13
15
|
};
|
14
16
|
} = {};
|
15
17
|
export function getOrCreateCachedComponent(
|
18
|
+
environment: IsographEnvironment,
|
16
19
|
root: DataId,
|
17
20
|
componentName: string,
|
18
21
|
readerArtifact: ReaderArtifact<any, any, any>,
|
@@ -28,7 +31,7 @@ export function getOrCreateCachedComponent(
|
|
28
31
|
byArgs[stringifiedArgs] ??
|
29
32
|
(() => {
|
30
33
|
function Component(additionalRuntimeProps) {
|
31
|
-
const data = readButDoNotEvaluate({
|
34
|
+
const data = readButDoNotEvaluate(environment, {
|
32
35
|
kind: 'FragmentReference',
|
33
36
|
readerArtifact: readerArtifact,
|
34
37
|
root,
|
package/src/context.tsx
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
import { ReactNode, createContext, useContext } from 'react';
|
2
|
+
import * as React from 'react';
|
3
|
+
import { subscribe } from './cache';
|
4
|
+
|
5
|
+
export const IsographEnvironmentContext =
|
6
|
+
createContext<IsographEnvironment | null>(null);
|
7
|
+
|
8
|
+
export type IsographEnvironment = {
|
9
|
+
store: IsographStore;
|
10
|
+
networkFunction: IsographNetworkFunction;
|
11
|
+
missingFieldHandler: MissingFieldHandler | null;
|
12
|
+
};
|
13
|
+
|
14
|
+
export type MissingFieldHandler = (
|
15
|
+
storeRecord: StoreRecord,
|
16
|
+
root: DataId,
|
17
|
+
fieldName: string,
|
18
|
+
arguments_: { [index: string]: any } | null,
|
19
|
+
variables: { [index: string]: any } | null,
|
20
|
+
) => Link | undefined;
|
21
|
+
|
22
|
+
export type IsographNetworkFunction = (
|
23
|
+
queryText: string,
|
24
|
+
variables: object,
|
25
|
+
) => Promise<any>;
|
26
|
+
|
27
|
+
export type Link = {
|
28
|
+
__link: DataId;
|
29
|
+
};
|
30
|
+
export type DataTypeValue =
|
31
|
+
// N.B. undefined is here to support optional id's, but
|
32
|
+
// undefined should not *actually* be present in the store.
|
33
|
+
| undefined
|
34
|
+
// Singular scalar fields:
|
35
|
+
| number
|
36
|
+
| boolean
|
37
|
+
| string
|
38
|
+
| null
|
39
|
+
// Singular linked fields:
|
40
|
+
| Link
|
41
|
+
// Plural scalar and linked fields:
|
42
|
+
| DataTypeValue[];
|
43
|
+
|
44
|
+
export type StoreRecord = {
|
45
|
+
[index: DataId | string]: DataTypeValue;
|
46
|
+
// TODO __typename?: T, which is restricted to being a concrete string
|
47
|
+
// TODO this shouldn't always be named id
|
48
|
+
id?: DataId;
|
49
|
+
};
|
50
|
+
|
51
|
+
export type DataId = string;
|
52
|
+
|
53
|
+
export const ROOT_ID: DataId & '__ROOT' = '__ROOT';
|
54
|
+
|
55
|
+
export type IsographStore = {
|
56
|
+
[index: DataId]: StoreRecord | null;
|
57
|
+
__ROOT: StoreRecord;
|
58
|
+
};
|
59
|
+
|
60
|
+
export type IsographEnvironmentProviderProps = {
|
61
|
+
environment: IsographEnvironment;
|
62
|
+
children: ReactNode;
|
63
|
+
};
|
64
|
+
|
65
|
+
export function IsographEnvironmentProvider({
|
66
|
+
environment,
|
67
|
+
children,
|
68
|
+
}: IsographEnvironmentProviderProps) {
|
69
|
+
const [, setState] = React.useState<object | void>();
|
70
|
+
React.useEffect(() => {
|
71
|
+
return subscribe(() => setState({}));
|
72
|
+
}, []);
|
73
|
+
|
74
|
+
return (
|
75
|
+
<IsographEnvironmentContext.Provider value={environment}>
|
76
|
+
{children}
|
77
|
+
</IsographEnvironmentContext.Provider>
|
78
|
+
);
|
79
|
+
}
|
80
|
+
|
81
|
+
export function useIsographEnvironment(): IsographEnvironment {
|
82
|
+
const context = useContext(IsographEnvironmentContext);
|
83
|
+
if (context == null) {
|
84
|
+
throw new Error(
|
85
|
+
'Unexpected null environment context. Make sure to render ' +
|
86
|
+
'this component within an IsographEnvironmentProvider component',
|
87
|
+
);
|
88
|
+
}
|
89
|
+
return context;
|
90
|
+
}
|
package/src/index.tsx
CHANGED
@@ -1,27 +1,36 @@
|
|
1
1
|
import {
|
2
|
-
DataId,
|
3
|
-
StoreRecord,
|
4
|
-
DataTypeValue,
|
5
|
-
Link,
|
6
|
-
ROOT_ID,
|
7
2
|
getOrCreateCacheForArtifact,
|
8
3
|
onNextChange,
|
9
|
-
getStore,
|
10
4
|
getParentRecordKey,
|
11
5
|
} from './cache';
|
12
6
|
import { useLazyDisposableState } from '@isograph/react-disposable-state';
|
13
7
|
import { type PromiseWrapper } from './PromiseWrapper';
|
14
8
|
import { getOrCreateCachedComponent } from './componentCache';
|
15
|
-
|
16
|
-
export {
|
17
|
-
setNetwork,
|
18
|
-
makeNetworkRequest,
|
19
|
-
subscribe,
|
9
|
+
import {
|
20
10
|
DataId,
|
11
|
+
DataTypeValue,
|
12
|
+
IsographEnvironment,
|
21
13
|
Link,
|
14
|
+
ROOT_ID,
|
22
15
|
StoreRecord,
|
23
|
-
|
24
|
-
} from './
|
16
|
+
useIsographEnvironment,
|
17
|
+
} from './context';
|
18
|
+
|
19
|
+
export { makeNetworkRequest, subscribe } from './cache';
|
20
|
+
export {
|
21
|
+
IsographEnvironmentContext,
|
22
|
+
ROOT_ID,
|
23
|
+
type DataId,
|
24
|
+
type DataTypeValue,
|
25
|
+
type IsographEnvironment,
|
26
|
+
IsographEnvironmentProvider,
|
27
|
+
type IsographEnvironmentProviderProps,
|
28
|
+
type IsographNetworkFunction,
|
29
|
+
type IsographStore,
|
30
|
+
type Link,
|
31
|
+
type StoreRecord,
|
32
|
+
useIsographEnvironment,
|
33
|
+
} from './context';
|
25
34
|
|
26
35
|
export { iso } from './iso';
|
27
36
|
|
@@ -177,7 +186,10 @@ function assertIsEntrypoint<
|
|
177
186
|
>(
|
178
187
|
value:
|
179
188
|
| IsographEntrypoint<TReadFromStore, TResolverProps, TResolverResult>
|
180
|
-
|
|
189
|
+
| ((_: any) => any)
|
190
|
+
// Temporarily, allow any here. Once we automatically provide
|
191
|
+
// types to entrypoints, we probably don't need this.
|
192
|
+
| any,
|
181
193
|
): asserts value is IsographEntrypoint<
|
182
194
|
TReadFromStore,
|
183
195
|
TResolverProps,
|
@@ -211,9 +223,11 @@ export function useLazyReference<TEntrypoint>(
|
|
211
223
|
ExtractResolverResult<TEntrypoint>
|
212
224
|
>;
|
213
225
|
} {
|
226
|
+
const environment = useIsographEnvironment();
|
214
227
|
assertIsEntrypoint(entrypoint);
|
215
228
|
// Typechecking fails here... TODO investigate
|
216
229
|
const cache = getOrCreateCacheForArtifact<ExtractResolverResult<TEntrypoint>>(
|
230
|
+
environment,
|
217
231
|
entrypoint,
|
218
232
|
variables,
|
219
233
|
);
|
@@ -234,11 +248,27 @@ export function useLazyReference<TEntrypoint>(
|
|
234
248
|
};
|
235
249
|
}
|
236
250
|
|
251
|
+
export function useRead<
|
252
|
+
TReadFromStore extends Object,
|
253
|
+
TResolverProps,
|
254
|
+
TResolverResult,
|
255
|
+
>(
|
256
|
+
fragmentReference: FragmentReference<
|
257
|
+
TReadFromStore,
|
258
|
+
TResolverProps,
|
259
|
+
TResolverResult
|
260
|
+
>,
|
261
|
+
): TResolverResult {
|
262
|
+
const environment = useIsographEnvironment();
|
263
|
+
return read(environment, fragmentReference);
|
264
|
+
}
|
265
|
+
|
237
266
|
export function read<
|
238
267
|
TReadFromStore extends Object,
|
239
268
|
TResolverProps,
|
240
269
|
TResolverResult,
|
241
270
|
>(
|
271
|
+
environment: IsographEnvironment,
|
242
272
|
fragmentReference: FragmentReference<
|
243
273
|
TReadFromStore,
|
244
274
|
TResolverProps,
|
@@ -248,6 +278,7 @@ export function read<
|
|
248
278
|
const variant = fragmentReference.readerArtifact.variant;
|
249
279
|
if (variant.kind === 'Eager') {
|
250
280
|
const data = readData(
|
281
|
+
environment,
|
251
282
|
fragmentReference.readerArtifact.readerAst,
|
252
283
|
fragmentReference.root,
|
253
284
|
fragmentReference.variables ?? {},
|
@@ -261,6 +292,7 @@ export function read<
|
|
261
292
|
} else if (variant.kind === 'Component') {
|
262
293
|
// @ts-ignore
|
263
294
|
return getOrCreateCachedComponent(
|
295
|
+
environment,
|
264
296
|
fragmentReference.root,
|
265
297
|
variant.componentName,
|
266
298
|
fragmentReference.readerArtifact,
|
@@ -273,9 +305,11 @@ export function read<
|
|
273
305
|
}
|
274
306
|
|
275
307
|
export function readButDoNotEvaluate<TReadFromStore extends Object>(
|
308
|
+
environment: IsographEnvironment,
|
276
309
|
reference: FragmentReference<TReadFromStore, unknown, unknown>,
|
277
310
|
): TReadFromStore {
|
278
311
|
const response = readData(
|
312
|
+
environment,
|
279
313
|
reference.readerArtifact.readerAst,
|
280
314
|
reference.root,
|
281
315
|
reference.variables ?? {},
|
@@ -303,12 +337,13 @@ type ReadDataResult<TReadFromStore> =
|
|
303
337
|
};
|
304
338
|
|
305
339
|
function readData<TReadFromStore>(
|
340
|
+
environment: IsographEnvironment,
|
306
341
|
ast: ReaderAst<TReadFromStore>,
|
307
342
|
root: DataId,
|
308
343
|
variables: { [index: string]: string },
|
309
344
|
nestedRefetchQueries: RefetchQueryArtifactWrapper[],
|
310
345
|
): ReadDataResult<TReadFromStore> {
|
311
|
-
let storeRecord =
|
346
|
+
let storeRecord = environment.store[root];
|
312
347
|
if (storeRecord === undefined) {
|
313
348
|
return { kind: 'MissingData', reason: 'No record for root ' + root };
|
314
349
|
}
|
@@ -358,6 +393,7 @@ function readData<TReadFromStore>(
|
|
358
393
|
continue;
|
359
394
|
}
|
360
395
|
const result = readData(
|
396
|
+
environment,
|
361
397
|
field.selections,
|
362
398
|
link.__link,
|
363
399
|
variables,
|
@@ -384,6 +420,8 @@ function readData<TReadFromStore>(
|
|
384
420
|
let link = assertLink(value);
|
385
421
|
if (link === undefined) {
|
386
422
|
// TODO make this configurable, and also generated and derived from the schema
|
423
|
+
const missingFieldHandler =
|
424
|
+
environment.missingFieldHandler ?? defaultMissingFieldHandler;
|
387
425
|
const altLink = missingFieldHandler(
|
388
426
|
storeRecord,
|
389
427
|
root,
|
@@ -411,6 +449,7 @@ function readData<TReadFromStore>(
|
|
411
449
|
}
|
412
450
|
const targetId = link.__link;
|
413
451
|
const data = readData(
|
452
|
+
environment,
|
414
453
|
field.selections,
|
415
454
|
targetId,
|
416
455
|
variables,
|
@@ -428,6 +467,7 @@ function readData<TReadFromStore>(
|
|
428
467
|
}
|
429
468
|
case 'RefetchField': {
|
430
469
|
const data = readData(
|
470
|
+
environment,
|
431
471
|
field.readerArtifact.readerAst,
|
432
472
|
root,
|
433
473
|
variables,
|
@@ -453,6 +493,7 @@ function readData<TReadFromStore>(
|
|
453
493
|
const allowedVariables = refetchQuery.allowedVariables;
|
454
494
|
|
455
495
|
target[field.alias] = field.readerArtifact.resolver(
|
496
|
+
environment,
|
456
497
|
refetchQueryArtifact,
|
457
498
|
{
|
458
499
|
...data.data,
|
@@ -466,6 +507,7 @@ function readData<TReadFromStore>(
|
|
466
507
|
}
|
467
508
|
case 'MutationField': {
|
468
509
|
const data = readData(
|
510
|
+
environment,
|
469
511
|
field.readerArtifact.readerAst,
|
470
512
|
root,
|
471
513
|
variables,
|
@@ -491,6 +533,7 @@ function readData<TReadFromStore>(
|
|
491
533
|
const allowedVariables = refetchQuery.allowedVariables;
|
492
534
|
|
493
535
|
target[field.alias] = field.readerArtifact.resolver(
|
536
|
+
environment,
|
494
537
|
refetchQueryArtifact,
|
495
538
|
data.data,
|
496
539
|
filterVariables(variables, allowedVariables),
|
@@ -507,6 +550,7 @@ function readData<TReadFromStore>(
|
|
507
550
|
const variant = field.readerArtifact.variant;
|
508
551
|
if (variant.kind === 'Eager') {
|
509
552
|
const data = readData(
|
553
|
+
environment,
|
510
554
|
field.readerArtifact.readerAst,
|
511
555
|
root,
|
512
556
|
variables,
|
@@ -523,6 +567,7 @@ function readData<TReadFromStore>(
|
|
523
567
|
}
|
524
568
|
} else if (variant.kind === 'Component') {
|
525
569
|
target[field.alias] = getOrCreateCachedComponent(
|
570
|
+
environment,
|
526
571
|
root,
|
527
572
|
variant.componentName,
|
528
573
|
field.readerArtifact,
|
@@ -537,37 +582,9 @@ function readData<TReadFromStore>(
|
|
537
582
|
return { kind: 'Success', data: target as any };
|
538
583
|
}
|
539
584
|
|
540
|
-
let customMissingFieldHandler: typeof defaultMissingFieldHandler | null = null;
|
541
|
-
|
542
|
-
function missingFieldHandler(
|
543
|
-
storeRecord: StoreRecord,
|
544
|
-
root: DataId,
|
545
|
-
fieldName: string,
|
546
|
-
arguments_: { [index: string]: any } | null,
|
547
|
-
variables: { [index: string]: any } | null,
|
548
|
-
): Link | undefined {
|
549
|
-
if (customMissingFieldHandler != null) {
|
550
|
-
return customMissingFieldHandler(
|
551
|
-
storeRecord,
|
552
|
-
root,
|
553
|
-
fieldName,
|
554
|
-
arguments_,
|
555
|
-
variables,
|
556
|
-
);
|
557
|
-
} else {
|
558
|
-
return defaultMissingFieldHandler(
|
559
|
-
storeRecord,
|
560
|
-
root,
|
561
|
-
fieldName,
|
562
|
-
arguments_,
|
563
|
-
variables,
|
564
|
-
);
|
565
|
-
}
|
566
|
-
}
|
567
|
-
|
568
585
|
export function defaultMissingFieldHandler(
|
569
|
-
|
570
|
-
|
586
|
+
_storeRecord: StoreRecord,
|
587
|
+
_root: DataId,
|
571
588
|
fieldName: string,
|
572
589
|
arguments_: { [index: string]: any } | null,
|
573
590
|
variables: { [index: string]: any } | null,
|
@@ -583,12 +600,6 @@ export function defaultMissingFieldHandler(
|
|
583
600
|
}
|
584
601
|
}
|
585
602
|
|
586
|
-
export function setMissingFieldHandler(
|
587
|
-
handler: typeof defaultMissingFieldHandler,
|
588
|
-
) {
|
589
|
-
customMissingFieldHandler = handler;
|
590
|
-
}
|
591
|
-
|
592
603
|
function assertLink(link: DataTypeValue): Link | undefined | null {
|
593
604
|
if (Array.isArray(link)) {
|
594
605
|
throw new Error('Unexpected array');
|