rescope
Version:
Flexible state management system based on flux architecture, stores data components & inheritable scopes
1,282 lines (1,095 loc) • 143 kB
JavaScript
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global) {"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _index = __webpack_require__(1);
var _index2 = _interopRequireDefault(_index);
var _Scope = __webpack_require__(2);
var _Scope2 = _interopRequireDefault(_Scope);
var _Store = __webpack_require__(15);
var _Store2 = _interopRequireDefault(_Store);
var _scopable = __webpack_require__(18);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// will use as external the index in dist
var $global = typeof window !== 'undefined' ? window : global; /*
* Copyright (c) 2018 Wise Wild Web .
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author : Nathanael Braun
* @contact : caipilabs@gmail.com
*/
if ($global.___rescope) {
console.warn("ReScope is defined multiple times !! \nCheck you're packaging");
} else {
$global.___rescope = _index2.default;
_Scope2.default.Store = _Store2.default;
_index2.default.Scope = _Scope2.default;
_index2.default.Context = _Scope2.default;
_index2.default.Store = _Store2.default;
_index2.default.reScope = _scopable.reScope;
_index2.default.scopeToState = _scopable.scopeToState;
_index2.default.reScopeState = _scopable.scopeToState;
_index2.default.addScopableType = _scopable.addScopableType;
_index2.default.scopeRef = function scopeRef(map, key) {
map[key] = new _Scope2.default.scopeRef(map[key]);
return map;
};
}
exports.default = $global.___rescope || _index2.default;
module.exports = exports["default"];
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ }),
/* 1 */
/***/ (function(module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
/*
* Copyright (c) 2018 Wise Wild Web .
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author : Nathanael Braun
* @contact : caipilabs@gmail.com
*/
// Common rescope modules int
exports.default = {};
module.exports = exports["default"];
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/*
* Copyright (c) 2018 Wise Wild Web .
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author : Nathanael Braun
* @contact : caipilabs@gmail.com
*/
var is = __webpack_require__(3),
EventEmitter = __webpack_require__(4),
shortid = __webpack_require__(5),
__proto__push = function __proto__push(target, id, parent) {
var fn = function fn() {};
fn.prototype = parent ? new parent._[id]() : target[id] || {};
target[id] = new fn();
target._[id] = fn;
},
openScopes = {},
SimpleObjectProto = {}.constructor;
/**
* Base Scope object
*/
var Scope = function (_EventEmitter) {
_inherits(Scope, _EventEmitter);
_createClass(Scope, null, [{
key: 'getScope',
// all active scopes
value: function getScope(scopes) {
var skey = is.array(scopes) ? scopes.sort(function (a, b) {
if (a.firstname < b.firstname) return -1;
if (a.firstname > b.firstname) return 1;
return 0;
}).join('::') : scopes;
return openScopes[skey] = openScopes[skey] || new Scope({}, { id: skey });
} // if > 0, will wait 'persistenceTm' ms before destroy when dispose reach 0
}, {
key: 'stateMapToRefList',
/**
* get a parsed reference list from stateMap
* @param _ref
* @returns {{storeId, path, alias: *, ref: *}}
*/
value: function stateMapToRefList(sm) {
var state = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var _refs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
var actions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var path = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : "";
Object.keys(sm).forEach(function (key) {
var cpath = path ? path + '.' + key : key;
sm[key] instanceof Scope.scopeRef ? _refs.push(sm[key].path + ':' + cpath) : sm[key] && sm[key] instanceof Function ? actions[key] = sm[key] : sm[key] && sm[key].prototype instanceof Scope.Store ? _refs.push(sm[key].as(cpath)) : state[cpath] = sm[key];
//: this.stateMapToRefList(sm[key], _refs, path + '.' + key)
});
return _refs;
}
/**
* Init a ReScope scope
*
* @param storesMap {Object} Object with the initial stores definition / instances
* @param config {Object} Scope config
* {
* parent {scope} @optional parent scope
*
* id {string} @optional id ( if this id exist storesMap will be merge on the 'id' scope)
* key {string} @optional key of the scope ( if no id is set, the scope id will be (parent.id+'::'+key)
* incrementId {bool} @optional true to add a suffix id, if the provided key or id globally exist
*
* state {Object} @optional initial state by store alias
* data {Object} @optional initial data by store alias
*
* rootEmitter {bool} @optional true to not being destabilized by parent
* boundedActions {array | regexp} @optional list or regexp of actions not propagated to the parent
*
* persistenceTm {number) if > 0, will wait 'persistenceTm' ms before destroy when dispose reach 0
* autoDestroy {bool} will trigger retain & dispose after start
* }
* @returns {Scope}
*/
}]);
function Scope(storesMap) {
var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
parent = _ref2.parent,
key = _ref2.key,
id = _ref2.id,
state = _ref2.state,
data = _ref2.data,
_ref2$incrementId = _ref2.incrementId,
incrementId = _ref2$incrementId === undefined ? !!key : _ref2$incrementId,
persistenceTm = _ref2.persistenceTm,
autoDestroy = _ref2.autoDestroy,
rootEmitter = _ref2.rootEmitter,
boundedActions = _ref2.boundedActions;
_classCallCheck(this, Scope);
var _this = _possibleConstructorReturn(this, (Scope.__proto__ || Object.getPrototypeOf(Scope)).call(this));
var _ = {};
id = id || key && (parent && parent._id || '') + '::' + key;
_.isLocalId = !id;
id = id || "_____" + shortid.generate();
if (openScopes[id] && !incrementId) {
var _ret;
_this._id = id;
openScopes[id].register(storesMap);
return _ret = openScopes[id], _possibleConstructorReturn(_this, _ret);
} else if (openScopes[id] && incrementId) {
var i = -1;
while (openScopes[id + '[' + ++i + ']']) {}
id = id + '[' + i + ']';
}
_this._id = id;
openScopes[id] = _this;
_.persistenceTm = persistenceTm || _this.constructor.persistenceTm;
_this.actions = {};
_this.stores = {};
_this.state = {};
_this.data = {};
_this.parent = parent;
_this._ = _;
if (parent && parent.dead) throw new Error("Can't use a dead scope as parent !");
__proto__push(_this, 'actions', parent);
__proto__push(_this, 'stores', parent);
__proto__push(_this, 'state', parent);
__proto__push(_this, 'data', parent);
_this.sources = [];
_.childScopes = [];
_.childScopesList = [];
_.unStableChilds = 0;
_this.__retains = { all: 0 };
_this.__locks = { all: 1 };
_._boundedActions = is.array(boundedActions) ? { test: boundedActions.includes.bind(boundedActions) } : boundedActions;
_._listening = {};
_._scope = {};
_._mixed = [];
_._mixedList = [];
_.followers = [];
if (parent) {
parent.retain("isMyParent");
if (!rootEmitter) {
!parent._stable && _this.wait("waitingParent");
parent.on(_._parentList = {
'stable': function stable(s) {
return _this.release("waitingParent");
},
'unstable': function unstable(s) {
return _this.wait("waitingParent");
},
'update': function update(s) {
return _this._propag();
}
});
} else {
parent.on(_._parentList = {
'update': function update(s) {
return _this._propag();
}
});
}
// this.register(parent.__scope, state, data);
}
_this.register(storesMap, state, data);
_this.__locks.all--;
_this._stable = !_this.__locks.all;
if (parent) {
parent._addChild(_this);
}
if (autoDestroy) setTimeout(function (tm) {
_this.retain("autoDestroy");
_this.dispose("autoDestroy");
});
return _this;
}
/**
* @deprecated
* @returns {*}
*/
_createClass(Scope, [{
key: 'mount',
/**
*
* Mount the stores in storesList, in this scope or in its parents or mixed scopes
*
* @param storesList {string|storeRef} Store name, Array of Store names, or Rescope store ref from Store::as or
* Store:as
* @param state
* @param data
* @returns {Scope}
*/
value: function mount(storesList, snapshot, state, data) {
var _this2 = this;
if (is.array(storesList)) {
storesList.forEach(function (k) {
return _this2._mount(k, snapshot, state, data);
});
} else {
this._mount.apply(this, arguments);
}
return this;
}
}, {
key: '_mount',
value: function _mount(id, snapshot, state, data) {
if (typeof id !== 'string') {
this.register(_defineProperty({}, id.name, id.store));
id = id.name;
}
if (!this._._scope[id]) {
var _parent;
//ask mixed || parent
if (this._._mixed.reduce(function (mounted, ctx) {
return mounted || ctx._mount(id, snapshot, state, data);
}, false) || !this.parent) return;
return (_parent = this.parent)._mount.apply(_parent, arguments);
} else {
var store = this._._scope[id],
ctx = void 0;
if (is.fn(store)) {
this._._scope[id] = new store(this, { snapshot: snapshot, name: id, state: state, data: data });
} else if (snapshot) store.restore(snapshot);else {
if (state !== undefined && data === undefined) store.setState(state);else if (state !== undefined) store.state = state;
if (data !== undefined) store.push(data);
}
this._watchStore(id);
}
return this._._scope[id];
}
}, {
key: '_watchStore',
value: function _watchStore(id, state, data) {
var _this3 = this;
//if ( !this.__scope[id] ) {//ask mixed || parent
// if ( this.__mixed.reduce(( mounted, ctx ) => (mounted || ctx._watchStore(id, state, data)), false) ||
// !this.parent )
// return;
// return this.parent._watchStore(...arguments);
//}
if (!this._._listening[id] && !is.fn(this._._scope[id])) {
!this._._scope[id]._autoDestroy && this._._scope[id].retain("scoped");
!this._._scope[id].isStable() && this.wait(id);
this._._scope[id].on(this._._listening[id] = {
'destroy': function destroy(s) {
delete _this3._._listening[id];
_this3._._scope[id] = _this3._._scope[id].constructor;
},
'update': function update(s) {
return _this3.propag();
},
'stable': function stable(s) {
return _this3.release(id);
},
'unstable': function unstable(s) {
return _this3.wait(id);
}
});
}
return true;
}
/**
* Mix targetCtx on this scope
* Mixed scope parents are NOT mapped
* @param targetCtx
*/
}, {
key: 'mixin',
value: function mixin(targetCtx) {
var _this4 = this;
var parent = this.parent,
lists = void 0;
this._._mixed.push(targetCtx);
targetCtx.retain("mixedTo");
if (!targetCtx._stable) this.wait(targetCtx._id);
this._._mixedList.push(lists = {
'stable': function stable(s) {
return _this4.release(targetCtx._id);
},
'unstable': function unstable(s) {
return _this4.wait(targetCtx._id);
},
'update': function update(s) {
return _this4._propag();
}
});
this.actions = {};
this.stores = {};
this.state = {};
this.data = {};
targetCtx.on(lists);
__proto__push(this, 'actions', parent);
__proto__push(this, 'stores', parent);
__proto__push(this, 'state', parent);
__proto__push(this, 'data', parent);
this.relink(this._._scope, this, false, true);
this._._mixed.forEach(function (ctx) {
__proto__push(_this4, 'actions');
__proto__push(_this4, 'stores');
__proto__push(_this4, 'state');
__proto__push(_this4, 'data');
ctx.relink(ctx._._scope, _this4, true, true);
});
}
/**
* Register stores in storesMap & link them in the protos
* @param storesMap
* @param state
* @param data
*/
}, {
key: 'register',
value: function register(storesMap) {
var _this5 = this;
var state = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var data = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
this.relink(storesMap, this, false, false);
Object.keys(storesMap).forEach(function (id) {
if (storesMap[id].singleton || is.fn(storesMap[id]) && (state[id] || data[id])) {
_this5._mount(id, undefined, state[id], data[id]);
} else if (state[id] || data[id]) {
if (data[id]) {
if (state[id]) _this5.stores[id].state = state[id];
_this5.stores[id].push(data[id]);
} else if (state[id]) {
_this5.stores[id].setState(state[id]);
}
} else {
_this5._watchStore(id);
}
});
}
/**
* Map srcCtx store's on targetCtx headers proto's
* @param srcCtx
* @param targetCtx
* @param state
* @param data
*/
}, {
key: 'relink',
value: function relink(srcCtx) {
var targetCtx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this;
var _this6 = this;
var external = arguments[2];
var force = arguments[3];
var lctx = targetCtx._.stores.prototype;
Object.keys(srcCtx).forEach(function (id) {
if (!force && targetCtx._._scope[id] === srcCtx[id] || targetCtx._._scope[id] && targetCtx._._scope[id].constructor === srcCtx[id]) return;
if (!force && targetCtx._._scope[id]) {
if (!external && !is.fn(targetCtx._._scope[id])) {
console.info("Rescope Store : ", id, " already exist in this scope ! ( try __proto__ hot patch )");
targetCtx._._scope[id].__proto__ = srcCtx[id].prototype;
}
if (!external && is.fn(targetCtx._._scope[id])) targetCtx._._scope[id] = srcCtx[id];
return;
} else if (!force && !external) _this6._._scope[id] = srcCtx[id];
Object.defineProperty(lctx, id, {
enumerable: true,
get: function get() {
return _this6._._scope[id];
}
});
Object.defineProperty(targetCtx._.state.prototype, id, {
enumerable: true,
get: function get() {
return _this6._._scope[id] && _this6._._scope[id].state;
},
set: function set(v) {
return _this6._mount(id, undefined, v);
}
});
Object.defineProperty(targetCtx._.data.prototype, id, {
enumerable: true,
get: function get() {
return _this6._._scope[id] && _this6._._scope[id].data;
},
set: function set(v) {
return _this6._mount(id, undefined, v);
}
});
var actions = srcCtx[id] instanceof Scope.Store ? srcCtx[id].constructor.actions : srcCtx[id].actions,
activeActions = targetCtx._.actions.prototype;
actions && Object.keys(actions).forEach(function (act) {
if (activeActions.hasOwnProperty(act)) activeActions[act].__targetStores++;else {
activeActions[act] = _this6.dispatch.bind(_this6, act);
activeActions[act].__targetStores = 1;
}
});
});
}
/**
* Bind stores from this scope, his parents and mixed scope
*
* @param obj {React.Component|Store|function}
* @param key {string} stores keys to bind updates
* @param as
* @param setInitial {bool} false to not propag initial value (default : true)
*/
}, {
key: 'bind',
value: function bind(obj, key, as) {
var _this7 = this;
var setInitial = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
var lastRevs = void 0,
data = void 0,
refKeys = void 0;
if (key && !is.array(key)) key = [key];
if (as === false || as === true) {
setInitial = as;
as = null;
}
refKeys = key.map(function (id) {
return is.string(id) ? id : id.name;
}).map(function (id) {
return _this7.parseRef(id);
});
this._.followers.push([obj, key, as || undefined, lastRevs = refKeys.reduce(function (revs, ref) {
revs[ref.storeId] = revs[ref.storeId] || {
rev: 0,
refs: []
};
revs[ref.storeId].refs.push(ref);
return revs;
}, {})]);
this.mount(key);
this.retainStores(Object.keys(lastRevs), 'listeners');
if (setInitial && this._stable) {
data = this.getUpdates(lastRevs);
if (!data) return;
if (typeof obj != "function") {
if (as) obj.setState(_defineProperty({}, as, data));else obj.setState(data);
} else {
obj(data);
}
}
return this;
}
/**
* Un bind this scope off the given component-keys
* @param obj
* @param key
* @returns {Array.<*>}
*/
}, {
key: 'unBind',
value: function unBind(obj, key, as) {
var followers = this._.followers,
i = followers && followers.length;
while (followers && i--) {
if (followers[i][0] === obj && '' + followers[i][1] == '' + key && followers[i][2] == as) {
this.disposeStores(Object.keys(followers[i][3]), 'listeners');
return followers.splice(i, 1);
}
}
}
/**
* Mount the stores in storesList from this scope, its parents and mixed scope
* Bind them to 'to'
* Hook 'to' so it will auto unbind on 'destroy' or 'componentWillUnmount'
* @param to
* @param storesList
* @param bind
* @returns {Object} Initial outputs of the stores in 'storesList'
*/
}, {
key: 'map',
value: function map(to, storesList) {
var _this8 = this;
var bind = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
var Store = this.constructor.Store;
storesList = is.array(storesList) ? storesList : [storesList];
var refList = storesList.map(this.parseRef);
this.mount(refList.map(function (ref) {
return ref.storeId;
}));
if (bind && to instanceof Store) {
Store.map(to, storesList, this, this, false);
} else if (bind) {
this.bind(to, storesList, undefined, false);
var mixedCWUnmount = void 0,
unMountKey = to.isReactComponent ? "componentWillUnmount" : "destroy";
if (to.hasOwnProperty(unMountKey)) {
mixedCWUnmount = to[unMountKey];
}
to[unMountKey] = function () {
delete to[unMountKey];
if (mixedCWUnmount) to[unMountKey] = mixedCWUnmount;
_this8.unBind(to, storesList);
return to[unMountKey] && to[unMountKey].apply(to, arguments);
};
}
return storesList.reduce(function (data, id) {
if (!is.string(id)) id = id.name;
id = id.split(':'); //@todo
id[0] = id[0].split('.');
data[id[1] || id[0][id[0].length - 1]] = _this8.stores[id[0][0]] && _this8.stores[id[0][0]].retrieve && _this8.stores[id[0][0]].retrieve(id[0].splice(1));
return data;
}, {});
}
/**
* Get current data value from json path
* @param path
* @returns {string|*}
*/
}, {
key: 'retrieve',
value: function retrieve() {
var path = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
path = is.string(path) ? path.split('.') : path;
return path && this.stores[path[0]] && this.stores[path[0]].retrieve(path.slice(1));
}
/**
* Get or update storesRevMap's revisions
* @param storesRevMap
* @param local
* @returns {{}}
*/
}, {
key: 'getStoresRevs',
value: function getStoresRevs() {
var storesRevMap = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var local = arguments[1];
var ctx = this._._scope;
if (!storesRevMap) {
storesRevMap = {};
}
Object.keys(ctx).forEach(function (id) {
if (!is.fn(ctx[id])) {
storesRevMap[id] = ctx[id]._rev;
} else if (!storesRevMap.hasOwnProperty(id)) storesRevMap[id] = false;
});
if (!local) {
this._._mixed.reduce(function (updated, ctx) {
return ctx.getStoresRevs(storesRevMap), storesRevMap;
}, storesRevMap);
this.parent && this.parent.getStoresRevs(storesRevMap);
}
return storesRevMap;
}
/**
* Get or update output basing storesRevMap's revisions.
* If a store in 'storesRevMap' was updated; add it to 'output' & update storesRevMap
* @param storesRevMap
* @param output
* @param updated
* @returns {*|{}}
*/
}, {
key: 'getUpdates',
value: function getUpdates(storesRevMap, output, updated) {
var _this9 = this;
var ctx = this._._scope;
output = output || {};
Object.keys(ctx).forEach(function (id) {
if (!output.hasOwnProperty(id) && !is.fn(ctx[id]) && (!storesRevMap || storesRevMap.hasOwnProperty(id) && storesRevMap[id] === undefined || !(!storesRevMap.hasOwnProperty(id) || ctx[id]._rev <= storesRevMap[id].rev))) {
updated = true;
output[id] = _this9.data[id];
if (storesRevMap && storesRevMap.hasOwnProperty(id)) {
storesRevMap[id].rev = ctx[id]._rev;
storesRevMap[id].refs.forEach(function (ref) {
//console.warn("update ref ", ref.ref, this.retrieve(ref.path));
output[ref.alias] = _this9.retrieve(ref.path);
});
} else {
//console.warn("update ", id, this.data[id]);
output[id] = _this9.data[id];
}
}
});
updated = this._._mixed.reduce(function (updated, ctx) {
return ctx.getUpdates(storesRevMap, output, updated) || updated;
}, updated);
updated = this.parent && this.parent.getUpdates(storesRevMap, output, updated) || updated;
return updated && output;
}
/**
* Recursively get all child scopes
* @param childs
* @returns {Array}
* @private
*/
}, {
key: '_getAllChilds',
value: function _getAllChilds() {
var childs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
childs.push.apply(childs, _toConsumableArray(this._.childScopes));
this._.childScopes.forEach(function (ctx) {
ctx._getAllChilds(childs);
});
return childs;
}
/**
* Serialize all active stores state & data in every childs & mixed scopes
*
* Scopes without key or id are ignored
* @param output
* @returns {{}}
*/
}, {
key: 'serialize',
value: function serialize() {
var _this10 = this;
var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
alias = _ref3.alias,
_ref3$withChilds = _ref3.withChilds,
withChilds = _ref3$withChilds === undefined ? true : _ref3$withChilds,
withParents = _ref3.withParents,
_ref3$withMixed = _ref3.withMixed,
withMixed = _ref3$withMixed === undefined ? true : _ref3$withMixed,
norefs = _ref3.norefs;
var output = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var ctx = this._._scope;
if (output[this._id]) return;
//@todo : better serialize method
output[this._id] = {};
Object.keys(ctx).forEach(function (id) {
if (is.fn(ctx[id])) return;
ctx[id].serialize(!norefs, output);
});
withParents && this.parent && this.parent.serialize({
withChild: false,
withParents: true,
withMixed: withMixed,
norefs: norefs
}, output);
withChilds && this._.childScopes.forEach(function (ctx) {
!ctx._.isLocalId && ctx.serialize({
withChild: true,
withParents: false,
withMixed: withMixed,
norefs: norefs
}, output);
});
withMixed && this._._mixed.forEach(function (ctx) {
!ctx._.isLocalId && ctx.serialize({
withChild: false,
withParents: false,
withMixed: withMixed,
norefs: norefs
}, output);
});
if (alias) {
output = Object.keys(output).reduce(function (h, k) {
return h[k.replace(_this10._id, alias)] = output[k], h;
}, {});
}
return output;
}
/**
* Restore state & data from the serialize fn
* @param snapshot
* @param force
*/
}, {
key: 'restore',
value: function restore(snapshot, force) {
var _this11 = this;
var ctx = this._._scope;
snapshot[this._id] && Object.keys(ctx).forEach(function (name) {
var snap = snapshot[_this11._id + '/' + name];
if (snap) {
if (force && !is.fn(ctx[name])) ctx[name].destroy();
_this11.mount(name, snapshot); // quiet
}
});
this._._mixed.forEach(function (ctx) {
!ctx._.isLocalId && ctx.restore(snapshot, force);
});
this._.childScopes.forEach(function (ctx) {
!ctx._.isLocalId && ctx.restore(snapshot, force);
});
}
/**
* get a parsed reference
* @param _ref
* @returns {{storeId, path, alias: *, ref: *}}
*/
}, {
key: 'parseRef',
value: function parseRef(_ref) {
var ref = _ref.split(':');
ref[0] = ref[0].split('.');
return {
storeId: ref[0][0],
path: ref[0],
alias: ref[1] || ref[0][ref[0].length - 1],
ref: _ref
};
}
/**
* Dispatch an action to the top parent & mixed scopes, in all stores
*
* @param action
* @param data
* @returns {Scope}
*/
}, {
key: 'dispatch',
value: function dispatch(action) {
var _this12 = this,
_parent2;
for (var _len = arguments.length, argz = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
argz[_key - 1] = arguments[_key];
}
if (this.dead) {
console.warn("Dispatch was called on a dead scope, check you're async functions in this stack...", new Error().stack);
return;
}
var bActs = this._._boundedActions;
Object.keys(this._._scope).forEach(function (id) {
var _$_scope$id;
if (!is.fn(_this12._._scope[id])) (_$_scope$id = _this12._._scope[id]).trigger.apply(_$_scope$id, [action].concat(argz));
});
if (bActs && bActs.test(action)) return;
this._._mixed.forEach(function (ctx) {
return ctx.dispatch.apply(ctx, [action].concat(argz));
});
this.parent && (_parent2 = this.parent).dispatch.apply(_parent2, [action].concat(argz));
return this;
}
/**
* once('stable', cb)
* @param obj {React.Component|Store|function)
* @param key {string} optional key where to map the public state
*/
}, {
key: 'then',
value: function then(cb) {
var _this13 = this;
if (this._stable) return cb(null, this.data);
this.once('stable', function (e) {
return cb(null, _this13.data);
});
}
/**
* Call retain on the scoped stores basing given
*
* @param stores
* @param reason
*/
}, {
key: 'retainStores',
value: function retainStores() {
var _this14 = this;
var stores = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var reason = arguments[1];
stores.forEach(function (id) {
return _this14.stores[id] && _this14.stores[id].retain && _this14.stores[id].retain(reason);
});
}
/**
* Call retain on the scoped stores
*
* @param stores
* @param reason
*/
}, {
key: 'disposeStores',
value: function disposeStores() {
var _this15 = this;
var stores = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var reason = arguments[1];
stores.forEach(function (id) {
return _this15.stores[id] && _this15.stores[id].dispose && _this15.stores[id].dispose(reason);
});
}
/**
* Keep the scope unstable until release is called
* @param reason
*/
}, {
key: 'wait',
value: function wait(reason) {
//console.log("wait", reason);
this._stable && !this.__locks.all && this.emit("unstable", this);
this._stable = false;
this.__locks.all++;
if (reason) {
this.__locks[reason] = this.__locks[reason] || 0;
this.__locks[reason]++;
}
}
/**
* Stabilize the scope if no more locks remain (wait fn)
* @param reason
*/
}, {
key: 'release',
value: function release(reason) {
var _this16 = this;
if (reason) {
if (this.__locks[reason] == 0) console.error("Release more than locking !", reason);
this.__locks[reason] = this.__locks[reason] || 0;
this.__locks[reason]--;
}
if (!reason && this.__locks.all == 0) console.error("Release more than locking !");
this.__locks.all--;
if (!this.__locks.all) {
this._.stabilizerTM && clearTimeout(this._.stabilizerTM);
this._.stabilizerTM = setTimeout(function (e) {
_this16._.stabilizerTM = null;
if (_this16.__locks.all) return;
_this16._.propagTM && clearTimeout(_this16._.propagTM);
_this16._stable = true;
_this16.emit("stable", _this16);
!_this16.dead && _this16._propag(); // stability can induce destroy
});
}
}
/**
* Propag stores updates basing theirs last updates
*/
}, {
key: 'propag',
value: function propag() {
var _this17 = this;
this._.propagTM && clearTimeout(this._.propagTM);
this._.propagTM = setTimeout(function (e) {
_this17._.propagTM = null;
_this17._propag();
}, 2);
}
}, {
key: '_propag',
value: function _propag() {
var _this18 = this;
if (this._.followers.length) this._.followers.forEach(function (_ref4) {
var obj = _ref4[0],
key = _ref4[1],
as = _ref4[2],
lastRevs = _ref4[3],
remaps = _ref4[3];
var data = _this18.getUpdates(lastRevs);
if (!data) return;
if (typeof obj != "function") {
//console.log("setState ",obj, Object.keys(data))
if (as) obj.setState(_defineProperty({}, as, data));else obj.setState(data);
} else {
obj(data, lastRevs && [].concat(_toConsumableArray(lastRevs)) || "no revs");
}
// lastRevs &&
// key.forEach(id => (lastRevs[id] = this.stores[id] && this.stores[id]._rev || 0));
});
this.emit("update", this.getUpdates());
}
/**
* is stable
* @returns bool
*/
}, {
key: 'isStable',
value: function isStable() {
return this._stable;
}
}, {
key: '_addChild',
value: function _addChild(ctx) {
var _this19 = this;
this._.childScopes.push(ctx);
var lists = {
'stable': function stable(s) {
_this19._.unStableChilds--;
if (!_this19._.unStableChilds) _this19.emit("stableTree", _this19);
},
'unstable': function unstable(s) {
_this19._.unStableChilds++;
if (1 == _this19._.unStableChilds) _this19.emit("unstableTree", _this19);
},
'stableTree': function stableTree(s) {
_this19._.unStableChilds--;
if (!_this19._.unStableChilds) _this19.emit("stableTree", _this19);
},
'unstableTree': function unstableTree(s) {
_this19._.unStableChilds++;
if (1 == _this19._.unStableChilds) _this19.emit("unstableTree", _this19);
},
'destroy': function destroy(ctx) {
if (ctx._.unStableChilds) _this19._.unStableChilds--;
if (!ctx.isStable()) _this19._.unStableChilds--;
if (!_this19._.unStableChilds) _this19.emit("stableTree", _this19);
}
},
wasStable = this._.unStableChilds;
//!ctx.isStable() && console.warn('add unstable child');
!ctx.isStable() && this._.unStableChilds++;
ctx._.unStableChilds && this._.unStableChilds++;
this._.childScopesList.push(lists);
if (!wasStable && this._.unStableChilds) this.emit("unstableTree", this);
ctx.on(lists);
}
}, {
key: '_rmChild',
value: function _rmChild(ctx) {
var i = this._.childScopes.indexOf(ctx),
wasStable = this._.unStableChilds;
if (i != -1) {
this._.childScopes.splice(i, 1);
!ctx.isStable() && this._.unStableChilds--;
ctx._.unStableChilds && this._.unStableChilds--;
ctx.un(this._.childScopesList.splice(i, 1)[0]);
if (wasStable && !this._.unStableChilds) this.emit("stableTree");
}
}
}, {
key: 'retain',
value: function retain(reason) {
this.__retains.all++;
//console.log("retain", this._id, reason);
if (reason) {
this.__retains[reason] = this.__retains[reason] || 0;
this.__retains[reason]++;
}
}
}, {
key: 'dispose',
value: function dispose(reason) {
var _this20 = this;
//console.log("dispose", this._id, reason);
if (reason) {
if (!this.__retains[reason]) throw new Error("Dispose more than retaining : " + reason);
this.__retains[reason]--;
}
if (!this.__retains.all) throw new Error("Dispose more than retaining !");
this.__retains.all--;
if (!this.__retains.all) {
//console.log("dispose do destroy ", this._id, this._persistenceTm);
if (this._.persistenceTm) {
this._.destroyTM && clearTimeout(this._.destroyTM);
this._.destroyTM = setTimeout(function (e) {
//this