Skip to content

Commit 6a27384

Browse files
atinuxcursoragent
andauthored
fix: prevent void HTML elements from swallowing subsequent content (#190)
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent bbb4301 commit 6a27384

4 files changed

Lines changed: 122 additions & 4 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
## Input
2+
3+
```md
4+
<br>
5+
6+
# After br
7+
```
8+
9+
## AST
10+
11+
```json
12+
{
13+
"frontmatter": {},
14+
"meta": {},
15+
"nodes": [
16+
[
17+
"br",
18+
{
19+
"$": {
20+
"html": 1,
21+
"block": 1
22+
}
23+
}
24+
],
25+
[
26+
"h1",
27+
{
28+
"id": "after-br"
29+
},
30+
"After br"
31+
]
32+
]
33+
}
34+
```
35+
36+
## HTML
37+
38+
```html
39+
<br />
40+
<h1 id="after-br">After br</h1>
41+
```
42+
43+
## Markdown
44+
45+
```md
46+
<br />
47+
48+
# After br
49+
```
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
## Input
2+
3+
```md
4+
<img src="https://github.com/comarkdown/comark/blob/main/assets/banner.jpg" width="100%" alt="Comark banner" />
5+
6+
# comark
7+
8+
A high-performance markdown parser and renderer.
9+
```
10+
11+
## AST
12+
13+
```json
14+
{
15+
"frontmatter": {},
16+
"meta": {},
17+
"nodes": [
18+
[
19+
"img",
20+
{
21+
"$": {
22+
"html": 1,
23+
"block": 1
24+
},
25+
"src": "https://github.com/comarkdown/comark/blob/main/assets/banner.jpg",
26+
"width": "100%",
27+
"alt": "Comark banner"
28+
}
29+
],
30+
[
31+
"h1",
32+
{
33+
"id": "comark"
34+
},
35+
"comark"
36+
],
37+
[
38+
"p",
39+
{},
40+
"A high-performance markdown parser and renderer."
41+
]
42+
]
43+
}
44+
```
45+
46+
## HTML
47+
48+
```html
49+
<img src="https://github.com/comarkdown/comark/blob/main/assets/banner.jpg" width="100%" alt="Comark banner" />
50+
<h1 id="comark">comark</h1>
51+
<p>A high-performance markdown parser and renderer.</p>
52+
```
53+
54+
## Markdown
55+
56+
```md
57+
<img src="https://github.com/comarkdown/comark/blob/main/assets/banner.jpg" width="100%" alt="Comark banner" />
58+
59+
# comark
60+
61+
A high-performance markdown parser and renderer.
62+
```

packages/comark/src/internal/parse/html/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Parser } from 'htmlparser2'
22
import type { ComarkNode } from 'comark'
33

4-
const VOID_ELEMENTS = new Set([
4+
export const VOID_ELEMENTS = new Set([
55
'area',
66
'base',
77
'br',

packages/comark/src/internal/parse/token-processor.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ComarkElementAttributes, ComarkNode } from 'comark'
2-
import { htmlToComarkNodes, parseInlineHtmlTag } from './html/index.ts'
2+
import { htmlToComarkNodes, parseInlineHtmlTag, VOID_ELEMENTS } from './html/index.ts'
33

44
// Mapping from token types to tag names
55
const BLOCK_TAG_MAP: Record<string, string> = {
@@ -289,11 +289,18 @@ function processBlockToken(
289289
return { node: [null, {}, inner] as unknown as ComarkNode, nextIndex: startIndex + 1 }
290290
}
291291

292-
const children = processBlockChildren(tokens, startIndex + 1, 'html_block_close', false, false, false, state)
293-
const [node1] = htmlToComarkNodes(content)
292+
const htmlNodes = htmlToComarkNodes(content)
293+
const [node1] = htmlNodes
294294
if (!node1) {
295295
return { node: null, nextIndex: startIndex + 1 }
296296
}
297+
298+
const isVoid = Array.isArray(node1) && VOID_ELEMENTS.has(node1[0] as string)
299+
if (isVoid) {
300+
return { node: node1, nextIndex: startIndex + 1 }
301+
}
302+
303+
const children = processBlockChildren(tokens, startIndex + 1, 'html_block_close', false, false, false, state)
297304
const node = [node1[0]!, node1[1]! as ComarkElementAttributes, ...children.nodes] as ComarkNode
298305

299306
return { node, nextIndex: children.nextIndex + 1 }

0 commit comments

Comments
 (0)