UNPKG

rescope

Version:

Flexible state management system based on flux architecture, stores data components & inheritable scopes

1,282 lines (1,095 loc) 143 kB
/******/ (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