Files
Voiced/src/pdf/templates/slots.lint.test.ts
T
xavierk 9de9a6ffee Add Ledger and Band template families with decor primitives
Crimson Grid, Tangerine Ledger, Slate Band and Teal Swoosh are rebuilt from
the reference PDFs with grid and band tables that survive page breaks,
full-bleed fixed bands, pennant tabs, gradient corner swooshes with
keep-outs, Carbon icon circles, and the user's logo in the measured slot
(knockout or white chip on the dark Slate band). Adds static Poppins
500-700 and Inter fonts. Thumbnails regenerated for all eight templates;
the item-count sweeps run in their own test file.
2026-10-04 08:34:18 +05:30

52 lines
1.7 KiB
TypeScript

import { readdirSync, readFileSync, statSync } from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
const ROOT = process.cwd();
const TEMPLATES_DIR = path.join(ROOT, "src/pdf/templates");
/**
* Model fields that carry regulated data. Templates must not read them: the data may leave the model
* only through the Slot components, so the contract test can see every place it is printed.
*/
const REGULATED = [
/\.gstin\b/,
/\.showGstin\b/,
/\.posLabel\b/,
/\.hsnSac\b/,
/\.taxRows\b/,
/\.amountInWords\b/,
/\.reverseCharge\b/,
/\.signature\b/,
/\.slots\b/,
];
function sources(dir: string): string[] {
return readdirSync(dir).flatMap((name) => {
const full = path.join(dir, name);
if (statSync(full).isDirectory()) return sources(full);
return /\.(ts|tsx)$/.test(name) && !/\.test\.|harness(\.check)?\.ts$/.test(name) ? [full] : [];
});
}
describe("templates read regulated data only through Slot.*", () => {
it("scans the classic template", () => {
expect(sources(TEMPLATES_DIR).some((f) => f.endsWith("classic/Layout.tsx"))).toBe(true);
});
it("finds no direct access to the regulated model fields", () => {
const hits: string[] = [];
for (const file of sources(TEMPLATES_DIR)) {
readFileSync(file, "utf8")
.split("\n")
.forEach((line, i) => {
if (/^\s*(\/\/|\*|\/\*)/.test(line)) return;
// The slot API itself is the sanctioned way in: Slot.TaxRows, slotHeights.amountInWords, ...
const code = line.replace(/\b(Slot|slotHeights)\.\w+/g, "");
for (const re of REGULATED) if (re.test(code)) hits.push(`${path.relative(ROOT, file)}:${i + 1} ${line.trim()}`);
});
}
expect(hits).toEqual([]);
});
});