diff options
author | 2022-08-05 18:55:38 -0500 | |
---|---|---|
committer | 2022-08-05 18:55:38 -0500 | |
commit | 2675b8633c5d5c45b237ec87940d5eaf1bfb1b4b (patch) | |
tree | 171d8ff13cb81ed038ac52dc34ed2a313ae78903 /packages/integrations/mdx/src/astro-data-utils.ts | |
parent | 4678a3f358840db853db55b753b329ae592a589c (diff) | |
download | astro-2675b8633c5d5c45b237ec87940d5eaf1bfb1b4b.tar.gz astro-2675b8633c5d5c45b237ec87940d5eaf1bfb1b4b.tar.zst astro-2675b8633c5d5c45b237ec87940d5eaf1bfb1b4b.zip |
Frontmatter injection for MD and MDX (#4176)
* feat: inject vfile data as exports
* feat: add vfile to renderMarkdown output
* feat: add safe astroExports parser to utils
* refactor: expose vite-plugin-utils on astro package
* feat: handle astroExports in mdx
* deps: vfile
* chore: lockfile
* test: astroExports in mdx
* refactor: merge plugin exports into forntmatter
* refactor: astroExports -> astro.frontmatter
* refactor: md astroExports -> astro.frontmatter
* feat: astro.frontmatter vite-plugin-markdown
* chore: remove unused import
* fix: inline safelyGetAstroData in MDX integration
* chore: check that frontmatter export is valid export name
* chore: error log naming
* test: mdx remark frontmatter injection
* fix: inconsistent shiki mod resolution
* fix: add new frontmatter and heading props
* test: remark vdata
* fix: spread astro.data.frontmatter
* test deps: mdast-util-to-string, reading-time
* fix: astro-md test package name
* test: md frontmatter injection
* fix: layouts
* deps: remove vite-plugin-utils export
* fix: package lock
* chore: remove dup import
* chore: changeset
* chore: add comment on safelyGetAstroData source
* deps: move mdast-util-to-string + reading-time to test fixture
* chore: move remark plugins to test fixture
* fix: override plugin frontmatter with user frontmatter
* test: md injected frontmatter overrides
* test: frontmatter injection overrides mdx
Diffstat (limited to 'packages/integrations/mdx/src/astro-data-utils.ts')
-rw-r--r-- | packages/integrations/mdx/src/astro-data-utils.ts | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/packages/integrations/mdx/src/astro-data-utils.ts b/packages/integrations/mdx/src/astro-data-utils.ts new file mode 100644 index 000000000..bfbc74461 --- /dev/null +++ b/packages/integrations/mdx/src/astro-data-utils.ts @@ -0,0 +1,82 @@ +import { name as isValidIdentifierName } from 'estree-util-is-identifier-name'; +import type { VFile } from 'vfile'; +import type { MdxjsEsm } from 'mdast-util-mdx'; +import type { MarkdownAstroData } from 'astro'; +import type { Data } from 'vfile'; +import { jsToTreeNode } from './utils.js'; + +export function remarkInitializeAstroData() { + return function (tree: any, vfile: VFile) { + if (!vfile.data.astro) { + vfile.data.astro = { frontmatter: {} }; + } + }; +} + +export function rehypeApplyFrontmatterExport( + pageFrontmatter: Record<string, any>, + exportName = 'frontmatter' +) { + return function (tree: any, vfile: VFile) { + if (!isValidIdentifierName(exportName)) { + throw new Error( + `[MDX] ${JSON.stringify( + exportName + )} is not a valid frontmatter export name! Make sure "frontmatterOptions.name" could be used as a JS export (i.e. "export const frontmatterName = ...")` + ); + } + const { frontmatter: injectedFrontmatter } = safelyGetAstroData(vfile.data); + const frontmatter = { ...injectedFrontmatter, ...pageFrontmatter }; + let exportNodes: MdxjsEsm[] = []; + if (!exportName) { + exportNodes = Object.entries(frontmatter).map(([k, v]) => { + if (!isValidIdentifierName(k)) { + throw new Error( + `[MDX] A remark or rehype plugin tried to inject ${JSON.stringify( + k + )} as a top-level export, which is not a valid export name.` + ); + } + return jsToTreeNode(`export const ${k} = ${JSON.stringify(v)};`); + }); + } else { + exportNodes = [jsToTreeNode(`export const ${exportName} = ${JSON.stringify(frontmatter)};`)]; + } + tree.children = exportNodes.concat(tree.children); + }; +} + +/** + * 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" + */ +export 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; +} |