1

Synchronisation du contenu avec lemmy

This commit is contained in:
2025-12-11 00:02:53 +01:00
parent a0e9a87e8d
commit 181223d3d9
10 changed files with 1268 additions and 50 deletions

View File

@@ -46,6 +46,33 @@ function applyEnvOverrides(config = {}) {
merged.goaccess.url = process.env.GOACCESS_URL;
}
const lemmy = config.lemmy || {};
const community = lemmy.community || {};
merged.lemmy = {
...lemmy,
auth: { ...(lemmy.auth || {}) },
community: {
...community,
prefixOverrides: { ...(community.prefixOverrides || {}) },
},
verificationTtlHours: { ...(lemmy.verificationTtlHours || {}) },
};
if (process.env.LEMMY_INSTANCE_URL) {
merged.lemmy.instanceUrl = process.env.LEMMY_INSTANCE_URL;
}
if (process.env.LEMMY_SITE_URL) {
merged.lemmy.siteUrl = process.env.LEMMY_SITE_URL;
}
if (process.env.LEMMY_JWT) {
merged.lemmy.auth.jwt = process.env.LEMMY_JWT;
}
if (process.env.LEMMY_USERNAME) {
merged.lemmy.auth.username = process.env.LEMMY_USERNAME;
}
if (process.env.LEMMY_PASSWORD) {
merged.lemmy.auth.password = process.env.LEMMY_PASSWORD;
}
return merged;
}

View File

@@ -92,8 +92,53 @@ async function resolveMarkdownTargets(inputs, { rootDir = process.cwd(), skipInd
return Array.from(targets);
}
async function collectBundles(rootDir) {
const bundles = [];
await walk(rootDir, rootDir, bundles);
bundles.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
return bundles;
}
async function walk(rootDir, currentDir, bucket) {
let entries;
try {
entries = await fs.readdir(currentDir, { withFileTypes: true });
} catch (error) {
console.warn(`⚠️ Lecture impossible de ${currentDir}: ${error.message}`);
return;
}
let hasIndex = false;
for (const entry of entries) {
if (entry.isFile() && entry.name === "index.md") {
hasIndex = true;
break;
}
}
if (hasIndex) {
const relative = path.relative(rootDir, currentDir);
const parts = relative.split(path.sep).filter(Boolean);
const slug = parts[parts.length - 1] || path.basename(currentDir);
bucket.push({
dir: currentDir,
indexPath: path.join(currentDir, "index.md"),
relativePath: parts.join("/"),
parts,
slug,
});
}
for (const entry of entries) {
if (!entry.isDirectory()) continue;
if (entry.name === ".git" || entry.name === "node_modules") continue;
await walk(rootDir, path.join(currentDir, entry.name), bucket);
}
}
module.exports = {
collectMarkdownFiles,
collectSectionIndexDirs,
resolveMarkdownTargets,
collectBundles,
};

View File

@@ -100,8 +100,48 @@ function formatDateTime(value = null) {
return formatted;
}
/**
* Convertit une valeur de frontmatter en DateTime si elle est valide.
* @param {import("luxon").DateTime|Date|string|number|null|undefined} value Valeur lue depuis le frontmatter.
* @returns {import("luxon").DateTime|null} DateTime utilisable ou null si invalide.
*/
function parseFrontmatterDate(value) {
const zone = getHugoTimeZone();
if (DateTime.isDateTime(value)) {
const zoned = value.setZone(zone);
return zoned.isValid ? zoned : null;
}
if (value instanceof Date) {
const zoned = DateTime.fromJSDate(value, { zone });
return zoned.isValid ? zoned : null;
}
if (typeof value === "string") {
const trimmed = value.trim();
if (!trimmed) {
return null;
}
const iso = DateTime.fromISO(trimmed, { setZone: true }).setZone(zone);
if (iso.isValid) {
return iso;
}
const rfc2822 = DateTime.fromRFC2822(trimmed, { setZone: true }).setZone(zone);
return rfc2822.isValid ? rfc2822 : null;
}
if (typeof value === "number" && Number.isFinite(value)) {
const zoned = DateTime.fromMillis(value, { zone }).setZone(zone);
return zoned.isValid ? zoned : null;
}
return null;
}
module.exports = {
formatDateTime,
getHugoTimeZone,
toHugoDateTime,
parseFrontmatterDate,
};

53
tools/lib/frontmatter.js Normal file
View File

@@ -0,0 +1,53 @@
const fs = require("node:fs");
const yaml = require("js-yaml");
const FRONTMATTER_PATTERN = /^---\n([\s\S]*?)\n---\n?/;
/**
* Lit le frontmatter d'un fichier Markdown et retourne son contenu brut.
* La fonction préserve également le corps du fichier afin de permettre
* une réécriture propre après modification.
* @param {string} filePath Chemin absolu du fichier à analyser.
* @returns {{ data: Record<string, any>, body: string, frontmatterText: string, raw: string }|null}
*/
function readFrontmatterFile(filePath) {
const raw = fs.readFileSync(filePath, "utf8");
const match = raw.match(FRONTMATTER_PATTERN);
if (!match) {
return null;
}
const frontmatterText = match[1];
const data = yaml.load(frontmatterText) || {};
const body = raw.slice(match[0].length);
return {
data,
body,
frontmatterText,
raw,
};
}
/**
* Réécrit complètement le fichier Markdown avec un frontmatter mis à jour.
* @param {string} filePath Chemin absolu du fichier.
* @param {Record<string, any>} frontmatter Objet contenant les métadonnées.
* @param {string} body Corps Markdown déjà prêt à être réinséré.
*/
function writeFrontmatterFile(filePath, frontmatter, body) {
if (
typeof frontmatter !== "object" ||
frontmatter === null ||
Array.isArray(frontmatter)
) {
throw new Error(`Frontmatter invalide pour ${filePath}`);
}
const serialized = yaml.dump(frontmatter, { lineWidth: 120, sortKeys: false }).trimEnd();
const contentBody = typeof body === "string" ? body : "";
const rewritten = `---\n${serialized}\n---\n${contentBody}`;
fs.writeFileSync(filePath, rewritten, "utf8");
}
module.exports = {
readFrontmatterFile,
writeFrontmatterFile,
};