/** * semantic.ts self-test. 该模块必须零 import(Node 原生类型剥离直连 .ts, * 同 tests/terminal-cwd.mjs 的约束)。锁三件事: * 1) isLightTheme 边界(>0.5 亮度为浅); * 2) 深色分支 = SEMANTIC 锚点原值(零回归锁定); * 3) 浅色分支全部达标:正文/fg ≥4.5,语义基色 ≥3.0。 * Run: node tests/semantic-theme.mjs (must exit 0) */ import { isLightTheme, semanticVars, SEMANTIC } from '../src/renderer/src/theme/semantic.ts' let failed = 0 const ok = (cond, msg) => { console.log(` ${cond ? 'ok' : 'FAIL'}: ${msg}`) if (!cond) failed += 1 } console.log('isLightTheme:') ok(isLightTheme('#ffffff') === true, '#ffffff is light') ok(isLightTheme('#fafafa') === true, '#fafafa is light') ok(isLightTheme('#fdf6e3') === true, '#fdf6e3 is light') ok(isLightTheme('#1e1e1e') === false, '#1e1e1e is dark') ok(isLightTheme('#282a36') === false, '#282a36 is dark') console.log('dark branch locks anchors (zero regression):') const dark = semanticVars({ background: '#1e1e1e', foreground: '#cccccc' }, false) ok(dark['--ot-text-muted'] === SEMANTIC.muted, '--ot-text-muted = anchor') ok(dark['--ot-success'] === SEMANTIC.success, '--ot-success = anchor') ok(dark['--ot-danger'] === SEMANTIC.danger, '--ot-danger = anchor') ok(dark['--ot-warning'] === SEMANTIC.warning, '--ot-warning = anchor') ok(dark['--ot-info'] === SEMANTIC.info, '--ot-info = anchor') ok(dark['--ot-scrollbar'] === SEMANTIC.scrollbar, '--ot-scrollbar = anchor') ok(dark['--ot-shadow'] === SEMANTIC.shadow, '--ot-shadow = anchor') ok(dark['color-scheme'] === 'dark', 'color-scheme dark') console.log('light branch meets ratios:') for (const bg of ['#f6f8fa', '#fafafa', '#fdf6e3']) { const v = semanticVars({ background: bg, foreground: '#383a42' }, true) const L = (h) => { const c = [1, 3, 5].map((i) => parseInt(h.slice(i, i + 2), 16) / 255) .map((s) => (s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4)) return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2] } const cr = (a, b) => { const x = L(a), y = L(b) return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05) } for (const key of ['--ot-text-muted', '--ot-text-secondary', '--ot-success-fg', '--ot-danger-fg', '--ot-warning-fg', '--ot-info-fg']) { ok(cr(v[key], bg) >= 4.5, `${bg} ${key} ${v[key]} >= 4.5 (${cr(v[key], bg).toFixed(2)})`) } for (const key of ['--ot-success', '--ot-danger', '--ot-warning', '--ot-info']) { ok(cr(v[key], bg) >= 3, `${bg} ${key} ${v[key]} >= 3.0 (${cr(v[key], bg).toFixed(2)})`) } ok(v['color-scheme'] === 'light', `${bg} color-scheme light`) } if (failed > 0) { console.error(`${failed} check(s) failed`) process.exit(1) } console.log('semantic-theme: all ok')