synstate 4.1.0 → 5.0.1

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 (73) hide show
  1. package/README.md +58 -1
  2. package/dist/core/class/child-observable-class.d.mts +30 -14
  3. package/dist/core/class/child-observable-class.d.mts.map +1 -1
  4. package/dist/core/class/child-observable-class.mjs +39 -25
  5. package/dist/core/class/child-observable-class.mjs.map +1 -1
  6. package/dist/core/class/create-child-observable.d.mts +8 -5
  7. package/dist/core/class/create-child-observable.d.mts.map +1 -1
  8. package/dist/core/class/create-child-observable.mjs.map +1 -1
  9. package/dist/core/class/manager-observable-class.d.mts +4 -15
  10. package/dist/core/class/manager-observable-class.d.mts.map +1 -1
  11. package/dist/core/class/manager-observable-class.mjs +5 -91
  12. package/dist/core/class/manager-observable-class.mjs.map +1 -1
  13. package/dist/core/class/observable-base-class.d.mts +9 -2
  14. package/dist/core/class/observable-base-class.d.mts.map +1 -1
  15. package/dist/core/class/observable-base-class.mjs +17 -0
  16. package/dist/core/class/observable-base-class.mjs.map +1 -1
  17. package/dist/core/class/observable-node.d.mts +4 -8
  18. package/dist/core/class/observable-node.d.mts.map +1 -1
  19. package/dist/core/class/observable-node.mjs.map +1 -1
  20. package/dist/core/class/propagation-state.d.mts +26 -0
  21. package/dist/core/class/propagation-state.d.mts.map +1 -1
  22. package/dist/core/class/propagation-state.mjs +190 -0
  23. package/dist/core/class/propagation-state.mjs.map +1 -1
  24. package/dist/core/operators/index.d.mts +1 -0
  25. package/dist/core/operators/index.d.mts.map +1 -1
  26. package/dist/core/operators/index.mjs +1 -0
  27. package/dist/core/operators/index.mjs.map +1 -1
  28. package/dist/core/operators/keep-equal-parts.d.mts +85 -0
  29. package/dist/core/operators/keep-equal-parts.d.mts.map +1 -0
  30. package/dist/core/operators/keep-equal-parts.mjs +129 -0
  31. package/dist/core/operators/keep-equal-parts.mjs.map +1 -0
  32. package/dist/core/operators/merge-map.mjs +1 -3
  33. package/dist/core/operators/merge-map.mjs.map +1 -1
  34. package/dist/core/operators/switch-map.mjs +1 -3
  35. package/dist/core/operators/switch-map.mjs.map +1 -1
  36. package/dist/core/types/id.d.mts +6 -2
  37. package/dist/core/types/id.d.mts.map +1 -1
  38. package/dist/core/types/observable-family.d.mts +1 -0
  39. package/dist/core/types/observable-family.d.mts.map +1 -1
  40. package/dist/core/utils/id-maker.d.mts +0 -8
  41. package/dist/core/utils/id-maker.d.mts.map +1 -1
  42. package/dist/core/utils/id-maker.mjs +1 -11
  43. package/dist/core/utils/id-maker.mjs.map +1 -1
  44. package/dist/utils/create-reducer.d.mts +30 -1
  45. package/dist/utils/create-reducer.d.mts.map +1 -1
  46. package/dist/utils/create-reducer.mjs +8 -1
  47. package/dist/utils/create-reducer.mjs.map +1 -1
  48. package/dist/utils/create-state.d.mts +53 -1
  49. package/dist/utils/create-state.d.mts.map +1 -1
  50. package/dist/utils/create-state.mjs +52 -0
  51. package/dist/utils/create-state.mjs.map +1 -1
  52. package/package.json +14 -14
  53. package/src/core/class/child-observable-class.mts +60 -55
  54. package/src/core/class/create-child-observable.mts +8 -5
  55. package/src/core/class/manager-observable-class.mts +15 -134
  56. package/src/core/class/observable-base-class.mts +23 -2
  57. package/src/core/class/observable-node.mts +5 -11
  58. package/src/core/class/propagation-order.test.mts +107 -0
  59. package/src/core/class/propagation-state.mts +262 -0
  60. package/src/core/class/remove-completed.test.mts +2 -2
  61. package/src/core/class/update-loop.test.mts +104 -0
  62. package/src/core/operators/flat-map-sync-inner.test.mts +90 -0
  63. package/src/core/operators/index.mts +1 -0
  64. package/src/core/operators/keep-equal-parts.mts +167 -0
  65. package/src/core/operators/keep-equal-parts.test.mts +132 -0
  66. package/src/core/operators/merge-map.mts +1 -3
  67. package/src/core/operators/switch-map.mts +1 -3
  68. package/src/core/types/id.mts +6 -2
  69. package/src/core/types/observable-family.mts +5 -0
  70. package/src/core/utils/id-maker.mts +1 -12
  71. package/src/utils/create-reducer.mts +42 -2
  72. package/src/utils/create-state.mts +53 -1
  73. package/src/utils/create-state.test.mts +88 -0
@@ -140,9 +140,7 @@ class SwitchMapObservableClass extends AsyncChildObservableClass {
140
140
  const innerScope = createScope(this.#ownerScope);
141
141
  this.#mut_innerScope = innerScope;
142
142
  const observable = innerScope.run(() => this.#mapToObservable(sn.value));
143
- this.#mut_subscription = observable.subscribe((curr) => {
144
- this.startUpdate(curr);
145
- });
143
+ this.#mut_subscription = this.subscribeInner(observable, updateToken);
146
144
  }
147
145
  teardown() {
148
146
  this.#releaseInner();
@@ -1 +1 @@
1
- {"version":3,"file":"switch-map.mjs","sourceRoot":"","sources":["../../../src/core/operators/switch-map.mts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,6EAA6E;AAC7E,yCAAyC;AACzC,2CAA2C;AAC3C,gDAAgD;AAChD,0DAA0D;AAC1D,kEAAkE;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAUlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8FG;AACH,MAAM,CAAC,MAAM,SAAS,GACpB,CACE,eAA2C,EACX,EAAE,CACpC,CAAC,gBAAgB,EAAE,EAAE,CACnB,IAAI,wBAAwB,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;AAEpE,MAAM,wBACJ,SAAQ,yBAA0C;IAGzC,gBAAgB,CAA6B;IAEtD;;;;OAIG;IACM,WAAW,CAAoB;IAExC,eAAe,CAAoB;IACnC,iBAAiB,CAA2B;IAE5C,YACE,gBAA+B,EAC/B,eAA2C;QAE3C,KAAK,CAAC;YACJ,OAAO,EAAE,CAAC,gBAAgB,CAAC;YAC3B,YAAY,EAAE,QAAQ,CAAC,IAAI;SAC5B,CAAC,CAAC;QAEH,IAAI,CAAC,gBAAgB,GAAG,eAAe,CAAC;QAExC,IAAI,CAAC,WAAW,GAAG,eAAe,EAAE,CAAC;QAErC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;QAEjC,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC;QAEnC,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAED,0EAA0E;IAC1E,aAAa;QACX,IAAI,CAAC,iBAAiB,EAAE,WAAW,EAAE,CAAC;QAEtC,IAAI,CAAC,eAAe,EAAE,OAAO,EAAE,CAAC;IAClC,CAAC;IAEQ,SAAS,CAAC,WAAwB;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAE5B,MAAM,EAAE,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QAE7B,IAAI,GAAG,CAAC,WAAW,KAAK,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3D,OAAO,CAAC,cAAc;QACxB,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAEjD,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC;QAElC,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAEzE,IAAI,CAAC,iBAAiB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;YACrD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAEkB,QAAQ;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;CACF"}
1
+ {"version":3,"file":"switch-map.mjs","sourceRoot":"","sources":["../../../src/core/operators/switch-map.mts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,6EAA6E;AAC7E,yCAAyC;AACzC,2CAA2C;AAC3C,gDAAgD;AAChD,0DAA0D;AAC1D,kEAAkE;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAUlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8FG;AACH,MAAM,CAAC,MAAM,SAAS,GACpB,CACE,eAA2C,EACX,EAAE,CACpC,CAAC,gBAAgB,EAAE,EAAE,CACnB,IAAI,wBAAwB,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;AAEpE,MAAM,wBACJ,SAAQ,yBAA0C;IAGzC,gBAAgB,CAA6B;IAEtD;;;;OAIG;IACM,WAAW,CAAoB;IAExC,eAAe,CAAoB;IACnC,iBAAiB,CAA2B;IAE5C,YACE,gBAA+B,EAC/B,eAA2C;QAE3C,KAAK,CAAC;YACJ,OAAO,EAAE,CAAC,gBAAgB,CAAC;YAC3B,YAAY,EAAE,QAAQ,CAAC,IAAI;SAC5B,CAAC,CAAC;QAEH,IAAI,CAAC,gBAAgB,GAAG,eAAe,CAAC;QAExC,IAAI,CAAC,WAAW,GAAG,eAAe,EAAE,CAAC;QAErC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;QAEjC,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC;QAEnC,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAED,0EAA0E;IAC1E,aAAa;QACX,IAAI,CAAC,iBAAiB,EAAE,WAAW,EAAE,CAAC;QAEtC,IAAI,CAAC,eAAe,EAAE,OAAO,EAAE,CAAC;IAClC,CAAC;IAEQ,SAAS,CAAC,WAAwB;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAE5B,MAAM,EAAE,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QAE7B,IAAI,GAAG,CAAC,WAAW,KAAK,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3D,OAAO,CAAC,cAAc;QACxB,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAEjD,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC;QAElC,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAEzE,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACxE,CAAC;IAEkB,QAAQ;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;CACF"}
@@ -1,3 +1,7 @@
1
- import type { Brand } from 'ts-type-forge';
2
- export type UpdateToken = Brand<symbol, 'update-token'>;
1
+ import type { Brand, UnknownRecord } from 'ts-type-forge';
2
+ /**
3
+ * Identifies one update. Opaque: an object issued per update, which is also
4
+ * that update's queue.
5
+ */
6
+ export type UpdateToken = Brand<UnknownRecord, 'update-token'>;
3
7
  //# sourceMappingURL=id.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"id.d.mts","sourceRoot":"","sources":["../../../src/core/types/id.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C,MAAM,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC"}
1
+ {"version":3,"file":"id.d.mts","sourceRoot":"","sources":["../../../src/core/types/id.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE1D;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,KAAK,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC"}
@@ -59,6 +59,7 @@ export type SkipUntilOperatorObservable<A> = SyncChildObservable<A, readonly [A]
59
59
  export type WithCurrentValueFromOperatorObservable<A, B> = SyncChildObservable<readonly [A, B], readonly [A]>;
60
60
  export type WithBufferedFromOperatorObservable<A, B> = SyncChildObservable<readonly [A, readonly B[]], readonly [A]>;
61
61
  export type FilterOperatorObservable<A> = SyncChildObservable<A, readonly [A]>;
62
+ export type KeepEqualPartsOperatorObservable<A> = SyncChildObservable<A, readonly [A]>;
62
63
  export type SkipIfNoChangeOperatorObservable<A> = SyncChildObservable<A, readonly [A]>;
63
64
  export type ThrottleOperatorObservable<A> = SyncChildObservable<A, readonly [A]>;
64
65
  export type AuditOperatorObservable<A> = AsyncChildObservable<A, readonly [A]>;
@@ -1 +1 @@
1
- {"version":3,"file":"observable-family.d.mts","sourceRoot":"","sources":["../../../src/core/types/observable-family.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"observable-family.d.mts","sourceRoot":"","sources":["../../../src/core/types/observable-family.mts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACT,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,8BAA8B,EAC9B,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,MAAM,EACP,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAIvD,MAAM,MAAM,2BAA2B,CAAC,CAAC,IAAI,QAAQ,CAAC;IACpD;;;OAGG;IACH,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;CACvB,CAAC,GACA,yBAAyB,CAAC,CAAC,CAAC,CAAC;AAE/B,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,QAAQ,CAAC;IACzC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CAC1B,CAAC,GACA,cAAc,CAAC,CAAC,CAAC,CAAC;AAEpB,MAAM,MAAM,qBAAqB,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,IAAI,cAAc,CAChE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,IAAI,cAAc,CACrE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC,GACA,cAAc,CAAC,QAAQ,CAAC,CAAC;AAE3B,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC,GACA,cAAc,CAAC,CAAC,CAAC,CAAC;AAIpB,MAAM,MAAM,kCAAkC,CAC5C,CAAC,EACD,CAAC,GAAG,CAAC,IACH,8BAA8B,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAExD,MAAM,MAAM,sBAAsB,CAAC,CAAC,EAAE,CAAC,IAAI,8BAA8B,CACvE,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AASF,kBAAU,iBAAiB,CAAC;IAC1B,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,mBAAmB,GAAG,CAAC,GAAG,KAAK,CAAC;IAEzD,MAAM,MAAM,gBAAgB,CAAC,EAAE,SAAS,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IACxE,EAAE,SAAS,aAAa,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC;IAE1E,KAAK,aAAa,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,SAAS;QACpD,qBAAqB,CAAC,OAAO,CAAC;KAC/B,GACG,IAAI,GACJ,KAAK,CAAC;IAEV,wDAAwD;IACxD,KAAK,YAAY,CAAC,CAAC,SAAS,OAAO,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,SAAS,CAAC,IAAI,CAAC,GACvE,IAAI,GACJ,SAAS,CAAC,CAAC,CAAC,SAAS,SAAS,CAAC,KAAK,CAAC,GACnC,KAAK,GACL,IAAI,CAAC;IAEX,KAAK,mBAAmB,CAAC,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,IAErD,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC;IAE1D,MAAM,MAAM,eAAe,CAAC,EAAE,SAAS,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IACvE,mBAAmB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAElC,KAAK,gCAAgC,CAAC,CAAC,SAAS,mBAAmB,IACjE,8BAA8B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEvC,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,mBAAmB,IAC7D,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5B,MAAM,MAAM,4BAA4B,CACtC,EAAE,SAAS,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAE7C,gBAAgB,CAAC,EAAE,CAAC,SAAS,IAAI,GAC7B,gCAAgC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAClD,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAExC,KAAK,4BAA4B,CAAC,CAAC,SAAS,mBAAmB,IAC7D,8BAA8B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEvC,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,mBAAmB,IACzD,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5B,MAAM,MAAM,wBAAwB,CAClC,EAAE,SAAS,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAE7C,gBAAgB,CAAC,EAAE,CAAC,SAAS,IAAI,GAC7B,4BAA4B,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAC9C,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAEpC,KAAK,8BAA8B,CAAC,CAAC,SAAS,mBAAmB,IAC/D,8BAA8B,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAErD,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,mBAAmB,IAC3D,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE1C,MAAM,MAAM,0BAA0B,CACpC,EAAE,SAAS,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAE7C,eAAe,CAAC,EAAE,CAAC,SAAS,IAAI,GAC5B,8BAA8B,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAChD,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;;CACvC;AAgDD,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,mBAAmB,IACzD,iBAAiB,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;AAE7C,MAAM,MAAM,wBAAwB,CAClC,EAAE,SAAS,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAC3C,iBAAiB,CAAC,4BAA4B,CAAC,EAAE,CAAC,CAAC;AAEvD,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,mBAAmB,IACrD,iBAAiB,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;AAEzC,MAAM,MAAM,oBAAoB,CAC9B,EAAE,SAAS,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAC3C,iBAAiB,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC;AAEnD,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,mBAAmB,IACvD,iBAAiB,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAE3C,MAAM,MAAM,sBAAsB,CAChC,EAAE,SAAS,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAC3C,iBAAiB,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAC;AAErD,MAAM,MAAM,qBAAqB,CAAC,CAAC,EAAE,CAAC,IAAI,mBAAmB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/E,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI,mBAAmB,CAC7D,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,EACtB,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,sBAAsB,CAAC,CAAC,IAAI,mBAAmB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7E,MAAM,MAAM,2BAA2B,CAAC,CAAC,IAAI,mBAAmB,CAC9D,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,CAAC,IAAI,mBAAmB,CAC9D,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,CAAC,IAAI,mBAAmB,CAC9D,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,CAAC,IAAI,mBAAmB,CAC9D,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,sCAAsC,CAAC,CAAC,EAAE,CAAC,IAAI,mBAAmB,CAC5E,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EACf,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,kCAAkC,CAAC,CAAC,EAAE,CAAC,IAAI,mBAAmB,CACxE,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,EAC1B,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,wBAAwB,CAAC,CAAC,IAAI,mBAAmB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/E,MAAM,MAAM,gCAAgC,CAAC,CAAC,IAAI,mBAAmB,CACnE,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,gCAAgC,CAAC,CAAC,IAAI,mBAAmB,CACnE,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI,mBAAmB,CAC7D,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAIF,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,oBAAoB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/E,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI,oBAAoB,CAC9D,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,CAAC,EAAE,CAAC,IAAI,oBAAoB,CAClE,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,CAAC,EAAE,CAAC,IAAI,oBAAoB,CACjE,CAAC,EACD,SAAS,CAAC,CAAC,CAAC,CACb,CAAC"}
@@ -1,12 +1,4 @@
1
1
  import type { UpdateToken } from '../types/index.mjs';
2
- /**
3
- * The token of a new update, which the update's root or async child passes to
4
- * every node it reaches. A `Symbol` with no description, issued once per
5
- * update and never per node, so its cost is spread over every node the
6
- * update reaches. Unique without any counter, so the tokens of two copies of
7
- * synstate in one program never coincide, and nothing is kept in a global.
8
- */
9
- export declare const issueUpdateToken: () => UpdateToken;
10
2
  /**
11
3
  * The token a node holds before its first update: one value shared by every
12
4
  * node of this copy, since no update is ever issued it, so creating a node
@@ -1 +1 @@
1
- {"version":3,"file":"id-maker.d.mts","sourceRoot":"","sources":["../../../src/core/utils/id-maker.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,QAAO,WAEX,CAAC;AAE1B;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,WAEuB,CAAC"}
1
+ {"version":3,"file":"id-maker.d.mts","sourceRoot":"","sources":["../../../src/core/utils/id-maker.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,WAEM,CAAC"}
@@ -3,17 +3,7 @@
3
3
 
4
4
 
5
5
 
6
-
7
-
8
- export const issueUpdateToken = () =>
9
-
10
- Symbol();
11
-
12
-
13
-
14
-
15
-
16
6
  export const notUpdatedYet =
17
7
 
18
- Symbol('synstate/not-updated-yet');
8
+ Object.freeze({});
19
9
  //# sourceMappingURL=id-maker.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"id-maker.mjs","sourceRoot":"","sources":["../../../src/core/utils/id-maker.mts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAgB,EAAE;AAChD,4DAA4D;AAC5D,MAAM,EAAiB,CAAC;AAE1B;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa;AACxB,4DAA4D;AAC5D,MAAM,CAAC,0BAA0B,CAAgB,CAAC"}
1
+ {"version":3,"file":"id-maker.mjs","sourceRoot":"","sources":["../../../src/core/utils/id-maker.mts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa;AACxB,4DAA4D;AAC5D,MAAM,CAAC,MAAM,CAAC,EAAE,CAAgB,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { type ReplaceEqualDeepOptions } from 'ts-data-forge';
1
2
  import type { Reducer } from 'ts-type-forge';
2
3
  import { type InitializedObservable } from '../core/index.mjs';
3
4
  /**
@@ -9,7 +10,8 @@ import { type InitializedObservable } from '../core/index.mjs';
9
10
  * @param reducer - A pure function that takes current state and action, returns new state
10
11
  * @param initialState - The initial value of the state
11
12
  * @param options - {@link StateOptions}: `equals` (default `Object.is`),
12
- * to pass on only the dispatches that change the state
13
+ * to pass on only the dispatches that change the state, and
14
+ * `keepEqualParts`, to keep the parts of the state a dispatch did not change
13
15
  * @returns A 3-element tuple: `[state, dispatch, { getSnapshot, initialState }]`.
14
16
  * `dispatch` returns the state it leaves; once `state` is completed, that
15
17
  * is the state held.
@@ -102,5 +104,32 @@ export type StateOptions<S> = Readonly<{
102
104
  * @param next - The state the update would set
103
105
  */
104
106
  equals?: (current: S, next: S) => boolean;
107
+ /**
108
+ * Whether an update keeps the parts of the state it did not change. With
109
+ * `true`, the next state is compared with the current one before it is
110
+ * written, and every part of it deeply equal to the same part of the
111
+ * current state is replaced by that part (`replaceEqualDeep` of
112
+ * ts-data-forge): a reader of an unchanged part keeps the object it has, so
113
+ * `skipIfNoChange()` with `Object.is` stops it. When the whole next state is
114
+ * deeply equal, the current state is kept and nothing is passed on, so
115
+ * `equals` can stay `Object.is`.
116
+ *
117
+ * This is for a state written whole from a source that answers with a new
118
+ * object every time, a server polled for a report, say. Array items are
119
+ * matched by index; pass `{ key }` to match them by key, an item for which
120
+ * `key` returns `undefined` being matched by index. Only plain objects and
121
+ * arrays are walked into; a `Map`, a `Set`, a `Date` or a class instance is
122
+ * compared and kept whole.
123
+ *
124
+ * Prefer this over `keepEqualParts()` downstream: keeping the parts where
125
+ * the state is written means no update with nothing in it is passed on at
126
+ * all, and nothing downstream has anything to undo.
127
+ *
128
+ * Defaults to `false`: the next state is written as given. With it on,
129
+ * each update compares deeply every part of the next state that is not
130
+ * the very object of the current one; a state whose updates already keep
131
+ * what they do not change, as `{ ...prev, x }` does, gains nothing from it.
132
+ */
133
+ keepEqualParts?: boolean | ReplaceEqualDeepOptions;
105
134
  }>;
106
135
  //# sourceMappingURL=create-reducer.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-reducer.d.mts","sourceRoot":"","sources":["../../src/utils/create-reducer.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAU,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2EG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,CAAC,WACvB,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,gBACR,CAAC,YACL,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KACjC,SAAS,CACV,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAC/B,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAC1B,KAAK,EAAE,QAAQ,CAAC;IACd,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CAoBH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,QAAQ,CAAC;IACrC;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;CAC3C,CAAC,CAAC"}
1
+ {"version":3,"file":"create-reducer.d.mts","sourceRoot":"","sources":["../../src/utils/create-reducer.mts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAU,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4EG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,CAAC,WACvB,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,gBACR,CAAC,YACL,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KACjC,SAAS,CACV,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAC/B,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAC1B,KAAK,EAAE,QAAQ,CAAC;IACd,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CA8BH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,QAAQ,CAAC;IACrC;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IAE1C;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,uBAAuB,CAAC;CACpD,CAAC,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { replaceEqualDeep } from 'ts-data-forge';
1
2
  import { source } from '../core/index.mjs';
2
3
 
3
4
 
@@ -73,14 +74,20 @@ import { source } from '../core/index.mjs';
73
74
 
74
75
 
75
76
 
77
+
76
78
 
77
79
 
78
80
  export const createReducer = (reducer, initialState, options) => {
79
81
  const state = source(initialState);
80
82
  const equals = options?.equals ?? Object.is;
83
+ const keepEqualParts = options?.keepEqualParts ?? false;
84
+ const keepOptions = typeof keepEqualParts === 'boolean' ? undefined : keepEqualParts;
81
85
  const dispatch = (action) => {
82
86
  const currentState = state.getSnapshot().value;
83
- const nextState = reducer(currentState, action);
87
+ const reduced = reducer(currentState, action);
88
+ const nextState = keepEqualParts === false
89
+ ? reduced
90
+ : replaceEqualDeep(currentState, reduced, keepOptions);
84
91
 
85
92
  return equals(currentState, nextState)
86
93
  ? currentState
@@ -1 +1 @@
1
- {"version":3,"file":"create-reducer.mjs","sourceRoot":"","sources":["../../src/utils/create-reducer.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAA8B,MAAM,mBAAmB,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2EG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,OAAsB,EACtB,YAAe,EACf,OAAkC,EAQlC,EAAE;IACF,MAAM,KAAK,GAAG,MAAM,CAAI,YAAY,CAAC,CAAC;IAEtC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC;IAE5C,MAAM,QAAQ,GAAG,CAAC,MAAS,EAAK,EAAE;QAChC,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC;QAE/C,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAEhD,8DAA8D;QAC9D,OAAO,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC;YACpC,CAAC,CAAC,YAAY;YACd,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,GAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC;IAEvD,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE,CAAU,CAAC;AACnE,CAAC,CAAC"}
1
+ {"version":3,"file":"create-reducer.mjs","sourceRoot":"","sources":["../../src/utils/create-reducer.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAgC,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAE,MAAM,EAA8B,MAAM,mBAAmB,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4EG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,OAAsB,EACtB,YAAe,EACf,OAAkC,EAQlC,EAAE;IACF,MAAM,KAAK,GAAG,MAAM,CAAI,YAAY,CAAC,CAAC;IAEtC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC;IAE5C,MAAM,cAAc,GAAG,OAAO,EAAE,cAAc,IAAI,KAAK,CAAC;IAExD,MAAM,WAAW,GACf,OAAO,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC;IAEnE,MAAM,QAAQ,GAAG,CAAC,MAAS,EAAK,EAAE;QAChC,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC;QAE/C,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAE9C,MAAM,SAAS,GACb,cAAc,KAAK,KAAK;YACtB,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,gBAAgB,CAAC,YAAY,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QAE3D,8DAA8D;QAC9D,OAAO,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC;YACpC,CAAC,CAAC,YAAY;YACd,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,GAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC;IAEvD,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE,CAAU,CAAC;AACnE,CAAC,CAAC"}
@@ -7,7 +7,8 @@ import { type StateOptions } from './create-reducer.mjs';
7
7
  * @template S - The type of the state
8
8
  * @param initialState - The initial value of the state
9
9
  * @param options - {@link StateOptions}: `equals` (default `Object.is`),
10
- * to pass on only the updates that change the state
10
+ * to pass on only the updates that change the state, and `keepEqualParts`,
11
+ * to keep the parts of the state an update did not change
11
12
  * @returns A 3-element tuple: `[state, setState, { updateState, resetState, getSnapshot, initialState }]`
12
13
  *
13
14
  * @example
@@ -67,6 +68,57 @@ import { type StateOptions } from './create-reducer.mjs';
67
68
  * ]);
68
69
  * ```
69
70
  *
71
+ * @example
72
+ * ```ts
73
+ * type PullReport = DeepReadonly<{
74
+ * summary: { open: number };
75
+ * pulls: { number: number; title: string }[];
76
+ * }>;
77
+ *
78
+ * const [report, setReport] = createState<PullReport>(
79
+ * { summary: { open: 0 }, pulls: [] },
80
+ * { keepEqualParts: true },
81
+ * );
82
+ *
83
+ * const summary = report.pipe(map((r) => r.summary)).pipe(skipIfNoChange());
84
+ *
85
+ * const summaryHistory: unknown[] = [];
86
+ *
87
+ * summary.subscribe((value) => {
88
+ * summaryHistory.push(value);
89
+ * });
90
+ *
91
+ * // A server answers each poll with the whole report, a new object every
92
+ * // time. What did not change keeps the object already held.
93
+ * setReport({
94
+ * summary: { open: 1 },
95
+ * pulls: [{ number: 1, title: 'one' }],
96
+ * });
97
+ *
98
+ * const held = report.getSnapshot().value;
99
+ *
100
+ * // An answer that changes nothing is not passed on at all.
101
+ * setReport({
102
+ * summary: { open: 1 },
103
+ * pulls: [{ number: 1, title: 'one' }],
104
+ * });
105
+ *
106
+ * assert.strictEqual(report.getSnapshot().value, held);
107
+ *
108
+ * // An edited title: a new report and a new array, while the summary is
109
+ * // the one held, so `summary` is not told of it.
110
+ * setReport({
111
+ * summary: { open: 1 },
112
+ * pulls: [{ number: 1, title: 'one (edited)' }],
113
+ * });
114
+ *
115
+ * assert.notStrictEqual(report.getSnapshot().value, held);
116
+ *
117
+ * assert.strictEqual(report.getSnapshot().value.summary, held.summary);
118
+ *
119
+ * assert.deepStrictEqual(summaryHistory, [{ open: 0 }, { open: 1 }]);
120
+ * ```
121
+ *
70
122
  * @note Do not call `setState`, `updateState` or `resetState` from a subscriber or a projection while another
71
123
  * update is propagating: the write propagates immediately, so subscribers can
72
124
  * see an intermediate state, and it logs a `console.warn` (once per
@@ -1 +1 @@
1
- {"version":3,"file":"create-state.d.mts","sourceRoot":"","sources":["../../src/utils/create-state.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAuBxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,gBACb,CAAC,YACL,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KACjC,SAAS,CACV,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAC/B,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EACrB,KAAK,EAAE,QAAQ,CAAC;IACd,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CA0BH,CAAC"}
1
+ {"version":3,"file":"create-state.d.mts","sourceRoot":"","sources":["../../src/utils/create-state.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAuBxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6HG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,gBACb,CAAC,YACL,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KACjC,SAAS,CACV,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAC/B,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EACrB,KAAK,EAAE,QAAQ,CAAC;IACd,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CA0BH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-state.mjs","sourceRoot":"","sources":["../../src/utils/create-state.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAqB,MAAM,sBAAsB,CAAC;AAaxE,MAAM,OAAO,GAAG,CAAK,KAAQ,EAAE,MAAiB,EAAK,EAAE;IACrD,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,KAAK;YACR,OAAO,MAAM,CAAC,SAAS,CAAC;QAE1B,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,YAAe,EACf,OAAkC,EAUlC,EAAE;IACF,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,GAAG,aAAa,CACtD,OAAO,EACP,YAAY,EACZ,OAAO,CACR,CAAC;IAEF,MAAM,WAAW,GAAG,CAAC,QAAwB,EAAK,EAAE,CAClD,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IAEzC,MAAM,QAAQ,GAAG,CAAC,SAAY,EAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAE3E,MAAM,UAAU,GAAG,GAAM,EAAE,CACzB,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC;IAErD,OAAO;QACL,KAAK;QACL,QAAQ;QACR;YACE,WAAW;YACX,UAAU;YACV,WAAW;YACX,YAAY;SACb;KACO,CAAC;AACb,CAAC,CAAC"}
1
+ {"version":3,"file":"create-state.mjs","sourceRoot":"","sources":["../../src/utils/create-state.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAqB,MAAM,sBAAsB,CAAC;AAaxE,MAAM,OAAO,GAAG,CAAK,KAAQ,EAAE,MAAiB,EAAK,EAAE;IACrD,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,KAAK;YACR,OAAO,MAAM,CAAC,SAAS,CAAC;QAE1B,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6HG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,YAAe,EACf,OAAkC,EAUlC,EAAE;IACF,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,GAAG,aAAa,CACtD,OAAO,EACP,YAAY,EACZ,OAAO,CACR,CAAC;IAEF,MAAM,WAAW,GAAG,CAAC,QAAwB,EAAK,EAAE,CAClD,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IAEzC,MAAM,QAAQ,GAAG,CAAC,SAAY,EAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAE3E,MAAM,UAAU,GAAG,GAAM,EAAE,CACzB,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC;IAErD,OAAO;QACL,KAAK;QACL,QAAQ;QACR;YACE,WAAW;YACX,UAAU;YACV,WAAW;YACX,YAAY;SACb;KACO,CAAC;AACb,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synstate",
3
- "version": "4.1.0",
3
+ "version": "5.0.1",
4
4
  "description": "Type-safe State Management Library for TypeScript/JavaScript",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,30 +29,30 @@
29
29
  "LICENSE"
30
30
  ],
31
31
  "dependencies": {
32
- "ts-data-forge": "^14.9.0",
32
+ "ts-data-forge": "^14.10.0",
33
33
  "ts-std-forge": "^0.5.2",
34
34
  "ts-type-forge": "^9.2.2"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@reduxjs/toolkit": "2.13.0",
38
- "@sumi-lang/cli": "0.0.7",
38
+ "@sumi-lang/cli": "0.1.1",
39
39
  "@types/react": "19.3.0",
40
- "@vitest/browser-playwright": "5.0.3",
41
- "argparse": "3.0.2",
42
- "eslint-config-typed": "5.19.0",
43
- "eslint-plugin-ts-data-forge": "0.10.0",
44
- "eslint-plugin-ts-fortress": "1.3.5",
45
- "eslint-plugin-ts-type-forge": "0.8.10",
40
+ "@vitest/browser-playwright": "5.0.5",
41
+ "argparse": "3.0.3",
42
+ "eslint-config-typed": "5.19.2",
43
+ "eslint-plugin-ts-data-forge": "0.10.3",
44
+ "eslint-plugin-ts-fortress": "1.3.8",
45
+ "eslint-plugin-ts-type-forge": "0.8.13",
46
46
  "jotai": "3.0.1",
47
47
  "mobx": "7.0.6",
48
- "playwright": "1.64.0",
49
- "prettier": "3.9.9",
48
+ "playwright": "1.64.1",
49
+ "prettier": "3.9.10",
50
50
  "prettier-plugin-organize-imports": "4.3.0",
51
51
  "prettier-plugin-packagejson": "3.0.2",
52
- "react": "19.3.0",
52
+ "react": "19.3.1",
53
53
  "rxjs": "7.8.2",
54
- "synstate-react-hooks": "4.1.0",
55
- "synstate-react-hooks-compat": "4.1.0",
54
+ "synstate-react-hooks": "5.0.1",
55
+ "synstate-react-hooks-compat": "5.0.1",
56
56
  "ts-repo-utils": "10.7.1",
57
57
  "valtio": "2.3.2",
58
58
  "zustand": "5.0.15"
@@ -2,7 +2,7 @@
2
2
  // @sumi-expect-error-file banned-syntax/no-this
3
3
  // @sumi-expect-error-file functions/prefer-arrow-function
4
4
  // @sumi-expect-error-file mutation/no-mutation-without-mut-prefix
5
- import { Arr, hasKey, isRecord, type Optional, type Some } from 'ts-data-forge';
5
+ import { hasKey, isRecord, type Optional, type Some } from 'ts-data-forge';
6
6
  import { panic } from 'ts-std-forge';
7
7
  import type { MutableSet } from 'ts-type-forge';
8
8
  import type {
@@ -14,18 +14,16 @@ import type {
14
14
  NonEmptyUnknownList,
15
15
  Observable,
16
16
  Operator,
17
+ Subscription,
17
18
  SyncChildObservable,
19
+ UpdateToken,
18
20
  WithInitialValueOperator,
19
21
  Wrap,
20
22
  } from '../types/index.mjs';
21
23
  import { maxDepth } from '../utils/index.mjs';
22
24
  import { ManagerObservableClass } from './manager-observable-class.mjs';
23
25
  import { ObservableBaseClass } from './observable-base-class.mjs';
24
- import {
25
- toNode,
26
- type ChildNode,
27
- type ManagerNode,
28
- } from './observable-node.mjs';
26
+ import { toNode, type ChildNode } from './observable-node.mjs';
29
27
  import { runAfterPropagation } from './propagation-state.mjs';
30
28
 
31
29
  type ChildObservableConfig<A, P extends NonEmptyUnknownList> = Readonly<{
@@ -57,7 +55,6 @@ export class SyncChildObservableClass<A, const P extends NonEmptyUnknownList>
57
55
  {
58
56
  #mut_isAttached: boolean;
59
57
  readonly parents: Wrap<P>;
60
- readonly managers: readonly ManagerNode[];
61
58
 
62
59
  constructor({
63
60
  parents,
@@ -72,17 +69,14 @@ export class SyncChildObservableClass<A, const P extends NonEmptyUnknownList>
72
69
 
73
70
  this.parents = parents;
74
71
 
75
- this.managers = managersOf(parents);
76
-
77
72
  this.#mut_isAttached = false;
78
73
  }
79
74
 
80
75
  /**
81
- * Joins the current scope and registers this observable to its parents
82
- * and the managers it is reached from. Completed parents never update
83
- * again, so a child created under them is complete from the start
84
- * (#2248), as is one its constructor completed; registering it would only
85
- * leave a reference in each parent.
76
+ * Joins the current scope and registers this observable to its parents.
77
+ * Completed parents never update again, so a child created under them is
78
+ * complete from the start (#2248), as is one its constructor completed;
79
+ * registering it would only leave a reference in each parent.
86
80
  */
87
81
  protected attach(): void {
88
82
  this.adoptIntoCurrentScope();
@@ -90,7 +84,7 @@ export class SyncChildObservableClass<A, const P extends NonEmptyUnknownList>
90
84
  if (this.isCompleted || this.parents.every((p) => p.isCompleted)) {
91
85
  this.complete();
92
86
  } else {
93
- registerChild(this, this.managers);
87
+ registerChild(this);
94
88
 
95
89
  this.#mut_isAttached = true;
96
90
  }
@@ -103,7 +97,7 @@ export class SyncChildObservableClass<A, const P extends NonEmptyUnknownList>
103
97
 
104
98
  this.#mut_isAttached = false;
105
99
 
106
- unregisterChild(this, this.managers);
100
+ unregisterChild(this);
107
101
  }
108
102
 
109
103
  override tryComplete(): void {
@@ -170,7 +164,7 @@ export class AsyncChildObservableClass<A, const P extends NonEmptyUnknownList>
170
164
  if (this.isCompleted || this.parents.every((p) => p.isCompleted)) {
171
165
  this.complete();
172
166
  } else {
173
- registerChild(this, managersOf(this.parents));
167
+ registerChild(this);
174
168
 
175
169
  this.#mut_isAttached = true;
176
170
  }
@@ -183,7 +177,7 @@ export class AsyncChildObservableClass<A, const P extends NonEmptyUnknownList>
183
177
 
184
178
  this.#mut_isAttached = false;
185
179
 
186
- unregisterChild(this, managersOf(this.parents));
180
+ unregisterChild(this);
187
181
  }
188
182
 
189
183
  override tryComplete(): void {
@@ -204,6 +198,40 @@ export class AsyncChildObservableClass<A, const P extends NonEmptyUnknownList>
204
198
  this.complete();
205
199
  });
206
200
  }
201
+
202
+ /**
203
+ * Subscribes to the inner observable that the projection of `switchMap` /
204
+ * `mergeMap` returned.
205
+ *
206
+ * If the inner observable already holds a value (`just(x)`, a state), it
207
+ * emits that value synchronously while being subscribed. That first value
208
+ * is emitted with `updateToken`, the token of the update that ran the
209
+ * projection, so it joins the propagation in progress like a sync
210
+ * operator's value would. Starting an update of its own instead would
211
+ * reach the nodes below before the current update reached this
212
+ * observable's siblings: a node reading both would see the new inner value
213
+ * beside stale sibling values (a glitch), and would emit twice.
214
+ *
215
+ * Values the inner observable emits later start updates of their own.
216
+ */
217
+ protected subscribeInner(
218
+ inner: Observable<A>,
219
+ updateToken: UpdateToken,
220
+ ): Subscription {
221
+ let mut_isSubscribing = true;
222
+
223
+ const subscription = inner.subscribe((value) => {
224
+ if (mut_isSubscribing) {
225
+ this.setNext(value, updateToken);
226
+ } else {
227
+ this.startUpdate(value);
228
+ }
229
+ });
230
+
231
+ mut_isSubscribing = false;
232
+
233
+ return subscription;
234
+ }
207
235
  }
208
236
 
209
237
  /**
@@ -247,11 +275,8 @@ const shouldComplete = (
247
275
  !child.isCompleted &&
248
276
  (child.parents.every((p) => p.isCompleted) || child.canEmitNoMore());
249
277
 
250
- /** Registers a child to its parents and to `managers`. */
251
- const registerChild = (
252
- child: ChildNode,
253
- managers: readonly ManagerNode[],
254
- ): void => {
278
+ /** Registers a child to its parents. */
279
+ const registerChild = (child: ChildNode): void => {
255
280
  if (checksCircularDependency) {
256
281
  detectCircularDependency(child);
257
282
  }
@@ -259,42 +284,19 @@ const registerChild = (
259
284
  for (const p of child.parents) {
260
285
  toNode(p).addChild(child);
261
286
  }
262
-
263
- for (const m of managers) {
264
- m.addDescendant(child);
265
- }
266
287
  };
267
288
 
268
289
  /**
269
290
  * Undoes {@link registerChild} for a completed child: its parents forget it,
270
- * and every manager it registered to stops propagating updates to it.
271
- * Without this a completed node stayed reachable for as long as its root
272
- * lived, and ran its `tryUpdate` on every update (#2134).
291
+ * so that no update puts it in its queue again. Without this a completed
292
+ * node stayed reachable for as long as its root lived (#2134).
273
293
  */
274
- const unregisterChild = (
275
- child: ChildNode,
276
- managers: readonly ManagerNode[],
277
- ): void => {
294
+ const unregisterChild = (child: ChildNode): void => {
278
295
  for (const p of child.parents) {
279
296
  toNode(p).deleteChild(child);
280
297
  }
281
-
282
- for (const m of managers) {
283
- m.deleteDescendant(child);
284
- }
285
298
  };
286
299
 
287
- /**
288
- * The managers the descendants of `parents` register to, shared with the
289
- * parent when there is one.
290
- */
291
- const managersOf = (
292
- parents: readonly Observable<unknown>[],
293
- ): readonly ManagerNode[] =>
294
- Arr.isFixedLengthArray(1, parents)
295
- ? toNode(parents[0]).managers
296
- : Array.from(new Set(parents.flatMap((p) => toNode(p).managers)));
297
-
298
300
  const isDevelopmentProcess = (): boolean => {
299
301
  const proc: unknown = Reflect.get(globalThis, 'process');
300
302
 
@@ -307,12 +309,15 @@ const isDevelopmentProcess = (): boolean => {
307
309
  };
308
310
 
309
311
  /**
310
- * Whether {@link registerChild} checks for a circular dependency: everywhere
311
- * but in a process whose `NODE_ENV` is `production`. A child's parents exist
312
- * before it and cannot be changed afterwards, so only code that rewrites an
313
- * observable's readonly `parents` can make a cycle, while the walk over every
314
- * ancestor is paid on every creation. Where there is no `process` (a browser
315
- * bundle) the check is off.
312
+ * Whether {@link registerChild} checks for a circular dependency: on in
313
+ * development, off in production. The public API cannot make a cycle — a
314
+ * child's parents exist before it and cannot be changed afterwards — so the
315
+ * check is a safety net for what propagation assumes (a DAG, a depth for every
316
+ * node) against code that rewrites an observable's readonly `parents`, and
317
+ * development is where that code runs first. It walks every ancestor of each
318
+ * new observable, a cost production does not pay: the check is off when
319
+ * `NODE_ENV` is `production`, and where there is no `process` (a browser
320
+ * bundle).
316
321
  */
317
322
  export const checksCircularDependency: boolean = isDevelopmentProcess();
318
323
 
@@ -61,7 +61,10 @@ export type AsyncChildObservableTools<A> = Readonly<{
61
61
  * hooks the factory calls, which read the state `init` creates.
62
62
  */
63
63
  export type SyncChildObservableHooks = Readonly<{
64
- /** Called with the token of every update that reaches this observable. */
64
+ /**
65
+ * Called with the token of every update in which a parent of this
66
+ * observable emitted.
67
+ */
65
68
  tryUpdate: (updateToken: UpdateToken) => void;
66
69
 
67
70
  /**
@@ -124,10 +127,10 @@ export type InitializedChildObservableConfig<
124
127
  * other synchronous operators are built with it.
125
128
  *
126
129
  * `init` runs during construction and receives the tools. It returns
127
- * `tryUpdate`, which is called with the token of every update that reaches
128
- * this observable — a parent that did not emit in that update has a different
129
- * `updateToken`; to emit, call `setNext` with the token received — or an
130
- * object holding `tryUpdate` and the other hooks
130
+ * `tryUpdate`, which is called with the token of every update in which some
131
+ * parent of this observable emitted — a parent that did not emit in that
132
+ * update has a different `updateToken`; to emit, call `setNext` with the
133
+ * token received — or an object holding `tryUpdate` and the other hooks
131
134
  * ({@link SyncChildObservableHooks}). State the hooks share can live inside
132
135
  * `init`, next to the teardown it registers with the `onComplete` tool.
133
136
  * `init` may complete the observable; it is then never registered to its