diff options
Diffstat (limited to 'packages/integrations/mdx/src/plugins.ts')
-rw-r--r-- | packages/integrations/mdx/src/plugins.ts | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/packages/integrations/mdx/src/plugins.ts b/packages/integrations/mdx/src/plugins.ts new file mode 100644 index 000000000..c44c8fffd --- /dev/null +++ b/packages/integrations/mdx/src/plugins.ts @@ -0,0 +1,111 @@ +import { + rehypeHeadingIds, + rehypePrism, + rehypeShiki, + remarkCollectImages, +} from '@astrojs/markdown-remark'; +import { createProcessor, nodeTypes } from '@mdx-js/mdx'; +import { rehypeAnalyzeAstroMetadata } from 'astro/jsx/rehype.js'; +import rehypeRaw from 'rehype-raw'; +import remarkGfm from 'remark-gfm'; +import remarkSmartypants from 'remark-smartypants'; +import { SourceMapGenerator } from 'source-map'; +import type { PluggableList } from 'unified'; +import type { MdxOptions } from './index.js'; +import { rehypeApplyFrontmatterExport } from './rehype-apply-frontmatter-export.js'; +import { rehypeInjectHeadingsExport } from './rehype-collect-headings.js'; +import { rehypeImageToComponent } from './rehype-images-to-component.js'; +import rehypeMetaString from './rehype-meta-string.js'; +import { rehypeOptimizeStatic } from './rehype-optimize-static.js'; + +// Skip nonessential plugins during performance benchmark runs +const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK); + +interface MdxProcessorExtraOptions { + sourcemap: boolean; + experimentalHeadingIdCompat: boolean; +} + +export function createMdxProcessor(mdxOptions: MdxOptions, extraOptions: MdxProcessorExtraOptions) { + return createProcessor({ + remarkPlugins: getRemarkPlugins(mdxOptions), + rehypePlugins: getRehypePlugins(mdxOptions, extraOptions), + recmaPlugins: mdxOptions.recmaPlugins, + remarkRehypeOptions: mdxOptions.remarkRehype, + jsxImportSource: 'astro', + // Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support + format: 'mdx', + mdExtensions: [], + elementAttributeNameCase: 'html', + SourceMapGenerator: extraOptions.sourcemap ? SourceMapGenerator : undefined, + }); +} + +function getRemarkPlugins(mdxOptions: MdxOptions): PluggableList { + let remarkPlugins: PluggableList = []; + + if (!isPerformanceBenchmark) { + if (mdxOptions.gfm) { + remarkPlugins.push(remarkGfm); + } + if (mdxOptions.smartypants) { + remarkPlugins.push(remarkSmartypants); + } + } + + remarkPlugins.push(...mdxOptions.remarkPlugins, remarkCollectImages); + + return remarkPlugins; +} + +function getRehypePlugins( + mdxOptions: MdxOptions, + { experimentalHeadingIdCompat }: MdxProcessorExtraOptions, +): PluggableList { + let rehypePlugins: PluggableList = [ + // ensure `data.meta` is preserved in `properties.metastring` for rehype syntax highlighters + rehypeMetaString, + // rehypeRaw allows custom syntax highlighters to work without added config + [rehypeRaw, { passThrough: nodeTypes }], + ]; + + const syntaxHighlight = mdxOptions.syntaxHighlight; + if (syntaxHighlight && !isPerformanceBenchmark) { + const syntaxHighlightType = + typeof syntaxHighlight === 'string' ? syntaxHighlight : syntaxHighlight?.type; + const excludeLangs = + typeof syntaxHighlight === 'object' ? syntaxHighlight?.excludeLangs : undefined; + // Apply syntax highlighters after user plugins to match `markdown/remark` behavior + if (syntaxHighlightType === 'shiki') { + rehypePlugins.push([rehypeShiki, mdxOptions.shikiConfig, excludeLangs]); + } else if (syntaxHighlightType === 'prism') { + rehypePlugins.push([rehypePrism, excludeLangs]); + } + } + + rehypePlugins.push(...mdxOptions.rehypePlugins, rehypeImageToComponent); + + if (!isPerformanceBenchmark) { + // getHeadings() is guaranteed by TS, so this must be included. + // We run `rehypeHeadingIds` _last_ to respect any custom IDs set by user plugins. + rehypePlugins.push( + [rehypeHeadingIds, { experimentalHeadingIdCompat }], + rehypeInjectHeadingsExport, + ); + } + + rehypePlugins.push( + // Render info from `vfile.data.astro.frontmatter` as JS + rehypeApplyFrontmatterExport, + // Analyze MDX nodes and attach to `vfile.data.__astroMetadata` + rehypeAnalyzeAstroMetadata, + ); + + if (mdxOptions.optimize) { + // Convert user `optimize` option to compatible `rehypeOptimizeStatic` option + const options = mdxOptions.optimize === true ? undefined : mdxOptions.optimize; + rehypePlugins.push([rehypeOptimizeStatic, options]); + } + + return rehypePlugins; +} |