#!/usr/bin/env node import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), ".."); const APP = path.join(ROOT, "app", "workspace"); const MODULE = path.join(ROOT, "modules", "workspace"); const MAX_LINES = 25; const errors = []; const ROUTES = [ "hub", "hubs", "hubs/[id]", "projects", "projects/[id]", "tasks", "teams", "teams/[id]", "content", "content/[id]", "content/calendar", "content/board", "approvals", "assets", "reports", ]; const FEATURE_FILES = [ "hub.tsx", "hubs.tsx", "hubDashboard.tsx", "projects.tsx", "projectDetail.tsx", "tasks.tsx", "teams.tsx", "teamDetail.tsx", "contentStudio.tsx", "contentDetail.tsx", "contentCalendar.tsx", "contentBoard.tsx", "approvals.tsx", "assets.tsx", "reports.tsx", ]; function walkPages(dir) { for (const ent of fs.readdirSync(dir, { withFileTypes: true })) { const p = path.join(dir, ent.name); if (ent.isDirectory()) walkPages(p); else if (ent.name === "page.tsx") checkPage(p); } } function checkPage(file) { const rel = path.relative(APP, file); const content = fs.readFileSync(file, "utf8"); const lines = content.split("\n").length; if (rel !== "page.tsx" && lines > MAX_LINES) errors.push(`${rel}: ${lines} lines (max ${MAX_LINES})`); if (rel !== "page.tsx" && !content.includes("@/modules/workspace/")) { errors.push(`${rel}: must import from @/modules/workspace/`); } } for (const route of ROUTES) { for (const file of ["page.tsx", "loading.tsx", "error.tsx"]) { const p = path.join(APP, route, file); if (!fs.existsSync(p)) errors.push(`missing app/workspace/${route}/${file}`); } } for (const file of FEATURE_FILES) { if (!fs.existsSync(path.join(MODULE, "features", file))) { errors.push(`missing modules/workspace/features/${file}`); } } for (const file of [ path.join(MODULE, "index.ts"), path.join(MODULE, "services", "workspace-api.ts"), path.join(MODULE, "labels.ts"), path.join(ROOT, "app", "api", "workspace", "[...path]", "route.ts"), path.join(APP, "layout.tsx"), path.join(APP, "page.tsx"), ]) { if (!fs.existsSync(file)) errors.push(`missing ${path.relative(ROOT, file)}`); } if (fs.existsSync(APP)) walkPages(APP); else errors.push("app/workspace not found"); if (errors.length) { console.error("Workspace route validation failed:\n" + errors.map((e) => " - " + e).join("\n")); process.exit(1); } console.log(`Workspace routes OK (${ROUTES.length} routes, ${FEATURE_FILES.length} features)`);