HaoAws/lib/markdown.ts

126 lines
3.8 KiB
TypeScript
Raw Normal View History

2025-09-16 16:37:48 +08:00
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
import { Locale } from './i18n';
export interface NewsArticle {
id: string;
title: string;
category: string;
date: string;
excerpt: string;
author: string;
readTime: string;
tags: string[];
featured: boolean;
content: string;
locale: Locale;
}
const DOCS_PATH = path.join(process.cwd(), 'docs', 'news');
export async function getNewsArticle(id: string, locale: Locale): Promise<NewsArticle | null> {
try {
const filePath = path.join(DOCS_PATH, locale, `${id}.md`);
if (!fs.existsSync(filePath)) {
return null;
}
const fileContents = fs.readFileSync(filePath, 'utf8');
const { data, content } = matter(fileContents);
return {
id,
title: data.title,
category: data.category,
date: data.date,
excerpt: data.excerpt,
author: data.author,
readTime: data.readTime,
tags: data.tags || [],
featured: data.featured || false,
content,
locale,
};
} catch (error) {
console.error(`Error reading article ${id} for locale ${locale}:`, error);
return null;
}
}
export async function getAllNewsArticles(locale: Locale): Promise<NewsArticle[]> {
try {
const articlesDir = path.join(DOCS_PATH, locale);
if (!fs.existsSync(articlesDir)) {
return [];
}
const filenames = fs.readdirSync(articlesDir);
const articles: NewsArticle[] = [];
for (const filename of filenames) {
if (filename.endsWith('.md')) {
const id = filename.replace(/\.md$/, '');
const article = await getNewsArticle(id, locale);
if (article) {
articles.push(article);
}
}
}
// Sort by date (newest first)
// Handle Chinese date format (e.g., "2024年1月15日")
const parseChineseDate = (dateStr: string): Date => {
// Try to parse Chinese date format first
const chineseDateMatch = dateStr.match(/(\d{4})年(\d{1,2})月(\d{1,2})日/);
if (chineseDateMatch) {
const [, year, month, day] = chineseDateMatch;
return new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
}
// Fallback to regular Date parsing
return new Date(dateStr);
};
return articles.sort((a, b) => {
const dateA = parseChineseDate(a.date);
const dateB = parseChineseDate(b.date);
return dateB.getTime() - dateA.getTime();
});
} catch (error) {
console.error(`Error reading articles for locale ${locale}:`, error);
return [];
}
}
export async function getAvailableLocalesForArticle(id: string): Promise<Locale[]> {
const availableLocales: Locale[] = [];
const locales: Locale[] = ['zh-CN', 'zh-TW', 'en'];
for (const locale of locales) {
const filePath = path.join(DOCS_PATH, locale, `${id}.md`);
if (fs.existsSync(filePath)) {
availableLocales.push(locale);
}
}
return availableLocales;
}
export function checkArticleExists(id: string, locale: Locale): boolean {
const filePath = path.join(DOCS_PATH, locale, `${id}.md`);
return fs.existsSync(filePath);
}
/**
*
* @param locale
* @param limit 3
* @returns
*/
export async function getLatestNewsArticles(locale: Locale, limit: number = 3): Promise<NewsArticle[]> {
const allArticles = await getAllNewsArticles(locale);
return allArticles.slice(0, limit);
}