Files
Dirigent/scripts/validate-rules.mjs

65 lines
1.8 KiB
JavaScript

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");