/** * Guard (docs/04 §6, reviewer request): betting-game UI text must never look like real money. * Scans the betting games' screens and shared chip/card components for currency-like wording. */ import { expect, test } from 'bun:test'; import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; import { join } from 'node:path'; const ROOTS = ['games/poker', 'games/seotda', 'games/gostop', 'games/marble', 'games/las-vegas', 'components/cards'].map((p) => join(import.meta.dir, p)); const FORBIDDEN: [RegExp, string][] = [ [/₩|\$\s?\d|\d\s?\$/, '통화 기호'], [/\d[\d,]*\s*(만\s*)?원(?![가-힣])/, '"원" 단위'], [/판돈|돈을|돈이|돈은|현금|머니|골드/, '돈을 떠올리는 낱말'], [/충전|환전|입금|출금|송금|결제|구매/, '거래 낱말'], ]; function files(dir: string): string[] { if (!existsSync(dir)) return []; return readdirSync(dir).flatMap((f) => { const p = join(dir, f); return statSync(p).isDirectory() ? files(p) : /\.(tsx?|css)$/.test(f) ? [p] : []; }); } /** Only string literals / JSX text matter; comments are ignored. */ function visibleText(src: string): string { return src.replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|[^:])\/\/.*$/gm, '$1'); } test('no currency-like wording in betting game UI', () => { const problems: string[] = []; for (const f of ROOTS.flatMap(files)) { const text = visibleText(readFileSync(f, 'utf8')); text.split('\n').forEach((line, i) => { for (const [re, why] of FORBIDDEN) if (re.test(line)) problems.push(`${f.split('/src/')[1]}:${i + 1} ${why}: ${line.trim().slice(0, 80)}`); }); } expect(problems).toEqual([]); });