@turbox3d/reactivity
Version:
Large-scale reactive state management library
306 lines • 10.5 kB
JavaScript
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import { fail, nextTick } from '@turbox3d/shared';
import { ctx } from '../const/config';
import { TimeTravel } from './time-travel';
import { actionTypeChain } from './store';
import { EDepState, ECollectType, ESpecialReservedKey } from '../const/enums';
import { Action } from './action';
import { rawCache } from './domain';
import { isDomain } from '../utils/common';
import { EEventName, emitter } from '../utils/event';
import { materialCallStack } from '../utils/materialCallStack';
var isInBlackList = function isInBlackList(propKey) {
var blackList = {
constructor: true,
$$turboxProperties: true,
context: true,
currentTarget: true,
originalArrayLength: true,
reactorConfigMap: true,
computedProperties: true,
propertyGet: true,
propertySet: true,
proxyDeleteProperty: true,
proxyOwnKeys: 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 reaction ids
*/
var DepCollector = /*#__PURE__*/function () {
function DepCollector() {
_classCallCheck(this, DepCollector);
this.dependencyGraph = new Map();
this.reactionIdDeps = new Map();
this.reactionIdStack = [];
}
return _createClass(DepCollector, [{
key: "start",
value: function start(id) {
this.reactionIdStack.push(id);
}
}, {
key: "collect",
value: function collect(target, propertyKey) {
if (isInBlackList(propertyKey)) {
return;
}
var stackLength = this.reactionIdStack.length;
if (stackLength === 0) {
return;
}
var currentReactionId = this.reactionIdStack[stackLength - 1];
var depNodeAssembly = this.dependencyGraph.get(target);
if (depNodeAssembly !== void 0) {
var depNode = depNodeAssembly.get(propertyKey);
if (depNode !== void 0) {
depNode.add(currentReactionId);
} else {
depNodeAssembly.set(propertyKey, new Set([currentReactionId]));
}
} else {
var map = new Map([[propertyKey, new Set([currentReactionId])]]);
this.dependencyGraph.set(target, map);
}
var reactionDeps = this.reactionIdDeps.get(currentReactionId);
if (reactionDeps !== void 0) {
var depNodeStatusAssembly = reactionDeps.get(target);
if (depNodeStatusAssembly !== void 0) {
depNodeStatusAssembly.set(propertyKey, EDepState.LATEST);
} else {
reactionDeps.set(target, new Map([[propertyKey, EDepState.LATEST]]));
}
} else {
this.reactionIdDeps.set(currentReactionId, new Map([[target, new Map([[propertyKey, EDepState.LATEST]])]]));
}
}
}, {
key: "end",
value: function end() {
var _this = this;
var currentReactionId = this.reactionIdStack.pop();
if (!currentReactionId) {
return;
}
var map = this.reactionIdDeps.get(currentReactionId);
if (!map) {
return;
}
map.forEach(function (depNode, target) {
depNode.forEach(function (value, key) {
// remove stale deps
if (value === EDepState.OBSERVED) {
var depNodeAssembly = _this.dependencyGraph.get(target);
if (depNodeAssembly) {
var idSet = depNodeAssembly.get(key);
idSet && idSet["delete"](currentReactionId);
depNode.set(key, EDepState.NOT_OBSERVED);
}
}
// reset dep status
if (value === EDepState.LATEST) {
depNode.set(key, EDepState.OBSERVED);
}
});
});
}
}, {
key: "clear",
value: function clear(id) {
var _this2 = this;
var map = this.reactionIdDeps.get(id);
if (!map) {
return;
}
map.forEach(function (depNode, target) {
depNode.forEach(function (value, key) {
var depNodeAssembly = _this2.dependencyGraph.get(target);
if (depNodeAssembly) {
var idSet = depNodeAssembly.get(key);
idSet && idSet["delete"](id);
}
});
});
this.reactionIdDeps["delete"](id);
}
}, {
key: "isObserved",
value: function isObserved(targetKey, propKey) {
var map = this.dependencyGraph.get(targetKey);
return map !== void 0 && map.has(propKey) && (map.get(propKey) || new Set()).size > 0;
}
}]);
}();
export var depCollector = new DepCollector();
var TriggerCollector = /*#__PURE__*/function () {
function TriggerCollector() {
_classCallCheck(this, TriggerCollector);
this.waitTriggerIds = new Set();
}
return _createClass(TriggerCollector, [{
key: "trigger",
value: function trigger(target, key, payload) {
var isNeedRecord = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
var devToolInfo = arguments.length > 4 ? arguments[4] : undefined;
var _a, _b;
var type = payload.type,
beforeUpdate = payload.beforeUpdate,
didUpdate = payload.didUpdate;
if (ctx.devTool && devToolInfo) {
try {
var stringify = (_a = window && window.__TURBOX_DEVTOOL_GOLBAL_STRINGIFY__) !== null && _a !== void 0 ? _a : JSON.stringify;
var event = {
time: Date.now(),
stackId: (_b = materialCallStack.currentStack) === null || _b === void 0 ? void 0 : _b.stackId,
domain: devToolInfo.domain,
keyPath: devToolInfo.keyPath,
newValue: stringify(didUpdate),
oldValue: stringify(beforeUpdate),
type: type
};
emitter.emit(EEventName.setProperty, event);
console.log(event);
} catch (e) {
fail(e);
}
}
var enhanceKey = type === ECollectType.ADD ? ESpecialReservedKey.ITERATE : key;
this.collectComponentId(target, enhanceKey);
if (!ctx.timeTravel.isActive || !TimeTravel.currentTimeTravel || !isNeedRecord || TimeTravel.processing || enhanceKey === ESpecialReservedKey.ITERATE || enhanceKey === ESpecialReservedKey.COMPUTED) {
return;
}
if (Action.context) {
this.recordDiff(target, enhanceKey, payload, Action.context.historyNode.history);
return;
}
this.recordDiff(target, enhanceKey, payload, TimeTravel.currentTimeTravel.currentHistory);
}
}, {
key: "endBatch",
value: function endBatch() {
var isClearHistory = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
var action = arguments.length > 1 ? arguments[1] : undefined;
if (!action) {
this.waitTriggerIds.clear();
}
if (!ctx.timeTravel.isActive || !TimeTravel.currentTimeTravel || !isClearHistory) {
return;
}
if (action) {
action.historyNode.actionChain.length = 0;
action.historyNode.history.clear();
nextTick(function () {
var ctt = TimeTravel.currentTimeTravel;
ctt && ctt.onChange(ctt.undoable, ctt.redoable, 'clear', action);
});
return;
}
actionTypeChain.length = 0;
TimeTravel.currentTimeTravel.currentHistory.clear();
}
}, {
key: "save",
value: function save(action) {
if (!ctx.timeTravel.isActive || !TimeTravel.currentTimeTravel || Action.context) {
return;
}
var ctt = TimeTravel.currentTimeTravel;
if (action) {
this.saveHistory(ctt, action.historyNode.actionChain, action.historyNode.history, action);
return;
}
this.saveHistory(ctt, actionTypeChain, ctt.currentHistory);
}
}, {
key: "collectComponentId",
value: function collectComponentId(target, enhanceKey) {
var _this3 = this;
var depNodeAssembly = depCollector.dependencyGraph.get(target);
if (depNodeAssembly !== void 0) {
var idSet = depNodeAssembly.get(enhanceKey);
if (idSet !== void 0 && idSet.size > 0) {
idSet.forEach(function (id) {
return _this3.waitTriggerIds.add(id);
});
}
}
}
}, {
key: "recordDiff",
value: function recordDiff(target, enhanceKey, payload, history) {
var type = payload.type,
beforeUpdate = payload.beforeUpdate,
didUpdate = payload.didUpdate;
var proxyTarget;
if (isDomain(target)) {
proxyTarget = target;
} else {
proxyTarget = rawCache.get(target);
}
if (!proxyTarget) {
return;
}
var keyToDiffChangeMap = history.get(proxyTarget);
if (keyToDiffChangeMap !== void 0) {
var diffInfo = keyToDiffChangeMap.get(enhanceKey);
if (diffInfo !== void 0) {
diffInfo.didUpdate = didUpdate;
} else {
keyToDiffChangeMap.set(enhanceKey, {
type: type,
beforeUpdate: beforeUpdate,
didUpdate: didUpdate
});
}
} else {
history.set(proxyTarget, new Map([[enhanceKey, {
type: type,
beforeUpdate: beforeUpdate,
didUpdate: didUpdate
}]]));
}
}
}, {
key: "saveHistory",
value: function saveHistory(ctt, actionChain, history, action) {
if (!history) {
return;
}
if (history.size === 0) {
return;
}
var clonedChain = ctx.timeTravel.keepActionChain ? actionChain.slice() : [];
var clonedHistory = new Map(history);
if (ctt.cursor === ctt.transactionHistories.length - 1) {
ctt.transactionHistories.push({
actionChain: clonedChain,
history: clonedHistory
});
ctt.cursor += 1;
} else if (ctt.cursor < ctt.transactionHistories.length - 1) {
ctt.transactionHistories = ctt.transactionHistories.slice(0, ctt.cursor + 1);
ctt.transactionHistories.push({
actionChain: clonedChain,
history: clonedHistory
});
ctt.cursor += 1;
}
if (ctt.transactionHistories.length > ctx.timeTravel.maxStepNumber) {
ctt.transactionHistories.shift();
ctt.cursor -= 1;
}
nextTick(function () {
ctt.onChange(ctt.undoable, ctt.redoable, 'save', action);
});
}
}]);
}();
export var triggerCollector = new TriggerCollector();