@isograph/react 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/FragmentReference.d.ts +25 -0
- package/dist/core/FragmentReference.d.ts.map +1 -0
- package/dist/core/FragmentReference.js +16 -0
- package/dist/core/IsographEnvironment.d.ts +89 -0
- package/dist/core/IsographEnvironment.d.ts.map +1 -0
- package/dist/core/IsographEnvironment.js +65 -0
- package/dist/core/PromiseWrapper.d.ts +28 -0
- package/dist/core/PromiseWrapper.d.ts.map +1 -0
- package/dist/core/PromiseWrapper.js +57 -0
- package/dist/core/areEqualWithDeepComparison.d.ts +5 -0
- package/dist/core/areEqualWithDeepComparison.d.ts.map +1 -0
- package/dist/core/areEqualWithDeepComparison.js +95 -0
- package/dist/core/cache.d.ts +44 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +514 -0
- package/dist/core/check.d.ts +18 -0
- package/dist/core/check.d.ts.map +1 -0
- package/dist/core/check.js +127 -0
- package/dist/core/componentCache.d.ts +5 -0
- package/dist/core/componentCache.d.ts.map +1 -0
- package/dist/core/componentCache.js +38 -0
- package/dist/core/entrypoint.d.ts +69 -0
- package/dist/core/entrypoint.d.ts.map +1 -0
- package/dist/core/entrypoint.js +7 -0
- package/dist/core/garbageCollection.d.ts +13 -0
- package/dist/core/garbageCollection.d.ts.map +1 -0
- package/dist/core/garbageCollection.js +107 -0
- package/dist/core/logging.d.ts +69 -0
- package/dist/core/logging.d.ts.map +1 -0
- package/dist/core/logging.js +19 -0
- package/dist/core/makeNetworkRequest.d.ts +9 -0
- package/dist/core/makeNetworkRequest.d.ts.map +1 -0
- package/dist/core/makeNetworkRequest.js +118 -0
- package/dist/core/read.d.ts +27 -0
- package/dist/core/read.d.ts.map +1 -0
- package/dist/core/read.js +478 -0
- package/dist/core/reader.d.ts +87 -0
- package/dist/core/reader.d.ts.map +1 -0
- package/dist/core/reader.js +2 -0
- package/dist/core/util.d.ts +19 -0
- package/dist/core/util.d.ts.map +1 -0
- package/dist/core/util.js +2 -0
- package/dist/index.d.ts +26 -120
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -306
- package/dist/loadable-hooks/useClientSideDefer.d.ts +16 -0
- package/dist/loadable-hooks/useClientSideDefer.d.ts.map +1 -0
- package/dist/loadable-hooks/useClientSideDefer.js +13 -0
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts +34 -0
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -0
- package/dist/loadable-hooks/useConnectionSpecPagination.js +160 -0
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +6 -0
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts.map +1 -0
- package/dist/loadable-hooks/useImperativeExposedMutationField.js +14 -0
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts +17 -0
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts.map +1 -0
- package/dist/loadable-hooks/useImperativeLoadableField.js +14 -0
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts +27 -0
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -0
- package/dist/loadable-hooks/useSkipLimitPagination.js +162 -0
- package/dist/react/FragmentReader.d.ts +16 -0
- package/dist/react/FragmentReader.d.ts.map +1 -0
- package/dist/{EntrypointReader.js → react/FragmentReader.js} +7 -5
- package/dist/react/IsographEnvironmentProvider.d.ts +11 -0
- package/dist/react/IsographEnvironmentProvider.d.ts.map +1 -0
- package/dist/{IsographEnvironment.js → react/IsographEnvironmentProvider.js} +4 -22
- package/dist/react/RenderAfterCommit__DO_NOT_USE.d.ts +10 -0
- package/dist/react/RenderAfterCommit__DO_NOT_USE.d.ts.map +1 -0
- package/dist/react/RenderAfterCommit__DO_NOT_USE.js +15 -0
- package/dist/react/useImperativeReference.d.ts +12 -0
- package/dist/react/useImperativeReference.d.ts.map +1 -0
- package/dist/react/useImperativeReference.js +35 -0
- package/dist/react/useLazyReference.d.ts +10 -0
- package/dist/react/useLazyReference.d.ts.map +1 -0
- package/dist/react/useLazyReference.js +21 -0
- package/dist/react/useReadAndSubscribe.d.ts +20 -0
- package/dist/react/useReadAndSubscribe.d.ts.map +1 -0
- package/dist/react/useReadAndSubscribe.js +40 -0
- package/dist/react/useRerenderOnChange.d.ts +8 -0
- package/dist/react/useRerenderOnChange.d.ts.map +1 -0
- package/dist/react/useRerenderOnChange.js +22 -0
- package/dist/react/useResult.d.ts +9 -0
- package/dist/react/useResult.d.ts.map +1 -0
- package/dist/react/useResult.js +39 -0
- package/docs/how-useLazyReference-works.md +117 -0
- package/isograph.config.json +7 -0
- package/package.json +18 -9
- package/schema.graphql +17 -0
- package/src/core/FragmentReference.ts +49 -0
- package/src/core/IsographEnvironment.ts +192 -0
- package/src/core/PromiseWrapper.ts +86 -0
- package/src/core/areEqualWithDeepComparison.ts +112 -0
- package/src/core/cache.ts +835 -0
- package/src/core/check.ts +207 -0
- package/src/core/componentCache.ts +62 -0
- package/src/core/entrypoint.ts +106 -0
- package/src/core/garbageCollection.ts +173 -0
- package/src/core/logging.ts +116 -0
- package/src/core/makeNetworkRequest.ts +175 -0
- package/src/core/read.ts +722 -0
- package/src/core/reader.ts +160 -0
- package/src/core/util.ts +27 -0
- package/src/index.ts +99 -0
- package/src/loadable-hooks/useClientSideDefer.ts +58 -0
- package/src/loadable-hooks/useConnectionSpecPagination.ts +331 -0
- package/src/loadable-hooks/useImperativeExposedMutationField.ts +17 -0
- package/src/loadable-hooks/useImperativeLoadableField.ts +52 -0
- package/src/loadable-hooks/useSkipLimitPagination.ts +352 -0
- package/src/react/FragmentReader.tsx +43 -0
- package/src/react/IsographEnvironmentProvider.tsx +33 -0
- package/src/react/RenderAfterCommit__DO_NOT_USE.tsx +17 -0
- package/src/react/useImperativeReference.ts +68 -0
- package/src/react/useLazyReference.ts +42 -0
- package/src/react/useReadAndSubscribe.ts +81 -0
- package/src/react/useRerenderOnChange.ts +38 -0
- package/src/react/useResult.ts +73 -0
- package/src/tests/__isograph/Query/meName/entrypoint.ts +52 -0
- package/src/tests/__isograph/Query/meName/output_type.ts +3 -0
- package/src/tests/__isograph/Query/meName/param_type.ts +9 -0
- package/src/tests/__isograph/Query/meName/resolver_reader.ts +33 -0
- package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +90 -0
- package/src/tests/__isograph/Query/meNameSuccessor/output_type.ts +3 -0
- package/src/tests/__isograph/Query/meNameSuccessor/param_type.ts +14 -0
- package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +57 -0
- package/src/tests/__isograph/Query/nodeField/entrypoint.ts +57 -0
- package/src/tests/__isograph/Query/nodeField/output_type.ts +3 -0
- package/src/tests/__isograph/Query/nodeField/param_type.ts +10 -0
- package/src/tests/__isograph/Query/nodeField/parameters_type.ts +3 -0
- package/src/tests/__isograph/Query/nodeField/resolver_reader.ts +38 -0
- package/src/tests/__isograph/Query/subquery/entrypoint.ts +67 -0
- package/src/tests/__isograph/Query/subquery/output_type.ts +3 -0
- package/src/tests/__isograph/Query/subquery/param_type.ts +12 -0
- package/src/tests/__isograph/Query/subquery/parameters_type.ts +3 -0
- package/src/tests/__isograph/Query/subquery/resolver_reader.ts +47 -0
- package/src/tests/__isograph/iso.ts +99 -0
- package/src/tests/garbageCollection.test.ts +142 -0
- package/src/tests/meNameSuccessor.ts +25 -0
- package/src/tests/nodeQuery.ts +19 -0
- package/src/tests/normalizeData.test.ts +120 -0
- package/src/tests/tsconfig.json +21 -0
- package/tsconfig.json +6 -0
- package/tsconfig.pkg.json +7 -1
- package/vitest.config.ts +20 -0
- package/dist/EntrypointReader.d.ts +0 -6
- package/dist/IsographEnvironment.d.ts +0 -56
- package/dist/PromiseWrapper.d.ts +0 -13
- package/dist/PromiseWrapper.js +0 -22
- package/dist/cache.d.ts +0 -26
- package/dist/cache.js +0 -274
- package/dist/componentCache.d.ts +0 -6
- package/dist/componentCache.js +0 -31
- package/dist/useImperativeReference.d.ts +0 -8
- package/dist/useImperativeReference.js +0 -28
- package/src/EntrypointReader.tsx +0 -20
- package/src/IsographEnvironment.tsx +0 -120
- package/src/PromiseWrapper.ts +0 -29
- package/src/cache.tsx +0 -484
- package/src/componentCache.ts +0 -41
- package/src/index.tsx +0 -617
- package/src/useImperativeReference.ts +0 -58
@@ -0,0 +1,99 @@
|
|
1
|
+
import type { IsographEntrypoint } from '@isograph/react';
|
2
|
+
import { type Query__meNameSuccessor__param } from './Query/meNameSuccessor/param_type';
|
3
|
+
import { type Query__meName__param } from './Query/meName/param_type';
|
4
|
+
import { type Query__nodeField__param } from './Query/nodeField/param_type';
|
5
|
+
import { type Query__subquery__param } from './Query/subquery/param_type';
|
6
|
+
import entrypoint_Query__meNameSuccessor from '../__isograph/Query/meNameSuccessor/entrypoint';
|
7
|
+
import entrypoint_Query__meName from '../__isograph/Query/meName/entrypoint';
|
8
|
+
import entrypoint_Query__nodeField from '../__isograph/Query/nodeField/entrypoint';
|
9
|
+
import entrypoint_Query__subquery from '../__isograph/Query/subquery/entrypoint';
|
10
|
+
|
11
|
+
// This is the type given to regular client fields.
|
12
|
+
// This means that the type of the exported iso literal is exactly
|
13
|
+
// the type of the passed-in function, which takes one parameter
|
14
|
+
// of type TParam.
|
15
|
+
type IdentityWithParam<TParam extends object> = <TClientFieldReturn>(
|
16
|
+
clientField: (param: TParam) => TClientFieldReturn
|
17
|
+
) => (param: TParam) => TClientFieldReturn;
|
18
|
+
|
19
|
+
// This is the type given it to client fields with @component.
|
20
|
+
// This means that the type of the exported iso literal is exactly
|
21
|
+
// the type of the passed-in function, which takes two parameters.
|
22
|
+
// The first has type TParam, and the second has type TComponentProps.
|
23
|
+
//
|
24
|
+
// TComponentProps becomes the types of the props you must pass
|
25
|
+
// whenever the @component field is rendered.
|
26
|
+
type IdentityWithParamComponent<TParam extends object> = <
|
27
|
+
TClientFieldReturn,
|
28
|
+
TComponentProps = Record<PropertyKey, never>,
|
29
|
+
>(
|
30
|
+
clientComponentField: (data: TParam, componentProps: TComponentProps) => TClientFieldReturn
|
31
|
+
) => (data: TParam, componentProps: TComponentProps) => TClientFieldReturn;
|
32
|
+
|
33
|
+
type WhitespaceCharacter = ' ' | '\t' | '\n';
|
34
|
+
type Whitespace<In> = In extends `${WhitespaceCharacter}${infer In}`
|
35
|
+
? Whitespace<In>
|
36
|
+
: In;
|
37
|
+
|
38
|
+
// This is a recursive TypeScript type that matches strings that
|
39
|
+
// start with whitespace, followed by TString. So e.g. if we have
|
40
|
+
// ```
|
41
|
+
// export function iso<T>(
|
42
|
+
// isographLiteralText: T & MatchesWhitespaceAndString<'field Query.foo', T>
|
43
|
+
// ): Bar;
|
44
|
+
// ```
|
45
|
+
// then, when you call
|
46
|
+
// ```
|
47
|
+
// const x = iso(`
|
48
|
+
// field Query.foo ...
|
49
|
+
// `);
|
50
|
+
// ```
|
51
|
+
// then the type of `x` will be `Bar`, both in VSCode and when running
|
52
|
+
// tsc. This is how we achieve type safety — you can only use fields
|
53
|
+
// that you have explicitly selected.
|
54
|
+
type MatchesWhitespaceAndString<
|
55
|
+
TString extends string,
|
56
|
+
T
|
57
|
+
> = Whitespace<T> extends `${TString}${string}` ? T : never;
|
58
|
+
|
59
|
+
export function iso<T>(
|
60
|
+
param: T & MatchesWhitespaceAndString<'field Query.meNameSuccessor', T>
|
61
|
+
): IdentityWithParam<Query__meNameSuccessor__param>;
|
62
|
+
|
63
|
+
export function iso<T>(
|
64
|
+
param: T & MatchesWhitespaceAndString<'field Query.meName', T>
|
65
|
+
): IdentityWithParam<Query__meName__param>;
|
66
|
+
|
67
|
+
export function iso<T>(
|
68
|
+
param: T & MatchesWhitespaceAndString<'field Query.nodeField', T>
|
69
|
+
): IdentityWithParam<Query__nodeField__param>;
|
70
|
+
|
71
|
+
export function iso<T>(
|
72
|
+
param: T & MatchesWhitespaceAndString<'field Query.subquery', T>
|
73
|
+
): IdentityWithParam<Query__subquery__param>;
|
74
|
+
|
75
|
+
export function iso<T>(
|
76
|
+
param: T & MatchesWhitespaceAndString<'entrypoint Query.meNameSuccessor', T>
|
77
|
+
): typeof entrypoint_Query__meNameSuccessor;
|
78
|
+
|
79
|
+
export function iso<T>(
|
80
|
+
param: T & MatchesWhitespaceAndString<'entrypoint Query.meName', T>
|
81
|
+
): typeof entrypoint_Query__meName;
|
82
|
+
|
83
|
+
export function iso<T>(
|
84
|
+
param: T & MatchesWhitespaceAndString<'entrypoint Query.nodeField', T>
|
85
|
+
): typeof entrypoint_Query__nodeField;
|
86
|
+
|
87
|
+
export function iso<T>(
|
88
|
+
param: T & MatchesWhitespaceAndString<'entrypoint Query.subquery', T>
|
89
|
+
): typeof entrypoint_Query__subquery;
|
90
|
+
|
91
|
+
export function iso(_isographLiteralText: string):
|
92
|
+
| IdentityWithParam<any>
|
93
|
+
| IdentityWithParamComponent<any>
|
94
|
+
| IsographEntrypoint<any, any>
|
95
|
+
{
|
96
|
+
throw new Error('iso: Unexpected invocation at runtime. Either the Babel transform ' +
|
97
|
+
'was not set up, or it failed to identify this call site. Make sure it ' +
|
98
|
+
'is being used verbatim as `iso`.');
|
99
|
+
}
|
@@ -0,0 +1,142 @@
|
|
1
|
+
import { describe, test, expect } from 'vitest';
|
2
|
+
import {
|
3
|
+
ROOT_ID,
|
4
|
+
createIsographEnvironment,
|
5
|
+
type IsographStore,
|
6
|
+
} from '../core/IsographEnvironment';
|
7
|
+
import {
|
8
|
+
garbageCollectEnvironment,
|
9
|
+
retainQuery,
|
10
|
+
} from '../core/garbageCollection';
|
11
|
+
import { iso } from './__isograph/iso';
|
12
|
+
import { nodeFieldRetainedQuery } from './nodeQuery';
|
13
|
+
|
14
|
+
const getDefaultStore = (): IsographStore => ({
|
15
|
+
Query: {
|
16
|
+
[ROOT_ID]: {
|
17
|
+
me: { __link: '0', __typename: 'Economist' },
|
18
|
+
you: { __link: '1', __typename: 'Economist' },
|
19
|
+
node____id___0: {
|
20
|
+
__link: '0',
|
21
|
+
__typename: 'Economist',
|
22
|
+
},
|
23
|
+
},
|
24
|
+
},
|
25
|
+
Economist: {
|
26
|
+
0: {
|
27
|
+
__typename: 'Economist',
|
28
|
+
id: '0',
|
29
|
+
name: 'Jeremy Bentham',
|
30
|
+
successor: { __link: '1', __typename: 'Economist' },
|
31
|
+
},
|
32
|
+
1: {
|
33
|
+
__typename: 'Economist',
|
34
|
+
id: '1',
|
35
|
+
name: 'John Stuart Mill',
|
36
|
+
predecessor: { __link: '0', __typename: 'Economist' },
|
37
|
+
successor: { __link: '2', __typename: 'Economist' },
|
38
|
+
},
|
39
|
+
2: {
|
40
|
+
__typename: 'Economist',
|
41
|
+
id: '2',
|
42
|
+
name: 'Henry Sidgwick',
|
43
|
+
predecessor: { __link: '1', __typename: 'Economist' },
|
44
|
+
},
|
45
|
+
},
|
46
|
+
});
|
47
|
+
|
48
|
+
export const meNameField = iso(`
|
49
|
+
field Query.meName {
|
50
|
+
me {
|
51
|
+
name
|
52
|
+
}
|
53
|
+
}
|
54
|
+
`)(() => {});
|
55
|
+
import { meNameSuccessorRetainedQuery } from './meNameSuccessor';
|
56
|
+
const meNameEntrypoint = iso(`entrypoint Query.meName`);
|
57
|
+
const meNameRetainedQuery = {
|
58
|
+
normalizationAst: meNameEntrypoint.networkRequestInfo.normalizationAst,
|
59
|
+
variables: {},
|
60
|
+
root: { __link: ROOT_ID, __typename: 'Query' },
|
61
|
+
};
|
62
|
+
|
63
|
+
describe('garbage collection', () => {
|
64
|
+
test('Unreferenced records should be garbage collected', () => {
|
65
|
+
const store = getDefaultStore();
|
66
|
+
const environment = createIsographEnvironment(
|
67
|
+
store,
|
68
|
+
null as any,
|
69
|
+
null as any,
|
70
|
+
);
|
71
|
+
|
72
|
+
expect(store.Economist?.[1]).not.toBe(undefined);
|
73
|
+
|
74
|
+
// TODO enable babel so we don't have to do this
|
75
|
+
retainQuery(environment, meNameRetainedQuery);
|
76
|
+
garbageCollectEnvironment(environment);
|
77
|
+
|
78
|
+
expect(store.Economist?.[1]).toBe(undefined);
|
79
|
+
});
|
80
|
+
|
81
|
+
test('Referenced records should not be garbage collected', () => {
|
82
|
+
const store = getDefaultStore();
|
83
|
+
const environment = createIsographEnvironment(
|
84
|
+
store,
|
85
|
+
null as any,
|
86
|
+
null as any,
|
87
|
+
);
|
88
|
+
|
89
|
+
expect(store.Economist?.[0]).not.toBe(undefined);
|
90
|
+
|
91
|
+
// TODO enable babel so we don't have to do this
|
92
|
+
retainQuery(environment, meNameRetainedQuery);
|
93
|
+
garbageCollectEnvironment(environment);
|
94
|
+
|
95
|
+
expect(store.Economist?.[0]).not.toBe(undefined);
|
96
|
+
});
|
97
|
+
|
98
|
+
test('Referenced records should not be garbage collected, and this should work with variables', () => {
|
99
|
+
const store = getDefaultStore();
|
100
|
+
const environment = createIsographEnvironment(
|
101
|
+
store,
|
102
|
+
null as any,
|
103
|
+
null as any,
|
104
|
+
);
|
105
|
+
|
106
|
+
expect(store.Economist?.[0]).not.toBe(undefined);
|
107
|
+
|
108
|
+
retainQuery(environment, nodeFieldRetainedQuery);
|
109
|
+
garbageCollectEnvironment(environment);
|
110
|
+
|
111
|
+
expect(store.Economist?.[0]).not.toBe(undefined);
|
112
|
+
});
|
113
|
+
|
114
|
+
test('Referenced records should not be garbage collected, and this should work through multiple levels', () => {
|
115
|
+
const store = getDefaultStore();
|
116
|
+
const environment = createIsographEnvironment(
|
117
|
+
store,
|
118
|
+
null as any,
|
119
|
+
null as any,
|
120
|
+
);
|
121
|
+
|
122
|
+
retainQuery(environment, meNameSuccessorRetainedQuery);
|
123
|
+
garbageCollectEnvironment(environment);
|
124
|
+
|
125
|
+
expect(store.Economist?.[0]).not.toBe(undefined);
|
126
|
+
expect(store.Economist?.[1]).not.toBe(undefined);
|
127
|
+
expect(store.Economist?.[2]).not.toBe(undefined);
|
128
|
+
});
|
129
|
+
|
130
|
+
test('ROOT_ID should be garbage collected, if there are no retained queries', () => {
|
131
|
+
const store = getDefaultStore();
|
132
|
+
const environment = createIsographEnvironment(
|
133
|
+
store,
|
134
|
+
null as any,
|
135
|
+
null as any,
|
136
|
+
);
|
137
|
+
garbageCollectEnvironment(environment);
|
138
|
+
|
139
|
+
expect(store.Query?.[ROOT_ID]).toBe(undefined);
|
140
|
+
expect(store.Economist?.[0]).toBe(undefined);
|
141
|
+
});
|
142
|
+
});
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { ROOT_ID } from '../core/IsographEnvironment';
|
2
|
+
import { iso } from './__isograph/iso';
|
3
|
+
|
4
|
+
export const meNameField = iso(`
|
5
|
+
field Query.meNameSuccessor {
|
6
|
+
me {
|
7
|
+
name
|
8
|
+
successor {
|
9
|
+
successor {
|
10
|
+
name
|
11
|
+
}
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
`)(() => {});
|
16
|
+
const meNameSuccessorEntrypoint = iso(`entrypoint Query.meNameSuccessor`);
|
17
|
+
export const meNameSuccessorRetainedQuery = {
|
18
|
+
normalizationAst:
|
19
|
+
meNameSuccessorEntrypoint.networkRequestInfo.normalizationAst,
|
20
|
+
variables: {},
|
21
|
+
root: {
|
22
|
+
__link: ROOT_ID,
|
23
|
+
__typename: 'Query',
|
24
|
+
},
|
25
|
+
};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { RetainedQuery } from '../core/garbageCollection';
|
2
|
+
import { ROOT_ID } from '../core/IsographEnvironment';
|
3
|
+
import { iso } from './__isograph/iso';
|
4
|
+
|
5
|
+
// TODO investigate why this can't be in garbageCollection.test.ts without
|
6
|
+
// typescript incorrectly thinking it is referenced in its own initializer
|
7
|
+
export const nodeField = iso(`
|
8
|
+
field Query.nodeField($id: ID!) {
|
9
|
+
node(id: $id) {
|
10
|
+
id
|
11
|
+
}
|
12
|
+
}
|
13
|
+
`)(() => {});
|
14
|
+
const nodeFieldEntrypoint = iso(`entrypoint Query.nodeField`);
|
15
|
+
export const nodeFieldRetainedQuery: RetainedQuery = {
|
16
|
+
normalizationAst: nodeFieldEntrypoint.networkRequestInfo.normalizationAst,
|
17
|
+
variables: { id: 0 },
|
18
|
+
root: { __link: ROOT_ID, __typename: 'Query' },
|
19
|
+
};
|
@@ -0,0 +1,120 @@
|
|
1
|
+
import { describe, expect, test, vi } from 'vitest';
|
2
|
+
import { getOrCreateCacheForArtifact, normalizeData } from '../core/cache';
|
3
|
+
import {
|
4
|
+
createIsographEnvironment,
|
5
|
+
createIsographStore,
|
6
|
+
ROOT_ID,
|
7
|
+
type IsographStore,
|
8
|
+
} from '../core/IsographEnvironment';
|
9
|
+
import {
|
10
|
+
readButDoNotEvaluate,
|
11
|
+
type WithEncounteredRecords,
|
12
|
+
} from '../core/read';
|
13
|
+
import { iso } from './__isograph/iso';
|
14
|
+
import type { Query__subquery__param } from './__isograph/Query/subquery/param_type';
|
15
|
+
|
16
|
+
export const subquery = iso(`
|
17
|
+
field Query.subquery($id: ID!) {
|
18
|
+
query {
|
19
|
+
node(id: $id) {
|
20
|
+
id
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
`)(() => {});
|
25
|
+
|
26
|
+
const entrypoint = iso(`entrypoint Query.subquery`);
|
27
|
+
|
28
|
+
describe('normalizeData', () => {
|
29
|
+
test('nested Query should be normalized', () => {
|
30
|
+
const store = createIsographStore();
|
31
|
+
const networkFunction = vi
|
32
|
+
.fn()
|
33
|
+
.mockRejectedValue(new Error('Fetch failed'));
|
34
|
+
const environment = createIsographEnvironment(store, networkFunction);
|
35
|
+
|
36
|
+
normalizeData(
|
37
|
+
environment,
|
38
|
+
entrypoint.networkRequestInfo.normalizationAst,
|
39
|
+
{
|
40
|
+
query: { node____id___v_id: { __typename: 'Economist', id: '1' } },
|
41
|
+
},
|
42
|
+
{ id: '1' },
|
43
|
+
entrypoint.readerWithRefetchQueries.nestedRefetchQueries,
|
44
|
+
{ __link: ROOT_ID, __typename: entrypoint.concreteType },
|
45
|
+
);
|
46
|
+
|
47
|
+
expect(store).toStrictEqual({
|
48
|
+
Economist: {
|
49
|
+
'1': {
|
50
|
+
__typename: 'Economist',
|
51
|
+
id: '1',
|
52
|
+
},
|
53
|
+
},
|
54
|
+
Query: {
|
55
|
+
[ROOT_ID]: {
|
56
|
+
node____id___1: {
|
57
|
+
__typename: 'Economist',
|
58
|
+
__link: '1',
|
59
|
+
},
|
60
|
+
query: {
|
61
|
+
__link: ROOT_ID,
|
62
|
+
__typename: 'Query',
|
63
|
+
},
|
64
|
+
},
|
65
|
+
},
|
66
|
+
} satisfies IsographStore);
|
67
|
+
});
|
68
|
+
});
|
69
|
+
|
70
|
+
describe('readData', () => {
|
71
|
+
test('nested Query should be read', () => {
|
72
|
+
const store: IsographStore = {
|
73
|
+
Economist: {
|
74
|
+
'1': {
|
75
|
+
__typename: 'Economist',
|
76
|
+
id: '1',
|
77
|
+
},
|
78
|
+
},
|
79
|
+
Query: {
|
80
|
+
[ROOT_ID]: {
|
81
|
+
node____id___1: {
|
82
|
+
__typename: 'Economist',
|
83
|
+
__link: '1',
|
84
|
+
},
|
85
|
+
query: {
|
86
|
+
__link: ROOT_ID,
|
87
|
+
__typename: 'Query',
|
88
|
+
},
|
89
|
+
},
|
90
|
+
},
|
91
|
+
};
|
92
|
+
const networkFunction = vi
|
93
|
+
.fn()
|
94
|
+
.mockRejectedValue(new Error('Fetch failed'));
|
95
|
+
const environment = createIsographEnvironment(store, networkFunction);
|
96
|
+
const [_cacheItem, item, _disposeOfTemporaryRetain] =
|
97
|
+
getOrCreateCacheForArtifact(environment, entrypoint, {
|
98
|
+
id: '1',
|
99
|
+
}).getOrPopulateAndTemporaryRetain();
|
100
|
+
|
101
|
+
const data = readButDoNotEvaluate(environment, item, {
|
102
|
+
suspendIfInFlight: true,
|
103
|
+
throwOnNetworkError: false,
|
104
|
+
});
|
105
|
+
|
106
|
+
expect(data).toStrictEqual({
|
107
|
+
encounteredRecords: new Map([
|
108
|
+
['Economist', new Set(['1'])],
|
109
|
+
['Query', new Set([ROOT_ID])],
|
110
|
+
]),
|
111
|
+
item: {
|
112
|
+
query: {
|
113
|
+
node: {
|
114
|
+
id: '1',
|
115
|
+
},
|
116
|
+
},
|
117
|
+
},
|
118
|
+
} satisfies WithEncounteredRecords<Query__subquery__param>);
|
119
|
+
});
|
120
|
+
});
|
@@ -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
package/tsconfig.pkg.json
CHANGED
package/vitest.config.ts
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
import babel from 'vite-plugin-babel';
|
2
|
+
import commonjs from 'vite-plugin-commonjs';
|
3
|
+
import { defineProject } from 'vitest/config';
|
4
|
+
|
5
|
+
export default defineProject({
|
6
|
+
plugins: [
|
7
|
+
babel({
|
8
|
+
filter: /\.[jt]sx?$/,
|
9
|
+
babelConfig: {
|
10
|
+
presets: ['@babel/preset-typescript'],
|
11
|
+
plugins: [require('../isograph-babel-plugin/BabelPluginIsograph')],
|
12
|
+
},
|
13
|
+
}),
|
14
|
+
commonjs({
|
15
|
+
advanced: {
|
16
|
+
importRules: 'merge',
|
17
|
+
},
|
18
|
+
}),
|
19
|
+
],
|
20
|
+
});
|
@@ -1,6 +0,0 @@
|
|
1
|
-
import * as React from 'react';
|
2
|
-
import { ExtractReadFromStore, IsographEntrypoint, type FragmentReference } from './index';
|
3
|
-
export declare function EntrypointReader<TEntrypoint extends IsographEntrypoint<any, React.FC<any>>>(props: {
|
4
|
-
queryReference: FragmentReference<ExtractReadFromStore<TEntrypoint>, React.FC<any>>;
|
5
|
-
additionalProps?: any | void;
|
6
|
-
}): ReturnType<React.FC<any>>;
|
@@ -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 {};
|
package/dist/PromiseWrapper.d.ts
DELETED
@@ -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 {};
|
package/dist/PromiseWrapper.js
DELETED
@@ -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>;
|
17
|
-
export declare function getOrCreateCacheForArtifact<T>(environment: IsographEnvironment, artifact: IsographEntrypoint<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 {};
|