UNPKG

@wiz-code/async-fsm

Version:

Finite StateMachine JavaScript Library

210 lines (155 loc) 5.94 kB
'use strict'; var _ = require('underscore'); var Elem = require('./elem'); var BaseState = require('./base-state'); var FinalState = require('./states').FinalState; var InitialPseudoState = require('./pseudo-states').InitialPseudoState; var TerminatePseudoState = require('./pseudo-states').TerminatePseudoState; var logger = require('./logger'); var util = require('./util'); var Transition = function (name, source, target, options) { Elem.call(this, name); this._type = 'transition'; if (source === FinalState) { logger.error('終了状態を遷移元にすることはできません。'); } else if (source instanceof TerminatePseudoState) { logger.error('停止状態を遷移元にすることはできません。'); } else if (source instanceof BaseState || util.isFalsy(source) || InitialPseudoState) { this._rawSource = source; } else { logger.error('第2引数に遷移元のStateインスタンス、またはfalseを指定してください。'); } if (target === InitialPseudoState) { logger.error('開始擬似状態を遷移先にすることはできません。'); } else if (target instanceof BaseState || util.isFalsy(target) || FinalState) { this._rawTarget = target; } else { logger.error('第3引数に遷移先のStateインスタンス、またはfalseを指定してください。'); } options = _.defaults(options || {}, _.clone(Transition.options)); if (!_.isUndefined(options.data)) { this.set(options.data); } this.save(); if (!_.isUndefined(options.props)) { this.setProp(options.props); } if (!_.isUndefined(options.methods)) { this.setMethod(options.methods); } this.container = null; this.source = null; this.target = null; this.guard = options.guard; this.effect = options.effect; this.internal = options.internal; if (this.internal) { if (this._rawSource !== this._rawTarget) { logger.error('遷移元と遷移先は同じStateインスタンスを指定してください。'); } } this.unlocked = options.unlocked; this._isExplicitEntry = false; this._exitViaExitPoint = false; this.setObserverType('container'); }; Transition.options = { guard: null, effect: null, internal: false, unlocked: false, }; Transition.prototype = _.create(Elem.prototype, { constructor: Transition, _cname: 'Transition', test: function () { var result = false; try { if ( !this.isActive() && this.container.isActive() && this.source.isActive() && !this.target.isActive() ) { result = true; } } catch (e) {} return result; }, trigger: function () { var params = _.toArray(arguments); if (this.isActive()) { logger.error('Transitionインスタンス"' + this._name + '"はすでにアクティブ化されています。'); } if (!this.container.isActive()) { logger.error('Transitionインスタンス"' + this._name + '"のコンテナが非アクティブです。'); } else if (!this.source.isActive()) { logger.error('遷移元' + this.source._cname + 'インスタンス"' + this.source._name + '"が非アクティブです。'); } else if (this.target.isActive()) { logger.error('遷移先' + this.target._cname + 'インスタンス"' + this.target._name + '"がアクティブです。'); } if (!_.isNull(this.guard)) { if (!this.guard.apply(this, params)) { logger.info('ガードが成立しませんでした。遷移は発生しません。'); return; } } if (this.internal) { if (this.source === this.target) { this._async(function () { logger.info('内部遷移を実行します。'); if (!_.isNull(this.effect)) { this.effect.apply(this, params); } }); return; } else { logger.error('遷移元と遷移先は同じStateインスタンスを指定してください。'); } } this._async(function () { var message = { priority: null, deepHistory: false, }; this._entry(); if (this._exitViaExitPoint) { this.source.notify('parent', 'exit'); } else { this.notify('source', 'exit'); } if (!_.isNull(this.effect)) { this.effect.apply(this, params); } message.deepHistory = !!util.findDeepHistoryPseudoState(this.container); if (this._isExplicitEntry) { message.priority = this.target; this.target.notify('parent', 'entry', message); } else { this.notify('target', 'entry', message); } this._exit(); }); }, update: function (event) { var params = _.toArray(arguments).slice(1); switch (event) { case 'refresh': this._refresh.apply(this, params); break; } }, _getParentState: function () { var result = null; if (!_.isNull(this.container) && !_.isNull(this.container.parent)) { result = this.container.parent; } return result; }, _refresh: function (depth) { this._depth = depth; this.parent = this._getParentState(); this.notify('children', 'refresh', depth); }, }); module.exports = Transition;