fix(01-02): TS-strict narrowing for EvalResult discriminated union
Rule 1 deviation: TS strict mode (noImplicitAny + strict) couldn't narrow
the EvalResult union via 'r.ok' direct access because the {unknown:true,raw}
variant has no 'ok' property. Added explicit type-guard helpers (isUnknown,
isOk, isFail) for both production and spec narrowing. Runtime behavior
unchanged; tsc --noEmit now exits clean for the leveling lib.
Files:
- prereq-evaluator.ts: 3 type-guard functions, used in OR/AND walkers
- prereq-evaluator.spec.ts: isFail() in lieu of result.ok=== checks
This commit is contained in:
@@ -291,6 +291,18 @@ type NodeResult =
|
||||
| { ok: false; reason: string }
|
||||
| { unknown: true; raw: string };
|
||||
|
||||
function isUnknown(r: NodeResult): r is { unknown: true; raw: string } {
|
||||
return 'unknown' in r;
|
||||
}
|
||||
|
||||
function isOk(r: NodeResult): r is { ok: true } {
|
||||
return 'ok' in r && r.ok === true;
|
||||
}
|
||||
|
||||
function isFail(r: NodeResult): r is { ok: false; reason: string } {
|
||||
return 'ok' in r && r.ok === false;
|
||||
}
|
||||
|
||||
function evaluateNode(node: Node, ctx: CharacterContext, raw: string): NodeResult {
|
||||
if (node.kind === 'atom') {
|
||||
return evaluateAtom(node.atom, ctx);
|
||||
@@ -300,12 +312,12 @@ function evaluateNode(node: Node, ctx: CharacterContext, raw: string): NodeResul
|
||||
let firstFailReason: string | null = null;
|
||||
for (const child of node.children) {
|
||||
const r = evaluateNode(child, ctx, raw);
|
||||
if ('unknown' in r && r.unknown) {
|
||||
if (isUnknown(r)) {
|
||||
// UNKNOWN-aggressive: any unknown atom poisons the whole prereq.
|
||||
return { unknown: true, raw };
|
||||
}
|
||||
if (r.ok) return { ok: true };
|
||||
if (firstFailReason === null && !r.ok) {
|
||||
if (isOk(r)) return { ok: true };
|
||||
if (firstFailReason === null && isFail(r)) {
|
||||
firstFailReason = r.reason;
|
||||
}
|
||||
}
|
||||
@@ -318,10 +330,10 @@ function evaluateNode(node: Node, ctx: CharacterContext, raw: string): NodeResul
|
||||
// AND
|
||||
for (const child of node.children) {
|
||||
const r = evaluateNode(child, ctx, raw);
|
||||
if ('unknown' in r && r.unknown) {
|
||||
if (isUnknown(r)) {
|
||||
return { unknown: true, raw };
|
||||
}
|
||||
if (!r.ok) return r;
|
||||
if (isFail(r)) return r;
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user