#!/usr/bin/env node /** * check-tokens.js * * Counts hardcoded hex color literals in sx props / color attributes * across src/components and src/pages. Fails (exit 1) if count exceeds THRESHOLD. * * Usage: * node scripts/check-tokens.js — report + fail if > threshold * node scripts/check-tokens.js --report — report only, always exits 0 * * Run via: npm run check:tokens */ import { readdirSync, readFileSync, statSync } from 'node:fs' import { join, extname } from 'node:path' // Hex literals allowed before CI blocks the build. // This is a ratchet — lower it as migration progresses. Never raise it. // Baseline after initial token migration (2026-05-24): 1958 // Nach der Token-Migration aller Farb-Properties (bgcolor/color/borderColor/ // background/fill/stroke): 925. Die verbleibenden Treffer stehen in // Farbverläufen, `rgba()`-Werten, Icon-Attributen und Datentabellen, die diese // Zählung mitnimmt, die ESLint-Regel aber nicht erfasst. const THRESHOLD = 925 const HEX_PATTERN = /#[0-9A-Fa-f]{3,8}\b/g const SEARCH_DIRS = ['src/components', 'src/pages'] function walk(dir) { const files = [] for (const entry of readdirSync(dir, { withFileTypes: true })) { const full = join(dir, entry.name) if (entry.isDirectory()) files.push(...walk(full)) else if (entry.isFile() && ['.ts', '.tsx'].includes(extname(entry.name))) files.push(full) } return files } const reportOnly = process.argv.includes('--report') const cwd = process.cwd() let totalViolations = 0 const fileViolations = [] for (const searchDir of SEARCH_DIRS) { const dir = join(cwd, searchDir) for (const file of walk(dir)) { const content = readFileSync(file, 'utf8') const matches = content.match(HEX_PATTERN) if (matches && matches.length > 0) { totalViolations += matches.length fileViolations.push({ file: file.replace(cwd + '\\', '').replace(cwd + '/', ''), count: matches.length }) } } } fileViolations.sort((a, b) => b.count - a.count) console.log('\n── Token Compliance Check ───────────────────────────────────────────') console.log(`Total hex violations: ${totalViolations} (threshold: ${THRESHOLD})`) console.log(`Status: ${totalViolations <= THRESHOLD ? '✅ PASS' : '❌ FAIL'}`) console.log('\nTop 15 offenders:') fileViolations.slice(0, 15).forEach(({ file, count }) => { console.log(` ${count.toString().padStart(3)} ${file}`) }) console.log('─────────────────────────────────────────────────────────────────────\n') if (!reportOnly && totalViolations > THRESHOLD) { console.error(`Error: ${totalViolations} hex violations exceed threshold of ${THRESHOLD}.`) console.error('Run `node scripts/check-tokens.js --report` to see the full list.') process.exit(1) }