Skip to content

Commit 8bd99ae

Browse files
authored
fix: normalize jsx img src attribute correctly and run pnpm dedupe (#1979)
1 parent 9af42d4 commit 8bd99ae

File tree

7 files changed

+189
-508
lines changed

7 files changed

+189
-508
lines changed

packages/core/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,14 @@
9999
"memfs": "^4.17.0",
100100
"postcss": "8.5.3",
101101
"rehype-stringify": "^9.0.4",
102+
"remark-mdx": "2.3.0",
102103
"remark-parse": "^10.0.2",
103104
"remark-rehype": "^10.1.0",
105+
"remark-stringify": "^10.0.3",
104106
"rimraf": "^6.0.1",
105107
"tailwindcss": "^3.4.17",
106-
"typescript": "^5.8.2"
108+
"typescript": "^5.8.2",
109+
"vfile": "^5.3.7"
107110
},
108111
"engines": {
109112
"node": ">=14.17.6"

packages/core/src/node/mdx/options.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ export async function createMDXOptions(
4141
),
4242
...globalComponentsFromConfig,
4343
];
44-
const defaultLang = config?.lang || '';
4544
return {
4645
providerImportSource: '@mdx-js/react',
4746
format: path.extname(filepath).slice(1) as 'mdx' | 'md',
@@ -52,7 +51,6 @@ export async function createMDXOptions(
5251
remarkPluginNormalizeLink,
5352
{
5453
cleanUrls,
55-
defaultLang,
5654
root: docDirectory,
5755
},
5856
],

packages/core/src/node/mdx/remarkPlugins/normalizeLink.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,21 +127,21 @@ export const remarkPluginNormalizeLink: Plugin<
127127
return;
128128
}
129129

130-
const src = getNodeAttribute(node, 'src');
130+
const srcAttr = getNodeAttribute(node, 'src', true);
131131

132-
if (typeof src !== 'string') {
132+
if (typeof srcAttr?.value !== 'string') {
133133
return;
134134
}
135135

136-
const imagePath = normalizeImageUrl(src);
136+
const imagePath = normalizeImageUrl(srcAttr.value);
137137

138138
if (!imagePath) {
139139
return;
140140
}
141141

142142
const tempVariableName = `image${images.length}`;
143143

144-
Object.assign(src, getMdxSrcAttribute(tempVariableName));
144+
Object.assign(srcAttr, getMdxSrcAttribute(tempVariableName));
145145

146146
images.push(getASTNodeImport(tempVariableName, imagePath));
147147
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`Markdown compile cases > remarkPluginNormalizeLink > should just work 1`] = `
4+
"import image0 from "./test3.jpg"
5+
6+
import image1 from "./test4.png"
7+
8+
[link1](/test1.html)
9+
10+
{/* jsx link will not be transformed */}
11+
12+
<a href="./test2">link2</a>
13+
14+
<img alt="alt1" src={image0} />
15+
16+
<img src={image1} alt="alt2" />
17+
"
18+
`;

packages/core/tests/md.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
import path from 'node:path';
12
import rehypeStringify from 'rehype-stringify';
3+
import remarkMdx from 'remark-mdx';
24
import remarkParse from 'remark-parse';
35
import remarkRehype from 'remark-rehype';
6+
import remarkStringify from 'remark-stringify';
47
import { unified } from 'unified';
8+
import { VFile } from 'vfile';
59
import { describe, expect, test } from 'vitest';
10+
import { remarkPluginNormalizeLink } from '../src/node/mdx/remarkPlugins/normalizeLink';
611

712
describe('Markdown compile cases', () => {
813
const processor = unified()
@@ -15,4 +20,35 @@ describe('Markdown compile cases', () => {
1520
const result = processor.processSync(mdContent);
1621
expect(result.value).toMatchInlineSnapshot('"<h1>123</h1>"');
1722
});
23+
24+
describe('remarkPluginNormalizeLink', () => {
25+
it('should just work', () => {
26+
const processor = unified()
27+
.use(remarkParse)
28+
.use(remarkMdx)
29+
.use(remarkPluginNormalizeLink, {
30+
root: process.cwd(),
31+
cleanUrls: false,
32+
})
33+
.use(remarkStringify);
34+
35+
const result = processor.processSync(
36+
new VFile({
37+
value: `
38+
[link1](./test1.md)
39+
40+
{/* jsx link will not be transformed */}
41+
42+
<a href="./test2">link2</a>
43+
44+
![alt1](./test3.jpg)
45+
46+
<img src="./test4.png" alt="alt2" />
47+
`.trim(),
48+
path: path.resolve('test.mdx'),
49+
}),
50+
);
51+
expect(result.value).matchSnapshot();
52+
});
53+
});
1854
});
Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
1-
import type { MdxJsxFlowElement, MdxJsxTextElement } from 'mdast-util-mdx-jsx';
1+
import type {
2+
MdxJsxAttribute,
3+
MdxJsxAttributeValueExpression,
4+
MdxJsxExpressionAttribute,
5+
MdxJsxFlowElement,
6+
MdxJsxTextElement,
7+
} from 'mdast-util-mdx-jsx';
28

3-
export const getNodeAttribute = (
9+
export function getNodeAttribute(
410
node: MdxJsxFlowElement | MdxJsxTextElement,
511
attrName: string,
6-
) => {
7-
return node.attributes.find(attr => 'name' in attr && attr.name === attrName)
8-
?.value;
9-
};
12+
attribute?: false,
13+
): string | MdxJsxAttributeValueExpression | null | undefined;
14+
export function getNodeAttribute(
15+
node: MdxJsxFlowElement | MdxJsxTextElement,
16+
attrName: string,
17+
attribute: true,
18+
): MdxJsxAttribute | MdxJsxExpressionAttribute | undefined;
19+
export function getNodeAttribute(
20+
node: MdxJsxFlowElement | MdxJsxTextElement,
21+
attrName: string,
22+
attribute?: boolean,
23+
) {
24+
const found = node.attributes.find(
25+
attr => 'name' in attr && attr.name === attrName,
26+
);
27+
return attribute ? found : found?.value;
28+
}

0 commit comments

Comments
 (0)