-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
90 additions
and
75 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,54 @@ | ||
import type { BlogMetadata } from '$lib/types'; | ||
import dayjs from 'dayjs'; | ||
import yaml from 'js-yaml'; | ||
import type { Root } from 'mdast'; | ||
import rehypeExternalLinks from 'rehype-external-links'; | ||
import highlight from 'rehype-highlight'; | ||
import rehypeHighlight from 'rehype-highlight'; | ||
import rehypeStringify from 'rehype-stringify'; | ||
import frontmatter from 'remark-frontmatter'; | ||
import gfm from 'remark-gfm'; | ||
import parse from 'remark-parse'; | ||
import remarkFrontmatter from 'remark-frontmatter'; | ||
import remarkGfm from 'remark-gfm'; | ||
import remarkParse from 'remark-parse'; | ||
import remark2rehype from 'remark-rehype'; | ||
import remarkUnwrapImages from 'remark-unwrap-images'; | ||
import * as vfile from 'to-vfile'; | ||
import { unified } from 'unified'; | ||
|
||
const parser = unified().use(parse).use(gfm).use(frontmatter, ['yaml']); | ||
const remarkParser = unified().use(remarkParse).use(remarkGfm).use(remarkFrontmatter, ['yaml']); | ||
|
||
const runner = unified() | ||
.use(remark2rehype) | ||
.use(highlight) | ||
.use(rehypeExternalLinks, { rel: ['nofollow', 'noopener'] }) | ||
.use(rehypeStringify) | ||
.use(remarkUnwrapImages); | ||
const rehypeConverter = unified() | ||
.use(remark2rehype) | ||
.use(remarkUnwrapImages) | ||
.use(rehypeHighlight) | ||
.use(rehypeExternalLinks, { rel: ['nofollow', 'noopener'] }) | ||
.use(rehypeStringify); | ||
|
||
export function process(filename: string): { metadata: BlogMetadata; content: string } { | ||
const tree = parser.parse(vfile.readSync(filename)); | ||
let metadata: BlogMetadata = null; | ||
const slug = filename.slice(filename.lastIndexOf('/') + 1, -3); | ||
if (tree.children.length > 0 && tree.children[0].type == 'yaml') { | ||
metadata = yaml.load(tree.children[0].value) as BlogMetadata; | ||
tree.children = tree.children.slice(1, tree.children.length); | ||
metadata.date = dayjs(metadata.date).valueOf(); | ||
metadata.slug = slug; | ||
} | ||
export async function processMetadata( | ||
filename: string | ||
): Promise<{ metadata: BlogMetadata; tree: Root }> { | ||
const file = await vfile.read(filename); | ||
const remarkTree = remarkParser.parse(file); | ||
const slug = filename.slice(filename.lastIndexOf('/') + 1, -3); | ||
let metadata: BlogMetadata = null; | ||
if (remarkTree.children.length > 0 && remarkTree.children[0].type == 'yaml') { | ||
metadata = yaml.load(remarkTree.children[0].value) as BlogMetadata; | ||
remarkTree.children = remarkTree.children.slice(1, remarkTree.children.length); | ||
metadata.date = dayjs(metadata.date).valueOf(); | ||
metadata.slug = slug; | ||
} | ||
if (!metadata) { | ||
throw new Error(`No Frontmatter in file ${filename}`); | ||
} | ||
return { | ||
metadata, | ||
tree: remarkTree | ||
}; | ||
} | ||
|
||
// the typings of remark and rehype are not compatible but remark2rehype works just fine anyway | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const remarkTree: any = runner.runSync(tree) | ||
let content = runner.stringify(remarkTree); | ||
if (!metadata) { | ||
metadata = { | ||
title: 'Error!', | ||
date: dayjs().valueOf(), | ||
excerpt: 'Missing Frontmatter! Expected at least a title and a date!', | ||
slug: slug, | ||
tags: [] | ||
}; | ||
content = 'Missing Frontmatter! Expected at least a title and a date!'; | ||
} | ||
return { metadata, content }; | ||
export async function process( | ||
filename: string | ||
): Promise<{ metadata: BlogMetadata; content: string }> { | ||
const { metadata, tree } = await processMetadata(filename); | ||
const rehypeTree = await rehypeConverter.run(tree); | ||
const content = rehypeConverter.stringify(rehypeTree); | ||
return { metadata, content }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,28 @@ | ||
import { process } from '$lib/blog/markdown'; | ||
import { processMetadata } from '$lib/blog/markdown'; | ||
import dayjs from 'dayjs'; | ||
import fs from 'fs'; | ||
|
||
const mdRegex = /.+\.md$/; | ||
|
||
export const getBlogPosts = function () { | ||
const posts = fs | ||
.readdirSync(`src/posts`) | ||
.filter((fileName) => /.+\.md$/.test(fileName)) | ||
.map((fileName) => { | ||
const { metadata } = process(`src/posts/${fileName}`); | ||
return metadata; | ||
}); | ||
// sort the posts by create date. | ||
posts.sort((a, b) => dayjs(b.date).valueOf() - dayjs(a.date).valueOf()); | ||
export const getBlogPosts = async function () { | ||
const filesPromise = new Promise<string[]>((resolve, reject) => { | ||
fs.readdir(`src/posts`, (err, files) => { | ||
if (err) { | ||
reject(err); | ||
} | ||
resolve(files.filter((fileName) => mdRegex.test(fileName))); | ||
}); | ||
}); | ||
const files = await filesPromise; | ||
const postMetas = await Promise.all( | ||
files.map(async (fileName) => { | ||
const { metadata } = await processMetadata(`src/posts/${fileName}`); | ||
return metadata; | ||
}) | ||
); | ||
|
||
return posts; | ||
} | ||
// sort the posts by create date. | ||
postMetas.sort((a, b) => dayjs(b.date).valueOf() - dayjs(a.date).valueOf()); | ||
|
||
return postMetas; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters