Source: mvc/StateMachine.js

  1. const collect = require('collect.js');
  2. const moment = require('moment');
  3. /**
  4. * The class implements a classic statemachine which allow state to change
  5. * when the {@link Transition|transtion guard function} is true.
  6. * Upon the change the {@link Transition|transition action function} is called
  7. */
  8. class StateMachine {
  9. /**
  10. * The construtcor
  11. * @param {Object} handler
  12. * The object to control.
  13. */
  14. constructor(handler) {
  15. if (handler == null) {
  16. throw Error('Illegal arguments');
  17. }
  18. this._transitions = collect({});
  19. this._state = 'start';
  20. this._handler = handler;
  21. }
  22. /**
  23. * Get current state
  24. * @returns {string}
  25. * The current state
  26. */
  27. get state() {
  28. return this._state;
  29. }
  30. /**
  31. * Add a single transition
  32. * @param {Transition} transition
  33. * The transition
  34. */
  35. add(transition) {
  36. let transitions = this._transitions.get(transition.from);
  37. if (transitions == null) {
  38. transitions = collect([]);
  39. this._transitions.put(transition.from, transitions)
  40. }
  41. transitions.push(transition);
  42. }
  43. /**
  44. * Run the statemachine
  45. * @param {Event} event
  46. * The event.
  47. */
  48. run(event) {
  49. //console.log(`${this._handler.constructor.name} ${event.toString()}`);
  50. let transitions = this._transitions.get(this._state);
  51. if (transitions == null) {
  52. throw Error(`No transitions found from state: ${this._state}`);
  53. }
  54. transitions.each(transtion => {
  55. if (transtion.canChange === undefined || transtion.canChange.call(this._handler, event)) {
  56. let ts = moment().format('hh:mm:ss:SSS');
  57. try {
  58. this._state = transtion.to;
  59. if (transtion.action != null) {
  60. console.log(`${ts} ${this._handler.constructor.name} State from: ${transtion.from} to: ${this._state} ${event.toString()}`);
  61. transtion.action.call(this._handler, event);
  62. return false;
  63. } else {
  64. console.warn(`${ts} ${this._handler.constructor.name} State from: ${transtion.from} to: ${this._state} ${event.toString()} has an empty action`)
  65. }
  66. } catch (e) {
  67. this._state = transtion.from;
  68. throw e;
  69. }
  70. }
  71. });
  72. }
  73. }
  74. exports.StateMachine = StateMachine;