You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
2.8 KiB
JavaScript

(() => {
// src/index.ts
var Machine = function(...states) {
return { states };
};
var State = function(name, ...ons) {
return { name, ons };
};
var On = function(eventName, ...reactions) {
return { eventName, reactions };
};
var Do = function(fn) {
return { type: "Do", fn };
};
var Goto = function(targetStateName) {
return { type: "Goto", targetStateName };
};
var Tick = function(doFunctions) {
return { doFunctions };
};
function interpret(machine2, options) {
let { state, context } = options;
if (typeof state === "undefined") {
state = machine2.states[0].name;
}
const interpreter = { machine: machine2, state, context, tickQueues: [] };
console.log(interpreter);
send(interpreter, ["entry", null]);
return interpreter;
}
function getState(interpreter) {
return interpreter.machine.states.find((state) => state.name === interpreter.state);
}
function getOns(state, event) {
return state.ons.filter((on) => on.eventName === event[0]);
}
function noop() {
}
function send(interpreter, event) {
const state = getState(interpreter);
const onsTree = getOns(state, event);
const reactions = onsTree.map((on) => on.reactions).flat();
const indexOfFirstGoto = reactions.findIndex((reaction) => reaction.type === "Goto");
const indexOfFinalReaction = indexOfFirstGoto === -1 ? reactions.length - 1 : indexOfFirstGoto;
const reactionsUntilFirstGoto = reactions.slice(0, indexOfFinalReaction + 1);
const functionsToRunInTick = reactionsUntilFirstGoto.map((reaction) => {
if (reaction.type === "Do") {
return reaction.fn;
} else if (reaction.type === "Goto") {
return (ctx, e, self) => {
self.state = reaction.targetStateName;
send(self, ["entry", e]);
};
} else {
return noop;
}
});
const tick = Tick(functionsToRunInTick);
tick.doFunctions.forEach((fn) => {
fn(interpreter.context, event, interpreter);
});
}
// src/tests/00-basic.ts
var beginTimer = (ctx, e, self) => {
setTimeout(() => {
send(self, ["timer-finished", null]);
}, 800);
};
var log = (ctx, e, self) => {
console.log(self.state);
};
var machine = Machine(
State(
"green",
On(
"entry",
Do(beginTimer),
Do(log)
),
On(
"timer-finished",
Goto("yellow")
)
),
State(
"yellow",
On(
"entry",
Do(beginTimer),
Do(log)
),
On(
"timer-finished",
Goto("red")
)
),
State(
"red",
On(
"entry",
Do(beginTimer),
Do(log)
),
On(
"timer-finished",
Goto("green")
)
)
);
var actor = interpret(machine, { context: {} });
})();