fix(journal): re-init reactivity and drop var del
Make the reactivity engine re-initialize when the loaded declarations change instead of only at import. ensureReactivity() reads the live completions signal, compares a signature, and rebuilds from the store (with exact bases) only when needed; dispatchCommand calls it before each dispatch. Remove the unused DispatchContext.declarations/tagModifiers fields, which were mount-time snapshots and could not be trusted. Build initReactivity's maps into locals and commit only after the circular check passes, so a failed re-init leaves the previous engine intact; clear inFlight on commit. Drop the unreachable var "del" action from the schema, render, and reducer.
This commit is contained in:
@@ -216,44 +216,46 @@ export function onReactivityDiagnostics(
|
||||
* Initialize (or re-initialize) the reactivity engine from declarations
|
||||
* and tag modifiers parsed from role=declare blocks.
|
||||
*
|
||||
* The new state is built into locals and only committed once validation
|
||||
* passes, so a throw (e.g. a circular dependency) leaves the previously
|
||||
* initialized engine intact rather than half-populated.
|
||||
*
|
||||
* Throws if a circular dependency is detected.
|
||||
*/
|
||||
export function initReactivity(state: VarReactivityState): void {
|
||||
depGraph = new Map();
|
||||
declExprs = new Map();
|
||||
tagModMap = new Map();
|
||||
baseValues.clear();
|
||||
numericMods.clear();
|
||||
tagMapMods.clear();
|
||||
sourceActivations.clear();
|
||||
clearReactivityDiagnostics();
|
||||
const nextTagModMap = new Map<
|
||||
string,
|
||||
Array<{ target: string; expression: string; threshold: number }>
|
||||
>();
|
||||
const nextDeclExprs = new Map<string, string>();
|
||||
const nextDepGraph = new Map<string, Set<string>>();
|
||||
|
||||
// Index tag modifiers
|
||||
for (const tm of state.tagModifiers) {
|
||||
let list = tagModMap.get(tm.tag);
|
||||
let list = nextTagModMap.get(tm.tag);
|
||||
if (!list) {
|
||||
list = [];
|
||||
tagModMap.set(tm.tag, list);
|
||||
nextTagModMap.set(tm.tag, list);
|
||||
}
|
||||
list.push({ target: tm.target, expression: tm.expression, threshold: tm.threshold });
|
||||
}
|
||||
|
||||
// Index declarations and build dependency graph
|
||||
for (const decl of state.declarations) {
|
||||
declExprs.set(decl.key, decl.expression);
|
||||
nextDeclExprs.set(decl.key, decl.expression);
|
||||
const deps = extractDependencies(decl.expression);
|
||||
for (const dep of deps) {
|
||||
let dependents = depGraph.get(dep);
|
||||
let dependents = nextDepGraph.get(dep);
|
||||
if (!dependents) {
|
||||
dependents = new Set();
|
||||
depGraph.set(dep, dependents);
|
||||
nextDepGraph.set(dep, dependents);
|
||||
}
|
||||
dependents.add(decl.key);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
checkCircular();
|
||||
checkCircular(nextDeclExprs);
|
||||
} catch (e) {
|
||||
reportDiagnostic({
|
||||
kind: "init",
|
||||
@@ -261,6 +263,17 @@ export function initReactivity(state: VarReactivityState): void {
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Validation passed — commit the new configuration and reset runtime state.
|
||||
depGraph = nextDepGraph;
|
||||
declExprs = nextDeclExprs;
|
||||
tagModMap = nextTagModMap;
|
||||
baseValues.clear();
|
||||
numericMods.clear();
|
||||
tagMapMods.clear();
|
||||
sourceActivations.clear();
|
||||
inFlight.clear();
|
||||
clearReactivityDiagnostics();
|
||||
}
|
||||
|
||||
/** Extract $var names from an expression string. */
|
||||
@@ -789,10 +802,8 @@ function topoSortAffected(affected: Set<string>): string[] {
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkCircular(): void {
|
||||
if (!declExprs) return;
|
||||
|
||||
const allKeys = [...declExprs.keys()];
|
||||
function checkCircular(exprs: Map<string, string>): void {
|
||||
const allKeys = [...exprs.keys()];
|
||||
const state = new Map<string, "unvisited" | "visiting" | "visited">();
|
||||
for (const k of allKeys) state.set(k, "unvisited");
|
||||
|
||||
@@ -812,11 +823,11 @@ function checkCircular(): void {
|
||||
state.set(key, "visiting");
|
||||
path.push(key);
|
||||
|
||||
const expr = declExprs!.get(key);
|
||||
const expr = exprs.get(key);
|
||||
if (expr) {
|
||||
const deps = extractDependencies(expr);
|
||||
for (const dep of deps) {
|
||||
if (declExprs!.has(dep)) {
|
||||
if (exprs.has(dep)) {
|
||||
dfs(dep);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user