Skip to content

Commit 4539e57

Browse files
committed
Convert paragraph content to markdown
- Introduce `isMarkdownEnabled` helper function to detect whether an MDX element sets `markdownEnabled` (either via shorthand or boolean expression). - Convert paragraph content to Markdown if `markdownEnabled` is set, accumulating the result in a new `node.markdown` field. - Use `toMarkdown` from `mdast-util-to-markdown` to transform AST nodes to Markdown.
1 parent d7fa29e commit 4539e57

File tree

4 files changed

+90
-16
lines changed

4 files changed

+90
-16
lines changed

packages/codehike/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"diff": "^5.1.0",
5858
"estree-util-visit": "^2.0.0",
5959
"mdast-util-mdx-jsx": "^3.0.0",
60+
"mdast-util-to-markdown": "^2.1.2",
6061
"unist-util-visit": "^5.0.0"
6162
},
6263
"devDependencies": {

packages/codehike/src/mdx/1.0.transform-hikes.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,47 @@
11
import { Root } from "mdast"
2-
import { MdxJsxFlowElement } from "mdast-util-mdx-jsx"
2+
import { MdxJsxAttribute, MdxJsxFlowElement } from "mdast-util-mdx-jsx"
33
import { visit } from "unist-util-visit"
44
import { isHikeElement, listToSection } from "./1.1.remark-list-to-section.js"
55
import { sectionToAttribute } from "./1.2.remark-section-to-attribute.js"
66
import { CodeHikeConfig } from "./config.js"
77

8+
/**
9+
* Determines whether Markdown is enabled for the given MDX JSX element.
10+
*
11+
* This function checks for the presence of a `markdownEnabled` attribute:
12+
* - If no attribute is found, it returns `false`.
13+
* - If the attribute is present in shorthand form (e.g. `<SomeTag
14+
* markdownEnabled>`), it returns `true`.
15+
* - If the attribute is an MDX expression (e.g. `<SomeTag
16+
* markdownEnabled={true} />`), it checks if the raw expression text is
17+
* literally `"true"`.
18+
*/
19+
export function isMarkdownEnabled(node: MdxJsxFlowElement): boolean {
20+
// Look for the "markdownEnabled" attribute within the node’s attributes.
21+
const markdownEnabledAttr = node.attributes.find(
22+
(attr): attr is MdxJsxAttribute =>
23+
attr.type === "mdxJsxAttribute" && attr.name === "markdownEnabled",
24+
)
25+
26+
if (!markdownEnabledAttr) return false
27+
28+
// Shorthand (<Component markdownEnabled>) implies true.
29+
if (markdownEnabledAttr.value === null) return true
30+
31+
// If the attribute value is an object, it indicates an MDX expression
32+
// (e.g. markdownEnabled={true}). The `.value` property on this object is the
33+
// raw string representation of the expression, so we check if it’s
34+
// literally "true".
35+
if (
36+
typeof markdownEnabledAttr.value === "object" &&
37+
markdownEnabledAttr.value.type === "mdxJsxAttributeValueExpression"
38+
) {
39+
return markdownEnabledAttr.value.value.trim() === "true"
40+
}
41+
42+
return false
43+
}
44+
845
export async function transformAllHikes(root: Root, config: CodeHikeConfig) {
946
let tree = wrapInHike(root)
1047

@@ -42,8 +79,10 @@ async function transformRemarkHike(
4279
node: MdxJsxFlowElement,
4380
config: CodeHikeConfig,
4481
) {
82+
const markdownEnabled = isMarkdownEnabled(node)
83+
4584
const section = await listToSection(node, config)
46-
const { children, attributes } = sectionToAttribute(section)
85+
const { children, attributes } = sectionToAttribute(section, markdownEnabled)
4786

4887
node.children = children
4988
node.attributes.push(...attributes)

packages/codehike/src/mdx/1.2.remark-section-to-attribute.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { MdxJsxAttribute, MdxJsxFlowElement } from "mdast-util-mdx-jsx"
2-
import {
3-
HikeContent,
4-
HikeSection,
5-
JSXChild,
6-
} from "./1.1.remark-list-to-section.js"
2+
import { toMarkdown } from "mdast-util-to-markdown"
3+
import { HikeSection, JSXChild } from "./1.1.remark-list-to-section.js"
74
import { getObjectAttribute } from "./estree.js"
85

9-
export function sectionToAttribute(root: HikeSection) {
6+
export function sectionToAttribute(
7+
root: HikeSection,
8+
markdownEnabled: boolean,
9+
) {
1010
const children: JSXChild[] = getSectionContainers(root, "")
1111

12-
const serializableTree = getSerializableNode(root, "")
12+
const serializableTree = getSerializableNode(root, "", markdownEnabled)
1313

1414
return {
1515
children,
@@ -23,7 +23,11 @@ export function sectionToAttribute(root: HikeSection) {
2323
}
2424
}
2525

26-
function getSerializableNode(section: HikeSection, path: string) {
26+
function getSerializableNode(
27+
section: HikeSection,
28+
path: string,
29+
markdownEnabled: boolean = false,
30+
) {
2731
const newPath = path ? [path, section.name].join(".") : section.name
2832
const node: any = {
2933
children: newPath,
@@ -33,10 +37,21 @@ function getSerializableNode(section: HikeSection, path: string) {
3337

3438
section.children.forEach((child) => {
3539
if (child.type === "content") {
40+
if (markdownEnabled) {
41+
// If Markdown is enabled, convert paragraph nodes into Markdown text
42+
// and accumulate them in the `node.markdown` property.
43+
if (child.value.type === "paragraph") {
44+
if (node.markdown == null) {
45+
node.markdown = toMarkdown(child.value)
46+
} else {
47+
node.markdown += toMarkdown(child.value)
48+
}
49+
}
50+
}
3651
return
3752
}
3853
if (child.type === "section") {
39-
const childNode = getSerializableNode(child, newPath)
54+
const childNode = getSerializableNode(child, newPath, markdownEnabled)
4055

4156
if (child.multi) {
4257
node[child.name] = node[child.name] || []

pnpm-lock.yaml

Lines changed: 24 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)