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