@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.
- package/NOTICE +4 -0
- package/README.md +14 -8
- package/dist/DevServer.d.ts +2 -1
- package/dist/DevServer.d.ts.map +1 -1
- package/dist/DevServer.js.map +1 -1
- package/dist/DevToolsProtocol.d.ts +167 -17
- package/dist/DevToolsProtocol.d.ts.map +1 -1
- package/dist/DevToolsProtocol.js +1 -1
- package/dist/MachineDocument.d.ts +98 -2
- package/dist/MachineDocument.d.ts.map +1 -1
- package/dist/MachineDocument.js +35 -1
- package/dist/MachineDocument.js.map +1 -1
- package/dist/MachineRegistry.d.ts +56 -6
- package/dist/MachineRegistry.d.ts.map +1 -1
- package/dist/MachineWalkthrough.d.ts +171 -0
- package/dist/MachineWalkthrough.d.ts.map +1 -0
- package/dist/MachineWalkthrough.js +98 -0
- package/dist/MachineWalkthrough.js.map +1 -0
- package/dist/client/assets/index-BTOAhezX.js +37 -0
- package/dist/client/assets/index-Cg7xzSkz.css +1 -0
- package/dist/client/index.html +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/devServer.d.ts +2 -1
- package/dist/internal/devServer.d.ts.map +1 -1
- package/dist/internal/devServer.js +4 -3
- package/dist/internal/devServer.js.map +1 -1
- package/dist/internal/evaluationWorker.d.ts.map +1 -1
- package/dist/internal/evaluationWorker.js +28 -9
- package/dist/internal/evaluationWorker.js.map +1 -1
- package/dist/internal/machineDocument.d.ts.map +1 -1
- package/dist/internal/machineDocument.js +65 -2
- package/dist/internal/machineDocument.js.map +1 -1
- package/dist/internal/machineWalkthrough.d.ts +26 -0
- package/dist/internal/machineWalkthrough.d.ts.map +1 -0
- package/dist/internal/machineWalkthrough.js +256 -0
- package/dist/internal/machineWalkthrough.js.map +1 -0
- package/dist/internal/projectInspector.d.ts.map +1 -1
- package/dist/internal/projectInspector.js +15 -9
- package/dist/internal/projectInspector.js.map +1 -1
- package/index.html +2 -2
- package/package.json +4 -3
- package/src/DevServer.ts +6 -2
- package/src/DevToolsProtocol.ts +1 -1
- package/src/MachineDocument.ts +56 -1
- package/src/MachineWalkthrough.ts +199 -0
- package/src/index.ts +2 -2
- package/src/internal/browser/chart-layout.ts +433 -0
- package/src/internal/browser/chart-model.ts +234 -0
- package/src/internal/browser/chart-renderer.ts +661 -0
- package/src/internal/browser/example-machine.ts +15 -6
- package/src/internal/browser/input-form.ts +252 -0
- package/src/internal/browser/invoke-outcomes-example.ts +231 -0
- package/src/internal/browser/parallel-completion-example.ts +199 -0
- package/src/internal/browser/planner-example.ts +145 -0
- package/src/internal/browser/protocol-events-example.ts +200 -0
- package/src/internal/browser/styles.css +959 -185
- package/src/internal/browser/transition-semantics-example.ts +236 -0
- package/src/internal/browser/visualizer-app.ts +818 -389
- package/src/internal/browser/visualizer-model.ts +104 -0
- package/src/internal/browser/visualizer.ts +1 -1
- package/src/internal/devServer.ts +9 -4
- package/src/internal/evaluationWorker.ts +28 -10
- package/src/internal/machineDocument.ts +77 -2
- package/src/internal/machineWalkthrough.ts +355 -0
- package/src/internal/projectInspector.ts +29 -14
- package/dist/MachineSimulator.d.ts +0 -169
- package/dist/MachineSimulator.d.ts.map +0 -1
- package/dist/MachineSimulator.js +0 -98
- package/dist/MachineSimulator.js.map +0 -1
- package/dist/client/assets/index-BGOhE3Ng.css +0 -1
- package/dist/client/assets/index-DiqGhsGR.js +0 -14
- package/dist/internal/machineSimulator.d.ts +0 -5
- package/dist/internal/machineSimulator.d.ts.map +0 -1
- package/dist/internal/machineSimulator.js +0 -156
- package/dist/internal/machineSimulator.js.map +0 -1
- package/src/MachineSimulator.ts +0 -154
- package/src/internal/machineSimulator.ts +0 -199
|
@@ -72,6 +72,110 @@ export const triggerLabel = (transition: VisualizationTransition): string => {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
const propertyAccess = (key: string): string => /^[$A-Z_a-z][$\w]*$/.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`
|
|
76
|
+
|
|
77
|
+
const pathAccess = (path: string): string => path.split(".").map(propertyAccess).join("")
|
|
78
|
+
|
|
79
|
+
const nearestCompoundScope = (
|
|
80
|
+
document: VisualizationDocument,
|
|
81
|
+
source: string
|
|
82
|
+
): string | undefined => {
|
|
83
|
+
const states = new Map(document.states.map((state) => [state.path, state]))
|
|
84
|
+
let current = states.get(source)
|
|
85
|
+
while (current !== undefined) {
|
|
86
|
+
if (current.type === "compound") return current.path
|
|
87
|
+
current = current.parent === null ? undefined : states.get(current.parent)
|
|
88
|
+
}
|
|
89
|
+
return undefined
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const localPathAccess = (
|
|
93
|
+
document: VisualizationDocument,
|
|
94
|
+
source: string,
|
|
95
|
+
path: string
|
|
96
|
+
): string | undefined => {
|
|
97
|
+
const scope = nearestCompoundScope(document, source)
|
|
98
|
+
if (scope === undefined) return undefined
|
|
99
|
+
if (path === scope) return ""
|
|
100
|
+
const prefix = `${scope}.`
|
|
101
|
+
return path.startsWith(prefix) ? pathAccess(path.slice(prefix.length)) : undefined
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Canonical Effect Machine selector represented by one retained transition branch. */
|
|
105
|
+
export const branchTargetApi = (
|
|
106
|
+
document: VisualizationDocument,
|
|
107
|
+
source: string,
|
|
108
|
+
branch: VisualizationBranch
|
|
109
|
+
): string | undefined => {
|
|
110
|
+
const { selection } = branch
|
|
111
|
+
if (selection.kind === "none") return "to.none"
|
|
112
|
+
const path = selection.path
|
|
113
|
+
if (path === null || selection.scope === null) return undefined
|
|
114
|
+
|
|
115
|
+
let api: string | undefined
|
|
116
|
+
if (selection.kind === "history" && selection.scope === "full") {
|
|
117
|
+
api = `to.history${pathAccess(path)}`
|
|
118
|
+
} else if (selection.scope === "local") {
|
|
119
|
+
const local = localPathAccess(document, source, path)
|
|
120
|
+
if (local === undefined) return undefined
|
|
121
|
+
switch (selection.kind) {
|
|
122
|
+
case "state":
|
|
123
|
+
api = local === "" ? "to.local.with" : `to.local${local}()`
|
|
124
|
+
break
|
|
125
|
+
case "choice":
|
|
126
|
+
api = local === "" ? undefined : `to.local${local}()`
|
|
127
|
+
break
|
|
128
|
+
case "initial":
|
|
129
|
+
api = local === "" ? undefined : `to.local${local}.initial`
|
|
130
|
+
break
|
|
131
|
+
case "update":
|
|
132
|
+
api = local === "" ? "to.local.update" : undefined
|
|
133
|
+
break
|
|
134
|
+
case "history":
|
|
135
|
+
break
|
|
136
|
+
}
|
|
137
|
+
} else if (selection.scope === "branch") {
|
|
138
|
+
switch (selection.kind) {
|
|
139
|
+
case "state":
|
|
140
|
+
case "choice":
|
|
141
|
+
api = `to.branch${pathAccess(path)}()`
|
|
142
|
+
break
|
|
143
|
+
case "initial":
|
|
144
|
+
api = `to.branch${pathAccess(path)}.initial`
|
|
145
|
+
break
|
|
146
|
+
case "update":
|
|
147
|
+
api = `to.branch${pathAccess(path)}.update`
|
|
148
|
+
break
|
|
149
|
+
case "history":
|
|
150
|
+
break
|
|
151
|
+
}
|
|
152
|
+
} else if (selection.scope === "full") {
|
|
153
|
+
switch (selection.kind) {
|
|
154
|
+
case "state":
|
|
155
|
+
case "choice":
|
|
156
|
+
api = `to.full${pathAccess(path)}()`
|
|
157
|
+
break
|
|
158
|
+
case "initial":
|
|
159
|
+
api = `to.full${pathAccess(path)}.initial`
|
|
160
|
+
break
|
|
161
|
+
case "history":
|
|
162
|
+
api = `to.history${pathAccess(path)}`
|
|
163
|
+
break
|
|
164
|
+
case "update":
|
|
165
|
+
break
|
|
166
|
+
}
|
|
167
|
+
} else if (selection.scope === "initial") {
|
|
168
|
+
if (selection.kind === "state") api = `to${pathAccess(path)}()`
|
|
169
|
+
if (selection.kind === "initial") api = `to${pathAccess(path)}.initial`
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (api === undefined || selection.kind === "update") return api
|
|
173
|
+
return branch.updates.reduce(
|
|
174
|
+
(expression, owner) => `${expression}.updating(to.branch${pathAccess(owner)})`,
|
|
175
|
+
api
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
75
179
|
const buildInitialPaths = (document: VisualizationDocument): ReadonlySet<string> => {
|
|
76
180
|
const initial = new Set<string>([document.initial.target])
|
|
77
181
|
for (const state of document.states) {
|
|
@@ -22,7 +22,7 @@ export const mountVisualizer = (root: HTMLElement, source: MachineResult): void
|
|
|
22
22
|
switch (source._tag) {
|
|
23
23
|
case "Ready":
|
|
24
24
|
case "Partial":
|
|
25
|
-
renderVisualizer(root, source.document, source.diagnostics)
|
|
25
|
+
renderVisualizer(root, source.key, source.document, source.diagnostics)
|
|
26
26
|
break
|
|
27
27
|
case "Failed":
|
|
28
28
|
renderError(root, source)
|
|
@@ -7,6 +7,7 @@ import { fileURLToPath } from "node:url"
|
|
|
7
7
|
import { createServer, type Plugin, type ViteDevServer } from "vite"
|
|
8
8
|
import type * as DevServer from "../DevServer.js"
|
|
9
9
|
import * as MachineRegistry from "../MachineRegistry.js"
|
|
10
|
+
import * as ProjectInspector from "../ProjectInspector.js"
|
|
10
11
|
|
|
11
12
|
type DevServerErrorConstructor = typeof DevServer.DevServerError
|
|
12
13
|
|
|
@@ -41,8 +42,8 @@ const isIgnored = (file: string): boolean =>
|
|
|
41
42
|
part === "references"
|
|
42
43
|
)
|
|
43
44
|
|
|
44
|
-
const writeJson = (response: ServerResponse, value: unknown): void => {
|
|
45
|
-
response.statusCode =
|
|
45
|
+
const writeJson = (response: ServerResponse, value: unknown, status = 200): void => {
|
|
46
|
+
response.statusCode = status
|
|
46
47
|
response.setHeader("content-type", "application/json; charset=utf-8")
|
|
47
48
|
response.setHeader("cache-control", "no-store")
|
|
48
49
|
response.end(JSON.stringify(value))
|
|
@@ -54,7 +55,7 @@ const apiPlugin = (
|
|
|
54
55
|
name: "effect-machine-devtools-api",
|
|
55
56
|
configureServer(server) {
|
|
56
57
|
server.middlewares.use((request: IncomingMessage, response: ServerResponse, next: () => void) => {
|
|
57
|
-
if (request.url === "/api/machines") {
|
|
58
|
+
if (request.method === "GET" && request.url === "/api/machines") {
|
|
58
59
|
void Effect.runPromise(registry.get).then(
|
|
59
60
|
(snapshot) => writeJson(response, snapshot),
|
|
60
61
|
(cause) => {
|
|
@@ -154,7 +155,11 @@ export const watcherOptions = (options: DevServer.Options): ChokidarOptions =>
|
|
|
154
155
|
export const run = (
|
|
155
156
|
ErrorType: DevServerErrorConstructor,
|
|
156
157
|
options: DevServer.Options
|
|
157
|
-
): Effect.Effect<
|
|
158
|
+
): Effect.Effect<
|
|
159
|
+
never,
|
|
160
|
+
DevServer.DevServerError,
|
|
161
|
+
MachineRegistry.MachineRegistry | ProjectInspector.ProjectInspector
|
|
162
|
+
> =>
|
|
158
163
|
Effect.gen(function*() {
|
|
159
164
|
const registry = yield* MachineRegistry.MachineRegistry
|
|
160
165
|
const server = yield* Effect.acquireRelease(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as NodeWorkerRunner from "@effect/platform-node/NodeWorkerRunner"
|
|
2
|
-
import
|
|
2
|
+
import { Machine } from "@typeonce/effect-machine"
|
|
3
3
|
import * as Effect from "effect/Effect"
|
|
4
|
+
import * as Schema from "effect/Schema"
|
|
4
5
|
import * as WorkerRunner from "effect/unstable/workers/WorkerRunner"
|
|
5
6
|
import { resolve } from "node:path"
|
|
6
7
|
import { pathToFileURL } from "node:url"
|
|
@@ -10,15 +11,20 @@ import * as MachineDocument from "../MachineDocument.js"
|
|
|
10
11
|
import type * as ProjectInspector from "../ProjectInspector.js"
|
|
11
12
|
|
|
12
13
|
interface EvaluationRequest {
|
|
14
|
+
readonly _tag: "InspectMachines"
|
|
13
15
|
readonly root: string
|
|
14
16
|
readonly revision: number
|
|
15
17
|
readonly candidates: ReadonlyArray<ProjectInspector.Candidate>
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
interface EvaluationResponse {
|
|
21
|
+
readonly _tag: "InspectedMachines"
|
|
19
22
|
readonly results: ReadonlyArray<DevToolsProtocol.MachineResult>
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
type WorkerRequest = EvaluationRequest
|
|
26
|
+
type WorkerResponse = EvaluationResponse
|
|
27
|
+
|
|
22
28
|
const isMachine = (value: unknown): value is Machine.Machine.Any =>
|
|
23
29
|
typeof value === "object" &&
|
|
24
30
|
value !== null &&
|
|
@@ -41,7 +47,22 @@ const diagnostic = (
|
|
|
41
47
|
statePath: null
|
|
42
48
|
})
|
|
43
49
|
|
|
44
|
-
const messageOf = (cause: unknown): string =>
|
|
50
|
+
const messageOf = (cause: unknown): string => {
|
|
51
|
+
if (Schema.isSchemaError(cause)) return `Invalid machine value: ${cause.message}`
|
|
52
|
+
if (cause instanceof Error && cause.message.length > 0) return cause.message
|
|
53
|
+
if (typeof cause === "object" && cause !== null && "cause" in cause && Schema.isSchemaError(cause.cause)) {
|
|
54
|
+
const boundary = "boundary" in cause ? String(cause.boundary) : "value"
|
|
55
|
+
return `Invalid machine ${boundary}: ${cause.cause.message}`
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const encoded = JSON.stringify(cause, null, 2)
|
|
59
|
+
if (encoded !== undefined && encoded !== "{}") return encoded
|
|
60
|
+
} catch {
|
|
61
|
+
// Fall back to the runtime string representation below.
|
|
62
|
+
}
|
|
63
|
+
const rendered = String(cause)
|
|
64
|
+
return rendered.length > 0 ? rendered : "The evaluator failed without a diagnostic message"
|
|
65
|
+
}
|
|
45
66
|
|
|
46
67
|
const failed = (
|
|
47
68
|
candidate: ProjectInspector.Candidate,
|
|
@@ -121,18 +142,15 @@ const handle = (server: ViteDevServer, request: EvaluationRequest): Effect.Effec
|
|
|
121
142
|
Effect.forEach(request.candidates, (candidate) => evaluateCandidate(server, request, candidate), {
|
|
122
143
|
concurrency: 1
|
|
123
144
|
}).pipe(
|
|
124
|
-
Effect.map((results) => ({ results: results.flat() }))
|
|
145
|
+
Effect.map((results) => ({ _tag: "InspectedMachines" as const, results: results.flat() }))
|
|
125
146
|
)
|
|
126
147
|
|
|
127
|
-
export const run = (server: ViteDevServer): Promise<void> =>
|
|
128
|
-
|
|
148
|
+
export const run = (server: ViteDevServer): Promise<void> =>
|
|
149
|
+
Effect.gen(function*() {
|
|
129
150
|
const platform = yield* WorkerRunner.WorkerRunnerPlatform
|
|
130
|
-
const runner = yield* platform.start<
|
|
131
|
-
yield* runner.run((_portId, request) =>
|
|
132
|
-
Effect.flatMap(handle(server, request), (response) => runner.send(0, response))
|
|
133
|
-
)
|
|
151
|
+
const runner = yield* platform.start<WorkerResponse, WorkerRequest>()
|
|
152
|
+
yield* runner.run((_portId, request) => Effect.flatMap(handle(server, request), (value) => runner.send(0, value)))
|
|
134
153
|
}).pipe(
|
|
135
154
|
Effect.provide(NodeWorkerRunner.layer),
|
|
136
155
|
Effect.runPromise
|
|
137
156
|
)
|
|
138
|
-
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Machine } from "@typeonce/effect-machine"
|
|
2
|
+
import * as Schema from "effect/Schema"
|
|
2
3
|
import type * as Public from "../MachineDocument.js"
|
|
3
4
|
|
|
4
5
|
const enabled = Machine.enabled as (
|
|
@@ -6,6 +7,72 @@ const enabled = Machine.enabled as (
|
|
|
6
7
|
snapshot: unknown
|
|
7
8
|
) => ReadonlyArray<PropertyKey>
|
|
8
9
|
|
|
10
|
+
const inputEventSchemas = Machine.inputEventSchemas as (
|
|
11
|
+
machine: Machine.Machine.Any
|
|
12
|
+
) => ReadonlyArray<Machine.Machine.TaggedSchema>
|
|
13
|
+
|
|
14
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
15
|
+
typeof value === "object" && value !== null && !Array.isArray(value)
|
|
16
|
+
|
|
17
|
+
const resolveReference = (
|
|
18
|
+
value: unknown,
|
|
19
|
+
definitions: Readonly<Record<string, unknown>>
|
|
20
|
+
): Record<string, unknown> | undefined => {
|
|
21
|
+
if (!isRecord(value)) return undefined
|
|
22
|
+
if (typeof value.$ref !== "string" || !value.$ref.startsWith("#/$defs/")) return value
|
|
23
|
+
const name = decodeURIComponent(value.$ref.slice("#/$defs/".length))
|
|
24
|
+
const target = definitions[name]
|
|
25
|
+
return isRecord(target) ? target : undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const tagsOf = (
|
|
29
|
+
value: unknown,
|
|
30
|
+
definitions: Readonly<Record<string, unknown>>
|
|
31
|
+
): ReadonlyArray<string> => {
|
|
32
|
+
const schema = resolveReference(value, definitions)
|
|
33
|
+
if (schema === undefined || !isRecord(schema.properties)) return []
|
|
34
|
+
const tag = resolveReference(schema.properties._tag, definitions)
|
|
35
|
+
if (tag === undefined) return []
|
|
36
|
+
if (typeof tag.const === "string" || typeof tag.const === "number") return [String(tag.const)]
|
|
37
|
+
return Array.isArray(tag.enum)
|
|
38
|
+
? tag.enum.filter((item): item is string | number => typeof item === "string" || typeof item === "number").map(
|
|
39
|
+
String
|
|
40
|
+
)
|
|
41
|
+
: []
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const inputSchema = (schema: Schema.Top): Public.InputSchema => {
|
|
45
|
+
const document = Schema.toJsonSchemaDocument(schema)
|
|
46
|
+
return {
|
|
47
|
+
dialect: document.dialect,
|
|
48
|
+
schema: document.schema as Schema.Json,
|
|
49
|
+
definitions: document.definitions as Record<string, Schema.Json>
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const eventInputs = (machine: Machine.Machine.Any): ReadonlyArray<Public.EventInput> => {
|
|
54
|
+
const inputs: Array<Public.EventInput> = []
|
|
55
|
+
for (const eventSchema of inputEventSchemas(machine)) {
|
|
56
|
+
const document = inputSchema(eventSchema)
|
|
57
|
+
const root = document.schema
|
|
58
|
+
const record = isRecord(root) ? root : undefined
|
|
59
|
+
const variants = record !== undefined && Array.isArray(record.anyOf)
|
|
60
|
+
? record.anyOf
|
|
61
|
+
: record !== undefined && Array.isArray(record.oneOf)
|
|
62
|
+
? record.oneOf
|
|
63
|
+
: [root]
|
|
64
|
+
for (const variant of variants) {
|
|
65
|
+
for (const event of tagsOf(variant, document.definitions)) {
|
|
66
|
+
inputs.push({
|
|
67
|
+
event,
|
|
68
|
+
schema: { ...document, schema: variant as Schema.Json }
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return inputs
|
|
74
|
+
}
|
|
75
|
+
|
|
9
76
|
const selection = (value: Machine.Machine.TransitionTargetSelection): Public.Selection => ({
|
|
10
77
|
path: value.path ?? null,
|
|
11
78
|
kind: value.kind,
|
|
@@ -102,7 +169,7 @@ export const make = <M extends Machine.Machine.Any>(
|
|
|
102
169
|
|
|
103
170
|
const initial = Machine.initialDefinition(machine)
|
|
104
171
|
return {
|
|
105
|
-
schemaVersion:
|
|
172
|
+
schemaVersion: 3,
|
|
106
173
|
revision: options.revision ?? 0,
|
|
107
174
|
source: options.source ?? null,
|
|
108
175
|
machineId: machine.id ?? "Machine",
|
|
@@ -123,16 +190,24 @@ export const make = <M extends Machine.Machine.Any>(
|
|
|
123
190
|
parent: node.parent ?? null,
|
|
124
191
|
children: [...childPaths.get(node.path) ?? []],
|
|
125
192
|
initial: node.initial ?? null,
|
|
193
|
+
valueSchema: node.schema === undefined ? null : inputSchema(node.schema),
|
|
194
|
+
outputSchema: node.output === undefined ? null : inputSchema(node.output),
|
|
126
195
|
transitionIds: [...transitionIds.get(node.path) ?? []],
|
|
127
196
|
activityIds: [...activityIds.get(node.path) ?? []]
|
|
128
197
|
})),
|
|
129
198
|
transitions,
|
|
130
199
|
activities,
|
|
200
|
+
inputs: {
|
|
201
|
+
machine: machine.input === undefined ? null : inputSchema(machine.input),
|
|
202
|
+
events: eventInputs(machine)
|
|
203
|
+
},
|
|
131
204
|
snapshot: options.snapshot === undefined
|
|
132
205
|
? null
|
|
133
206
|
: {
|
|
134
207
|
activePaths: Machine.configuration(machine, options.snapshot).map((node) => node.path),
|
|
135
|
-
candidateEvents: enabled(machine, options.snapshot)
|
|
208
|
+
candidateEvents: enabled(machine, options.snapshot)
|
|
209
|
+
.map(String)
|
|
210
|
+
.filter((event) => Object.hasOwn(machine.events, event))
|
|
136
211
|
}
|
|
137
212
|
}
|
|
138
213
|
}
|