Restore the novel script's lost module-scope constants (#74)
novel-bookmark.user.js was split out of manga-bookmark.user.js and lost four constants: CACHE_KEY, LASTCHECKED_KEY, LATEST_CHECK_THROTTLE_MS and LATEST_CHECK_BATCH. Every use sits behind a try/catch or a fire-and-forget promise, so the ReferenceErrors were swallowed: backgroundRefreshLatest() threw before its first fetch, and the local cache silently read empty and never persisted. The issue named the two throttle constants; the cache keys are the same lost lines and are fixed here too. Add a static guard over both scripts, since no behavioural test can see a swallowed ReferenceError.
This commit is contained in:
@@ -25,6 +25,13 @@
|
||||
// This script owns the novel library; the manga script is a separate install
|
||||
// with its own prefix, so the two never share a cache, a queue or a panel.
|
||||
const STORE_PREFIX = "bmgr:novel:";
|
||||
const CACHE_KEY = STORE_PREFIX + "cache";
|
||||
|
||||
// Per-device record of when each series was last checked for new chapters.
|
||||
// Deliberately not synced: each device does its own checking.
|
||||
const LASTCHECKED_KEY = STORE_PREFIX + "lastchecked";
|
||||
const LATEST_CHECK_THROTTLE_MS = 4 * 60 * 60 * 1000;
|
||||
const LATEST_CHECK_BATCH = 1; // series fetched per navigation // series fetched per navigation
|
||||
|
||||
// Which library this script's rows belong to. The manga script is a separate
|
||||
// install that declares "manga"; the backend keeps whichever it is told.
|
||||
|
||||
@@ -165,3 +165,28 @@ test("kindOf defaults a missing kind to manga", () => {
|
||||
test("kindOf passes through novel", () => {
|
||||
assert.equal(kindOf({ kind: "novel" }), "novel");
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// Source guard
|
||||
//
|
||||
// Issue #74: the novel script was split off the manga one and lost four
|
||||
// module-scope constants. The reads sit inside try/catch or a fire-and-forget
|
||||
// promise, so the ReferenceError never surfaced — nothing but a static check
|
||||
// catches this class.
|
||||
// ============================================================
|
||||
|
||||
test("every SCREAMING_CASE constant the script uses is declared in it", () => {
|
||||
const fs = require("node:fs");
|
||||
for (const f of ["novel-bookmark.user.js", "manga-bookmark.user.js"]) {
|
||||
const src = fs.readFileSync(require.resolve("../" + f), "utf8")
|
||||
// comments and strings carry prose and SVG path data in the same shape
|
||||
.replace(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"[^"\n]*"|'[^'\n]*'|`[\s\S]*?`/g, " ");
|
||||
const declared = new Set(
|
||||
[...src.matchAll(/\b(?:const|let|var|function)\s+([A-Z][A-Z0-9_]{2,})\b/g)].map((m) => m[1]),
|
||||
);
|
||||
for (const name of new Set(src.match(/\b[A-Z][A-Z0-9_]{2,}\b/g) || [])) {
|
||||
if (name.startsWith("GM_") || name in globalThis) continue;
|
||||
assert.ok(declared.has(name), `${f} uses ${name} but never declares it`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user