fix(journal): unify $var lookup and error
EvalContext.lookup now receives the full $var name, matching getCombined, setBase, and getMods, and parseFactor throws "Unknown variable" when the lookup returns undefined. /set and /roll use the new resolveVariable() so a typo errors instead of silently evaluating to 0. Declarations and tag modifiers stay lenient (unknown -> 0): the documented $hp = $con*5+$mod_hp pattern depends on external/undeclared variables defaulting to 0.
This commit is contained in:
@@ -41,6 +41,7 @@ import {
|
||||
extractDependencies,
|
||||
rebuildReactivityFromStore,
|
||||
getReactivityDiagnostics,
|
||||
resolveVariable,
|
||||
} from "../../components/journal/var-reactivity";
|
||||
import { parseInput } from "../../components/journal/command-parser";
|
||||
import {
|
||||
@@ -273,32 +274,31 @@ describe("evaluateExpression", () => {
|
||||
test("evaluates variable references", () => {
|
||||
const result = evaluateExpression("$con * 5 + $mod_hp", {
|
||||
lookup: (name) => {
|
||||
if (name === "con") return "12";
|
||||
if (name === "mod_hp") return "20";
|
||||
if (name === "$con") return "12";
|
||||
if (name === "$mod_hp") return "20";
|
||||
return undefined;
|
||||
},
|
||||
});
|
||||
expect(result.value).toEqual({ kind: "number", value: 80 }); // 12*5 + 20
|
||||
});
|
||||
|
||||
test("returns 0 for undefined variables", () => {
|
||||
const result = evaluateExpression("$unknown + 5", {
|
||||
lookup: () => undefined,
|
||||
});
|
||||
expect(result.value).toEqual({ kind: "number", value: 5 });
|
||||
test("throws on unknown variables", () => {
|
||||
expect(() =>
|
||||
evaluateExpression("$unknown + 5", { lookup: () => undefined }),
|
||||
).toThrow("Unknown variable: $unknown");
|
||||
});
|
||||
|
||||
test("throws on type mismatch (tagmap + number)", () => {
|
||||
expect(() =>
|
||||
evaluateExpression("$class + 5", {
|
||||
lookup: (name) => (name === "class" ? "#warrior" : undefined),
|
||||
lookup: (name) => (name === "$class" ? "#warrior" : undefined),
|
||||
}),
|
||||
).toThrow("Type mismatch");
|
||||
});
|
||||
|
||||
test("resolves tagmap variable without arithmetic", () => {
|
||||
const result = evaluateExpression("$class", {
|
||||
lookup: (name) => (name === "class" ? "#warrior:1" : undefined),
|
||||
lookup: (name) => (name === "$class" ? "#warrior:1" : undefined),
|
||||
});
|
||||
expect(result.value).toEqual({ kind: "tagmap", value: { "#warrior": 1 } });
|
||||
});
|
||||
@@ -422,8 +422,8 @@ describe("evaluateExpression", () => {
|
||||
test("complex expression with variables and functions", () => {
|
||||
const result = evaluateExpression("floor($con / 2) + $mod", {
|
||||
lookup: (name) => {
|
||||
if (name === "con") return "15";
|
||||
if (name === "mod") return "3";
|
||||
if (name === "$con") return "15";
|
||||
if (name === "$mod") return "3";
|
||||
return undefined;
|
||||
},
|
||||
});
|
||||
@@ -742,6 +742,25 @@ describe("var-reactivity", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveVariable", () => {
|
||||
test("returns undefined for unknown variables", () => {
|
||||
initReactivity({ declarations: [], tagModifiers: [] });
|
||||
expect(resolveVariable("$nope")).toBeUndefined();
|
||||
expect(resolveVariable("$nope", {})).toBeUndefined();
|
||||
});
|
||||
|
||||
test("returns a real 0 rather than undefined", () => {
|
||||
initReactivity({ declarations: [], tagModifiers: [] });
|
||||
setBase("$zero", "0");
|
||||
expect(resolveVariable("$zero")).toBe("0");
|
||||
});
|
||||
|
||||
test("resolves keys present only in the fallback store", () => {
|
||||
initReactivity({ declarations: [], tagModifiers: [] });
|
||||
expect(resolveVariable("$hp", { $hp: "12" })).toBe("12");
|
||||
});
|
||||
});
|
||||
|
||||
describe("rebuildReactivityFromStore", () => {
|
||||
test("restores bases exactly without double-counting modifiers", () => {
|
||||
initReactivity({
|
||||
|
||||
Reference in New Issue
Block a user