17 lines
1.2 KiB
JavaScript
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;
|