tiffmin hat die Gist bearbeitet . Zu Änderung gehen
1 file changed, 3 insertions
11ty-to-astro.mjs
@@ -1,3 +1,6 @@ | |||
1 | + | // ChatGPT conversation to help with this script: | |
2 | + | // https://chatgpt.com/share/6817d17d-5a24-8002-9471-b5aa174f689d | |
3 | + | ||
1 | 4 | import fs from "fs"; | |
2 | 5 | import path from "path"; | |
3 | 6 | import matter from "gray-matter"; |
tiffmin hat die Gist bearbeitet . Zu Änderung gehen
1 file changed, 140 insertions
11ty-to-astro.mjs(Datei erstellt)
@@ -0,0 +1,140 @@ | |||
1 | + | import fs from "fs"; | |
2 | + | import path from "path"; | |
3 | + | import matter from "gray-matter"; | |
4 | + | import yaml from "js-yaml"; | |
5 | + | ||
6 | + | // Configuration | |
7 | + | const inputDir = "./src/content/post/"; // Folder containing markdown files | |
8 | + | const backupDir = "./backup"; // Backup before modifying | |
9 | + | ||
10 | + | // Create backup directory if it doesn't exist | |
11 | + | if (!fs.existsSync(backupDir)) { | |
12 | + | fs.mkdirSync(backupDir); | |
13 | + | } | |
14 | + | ||
15 | + | // Preferred frontmatter key order | |
16 | + | const preferredKeyOrder = [ | |
17 | + | "title", | |
18 | + | "description", | |
19 | + | "publishDate", | |
20 | + | "updatedDate", | |
21 | + | "tags", | |
22 | + | "slug", | |
23 | + | "draft", | |
24 | + | ]; | |
25 | + | ||
26 | + | function sortFrontmatterKeys(data) { | |
27 | + | const sorted = {}; | |
28 | + | preferredKeyOrder.forEach((key) => { | |
29 | + | if (data[key] !== undefined) { | |
30 | + | sorted[key] = data[key]; | |
31 | + | } | |
32 | + | }); | |
33 | + | Object.keys(data).forEach((key) => { | |
34 | + | if (!sorted.hasOwnProperty(key)) { | |
35 | + | sorted[key] = data[key]; | |
36 | + | } | |
37 | + | }); | |
38 | + | return sorted; | |
39 | + | } | |
40 | + | ||
41 | + | // Format dates consistently | |
42 | + | function formatDate(value) { | |
43 | + | if (value instanceof Date) { | |
44 | + | return value.toISOString().split("T")[0]; | |
45 | + | } | |
46 | + | return value; | |
47 | + | } | |
48 | + | ||
49 | + | // Extract date from filename if present | |
50 | + | function extractDateFromFilename(filename) { | |
51 | + | const match = filename.match(/^(\d{4}-\d{2}-\d{2})-(.+)$/); | |
52 | + | if (match) { | |
53 | + | return { | |
54 | + | date: match[1], | |
55 | + | newFilename: match[2], | |
56 | + | }; | |
57 | + | } | |
58 | + | return null; | |
59 | + | } | |
60 | + | ||
61 | + | // Clean and fix a single file | |
62 | + | function fixFile(filePath) { | |
63 | + | const rawContent = fs.readFileSync(filePath, "utf8"); | |
64 | + | const { data: frontmatter, content } = matter(rawContent); | |
65 | + | ||
66 | + | let cleanedFrontmatter = { ...frontmatter }; | |
67 | + | const fileName = path.basename(filePath); | |
68 | + | const dateInfo = extractDateFromFilename(fileName); | |
69 | + | ||
70 | + | // Move date from filename into publishDate if missing | |
71 | + | if (dateInfo) { | |
72 | + | if (!cleanedFrontmatter.publishDate) { | |
73 | + | cleanedFrontmatter.publishDate = dateInfo.date; | |
74 | + | } | |
75 | + | } | |
76 | + | ||
77 | + | // Rename "date" -> "publishDate" if necessary | |
78 | + | if (cleanedFrontmatter.date && !cleanedFrontmatter.publishDate) { | |
79 | + | cleanedFrontmatter.publishDate = cleanedFrontmatter.date; | |
80 | + | delete cleanedFrontmatter.date; | |
81 | + | } | |
82 | + | ||
83 | + | // Fix date formats | |
84 | + | Object.keys(cleanedFrontmatter).forEach((key) => { | |
85 | + | if (key.toLowerCase().includes("date")) { | |
86 | + | cleanedFrontmatter[key] = formatDate(cleanedFrontmatter[key]); | |
87 | + | } | |
88 | + | }); | |
89 | + | ||
90 | + | // If publishDate missing, set draft: true | |
91 | + | if ( | |
92 | + | !cleanedFrontmatter.publishDate && cleanedFrontmatter.draft === undefined | |
93 | + | ) { | |
94 | + | cleanedFrontmatter.draft = true; | |
95 | + | } | |
96 | + | ||
97 | + | // Sort frontmatter keys | |
98 | + | cleanedFrontmatter = sortFrontmatterKeys(cleanedFrontmatter); | |
99 | + | ||
100 | + | const yamlContent = yaml.dump(cleanedFrontmatter, { | |
101 | + | lineWidth: 1000, | |
102 | + | quotingType: '"', | |
103 | + | }); | |
104 | + | ||
105 | + | const finalContent = `---\n${yamlContent}---\n\n${content.trim()}\n`; | |
106 | + | ||
107 | + | // Backup original | |
108 | + | const backupPath = path.join(backupDir, fileName); | |
109 | + | fs.copyFileSync(filePath, backupPath); | |
110 | + | ||
111 | + | // Determine new filename | |
112 | + | let outputPath = filePath; | |
113 | + | if (dateInfo) { | |
114 | + | const newFilename = dateInfo.newFilename; | |
115 | + | outputPath = path.join(path.dirname(filePath), newFilename); | |
116 | + | } | |
117 | + | ||
118 | + | // Write cleaned file (possibly with new filename) | |
119 | + | fs.writeFileSync(outputPath, finalContent, "utf8"); | |
120 | + | ||
121 | + | // If filename changed, delete the old file | |
122 | + | if (outputPath !== filePath) { | |
123 | + | fs.unlinkSync(filePath); | |
124 | + | console.log(`Fixed & Renamed: ${fileName} -> ${path.basename(outputPath)}`); | |
125 | + | } else { | |
126 | + | console.log(`Fixed: ${fileName}`); | |
127 | + | } | |
128 | + | } | |
129 | + | ||
130 | + | // Process all markdown files | |
131 | + | function fixAllFiles() { | |
132 | + | const files = fs.readdirSync(inputDir); | |
133 | + | files.forEach((file) => { | |
134 | + | if (file.endsWith(".md")) { | |
135 | + | fixFile(path.join(inputDir, file)); | |
136 | + | } | |
137 | + | }); | |
138 | + | } | |
139 | + | ||
140 | + | fixAllFiles(); |