import marked from "marked"; import express from "express" import ejs from "ejs"; import fs from "fs"; import path from "path"; import jsdom from "jsdom"; import config from "./data/config.json" let app = express(); // set view engine to ejs app.set("view engine", "ejs") app.set('views', path.join(__dirname, 'data','templates')) // type for post object type Post = { file: string; title: string; parsedPost: string; rawPost: string; metadata: fs.Stats; } // html stripper, used for title async function htmlstripper(html: string){ return new jsdom.JSDOM(html).window.document.body.textContent || " "; } // returns Post array async function contentScan(){ let posts: Post[] = [] let postsDir = path.join(__dirname, 'data',"posts") let files = await fs.readdirSync(postsDir).filter((name: string) => name.toLowerCase().endsWith(".md")) for (const file of files) { let postPath = path.join(postsDir, file) let metadata = fs.statSync(postPath) let postContent = fs.readFileSync(postPath, "utf-8") posts.push( { file: file, title: await htmlstripper( await marked.parse( postContent.split("\n")[0] ) ), metadata: metadata, parsedPost: await marked.parse(postContent), rawPost: postContent } ) } return posts; } app.get("/", async (req:express.Request,res:express.Response) => { res.render("index", {posts: (await contentScan()), config: config}) }); app.use("/post/:post", async (req:express.Request,res:express.Response) => { let pathToPost = path.join(__dirname, "posts", req.params.post); if(!fs.existsSync(pathToPost)) return res.end("404."); let posts = await contentScan(); let post = posts.filter(post => post.file === req.params.post) if(!post[0]) return res.end("404.") res.render("post", {posts: posts, post: post[0], config: config}) }) app.listen(3024)