import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { join, resolve } from "node:path"; import test from "node:test"; const root = resolve(import.meta.dirname, ".."); const read = (path) => readFileSync(join(root, path), "utf8"); /** * The radius and colour names a stylesheet gives Tailwind (`--radius-*` and * `--color-*`), as the utilities use them: `rounded-nav-item`, and * `nav-item-active` for bg-, text-, border- and ring-. */ function themeNames(path) { const radius = new Set(); const color = new Set(); for (const [, kind, name] of read(path).matchAll(/--(radius|color)-([a-z0-9-]+):\s*var\(--/g)) { (kind === "radius" ? radius : color).add(name); } return { radius, color }; } /** The component aliases: what components read and themes set (docs/theming.md). */ const componentAliases = () => themeNames("packages/ui/styles/theme-variables.css"); const VOID = new Set(["input", "br", "img", "meta", "hr"]); /** The fixture's elements, each with its tag, attributes, classes, own text and parent. */ function parseFixture() { const html = read("scripts/theme-preview/fixture.html"); const elements = []; const stack = []; const tag = /|<(\/?)([a-zA-Z][\w-]*)((?:\s+[^\s=>/]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)\s*(\/?)>/g; let last = 0; for (const match of html.matchAll(tag)) { const [token, closing, name, rawAttrs, selfClosing] = match; if (stack.length > 0) stack.at(-1).text += html.slice(last, match.index).trim(); last = match.index + token.length; if (token.startsWith("