import { getPayload } from "payload"; import configPromise from "../payload.config"; import fs from "fs"; import path from "path"; import { parseMarkdownToLexical } from "@mintel/payload-ai"; function extractFrontmatter(content: string) { const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/); if (!fmMatch) return {}; const fm = fmMatch[1]; const titleMatch = fm.match(/title:\s*"?([^"\n]+)"?/); const descMatch = fm.match(/description:\s*"?([^"\n]+)"?/); const tagsMatch = fm.match(/tags:\s*\[(.*?)\]/); return { title: titleMatch ? titleMatch[1] : "Untitled Draft", description: descMatch ? descMatch[1] : "No description", tags: tagsMatch ? tagsMatch[1].split(",").map((s) => s.trim().replace(/"/g, "")) : [], }; } async function run() { try { const payload = await getPayload({ config: configPromise }); console.log("Payload initialized."); const draftsDir = path.resolve(process.cwd(), "content/drafts"); const publicBlogDir = path.resolve(process.cwd(), "public/blog"); if (!fs.existsSync(draftsDir)) { console.log(`Drafts directory not found at ${draftsDir}`); process.exit(0); } const files = fs.readdirSync(draftsDir).filter((f) => f.endsWith(".md")); let count = 0; for (const file of files) { console.log(`Processing ${file}...`); const filePath = path.join(draftsDir, file); const content = fs.readFileSync(filePath, "utf8"); const fm = extractFrontmatter(content); const lexicalNodes = parseMarkdownToLexical(content); const lexicalContent = { root: { type: "root", format: "" as const, indent: 0, version: 1, direction: "ltr" as const, children: lexicalNodes, }, }; // Upload thumbnail if exists let featuredImageId = null; const thumbPath = path.join(publicBlogDir, `${file}.png`); if (fs.existsSync(thumbPath)) { console.log(`Uploading thumbnail ${file}.png...`); const fileData = fs.readFileSync(thumbPath); const stat = fs.statSync(thumbPath); try { const newMedia = await payload.create({ collection: "media", data: { alt: `Thumbnail for ${fm.title}`, }, file: { data: fileData, name: `optimized-${file}.png`, mimetype: "image/png", size: stat.size, }, }); featuredImageId = newMedia.id; } catch (e) { console.log("Failed to upload thumbnail", e); } } const tagsArray = fm.tags.map((tag) => ({ tag })); const slug = fm.title .toLowerCase() .replace(/[^a-z0-9]+/g, "-") .replace(/(^-|-$)/g, "") .substring(0, 60); // Check if already exists const existing = await payload.find({ collection: "posts", where: { slug: { equals: slug } }, }); if (existing.totalDocs === 0) { await payload.create({ collection: "posts", data: { title: fm.title, slug: slug, description: fm.description, date: new Date().toISOString(), tags: tagsArray, featuredImage: featuredImageId, content: lexicalContent, _status: "published", }, }); console.log(`Created CMS entry for ${file}.`); count++; } else { console.log(`Post with slug ${slug} already exists. Skipping.`); } } console.log( `Migration successful! Added ${count} new optimized posts to the database.`, ); process.exit(0); } catch (e) { console.error("Migration failed:", e); process.exit(1); } } run();