UNPKG

@tacky/store

Version:

State management framework based on react

238 lines (194 loc) 7.75 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.Domain = exports.materialCallStack = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _symbol = require("../const/symbol"); var _interfaces = require("../interfaces"); var _common = require("../utils/common"); var _error = require("../utils/error"); var _uuid = _interopRequireDefault(require("../utils/uuid")); var _collector = require("./collector"); var _decorator = require("../utils/decorator"); var _store = require("./store"); var proxyCache = new WeakMap(); var rawCache = new WeakMap(); var rootKeyCache = new WeakMap(); var materialCallStack = []; /** * Framework base class 'Domain', class must be extends this base class which is need to be observable. */ exports.materialCallStack = materialCallStack; var Domain = /*#__PURE__*/function () { function Domain() { (0, _classCallCheck2["default"])(this, Domain); // prompt: add property do not forget sync to black list this.properties = {}; this.reactorConfigMap = {}; var target = Object.getPrototypeOf(this); var domainName = target.constructor.name || 'TACKY_DOMAIN'; var namespace = "".concat(domainName, "_").concat((0, _uuid["default"])()); this[_symbol.CURRENT_MATERIAL_TYPE] = _interfaces.EMaterialType.DEFAULT; this[_symbol.NAMESPACE] = namespace; } (0, _createClass2["default"])(Domain, [{ key: "propertyGet", value: function propertyGet(key, config) { var stringKey = (0, _common.convert2UniqueString)(key); var v = this.properties[stringKey]; this.reactorConfigMap[stringKey] = config; _collector.depCollector.collect(this, stringKey); return (0, _common.isObject)(v) && !(0, _common.isDomain)(v) && config.deepProxy ? this.proxyReactive(v, stringKey) : v; } }, { key: "propertySet", value: function propertySet(key, v, config) { var stringKey = (0, _common.convert2UniqueString)(key); this.illegalAssignmentCheck(this, stringKey); var oldValue = this.properties[stringKey]; this.reactorConfigMap[stringKey] = config; if (oldValue !== v) { this.properties[stringKey] = v; _collector.historyCollector.collect(this, stringKey, { type: "set" /* SET */ , beforeUpdate: oldValue, didUpdate: v }, config.isNeedRecord); } } }, { key: "proxySet", value: function proxySet(target, key, value, receiver) { var stringKey = (0, _common.convert2UniqueString)(key); this.illegalAssignmentCheck(target, stringKey); var hadKey = (0, _common.hasOwn)(target, key); var oldValue = target[key]; var rootKey = rootKeyCache.get(target); // do nothing if target is in the prototype chain if (target === proxyCache.get(receiver)) { var result = Reflect.set(target, key, value, receiver); if (!hadKey) { _collector.historyCollector.collect(target, stringKey, { type: "add" /* ADD */ , beforeUpdate: oldValue, didUpdate: value }, this.reactorConfigMap[rootKey].isNeedRecord); } else if (value !== oldValue) { _collector.historyCollector.collect(target, stringKey, { type: "set" /* SET */ , beforeUpdate: oldValue, didUpdate: value }, this.reactorConfigMap[rootKey].isNeedRecord); } return result; } return false; } }, { key: "proxyGet", value: function proxyGet(target, key, receiver) { var res = Reflect.get(target, key, receiver); var stringKey = (0, _common.convert2UniqueString)(key); var rootKey = rootKeyCache.get(target); _collector.depCollector.collect(target, stringKey); return (0, _common.isObject)(res) && !(0, _common.isDomain)(res) ? this.proxyReactive(res, rootKey) : res; } }, { key: "proxyOwnKeys", value: function proxyOwnKeys(target) { _collector.depCollector.collect(target, "iterate" /* ITERATE */ ); return Reflect.ownKeys(target); } /** * proxy value could be boolean, string, number, undefined, null, custom instance, array[], plainObject{} * @todo: support Map、Set、WeakMap、WeakSet */ }, { key: "proxyReactive", value: function proxyReactive(raw, rootKey) { var _this = this; rootKeyCache.set(raw, rootKey); // different props use same ref var refProxy = rawCache.get(raw); if (refProxy !== void 0) { return refProxy; } // raw is already a Proxy if (proxyCache.has(raw)) { return raw; } if (!(0, _decorator.canObserve)(raw)) { return raw; } var proxy = new Proxy(raw, { get: (0, _common.bind)(_this.proxyGet, _this), set: (0, _common.bind)(_this.proxySet, _this), ownKeys: (0, _common.bind)(_this.proxyOwnKeys, _this) }); proxyCache.set(proxy, raw); rawCache.set(raw, proxy); return proxy; } /** * the syntax sweet of updating state out of mutation */ }, { key: "$update", value: function $update(obj, actionName) { (0, _error.invariant)((0, _common.isPlainObject)(obj), 'resetState(...) param type error. Param should be a plain object.'); this.dispatch(obj, actionName); } /** * observed value could be assigned value to @reactor only in @mutation/$update, otherwise throw error. */ }, { key: "illegalAssignmentCheck", value: function illegalAssignmentCheck(target, stringKey) { if (_collector.depCollector.isObserved(target, stringKey)) { var length = materialCallStack.length; var firstLevelMaterial = materialCallStack[length - 1] || _interfaces.EMaterialType.DEFAULT; (0, _error.invariant)(firstLevelMaterial === _interfaces.EMaterialType.MUTATION || firstLevelMaterial === _interfaces.EMaterialType.UPDATE || firstLevelMaterial === _interfaces.EMaterialType.TIME_TRAVEL, 'You cannot update value to observed \'@reactor property\' directly. Please use mutation or $update({}).'); } } }, { key: "dispatch", value: function dispatch(obj, actionName) { var original = function original() { var keys = Object.keys(obj); for (var i = 0, len = keys.length; i < len; i++) { var key = keys[i]; this[key] = obj[key]; } }; this[_symbol.CURRENT_MATERIAL_TYPE] = _interfaces.EMaterialType.UPDATE; materialCallStack.push(this[_symbol.CURRENT_MATERIAL_TYPE]); // update state before store init if (_store.store === void 0) { original.call(this); materialCallStack.pop(); var _length = materialCallStack.length; this[_symbol.CURRENT_MATERIAL_TYPE] = materialCallStack[_length - 1] || _interfaces.EMaterialType.DEFAULT; return; } // update state after store init _store.store.dispatch({ name: actionName || "$update_".concat((0, _uuid["default"])()), payload: [], type: _interfaces.EMaterialType.UPDATE, domain: this, original: (0, _common.bind)(original, this) }); materialCallStack.pop(); var length = materialCallStack.length; this[_symbol.CURRENT_MATERIAL_TYPE] = materialCallStack[length - 1] || _interfaces.EMaterialType.DEFAULT; } }]); return Domain; }(); exports.Domain = Domain;