diff --git a/packages/@contentlayer/core/src/markdown.ts b/packages/@contentlayer/core/src/markdown.ts index f5cdf1c2..37a9b254 100644 --- a/packages/@contentlayer/core/src/markdown.ts +++ b/packages/@contentlayer/core/src/markdown.ts @@ -5,6 +5,7 @@ import rehypeStringify from 'rehype-stringify' import remarkFrontmatter from 'remark-frontmatter' import remarkParse from 'remark-parse' import remark2rehype from 'remark-rehype' +import type { Transformer } from 'unified' import { unified } from 'unified' import type { MarkdownOptions } from './plugin.js' @@ -12,9 +13,11 @@ import type { MarkdownOptions } from './plugin.js' export const markdownToHtml = ({ mdString, options, + data = {}, }: { mdString: string options?: MarkdownOptions + data: any }): T.Effect => pipe( T.gen(function* ($) { @@ -35,6 +38,12 @@ export const markdownToHtml = ({ const builder = unified() + const addRawDocumentMeta = (): Transformer => (_, vfile) => { + Object.assign(vfile.data, data) + } + + builder.use(addRawDocumentMeta) + // parses out the frontmatter (which is needed for full-document parsing) builder.use(remarkFrontmatter) diff --git a/packages/@contentlayer/core/src/mdx.ts b/packages/@contentlayer/core/src/mdx.ts index 233e370d..17c50a11 100644 --- a/packages/@contentlayer/core/src/mdx.ts +++ b/packages/@contentlayer/core/src/mdx.ts @@ -3,6 +3,7 @@ import { OT, pipe, T, Tagged } from '@contentlayer/utils/effect' import * as mdxBundler from 'mdx-bundler' import type { BundleMDXOptions } from 'mdx-bundler/dist/types' import * as path from 'path' +import type { Transformer } from 'unified' import type { MDXOptions } from './plugin.js' @@ -10,10 +11,12 @@ export const bundleMDX = ({ mdxString, options, contentDirPath, + data = {}, }: { mdxString: string options?: MDXOptions contentDirPath: string + data: any }): T.Effect => pipe( T.gen(function* ($) { @@ -28,10 +31,14 @@ export const bundleMDX = ({ path.isAbsolute(contentDirPath) ? contentDirPath : path.join(process.cwd(), contentDirPath) const cwd = cwd_ ?? getCwdFromContentDirPath() + const addRawDocumentMeta = (): Transformer => (_, vfile) => { + Object.assign(vfile.data, data) + } + const mdxOptions: BundleMDXOptions = { mdxOptions: (opts) => { opts.rehypePlugins = [...(opts.rehypePlugins ?? []), ...(rehypePlugins ?? [])] - opts.remarkPlugins = [...(opts.remarkPlugins ?? []), ...(remarkPlugins ?? [])] + opts.remarkPlugins = [addRawDocumentMeta, ...(opts.remarkPlugins ?? []), ...(remarkPlugins ?? [])] return opts }, cwd, diff --git a/packages/@contentlayer/source-files/src/fetchData/mapping.ts b/packages/@contentlayer/source-files/src/fetchData/mapping.ts index e3b875b7..ef51a403 100644 --- a/packages/@contentlayer/source-files/src/fetchData/mapping.ts +++ b/packages/@contentlayer/source-files/src/fetchData/mapping.ts @@ -273,6 +273,13 @@ const getDataForFieldDef = ({ return value case 'markdown': { const isBodyField = fieldDef.name === options.fieldOptions.bodyFieldName + const data: RawDocumentData = { + sourceFilePath: relativeFilePath, + sourceFileName: path.basename(relativeFilePath), + sourceFileDir: path.dirname(relativeFilePath), + contentType: `markdown`, + flattenedPath: getFlattenedPath(relativeFilePath), + } // NOTE for the body field, we're passing the entire document file contents to MDX (e.g. in case some remark/rehype plugins need access to the frontmatter) // TODO we should come up with a better way to do this if (isBodyField) { @@ -280,16 +287,23 @@ const getDataForFieldDef = ({ if (rawContent.kind !== 'markdown' && rawContent.kind !== 'mdx') return utils.assertNever(rawContent) const html = yield* $( - core.markdownToHtml({ mdString: rawContent.rawDocumentContent, options: options?.markdown }), + core.markdownToHtml({ mdString: rawContent.rawDocumentContent, options: options?.markdown, data }), ) return identity({ raw: rawFieldData, html }) } else { - const html = yield* $(core.markdownToHtml({ mdString: rawFieldData, options: options?.markdown })) + const html = yield* $(core.markdownToHtml({ mdString: rawFieldData, options: options?.markdown, data })) return identity({ raw: rawFieldData, html }) } } case 'mdx': { const isBodyField = fieldDef.name === options.fieldOptions.bodyFieldName + const data: RawDocumentData = { + sourceFilePath: relativeFilePath, + sourceFileName: path.basename(relativeFilePath), + sourceFileDir: path.dirname(relativeFilePath), + contentType: `mdx`, + flattenedPath: getFlattenedPath(relativeFilePath), + } // NOTE for the body field, we're passing the entire document file contents to MDX (e.g. in case some remark/rehype plugins need access to the frontmatter) // TODO we should come up with a better way to do this if (isBodyField) { @@ -297,11 +311,13 @@ const getDataForFieldDef = ({ if (rawContent.kind !== 'mdx' && rawContent.kind !== 'markdown') return utils.assertNever(rawContent) const code = yield* $( - core.bundleMDX({ mdxString: rawContent.rawDocumentContent, options: options?.mdx, contentDirPath }), + core.bundleMDX({ mdxString: rawContent.rawDocumentContent, options: options?.mdx, contentDirPath, data }), ) return identity({ raw: rawFieldData, code }) } else { - const code = yield* $(core.bundleMDX({ mdxString: rawFieldData, options: options?.mdx, contentDirPath })) + const code = yield* $( + core.bundleMDX({ mdxString: rawFieldData, options: options?.mdx, contentDirPath, data }), + ) return identity({ raw: rawFieldData, code }) } }