Skip to content

Commit 02add77

Browse files
authored
Table fixes (#458)
* test: add failing tests * test(#428): add test for #428 * fix(tables): handle table expressions literally * fix: revert originalIM changes * test(#417): add test case * fix(#384): handle components in table * test(#381): add test case for #381 * fix(#427): handle slots in tables * chore: add changeset Co-authored-by: Nate Moore <[email protected]>
1 parent 9457a91 commit 02add77

File tree

3 files changed

+182
-12
lines changed

3 files changed

+182
-12
lines changed

.changeset/angry-knives-sip.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@astrojs/compiler': patch
3+
---
4+
5+
Fixes many edge cases around tables when used with components, slots, or expressions

internal/parser.go

Lines changed: 98 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,13 @@ func inTableIM(p *parser) bool {
17411741
return true
17421742
case StartTagToken:
17431743
switch p.tok.DataAtom {
1744+
case a.Slot:
1745+
p.addElement()
1746+
if p.hasSelfClosingToken {
1747+
p.oe.pop()
1748+
p.acknowledgeSelfClosingTag()
1749+
}
1750+
return true
17441751
case a.Caption:
17451752
p.clearStackToContext(tableScope)
17461753
p.afe = append(p.afe, &scopeMarker)
@@ -1800,6 +1807,14 @@ func inTableIM(p *parser) bool {
18001807
p.im = inSelectInTableIM
18011808
return true
18021809
}
1810+
if isComponent(p.tok.Data) {
1811+
p.addElement()
1812+
if p.hasSelfClosingToken {
1813+
p.oe.pop()
1814+
p.acknowledgeSelfClosingTag()
1815+
}
1816+
return true
1817+
}
18031818
case EndTagToken:
18041819
switch p.tok.DataAtom {
18051820
case a.Table:
@@ -1814,6 +1829,13 @@ func inTableIM(p *parser) bool {
18141829
return true
18151830
case a.Template:
18161831
return inHeadIM(p)
1832+
case a.Slot:
1833+
p.oe.pop()
1834+
return true
1835+
}
1836+
if isComponent(p.tok.Data) {
1837+
p.oe.pop()
1838+
return true
18171839
}
18181840
case CommentToken:
18191841
p.addChild(&Node{
@@ -1831,7 +1853,6 @@ func inTableIM(p *parser) bool {
18311853

18321854
p.fosterParenting = true
18331855
defer func() { p.fosterParenting = false }()
1834-
18351856
return inBodyIM(p)
18361857
}
18371858

@@ -1840,6 +1861,13 @@ func inCaptionIM(p *parser) bool {
18401861
switch p.tok.Type {
18411862
case StartTagToken:
18421863
switch p.tok.DataAtom {
1864+
case a.Slot:
1865+
p.addElement()
1866+
if p.hasSelfClosingToken {
1867+
p.oe.pop()
1868+
p.acknowledgeSelfClosingTag()
1869+
}
1870+
return true
18431871
case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Td, a.Tfoot, a.Thead, a.Tr:
18441872
if !p.popUntil(tableScope, a.Caption) {
18451873
// Ignore the token.
@@ -1913,6 +1941,13 @@ func inColumnGroupIM(p *parser) bool {
19131941
return true
19141942
case StartTagToken:
19151943
switch p.tok.DataAtom {
1944+
case a.Slot:
1945+
p.addElement()
1946+
if p.hasSelfClosingToken {
1947+
p.oe.pop()
1948+
p.acknowledgeSelfClosingTag()
1949+
}
1950+
return true
19161951
case a.Html:
19171952
return inBodyIM(p)
19181953
case a.Col:
@@ -1962,6 +1997,13 @@ func inTableBodyIM(p *parser) bool {
19621997
switch p.tok.Type {
19631998
case StartTagToken:
19641999
switch p.tok.DataAtom {
2000+
case a.Slot:
2001+
p.addElement()
2002+
if p.hasSelfClosingToken {
2003+
p.oe.pop()
2004+
p.acknowledgeSelfClosingTag()
2005+
}
2006+
return true
19652007
case a.Tr:
19662008
p.clearStackToContext(tableBodyScope)
19672009
p.addElement()
@@ -2022,8 +2064,21 @@ func inTableBodyIM(p *parser) bool {
20222064
// Section 12.2.6.4.14.
20232065
func inRowIM(p *parser) bool {
20242066
switch p.tok.Type {
2067+
case StartExpressionToken:
2068+
p.addExpression()
2069+
p.afe = append(p.afe, &scopeMarker)
2070+
p.originalIM = inRowIM
2071+
p.im = inExpressionIM
2072+
return true
20252073
case StartTagToken:
20262074
switch p.tok.DataAtom {
2075+
case a.Slot:
2076+
p.addElement()
2077+
if p.hasSelfClosingToken {
2078+
p.oe.pop()
2079+
p.acknowledgeSelfClosingTag()
2080+
}
2081+
return true
20272082
case a.Td, a.Th:
20282083
p.clearStackToContext(tableRowScope)
20292084
p.addElement()
@@ -2065,12 +2120,6 @@ func inRowIM(p *parser) bool {
20652120
// Ignore the token.
20662121
return true
20672122
}
2068-
case StartExpressionToken:
2069-
p.addExpression()
2070-
p.afe = append(p.afe, &scopeMarker)
2071-
p.originalIM = inTableIM
2072-
p.im = inExpressionIM
2073-
return true
20742123
case EndExpressionToken:
20752124
p.oe.pop()
20762125
return true
@@ -2092,6 +2141,13 @@ func inCellIM(p *parser) bool {
20922141
return true
20932142
case StartTagToken:
20942143
switch p.tok.DataAtom {
2144+
case a.Slot:
2145+
p.addElement()
2146+
if p.hasSelfClosingToken {
2147+
p.oe.pop()
2148+
p.acknowledgeSelfClosingTag()
2149+
}
2150+
return true
20952151
case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
20962152
if p.popUntil(tableScope, a.Td, a.Th) {
20972153
// Close the cell and reprocess.
@@ -2583,7 +2639,42 @@ func frontmatterIM(p *parser) bool {
25832639
}
25842640
}
25852641

2642+
// Handle expressions inside tables very literally
2643+
func inExpressionTableIM(p *parser) bool {
2644+
switch p.tok.Type {
2645+
case ErrorToken:
2646+
p.oe.pop()
2647+
case TextToken:
2648+
p.addText(p.tok.Data)
2649+
return true
2650+
case StartTagToken:
2651+
p.addElement()
2652+
if p.hasSelfClosingToken {
2653+
p.oe.pop()
2654+
p.acknowledgeSelfClosingTag()
2655+
}
2656+
return true
2657+
case EndTagToken:
2658+
p.oe.pop()
2659+
return true
2660+
case StartExpressionToken:
2661+
p.addExpression()
2662+
return true
2663+
case EndExpressionToken:
2664+
p.addLoc()
2665+
p.oe.pop()
2666+
return true
2667+
}
2668+
p.im = p.originalIM
2669+
p.originalIM = nil
2670+
return p.tok.Type == EndTagToken
2671+
}
2672+
25862673
func inExpressionIM(p *parser) bool {
2674+
if p.oe.contains(a.Table) {
2675+
p.clearActiveFormattingElements()
2676+
return inExpressionTableIM(p)
2677+
}
25872678
switch p.tok.Type {
25882679
case ErrorToken:
25892680
p.oe.pop()
@@ -2593,7 +2684,6 @@ func inExpressionIM(p *parser) bool {
25932684
if isComponent(p.tok.Data) {
25942685
return inBodyIM(p)
25952686
}
2596-
25972687
n := p.oe.top()
25982688
if p.isInsideHead() {
25992689
switch p.tok.DataAtom {
@@ -2624,8 +2714,6 @@ func inExpressionIM(p *parser) bool {
26242714
p.originalIM = inBodyIM
26252715
return false
26262716
}
2627-
} else if p.oe.contains(a.Table) {
2628-
return inTableBodyIM(p)
26292717
} else {
26302718
return inBodyIM(p)
26312719
}

internal/printer/printer_test.go

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,6 +1726,20 @@ const items = ["Dog", "Cat", "Platipus"];
17261726
code: `${$$maybeRenderHead($$result)}<table><tr><td><h2>Row 1</h2></td><td>${title}</td></tr></table>`,
17271727
},
17281728
},
1729+
{
1730+
name: "td expressions II",
1731+
source: `<table>{data.map(row => <tr>{row.map(cell => <td>{cell}</td>)}</tr>)}</table>`,
1732+
want: want{
1733+
code: "${$$maybeRenderHead($$result)}<table>${data.map(row => $$render`<tr>${row.map(cell => $$render`<td>${cell}</td>`)}</tr>`)}</table>",
1734+
},
1735+
},
1736+
{
1737+
name: "self-closing td",
1738+
source: `<table>{data.map(row => <tr>{row.map(cell => <td set:html={cell} />)}</tr>)}</table>`,
1739+
want: want{
1740+
code: "${$$maybeRenderHead($$result)}<table>${data.map(row => $$render`<tr>${row.map(cell => $$render`<td>${$$unescapeHTML(cell)}</td>`)}</tr>`)}</table>",
1741+
},
1742+
},
17291743
{
17301744
name: "th expressions",
17311745
source: `<table><thead><tr><th>{title}</th></tr></thead></table>`,
@@ -1844,8 +1858,71 @@ const items = ["Dog", "Cat", "Platipus"];
18441858
${true ? ($$render%s<tr><td>Row 1</td></tr>%s) : null}
18451859
${true ? ($$render%s<tr><td>Row 2</td></tr>%s) : null}
18461860
${true ? ($$render%s<tr><td>Row 3</td></tr>%s) : null}
1847-
1848-
</table></body></html>`, BACKTICK, BACKTICK, BACKTICK, BACKTICK, BACKTICK, BACKTICK),
1861+
</table>
1862+
</body></html>`, BACKTICK, BACKTICK, BACKTICK, BACKTICK, BACKTICK, BACKTICK),
1863+
},
1864+
},
1865+
{
1866+
name: "table",
1867+
source: "<table><tr>{[0,1,2].map(x => (<td>{x}</td>))}</tr></table>",
1868+
want: want{
1869+
code: "${$$maybeRenderHead($$result)}<table><tr>${[0,1,2].map(x => ($$render`<td>${x}</td>`))}</tr></table>",
1870+
},
1871+
},
1872+
{
1873+
name: "table II",
1874+
source: "<table><thead><tr>{['Hey','Ho'].map((item)=> <th scope=\"col\">{item}</th>)}</tr></thead></table>",
1875+
want: want{
1876+
code: "${$$maybeRenderHead($$result)}<table><thead><tr>${['Hey','Ho'].map((item)=> $$render`<th scope=\"col\">${item}</th>`)}</tr></thead></table>",
1877+
},
1878+
},
1879+
{
1880+
name: "table III",
1881+
source: "<table><tbody><tr><td>Cell</td><Cell /><Cell /><Cell /></tr></tbody></table>",
1882+
want: want{
1883+
code: "${$$maybeRenderHead($$result)}<table><tbody><tr><td>Cell</td>${$$renderComponent($$result,'Cell',Cell,{})}${$$renderComponent($$result,'Cell',Cell,{})}${$$renderComponent($$result,'Cell',Cell,{})}</tr></tbody></table>",
1884+
},
1885+
},
1886+
{
1887+
name: "table IV",
1888+
source: "<body><div><tr><td>hello world</td></tr></div></body>",
1889+
want: want{
1890+
code: "${$$maybeRenderHead($$result)}<body><div><tr><td>hello world</td></tr></div></body>",
1891+
},
1892+
},
1893+
{
1894+
name: "table slot I",
1895+
source: "<table><slot /></table>",
1896+
want: want{
1897+
code: "${$$maybeRenderHead($$result)}<table>${$$renderSlot($$result,$$slots[\"default\"])}</table>",
1898+
},
1899+
},
1900+
{
1901+
name: "table slot II",
1902+
source: "<table><tr><slot /></tr></table>",
1903+
want: want{
1904+
code: "${$$maybeRenderHead($$result)}<table><tr>${$$renderSlot($$result,$$slots[\"default\"])}</tr></table>",
1905+
},
1906+
},
1907+
{
1908+
name: "table slot III",
1909+
source: "<table><td><slot /></td></table>",
1910+
want: want{
1911+
code: "${$$maybeRenderHead($$result)}<table><td>${$$renderSlot($$result,$$slots[\"default\"])}</td></table>",
1912+
},
1913+
},
1914+
{
1915+
name: "table slot IV",
1916+
source: "<table><thead><slot /></thead></table>",
1917+
want: want{
1918+
code: "${$$maybeRenderHead($$result)}<table><thead>${$$renderSlot($$result,$$slots[\"default\"])}</thead></table>",
1919+
},
1920+
},
1921+
{
1922+
name: "table slot V",
1923+
source: "<table><tbody><slot /></tbody></table>",
1924+
want: want{
1925+
code: "${$$maybeRenderHead($$result)}<table><tbody>${$$renderSlot($$result,$$slots[\"default\"])}</tbody></table>",
18491926
},
18501927
},
18511928
{

0 commit comments

Comments
 (0)