Implement the 031-quality-gates-hygiene feature that strengthens automated quality gates by adding pnpm audit to the check script, v8 coverage thresholds with per-directory auto-ratchet (domain 96%, adapters 71%, persistence 87%), Biome cognitive complexity enforcement (max 15), and keyboard accessibility for the combatant row, while cleaning up all blanket biome-ignore comments, refactoring 5 overly complex functions into smaller helpers, and codifying the early-enforcement principle in the constitution and CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-11 00:52:29 +01:00
parent 47da942b73
commit 69363d4f7d
19 changed files with 1265 additions and 163 deletions

View File

@@ -18,6 +18,76 @@ export function saveEncounter(encounter: Encounter): void {
}
}
function validateAc(value: unknown): number | undefined {
return typeof value === "number" && Number.isInteger(value) && value >= 0
? value
: undefined;
}
function validateConditions(value: unknown): ConditionId[] | undefined {
if (!Array.isArray(value)) return undefined;
const valid = value.filter(
(v): v is ConditionId =>
typeof v === "string" && VALID_CONDITION_IDS.has(v),
);
return valid.length > 0 ? valid : undefined;
}
function validateCreatureId(value: unknown) {
return typeof value === "string" && value.length > 0
? creatureId(value)
: undefined;
}
function validateHp(
rawMaxHp: unknown,
rawCurrentHp: unknown,
): { maxHp: number; currentHp: number } | undefined {
if (
typeof rawMaxHp !== "number" ||
!Number.isInteger(rawMaxHp) ||
rawMaxHp < 1
) {
return undefined;
}
const validCurrentHp =
typeof rawCurrentHp === "number" &&
Number.isInteger(rawCurrentHp) &&
rawCurrentHp >= 0 &&
rawCurrentHp <= rawMaxHp;
return {
maxHp: rawMaxHp,
currentHp: validCurrentHp ? rawCurrentHp : rawMaxHp,
};
}
function rehydrateCombatant(c: unknown) {
const entry = c as Record<string, unknown>;
const base = {
id: combatantId(entry.id as string),
name: entry.name as string,
initiative:
typeof entry.initiative === "number" ? entry.initiative : undefined,
};
const shared = {
...base,
ac: validateAc(entry.ac),
conditions: validateConditions(entry.conditions),
isConcentrating: entry.isConcentrating === true ? true : undefined,
creatureId: validateCreatureId(entry.creatureId),
};
const hp = validateHp(entry.maxHp, entry.currentHp);
return hp ? { ...shared, ...hp } : shared;
}
function isValidCombatantEntry(c: unknown): boolean {
if (typeof c !== "object" || c === null || Array.isArray(c)) return false;
const entry = c as Record<string, unknown>;
return typeof entry.id === "string" && typeof entry.name === "string";
}
export function loadEncounter(): Encounter | null {
try {
const raw = localStorage.getItem(STORAGE_KEY);
@@ -45,82 +115,9 @@ export function loadEncounter(): Encounter | null {
};
}
for (const c of combatants) {
if (typeof c !== "object" || c === null || Array.isArray(c)) return null;
const entry = c as Record<string, unknown>;
if (typeof entry.id !== "string") return null;
if (typeof entry.name !== "string") return null;
}
if (!combatants.every(isValidCombatantEntry)) return null;
const rehydrated = combatants.map((c) => {
const entry = c as Record<string, unknown>;
const base = {
id: combatantId(entry.id as string),
name: entry.name as string,
initiative:
typeof entry.initiative === "number" ? entry.initiative : undefined,
};
// Validate AC field
const ac = entry.ac;
const validAc =
typeof ac === "number" && Number.isInteger(ac) && ac >= 0
? ac
: undefined;
// Validate conditions field
const rawConditions = entry.conditions;
const validConditions: ConditionId[] | undefined = Array.isArray(
rawConditions,
)
? (rawConditions.filter(
(v): v is ConditionId =>
typeof v === "string" && VALID_CONDITION_IDS.has(v),
) as ConditionId[])
: undefined;
const conditions =
validConditions && validConditions.length > 0
? validConditions
: undefined;
// Validate isConcentrating field
const isConcentrating = entry.isConcentrating === true ? true : undefined;
// Validate creatureId field
const rawCreatureId = entry.creatureId;
const validCreatureId =
typeof rawCreatureId === "string" && rawCreatureId.length > 0
? creatureId(rawCreatureId)
: undefined;
// Validate and attach HP fields if valid
const maxHp = entry.maxHp;
const currentHp = entry.currentHp;
if (typeof maxHp === "number" && Number.isInteger(maxHp) && maxHp >= 1) {
const validCurrentHp =
typeof currentHp === "number" &&
Number.isInteger(currentHp) &&
currentHp >= 0 &&
currentHp <= maxHp;
return {
...base,
ac: validAc,
conditions,
isConcentrating,
creatureId: validCreatureId,
maxHp,
currentHp: validCurrentHp ? currentHp : maxHp,
};
}
return {
...base,
ac: validAc,
conditions,
isConcentrating,
creatureId: validCreatureId,
};
});
const rehydrated = combatants.map(rehydrateCombatant);
const result = createEncounter(
rehydrated,