-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
mdsvex.config.ts
131 lines (124 loc) · 4.16 KB
/
mdsvex.config.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// mdsvex config type
import type { MdsvexOptions } from 'mdsvex'
// rehype plugins
import rehypeSlug from 'rehype-slug'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypeExternalLinks from 'rehype-external-links'
// urara remark plugins
import type { Node, Data } from 'unist'
// import { statSync } from 'fs'
import { parse, join } from 'path'
import { visit } from 'unist-util-visit'
import { toString } from 'mdast-util-to-string'
import Slugger from 'github-slugger'
import remarkFFF from 'remark-fff'
import remarkFootnotes from 'remark-footnotes'
// highlighter
import { escapeSvelte } from 'mdsvex'
import { lex, parse as parseFence } from 'fenceparser'
import { renderCodeToHTML, runTwoSlash, createShikiHighlighter } from 'shiki-twoslash'
type VALUE = { [key in string | number]: VALUE } | Array<VALUE> | string | boolean | number
const remarkUraraFm =
() =>
(tree: Node<Data>, { data, filename }: { data: { fm?: Record<string, unknown> }; filename?: string }) => {
const filepath = (filename as string).split('/src/routes')[1]
const { dir, name } = parse(filepath)
if (!data.fm) data.fm = {}
// Generate slug & path
data.fm.slug = filepath
data.fm.path = join(dir, `/${name}`.replace('/+page', '').replace('.svelte', ''))
// Generate ToC
if (data.fm.toc !== false) {
const [slugs, toc]: [slugs: Slugger, toc: { depth: number; title: string; slug: string }[]] = [new Slugger(), []]
visit(tree, 'heading', (node: { depth: number }) => {
toc.push({
depth: node.depth,
title: toString(node),
slug: slugs.slug(toString(node), false)
})
})
data.fm.toc = toc
}
// Rename
if (data.fm.date) data.fm.created = data.fm.date
if (data.fm.lastmod) data.fm.updated = data.fm.lastmod
if (data.fm.cover) data.fm.photo = data.fm.cover
if (data.fm.descr) data.fm.summary = data.fm.descr
// Auto-read created & updated
// if (!data.fm.created || !data.fm.updated) {
// const { ctime, mtime } = statSync(new URL(`./urara${filepath}`, import.meta.url))
// if (!data.fm.created) data.fm.created = ctime
// if (!data.fm.updated) data.fm.updated = mtime
// }
}
// Better type definitions needed
const remarkUraraSpoiler = () => (tree: Node<Data>) =>
visit(tree, 'paragraph', (node: any) => {
const { children } = node
const text = children[0].value
const re = /\|\|(.{1,}?)\|\|/g
if (re.test(children[0].value)) {
children[0].type = 'html'
children[0].value = text.replace(re, (_match: unknown, p1: string) => `<span class="spoiler">${p1}</span>`)
}
return node
})
const defineConfig = (config: MdsvexOptions) => config
export default defineConfig({
extensions: ['.svelte.md', '.md'],
smartypants: {
dashes: 'oldschool'
},
layout: {
_: './src/lib/components/post_layout.svelte'
},
highlight: {
highlighter: async (code, lang, meta) => {
let fence: Record<string, VALUE> | null
let twoslash: any
try {
fence = parseFence(lex([lang, meta].filter(Boolean).join(' ')))
} catch (error) {
throw new Error(`Could not parse the codefence for this code sample \n${code}`)
}
if (fence?.twoslash === true) twoslash = runTwoSlash(code, lang as string)
return `{@html \`${escapeSvelte(
renderCodeToHTML(
code,
lang as string,
fence ?? {},
{ themeName: 'material-default' },
await createShikiHighlighter({ theme: 'material-default' }),
twoslash
)
)}\` }`
}
},
remarkPlugins: [
[
remarkFFF as any,
{
presets: ['hugo'],
target: 'mdsvex',
autofill: {
provider: 'fs',
path: (path: string) => new URL(`./urara${path.split('/src/routes')[1]}`, import.meta.url)
}
}
],
remarkUraraFm,
remarkUraraSpoiler,
[remarkFootnotes, { inlineNotes: true }]
],
rehypePlugins: [
rehypeSlug as any,
[rehypeAutolinkHeadings, { behavior: 'wrap' }],
[
rehypeExternalLinks,
{
rel: ['nofollow', 'noopener', 'noreferrer', 'external'],
target: '_blank'
}
]
]
})