49 lines
4.7 KiB
Python
49 lines
4.7 KiB
Python
# mutate.py <id>: apply one named mutant to the candidate (exact text, must match once). Run from the tree root.
|
||
import sys
|
||
B, A, C, S, H = "packages/webui/src/public/bus.js", "packages/webui/src/public/app.js", "packages/webui/src/public/shell.css", "packages/webui/src/serve.mjs", "packages/webui/src/public/index.html"
|
||
M = {
|
||
"M01": [(B, "err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);", "err.status === 403;")],
|
||
"M02": [(A, "const refused = err.status === 403;", "const refused = false;")],
|
||
"M03": [(A, "document.body.classList.toggle('board-refused', refused);", "")],
|
||
"M04": [(B, "<b>refused: <code>${txt(err.code)}</code>.</b> ", "<b>refused: ${txt(err.code)}.</b> ")],
|
||
"M05": [(B, "${state === 'stale' ? ' · <span class=\"warn\">stale: the last read failed</span>' : ''}", "")],
|
||
"M06": [(A, "if (mode === 'system') delete document.documentElement.dataset.mode; else document.documentElement.dataset.mode = mode;", "document.documentElement.dataset.mode = mode;")],
|
||
"M07": [(B, "t.innerHTML = `<span>${esc(text)}</span>", "t.innerHTML = `<span>${text}</span>")],
|
||
"M08": [(B, "<span>${txt(i.label)}</span><span class=\"g\">", "<span>${i.label}</span><span class=\"g\">")],
|
||
"M09": [(C, ":focus-visible{outline:2px solid var(--focus);outline-offset:2px}", ":focus-visible{outline:2px solid var(--focus);outline-offset:0}")],
|
||
"M10": [(C, ":focus-visible{outline:2px solid var(--focus);outline-offset:2px}", ":focus-visible{outline:1px solid var(--focus);outline-offset:2px}")],
|
||
"M11": [(C, " .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:auto;", " .s1-sections{display:flex;flex-wrap:wrap;overflow-x:visible;")],
|
||
"M21": [(B, "function forget() { last.clear(); inboxCount = null; }", "function forget() {}")],
|
||
"M22": [(B, "catch (err) { if (refusal(err)) { forget(); if (g === gen) sections(path); } }", "catch {}")],
|
||
"M23": [(B, " if (refusal(err)) forget();\n", "")],
|
||
"M24": [(B, "if (rs.some(r => r.status === 'rejected' && refusal(r.reason))) { forget(); sections(routeOf().split('?')[0]); }", "")],
|
||
"M25": [(A, "data = null; selected = null; project = null;", "data = null; project = null;")],
|
||
"M26": [(A, "failed === 'refused' ? 'Board <span class=\"warn\">not read: refused</span>' : ", "")],
|
||
"M27": [(A, " $('footer').textContent = 'Board not read: refused';\n", "")],
|
||
"M28": [(A, " $('status').textContent = 'Not read: the board refused the read';\n", "")],
|
||
"M29": [(A, " $('projects').innerHTML = '<p class=\"muted\">Not read: the board refused the read.</p>';\n", "")],
|
||
"M30": [(A, " for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–';\n", "")],
|
||
"M31": [(B, "state === 'refused' ? 'Bus <span class=\"warn\">not read: refused</span>' : ", "")],
|
||
"M32": [(C, ".toast:not(.on){width:1px;height:1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;box-shadow:none}", ".toast:not(.on){display:none}")],
|
||
"M33": [(B, "function forget() { last.clear(); inboxCount = null; }", "function forget() { last.clear(); }")],
|
||
"M34": [(B, "function forget() { last.clear(); inboxCount = null; }", "function forget() { inboxCount = null; }")],
|
||
"M35": [(A, "`${new Date(at).toISOString().slice(11, 19)} UTC`", "new Date(at).toLocaleTimeString([], { hour12: false })")],
|
||
"M36": [(C, " .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:auto;", " .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:visible;")],
|
||
"M37": [(C, " .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:auto;", " .s1-sections{display:flex;flex-wrap:wrap;overflow-x:auto;")],
|
||
"M12": [(B, "<svg class=\"i\" aria-hidden=\"true\"><use href=\"/icons.svg#i-${icon}\"/></svg>", "")],
|
||
"M13": [(A, " $('board-refused').hidden = true; document.body.classList.remove('board-refused');\n", "")],
|
||
"M14": [(B, "links[i + (e.key === 'ArrowDown' ? 1 : -1)]?.focus();", "links[i + (e.key === 'ArrowDown' ? -1 : 1)]?.focus();")],
|
||
"M15": [(S, "['/icons.svg', ['icons.svg', 'image/svg+xml']],", "['/icons.svg', ['icons.svg', 'text/plain']],")],
|
||
"M16": [(C, ".count,td,.s1-twhen,time,.fresh,.kv dd{font-variant-numeric:tabular-nums}", "")],
|
||
"M17": [(A, "try { localStorage.setItem('mosaic-console-appearance',", "try { localStorage.setItem('mosaic-console-look',")],
|
||
"M18": [(C, "body.board-refused #board-view{display:none}", "")],
|
||
"M19": [(B, "if (refusal(err)) throw err; html = await view(kept,", "html = await view(kept,")],
|
||
"M20": [(A, "$('error').className = refused ? 'banner ref' : 'banner err';", "$('error').className = 'banner err';")],
|
||
}
|
||
for f, old, new in M[sys.argv[1]]:
|
||
s = open(f).read()
|
||
n = s.count(old)
|
||
if n != 1: sys.exit(f"{sys.argv[1]}: {n} matches in {f}")
|
||
open(f, "w").write(s.replace(old, new))
|
||
print(sys.argv[1], "applied")
|