import { readdirSync, readFileSync } from "node:fs"; import { describe, expect, it } from "vitest"; // DESIGN "A glyph means one thing": a menu row wears the glyph its action wears everywhere else. The // "…" menus' Play from the beginning wore the skip arrow ⏮, which beside the player is Previous, while // the card's own Restart wore RotateCcw — and RotateCcw was the same menu's Reset, the Files menu's // Redownload. Each row is a `label: t("…")` followed by its `icon`. const ROW_GLYPHS: Record = { "card.restartTitle": "RotateCcw", "card.resetState": "Eraser", "files.actions.redownload": "RefreshCw", }; const root = new URL("../", import.meta.url); const sources = () => readdirSync(root, { recursive: true, encoding: "utf8" }) .map((f) => f.replace(/\\/g, "/")) .filter((f) => /\.tsx?$/.test(f) && !f.includes(".test.") && !f.startsWith("design-lab/")) .map((f) => ({ f, src: readFileSync(new URL(f, root), "utf8") })); describe("a menu row's glyph", () => { for (const [key, glyph] of Object.entries(ROW_GLYPHS)) it(`${key} wears ${glyph}`, () => { const row = new RegExp( `label: t\\("${key.replace(/\./g, "\\.")}"\\),\\s*icon: (?:<|icon\\()(\\w+)`, "g", ); const worn = sources().flatMap(({ f, src }) => [...src.matchAll(row)].map((m) => `${f}: ${m[1]}`), ); expect(worn.length, key).toBeGreaterThan(0); expect(worn.filter((w) => !w.endsWith(`: ${glyph}`))).toEqual([]); }); });