#!/usr/bin/env node import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const ROOT = path.resolve(__dirname, ".."); const PAGES = [ { file: "app/page.tsx", dir: "components/home", pageName: "HomePage", imports: ['import LottiePlayer from "@/components/LottiePlayer"', 'import VideoLightbox from "@/components/VideoLightbox"'], }, { file: "app/about/page.tsx", dir: "components/about", pageName: "AboutPage", imports: ['import LottiePlayer from "@/components/LottiePlayer"'], }, { file: "app/blog/page.tsx", dir: "components/blog", pageName: "BlogPage", imports: [], }, { file: "app/contact/page.tsx", dir: "components/contact", pageName: "ContactPage", imports: ['import LottiePlayer from "@/components/LottiePlayer"'], }, ]; function toPascalCase(str) { return str .replace(/[^a-zA-Z0-9]+/g, " ") .trim() .split(/\s+/) .map((w) => w[0].toUpperCase() + w.slice(1).toLowerCase()) .join(""); } function extractSectionName(openTag) { const classMatch = openTag.match(/className="([^"]*)"/); if (!classMatch) return "Section"; const cls = classMatch[1]; const meaningful = cls .split(/\s+/) .filter((c) => !["section", "section-small", "overflow-hidden", "w-variant-daeb6173-296b-8c16-4f2d-1c7fb3f823cc"].includes(c)) .join(" "); if (!meaningful) return "Section"; return toPascalCase(meaningful) || "Section"; } for (const page of PAGES) { const filePath = path.join(ROOT, page.file); const content = fs.readFileSync(filePath, "utf8"); const lines = content.split("\n"); // Find
content boundaries let mainStart = -1; let mainEnd = -1; for (let i = 0; i < lines.length; i++) { if (lines[i].trim() === "
") mainStart = i + 1; if (lines[i].trim() === "
") mainEnd = i; } if (mainStart === -1 || mainEnd === -1) { console.log(`Skipping ${page.file}: no
found`); continue; } // Find top-level sections (indented at 6 spaces inside main) const sections = []; let currentSection = null; let depth = 0; const sectionIndent = lines[mainStart]?.search(/\S/) ?? 6; for (let i = mainStart; i < mainEnd; i++) { const line = lines[i]; const indent = line.search(/\S/); if (indent === -1) { if (currentSection) currentSection.lines.push(line); continue; } if (indent === sectionIndent && line.trim().startsWith("") { sections.push(currentSection); currentSection = null; } } } if (currentSection) sections.push(currentSection); if (!sections.length) { console.log(`Skipping ${page.file}: no sections found`); continue; } // Create component directory const compDir = path.join(ROOT, page.dir); fs.mkdirSync(compDir, { recursive: true }); const componentNames = []; const usedNames = new Set(); for (let idx = 0; idx < sections.length; idx++) { const section = sections[idx]; let baseName = extractSectionName(section.openTag); if (usedNames.has(baseName)) baseName += (idx + 1); usedNames.add(baseName); const compName = baseName + "Section"; componentNames.push(compName); // Determine needed imports for this section const sectionContent = section.lines.join("\n"); const neededImports = []; if (sectionContent.includes("LottiePlayer")) neededImports.push('import LottiePlayer from "@/components/LottiePlayer"'); if (sectionContent.includes("VideoLightbox")) neededImports.push('import VideoLightbox from "@/components/VideoLightbox"'); // Dedent section content const minIndent = sectionIndent; const dedented = section.lines.map((l) => { if (l.trim() === "") return ""; return l.length > minIndent ? " " + l.slice(minIndent) : " " + l.trimStart(); }); const tsx = `${neededImports.length ? neededImports.join("\n") + "\n\n" : ""}export default function ${compName}() { return ( ${dedented.join("\n")} ) } `; const compFile = path.join(compDir, `${compName}.tsx`); fs.writeFileSync(compFile, tsx, "utf8"); } // Write index.ts barrel const barrel = componentNames .map((n) => `export { default as ${n} } from "./${n}"`) .join("\n") + "\n"; fs.writeFileSync(path.join(compDir, "index.ts"), barrel, "utf8"); // Rewrite page.tsx const relDir = page.dir.replace(/^components\//, "@/components/"); const importLine = `import { ${componentNames.join(", ")} } from "${relDir}"`; const sectionJsx = componentNames.map((n) => ` <${n} />`).join("\n"); const newPage = `${importLine} export default function ${page.pageName}() { return (
${sectionJsx}
) } `; fs.writeFileSync(filePath, newPage, "utf8"); console.log(`${page.file}: split into ${sections.length} sections → ${page.dir}/`); }