This repository has no description
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161import path from 'node:path'import { fileURLToPath } from 'node:url'import { discoverAll } from './import/discover'import { collectUniqueTags, upsertTags } from './import/tags'import { scanImageRefs } from './import/scan-image-refs'import { preprocessMdx } from './import/preprocess-mdx'import { markdownToLexical } from './import/markdown-to-lexical'import { loadImageCache, persistImageCache, uploadImage } from './import/images'import { loadOgCache, persistOgCache } from './import/og-fetch'import { upsertRecord } from './import/upsert-record'import { slugify } from '@/lib/slugify'
const args = new Map<string, string | true>( process.argv.slice(2).map((a) => { const m = a.match(/^--([^=]+)(?:=(.*))?$/) return m ? [m[1], m[2] ?? true] : ['_', a] }),)const dryRun = args.get('dry-run') === trueconst sourceRoot = (args.get('source') as string | undefined) ?? path.resolve(fileURLToPath(import.meta.url), '../../../arter-blog')
async function main() { console.log(`[import] source=${sourceRoot} dryRun=${dryRun}`) const { posts, projects, pages } = await discoverAll(sourceRoot) console.log(`[import] discovered: ${posts.length} posts, ${projects.length} projects, ${pages.length} pages`)
const tags = collectUniqueTags(posts.map((p) => ({ tags: p.frontmatter.tags ?? [] }))) console.log(`[import] unique tags: ${tags.length}`)
const allRefs = new Set<string>() for (const p of [...posts, ...projects, ...pages]) { for (const ref of scanImageRefs(p.body)) allRefs.add(ref) const seoSrc = (p.frontmatter as { seo?: { image?: { src?: string } } }).seo?.image?.src if (seoSrc?.startsWith('/images/')) allRefs.add(seoSrc) } console.log(`[import] unique image refs: ${allRefs.size}`)
const imageCache = await loadImageCache() const ogCache = await loadOgCache()
if (dryRun) { // Dry-run only validates discovery + counts; conversion now requires Payload. console.log('[import] dry-run: skipping conversion (requires Payload).') await persistImageCache(imageCache) await persistOgCache(ogCache) return }
const { getPayload } = await import('payload') const { default: config } = await import('@/payload.config') const payload = await getPayload({ config }) const tagIdBySlug = await upsertTags(payload, tags) console.log(`[import] tags upserted: ${tagIdBySlug.size}`)
// upload all unique image refs first for (const ref of allRefs) { const id = await uploadImage(payload, ref, sourceRoot, ref.split('/').pop() ?? ref, imageCache) if (id !== undefined) imageCache[ref] = id } const imageMap = new Map<string, string | number>(Object.entries(imageCache)) console.log(`[import] images uploaded/cached: ${imageMap.size}`)
// write posts let created = 0, updated = 0 for (const file of posts) { const pre = preprocessMdx(file.body, imageMap) const body = await markdownToLexical(payload, pre) const fm = file.frontmatter const tagIds = (fm.tags ?? []) .map((t) => tagIdBySlug.get(slugify(t))) .filter((id): id is string | number => id !== undefined) const seoSrc = fm.seo?.image?.src const coverImage = seoSrc?.startsWith('/images/') ? imageCache[seoSrc] : undefined const data = { title: fm.title, subtitle: fm.subtitle, excerpt: fm.excerpt, publishDate: fm.publishDate, updatedDate: fm.updatedDate, isFeatured: fm.isFeatured, tags: tagIds, coverImage, seo: { title: fm.seo?.title, description: fm.seo?.description, pageType: fm.seo?.pageType ?? 'article', image: coverImage, }, body, _status: 'published', } const r = await upsertRecord(payload, 'posts', file.slug, data) r.action === 'created' ? created++ : updated++ } console.log(`[import] posts: ${created} created, ${updated} updated`)
// write projects let pCreated = 0, pUpdated = 0 for (const file of projects) { const pre = preprocessMdx(file.body, imageMap) const body = await markdownToLexical(payload, pre) const fm = file.frontmatter const seoSrc = fm.seo?.image?.src const coverImage = seoSrc?.startsWith('/images/') ? imageCache[seoSrc] : undefined const data = { title: fm.title, description: fm.description, publishDate: fm.publishDate, isFeatured: fm.isFeatured, coverImage, seo: { title: fm.seo?.title, description: fm.seo?.description, pageType: fm.seo?.pageType ?? 'article', image: coverImage, }, body, _status: 'published', } const r = await upsertRecord(payload, 'projects', file.slug, data) r.action === 'created' ? pCreated++ : pUpdated++ } console.log(`[import] projects: ${pCreated} created, ${pUpdated} updated`)
// write pages let pgCreated = 0, pgUpdated = 0 for (const file of pages) { const pre = preprocessMdx(file.body, imageMap) const body = await markdownToLexical(payload, pre) const fm = file.frontmatter const seoSrc = fm.seo?.image?.src const coverImage = seoSrc?.startsWith('/images/') ? imageCache[seoSrc] : undefined const data = { title: fm.title, subtitle: fm.subtitle, description: fm.description, seo: { title: fm.seo?.title, description: fm.seo?.description, pageType: fm.seo?.pageType ?? 'website', image: coverImage, }, body, _status: 'published', } const r = await upsertRecord(payload, 'pages', file.slug, data) r.action === 'created' ? pgCreated++ : pgUpdated++ } console.log(`[import] pages: ${pgCreated} created, ${pgUpdated} updated`)
await persistImageCache(imageCache) await persistOgCache(ogCache)}
main().catch((err) => { console.error(err) process.exit(1)})