import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; const sourceRoot = path.resolve("src"); function sourceFiles(directory) { return fs.readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { const target = path.join(directory, entry.name); if (entry.isDirectory()) return sourceFiles(target); return /\.(tsx|ts)$/.test(entry.name) ? [target] : []; }); } const sources = sourceFiles(sourceRoot).map((file) => ({ file, value: fs.readFileSync(file, "utf8"), })); const nonSemanticClicks = sources.flatMap(({ file, value }) => [...value.matchAll(/<(div|span|li|tr)\b[^>]*\bonClick\s*=/g)].map( (match) => `${path.relative(sourceRoot, file)}:${match.index}`, ), ); assert.deepEqual( nonSemanticClicks, [], `Use a semantic button/link instead of clickable layout elements: ${nonSemanticClicks.join(", ")}`, ); const preview = fs.readFileSync( path.join(sourceRoot, "features/campaigns/components/MessagePreviewOverlay.tsx"), "utf8", ); for (const handler of ["onFirst", "onPrevious", "onNext", "onLast"]) { const buttonLine = preview .split("\n") .find((line) => line.includes(`