machinalayout 0.1.0 → 0.3.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 +295 -49
- package/dist/chunk-2ZQ2RFFI.js +400 -0
- package/dist/chunk-33CKBEJH.js +186 -0
- package/dist/chunk-BJOQRPPX.js +382 -0
- package/dist/chunk-KYWOCAHK.js +205 -0
- package/dist/chunk-RJYRJ3LD.js +0 -0
- package/dist/chunk-SVWYWI7I.js +59 -0
- package/dist/chunk-VREK57S3.js +13 -0
- package/dist/chunk-ZVDE7PX4.js +222 -0
- package/dist/debugOverlay-pJpj0n5H.d.ts +125 -0
- package/dist/deus/index.d.ts +14 -0
- package/dist/deus/index.js +26 -0
- package/dist/dispatch/index.d.ts +49 -0
- package/dist/dispatch/index.js +217 -0
- package/dist/handoff/index.d.ts +44 -0
- package/dist/handoff/index.js +83 -0
- package/dist/index.d.ts +54 -236
- package/dist/index.js +753 -583
- package/dist/inspect/index.d.ts +8 -0
- package/dist/inspect/index.js +97 -0
- package/dist/react/index.d.ts +41 -0
- package/dist/react/index.js +9 -0
- package/dist/react-native/index.d.ts +30 -0
- package/dist/react-native/index.js +84 -0
- package/dist/screenCatalog-ZjonGiOi.d.ts +46 -0
- package/dist/text/index.d.ts +10 -0
- package/dist/text/index.js +9 -0
- package/dist/text/react/index.d.ts +14 -0
- package/dist/text/react/index.js +7 -0
- package/dist/text/react-native/index.d.ts +16 -0
- package/dist/text/react-native/index.js +155 -0
- package/dist/text/vue/index.d.ts +113 -0
- package/dist/text/vue/index.js +202 -0
- package/dist/types-B90jb3RW.d.ts +184 -0
- package/dist/types-C4poVJpR.d.ts +74 -0
- package/dist/types-DLYAhNXw.d.ts +32 -0
- package/dist/vue/index.d.ts +173 -0
- package/dist/vue/index.js +112 -0
- package/docs/adapter-packaging-a0-plan.md +352 -0
- package/docs/adapters.md +19 -0
- package/docs/api-coherence-m8-audit.md +397 -0
- package/docs/deusmachina.md +108 -0
- package/docs/error-codes.md +95 -0
- package/docs/grid-arrange-m5a-contract.md +480 -0
- package/docs/grid-arrange.md +51 -0
- package/docs/inspection-and-handoff.md +126 -0
- package/docs/layout-interpolation.md +52 -0
- package/docs/machina-dispatch-d0-contract.md +496 -0
- package/docs/machina-dispatch.md +143 -0
- package/docs/named-layers.md +40 -0
- package/docs/react-adapter.md +63 -58
- package/docs/react-native-adapter.md +56 -0
- package/docs/react-native-text-renderer.md +50 -0
- package/docs/reference-alignment-m7a-contract.md +384 -0
- package/docs/reference-alignment.md +44 -0
- package/docs/responsive-variants.md +54 -0
- package/docs/screen-catalog-and-viewports.md +124 -0
- package/docs/stack-geometry-helpers.md +115 -0
- package/docs/vue-adapter.md +55 -0
- package/docs/vue-text-renderer.md +55 -0
- package/package.json +127 -60
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getMachinaDebugOverlayBehavior
|
|
3
|
+
} from "./chunk-2ZQ2RFFI.js";
|
|
4
|
+
import {
|
|
5
|
+
toResolvedTree
|
|
6
|
+
} from "./chunk-SVWYWI7I.js";
|
|
7
|
+
|
|
8
|
+
// src/react/MachinaReactView.tsx
|
|
9
|
+
import React from "react";
|
|
10
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
function normalizeLayerZ(value) {
|
|
12
|
+
if (value === void 0 || !Number.isFinite(value) || !Number.isInteger(value) || value < -5 || value > 5) {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
function getEffectiveLayer(node, defaultLayer) {
|
|
18
|
+
return node.layer ?? defaultLayer;
|
|
19
|
+
}
|
|
20
|
+
function getEffectiveLayerZ(node, layers, defaultLayer) {
|
|
21
|
+
const layerName = getEffectiveLayer(node, defaultLayer);
|
|
22
|
+
return normalizeLayerZ(layers[layerName]?.z);
|
|
23
|
+
}
|
|
24
|
+
function renderNode(node, parentRect, views, viewData, nodeData, nodeClassName, debug, nodeContainment, nodeContentVisibility, nodeContainIntrinsicSize, nodesById, layers, defaultLayer) {
|
|
25
|
+
const viewKey = node.view ?? node.slot;
|
|
26
|
+
const View = viewKey ? views[viewKey] : void 0;
|
|
27
|
+
const selectedViewData = viewKey ? viewData?.[viewKey] : void 0;
|
|
28
|
+
const selectedNodeData = nodeData?.[node.id];
|
|
29
|
+
const left = node.rect.x - parentRect.x;
|
|
30
|
+
const top = node.rect.y - parentRect.y;
|
|
31
|
+
const effectiveLayer = getEffectiveLayer(node, defaultLayer);
|
|
32
|
+
const effectiveLayerZ = getEffectiveLayerZ(node, layers, defaultLayer);
|
|
33
|
+
const style = {
|
|
34
|
+
position: "absolute",
|
|
35
|
+
left,
|
|
36
|
+
top,
|
|
37
|
+
width: node.rect.width,
|
|
38
|
+
height: node.rect.height,
|
|
39
|
+
boxSizing: "border-box",
|
|
40
|
+
zIndex: effectiveLayerZ * 100 + (node.z ?? 0),
|
|
41
|
+
...nodeContainment === "layout-paint" ? { contain: "layout paint" } : null,
|
|
42
|
+
...nodeContainment === "strict" ? { contain: "strict" } : null,
|
|
43
|
+
...nodeContentVisibility === "auto" ? { contentVisibility: "auto" } : null,
|
|
44
|
+
...nodeContainIntrinsicSize !== void 0 ? { containIntrinsicSize: nodeContainIntrinsicSize } : null,
|
|
45
|
+
...debug ? { outline: "1px dashed rgba(59, 130, 246, 0.9)" } : null
|
|
46
|
+
};
|
|
47
|
+
const renderedSlot = View && nodesById[node.id] ? React.createElement(View, {
|
|
48
|
+
id: node.id,
|
|
49
|
+
rect: { ...node.rect },
|
|
50
|
+
debugLabel: node.debugLabel,
|
|
51
|
+
node: { ...nodesById[node.id], rect: { ...nodesById[node.id].rect } },
|
|
52
|
+
viewKey,
|
|
53
|
+
viewData: selectedViewData,
|
|
54
|
+
nodeData: selectedNodeData
|
|
55
|
+
}) : null;
|
|
56
|
+
return /* @__PURE__ */ jsxs(
|
|
57
|
+
"div",
|
|
58
|
+
{
|
|
59
|
+
"data-testid": `machina-node-${node.id}`,
|
|
60
|
+
className: nodeClassName,
|
|
61
|
+
style,
|
|
62
|
+
"data-machina-node-id": node.id,
|
|
63
|
+
"data-machina-slot": node.slot,
|
|
64
|
+
"data-machina-view": viewKey,
|
|
65
|
+
"data-machina-debug-label": node.debugLabel,
|
|
66
|
+
"data-machina-layer": effectiveLayer,
|
|
67
|
+
children: [
|
|
68
|
+
debug ? /* @__PURE__ */ jsx("small", { children: node.debugLabel ?? node.id }) : null,
|
|
69
|
+
renderedSlot,
|
|
70
|
+
[...node.children].map((child, index) => ({ child, index })).sort(
|
|
71
|
+
(a, b) => getEffectiveLayerZ(a.child, layers, defaultLayer) - getEffectiveLayerZ(b.child, layers, defaultLayer) || (a.child.z ?? 0) - (b.child.z ?? 0) || a.index - b.index
|
|
72
|
+
).map(
|
|
73
|
+
({ child }) => renderNode(
|
|
74
|
+
child,
|
|
75
|
+
node.rect,
|
|
76
|
+
views,
|
|
77
|
+
viewData,
|
|
78
|
+
nodeData,
|
|
79
|
+
nodeClassName,
|
|
80
|
+
debug,
|
|
81
|
+
nodeContainment,
|
|
82
|
+
nodeContentVisibility,
|
|
83
|
+
nodeContainIntrinsicSize,
|
|
84
|
+
nodesById,
|
|
85
|
+
layers,
|
|
86
|
+
defaultLayer
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
node.id
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
function collectOverlayNodes(node) {
|
|
95
|
+
return [node, ...node.children.flatMap((child) => collectOverlayNodes(child))];
|
|
96
|
+
}
|
|
97
|
+
function renderDebugOverlay(tree, options) {
|
|
98
|
+
const board = {
|
|
99
|
+
mode: options.mode ?? "collapsed",
|
|
100
|
+
labels: options.labels ?? true,
|
|
101
|
+
borders: options.borders ?? true,
|
|
102
|
+
selectedNodeId: options.selectedNodeId
|
|
103
|
+
};
|
|
104
|
+
const behavior = getMachinaDebugOverlayBehavior(board);
|
|
105
|
+
if (!behavior.visible) return null;
|
|
106
|
+
const nodes = collectOverlayNodes(tree);
|
|
107
|
+
return /* @__PURE__ */ jsxs(
|
|
108
|
+
"div",
|
|
109
|
+
{
|
|
110
|
+
"data-testid": "machina-debug-overlay",
|
|
111
|
+
"data-machina-debug-overlay-mode": board.mode,
|
|
112
|
+
style: {
|
|
113
|
+
position: "absolute",
|
|
114
|
+
inset: 0,
|
|
115
|
+
pointerEvents: behavior.pointerEvents,
|
|
116
|
+
zIndex: 1e4,
|
|
117
|
+
boxSizing: "border-box"
|
|
118
|
+
},
|
|
119
|
+
children: [
|
|
120
|
+
nodes.map((node) => /* @__PURE__ */ jsx(
|
|
121
|
+
"div",
|
|
122
|
+
{
|
|
123
|
+
"data-testid": `machina-debug-overlay-node-${node.id}`,
|
|
124
|
+
"data-machina-debug-overlay-node-id": node.id,
|
|
125
|
+
style: {
|
|
126
|
+
position: "absolute",
|
|
127
|
+
left: node.rect.x - tree.rect.x,
|
|
128
|
+
top: node.rect.y - tree.rect.y,
|
|
129
|
+
width: node.rect.width,
|
|
130
|
+
height: node.rect.height,
|
|
131
|
+
boxSizing: "border-box",
|
|
132
|
+
border: behavior.showBorders ? "1px solid rgba(14, 165, 233, 0.9)" : "0",
|
|
133
|
+
pointerEvents: behavior.pointerEvents
|
|
134
|
+
},
|
|
135
|
+
children: behavior.showLabels ? /* @__PURE__ */ jsx(
|
|
136
|
+
"span",
|
|
137
|
+
{
|
|
138
|
+
style: {
|
|
139
|
+
position: "absolute",
|
|
140
|
+
left: 0,
|
|
141
|
+
top: 0,
|
|
142
|
+
fontSize: 10,
|
|
143
|
+
lineHeight: "12px",
|
|
144
|
+
background: "rgba(14, 165, 233, 0.9)",
|
|
145
|
+
color: "white",
|
|
146
|
+
padding: "0 3px"
|
|
147
|
+
},
|
|
148
|
+
children: node.debugLabel ?? node.id
|
|
149
|
+
}
|
|
150
|
+
) : null
|
|
151
|
+
},
|
|
152
|
+
node.id
|
|
153
|
+
)),
|
|
154
|
+
behavior.showPanel ? /* @__PURE__ */ jsxs(
|
|
155
|
+
"div",
|
|
156
|
+
{
|
|
157
|
+
"data-testid": "machina-debug-overlay-panel",
|
|
158
|
+
style: {
|
|
159
|
+
position: "absolute",
|
|
160
|
+
right: 8,
|
|
161
|
+
top: 8,
|
|
162
|
+
background: "rgba(15, 23, 42, 0.92)",
|
|
163
|
+
color: "white",
|
|
164
|
+
padding: 8
|
|
165
|
+
},
|
|
166
|
+
children: [
|
|
167
|
+
"Debug overlay",
|
|
168
|
+
board.selectedNodeId ? `: ${board.selectedNodeId}` : ""
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
) : null
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
function MachinaReactView(props) {
|
|
177
|
+
const {
|
|
178
|
+
layout,
|
|
179
|
+
views = {},
|
|
180
|
+
viewData,
|
|
181
|
+
nodeData,
|
|
182
|
+
className,
|
|
183
|
+
style,
|
|
184
|
+
nodeClassName,
|
|
185
|
+
debug,
|
|
186
|
+
nodeContainment = "layout-paint",
|
|
187
|
+
nodeContentVisibility = "none",
|
|
188
|
+
nodeContainIntrinsicSize,
|
|
189
|
+
layers = { base: { z: 0 } },
|
|
190
|
+
defaultLayer = "base",
|
|
191
|
+
debugOverlay
|
|
192
|
+
} = props;
|
|
193
|
+
const tree = toResolvedTree(layout);
|
|
194
|
+
const wrapperStyle = {
|
|
195
|
+
position: "relative",
|
|
196
|
+
width: tree.rect.width,
|
|
197
|
+
height: tree.rect.height,
|
|
198
|
+
...style
|
|
199
|
+
};
|
|
200
|
+
return /* @__PURE__ */ jsxs("div", { className, style: wrapperStyle, "data-machina-root-id": tree.id, children: [
|
|
201
|
+
renderNode(
|
|
202
|
+
tree,
|
|
203
|
+
tree.rect,
|
|
204
|
+
views,
|
|
205
|
+
viewData,
|
|
206
|
+
nodeData,
|
|
207
|
+
nodeClassName,
|
|
208
|
+
debug,
|
|
209
|
+
nodeContainment,
|
|
210
|
+
nodeContentVisibility,
|
|
211
|
+
nodeContainIntrinsicSize,
|
|
212
|
+
layout.nodes,
|
|
213
|
+
layers,
|
|
214
|
+
defaultLayer
|
|
215
|
+
),
|
|
216
|
+
debugOverlay ? renderDebugOverlay(tree, debugOverlay) : null
|
|
217
|
+
] });
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export {
|
|
221
|
+
MachinaReactView
|
|
222
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
declare class DeusMachinaError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
constructor(code: string, message: string);
|
|
4
|
+
}
|
|
5
|
+
type UtilityScore<TContext> = number | ((context: TContext) => number);
|
|
6
|
+
type UtilityCandidate<TContext, TKey extends string = string> = {
|
|
7
|
+
key: TKey;
|
|
8
|
+
when?: (context: TContext) => boolean;
|
|
9
|
+
score: UtilityScore<TContext>;
|
|
10
|
+
reason?: string | ((context: TContext) => string);
|
|
11
|
+
};
|
|
12
|
+
type UtilityCandidateResult<TKey extends string = string> = {
|
|
13
|
+
key: TKey;
|
|
14
|
+
eligible: boolean;
|
|
15
|
+
score: number;
|
|
16
|
+
index: number;
|
|
17
|
+
reason?: string;
|
|
18
|
+
};
|
|
19
|
+
type UtilityJudgment<TKey extends string = string> = {
|
|
20
|
+
selected: UtilityCandidateResult<TKey> | null;
|
|
21
|
+
candidates: UtilityCandidateResult<TKey>[];
|
|
22
|
+
};
|
|
23
|
+
type JudgeUtilityOptions<TKey extends string = string> = {
|
|
24
|
+
previousKey?: TKey;
|
|
25
|
+
hysteresis?: number;
|
|
26
|
+
};
|
|
27
|
+
type DeusStatePath = readonly string[];
|
|
28
|
+
type DeusEvent = {
|
|
29
|
+
type: string;
|
|
30
|
+
};
|
|
31
|
+
type DeusAction<TBoard, TEvent extends DeusEvent> = (board: TBoard, event: TEvent) => void;
|
|
32
|
+
type DeusStateRow<TBoard, TEvent extends DeusEvent> = {
|
|
33
|
+
path: DeusStatePath;
|
|
34
|
+
onEnter?: DeusAction<TBoard, TEvent>;
|
|
35
|
+
onExit?: DeusAction<TBoard, TEvent>;
|
|
36
|
+
};
|
|
37
|
+
type DeusUtilityTransitionCandidate<TBoard, TEvent extends DeusEvent, TKey extends string = string> = {
|
|
38
|
+
key: TKey;
|
|
39
|
+
when?: (board: TBoard, event: TEvent) => boolean;
|
|
40
|
+
score: number | ((board: TBoard, event: TEvent) => number);
|
|
41
|
+
do?: DeusAction<TBoard, TEvent>;
|
|
42
|
+
reason?: string | ((board: TBoard, event: TEvent) => string);
|
|
43
|
+
};
|
|
44
|
+
type DeusTransitionRow<TBoard, TEvent extends DeusEvent> = {
|
|
45
|
+
key: string;
|
|
46
|
+
from: DeusStatePath;
|
|
47
|
+
event?: TEvent["type"];
|
|
48
|
+
to?: DeusStatePath | ((board: TBoard, event: TEvent) => DeusStatePath);
|
|
49
|
+
when?: (board: TBoard, event: TEvent) => boolean;
|
|
50
|
+
score?: number | ((board: TBoard, event: TEvent) => number);
|
|
51
|
+
do?: DeusAction<TBoard, TEvent>;
|
|
52
|
+
reason?: string | ((board: TBoard, event: TEvent) => string);
|
|
53
|
+
utility?: readonly DeusUtilityTransitionCandidate<TBoard, TEvent>[];
|
|
54
|
+
hysteresis?: {
|
|
55
|
+
previous: (board: TBoard) => string | undefined;
|
|
56
|
+
margin: number;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
type DeusMachine<TBoard, TEvent extends DeusEvent> = {
|
|
60
|
+
initial: DeusStatePath;
|
|
61
|
+
states: readonly DeusStateRow<TBoard, TEvent>[];
|
|
62
|
+
transitions: readonly DeusTransitionRow<TBoard, TEvent>[];
|
|
63
|
+
};
|
|
64
|
+
type DeusSnapshot<TBoard> = {
|
|
65
|
+
state: DeusStatePath;
|
|
66
|
+
board: TBoard;
|
|
67
|
+
stepIndex: number;
|
|
68
|
+
};
|
|
69
|
+
type DeusTransitionTrace = {
|
|
70
|
+
key: string;
|
|
71
|
+
from: DeusStatePath;
|
|
72
|
+
to?: DeusStatePath;
|
|
73
|
+
event?: string;
|
|
74
|
+
eligible: boolean;
|
|
75
|
+
score: number;
|
|
76
|
+
index: number;
|
|
77
|
+
reason?: string;
|
|
78
|
+
utility?: UtilityJudgment<string>;
|
|
79
|
+
};
|
|
80
|
+
type DeusStepTrace = {
|
|
81
|
+
stateBefore: DeusStatePath;
|
|
82
|
+
stateAfter: DeusStatePath;
|
|
83
|
+
event: string;
|
|
84
|
+
selectedTransition?: DeusTransitionTrace;
|
|
85
|
+
transitions: DeusTransitionTrace[];
|
|
86
|
+
};
|
|
87
|
+
type DeusStepResult<TBoard> = {
|
|
88
|
+
snapshot: DeusSnapshot<TBoard>;
|
|
89
|
+
trace: DeusStepTrace;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
type MachinaDebugOverlayMode = "collapsed" | "nonInteractiveOverlay" | "interactivePanel";
|
|
93
|
+
type MachinaDebugOverlayBoard = {
|
|
94
|
+
mode: MachinaDebugOverlayMode;
|
|
95
|
+
labels: boolean;
|
|
96
|
+
borders: boolean;
|
|
97
|
+
selectedNodeId?: string;
|
|
98
|
+
};
|
|
99
|
+
type MachinaDebugOverlayEvent = {
|
|
100
|
+
type: "showOverlay";
|
|
101
|
+
} | {
|
|
102
|
+
type: "openPanel";
|
|
103
|
+
nodeId?: string;
|
|
104
|
+
} | {
|
|
105
|
+
type: "collapse";
|
|
106
|
+
} | {
|
|
107
|
+
type: "toggleLabels";
|
|
108
|
+
} | {
|
|
109
|
+
type: "toggleBorders";
|
|
110
|
+
} | {
|
|
111
|
+
type: "selectNode";
|
|
112
|
+
nodeId: string;
|
|
113
|
+
};
|
|
114
|
+
type MachinaDebugOverlayBehavior = {
|
|
115
|
+
visible: boolean;
|
|
116
|
+
pointerEvents: "none" | "auto";
|
|
117
|
+
consumesLayoutSpace: boolean;
|
|
118
|
+
showPanel: boolean;
|
|
119
|
+
showLabels: boolean;
|
|
120
|
+
showBorders: boolean;
|
|
121
|
+
};
|
|
122
|
+
declare function createMachinaDebugOverlayMachine(): DeusMachine<MachinaDebugOverlayBoard, MachinaDebugOverlayEvent>;
|
|
123
|
+
declare function getMachinaDebugOverlayBehavior(board: MachinaDebugOverlayBoard): MachinaDebugOverlayBehavior;
|
|
124
|
+
|
|
125
|
+
export { type DeusEvent as D, type JudgeUtilityOptions as J, type MachinaDebugOverlayBehavior as M, type UtilityCandidate as U, type UtilityJudgment as a, type DeusMachine as b, type DeusSnapshot as c, type DeusStatePath as d, type DeusStepTrace as e, type DeusStepResult as f, type DeusAction as g, DeusMachinaError as h, type DeusStateRow as i, type DeusTransitionRow as j, type DeusTransitionTrace as k, type DeusUtilityTransitionCandidate as l, type MachinaDebugOverlayBoard as m, type MachinaDebugOverlayEvent as n, type MachinaDebugOverlayMode as o, type UtilityCandidateResult as p, type UtilityScore as q, createMachinaDebugOverlayMachine as r, getMachinaDebugOverlayBehavior as s };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { U as UtilityCandidate, J as JudgeUtilityOptions, a as UtilityJudgment, D as DeusEvent, b as DeusMachine, c as DeusSnapshot, d as DeusStatePath, e as DeusStepTrace, f as DeusStepResult } from '../debugOverlay-pJpj0n5H.js';
|
|
2
|
+
export { g as DeusAction, h as DeusMachinaError, i as DeusStateRow, j as DeusTransitionRow, k as DeusTransitionTrace, l as DeusUtilityTransitionCandidate, M as MachinaDebugOverlayBehavior, m as MachinaDebugOverlayBoard, n as MachinaDebugOverlayEvent, o as MachinaDebugOverlayMode, p as UtilityCandidateResult, q as UtilityScore, r as createMachinaDebugOverlayMachine, s as getMachinaDebugOverlayBehavior } from '../debugOverlay-pJpj0n5H.js';
|
|
3
|
+
|
|
4
|
+
declare function judgeUtility<TContext, TKey extends string = string>(context: TContext, candidates: readonly UtilityCandidate<TContext, TKey>[], options?: JudgeUtilityOptions<TKey>): UtilityJudgment<TKey>;
|
|
5
|
+
|
|
6
|
+
declare function formatDeusPath(path: DeusStatePath): string;
|
|
7
|
+
declare function sameDeusPath(a: DeusStatePath, b: DeusStatePath): boolean;
|
|
8
|
+
declare function isDeusAncestorPath(ancestor: DeusStatePath, path: DeusStatePath): boolean;
|
|
9
|
+
declare function defineDeusMachine<TBoard, TEvent extends DeusEvent>(machine: DeusMachine<TBoard, TEvent>): DeusMachine<TBoard, TEvent>;
|
|
10
|
+
declare function createDeusSnapshot<TBoard, TEvent extends DeusEvent>(machine: DeusMachine<TBoard, TEvent>, board: TBoard): DeusSnapshot<TBoard>;
|
|
11
|
+
declare function stepDeusMachine<TBoard, TEvent extends DeusEvent>(machine: DeusMachine<TBoard, TEvent>, snapshot: DeusSnapshot<TBoard>, event: NoInfer<TEvent>): DeusStepResult<TBoard>;
|
|
12
|
+
declare function formatDeusStepTrace(trace: DeusStepTrace): string;
|
|
13
|
+
|
|
14
|
+
export { DeusEvent, DeusMachine, DeusSnapshot, DeusStatePath, DeusStepResult, DeusStepTrace, JudgeUtilityOptions, UtilityCandidate, UtilityJudgment, createDeusSnapshot, defineDeusMachine, formatDeusPath, formatDeusStepTrace, isDeusAncestorPath, judgeUtility, sameDeusPath, stepDeusMachine };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DeusMachinaError,
|
|
3
|
+
createDeusSnapshot,
|
|
4
|
+
createMachinaDebugOverlayMachine,
|
|
5
|
+
defineDeusMachine,
|
|
6
|
+
formatDeusPath,
|
|
7
|
+
formatDeusStepTrace,
|
|
8
|
+
getMachinaDebugOverlayBehavior,
|
|
9
|
+
isDeusAncestorPath,
|
|
10
|
+
judgeUtility,
|
|
11
|
+
sameDeusPath,
|
|
12
|
+
stepDeusMachine
|
|
13
|
+
} from "../chunk-2ZQ2RFFI.js";
|
|
14
|
+
export {
|
|
15
|
+
DeusMachinaError,
|
|
16
|
+
createDeusSnapshot,
|
|
17
|
+
createMachinaDebugOverlayMachine,
|
|
18
|
+
defineDeusMachine,
|
|
19
|
+
formatDeusPath,
|
|
20
|
+
formatDeusStepTrace,
|
|
21
|
+
getMachinaDebugOverlayBehavior,
|
|
22
|
+
isDeusAncestorPath,
|
|
23
|
+
judgeUtility,
|
|
24
|
+
sameDeusPath,
|
|
25
|
+
stepDeusMachine
|
|
26
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
type SetDispatchTable<TState> = {
|
|
2
|
+
events: readonly string[];
|
|
3
|
+
fields: readonly (keyof TState)[];
|
|
4
|
+
values: readonly unknown[];
|
|
5
|
+
};
|
|
6
|
+
type ToggleDispatchTable<TState> = {
|
|
7
|
+
events: readonly string[];
|
|
8
|
+
fields: readonly (keyof TState)[];
|
|
9
|
+
};
|
|
10
|
+
type IncrementDispatchTable<TState> = {
|
|
11
|
+
events: readonly string[];
|
|
12
|
+
fields: readonly (keyof TState)[];
|
|
13
|
+
by?: readonly number[];
|
|
14
|
+
};
|
|
15
|
+
type PrefixSetDispatchTable<TState> = {
|
|
16
|
+
prefixes: readonly string[];
|
|
17
|
+
fields: readonly (keyof TState)[];
|
|
18
|
+
allowedSuffixes?: readonly (readonly string[] | undefined)[];
|
|
19
|
+
};
|
|
20
|
+
type PrefixIncrementDispatchTable<TState> = {
|
|
21
|
+
prefixes: readonly string[];
|
|
22
|
+
fields: readonly (keyof TState)[];
|
|
23
|
+
by?: readonly number[];
|
|
24
|
+
allowedSuffixes?: readonly (readonly string[] | undefined)[];
|
|
25
|
+
};
|
|
26
|
+
type MachinaDispatchTables<TState> = {
|
|
27
|
+
set?: SetDispatchTable<TState>;
|
|
28
|
+
toggle?: ToggleDispatchTable<TState>;
|
|
29
|
+
increment?: IncrementDispatchTable<TState>;
|
|
30
|
+
setSuffix?: PrefixSetDispatchTable<TState>;
|
|
31
|
+
incrementSuffix?: PrefixIncrementDispatchTable<TState>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
declare function dispatchEvent<TState extends Record<string, unknown>>(state: TState, event: string, tables: MachinaDispatchTables<TState>): TState;
|
|
35
|
+
|
|
36
|
+
type MachinaDispatchErrorCode = "InvalidDispatchTable" | "InvalidDispatchField" | "InvalidDispatchValue" | "InvalidDispatchEvent";
|
|
37
|
+
declare class MachinaDispatchError extends Error {
|
|
38
|
+
readonly code: MachinaDispatchErrorCode;
|
|
39
|
+
constructor(code: MachinaDispatchErrorCode, message: string);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
declare function defineDispatchTables<TState>(tables: MachinaDispatchTables<TState>): MachinaDispatchTables<TState>;
|
|
43
|
+
declare function resolveEventValue<TValue>(event: string, table: {
|
|
44
|
+
events: readonly string[];
|
|
45
|
+
values: readonly TValue[];
|
|
46
|
+
}): TValue | undefined;
|
|
47
|
+
declare function matchEventPrefix(event: string, prefix: string, allowedSuffixes?: readonly string[]): string | undefined;
|
|
48
|
+
|
|
49
|
+
export { type IncrementDispatchTable, MachinaDispatchError, type MachinaDispatchErrorCode, type MachinaDispatchTables, type PrefixIncrementDispatchTable, type PrefixSetDispatchTable, type SetDispatchTable, type ToggleDispatchTable, defineDispatchTables, dispatchEvent, matchEventPrefix, resolveEventValue };
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
// src/dispatch/errors.ts
|
|
2
|
+
var MachinaDispatchError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(code, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "MachinaDispatchError";
|
|
7
|
+
this.code = code;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/dispatch/helpers.ts
|
|
12
|
+
var isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
13
|
+
var validateLengths = (name, ...columns) => {
|
|
14
|
+
const expected = columns[0]?.length ?? 0;
|
|
15
|
+
if (!columns.every((column) => Array.isArray(column) && column.length === expected)) {
|
|
16
|
+
throw new MachinaDispatchError("InvalidDispatchTable", `${name} column lengths must match`);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var validateAllowedSuffixes = (allowedSuffixes, expectedLength, tableName) => {
|
|
20
|
+
if (allowedSuffixes === void 0) return;
|
|
21
|
+
if (!Array.isArray(allowedSuffixes) || allowedSuffixes.length !== expectedLength) {
|
|
22
|
+
throw new MachinaDispatchError(
|
|
23
|
+
"InvalidDispatchTable",
|
|
24
|
+
`${tableName}.allowedSuffixes length mismatch`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
for (const row of allowedSuffixes) {
|
|
28
|
+
if (row !== void 0 && !isStringArray(row)) {
|
|
29
|
+
throw new MachinaDispatchError(
|
|
30
|
+
"InvalidDispatchTable",
|
|
31
|
+
`${tableName}.allowedSuffixes must be string arrays`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var validateBy = (by, expectedLength, tableName) => {
|
|
37
|
+
if (by === void 0) return;
|
|
38
|
+
if (!Array.isArray(by) || by.length !== expectedLength) {
|
|
39
|
+
throw new MachinaDispatchError("InvalidDispatchTable", `${tableName}.by length mismatch`);
|
|
40
|
+
}
|
|
41
|
+
for (const value of by) {
|
|
42
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
43
|
+
throw new MachinaDispatchError(
|
|
44
|
+
"InvalidDispatchTable",
|
|
45
|
+
`${tableName}.by must contain finite numbers`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var validateSetTable = (table) => {
|
|
51
|
+
validateLengths("set", table.events, table.fields, table.values);
|
|
52
|
+
if (!isStringArray(table.events))
|
|
53
|
+
throw new MachinaDispatchError("InvalidDispatchTable", "set.events must be strings");
|
|
54
|
+
};
|
|
55
|
+
var validateToggleTable = (table) => {
|
|
56
|
+
validateLengths("toggle", table.events, table.fields);
|
|
57
|
+
if (!isStringArray(table.events))
|
|
58
|
+
throw new MachinaDispatchError("InvalidDispatchTable", "toggle.events must be strings");
|
|
59
|
+
};
|
|
60
|
+
var validateIncrementTable = (table) => {
|
|
61
|
+
validateLengths("increment", table.events, table.fields);
|
|
62
|
+
if (!isStringArray(table.events))
|
|
63
|
+
throw new MachinaDispatchError("InvalidDispatchTable", "increment.events must be strings");
|
|
64
|
+
validateBy(table.by, table.events.length, "increment");
|
|
65
|
+
};
|
|
66
|
+
var validatePrefixSetTable = (table) => {
|
|
67
|
+
validateLengths("setSuffix", table.prefixes, table.fields);
|
|
68
|
+
if (!isStringArray(table.prefixes))
|
|
69
|
+
throw new MachinaDispatchError("InvalidDispatchTable", "setSuffix.prefixes must be strings");
|
|
70
|
+
validateAllowedSuffixes(table.allowedSuffixes, table.prefixes.length, "setSuffix");
|
|
71
|
+
};
|
|
72
|
+
var validatePrefixIncrementTable = (table) => {
|
|
73
|
+
validateLengths("incrementSuffix", table.prefixes, table.fields);
|
|
74
|
+
if (!isStringArray(table.prefixes))
|
|
75
|
+
throw new MachinaDispatchError(
|
|
76
|
+
"InvalidDispatchTable",
|
|
77
|
+
"incrementSuffix.prefixes must be strings"
|
|
78
|
+
);
|
|
79
|
+
validateBy(table.by, table.prefixes.length, "incrementSuffix");
|
|
80
|
+
validateAllowedSuffixes(table.allowedSuffixes, table.prefixes.length, "incrementSuffix");
|
|
81
|
+
};
|
|
82
|
+
function defineDispatchTables(tables) {
|
|
83
|
+
if (tables.set) validateSetTable(tables.set);
|
|
84
|
+
if (tables.toggle) validateToggleTable(tables.toggle);
|
|
85
|
+
if (tables.increment) validateIncrementTable(tables.increment);
|
|
86
|
+
if (tables.setSuffix) validatePrefixSetTable(tables.setSuffix);
|
|
87
|
+
if (tables.incrementSuffix) validatePrefixIncrementTable(tables.incrementSuffix);
|
|
88
|
+
return tables;
|
|
89
|
+
}
|
|
90
|
+
function resolveEventValue(event, table) {
|
|
91
|
+
validateLengths("resolveEventValue", table.events, table.values);
|
|
92
|
+
if (!isStringArray(table.events))
|
|
93
|
+
throw new MachinaDispatchError("InvalidDispatchTable", "events must be strings");
|
|
94
|
+
for (let i = 0; i < table.events.length; i += 1) {
|
|
95
|
+
if (table.events[i] === event) return table.values[i];
|
|
96
|
+
}
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
function matchEventPrefix(event, prefix, allowedSuffixes) {
|
|
100
|
+
if (typeof event !== "string" || typeof prefix !== "string") {
|
|
101
|
+
throw new MachinaDispatchError("InvalidDispatchEvent", "event and prefix must be strings");
|
|
102
|
+
}
|
|
103
|
+
if (allowedSuffixes !== void 0 && !isStringArray(allowedSuffixes)) {
|
|
104
|
+
throw new MachinaDispatchError(
|
|
105
|
+
"InvalidDispatchTable",
|
|
106
|
+
"allowedSuffixes must be a string array"
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
if (!event.startsWith(prefix)) return void 0;
|
|
110
|
+
const suffix = event.slice(prefix.length);
|
|
111
|
+
if (allowedSuffixes && !allowedSuffixes.includes(suffix)) return void 0;
|
|
112
|
+
return suffix;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/dispatch/dispatchEvent.ts
|
|
116
|
+
var hasOwn = (state, field) => Object.hasOwn(state, field);
|
|
117
|
+
function dispatchEvent(state, event, tables) {
|
|
118
|
+
if (typeof event !== "string") {
|
|
119
|
+
throw new MachinaDispatchError("InvalidDispatchEvent", "event must be a string");
|
|
120
|
+
}
|
|
121
|
+
const base = state;
|
|
122
|
+
if (tables.set) {
|
|
123
|
+
validateSetTable(tables.set);
|
|
124
|
+
for (let i = 0; i < tables.set.events.length; i += 1) {
|
|
125
|
+
if (tables.set.events[i] !== event) continue;
|
|
126
|
+
const field = tables.set.fields[i];
|
|
127
|
+
if (!hasOwn(base, field))
|
|
128
|
+
throw new MachinaDispatchError("InvalidDispatchField", `missing field: ${String(field)}`);
|
|
129
|
+
const nextValue = tables.set.values[i];
|
|
130
|
+
if (Object.is(base[field], nextValue)) return state;
|
|
131
|
+
return { ...state, [field]: nextValue };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (tables.toggle) {
|
|
135
|
+
validateToggleTable(tables.toggle);
|
|
136
|
+
for (let i = 0; i < tables.toggle.events.length; i += 1) {
|
|
137
|
+
if (tables.toggle.events[i] !== event) continue;
|
|
138
|
+
const field = tables.toggle.fields[i];
|
|
139
|
+
if (!hasOwn(base, field))
|
|
140
|
+
throw new MachinaDispatchError("InvalidDispatchField", `missing field: ${String(field)}`);
|
|
141
|
+
const current = base[field];
|
|
142
|
+
if (typeof current !== "boolean")
|
|
143
|
+
throw new MachinaDispatchError(
|
|
144
|
+
"InvalidDispatchValue",
|
|
145
|
+
`field must be boolean: ${String(field)}`
|
|
146
|
+
);
|
|
147
|
+
return { ...state, [field]: !current };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (tables.increment) {
|
|
151
|
+
validateIncrementTable(tables.increment);
|
|
152
|
+
for (let i = 0; i < tables.increment.events.length; i += 1) {
|
|
153
|
+
if (tables.increment.events[i] !== event) continue;
|
|
154
|
+
const field = tables.increment.fields[i];
|
|
155
|
+
if (!hasOwn(base, field))
|
|
156
|
+
throw new MachinaDispatchError("InvalidDispatchField", `missing field: ${String(field)}`);
|
|
157
|
+
const current = base[field];
|
|
158
|
+
if (typeof current !== "number")
|
|
159
|
+
throw new MachinaDispatchError(
|
|
160
|
+
"InvalidDispatchValue",
|
|
161
|
+
`field must be number: ${String(field)}`
|
|
162
|
+
);
|
|
163
|
+
const delta = tables.increment.by?.[i] ?? 1;
|
|
164
|
+
if (!Number.isFinite(delta))
|
|
165
|
+
throw new MachinaDispatchError("InvalidDispatchValue", "increment delta must be finite");
|
|
166
|
+
return { ...state, [field]: current + delta };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (tables.setSuffix) {
|
|
170
|
+
validatePrefixSetTable(tables.setSuffix);
|
|
171
|
+
for (let i = 0; i < tables.setSuffix.prefixes.length; i += 1) {
|
|
172
|
+
const suffix = matchEventPrefix(
|
|
173
|
+
event,
|
|
174
|
+
tables.setSuffix.prefixes[i],
|
|
175
|
+
tables.setSuffix.allowedSuffixes?.[i]
|
|
176
|
+
);
|
|
177
|
+
if (suffix === void 0) continue;
|
|
178
|
+
const field = tables.setSuffix.fields[i];
|
|
179
|
+
if (!hasOwn(base, field))
|
|
180
|
+
throw new MachinaDispatchError("InvalidDispatchField", `missing field: ${String(field)}`);
|
|
181
|
+
if (Object.is(base[field], suffix)) return state;
|
|
182
|
+
return { ...state, [field]: suffix };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (tables.incrementSuffix) {
|
|
186
|
+
validatePrefixIncrementTable(tables.incrementSuffix);
|
|
187
|
+
for (let i = 0; i < tables.incrementSuffix.prefixes.length; i += 1) {
|
|
188
|
+
const suffix = matchEventPrefix(
|
|
189
|
+
event,
|
|
190
|
+
tables.incrementSuffix.prefixes[i],
|
|
191
|
+
tables.incrementSuffix.allowedSuffixes?.[i]
|
|
192
|
+
);
|
|
193
|
+
if (suffix === void 0) continue;
|
|
194
|
+
const field = tables.incrementSuffix.fields[i];
|
|
195
|
+
if (!hasOwn(base, field))
|
|
196
|
+
throw new MachinaDispatchError("InvalidDispatchField", `missing field: ${String(field)}`);
|
|
197
|
+
const current = base[field];
|
|
198
|
+
if (typeof current !== "number")
|
|
199
|
+
throw new MachinaDispatchError(
|
|
200
|
+
"InvalidDispatchValue",
|
|
201
|
+
`field must be number: ${String(field)}`
|
|
202
|
+
);
|
|
203
|
+
const delta = tables.incrementSuffix.by?.[i] ?? 1;
|
|
204
|
+
if (!Number.isFinite(delta))
|
|
205
|
+
throw new MachinaDispatchError("InvalidDispatchValue", "increment delta must be finite");
|
|
206
|
+
return { ...state, [field]: current + delta };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return state;
|
|
210
|
+
}
|
|
211
|
+
export {
|
|
212
|
+
MachinaDispatchError,
|
|
213
|
+
defineDispatchTables,
|
|
214
|
+
dispatchEvent,
|
|
215
|
+
matchEventPrefix,
|
|
216
|
+
resolveEventValue
|
|
217
|
+
};
|