summaryrefslogtreecommitdiff
path: root/packages/integrations/mdx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/mdx')
-rw-r--r--packages/integrations/mdx/src/index.ts15
-rw-r--r--packages/integrations/mdx/src/plugins.ts76
-rw-r--r--packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/astro.config.mjs4
-rw-r--r--packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/markdown-plugins.mjs7
-rw-r--r--packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/page-1.mdx1
-rw-r--r--packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/page-2.mdx1
-rw-r--r--packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/with-overrides.mdx7
-rw-r--r--packages/integrations/mdx/test/mdx-frontmatter-injection.test.js11
8 files changed, 39 insertions, 83 deletions
diff --git a/packages/integrations/mdx/src/index.ts b/packages/integrations/mdx/src/index.ts
index d788a171a..e9d81ca1f 100644
--- a/packages/integrations/mdx/src/index.ts
+++ b/packages/integrations/mdx/src/index.ts
@@ -1,3 +1,4 @@
+import { toRemarkInitializeAstroData } from '@astrojs/markdown-remark/dist/internal.js';
import { compile as mdxCompile } from '@mdx-js/mdx';
import { PluggableList } from '@mdx-js/mdx/lib/core.js';
import mdxPlugin, { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
@@ -7,12 +8,7 @@ import fs from 'node:fs/promises';
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
import { VFile } from 'vfile';
import type { Plugin as VitePlugin } from 'vite';
-import {
- getRehypePlugins,
- getRemarkPlugins,
- recmaInjectImportMetaEnvPlugin,
- rehypeApplyFrontmatterExport,
-} from './plugins.js';
+import { getRehypePlugins, getRemarkPlugins, recmaInjectImportMetaEnvPlugin } from './plugins.js';
import { getFileInfo, parseFrontmatter } from './utils.js';
const RAW_CONTENT_ERROR =
@@ -86,9 +82,10 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
...mdxPluginOpts,
- rehypePlugins: [
- ...(mdxPluginOpts.rehypePlugins ?? []),
- () => rehypeApplyFrontmatterExport(frontmatter),
+ remarkPlugins: [
+ // Ensure `data.astro` is available to all remark plugins
+ toRemarkInitializeAstroData({ userFrontmatter: frontmatter }),
+ ...(mdxPluginOpts.remarkPlugins ?? []),
],
recmaPlugins: [
...(mdxPluginOpts.recmaPlugins ?? []),
diff --git a/packages/integrations/mdx/src/plugins.ts b/packages/integrations/mdx/src/plugins.ts
index c823c6e7c..4701b1679 100644
--- a/packages/integrations/mdx/src/plugins.ts
+++ b/packages/integrations/mdx/src/plugins.ts
@@ -2,7 +2,11 @@ import { rehypeHeadingIds } from '@astrojs/markdown-remark';
import { nodeTypes } from '@mdx-js/mdx';
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
import type { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
-import type { AstroConfig, MarkdownAstroData } from 'astro';
+import type { AstroConfig } from 'astro';
+import {
+ safelyGetAstroData,
+ InvalidAstroDataError,
+} from '@astrojs/markdown-remark/dist/internal.js';
import type { Literal, MemberExpression } from 'estree';
import { visit as estreeVisit } from 'estree-util-visit';
import { bold, yellow } from 'kleur/colors';
@@ -47,26 +51,18 @@ export function recmaInjectImportMetaEnvPlugin({
};
}
-export function remarkInitializeAstroData() {
+export function rehypeApplyFrontmatterExport() {
return function (tree: any, vfile: VFile) {
- if (!vfile.data.astro) {
- vfile.data.astro = { frontmatter: {} };
- }
- };
-}
-
-export function rehypeApplyFrontmatterExport(pageFrontmatter: Record<string, any>) {
- return function (tree: any, vfile: VFile) {
- const { frontmatter: injectedFrontmatter } = safelyGetAstroData(vfile.data);
- const frontmatter = { ...injectedFrontmatter, ...pageFrontmatter };
+ const astroData = safelyGetAstroData(vfile.data);
+ if (astroData instanceof InvalidAstroDataError)
+ throw new Error(
+ // Copied from Astro core `errors-data`
+ // TODO: find way to import error data from core
+ '[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`.'
+ );
+ const { frontmatter } = astroData;
const exportNodes = [
- jsToTreeNode(
- `export const frontmatter = ${JSON.stringify(
- frontmatter
- )};\nexport const _internal = { injectedFrontmatter: ${JSON.stringify(
- injectedFrontmatter
- )} };`
- ),
+ jsToTreeNode(`export const frontmatter = ${JSON.stringify(frontmatter)};`),
];
if (frontmatter.layout) {
// NOTE(bholmesdev) 08-22-2022
@@ -151,10 +147,7 @@ export async function getRemarkPlugins(
mdxOptions: MdxOptions,
config: AstroConfig
): Promise<MdxRollupPluginOptions['remarkPlugins']> {
- let remarkPlugins: PluggableList = [
- // Set "vfile.data.astro" for plugins to inject frontmatter
- remarkInitializeAstroData,
- ];
+ let remarkPlugins: PluggableList = [];
switch (mdxOptions.extendPlugins) {
case false:
break;
@@ -217,6 +210,8 @@ export function getRehypePlugins(
// We run `rehypeHeadingIds` _last_ to respect any custom IDs set by user plugins.
rehypeHeadingIds,
rehypeInjectHeadingsExport,
+ // computed from `astro.data.frontmatter` in VFile data
+ rehypeApplyFrontmatterExport,
];
return rehypePlugins;
}
@@ -251,41 +246,6 @@ function ignoreStringPlugins(plugins: any[]) {
}
/**
- * Copied from markdown utils
- * @see "vite-plugin-utils"
- */
-function isValidAstroData(obj: unknown): obj is MarkdownAstroData {
- if (typeof obj === 'object' && obj !== null && obj.hasOwnProperty('frontmatter')) {
- const { frontmatter } = obj as any;
- try {
- // ensure frontmatter is JSON-serializable
- JSON.stringify(frontmatter);
- } catch {
- return false;
- }
- return typeof frontmatter === 'object' && frontmatter !== null;
- }
- return false;
-}
-
-/**
- * Copied from markdown utils
- * @see "vite-plugin-utils"
- */
-function safelyGetAstroData(vfileData: Data): MarkdownAstroData {
- const { astro } = vfileData;
-
- if (!astro) return { frontmatter: {} };
- if (!isValidAstroData(astro)) {
- throw Error(
- `[MDX] A remark or rehype plugin tried to add invalid frontmatter. Ensure "astro.frontmatter" is a JSON object!`
- );
- }
-
- return astro;
-}
-
-/**
* Check if estree entry is "import.meta.env.VARIABLE"
* If it is, return the variable name (i.e. "VARIABLE")
*/
diff --git a/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/astro.config.mjs b/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/astro.config.mjs
index fc15686c2..5335fac87 100644
--- a/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/astro.config.mjs
+++ b/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/astro.config.mjs
@@ -1,12 +1,12 @@
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
-import { rehypeReadingTime, remarkTitle } from './src/markdown-plugins.mjs';
+import { rehypeReadingTime, remarkDescription, remarkTitle } from './src/markdown-plugins.mjs';
// https://astro.build/config
export default defineConfig({
site: 'https://astro.build/',
integrations: [mdx({
- remarkPlugins: [remarkTitle],
+ remarkPlugins: [remarkTitle, remarkDescription],
rehypePlugins: [rehypeReadingTime],
})],
});
diff --git a/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/markdown-plugins.mjs b/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/markdown-plugins.mjs
index c0d5f7b2e..35b415787 100644
--- a/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/markdown-plugins.mjs
+++ b/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/markdown-plugins.mjs
@@ -18,3 +18,10 @@ export function remarkTitle() {
});
};
}
+
+export function remarkDescription() {
+ return function (tree, vfile) {
+ const { frontmatter } = vfile.data.astro;
+ frontmatter.description = `Processed by remarkDescription plugin: ${frontmatter.description}`
+ };
+}
diff --git a/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/page-1.mdx b/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/page-1.mdx
index 1092099f0..0d96d95b9 100644
--- a/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/page-1.mdx
+++ b/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/page-1.mdx
@@ -1,5 +1,6 @@
---
layout: '../layouts/Base.astro'
+description: Page 1 description
---
# Page 1
diff --git a/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/page-2.mdx b/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/page-2.mdx
index c82eb97c2..fe6a8286b 100644
--- a/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/page-2.mdx
+++ b/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/page-2.mdx
@@ -1,5 +1,6 @@
---
layout: '../layouts/Base.astro'
+description: Page 2 description
---
# Page 2
diff --git a/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/with-overrides.mdx b/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/with-overrides.mdx
deleted file mode 100644
index 4e11c1c37..000000000
--- a/packages/integrations/mdx/test/fixtures/mdx-frontmatter-injection/src/pages/with-overrides.mdx
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: 'Overridden title'
-injectedReadingTime:
- text: '1000 min read'
----
-
-# Working!
diff --git a/packages/integrations/mdx/test/mdx-frontmatter-injection.test.js b/packages/integrations/mdx/test/mdx-frontmatter-injection.test.js
index 780f7252c..8f598b78e 100644
--- a/packages/integrations/mdx/test/mdx-frontmatter-injection.test.js
+++ b/packages/integrations/mdx/test/mdx-frontmatter-injection.test.js
@@ -33,14 +33,11 @@ describe('MDX frontmatter injection', () => {
}
});
- it('overrides injected frontmatter with user frontmatter', async () => {
+ it('allow user frontmatter mutation', async () => {
const frontmatterByPage = JSON.parse(await fixture.readFile('/glob.json'));
- const readingTimes = frontmatterByPage.map(
- (frontmatter = {}) => frontmatter.injectedReadingTime?.text
- );
- const titles = frontmatterByPage.map((frontmatter = {}) => frontmatter.title);
- expect(titles).to.contain('Overridden title');
- expect(readingTimes).to.contain('1000 min read');
+ const descriptions = frontmatterByPage.map((frontmatter = {}) => frontmatter.description);
+ expect(descriptions).to.contain('Processed by remarkDescription plugin: Page 1 description');
+ expect(descriptions).to.contain('Processed by remarkDescription plugin: Page 2 description');
});
it('passes injected frontmatter to layouts', async () => {