@typeonce/effect-machine-devtools 0.23.0 → 0.25.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.
Files changed (80) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +14 -8
  3. package/dist/DevServer.d.ts +2 -1
  4. package/dist/DevServer.d.ts.map +1 -1
  5. package/dist/DevServer.js.map +1 -1
  6. package/dist/DevToolsProtocol.d.ts +167 -17
  7. package/dist/DevToolsProtocol.d.ts.map +1 -1
  8. package/dist/DevToolsProtocol.js +1 -1
  9. package/dist/MachineDocument.d.ts +98 -2
  10. package/dist/MachineDocument.d.ts.map +1 -1
  11. package/dist/MachineDocument.js +35 -1
  12. package/dist/MachineDocument.js.map +1 -1
  13. package/dist/MachineRegistry.d.ts +56 -6
  14. package/dist/MachineRegistry.d.ts.map +1 -1
  15. package/dist/MachineWalkthrough.d.ts +171 -0
  16. package/dist/MachineWalkthrough.d.ts.map +1 -0
  17. package/dist/MachineWalkthrough.js +98 -0
  18. package/dist/MachineWalkthrough.js.map +1 -0
  19. package/dist/client/assets/index-BTOAhezX.js +37 -0
  20. package/dist/client/assets/index-Cg7xzSkz.css +1 -0
  21. package/dist/client/index.html +4 -4
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +2 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/internal/devServer.d.ts +2 -1
  27. package/dist/internal/devServer.d.ts.map +1 -1
  28. package/dist/internal/devServer.js +4 -3
  29. package/dist/internal/devServer.js.map +1 -1
  30. package/dist/internal/evaluationWorker.d.ts.map +1 -1
  31. package/dist/internal/evaluationWorker.js +28 -9
  32. package/dist/internal/evaluationWorker.js.map +1 -1
  33. package/dist/internal/machineDocument.d.ts.map +1 -1
  34. package/dist/internal/machineDocument.js +65 -2
  35. package/dist/internal/machineDocument.js.map +1 -1
  36. package/dist/internal/machineWalkthrough.d.ts +26 -0
  37. package/dist/internal/machineWalkthrough.d.ts.map +1 -0
  38. package/dist/internal/machineWalkthrough.js +256 -0
  39. package/dist/internal/machineWalkthrough.js.map +1 -0
  40. package/dist/internal/projectInspector.d.ts.map +1 -1
  41. package/dist/internal/projectInspector.js +15 -9
  42. package/dist/internal/projectInspector.js.map +1 -1
  43. package/index.html +2 -2
  44. package/package.json +4 -3
  45. package/src/DevServer.ts +6 -2
  46. package/src/DevToolsProtocol.ts +1 -1
  47. package/src/MachineDocument.ts +56 -1
  48. package/src/MachineWalkthrough.ts +199 -0
  49. package/src/index.ts +2 -2
  50. package/src/internal/browser/chart-layout.ts +433 -0
  51. package/src/internal/browser/chart-model.ts +234 -0
  52. package/src/internal/browser/chart-renderer.ts +661 -0
  53. package/src/internal/browser/example-machine.ts +15 -6
  54. package/src/internal/browser/input-form.ts +252 -0
  55. package/src/internal/browser/invoke-outcomes-example.ts +231 -0
  56. package/src/internal/browser/parallel-completion-example.ts +199 -0
  57. package/src/internal/browser/planner-example.ts +145 -0
  58. package/src/internal/browser/protocol-events-example.ts +200 -0
  59. package/src/internal/browser/styles.css +959 -185
  60. package/src/internal/browser/transition-semantics-example.ts +236 -0
  61. package/src/internal/browser/visualizer-app.ts +818 -389
  62. package/src/internal/browser/visualizer-model.ts +104 -0
  63. package/src/internal/browser/visualizer.ts +1 -1
  64. package/src/internal/devServer.ts +9 -4
  65. package/src/internal/evaluationWorker.ts +28 -10
  66. package/src/internal/machineDocument.ts +77 -2
  67. package/src/internal/machineWalkthrough.ts +355 -0
  68. package/src/internal/projectInspector.ts +29 -14
  69. package/dist/MachineSimulator.d.ts +0 -169
  70. package/dist/MachineSimulator.d.ts.map +0 -1
  71. package/dist/MachineSimulator.js +0 -98
  72. package/dist/MachineSimulator.js.map +0 -1
  73. package/dist/client/assets/index-BGOhE3Ng.css +0 -1
  74. package/dist/client/assets/index-DiqGhsGR.js +0 -14
  75. package/dist/internal/machineSimulator.d.ts +0 -5
  76. package/dist/internal/machineSimulator.d.ts.map +0 -1
  77. package/dist/internal/machineSimulator.js +0 -156
  78. package/dist/internal/machineSimulator.js.map +0 -1
  79. package/src/MachineSimulator.ts +0 -154
  80. package/src/internal/machineSimulator.ts +0 -199
@@ -0,0 +1,234 @@
1
+ import type {
2
+ Activity as VisualizationActivity,
3
+ Branch as VisualizationBranch,
4
+ MachineDocument as VisualizationDocument,
5
+ State as VisualizationState,
6
+ Transition as VisualizationTransition
7
+ } from "../../MachineDocument.js"
8
+ import { type InputField, projectInputSchema } from "./input-form.js"
9
+ import { stateLabel, triggerLabel } from "./visualizer-model.js"
10
+
11
+ export interface ChartField {
12
+ readonly key: string
13
+ readonly label: string
14
+ readonly type: string
15
+ readonly required: boolean
16
+ }
17
+
18
+ export interface ChartActivity {
19
+ readonly id: string
20
+ readonly kind: VisualizationActivity["type"]
21
+ readonly label: string
22
+ }
23
+
24
+ export interface ChartNode {
25
+ readonly path: string
26
+ readonly label: string
27
+ readonly type: VisualizationState["type"]
28
+ readonly parent: string | null
29
+ readonly children: ReadonlyArray<string>
30
+ readonly active: boolean
31
+ readonly initial: boolean
32
+ readonly fields: ReadonlyArray<ChartField>
33
+ readonly activities: ReadonlyArray<ChartActivity>
34
+ }
35
+
36
+ export interface ChartEdge {
37
+ readonly id: string
38
+ readonly transitionId: string
39
+ readonly branchIds: ReadonlyArray<string>
40
+ readonly kind: "target" | "targetless" | "runtime"
41
+ readonly source: string
42
+ readonly target: string | null
43
+ readonly label: string
44
+ readonly trigger: VisualizationTransition["trigger"]
45
+ readonly reenter: boolean
46
+ readonly acceptance: VisualizationTransition["acceptance"]
47
+ }
48
+
49
+ export interface ChartRuntimeTarget {
50
+ readonly id: string
51
+ readonly edgeId: string
52
+ readonly parent: string | null
53
+ readonly label: string
54
+ }
55
+
56
+ export interface ChartInitial {
57
+ readonly id: string
58
+ readonly target: string
59
+ readonly parent: string | null
60
+ }
61
+
62
+ export interface ChartModel {
63
+ readonly machineId: string
64
+ readonly roots: ReadonlyArray<string>
65
+ readonly nodes: ReadonlyArray<ChartNode>
66
+ readonly edges: ReadonlyArray<ChartEdge>
67
+ readonly runtimeTargets: ReadonlyArray<ChartRuntimeTarget>
68
+ readonly initials: ReadonlyArray<ChartInitial>
69
+ }
70
+
71
+ const literalType = (value: string | number | boolean | null): string =>
72
+ typeof value === "string" ? JSON.stringify(value) : String(value)
73
+
74
+ const fieldType = (field: InputField): string => {
75
+ switch (field._tag) {
76
+ case "String":
77
+ return field.format ?? "string"
78
+ case "Number":
79
+ return field.integer ? "integer" : "number"
80
+ case "Boolean":
81
+ return "boolean"
82
+ case "Enum":
83
+ return field.values.map(literalType).join(" | ")
84
+ case "Literal":
85
+ return literalType(field.value)
86
+ case "Object":
87
+ return "object"
88
+ case "Array":
89
+ return `${fieldType(field.item)}[]`
90
+ case "Union":
91
+ return field.alternatives.map(fieldType).join(" | ")
92
+ case "Unsupported":
93
+ return "unknown"
94
+ }
95
+ }
96
+
97
+ const stateFields = (state: VisualizationState): ReadonlyArray<ChartField> => {
98
+ if (state.valueSchema === null) return []
99
+ const projected = projectInputSchema(state.valueSchema)
100
+ if (projected._tag !== "Object") {
101
+ return [{
102
+ key: "value",
103
+ label: projected.title ?? "value",
104
+ type: fieldType(projected),
105
+ required: true
106
+ }]
107
+ }
108
+ return projected.fields
109
+ .filter(({ key }) => key !== "_tag")
110
+ .map(({ field, key, required }) => ({
111
+ key,
112
+ label: field.title ?? key,
113
+ type: fieldType(field),
114
+ required
115
+ }))
116
+ }
117
+
118
+ const activityLabel = (activity: VisualizationActivity): string => {
119
+ switch (activity.type) {
120
+ case "machine":
121
+ return `${activity.lifecycleId} → ${activity.child.machineId ?? activity.child.id}`
122
+ case "timer":
123
+ return `${activity.lifecycleId} · ${activity.duration}`
124
+ case "process":
125
+ case "effect":
126
+ case "stream":
127
+ return activity.lifecycleId
128
+ }
129
+ }
130
+
131
+ const transitionLabel = (transition: VisualizationTransition, branch: VisualizationBranch): string => {
132
+ const trigger = triggerLabel(transition)
133
+ return branch.type === "branch" ? `${trigger} · ${branch.title}` : trigger
134
+ }
135
+
136
+ interface EdgeGroup {
137
+ readonly kind: ChartEdge["kind"]
138
+ readonly target: string | null
139
+ readonly branches: Array<VisualizationBranch>
140
+ }
141
+
142
+ const edgeGroup = (
143
+ branch: VisualizationBranch,
144
+ states: ReadonlyMap<string, VisualizationState>
145
+ ): { readonly key: string; readonly kind: ChartEdge["kind"]; readonly target: string | null } => {
146
+ if (branch.target !== null && states.has(branch.target)) {
147
+ return { key: `target:${branch.target}`, kind: "target", target: branch.target }
148
+ }
149
+ if (branch.selection.kind === "none" || branch.selection.kind === "update") {
150
+ return { key: "targetless", kind: "targetless", target: null }
151
+ }
152
+ return { key: "runtime", kind: "runtime", target: null }
153
+ }
154
+
155
+ export const makeChartModel = (document: VisualizationDocument): ChartModel => {
156
+ const active = new Set(document.snapshot?.activePaths ?? [])
157
+ const initialPaths = new Set([document.initial.target])
158
+ const activities = new Map(document.activities.map((activity) => [activity.id, activity]))
159
+ const states = new Map(document.states.map((state) => [state.path, state]))
160
+
161
+ for (const state of document.states) {
162
+ if (state.initial !== null) initialPaths.add(state.initial)
163
+ }
164
+
165
+ const nodes = document.states.map((state): ChartNode => ({
166
+ path: state.path,
167
+ label: stateLabel(state),
168
+ type: state.type,
169
+ parent: state.parent,
170
+ children: [...state.children],
171
+ active: active.has(state.path),
172
+ initial: initialPaths.has(state.path),
173
+ fields: stateFields(state),
174
+ activities: state.activityIds.flatMap((id): ReadonlyArray<ChartActivity> => {
175
+ const activity = activities.get(id)
176
+ return activity === undefined ? [] : [{ id, kind: activity.type, label: activityLabel(activity) }]
177
+ })
178
+ }))
179
+
180
+ const edges = document.transitions.flatMap((transition): ReadonlyArray<ChartEdge> => {
181
+ if (!states.has(transition.source)) return []
182
+ const groups = new Map<string, EdgeGroup>()
183
+ for (const branch of transition.branches) {
184
+ const group = edgeGroup(branch, states)
185
+ const current = groups.get(group.key)
186
+ if (current === undefined) {
187
+ groups.set(group.key, { kind: group.kind, target: group.target, branches: [branch] })
188
+ } else {
189
+ current.branches.push(branch)
190
+ }
191
+ }
192
+ return [...groups].map(([key, { branches, kind, target }]): ChartEdge => ({
193
+ id: branches.length === 1 ? branches[0]!.id : `${transition.id}:${key}`,
194
+ transitionId: transition.id,
195
+ branchIds: branches.map(({ id }) => id),
196
+ kind,
197
+ source: transition.source,
198
+ target,
199
+ label: branches.length === 1
200
+ ? transitionLabel(transition, branches[0]!)
201
+ : `${triggerLabel(transition)} · ${branches.length} branches`,
202
+ trigger: transition.trigger,
203
+ reenter: transition.reenter,
204
+ acceptance: transition.acceptance
205
+ }))
206
+ })
207
+
208
+ const runtimeTargets = edges.flatMap((edge): ReadonlyArray<ChartRuntimeTarget> => {
209
+ if (edge.kind !== "runtime") return []
210
+ const source = states.get(edge.source)
211
+ return source === undefined
212
+ ? []
213
+ : [{
214
+ id: `runtime:${edge.id}`,
215
+ edgeId: edge.id,
216
+ parent: source.parent,
217
+ label: "runtime target"
218
+ }]
219
+ })
220
+
221
+ const initials = [...initialPaths].flatMap((target): ReadonlyArray<ChartInitial> => {
222
+ const state = states.get(target)
223
+ return state === undefined ? [] : [{ id: `initial:${target}`, target, parent: state.parent }]
224
+ })
225
+
226
+ return {
227
+ machineId: document.machineId,
228
+ roots: [...document.roots],
229
+ nodes,
230
+ edges,
231
+ runtimeTargets,
232
+ initials
233
+ }
234
+ }