// @ts-nocheck import { readdirSync, readFileSync, statSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; /** * The public route group installs a reduced catalogue (see * `publicClientMessages`). Anything a public page asks for must therefore live * outside the staff-only namespaces — a reference to one of them would silently * fall back to the raw key, so this is enforced here rather than discovered in * production. */ const SITE_DIR = join(process.cwd(), "src/app/(site)"); const STAFF_NAMESPACES = ['useTranslations("admin', 'getTranslations("admin']; function sourceFiles(dir: string): string[] { const out: string[] = []; for (const entry of readdirSync(dir)) { const full = join(dir, entry); if (statSync(full).isDirectory()) { out.push(...sourceFiles(full)); } else if (/\.(ts|tsx)$/.test(entry)) { out.push(full); } } return out; } describe("public client message scope", () => { it("the site route group has pages to check", () => { expect(sourceFiles(SITE_DIR).length).toBeGreaterThan(10); }); it("no public page reads a staff-only namespace", () => { const offenders: string[] = []; for (const file of sourceFiles(SITE_DIR)) { const src = readFileSync(file, "utf8"); for (const ns of STAFF_NAMESPACES) { // `pages.admin.*` is the second form; `admin.*` the first. for (const needle of [ `${ns})`, `${ns}.`, ns.replace("(admin", "(pages.admin"), ]) { if (src.includes(needle)) { offenders.push(`${file.replace(process.cwd(), "")}: ${needle}`); } } } } expect(offenders).toEqual([]); }); }); describe("publicClientMessages", () => { async function load() { const mod = await import("@/lib/i18n-client-messages"); return mod.publicClientMessages; } it("strips the staff-only namespaces", async () => { const publicClientMessages = await load(); const result = publicClientMessages({ admin: { title: "x" }, nav: { home: "Home" }, pages: { admin: { dashboard: "y" }, home: { title: "z" }, }, }); expect(result.admin).toBeUndefined(); expect(result.nav).toEqual({ home: "Home" }); expect(result.pages.admin).toBeUndefined(); expect(result.pages.home).toEqual({ title: "z" }); }); it("keeps every non-admin top-level namespace", async () => { const publicClientMessages = await load(); const en = JSON.parse( readFileSync(join(process.cwd(), "src/messages/en.json"), "utf8"), ); const result = publicClientMessages(en); for (const key of Object.keys(en)) { if (key === "admin") continue; expect(result[key]).toBeDefined(); } expect(result.pages.admin).toBeUndefined(); }); it("actually shrinks the catalogue", async () => { const publicClientMessages = await load(); const en = JSON.parse( readFileSync(join(process.cwd(), "src/messages/en.json"), "utf8"), ); const full = JSON.stringify(en).length; const scoped = JSON.stringify(publicClientMessages(en)).length; // The staff-tool namespaces dominate the file; without them the payload // should drop by well over half. expect(scoped).toBeLessThan(full * 0.5); }); it("does not mutate the input", async () => { const publicClientMessages = await load(); const en = JSON.parse( readFileSync(join(process.cwd(), "src/messages/en.json"), "utf8"), ); const before = JSON.stringify(en).length; publicClientMessages(en); expect(JSON.stringify(en).length).toBe(before); expect(en.pages.admin).toBeDefined(); }); });