c77d0a8e89
Build & Push / Build & Push Docker Image (push) Failing after 10m39s
Replace storefront naming across source, tests, docs, config, and production scripts. Rename the legacy top-level app directory and Carplace component files, remove duplicate storefront startup scripts, and refresh the lockfile.
120 lines
4.9 KiB
JavaScript
120 lines
4.9 KiB
JavaScript
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import process from 'node:process';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
const errors = [];
|
|
|
|
async function exists(target) {
|
|
try { await stat(target); return true; } catch { return false; }
|
|
}
|
|
|
|
async function walk(directory) {
|
|
const files = [];
|
|
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
if (['node_modules', '.next', '.turbo', 'dist', 'coverage'].includes(entry.name)) continue;
|
|
const target = path.join(directory, entry.name);
|
|
if (entry.isDirectory()) files.push(...(await walk(target)));
|
|
else files.push(target);
|
|
}
|
|
return files;
|
|
}
|
|
|
|
function requireText(contents, required, label) {
|
|
for (const marker of required) {
|
|
if (!contents.includes(marker)) errors.push(`${label}: missing ${marker}`);
|
|
}
|
|
}
|
|
|
|
for (const app of ['admin', 'api', 'dashboard', 'homepage', 'carplace']) {
|
|
if (!(await exists(path.join(root, app)))) errors.push(`missing application directory: ${app}`);
|
|
if (!(await exists(path.join(root, app, 'package.json')))) errors.push(`${app}: missing package.json`);
|
|
}
|
|
|
|
for (const app of ['admin', 'dashboard']) {
|
|
const tokenPath = path.join(root, app, 'src/styles/phase16-tokens.css');
|
|
const globalsPath = path.join(root, app, 'src/app/globals.css');
|
|
if (!(await exists(tokenPath))) errors.push(`${app}: missing Phase 16 token file`);
|
|
if (!(await exists(globalsPath))) errors.push(`${app}: missing globals.css`);
|
|
|
|
const tokens = await readFile(tokenPath, 'utf8');
|
|
requireText(tokens, [
|
|
'--rdg-blue-700', '--rdg-orange-600', '--rdg-sidebar-size',
|
|
'--rdg-header-size', '--rdg-radius-lg', '--rdg-shadow-card',
|
|
], `${app} tokens`);
|
|
|
|
const globals = await readFile(globalsPath, 'utf8');
|
|
requireText(globals, [
|
|
'phase16-tokens.css', '.rdg-app-shell', '.rdg-sidebar', '.rdg-topbar',
|
|
'.rdg-page-hero', '.rdg-page-heading', '.btn-primary', '.btn-conversion',
|
|
'.panel', '.field', '@media (forced-colors: active)',
|
|
], `${app} globals`);
|
|
|
|
const withoutComments = globals.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
const balance = [...withoutComments].reduce((value, character) =>
|
|
character === '{' ? value + 1 : character === '}' ? value - 1 : value, 0);
|
|
if (balance !== 0) errors.push(`${app}: unbalanced CSS braces (${balance})`);
|
|
}
|
|
|
|
const dashboardLayout = await readFile(path.join(root, 'dashboard/src/app/(dashboard)/layout.tsx'), 'utf8');
|
|
requireText(dashboardLayout, ['rdg-app-shell', 'rdg-workspace', 'rdg-app-main', 'rdg-app-content'], 'dashboard shell');
|
|
|
|
const dashboardSidebar = await readFile(path.join(root, 'dashboard/src/components/layout/Sidebar.tsx'), 'utf8');
|
|
requireText(dashboardSidebar, ['rdg-sidebar', 'rdg-nav-item', 'aria-current', 'RentalDriveGo'], 'dashboard sidebar');
|
|
|
|
const dashboardTopbar = await readFile(path.join(root, 'dashboard/src/components/layout/TopBar.tsx'), 'utf8');
|
|
requireText(dashboardTopbar, ['rdg-topbar', 'rdg-system-status', 'rdg-search-field'], 'dashboard topbar');
|
|
|
|
const adminLayout = await readFile(path.join(root, 'admin/src/app/dashboard/layout.tsx'), 'utf8');
|
|
requireText(adminLayout, [
|
|
'rdg-app-shell', 'rdg-sidebar', 'rdg-nav-item', 'rdg-topbar',
|
|
'rdg-system-status', 'aria-current', 'RentalDriveGo',
|
|
], 'admin shell');
|
|
|
|
const routeRoots = [
|
|
path.join(root, 'admin/src/app/dashboard'),
|
|
path.join(root, 'dashboard/src/app/(dashboard)'),
|
|
];
|
|
for (const routeRoot of routeRoots) {
|
|
const pages = (await walk(routeRoot)).filter((file) => file.endsWith('page.tsx'));
|
|
for (const page of pages) {
|
|
const contents = await readFile(page, 'utf8');
|
|
if (!['rdg-page-heading', 'rdg-page-hero'].some((marker) => contents.includes(marker))) {
|
|
errors.push(`${path.relative(root, page)}: missing Phase 16 page heading or hero`);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const app of ['admin', 'dashboard']) {
|
|
for (const file of await walk(path.join(root, app, 'src'))) {
|
|
if (!/\.(ts|tsx|css|json)$/.test(file)) continue;
|
|
const contents = await readFile(file, 'utf8');
|
|
if (/RentalDriveGo/i.test(contents)) errors.push(`${path.relative(root, file)}: retired RentalDriveGo brand remains`);
|
|
}
|
|
}
|
|
|
|
const authChecks = [
|
|
'dashboard/src/app/sign-in/[[...sign-in]]/SignInPageClient.tsx',
|
|
'dashboard/src/app/sign-up/[[...sign-up]]/SignUpForm.tsx',
|
|
];
|
|
for (const relative of authChecks) {
|
|
const contents = await readFile(path.join(root, relative), 'utf8');
|
|
if (!contents.includes('PublicPageLayout')) errors.push(`${relative}: shared public layout not applied`);
|
|
}
|
|
|
|
for (const relative of [
|
|
'carplace/src/components/public/SiteNavbar.tsx',
|
|
'carplace/src/components/public/SiteFooter.tsx',
|
|
'carplace/src/components/public/SitePageLayout.tsx',
|
|
]) {
|
|
if (!(await exists(path.join(root, relative)))) errors.push(`missing shared carplace component: ${relative}`);
|
|
}
|
|
|
|
if (errors.length) {
|
|
console.error(errors.join('\n'));
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log('Phase 16 dashboard/admin design checks passed.');
|