@tacky/store
Version:
State management framework based on react
238 lines (194 loc) • 7.75 kB
JavaScript
"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;