@dark-engine/core
Version:
The lightweight and powerful UI rendering engine without dependencies and written in TypeScript (Browser, Node.js, Android, iOS, Windows, Linux, macOS)
143 lines (142 loc) • 4.37 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
exports.Reconciler = void 0;
const utils_1 = require('../utils');
const constants_1 = require('../constants');
const view_1 = require('../view');
class Reconciler {
store;
constructor(store = {}) {
this.store = store;
}
get(id) {
return this.store[id];
}
reset() {
this.store = {};
}
fork() {
return new Reconciler({ ...this.store });
}
reconcile(fiber, alt, $scope) {
const { id, inst } = fiber;
const areSameTypes = (0, view_1.detectAreSameInstanceTypes)(alt.inst, inst);
const nextChildren = inst.children;
if (!areSameTypes) {
$scope.addDeletion(alt);
} else if ((0, view_1.hasChildrenProp)(alt.inst) && nextChildren) {
const { prevKeys, nextKeys, prevKeysMap, nextKeysMap, keyedFibersMap } = extractKeys(alt.child, nextChildren);
const flush = nextKeys.length === 0;
let size = Math.max(prevKeys.length, nextKeys.length);
let p = 0;
let n = 0;
this.createStore(id, keyedFibersMap);
for (let i = 0; i < size; i++) {
const nextKey = nextKeys[i - n] ?? null;
const prevKey = prevKeys[i - p] ?? null;
const prevKeyFiber = keyedFibersMap[prevKey] || null;
if (nextKey !== prevKey) {
if (nextKey !== null && !prevKeysMap[nextKey]) {
if (prevKey !== null && !nextKeysMap[prevKey]) {
this.replace(id, nextKey);
$scope.addDeletion(prevKeyFiber);
} else {
this.insert(id, nextKey);
p++;
size++;
}
} else if (!nextKeysMap[prevKey]) {
this.remove(id, prevKey);
$scope.addDeletion(prevKeyFiber);
flush && (prevKeyFiber.mask |= constants_1.FLUSH_MASK);
n++;
size++;
} else if (nextKeysMap[prevKey] && nextKeysMap[nextKey]) {
this.move(id, nextKey);
}
} else if (nextKey !== null) {
this.stable(id, nextKey);
}
}
}
}
createStore(id, map) {
this.store[id] = {
map,
replace: null,
insert: null,
remove: null,
move: null,
stable: null,
};
}
replace(id, nextKey) {
!this.store[id].replace && (this.store[id].replace = {});
this.store[id].replace[nextKey] = true;
}
insert(id, nextKey) {
!this.store[id].insert && (this.store[id].insert = {});
this.store[id].insert[nextKey] = true;
}
remove(id, prevKey) {
!this.store[id].remove && (this.store[id].remove = {});
this.store[id].remove[prevKey] = true;
}
move(id, nextKey) {
!this.store[id].move && (this.store[id].move = {});
this.store[id].move[nextKey] = true;
}
stable(id, nextKey) {
!this.store[id].stable && (this.store[id].stable = {});
this.store[id].stable[nextKey] = true;
}
}
exports.Reconciler = Reconciler;
function extractKeys(alt, children) {
let nextFiber = alt;
let idx = 0;
const prevKeys = [];
const nextKeys = [];
const prevKeysMap = {};
const nextKeysMap = {};
const keyedFibersMap = {};
const usedKeysMap = {};
while (nextFiber || idx < children.length) {
if (nextFiber) {
const key = (0, view_1.getElementKey)(nextFiber.inst);
const prevKey = (0, utils_1.detectIsEmpty)(key) ? (0, utils_1.createIndexKey)(idx) : key;
if (!prevKeysMap[prevKey]) {
prevKeysMap[prevKey] = true;
prevKeys.push(prevKey);
}
keyedFibersMap[prevKey] = nextFiber;
}
if (idx < children.length) {
const inst = children[idx];
const key = (0, view_1.getElementKey)(inst);
const nextKey = (0, utils_1.detectIsEmpty)(key) ? (0, utils_1.createIndexKey)(idx) : key;
if (process.env.NODE_ENV !== 'production') {
if (usedKeysMap[nextKey]) {
(0, utils_1.logError)((0, utils_1.formatErrorMsg)(`The key of node [${nextKey}] already has been used!`), [
inst,
]);
}
}
if (!nextKeysMap[nextKey]) {
nextKeysMap[nextKey] = true;
nextKeys.push(nextKey);
}
usedKeysMap[nextKey] = true;
}
nextFiber = nextFiber ? nextFiber.next : null;
idx++;
}
return {
prevKeys,
nextKeys,
prevKeysMap,
nextKeysMap,
keyedFibersMap,
};
}
//# sourceMappingURL=reconciler.js.map