// rehype plugins import rehypeSlug from 'rehype-slug'; import rehypeAutolinkHeadings from 'rehype-autolink-headings'; import rehypeExternalLinks from 'rehype-external-links'; 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 remarkFootnotes from 'remark-footnotes'; // highlighter import { escapeSvelte } from 'mdsvex'; import { lex, parse as parseFence } from 'fenceparser'; import { renderCodeToHTML, runTwoSlash, createShikiHighlighter } from 'shiki-twoslash'; const remarkUraraFm = () => (tree, { data, filename }) => { const filepath = filename.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('/index', '').replace('.svelte', '')); // Generate ToC if (data.fm.toc !== false) { const [slugs, toc] = [new Slugger(), []]; visit(tree, 'heading', (node) => { toc.push({ depth: node.depth, title: toString(node), slug: slugs.slug(toString(node), false) }); }); data.fm.toc = toc; } // 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) => visit(tree, 'paragraph', (node) => { 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, p1) => `${p1}`); } return node; }); const defineConfig = (config) => 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; let twoslash; 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); return `{@html \`${escapeSvelte(renderCodeToHTML(code, lang, fence ?? {}, { themeName: 'material-default' }, await createShikiHighlighter({ theme: 'material-default' }), twoslash))}\` }`; } }, remarkPlugins: [remarkUraraFm, remarkUraraSpoiler, [remarkFootnotes, { inlineNotes: true }]], rehypePlugins: [ rehypeSlug, [rehypeAutolinkHeadings, { behavior: 'wrap' }], [ rehypeExternalLinks, { rel: ['nofollow', 'noopener', 'noreferrer', 'external'], target: '_blank' } ] ] });