state
Version:
First-class states
1,506 lines (1,400 loc) • 48.5 kB
JavaScript
// Generated by CoffeeScript 1.6.3
(function() {
var O, STATE_ATTRIBUTES, State, StateEventEmitter, StateExpression, TRAVERSAL_FLAGS, TransitionExpression, state,
__hasProp = {}.hasOwnProperty,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__slice = [].slice;
O = require('omicron');
state = require('./state-function');
StateEventEmitter = null;
StateExpression = null;
TransitionExpression = null;
STATE_ATTRIBUTES = state.STATE_ATTRIBUTES, TRAVERSAL_FLAGS = state.TRAVERSAL_FLAGS;
module.exports = State = (function() {
var ABSTRACT, ABSTRACT_OR_CONCRETE, ATOMIC, CONCLUSIVE, CONCRETE, CONCURRENT, DEFAULT, DESTROYED, FINAL, FINITE, HISTORY, IMMUTABLE, INCIPIENT, INCIPIENT_OR_MUTABLE, INCIPIENT_OR_VIRTUAL, INITIAL, MUTABLE, MUTABLE_OR_FINITE, NIL, NORMAL, PARASTATIC, PROTO_HERITABLE_ATTRIBUTES, REFLECTIVE, RETAINED, SHALLOW, STATIC, VIA_ALL, VIA_NONE, VIA_PROTO, VIA_SUB, VIA_SUPER, VIRTUAL, assign, clone, createDispatcher, delta, edit, env, flatten, has, hasOwn, isArray, isEmpty, lookup, memoizeProtostates, useDispatchTables, _ref, _ref1, _ref2;
_ref = state.options, memoizeProtostates = _ref.memoizeProtostates, useDispatchTables = _ref.useDispatchTables;
env = O.env, NIL = O.NIL, isArray = O.isArray, isEmpty = O.isEmpty, has = O.has, hasOwn = O.hasOwn;
assign = O.assign, edit = O.edit, delta = O.delta, clone = O.clone, lookup = O.lookup, flatten = O.flatten;
_ref1 = assign(State, STATE_ATTRIBUTES), INCIPIENT = _ref1.INCIPIENT, ATOMIC = _ref1.ATOMIC, DESTROYED = _ref1.DESTROYED, VIRTUAL = _ref1.VIRTUAL, PARASTATIC = _ref1.PARASTATIC, MUTABLE = _ref1.MUTABLE, FINITE = _ref1.FINITE, STATIC = _ref1.STATIC, IMMUTABLE = _ref1.IMMUTABLE, INITIAL = _ref1.INITIAL, CONCLUSIVE = _ref1.CONCLUSIVE, FINAL = _ref1.FINAL, ABSTRACT = _ref1.ABSTRACT, CONCRETE = _ref1.CONCRETE, DEFAULT = _ref1.DEFAULT, REFLECTIVE = _ref1.REFLECTIVE, HISTORY = _ref1.HISTORY, RETAINED = _ref1.RETAINED, SHALLOW = _ref1.SHALLOW, CONCURRENT = _ref1.CONCURRENT, NORMAL = _ref1.NORMAL;
_ref2 = assign(State, TRAVERSAL_FLAGS), VIA_NONE = _ref2.VIA_NONE, VIA_SUB = _ref2.VIA_SUB, VIA_SUPER = _ref2.VIA_SUPER, VIA_PROTO = _ref2.VIA_PROTO, VIA_ALL = _ref2.VIA_ALL;
MUTABLE_OR_FINITE = MUTABLE | FINITE;
ABSTRACT_OR_CONCRETE = ABSTRACT | CONCRETE;
INCIPIENT_OR_VIRTUAL = INCIPIENT | VIRTUAL;
INCIPIENT_OR_MUTABLE = INCIPIENT | MUTABLE;
PROTO_HERITABLE_ATTRIBUTES = PARASTATIC | MUTABLE | FINITE | STATIC | IMMUTABLE | INITIAL | CONCLUSIVE | FINAL | ABSTRACT | CONCRETE | DEFAULT | REFLECTIVE | HISTORY | RETAINED | SHALLOW | CONCURRENT | NORMAL;
State.prototype.Metaobject = null;
State.prototype.Expression = null;
function State(base, name, expression) {
var attributes, owner, protoAttr, protostate, root, superAttr, superstate;
this.name = name;
if (base instanceof State) {
superstate = base;
root = superstate.root;
owner = root.owner;
} else {
superstate = null;
root = this;
owner = base;
}
this.owner = owner;
this.root = root;
this.superstate = superstate;
this.protostate = protostate = this.getProtostate() || null;
this.order = null;
attributes = (expression != null ? expression.attributes : void 0) || NORMAL;
if (superstate != null) {
superAttr = superstate.attributes;
attributes |= superAttr & MUTABLE_OR_FINITE;
}
if (protostate != null) {
protoAttr = protostate.attributes & PROTO_HERITABLE_ATTRIBUTES;
if (attributes & CONCRETE) {
attributes &= ~ABSTRACT;
}
if (attributes & ABSTRACT_OR_CONCRETE) {
protoAttr &= ~ABSTRACT_OR_CONCRETE;
}
attributes |= protoAttr;
}
if (~attributes & ABSTRACT) {
attributes |= CONCRETE;
}
attributes |= (superAttr | protoAttr) & IMMUTABLE;
if (attributes & IMMUTABLE) {
attributes = attributes & ~MUTABLE | FINITE;
}
this.attributes = attributes;
if (!(attributes & VIRTUAL)) {
this.initialize(expression);
}
if (env.debug) {
this[' <path>'] = this.path();
this['<attributes>'] = StateExpression.decodeAttributes(attributes);
}
}
createDispatcher = (function() {
var toString;
toString = function() {
return "[dispatcher]";
};
return function(accessorName, methodName, original) {
var dispatcher;
dispatcher = function() {
return this[accessorName]().apply(methodName, arguments);
};
dispatcher.isDispatcher = true;
if (env.debug) {
dispatcher.toString = toString;
}
if (original) {
dispatcher.original = original;
}
return dispatcher;
};
})();
State.prototype.initialize = function(expression) {
var attributes;
attributes = this.attributes;
if (attributes & VIRTUAL) {
return;
}
this.attributes |= INCIPIENT;
this.realize(expression);
this.attributes &= ~INCIPIENT;
this.emit('construct', expression, VIA_PROTO);
return this;
};
State.prototype.realize = function(expression) {
var attributes, key, method, name, parastates, ss, substates, _base, _ref3;
attributes = this.attributes, name = this.name;
if (!(attributes & INCIPIENT_OR_VIRTUAL)) {
return this;
}
if (attributes & VIRTUAL) {
if (ss = this.superstate) {
if (ss.attributes & VIRTUAL) {
ss.realize();
}
substates = (_base = ss._).substates != null ? (_base = ss._).substates : _base.substates = {};
if (substates[name] != null) {
substates[name].destroy();
}
substates[name] = this;
}
this.attributes &= ~VIRTUAL;
}
if (this._ == null) {
this._ = new this.Metaobject;
}
if (parastates = expression != null ? expression.parastates : void 0) {
if (isArray(parastates)) {
parastates = parastates.join(',');
}
if (typeof parastates !== 'string') {
throw TypeError;
}
parastates = parastates.split(/\s*,\s*/);
if (parastates.length) {
this._.parastates = parastates;
this.attributes |= PARASTATIC;
}
}
if (expression != null) {
this.mutate(expression);
}
if (this === this.root) {
_ref3 = this.owner;
for (key in _ref3) {
if (!__hasProp.call(_ref3, key)) continue;
method = _ref3[key];
if (key !== 'constructor' && typeof method === 'function' && !method.isDispatcher && this.method(key, VIA_PROTO)) {
this.addMethod(key, method);
}
}
}
if (this === this.root || ~attributes & INCIPIENT) {
this.linearize(VIA_SUB);
}
return this;
};
State.prototype.virtualize = function(inheritor) {
var derivation, expr, i, name, real, s;
if (!(inheritor instanceof State && this.owner.isPrototypeOf(inheritor.owner))) {
return null;
}
if (!(derivation = this.derivation(true)).length) {
return null;
}
i = 0;
s = inheritor.root;
while (name = derivation[i++]) {
if (!(real = s.substate(name, VIA_NONE))) {
break;
}
s = real;
}
expr = {
attributes: VIRTUAL
};
while (name) {
s = new State(s, name, expr);
name = derivation[i++];
}
return s;
};
State.prototype.linearize = (function() {
var getParastateDeclarations, linearize, merge;
getParastateDeclarations = function() {
var head, ps, tail, _ref3, _ref4;
head = (_ref3 = this._) != null ? _ref3.parastates : void 0;
if (ps = this.protostate) {
tail = getParastateDeclarations.call(ps);
}
if (tail != null) {
return (_ref4 = head != null ? head.concat(tail) : void 0) != null ? _ref4 : tail;
} else {
return head;
}
};
merge = function(out, lists) {
var bad, head, headList, i, index, item, list, otherList, remainingLists, _i, _j, _k, _len, _len1, _len2;
if (!lists.length) {
return out;
}
for (index = _i = 0, _len = lists.length; _i < _len; index = ++_i) {
headList = lists[index];
if (!(headList != null)) {
continue;
}
head = headList[0];
bad = false;
for (_j = 0, _len1 = lists.length; _j < _len1; _j++) {
otherList = lists[_j];
if (!(otherList !== headList)) {
continue;
}
i = 1;
while (item = otherList[i++]) {
if (item === head) {
bad = true;
break;
}
}
if (bad) {
break;
}
}
if (bad) {
continue;
}
out.push(head);
remainingLists = [];
for (_k = 0, _len2 = lists.length; _k < _len2; _k++) {
list = lists[_k];
if (list[0] === head) {
list.shift();
}
if (list.length) {
remainingLists.push(list);
}
}
return merge(out, remainingLists);
}
throw new TypeError("Ambiguous resolution order for '" + (out.pop()) + "'");
};
return linearize = function(via) {
var lists, name, order, owner, parastate, parent, parents, path, paths, s, _i, _j, _len, _len1, _ref3, _ref4;
if (via == null) {
via = VIA_NONE;
}
if (this === this.root) {
order = [this];
} else {
parents = [];
if (paths = getParastateDeclarations.call(this)) {
owner = this.owner;
for (_i = 0, _len = paths.length; _i < _len; _i++) {
path = paths[_i];
if (!(parastate = state.own(owner, path))) {
throw new ReferenceError("Unresolvable parastate '" + path + "'");
}
if (__indexOf.call(parents, parastate) < 0) {
parents.push(parastate);
}
}
}
parents.push(this.superstate);
lists = [];
for (_j = 0, _len1 = parents.length; _j < _len1; _j++) {
parent = parents[_j];
lists.push(((_ref3 = parent.order) != null ? _ref3 : parent.linearize()).slice(0));
}
lists.push(parents);
order = merge([this], lists);
}
this.order = order;
if (via & VIA_SUB) {
_ref4 = this._.substates;
for (name in _ref4) {
if (!__hasProp.call(_ref4, name)) continue;
s = _ref4[name];
s.linearize(via);
}
}
return order;
};
})();
State.prototype.express = (function() {
var cloneCategory, cloneEvents, cloneSubstates, express;
cloneCategory = function(object) {
var key, out, value;
if (object == null) {
return;
}
for (key in object) {
out = {};
break;
}
if (out) {
for (key in object) {
value = object[key];
out[key] = value && typeof value === 'object' ? clone(value) : value;
}
}
return out;
};
cloneEvents = function(events) {
var emitter, out, type;
if (events == null) {
return;
}
for (type in events) {
emitter = events[type];
if (emitter) {
out = {};
break;
}
}
for (type in events) {
emitter = events[type];
if (emitter) {
out[type] = clone(emitter.items);
}
}
return out;
};
cloneSubstates = function(substates, typed) {
var name, out, substate;
if (substates == null) {
return;
}
for (name in substates) {
out = {};
break;
}
for (name in substates) {
substate = substates[name];
out[name] = substate.express(typed);
}
return out;
};
return express = function(typed) {
var expression, _;
if (_ = this._) {
expression = edit({}, {
attributes: this.attributes,
data: cloneCategory(_.data),
methods: cloneCategory(_.methods),
events: cloneEvents(_.events),
guards: cloneCategory(_.guards),
states: cloneSubstates(_.substates, typed),
transitions: cloneCategory(_.transitions)
});
}
if (typed) {
return new this.Expression(expression);
} else {
return expression;
}
};
})();
State.prototype.mutate = (function() {
var diff, editEvent, isPlainObject, mutate;
NIL = O.NIL, isArray = O.isArray, isEmpty = O.isEmpty, isPlainObject = O.isPlainObject, edit = O.edit, diff = O.diff;
editEvent = function(object, emitter) {
var items, key, value, _results;
items = emitter.items;
_results = [];
for (key in object) {
if (!__hasProp.call(object, key)) continue;
value = object[key];
if (value === NIL) {
_results.push(emitter.remove(key));
} else if (value && value !== items[key]) {
_results.push(emitter.set(key, value));
} else {
_results.push(void 0);
}
}
return _results;
};
return mutate = function(expr) {
var Expression, after, attributes, before, data, element, emitter, event, events, guards, incipient, method, methods, mutable, name, residue, stateExpr, substates, transitionExpr, transitions, type, _base, _base1, _i, _len, _ref3, _ref4, _ref5, _ref6, _ref7;
attributes = this.attributes, Expression = this.Expression;
incipient = attributes & INCIPIENT;
if (!incipient && attributes & IMMUTABLE) {
return;
}
mutable = incipient || attributes & MUTABLE;
if (attributes & VIRTUAL) {
this.realize();
}
_ref3 = this._, data = _ref3.data, methods = _ref3.methods, events = _ref3.events, guards = _ref3.guards, substates = _ref3.substates, transitions = _ref3.transitions;
if (!(expr instanceof Expression)) {
expr = new Expression(expr);
}
if (!incipient) {
before = this.express();
}
this.attributes |= ATOMIC;
if (expr.data) {
this.data(expr.data);
}
if (mutable) {
_ref4 = expr.methods;
for (name in _ref4) {
if (!__hasProp.call(_ref4, name)) continue;
method = _ref4[name];
if (method !== NIL) {
this.addMethod(name, method);
} else {
this.removeMethod(name);
}
}
}
if (mutable) {
_ref5 = expr.events;
for (type in _ref5) {
if (!__hasProp.call(_ref5, type)) continue;
event = _ref5[type];
events || (events = (_base = this._).events || (_base.events = {}));
emitter = events[type];
if (event === NIL) {
if (emitter != null) {
emitter.empty();
}
continue;
}
if (!emitter && event && !isEmpty(event)) {
emitter = events[type] = new StateEventEmitter(this, type);
}
if (isArray(event)) {
for (_i = 0, _len = event.length; _i < _len; _i++) {
element = event[_i];
if ((element != null) && element !== NIL) {
if (isPlainObject(element)) {
editEvent(element, emitter);
} else {
this.addEvent(type, element);
}
}
}
} else {
if (isPlainObject(event)) {
editEvent(event, emitter);
}
}
if (!emitter.length) {
emitter.destroy();
delete events[type];
}
}
}
if (mutable && expr.guards) {
guards || (guards = (_base1 = this._).guards || (_base1.guards = {}));
edit('deep', guards, expr.guards);
}
_ref6 = expr.substates;
for (name in _ref6) {
if (!__hasProp.call(_ref6, name)) continue;
stateExpr = _ref6[name];
if (substates && name in substates) {
if (stateExpr === NIL) {
this.removeSubstate(name);
} else {
substates[name].mutate(stateExpr);
}
} else {
if (stateExpr !== NIL) {
this.addSubstate(name, stateExpr);
}
}
}
if (mutable) {
_ref7 = expr.transitions;
for (name in _ref7) {
if (!__hasProp.call(_ref7, name)) continue;
transitionExpr = _ref7[name];
if (transitions && name in transitions) {
if (transitionExpr === NIL) {
delete transitions[name];
} else {
transitions[name] = new TransitionExpression(transitionExpr);
}
} else {
if (transitionExpr !== NIL) {
this.addTransition(name, transitionExpr);
}
}
}
}
this.attributes &= ~ATOMIC;
if (!incipient) {
after = this.express();
residue = diff(before, after);
if (!isEmpty(residue)) {
this.emit('mutate', [expr, residue, before, after], VIA_PROTO);
}
}
return this;
};
})();
State.prototype.destroy = function() {
var dispatcher, event, events, key, methods, name, owner, ownerMethod, root, substate, substates, superstate, transition, _;
owner = this.owner, root = this.root, superstate = this.superstate, _ = this._;
if (_) {
methods = _.methods, events = _.events, substates = _.substates;
}
if (transition = root._transition) {
if (this === root) {
transition.abort();
} else {
if ((transition.origin.isIn(this)) || (transition.target.isIn(this))) {
return false;
}
}
}
for (name in substates) {
if (!__hasProp.call(substates, name)) continue;
substate = substates[name];
substate.destroy();
}
this.emit('destroy', VIA_PROTO);
if (events) {
for (key in events) {
event = events[key];
event.destroy();
delete events[key];
}
}
if (this === root) {
for (name in methods) {
if (!(dispatcher = owner[name])) {
continue;
}
if (!dispatcher.isDispatcher) {
continue;
}
if (ownerMethod = dispatcher.original) {
owner[name] = ownerMethod;
} else {
delete owner[name];
}
}
delete owner[this.accessorName];
}
this._ = null;
this.attributes |= DESTROYED;
if (superstate != null) {
superstate.removeSubstate(this.name);
}
return true;
};
State.prototype.isVirtual = function() {
return !!(this.attributes & VIRTUAL);
};
State.prototype.isMutable = function() {
return !!(this.attributes & MUTABLE);
};
State.prototype.isFinite = function() {
return !!(this.attributes & FINITE);
};
State.prototype.isStatic = function() {
return !!(this.attributes & STATIC);
};
State.prototype.isImmutable = function() {
return !!(this.attributes & IMMUTABLE);
};
State.prototype.isInitial = function() {
return !!(this.attributes & INITIAL);
};
State.prototype.isConclusive = function() {
return !!(this.attributes & CONCLUSIVE);
};
State.prototype.isFinal = function() {
return !!(this.attributes & FINAL);
};
State.prototype.isAbstract = function() {
return !!(this.attributes & ABSTRACT);
};
State.prototype.isConcrete = function() {
return !!(this.attributes & CONCRETE);
};
State.prototype.isDefault = function() {
return !!(this.attributes & DEFAULT);
};
State.prototype.isReflective = function() {
return !!(this.attributes & REFLECTIVE);
};
State.prototype.hasHistory = function() {
return !!(this.attributes & HISTORY);
};
State.prototype.isRetained = function() {
return !!(this.attributes & RETAINED);
};
State.prototype.isShallow = function() {
return !!(this.attributes & SHALLOW);
};
State.prototype.isConcurrent = function() {
return !!(this.attributes & CONCURRENT);
};
State.prototype.substate = function(name, via) {
var s, ss, _ref3, _ref4, _ref5;
if (via == null) {
via = VIA_PROTO;
}
s = this.root._current;
while ((s != null ? s.attributes : void 0) & VIRTUAL && (ss = s.superstate)) {
if (ss === this && s.name === name) {
return s;
}
s = ss;
}
return ((_ref3 = this._) != null ? (_ref4 = _ref3.substates) != null ? _ref4[name] : void 0 : void 0) || via & VIA_PROTO && ((_ref5 = this.protostate) != null ? _ref5.substate(name) : void 0);
};
State.prototype.substates = function(virtual, deep) {
var name, result, s, ss, substate, _ref3, _ref4;
result = [];
if (virtual && (s = this.root._current) && s.attributes & VIRTUAL && this.isSuperstateOf(s)) {
while (s && s !== this && s.attributes & VIRTUAL && (ss = s.superstate)) {
if (deep || ss === this) {
result.unshift(s);
}
s = ss;
}
}
_ref4 = (_ref3 = this._) != null ? _ref3.substates : void 0;
for (name in _ref4) {
if (!__hasProp.call(_ref4, name)) continue;
substate = _ref4[name];
result.push(substate);
if (deep) {
result = result.concat(substate.substates(void 0, true));
}
}
return result;
};
State.prototype.descendants = function(virtual) {
return this.substates(virtual, true);
};
State.prototype.addSubstate = function(name, expression) {
var attributes, substate, substates, _base;
attributes = this.attributes;
if (!(attributes & INCIPIENT)) {
if (attributes & FINITE) {
return;
}
if (!(attributes & MUTABLE)) {
return;
}
}
if (attributes & VIRTUAL) {
this.realize();
}
substates = (_base = this._).substates || (_base.substates = {});
if (substate = substates[name]) {
substate.destroy();
}
substate = expression instanceof State ? expression.superstate === this ? expression.realize() : void 0 : new State(this, name, expression);
if (!substate) {
return null;
}
return substates[name] = substate;
};
State.prototype.removeSubstate = function(name) {
var attributes, substate, substates, transition, _ref3;
attributes = this.attributes;
if (attributes & VIRTUAL) {
return;
}
substates = (_ref3 = this._) != null ? _ref3.substates : void 0;
if (!(substate = substates != null ? substates[name] : void 0)) {
return;
}
if (!(attributes & MUTABLE || (substate != null ? substate.attributes : void 0) & DESTROYED)) {
return;
}
if ((transition = this.root._transition) && (substate.isSuperstateOf(transition) || substate === transition.origin || substate === transition.target)) {
return false;
}
if (this.root._current.isIn(substate)) {
this.change(this, {
forced: true
});
}
delete substates[name];
return substate;
};
State.prototype.derivation = function(byName) {
var results, s, ss;
results = [];
ss = this;
while ((s = ss) && (ss = s.superstate)) {
results.push(byName ? s.name || '' : s);
}
return results.reverse();
};
State.prototype.path = function() {
return this.derivation(true).join('.');
};
State.prototype.toString = State.prototype.path;
State.prototype.depth = function() {
var n, s;
n = 0;
s = this;
while (s = s.superstate) {
n += 1;
}
return n;
};
State.prototype.common = function(other) {
var s;
if (!(other instanceof State)) {
other = this.query(other);
}
if (this.depth() > other.depth()) {
s = other;
other = this;
} else {
s = this;
}
while (s) {
if (s === other || s.isSuperstateOf(other)) {
return s;
}
s = s.superstate;
}
return null;
};
State.prototype.is = function(other) {
if (!(other instanceof State)) {
other = this.query(other);
}
return other === this;
};
State.prototype.isIn = function(other) {
if (!(other instanceof State)) {
other = this.query(other);
}
return other === this || other.isSuperstateOf(this);
};
State.prototype.hasSubstate = function(other) {
if (!(other instanceof State)) {
other = this.query(other);
}
return other === this || this.isSuperstateOf(other);
};
State.prototype.isSuperstateOf = function(other) {
var superstate;
if (!(other instanceof State)) {
other = this.query(other);
}
if (superstate = other.superstate) {
return this === superstate || this.isSuperstateOf(superstate);
} else {
return false;
}
};
State.prototype.defaultSubstate = function(via, first) {
var protostate, s, substates, _i, _len, _ref3;
if (via == null) {
via = VIA_PROTO;
}
_ref3 = substates = this.substates();
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
s = _ref3[_i];
if (s.attributes & DEFAULT) {
return s;
}
}
first || substates.length && (first = substates[0]);
if (via & VIA_PROTO && (protostate = this.protostate)) {
return protostate.defaultSubstate(VIA_PROTO);
}
return first;
};
State.prototype.initialSubstate = function(via) {
var i, protostate, queue, s, subject, substates, _i, _len, _ref3;
if (via == null) {
via = VIA_PROTO;
}
i = 0;
queue = [this];
while (subject = queue[i++]) {
_ref3 = substates = subject.substates(void 0, !!VIA_PROTO);
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
s = _ref3[_i];
if (s.attributes & INITIAL) {
return s.initialSubstate(VIA_NONE) || s;
}
queue.push(s);
}
}
if (via & VIA_PROTO && (protostate = this.protostate)) {
return protostate.initialSubstate(VIA_PROTO);
}
};
State.prototype.getProtostate = function() {
var accessorName, getPrototypeOf, owner, path, protostate, prototype, root;
getPrototypeOf = O.getPrototypeOf;
owner = this.owner, root = this.root;
accessorName = root.accessorName;
path = this.path();
prototype = getPrototypeOf(owner);
while (prototype) {
if (protostate = typeof prototype[accessorName] === "function" ? prototype[accessorName](path, VIA_NONE) : void 0) {
return protostate;
}
prototype = getPrototypeOf(prototype);
}
return null;
};
State.prototype.isProtostateOf = function(other) {
var protostate;
if (!(other instanceof State)) {
other = this.query(other);
}
if (protostate = other.protostate) {
return this === protostate || this.isProtostateOf(protostate);
} else {
return false;
}
};
State.prototype.query = function(selector, against, via, toBeSkipped) {
var cursor, i, l, name, next, parts, queue, result, subject, substate, _i, _len, _ref3, _ref4, _ref5;
if (typeof against === 'number') {
toBeSkipped = via;
via = against;
against = void 0;
}
if (via == null) {
via = VIA_ALL;
}
if (selector == null) {
if (against === void 0) {
return null;
} else {
return false;
}
}
if (selector === '.') {
if (against === void 0) {
return this;
} else {
return against === this;
}
}
if (selector === '') {
if (against === void 0) {
return this.root;
} else {
return against === this.root;
}
}
if (against && against === this.root && /^\*+$/.test(selector)) {
return true;
}
if (/^\.*\**$/.test(selector)) {
via &= ~(VIA_SUB | VIA_SUPER);
}
if (selector.charAt(0) !== '.') {
return this.root.query('.' + selector, against, VIA_SUB | VIA_PROTO);
}
selector = selector.replace(/^(\.+)\.$/, '$1');
parts = selector.split('.');
i = 0;
l = parts.length;
cursor = this;
while (cursor) {
i += 1;
if (i >= l) {
return (against ? against === cursor : cursor);
}
name = parts[i];
if (name === '*') {
if (!against) {
return cursor.substates();
}
if (cursor === against.superstate) {
return true;
}
break;
}
if (name === '**') {
if (!against) {
return cursor.substates(void 0, true);
}
if (cursor.isSuperstateOf(against)) {
return true;
}
break;
}
if (name === '') {
cursor = cursor.superstate;
} else if (next = cursor.substate(name)) {
cursor = next;
} else {
break;
}
}
if (via & VIA_SUB) {
i = 0;
queue = [this];
while (subject = queue[i++]) {
_ref3 = subject.substates(true);
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
substate = _ref3[_i];
if (substate === toBeSkipped) {
continue;
}
result = substate.query(selector, against, VIA_NONE);
if (result) {
return result;
}
queue.push(substate);
}
}
}
if (via & VIA_SUPER) {
if (result = (_ref4 = this.superstate) != null ? _ref4.query(selector, against, via & VIA_SUB | VIA_SUPER, via & VIA_SUB ? this : void 0) : void 0) {
return result;
}
}
if (via & VIA_PROTO) {
if (result = (_ref5 = this.protostate) != null ? _ref5.query(selector, against, via) : void 0) {
return result;
}
}
if (against) {
return false;
} else {
return null;
}
};
State.prototype.$ = function() {
var args, expr, match, method;
expr = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
if (typeof expr === 'function') {
if (expr = expr()) {
return this.change.apply(this, [expr].concat(args));
}
} else if (typeof expr === 'string' && (match = expr.match(rxTransitionArrow)) && (method = transitionArrowMethods[match[1]])) {
if (args.length) {
return this[method].apply(this, [match[2]].concat(args));
} else {
return this[method](match[2]);
}
}
};
State.prototype.current = function() {
return this.root._current;
};
State.prototype.isCurrent = function() {
return this === this.current();
};
State.prototype.isActive = function() {
var current;
return this === (current = this.current()) || this.isSuperstateOf(current);
};
State.prototype.change = function(target, options) {
var root;
return (root = this.root).change.apply(root, arguments);
};
State.prototype.go = State.prototype.change;
State.prototype.be = State.prototype.change;
State.prototype.data = function(via, out) {
var attributes, mutation, relative, residue, _base, _i, _ref3, _ref4, _ref5, _ref6;
if (via == null) {
via = VIA_ALL;
}
if (via !== via << 0) {
mutation = via;
}
if (mutation) {
attributes = this.attributes;
if (attributes & INCIPIENT_OR_MUTABLE && !isEmpty(mutation)) {
if (attributes & VIRTUAL) {
return this.realize().data(mutation);
}
residue = delta((_base = this._).data != null ? (_base = this._).data : _base.data = {}, mutation);
if (~attributes & ATOMIC && residue && !isEmpty(residue)) {
this.emit('mutate', [mutation, residue], VIA_PROTO);
}
}
return this;
} else {
if (out == null) {
out = {};
}
_ref4 = (_ref3 = this.order) != null ? _ref3 : this.linearize();
for (_i = _ref4.length - 1; _i >= 0; _i += -1) {
relative = _ref4[_i];
if (!(via & VIA_SUPER || relative === this)) {
continue;
}
edit('deep all', out, (via & VIA_PROTO ? (_ref5 = relative.protostate) != null ? _ref5.data(VIA_PROTO, out) : void 0 : void 0), (_ref6 = relative._) != null ? _ref6.data : void 0);
}
return out;
}
};
State.prototype.has = function(key, via) {
var data, relative, s, viaProto, viaSuper, _i, _len, _ref3, _ref4, _ref5;
if (via == null) {
via = VIA_ALL;
}
viaSuper = via & VIA_SUPER;
viaProto = via & VIA_PROTO;
_ref4 = (_ref3 = this.order) != null ? _ref3 : this.linearize();
for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
relative = _ref4[_i];
s = relative;
while (s != null) {
if (((data = (_ref5 = s._) != null ? _ref5.data : void 0) != null) && hasOwn.call(data, key)) {
return true;
}
if (viaProto) {
s = s.protostate;
} else {
break;
}
if (viaSuper) {
continue;
}
}
}
return false;
};
State.prototype.get = function(key, via) {
var data, relative, s, viaProto, viaSuper, _i, _len, _ref3, _ref4, _ref5;
if (via == null) {
via = VIA_ALL;
}
viaSuper = via & VIA_SUPER;
viaProto = via & VIA_PROTO;
_ref4 = (_ref3 = this.order) != null ? _ref3 : this.linearize();
for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
relative = _ref4[_i];
s = relative;
while (s != null) {
if (((data = (_ref5 = s._) != null ? _ref5.data : void 0) != null) && hasOwn.call(data, key)) {
return data[key];
}
if (viaProto) {
s = s.protostate;
} else {
break;
}
}
if (viaSuper) {
continue;
}
}
};
State.prototype["let"] = function(key, value) {
var attributes, data, displaced, mutation, residue, _base;
attributes = this.attributes;
if (!(attributes & INCIPIENT_OR_MUTABLE)) {
return;
}
if (attributes & VIRTUAL) {
this.realize();
}
data = (_base = this._).data || (_base.data = {});
if (value !== (displaced = lookup(data, key))) {
assign(data, key, value);
assign((mutation = {}).data = {}, key, value);
assign((residue = {}).data = {}, key, displaced);
this.emit('mutate', [mutation, residue], VIA_PROTO);
}
return value;
};
State.prototype.set = function(key, value) {
var attributes, data, relative, _i, _len, _ref3, _ref4, _ref5;
attributes = this.attributes;
if (!(attributes & INCIPIENT_OR_MUTABLE)) {
return;
}
if (attributes & VIRTUAL) {
this.realize();
}
_ref4 = (_ref3 = this.order) != null ? _ref3 : this.linearize();
for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
relative = _ref4[_i];
if (((data = (_ref5 = relative._) != null ? _ref5.data : void 0) != null) && hasOwn.call(data, key)) {
if (relative.attributes & MUTABLE) {
return relative["let"](key, value);
}
break;
}
}
return this["let"](key, value);
};
State.prototype["delete"] = function(key) {
if (!(this.attributes & MUTABLE)) {
return;
}
return NIL === this["let"](key, NIL);
};
State.prototype.method = function(methodName, via, out, returnBoxed) {
var attributes, context, inherited, method, realized, record, relative, table, viaProto, _base, _i, _len, _ref10, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9;
if (via == null) {
via = VIA_ALL;
}
attributes = this.attributes;
realized = ~attributes & VIRTUAL;
while (true) {
if (realized) {
if (method = (_ref3 = this._) != null ? (_ref4 = _ref3.methods) != null ? _ref4[methodName] : void 0 : void 0) {
context = this;
break;
}
if (record = (_ref5 = this._) != null ? (_ref6 = _ref5.__dispatch_table__) != null ? _ref6[methodName] : void 0 : void 0) {
method = record[0], context = record[1];
if (method != null) {
break;
}
}
}
if (viaProto = via & VIA_PROTO) {
if (method = (_ref7 = this.protostate) != null ? _ref7.method(methodName, VIA_PROTO, out, true) : void 0) {
context = this;
inherited = true;
break;
}
}
if (via & VIA_SUPER) {
_ref9 = (_ref8 = this.order) != null ? _ref8 : this.linearize();
for (_i = 0, _len = _ref9.length; _i < _len; _i++) {
relative = _ref9[_i];
if (relative !== this) {
if (method = relative.method(methodName, viaProto, out, true)) {
context = (_ref10 = out != null ? out.context : void 0) != null ? _ref10 : null;
inherited = true;
break;
}
}
}
if (method != null) {
break;
}
}
context = null;
break;
}
if (method != null) {
if (typeof method === 'function') {
context = null;
}
if (realized && inherited && useDispatchTables) {
table = (_base = this._).__dispatch_table__ != null ? (_base = this._).__dispatch_table__ : _base.__dispatch_table__ = {};
table[methodName] = [method, context];
}
if (!returnBoxed) {
if (method.type === 'state-bound-function') {
method = method.fn;
}
}
}
if (out != null) {
out.method = method;
out.context = context;
}
return method;
};
State.prototype.methodNames = function() {
var methods, _ref3;
if (methods = (_ref3 = this._) != null ? _ref3.methods : void 0) {
return keys(methods);
}
};
State.prototype.addMethod = function(methodName, fn) {
var methods, owner, ownerMethod, root, _ref3, _ref4, _ref5;
if (!(this.attributes & INCIPIENT_OR_MUTABLE)) {
return;
}
if (typeof fn === 'object' && fn.type === 'state-fixed-function') {
fn = fn.fn(this, this.protostate);
}
if (!(typeof fn === 'function' || (fn != null ? fn.type : void 0) === 'state-bound-function')) {
throw new TypeError("Must supply a plain, bound, or fixed function");
}
owner = this.owner;
if (!((_ref3 = (ownerMethod = owner[methodName])) != null ? _ref3.isDispatcher : void 0)) {
root = this.root;
owner[methodName] = createDispatcher(root.accessorName, methodName, ownerMethod);
if ((ownerMethod != null) && this !== root) {
methods = (_ref4 = root._) != null ? _ref4.methods || (_ref4.methods = {}) : void 0;
methods[methodName] = ownerMethod;
}
}
methods = (_ref5 = this._) != null ? _ref5.methods || (_ref5.methods = {}) : void 0;
return methods[methodName] = fn;
};
State.prototype.removeMethod = function(methodName) {
var fn, methods, _ref3;
if (!(this.attributes & MUTABLE && (methods = (_ref3 = this._) != null ? _ref3.methods : void 0) && (fn = methods[methodName]))) {
return;
}
delete methods[methodName];
return fn;
};
State.prototype.hasMethod = function(methodName) {
var method;
return method = this.method(methodName);
};
State.prototype.hasOwnMethod = function(methodName) {
return !!this.method(methodName, VIA_NONE);
};
State.prototype.apply = function(methodName, args) {
var context, method, out, record, _ref3, _ref4;
if (record = (_ref3 = this._) != null ? (_ref4 = _ref3.__dispatch_table__) != null ? _ref4[methodName] : void 0 : void 0) {
method = record[0], context = record[1];
if ((method != null ? method.type : void 0) === 'state-bound-function') {
method = method.fn;
}
}
if (method == null) {
if (method = this.method(methodName, VIA_ALL, out = {})) {
context = out.context;
} else {
this.emit('noSuchMethod', [methodName, args]);
this.emit('noSuchMethod:' + methodName, args);
return;
}
}
return method.apply(context || this.owner, args);
};
State.prototype.call = function() {
var args, methodName;
methodName = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
return this.apply(methodName, args);
};
State.prototype.event = function(eventType, id) {
var emitter, _ref3, _ref4;
if (!(emitter = (_ref3 = this._) != null ? (_ref4 = _ref3.events) != null ? _ref4[eventType] : void 0 : void 0)) {
return;
}
if (id === void 0) {
return emitter.length;
}
if (typeof id === 'function') {
id = emitter.key(id);
}
return emitter.get(id);
};
State.prototype.addEvent = function(eventType, fn, context) {
var events, _base;
if (this.attributes & VIRTUAL) {
this.realize();
}
events = (_base = this._).events || (_base.events = {});
if (!hasOwn.call(events, eventType)) {
events[eventType] = new StateEventEmitter(this);
}
if (fn.type === 'state-fixed-function') {
fn = fn.fn(this, this.protostate);
}
return events[eventType].add(fn, context);
};
State.prototype.on = State.prototype.addEvent;
State.prototype.removeEvent = function(eventType, id) {
var _ref3, _ref4;
return (_ref3 = this._) != null ? (_ref4 = _ref3.events) != null ? _ref4[eventType].remove(id) : void 0 : void 0;
};
State.prototype.off = State.prototype.removeEvent;
State.prototype.emit = function(eventType, args, context, via) {
var relative, _i, _len, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8;
if (via == null) {
via = VIA_ALL;
}
if (typeof eventType !== 'string') {
return;
}
if (typeof args === 'number') {
via = context;
context = args;
args = void 0;
}
if (typeof context === 'number') {
via = context;
context = void 0;
}
if ((args != null) && !isArray(args)) {
args = [args];
}
if ((_ref3 = this._) != null) {
if ((_ref4 = _ref3.events) != null) {
if ((_ref5 = _ref4[eventType]) != null) {
_ref5.emit(args, context != null ? context : this);
}
}
}
if (via & VIA_PROTO) {
if ((_ref6 = this.protostate) != null) {
_ref6.emit(eventType, args, context != null ? context : this, VIA_PROTO);
}
}
if (via & VIA_SUPER) {
_ref8 = (_ref7 = this.order) != null ? _ref7 : this.linearize();
for (_i = 0, _len = _ref8.length; _i < _len; _i++) {
relative = _ref8[_i];
if (relative !== this) {
relative.emit(eventType, args, context != null ? context : relative);
}
}
}
};
State.prototype.trigger = State.prototype.emit;
State.prototype.guard = function(guardType) {
var guard, _ref3, _ref4, _ref5;
if (guard = (_ref3 = this._) != null ? (_ref4 = _ref3.guards) != null ? _ref4[guardType] : void 0 : void 0) {
return clone(guard);
} else {
return ((_ref5 = this.protostate) != null ? _ref5.guard(guardType) : void 0) || void 0;
}
};
State.prototype.addGuard = function(guardType, guard) {
var attributes, guards, _base;
attributes = this.attributes;
if (!(attributes & INCIPIENT_OR_MUTABLE)) {
return;
}
if (attributes & VIRTUAL) {
this.realize();
}
guards = (_base = this._).guards || (_base.guards = {});
return edit(guards[guardType] || (guards[guardType] = {}), guard);
};
State.prototype.removeGuard = function() {
var args, attributes, entry, guard, guardType, guards, key, _i, _len, _ref3;
guardType = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
attributes = this.attributes;
if (attributes & VIRTUAL) {
return;
}
if (!(attributes & MUTABLE && (guards = this._.guards))) {
return;
}
if (!(guard = guards[guardType])) {
return null;
}
if (!args.length) {
return (delete guards[guardType] ? guard : void 0);
}
_ref3 = flatten(args);
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
key = _ref3[_i];
if (!(typeof key === 'string')) {
continue;
}
entry = guard[key];
if (delete guard[key]) {
return entry;
}
}
};
State.prototype.transition = function(name) {
var _ref3, _ref4;
return (_ref3 = this._) != null ? (_ref4 = _ref3.transitions) != null ? _ref4[name] : void 0 : void 0;
};
State.prototype.transitions = function() {
var _ref3;
return clone((_ref3 = this._) != null ? _ref3.transitions : void 0);
};
State.prototype.addTransition = function(name, expression) {
var attributes, transitions, _base;
attributes = this.attributes;
if (!(attributes & INCIPIENT_OR_MUTABLE)) {
return;
}
if (attributes & VIRTUAL) {
this.realize();
}
if (!(expression instanceof TransitionExpression)) {
expression = new TransitionExpression(expression);
}
transitions = (_base = this._).transitions || (_base.transitions = {});
return transitions[name] = expression;
};
State.prototype.removeTransition = function(name) {
var attributes, transition, transitions;
attributes = this.attributes;
if (attributes & VIRTUAL) {
return;
}
if (!(attributes & MUTABLE && (transitions = this._.transitions))) {
return;
}
transition = transitions[name];
if (transition) {
delete transitions[name];
}
return transition;
};
return State;
})();
State.prototype.Metaobject = require('./state-metaobject');
State.prototype.Expression = StateExpression = require('./state-expression');
StateEventEmitter = require('./state-event-emitter');
TransitionExpression = require('./transition-expression');
}).call(this);