import fs from 'node:fs'; import mustache from 'mustache'; import {u} from 'unist-builder'; import {h} from 'hastscript'; import {select} from 'hast-util-select'; import {toString as hastToString} from 'mdast-util-to-string'; import cssesc from 'cssesc'; import {toHtmlRaw, toString, toMdRaw, mdToHtmlRaw} from './to-html.mjs'; import loadSVG from './load-svg.mjs'; import listArticles from './list-articles.mjs'; import getRSS from './rss.mjs'; import toml from '@ltd/j-toml'; function getArticleYear(article) { if(article.metaData.pubDate.getFullYear) { return article.metaData.pubDate.getFullYear(); } else if(article.metaData.pubDate.getUTCFullYear) { return article.metaData.pubDate.getUTCFullYear(); } return 0; } function getArticleDate(article) { if(article.metaData.pubDate.getDate) { return article.metaData.pubDate.getFullYear() * 100 + article.metaData.pubDate.getDate(); } else if(article.metaData.pubDate.getUTCDate) { return article.metaData.pubDate.getUTCFullYear() * 100 + article.metaData.pubDate.getDate(); } return 0; } function cmpArticles(a, b) { return getArticleDate(b) - getArticleDate(a); } const loadMD = (listFile, suffix) => { const listContent = []; for (const file of listFile) { console.log(`Working on ${file}`); const content = fs.readFileSync(`${suffix}/${file}`, 'utf8'); const mdRaw = toMdRaw(content); const tomlStringValue = mdRaw.children[0].value; const metaData = toml.parse(tomlStringValue); const newHTML = mdToHtmlRaw(mdRaw); const htmlContent = newHTML; const htmlRender = toString(htmlContent); const titleHtml = select('h1', htmlContent); const intro = select('p', htmlContent); intro.children = intro.children.filter(child => child.tagName !== 'br'); const logo = select('img', intro); logo.properties.src = `${suffix}/${logo.properties.src}`; logo.properties.height = '150'; logo.properties.width = '150'; titleHtml.children[0].properties.href = `${suffix}/${file.slice(0, -3)}`; const title = hastToString(titleHtml); const domTitle = cssesc(title.replace(/\s+/g, '-').replace(/['"#@]/, '').toLowerCase()); // Maybe encodeURI const readMore = h('a', 'Lire plus...'); readMore.properties.href = `${suffix}/${file.slice(0, -3)}`; const pubYear = getArticleYear({metaData}); listContent.push({ name: file.slice(0, -3), content: htmlRender, intro: toString(u('root', [titleHtml, intro, readMore])), introDesc: hastToString(intro), imageUrl: logo.properties.src, metaData, pubYear, title, domTitle, url: `/${suffix}/${file.slice(0, -3)}`, }); } return listContent; }; const leftPanelTmpl = fs.readFileSync('src/templates/left.tmpl', 'utf8'); const headerTmpl = fs.readFileSync('src/templates/header.tmpl', 'utf8'); const articleTmpl = fs.readFileSync('src/templates/article.tmpl', 'utf8'); const indexTmpl = fs.readFileSync('src/templates/index.tmpl', 'utf8'); const tagTmpl = fs.readFileSync('src/templates/tag.tmpl', 'utf8'); const hidTmpl = fs.readFileSync('src/templates/hid.tmpl', 'utf8'); const baseUrl = 'https://ache.one/'; const partials = { header: headerTmpl, leftPanel: leftPanelTmpl, hid: hidTmpl, }; const svg = loadSVG(); const articles = loadMD(listArticles, 'articles'); const tagsArticle = new Map(); for (const article of articles) { const context = { svg, title: `${article.title} - ache`, canonical: article.url, content: article.content, domTitle: article.domTitle, metaData: article.metaData, }; const output = mustache.render(articleTmpl, context, partials); console.log(`Create : ${article.title}`); fs.writeFileSync(`articles/${article.name}.html`, output); for (const tag of article.metaData.tags) { if (tagsArticle.has(tag)) { tagsArticle.get(tag).push(article); } else { tagsArticle.set(tag, [article]); } } } try { fs.mkdirSync('tag'); } catch { fs.rmSync('tag', {force: true, recursive: true}); fs.mkdirSync('tag'); } for (const [tag, articles] of tagsArticle.entries()) { console.log(`Create tag page : ${tag}.xml`); articles.sort(cmpArticles); const context = { svg, title: `ache - Tag: ${tag}`, tag, articles, }; const output = mustache.render(tagTmpl, context, partials); fs.writeFileSync(`tag/${tag}.html`, output); } console.log('Create RSS Flux: rss.xml'); const xmlFeed = getRSS(articles, baseUrl); fs.writeFileSync('rss.xml', xmlFeed); { const context = { title: 'ache: Blog personnel', canonical: baseUrl, svg, articles, }; console.log('Create : Home page'); const output = mustache.render(indexTmpl, context, partials); fs.writeFileSync('index.html', output); }