|
|
|
|
@@ -1,52 +1,78 @@
|
|
|
|
|
import { Stream } from './stream.js';
|
|
|
|
|
import { Stream } from "stream";
|
|
|
|
|
|
|
|
|
|
export class Interactor {
|
|
|
|
|
_actions = new Stream();
|
|
|
|
|
_reactions = new Stream();
|
|
|
|
|
_latestReaction;
|
|
|
|
|
#actions = new Stream();
|
|
|
|
|
#reactions = new Stream();
|
|
|
|
|
#latestReaction;
|
|
|
|
|
#latestReactions = {};
|
|
|
|
|
|
|
|
|
|
constructor(initialReaction = new Reaction()) {
|
|
|
|
|
this._latestReactions = {};
|
|
|
|
|
this._actions.listen((action) => this._interaction(action));
|
|
|
|
|
this.#actions.listen((action) => {
|
|
|
|
|
this[`_handle${action.constructor.name}`](action);
|
|
|
|
|
});
|
|
|
|
|
this._react(initialReaction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
act(action) {
|
|
|
|
|
if (!(action instanceof Action)) throw 'invalid action';
|
|
|
|
|
this._actions.add(action);
|
|
|
|
|
if (!(action instanceof Action)) throw "invalid action";
|
|
|
|
|
this.#actions.add(action);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
observe(reactionHandler, provideLatestReaction = true) {
|
|
|
|
|
if (provideLatestReaction) reactionHandler(this._latestReaction);
|
|
|
|
|
if (provideLatestReaction) reactionHandler(this.#latestReaction);
|
|
|
|
|
let listener = (reaction) => {
|
|
|
|
|
if (!(reaction instanceof Reaction)) throw 'invalid reaction';
|
|
|
|
|
if (!(reaction instanceof Reaction)) throw "invalid reaction";
|
|
|
|
|
reactionHandler(reaction);
|
|
|
|
|
};
|
|
|
|
|
this._reactions.listen(listener);
|
|
|
|
|
this.#reactions.listen(listener);
|
|
|
|
|
return listener;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ignore(listener) {
|
|
|
|
|
this._reactions.ignore(listener);
|
|
|
|
|
this.#reactions.ignore(listener);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_interaction(action) {}
|
|
|
|
|
|
|
|
|
|
_react(reaction) {
|
|
|
|
|
if (!(reaction instanceof Reaction)) throw 'invalid reaction';
|
|
|
|
|
let latest = this._latestReactions[reaction.constructor.name];
|
|
|
|
|
if (!(reaction instanceof Reaction)) throw "invalid reaction";
|
|
|
|
|
let latest = this.#latestReactions[reaction.constructor.name];
|
|
|
|
|
if (!reaction.equals(latest)) {
|
|
|
|
|
this._latestReaction = reaction;
|
|
|
|
|
this._latestReactions[reaction.constructor.name] = reaction;
|
|
|
|
|
this._reactions.add(reaction);
|
|
|
|
|
this.#latestReaction = reaction;
|
|
|
|
|
this.#latestReactions[reaction.constructor.name] = reaction;
|
|
|
|
|
this.#reactions.add(reaction);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class Action {}
|
|
|
|
|
|
|
|
|
|
export class ActionBundle {
|
|
|
|
|
add(action) {
|
|
|
|
|
if (!(action.prototype instanceof Action)) {
|
|
|
|
|
throw "Only classes extended by `Action` can be added to a `ActionBundle`";
|
|
|
|
|
}
|
|
|
|
|
let actionName = action.name;
|
|
|
|
|
this[`#${actionName}`] = action;
|
|
|
|
|
Object.defineProperty(this, actionName, {
|
|
|
|
|
get: () => this[`#${actionName}`],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class Reaction {
|
|
|
|
|
equals(reaction) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class ReactionBundle {
|
|
|
|
|
add(reaction) {
|
|
|
|
|
if (!(reaction.prototype instanceof Reaction)) {
|
|
|
|
|
throw "Only classes extended by `Reaction` can be added to a `ReactionBundle`";
|
|
|
|
|
}
|
|
|
|
|
let reactionName = reaction.name;
|
|
|
|
|
this[`#${reactionName}`] = reaction;
|
|
|
|
|
Object.defineProperty(this, reactionName, {
|
|
|
|
|
get: () => this[`#${reactionName}`],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|