mirror of
https://github.com/morluto/rea.git
synced 2026-11-01 04:16:28 +00:00
42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
import type { ProcessReactiveScenario } from "./processReactiveScenario.js";
|
|
|
|
/** Checkpoints guaranteed on every known path entering each reactive state. */
|
|
export const definitelyAvailableCheckpoints = (
|
|
scenario: ProcessReactiveScenario,
|
|
): ReadonlyMap<string, ReadonlySet<string>> => {
|
|
const available = new Map<string, Set<string>>([
|
|
[scenario.initial_state, new Set()],
|
|
]);
|
|
let changed = true;
|
|
while (changed) {
|
|
changed = false;
|
|
for (const state of scenario.states) {
|
|
const before = available.get(state.id);
|
|
if (before === undefined) continue;
|
|
for (const transition of state.on) {
|
|
if (transition.target.kind !== "goto") continue;
|
|
const after = new Set(before);
|
|
for (const name of transition.actions.flatMap((action) =>
|
|
action.type === "checkpoint" ? [action.name] : [],
|
|
))
|
|
after.add(name);
|
|
const prior = available.get(transition.target.state);
|
|
const next =
|
|
prior === undefined
|
|
? after
|
|
: new Set([...prior].filter((name) => after.has(name)));
|
|
if (prior !== undefined && setsEqual(prior, next)) continue;
|
|
available.set(transition.target.state, next);
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
return available;
|
|
};
|
|
|
|
const setsEqual = (
|
|
left: ReadonlySet<string>,
|
|
right: ReadonlySet<string>,
|
|
): boolean =>
|
|
left.size === right.size && [...left].every((value) => right.has(value));
|