import fs from "fs"; import path from "path"; import { createClient } from "@sanity/client"; import dotenv from "dotenv"; dotenv.config({ path: path.resolve("studio/.env.local") }); const projectId = process.env.SANITY_STUDIO_PROJECT_ID || "gdvj8e5j"; const dataset = process.env.SANITY_STUDIO_DATASET || "production"; const token = process.env.SANITY_AUTH_TOKEN; const client = createClient({ projectId, dataset, token, apiVersion: "2024-10-31", useCdn: false, }); const BACKUP_DIR = "/Users/keira/Documents/GitHub/docs/content-backup"; const MANIFEST_FILE = path.join(BACKUP_DIR, "manifest.json"); function createBlock(text, style = "normal") { return { _key: `block-${Math.random().toString(36).slice(2, 9)}`, _type: "block", style, markDefs: [], children: [ { _key: `span-${Math.random().toString(36).slice(2, 9)}`, _type: "span", marks: [], text, }, ], }; } function markdownToPortableText(markdown) { const lines = markdown.split("\n"); const blocks = []; for (let line of lines) { const trimmed = line.trim(); if (!trimmed) continue; if (trimmed.startsWith("---") || trimmed.startsWith("> /icons/")) continue; if (trimmed.startsWith("# ")) { blocks.push(createBlock(trimmed.replace(/^#\s+/, ""), "h1")); } else if (trimmed.startsWith("## ")) { blocks.push(createBlock(trimmed.replace(/^##\s+/, ""), "h2")); } else if (trimmed.startsWith("### ")) { blocks.push(createBlock(trimmed.replace(/^###\s+/, ""), "h3")); } else if (trimmed.startsWith("#### ")) { blocks.push(createBlock(trimmed.replace(/^####\s+/, ""), "h4")); } else if (trimmed.startsWith("* ") || trimmed.startsWith("- ")) { blocks.push(createBlock(trimmed.replace(/^[*|-]\s+/, ""), "normal")); } else { blocks.push(createBlock(trimmed, "normal")); } } return blocks; } function parseFrontmatter(content) { const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/); if (!match) return { meta: {}, bodyText: content }; const rawMeta = match[1]; const bodyText = match[2]; const meta = {}; rawMeta.split("\n").forEach((line) => { const colonIdx = line.indexOf(":"); if (colonIdx > 0) { const key = line.slice(0, colonIdx).trim(); let val = line.slice(colonIdx + 1).trim(); if (val.startsWith('"') && val.endsWith('"')) { val = val.slice(1, -1); } meta[key] = val; } }); return { meta, bodyText }; } async function run() { console.log("🌿 VWG Blog v2 — Importing all backed up Posts into Sanity Content Lake..."); const manifest = JSON.parse(fs.readFileSync(MANIFEST_FILE, "utf8")); // Post slugs we should import as blog posts const postEntries = manifest.filter((entry) => { // Exclude root/static pages that are not blog articles return ![ "about", "blog", "index", "vwg-vietnam-wedding-guide", "private-consultant-services" ].includes(entry.slug); }); console.log(`Found ${postEntries.length} post articles to import.`); for (const entry of postEntries) { const filePath = path.join(BACKUP_DIR, entry.file); if (!fs.existsSync(filePath)) { console.warn(`File not found: ${filePath}`); continue; } const fileContent = fs.readFileSync(filePath, "utf8"); const { meta, bodyText } = parseFrontmatter(fileContent); const title = meta.title || entry.title; const slug = meta.slug || entry.slug; const publishedAt = meta.createdTime || entry.createdTime || new Date().toISOString(); // Generate excerpt from first few sentences const cleanBody = bodyText.replace(/#+\s+/g, "").trim(); const excerpt = cleanBody.slice(0, 220).replace(/\n/g, " ") + "..."; const blocks = markdownToPortableText(bodyText); const postDoc = { _id: `post-${slug}`, _type: "post", title, slug: { _type: "slug", current: slug, }, publishedAt, excerpt, author: { _type: "reference", _ref: "author-nhi-vo", }, categories: [ { _type: "reference", _ref: slug.includes("ngan-sach") || slug.includes("budget") || slug.includes("cost") ? "category-budget" : slug.includes("tai-sao") || slug.includes("why") ? "category-destination" : "category-planning", }, ], body: blocks, }; try { await client.createOrReplace(postDoc); console.log(` āœ“ Imported post: [${slug}] "${title}" (${blocks.length} blocks)`); } catch (err) { console.error(` āœ— Error importing post [${slug}]:`, err.message); } } console.log("\nāœ… All articles from backup have been successfully imported into Sanity Cloud!"); } run().catch(console.error);