mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 06:32:03 +00:00
A guard that compares a sweep against an allowlist, or against "none of
these may exist", passes when the sweep comes back empty. walkSourceFiles
already refuses a short walk; this adds the same refusal for what a guard
does with the walk.
- requireFloor(label, found, floor) throws below the floor and refuses a
floor of zero.
- scanSourceMatches(root, pattern, { fileFloor, matchFloor }) walks, matches
and floors both the files read and the hits found.
Floors added, pinned at the current counts:
- coach_usage owner columns: the clauses it actually examined (6).
- measurement reference index: the foreign keys it extracted (2).
- job outcome fact inventory: job files (130, floor 120) and fact keys
(399, floor 350).
- tone harness: assessment prompt modules (11).
- coach locale default: turn pipeline modules (15, floor 12).
- locale integrity: message bundles (7).
- settings card header coverage and settings anatomy: the walked cards.
- coach metric scope inventory: insight route sources.
- side-effect drift guard: both enums populated, since two empty keysets
are equal.
The pill-mapper guard walked with globSync, which skips dot-prefixed
directories; it now walks through walkSourceFiles like the rest.
86 lines
3.4 KiB
TypeScript
86 lines
3.4 KiB
TypeScript
/**
|
|
* Settings card-header drift guard.
|
|
*
|
|
* Every Settings card paints the same header shape — a muted icon, an
|
|
* `<h2 class="text-lg font-semibold">` title, and an optional muted
|
|
* description. The canonical primitive `SettingsCardHeader`
|
|
* (`_card-header.tsx`) owns that shape; routing every card header through
|
|
* it keeps the typography, the icon sizing, and the description size in
|
|
* one place instead of drifting across hand-rolled `flex … <h2 text-lg`
|
|
* permutations (the audit found five distinct variants once).
|
|
*
|
|
* This test globs every `*-section.tsx` / `*-card.tsx` under
|
|
* `src/components/settings/` and flags any file that still hand-rolls a
|
|
* top-level card header — a `<h2>` tag whose className carries `text-lg`.
|
|
* The primitive itself is excluded (it OWNS the `<h2 text-lg>`), and a
|
|
* short, explicitly-documented allowlist covers the handful of headers
|
|
* that legitimately cannot use the primitive yet.
|
|
*
|
|
* Mirrors the call-site coverage guards under `src/__tests__/`: walk the
|
|
* tree, match a mechanical pattern, assert the offending set is empty.
|
|
*/
|
|
import { describe, it, expect } from "vitest";
|
|
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
import { join, relative } from "node:path";
|
|
|
|
import { requireFloor } from "@/__tests__/helpers/source-files";
|
|
|
|
const ROOT = join(__dirname, "../../../..");
|
|
const SETTINGS_DIR = join(ROOT, "src/components/settings");
|
|
|
|
// Files allowed to retain a hand-rolled `<h2 text-lg>` header.
|
|
const ALLOWLIST = new Set<string>([
|
|
// allowed: collapsible-toggle header, button-wrapped, typography already canonical
|
|
"security-activity-card.tsx",
|
|
// allowed: collapsible-toggle header, button-wrapped, typography already canonical
|
|
"security-sessions-card.tsx",
|
|
]);
|
|
|
|
// The primitive itself owns the canonical `<h2 text-lg>`.
|
|
const PRIMITIVE = "_card-header.tsx";
|
|
|
|
function walk(dir: string, out: string[] = []): string[] {
|
|
for (const name of readdirSync(dir)) {
|
|
if (name === "__tests__" || name === "node_modules") continue;
|
|
const p = join(dir, name);
|
|
const stat = statSync(p);
|
|
if (stat.isDirectory()) {
|
|
walk(p, out);
|
|
} else if (name.endsWith("-section.tsx") || name.endsWith("-card.tsx")) {
|
|
out.push(p);
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
// A hand-rolled card header: a `<h2` tag whose className (within a small
|
|
// window, so a multi-line opening tag still matches) carries `text-lg`.
|
|
const AD_HOC_HEADER = /<h2\b[\s\S]{0,160}?text-lg/;
|
|
|
|
describe("Settings card headers route through SettingsCardHeader", () => {
|
|
it("has no hand-rolled <h2 text-lg> outside the primitive + allowlist", () => {
|
|
const offenders: string[] = [];
|
|
|
|
const files = requireFloor("settings cards", walk(SETTINGS_DIR), 80);
|
|
for (const file of files) {
|
|
const base = file.slice(file.lastIndexOf("/") + 1);
|
|
if (base === PRIMITIVE) continue;
|
|
if (ALLOWLIST.has(base)) continue;
|
|
|
|
const source = readFileSync(file, "utf8");
|
|
if (AD_HOC_HEADER.test(source)) {
|
|
offenders.push(relative(ROOT, file));
|
|
}
|
|
}
|
|
|
|
expect(
|
|
offenders,
|
|
`These Settings files still hand-roll a card header (\`<h2 ... text-lg>\`).\n` +
|
|
`Route them through <SettingsCardHeader> (src/components/settings/_card-header.tsx),\n` +
|
|
`or, if a header genuinely cannot use the primitive, add it to the ALLOWLIST\n` +
|
|
`in this test with a one-line justification.\n\n` +
|
|
offenders.map((f) => ` - ${f}`).join("\n"),
|
|
).toEqual([]);
|
|
});
|
|
});
|