import{readFileSync,writeFileSync,mkdirSync,cpSync,readdirSync,existsSync,statSync}from'fs' import{join,extname}from'path' import matter from'gray-matter' import{marked}from'marked' const ARTICLES='articles',DIST='dist',TEMPLATES='templates',STATIC='static' const template=n=>readFileSync(join(TEMPLATES,n),'utf-8') const articleTmpl=template('article.html') const homeTmpl=template('home.html') mkdirSync(DIST,{recursive:true}) if(existsSync(STATIC)) cpSync(STATIC,DIST,{recursive:true}) const articles=[] for(const slug of readdirSync(ARTICLES)){ const dir=join(ARTICLES,slug) if(!statSync(dir).isDirectory()) continue const mdPath=join(dir,'index.md') if(!existsSync(mdPath)) continue const{data,content}=matter(readFileSync(mdPath,'utf-8')) const html=marked(content) const outDir=join(DIST,slug) mkdirSync(outDir,{recursive:true}) // copy co-located assets for(const f of readdirSync(dir)){ if(f==='index.md') continue cpSync(join(dir,f),join(outDir,f)) } const page=articleTmpl .replace('{{title}}',data.title||slug) .replace('{{date}}',data.date?new Date(data.date).toLocaleDateString('en-US',{month:'long',day:'numeric',year:'numeric'}):'') .replace('{{date_iso}}',data.date?new Date(data.date).toISOString().split('T')[0]:'') .replace('{{tags}}', (data.tags||[]).map(t=>`${t}`).join(' ')) .replace('{{excerpt}}',data.excerpt||'') .replace('{{slug}}',slug) .replace('{{body}}',html) writeFileSync(join(outDir,'index.html'),page) articles.push({slug,...data}) console.log(`āœ… ${slug}`) } articles.sort((a,b)=>new Date(b.date)-new Date(a.date)) const articleListHtml=articles.map(a=>`

${a.title}

${a.excerpt?`

${a.excerpt}

`:''}
${(a.tags||[]).map(t=>`${t}`).join('')}
`).join('\n') const home=homeTmpl.replace('{{articles}}',articleListHtml) writeFileSync(join(DIST,'index.html'),home) console.log(`\nšŸ  index.html → ${articles.length} article(s)`)