@e280/strata 0.2.2 → 0.2.3

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 (87) hide show
  1. package/README.md +123 -128
  2. package/package.json +6 -4
  3. package/s/index.ts +1 -0
  4. package/s/prism/chrono/chronicle.ts +11 -0
  5. package/s/prism/chrono/chrono.ts +91 -0
  6. package/s/prism/chrono/types.ts +12 -0
  7. package/s/prism/index.ts +11 -0
  8. package/s/prism/lens.ts +54 -0
  9. package/s/prism/prism.test.ts +330 -0
  10. package/s/prism/prism.ts +41 -0
  11. package/s/prism/types.ts +27 -0
  12. package/s/prism/utils/cache-cell.ts +22 -0
  13. package/s/prism/utils/immute.ts +8 -0
  14. package/s/prism/utils/optic-symbol.ts +3 -0
  15. package/s/prism/vault/local-store.ts +31 -0
  16. package/s/prism/vault/types.ts +19 -0
  17. package/s/prism/vault/vault.ts +19 -0
  18. package/s/tests.test.ts +4 -1
  19. package/s/tree/parts/branch.ts +25 -12
  20. package/s/tree/parts/chronobranch.ts +3 -1
  21. package/s/tree/parts/trunk.ts +3 -1
  22. package/s/tree/parts/types.ts +32 -30
  23. package/s/tree/parts/utils/immute.ts +4 -4
  24. package/s/tree/tree.test.ts +30 -2
  25. package/x/index.d.ts +1 -0
  26. package/x/index.js +1 -0
  27. package/x/index.js.map +1 -1
  28. package/x/prism/chrono/chronicle.d.ts +2 -0
  29. package/x/prism/chrono/chronicle.js +8 -0
  30. package/x/prism/chrono/chronicle.js.map +1 -0
  31. package/x/prism/chrono/chrono.d.ts +26 -0
  32. package/x/prism/chrono/chrono.js +79 -0
  33. package/x/prism/chrono/chrono.js.map +1 -0
  34. package/x/prism/chrono/types.d.ts +5 -0
  35. package/x/prism/chrono/types.js +2 -0
  36. package/x/prism/chrono/types.js.map +1 -0
  37. package/x/prism/index.d.ts +9 -0
  38. package/x/prism/index.js +10 -0
  39. package/x/prism/index.js.map +1 -0
  40. package/x/prism/lens.d.ts +13 -0
  41. package/x/prism/lens.js +45 -0
  42. package/x/prism/lens.js.map +1 -0
  43. package/x/prism/prism.d.ts +10 -0
  44. package/x/prism/prism.js +34 -0
  45. package/x/prism/prism.js.map +1 -0
  46. package/x/prism/prism.test.d.ts +35 -0
  47. package/x/prism/prism.test.js +286 -0
  48. package/x/prism/prism.test.js.map +1 -0
  49. package/x/prism/types.d.ts +17 -0
  50. package/x/prism/types.js +2 -0
  51. package/x/prism/types.js.map +1 -0
  52. package/x/prism/utils/cache-cell.d.ts +7 -0
  53. package/x/prism/utils/cache-cell.js +20 -0
  54. package/x/prism/utils/cache-cell.js.map +1 -0
  55. package/x/prism/utils/immute.d.ts +2 -0
  56. package/x/prism/utils/immute.js +5 -0
  57. package/x/prism/utils/immute.js.map +1 -0
  58. package/x/prism/utils/optic-symbol.d.ts +1 -0
  59. package/x/prism/utils/optic-symbol.js +2 -0
  60. package/x/prism/utils/optic-symbol.js.map +1 -0
  61. package/x/prism/vault/local-store.d.ts +9 -0
  62. package/x/prism/vault/local-store.js +27 -0
  63. package/x/prism/vault/local-store.js.map +1 -0
  64. package/x/prism/vault/types.d.ts +14 -0
  65. package/x/prism/vault/types.js +2 -0
  66. package/x/prism/vault/types.js.map +1 -0
  67. package/x/prism/vault/vault.d.ts +7 -0
  68. package/x/prism/vault/vault.js +17 -0
  69. package/x/prism/vault/vault.js.map +1 -0
  70. package/x/tests.test.js +3 -1
  71. package/x/tests.test.js.map +1 -1
  72. package/x/tree/parts/branch.d.ts +4 -2
  73. package/x/tree/parts/branch.js +17 -9
  74. package/x/tree/parts/branch.js.map +1 -1
  75. package/x/tree/parts/chronobranch.d.ts +3 -1
  76. package/x/tree/parts/chronobranch.js +1 -0
  77. package/x/tree/parts/chronobranch.js.map +1 -1
  78. package/x/tree/parts/trunk.d.ts +6 -4
  79. package/x/tree/parts/trunk.js +1 -0
  80. package/x/tree/parts/trunk.js.map +1 -1
  81. package/x/tree/parts/types.d.ts +2 -19
  82. package/x/tree/parts/utils/immute.d.ts +2 -1
  83. package/x/tree/parts/utils/immute.js +2 -3
  84. package/x/tree/parts/utils/immute.js.map +1 -1
  85. package/x/tree/tree.test.d.ts +4 -2
  86. package/x/tree/tree.test.js +28 -2
  87. package/x/tree/tree.test.js.map +1 -1
@@ -1,4 +1,6 @@
1
1
 
2
+ import { EzStore, Versioned } from "../../prism/index.js"
3
+ import { Immutable } from "../../prism/types.js"
2
4
  import {Branch} from "./branch.js"
3
5
 
4
6
  export type TreeOptions = {
@@ -14,22 +16,22 @@ export type Mutator<S> = (state: S) => void
14
16
  export type Trunkstate = {}
15
17
  export type Branchstate = {} | null | undefined
16
18
 
17
- export type Versioned<S extends Trunkstate> = {
18
- state: S
19
- version: number
20
- }
21
-
22
- export type Immutable<T> =
23
- T extends (...args: any[]) => any ? T :
24
- T extends readonly any[] ? ReadonlyArray<Immutable<T[number]>> :
25
- T extends object ? { readonly [K in keyof T]: Immutable<T[K]> } :
26
- T
27
-
28
- export type Mutable<T> =
29
- T extends (...args: any[]) => any ? T :
30
- T extends ReadonlyArray<infer U> ? Mutable<U>[] :
31
- T extends object ? { -readonly [K in keyof T]: Mutable<T[K]> } :
32
- T
19
+ // export type Versioned<S extends Trunkstate> = {
20
+ // state: S
21
+ // version: number
22
+ // }
23
+ //
24
+ // export type Immutable<T> =
25
+ // T extends (...args: any[]) => any ? T :
26
+ // T extends readonly any[] ? ReadonlyArray<Immutable<T[number]>> :
27
+ // T extends object ? { readonly [K in keyof T]: Immutable<T[K]> } :
28
+ // T
29
+ //
30
+ // export type Mutable<T> =
31
+ // T extends (...args: any[]) => any ? T :
32
+ // T extends ReadonlyArray<infer U> ? Mutable<U>[] :
33
+ // T extends object ? { -readonly [K in keyof T]: Mutable<T[K]> } :
34
+ // T
33
35
 
34
36
  export type Tree<S extends Branchstate> = {
35
37
  get state(): Immutable<S>
@@ -45,21 +47,21 @@ export type SetupOptions<S extends Trunkstate> = {
45
47
  persistence?: Persistence<Versioned<S>>
46
48
  }
47
49
 
48
- export type Chronicle<S extends Branchstate> = {
49
- // [abc] d [efg]
50
- // \ \ \
51
- // \ \ future
52
- // \ present
53
- // past
54
- past: S[]
55
- present: S
56
- future: S[]
57
- }
50
+ // export type Chronicle<S extends Branchstate> = {
51
+ // // [abc] d [efg]
52
+ // // \ \ \
53
+ // // \ \ future
54
+ // // \ present
55
+ // // past
56
+ // past: S[]
57
+ // present: S
58
+ // future: S[]
59
+ // }
58
60
 
59
- export type EzStore<X> = {
60
- get(): Promise<X | undefined>
61
- set(state: X | undefined): Promise<void>
62
- }
61
+ // export type EzStore<X> = {
62
+ // get(): Promise<X | undefined>
63
+ // set(state: X | undefined): Promise<void>
64
+ // }
63
65
 
64
66
  export type Persistence<X> = {
65
67
  store: EzStore<X>
@@ -1,7 +1,8 @@
1
1
 
2
- import {deep, microbounce, sub} from "@e280/stz"
3
- import {Immutable, TreeOptions} from "../types.js"
2
+ import {deep, sub} from "@e280/stz"
3
+ import {TreeOptions} from "../types.js"
4
4
  import {tracker} from "../../../tracker/tracker.js"
5
+ import {Immutable} from "../../../prism/types.js"
5
6
 
6
7
  export class Immute<S> {
7
8
  #mutable: S
@@ -19,7 +20,6 @@ export class Immute<S> {
19
20
  }
20
21
 
21
22
  on = sub<[Immutable<S>]>()
22
- #debouncePublish = microbounce(async() => this.on.publish(this.#immutable))
23
23
 
24
24
  get() {
25
25
  tracker.notifyRead(this)
@@ -30,7 +30,7 @@ export class Immute<S> {
30
30
  this.#mutable = mutable
31
31
  this.#immutable = deep.freeze(this.options.clone(this.get())) as Immutable<S>
32
32
  await Promise.all([
33
- this.#debouncePublish(),
33
+ this.on.publish(this.#immutable),
34
34
  tracker.notifyWrite(this),
35
35
  ])
36
36
  }
@@ -56,7 +56,7 @@ export default Science.suite({
56
56
  expect(mutationCount).is(2)
57
57
  }),
58
58
 
59
- "signal.on is debounced": Science.test(async() => {
59
+ "trunk.on is debounced": Science.test.skip(async() => {
60
60
  const trunk = new Trunk({count: 0})
61
61
  let mutationCount = 0
62
62
  trunk.on.sub(() => {mutationCount++})
@@ -111,6 +111,20 @@ export default Science.suite({
111
111
  expect(branch.state.rofls).is(0)
112
112
  }),
113
113
 
114
+ "mutation triggers effect": Science.test(async() => {
115
+ const trunk = new Trunk({a: {x: 0}})
116
+ const branch = trunk.branch(s => s.a)
117
+ expect(branch.state.x).is(0)
118
+ let triggered = 0
119
+ effect(() => {
120
+ void branch.state.x
121
+ triggered++
122
+ })
123
+ expect(triggered).is(1)
124
+ await branch.mutate(s => s.x++)
125
+ expect(triggered).is(2)
126
+ }),
127
+
114
128
  "sync coherence": Science.test(async() => {
115
129
  const trunk = new Trunk({count: 0, sub: {rofls: 0}})
116
130
  const branch = trunk.branch(s => s.sub)
@@ -161,7 +175,7 @@ export default Science.suite({
161
175
  expect(b.state.c).is(103)
162
176
  }),
163
177
 
164
- "signal.on ignores outside mutations": Science.test(async() => {
178
+ "branch.on ignores outside mutations": Science.test(async() => {
165
179
  const trunk = new Trunk({a: {x: 0}, b: {x: 0}})
166
180
  const a = trunk.branch(s => s.a)
167
181
  const b = trunk.branch(s => s.b)
@@ -172,6 +186,20 @@ export default Science.suite({
172
186
  expect(counted).is(0)
173
187
  }),
174
188
 
189
+ "effects ignore outside mutations": Science.test(async() => {
190
+ const trunk = new Trunk({a: {x: 0}, b: {x: 0}})
191
+ const a = trunk.branch(s => s.a)
192
+ const b = trunk.branch(s => s.b)
193
+ let counted = 0
194
+ effect(() => {
195
+ void b.state.x
196
+ counted++
197
+ })
198
+ expect(counted).is(1)
199
+ await a.mutate(a => a.x++)
200
+ expect(counted).is(1)
201
+ }),
202
+
175
203
  "forbid submutation in mutation": Science.test(async() => {
176
204
  const trunk = new Trunk({a: {b: 0}})
177
205
  const a = trunk.branch(s => s.a)
package/x/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./prism/index.js";
1
2
  export * from "./signals/index.js";
2
3
  export * from "./tracker/index.js";
3
4
  export * from "./tree/index.js";
package/x/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./prism/index.js";
1
2
  export * from "./signals/index.js";
2
3
  export * from "./tracker/index.js";
3
4
  export * from "./tree/index.js";
package/x/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../s/index.ts"],"names":[],"mappings":"AACA,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../s/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,2 @@
1
+ import { Chronicle } from "./types.js";
2
+ export declare function chronicle<State>(state: State): Chronicle<State>;
@@ -0,0 +1,8 @@
1
+ export function chronicle(state) {
2
+ return {
3
+ past: [],
4
+ present: state,
5
+ future: [],
6
+ };
7
+ }
8
+ //# sourceMappingURL=chronicle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chronicle.js","sourceRoot":"","sources":["../../../s/prism/chrono/chronicle.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,SAAS,CAAQ,KAAY;IAC5C,OAAO;QACN,IAAI,EAAE,EAAE;QACR,OAAO,EAAE,KAAK;QACd,MAAM,EAAE,EAAE;KACV,CAAA;AACF,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { Lens } from "../lens.js";
2
+ import { Chronicle } from "./types.js";
3
+ import { LensLike } from "../types.js";
4
+ export declare class Chrono<State> implements LensLike<State> {
5
+ #private;
6
+ limit: number;
7
+ private basis;
8
+ constructor(limit: number, basis: Lens<Chronicle<State>>);
9
+ get chronicle(): {
10
+ readonly past: readonly import("../types.js").Immutable<State>[];
11
+ readonly present: import("../types.js").Immutable<State>;
12
+ readonly future: readonly import("../types.js").Immutable<State>[];
13
+ };
14
+ get state(): import("../types.js").Immutable<State>;
15
+ get undoable(): number;
16
+ get redoable(): number;
17
+ /** progress forwards, depositing history into the past */
18
+ mutate<R>(fn: (state: State) => R): Promise<R>;
19
+ /** step backwards into the past, by n steps */
20
+ undo(n?: number): Promise<void>;
21
+ /** step forwards into the future, by n steps */
22
+ redo(n?: number): Promise<void>;
23
+ /** wipe past and future snapshots */
24
+ wipe(): Promise<void>;
25
+ lens<State2>(selector: (state: State) => State2): Lens<State2>;
26
+ }
@@ -0,0 +1,79 @@
1
+ import { deep } from "@e280/stz";
2
+ import { Lens } from "../lens.js";
3
+ import { _optic } from "../utils/optic-symbol.js";
4
+ export class Chrono {
5
+ limit;
6
+ basis;
7
+ constructor(limit, basis) {
8
+ this.limit = limit;
9
+ this.basis = basis;
10
+ }
11
+ get chronicle() {
12
+ return this.basis.state;
13
+ }
14
+ get state() {
15
+ return this.basis.state.present;
16
+ }
17
+ get undoable() {
18
+ return this.chronicle.past.length;
19
+ }
20
+ get redoable() {
21
+ return this.chronicle.future.length;
22
+ }
23
+ #mut(chronicle, fn) {
24
+ const limit = Math.max(0, this.limit);
25
+ const snapshot = deep.clone(this.chronicle.present);
26
+ const result = fn(chronicle.present);
27
+ chronicle.past.push(snapshot);
28
+ chronicle.past = chronicle.past.slice(-limit);
29
+ chronicle.future = [];
30
+ return result;
31
+ }
32
+ /** progress forwards, depositing history into the past */
33
+ async mutate(fn) {
34
+ return this.basis.mutate(chronicle => this.#mut(chronicle, fn));
35
+ }
36
+ /** step backwards into the past, by n steps */
37
+ async undo(n = 1) {
38
+ await this.basis.mutate(chronicle => {
39
+ const snapshots = chronicle.past.slice(-n);
40
+ if (snapshots.length >= n) {
41
+ const oldPresent = chronicle.present;
42
+ chronicle.present = snapshots.shift();
43
+ chronicle.past = chronicle.past.slice(0, -n);
44
+ chronicle.future.unshift(oldPresent, ...snapshots);
45
+ }
46
+ });
47
+ }
48
+ /** step forwards into the future, by n steps */
49
+ async redo(n = 1) {
50
+ await this.basis.mutate(chronicle => {
51
+ const snapshots = chronicle.future.slice(0, n);
52
+ if (snapshots.length >= n) {
53
+ const oldPresent = chronicle.present;
54
+ chronicle.present = snapshots.shift();
55
+ chronicle.past.push(oldPresent, ...snapshots);
56
+ chronicle.future = chronicle.future.slice(n);
57
+ }
58
+ });
59
+ }
60
+ /** wipe past and future snapshots */
61
+ async wipe() {
62
+ await this.basis.mutate(chronicle => {
63
+ chronicle.past = [];
64
+ chronicle.future = [];
65
+ });
66
+ }
67
+ lens(selector) {
68
+ const lens = new Lens({
69
+ registerLens: this.basis[_optic].registerLens,
70
+ getState: () => selector(this.basis[_optic].getState().present),
71
+ mutate: fn => this.basis[_optic].mutate(chronicle => {
72
+ return this.#mut(chronicle, state => fn(selector(state)));
73
+ }),
74
+ });
75
+ this.basis[_optic].registerLens(lens);
76
+ return lens;
77
+ }
78
+ }
79
+ //# sourceMappingURL=chrono.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrono.js","sourceRoot":"","sources":["../../../s/prism/chrono/chrono.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export type Chronicle<State> = {
2
+ past: State[];
3
+ present: State;
4
+ future: State[];
5
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../s/prism/chrono/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ export * from "./chrono/chronicle.js";
2
+ export * from "./chrono/chrono.js";
3
+ export * from "./chrono/types.js";
4
+ export * from "./vault/local-store.js";
5
+ export * from "./vault/vault.js";
6
+ export * from "./vault/types.js";
7
+ export * from "./lens.js";
8
+ export * from "./prism.js";
9
+ export * from "./types.js";
@@ -0,0 +1,10 @@
1
+ export * from "./chrono/chronicle.js";
2
+ export * from "./chrono/chrono.js";
3
+ export * from "./chrono/types.js";
4
+ export * from "./vault/local-store.js";
5
+ export * from "./vault/vault.js";
6
+ export * from "./vault/types.js";
7
+ export * from "./lens.js";
8
+ export * from "./prism.js";
9
+ export * from "./types.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../s/prism/index.ts"],"names":[],"mappings":"AACA,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA;AACtC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,13 @@
1
+ import { _optic } from "./utils/optic-symbol.js";
2
+ import { Immutable, LensLike, Optic } from "./types.js";
3
+ /** reactive view into a state prism, with formalized mutations */
4
+ export declare class Lens<State> implements LensLike<State> {
5
+ #private;
6
+ on: import("@e280/stz").Sub<[state: Immutable<State>]>;
7
+ [_optic]: Optic<State>;
8
+ constructor(optic: Optic<State>);
9
+ update(): Promise<void>;
10
+ get state(): Immutable<State>;
11
+ mutate<R>(fn: (state: State) => R): Promise<R>;
12
+ lens<State2>(selector: (state: State) => State2): Lens<State2>;
13
+ }
@@ -0,0 +1,45 @@
1
+ import { deep, microbounce, sub } from "@e280/stz";
2
+ import { immute } from "./utils/immute.js";
3
+ import { tracker } from "../tracker/tracker.js";
4
+ import { _optic } from "./utils/optic-symbol.js";
5
+ import { CacheCell } from "./utils/cache-cell.js";
6
+ /** reactive view into a state prism, with formalized mutations */
7
+ export class Lens {
8
+ on = sub();
9
+ [_optic];
10
+ #previous;
11
+ #immutable;
12
+ #onPublishDebounced = microbounce(() => this.on.publish(this.state));
13
+ constructor(optic) {
14
+ this[_optic] = optic;
15
+ this.#previous = deep.clone(optic.getState());
16
+ this.#immutable = new CacheCell(() => immute(optic.getState()));
17
+ }
18
+ async update() {
19
+ const state = this[_optic].getState();
20
+ const isChanged = !deep.equal(state, this.#previous);
21
+ if (isChanged) {
22
+ this.#immutable.invalidate();
23
+ this.#previous = deep.clone(state);
24
+ this.#onPublishDebounced();
25
+ await tracker.notifyWrite(this);
26
+ }
27
+ }
28
+ get state() {
29
+ tracker.notifyRead(this);
30
+ return this.#immutable.get();
31
+ }
32
+ async mutate(fn) {
33
+ return this[_optic].mutate(fn);
34
+ }
35
+ lens(selector) {
36
+ const lens = new Lens({
37
+ getState: () => selector(this[_optic].getState()),
38
+ mutate: fn => this[_optic].mutate(state => fn(selector(state))),
39
+ registerLens: this[_optic].registerLens,
40
+ });
41
+ this[_optic].registerLens(lens);
42
+ return lens;
43
+ }
44
+ }
45
+ //# sourceMappingURL=lens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lens.js","sourceRoot":"","sources":["../../s/prism/lens.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAC,MAAM,WAAW,CAAA;AAChD,OAAO,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAA;AACxC,OAAO,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAA;AAC9C,OAAO,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAA;AAG/C,kEAAkE;AAClE,MAAM,OAAO,IAAI;IAChB,EAAE,GAAG,GAAG,EAA6B,CAEpC;IAAA,CAAC,MAAM,CAAC,CAAc;IACvB,SAAS,CAAO;IAChB,UAAU,CAA6B;IACvC,mBAAmB,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IAEpE,YAAY,KAAmB;QAC9B,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,CAAA;QACpB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC7C,IAAI,CAAC,UAAU,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;IAChE,CAAC;IAED,KAAK,CAAC,MAAM;QACX,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;QACrC,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QACpD,IAAI,SAAS,EAAE,CAAC;YACf,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAA;YAC5B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAClC,IAAI,CAAC,mBAAmB,EAAE,CAAA;YAC1B,MAAM,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;QAChC,CAAC;IACF,CAAC;IAED,IAAI,KAAK;QACR,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACxB,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAA;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CAAI,EAAuB;QACtC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAC/B,CAAC;IAED,IAAI,CAAS,QAAkC;QAC9C,MAAM,IAAI,GAAG,IAAI,IAAI,CAAS;YAC7B,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;YACjD,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/D,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,YAAY;SACvC,CAAC,CAAA;QACF,IAAI,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;QAC/B,OAAO,IAAI,CAAA;IACZ,CAAC;CACD"}
@@ -0,0 +1,10 @@
1
+ import { Lens } from "./lens.js";
2
+ /** state mangagement source-of-truth */
3
+ export declare class Prism<State> {
4
+ #private;
5
+ on: import("@e280/stz").Sub<[state: State]>;
6
+ constructor(state: State);
7
+ get(): State;
8
+ set(state: State): Promise<void>;
9
+ lens<State2>(selector: (state: State) => State2): Lens<State2>;
10
+ }
@@ -0,0 +1,34 @@
1
+ import { microbounce, sub } from "@e280/stz";
2
+ import { Lens } from "./lens.js";
3
+ /** state mangagement source-of-truth */
4
+ export class Prism {
5
+ #state;
6
+ #lenses = new Set();
7
+ on = sub();
8
+ #onPublishDebounced = microbounce(() => this.on.publish(this.#state));
9
+ constructor(state) {
10
+ this.#state = state;
11
+ }
12
+ get() {
13
+ return this.#state;
14
+ }
15
+ async set(state) {
16
+ this.#state = state;
17
+ await Promise.all([...this.#lenses].map(lens => lens.update()));
18
+ await this.#onPublishDebounced();
19
+ }
20
+ lens(selector) {
21
+ const lens = new Lens({
22
+ getState: () => selector(this.#state),
23
+ mutate: async (fn) => {
24
+ const result = fn(selector(this.#state));
25
+ await this.set(this.#state);
26
+ return result;
27
+ },
28
+ registerLens: lens => this.#lenses.add(lens),
29
+ });
30
+ this.#lenses.add(lens);
31
+ return lens;
32
+ }
33
+ }
34
+ //# sourceMappingURL=prism.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prism.js","sourceRoot":"","sources":["../../s/prism/prism.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAE,GAAG,EAAC,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAE9B,wCAAwC;AACxC,MAAM,OAAO,KAAK;IACjB,MAAM,CAAO;IACb,OAAO,GAAG,IAAI,GAAG,EAAa,CAAA;IAE9B,EAAE,GAAG,GAAG,EAAkB,CAAA;IAC1B,mBAAmB,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;IAErE,YAAY,KAAY;QACvB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;IACpB,CAAC;IAED,GAAG;QACF,OAAO,IAAI,CAAC,MAAM,CAAA;IACnB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAY;QACrB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;QACnB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAC/D,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAA;IACjC,CAAC;IAED,IAAI,CAAS,QAAkC;QAC9C,MAAM,IAAI,GAAG,IAAI,IAAI,CAAS;YAC7B,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;YACrC,MAAM,EAAE,KAAK,EAAC,EAAE,EAAC,EAAE;gBAClB,MAAM,MAAM,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;gBACxC,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBAC3B,OAAO,MAAM,CAAA;YACd,CAAC;YACD,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;SAC5C,CAAC,CAAA;QACF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACtB,OAAO,IAAI,CAAA;IACZ,CAAC;CACD"}
@@ -0,0 +1,35 @@
1
+ declare const _default: {
2
+ prism: {
3
+ "get and set state": import("@e280/science").Test;
4
+ };
5
+ lens: {
6
+ "get state": import("@e280/science").Test;
7
+ "state is immutable": import("@e280/science").Test;
8
+ "proper mutation": import("@e280/science").Test;
9
+ "state after mutation is frozen": import("@e280/science").Test;
10
+ "effect reacts": import("@e280/science").Test;
11
+ "lens.on is debounced": import("@e280/science").Test;
12
+ "array pushes are reactive": import("@e280/science").Test;
13
+ "sync coherence": import("@e280/science").Test;
14
+ "nullable selector": import("@e280/science").Test;
15
+ "deep composition": import("@e280/science").Test;
16
+ "deep mutations": import("@e280/science").Test;
17
+ "outside mutations ignored": import("@e280/science").Test;
18
+ "outside mutations ignored for effects": import("@e280/science").Test;
19
+ };
20
+ chrono: {
21
+ "get present state": import("@e280/science").Test;
22
+ mutation: import("@e280/science").Test;
23
+ "undoable/redoable": import("@e280/science").Test;
24
+ undo: import("@e280/science").Test;
25
+ "sync undo": import("@e280/science").Test;
26
+ redo: import("@e280/science").Test;
27
+ "undo/redo is orderly": import("@e280/science").Test;
28
+ "undo nothing does nothing": import("@e280/science").Test;
29
+ "redo nothing does nothing": import("@e280/science").Test;
30
+ "undo 2x": import("@e280/science").Test;
31
+ "redo 2x": import("@e280/science").Test;
32
+ "sublens mutations are undoable": import("@e280/science").Test;
33
+ };
34
+ };
35
+ export default _default;