tiff-personal/fix-frontmatter.mjs
2025-04-29 00:06:59 -04:00

141 lines
3.4 KiB
JavaScript

import fs from "fs";
import path from "path";
import matter from "gray-matter";
import yaml from "js-yaml";
// Configuration
const inputDir = "./src/content/post/"; // Folder containing markdown files
const backupDir = "./backup"; // Backup before modifying
// Create backup directory if it doesn't exist
if (!fs.existsSync(backupDir)) {
fs.mkdirSync(backupDir);
}
// Preferred frontmatter key order
const preferredKeyOrder = [
"title",
"description",
"publishDate",
"updatedDate",
"tags",
"slug",
"draft",
];
function sortFrontmatterKeys(data) {
const sorted = {};
preferredKeyOrder.forEach((key) => {
if (data[key] !== undefined) {
sorted[key] = data[key];
}
});
Object.keys(data).forEach((key) => {
if (!sorted.hasOwnProperty(key)) {
sorted[key] = data[key];
}
});
return sorted;
}
// Format dates consistently
function formatDate(value) {
if (value instanceof Date) {
return value.toISOString().split("T")[0];
}
return value;
}
// Extract date from filename if present
function extractDateFromFilename(filename) {
const match = filename.match(/^(\d{4}-\d{2}-\d{2})-(.+)$/);
if (match) {
return {
date: match[1],
newFilename: match[2],
};
}
return null;
}
// Clean and fix a single file
function fixFile(filePath) {
const rawContent = fs.readFileSync(filePath, "utf8");
const { data: frontmatter, content } = matter(rawContent);
let cleanedFrontmatter = { ...frontmatter };
const fileName = path.basename(filePath);
const dateInfo = extractDateFromFilename(fileName);
// Move date from filename into publishDate if missing
if (dateInfo) {
if (!cleanedFrontmatter.publishDate) {
cleanedFrontmatter.publishDate = dateInfo.date;
}
}
// Rename "date" -> "publishDate" if necessary
if (cleanedFrontmatter.date && !cleanedFrontmatter.publishDate) {
cleanedFrontmatter.publishDate = cleanedFrontmatter.date;
delete cleanedFrontmatter.date;
}
// Fix date formats
Object.keys(cleanedFrontmatter).forEach((key) => {
if (key.toLowerCase().includes("date")) {
cleanedFrontmatter[key] = formatDate(cleanedFrontmatter[key]);
}
});
// If publishDate missing, set draft: true
if (
!cleanedFrontmatter.publishDate && cleanedFrontmatter.draft === undefined
) {
cleanedFrontmatter.draft = true;
}
// Sort frontmatter keys
cleanedFrontmatter = sortFrontmatterKeys(cleanedFrontmatter);
const yamlContent = yaml.dump(cleanedFrontmatter, {
lineWidth: 1000,
quotingType: '"',
});
const finalContent = `---\n${yamlContent}---\n\n${content.trim()}\n`;
// Backup original
const backupPath = path.join(backupDir, fileName);
fs.copyFileSync(filePath, backupPath);
// Determine new filename
let outputPath = filePath;
if (dateInfo) {
const newFilename = dateInfo.newFilename;
outputPath = path.join(path.dirname(filePath), newFilename);
}
// Write cleaned file (possibly with new filename)
fs.writeFileSync(outputPath, finalContent, "utf8");
// If filename changed, delete the old file
if (outputPath !== filePath) {
fs.unlinkSync(filePath);
console.log(`Fixed & Renamed: ${fileName} -> ${path.basename(outputPath)}`);
} else {
console.log(`Fixed: ${fileName}`);
}
}
// Process all markdown files
function fixAllFiles() {
const files = fs.readdirSync(inputDir);
files.forEach((file) => {
if (file.endsWith(".md")) {
fixFile(path.join(inputDir, file));
}
});
}
fixAllFiles();