Page de statistiques
This commit is contained in:
91
tools/lib/stats/articles.js
Normal file
91
tools/lib/stats/articles.js
Normal file
@@ -0,0 +1,91 @@
|
||||
const path = require("path");
|
||||
const { DateTime } = require("luxon");
|
||||
const { collectMarkdownFiles, collectSectionIndexDirs } = require("../content");
|
||||
const { readFrontmatter } = require("../weather/frontmatter");
|
||||
|
||||
function parseDate(value) {
|
||||
if (!value) return null;
|
||||
|
||||
if (value instanceof Date) {
|
||||
return DateTime.fromJSDate(value);
|
||||
}
|
||||
|
||||
if (typeof value === "string") {
|
||||
let parsed = DateTime.fromISO(value);
|
||||
|
||||
if (!parsed.isValid) {
|
||||
parsed = DateTime.fromRFC2822(value);
|
||||
}
|
||||
|
||||
return parsed.isValid ? parsed : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function countWords(body) {
|
||||
if (!body) return 0;
|
||||
|
||||
const cleaned = body
|
||||
.replace(/```[\s\S]*?```/g, " ") // fenced code blocks
|
||||
.replace(/`[^`]*`/g, " ") // inline code
|
||||
.replace(/<[^>]+>/g, " "); // html tags
|
||||
|
||||
const words = cleaned.match(/[\p{L}\p{N}'-]+/gu);
|
||||
return words ? words.length : 0;
|
||||
}
|
||||
|
||||
async function loadArticles(contentDir) {
|
||||
const files = await collectMarkdownFiles(contentDir);
|
||||
const sectionDirs = await collectSectionIndexDirs(contentDir);
|
||||
const rootDir = path.resolve(contentDir);
|
||||
const articles = [];
|
||||
|
||||
function resolveSection(filePath) {
|
||||
const absolute = path.resolve(filePath);
|
||||
let current = path.dirname(absolute);
|
||||
|
||||
while (current.startsWith(rootDir)) {
|
||||
if (sectionDirs.has(current)) {
|
||||
return path.relative(rootDir, current).replace(/\\/g, "/") || ".";
|
||||
}
|
||||
const parent = path.dirname(current);
|
||||
if (parent === current) break;
|
||||
current = parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const file of files) {
|
||||
const frontmatter = await readFrontmatter(file);
|
||||
if (!frontmatter) continue;
|
||||
|
||||
const date = parseDate(frontmatter.doc.get("date"));
|
||||
const title = frontmatter.doc.get("title") || path.basename(file, ".md");
|
||||
const body = frontmatter.body.trim();
|
||||
const wordCount = countWords(body);
|
||||
const relativePath = path.relative(contentDir, file);
|
||||
const section = resolveSection(file);
|
||||
|
||||
articles.push({
|
||||
path: file,
|
||||
relativePath,
|
||||
title,
|
||||
date,
|
||||
body,
|
||||
wordCount,
|
||||
section,
|
||||
frontmatter: frontmatter.doc.toJS ? frontmatter.doc.toJS() : frontmatter.doc.toJSON(),
|
||||
});
|
||||
}
|
||||
|
||||
return articles;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
collectMarkdownFiles,
|
||||
countWords,
|
||||
loadArticles,
|
||||
parseDate,
|
||||
};
|
||||
Reference in New Issue
Block a user