Skip to content

Commit ef2921e

Browse files
authored
feat(parse): handle slot attributes (#189)
1 parent 6a27384 commit ef2921e

4 files changed

Lines changed: 143 additions & 4 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
## Input
2+
3+
```md
4+
::comp
5+
#header{unwrap="p" preset="title"}
6+
Title
7+
::
8+
```
9+
10+
## AST
11+
12+
```json
13+
{
14+
"frontmatter": {},
15+
"meta": {},
16+
"nodes": [
17+
[
18+
"comp",
19+
{},
20+
[
21+
"template",
22+
{
23+
"name": "header",
24+
"unwrap": "p",
25+
"preset": "title"
26+
},
27+
"Title"
28+
]
29+
]
30+
]
31+
}
32+
```
33+
34+
## HTML
35+
36+
```html
37+
<comp>
38+
<template name="header" unwrap="p" preset="title">
39+
Title
40+
</template>
41+
</comp>
42+
```
43+
44+
## Markdown
45+
46+
```md
47+
::comp
48+
#header{unwrap="p" preset="title"}
49+
Title
50+
::
51+
```
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
## Input
2+
3+
```md
4+
::feature
5+
#title{unwrap="p"}
6+
Visual Editor
7+
8+
#description{unwrap="p"}
9+
Edit without code.
10+
::
11+
```
12+
13+
## AST
14+
15+
```json
16+
{
17+
"frontmatter": {},
18+
"meta": {},
19+
"nodes": [
20+
[
21+
"feature",
22+
{},
23+
[
24+
"template",
25+
{
26+
"name": "title",
27+
"unwrap": "p"
28+
},
29+
"Visual Editor"
30+
],
31+
[
32+
"template",
33+
{
34+
"name": "description",
35+
"unwrap": "p"
36+
},
37+
"Edit without code."
38+
]
39+
]
40+
]
41+
}
42+
```
43+
44+
## HTML
45+
46+
```html
47+
<feature>
48+
<template name="title" unwrap="p">
49+
Visual Editor
50+
</template>
51+
<template name="description" unwrap="p">
52+
Edit without code.
53+
</template>
54+
</feature>
55+
```
56+
57+
## Markdown
58+
59+
```md
60+
::feature
61+
#title{unwrap="p"}
62+
Visual Editor
63+
64+
#description{unwrap="p"}
65+
Edit without code.
66+
::
67+
```

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

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ function processBlockChildrenWithSlots(
449449
const nodes: ComarkNode[] = []
450450
let i = startIndex
451451
let currentSlotName: string | null = null
452+
let currentSlotAttrs: Record<string, unknown> = {}
452453
let currentSlotChildren: ComarkNode[] = []
453454

454455
while (i < tokens.length && tokens[i].type !== closeType) {
@@ -469,22 +470,31 @@ function processBlockChildrenWithSlots(
469470
// Check for slot marker: #slotname creates mdc_block_slot tokens
470471
if (token.type === 'mdc_block_slot') {
471472
// Extract slot name from token.attrs
472-
// The attrs array contains [["#slotname", ""]] for open, and null/empty for close
473+
// The attrs array contains [["#slotname", ""], ...props] for open, and null/empty for close
473474
if (token.attrs && Array.isArray(token.attrs) && token.attrs.length > 0) {
474475
const firstAttr = token.attrs[0]
475476
if (Array.isArray(firstAttr) && firstAttr.length > 0) {
476477
const slotKey = firstAttr[0] as string
477478
// Remove the # prefix to get the slot name
478479
if (slotKey.startsWith('#')) {
479480
const slotName = slotKey.substring(1)
481+
const slotAttrs = processAttributes(token.attrs.slice(1))
480482

481483
// Save previous slot if any
482484
if (currentSlotName !== null && currentSlotChildren.length > 0) {
483-
nodes.push(['template', { name: currentSlotName }, ...currentSlotChildren] as ComarkNode)
485+
nodes.push([
486+
'template',
487+
{
488+
name: currentSlotName,
489+
...currentSlotAttrs,
490+
},
491+
...currentSlotChildren,
492+
] as ComarkNode)
484493
currentSlotChildren = []
485494
}
486495

487496
currentSlotName = slotName
497+
currentSlotAttrs = slotAttrs
488498
i++
489499
continue
490500
}
@@ -513,7 +523,14 @@ function processBlockChildrenWithSlots(
513523

514524
// Save last slot if any
515525
if (currentSlotName !== null && currentSlotChildren.length > 0) {
516-
nodes.push(['template', { name: currentSlotName }, ...currentSlotChildren] as ComarkNode)
526+
nodes.push([
527+
'template',
528+
{
529+
name: currentSlotName,
530+
...currentSlotAttrs,
531+
},
532+
...currentSlotChildren,
533+
] as ComarkNode)
517534
}
518535

519536
return { nodes, nextIndex: i }

packages/comark/src/internal/stringify/handlers/template.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { State } from 'comark/render'
22
import type { ComarkElement, ComarkNode } from 'comark'
3+
import { comarkAttributes } from '../attributes.ts'
34

45
// slot template
56
export async function template(node: ComarkElement, state: State, parent?: ComarkElement) {
@@ -18,5 +19,8 @@ export async function template(node: ComarkElement, state: State, parent?: Comar
1819
}
1920
}
2021

21-
return `#${attrs.name}\n${content}` + state.context.blockSeparator
22+
const { name: _name, $: _$, ...rest } = attrs
23+
const extraAttrs = comarkAttributes(rest)
24+
25+
return `#${attrs.name}${extraAttrs}\n${content}` + state.context.blockSeparator
2226
}

0 commit comments

Comments
 (0)