Normalisation des dates/heures
This commit is contained in:
125
tools/normalize_article_dates.js
Normal file
125
tools/normalize_article_dates.js
Normal file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs/promises");
|
||||
const path = require("path");
|
||||
const {
|
||||
extractRawDate,
|
||||
readFrontmatter,
|
||||
writeFrontmatter,
|
||||
} = require("./lib/weather/frontmatter");
|
||||
const { parseFrontmatterDate, formatDateTime, getHugoTimeZone } = require("./lib/datetime");
|
||||
|
||||
const CONTENT_ROOT = path.join(process.cwd(), "content");
|
||||
|
||||
/**
|
||||
* Liste récursivement tous les fichiers Markdown d'un dossier.
|
||||
* @param {string} root Dossier racine à parcourir.
|
||||
* @returns {Promise<string[]>} Chemins absolus des fichiers trouvés.
|
||||
*/
|
||||
async function listMarkdownFiles(root) {
|
||||
const entries = await fs.readdir(root, { withFileTypes: true });
|
||||
const results = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(root, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
const nested = await listMarkdownFiles(fullPath);
|
||||
results.push(...nested);
|
||||
continue;
|
||||
}
|
||||
if (entry.isFile() && entry.name.endsWith(".md")) {
|
||||
results.push(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Harmonise la date d'un fichier Markdown si nécessaire.
|
||||
* @param {string} filePath Chemin absolu du fichier.
|
||||
* @returns {Promise<"updated"|"unchanged"|"skipped"|"invalid">} Statut de traitement.
|
||||
*/
|
||||
async function normalizeFileDate(filePath) {
|
||||
const frontmatter = await readFrontmatter(filePath);
|
||||
if (!frontmatter) {
|
||||
return "skipped";
|
||||
}
|
||||
|
||||
const rawDate = extractRawDate(frontmatter.frontmatterText);
|
||||
const dateValue = frontmatter.doc.get("date");
|
||||
|
||||
if (!rawDate && (dateValue === undefined || dateValue === null)) {
|
||||
return "skipped";
|
||||
}
|
||||
|
||||
const sourceValue = rawDate !== null ? rawDate : dateValue;
|
||||
const parsed = parseFrontmatterDate(sourceValue);
|
||||
if (!parsed) {
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
let hasTime = false;
|
||||
if (typeof rawDate === "string") {
|
||||
const timeMatch = rawDate.match(/[T ](\d{2}):(\d{2})(?::(\d{2}))?/);
|
||||
if (timeMatch) {
|
||||
const hour = Number(timeMatch[1]);
|
||||
const minute = Number(timeMatch[2]);
|
||||
const second = Number(timeMatch[3] || "0");
|
||||
hasTime = !(hour === 0 && minute === 0 && second === 0);
|
||||
}
|
||||
}
|
||||
const normalized = hasTime
|
||||
? parsed.set({ millisecond: 0 })
|
||||
: parsed.set({ hour: 12, minute: 0, second: 0, millisecond: 0 });
|
||||
const formatted = formatDateTime(normalized);
|
||||
const current = typeof dateValue === "string" ? dateValue.trim() : rawDate;
|
||||
const quotedFormatted = `"${formatted}"`;
|
||||
const currentComparable = typeof current === "string" ? current.trim() : "";
|
||||
|
||||
if (currentComparable === formatted || currentComparable === quotedFormatted) {
|
||||
return "unchanged";
|
||||
}
|
||||
|
||||
frontmatter.doc.set("date", formatted);
|
||||
await writeFrontmatter(filePath, frontmatter.doc, frontmatter.body);
|
||||
const rewritten = await fs.readFile(filePath, "utf8");
|
||||
const normalizedContent = rewritten.replace(/^date:\s*.+$/m, `date: ${quotedFormatted}`);
|
||||
if (rewritten !== normalizedContent) {
|
||||
await fs.writeFile(filePath, normalizedContent, "utf8");
|
||||
}
|
||||
return "updated";
|
||||
}
|
||||
|
||||
/**
|
||||
* Point d'entrée du script.
|
||||
*/
|
||||
async function main() {
|
||||
const timezone = getHugoTimeZone();
|
||||
console.log(`Fuseau horaire Hugo : ${timezone}`);
|
||||
|
||||
const files = await listMarkdownFiles(CONTENT_ROOT);
|
||||
let updated = 0;
|
||||
let unchanged = 0;
|
||||
let skipped = 0;
|
||||
let invalid = 0;
|
||||
|
||||
for (const file of files) {
|
||||
const status = await normalizeFileDate(file);
|
||||
if (status === "updated") updated += 1;
|
||||
else if (status === "unchanged") unchanged += 1;
|
||||
else if (status === "invalid") {
|
||||
invalid += 1;
|
||||
const relative = path.relative(process.cwd(), file);
|
||||
console.warn(`Date invalide : ${relative}`);
|
||||
} else {
|
||||
skipped += 1;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Terminé. ${updated} mis à jour, ${unchanged} inchangés, ${skipped} ignorés, ${invalid} invalides.`
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user