linktree/node_modules/@prefresh/core/src/index.js
2025-06-16 13:37:14 +02:00

209 lines
6.2 KiB
JavaScript

// Options for Preact.
import './runtime/catchError';
import './runtime/debounceRendering';
import './runtime/vnode';
import './runtime/unmount';
import { Component } from 'preact';
import {
VNODE_COMPONENT,
NAMESPACE,
HOOKS_LIST,
EFFECTS_LIST,
COMPONENT_HOOKS,
HOOK_ARGS,
HOOK_VALUE,
HOOK_CLEANUP,
} from './constants';
import { computeKey } from './computeKey';
import { vnodesForComponent, mappedVNodes } from './runtime/vnodesForComponent';
import { signaturesForType } from './runtime/signaturesForType';
let typesById = new Map();
let pendingUpdates = [];
function sign(type, key, forceReset, getCustomHooks, status) {
if (type) {
let signature = signaturesForType.get(type);
if (status === 'begin') {
signaturesForType.set(type, {
type,
key,
forceReset,
getCustomHooks: getCustomHooks || (() => []),
});
return 'needsHooks';
} else if (status === 'needsHooks') {
signature.fullKey = computeKey(signature);
}
}
}
function replaceComponent(OldType, NewType, resetHookState) {
const vnodes = vnodesForComponent.get(OldType);
if (!vnodes) return;
// migrate the list to our new constructor reference
vnodesForComponent.delete(OldType);
vnodesForComponent.set(NewType, vnodes);
mappedVNodes.set(OldType, NewType);
pendingUpdates = pendingUpdates.filter(p => p[0] !== OldType);
vnodes.forEach(vnode => {
if (!vnode.__c || !vnode.__c.__P) return;
// update the type in-place to reference the new component
vnode.type = NewType;
if (vnode[VNODE_COMPONENT]) {
vnode[VNODE_COMPONENT].constructor = vnode.type;
try {
if (vnode[VNODE_COMPONENT] instanceof OldType) {
const oldInst = vnode[VNODE_COMPONENT];
const newInst = new NewType(
vnode[VNODE_COMPONENT].props,
vnode[VNODE_COMPONENT].context
);
vnode[VNODE_COMPONENT] = newInst;
// copy old properties onto the new instance.
// - Objects (including refs) in the new instance are updated with their old values
// - Missing or null properties are restored to their old values
// - Updated Functions are not reverted
// - Scalars are copied
for (let i in oldInst) {
const type = typeof oldInst[i];
if (!(i in newInst)) {
newInst[i] = oldInst[i];
} else if (type !== 'function' && typeof newInst[i] === type) {
if (
type === 'object' &&
newInst[i] != null &&
newInst[i].constructor === oldInst[i].constructor
) {
Object.assign(newInst[i], oldInst[i]);
} else {
newInst[i] = oldInst[i];
}
}
}
}
} catch (e) {
/* Functional component */
vnode[VNODE_COMPONENT].constructor = NewType;
}
if (resetHookState) {
if (
vnode[VNODE_COMPONENT][COMPONENT_HOOKS] &&
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST] &&
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST].length
) {
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST].forEach(
possibleEffect => {
if (
possibleEffect[HOOK_CLEANUP] &&
typeof possibleEffect[HOOK_CLEANUP] === 'function'
) {
possibleEffect[HOOK_CLEANUP]();
possibleEffect[HOOK_CLEANUP] = undefined;
} else if (
possibleEffect[HOOK_ARGS] &&
possibleEffect[HOOK_VALUE] &&
Object.keys(possibleEffect).length === 3
) {
const cleanupKey = Object.keys(possibleEffect).find(
key => key !== HOOK_ARGS && key !== HOOK_VALUE
);
if (
cleanupKey &&
typeof possibleEffect[cleanupKey] == 'function'
) {
possibleEffect[cleanupKey]();
possibleEffect[cleanupKey] = undefined;
}
}
}
);
}
vnode[VNODE_COMPONENT][COMPONENT_HOOKS] = {
[HOOKS_LIST]: [],
[EFFECTS_LIST]: [],
};
} else if (
vnode[VNODE_COMPONENT][COMPONENT_HOOKS] &&
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST] &&
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST].length
) {
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST].forEach(
possibleEffect => {
if (
possibleEffect[HOOK_CLEANUP] &&
typeof possibleEffect[HOOK_CLEANUP] === 'function'
) {
possibleEffect[HOOK_CLEANUP]();
possibleEffect[HOOK_CLEANUP] = undefined;
} else if (
possibleEffect[HOOK_ARGS] &&
possibleEffect[HOOK_VALUE] &&
Object.keys(possibleEffect).length === 3
) {
const cleanupKey = Object.keys(possibleEffect).find(
key => key !== HOOK_ARGS && key !== HOOK_VALUE
);
if (cleanupKey && typeof possibleEffect[cleanupKey] == 'function')
possibleEffect[cleanupKey]();
possibleEffect[cleanupKey] = undefined;
}
}
);
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST].forEach(hook => {
if (hook.__H && Array.isArray(hook.__H)) {
hook.__H = undefined;
}
});
}
Component.prototype.forceUpdate.call(vnode[VNODE_COMPONENT]);
}
});
}
self[NAMESPACE] = {
getSignature: type => signaturesForType.get(type),
register: (type, id) => {
if (typeof type !== 'function') return;
if (typesById.has(id)) {
const existing = typesById.get(id);
if (existing !== type) {
pendingUpdates.push([existing, type]);
typesById.set(id, type);
}
} else {
typesById.set(id, type);
}
if (!signaturesForType.has(type)) {
signaturesForType.set(type, {
getCustomHooks: () => [],
type,
});
}
},
getPendingUpdates: () => pendingUpdates,
flush: () => {
pendingUpdates = [];
},
replaceComponent,
sign,
computeKey,
};