107 lines
5.3 KiB
JavaScript
107 lines
5.3 KiB
JavaScript
// Rôle : protège les frontières Sass, les conventions publiques et le découpage des fichiers.
|
|
import { readFile, readdir } from "node:fs/promises";
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
function countLines(source) {
|
|
return source.trimEnd().split("\n").length;
|
|
}
|
|
|
|
test("Sass layers retain ownership boundaries and exclude removed APIs", async () => {
|
|
const root = "website/src/styles";
|
|
const paths = (await readdir(root, { recursive: true })).filter((path) => path.endsWith(".scss"));
|
|
const sources = new Map(await Promise.all(paths.map(async (path) => [path, await readFile(`${root}/${path}`, "utf8")])));
|
|
assert.doesNotMatch(sources.get("_base.scss"), /\.(?:card-icon-button|drawer-action-button|import-icon-button)/);
|
|
assert.doesNotMatch(sources.get("_cards.scss"), /@use "design-system\/surfaces"|controls\.card-pattern|\.compact-data-card\s*\{/);
|
|
assert.doesNotMatch(sources.get("_mhwilds.scss"), /\.game-(home-card|layout|grid)/);
|
|
const home = [...sources].filter(([path]) => path === "_home.scss" || path.startsWith("home/")).map(([, source]) => source).join("\n");
|
|
assert.doesNotMatch(home, /\.nebula-panel\s*\{/);
|
|
assert.doesNotMatch(sources.get("toolboxes/_notepad.scss"), /lecture seule/);
|
|
assert.match(sources.get("design-system/_controls.scss"), /@forward "controls\/patterns"/);
|
|
assert.match(sources.get("design-system/_attributes.scss"), /@use "attributes\/patterns"/);
|
|
const branch = await readFile("website/src/features/toolboxes/modules/GoalTreeBranch.jsx", "utf8");
|
|
assert.doesNotMatch(
|
|
[...sources.values(), branch].join("\n"),
|
|
/(?:data-size="tiny"|icon-button(?:-icon)?\(tiny\)|\$size == tiny)/
|
|
);
|
|
});
|
|
|
|
test("product components keep the public NDS pattern vocabulary", async () => {
|
|
const paths = [
|
|
"website/src/pages/HomePage.jsx",
|
|
"website/src/pages/LibraryPage.jsx",
|
|
"website/src/pages/AboutPage.jsx",
|
|
"website/src/features/games/GamesPage.jsx",
|
|
"website/src/features/games/GameFiltersPanel.jsx",
|
|
"website/src/features/games/diablo4/Diablo4AffixCard.jsx",
|
|
"website/src/features/toolboxes/ToolboxCard.jsx",
|
|
"website/src/features/toolboxes/ToolboxPages.jsx",
|
|
"website/src/components/AppOverlays.jsx",
|
|
"website/src/components/StorageQuota.jsx",
|
|
"website/src/components/ToolboxModals.jsx",
|
|
"website/src/features/toolboxes/modules/AddToolControls.jsx",
|
|
"website/src/features/toolboxes/modules/TextImportModal.jsx"
|
|
];
|
|
const consumers = (await Promise.all(paths.map((path) => readFile(path, "utf8")))).join("\n");
|
|
for (const family of [
|
|
"page-hero", "panel", "card", "card-cover", "tool-panel", "filter-panel",
|
|
"chip", "badge", "empty-state", "inline-notice", "progress", "modal", "drawer-panel", "toast"
|
|
]) {
|
|
assert.ok(consumers.includes(`nds-${family}`), `public nds-${family} convention must remain in use`);
|
|
}
|
|
});
|
|
|
|
test("large sass files stay split by stable responsibility", async () => {
|
|
const orchestrators = [
|
|
"website/src/styles/home/_library.scss",
|
|
"website/src/styles/home/_about.scss",
|
|
"website/src/styles/_overlays.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_nodes.scss",
|
|
"website/src/styles/_icons.scss",
|
|
"website/src/styles/toolboxes/calendar/_form.scss"
|
|
];
|
|
const partials = [
|
|
"website/src/styles/home/library/_page.scss",
|
|
"website/src/styles/home/library/_summary.scss",
|
|
"website/src/styles/home/library/_toc.scss",
|
|
"website/src/styles/home/library/_tool-cards.scss",
|
|
"website/src/styles/home/library/_examples.scss",
|
|
"website/src/styles/home/library/_previews.scss",
|
|
"website/src/styles/home/about/_page.scss",
|
|
"website/src/styles/home/about/_story.scss",
|
|
"website/src/styles/home/about/_contribute.scss",
|
|
"website/src/styles/home/about/_tools.scss",
|
|
"website/src/styles/home/about/_reminders.scss",
|
|
"website/src/styles/overlays/_image-viewer.scss",
|
|
"website/src/styles/overlays/_drawers.scss",
|
|
"website/src/styles/overlays/_modals.scss",
|
|
"website/src/styles/overlays/_notifications.scss",
|
|
"website/src/styles/overlays/_tool-add.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-card.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-content.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-actions.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-drag.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-responsive.scss",
|
|
"website/src/styles/icons/_base.scss",
|
|
"website/src/styles/icons/_navigation.scss",
|
|
"website/src/styles/icons/_toolbox.scss",
|
|
"website/src/styles/icons/_actions.scss",
|
|
"website/src/styles/icons/_equipment.scss",
|
|
"website/src/styles/toolboxes/calendar/_form-layout.scss",
|
|
"website/src/styles/toolboxes/calendar/_date-picker.scss",
|
|
"website/src/styles/toolboxes/calendar/_event-controls.scss",
|
|
"website/src/styles/toolboxes/calendar/_form-actions.scss"
|
|
];
|
|
|
|
for (const path of orchestrators) {
|
|
const source = await readFile(path, "utf8");
|
|
assert.ok(source.startsWith("// Rôle :"), `${path} must keep a role header`);
|
|
assert.ok(countLines(source) <= 120, `${path} should remain an orchestrator`);
|
|
}
|
|
|
|
for (const path of partials) {
|
|
const source = await readFile(path, "utf8");
|
|
assert.ok(source.startsWith("// Rôle :"), `${path} must keep a role header`);
|
|
assert.ok(countLines(source) <= 300, `${path} should stay scoped to one responsibility`);
|
|
}
|
|
});
|