import fs from "node:fs"; import path from "node:path"; function getLastChar(input) { const t = (input || "").trim(); return t.length ? t[t.length - 1] : ""; } function evaluateDecision({ config, channel, senderId, content }) { if (config.enabled === false) { return { shouldUseNoReply: false, reason: "disabled" }; } const ch = (channel || "").toLowerCase(); if (config.discordOnly !== false && ch !== "discord") { return { shouldUseNoReply: false, reason: "non_discord" }; } if (senderId && (config.bypassUserIds || []).includes(senderId)) { return { shouldUseNoReply: false, reason: "bypass_sender" }; } const last = getLastChar(content || ""); if (last && (config.endSymbols || []).includes(last)) { return { shouldUseNoReply: false, reason: `end_symbol:${last}` }; } return { shouldUseNoReply: true, reason: "rule_match_no_end_symbol" }; } function shouldInjectEndMarker(reason) { return reason === "bypass_sender" || String(reason).startsWith("end_symbol:"); } const fixturePath = path.join(process.cwd(), "docs", "rule-cases.json"); const payload = JSON.parse(fs.readFileSync(fixturePath, "utf8")); let ok = true; for (const c of payload.cases || []) { const d = evaluateDecision({ config: payload.config, channel: c.channel, senderId: c.senderId, content: c.content, }); const inject = shouldInjectEndMarker(d.reason); const pass = d.shouldUseNoReply === c.expect.shouldUseNoReply && d.reason === c.expect.reason && inject === c.expect.injectEndMarker; if (!pass) { ok = false; console.error(`FAIL ${c.name}`); console.error(` got: ${JSON.stringify({ ...d, injectEndMarker: inject })}`); console.error(` expect: ${JSON.stringify(c.expect)}`); } else { console.log(`OK ${c.name}`); } } if (!ok) process.exit(1); console.log("all rule cases passed");