@xmachines/play-xstate 2.2.0 → 4.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/README.md +158 -54
- package/dist/capabilities.d.ts +92 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +4 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/define-player.d.ts +7 -1
- package/dist/define-player.d.ts.map +1 -1
- package/dist/define-player.js +9 -60
- package/dist/define-player.js.map +1 -1
- package/dist/errors.d.ts +29 -26
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +53 -35
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -4
- package/dist/index.js.map +1 -1
- package/dist/player-actor.d.ts +74 -114
- package/dist/player-actor.d.ts.map +1 -1
- package/dist/player-actor.js +94 -223
- package/dist/player-actor.js.map +1 -1
- package/dist/routing/derive-current-route.d.ts +1 -36
- package/dist/routing/derive-current-route.d.ts.map +1 -1
- package/dist/routing/derive-current-route.js +2 -76
- package/dist/routing/derive-current-route.js.map +1 -1
- package/dist/routing/derive-initial-route.d.ts.map +1 -1
- package/dist/routing/derive-initial-route.js +11 -0
- package/dist/routing/derive-initial-route.js.map +1 -1
- package/dist/routing/derive-route.d.ts +81 -2
- package/dist/routing/derive-route.d.ts.map +1 -1
- package/dist/routing/derive-route.js +97 -3
- package/dist/routing/derive-route.js.map +1 -1
- package/dist/routing/format-play-route-transitions.d.ts +8 -2
- package/dist/routing/format-play-route-transitions.d.ts.map +1 -1
- package/dist/routing/format-play-route-transitions.js +170 -43
- package/dist/routing/format-play-route-transitions.js.map +1 -1
- package/dist/routing/index.d.ts +1 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/types.d.ts +9 -5
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/state-meta.d.ts +52 -0
- package/dist/state-meta.d.ts.map +1 -0
- package/dist/state-meta.js +77 -0
- package/dist/state-meta.js.map +1 -0
- package/dist/types.d.ts +18 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/view/derive-current-view.d.ts +1 -1
- package/dist/view/derive-current-view.d.ts.map +1 -1
- package/dist/view/derive-current-view.js +35 -17
- package/dist/view/derive-current-view.js.map +1 -1
- package/dist/with-routing.d.ts +45 -0
- package/dist/with-routing.d.ts.map +1 -0
- package/dist/with-routing.js +78 -0
- package/dist/with-routing.js.map +1 -0
- package/dist/with-view.d.ts +42 -0
- package/dist/with-view.d.ts.map +1 -0
- package/dist/with-view.js +150 -0
- package/dist/with-view.js.map +1 -0
- package/package.json +39 -18
- package/dist/guards/compose.d.ts +0 -158
- package/dist/guards/compose.d.ts.map +0 -1
- package/dist/guards/compose.js +0 -188
- package/dist/guards/compose.js.map +0 -1
- package/dist/guards/helpers.d.ts +0 -62
- package/dist/guards/helpers.d.ts.map +0 -1
- package/dist/guards/helpers.js +0 -85
- package/dist/guards/helpers.js.map +0 -1
- package/dist/guards/index.d.ts +0 -20
- package/dist/guards/index.d.ts.map +0 -1
- package/dist/guards/index.js +0 -18
- package/dist/guards/index.js.map +0 -1
- package/dist/guards/types.d.ts +0 -22
- package/dist/guards/types.d.ts.map +0 -1
- package/dist/guards/types.js +0 -2
- package/dist/guards/types.js.map +0 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { Signal } from "@xmachines/play-signals";
|
|
2
|
+
import { shallowEqualExcept } from "@xmachines/play";
|
|
3
|
+
import { reuseComposedState } from "@xmachines/play-view";
|
|
4
|
+
import { toError } from "./player-actor.js";
|
|
5
|
+
import { deriveCurrentView } from "./view/derive-current-view.js";
|
|
6
|
+
/**
|
|
7
|
+
* The structural equality of two derived view specs, with a limit on its depth.
|
|
8
|
+
*
|
|
9
|
+
* The function walks exactly the shape that `deriveCurrentView` builds: the spec
|
|
10
|
+
* fields, then `elements`, then the `props` object of each element. It compares
|
|
11
|
+
* each leaf with `Object.is`. It never enters the VALUE of a prop: a new reference
|
|
12
|
+
* therefore emits the view again, also when the contents are equal. This design
|
|
13
|
+
* keeps two things correct: a prop of a container (a Map, a Set, or an instance of a
|
|
14
|
+
* class, which a structural comparison cannot see), and a cyclic value, which gives
|
|
15
|
+
* a structural comparison a recursion without an end.
|
|
16
|
+
*/
|
|
17
|
+
const viewSpecsEquivalent = (a, b) => {
|
|
18
|
+
if (a === b)
|
|
19
|
+
return true;
|
|
20
|
+
if (!a || !b)
|
|
21
|
+
return false;
|
|
22
|
+
if (!shallowEqualExcept(a, b, "elements"))
|
|
23
|
+
return false;
|
|
24
|
+
const aElements = a.elements ?? {};
|
|
25
|
+
const bElements = b.elements ?? {};
|
|
26
|
+
// A derived spec spreads the same static meta.view. Therefore the elements
|
|
27
|
+
// usually have the same reference, and the walk over each element is then not
|
|
28
|
+
// necessary.
|
|
29
|
+
if (aElements === bElements)
|
|
30
|
+
return true;
|
|
31
|
+
const elementKeys = Object.keys(aElements);
|
|
32
|
+
if (elementKeys.length !== Object.keys(bElements).length)
|
|
33
|
+
return false;
|
|
34
|
+
for (const key of elementKeys) {
|
|
35
|
+
const aElement = aElements[key]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
36
|
+
const bElement = bElements[key]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
37
|
+
if (aElement === bElement)
|
|
38
|
+
continue;
|
|
39
|
+
if (!aElement || !bElement)
|
|
40
|
+
return false;
|
|
41
|
+
if (!shallowEqualExcept(aElement, bElement, "props"))
|
|
42
|
+
return false;
|
|
43
|
+
if (!shallowEqualExcept(aElement.props ?? {}, bElement.props ?? {}))
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* The last snapshot that the view pipeline of each actor read.
|
|
50
|
+
*
|
|
51
|
+
* A WeakMap at the module level, and not a field of the class: a `private` or a `#` field
|
|
52
|
+
* makes a class type NOMINAL, so the compiler then compares the mixin class with no other
|
|
53
|
+
* type and the return of this function needs `as unknown as`. The map holds the same state
|
|
54
|
+
* with no member, and it releases each entry with its actor.
|
|
55
|
+
*
|
|
56
|
+
* XState notifies each observer on EVERY event that it processes, and an event that it
|
|
57
|
+
* ignores delivers the identical snapshot again. `deriveCurrentView` is pure in the
|
|
58
|
+
* snapshot, so an identical reference can change no result. An actor that the map does not
|
|
59
|
+
* hold has read no snapshot yet, which is correct for the first derivation: the snapshot of
|
|
60
|
+
* the construction has the same reference as the snapshot that `start()` replays.
|
|
61
|
+
*/
|
|
62
|
+
const lastViewSnapshots = new WeakMap();
|
|
63
|
+
/**
|
|
64
|
+
* Adds the view capability to an actor class.
|
|
65
|
+
*
|
|
66
|
+
* Compose it AFTER the routing capability. An override calls `super.onSnapshot()` first,
|
|
67
|
+
* so `compose(PlayerActor, withRouting, withView)` gives the route its new value before
|
|
68
|
+
* the view derives from the same transition. A router bridge therefore sees a guard
|
|
69
|
+
* redirect before a renderer sees the view of the state that the guard refused.
|
|
70
|
+
*
|
|
71
|
+
* @param Base - The actor class to extend, normally `PlayerActor` or the result of
|
|
72
|
+
* another capability.
|
|
73
|
+
*/
|
|
74
|
+
export function withView(Base) {
|
|
75
|
+
class ViewableActor extends Base {
|
|
76
|
+
/**
|
|
77
|
+
* The reactive signal of the current view spec. The signal derives the spec from the
|
|
78
|
+
* `meta.view` metadata of the active state.
|
|
79
|
+
*
|
|
80
|
+
* It emits a **new object reference** on each real change of the view on the screen:
|
|
81
|
+
* the view of a different state, or a change of a param or of the context that changes
|
|
82
|
+
* the resolved spec. A re-entry with `reenter: true` and new params also changes the
|
|
83
|
+
* spec. A snapshot that changes no view on the screen, such as an assign of the
|
|
84
|
+
* context alone, keeps the previous reference. A provider below the signal therefore
|
|
85
|
+
* mounts the UI again not on every event.
|
|
86
|
+
*
|
|
87
|
+
* The `PlaySpec` of the emission carries the context of the machine in its composed
|
|
88
|
+
* `state` field, under the read-only `/context` subtree. A spec therefore reads the
|
|
89
|
+
* context, and also each URL param, through the ordinary state grammar
|
|
90
|
+
* (`{ $state: "/context/params/section" }`). The context-projection module of
|
|
91
|
+
* `@xmachines/play-view` holds the complete contract.
|
|
92
|
+
*
|
|
93
|
+
* The signal returns `null` when the current state has no `meta.view` metadata.
|
|
94
|
+
*
|
|
95
|
+
* Two states can declare two separate `meta.view` literals with an identical
|
|
96
|
+
* structure. A transition between those two states then emits two different
|
|
97
|
+
* references, and a provider mounts the UI again. Move the shared literal into one
|
|
98
|
+
* `typedSpec` constant, and the identity then removes the duplicate.
|
|
99
|
+
*/
|
|
100
|
+
currentView = new Signal.State(null);
|
|
101
|
+
onSnapshot(snapshot) {
|
|
102
|
+
// FIRST, so that every capability composed before this one holds its new value.
|
|
103
|
+
super.onSnapshot(snapshot);
|
|
104
|
+
this.validateAndCacheView(snapshot);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Derives the view at the entry of a state, and keeps it. This happens one time for
|
|
108
|
+
* each transition. The signal holds the view, and the code computes it not on each
|
|
109
|
+
* read.
|
|
110
|
+
*
|
|
111
|
+
* @param snapshot - The current XState snapshot
|
|
112
|
+
*/
|
|
113
|
+
validateAndCacheView(snapshot) {
|
|
114
|
+
if (snapshot === lastViewSnapshots.get(this)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
lastViewSnapshots.set(this, snapshot);
|
|
118
|
+
try {
|
|
119
|
+
const view = deriveCurrentView(snapshot);
|
|
120
|
+
// Emit only after a real change of the view on the screen: deriveCurrentView
|
|
121
|
+
// returns a fresh object on each call, and the identity of the reference therefore
|
|
122
|
+
// tells nothing. A new reference for a snapshot that changes the view not, for
|
|
123
|
+
// example a context-only assign, makes a provider below mount the UI again, and
|
|
124
|
+
// that removes the state of the view. A deep equality test is deliberately NOT
|
|
125
|
+
// here: it sees nothing inside a Map or a Set, and it therefore stops a real
|
|
126
|
+
// change, and it recurses without an end on a cyclic prop. The last spec of an
|
|
127
|
+
// emission IS the current value of the signal. Read it without a track, so that
|
|
128
|
+
// the gate registers currentView never as a dependency of a computation around it.
|
|
129
|
+
const lastEmittedView = Signal.subtle.untrack(() => this.currentView.get());
|
|
130
|
+
// Use the reference of the previous composed state again when the value of the
|
|
131
|
+
// /context projection did not change. A context-only assign that changes no
|
|
132
|
+
// projected value therefore changes the identity of the state not.
|
|
133
|
+
const nextView = reuseComposedState(lastEmittedView, view);
|
|
134
|
+
if (viewSpecsEquivalent(lastEmittedView, nextView)) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
this.currentView.set(nextView);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
const onError = this.hooks.onError;
|
|
141
|
+
if (onError) {
|
|
142
|
+
onError(this, toError(error));
|
|
143
|
+
}
|
|
144
|
+
// On an error: keep the last valid view, and clear it not
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return ViewableActor;
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=with-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-view.js","sourceRoot":"","sources":["../src/with-view.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmachines/play-xstate",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "XState v5 adapter for Play Architecture",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"actor-model",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"xstate"
|
|
11
11
|
],
|
|
12
12
|
"license": "MIT",
|
|
13
|
-
"author": "",
|
|
13
|
+
"author": "XMachines Contributors",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
16
|
"url": "git+https://gitlab.com/xmachin-es/xmachines-js.git",
|
|
@@ -30,6 +30,14 @@
|
|
|
30
30
|
"types": "./dist/index.d.ts",
|
|
31
31
|
"default": "./dist/index.js"
|
|
32
32
|
},
|
|
33
|
+
"./routing": {
|
|
34
|
+
"types": "./dist/with-routing.d.ts",
|
|
35
|
+
"default": "./dist/with-routing.js"
|
|
36
|
+
},
|
|
37
|
+
"./view": {
|
|
38
|
+
"types": "./dist/with-view.d.ts",
|
|
39
|
+
"default": "./dist/with-view.js"
|
|
40
|
+
},
|
|
33
41
|
"./errors": {
|
|
34
42
|
"types": "./dist/errors.d.ts",
|
|
35
43
|
"default": "./dist/errors.js"
|
|
@@ -43,33 +51,46 @@
|
|
|
43
51
|
"build": "vite build && tsc --build",
|
|
44
52
|
"clean": "rm -rf dist *.tsbuildinfo coverage node_modules/.svelte2tsx-* node_modules/.vite*",
|
|
45
53
|
"lint": "oxlint .",
|
|
54
|
+
"lint:security": "node ../../scripts/semgrep-scan.mjs",
|
|
46
55
|
"format": "oxfmt .",
|
|
47
56
|
"test": "vitest",
|
|
48
57
|
"test:coverage": "vitest run --coverage"
|
|
49
58
|
},
|
|
50
59
|
"dependencies": {
|
|
51
|
-
"@xmachines/play": "
|
|
52
|
-
"@xmachines/play-actor": "2.2.0",
|
|
53
|
-
"@xmachines/play-signals": "2.2.0",
|
|
54
|
-
"dequal": "^2.0.3"
|
|
60
|
+
"@xmachines/play-actor": "4.0.0"
|
|
55
61
|
},
|
|
56
62
|
"devDependencies": {
|
|
57
|
-
"@testing-library/jest-dom": "^
|
|
58
|
-
"@types/node": "^26.2
|
|
59
|
-
"@xmachines/json-render-core": "^0.20.0-xm.
|
|
60
|
-
"@xmachines/play
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
+
"@testing-library/jest-dom": "^7.0.1",
|
|
64
|
+
"@types/node": "^26.6.2",
|
|
65
|
+
"@xmachines/json-render-core": "^0.20.0-xm.4",
|
|
66
|
+
"@xmachines/play": "4.0.0",
|
|
67
|
+
"@xmachines/play-router": "4.0.0",
|
|
68
|
+
"@xmachines/play-signals": "4.0.0",
|
|
69
|
+
"@xmachines/play-view": "4.0.0",
|
|
70
|
+
"oxfmt": "^0.68.0",
|
|
71
|
+
"oxlint": "^1.83.0",
|
|
63
72
|
"typescript": "^5.9.3 || ^6.0.3",
|
|
64
|
-
"vite": "^8.0
|
|
65
|
-
"vitest": "^
|
|
66
|
-
"xstate": "^5.
|
|
73
|
+
"vite": "^8.3.0",
|
|
74
|
+
"vitest": "^5.0.1",
|
|
75
|
+
"xstate": "^5.33.0"
|
|
67
76
|
},
|
|
68
77
|
"peerDependencies": {
|
|
69
|
-
"
|
|
78
|
+
"@xmachines/play": "4.0.0",
|
|
79
|
+
"@xmachines/play-router": "4.0.0",
|
|
80
|
+
"@xmachines/play-signals": "4.0.0",
|
|
81
|
+
"@xmachines/play-view": "4.0.0",
|
|
82
|
+
"xstate": "^5.33.0"
|
|
83
|
+
},
|
|
84
|
+
"peerDependenciesMeta": {
|
|
85
|
+
"@xmachines/play-view": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"@xmachines/play-router": {
|
|
89
|
+
"optional": true
|
|
90
|
+
}
|
|
70
91
|
},
|
|
71
92
|
"engines": {
|
|
72
|
-
"node": ">=
|
|
93
|
+
"node": ">=24.0.0"
|
|
73
94
|
},
|
|
74
|
-
"_devDependencies_note": "xstate appears in both peerDependencies and devDependencies intentionally. devDependencies provides workspace resolution for local builds, tests, and typechecking. peerDependencies declares the consumer version constraint. Both
|
|
95
|
+
"_devDependencies_note": "xstate appears in both peerDependencies and devDependencies intentionally. devDependencies provides workspace resolution for local builds, tests, and typechecking. peerDependencies declares the consumer version constraint. Both hold the same range, to prevent drift."
|
|
75
96
|
}
|
package/dist/guards/compose.d.ts
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import type { GuardPredicate } from "xstate";
|
|
2
|
-
import type { Guard, GuardArray } from "./types.js";
|
|
3
|
-
import type { MachineContext, EventObject, ParameterizedObject } from "xstate";
|
|
4
|
-
/**
|
|
5
|
-
* The narrowest public return type of the guard composition helpers.
|
|
6
|
-
*
|
|
7
|
-
* `GuardPredicate<MachineContext, EventObject, unknown, ParameterizedObject>` is the
|
|
8
|
-
* concrete XState guard type with the widest compatibility that uses no `any`.
|
|
9
|
-
*
|
|
10
|
-
* @public
|
|
11
|
-
* @deprecated The next major version removes the guard utilities. Use the
|
|
12
|
-
* combinator types of XState directly.
|
|
13
|
-
*/
|
|
14
|
-
export type ComposedGuard = GuardPredicate<MachineContext, EventObject, unknown, ParameterizedObject>;
|
|
15
|
-
/**
|
|
16
|
-
* Composes the guards with the AND logic, through the and() helper of XState
|
|
17
|
-
*
|
|
18
|
-
* The function joins more than one guard predicate with the AND semantics: every
|
|
19
|
-
* guard must pass, and the composition then succeeds. It uses the built-in `and()`
|
|
20
|
-
* helper of XState. The type inference and the serialization of the machine are
|
|
21
|
-
* therefore correct.
|
|
22
|
-
*
|
|
23
|
-
* **Architectural context:** the function supports **Actor Authority (INV-01)**,
|
|
24
|
-
* because it composes the guards of a state machine transition declaratively. A
|
|
25
|
-
* guard enforces a rule of the business logic, and that rule decides if a
|
|
26
|
-
* navigation or an action is valid.
|
|
27
|
-
*
|
|
28
|
-
* @typeParam TContext - The context type of the state machine
|
|
29
|
-
* @typeParam TEvent - The event type
|
|
30
|
-
*
|
|
31
|
-
* @param guards - The array of the guard predicates, or of the guard names as strings
|
|
32
|
-
* @returns The and() guard composition of XState
|
|
33
|
-
*
|
|
34
|
-
* @throws {Error} When the array of the guards is empty
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* An AND composition with named guards
|
|
38
|
-
* ```typescript
|
|
39
|
-
* import { setup } from "xstate";
|
|
40
|
-
* import { composeGuards } from "@xmachines/play-xstate";
|
|
41
|
-
*
|
|
42
|
-
* const machine = setup({
|
|
43
|
-
* guards: {
|
|
44
|
-
* isLoggedIn: ({ context }) => !!context.userId,
|
|
45
|
-
* hasPermission: ({ context }) => context.permissions.includes('admin'),
|
|
46
|
-
* }
|
|
47
|
-
* }).createMachine({
|
|
48
|
-
* on: {
|
|
49
|
-
* accessAdmin: {
|
|
50
|
-
* // Both guards must pass
|
|
51
|
-
* guard: composeGuards(['isLoggedIn', 'hasPermission']),
|
|
52
|
-
* target: 'adminPanel'
|
|
53
|
-
* }
|
|
54
|
-
* }
|
|
55
|
-
* });
|
|
56
|
-
* ```
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* An AND composition with inline predicates
|
|
60
|
-
* ```typescript
|
|
61
|
-
* import { composeGuards } from "@xmachines/play-xstate";
|
|
62
|
-
*
|
|
63
|
-
* guard: composeGuards([
|
|
64
|
-
* ({ context }) => context.age >= 18,
|
|
65
|
-
* ({ context }) => context.verified
|
|
66
|
-
* ])
|
|
67
|
-
* ```
|
|
68
|
-
*
|
|
69
|
-
* @see {@link composeGuardsOr} for the OR composition
|
|
70
|
-
* @see {@link negateGuard} for the NOT logic
|
|
71
|
-
* @deprecated Use the `and()`, `or()`, and `not()` combinators of XState directly. This helper
|
|
72
|
-
* does not compose with a guard slot that `setup()` types, and the next major version removes it.
|
|
73
|
-
*/
|
|
74
|
-
export declare const composeGuards: <TContext = any, TEvent = any>(guards: GuardArray<TContext, TEvent>) => ComposedGuard;
|
|
75
|
-
/**
|
|
76
|
-
* Composes the guards with the OR logic, through the or() helper of XState
|
|
77
|
-
*
|
|
78
|
-
* The function joins more than one guard predicate with the OR semantics: one guard
|
|
79
|
-
* must pass at least, and the composition then succeeds. It uses the built-in `or()`
|
|
80
|
-
* helper of XState, and the type inference is therefore correct.
|
|
81
|
-
*
|
|
82
|
-
* @typeParam TContext - The context type of the state machine
|
|
83
|
-
* @typeParam TEvent - The event type
|
|
84
|
-
*
|
|
85
|
-
* @param guards - The array of the guard predicates, or of the guard names
|
|
86
|
-
* @returns The or() guard composition of XState
|
|
87
|
-
*
|
|
88
|
-
* @throws {Error} When the array of the guards is empty
|
|
89
|
-
*
|
|
90
|
-
* @example
|
|
91
|
-
* An OR composition with named guards
|
|
92
|
-
* ```typescript
|
|
93
|
-
* import { setup } from "xstate";
|
|
94
|
-
* import { composeGuardsOr } from "@xmachines/play-xstate";
|
|
95
|
-
*
|
|
96
|
-
* const machine = setup({
|
|
97
|
-
* guards: {
|
|
98
|
-
* isOwner: ({ context }) => context.role === 'owner',
|
|
99
|
-
* isAdmin: ({ context }) => context.role === 'admin'
|
|
100
|
-
* }
|
|
101
|
-
* }).createMachine({
|
|
102
|
-
* on: {
|
|
103
|
-
* deleteResource: {
|
|
104
|
-
* // One guard is sufficient
|
|
105
|
-
* guard: composeGuardsOr(['isOwner', 'isAdmin']),
|
|
106
|
-
* actions: 'delete'
|
|
107
|
-
* }
|
|
108
|
-
* }
|
|
109
|
-
* });
|
|
110
|
-
* ```
|
|
111
|
-
*
|
|
112
|
-
* @see {@link composeGuards} for the AND composition
|
|
113
|
-
* @see {@link negateGuard} for the NOT logic
|
|
114
|
-
* @deprecated Use the `and()`, `or()`, and `not()` combinators of XState directly. This helper
|
|
115
|
-
* does not compose with a guard slot that `setup()` types, and the next major version removes it.
|
|
116
|
-
*/
|
|
117
|
-
export declare const composeGuardsOr: <TContext = any, TEvent = any>(guards: GuardArray<TContext, TEvent>) => ComposedGuard;
|
|
118
|
-
/**
|
|
119
|
-
* Negates a guard, through the not() helper of XState
|
|
120
|
-
*
|
|
121
|
-
* The function inverts the result of a guard: the guard passes, and NOT then fails;
|
|
122
|
-
* the guard fails, and NOT then passes. It uses the built-in `not()` helper of
|
|
123
|
-
* XState, and the serialization is therefore correct.
|
|
124
|
-
*
|
|
125
|
-
* @typeParam TContext - The context type of the state machine
|
|
126
|
-
* @typeParam TEvent - The event type
|
|
127
|
-
*
|
|
128
|
-
* @param guard - The guard predicate to negate, or its name
|
|
129
|
-
* @returns The not() guard negation of XState
|
|
130
|
-
*
|
|
131
|
-
* @example
|
|
132
|
-
* A NOT composition with a named guard
|
|
133
|
-
* ```typescript
|
|
134
|
-
* import { setup } from "xstate";
|
|
135
|
-
* import { negateGuard } from "@xmachines/play-xstate";
|
|
136
|
-
*
|
|
137
|
-
* const machine = setup({
|
|
138
|
-
* guards: {
|
|
139
|
-
* isGuest: ({ context }) => !context.userId
|
|
140
|
-
* }
|
|
141
|
-
* }).createMachine({
|
|
142
|
-
* on: {
|
|
143
|
-
* accessDashboard: {
|
|
144
|
-
* // Permit the transition when the user is NOT a guest, which means an authenticated user
|
|
145
|
-
* guard: negateGuard('isGuest'),
|
|
146
|
-
* target: 'dashboard'
|
|
147
|
-
* }
|
|
148
|
-
* }
|
|
149
|
-
* });
|
|
150
|
-
* ```
|
|
151
|
-
*
|
|
152
|
-
* @see {@link composeGuards} for the AND composition
|
|
153
|
-
* @see {@link composeGuardsOr} for the OR composition
|
|
154
|
-
* @deprecated Use the `and()`, `or()`, and `not()` combinators of XState directly. This helper
|
|
155
|
-
* does not compose with a guard slot that `setup()` types, and the next major version removes it.
|
|
156
|
-
*/
|
|
157
|
-
export declare const negateGuard: <TContext = any, TEvent = any>(guard: Guard<TContext, TEvent> | string) => ComposedGuard;
|
|
158
|
-
//# sourceMappingURL=compose.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/guards/compose.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAmB/E;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,CACzC,cAAc,EACd,WAAW,EACX,OAAO,EACP,mBAAmB,CACnB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EACzD,QAAQ,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAClC,aAYF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,eAAO,MAAM,eAAe,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAC3D,QAAQ,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAClC,aAYF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,eAAO,MAAM,WAAW,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EACvD,OAAO,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,KACrC,aAIF,CAAC"}
|
package/dist/guards/compose.js
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { and, or, not } from "xstate";
|
|
2
|
-
import { EmptyGuardArrayError } from "../errors.js";
|
|
3
|
-
/**
|
|
4
|
-
* The one unsound boundary of the PRODUCTION code, and it covers the guard types of
|
|
5
|
-
* XState only. (The test code uses `unsafeCast` from
|
|
6
|
-
* `@xmachines/shared/test-support` instead. The two functions are counterparts, and
|
|
7
|
-
* an audit of the casts with grep must cover both names.)
|
|
8
|
-
*
|
|
9
|
-
* These deprecated helpers close two known gaps in the types of XState 5.28. In the
|
|
10
|
-
* first gap, our `Guard<TContext, TEvent>` type does not match `ComposedGuard`
|
|
11
|
-
* structurally, because the event generic is different. In the second gap, `and()`
|
|
12
|
-
* and `or()` need a `readonly [...tuple]`, and `GuardArray` is a mutable array. The
|
|
13
|
-
* values at run time are identical in each case. The parameter has the type
|
|
14
|
-
* `unknown`. Therefore one `as` cast is here, and no call site needs a double cast.
|
|
15
|
-
* Follow the improvements of the XState types: https://github.com/statelyai/xstate/issues
|
|
16
|
-
*/
|
|
17
|
-
const asXStateGuard = (value) => value;
|
|
18
|
-
/**
|
|
19
|
-
* Composes the guards with the AND logic, through the and() helper of XState
|
|
20
|
-
*
|
|
21
|
-
* The function joins more than one guard predicate with the AND semantics: every
|
|
22
|
-
* guard must pass, and the composition then succeeds. It uses the built-in `and()`
|
|
23
|
-
* helper of XState. The type inference and the serialization of the machine are
|
|
24
|
-
* therefore correct.
|
|
25
|
-
*
|
|
26
|
-
* **Architectural context:** the function supports **Actor Authority (INV-01)**,
|
|
27
|
-
* because it composes the guards of a state machine transition declaratively. A
|
|
28
|
-
* guard enforces a rule of the business logic, and that rule decides if a
|
|
29
|
-
* navigation or an action is valid.
|
|
30
|
-
*
|
|
31
|
-
* @typeParam TContext - The context type of the state machine
|
|
32
|
-
* @typeParam TEvent - The event type
|
|
33
|
-
*
|
|
34
|
-
* @param guards - The array of the guard predicates, or of the guard names as strings
|
|
35
|
-
* @returns The and() guard composition of XState
|
|
36
|
-
*
|
|
37
|
-
* @throws {Error} When the array of the guards is empty
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* An AND composition with named guards
|
|
41
|
-
* ```typescript
|
|
42
|
-
* import { setup } from "xstate";
|
|
43
|
-
* import { composeGuards } from "@xmachines/play-xstate";
|
|
44
|
-
*
|
|
45
|
-
* const machine = setup({
|
|
46
|
-
* guards: {
|
|
47
|
-
* isLoggedIn: ({ context }) => !!context.userId,
|
|
48
|
-
* hasPermission: ({ context }) => context.permissions.includes('admin'),
|
|
49
|
-
* }
|
|
50
|
-
* }).createMachine({
|
|
51
|
-
* on: {
|
|
52
|
-
* accessAdmin: {
|
|
53
|
-
* // Both guards must pass
|
|
54
|
-
* guard: composeGuards(['isLoggedIn', 'hasPermission']),
|
|
55
|
-
* target: 'adminPanel'
|
|
56
|
-
* }
|
|
57
|
-
* }
|
|
58
|
-
* });
|
|
59
|
-
* ```
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* An AND composition with inline predicates
|
|
63
|
-
* ```typescript
|
|
64
|
-
* import { composeGuards } from "@xmachines/play-xstate";
|
|
65
|
-
*
|
|
66
|
-
* guard: composeGuards([
|
|
67
|
-
* ({ context }) => context.age >= 18,
|
|
68
|
-
* ({ context }) => context.verified
|
|
69
|
-
* ])
|
|
70
|
-
* ```
|
|
71
|
-
*
|
|
72
|
-
* @see {@link composeGuardsOr} for the OR composition
|
|
73
|
-
* @see {@link negateGuard} for the NOT logic
|
|
74
|
-
* @deprecated Use the `and()`, `or()`, and `not()` combinators of XState directly. This helper
|
|
75
|
-
* does not compose with a guard slot that `setup()` types, and the next major version removes it.
|
|
76
|
-
*/
|
|
77
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
|
-
export const composeGuards = (guards) => {
|
|
79
|
-
if (guards.length === 0) {
|
|
80
|
-
throw new EmptyGuardArrayError("and");
|
|
81
|
-
}
|
|
82
|
-
if (guards.length === 1) {
|
|
83
|
-
// One guard passes through. asXStateGuard gives the reason for the boundary.
|
|
84
|
-
return asXStateGuard(guards[0]);
|
|
85
|
-
}
|
|
86
|
-
// Use the built-in and() of XState, for the type inference and the serialization.
|
|
87
|
-
return and(asXStateGuard(guards));
|
|
88
|
-
};
|
|
89
|
-
/**
|
|
90
|
-
* Composes the guards with the OR logic, through the or() helper of XState
|
|
91
|
-
*
|
|
92
|
-
* The function joins more than one guard predicate with the OR semantics: one guard
|
|
93
|
-
* must pass at least, and the composition then succeeds. It uses the built-in `or()`
|
|
94
|
-
* helper of XState, and the type inference is therefore correct.
|
|
95
|
-
*
|
|
96
|
-
* @typeParam TContext - The context type of the state machine
|
|
97
|
-
* @typeParam TEvent - The event type
|
|
98
|
-
*
|
|
99
|
-
* @param guards - The array of the guard predicates, or of the guard names
|
|
100
|
-
* @returns The or() guard composition of XState
|
|
101
|
-
*
|
|
102
|
-
* @throws {Error} When the array of the guards is empty
|
|
103
|
-
*
|
|
104
|
-
* @example
|
|
105
|
-
* An OR composition with named guards
|
|
106
|
-
* ```typescript
|
|
107
|
-
* import { setup } from "xstate";
|
|
108
|
-
* import { composeGuardsOr } from "@xmachines/play-xstate";
|
|
109
|
-
*
|
|
110
|
-
* const machine = setup({
|
|
111
|
-
* guards: {
|
|
112
|
-
* isOwner: ({ context }) => context.role === 'owner',
|
|
113
|
-
* isAdmin: ({ context }) => context.role === 'admin'
|
|
114
|
-
* }
|
|
115
|
-
* }).createMachine({
|
|
116
|
-
* on: {
|
|
117
|
-
* deleteResource: {
|
|
118
|
-
* // One guard is sufficient
|
|
119
|
-
* guard: composeGuardsOr(['isOwner', 'isAdmin']),
|
|
120
|
-
* actions: 'delete'
|
|
121
|
-
* }
|
|
122
|
-
* }
|
|
123
|
-
* });
|
|
124
|
-
* ```
|
|
125
|
-
*
|
|
126
|
-
* @see {@link composeGuards} for the AND composition
|
|
127
|
-
* @see {@link negateGuard} for the NOT logic
|
|
128
|
-
* @deprecated Use the `and()`, `or()`, and `not()` combinators of XState directly. This helper
|
|
129
|
-
* does not compose with a guard slot that `setup()` types, and the next major version removes it.
|
|
130
|
-
*/
|
|
131
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
132
|
-
export const composeGuardsOr = (guards) => {
|
|
133
|
-
if (guards.length === 0) {
|
|
134
|
-
throw new EmptyGuardArrayError("or");
|
|
135
|
-
}
|
|
136
|
-
if (guards.length === 1) {
|
|
137
|
-
// One guard passes through. asXStateGuard gives the reason for the boundary.
|
|
138
|
-
return asXStateGuard(guards[0]);
|
|
139
|
-
}
|
|
140
|
-
// Use the built-in or() of XState, for the type inference and the serialization.
|
|
141
|
-
return or(asXStateGuard(guards));
|
|
142
|
-
};
|
|
143
|
-
/**
|
|
144
|
-
* Negates a guard, through the not() helper of XState
|
|
145
|
-
*
|
|
146
|
-
* The function inverts the result of a guard: the guard passes, and NOT then fails;
|
|
147
|
-
* the guard fails, and NOT then passes. It uses the built-in `not()` helper of
|
|
148
|
-
* XState, and the serialization is therefore correct.
|
|
149
|
-
*
|
|
150
|
-
* @typeParam TContext - The context type of the state machine
|
|
151
|
-
* @typeParam TEvent - The event type
|
|
152
|
-
*
|
|
153
|
-
* @param guard - The guard predicate to negate, or its name
|
|
154
|
-
* @returns The not() guard negation of XState
|
|
155
|
-
*
|
|
156
|
-
* @example
|
|
157
|
-
* A NOT composition with a named guard
|
|
158
|
-
* ```typescript
|
|
159
|
-
* import { setup } from "xstate";
|
|
160
|
-
* import { negateGuard } from "@xmachines/play-xstate";
|
|
161
|
-
*
|
|
162
|
-
* const machine = setup({
|
|
163
|
-
* guards: {
|
|
164
|
-
* isGuest: ({ context }) => !context.userId
|
|
165
|
-
* }
|
|
166
|
-
* }).createMachine({
|
|
167
|
-
* on: {
|
|
168
|
-
* accessDashboard: {
|
|
169
|
-
* // Permit the transition when the user is NOT a guest, which means an authenticated user
|
|
170
|
-
* guard: negateGuard('isGuest'),
|
|
171
|
-
* target: 'dashboard'
|
|
172
|
-
* }
|
|
173
|
-
* }
|
|
174
|
-
* });
|
|
175
|
-
* ```
|
|
176
|
-
*
|
|
177
|
-
* @see {@link composeGuards} for the AND composition
|
|
178
|
-
* @see {@link composeGuardsOr} for the OR composition
|
|
179
|
-
* @deprecated Use the `and()`, `or()`, and `not()` combinators of XState directly. This helper
|
|
180
|
-
* does not compose with a guard slot that `setup()` types, and the next major version removes it.
|
|
181
|
-
*/
|
|
182
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
183
|
-
export const negateGuard = (guard) => {
|
|
184
|
-
// XState 5.28.0: not() requires one SingleGuardArg shape, and not the Guard
|
|
185
|
-
// type of this package. See asXStateGuard.
|
|
186
|
-
return not(asXStateGuard(guard));
|
|
187
|
-
};
|
|
188
|
-
//# sourceMappingURL=compose.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../src/guards/compose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAItC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;;;;;;;;;;GAaG;AACH,MAAM,aAAa,GAAG,CAAI,KAAc,EAAK,EAAE,CAAC,KAAU,CAAC;AAmB3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,CAC5B,MAAoC,EACpB,EAAE;IAClB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,6EAA6E;QAC7E,OAAO,aAAa,CAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,kFAAkF;IAClF,OAAO,GAAG,CAAC,aAAa,CAA4B,MAAM,CAAC,CAAC,CAAC;AAC9D,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,eAAe,GAAG,CAC9B,MAAoC,EACpB,EAAE;IAClB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,6EAA6E;QAC7E,OAAO,aAAa,CAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,iFAAiF;IACjF,OAAO,EAAE,CAAC,aAAa,CAA2B,MAAM,CAAC,CAAC,CAAC;AAC5D,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAC1B,KAAuC,EACvB,EAAE;IAClB,4EAA4E;IAC5E,2CAA2C;IAC3C,OAAO,GAAG,CAAC,aAAa,CAA4B,KAAK,CAAC,CAAC,CAAC;AAC7D,CAAC,CAAC"}
|
package/dist/guards/helpers.d.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { Guard } from "./types.js";
|
|
2
|
-
import type { PlayEvent } from "@xmachines/play";
|
|
3
|
-
/**
|
|
4
|
-
* Tells you if the context holds a value at the path, and that the value is truthy
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```typescript
|
|
8
|
-
* const machine = setup({
|
|
9
|
-
* guards: {
|
|
10
|
-
* hasUserId: hasContext('userId'),
|
|
11
|
-
* hasEmail: hasContext('user.email')
|
|
12
|
-
* }
|
|
13
|
-
* });
|
|
14
|
-
* ```
|
|
15
|
-
*
|
|
16
|
-
* @param path - The path to the context property, with a dot between two segments
|
|
17
|
-
* @returns The guard predicate. It tests the property for a truthy value
|
|
18
|
-
* @deprecated This function is part of the guard utilities, and the next major version removes
|
|
19
|
-
* them. Write a plain typed predicate instead.
|
|
20
|
-
*/
|
|
21
|
-
export declare const hasContext: <TContext = Record<string, unknown>>(path: string) => Guard<TContext, PlayEvent>;
|
|
22
|
-
/**
|
|
23
|
-
* Tells you if the type of the event is the expected type
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```typescript
|
|
27
|
-
* const machine = setup({
|
|
28
|
-
* guards: {
|
|
29
|
-
* isSubmitEvent: eventMatches('submit'),
|
|
30
|
-
* isBackOrForward: composeGuardsOr([
|
|
31
|
-
* eventMatches('back'),
|
|
32
|
-
* eventMatches('forward')
|
|
33
|
-
* ])
|
|
34
|
-
* }
|
|
35
|
-
* });
|
|
36
|
-
* ```
|
|
37
|
-
*
|
|
38
|
-
* @param eventType - The expected event type
|
|
39
|
-
* @returns The guard predicate. It tests the event type
|
|
40
|
-
* @deprecated This function is part of the guard utilities, and the next major version removes
|
|
41
|
-
* them. Write a plain typed predicate instead.
|
|
42
|
-
*/
|
|
43
|
-
export declare const eventMatches: <TEvent extends PlayEvent = PlayEvent>(eventType: string) => Guard<unknown, TEvent>;
|
|
44
|
-
/**
|
|
45
|
-
* Tells you if a context field holds the expected value.
|
|
46
|
-
*
|
|
47
|
-
* - The function accepts an explicit field path, with a dot between two segments, for example `"user.role"`
|
|
48
|
-
* - It compares a primitive with a strict equality, and an object with a deep structural equality
|
|
49
|
-
* - The order of the keys has no effect on the comparison of an object: `{a:1,b:2}` equals `{b:2,a:1}`
|
|
50
|
-
* - It supports a Date, a RegExp, an instance of a class, a nested object, and an array, through `dequal/lite`
|
|
51
|
-
* - It does NOT match a substring: `"a"` does not match `"active"`
|
|
52
|
-
*
|
|
53
|
-
* For a match of an XState state node, use the built-in `in:` guard syntax instead.
|
|
54
|
-
*
|
|
55
|
-
* @param fieldPath - The path to the context property, with a dot between two segments, for example "status" or "user.role"
|
|
56
|
-
* @param expectedValue - The value for the comparison: a string, an object, a Date, and so on
|
|
57
|
-
* @returns The guard predicate. It tests the context field for the value
|
|
58
|
-
* @deprecated This function is part of the guard utilities, and the next major version removes
|
|
59
|
-
* them. Write a plain typed predicate instead.
|
|
60
|
-
*/
|
|
61
|
-
export declare const contextFieldMatches: <TContext = Record<string, unknown>>(fieldPath: string, expectedValue: unknown) => Guard<TContext, PlayEvent>;
|
|
62
|
-
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/guards/helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU,GACrB,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,MAAM,KAAG,KAAK,CAAC,QAAQ,EAAE,SAAS,CAI5E,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,SAAS,SAAS,GAAG,SAAS,EAAE,WAAW,MAAM,KAAG,KAAK,CAAC,OAAO,EAAE,MAAM,CAG/E,CAAC;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,WAAW,MAAM,EACjB,eAAe,OAAO,KACpB,KAAK,CAAC,QAAQ,EAAE,SAAS,CAI3B,CAAC"}
|