Files

17 lines
1.2 KiB
JavaScript

import {readFileSync,writeFileSync} from 'node:fs';
const tokens=JSON.parse(readFileSync(new URL('tokens.json',import.meta.url),'utf8'));
function luminance(hex){
if(!/^#[0-9a-f]{6}$/i.test(hex))throw new Error(`Expected opaque sRGB hex: ${hex}`);
const c=[1,3,5].map(i=>parseInt(hex.slice(i,i+2),16)/255).map(v=>v<=0.04045?v/12.92:((v+0.055)/1.055)**2.4);
return .2126*c[0]+.7152*c[1]+.0722*c[2];
}
const resolve=k=>tokens.color[k]??k;
const rows=tokens.contrastPairs.map(p=>{
const foreground=resolve(p.fg),background=resolve(p.bg),a=luminance(foreground),b=luminance(background);
const ratio=(Math.max(a,b)+.05)/(Math.min(a,b)+.05);
return {...p,foreground,background,ratio,pass:p.minimum===null?null:ratio>=p.minimum};
});
writeFileSync(new URL('contrast-audit.json',import.meta.url),JSON.stringify({method:'WCAG relative luminance, opaque sRGB; threshold checked without rounding; does not validate all composed/animated UI states',rows},null,2)+'\n');
console.table(rows.map(r=>({pair:r.name,foreground:r.foreground,background:r.background,ratio:r.ratio.toFixed(3),minimum:r.minimum,result:r.pass===null?'diagnostic':r.pass?'pass':'FAIL'})));
if(rows.some(r=>r.pass===false))process.exitCode=1;