50 lines
2.3 KiB
JavaScript
50 lines
2.3 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
|
|
const styles = readFileSync(new URL("../src/styles.css", import.meta.url), "utf8");
|
|
|
|
function cssBlock(selector) {
|
|
const escapedSelector = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
const block = styles.match(new RegExp(`${escapedSelector}\\s*\\{([^}]+)\\}`))?.[1];
|
|
assert.ok(block, `Missing CSS token block ${selector}`);
|
|
return block;
|
|
}
|
|
|
|
function token(block, name) {
|
|
const value = block.match(new RegExp(`--${name}:\\s*(#[\\da-fA-F]{6})`))?.[1];
|
|
assert.ok(value, `Missing color token --${name}`);
|
|
return value;
|
|
}
|
|
|
|
function luminance(hex) {
|
|
const color = Number.parseInt(hex.slice(1), 16);
|
|
const channels = [(color >> 16) & 255, (color >> 8) & 255, color & 255].map((channel) => {
|
|
const srgb = channel / 255;
|
|
return srgb <= 0.04045 ? srgb / 12.92 : ((srgb + 0.055) / 1.055) ** 2.4;
|
|
});
|
|
return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2];
|
|
}
|
|
|
|
function contrastRatio(foreground, background) {
|
|
const foregroundLuminance = luminance(foreground);
|
|
const backgroundLuminance = luminance(background);
|
|
return (Math.max(foregroundLuminance, backgroundLuminance) + 0.05) /
|
|
(Math.min(foregroundLuminance, backgroundLuminance) + 0.05);
|
|
}
|
|
|
|
const dark = cssBlock(":root");
|
|
const darkFaint = token(dark, "text-faint");
|
|
const darkCardRatio = contrastRatio(darkFaint, token(dark, "n-02"));
|
|
const darkRaisedRatio = contrastRatio(darkFaint, token(dark, "n-03"));
|
|
assert.ok(darkCardRatio >= 4.5, `Dark faint text on --n-02 is ${darkCardRatio.toFixed(2)}:1`);
|
|
assert.ok(darkRaisedRatio >= 4.5, `Dark faint text on --n-03 is ${darkRaisedRatio.toFixed(2)}:1`);
|
|
|
|
const light = cssBlock(':root[data-theme="light"]');
|
|
const lightFaint = token(light, "text-faint");
|
|
const lightSurfaceRatio = contrastRatio(lightFaint, token(light, "n-01"));
|
|
const lightCardRatio = contrastRatio(lightFaint, token(light, "n-02"));
|
|
assert.ok(lightSurfaceRatio >= 4.5, `Light faint text on --n-01 is ${lightSurfaceRatio.toFixed(2)}:1`);
|
|
assert.ok(lightCardRatio >= 4.5, `Light faint text on --n-02 is ${lightCardRatio.toFixed(2)}:1`);
|
|
|
|
console.log(`Contrast token gate passed (dark ${darkCardRatio.toFixed(2)}:1/${darkRaisedRatio.toFixed(2)}:1; light ${lightSurfaceRatio.toFixed(2)}:1/${lightCardRatio.toFixed(2)}:1).`);
|