jonbio/lib/mdx.js

111 lines
3.2 KiB
JavaScript
Raw Normal View History

2021-05-26 00:11:20 +08:00
import { MDXComponents } from '@/components/MDXComponents'
2021-01-09 17:50:45 +08:00
import fs from 'fs'
import matter from 'gray-matter'
import { serialize } from 'next-mdx-remote/serialize'
2021-01-09 17:50:45 +08:00
import path from 'path'
import readingTime from 'reading-time'
import visit from 'unist-util-visit'
2021-01-09 17:50:45 +08:00
import imgToJsx from './img-to-jsx'
import getAllFilesRecursively from './utils/files'
2021-01-09 17:50:45 +08:00
const root = process.cwd()
const tokenClassNames = {
tag: 'text-code-red',
'attr-name': 'text-code-yellow',
'attr-value': 'text-code-green',
deleted: 'text-code-red',
inserted: 'text-code-green',
punctuation: 'text-code-white',
keyword: 'text-code-purple',
string: 'text-code-green',
function: 'text-code-blue',
boolean: 'text-code-red',
comment: 'text-gray-400 italic',
}
export function getFiles(type) {
const prefixPaths = path.join(root, 'data', type)
const files = getAllFilesRecursively(prefixPaths)
2021-05-11 22:34:26 +08:00
// Only want to return blog/path and ignore root, replace is needed to work on Windows
return files.map((file) => file.slice(prefixPaths.length + 1).replace(/\\/g, '/'))
2021-01-09 17:50:45 +08:00
}
2021-01-16 18:38:45 +08:00
export function formatSlug(slug) {
return slug.replace(/\.(mdx|md)/, '')
}
2021-01-09 17:50:45 +08:00
export function dateSortDesc(a, b) {
if (a > b) return -1
if (a < b) return 1
return 0
}
export async function getFileBySlug(type, slug) {
const mdxPath = path.join(root, 'data', type, `${slug.join('/')}.mdx`)
const mdPath = path.join(root, 'data', type, `${slug.join('/')}.md`)
2021-01-09 17:50:45 +08:00
const source = fs.existsSync(mdxPath)
? fs.readFileSync(mdxPath, 'utf8')
: fs.readFileSync(mdPath, 'utf8')
const { data, content } = matter(source)
const mdxSource = await serialize(content, {
2021-01-09 17:50:45 +08:00
components: MDXComponents,
mdxOptions: {
remarkPlugins: [
require('remark-slug'),
require('remark-autolink-headings'),
require('remark-code-titles'),
require('remark-math'),
imgToJsx,
],
inlineNotes: true,
rehypePlugins: [
require('rehype-katex'),
require('@mapbox/rehype-prism'),
() => {
return (tree) => {
visit(tree, 'element', (node, index, parent) => {
let [token, type] = node.properties.className || []
if (token === 'token') {
node.properties.className = [tokenClassNames[type]]
}
})
}
},
],
},
})
return {
mdxSource,
frontMatter: {
wordCount: content.split(/\s+/gu).length,
readingTime: readingTime(content),
slug: slug || null,
2021-01-10 16:55:38 +08:00
fileName: fs.existsSync(mdxPath) ? `${slug}.mdx` : `${slug}.md`,
2021-01-09 17:50:45 +08:00
...data,
},
}
}
export async function getAllFilesFrontMatter(folder) {
const prefixPaths = path.join(root, 'data', folder)
const files = getAllFilesRecursively(prefixPaths)
2021-01-09 17:50:45 +08:00
2021-01-16 18:36:25 +08:00
const allFrontMatter = []
files.forEach((file) => {
2021-05-11 22:34:26 +08:00
// Replace is needed to work on Windows
const fileName = file.slice(prefixPaths.length + 1).replace(/\\/g, '/')
const source = fs.readFileSync(file, 'utf8')
2021-01-09 17:50:45 +08:00
const { data } = matter(source)
2021-01-16 18:36:25 +08:00
if (data.draft !== true) {
allFrontMatter.push({ ...data, slug: formatSlug(fileName) })
2021-01-16 18:36:25 +08:00
}
})
2021-01-09 17:50:45 +08:00
return allFrontMatter.sort((a, b) => dateSortDesc(a.date, b.date))
}