@@ -4,101 +4,49 @@ import {
4
4
remarkPrism ,
5
5
remarkShiki ,
6
6
} from '@astrojs/markdown-remark' ;
7
- import {
8
- InvalidAstroDataError ,
9
- safelyGetAstroData ,
10
- } from '@astrojs/markdown-remark/dist/internal.js' ;
11
- import { nodeTypes } from '@mdx-js/mdx' ;
7
+ import { createProcessor , nodeTypes } from '@mdx-js/mdx' ;
12
8
import type { PluggableList } from '@mdx-js/mdx/lib/core.js' ;
13
- import type { Literal , MemberExpression } from 'estree' ;
14
- import { visit as estreeVisit } from 'estree-util-visit' ;
15
9
import rehypeRaw from 'rehype-raw' ;
16
10
import remarkGfm from 'remark-gfm' ;
17
11
import remarkSmartypants from 'remark-smartypants' ;
18
- import type { VFile } from 'vfile' ;
12
+ import { SourceMapGenerator } from 'source-map' ;
13
+ import type { Processor } from 'unified' ;
19
14
import type { MdxOptions } from './index.js' ;
15
+ import { recmaInjectImportMetaEnv } from './recma-inject-import-meta-env.js' ;
16
+ import { rehypeApplyFrontmatterExport } from './rehype-apply-frontmatter-export.js' ;
20
17
import { rehypeInjectHeadingsExport } from './rehype-collect-headings.js' ;
21
18
import rehypeMetaString from './rehype-meta-string.js' ;
22
19
import { rehypeOptimizeStatic } from './rehype-optimize-static.js' ;
23
20
import { remarkImageToComponent } from './remark-images-to-component.js' ;
24
- import { jsToTreeNode } from './utils.js' ;
25
21
26
22
// Skip nonessential plugins during performance benchmark runs
27
23
const isPerformanceBenchmark = Boolean ( process . env . ASTRO_PERFORMANCE_BENCHMARK ) ;
28
24
29
- export function recmaInjectImportMetaEnvPlugin ( {
30
- importMetaEnv,
31
- } : {
25
+ interface MdxProcessorExtraOptions {
26
+ sourcemap : boolean ;
32
27
importMetaEnv : Record < string , any > ;
33
- } ) {
34
- return ( tree : any ) => {
35
- estreeVisit ( tree , ( node ) => {
36
- if ( node . type === 'MemberExpression' ) {
37
- // attempt to get "import.meta.env" variable name
38
- const envVarName = getImportMetaEnvVariableName ( node ) ;
39
- if ( typeof envVarName === 'string' ) {
40
- // clear object keys to replace with envVarLiteral
41
- for ( const key in node ) {
42
- delete ( node as any ) [ key ] ;
43
- }
44
- const envVarLiteral : Literal = {
45
- type : 'Literal' ,
46
- value : importMetaEnv [ envVarName ] ,
47
- raw : JSON . stringify ( importMetaEnv [ envVarName ] ) ,
48
- } ;
49
- Object . assign ( node , envVarLiteral ) ;
50
- }
51
- }
52
- } ) ;
53
- } ;
54
28
}
55
29
56
- export function rehypeApplyFrontmatterExport ( ) {
57
- return function ( tree : any , vfile : VFile ) {
58
- const astroData = safelyGetAstroData ( vfile . data ) ;
59
- if ( astroData instanceof InvalidAstroDataError )
60
- throw new Error (
61
- // Copied from Astro core `errors-data`
62
- // TODO: find way to import error data from core
63
- '[MDX] A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.'
64
- ) ;
65
- const { frontmatter } = astroData ;
66
- const exportNodes = [
67
- jsToTreeNode ( `export const frontmatter = ${ JSON . stringify ( frontmatter ) } ;` ) ,
68
- ] ;
69
- if ( frontmatter . layout ) {
70
- // NOTE(bholmesdev) 08-22-2022
71
- // Using an async layout import (i.e. `const Layout = (await import...)`)
72
- // Preserves the dev server import cache when globbing a large set of MDX files
73
- // Full explanation: 'https://github.com/withastro/astro/pull/4428'
74
- exportNodes . unshift (
75
- jsToTreeNode (
76
- /** @see 'vite-plugin-markdown' for layout props reference */
77
- `import { jsx as layoutJsx } from 'astro/jsx-runtime';
78
-
79
- export default async function ({ children }) {
80
- const Layout = (await import(${ JSON . stringify ( frontmatter . layout ) } )).default;
81
- const { layout, ...content } = frontmatter;
82
- content.file = file;
83
- content.url = url;
84
- return layoutJsx(Layout, {
85
- file,
86
- url,
87
- content,
88
- frontmatter: content,
89
- headings: getHeadings(),
90
- 'server:root': true,
91
- children,
92
- });
93
- };`
94
- )
95
- ) ;
96
- }
97
- tree . children = exportNodes . concat ( tree . children ) ;
98
- } ;
30
+ export function createMdxProcessor (
31
+ mdxOptions : MdxOptions ,
32
+ extraOptions : MdxProcessorExtraOptions
33
+ ) : Processor {
34
+ return createProcessor ( {
35
+ remarkPlugins : getRemarkPlugins ( mdxOptions ) ,
36
+ rehypePlugins : getRehypePlugins ( mdxOptions ) ,
37
+ recmaPlugins : getRecmaPlugins ( mdxOptions , extraOptions . importMetaEnv ) ,
38
+ remarkRehypeOptions : mdxOptions . remarkRehype ,
39
+ jsx : true ,
40
+ jsxImportSource : 'astro' ,
41
+ // Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support
42
+ format : 'mdx' ,
43
+ mdExtensions : [ ] ,
44
+ elementAttributeNameCase : 'html' ,
45
+ SourceMapGenerator : extraOptions . sourcemap ? SourceMapGenerator : undefined ,
46
+ } ) ;
99
47
}
100
48
101
- export async function getRemarkPlugins ( mdxOptions : MdxOptions ) : Promise < PluggableList > {
49
+ function getRemarkPlugins ( mdxOptions : MdxOptions ) : PluggableList {
102
50
let remarkPlugins : PluggableList = [ remarkCollectImages , remarkImageToComponent ] ;
103
51
104
52
if ( ! isPerformanceBenchmark ) {
@@ -125,7 +73,7 @@ export async function getRemarkPlugins(mdxOptions: MdxOptions): Promise<Pluggabl
125
73
return remarkPlugins ;
126
74
}
127
75
128
- export function getRehypePlugins ( mdxOptions : MdxOptions ) : PluggableList {
76
+ function getRehypePlugins ( mdxOptions : MdxOptions ) : PluggableList {
129
77
let rehypePlugins : PluggableList = [
130
78
// ensure `data.meta` is preserved in `properties.metastring` for rehype syntax highlighters
131
79
rehypeMetaString ,
@@ -152,38 +100,9 @@ export function getRehypePlugins(mdxOptions: MdxOptions): PluggableList {
152
100
return rehypePlugins ;
153
101
}
154
102
155
- /**
156
- * Check if estree entry is "import.meta.env.VARIABLE"
157
- * If it is, return the variable name (i.e. "VARIABLE")
158
- */
159
- function getImportMetaEnvVariableName ( node : MemberExpression ) : string | Error {
160
- try {
161
- // check for ".[ANYTHING]"
162
- if ( node . object . type !== 'MemberExpression' || node . property . type !== 'Identifier' )
163
- return new Error ( ) ;
164
-
165
- const nestedExpression = node . object ;
166
- // check for ".env"
167
- if ( nestedExpression . property . type !== 'Identifier' || nestedExpression . property . name !== 'env' )
168
- return new Error ( ) ;
169
-
170
- const envExpression = nestedExpression . object ;
171
- // check for ".meta"
172
- if (
173
- envExpression . type !== 'MetaProperty' ||
174
- envExpression . property . type !== 'Identifier' ||
175
- envExpression . property . name !== 'meta'
176
- )
177
- return new Error ( ) ;
178
-
179
- // check for "import"
180
- if ( envExpression . meta . name !== 'import' ) return new Error ( ) ;
181
-
182
- return node . property . name ;
183
- } catch ( e ) {
184
- if ( e instanceof Error ) {
185
- return e ;
186
- }
187
- return new Error ( 'Unknown parsing error' ) ;
188
- }
103
+ function getRecmaPlugins (
104
+ mdxOptions : MdxOptions ,
105
+ importMetaEnv : Record < string , any >
106
+ ) : PluggableList {
107
+ return [ ...( mdxOptions . recmaPlugins ?? [ ] ) , [ recmaInjectImportMetaEnv , { importMetaEnv } ] ] ;
189
108
}
0 commit comments