feat(journal): seed declared variables on initialization
Implement `computeInitialValues` to calculate the starting state of declared variables and seed them into the journal stream store during the completions initialization process.
This commit is contained in:
parent
c9c977bee1
commit
a2d9605f4b
|
|
@ -151,4 +151,4 @@ function escapeAttr(s: string): string {
|
|||
.replace(/>/g, ">");
|
||||
}
|
||||
|
||||
export default ReactiveVariableManager;
|
||||
export default ReactiveVariableManager;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ import {
|
|||
} from "../../cli/completions/directive-scanner";
|
||||
import { parseDeclareCsv } from "./declare-parser";
|
||||
import type { VarDeclaration, TagModifier } from "./declare-parser";
|
||||
import { initReactivity } from "./var-reactivity";
|
||||
import { initReactivity, computeInitialValues } from "./var-reactivity";
|
||||
import { sendMessage, journalStreamState } from "../stores/journalStream";
|
||||
|
||||
export type { VarDeclaration, TagModifier };
|
||||
|
||||
|
|
@ -171,7 +172,10 @@ const _initPromise: Promise<void> = (async () => {
|
|||
const serverData = await tryServer();
|
||||
if (serverData) {
|
||||
setCompletionsState({ status: "loaded", data: serverData });
|
||||
try { initReactivity({ declarations: serverData.declarations, tagModifiers: serverData.tagModifiers }); } catch (e) { console.warn("[completions] reactivity init error:", e); }
|
||||
try {
|
||||
initReactivity({ declarations: serverData.declarations, tagModifiers: serverData.tagModifiers });
|
||||
seedDeclaredVariables();
|
||||
} catch (e) { console.warn("[completions] reactivity init error:", e); }
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +184,10 @@ const _initPromise: Promise<void> = (async () => {
|
|||
const data = await scanClientSide();
|
||||
if (data.dice.length > 0 || data.links.length > 0) {
|
||||
setCompletionsState({ status: "loaded", data });
|
||||
try { initReactivity({ declarations: data.declarations, tagModifiers: data.tagModifiers }); } catch (e) { console.warn("[completions] reactivity init error:", e); }
|
||||
try {
|
||||
initReactivity({ declarations: data.declarations, tagModifiers: data.tagModifiers });
|
||||
seedDeclaredVariables();
|
||||
} catch (e) { console.warn("[completions] reactivity init error:", e); }
|
||||
} else {
|
||||
setCompletionsState({ status: "empty" });
|
||||
}
|
||||
|
|
@ -230,4 +237,15 @@ export function useJournalCompletions(): {
|
|||
tagModifiers: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Seed declared variables into the store on load
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function seedDeclaredVariables(): void {
|
||||
const initial = computeInitialValues(journalStreamState.variables);
|
||||
for (const { key, value } of initial) {
|
||||
sendMessage("var", { action: "set", key, value });
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ export { parseDeclareCsv } from "./declare-parser";
|
|||
export type { VarDeclaration, TagModifier } from "./declare-parser";
|
||||
export { evaluateExpression, expressionIsTag } from "./variable-expression";
|
||||
export type { EvalContext, EvalResult } from "./variable-expression";
|
||||
export { initReactivity, computeCascade, computeActiveTags, extractDependencies } from "./var-reactivity";
|
||||
export { initReactivity, computeCascade, computeActiveTags, extractDependencies, computeInitialValues } from "./var-reactivity";
|
||||
export type { VarReactivityState, VariableStore } from "./var-reactivity";
|
||||
export { JournalContext, useJournalContext } from "./JournalContext";
|
||||
export type { JournalContextValue } from "./JournalContext";
|
||||
|
|
|
|||
|
|
@ -174,6 +174,49 @@ export function computeCascade(
|
|||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute initial values for all declared variables.
|
||||
* Called once after initReactivity() to seed the store.
|
||||
* Unset dependencies default to 0.
|
||||
*/
|
||||
export function computeInitialValues(
|
||||
currentVars: VariableStore,
|
||||
): Array<{ key: string; value: string }> {
|
||||
if (!declExprs) return [];
|
||||
|
||||
const allKeys = [...declExprs.keys()];
|
||||
const sorted = topoSortAffected(new Set(allKeys));
|
||||
|
||||
const results: Array<{ key: string; value: string }> = [];
|
||||
const localVars = { ...currentVars };
|
||||
|
||||
for (const key of sorted) {
|
||||
const expr = declExprs.get(key);
|
||||
if (!expr) continue;
|
||||
|
||||
try {
|
||||
const result = evaluateExpression(expr, {
|
||||
lookup: (name: string) => {
|
||||
const k = "$" + name;
|
||||
return localVars[k] ?? undefined;
|
||||
},
|
||||
});
|
||||
|
||||
const newValue = String(result.value);
|
||||
const finalValue = applyTagModifiersTo(key, newValue, localVars);
|
||||
|
||||
if (finalValue !== (localVars[key] ?? "")) {
|
||||
localVars[key] = finalValue;
|
||||
results.push({ key, value: finalValue });
|
||||
}
|
||||
} catch {
|
||||
// skip failed evaluations at init time
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute which tags are active given the current variable store.
|
||||
* A tag is active if any variable has that tag as its value.
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ function parseFactor(
|
|||
const varName = tok.value; // includes $ prefix
|
||||
const resolved = ctx.lookup(varName.slice(1)); // strip $ for lookup
|
||||
if (resolved === undefined) {
|
||||
throw new Error(`Unknown variable: ${varName}`);
|
||||
return { value: 0, next: pos + 1 };
|
||||
}
|
||||
// Tag values cannot be used in arithmetic
|
||||
if (resolved.startsWith("#")) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue