Skip to content

Instantly share code, notes, and snippets.

@i-am-the-slime
Last active June 24, 2023 10:40
Show Gist options
  • Save i-am-the-slime/35f212988e306c58b63fd423d48b09a0 to your computer and use it in GitHub Desktop.
Save i-am-the-slime/35f212988e306c58b63fd423d48b09a0 to your computer and use it in GitHub Desktop.
module BuildTime.GetMDXFiles where
import Prelude
import Node.FS.Aff (readTextFile, readdir)
import Data.Foldable (for_)
import Node.Glob.Basic (expandGlobsCwd)
import BuildTime.MDXBundler (EsbuildOptions, Extension(Extension), RehypePlugin, RemarkPlugin, addLoader, addRehypePlugins, addRemarkPlugins, bundleMDX, setPlatform)
import Node.Encoding (Encoding(..))
import Debug (spy)
import Effect.Aff (launchAff_)
import Effect.Uncurried (EffectFn1, EffectFn2, mkEffectFn1, mkEffectFn2)
import Effect (Effect)
import Record.Unsafe (unsafeSet)
import Unsafe.Coerce (unsafeCoerce)
import Data.Traversable (for)
import Control.Promise (fromAff) as Promise
import Control.Promise (Promise)
import Data.Set (Set)
import Data.Set (toUnfoldable) as Set
type Frontmatter = {}
getMdxFiles :: EffectFn2 { remarkPlugins :: Array RemarkPlugin, rehypePlugins :: Array RehypePlugin } (Array String) (Promise (Array _))
getMdxFiles = mkEffectFn2 \plugins globs -> Promise.fromAff do
filePaths <- expandGlobsCwd globs <#> Set.toUnfoldable
parsed <- for filePaths \filePath -> do
source <- readTextFile UTF8 filePath
{ code, frontmatter } <- bundleMDX @Frontmatter
{ source
, mdxOptions: mkEffectFn2 \opts (_ :: Frontmatter) -> do
opts # addRehypePlugins plugins.rehypePlugins
opts # addRemarkPlugins plugins.remarkPlugins
pure opts
, esbuildOptions: mkEffectFn2
\(opts :: EsbuildOptions) (_ :: Frontmatter) -> do
opts # setPlatform "node"
opts # addLoader (Extension ".purs") "text"
pure opts
}
let _ = spy "path" filePath
pure { path: filePath, code, frontmatter }
pure parsed
import {bundleMDX} from 'mdx-bundler'
export const bundleMDXImpl = bundleMDX
export const addRehypePluginsImpl = (plugins, config) => config.rehypePlugins = [...(config.rehypePlugins ?? []), ...plugins]
export const addRemarkPluginsImpl = (plugins, config) => config.remarkPlugins = [...(config.remarkPlugins ?? []), ...plugins]
export const setPlatformImpl = (value, config) => config.platform = value
export const addLoaderImpl = (filetype, loader, config) => config.loader = {...config.loader, [filetype]: loader }
module BuildTime.MDXBundler where
import Prelude
import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, runEffectFn1, runEffectFn2, runEffectFn3)
import Data.Undefined.NoProblem (Opt, SNil)
import Control.Promise (Promise, toAffE)
import Data.Undefined.NoProblem.Open (class Coerce, class CoerceProp, coerce) as Open
import Effect.Aff (Aff)
import Effect (Effect)
import Unsafe.Coerce (unsafeCoerce)
foreign import data MdxOptions :: Type
foreign import data Frontmatter :: Type
foreign import data EsbuildOptions :: Type
foreign import data RemarkPlugin :: Type
foreign import data RehypePlugin :: Type
type BundleMdxOptions frontmatter =
{ source :: String
, mdxOptions :: Opt (EffectFn2 MdxOptions frontmatter MdxOptions)
, esbuildOptions :: Opt (EffectFn2 EsbuildOptions frontmatter EsbuildOptions)
}
foreign import bundleMDXImpl :: forall frontmatter. EffectFn1
(BundleMdxOptions frontmatter)
(Promise { code :: String, frontmatter :: frontmatter })
bundleMDX :: forall @frontmatter given.
Open.Coerce given (BundleMdxOptions frontmatter)
=> given -> Aff { code :: String , frontmatter :: frontmatter }
bundleMDX opts = toAffE (runEffectFn1 bundleMDXImpl (Open.coerce opts))
foreign import addRehypePluginsImpl :: EffectFn2 (Array RehypePlugin) MdxOptions Unit
foreign import addRemarkPluginsImpl :: EffectFn2 (Array RemarkPlugin) MdxOptions Unit
addRehypePlugins :: (Array RehypePlugin) -> MdxOptions -> Effect Unit
addRehypePlugins = runEffectFn2 addRehypePluginsImpl
addRemarkPlugins :: (Array RemarkPlugin) -> MdxOptions -> Effect Unit
addRemarkPlugins = runEffectFn2 addRemarkPluginsImpl
foreign import setPlatformImpl :: EffectFn2 String EsbuildOptions Unit
setPlatform :: String -> EsbuildOptions -> Effect Unit
setPlatform = runEffectFn2 setPlatformImpl
newtype Extension = Extension String
foreign import addLoaderImpl :: EffectFn3 Extension String EsbuildOptions Unit
addLoader :: Extension -> String -> EsbuildOptions -> Effect Unit
addLoader = runEffectFn3 addLoaderImpl
import {allPosts} from 'contentlayer/generated'
import {default as Page} from "@/output/Alethic.Page.View"
import {notFound} from "next/navigation";
import {getMdxFiles} from "@/output/BuildTime.GetMDXFiles"
import remarkGfm from "remark-gfm";
import rehypeSlug from "rehype-slug";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import {h, s} from "hastscript";
import rehypePrettyCode from "rehype-pretty-code";
import {getHighlighter} from "@/contentlayer/shiki";
const mdx = {
remarkPlugins: [[remarkGfm]],
rehypePlugins: [
[rehypeSlug],
[
rehypeAutolinkHeadings,
{
behavior: "prepend",
properties: {
properties: {
className: 'autolink',
ariaHidden: true,
tabIndex: -1,
},
},
content: [
h('span.autolink-info', {className: "sr-only"}, ' permalink'),
s(
'svg.autolink-svg',
{
xmlns: 'http://www.w3.org/2000/svg',
width: 20,
height: 20,
fill: 'currentColor',
viewBox: '0 0 24 24',
className: "opacity-0 group-hover:opacity-100"
},
s('path', {
d: 'M9.199 13.599a5.99 5.99 0 0 0 3.949 2.345 5.987 5.987 0 0 0 5.105-1.702l2.995-2.994a5.992 5.992 0 0 0 1.695-4.285 5.976 5.976 0 0 0-1.831-4.211 5.99 5.99 0 0 0-6.431-1.242 6.003 6.003 0 0 0-1.905 1.24l-1.731 1.721a.999.999 0 1 0 1.41 1.418l1.709-1.699a3.985 3.985 0 0 1 2.761-1.123 3.975 3.975 0 0 1 2.799 1.122 3.997 3.997 0 0 1 .111 5.644l-3.005 3.006a3.982 3.982 0 0 1-3.395 1.126 3.987 3.987 0 0 1-2.632-1.563A1 1 0 0 0 9.201 13.6zm5.602-3.198a5.99 5.99 0 0 0-3.949-2.345 5.987 5.987 0 0 0-5.105 1.702l-2.995 2.994a5.992 5.992 0 0 0-1.695 4.285 5.976 5.976 0 0 0 1.831 4.211 5.99 5.99 0 0 0 6.431 1.242 6.003 6.003 0 0 0 1.905-1.24l1.723-1.723a.999.999 0 1 0-1.414-1.414L9.836 19.81a3.985 3.985 0 0 1-2.761 1.123 3.975 3.975 0 0 1-2.799-1.122 3.997 3.997 0 0 1-.111-5.644l3.005-3.006a3.982 3.982 0 0 1 3.395-1.126 3.987 3.987 0 0 1 2.632 1.563 1 1 0 0 0 1.602-1.198z',
})
),
],
},
],
[rehypePrettyCode, {
keepBackground: true,
getHighlighter,
onVisitLine: node => {
if (node.children && node.children[0] && node.children[0].children[0] && node.children[0].children[0].value == 'import') {
if (node.properties)
if (node.properties.className) {
node.properties.className.push(" import-line")
} else {
node.properties.className = ["import-line"]
}
}
},
onVisitHighlightedWord: (element) => {
// Each word element has no className by default.
element.properties.className = ['highlighted-word'];
element.style = "color:#000"
},
}]
]
}
export const generateStaticParams = async () => {
const mdxFiles = await getMdxFiles(mdx, ['./content/**/*.mdx'])
console.log(mdxFiles)
return [] // allPosts.filter(post => post.docType == 'page').map((post) => ({slug: post._raw.flattenedPath}))
}
@i-am-the-slime
Copy link
Author

This is for building your own: find some mdx files at build time on the server-side and parse them etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment