@e280/strata 0.0.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +73 -0
- package/package.json +46 -0
- package/s/index.ts +5 -0
- package/s/parts/strata.ts +48 -0
- package/s/parts/substrata.ts +55 -0
- package/s/parts/types.ts +11 -0
- package/s/parts/utils/process-options.ts +7 -0
- package/s/tests.test.ts +119 -0
- package/x/index.d.ts +3 -0
- package/x/index.js +3 -0
- package/x/index.js.map +1 -0
- package/x/parts/strata.d.ts +10 -0
- package/x/parts/strata.js +38 -0
- package/x/parts/strata.js.map +1 -0
- package/x/parts/substrata.d.ts +13 -0
- package/x/parts/substrata.js +42 -0
- package/x/parts/substrata.js.map +1 -0
- package/x/parts/types.d.ts +7 -0
- package/x/parts/types.js +2 -0
- package/x/parts/types.js.map +1 -0
- package/x/parts/utils/process-options.d.ts +2 -0
- package/x/parts/utils/process-options.js +4 -0
- package/x/parts/utils/process-options.js.map +1 -0
- package/x/tests.test.d.ts +1 -0
- package/x/tests.test.js +106 -0
- package/x/tests.test.js.map +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2025 Chase Moskal
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
23
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
|
|
2
|
+
# ⛏️ strata
|
|
3
|
+
|
|
4
|
+
**my 10th state management library, probably**
|
|
5
|
+
- 📦 `npm install @e280/strata`
|
|
6
|
+
- single-source-of-truth state tree
|
|
7
|
+
- immutable except for `mutate(fn)` calls
|
|
8
|
+
- undo/redo history, cross-tab sync, localStorage persistence
|
|
9
|
+
|
|
10
|
+
## good state management
|
|
11
|
+
|
|
12
|
+
### establish a strata with some state
|
|
13
|
+
- better stick to json-friendly serializable data
|
|
14
|
+
```ts
|
|
15
|
+
import {Strata} from "@e280/strata"
|
|
16
|
+
|
|
17
|
+
const strata = new Strata({
|
|
18
|
+
count: 0,
|
|
19
|
+
stuff: {
|
|
20
|
+
peanuts: 8,
|
|
21
|
+
items: ["hello", "world"],
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
strata.state.count // 0
|
|
26
|
+
strata.state.stuff.peanuts // 8
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### how mutations work
|
|
30
|
+
- ⛔ informal mutations are denied
|
|
31
|
+
```ts
|
|
32
|
+
strata.state.count++ // error is thrown
|
|
33
|
+
```
|
|
34
|
+
- ✅ formal mutation is allowed
|
|
35
|
+
```ts
|
|
36
|
+
await strata.mutate(s => s.count++)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### substrata and selectors
|
|
40
|
+
- a substrata is a view into a subset of the state tree
|
|
41
|
+
```ts
|
|
42
|
+
const stuff = strata.substrata(s => s.stuff)
|
|
43
|
+
```
|
|
44
|
+
- run substrata mutations
|
|
45
|
+
```ts
|
|
46
|
+
await stuff.mutate(s => s.peanuts++)
|
|
47
|
+
```
|
|
48
|
+
- array mutations are cool, actually
|
|
49
|
+
```ts
|
|
50
|
+
await stuff.mutate(s => s.items.push("lol"))
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### onMutation events
|
|
54
|
+
- you can listen to global mutations on the strata
|
|
55
|
+
```ts
|
|
56
|
+
strata.onMutation(s => console.log(s.count))
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- substrata listeners don't care about outside changes
|
|
60
|
+
```ts
|
|
61
|
+
stuff.onMutation(s => console.log(s.peanuts))
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- onMutation returns a fn to stop listening
|
|
65
|
+
```ts
|
|
66
|
+
const stop = strata.onMutation(s => console.log(s.count))
|
|
67
|
+
stop() // stop listening
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## a buildercore e280 project
|
|
71
|
+
free and open source by https://e280.org/
|
|
72
|
+
join us if you're cool and good at dev
|
|
73
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@e280/strata",
|
|
3
|
+
"version": "0.0.0-0",
|
|
4
|
+
"description": "state management",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Chase Moskal <chasemoskal@gmail.com>",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "x/index.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"x",
|
|
11
|
+
"s"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "run-s _clean _links _tsc",
|
|
15
|
+
"test": "node x/tests.test.js",
|
|
16
|
+
"test-watch": "node --watch x/tests.test.js",
|
|
17
|
+
"test-inspect": "node inspect x/tests.test.js",
|
|
18
|
+
"count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +",
|
|
19
|
+
"watch": "run-p _tscw test-watch",
|
|
20
|
+
"_clean": "rm -rf x && mkdir x",
|
|
21
|
+
"_links": "ln -s \"$(realpath node_modules)\" x/node_modules",
|
|
22
|
+
"_tsc": "tsc",
|
|
23
|
+
"_tscw": "tsc -w"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@e280/science": "^0.0.5",
|
|
27
|
+
"@types/node": "^24.0.3",
|
|
28
|
+
"npm-run-all": "^4.1.5",
|
|
29
|
+
"typescript": "^5.8.3"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"state",
|
|
33
|
+
"state management"
|
|
34
|
+
],
|
|
35
|
+
"homepage": "https://github.com/e280/strata#readme",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/e280/strata.git"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/e280/strata/issues"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@e280/stz": "^0.0.0-24"
|
|
45
|
+
}
|
|
46
|
+
}
|
package/s/index.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
|
|
2
|
+
import {debounce, deep, sub} from "@e280/stz"
|
|
3
|
+
|
|
4
|
+
import {Substrata} from "./substrata.js"
|
|
5
|
+
import {processOptions} from "./utils/process-options.js"
|
|
6
|
+
import {Mutator, Options, Selector, State, Substate} from "./types.js"
|
|
7
|
+
|
|
8
|
+
export class Strata<S extends State> {
|
|
9
|
+
onMutation = sub<[state: S]>()
|
|
10
|
+
|
|
11
|
+
#options: Options
|
|
12
|
+
#mutable: S
|
|
13
|
+
#immutable: S
|
|
14
|
+
#dispatchMutation = debounce(0, (state: S) => this.onMutation.pub(state))
|
|
15
|
+
|
|
16
|
+
constructor(state: S, options: Partial<Options> = {}) {
|
|
17
|
+
this.#options = processOptions(options)
|
|
18
|
+
this.#mutable = state
|
|
19
|
+
this.#immutable = deep.freeze(this.#options.clone(state))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#updateState(state: S) {
|
|
23
|
+
this.#mutable = state
|
|
24
|
+
this.#immutable = deep.freeze(this.#options.clone(state))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get state() {
|
|
28
|
+
return this.#immutable
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
substrata<Sub extends Substate>(selector: Selector<S, Sub>) {
|
|
32
|
+
return new Substrata(this, selector, this.#options)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async mutate(mutator: Mutator<S>) {
|
|
36
|
+
const oldState = this.#options.clone(this.#mutable)
|
|
37
|
+
mutator(this.#mutable)
|
|
38
|
+
const newState = this.#mutable
|
|
39
|
+
const isChanged = !deep.equal(newState, oldState)
|
|
40
|
+
if (isChanged) {
|
|
41
|
+
this.#updateState(newState)
|
|
42
|
+
const immutable = this.state
|
|
43
|
+
await this.#dispatchMutation(immutable)
|
|
44
|
+
}
|
|
45
|
+
return this.#immutable
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
|
|
2
|
+
import {debounce, deep, sub} from "@e280/stz"
|
|
3
|
+
|
|
4
|
+
import {Strata} from "./strata.js"
|
|
5
|
+
import {processOptions} from "./utils/process-options.js"
|
|
6
|
+
import {Mutator, Options, Selector, State, Substate} from "./types.js"
|
|
7
|
+
|
|
8
|
+
export class Substrata<ParentState extends State, S extends Substate> {
|
|
9
|
+
dispose: () => void
|
|
10
|
+
onMutation = sub<[state: S]>()
|
|
11
|
+
|
|
12
|
+
#options: Options
|
|
13
|
+
#immutable: S
|
|
14
|
+
#dispatchMutation = debounce(0, (state: S) => this.onMutation.pub(state))
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
private strata: Strata<ParentState>,
|
|
18
|
+
private selector: Selector<ParentState, S>,
|
|
19
|
+
options: Partial<Options> = {},
|
|
20
|
+
) {
|
|
21
|
+
|
|
22
|
+
this.#options = processOptions(options)
|
|
23
|
+
const state = this.selector(this.strata.state)
|
|
24
|
+
this.#immutable = deep.freeze(this.#options.clone(state))
|
|
25
|
+
|
|
26
|
+
this.dispose = this.strata.onMutation(async parentState => {
|
|
27
|
+
const oldState = this.#immutable
|
|
28
|
+
const newState = this.selector(parentState)
|
|
29
|
+
const isChanged = !deep.equal(newState, oldState)
|
|
30
|
+
if (isChanged) {
|
|
31
|
+
this.#updateState(newState)
|
|
32
|
+
const immutable = this.state
|
|
33
|
+
await this.#dispatchMutation(immutable)
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#updateState(state: S) {
|
|
39
|
+
this.#immutable = deep.freeze(this.#options.clone(state))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get state(): S {
|
|
43
|
+
return this.#immutable
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async mutate(mutator: Mutator<S>) {
|
|
47
|
+
await this.strata.mutate(parentState => mutator(this.selector(parentState)))
|
|
48
|
+
return this.#immutable
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
substrata<Sub extends Substate>(selector: Selector<S, Sub>) {
|
|
52
|
+
return this.strata.substrata(parentState => selector(this.selector(parentState)))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
package/s/parts/types.ts
ADDED
package/s/tests.test.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
|
|
2
|
+
import {expect, Science} from "@e280/science"
|
|
3
|
+
import {Strata} from "./parts/strata.js"
|
|
4
|
+
|
|
5
|
+
await Science.run({
|
|
6
|
+
"strata": Science.suite({
|
|
7
|
+
"get state": Science.test(async() => {
|
|
8
|
+
const strata = new Strata({count: 0})
|
|
9
|
+
expect(strata.state.count).is(0)
|
|
10
|
+
}),
|
|
11
|
+
|
|
12
|
+
"state is immutable": Science.test(async() => {
|
|
13
|
+
const strata = new Strata({count: 0})
|
|
14
|
+
expect(() => strata.state.count++).throws()
|
|
15
|
+
}),
|
|
16
|
+
|
|
17
|
+
"run a proper mutation": Science.test(async() => {
|
|
18
|
+
const strata = new Strata({count: 0})
|
|
19
|
+
expect(strata.state.count).is(0)
|
|
20
|
+
await strata.mutate(state => state.count++)
|
|
21
|
+
expect(strata.state.count).is(1)
|
|
22
|
+
await strata.mutate(state => state.count++)
|
|
23
|
+
expect(strata.state.count).is(2)
|
|
24
|
+
}),
|
|
25
|
+
|
|
26
|
+
"state after mutation is frozen": Science.test(async () => {
|
|
27
|
+
const strata = new Strata({x: 1})
|
|
28
|
+
await strata.mutate(s => { s.x = 2 })
|
|
29
|
+
expect(() => strata.state.x = 3).throws()
|
|
30
|
+
}),
|
|
31
|
+
|
|
32
|
+
"onMutation is published": Science.test(async() => {
|
|
33
|
+
const strata = new Strata({count: 0})
|
|
34
|
+
let mutationCount = 0
|
|
35
|
+
strata.onMutation.sub(() => {mutationCount++})
|
|
36
|
+
await strata.mutate(state => state.count++)
|
|
37
|
+
expect(mutationCount).is(1)
|
|
38
|
+
}),
|
|
39
|
+
|
|
40
|
+
"onMutation is debounced": Science.test(async() => {
|
|
41
|
+
const strata = new Strata({count: 0})
|
|
42
|
+
let mutationCount = 0
|
|
43
|
+
strata.onMutation.sub(() => {mutationCount++})
|
|
44
|
+
const promise = strata.mutate(state => state.count++)
|
|
45
|
+
expect(mutationCount).is(0)
|
|
46
|
+
await promise
|
|
47
|
+
expect(mutationCount).is(1)
|
|
48
|
+
}),
|
|
49
|
+
|
|
50
|
+
"onMutation is fired when array item is pushed": Science.test(async() => {
|
|
51
|
+
const strata = new Strata({items: ["hello", "world"]})
|
|
52
|
+
let mutationCount = 0
|
|
53
|
+
strata.onMutation.sub(() => {mutationCount++})
|
|
54
|
+
await strata.mutate(state => state.items.push("lol"))
|
|
55
|
+
expect(mutationCount).is(1)
|
|
56
|
+
expect(strata.state.items.length).is(3)
|
|
57
|
+
}),
|
|
58
|
+
}),
|
|
59
|
+
|
|
60
|
+
"substrata": Science.suite({
|
|
61
|
+
"get state": Science.test(async() => {
|
|
62
|
+
const strata = new Strata({count: 0, sub: {rofls: 0}})
|
|
63
|
+
const substrata = strata.substrata(s => s.sub)
|
|
64
|
+
expect(substrata.state.rofls).is(0)
|
|
65
|
+
}),
|
|
66
|
+
|
|
67
|
+
"nullable selector": Science.test(async () => {
|
|
68
|
+
const strata = new Strata({
|
|
69
|
+
a: {b: 0} as (null | {b: number}),
|
|
70
|
+
})
|
|
71
|
+
const a = strata.substrata(s => s.a)
|
|
72
|
+
expect(strata.state.a?.b).is(0)
|
|
73
|
+
expect(a.state?.b).is(0)
|
|
74
|
+
await a.mutate(a => { a!.b = 1 })
|
|
75
|
+
expect(strata.state.a?.b).is(1)
|
|
76
|
+
expect(a.state?.b).is(1)
|
|
77
|
+
await strata.mutate(s => s.a = null)
|
|
78
|
+
expect(strata.state.a?.b).is(undefined)
|
|
79
|
+
expect(a.state?.b).is(undefined)
|
|
80
|
+
}),
|
|
81
|
+
|
|
82
|
+
"composition": Science.test(async () => {
|
|
83
|
+
const strata = new Strata({a: {b: {c: 0}}})
|
|
84
|
+
const a = strata.substrata(s => s.a)
|
|
85
|
+
const b = a.substrata(s => s.b)
|
|
86
|
+
expect(strata.state.a.b.c).is(0)
|
|
87
|
+
expect(b.state.c).is(0)
|
|
88
|
+
}),
|
|
89
|
+
|
|
90
|
+
"deep mutations": Science.test(async () => {
|
|
91
|
+
const strata = new Strata({a: {b: {c: 0}}})
|
|
92
|
+
const a = strata.substrata(s => s.a)
|
|
93
|
+
const b = a.substrata(s => s.b)
|
|
94
|
+
await b.mutate(b => { b.c = 101 })
|
|
95
|
+
expect(strata.state.a.b.c).is(101)
|
|
96
|
+
expect(a.state.b.c).is(101)
|
|
97
|
+
expect(b.state.c).is(101)
|
|
98
|
+
await a.mutate(a => { a.b = {c: 102} })
|
|
99
|
+
expect(strata.state.a.b.c).is(102)
|
|
100
|
+
expect(a.state.b.c).is(102)
|
|
101
|
+
expect(b.state.c).is(102)
|
|
102
|
+
await strata.mutate(s => { s.a = {b: {c: 103}} })
|
|
103
|
+
expect(strata.state.a.b.c).is(103)
|
|
104
|
+
expect(a.state.b.c).is(103)
|
|
105
|
+
expect(b.state.c).is(103)
|
|
106
|
+
}),
|
|
107
|
+
|
|
108
|
+
"onMutation ignores outside mutations": Science.test(async() => {
|
|
109
|
+
const strata = new Strata({a: {x: 0}, b: {x: 0}})
|
|
110
|
+
const a = strata.substrata(s => s.a)
|
|
111
|
+
const b = strata.substrata(s => s.b)
|
|
112
|
+
let counted = 0
|
|
113
|
+
b.onMutation.sub(() => {counted++})
|
|
114
|
+
await a.mutate(a => a.x = 1)
|
|
115
|
+
expect(counted).is(0)
|
|
116
|
+
}),
|
|
117
|
+
}),
|
|
118
|
+
})
|
|
119
|
+
|
package/x/index.d.ts
ADDED
package/x/index.js
ADDED
package/x/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../s/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAA;AACxC,OAAO,EAAC,SAAS,EAAC,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Substrata } from "./substrata.js";
|
|
2
|
+
import { Mutator, Options, Selector, State, Substate } from "./types.js";
|
|
3
|
+
export declare class Strata<S extends State> {
|
|
4
|
+
#private;
|
|
5
|
+
onMutation: import("@e280/stz").Sub<[state: S]>;
|
|
6
|
+
constructor(state: S, options?: Partial<Options>);
|
|
7
|
+
get state(): S;
|
|
8
|
+
substrata<Sub extends Substate>(selector: Selector<S, Sub>): Substrata<S, Sub>;
|
|
9
|
+
mutate(mutator: Mutator<S>): Promise<S>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { debounce, deep, sub } from "@e280/stz";
|
|
2
|
+
import { Substrata } from "./substrata.js";
|
|
3
|
+
import { processOptions } from "./utils/process-options.js";
|
|
4
|
+
export class Strata {
|
|
5
|
+
onMutation = sub();
|
|
6
|
+
#options;
|
|
7
|
+
#mutable;
|
|
8
|
+
#immutable;
|
|
9
|
+
#dispatchMutation = debounce(0, (state) => this.onMutation.pub(state));
|
|
10
|
+
constructor(state, options = {}) {
|
|
11
|
+
this.#options = processOptions(options);
|
|
12
|
+
this.#mutable = state;
|
|
13
|
+
this.#immutable = deep.freeze(this.#options.clone(state));
|
|
14
|
+
}
|
|
15
|
+
#updateState(state) {
|
|
16
|
+
this.#mutable = state;
|
|
17
|
+
this.#immutable = deep.freeze(this.#options.clone(state));
|
|
18
|
+
}
|
|
19
|
+
get state() {
|
|
20
|
+
return this.#immutable;
|
|
21
|
+
}
|
|
22
|
+
substrata(selector) {
|
|
23
|
+
return new Substrata(this, selector, this.#options);
|
|
24
|
+
}
|
|
25
|
+
async mutate(mutator) {
|
|
26
|
+
const oldState = this.#options.clone(this.#mutable);
|
|
27
|
+
mutator(this.#mutable);
|
|
28
|
+
const newState = this.#mutable;
|
|
29
|
+
const isChanged = !deep.equal(newState, oldState);
|
|
30
|
+
if (isChanged) {
|
|
31
|
+
this.#updateState(newState);
|
|
32
|
+
const immutable = this.state;
|
|
33
|
+
await this.#dispatchMutation(immutable);
|
|
34
|
+
}
|
|
35
|
+
return this.#immutable;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=strata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strata.js","sourceRoot":"","sources":["../../s/parts/strata.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAC,MAAM,WAAW,CAAA;AAE7C,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAA;AAGzD,MAAM,OAAO,MAAM;IAClB,UAAU,GAAG,GAAG,EAAc,CAAA;IAE9B,QAAQ,CAAS;IACjB,QAAQ,CAAG;IACX,UAAU,CAAG;IACb,iBAAiB,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;IAEzE,YAAY,KAAQ,EAAE,UAA4B,EAAE;QACnD,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QACvC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAA;QACrB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IAC1D,CAAC;IAED,YAAY,CAAC,KAAQ;QACpB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAA;QACrB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IAC1D,CAAC;IAED,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,UAAU,CAAA;IACvB,CAAC;IAED,SAAS,CAAuB,QAA0B;QACzD,OAAO,IAAI,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;IACpD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAmB;QAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACnD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;QAC9B,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;QACjD,IAAI,SAAS,EAAE,CAAC;YACf,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;YAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAA;YAC5B,MAAM,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAA;QACxC,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAA;IACvB,CAAC;CACD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Strata } from "./strata.js";
|
|
2
|
+
import { Mutator, Options, Selector, State, Substate } from "./types.js";
|
|
3
|
+
export declare class Substrata<ParentState extends State, S extends Substate> {
|
|
4
|
+
#private;
|
|
5
|
+
private strata;
|
|
6
|
+
private selector;
|
|
7
|
+
dispose: () => void;
|
|
8
|
+
onMutation: import("@e280/stz").Sub<[state: S]>;
|
|
9
|
+
constructor(strata: Strata<ParentState>, selector: Selector<ParentState, S>, options?: Partial<Options>);
|
|
10
|
+
get state(): S;
|
|
11
|
+
mutate(mutator: Mutator<S>): Promise<S>;
|
|
12
|
+
substrata<Sub extends Substate>(selector: Selector<S, Sub>): Substrata<ParentState, Sub>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { debounce, deep, sub } from "@e280/stz";
|
|
2
|
+
import { processOptions } from "./utils/process-options.js";
|
|
3
|
+
export class Substrata {
|
|
4
|
+
strata;
|
|
5
|
+
selector;
|
|
6
|
+
dispose;
|
|
7
|
+
onMutation = sub();
|
|
8
|
+
#options;
|
|
9
|
+
#immutable;
|
|
10
|
+
#dispatchMutation = debounce(0, (state) => this.onMutation.pub(state));
|
|
11
|
+
constructor(strata, selector, options = {}) {
|
|
12
|
+
this.strata = strata;
|
|
13
|
+
this.selector = selector;
|
|
14
|
+
this.#options = processOptions(options);
|
|
15
|
+
const state = this.selector(this.strata.state);
|
|
16
|
+
this.#immutable = deep.freeze(this.#options.clone(state));
|
|
17
|
+
this.dispose = this.strata.onMutation(async (parentState) => {
|
|
18
|
+
const oldState = this.#immutable;
|
|
19
|
+
const newState = this.selector(parentState);
|
|
20
|
+
const isChanged = !deep.equal(newState, oldState);
|
|
21
|
+
if (isChanged) {
|
|
22
|
+
this.#updateState(newState);
|
|
23
|
+
const immutable = this.state;
|
|
24
|
+
await this.#dispatchMutation(immutable);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
#updateState(state) {
|
|
29
|
+
this.#immutable = deep.freeze(this.#options.clone(state));
|
|
30
|
+
}
|
|
31
|
+
get state() {
|
|
32
|
+
return this.#immutable;
|
|
33
|
+
}
|
|
34
|
+
async mutate(mutator) {
|
|
35
|
+
await this.strata.mutate(parentState => mutator(this.selector(parentState)));
|
|
36
|
+
return this.#immutable;
|
|
37
|
+
}
|
|
38
|
+
substrata(selector) {
|
|
39
|
+
return this.strata.substrata(parentState => selector(this.selector(parentState)));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=substrata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"substrata.js","sourceRoot":"","sources":["../../s/parts/substrata.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAC,MAAM,WAAW,CAAA;AAG7C,OAAO,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAA;AAGzD,MAAM,OAAO,SAAS;IASX;IACA;IATV,OAAO,CAAY;IACnB,UAAU,GAAG,GAAG,EAAc,CAAA;IAE9B,QAAQ,CAAS;IACjB,UAAU,CAAG;IACb,iBAAiB,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;IAEzE,YACU,MAA2B,EAC3B,QAAkC,EAC1C,UAA4B,EAAE;QAFtB,WAAM,GAAN,MAAM,CAAqB;QAC3B,aAAQ,GAAR,QAAQ,CAA0B;QAI3C,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC9C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;QAEzD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAC,WAAW,EAAC,EAAE;YACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAA;YAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;YAC3C,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;YACjD,IAAI,SAAS,EAAE,CAAC;gBACf,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;gBAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAA;gBAC5B,MAAM,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAA;YACxC,CAAC;QACF,CAAC,CAAC,CAAA;IACH,CAAC;IAED,YAAY,CAAC,KAAQ;QACpB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IAC1D,CAAC;IAED,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,UAAU,CAAA;IACvB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAmB;QAC/B,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;QAC5E,OAAO,IAAI,CAAC,UAAU,CAAA;IACvB,CAAC;IAED,SAAS,CAAuB,QAA0B;QACzD,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;IAClF,CAAC;CACD"}
|
package/x/parts/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../s/parts/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-options.js","sourceRoot":"","sources":["../../../s/parts/utils/process-options.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAyB,EAAW,EAAE,CAAC,CAAC;IACtE,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,eAAe;CACvC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/x/tests.test.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { expect, Science } from "@e280/science";
|
|
2
|
+
import { Strata } from "./parts/strata.js";
|
|
3
|
+
await Science.run({
|
|
4
|
+
"strata": Science.suite({
|
|
5
|
+
"get state": Science.test(async () => {
|
|
6
|
+
const strata = new Strata({ count: 0 });
|
|
7
|
+
expect(strata.state.count).is(0);
|
|
8
|
+
}),
|
|
9
|
+
"state is immutable": Science.test(async () => {
|
|
10
|
+
const strata = new Strata({ count: 0 });
|
|
11
|
+
expect(() => strata.state.count++).throws();
|
|
12
|
+
}),
|
|
13
|
+
"run a proper mutation": Science.test(async () => {
|
|
14
|
+
const strata = new Strata({ count: 0 });
|
|
15
|
+
expect(strata.state.count).is(0);
|
|
16
|
+
await strata.mutate(state => state.count++);
|
|
17
|
+
expect(strata.state.count).is(1);
|
|
18
|
+
await strata.mutate(state => state.count++);
|
|
19
|
+
expect(strata.state.count).is(2);
|
|
20
|
+
}),
|
|
21
|
+
"state after mutation is frozen": Science.test(async () => {
|
|
22
|
+
const strata = new Strata({ x: 1 });
|
|
23
|
+
await strata.mutate(s => { s.x = 2; });
|
|
24
|
+
expect(() => strata.state.x = 3).throws();
|
|
25
|
+
}),
|
|
26
|
+
"onMutation is published": Science.test(async () => {
|
|
27
|
+
const strata = new Strata({ count: 0 });
|
|
28
|
+
let mutationCount = 0;
|
|
29
|
+
strata.onMutation.sub(() => { mutationCount++; });
|
|
30
|
+
await strata.mutate(state => state.count++);
|
|
31
|
+
expect(mutationCount).is(1);
|
|
32
|
+
}),
|
|
33
|
+
"onMutation is debounced": Science.test(async () => {
|
|
34
|
+
const strata = new Strata({ count: 0 });
|
|
35
|
+
let mutationCount = 0;
|
|
36
|
+
strata.onMutation.sub(() => { mutationCount++; });
|
|
37
|
+
const promise = strata.mutate(state => state.count++);
|
|
38
|
+
expect(mutationCount).is(0);
|
|
39
|
+
await promise;
|
|
40
|
+
expect(mutationCount).is(1);
|
|
41
|
+
}),
|
|
42
|
+
"onMutation is fired when array item is pushed": Science.test(async () => {
|
|
43
|
+
const strata = new Strata({ items: ["hello", "world"] });
|
|
44
|
+
let mutationCount = 0;
|
|
45
|
+
strata.onMutation.sub(() => { mutationCount++; });
|
|
46
|
+
await strata.mutate(state => state.items.push("lol"));
|
|
47
|
+
expect(mutationCount).is(1);
|
|
48
|
+
expect(strata.state.items.length).is(3);
|
|
49
|
+
}),
|
|
50
|
+
}),
|
|
51
|
+
"substrata": Science.suite({
|
|
52
|
+
"get state": Science.test(async () => {
|
|
53
|
+
const strata = new Strata({ count: 0, sub: { rofls: 0 } });
|
|
54
|
+
const substrata = strata.substrata(s => s.sub);
|
|
55
|
+
expect(substrata.state.rofls).is(0);
|
|
56
|
+
}),
|
|
57
|
+
"nullable selector": Science.test(async () => {
|
|
58
|
+
const strata = new Strata({
|
|
59
|
+
a: { b: 0 },
|
|
60
|
+
});
|
|
61
|
+
const a = strata.substrata(s => s.a);
|
|
62
|
+
expect(strata.state.a?.b).is(0);
|
|
63
|
+
expect(a.state?.b).is(0);
|
|
64
|
+
await a.mutate(a => { a.b = 1; });
|
|
65
|
+
expect(strata.state.a?.b).is(1);
|
|
66
|
+
expect(a.state?.b).is(1);
|
|
67
|
+
await strata.mutate(s => s.a = null);
|
|
68
|
+
expect(strata.state.a?.b).is(undefined);
|
|
69
|
+
expect(a.state?.b).is(undefined);
|
|
70
|
+
}),
|
|
71
|
+
"composition": Science.test(async () => {
|
|
72
|
+
const strata = new Strata({ a: { b: { c: 0 } } });
|
|
73
|
+
const a = strata.substrata(s => s.a);
|
|
74
|
+
const b = a.substrata(s => s.b);
|
|
75
|
+
expect(strata.state.a.b.c).is(0);
|
|
76
|
+
expect(b.state.c).is(0);
|
|
77
|
+
}),
|
|
78
|
+
"deep mutations": Science.test(async () => {
|
|
79
|
+
const strata = new Strata({ a: { b: { c: 0 } } });
|
|
80
|
+
const a = strata.substrata(s => s.a);
|
|
81
|
+
const b = a.substrata(s => s.b);
|
|
82
|
+
await b.mutate(b => { b.c = 101; });
|
|
83
|
+
expect(strata.state.a.b.c).is(101);
|
|
84
|
+
expect(a.state.b.c).is(101);
|
|
85
|
+
expect(b.state.c).is(101);
|
|
86
|
+
await a.mutate(a => { a.b = { c: 102 }; });
|
|
87
|
+
expect(strata.state.a.b.c).is(102);
|
|
88
|
+
expect(a.state.b.c).is(102);
|
|
89
|
+
expect(b.state.c).is(102);
|
|
90
|
+
await strata.mutate(s => { s.a = { b: { c: 103 } }; });
|
|
91
|
+
expect(strata.state.a.b.c).is(103);
|
|
92
|
+
expect(a.state.b.c).is(103);
|
|
93
|
+
expect(b.state.c).is(103);
|
|
94
|
+
}),
|
|
95
|
+
"onMutation ignores outside mutations": Science.test(async () => {
|
|
96
|
+
const strata = new Strata({ a: { x: 0 }, b: { x: 0 } });
|
|
97
|
+
const a = strata.substrata(s => s.a);
|
|
98
|
+
const b = strata.substrata(s => s.b);
|
|
99
|
+
let counted = 0;
|
|
100
|
+
b.onMutation.sub(() => { counted++; });
|
|
101
|
+
await a.mutate(a => a.x = 1);
|
|
102
|
+
expect(counted).is(0);
|
|
103
|
+
}),
|
|
104
|
+
}),
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=tests.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tests.test.js","sourceRoot":"","sources":["../s/tests.test.ts"],"names":[],"mappings":"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"}
|