const fs = require('fs'); const path = require('path'); const matter = require('gray-matter'); const postsDir = path.resolve(__dirname, '../content/post'); function formatDate(date) { if (!date) return null; const d = new Date(date); if (isNaN(d.getTime())) return null; const year = d.getFullYear(); const month = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return `${year}${month}${day}`; } function traverseDir(dir) { const files = fs.readdirSync(dir); files.forEach(file => { const filePath = path.join(dir, file); const stat = fs.statSync(filePath); if (stat.isDirectory()) { traverseDir(filePath); } else if (file.endsWith('.md')) { processFile(filePath); } }); } function processFile(filePath) { try { const fileContent = fs.readFileSync(filePath, 'utf8'); const parsed = matter(fileContent); // Check if slug is already in target format (YYYYMMDDHHmm) // Or if it matches YYYYMMDD (old format we are migrating to) if (parsed.data.slug && /^\d{8,12}$/.test(String(parsed.data.slug))) { // console.log(`Skipping ${filePath}: Slug already formatted (${parsed.data.slug})`); return; } const dateSlug = formatDate(parsed.data.date); if (!dateSlug) { console.warn(`Skipping ${filePath}: No valid date found`); return; } // Update slug // Note: gray-matter might reformat the front matter slightly // We preserve existing data but update slug parsed.data.slug = dateSlug; // Convert back to string // Hugo front matter usually uses '---' delimiters // gray-matter defaults to '---' // We need to be careful about date formatting in output, // but gray-matter usually handles Date objects by converting to ISO string // Force date to be string if it was parsed as Date object to avoid format changes? // Actually, Hugo likes ISO dates, so Date object to ISO string is fine. const newContent = matter.stringify(parsed.content, parsed.data); // fs.writeFileSync(filePath, newContent); // console.log(`Updated ${filePath}: slug set to ${dateSlug}`); // Wait, gray-matter stringify might change the order or format of other fields. // A safer approach is regex replacement if we only want to change slug. // But regex is brittle. // Let's stick to gray-matter but be careful. // Actually, let's use a custom replacement to be safe and preserve comments/formatting. let lines = fileContent.split('\n'); let inFrontMatter = false; let slugFound = false; let dateFound = false; let newLines = []; let fmEndIndex = -1; for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line.trim() === '---') { if (!inFrontMatter) { inFrontMatter = true; } else { inFrontMatter = false; fmEndIndex = i; } newLines.push(line); continue; } if (inFrontMatter) { if (line.trim().startsWith('slug:')) { newLines.push(`slug: ${dateSlug}`); slugFound = true; } else if (line.trim().startsWith('date:')) { newLines.push(line); dateFound = true; } else { newLines.push(line); } } else { newLines.push(line); } } if (!slugFound && fmEndIndex !== -1) { // Insert slug before the end of front matter // Find the last non-empty line before --- newLines.splice(fmEndIndex, 0, `slug: ${dateSlug}`); } fs.writeFileSync(filePath, newLines.join('\n')); console.log(`Updated ${filePath}: slug set to ${dateSlug}`); } catch (e) { console.error(`Error processing ${filePath}:`, e); } } console.log('Starting slug migration...'); traverseDir(postsDir); console.log('Migration complete.');