contract.test.ts
1.7 kB · typescript · 43 lines
1import { describe, expect, test } from "bun:test";2import { readFileSync, readdirSync } from "node:fs";3import { join, relative, resolve } from "node:path";45const KIT = resolve(import.meta.dir, "..");67const READS = /var\(\s*(--[a-z0-9-]+)/g;89const DECLARES = /(--[a-z0-9-]+)\s*:/g;1011const sheets = (dir: string): string[] =>12 readdirSync(dir, { withFileTypes: true })13 .flatMap((item) => (item.isDirectory() ? sheets(join(dir, item.name)) : item.name.endsWith(".css") ? [join(dir, item.name)] : []))14 .sort();1516const read: { name: string; where: string }[] = [];17for (const file of sheets(KIT)) {18 const where = relative(KIT, file);19 for (const hit of readFileSync(file, "utf8").matchAll(READS)) read.push({ name: hit[1], where });20}2122const declared = (leaf: string) => new Set([...readFileSync(join(KIT, leaf), "utf8").matchAll(DECLARES)].map((hit) => hit[1]));2324const contract = declared("code/contract.css");2526const palette = declared("palette.css");2728const names = [...new Set(read.map((one) => one.name))].sort();2930describe("contract", () => {31 test("every name the kit's CSS reads is declared by the contract or the palette", () => {32 console.log(names.join("\n"));33 const loose = read.filter((one) => !contract.has(one.name) && !palette.has(one.name));34 const wild = loose.filter((one) => !(one.where === "code/contract.css" && one.name.startsWith("--site-")));35 expect(wild.map((one) => `${one.where} reads ${one.name}`).sort()).toEqual([]);36 });3738 test("the contract declares no kit name the kit's CSS never reads", () => {39 const live = new Set(names);40 const dead = [...contract].filter((name) => name.startsWith("--kit-") && !live.has(name)).sort();41 expect(dead).toEqual([]);42 });43});