Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 192 Expose RawDocumentData on vFile data field for Markdown/MDX Files #195

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/@contentlayer/core/src/markdown.ts
Expand Up @@ -5,16 +5,19 @@ 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'

export const markdownToHtml = ({
mdString,
options,
data = {},
}: {
mdString: string
options?: MarkdownOptions
data: any
}): T.Effect<OT.HasTracer & HasConsole, UnexpectedMarkdownError, string> =>
pipe(
T.gen(function* ($) {
Expand All @@ -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)

Expand Down
9 changes: 8 additions & 1 deletion packages/@contentlayer/core/src/mdx.ts
Expand Up @@ -3,17 +3,20 @@ 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'

export const bundleMDX = ({
mdxString,
options,
contentDirPath,
data = {},
}: {
mdxString: string
options?: MDXOptions
contentDirPath: string
data: any
}): T.Effect<OT.HasTracer, UnexpectedMDXError, string> =>
pipe(
T.gen(function* ($) {
Expand All @@ -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<any> = {
mdxOptions: (opts) => {
opts.rehypePlugins = [...(opts.rehypePlugins ?? []), ...(rehypePlugins ?? [])]
opts.remarkPlugins = [...(opts.remarkPlugins ?? []), ...(remarkPlugins ?? [])]
opts.remarkPlugins = [addRawDocumentMeta, ...(opts.remarkPlugins ?? []), ...(remarkPlugins ?? [])]
return opts
},
cwd,
Expand Down
24 changes: 20 additions & 4 deletions packages/@contentlayer/source-files/src/fetchData/mapping.ts
Expand Up @@ -273,35 +273,51 @@ 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) {
const rawContent = yield* $(getFromDocumentContext('rawContent'))
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<core.Markdown>({ 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<core.Markdown>({ 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) {
const rawContent = yield* $(getFromDocumentContext('rawContent'))
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<core.MDX>({ 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<core.MDX>({ raw: rawFieldData, code })
}
}
Expand Down