import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; const globalStylesUrl = new URL("../src/app/globals.css", import.meta.url); /** * Declaration text for every rule that targets `selector`. * * A selector is normally declared once at the base layer and again inside * media queries, so reading only the first occurrence reports whichever rule * happens to appear earliest in the file. That makes a positive assertion fail * when a responsive override is added above the base rule, and lets a negative * assertion pass while an override still declares the forbidden property. * Joining every matching rule keeps both directions honest. */ export function cssDeclarations(selector: string, source = readFileSync(globalStylesUrl, "utf8")) { // A comment sits between the previous rule and the selector it documents, so // it lands inside the captured selector text unless it is removed first. const withoutComments = source.replace(/\/\*[\s\S]*?\*\//g, " "); const normalize = (value: string) => value.trim().replace(/\s+/g, " "); // A caller may ask for a whole group, so any component counts as a hit. const wanted = selector.split(",").map(normalize).filter(Boolean); const bodies: string[] = []; for (const [, selectorList, body] of withoutComments.matchAll(/([^{}]+)\{([^{}]*)\}/g)) { const targets = selectorList.split(",").map(normalize); const hit = targets.some((target) => wanted.some( (value) => target === value || target.endsWith(` ${value}`), )); if (hit) bodies.push(body.trim()); } assert.notEqual(bodies.length, 0, `missing CSS selector: ${selector}`); return bodies.join(" "); }