@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 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,5 @@
1
+
2
+ export {Strata} from "./parts/strata.js"
3
+ export {Substrata} from "./parts/substrata.js"
4
+ export {Options, Mutator, Selector} from "./parts/types.js"
5
+
@@ -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
+
@@ -0,0 +1,11 @@
1
+
2
+ export type Options = {
3
+ clone: <X>(x: X) => X
4
+ }
5
+
6
+ export type Selector<S, Sub> = (state: S) => Sub
7
+ export type Mutator<S> = (state: S) => void
8
+
9
+ export type State = {}
10
+ export type Substate = {} | null | undefined
11
+
@@ -0,0 +1,7 @@
1
+
2
+ import {Options} from "../types.js"
3
+
4
+ export const processOptions = (options: Partial<Options>): Options => ({
5
+ clone: options.clone ?? structuredClone,
6
+ })
7
+
@@ -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
@@ -0,0 +1,3 @@
1
+ export { Strata } from "./parts/strata.js";
2
+ export { Substrata } from "./parts/substrata.js";
3
+ export { Options, Mutator, Selector } from "./parts/types.js";
package/x/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { Strata } from "./parts/strata.js";
2
+ export { Substrata } from "./parts/substrata.js";
3
+ //# sourceMappingURL=index.js.map
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"}
@@ -0,0 +1,7 @@
1
+ export type Options = {
2
+ clone: <X>(x: X) => X;
3
+ };
4
+ export type Selector<S, Sub> = (state: S) => Sub;
5
+ export type Mutator<S> = (state: S) => void;
6
+ export type State = {};
7
+ export type Substate = {} | null | undefined;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../s/parts/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ import { Options } from "../types.js";
2
+ export declare const processOptions: (options: Partial<Options>) => Options;
@@ -0,0 +1,4 @@
1
+ export const processOptions = (options) => ({
2
+ clone: options.clone ?? structuredClone,
3
+ });
4
+ //# sourceMappingURL=process-options.js.map
@@ -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 {};
@@ -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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"}