From dd4412a4143dd12a6c042657483c7055a4a04c5f Mon Sep 17 00:00:00 2001 From: dev_agent Date: Sat, 3 Oct 2026 15:56:35 -0400 Subject: [PATCH] Scan all of web/ for hex colour literals lint:colors only walked web/src, so a hex colour in a CSS or TypeScript file elsewhere under web/ (for example web/public/theme.css or web/theme.tsx) passed. It now walks the whole of web/, skipping the top-level node_modules and dist directories and hidden tool-cache directories. src/styles/tokens.css remains the only file allowed to contain hex literals. Co-Authored-By: Claude Opus 5.5 --- web/scripts/lint-colors.mjs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/web/scripts/lint-colors.mjs b/web/scripts/lint-colors.mjs index 9f0ffc2..e6ed7e5 100644 --- a/web/scripts/lint-colors.mjs +++ b/web/scripts/lint-colors.mjs @@ -1,25 +1,28 @@ -// Fails when a hex colour literal appears in web/src outside the design -// tokens: every colour must come from a custom property in tokens.css. +// Fails when a hex colour literal appears in any CSS or TypeScript file under +// web/ outside the design tokens: every colour must come from a custom +// property in tokens.css. Dependencies, build output and hidden directories +// (tool caches) are not source and are skipped. import { readFileSync, readdirSync } from 'node:fs' import { extname, join, relative } from 'node:path' import { fileURLToPath } from 'node:url' const webRoot = fileURLToPath(new URL('..', import.meta.url)) -const srcDir = join(webRoot, 'src') const allowed = new Set(['src/styles/tokens.css']) +const skippedDirs = new Set([join(webRoot, 'node_modules'), join(webRoot, 'dist')]) const extensions = new Set(['.css', '.ts', '.tsx']) const hexColour = /#(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{3,4})\b/g function* sourceFiles(dir) { for (const entry of readdirSync(dir, { withFileTypes: true })) { const path = join(dir, entry.name) - if (entry.isDirectory()) yield* sourceFiles(path) - else if (extensions.has(extname(entry.name))) yield path + if (entry.isDirectory()) { + if (!skippedDirs.has(path) && !entry.name.startsWith('.')) yield* sourceFiles(path) + } else if (extensions.has(extname(entry.name))) yield path } } const violations = [] -for (const path of sourceFiles(srcDir)) { +for (const path of sourceFiles(webRoot)) { const name = relative(webRoot, path).split('\\').join('/') if (allowed.has(name)) continue readFileSync(path, 'utf8')