Files
DumiFlex 31a7b69022 refactor: take the kit from npm (@dumiflex/wp-kit) (#214)
The manager and canvas import the kit from the @dumiflex/wp-kit package through the @/kit alias instead of a copied src/kit; kit-pull and the kit:check CI step are gone.
2026-11-02 19:20:40 +01:00

73 lines
3.6 KiB
JavaScript

// Guards for the theme audit (audit.mjs) that run in plain vitest:
// - its look / palette lists match the ones the manager offers,
// - no manager-rendered stylesheet hard-codes a corner the looks can't
// square (write min(Npx, var(--wp-radius-cap, 999px)), or a token).
import { readFileSync } from "node:fs";
import { globSync } from "node:fs";
import { join, relative } from "node:path";
import { describe, expect, it } from "vitest";
import { LOOK_OPTIONS, PALETTE_OPTIONS } from "../../src/manager/stores/tweaksStore";
import { LOOKS, PALETTES } from "./audit.mjs";
const ROOT = join(import.meta.dirname, "..", "..");
describe("theme audit", () => {
it("walks every look and palette the manager offers", () => {
expect([...LOOKS].sort()).toEqual(LOOK_OPTIONS.map((o) => o.id).sort());
expect([...PALETTES].sort()).toEqual(PALETTE_OPTIONS.map((o) => o.id).sort());
});
it("leaves no raw corner radius the looks can't reach", () => {
// Files whose corners are not the manager look's on purpose: the look
// sheet itself, the look/palette previews, and the canvas colour sheet.
const EXEMPT = new Set([
"node_modules/@dumiflex/wp-kit/src/theme/looks.css",
"src/manager/components/settings/ThemeChoices.vue",
"src/components/shared/theme.css",
]);
const files = [
...globSync("src/**/*.vue", { cwd: ROOT }),
...globSync("src/manager/**/*.css", { cwd: ROOT }),
...globSync("src/components/shared/**/*.css", { cwd: ROOT }),
// The kit, from its npm package.
...globSync("node_modules/@dumiflex/wp-kit/src/**/*.css", { cwd: ROOT }),
].filter((f) => !EXEMPT.has(f.split("\\").join("/")));
const RAW = /border-(?:(?:top|bottom)-(?:left|right)-|(?:start|end)-(?:start|end)-)?radius\s*:\s*([^;{}\n]+)/g;
const bad = [];
for (const f of files) {
const text = readFileSync(join(ROOT, f), "utf8");
const css = f.endsWith(".vue") ? (text.match(/<style[^>]*>[\s\S]*?<\/style>/g) ?? []).join("\n") : text;
for (const m of css.matchAll(RAW)) {
const v = m[1].replace(/!important/, "").trim();
if (/var\(|calc\(|min\(|%|^(0|inherit|initial|unset)$/.test(v)) continue;
if (v.split(/\s+/).every((t) => t === "0" || t === "0px")) continue;
bad.push(`${relative(ROOT, join(ROOT, f))}: border-radius: ${v}`);
}
}
expect(bad, "Write min(Npx, var(--wp-radius-cap, 999px)) or a --wp-radius-* token so the square looks square it").toEqual([]);
});
it("decides every circle: squares with the look, or round on purpose", () => {
// A 50% corner inside a control (switch knob, slider thumb, step mark,
// round icon button) must square with the look:
// min(50%, var(--wp-radius-cap, 999px)). A dot, avatar, swatch or radio
// that stays round in every look says so on the same line:
// /* round: <why> */.
const files = [
...globSync("src/manager/**/*.{vue,css}", { cwd: ROOT }),
...globSync("src/components/shared/**/*.{vue,css}", { cwd: ROOT }),
...globSync("node_modules/@dumiflex/wp-kit/src/**/*.{vue,css}", { cwd: ROOT }),
].filter((f) => !f.split("\\").join("/").endsWith("theme/looks.css"));
const bad = [];
for (const f of files) {
const lines = readFileSync(join(ROOT, f), "utf8").split("\n");
lines.forEach((line, i) => {
if (!/border-(?:[a-z-]+-)?radius\s*:\s*50%/.test(line)) return;
if (/\/\*\s*round:/.test(line)) return;
bad.push(`${f}:${i + 1}: ${line.trim()}`);
});
}
expect(bad, "Write min(50%, var(--wp-radius-cap, 999px)) or add /* round: <why> */").toEqual([]);
});
});