#!/usr/bin/env node /** Ensure app/beauty routes remain wired and URLs are preserved. */ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs"; import { join, relative, sep } from "node:path"; import { fileURLToPath } from "node:url"; const ROOT = join(fileURLToPath(new URL(".", import.meta.url)), ".."); const BEAUTY_APP = join(ROOT, "app", "beauty"); const REQUIRED_LAYOUTS = [ "layout.tsx", "admin/layout.tsx", "customer/layout.tsx", "owner/layout.tsx", "(owner)/layout.tsx", "reception/layout.tsx", "staff-portal/layout.tsx", "site/layout.tsx", ]; /** @type {string[]} */ const issues = []; function walkPages(dir, pages = []) { for (const entry of readdirSync(dir)) { const full = join(dir, entry); if (statSync(full).isDirectory()) walkPages(full, pages); else if (entry === "page.tsx") pages.push(full); } return pages; } if (!existsSync(BEAUTY_APP)) { console.error("❌ app/beauty missing"); process.exit(1); } for (const layout of REQUIRED_LAYOUTS) { const p = join(BEAUTY_APP, layout); if (!existsSync(p)) issues.push(`Missing layout: app/beauty/${layout}`); } const pages = walkPages(BEAUTY_APP); if (pages.length < 90) { issues.push(`Expected ~100 beauty pages, found ${pages.length}`); } for (const page of pages) { const rel = relative(ROOT, page).split(sep).join("/"); const content = readFileSync(page, "utf8"); if (!/export\s+(default|\{)/.test(content)) { issues.push(`${rel}: no default export`); } // Route files should not contain heavy business logic (>80 lines) const lines = content.split("\n").length; if (lines > 80 && !rel.includes("(owner)")) { // owner routes recreated as thin - warn only for non-owner if (lines > 15 && !content.includes("@/modules/beauty")) { issues.push(`${rel}: ${lines} lines — route should re-export from modules/beauty`); } } } // Hub entry redirect const rootPage = join(BEAUTY_APP, "page.tsx"); if (existsSync(rootPage)) { const c = readFileSync(rootPage, "utf8"); if (!c.includes("/beauty/hub") && !c.includes("redirect")) { issues.push("app/beauty/page.tsx should redirect to hub"); } } console.log("Beauty Route Validation\n"); console.log(`Pages: ${pages.length}`); console.log(`Layouts checked: ${REQUIRED_LAYOUTS.length}`); if (issues.length) { console.error(`\n❌ ${issues.length} issue(s):`); for (const i of issues) console.error(` - ${i}`); process.exit(1); } console.log("\n✅ All beauty routes and layouts present"); console.log("✅ Route files are thin adapters"); process.exit(0);