@isograph/react 0.0.0-main-0eb53a17 → 0.0.0-main-cddcd660
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/.turbo/turbo-compile-libs.log +1 -1
- package/dist/core/FragmentReference.d.ts +2 -2
- package/dist/core/FragmentReference.d.ts.map +1 -1
- package/dist/core/IsographEnvironment.d.ts +12 -7
- package/dist/core/IsographEnvironment.d.ts.map +1 -1
- package/dist/core/areEqualWithDeepComparison.d.ts +1 -3
- package/dist/core/areEqualWithDeepComparison.d.ts.map +1 -1
- package/dist/core/areEqualWithDeepComparison.js +0 -2
- package/dist/core/brand.d.ts +2 -0
- package/dist/core/brand.d.ts.map +1 -0
- package/dist/core/brand.js +2 -0
- package/dist/core/cache.d.ts +4 -4
- package/dist/core/cache.d.ts.map +1 -1
- package/dist/core/cache.js +8 -3
- package/dist/core/check.d.ts +3 -3
- package/dist/core/check.d.ts.map +1 -1
- package/dist/core/garbageCollection.d.ts +2 -2
- package/dist/core/garbageCollection.d.ts.map +1 -1
- package/dist/core/logging.d.ts +13 -4
- package/dist/core/logging.d.ts.map +1 -1
- package/dist/core/makeNetworkRequest.d.ts.map +1 -1
- package/dist/core/read.d.ts +7 -7
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/reader.d.ts +3 -3
- package/dist/core/reader.d.ts.map +1 -1
- package/dist/core/startUpdate.d.ts.map +1 -1
- package/dist/core/startUpdate.js +9 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/react/FragmentReader.d.ts +4 -10
- package/dist/react/FragmentReader.d.ts.map +1 -1
- package/dist/react/FragmentReader.js +3 -30
- package/dist/react/FragmentRenderer.d.ts +15 -0
- package/dist/react/FragmentRenderer.d.ts.map +1 -0
- package/dist/react/FragmentRenderer.js +35 -0
- package/dist/react/LoadableFieldReader.d.ts.map +1 -1
- package/dist/react/LoadableFieldReader.js +0 -3
- package/dist/react/LoadableFieldRenderer.d.ts +13 -0
- package/dist/react/LoadableFieldRenderer.d.ts.map +1 -0
- package/dist/react/LoadableFieldRenderer.js +37 -0
- package/package.json +4 -4
- package/src/core/FragmentReference.ts +2 -2
- package/src/core/IsographEnvironment.ts +13 -7
- package/src/core/areEqualWithDeepComparison.ts +5 -5
- package/src/core/brand.ts +18 -0
- package/src/core/cache.ts +22 -14
- package/src/core/check.ts +4 -4
- package/src/core/garbageCollection.ts +3 -3
- package/src/core/logging.ts +16 -4
- package/src/core/makeNetworkRequest.ts +2 -2
- package/src/core/read.ts +12 -10
- package/src/core/reader.ts +3 -3
- package/src/core/startUpdate.ts +11 -2
- package/src/index.ts +5 -2
- package/src/react/FragmentReader.tsx +17 -36
- package/src/react/FragmentRenderer.tsx +46 -0
- package/src/react/LoadableFieldReader.tsx +0 -3
- package/src/react/LoadableFieldRenderer.tsx +41 -0
- package/src/tests/__isograph/Economist/link/output_type.ts +2 -0
- package/src/tests/__isograph/Node/asEconomist/resolver_reader.ts +1 -1
- package/src/tests/__isograph/Node/link/output_type.ts +3 -0
- package/src/tests/__isograph/Query/linkedUpdate/param_type.ts +4 -4
- package/src/tests/__isograph/iso.ts +1 -1
- package/src/tests/__isograph/tsconfig.json +8 -0
|
@@ -1,35 +1,8 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
3
|
exports.FragmentReader = FragmentReader;
|
|
27
|
-
const React = __importStar(require("react"));
|
|
28
4
|
const useResult_1 = require("./useResult");
|
|
29
|
-
function FragmentReader(
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
// it means that TProps === JSX.IntrinsicAttributes.
|
|
33
|
-
// @ts-expect-error
|
|
34
|
-
return React.createElement(Component, Object.assign({}, props.additionalProps));
|
|
5
|
+
function FragmentReader({ fragmentReference, networkRequestOptions, children, }) {
|
|
6
|
+
const result = (0, useResult_1.useResult)(fragmentReference, networkRequestOptions);
|
|
7
|
+
return children(result);
|
|
35
8
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type ExtractReadFromStore, type IsographEntrypoint } from '../core/entrypoint';
|
|
3
|
+
import { type FragmentReference } from '../core/FragmentReference';
|
|
4
|
+
import { type NetworkRequestReaderOptions } from '../core/read';
|
|
5
|
+
export type IsExactlyIntrinsicAttributes<T> = T extends JSX.IntrinsicAttributes ? JSX.IntrinsicAttributes extends T ? true : false : false;
|
|
6
|
+
export declare function FragmentRenderer<TProps extends Record<any, any>, TEntrypoint extends IsographEntrypoint<any, React.FC<TProps>, any>>(props: IsExactlyIntrinsicAttributes<TProps> extends true ? {
|
|
7
|
+
fragmentReference: FragmentReference<ExtractReadFromStore<TEntrypoint>, React.FC<TProps>>;
|
|
8
|
+
additionalProps?: Record<PropertyKey, never>;
|
|
9
|
+
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
10
|
+
} : {
|
|
11
|
+
fragmentReference: FragmentReference<ExtractReadFromStore<TEntrypoint>, React.FC<TProps>>;
|
|
12
|
+
additionalProps: Omit<TProps, keyof JSX.IntrinsicAttributes>;
|
|
13
|
+
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
14
|
+
}): React.ReactNode;
|
|
15
|
+
//# sourceMappingURL=FragmentRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FragmentRenderer.d.ts","sourceRoot":"","sources":["../../src/react/FragmentRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAGhE,MAAM,MAAM,4BAA4B,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,mBAAmB,GAC3E,GAAG,CAAC,mBAAmB,SAAS,CAAC,GAC/B,IAAI,GACJ,KAAK,GACP,KAAK,CAAC;AAEV,wBAAgB,gBAAgB,CAC9B,MAAM,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAC/B,WAAW,SAAS,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,EAElE,KAAK,EAAE,4BAA4B,CAAC,MAAM,CAAC,SAAS,IAAI,GACpD;IACE,iBAAiB,EAAE,iBAAiB,CAClC,oBAAoB,CAAC,WAAW,CAAC,EACjC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CACjB,CAAC;IACF,eAAe,CAAC,EAAE,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC7C,qBAAqB,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;CAC9D,GACD;IACE,iBAAiB,EAAE,iBAAiB,CAClC,oBAAoB,CAAC,WAAW,CAAC,EACjC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CACjB,CAAC;IACF,eAAe,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC7D,qBAAqB,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;CAC9D,GACJ,KAAK,CAAC,SAAS,CASjB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
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.FragmentRenderer = FragmentRenderer;
|
|
27
|
+
const React = __importStar(require("react"));
|
|
28
|
+
const useResult_1 = require("./useResult");
|
|
29
|
+
function FragmentRenderer(props) {
|
|
30
|
+
const Component = (0, useResult_1.useResult)(props.fragmentReference, props.networkRequestOptions);
|
|
31
|
+
// TypeScript is not understanding that if additionalProps is Record<PropertyKey, never>,
|
|
32
|
+
// it means that TProps === JSX.IntrinsicAttributes.
|
|
33
|
+
// @ts-expect-error
|
|
34
|
+
return React.createElement(Component, Object.assign({}, props.additionalProps));
|
|
35
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoadableFieldReader.d.ts","sourceRoot":"","sources":["../../src/react/LoadableFieldReader.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC3B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"LoadableFieldReader.d.ts","sourceRoot":"","sources":["../../src/react/LoadableFieldReader.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC3B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD,wBAAgB,mBAAmB,CACjC,cAAc,SAAS,qBAAqB,EAC5C,OAAO,EACP,aAAa,SAAS,MAAM,EAC5B,eAAe,EACf,KAAK,EAAE;IACP,aAAa,EAAE,aAAa,CAC1B,cAAc,EACd,OAAO,EACP,IAAI,CAAC,iBAAiB,CAAC,cAAc,CAAC,EAAE,MAAM,aAAa,CAAC,CAC7D,CAAC;IAEF,IAAI,EAAE,IAAI,CAAC,iBAAiB,CAAC,cAAc,CAAC,EAAE,MAAM,aAAa,CAAC,CAAC;IACnE,YAAY,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IACrC,qBAAqB,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC7D,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,eAAe,CAAC;CAC7C,GAAG,eAAe,CAalB"}
|
|
@@ -3,9 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.LoadableFieldReader = LoadableFieldReader;
|
|
4
4
|
const useClientSideDefer_1 = require("../loadable-hooks/useClientSideDefer");
|
|
5
5
|
const useResult_1 = require("./useResult");
|
|
6
|
-
// TODO
|
|
7
|
-
// - LoadableFieldRenderer, which works for @loadable fields that are components,
|
|
8
|
-
// i.e. just renders the resulting component
|
|
9
6
|
function LoadableFieldReader(props) {
|
|
10
7
|
const { fragmentReference } = (0, useClientSideDefer_1.useClientSideDefer)(props.loadableField, props.args, props.fetchOptions);
|
|
11
8
|
const readOutFragmentData = (0, useResult_1.useResult)(fragmentReference, props.networkRequestOptions);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type FetchOptions } from '../core/check';
|
|
3
|
+
import { ExtractParameters, type UnknownTReadFromStore } from '../core/FragmentReference';
|
|
4
|
+
import { type NetworkRequestReaderOptions } from '../core/read';
|
|
5
|
+
import { type LoadableField } from '../core/reader';
|
|
6
|
+
export declare function LoadableFieldRenderer<TReadFromStore extends UnknownTReadFromStore, TProvidedArgs extends object, TChildrenResult, TProps>(props: {
|
|
7
|
+
loadableField: LoadableField<TReadFromStore, React.FC<TProps>, Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>>;
|
|
8
|
+
args: Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>;
|
|
9
|
+
fetchOptions?: FetchOptions<React.FC<TProps>>;
|
|
10
|
+
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
11
|
+
additionalProps: Omit<TProps, keyof JSX.IntrinsicAttributes>;
|
|
12
|
+
}): TChildrenResult;
|
|
13
|
+
//# sourceMappingURL=LoadableFieldRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoadableFieldRenderer.d.ts","sourceRoot":"","sources":["../../src/react/LoadableFieldRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC3B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD,wBAAgB,qBAAqB,CACnC,cAAc,SAAS,qBAAqB,EAC5C,aAAa,SAAS,MAAM,EAC5B,eAAe,EACf,MAAM,EACN,KAAK,EAAE;IACP,aAAa,EAAE,aAAa,CAC1B,cAAc,EACd,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAChB,IAAI,CAAC,iBAAiB,CAAC,cAAc,CAAC,EAAE,MAAM,aAAa,CAAC,CAC7D,CAAC;IAEF,IAAI,EAAE,IAAI,CAAC,iBAAiB,CAAC,cAAc,CAAC,EAAE,MAAM,aAAa,CAAC,CAAC;IACnE,YAAY,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,qBAAqB,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC7D,eAAe,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,mBAAmB,CAAC,CAAC;CAC9D,GAAG,eAAe,CAalB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
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.LoadableFieldRenderer = LoadableFieldRenderer;
|
|
27
|
+
const React = __importStar(require("react"));
|
|
28
|
+
const useClientSideDefer_1 = require("../loadable-hooks/useClientSideDefer");
|
|
29
|
+
const useResult_1 = require("./useResult");
|
|
30
|
+
function LoadableFieldRenderer(props) {
|
|
31
|
+
const { fragmentReference } = (0, useClientSideDefer_1.useClientSideDefer)(props.loadableField, props.args, props.fetchOptions);
|
|
32
|
+
const Component = (0, useResult_1.useResult)(fragmentReference, props.networkRequestOptions);
|
|
33
|
+
// TODO we probably can figure out a way to convince TypeScript of
|
|
34
|
+
// the validity of this.
|
|
35
|
+
// @ts-expect-error
|
|
36
|
+
return React.createElement(Component, Object.assign({}, props.additionalProps));
|
|
37
|
+
}
|
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-cddcd660",
|
|
4
4
|
"description": "Use Isograph with React",
|
|
5
5
|
"homepage": "https://isograph.dev",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"iso": "cross-env ISO_PRINT_ABSOLUTE_FILEPATH=1 ../../target/debug/isograph_cli --config ./isograph.config.json"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@isograph/disposable-types": "0.0.0-main-
|
|
23
|
-
"@isograph/react-disposable-state": "0.0.0-main-
|
|
24
|
-
"@isograph/reference-counted-pointer": "0.0.0-main-
|
|
22
|
+
"@isograph/disposable-types": "0.0.0-main-cddcd660",
|
|
23
|
+
"@isograph/react-disposable-state": "0.0.0-main-cddcd660",
|
|
24
|
+
"@isograph/reference-counted-pointer": "0.0.0-main-cddcd660"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"react": "^18.0.0 || ^19.0.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReaderWithRefetchQueries } from '../core/entrypoint';
|
|
2
2
|
import { stableCopy } from './cache';
|
|
3
|
-
import { type
|
|
3
|
+
import { type StoreLink } from './IsographEnvironment';
|
|
4
4
|
import { PromiseWrapper } from './PromiseWrapper';
|
|
5
5
|
import type { StartUpdate } from './reader';
|
|
6
6
|
|
|
@@ -52,7 +52,7 @@ export type FragmentReference<
|
|
|
52
52
|
readonly readerWithRefetchQueries: PromiseWrapper<
|
|
53
53
|
ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>
|
|
54
54
|
>;
|
|
55
|
-
readonly root:
|
|
55
|
+
readonly root: StoreLink;
|
|
56
56
|
// TODO we potentially stably copy and stringify variables a lot!
|
|
57
57
|
// So, we should employ interior mutability: pretend that fragent reference
|
|
58
58
|
// is immutable, but actually store something like
|
|
@@ -15,6 +15,7 @@ import { LogFunction, WrappedLogFunction } from './logging';
|
|
|
15
15
|
import { PromiseWrapper, wrapPromise } from './PromiseWrapper';
|
|
16
16
|
import { WithEncounteredRecords } from './read';
|
|
17
17
|
import type { ReaderAst, StartUpdate } from './reader';
|
|
18
|
+
import type { Brand } from './brand';
|
|
18
19
|
|
|
19
20
|
export type ComponentOrFieldName = string;
|
|
20
21
|
export type StringifiedArgs = string;
|
|
@@ -38,7 +39,7 @@ export type FragmentSubscription<TReadFromStore extends UnknownTReadFromStore> =
|
|
|
38
39
|
export type AnyChangesToRecordSubscription = {
|
|
39
40
|
readonly kind: 'AnyChangesToRecord';
|
|
40
41
|
readonly callback: () => void;
|
|
41
|
-
readonly recordLink:
|
|
42
|
+
readonly recordLink: StoreLink;
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
export type AnyRecordSubscription = {
|
|
@@ -77,18 +78,23 @@ export type IsographEnvironment = {
|
|
|
77
78
|
|
|
78
79
|
export type MissingFieldHandler = (
|
|
79
80
|
storeRecord: StoreRecord,
|
|
80
|
-
root:
|
|
81
|
+
root: StoreLink,
|
|
81
82
|
fieldName: string,
|
|
82
83
|
arguments_: { [index: string]: any } | null,
|
|
83
84
|
variables: Variables | null,
|
|
84
|
-
) =>
|
|
85
|
+
) => StoreLink | undefined;
|
|
85
86
|
|
|
86
87
|
export type IsographNetworkFunction = (
|
|
87
88
|
operation: IsographOperation | IsographPersistedOperation,
|
|
88
89
|
variables: Variables,
|
|
89
90
|
) => Promise<any>;
|
|
90
91
|
|
|
91
|
-
export
|
|
92
|
+
export interface Link<T extends TypeName> extends StoreLink {
|
|
93
|
+
readonly __link: Brand<DataId, T>;
|
|
94
|
+
readonly __typename: T;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export type StoreLink = {
|
|
92
98
|
readonly __link: DataId;
|
|
93
99
|
readonly __typename: TypeName;
|
|
94
100
|
};
|
|
@@ -103,7 +109,7 @@ export type DataTypeValue =
|
|
|
103
109
|
| string
|
|
104
110
|
| null
|
|
105
111
|
// Singular linked fields:
|
|
106
|
-
|
|
|
112
|
+
| StoreLink
|
|
107
113
|
// Plural scalar and linked fields:
|
|
108
114
|
| DataTypeValue[];
|
|
109
115
|
|
|
@@ -162,7 +168,7 @@ export function createIsographStore(): IsographStore {
|
|
|
162
168
|
};
|
|
163
169
|
}
|
|
164
170
|
|
|
165
|
-
export function assertLink(link: DataTypeValue):
|
|
171
|
+
export function assertLink(link: DataTypeValue): StoreLink | null | undefined {
|
|
166
172
|
if (Array.isArray(link)) {
|
|
167
173
|
throw new Error('Unexpected array');
|
|
168
174
|
}
|
|
@@ -175,7 +181,7 @@ export function assertLink(link: DataTypeValue): Link | null | undefined {
|
|
|
175
181
|
throw new Error('Invalid link');
|
|
176
182
|
}
|
|
177
183
|
|
|
178
|
-
export function getLink(maybeLink: DataTypeValue):
|
|
184
|
+
export function getLink(maybeLink: DataTypeValue): StoreLink | null {
|
|
179
185
|
if (
|
|
180
186
|
maybeLink != null &&
|
|
181
187
|
typeof maybeLink === 'object' &&
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StoreLink } from './IsographEnvironment';
|
|
2
2
|
import type { ReaderAst, ReaderLinkedField, ReaderScalarField } from './reader';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
function mergeUsingReaderAst(
|
|
5
5
|
field: ReaderScalarField | ReaderLinkedField,
|
|
6
6
|
oldItem: unknown,
|
|
7
7
|
newItem: unknown,
|
|
@@ -40,7 +40,7 @@ export function mergeUsingReaderAst(
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
function mergeArraysUsingReaderAst(
|
|
44
44
|
field: ReaderScalarField | ReaderLinkedField,
|
|
45
45
|
oldItems: ReadonlyArray<unknown>,
|
|
46
46
|
newItems: Array<unknown>,
|
|
@@ -101,9 +101,9 @@ export function mergeObjectsUsingReaderAst(
|
|
|
101
101
|
case 'Link': {
|
|
102
102
|
const key = field.alias;
|
|
103
103
|
// @ts-expect-error
|
|
104
|
-
const oldValue:
|
|
104
|
+
const oldValue: StoreLink = oldItemObject[key];
|
|
105
105
|
// @ts-expect-error
|
|
106
|
-
const newValue:
|
|
106
|
+
const newValue: StoreLink = newItemObject[key];
|
|
107
107
|
|
|
108
108
|
if (
|
|
109
109
|
oldValue.__link !== newValue.__link ||
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Suppress the TypeScript compiler warning for this branded-type trick.
|
|
2
|
+
// See discussion: https://github.com/microsoft/TypeScript/issues/202#issuecomment-436900738
|
|
3
|
+
// Pattern: “Brand<BaseType, Brand>” leverages TypeScript conditional and `infer` types to create a pseudo-nominal type,
|
|
4
|
+
// enabling BaseType to be treated as distinct only when tagged with Brand, even though Brand doesn't exist at runtime.
|
|
5
|
+
//
|
|
6
|
+
// Explanation:
|
|
7
|
+
// - Brand extends `symbol | string` acts as a “brand” identifier.
|
|
8
|
+
// - The type uses a conditional check `infer _ extends Brand ? BaseType : never` to strip out BaseType when the branding doesn't match.
|
|
9
|
+
// - This yields a branded type system: `Brand<string, "UserId">` is not accidentally assignable to `Brand<string, "ProductId">`.
|
|
10
|
+
//
|
|
11
|
+
// Usage: Helps enforce semantic distinctions (e.g., distinguishing user IDs from product IDs) even when their runtime values are both strings.
|
|
12
|
+
//
|
|
13
|
+
// Caveat: This is purely a compile-time trick—Brand is erased in emitted JavaScript, so runtime checks must rely on other mechanisms.
|
|
14
|
+
export type Brand<
|
|
15
|
+
BaseType,
|
|
16
|
+
Brand extends symbol | string,
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
> = infer _ extends Brand ? BaseType : never;
|
package/src/core/cache.ts
CHANGED
|
@@ -26,8 +26,8 @@ import {
|
|
|
26
26
|
DataTypeValue,
|
|
27
27
|
FragmentSubscription,
|
|
28
28
|
getLink,
|
|
29
|
-
Link,
|
|
30
29
|
ROOT_ID,
|
|
30
|
+
StoreLink,
|
|
31
31
|
StoreRecord,
|
|
32
32
|
type IsographEnvironment,
|
|
33
33
|
type TypeName,
|
|
@@ -157,7 +157,7 @@ export function normalizeData(
|
|
|
157
157
|
normalizationAst: NormalizationAstNodes,
|
|
158
158
|
networkResponse: NetworkResponseObject,
|
|
159
159
|
variables: Variables,
|
|
160
|
-
root:
|
|
160
|
+
root: StoreLink,
|
|
161
161
|
): EncounteredIds {
|
|
162
162
|
const encounteredIds: EncounteredIds = new Map();
|
|
163
163
|
|
|
@@ -205,7 +205,7 @@ export function subscribeToAnyChange(
|
|
|
205
205
|
|
|
206
206
|
export function subscribeToAnyChangesToRecord(
|
|
207
207
|
environment: IsographEnvironment,
|
|
208
|
-
recordLink:
|
|
208
|
+
recordLink: StoreLink,
|
|
209
209
|
callback: () => void,
|
|
210
210
|
): () => void {
|
|
211
211
|
const subscription = {
|
|
@@ -240,7 +240,7 @@ export function subscribe<TReadFromStore extends UnknownTReadFromStore>(
|
|
|
240
240
|
|
|
241
241
|
export function onNextChangeToRecord(
|
|
242
242
|
environment: IsographEnvironment,
|
|
243
|
-
recordLink:
|
|
243
|
+
recordLink: StoreLink,
|
|
244
244
|
): Promise<void> {
|
|
245
245
|
return new Promise((resolve) => {
|
|
246
246
|
const unsubscribe = subscribeToAnyChangesToRecord(
|
|
@@ -259,11 +259,19 @@ export function onNextChangeToRecord(
|
|
|
259
259
|
//
|
|
260
260
|
// That's probably okay to ignore. We don't, however, want to prevent
|
|
261
261
|
// updating other subscriptions if one subscription had missing data.
|
|
262
|
-
function withErrorHandling<T>(
|
|
262
|
+
function withErrorHandling<T>(
|
|
263
|
+
environment: IsographEnvironment,
|
|
264
|
+
f: (t: T) => void,
|
|
265
|
+
): (t: T) => void {
|
|
263
266
|
return (t) => {
|
|
264
267
|
try {
|
|
265
268
|
return f(t);
|
|
266
|
-
} catch {
|
|
269
|
+
} catch (e) {
|
|
270
|
+
logMessage(environment, () => ({
|
|
271
|
+
kind: 'ErrorEncounteredInWithErrorHandling',
|
|
272
|
+
error: e,
|
|
273
|
+
}));
|
|
274
|
+
}
|
|
267
275
|
};
|
|
268
276
|
}
|
|
269
277
|
|
|
@@ -272,7 +280,7 @@ export function callSubscriptions(
|
|
|
272
280
|
recordsEncounteredWhenNormalizing: EncounteredIds,
|
|
273
281
|
) {
|
|
274
282
|
environment.subscriptions.forEach(
|
|
275
|
-
withErrorHandling((subscription) => {
|
|
283
|
+
withErrorHandling(environment, (subscription) => {
|
|
276
284
|
switch (subscription.kind) {
|
|
277
285
|
case 'FragmentSubscription': {
|
|
278
286
|
// TODO if there are multiple components subscribed to the same
|
|
@@ -387,7 +395,7 @@ function normalizeDataIntoRecord(
|
|
|
387
395
|
normalizationAst: NormalizationAstNodes,
|
|
388
396
|
networkResponseParentRecord: NetworkResponseObject,
|
|
389
397
|
targetParentRecord: StoreRecord,
|
|
390
|
-
targetParentRecordLink:
|
|
398
|
+
targetParentRecordLink: StoreLink,
|
|
391
399
|
variables: Variables,
|
|
392
400
|
mutableEncounteredIds: EncounteredIds,
|
|
393
401
|
): RecordHasBeenUpdated {
|
|
@@ -492,7 +500,7 @@ function normalizeLinkedField(
|
|
|
492
500
|
astNode: NormalizationLinkedField,
|
|
493
501
|
networkResponseParentRecord: NetworkResponseObject,
|
|
494
502
|
targetParentRecord: StoreRecord,
|
|
495
|
-
targetParentRecordLink:
|
|
503
|
+
targetParentRecordLink: StoreLink,
|
|
496
504
|
variables: Variables,
|
|
497
505
|
mutableEncounteredIds: EncounteredIds,
|
|
498
506
|
): RecordHasBeenUpdated {
|
|
@@ -517,7 +525,7 @@ function normalizeLinkedField(
|
|
|
517
525
|
|
|
518
526
|
if (Array.isArray(networkResponseData)) {
|
|
519
527
|
// TODO check astNode.plural or the like
|
|
520
|
-
const dataIds: (
|
|
528
|
+
const dataIds: (StoreLink | null)[] = [];
|
|
521
529
|
for (let i = 0; i < networkResponseData.length; i++) {
|
|
522
530
|
const networkResponseObject = networkResponseData[i];
|
|
523
531
|
if (networkResponseObject == null) {
|
|
@@ -588,7 +596,7 @@ function normalizeInlineFragment(
|
|
|
588
596
|
astNode: NormalizationInlineFragment,
|
|
589
597
|
networkResponseParentRecord: NetworkResponseObject,
|
|
590
598
|
targetParentRecord: StoreRecord,
|
|
591
|
-
targetParentRecordLink:
|
|
599
|
+
targetParentRecordLink: StoreLink,
|
|
592
600
|
variables: Variables,
|
|
593
601
|
mutableEncounteredIds: EncounteredIds,
|
|
594
602
|
): RecordHasBeenUpdated {
|
|
@@ -610,7 +618,7 @@ function normalizeInlineFragment(
|
|
|
610
618
|
|
|
611
619
|
function dataIdsAreTheSame(
|
|
612
620
|
existingValue: DataTypeValue,
|
|
613
|
-
newDataIds: (
|
|
621
|
+
newDataIds: (StoreLink | null)[],
|
|
614
622
|
): boolean {
|
|
615
623
|
if (Array.isArray(existingValue)) {
|
|
616
624
|
if (newDataIds.length !== existingValue.length) {
|
|
@@ -635,7 +643,7 @@ function normalizeNetworkResponseObject(
|
|
|
635
643
|
environment: IsographEnvironment,
|
|
636
644
|
astNode: NormalizationLinkedField,
|
|
637
645
|
networkResponseData: NetworkResponseObject,
|
|
638
|
-
targetParentRecordLink:
|
|
646
|
+
targetParentRecordLink: StoreLink,
|
|
639
647
|
variables: Variables,
|
|
640
648
|
index: number | null,
|
|
641
649
|
mutableEncounteredIds: EncounteredIds,
|
|
@@ -830,7 +838,7 @@ export const THIRD_SPLIT_KEY = '__';
|
|
|
830
838
|
|
|
831
839
|
// Returns a key to look up an item in the store
|
|
832
840
|
function getDataIdOfNetworkResponse(
|
|
833
|
-
parentRecordLink:
|
|
841
|
+
parentRecordLink: StoreLink,
|
|
834
842
|
dataToNormalize: NetworkResponseObject,
|
|
835
843
|
astNode: NormalizationLinkedField,
|
|
836
844
|
variables: Variables,
|
package/src/core/check.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { Variables } from './FragmentReference';
|
|
|
4
4
|
import {
|
|
5
5
|
getLink,
|
|
6
6
|
IsographEnvironment,
|
|
7
|
-
|
|
7
|
+
StoreLink,
|
|
8
8
|
StoreRecord,
|
|
9
9
|
} from './IsographEnvironment';
|
|
10
10
|
import { logMessage } from './logging';
|
|
@@ -30,14 +30,14 @@ export type CheckResult =
|
|
|
30
30
|
}
|
|
31
31
|
| {
|
|
32
32
|
kind: 'MissingData';
|
|
33
|
-
record:
|
|
33
|
+
record: StoreLink;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
export function check(
|
|
37
37
|
environment: IsographEnvironment,
|
|
38
38
|
normalizationAst: NormalizationAstNodes,
|
|
39
39
|
variables: Variables,
|
|
40
|
-
root:
|
|
40
|
+
root: StoreLink,
|
|
41
41
|
): CheckResult {
|
|
42
42
|
const recordsById = (environment.store[root.__typename] ??= {});
|
|
43
43
|
const newStoreRecord = (recordsById[root.__link] ??= {});
|
|
@@ -61,7 +61,7 @@ function checkFromRecord(
|
|
|
61
61
|
normalizationAst: NormalizationAstNodes,
|
|
62
62
|
variables: Variables,
|
|
63
63
|
record: StoreRecord,
|
|
64
|
-
recordLink:
|
|
64
|
+
recordLink: StoreLink,
|
|
65
65
|
): CheckResult {
|
|
66
66
|
normalizationAstLoop: for (const normalizationAstNode of normalizationAst) {
|
|
67
67
|
switch (normalizationAstNode.kind) {
|
|
@@ -7,14 +7,14 @@ import {
|
|
|
7
7
|
IsographEnvironment,
|
|
8
8
|
IsographStore,
|
|
9
9
|
StoreRecord,
|
|
10
|
-
type
|
|
10
|
+
type StoreLink,
|
|
11
11
|
type TypeName,
|
|
12
12
|
} from './IsographEnvironment';
|
|
13
13
|
|
|
14
14
|
export type RetainedQuery = {
|
|
15
15
|
readonly normalizationAst: NormalizationAstNodes;
|
|
16
16
|
readonly variables: {};
|
|
17
|
-
readonly root:
|
|
17
|
+
readonly root: StoreLink;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
export type DidUnretainSomeQuery = boolean;
|
|
@@ -117,7 +117,7 @@ function recordReachableIdsFromRecord(
|
|
|
117
117
|
const linkKey = getParentRecordKey(selection, variables ?? {});
|
|
118
118
|
const linkedFieldOrFields = currentRecord[linkKey];
|
|
119
119
|
|
|
120
|
-
const links:
|
|
120
|
+
const links: StoreLink[] = [];
|
|
121
121
|
if (Array.isArray(linkedFieldOrFields)) {
|
|
122
122
|
for (const maybeLink of linkedFieldOrFields) {
|
|
123
123
|
const link = assertLink(maybeLink);
|
package/src/core/logging.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
IsographEnvironment,
|
|
12
12
|
IsographStore,
|
|
13
13
|
StoreRecord,
|
|
14
|
-
type
|
|
14
|
+
type StoreLink,
|
|
15
15
|
} from './IsographEnvironment';
|
|
16
16
|
import { ReadDataResult } from './read';
|
|
17
17
|
import { Arguments } from './util';
|
|
@@ -38,7 +38,7 @@ export type LogMessage =
|
|
|
38
38
|
| {
|
|
39
39
|
kind: 'ComponentRerendered';
|
|
40
40
|
componentName: string;
|
|
41
|
-
rootLink:
|
|
41
|
+
rootLink: StoreLink;
|
|
42
42
|
}
|
|
43
43
|
| {
|
|
44
44
|
kind: 'MakeNetworkRequest';
|
|
@@ -61,7 +61,7 @@ export type LogMessage =
|
|
|
61
61
|
}
|
|
62
62
|
| {
|
|
63
63
|
kind: 'MissingFieldHandlerCalled';
|
|
64
|
-
root:
|
|
64
|
+
root: StoreLink;
|
|
65
65
|
storeRecord: StoreRecord;
|
|
66
66
|
fieldName: string;
|
|
67
67
|
arguments: Arguments | null;
|
|
@@ -71,7 +71,7 @@ export type LogMessage =
|
|
|
71
71
|
kind: 'DoneReading';
|
|
72
72
|
response: ReadDataResult<any>;
|
|
73
73
|
fieldName: string;
|
|
74
|
-
root:
|
|
74
|
+
root: StoreLink;
|
|
75
75
|
}
|
|
76
76
|
| {
|
|
77
77
|
kind: 'NonEntrypointReceived';
|
|
@@ -83,6 +83,18 @@ export type LogMessage =
|
|
|
83
83
|
}
|
|
84
84
|
| {
|
|
85
85
|
kind: 'EnvironmentCreated';
|
|
86
|
+
}
|
|
87
|
+
| {
|
|
88
|
+
kind: 'StartUpdateError';
|
|
89
|
+
error: any;
|
|
90
|
+
}
|
|
91
|
+
| {
|
|
92
|
+
kind: 'StartUpdateComplete';
|
|
93
|
+
updatedIds: EncounteredIds;
|
|
94
|
+
}
|
|
95
|
+
| {
|
|
96
|
+
kind: 'ErrorEncounteredInWithErrorHandling';
|
|
97
|
+
error: any;
|
|
86
98
|
};
|
|
87
99
|
|
|
88
100
|
export type LogFunction = (logMessage: LogMessage) => void;
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
retainQuery,
|
|
21
21
|
unretainQuery,
|
|
22
22
|
} from './garbageCollection';
|
|
23
|
-
import { IsographEnvironment,
|
|
23
|
+
import { IsographEnvironment, ROOT_ID, StoreLink } from './IsographEnvironment';
|
|
24
24
|
import { logMessage } from './logging';
|
|
25
25
|
import {
|
|
26
26
|
AnyError,
|
|
@@ -260,7 +260,7 @@ function readDataForOnComplete<
|
|
|
260
260
|
>(
|
|
261
261
|
artifact: TArtifact,
|
|
262
262
|
environment: IsographEnvironment,
|
|
263
|
-
root:
|
|
263
|
+
root: StoreLink,
|
|
264
264
|
variables: ExtractParameters<TReadFromStore>,
|
|
265
265
|
readerWithRefetchQueries:
|
|
266
266
|
| ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>
|