Files

62 lines
2.2 KiB
JavaScript

// Appends a batch of new cards to a category file.
// node tools/add-cards.mjs <category> <batch.json>
// The batch is a JSON array of cards. Ids must be new across ALL card files, and every card's
// `category` must match. Existing cards are kept as they are. The file is rewritten in a compact
// layout (small objects on one line). Run `go test ./server` afterwards for the full validation.
import fs from "node:fs";
import { fileURLToPath } from "node:url";
import { format } from "./cardfmt.mjs";
const dir = fileURLToPath(new URL("../web/data/cards/", import.meta.url));
const [category, batchPath] = process.argv.slice(2);
if (!category || !batchPath) {
console.error("usage: node tools/add-cards.mjs <category> <batch.json>");
process.exit(2);
}
const manifest = JSON.parse(fs.readFileSync(dir + "index.json", "utf8")).files;
const file = `${category}.json`;
if (!manifest.includes(file)) {
console.error(`unknown category "${category}" (known: ${manifest.map((f) => f.replace(".json", "")).join(", ")})`);
process.exit(2);
}
const existing = {};
const used = new Set();
for (const f of manifest) {
existing[f] = JSON.parse(fs.readFileSync(dir + f, "utf8"));
for (const c of existing[f]) used.add(c.id);
}
let batch;
try {
batch = JSON.parse(fs.readFileSync(batchPath, "utf8"));
} catch (e) {
console.error(`cannot read the batch: ${e.message}`);
process.exit(1);
}
if (!Array.isArray(batch)) {
console.error("the batch must be a JSON array of cards");
process.exit(1);
}
const problems = [];
const seen = new Set();
for (const [i, c] of batch.entries()) {
const who = c?.id ?? `#${i}`;
if (!c?.id) problems.push(`${who}: missing id`);
else if (used.has(c.id) || seen.has(c.id)) problems.push(`${who}: id already exists`);
seen.add(c?.id);
if (c?.category !== category) problems.push(`${who}: category must be "${category}"`);
if (!c?.title || !c?.body || !c?.yes || !c?.no) problems.push(`${who}: needs title, body, yes and no`);
}
if (problems.length) {
console.error("batch rejected, nothing written:\n " + problems.join("\n "));
process.exit(1);
}
const all = [...existing[file], ...batch];
fs.writeFileSync(dir + file, `${format(all)}\n`);
console.log(`${file}: +${batch.length} cards, ${all.length} in total`);