@e280/strata 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -128
- package/package.json +6 -4
- package/s/index.ts +1 -0
- package/s/prism/chrono/chronicle.ts +11 -0
- package/s/prism/chrono/chrono.ts +91 -0
- package/s/prism/chrono/types.ts +12 -0
- package/s/prism/index.ts +11 -0
- package/s/prism/lens.ts +54 -0
- package/s/prism/prism.test.ts +342 -0
- package/s/prism/prism.ts +44 -0
- package/s/prism/types.ts +27 -0
- package/s/prism/utils/cache-cell.ts +22 -0
- package/s/prism/utils/immute.ts +8 -0
- package/s/prism/utils/optic-symbol.ts +3 -0
- package/s/prism/vault/local-store.ts +31 -0
- package/s/prism/vault/types.ts +19 -0
- package/s/prism/vault/vault.ts +19 -0
- package/s/tests.test.ts +4 -1
- package/s/tree/parts/branch.ts +25 -12
- package/s/tree/parts/chronobranch.ts +3 -1
- package/s/tree/parts/trunk.ts +3 -1
- package/s/tree/parts/types.ts +32 -30
- package/s/tree/parts/utils/immute.ts +4 -4
- package/s/tree/tree.test.ts +30 -2
- package/x/index.d.ts +1 -0
- package/x/index.js +1 -0
- package/x/index.js.map +1 -1
- package/x/prism/chrono/chronicle.d.ts +2 -0
- package/x/prism/chrono/chronicle.js +8 -0
- package/x/prism/chrono/chronicle.js.map +1 -0
- package/x/prism/chrono/chrono.d.ts +26 -0
- package/x/prism/chrono/chrono.js +79 -0
- package/x/prism/chrono/chrono.js.map +1 -0
- package/x/prism/chrono/types.d.ts +5 -0
- package/x/prism/chrono/types.js +2 -0
- package/x/prism/chrono/types.js.map +1 -0
- package/x/prism/index.d.ts +9 -0
- package/x/prism/index.js +10 -0
- package/x/prism/index.js.map +1 -0
- package/x/prism/lens.d.ts +13 -0
- package/x/prism/lens.js +45 -0
- package/x/prism/lens.js.map +1 -0
- package/x/prism/prism.d.ts +10 -0
- package/x/prism/prism.js +37 -0
- package/x/prism/prism.js.map +1 -0
- package/x/prism/prism.test.d.ts +36 -0
- package/x/prism/prism.test.js +298 -0
- package/x/prism/prism.test.js.map +1 -0
- package/x/prism/types.d.ts +17 -0
- package/x/prism/types.js +2 -0
- package/x/prism/types.js.map +1 -0
- package/x/prism/utils/cache-cell.d.ts +7 -0
- package/x/prism/utils/cache-cell.js +20 -0
- package/x/prism/utils/cache-cell.js.map +1 -0
- package/x/prism/utils/immute.d.ts +2 -0
- package/x/prism/utils/immute.js +5 -0
- package/x/prism/utils/immute.js.map +1 -0
- package/x/prism/utils/optic-symbol.d.ts +1 -0
- package/x/prism/utils/optic-symbol.js +2 -0
- package/x/prism/utils/optic-symbol.js.map +1 -0
- package/x/prism/vault/local-store.d.ts +9 -0
- package/x/prism/vault/local-store.js +27 -0
- package/x/prism/vault/local-store.js.map +1 -0
- package/x/prism/vault/types.d.ts +14 -0
- package/x/prism/vault/types.js +2 -0
- package/x/prism/vault/types.js.map +1 -0
- package/x/prism/vault/vault.d.ts +7 -0
- package/x/prism/vault/vault.js +17 -0
- package/x/prism/vault/vault.js.map +1 -0
- package/x/tests.test.js +3 -1
- package/x/tests.test.js.map +1 -1
- package/x/tree/parts/branch.d.ts +4 -2
- package/x/tree/parts/branch.js +17 -9
- package/x/tree/parts/branch.js.map +1 -1
- package/x/tree/parts/chronobranch.d.ts +3 -1
- package/x/tree/parts/chronobranch.js +1 -0
- package/x/tree/parts/chronobranch.js.map +1 -1
- package/x/tree/parts/trunk.d.ts +6 -4
- package/x/tree/parts/trunk.js +1 -0
- package/x/tree/parts/trunk.js.map +1 -1
- package/x/tree/parts/types.d.ts +2 -19
- package/x/tree/parts/utils/immute.d.ts +2 -1
- package/x/tree/parts/utils/immute.js +2 -3
- package/x/tree/parts/utils/immute.js.map +1 -1
- package/x/tree/tree.test.d.ts +4 -2
- package/x/tree/tree.test.js +28 -2
- package/x/tree/tree.test.js.map +1 -1
package/s/tree/parts/types.ts
CHANGED
|
@@ -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
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type Immutable<T> =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export type Mutable<T> =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
61
|
-
|
|
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,
|
|
3
|
-
import {
|
|
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.#
|
|
33
|
+
this.on.publish(this.#immutable),
|
|
34
34
|
tracker.notifyWrite(this),
|
|
35
35
|
])
|
|
36
36
|
}
|
package/s/tree/tree.test.ts
CHANGED
|
@@ -56,7 +56,7 @@ export default Science.suite({
|
|
|
56
56
|
expect(mutationCount).is(2)
|
|
57
57
|
}),
|
|
58
58
|
|
|
59
|
-
"
|
|
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
|
-
"
|
|
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
package/x/index.js
CHANGED
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 @@
|
|
|
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 @@
|
|
|
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";
|
package/x/prism/index.js
ADDED
|
@@ -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
|
+
}
|
package/x/prism/lens.js
ADDED
|
@@ -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
|
+
}
|
package/x/prism/prism.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { microbounce, sub } from "@e280/stz";
|
|
2
|
+
import { Lens } from "./lens.js";
|
|
3
|
+
import { tracker } from "../tracker/tracker.js";
|
|
4
|
+
/** state mangagement source-of-truth */
|
|
5
|
+
export class Prism {
|
|
6
|
+
#state;
|
|
7
|
+
#lenses = new Set();
|
|
8
|
+
on = sub();
|
|
9
|
+
#onPublishDebounced = microbounce(() => this.on.publish(this.#state));
|
|
10
|
+
constructor(state) {
|
|
11
|
+
this.#state = state;
|
|
12
|
+
}
|
|
13
|
+
get() {
|
|
14
|
+
tracker.notifyRead(this);
|
|
15
|
+
return this.#state;
|
|
16
|
+
}
|
|
17
|
+
async set(state) {
|
|
18
|
+
this.#state = state;
|
|
19
|
+
await Promise.all([...this.#lenses].map(lens => lens.update()));
|
|
20
|
+
await this.#onPublishDebounced();
|
|
21
|
+
await tracker.notifyWrite(this);
|
|
22
|
+
}
|
|
23
|
+
lens(selector) {
|
|
24
|
+
const lens = new Lens({
|
|
25
|
+
getState: () => selector(this.#state),
|
|
26
|
+
mutate: async (fn) => {
|
|
27
|
+
const result = fn(selector(this.#state));
|
|
28
|
+
await this.set(this.#state);
|
|
29
|
+
return result;
|
|
30
|
+
},
|
|
31
|
+
registerLens: lens => this.#lenses.add(lens),
|
|
32
|
+
});
|
|
33
|
+
this.#lenses.add(lens);
|
|
34
|
+
return lens;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# 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;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAE/C,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,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACxB,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;QAChC,MAAM,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAChC,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,36 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
prism: {
|
|
3
|
+
"get/set state": import("@e280/science").Test;
|
|
4
|
+
"get/set state can trigger effects": import("@e280/science").Test;
|
|
5
|
+
};
|
|
6
|
+
lens: {
|
|
7
|
+
"get state": import("@e280/science").Test;
|
|
8
|
+
"state is immutable": import("@e280/science").Test;
|
|
9
|
+
"proper mutation": import("@e280/science").Test;
|
|
10
|
+
"state after mutation is frozen": import("@e280/science").Test;
|
|
11
|
+
"effect reacts": import("@e280/science").Test;
|
|
12
|
+
"lens.on is debounced": import("@e280/science").Test;
|
|
13
|
+
"array pushes are reactive": import("@e280/science").Test;
|
|
14
|
+
"sync coherence": import("@e280/science").Test;
|
|
15
|
+
"nullable selector": import("@e280/science").Test;
|
|
16
|
+
"deep composition": import("@e280/science").Test;
|
|
17
|
+
"deep mutations": import("@e280/science").Test;
|
|
18
|
+
"outside mutations ignored": import("@e280/science").Test;
|
|
19
|
+
"outside mutations ignored for effects": import("@e280/science").Test;
|
|
20
|
+
};
|
|
21
|
+
chrono: {
|
|
22
|
+
"get present state": import("@e280/science").Test;
|
|
23
|
+
mutation: import("@e280/science").Test;
|
|
24
|
+
"undoable/redoable": import("@e280/science").Test;
|
|
25
|
+
undo: import("@e280/science").Test;
|
|
26
|
+
"sync undo": import("@e280/science").Test;
|
|
27
|
+
redo: import("@e280/science").Test;
|
|
28
|
+
"undo/redo is orderly": import("@e280/science").Test;
|
|
29
|
+
"undo nothing does nothing": import("@e280/science").Test;
|
|
30
|
+
"redo nothing does nothing": import("@e280/science").Test;
|
|
31
|
+
"undo 2x": import("@e280/science").Test;
|
|
32
|
+
"redo 2x": import("@e280/science").Test;
|
|
33
|
+
"sublens mutations are undoable": import("@e280/science").Test;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export default _default;
|