@isograph/react 0.2.0 → 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.
Files changed (134) hide show
  1. package/dist/core/FragmentReference.d.ts +14 -4
  2. package/dist/core/FragmentReference.d.ts.map +1 -0
  3. package/dist/core/FragmentReference.js +2 -3
  4. package/dist/core/IsographEnvironment.d.ts +28 -10
  5. package/dist/core/IsographEnvironment.d.ts.map +1 -0
  6. package/dist/core/IsographEnvironment.js +15 -22
  7. package/dist/core/PromiseWrapper.d.ts +1 -0
  8. package/dist/core/PromiseWrapper.d.ts.map +1 -0
  9. package/dist/core/PromiseWrapper.js +4 -5
  10. package/dist/core/areEqualWithDeepComparison.d.ts +5 -3
  11. package/dist/core/areEqualWithDeepComparison.d.ts.map +1 -0
  12. package/dist/core/areEqualWithDeepComparison.js +73 -39
  13. package/dist/core/cache.d.ts +26 -10
  14. package/dist/core/cache.d.ts.map +1 -0
  15. package/dist/core/cache.js +160 -98
  16. package/dist/core/check.d.ts +18 -0
  17. package/dist/core/check.d.ts.map +1 -0
  18. package/dist/core/check.js +127 -0
  19. package/dist/core/componentCache.d.ts +1 -1
  20. package/dist/core/componentCache.d.ts.map +1 -0
  21. package/dist/core/componentCache.js +14 -14
  22. package/dist/core/entrypoint.d.ts +27 -8
  23. package/dist/core/entrypoint.d.ts.map +1 -0
  24. package/dist/core/entrypoint.js +1 -2
  25. package/dist/core/garbageCollection.d.ts +3 -1
  26. package/dist/core/garbageCollection.d.ts.map +1 -0
  27. package/dist/core/garbageCollection.js +48 -15
  28. package/dist/core/logging.d.ts +69 -0
  29. package/dist/core/logging.d.ts.map +1 -0
  30. package/dist/core/logging.js +19 -0
  31. package/dist/core/makeNetworkRequest.d.ts +4 -1
  32. package/dist/core/makeNetworkRequest.d.ts.map +1 -0
  33. package/dist/core/makeNetworkRequest.js +71 -15
  34. package/dist/core/read.d.ts +20 -5
  35. package/dist/core/read.d.ts.map +1 -0
  36. package/dist/core/read.js +104 -41
  37. package/dist/core/reader.d.ts +34 -10
  38. package/dist/core/reader.d.ts.map +1 -0
  39. package/dist/core/util.d.ts +2 -0
  40. package/dist/core/util.d.ts.map +1 -0
  41. package/dist/index.d.ts +10 -5
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +10 -2
  44. package/dist/loadable-hooks/useClientSideDefer.d.ts +15 -3
  45. package/dist/loadable-hooks/useClientSideDefer.d.ts.map +1 -0
  46. package/dist/loadable-hooks/useClientSideDefer.js +4 -6
  47. package/dist/loadable-hooks/useConnectionSpecPagination.d.ts +34 -0
  48. package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -0
  49. package/dist/loadable-hooks/useConnectionSpecPagination.js +160 -0
  50. package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +1 -0
  51. package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts.map +1 -0
  52. package/dist/loadable-hooks/useImperativeExposedMutationField.js +1 -2
  53. package/dist/loadable-hooks/useImperativeLoadableField.d.ts +13 -5
  54. package/dist/loadable-hooks/useImperativeLoadableField.d.ts.map +1 -0
  55. package/dist/loadable-hooks/useImperativeLoadableField.js +3 -4
  56. package/dist/loadable-hooks/useSkipLimitPagination.d.ts +18 -24
  57. package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -0
  58. package/dist/loadable-hooks/useSkipLimitPagination.js +88 -44
  59. package/dist/react/FragmentReader.d.ts +7 -4
  60. package/dist/react/FragmentReader.d.ts.map +1 -0
  61. package/dist/react/FragmentReader.js +4 -2
  62. package/dist/react/IsographEnvironmentProvider.d.ts +1 -0
  63. package/dist/react/IsographEnvironmentProvider.d.ts.map +1 -0
  64. package/dist/react/IsographEnvironmentProvider.js +3 -3
  65. package/dist/react/RenderAfterCommit__DO_NOT_USE.d.ts +10 -0
  66. package/dist/react/RenderAfterCommit__DO_NOT_USE.d.ts.map +1 -0
  67. package/dist/react/RenderAfterCommit__DO_NOT_USE.js +15 -0
  68. package/dist/react/useImperativeReference.d.ts +8 -3
  69. package/dist/react/useImperativeReference.d.ts.map +1 -0
  70. package/dist/react/useImperativeReference.js +4 -5
  71. package/dist/react/useLazyReference.d.ts +7 -2
  72. package/dist/react/useLazyReference.d.ts.map +1 -0
  73. package/dist/react/useLazyReference.js +11 -4
  74. package/dist/react/useReadAndSubscribe.d.ts +12 -3
  75. package/dist/react/useReadAndSubscribe.d.ts.map +1 -0
  76. package/dist/react/useReadAndSubscribe.js +6 -7
  77. package/dist/react/useRerenderOnChange.d.ts +6 -1
  78. package/dist/react/useRerenderOnChange.d.ts.map +1 -0
  79. package/dist/react/useRerenderOnChange.js +3 -4
  80. package/dist/react/useResult.d.ts +5 -1
  81. package/dist/react/useResult.d.ts.map +1 -0
  82. package/dist/react/useResult.js +8 -5
  83. package/{src/tests/isograph.config.json → isograph.config.json} +1 -1
  84. package/package.json +12 -8
  85. package/{src/tests/schema.graphql → schema.graphql} +1 -0
  86. package/src/core/FragmentReference.ts +17 -5
  87. package/src/core/IsographEnvironment.ts +38 -29
  88. package/src/core/areEqualWithDeepComparison.ts +76 -42
  89. package/src/core/cache.ts +237 -123
  90. package/src/core/check.ts +207 -0
  91. package/src/core/componentCache.ts +18 -17
  92. package/src/core/entrypoint.ts +15 -8
  93. package/src/core/garbageCollection.ts +71 -20
  94. package/src/core/logging.ts +116 -0
  95. package/src/core/makeNetworkRequest.ts +89 -13
  96. package/src/core/read.ts +162 -55
  97. package/src/core/reader.ts +40 -13
  98. package/src/core/util.ts +4 -0
  99. package/src/index.ts +14 -1
  100. package/src/loadable-hooks/useClientSideDefer.ts +45 -15
  101. package/src/loadable-hooks/useConnectionSpecPagination.ts +331 -0
  102. package/src/loadable-hooks/useImperativeLoadableField.ts +36 -10
  103. package/src/loadable-hooks/useSkipLimitPagination.ts +231 -90
  104. package/src/react/FragmentReader.tsx +13 -4
  105. package/src/react/RenderAfterCommit__DO_NOT_USE.tsx +17 -0
  106. package/src/react/useImperativeReference.ts +18 -7
  107. package/src/react/useLazyReference.ts +24 -4
  108. package/src/react/useReadAndSubscribe.ts +20 -5
  109. package/src/react/useRerenderOnChange.ts +6 -1
  110. package/src/react/useResult.ts +10 -2
  111. package/src/tests/__isograph/Query/meName/entrypoint.ts +7 -2
  112. package/src/tests/__isograph/Query/meName/param_type.ts +5 -2
  113. package/src/tests/__isograph/Query/meName/resolver_reader.ts +1 -0
  114. package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +9 -2
  115. package/src/tests/__isograph/Query/meNameSuccessor/param_type.ts +9 -6
  116. package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +3 -0
  117. package/src/tests/__isograph/Query/nodeField/entrypoint.ts +13 -2
  118. package/src/tests/__isograph/Query/nodeField/param_type.ts +7 -3
  119. package/src/tests/__isograph/Query/nodeField/parameters_type.ts +3 -0
  120. package/src/tests/__isograph/Query/nodeField/resolver_reader.ts +1 -0
  121. package/src/tests/__isograph/Query/subquery/entrypoint.ts +67 -0
  122. package/src/tests/__isograph/Query/subquery/output_type.ts +3 -0
  123. package/src/tests/__isograph/Query/subquery/param_type.ts +12 -0
  124. package/src/tests/__isograph/Query/subquery/parameters_type.ts +3 -0
  125. package/src/tests/__isograph/Query/subquery/resolver_reader.ts +47 -0
  126. package/src/tests/__isograph/iso.ts +22 -11
  127. package/src/tests/garbageCollection.test.ts +45 -39
  128. package/src/tests/meNameSuccessor.ts +8 -3
  129. package/src/tests/nodeQuery.ts +6 -4
  130. package/src/tests/normalizeData.test.ts +120 -0
  131. package/src/tests/tsconfig.json +3 -3
  132. package/tsconfig.json +2 -2
  133. package/tsconfig.pkg.json +6 -1
  134. package/vitest.config.ts +20 -0
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useImperativeReference = void 0;
3
+ exports.useImperativeReference = useImperativeReference;
4
4
  const react_disposable_state_1 = require("@isograph/react-disposable-state");
5
5
  const IsographEnvironmentProvider_1 = require("./IsographEnvironmentProvider");
6
6
  const IsographEnvironment_1 = require("../core/IsographEnvironment");
@@ -12,8 +12,8 @@ function useImperativeReference(entrypoint) {
12
12
  const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
13
13
  return {
14
14
  fragmentReference: state,
15
- loadFragmentReference: (variables) => {
16
- const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.makeNetworkRequest)(environment, entrypoint, variables);
15
+ loadFragmentReference: (variables, fetchOptions) => {
16
+ const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.maybeMakeNetworkRequest)(environment, entrypoint, variables, fetchOptions);
17
17
  setState([
18
18
  {
19
19
  kind: 'FragmentReference',
@@ -22,7 +22,7 @@ function useImperativeReference(entrypoint) {
22
22
  readerArtifact: entrypoint.readerWithRefetchQueries.readerArtifact,
23
23
  nestedRefetchQueries: entrypoint.readerWithRefetchQueries.nestedRefetchQueries,
24
24
  }),
25
- root: IsographEnvironment_1.ROOT_ID,
25
+ root: { __link: IsographEnvironment_1.ROOT_ID, __typename: entrypoint.concreteType },
26
26
  variables,
27
27
  networkRequest,
28
28
  },
@@ -33,4 +33,3 @@ function useImperativeReference(entrypoint) {
33
33
  },
34
34
  };
35
35
  }
36
- exports.useImperativeReference = useImperativeReference;
@@ -1,5 +1,10 @@
1
- import { FragmentReference, Variables } from '../core/FragmentReference';
1
+ import { FragmentReference, ExtractParameters } from '../core/FragmentReference';
2
2
  import { IsographEntrypoint } from '../core/entrypoint';
3
- export declare function useLazyReference<TReadFromStore extends Object, TClientFieldValue>(entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: Variables): {
3
+ import { FetchOptions } from '../core/check';
4
+ export declare function useLazyReference<TReadFromStore extends {
5
+ parameters: object;
6
+ data: object;
7
+ }, TClientFieldValue>(entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: ExtractParameters<TReadFromStore>, fetchOptions?: FetchOptions): {
4
8
  fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>;
5
9
  };
10
+ //# sourceMappingURL=useLazyReference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLazyReference.d.ts","sourceRoot":"","sources":["../../src/react/useLazyReference.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,wBAAgB,gBAAgB,CAC9B,cAAc,SAAS;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC3D,iBAAiB,EAEjB,UAAU,EAAE,kBAAkB,CAAC,cAAc,EAAE,iBAAiB,CAAC,EACjE,SAAS,EAAE,iBAAiB,CAAC,cAAc,CAAC,EAC5C,YAAY,CAAC,EAAE,YAAY,GAC1B;IACD,iBAAiB,EAAE,iBAAiB,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;CACzE,CAqBA"}
@@ -1,14 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useLazyReference = void 0;
3
+ exports.useLazyReference = useLazyReference;
4
4
  const IsographEnvironmentProvider_1 = require("./IsographEnvironmentProvider");
5
5
  const cache_1 = require("../core/cache");
6
6
  const react_disposable_state_1 = require("@isograph/react-disposable-state");
7
- function useLazyReference(entrypoint, variables) {
7
+ const logging_1 = require("../core/logging");
8
+ function useLazyReference(entrypoint, variables, fetchOptions) {
8
9
  const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
9
- const cache = (0, cache_1.getOrCreateCacheForArtifact)(environment, entrypoint, variables);
10
+ if ((entrypoint === null || entrypoint === void 0 ? void 0 : entrypoint.kind) !== 'Entrypoint') {
11
+ // TODO have a separate error logger
12
+ (0, logging_1.logMessage)(environment, {
13
+ kind: 'NonEntrypointReceived',
14
+ entrypoint,
15
+ });
16
+ }
17
+ const cache = (0, cache_1.getOrCreateCacheForArtifact)(environment, entrypoint, variables, fetchOptions);
10
18
  return {
11
19
  fragmentReference: (0, react_disposable_state_1.useLazyDisposableState)(cache).state,
12
20
  };
13
21
  }
14
- exports.useLazyReference = useLazyReference;
@@ -1,11 +1,20 @@
1
- import { FragmentReference } from '../core/FragmentReference';
1
+ import { FragmentReference, ExtractData } from '../core/FragmentReference';
2
2
  import { NetworkRequestReaderOptions, WithEncounteredRecords } from '../core/read';
3
+ import type { ReaderAst } from '../core/reader';
3
4
  /**
4
5
  * Read the data from a fragment reference and subscribe to updates.
5
6
  */
6
- export declare function useReadAndSubscribe<TReadFromStore extends Object>(fragmentReference: FragmentReference<TReadFromStore, any>, networkRequestOptions: NetworkRequestReaderOptions): TReadFromStore;
7
- export declare function useSubscribeToMultiple<TReadFromStore extends Object>(items: ReadonlyArray<{
7
+ export declare function useReadAndSubscribe<TReadFromStore extends {
8
+ parameters: object;
9
+ data: object;
10
+ }>(fragmentReference: FragmentReference<TReadFromStore, any>, networkRequestOptions: NetworkRequestReaderOptions, readerAst: ReaderAst<TReadFromStore>): ExtractData<TReadFromStore>;
11
+ export declare function useSubscribeToMultiple<TReadFromStore extends {
12
+ parameters: object;
13
+ data: object;
14
+ }>(items: ReadonlyArray<{
8
15
  records: WithEncounteredRecords<TReadFromStore>;
9
16
  callback: (updatedRecords: WithEncounteredRecords<TReadFromStore>) => void;
10
17
  fragmentReference: FragmentReference<TReadFromStore, any>;
18
+ readerAst: ReaderAst<TReadFromStore>;
11
19
  }>): void;
20
+ //# sourceMappingURL=useReadAndSubscribe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useReadAndSubscribe.d.ts","sourceRoot":"","sources":["../../src/react/useReadAndSubscribe.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EAEjB,WAAW,EACZ,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,2BAA2B,EAE3B,sBAAsB,EACvB,MAAM,cAAc,CAAC;AAItB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,SAAS;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAE3D,iBAAiB,EAAE,iBAAiB,CAAC,cAAc,EAAE,GAAG,CAAC,EACzD,qBAAqB,EAAE,2BAA2B,EAClD,SAAS,EAAE,SAAS,CAAC,cAAc,CAAC,GACnC,WAAW,CAAC,cAAc,CAAC,CAY7B;AAED,wBAAgB,sBAAsB,CACpC,cAAc,SAAS;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAE3D,KAAK,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,sBAAsB,CAAC,cAAc,CAAC,CAAC;IAChD,QAAQ,EAAE,CAAC,cAAc,EAAE,sBAAsB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAC3E,iBAAiB,EAAE,iBAAiB,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IAC1D,SAAS,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;CACtC,CAAC,QAiCH"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useSubscribeToMultiple = exports.useReadAndSubscribe = void 0;
3
+ exports.useReadAndSubscribe = useReadAndSubscribe;
4
+ exports.useSubscribeToMultiple = useSubscribeToMultiple;
4
5
  const react_1 = require("react");
5
6
  const FragmentReference_1 = require("../core/FragmentReference");
6
7
  const read_1 = require("../core/read");
@@ -10,18 +11,17 @@ const cache_1 = require("../core/cache");
10
11
  /**
11
12
  * Read the data from a fragment reference and subscribe to updates.
12
13
  */
13
- function useReadAndSubscribe(fragmentReference, networkRequestOptions) {
14
+ function useReadAndSubscribe(fragmentReference, networkRequestOptions, readerAst) {
14
15
  const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
15
16
  const [readOutDataAndRecords, setReadOutDataAndRecords] = (0, react_1.useState)(() => (0, read_1.readButDoNotEvaluate)(environment, fragmentReference, networkRequestOptions));
16
- (0, useRerenderOnChange_1.useRerenderOnChange)(readOutDataAndRecords, fragmentReference, setReadOutDataAndRecords);
17
+ (0, useRerenderOnChange_1.useRerenderOnChange)(readOutDataAndRecords, fragmentReference, setReadOutDataAndRecords, readerAst);
17
18
  return readOutDataAndRecords.item;
18
19
  }
19
- exports.useReadAndSubscribe = useReadAndSubscribe;
20
20
  function useSubscribeToMultiple(items) {
21
21
  const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
22
22
  (0, react_1.useEffect)(() => {
23
- const cleanupFns = items.map(({ records, callback, fragmentReference }) => {
24
- return (0, cache_1.subscribe)(environment, records, fragmentReference, callback);
23
+ const cleanupFns = items.map(({ records, callback, fragmentReference, readerAst }) => {
24
+ return (0, cache_1.subscribe)(environment, records, fragmentReference, callback, readerAst);
25
25
  });
26
26
  return () => {
27
27
  cleanupFns.forEach((loader) => {
@@ -38,4 +38,3 @@ function useSubscribeToMultiple(items) {
38
38
  .join('.'),
39
39
  ]);
40
40
  }
41
- exports.useSubscribeToMultiple = useSubscribeToMultiple;
@@ -1,3 +1,8 @@
1
1
  import { WithEncounteredRecords } from '../core/read';
2
2
  import { FragmentReference } from '../core/FragmentReference';
3
- export declare function useRerenderOnChange<TReadFromStore extends Object>(encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>, fragmentReference: FragmentReference<any, any>, setEncounteredDataAndRecords: (data: WithEncounteredRecords<TReadFromStore>) => void): void;
3
+ import type { ReaderAst } from '../core/reader';
4
+ export declare function useRerenderOnChange<TReadFromStore extends {
5
+ parameters: object;
6
+ data: object;
7
+ }>(encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>, fragmentReference: FragmentReference<any, any>, setEncounteredDataAndRecords: (data: WithEncounteredRecords<TReadFromStore>) => void, readerAst: ReaderAst<TReadFromStore>): void;
8
+ //# sourceMappingURL=useRerenderOnChange.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRerenderOnChange.d.ts","sourceRoot":"","sources":["../../src/react/useRerenderOnChange.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAIhD,wBAAgB,mBAAmB,CACjC,cAAc,SAAS;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAE3D,yBAAyB,EAAE,sBAAsB,CAAC,cAAc,CAAC,EACjE,iBAAiB,EAAE,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,EAC9C,4BAA4B,EAAE,CAC5B,IAAI,EAAE,sBAAsB,CAAC,cAAc,CAAC,KACzC,IAAI,EACT,SAAS,EAAE,SAAS,CAAC,cAAc,CAAC,QAoBrC"}
@@ -1,17 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useRerenderOnChange = void 0;
3
+ exports.useRerenderOnChange = useRerenderOnChange;
4
4
  const react_1 = require("react");
5
5
  const cache_1 = require("../core/cache");
6
6
  const IsographEnvironmentProvider_1 = require("./IsographEnvironmentProvider");
7
7
  // TODO add unit tests for this. Add integration tests that test
8
8
  // behavior when the encounteredRecords underneath a fragment change.
9
- function useRerenderOnChange(encounteredDataAndRecords, fragmentReference, setEncounteredDataAndRecords) {
9
+ function useRerenderOnChange(encounteredDataAndRecords, fragmentReference, setEncounteredDataAndRecords, readerAst) {
10
10
  const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
11
11
  (0, react_1.useEffect)(() => {
12
12
  return (0, cache_1.subscribe)(environment, encounteredDataAndRecords, fragmentReference, (newEncounteredDataAndRecords) => {
13
13
  setEncounteredDataAndRecords(newEncounteredDataAndRecords);
14
- });
14
+ }, readerAst);
15
15
  // Note: this is an empty array on purpose:
16
16
  // - the fragment reference is stable for the life of the component
17
17
  // - ownership of encounteredDataAndRecords is transferred into the
@@ -20,4 +20,3 @@ function useRerenderOnChange(encounteredDataAndRecords, fragmentReference, setEn
20
20
  // the dependency array
21
21
  }, []);
22
22
  }
23
- exports.useRerenderOnChange = useRerenderOnChange;
@@ -1,5 +1,9 @@
1
1
  import { FragmentReference } from '../core/FragmentReference';
2
2
  import { NetworkRequestReaderOptions } from '../core/read';
3
3
  import { PromiseWrapper } from '../core/PromiseWrapper';
4
- export declare function useResult<TReadFromStore extends Object, TClientFieldValue>(fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>, partialNetworkRequestOptions?: Partial<NetworkRequestReaderOptions> | void): TClientFieldValue;
4
+ export declare function useResult<TReadFromStore extends {
5
+ parameters: object;
6
+ data: object;
7
+ }, TClientFieldValue>(fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>, partialNetworkRequestOptions?: Partial<NetworkRequestReaderOptions> | void): TClientFieldValue;
5
8
  export declare function maybeUnwrapNetworkRequest(networkRequest: PromiseWrapper<void, any>, networkRequestOptions: NetworkRequestReaderOptions): void;
9
+ //# sourceMappingURL=useResult.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useResult.d.ts","sourceRoot":"","sources":["../../src/react/useResult.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,OAAO,EAEL,2BAA2B,EAC5B,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,SAAS,CACvB,cAAc,SAAS;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC3D,iBAAiB,EAEjB,iBAAiB,EAAE,iBAAiB,CAAC,cAAc,EAAE,iBAAiB,CAAC,EACvE,4BAA4B,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAAG,IAAI,GACzE,iBAAiB,CAqCnB;AAED,wBAAgB,yBAAyB,CACvC,cAAc,EAAE,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,EACzC,qBAAqB,EAAE,2BAA2B,QAWnD"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.maybeUnwrapNetworkRequest = exports.useResult = void 0;
3
+ exports.useResult = useResult;
4
+ exports.maybeUnwrapNetworkRequest = maybeUnwrapNetworkRequest;
4
5
  const IsographEnvironmentProvider_1 = require("../react/IsographEnvironmentProvider");
5
6
  const componentCache_1 = require("../core/componentCache");
6
7
  const useReadAndSubscribe_1 = require("./useReadAndSubscribe");
@@ -17,12 +18,15 @@ function useResult(fragmentReference, partialNetworkRequestOptions) {
17
18
  return (0, componentCache_1.getOrCreateCachedComponent)(environment, readerWithRefetchQueries.readerArtifact.componentName, fragmentReference, networkRequestOptions);
18
19
  }
19
20
  case 'EagerReaderArtifact': {
20
- const data = (0, useReadAndSubscribe_1.useReadAndSubscribe)(fragmentReference, networkRequestOptions);
21
- return readerWithRefetchQueries.readerArtifact.resolver(data);
21
+ const data = (0, useReadAndSubscribe_1.useReadAndSubscribe)(fragmentReference, networkRequestOptions, readerWithRefetchQueries.readerArtifact.readerAst);
22
+ const param = {
23
+ data: data,
24
+ parameters: fragmentReference.variables,
25
+ };
26
+ return readerWithRefetchQueries.readerArtifact.resolver(param);
22
27
  }
23
28
  }
24
29
  }
25
- exports.useResult = useResult;
26
30
  function maybeUnwrapNetworkRequest(networkRequest, networkRequestOptions) {
27
31
  const state = (0, PromiseWrapper_1.getPromiseState)(networkRequest);
28
32
  if (state.kind === 'Err' && networkRequestOptions.throwOnNetworkError) {
@@ -33,4 +37,3 @@ function maybeUnwrapNetworkRequest(networkRequest, networkRequestOptions) {
33
37
  throw state.promise;
34
38
  }
35
39
  }
36
- exports.maybeUnwrapNetworkRequest = maybeUnwrapNetworkRequest;
@@ -1,5 +1,5 @@
1
1
  {
2
- "project_root": ".",
2
+ "project_root": "./src/tests",
3
3
  "schema": "./schema.graphql",
4
4
  "options": {
5
5
  "on_invalid_id_type": "error"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isograph/react",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Use Isograph with React",
5
5
  "homepage": "https://isograph.dev",
6
6
  "main": "dist/index.js",
@@ -13,22 +13,26 @@
13
13
  "test": "vitest run",
14
14
  "test-watch": "vitest watch",
15
15
  "coverage": "vitest run --coverage",
16
- "prepack": "yarn run test && yarn run compile",
17
- "tsc": "tsc"
16
+ "prepack": "pnpm run test && pnpm run compile",
17
+ "tsc": "tsc",
18
+ "iso": "../../target/debug/isograph_cli --config ./isograph.config.json",
19
+ "iso-watch": "../../target/debug/isograph_cli --config ./isograph.config.json --watch"
18
20
  },
19
21
  "dependencies": {
20
- "@isograph/disposable-types": "0.2.0",
22
+ "@isograph/disposable-types": "*",
21
23
  "@isograph/react-disposable-state": "*",
22
24
  "@isograph/reference-counted-pointer": "*"
23
25
  },
24
26
  "peerDependencies": {
25
- "react": "18.2.0"
27
+ "react": "18.3.1"
26
28
  },
27
29
  "devDependencies": {
28
- "@types/react": "^18.0.31",
30
+ "@babel/preset-typescript": "^7.24.7",
31
+ "@types/react": "18.3.1",
29
32
  "react-test-renderer": "^18.2.0",
30
- "vitest": "^0.29.8",
31
- "typescript": "^5.0.3"
33
+ "typescript": "5.6.3",
34
+ "vite-plugin-babel": "^1.2.0",
35
+ "vite-plugin-commonjs": "^0.10.1"
32
36
  },
33
37
  "repository": {
34
38
  "type": "git",
@@ -2,6 +2,7 @@ type Query {
2
2
  me: Economist!
3
3
  you: Economist!
4
4
  node(id: ID!): Node
5
+ query: Query!
5
6
  }
6
7
 
7
8
  type Economist implements Node {
@@ -1,4 +1,4 @@
1
- import { DataId } from './IsographEnvironment';
1
+ import { type Link } from './IsographEnvironment';
2
2
  import { ReaderWithRefetchQueries } from '../core/entrypoint';
3
3
  import { PromiseWrapper } from './PromiseWrapper';
4
4
 
@@ -7,23 +7,35 @@ export type VariableValue = string | number | boolean | null | object;
7
7
 
8
8
  export type Variables = { readonly [index: string]: VariableValue };
9
9
 
10
+ export type ExtractData<T> = T extends {
11
+ data: infer D extends object;
12
+ }
13
+ ? D
14
+ : never;
15
+
16
+ export type ExtractParameters<T> = T extends {
17
+ parameters: infer P extends Variables;
18
+ }
19
+ ? P
20
+ : Variables;
21
+
10
22
  export type FragmentReference<
11
- TReadFromStore extends Object,
23
+ TReadFromStore extends { parameters: object; data: object },
12
24
  TClientFieldValue,
13
25
  > = {
14
26
  readonly kind: 'FragmentReference';
15
27
  readonly readerWithRefetchQueries: PromiseWrapper<
16
28
  ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>
17
29
  >;
18
- readonly root: DataId;
19
- readonly variables: Variables | null;
30
+ readonly root: Link;
31
+ readonly variables: ExtractParameters<TReadFromStore>;
20
32
  readonly networkRequest: PromiseWrapper<void, any>;
21
33
  };
22
34
 
23
35
  export function stableIdForFragmentReference(
24
36
  fragmentReference: FragmentReference<any, any>,
25
37
  ): string {
26
- return `${fragmentReference.root}/TODO_FRAGMENT_NAME/${serializeVariables(fragmentReference.variables ?? {})}`;
38
+ return `${fragmentReference.root.__typename}/${fragmentReference.root.__link}/TODO_FRAGMENT_NAME/${serializeVariables(fragmentReference.variables ?? {})}`;
27
39
  }
28
40
 
29
41
  function serializeVariables(variables: Variables) {
@@ -4,6 +4,8 @@ import { WithEncounteredRecords } from './read';
4
4
  import { FragmentReference, Variables } from './FragmentReference';
5
5
  import { PromiseWrapper, wrapPromise } from './PromiseWrapper';
6
6
  import { IsographEntrypoint } from './entrypoint';
7
+ import type { ReaderAst } from './reader';
8
+ import { LogFunction, WrappedLogFunction } from './logging';
7
9
 
8
10
  export type ComponentOrFieldName = string;
9
11
  export type StringifiedArgs = string;
@@ -13,7 +15,9 @@ type ComponentCache = {
13
15
  };
14
16
  };
15
17
 
16
- export type FragmentSubscription<TReadFromStore extends Object> = {
18
+ export type FragmentSubscription<
19
+ TReadFromStore extends { parameters: object; data: object },
20
+ > = {
17
21
  readonly kind: 'FragmentSubscription';
18
22
  readonly callback: (
19
23
  newEncounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>,
@@ -21,13 +25,24 @@ export type FragmentSubscription<TReadFromStore extends Object> = {
21
25
  /** The value read out from the previous call to readButDoNotEvaluate */
22
26
  readonly encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>;
23
27
  readonly fragmentReference: FragmentReference<TReadFromStore, any>;
28
+ readonly readerAst: ReaderAst<TReadFromStore>;
24
29
  };
30
+
31
+ type AnyChangesToRecordSubscription = {
32
+ readonly kind: 'AnyChangesToRecord';
33
+ readonly callback: () => void;
34
+ readonly recordLink: Link;
35
+ };
36
+
25
37
  type AnyRecordSubscription = {
26
38
  readonly kind: 'AnyRecords';
27
39
  readonly callback: () => void;
28
40
  };
29
41
 
30
- type Subscription = FragmentSubscription<Object> | AnyRecordSubscription;
42
+ type Subscription =
43
+ | FragmentSubscription<{ parameters: object; data: object }>
44
+ | AnyChangesToRecordSubscription
45
+ | AnyRecordSubscription;
31
46
  type Subscriptions = Set<Subscription>;
32
47
  // Should this be a map?
33
48
  type CacheMap<T> = { [index: string]: ParentCache<T> };
@@ -49,11 +64,12 @@ export type IsographEnvironment = {
49
64
  readonly retainedQueries: Set<RetainedQuery>;
50
65
  readonly gcBuffer: Array<RetainedQuery>;
51
66
  readonly gcBufferSize: number;
67
+ readonly loggers: Set<WrappedLogFunction>;
52
68
  };
53
69
 
54
70
  export type MissingFieldHandler = (
55
71
  storeRecord: StoreRecord,
56
- root: DataId,
72
+ root: Link,
57
73
  fieldName: string,
58
74
  arguments_: { [index: string]: any } | null,
59
75
  variables: Variables | null,
@@ -66,6 +82,7 @@ export type IsographNetworkFunction = (
66
82
 
67
83
  export type Link = {
68
84
  readonly __link: DataId;
85
+ readonly __typename: TypeName;
69
86
  };
70
87
 
71
88
  export type DataTypeValue =
@@ -89,20 +106,26 @@ export type StoreRecord = {
89
106
  readonly id?: DataId;
90
107
  };
91
108
 
109
+ export type TypeName = string;
92
110
  export type DataId = string;
93
111
 
94
112
  export const ROOT_ID: DataId & '__ROOT' = '__ROOT';
95
113
 
96
114
  export type IsographStore = {
97
- [index: DataId]: StoreRecord | null;
98
- readonly __ROOT: StoreRecord;
115
+ [index: TypeName]: {
116
+ [index: DataId]: StoreRecord | null;
117
+ } | null;
118
+ readonly Query: {
119
+ readonly __ROOT: StoreRecord;
120
+ };
99
121
  };
100
122
 
101
123
  const DEFAULT_GC_BUFFER_SIZE = 10;
102
124
  export function createIsographEnvironment(
103
125
  store: IsographStore,
104
126
  networkFunction: IsographNetworkFunction,
105
- missingFieldHandler?: MissingFieldHandler,
127
+ missingFieldHandler?: MissingFieldHandler | null,
128
+ logFunction?: LogFunction | null,
106
129
  ): IsographEnvironment {
107
130
  return {
108
131
  store,
@@ -115,34 +138,18 @@ export function createIsographEnvironment(
115
138
  retainedQueries: new Set(),
116
139
  gcBuffer: [],
117
140
  gcBufferSize: DEFAULT_GC_BUFFER_SIZE,
141
+ loggers: logFunction != null ? new Set([{ log: logFunction }]) : new Set(),
118
142
  };
119
143
  }
120
144
 
121
145
  export function createIsographStore(): IsographStore {
122
146
  return {
123
- [ROOT_ID]: {},
147
+ Query: {
148
+ [ROOT_ID]: {},
149
+ },
124
150
  };
125
151
  }
126
152
 
127
- export function defaultMissingFieldHandler(
128
- _storeRecord: StoreRecord,
129
- _root: DataId,
130
- fieldName: string,
131
- arguments_: { [index: string]: any } | null,
132
- variables: Variables | null,
133
- ): Link | undefined {
134
- if (fieldName === 'node' || fieldName === 'user') {
135
- const variable = arguments_?.['id'];
136
- const value = variables?.[variable];
137
-
138
- // TODO can we handle explicit nulls here too? Probably, after wrapping in objects
139
- if (value != null) {
140
- // @ts-expect-error
141
- return { __link: value };
142
- }
143
- }
144
- }
145
-
146
153
  export function assertLink(link: DataTypeValue): Link | null | undefined {
147
154
  if (Array.isArray(link)) {
148
155
  throw new Error('Unexpected array');
@@ -160,10 +167,12 @@ export function getLink(maybeLink: DataTypeValue): Link | null {
160
167
  if (
161
168
  maybeLink != null &&
162
169
  typeof maybeLink === 'object' &&
163
- // @ts-expect-error this is safe
164
- maybeLink.__link != null
170
+ '__link' in maybeLink &&
171
+ maybeLink.__link != null &&
172
+ '__typename' in maybeLink &&
173
+ maybeLink.__typename != null
165
174
  ) {
166
- return maybeLink as any;
175
+ return maybeLink;
167
176
  }
168
177
  return null;
169
178
  }
@@ -1,78 +1,112 @@
1
- export function areEqualWithDeepComparison(
1
+ import type { ReaderAst, ReaderLinkedField, ReaderScalarField } from './reader';
2
+ export function mergeUsingReaderAst(
3
+ field: ReaderScalarField | ReaderLinkedField,
2
4
  oldItem: unknown,
3
5
  newItem: unknown,
4
- ): boolean {
6
+ ): unknown {
5
7
  if (newItem === null) {
6
- return oldItem === null;
8
+ return oldItem === null ? oldItem : newItem;
7
9
  }
8
10
 
9
11
  if (newItem === undefined) {
10
- return oldItem === undefined;
12
+ return oldItem === undefined ? oldItem : newItem;
11
13
  }
12
14
 
13
15
  if (Array.isArray(newItem)) {
14
16
  if (!Array.isArray(oldItem)) {
15
- return false;
17
+ return newItem;
16
18
  }
17
19
 
18
- return areEqualArraysWithDeepComparison(oldItem, newItem);
20
+ return mergeArraysUsingReaderAst(field, oldItem, newItem);
19
21
  }
20
22
 
21
- if (typeof newItem === 'object') {
22
- if (typeof oldItem !== 'object') {
23
- return false;
24
- }
23
+ switch (field.kind) {
24
+ case 'Scalar':
25
+ return oldItem === newItem ? oldItem : newItem;
26
+ case 'Linked':
27
+ if (oldItem == null) {
28
+ return newItem;
29
+ }
25
30
 
26
- if (oldItem === null) {
27
- return false;
31
+ return mergeObjectsUsingReaderAst(field.selections, oldItem, newItem);
32
+ default: {
33
+ // Ensure we have covered all variants
34
+ let _: never = field;
35
+ _;
36
+ throw new Error('Unexpected case.');
28
37
  }
29
-
30
- return areEqualObjectsWithDeepComparison(oldItem, newItem);
31
38
  }
32
-
33
- return newItem === oldItem;
34
39
  }
35
40
 
36
- export function areEqualArraysWithDeepComparison(
41
+ export function mergeArraysUsingReaderAst(
42
+ field: ReaderScalarField | ReaderLinkedField,
37
43
  oldItems: ReadonlyArray<unknown>,
38
- newItems: ReadonlyArray<unknown>,
39
- ): boolean {
44
+ newItems: Array<unknown>,
45
+ ): ReadonlyArray<unknown> {
40
46
  if (newItems.length !== oldItems.length) {
41
- return false;
47
+ return newItems;
42
48
  }
43
49
 
50
+ let canRecycle = true;
44
51
  for (let i = 0; i < newItems.length; i++) {
45
- if (!areEqualWithDeepComparison(oldItems[i], newItems[i])) {
46
- return false;
52
+ const mergedItem = mergeUsingReaderAst(field, oldItems[i], newItems[i]);
53
+ if (mergedItem !== oldItems[i]) {
54
+ canRecycle = false;
55
+ } else {
56
+ newItems[i] = mergedItem;
47
57
  }
48
58
  }
49
59
 
50
- return true;
60
+ return canRecycle ? oldItems : newItems;
51
61
  }
52
62
 
53
- export function areEqualObjectsWithDeepComparison(
63
+ export function mergeObjectsUsingReaderAst(
64
+ ast: ReaderAst<object>,
54
65
  oldItemObject: object,
55
66
  newItemObject: object,
56
- ): boolean {
57
- const oldKeys = Object.keys(oldItemObject);
58
- const newKeys = Object.keys(newItemObject);
67
+ ): object {
68
+ let canRecycle = true;
69
+ for (const field of ast) {
70
+ switch (field.kind) {
71
+ case 'Scalar':
72
+ case 'Linked':
73
+ const key = field.alias ?? field.fieldName;
74
+ // @ts-expect-error
75
+ const oldValue = oldItemObject[key];
76
+ // @ts-expect-error
77
+ const newValue = newItemObject[key];
59
78
 
60
- if (oldKeys.length !== newKeys.length) {
61
- return false;
62
- }
79
+ const mergedValue = mergeUsingReaderAst(field, oldValue, newValue);
80
+ if (mergedValue !== oldValue) {
81
+ canRecycle = false;
82
+ } else {
83
+ // @ts-expect-error
84
+ newItemObject[key] = mergedValue;
85
+ }
86
+ break;
87
+ case 'Resolver': {
88
+ const key = field.alias;
89
+ // @ts-expect-error
90
+ const oldValue = oldItemObject[key];
91
+ // @ts-expect-error
92
+ const newValue = newItemObject[key];
63
93
 
64
- for (const oldKey of oldKeys) {
65
- if (!(oldKey in newItemObject)) {
66
- return false;
67
- }
68
- // @ts-expect-error
69
- const oldValue = oldItemObject[oldKey];
70
- // @ts-expect-error
71
- const newValue = newItemObject[oldKey];
72
-
73
- if (!areEqualWithDeepComparison(oldValue, newValue)) {
74
- return false;
94
+ if (oldValue !== newValue) {
95
+ canRecycle = false;
96
+ }
97
+ break;
98
+ }
99
+ case 'ImperativelyLoadedField':
100
+ case 'LoadablySelectedField':
101
+ break;
102
+ default: {
103
+ // Ensure we have covered all variants
104
+ let _: never = field;
105
+ _;
106
+ throw new Error('Unexpected case.');
107
+ }
75
108
  }
76
109
  }
77
- return true;
110
+
111
+ return canRecycle ? oldItemObject : newItemObject;
78
112
  }