Skip to content

Commit a91e04f

Browse files
authored
feat: ignore <style> tag content in markdown (#3)
## Summary - Ignore `<style>` nodes during Markdown serialization so CSS content is omitted from SSG-MD output. - Add a regression test for `<style>` handling. - Document `<style>` behavior in the supported elements table. ## Testing - `pnpm test` - `pnpm exec biome check .` - `pnpm build`
1 parent 6bfc18a commit a91e04f

3 files changed

Lines changed: 57 additions & 31 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ For languages that may contain triple backticks (like `markdown`, `mdx`, `md`),
112112
| `<blockquote>` | `> blockquote` |
113113
| `<br>` | Line break |
114114
| `<hr>` | `---` horizontal rule |
115+
| `<style>` | Ignored |
115116
| `<table>`, `<thead>`, `<tbody>`, `<tr>`, `<th>`, `<td>` | GFM table |
116117

117118
Any unrecognized elements (e.g. `<div>`, `<span>`, `<section>`) render their children as-is, acting as transparent wrappers.

src/react/render.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,28 @@ console.log('Hello, world!');
260260
});
261261

262262
describe('renderToMarkdownString - styles', () => {
263+
it('ignores style tag content', async () => {
264+
expect(
265+
await renderToMarkdownString(
266+
<div>
267+
<h1>Title</h1>
268+
<style>{`
269+
.rspress-doc {
270+
color: red;
271+
}
272+
`}</style>
273+
<p>Content</p>
274+
</div>,
275+
),
276+
).toMatchInlineSnapshot(`
277+
"# Title
278+
279+
Content
280+
281+
"
282+
`);
283+
});
284+
263285
it('renders two row correctly', async () => {
264286
const Comp1 = () => {
265287
return (

src/react/render.ts

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -99,46 +99,47 @@ function toMarkdown(root: MarkdownNode): string {
9999
const { type, props, children } = root;
100100

101101
// Get children's Markdown
102-
const childrenMd = children
103-
.map((child) => {
104-
if (child instanceof TextNode) {
105-
return child.text;
106-
}
107-
return toMarkdown(child);
108-
})
109-
.join('');
102+
const childrenMd = () =>
103+
children
104+
.map((child) => {
105+
if (child instanceof TextNode) {
106+
return child.text;
107+
}
108+
return toMarkdown(child);
109+
})
110+
.join('');
110111

111112
// Generate corresponding Markdown based on element type
112113
switch (type) {
113114
case 'root':
114-
return childrenMd;
115+
return childrenMd();
115116
case 'h1':
116-
return `# ${childrenMd}\n\n`;
117+
return `# ${childrenMd()}\n\n`;
117118
case 'h2':
118-
return `## ${childrenMd}\n\n`;
119+
return `## ${childrenMd()}\n\n`;
119120
case 'h3':
120-
return `### ${childrenMd}\n\n`;
121+
return `### ${childrenMd()}\n\n`;
121122
case 'h4':
122-
return `#### ${childrenMd}\n\n`;
123+
return `#### ${childrenMd()}\n\n`;
123124
case 'h5':
124-
return `##### ${childrenMd}\n\n`;
125+
return `##### ${childrenMd()}\n\n`;
125126
case 'h6':
126-
return `###### ${childrenMd}\n\n`;
127+
return `###### ${childrenMd()}\n\n`;
127128
case 'p':
128-
return `${childrenMd}\n\n`;
129+
return `${childrenMd()}\n\n`;
129130
case 'strong':
130131
case 'b':
131-
return `**${childrenMd}**`;
132+
return `**${childrenMd()}**`;
132133
case 'em':
133134
case 'i':
134-
return `*${childrenMd}*`;
135+
return `*${childrenMd()}*`;
135136
case 'code':
136137
// When <code> is nested inside <pre>, it represents the code block body,
137138
// so we must not wrap it with inline backticks (would create nested fences).
138139
if (root.parent?.type === 'pre') {
139-
return childrenMd;
140+
return childrenMd();
140141
}
141-
return `\`${childrenMd}\``;
142+
return `\`${childrenMd()}\``;
142143
case 'pre': {
143144
const _language =
144145
props['data-lang'] || props.language || props.lang || '';
@@ -149,33 +150,35 @@ function toMarkdown(root: MarkdownNode): string {
149150
? '````'
150151
: '```';
151152

152-
return `\n${block}${language}${title ? ` title=${title}` : ''}\n${childrenMd}\n${block}\n`;
153+
return `\n${block}${language}${title ? ` title=${title}` : ''}\n${childrenMd()}\n${block}\n`;
153154
}
154155
case 'a':
155-
return `[${childrenMd}](${props.href || '#'})`;
156+
return `[${childrenMd()}](${props.href || '#'})`;
156157
case 'img':
157158
return `![${props.alt || ''}](${props.src || ''})`;
158159
case 'ul':
159-
return `${childrenMd}\n`;
160+
return `${childrenMd()}\n`;
160161
case 'ol':
161-
return `${childrenMd}\n`;
162+
return `${childrenMd()}\n`;
162163
case 'li': {
163164
const isOrdered = root.parent && root.parent.type === 'ol';
164165
const prefix = isOrdered ? '1. ' : '- ';
165-
return `${prefix}${childrenMd}\n`;
166+
return `${prefix}${childrenMd()}\n`;
166167
}
167168
case 'blockquote':
168-
return `> ${childrenMd.split('\n').join('\n> ')}\n\n`;
169+
return `> ${childrenMd().split('\n').join('\n> ')}\n\n`;
169170
case 'br':
170171
return '\n';
171172
case 'hr':
172173
return '---\n\n';
174+
case 'style':
175+
return '';
173176
case 'table':
174-
return `${childrenMd}\n`;
177+
return `${childrenMd()}\n`;
175178
case 'thead':
176-
return childrenMd;
179+
return childrenMd();
177180
case 'tbody':
178-
return childrenMd;
181+
return childrenMd();
179182
case 'tr': {
180183
const cells = children
181184
.filter((child): child is MarkdownNode => child instanceof MarkdownNode)
@@ -191,9 +194,9 @@ function toMarkdown(root: MarkdownNode): string {
191194
}
192195
case 'th':
193196
case 'td':
194-
return childrenMd;
197+
return childrenMd();
195198
default:
196-
return childrenMd;
199+
return childrenMd();
197200
}
198201
}
199202

0 commit comments

Comments
 (0)