diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 6eed5d3..1c50425 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -27,3 +27,4 @@ jobs: - run: pnpm test - run: pnpm build - run: pnpm check:size + - run: pnpm check:colors diff --git a/web/package.json b/web/package.json index be54783..3ad401b 100644 --- a/web/package.json +++ b/web/package.json @@ -14,6 +14,7 @@ "lint": "eslint .", "gen:api": "openapi-typescript http://localhost:8080/api-docs/openapi.json -o src/api/schema.d.ts", "check:size": "node scripts/check-bundle-size.mjs", + "check:colors": "node scripts/check-no-raw-colors.mjs", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build" }, diff --git a/web/scripts/check-no-raw-colors.mjs b/web/scripts/check-no-raw-colors.mjs new file mode 100644 index 0000000..e2bc9d6 --- /dev/null +++ b/web/scripts/check-no-raw-colors.mjs @@ -0,0 +1,42 @@ +// Fails if any raw Tailwind color utility appears outside src/components/ui/. +import { readdirSync, readFileSync } from "node:fs"; +import { join, relative } from "node:path"; + +const root = "src"; +const excludeDir = join("src", "components", "ui"); +const RAW_COLOR = + /(?:text|bg|border|ring|fill|stroke|from|to|via|decoration|outline|divide|placeholder)-(?:neutral|gray|slate|zinc|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950)\b/; + +function walk(dir) { + const files = []; + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const path = join(dir, entry.name); + if (entry.isDirectory()) { + if (path === excludeDir) continue; + files.push(...walk(path)); + } else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) { + files.push(path); + } + } + return files; +} + +const files = walk(root); +const offenses = []; +for (const file of files) { + const lines = readFileSync(file, "utf8").split("\n"); + for (let i = 0; i < lines.length; i++) { + const match = RAW_COLOR.exec(lines[i]); + if (match) offenses.push(`${relative(".", file)}:${i + 1}: ${match[0]}`); + } +} + +if (offenses.length > 0) { + console.error( + `raw color utilities found outside components/ui/ (${offenses.length}):`, + ); + for (const offense of offenses) console.error(` ${offense}`); + process.exit(1); +} + +console.log(`no raw color utilities outside components/ui/ (${files.length} files scanned)`);