Skip to content

Commit c0ee61c

Browse files
committed
fix: mdx placedholder replacement
1 parent 2f8a489 commit c0ee61c

3 files changed

Lines changed: 61 additions & 27 deletions

File tree

.changeset/sour-news-add.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"lingo.dev": patch
3+
---
4+
5+
mdx placeholder replacement

packages/cli/src/cli/loaders/mdx2/code-placeholder.spec.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,21 @@ describe("mdx code placeholder loader", () => {
2020
frontmatter: {},
2121
content: sampleMdxContent,
2222
});
23-
2423
// expect two placeholders
2524
const placeholderKeys = Object.keys(result.codePlaceholders);
26-
const placeholder1 = `__PLACEHOLDER_${md5("inline")}__`;
27-
const placeholder2 = `__PLACEHOLDER_${md5('console.log("foo");')}__`;
25+
const placeholder1 = `__PLACEHOLDER_${md5("`inline`")}__`;
26+
const placeholder2 = `__PLACEHOLDER_${md5('```js\nconsole.log("foo");\n```')}__`;
2827
expect(placeholderKeys).toEqual([placeholder1, placeholder2]);
2928

3029
// mapping values should equal original code snippets
31-
const expectedInline = "inline";
32-
const expectedBlock = 'console.log("foo");';
30+
const expectedInline = "`inline`";
31+
const expectedBlock = '```js\nconsole.log("foo");\n```';
3332
expect(Object.values(result.codePlaceholders).sort()).toEqual(
3433
[expectedBlock, expectedInline].sort(),
3534
);
3635

3736
// content should have placeholders substituted exactly
38-
const expectedContent = `Paragraph with some \`${placeholder1}\` code.\n\n\`\`\`js\n${placeholder2}\n\`\`\``;
37+
const expectedContent = `Paragraph with some ${placeholder1} code.\n\n${placeholder2}`;
3938
expect(result.content.trim()).toBe(expectedContent.trim());
4039
});
4140

packages/cli/src/cli/loaders/mdx2/code-placeholder.ts

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,34 +35,64 @@ function extractCodePlaceholders(content: string): {
3535
content: string;
3636
codePlaceholders: Record<string, string>;
3737
} {
38-
const ast = parseMdast(content);
39-
const placeholderableElements: (keyof RootContentMap)[] = [
40-
"code",
41-
"inlineCode",
42-
];
38+
let shouldSearchForPlaceholders = true;
4339
let finalContent = content;
4440
const codePlaceholders: Record<string, string> = {};
4541

46-
traverseMdast(ast, (_node) => {
47-
if (!placeholderableElements.includes(_node.type as any)) {
48-
return;
49-
}
50-
const node = _node as Code | InlineCode;
51-
const nodeContent = node.value;
42+
while (shouldSearchForPlaceholders) {
43+
const ast = parseMdast(finalContent);
5244

53-
const nodeContentHash = md5(nodeContent);
54-
const placeholderId = `__PLACEHOLDER_${nodeContentHash}__`;
45+
traverseMdast(ast, (_node) => {
46+
shouldSearchForPlaceholders = false;
5547

56-
const nodeContentStart = node.position?.start.offset;
57-
const nodeContentEnd = node.position?.end.offset;
48+
if (_node.type === "code") {
49+
const node = _node as Code;
5850

59-
if (!nodeContentStart || !nodeContentEnd) {
60-
return;
61-
}
51+
const nodeContentStartLine = node.position?.start.line;
52+
const nodeContentEndLine = node.position?.end.line;
6253

63-
codePlaceholders[placeholderId] = nodeContent;
64-
finalContent = finalContent.split(nodeContent).join(placeholderId);
65-
});
54+
if (!nodeContentStartLine || !nodeContentEndLine) {
55+
return;
56+
}
57+
58+
const nodeContentPreStartLine = nodeContentStartLine - 1;
59+
const nodeContentPostEndLine = nodeContentEndLine + 1;
60+
61+
const nodeContent = finalContent
62+
.split("\n")
63+
.slice(nodeContentPreStartLine, nodeContentPostEndLine)
64+
.join("\n");
65+
66+
const nodeContentHash = md5(nodeContent);
67+
const placeholderId = `__PLACEHOLDER_${nodeContentHash}__`;
68+
69+
codePlaceholders[placeholderId] = nodeContent;
70+
finalContent = finalContent.replace(nodeContent, placeholderId);
71+
shouldSearchForPlaceholders = true;
72+
} else if (_node.type === "inlineCode") {
73+
const node = _node as InlineCode;
74+
75+
const nodeContentStartIndex = node.position?.start.offset;
76+
const nodeContentEndIndex = node.position?.end.offset;
77+
78+
if (!nodeContentStartIndex || !nodeContentEndIndex) {
79+
return;
80+
}
81+
82+
const nodeContent = finalContent.slice(
83+
nodeContentStartIndex,
84+
nodeContentEndIndex,
85+
);
86+
87+
const nodeContentHash = md5(nodeContent);
88+
const placeholderId = `__PLACEHOLDER_${nodeContentHash}__`;
89+
90+
codePlaceholders[placeholderId] = nodeContent;
91+
finalContent = finalContent.replace(nodeContent, placeholderId);
92+
shouldSearchForPlaceholders = true;
93+
}
94+
});
95+
}
6696

6797
return {
6898
content: finalContent,

0 commit comments

Comments
 (0)