7934da7669
Token infrastructure (src/lib/ds.ts): - DS_TEXT: 16 semantic text color tokens (primary/secondary/muted/success/ warning/error/info/brand/signal + dark variants successDark/warningDark/ signalDark/infoDark for text on tinted surfaces) - DS_BG: page/surface/subtle/muted background tokens - DS_BORDER: default/muted/strong border tokens - DS_SURFACE: 10 bg+border surface pairs (success/warning/error/info/indigo/ purple/orange/blue/neutral/slate) - DS_MATCH_TIER: score-tier surface aliases keyed by strong/moderate/weak - DS_PRE_MARKET / DS_MARKET_SIGNAL: named aliases for futureCard tokens - DS_SHADOW: card/panel/dialog elevation tokens - BADGE_COLORS: 14 semantic presets for GenericBadge (confidenceHigh, riskMedium, preMarket, marketSignal, verified, gold, silver, bronze…) GenericBadge (src/components/shared/GenericBadge.tsx): - New semanticVariant prop (keyof BADGE_COLORS) — preferred over raw hex - color prop becomes optional (fallback), type-documented as escape hatch Priority file migrations — 237 hex literals replaced across 10 files: ScoreBreakdownPanel.tsx −22 PipelineDetailPanel.tsx −22 FutureAvailabilityCard.tsx −26 AICompareSummary.tsx −27 LocationIntelligencePanel −39 AssistantPromptSuggestions −18 UnitStructurePanel.tsx −25 BerichtDialog.tsx −24 PreMarketPanel.tsx −24 PropertyActivityLogPanel −10 ESLint (eslint.config.js): - Updated rule message to reference new tokens (DS_TEXT, DS_SURFACE, etc.) - Added 'stroke' to monitored property names - Remains 'warn' for gradual migration; use check:tokens for CI gate CI script (scripts/check-tokens.js + npm run check:tokens): - Counts hex patterns in components/ + pages/ - Fails if count > THRESHOLD (ratchet: 1958 baseline, lower per sprint) - Reports top 15 offenders for prioritizing next migration batch Results: ESLint targeted sx-prop violations: 1752 → 1030 (−41%) 0 TypeScript errors, 154 tests green Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
71 lines
2.6 KiB
JavaScript
71 lines
2.6 KiB
JavaScript
#!/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
|
|
const THRESHOLD = 1958
|
|
|
|
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)
|
|
}
|