@isograph/react 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/core/FragmentReference.d.ts +15 -0
  2. package/dist/core/FragmentReference.js +17 -0
  3. package/dist/core/IsographEnvironment.d.ts +71 -0
  4. package/dist/core/IsographEnvironment.js +72 -0
  5. package/dist/core/PromiseWrapper.d.ts +27 -0
  6. package/dist/core/PromiseWrapper.js +58 -0
  7. package/dist/core/areEqualWithDeepComparison.d.ts +3 -0
  8. package/dist/core/areEqualWithDeepComparison.js +61 -0
  9. package/dist/core/cache.d.ts +28 -0
  10. package/dist/core/cache.js +452 -0
  11. package/dist/core/componentCache.d.ts +5 -0
  12. package/dist/core/componentCache.js +38 -0
  13. package/dist/core/entrypoint.d.ts +50 -0
  14. package/dist/core/entrypoint.js +8 -0
  15. package/dist/core/garbageCollection.d.ts +11 -0
  16. package/dist/core/garbageCollection.js +74 -0
  17. package/dist/core/makeNetworkRequest.d.ts +6 -0
  18. package/dist/core/makeNetworkRequest.js +62 -0
  19. package/dist/core/read.d.ts +12 -0
  20. package/dist/core/read.js +415 -0
  21. package/dist/core/reader.d.ts +63 -0
  22. package/dist/core/reader.js +2 -0
  23. package/dist/core/util.d.ts +17 -0
  24. package/dist/core/util.js +2 -0
  25. package/dist/index.d.ts +21 -118
  26. package/dist/index.js +50 -303
  27. package/dist/loadable-hooks/useClientSideDefer.d.ts +4 -0
  28. package/dist/loadable-hooks/useClientSideDefer.js +15 -0
  29. package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +5 -0
  30. package/dist/loadable-hooks/useImperativeExposedMutationField.js +15 -0
  31. package/dist/loadable-hooks/useImperativeLoadableField.d.ts +9 -0
  32. package/dist/loadable-hooks/useImperativeLoadableField.js +15 -0
  33. package/dist/loadable-hooks/useSkipLimitPagination.d.ts +33 -0
  34. package/dist/loadable-hooks/useSkipLimitPagination.js +118 -0
  35. package/dist/react/FragmentReader.d.ts +13 -0
  36. package/dist/react/FragmentReader.js +33 -0
  37. package/dist/react/IsographEnvironmentProvider.d.ts +10 -0
  38. package/dist/{IsographEnvironment.js → react/IsographEnvironmentProvider.js} +2 -20
  39. package/dist/react/useImperativeReference.d.ts +7 -0
  40. package/dist/react/useImperativeReference.js +36 -0
  41. package/dist/react/useLazyReference.d.ts +5 -0
  42. package/dist/react/useLazyReference.js +14 -0
  43. package/dist/react/useReadAndSubscribe.d.ts +11 -0
  44. package/dist/react/useReadAndSubscribe.js +41 -0
  45. package/dist/react/useRerenderOnChange.d.ts +3 -0
  46. package/dist/react/useRerenderOnChange.js +23 -0
  47. package/dist/react/useResult.d.ts +5 -0
  48. package/dist/react/useResult.js +36 -0
  49. package/docs/how-useLazyReference-works.md +117 -0
  50. package/package.json +12 -6
  51. package/src/core/FragmentReference.ts +37 -0
  52. package/src/core/IsographEnvironment.ts +183 -0
  53. package/src/core/PromiseWrapper.ts +86 -0
  54. package/src/core/areEqualWithDeepComparison.ts +78 -0
  55. package/src/core/cache.ts +721 -0
  56. package/src/core/componentCache.ts +61 -0
  57. package/src/core/entrypoint.ts +99 -0
  58. package/src/core/garbageCollection.ts +122 -0
  59. package/src/core/makeNetworkRequest.ts +99 -0
  60. package/src/core/read.ts +615 -0
  61. package/src/core/reader.ts +133 -0
  62. package/src/core/util.ts +23 -0
  63. package/src/index.ts +86 -0
  64. package/src/loadable-hooks/useClientSideDefer.ts +28 -0
  65. package/src/loadable-hooks/useImperativeExposedMutationField.ts +17 -0
  66. package/src/loadable-hooks/useImperativeLoadableField.ts +26 -0
  67. package/src/loadable-hooks/useSkipLimitPagination.ts +211 -0
  68. package/src/react/FragmentReader.tsx +34 -0
  69. package/src/react/IsographEnvironmentProvider.tsx +33 -0
  70. package/src/react/useImperativeReference.ts +57 -0
  71. package/src/react/useLazyReference.ts +22 -0
  72. package/src/react/useReadAndSubscribe.ts +66 -0
  73. package/src/react/useRerenderOnChange.ts +33 -0
  74. package/src/react/useResult.ts +65 -0
  75. package/src/tests/__isograph/Query/meName/entrypoint.ts +47 -0
  76. package/src/tests/__isograph/Query/meName/output_type.ts +3 -0
  77. package/src/tests/__isograph/Query/meName/param_type.ts +6 -0
  78. package/src/tests/__isograph/Query/meName/resolver_reader.ts +32 -0
  79. package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +83 -0
  80. package/src/tests/__isograph/Query/meNameSuccessor/output_type.ts +3 -0
  81. package/src/tests/__isograph/Query/meNameSuccessor/param_type.ts +11 -0
  82. package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +54 -0
  83. package/src/tests/__isograph/Query/nodeField/entrypoint.ts +46 -0
  84. package/src/tests/__isograph/Query/nodeField/output_type.ts +3 -0
  85. package/src/tests/__isograph/Query/nodeField/param_type.ts +6 -0
  86. package/src/tests/__isograph/Query/nodeField/resolver_reader.ts +37 -0
  87. package/src/tests/__isograph/iso.ts +88 -0
  88. package/src/tests/garbageCollection.test.ts +136 -0
  89. package/src/tests/isograph.config.json +7 -0
  90. package/src/tests/meNameSuccessor.ts +20 -0
  91. package/src/tests/nodeQuery.ts +17 -0
  92. package/src/tests/schema.graphql +16 -0
  93. package/src/tests/tsconfig.json +21 -0
  94. package/tsconfig.json +6 -0
  95. package/tsconfig.pkg.json +2 -1
  96. package/dist/IsographEnvironment.d.ts +0 -56
  97. package/dist/PromiseWrapper.d.ts +0 -13
  98. package/dist/PromiseWrapper.js +0 -22
  99. package/dist/cache.d.ts +0 -26
  100. package/dist/cache.js +0 -274
  101. package/dist/componentCache.d.ts +0 -6
  102. package/dist/componentCache.js +0 -31
  103. package/src/IsographEnvironment.tsx +0 -120
  104. package/src/PromiseWrapper.ts +0 -29
  105. package/src/cache.tsx +0 -484
  106. package/src/componentCache.ts +0 -44
  107. package/src/index.tsx +0 -651
@@ -0,0 +1,136 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import {
3
+ ROOT_ID,
4
+ createIsographEnvironment,
5
+ } from '../core/IsographEnvironment';
6
+ import {
7
+ garbageCollectEnvironment,
8
+ retainQuery,
9
+ } from '../core/garbageCollection';
10
+ import { iso } from './__isograph/iso';
11
+ import { nodeFieldRetainedQuery } from './nodeQuery';
12
+
13
+ const getDefaultStore = () => ({
14
+ [ROOT_ID]: {
15
+ me: { __link: '0' },
16
+ you: { __link: '1' },
17
+ node____id___0: {
18
+ __link: '0',
19
+ },
20
+ },
21
+ 0: {
22
+ __typename: 'Economist',
23
+ id: '0',
24
+ name: 'Jeremy Bentham',
25
+ successor: { __link: '1' },
26
+ },
27
+ 1: {
28
+ __typename: 'Economist',
29
+ id: '1',
30
+ name: 'John Stuart Mill',
31
+ predecessor: { __link: '0' },
32
+ successor: { __link: '2' },
33
+ },
34
+ 2: {
35
+ __typename: 'Economist',
36
+ id: '2',
37
+ name: 'Henry Sidgwick',
38
+ predecessor: { __link: '1' },
39
+ },
40
+ });
41
+
42
+ export const meNameField = iso(`
43
+ field Query.meName {
44
+ me {
45
+ name
46
+ }
47
+ }
48
+ `)(() => {});
49
+ import meNameEntrypoint from './__isograph/Query/meName/entrypoint';
50
+ import { meNameSuccessorRetainedQuery } from './meNameSuccessor';
51
+ iso(`entrypoint Query.meName`);
52
+ const meNameRetainedQuery = {
53
+ normalizationAst: meNameEntrypoint.normalizationAst,
54
+ variables: {},
55
+ };
56
+
57
+ describe('garbage collection', () => {
58
+ test('Unreferenced records should be garbage collected', () => {
59
+ const store = getDefaultStore();
60
+ const environment = createIsographEnvironment(
61
+ store,
62
+ null as any,
63
+ null as any,
64
+ );
65
+
66
+ expect(store[1]).not.toBe(undefined);
67
+
68
+ // TODO enable babel so we don't have to do this
69
+ retainQuery(environment, meNameRetainedQuery);
70
+ garbageCollectEnvironment(environment);
71
+
72
+ expect(store[1]).toBe(undefined);
73
+ });
74
+
75
+ test('Referenced records should not be garbage collected', () => {
76
+ const store = getDefaultStore();
77
+ const environment = createIsographEnvironment(
78
+ store,
79
+ null as any,
80
+ null as any,
81
+ );
82
+
83
+ expect(store[0]).not.toBe(undefined);
84
+
85
+ // TODO enable babel so we don't have to do this
86
+ retainQuery(environment, meNameRetainedQuery);
87
+ garbageCollectEnvironment(environment);
88
+
89
+ expect(store[0]).not.toBe(undefined);
90
+ });
91
+
92
+ test('Referenced records should not be garbage collected, and this should work with variables', () => {
93
+ const store = getDefaultStore();
94
+ const environment = createIsographEnvironment(
95
+ store,
96
+ null as any,
97
+ null as any,
98
+ );
99
+
100
+ expect(store[0]).not.toBe(undefined);
101
+
102
+ retainQuery(environment, nodeFieldRetainedQuery);
103
+ garbageCollectEnvironment(environment);
104
+
105
+ expect(store[0]).not.toBe(undefined);
106
+ });
107
+
108
+ test('Referenced records should not be garbage collected, and this should work through multiple levels', () => {
109
+ const store = getDefaultStore();
110
+ const environment = createIsographEnvironment(
111
+ store,
112
+ null as any,
113
+ null as any,
114
+ );
115
+
116
+ retainQuery(environment, meNameSuccessorRetainedQuery);
117
+ garbageCollectEnvironment(environment);
118
+
119
+ expect(store[0]).not.toBe(undefined);
120
+ expect(store[1]).not.toBe(undefined);
121
+ expect(store[2]).not.toBe(undefined);
122
+ });
123
+
124
+ test('ROOT_ID should not be garbage collected, even if there are no retained queries', () => {
125
+ const store = getDefaultStore();
126
+ const environment = createIsographEnvironment(
127
+ store,
128
+ null as any,
129
+ null as any,
130
+ );
131
+ garbageCollectEnvironment(environment);
132
+
133
+ expect(store[ROOT_ID]).not.toBe(undefined);
134
+ expect(store[0]).toBe(undefined);
135
+ });
136
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "project_root": ".",
3
+ "schema": "./schema.graphql",
4
+ "options": {
5
+ "on_invalid_id_type": "error"
6
+ }
7
+ }
@@ -0,0 +1,20 @@
1
+ import { iso } from './__isograph/iso';
2
+
3
+ export const meNameField = iso(`
4
+ field Query.meNameSuccessor {
5
+ me {
6
+ name
7
+ successor {
8
+ successor {
9
+ name
10
+ }
11
+ }
12
+ }
13
+ }
14
+ `)(() => {});
15
+ import meNameSuccessorEntrypoint from './__isograph/Query/meNameSuccessor/entrypoint';
16
+ iso(`entrypoint Query.meNameSuccessor`);
17
+ export const meNameSuccessorRetainedQuery = {
18
+ normalizationAst: meNameSuccessorEntrypoint.normalizationAst,
19
+ variables: {},
20
+ };
@@ -0,0 +1,17 @@
1
+ import { iso } from './__isograph/iso';
2
+
3
+ // TODO investigate why this can't be in garbageCollection.test.ts without
4
+ // typescript incorrectly thinking it is referenced in its own initializer
5
+ export const nodeField = iso(`
6
+ field Query.nodeField($id: ID!) {
7
+ node(id: $id) {
8
+ id
9
+ }
10
+ }
11
+ `)(() => {});
12
+ import nodeFieldEntrypoint from './__isograph/Query/nodeField/entrypoint';
13
+ iso(`entrypoint Query.nodeField`);
14
+ export const nodeFieldRetainedQuery = {
15
+ normalizationAst: nodeFieldEntrypoint.normalizationAst,
16
+ variables: { id: 0 },
17
+ };
@@ -0,0 +1,16 @@
1
+ type Query {
2
+ me: Economist!
3
+ you: Economist!
4
+ node(id: ID!): Node
5
+ }
6
+
7
+ type Economist implements Node {
8
+ id: ID!
9
+ name: String!
10
+ predecessor: Economist
11
+ successor: Economist
12
+ }
13
+
14
+ interface Node {
15
+ id: ID!
16
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es5",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "preserve",
15
+ "incremental": true,
16
+ "allowImportingTsExtensions": true,
17
+ "paths": {
18
+ "@isograph/react": ["../index.ts"],
19
+ },
20
+ },
21
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "./tsconfig.pkg.json",
3
+ "compilerOptions": {
4
+ "noEmit": true,
5
+ },
6
+ }
package/tsconfig.pkg.json CHANGED
@@ -7,5 +7,6 @@
7
7
  "jsx": "react",
8
8
  "lib": ["es2017", "DOM"]
9
9
  },
10
- "include": ["./**/*.ts", "./**/*.tsx"]
10
+ "include": ["./**/*.ts", "./**/*.tsx"],
11
+ "exclude": ["./src/tests/**/*"]
11
12
  }
@@ -1,56 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import * as React from 'react';
3
- import { ParentCache } from '@isograph/isograph-react-disposable-state';
4
- export declare const IsographEnvironmentContext: React.Context<IsographEnvironment | null>;
5
- type ComponentName = string;
6
- type StringifiedArgs = string;
7
- type ComponentCache = {
8
- [key: DataId]: {
9
- [key: ComponentName]: {
10
- [key: StringifiedArgs]: React.FC<any>;
11
- };
12
- };
13
- };
14
- export type Subscriptions = Set<() => void>;
15
- type SuspenseCache = {
16
- [index: string]: ParentCache<any>;
17
- };
18
- export type IsographEnvironment = {
19
- store: IsographStore;
20
- networkFunction: IsographNetworkFunction;
21
- missingFieldHandler: MissingFieldHandler | null;
22
- componentCache: ComponentCache;
23
- subscriptions: Subscriptions;
24
- suspenseCache: SuspenseCache;
25
- };
26
- export type MissingFieldHandler = (storeRecord: StoreRecord, root: DataId, fieldName: string, arguments_: {
27
- [index: string]: any;
28
- } | null, variables: {
29
- [index: string]: any;
30
- } | null) => Link | undefined;
31
- export type IsographNetworkFunction = (queryText: string, variables: object) => Promise<any>;
32
- export type Link = {
33
- __link: DataId;
34
- };
35
- export type DataTypeValue = undefined | number | boolean | string | null | Link | DataTypeValue[];
36
- export type StoreRecord = {
37
- [index: DataId | string]: DataTypeValue;
38
- id?: DataId;
39
- };
40
- export type DataId = string;
41
- export declare const ROOT_ID: DataId & '__ROOT';
42
- export type IsographStore = {
43
- [index: DataId]: StoreRecord | null;
44
- __ROOT: StoreRecord;
45
- };
46
- export type IsographEnvironmentProviderProps = {
47
- environment: IsographEnvironment;
48
- children: ReactNode;
49
- };
50
- export declare function IsographEnvironmentProvider({ environment, children, }: IsographEnvironmentProviderProps): React.JSX.Element;
51
- export declare function useIsographEnvironment(): IsographEnvironment;
52
- export declare function createIsographEnvironment(store: IsographStore, networkFunction: IsographNetworkFunction, missingFieldHandler?: MissingFieldHandler): IsographEnvironment;
53
- export declare function createIsographStore(): {
54
- __ROOT: {};
55
- };
56
- export {};
@@ -1,13 +0,0 @@
1
- declare const NOT_SET: Symbol;
2
- type NotSet = typeof NOT_SET;
3
- /**
4
- * Invariant:
5
- * Before the promise is resolved, value becomes non-null.
6
- */
7
- export type PromiseWrapper<T> = {
8
- promise: Promise<T>;
9
- value: Exclude<T, NotSet> | NotSet;
10
- };
11
- export declare function wrapPromise<T>(promise: Promise<T>): PromiseWrapper<T>;
12
- export declare function useReadPromise<T>(p: PromiseWrapper<T>): T;
13
- export {};
@@ -1,22 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useReadPromise = exports.wrapPromise = void 0;
4
- const NOT_SET = Symbol('NOT_SET');
5
- function wrapPromise(promise) {
6
- // TODO confirm suspense works if the promise is already resolved.
7
- const wrapper = { promise, value: NOT_SET };
8
- promise.then((v) => {
9
- // T is assignable to Exclude<T, Symbol> | Symbol
10
- wrapper.value = v;
11
- });
12
- return wrapper;
13
- }
14
- exports.wrapPromise = wrapPromise;
15
- function useReadPromise(p) {
16
- if (p.value !== NOT_SET) {
17
- // Safety: p.value is either NOT_SET or an actual value.
18
- return p.value;
19
- }
20
- throw p.promise;
21
- }
22
- exports.useReadPromise = useReadPromise;
package/dist/cache.d.ts DELETED
@@ -1,26 +0,0 @@
1
- import { ItemCleanupPair, ParentCache } from '@isograph/react-disposable-state';
2
- import { PromiseWrapper } from './PromiseWrapper';
3
- import { IsographEntrypoint, NormalizationLinkedField, NormalizationScalarField, ReaderLinkedField, ReaderScalarField } from './index';
4
- import { type IsographEnvironment } from './IsographEnvironment';
5
- declare global {
6
- interface Window {
7
- __LOG: boolean;
8
- }
9
- }
10
- /**
11
- * Creates a copy of the provided value, ensuring any nested objects have their
12
- * keys sorted such that equivalent values would have identical JSON.stringify
13
- * results.
14
- */
15
- export declare function stableCopy<T>(value: T): T;
16
- type IsoResolver = IsographEntrypoint<any, any, any>;
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>>;
19
- export declare function subscribe(environment: IsographEnvironment, callback: () => void): () => void;
20
- export declare function onNextChange(environment: IsographEnvironment): Promise<void>;
21
- export declare function getParentRecordKey(astNode: NormalizationLinkedField | NormalizationScalarField | ReaderLinkedField | ReaderScalarField, variables: {
22
- [index: string]: string;
23
- }): string;
24
- export declare const FIRST_SPLIT_KEY = "____";
25
- export declare const SECOND_SPLIT_KEY = "___";
26
- export {};
package/dist/cache.js DELETED
@@ -1,274 +0,0 @@
1
- "use strict";
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;
4
- const react_disposable_state_1 = require("@isograph/react-disposable-state");
5
- const PromiseWrapper_1 = require("./PromiseWrapper");
6
- const IsographEnvironment_1 = require("./IsographEnvironment");
7
- function getOrCreateCache(environment, index, factory) {
8
- if (typeof window !== 'undefined' && window.__LOG) {
9
- console.log('getting cache for', {
10
- index,
11
- cache: Object.keys(environment.suspenseCache),
12
- found: !!environment.suspenseCache[index],
13
- });
14
- }
15
- if (environment.suspenseCache[index] == null) {
16
- environment.suspenseCache[index] = new react_disposable_state_1.ParentCache(factory);
17
- }
18
- return environment.suspenseCache[index];
19
- }
20
- /**
21
- * Creates a copy of the provided value, ensuring any nested objects have their
22
- * keys sorted such that equivalent values would have identical JSON.stringify
23
- * results.
24
- */
25
- function stableCopy(value) {
26
- if (!value || typeof value !== 'object') {
27
- return value;
28
- }
29
- if (Array.isArray(value)) {
30
- // @ts-ignore
31
- return value.map(stableCopy);
32
- }
33
- const keys = Object.keys(value).sort();
34
- const stable = {};
35
- for (let i = 0; i < keys.length; i++) {
36
- // @ts-ignore
37
- stable[keys[i]] = stableCopy(value[keys[i]]);
38
- }
39
- return stable;
40
- }
41
- exports.stableCopy = stableCopy;
42
- function getOrCreateCacheForArtifact(environment, artifact, variables) {
43
- const cacheKey = artifact.queryText + JSON.stringify(stableCopy(variables));
44
- const factory = () => makeNetworkRequest(environment, artifact, variables);
45
- return getOrCreateCache(environment, cacheKey, factory);
46
- }
47
- exports.getOrCreateCacheForArtifact = getOrCreateCacheForArtifact;
48
- function makeNetworkRequest(environment, artifact, variables) {
49
- if (typeof window !== 'undefined' && window.__LOG) {
50
- console.log('make network request', artifact, variables);
51
- }
52
- const promise = environment
53
- .networkFunction(artifact.queryText, variables)
54
- .then((networkResponse) => {
55
- if (typeof window !== 'undefined' && window.__LOG) {
56
- console.log('network response', artifact);
57
- }
58
- normalizeData(environment, artifact.normalizationAst, networkResponse.data, variables, artifact.nestedRefetchQueries);
59
- return networkResponse.data;
60
- });
61
- const wrapper = (0, PromiseWrapper_1.wrapPromise)(promise);
62
- const response = [
63
- wrapper,
64
- () => {
65
- // delete from cache
66
- },
67
- ];
68
- return response;
69
- }
70
- exports.makeNetworkRequest = makeNetworkRequest;
71
- function normalizeData(environment, normalizationAst, networkResponse, variables, nestedRefetchQueries) {
72
- if (typeof window !== 'undefined' && window.__LOG) {
73
- console.log('about to normalize', normalizationAst, networkResponse, variables);
74
- }
75
- normalizeDataIntoRecord(environment, normalizationAst, networkResponse, environment.store.__ROOT, IsographEnvironment_1.ROOT_ID, variables, nestedRefetchQueries);
76
- if (typeof window !== 'undefined' && window.__LOG) {
77
- console.log('after normalization', { store: environment.store });
78
- }
79
- callSubscriptions(environment);
80
- }
81
- function subscribe(environment, callback) {
82
- environment.subscriptions.add(callback);
83
- return () => environment.subscriptions.delete(callback);
84
- }
85
- exports.subscribe = subscribe;
86
- function onNextChange(environment) {
87
- return new Promise((resolve) => {
88
- const unsubscribe = subscribe(environment, () => {
89
- unsubscribe();
90
- resolve();
91
- });
92
- });
93
- }
94
- exports.onNextChange = onNextChange;
95
- function callSubscriptions(environment) {
96
- environment.subscriptions.forEach((callback) => callback());
97
- }
98
- /**
99
- * Mutate targetParentRecord according to the normalizationAst and networkResponseParentRecord.
100
- */
101
- function normalizeDataIntoRecord(environment, normalizationAst, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries) {
102
- for (const normalizationNode of normalizationAst) {
103
- switch (normalizationNode.kind) {
104
- case 'Scalar': {
105
- normalizeScalarField(normalizationNode, networkResponseParentRecord, targetParentRecord, variables);
106
- break;
107
- }
108
- case 'Linked': {
109
- normalizeLinkedField(environment, normalizationNode, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries);
110
- break;
111
- }
112
- }
113
- }
114
- }
115
- function normalizeScalarField(astNode, networkResponseParentRecord, targetStoreRecord, variables) {
116
- const networkResponseKey = getNetworkResponseKey(astNode);
117
- const networkResponseData = networkResponseParentRecord[networkResponseKey];
118
- const parentRecordKey = getParentRecordKey(astNode, variables);
119
- if (networkResponseData == null ||
120
- isScalarOrEmptyArray(networkResponseData)) {
121
- targetStoreRecord[parentRecordKey] = networkResponseData;
122
- }
123
- else {
124
- throw new Error('Unexpected object array when normalizing scalar');
125
- }
126
- }
127
- /**
128
- * Mutate targetParentRecord with a given linked field ast node.
129
- */
130
- function normalizeLinkedField(environment, astNode, networkResponseParentRecord, targetParentRecord, targetParentRecordId, variables, nestedRefetchQueries) {
131
- const networkResponseKey = getNetworkResponseKey(astNode);
132
- const networkResponseData = networkResponseParentRecord[networkResponseKey];
133
- const parentRecordKey = getParentRecordKey(astNode, variables);
134
- if (networkResponseData == null) {
135
- targetParentRecord[parentRecordKey] = null;
136
- return;
137
- }
138
- if (isScalarButNotEmptyArray(networkResponseData)) {
139
- throw new Error('Unexpected scalar network response when normalizing a linked field');
140
- }
141
- if (Array.isArray(networkResponseData)) {
142
- // TODO check astNode.plural or the like
143
- const dataIds = [];
144
- for (let i = 0; i < networkResponseData.length; i++) {
145
- const networkResponseObject = networkResponseData[i];
146
- const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseObject, targetParentRecordId, variables, i, nestedRefetchQueries);
147
- dataIds.push({ __link: newStoreRecordId });
148
- }
149
- targetParentRecord[parentRecordKey] = dataIds;
150
- }
151
- else {
152
- const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseData, targetParentRecordId, variables, null, nestedRefetchQueries);
153
- targetParentRecord[parentRecordKey] = {
154
- __link: newStoreRecordId,
155
- };
156
- }
157
- }
158
- function normalizeNetworkResponseObject(environment, astNode, networkResponseData, targetParentRecordId, variables, index, nestedRefetchQueries) {
159
- var _a;
160
- const newStoreRecordId = getDataIdOfNetworkResponse(targetParentRecordId, networkResponseData, astNode, variables, index);
161
- const newStoreRecord = (_a = environment.store[newStoreRecordId]) !== null && _a !== void 0 ? _a : {};
162
- environment.store[newStoreRecordId] = newStoreRecord;
163
- normalizeDataIntoRecord(environment, astNode.selections, networkResponseData, newStoreRecord, newStoreRecordId, variables, nestedRefetchQueries);
164
- return newStoreRecordId;
165
- }
166
- function isScalarOrEmptyArray(data) {
167
- // N.B. empty arrays count as empty arrays of scalar fields.
168
- if (Array.isArray(data)) {
169
- // This is maybe fixed in a new version of Typescript??
170
- return data.every((x) => isScalarOrEmptyArray(x));
171
- }
172
- const isScalarValue = typeof data === 'string' ||
173
- typeof data === 'number' ||
174
- typeof data === 'boolean';
175
- return isScalarValue;
176
- }
177
- function isScalarButNotEmptyArray(data) {
178
- // N.B. empty arrays count as empty arrays of linked fields.
179
- if (Array.isArray(data)) {
180
- if (data.length === 0) {
181
- return false;
182
- }
183
- // This is maybe fixed in a new version of Typescript??
184
- return data.every((x) => isScalarOrEmptyArray(x));
185
- }
186
- const isScalarValue = typeof data === 'string' ||
187
- typeof data === 'number' ||
188
- typeof data === 'boolean';
189
- return isScalarValue;
190
- }
191
- function getParentRecordKey(astNode, variables) {
192
- let parentRecordKey = astNode.fieldName;
193
- const fieldParameters = astNode.arguments;
194
- if (fieldParameters != null) {
195
- for (const fieldParameter of fieldParameters) {
196
- parentRecordKey += getStoreKeyChunkForArgument(fieldParameter, variables);
197
- }
198
- }
199
- return parentRecordKey;
200
- }
201
- exports.getParentRecordKey = getParentRecordKey;
202
- function getStoreKeyChunkForArgumentValue(argumentValue, variables) {
203
- switch (argumentValue.kind) {
204
- case 'Literal': {
205
- return argumentValue.value;
206
- break;
207
- }
208
- case 'Variable': {
209
- return variables[argumentValue.name];
210
- break;
211
- }
212
- default: {
213
- // TODO configure eslint to allow unused vars starting with _
214
- // @ts-expect-error
215
- const _ = argumentValue;
216
- throw new Error('Unexpected case');
217
- }
218
- }
219
- }
220
- function getStoreKeyChunkForArgument(argument, variables) {
221
- const chunk = getStoreKeyChunkForArgumentValue(argument[1], variables);
222
- return `${exports.FIRST_SPLIT_KEY}${argument[0]}${exports.SECOND_SPLIT_KEY}${chunk}`;
223
- }
224
- function getNetworkResponseKey(astNode) {
225
- let networkResponseKey = astNode.fieldName;
226
- const fieldParameters = astNode.arguments;
227
- if (fieldParameters != null) {
228
- for (const fieldParameter of fieldParameters) {
229
- const [argumentName, argumentValue] = fieldParameter;
230
- let argumentValueChunk;
231
- switch (argumentValue.kind) {
232
- case 'Literal': {
233
- argumentValueChunk = 'l_' + argumentValue.value;
234
- break;
235
- }
236
- case 'Variable': {
237
- argumentValueChunk = 'v_' + argumentValue.name;
238
- break;
239
- }
240
- default: {
241
- // @ts-expect-error
242
- let _ = argumentValue;
243
- throw new Error('Unexpected case');
244
- }
245
- }
246
- networkResponseKey += `${exports.FIRST_SPLIT_KEY}${argumentName}${exports.SECOND_SPLIT_KEY}${argumentValueChunk}`;
247
- }
248
- }
249
- return networkResponseKey;
250
- }
251
- // an alias might be pullRequests____first___first____after___cursor
252
- exports.FIRST_SPLIT_KEY = '____';
253
- exports.SECOND_SPLIT_KEY = '___';
254
- // Returns a key to look up an item in the store
255
- function getDataIdOfNetworkResponse(parentRecordId, dataToNormalize, astNode, variables, index) {
256
- // Check whether the dataToNormalize has an id field. If so, that is the key.
257
- // If not, we construct an id from the parentRecordId and the field parameters.
258
- const dataId = dataToNormalize.id;
259
- if (dataId != null) {
260
- return dataId;
261
- }
262
- let storeKey = `${parentRecordId}.${astNode.fieldName}`;
263
- if (index != null) {
264
- storeKey += `.${index}`;
265
- }
266
- const fieldParameters = astNode.arguments;
267
- if (fieldParameters == null) {
268
- return storeKey;
269
- }
270
- for (const fieldParameter of fieldParameters) {
271
- storeKey += getStoreKeyChunkForArgument(fieldParameter, variables);
272
- }
273
- return storeKey;
274
- }
@@ -1,6 +0,0 @@
1
- /// <reference types="react" />
2
- import { ReaderArtifact, RefetchQueryArtifactWrapper } from './index';
3
- import { IsographEnvironment, DataId } from './IsographEnvironment';
4
- export declare function getOrCreateCachedComponent(environment: IsographEnvironment, root: DataId, componentName: string, readerArtifact: ReaderArtifact<any, any, any>, variables: {
5
- [key: string]: string;
6
- }, resolverRefetchQueries: RefetchQueryArtifactWrapper[]): import("react").FC<any>;
@@ -1,31 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getOrCreateCachedComponent = void 0;
4
- const index_1 = require("./index");
5
- const cache_1 = require("./cache");
6
- function getOrCreateCachedComponent(environment, root, componentName, readerArtifact, variables, resolverRefetchQueries) {
7
- var _a, _b, _c;
8
- const cachedComponentsById = environment.componentCache;
9
- const stringifiedArgs = JSON.stringify((0, cache_1.stableCopy)(variables));
10
- cachedComponentsById[root] = (_a = cachedComponentsById[root]) !== null && _a !== void 0 ? _a : {};
11
- const componentsByName = cachedComponentsById[root];
12
- componentsByName[componentName] = (_b = componentsByName[componentName]) !== null && _b !== void 0 ? _b : {};
13
- const byArgs = componentsByName[componentName];
14
- byArgs[stringifiedArgs] =
15
- (_c = byArgs[stringifiedArgs]) !== null && _c !== void 0 ? _c : (() => {
16
- function Component(additionalRuntimeProps) {
17
- const data = (0, index_1.readButDoNotEvaluate)(environment, {
18
- kind: 'FragmentReference',
19
- readerArtifact: readerArtifact,
20
- root,
21
- variables,
22
- nestedRefetchQueries: resolverRefetchQueries,
23
- });
24
- return readerArtifact.resolver(Object.assign({ data }, additionalRuntimeProps));
25
- }
26
- Component.displayName = `${componentName} (id: ${root}) @component`;
27
- return Component;
28
- })();
29
- return byArgs[stringifiedArgs];
30
- }
31
- exports.getOrCreateCachedComponent = getOrCreateCachedComponent;