iboard/server/articles.js
2026-08-03 18:05:50 +08:00

49 lines
1.6 KiB
JavaScript

// 从 content/articles/*.md 读取文章列表和详情
import fs from 'node:fs'
import path from 'node:path'
import matter from 'gray-matter'
import { marked } from 'marked'
const DIR = path.join(process.cwd(), 'content', 'articles')
function readAll() {
if (!fs.existsSync(DIR)) return []
return fs.readdirSync(DIR)
.filter((f) => f.endsWith('.md'))
.map((fileName) => {
const fullPath = path.join(DIR, fileName)
const raw = fs.readFileSync(fullPath, 'utf8')
const { data, content } = matter(raw)
const slug = fileName.replace(/\.md$/, '')
const dateMatch = fileName.match(/^(\d{4}-\d{2}-\d{2})-/)
const date = dateMatch ? dateMatch[1] : ''
return {
slug,
date,
title: data.title || slug.replace(/^\d{4}-\d{2}-\d{2}-/, ''),
excerpt: content.replace(/\s+/g, ' ').trim().slice(0, 150) + (content.length > 150 ? '...' : ''),
}
})
.sort((a, b) => (a.date < b.date ? 1 : -1))
}
export function listArticles() {
return readAll().map(({ slug, title, date, excerpt }) => ({ slug, title, date, excerpt }))
}
export function getArticle(slug) {
// 防止路径穿越
if (slug.includes('/') || slug.includes('\\') || slug.includes('..')) return null
const fullPath = path.join(DIR, slug + '.md')
if (!fs.existsSync(fullPath)) return null
const raw = fs.readFileSync(fullPath, 'utf8')
const { data, content } = matter(raw)
const dateMatch = slug.match(/^(\d{4}-\d{2}-\d{2})-/)
const date = dateMatch ? dateMatch[1] : ''
return {
slug,
date,
title: data.title || slug.replace(/^\d{4}-\d{2}-\d{2}-/, ''),
contentHtml: marked.parse(content),
}
}