💂‍♂️ fixed lint and prittier

This commit is contained in:
RJ
2025-11-14 15:33:00 +02:00
parent 5e9093cf9c
commit 820a2b88d5
43 changed files with 5717 additions and 423 deletions

View File

@@ -1,43 +1,43 @@
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
import { FrontMatter, Post } from './types/frontmatter';
import { generateExcerpt } from './utils';
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import { FrontMatter, Post } from './types/frontmatter'
import { generateExcerpt } from './utils'
const POSTS_PATH = path.join(process.cwd(), 'content', 'blog');
const POSTS_PATH = path.join(process.cwd(), 'content', 'blog')
export function sanitizePath(inputPath: string): string {
const normalized = path.normalize(inputPath).replace(/^(\.\.[\/\\])+/, '');
const normalized = path.normalize(inputPath).replace(/^(\.\.[/\\])+/, '')
if (normalized.includes('..') || path.isAbsolute(normalized)) {
throw new Error('Invalid path');
throw new Error('Invalid path')
}
return normalized;
return normalized
}
export function calculateReadingTime(content: string): number {
const wordsPerMinute = 200;
const words = content.trim().split(/\s+/).length;
return Math.ceil(words / wordsPerMinute);
const wordsPerMinute = 200
const words = content.trim().split(/\s+/).length
return Math.ceil(words / wordsPerMinute)
}
export function validateFrontmatter(data: any): FrontMatter {
if (!data.title || typeof data.title !== 'string') {
throw new Error('Invalid title');
throw new Error('Invalid title')
}
if (!data.description || typeof data.description !== 'string') {
throw new Error('Invalid description');
throw new Error('Invalid description')
}
if (!data.date || typeof data.date !== 'string') {
throw new Error('Invalid date');
throw new Error('Invalid date')
}
if (!data.author || typeof data.author !== 'string') {
throw new Error('Invalid author');
throw new Error('Invalid author')
}
if (!data.category || typeof data.category !== 'string') {
throw new Error('Invalid category');
throw new Error('Invalid category')
}
if (!Array.isArray(data.tags) || data.tags.length === 0 || data.tags.length > 3) {
throw new Error('Tags must be array with 1-3 items');
throw new Error('Tags must be array with 1-3 items')
}
return {
@@ -49,21 +49,21 @@ export function validateFrontmatter(data: any): FrontMatter {
tags: data.tags,
image: data.image,
draft: data.draft || false,
};
}
}
export function getPostBySlug(slug: string | string[]): Post | null {
const slugArray = Array.isArray(slug) ? slug : slug.split('/');
const sanitized = slugArray.map(s => sanitizePath(s));
const fullPath = path.join(POSTS_PATH, ...sanitized) + '.md';
const slugArray = Array.isArray(slug) ? slug : slug.split('/')
const sanitized = slugArray.map(s => sanitizePath(s))
const fullPath = path.join(POSTS_PATH, ...sanitized) + '.md'
if (!fs.existsSync(fullPath)) {
return null;
return null
}
const fileContents = fs.readFileSync(fullPath, 'utf8');
const { data, content } = matter(fileContents);
const frontmatter = validateFrontmatter(data);
const fileContents = fs.readFileSync(fullPath, 'utf8')
const { data, content } = matter(fileContents)
const frontmatter = validateFrontmatter(data)
return {
slug: sanitized.join('/'),
@@ -71,84 +71,86 @@ export function getPostBySlug(slug: string | string[]): Post | null {
content,
readingTime: calculateReadingTime(content),
excerpt: generateExcerpt(content),
};
}
}
export function getAllPosts(includeContent = false): Post[] {
const posts: Post[] = [];
const posts: Post[] = []
function walkDir(dir: string, prefix = ''): void {
const files = fs.readdirSync(dir);
const files = fs.readdirSync(dir)
for (const file of files) {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
const filePath = path.join(dir, file)
const stat = fs.statSync(filePath)
if (stat.isDirectory()) {
walkDir(filePath, prefix ? `${prefix}/${file}` : file);
walkDir(filePath, prefix ? `${prefix}/${file}` : file)
} else if (file.endsWith('.md')) {
const slug = prefix ? `${prefix}/${file.replace(/\.md$/, '')}` : file.replace(/\.md$/, '');
const slug = prefix ? `${prefix}/${file.replace(/\.md$/, '')}` : file.replace(/\.md$/, '')
try {
const post = getPostBySlug(slug.split('/'));
const post = getPostBySlug(slug.split('/'))
if (post && !post.frontmatter.draft) {
posts.push(includeContent ? post : { ...post, content: '' });
posts.push(includeContent ? post : { ...post, content: '' })
}
} catch (error) {
console.error(`Error loading post ${slug}:`, error);
console.error(`Error loading post ${slug}:`, error)
}
}
}
}
if (fs.existsSync(POSTS_PATH)) {
walkDir(POSTS_PATH);
walkDir(POSTS_PATH)
}
return posts.sort((a, b) => new Date(b.frontmatter.date).getTime() - new Date(a.frontmatter.date).getTime());
return posts.sort(
(a, b) => new Date(b.frontmatter.date).getTime() - new Date(a.frontmatter.date).getTime()
)
}
export async function getRelatedPosts(currentSlug: string, limit = 3): Promise<Post[]> {
const currentPost = getPostBySlug(currentSlug);
if (!currentPost) return [];
const currentPost = getPostBySlug(currentSlug)
if (!currentPost) return []
const allPosts = getAllPosts(false);
const { category, tags } = currentPost.frontmatter;
const allPosts = getAllPosts(false)
const { category, tags } = currentPost.frontmatter
const scored = allPosts
.filter(post => post.slug !== currentSlug)
.map(post => {
let score = 0;
if (post.frontmatter.category === category) score += 3;
score += post.frontmatter.tags.filter(tag => tags.includes(tag)).length * 2;
return { post, score };
let score = 0
if (post.frontmatter.category === category) score += 3
score += post.frontmatter.tags.filter(tag => tags.includes(tag)).length * 2
return { post, score }
})
.filter(({ score }) => score > 0)
.sort((a, b) => b.score - a.score);
.sort((a, b) => b.score - a.score)
return scored.slice(0, limit).map(({ post }) => post);
return scored.slice(0, limit).map(({ post }) => post)
}
export function getAllPostSlugs(): string[][] {
const slugs: string[][] = [];
const slugs: string[][] = []
function walkDir(dir: string, prefix: string[] = []): void {
const files = fs.readdirSync(dir);
const files = fs.readdirSync(dir)
for (const file of files) {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
const filePath = path.join(dir, file)
const stat = fs.statSync(filePath)
if (stat.isDirectory()) {
walkDir(filePath, [...prefix, file]);
walkDir(filePath, [...prefix, file])
} else if (file.endsWith('.md')) {
slugs.push([...prefix, file.replace(/\.md$/, '')]);
slugs.push([...prefix, file.replace(/\.md$/, '')])
}
}
}
if (fs.existsSync(POSTS_PATH)) {
walkDir(POSTS_PATH);
walkDir(POSTS_PATH)
}
return slugs;
return slugs
}