@tacky/store
Version:
State management framework based on react
414 lines (339 loc) • 12 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getTimeTravelStatus = exports.redo = exports.undo = exports.historyCollector = exports.EOperationTypes = exports.depCollector = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _common = require("../utils/common");
var _config = require("../const/config");
var _store = require("./store");
var _uuid = _interopRequireDefault(require("../utils/uuid"));
var _domain = require("./domain");
var _interfaces = require("../interfaces");
;
var isInBlackList = function isInBlackList(propKey) {
var blackList = {
constructor: true,
properties: true,
reactorConfigMap: true,
propertyGet: true,
propertySet: true,
proxySet: true,
proxyGet: true,
proxyReactive: true,
$update: true,
illegalAssignmentCheck: true,
dispatch: true
};
return !!blackList[propKey];
};
/**
* collect relation map of the dep key and the component ids
*/
var DepCollector = /*#__PURE__*/function () {
function DepCollector() {
(0, _classCallCheck2["default"])(this, DepCollector);
this.dependencyMap = new WeakMap();
/**
* Using a small amount of memory to improve execute performance
*/
this.reverseDependencyMap = new WeakMap();
this.componentIdStack = [];
}
(0, _createClass2["default"])(DepCollector, [{
key: "clearCurrentComponentOldDeps",
value: function clearCurrentComponentOldDeps(id) {
var _this = this;
var targetToKeysMap = this.reverseDependencyMap.get(id);
if (targetToKeysMap !== void 0) {
targetToKeysMap.forEach(function (propKeys, targetKey) {
var keyToComponentIdsMap = _this.dependencyMap.get(targetKey);
if (keyToComponentIdsMap !== void 0 && Object.keys(keyToComponentIdsMap).length > 0) {
for (var index = 0; index < propKeys.length; index++) {
var propKey = propKeys[index];
var componentIds = keyToComponentIdsMap[propKey];
if (componentIds !== void 0 && componentIds.length > 0) {
keyToComponentIdsMap[propKey] = componentIds.filter(function (cid) {
return cid !== id;
});
} else if (componentIds === void 0 || componentIds.length === 0) {
delete keyToComponentIdsMap[propKey];
}
}
} else if (keyToComponentIdsMap === void 0 || Object.keys(keyToComponentIdsMap).length === 0) {
_this.dependencyMap["delete"](targetKey);
}
});
}
}
}, {
key: "start",
value: function start(id) {
this.clearCurrentComponentOldDeps(id);
this.reverseDependencyMap["delete"](id);
this.componentIdStack.push(id);
}
}, {
key: "collect",
value: function collect(targetKey, propKey) {
if (isInBlackList(propKey)) {
return;
}
var stackLength = this.componentIdStack.length;
if (stackLength === 0) {
return;
}
var currentComponentId = this.componentIdStack[stackLength - 1];
var targetToKeysMap = this.reverseDependencyMap.get(currentComponentId);
if (targetToKeysMap !== void 0) {
var keys = targetToKeysMap.get(targetKey);
if (keys !== void 0) {
if (!(0, _common.includes)(keys, propKey)) keys.push(propKey);
} else {
targetToKeysMap.set(targetKey, [propKey]);
}
} else {
var wm = new Map();
wm.set(targetKey, [propKey]);
this.reverseDependencyMap.set(currentComponentId, wm);
}
var keyToComponentIdsMap = this.dependencyMap.get(targetKey);
if (keyToComponentIdsMap !== void 0) {
var idsArray = keyToComponentIdsMap[propKey];
if (idsArray !== void 0) {
if (!(0, _common.includes)(idsArray, currentComponentId)) idsArray.push(currentComponentId);
} else {
keyToComponentIdsMap[propKey] = [currentComponentId];
}
} else {
this.dependencyMap.set(targetKey, (0, _defineProperty2["default"])({}, propKey, [currentComponentId]));
}
}
}, {
key: "end",
value: function end() {
this.componentIdStack.pop();
}
}, {
key: "isObserved",
value: function isObserved(targetKey, propKey) {
var map = this.dependencyMap.get(targetKey);
return map !== void 0 && propKey in map;
}
}]);
return DepCollector;
}();
var depCollector = new DepCollector();
exports.depCollector = depCollector;
var EOperationTypes;
exports.EOperationTypes = EOperationTypes;
(function (EOperationTypes) {
EOperationTypes["SET"] = "set";
EOperationTypes["ADD"] = "add";
EOperationTypes["DELETE"] = "delete";
EOperationTypes["CLEAR"] = "clear";
EOperationTypes["GET"] = "get";
EOperationTypes["HAS"] = "has";
EOperationTypes["ITERATE"] = "iterate";
})(EOperationTypes || (exports.EOperationTypes = EOperationTypes = {}));
/**
* collect prop diff history record
*/
var HistoryCollector = /*#__PURE__*/function () {
function HistoryCollector() {
(0, _classCallCheck2["default"])(this, HistoryCollector);
this.transactionHistories = [];
this.waitTriggerComponentIds = [];
this.cursor = -1;
}
(0, _createClass2["default"])(HistoryCollector, [{
key: "collect",
value: function collect(target, key, payload) {
var isNeedRecord = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
var beforeUpdate = payload.beforeUpdate,
didUpdate = payload.didUpdate,
type = payload.type;
this.collectComponentId(target, key, type);
if (!_config.ctx.timeTravel.isActive || !isNeedRecord) {
return;
}
if (this.currentHistoryIdSet === void 0) {
this.currentHistoryIdSet = new Set();
}
if (this.currentHistory === void 0) {
this.currentHistory = new WeakMap();
}
var keyToDiffChangeMap = this.currentHistory.get(target);
if (keyToDiffChangeMap !== void 0) {
if (keyToDiffChangeMap[key] !== void 0) {
keyToDiffChangeMap[key].didUpdate = didUpdate;
} else {
keyToDiffChangeMap[key] = {
beforeUpdate: beforeUpdate,
didUpdate: didUpdate
};
}
} else {
this.currentHistory.set(target, (0, _defineProperty2["default"])({}, key, {
beforeUpdate: beforeUpdate,
didUpdate: didUpdate
}));
}
this.currentHistoryIdSet.add(target);
}
}, {
key: "collectComponentId",
value: function collectComponentId(target, key, type) {
var _this$waitTriggerComp;
var keyToComponentIdsMap = depCollector.dependencyMap.get(target);
if (keyToComponentIdsMap === void 0) {
return;
}
var tempKey = type === "add"
/* ADD */
? Array.isArray(target) ? 'length' : "iterate"
/* ITERATE */
: key;
var idsArray = keyToComponentIdsMap[tempKey];
if (idsArray === void 0 || idsArray.length === 0) {
return;
}
(_this$waitTriggerComp = this.waitTriggerComponentIds).push.apply(_this$waitTriggerComp, (0, _toConsumableArray2["default"])(idsArray));
}
}, {
key: "endBatch",
value: function endBatch() {
var isClearHistory = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
this.waitTriggerComponentIds = [];
if (!_config.ctx.timeTravel.isActive || !isClearHistory) {
return;
}
this.currentHistory = void 0;
this.currentHistoryIdSet = void 0;
}
}, {
key: "canUndo",
value: function canUndo() {
return this.cursor >= 0;
}
}, {
key: "canRedo",
value: function canRedo() {
return this.cursor < this.transactionHistories.length - 1;
}
/**
* @todo support multiple steps
* revert to the previous history status
*/
}, {
key: "undo",
value: function undo() {
var stepNum = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
if (!this.canUndo()) {
return;
}
var currentHistory = this.transactionHistories[this.cursor];
var original = function original() {
currentHistory.historyKey.forEach(function (target) {
var keyToDiffObj = currentHistory.history.get(target);
if (keyToDiffObj) {
var keys = Object.keys(keyToDiffObj);
for (var i = 0; i < keys.length; i++) {
var propKey = keys[i];
target[propKey] = keyToDiffObj[propKey].beforeUpdate;
}
}
});
};
_domain.materialCallStack.push(_interfaces.EMaterialType.TIME_TRAVEL);
_store.store.dispatch({
name: "$timeTravel_".concat((0, _uuid["default"])()),
payload: [],
original: original,
isInner: true
});
_domain.materialCallStack.pop();
this.cursor -= 1;
}
/**
* @todo support multiple steps
* apply the next history status
*/
}, {
key: "redo",
value: function redo() {
var stepNum = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
if (!this.canRedo()) {
return;
}
this.cursor += 1;
var currentHistory = this.transactionHistories[this.cursor];
var original = function original() {
currentHistory.historyKey.forEach(function (target) {
var keyToDiffObj = currentHistory.history.get(target);
if (keyToDiffObj) {
var keys = Object.keys(keyToDiffObj);
for (var i = 0; i < keys.length; i++) {
var propKey = keys[i];
target[propKey] = keyToDiffObj[propKey].didUpdate;
}
}
});
};
_domain.materialCallStack.push(_interfaces.EMaterialType.TIME_TRAVEL);
_store.store.dispatch({
name: "$timeTravel_".concat((0, _uuid["default"])()),
payload: [],
original: original,
isInner: true
});
_domain.materialCallStack.pop();
}
}, {
key: "save",
value: function save() {
if (this.cursor === this.transactionHistories.length - 1) {
this.transactionHistories.push({
historyKey: this.currentHistoryIdSet,
history: this.currentHistory
});
this.cursor += 1;
} else if (this.cursor < this.transactionHistories.length - 1) {
this.transactionHistories = this.transactionHistories.slice(0, this.cursor + 1);
this.transactionHistories.push({
historyKey: this.currentHistoryIdSet,
history: this.currentHistory
});
this.cursor += 1;
}
if (this.transactionHistories.length > _config.ctx.timeTravel.maxStepNumber) {
this.transactionHistories.shift();
this.cursor -= 1;
}
}
}]);
return HistoryCollector;
}();
var historyCollector = new HistoryCollector();
exports.historyCollector = historyCollector;
var undo = function undo() {
var stepNum = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
historyCollector.undo(stepNum);
};
exports.undo = undo;
var redo = function redo() {
var stepNum = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
historyCollector.redo(stepNum);
};
exports.redo = redo;
var getTimeTravelStatus = function getTimeTravelStatus() {
return {
canUndo: historyCollector.canUndo(),
canRedo: historyCollector.canRedo()
};
};
exports.getTimeTravelStatus = getTimeTravelStatus;