const fs = require('fs'); const path = require('path'); function walkDir(dir, callback) { fs.readdirSync(dir).forEach(f => { let dirPath = path.join(dir, f); if (fs.statSync(dirPath).isDirectory()) { walkDir(dirPath, callback); } else { callback(dirPath); } }); } walkDir('apps/website/src/app/[lang]', (filePath) => { if (!filePath.endsWith('.tsx') && !filePath.endsWith('.ts')) return; let content = fs.readFileSync(filePath, 'utf8'); let changed = false; // 1. Convert `export const metadata = { title: '...', description: '...' }` to generateMetadata // We need to parse: // export const metadata = { // title: '...', // description: '...', // } const metadataRegex = /export const metadata\s*(?::\s*Metadata\s*)?=\s*\{([\s\S]*?)\};?/g; // Exclude layout.tsx because we'll keep its global metadata, and handle it separately. if (filePath.endsWith('layout.tsx')) return; content = content.replace(metadataRegex, (match, body) => { changed = true; // Extract title and description const titleMatch = body.match(/title:\s*['"`](.*?)['"`]/); const descMatch = body.match(/description:\s*['"`](.*?)['"`]/); const title = titleMatch ? titleMatch[1] : ''; const desc = descMatch ? descMatch[1] : ''; // Determine the route path (e.g. /shop, /about, /checkout) // from the filePath. e.g. apps/website/src/app/[lang]/shop/page.tsx -> /shop let routePath = ''; const relPath = filePath.split('app/[lang]/')[1].replace('/page.tsx', '').replace('page.tsx', ''); if (relPath && !relPath.includes('[') && !relPath.includes(']')) { routePath = '/' + relPath; } else if (relPath.includes('[') && relPath.includes(']')) { // Dynamic route, can't just use string replacement easily. We will leave it to be manually fixed or use params. // But wait! If it's a dynamic route, it probably already has `generateMetadata`! // Let's check if there are static metadata in dynamic routes. // Wait, `/order/[id]/page.tsx` has `generateMetadata`. } if (relPath.includes('[')) { // Just fallback to empty for dynamic segments if any static metadata exists routePath = ''; } return `export async function generateMetadata({ params }: { params: Promise<{ lang: string }> }) { const { lang } = await params; return generateSeoMetadata({ title: '${title}', description: '${desc}', path: '${routePath}', lang, }); }`; }); if (changed) { if (!content.includes('generateSeoMetadata')) { // Insert import at the top content = `import { generateSeoMetadata } from '@/lib/seo';\n` + content; } fs.writeFileSync(filePath, content, 'utf8'); console.log('Converted static metadata in', filePath); } });