2023-02-06 16:13:57 +00:00
import type { AstroIntegration } from 'astro' ;
2023-02-06 16:21:17 +00:00
import type { InlineConfig } from 'vite' ;
2023-03-01 18:39:29 +00:00
import type { Config } from '@markdoc/markdoc' ;
import Markdoc from '@markdoc/markdoc' ;
2023-02-07 21:01:34 +00:00
import { parseFrontmatter } from './utils.js' ;
import { fileURLToPath } from 'node:url' ;
2023-02-10 14:00:53 +00:00
import fs from 'node:fs' ;
2023-02-07 21:01:34 +00:00
2023-03-01 18:35:53 +00:00
export default function markdoc ( markdocConfig : Config ) : AstroIntegration {
const entryBodyByFileIdCache = new Map < string , string > ( ) ;
2023-02-06 16:13:57 +00:00
return {
name : '@astrojs/markdoc' ,
hooks : {
2023-03-01 18:35:53 +00:00
'astro:config:setup' : async ( { updateConfig , config , addContentEntryType } : any ) = > {
2023-02-13 19:13:02 +00:00
const contentEntryType = {
2023-02-15 14:43:04 +00:00
extensions : [ '.mdoc' ] ,
2023-03-01 18:35:53 +00:00
getEntryInfo ( { fileUrl , contents } : { fileUrl : URL ; contents : string } ) {
2023-02-13 19:13:02 +00:00
const parsed = parseFrontmatter ( contents , fileURLToPath ( fileUrl ) ) ;
2023-03-01 18:35:53 +00:00
entryBodyByFileIdCache . set ( fileUrl . pathname , parsed . content ) ;
2023-02-13 19:13:02 +00:00
return {
data : parsed.data ,
body : parsed.content ,
slug : parsed.data.slug ,
rawData : parsed.matter ,
} ;
} ,
contentModuleTypes : await fs . promises . readFile (
new URL ( '../template/content-module-types.d.ts' , import . meta . url ) ,
'utf-8'
) ,
} ;
2023-02-07 21:01:34 +00:00
addContentEntryType ( contentEntryType ) ;
2023-02-10 14:10:06 +00:00
2023-02-06 16:21:17 +00:00
const viteConfig : InlineConfig = {
plugins : [
{
name : '@astrojs/markdoc' ,
async transform ( code , id ) {
2023-02-15 14:43:04 +00:00
if ( ! id . endsWith ( '.mdoc' ) ) return ;
2023-03-01 18:35:53 +00:00
const body = entryBodyByFileIdCache . get ( id ) ;
if ( ! body ) {
// Cache entry should exist if `getCollection()` was called
// (see `getEntryInfo()` above)
// If not, the user probably tried to import directly.
throw new Error (
` Unable to render ${ JSON . stringify (
id . replace ( config . root . pathname , '' )
) } . If you tried to import this file directly , please use a Content Collection query instead . See https : //docs.astro.build/en/guides/content-collections/#rendering-content-to-html for more information.`
) ;
}
2023-03-01 18:38:53 +00:00
const ast = Markdoc . parse ( body ) ;
const content = Markdoc . transform ( ast , markdocConfig ) ;
2023-03-01 18:35:53 +00:00
2023-03-01 18:38:53 +00:00
return ` import { jsx as h } from 'astro/jsx-runtime'; \ nimport { Renderer } from '@astrojs/markdoc/components'; \ nconst transformedContent = ${ JSON . stringify (
content
) } ; \ nexport async function Content ( { components } ) { return h ( Renderer , { content : transformedContent , components } ) ; } \ nContent [ Symbol . for ( 'astro.needsHeadRendering' ) ] = true ; ` ;
2023-02-06 16:21:17 +00:00
} ,
} ,
] ,
} ;
updateConfig ( { vite : viteConfig } ) ;
2023-02-06 16:13:57 +00:00
} ,
} ,
} ;
}