Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test #974 and #939 #976

Draft
wants to merge 36 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9c918ad
fix(#935): set transform to literal mode
natemoo-re Jan 11, 2024
cff221c
fix: whitespace handling
natemoo-re Jan 11, 2024
eaa580a
chore: remove only
natemoo-re Jan 11, 2024
4abbf3c
chore: fix test typos
natemoo-re Jan 11, 2024
2b06c85
chore: add regression test for tokenizer
natemoo-re Jan 11, 2024
838be7e
Merge branch 'main' of https://github.com/withastro/compiler into fix…
MoustaphaDev Feb 29, 2024
58888df
test: fix incorrect tests
MoustaphaDev Feb 29, 2024
1c00621
test: add test for #958
MoustaphaDev Feb 29, 2024
b827dbb
refactor `addFrontmatter`
MoustaphaDev Mar 1, 2024
85fa4dc
test: add json test case
MoustaphaDev Mar 1, 2024
2b93f83
update transition scopes
MoustaphaDev Mar 1, 2024
34dddcd
test: fix incorrect tests
MoustaphaDev Mar 1, 2024
3d2f263
test: add test for #958
MoustaphaDev Mar 1, 2024
9b1def4
test: add json test case
MoustaphaDev Mar 1, 2024
51d7a6d
test: update transition scopes
MoustaphaDev Mar 1, 2024
e4178e2
refactor `addFrontmatter`
MoustaphaDev Mar 1, 2024
0784dd7
test: add test for #971
MoustaphaDev Mar 1, 2024
abf1c11
chore: proper name for added tests
MoustaphaDev Mar 1, 2024
6970684
chore: `only` helper for json test
MoustaphaDev Mar 1, 2024
045f4c0
fix: remove divergence from html spec
MoustaphaDev Mar 1, 2024
1d077f8
test: add test for #712
MoustaphaDev Mar 1, 2024
69e4d4a
`addLoc` before popping the stack of oe
MoustaphaDev Mar 2, 2024
851a128
test: add test
MoustaphaDev Mar 5, 2024
261d7d3
literal parsing after `body` and `html`
MoustaphaDev Mar 6, 2024
b951379
test: add test for style tag after body
MoustaphaDev Mar 6, 2024
4f8f51a
test: add tsx tests
MoustaphaDev Mar 6, 2024
54cf6d8
Merge branch 'fix/transform-literal-html-head-body-progress' into fix…
MoustaphaDev Mar 6, 2024
4519556
test: add missing semicolon in test
MoustaphaDev Mar 6, 2024
d437012
test: update test to reflect `addFrontmatter` refactor
MoustaphaDev Mar 6, 2024
968b6c4
test: remove code from bad merge commit
MoustaphaDev Mar 6, 2024
8bdf5d5
Merge branch 'main' into fix/transform-literal-html-head-body
MoustaphaDev Mar 6, 2024
c5a3f94
chore: update transition scope
MoustaphaDev Mar 6, 2024
c24e926
Merge branch 'mk/fix-712' into mk/test-compiler
MoustaphaDev Mar 6, 2024
b03c604
test: add more tests from duplicates
MoustaphaDev Mar 6, 2024
4cb45cd
Merge branch 'main' into mk/test-compiler
MoustaphaDev Mar 8, 2024
d665e43
Merge branch 'main' into mk/test-compiler
MoustaphaDev Mar 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/shiny-plums-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/compiler': minor
---

Fixes an edge case that caused `html` and `body` tags with attributes to be ignored when they were wrapped in a component.
6 changes: 3 additions & 3 deletions cmd/astro-wasm/astro-wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func Parse() any {
h := handler.NewHandler(source, parseOptions.Filename)

var doc *astro.Node
doc, err := astro.ParseWithOptions(strings.NewReader(source), astro.ParseOptionWithHandler(h), astro.ParseOptionEnableLiteral(true))
doc, err := astro.ParseWithOptions(strings.NewReader(source), astro.ParseOptionEnableLiteral(true), astro.ParseOptionWithHandler(h))
if err != nil {
h.AppendError(err)
}
Expand All @@ -256,7 +256,7 @@ func ConvertToTSX() any {
h := handler.NewHandler(source, transformOptions.Filename)

var doc *astro.Node
doc, err := astro.ParseWithOptions(strings.NewReader(source), astro.ParseOptionWithHandler(h), astro.ParseOptionEnableLiteral(true))
doc, err := astro.ParseWithOptions(strings.NewReader(source), astro.ParseOptionEnableLiteral(true), astro.ParseOptionWithHandler(h))
if err != nil {
h.AppendError(err)
}
Expand Down Expand Up @@ -307,7 +307,7 @@ func Transform() any {
}
}()

doc, err := astro.ParseWithOptions(strings.NewReader(source), astro.ParseOptionWithHandler(h))
doc, err := astro.ParseWithOptions(strings.NewReader(source), astro.ParseOptionEnableLiteral(true), astro.ParseOptionWithHandler(h))
if err != nil {
reject.Invoke(wasm_utils.ErrorToJSError(h, err))
return
Expand Down
34 changes: 16 additions & 18 deletions internal/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ func (p *parser) addText(text string) {
})
}

func (p *parser) addFrontmatter(empty bool) {
func (p *parser) addFrontmatter() {
if p.frontmatterState == FrontmatterInitial {
if p.doc.FirstChild != nil {
p.fm = &Node{
Expand All @@ -369,13 +369,8 @@ func (p *parser) addFrontmatter(empty bool) {
}
p.doc.AppendChild(p.fm)
}
if empty {
p.frontmatterState = FrontmatterClosed
p.fm.Attr = append(p.fm.Attr, Attribute{Key: ImplicitNodeMarker, Type: EmptyAttribute})
} else {
p.frontmatterState = FrontmatterOpen
p.oe = append(p.oe, p.fm)
}
p.frontmatterState = FrontmatterOpen
p.oe = append(p.oe, p.fm)
}
}

Expand Down Expand Up @@ -646,9 +641,6 @@ func initialIM(p *parser) bool {
p.im = beforeHTMLIM
return true
}
if p.frontmatterState == FrontmatterInitial {
p.addFrontmatter(true)
}
p.quirks = true
p.im = beforeHTMLIM
return false
Expand Down Expand Up @@ -902,8 +894,10 @@ func inHeadIM(p *parser) bool {
p.im = afterHeadIM
return true
case a.Body, a.Html, a.Br:
p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
p.addLoc()
p.oe.pop()
p.originalIM = nil
p.im = afterHeadIM
return false
case a.Template:
if !p.oe.contains(a.Template) {
Expand Down Expand Up @@ -1437,12 +1431,18 @@ func inBodyIM(p *parser) bool {
if p.elementInScope(defaultScope, a.Body) {
p.im = afterBodyIM
}
if p.literal {
p.oe.pop()
}
case a.Html:
p.addLoc()
if p.elementInScope(defaultScope, a.Body) {
p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
return false
}
if p.literal {
p.oe.pop()
}
return true
case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
p.addLoc()
Expand Down Expand Up @@ -1534,9 +1534,6 @@ func inBodyIM(p *parser) bool {
}
}
}
if p.frontmatterState == FrontmatterInitial {
p.addFrontmatter(true)
}
return true
}

Expand Down Expand Up @@ -2642,7 +2639,7 @@ func frontmatterIM(p *parser) bool {
switch p.tok.Type {
case FrontmatterFenceToken:
if p.frontmatterState == FrontmatterInitial {
p.addFrontmatter(false)
p.addFrontmatter()
return true
} else {
p.frontmatterState = FrontmatterClosed
Expand Down Expand Up @@ -2700,9 +2697,10 @@ func inLiteralIM(p *parser) bool {
p.addLoc()
p.oe.pop()
p.acknowledgeSelfClosingTag()
} else {
// always continue `inLiteralIM`
return true
}
// always continue `inLiteralIM`
return true
case StartExpressionToken:
p.addExpression()
// always continue `inLiteralIM`
Expand Down
116 changes: 99 additions & 17 deletions internal/printer/printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type jsonTestcase struct {
name string
source string
want []ASTNode
only bool
}

func TestPrinter(t *testing.T) {
Expand Down Expand Up @@ -259,7 +260,7 @@ func TestPrinter(t *testing.T) {
},
{
name: "slot with fallback",
source: `<body><slot><p>Hello world!</p></slot><body>`,
source: `<body><slot><p>Hello world!</p></slot></body>`,
want: want{
code: `${$$maybeRenderHead($$result)}<body>${$$renderSlot($$result,$$slots["default"],$$render` + BACKTICK + `<p>Hello world!</p>` + BACKTICK + `)}</body>`,
},
Expand Down Expand Up @@ -568,9 +569,9 @@ import type data from "test"
<h2>div+h2 ${dummyKey}</h2>
</div>
<p>
</p><h2>p+h2 ${dummyKey}</h2>
` + BACKTICK + `
);
<h2>p+h2 ${dummyKey}</h2>
</p>` + BACKTICK + `
);
})
}
</main>
Expand All @@ -588,8 +589,8 @@ import type data from "test"
want: want{
code: `<html lang="en">
${$$maybeRenderHead($$result)}<body>
${Object.keys(importedAuthors).map(author => $$render` + BACKTICK + `<p></p><div>hello</div>` + BACKTICK + `)}
${Object.keys(importedAuthors).map(author => $$render` + BACKTICK + `<p></p><div>${author}</div>` + BACKTICK + `)}
${Object.keys(importedAuthors).map(author => $$render` + BACKTICK + `<p><div>hello</div></p>` + BACKTICK + `)}
${Object.keys(importedAuthors).map(author => $$render` + BACKTICK + `<p><div>${author}</div></p>` + BACKTICK + `)}
</body>
</html>`,
},
Expand Down Expand Up @@ -1602,6 +1603,13 @@ const name = 'named';
code: "${cond && $$render`<meta charset=\"utf8\">`}${cond && $$render`<title>My title</title>`}",
},
},
{
name: "top-level component does not drop body attributes",
source: `<Base><body class="foobar"><slot /></body></Base>`,
want: want{
code: "${$$renderComponent($$result,'Base',Base,{},{\"default\": () => $$render`${$$maybeRenderHead($$result)}<body class=\"foobar\">${$$renderSlot($$result,$$slots[\"default\"])}</body>`,})}",
},
},
{
name: "custom elements",
source: `---
Expand Down Expand Up @@ -1661,7 +1669,7 @@ ${$$renderComponent($$result,'my-element','my-element',{"client:load":true,"clie
},
{
name: "Self-closing script in head works",
source: `<html><head><script is:inline /></head><html>`,
source: `<html><head><script is:inline /></head></html>`,
want: want{
code: `<html><head><script></script>` + RENDER_HEAD_RESULT + `</head></html>`,
},
Expand All @@ -1682,7 +1690,7 @@ ${$$renderComponent($$result,'my-element','my-element',{"client:load":true,"clie
},
{
name: "Self-closing components in head can have siblings",
source: `<html><head><BaseHead /><link href="test"></head><html>`,
source: `<html><head><BaseHead /><link href="test"></head></html>`,
want: want{
code: `<html><head>${$$renderComponent($$result,'BaseHead',BaseHead,{})}<link href="test">` + RENDER_HEAD_RESULT + `</head></html>`,
},
Expand Down Expand Up @@ -2082,7 +2090,7 @@ import { Container, Col, Row } from 'react-bootstrap';
name: "Preserve namespaces in expressions",
source: `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><rect xlink:href={` + BACKTICK + `#${iconId}` + BACKTICK + `}></svg>`,
want: want{
code: `${$$maybeRenderHead($$result)}<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><rect ${$$addAttribute(` + BACKTICK + `#${iconId}` + BACKTICK + `, "xlink:href")}></rect></svg>`,
code: `${$$maybeRenderHead($$result)}<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><rect${$$addAttribute(` + BACKTICK + `#${iconId}` + BACKTICK + `, "xlink:href")}></rect></svg>`,
},
},
{
Expand Down Expand Up @@ -2297,6 +2305,42 @@ const content = "lol";
</html>`,
},
},
{
// ensurethere are no duplicate elements matching the ones in the link below (`<a>` in this test)
// https://github.com/withastro/compiler/blob/a90d99ee8cc3ad92d1b39d73df1f7301011ee970/internal/parser.go#L1490
name: "<a> tag with expression in table ",
source: `<main>
<table>
<tr>
<td><a href={linkURL}>{linkURL}</a></td>
</tr>
</table>
</main>`,
want: want{
code: `${$$maybeRenderHead($$result)}<main>
<table>
<tr>
<td><a${$$addAttribute(linkURL, "href")}>${linkURL}</a></td>
</tr>
</table>
</main>`,
},
},
{
// makes sure that there are no duplicate elements matching the ones in the link below (`<a>` in this test)
// https://github.com/withastro/compiler/blob/a90d99ee8cc3ad92d1b39d73df1f7301011ee970/internal/parser.go#L1490
name: "<a> tag with expression in template",
source: `<template>
<a href="https://example.com">{text}</a>.
</template>
<p>This should not be a link</p>`,
want: want{
code: `<template>
${$$maybeRenderHead($$result)}<a href="https://example.com">${text}</a>.
</template>
<p>This should not be a link</p>`,
},
},
{
name: "complex table",
source: `<html lang="en">
Expand Down Expand Up @@ -3444,7 +3488,7 @@ const items = ["Dog", "Cat", "Platipus"];
filename: "/projects/app/src/pages/page.astro",
transitions: true,
want: want{
code: `${$$maybeRenderHead($$result)}<div${$$addAttribute($$renderTransition($$result, "daiq24ry", "", (one + '-' + 'two')), "data-astro-transition-scope")}></div>`,
code: `${$$maybeRenderHead($$result)}<div${$$addAttribute($$renderTransition($$result, "eh4gbiwl", "", (one + '-' + 'two')), "data-astro-transition-scope")}></div>`,
},
},
{
Expand All @@ -3453,7 +3497,7 @@ const items = ["Dog", "Cat", "Platipus"];
filename: "/projects/app/src/pages/page.astro",
transitions: true,
want: want{
code: `${$$maybeRenderHead($$result)}<div${$$addAttribute($$renderTransition($$result, "vvov4lyr", "", ` + BACKTICK + `${one}-two` + BACKTICK + `), "data-astro-transition-scope")}></div>`,
code: `${$$maybeRenderHead($$result)}<div${$$addAttribute($$renderTransition($$result, "2oo357hq", "", ` + BACKTICK + `${one}-two` + BACKTICK + `), "data-astro-transition-scope")}></div>`,
},
},
{
Expand All @@ -3462,7 +3506,7 @@ const items = ["Dog", "Cat", "Platipus"];
filename: "/projects/app/src/pages/page.astro",
transitions: true,
want: want{
code: `${$$maybeRenderHead($$result)}<div${$$addAttribute($$renderTransition($$result, "ih7yuffh", (slide({duration:15})), ""), "data-astro-transition-scope")}></div>`,
code: `${$$maybeRenderHead($$result)}<div${$$addAttribute($$renderTransition($$result, "x2dt3p4g", (slide({duration:15})), ""), "data-astro-transition-scope")}></div>`,
},
},
{
Expand All @@ -3471,31 +3515,31 @@ const items = ["Dog", "Cat", "Platipus"];
filename: "/projects/app/src/pages/page.astro",
transitions: true,
want: want{
code: `${$$renderComponent($$result,'Component',Component,{"class":"bar","data-astro-transition-scope":($$renderTransition($$result, "wkm5vset", "morph", ""))})}`,
code: `${$$renderComponent($$result,'Component',Component,{"class":"bar","data-astro-transition-scope":($$renderTransition($$result, "byigm4lx", "morph", ""))})}`,
},
},
{
name: "transition:persist converted to a data attribute",
source: `<div transition:persist></div>`,
transitions: true,
want: want{
code: `${$$maybeRenderHead($$result)}<div${$$addAttribute($$createTransitionScope($$result, "pflz5ime"), "data-astro-transition-persist")}></div>`,
code: `${$$maybeRenderHead($$result)}<div${$$addAttribute($$createTransitionScope($$result, "z45b6una"), "data-astro-transition-persist")}></div>`,
},
},
{
name: "transition:persist uses transition:name if defined",
source: `<div transition:persist transition:name="foo"></div>`,
transitions: true,
want: want{
code: `${$$maybeRenderHead($$result)}<div data-astro-transition-persist="foo"${$$addAttribute($$renderTransition($$result, "peuy4xf7", "", "foo"), "data-astro-transition-scope")}></div>`,
code: `${$$maybeRenderHead($$result)}<div data-astro-transition-persist="foo"${$$addAttribute($$renderTransition($$result, "nqtd2ecx", "", "foo"), "data-astro-transition-scope")}></div>`,
},
},
{
name: "transition:persist-props converted to a data attribute",
source: `<my-island transition:persist transition:persist-props="false"></my-island>`,
transitions: true,
want: want{
code: `${$$renderComponent($$result,'my-island','my-island',{"data-astro-transition-persist-props":"false","data-astro-transition-persist":($$createTransitionScope($$result, "otghnj5u"))})}`,
code: `${$$renderComponent($$result,'my-island','my-island',{"data-astro-transition-persist-props":"false","data-astro-transition-persist":($$createTransitionScope($$result, "rho3aldc"))})}`,
},
},
{
Expand All @@ -3520,8 +3564,8 @@ const items = ["Dog", "Cat", "Platipus"];
// transform output from source
code := test_utils.Dedent(tt.source)

doc, err := astro.Parse(strings.NewReader(code))
h := handler.NewHandler(code, "<stdin>")
doc, err := astro.ParseWithOptions(strings.NewReader(code), astro.ParseOptionEnableLiteral(true), astro.ParseOptionWithHandler(h))

if err != nil {
t.Error(err)
Expand Down Expand Up @@ -3746,11 +3790,36 @@ const c = '\''
source: `<style></style><html><body><h1>Hello world!</h1></body></html>`,
want: []ASTNode{{Type: "element", Name: "style"}, {Type: "element", Name: "html", Children: []ASTNode{{Type: "element", Name: "body", Children: []ASTNode{{Type: "element", Name: "h1", Children: []ASTNode{{Type: "text", Value: "Hello world!"}}}}}}}},
},
{
name: "empty style",
source: `<style define:vars={{ color: "Gainsboro" }}></style>`,
want: []ASTNode{{Type: "element", Name: "style", Attributes: []ASTNode{{Type: "attribute", Kind: "expression", Name: "define:vars", Value: "{ color: \"Gainsboro\" }"}}}},
},
{
name: "style after html",
source: `<html><body><h1>Hello world!</h1></body></html><style></style>`,
want: []ASTNode{{Type: "element", Name: "html", Children: []ASTNode{{Type: "element", Name: "body", Children: []ASTNode{{Type: "element", Name: "h1", Children: []ASTNode{{Type: "text", Value: "Hello world!"}}}}}}}, {Type: "element", Name: "style"}},
},
{
name: "style after empty html",
source: `<html></html><style></style>`,
want: []ASTNode{{Type: "element", Name: "html"}, {Type: "element", Name: "style"}},
},
{
name: "style after html with component in head",
source: `<html lang="en"><head><BaseHead /></head></html><style>@use "../styles/global.scss";</style>`,
want: []ASTNode{{Type: "element", Name: "html", Attributes: []ASTNode{{Type: "attribute", Kind: "quoted", Name: "lang", Value: "en", Raw: "\"en\""}}, Children: []ASTNode{{Type: "element", Name: "head", Children: []ASTNode{{Type: "component", Name: "BaseHead"}}}}}, {Type: "element", Name: "style", Children: []ASTNode{{Type: "text", Value: "@use \"../styles/global.scss\";"}}}},
},
{
name: "style after html with component in head and body",
source: `<html lang="en"><head><BaseHead /></head><body><Header /></body></html><style>@use "../styles/global.scss";</style>`,
want: []ASTNode{{Type: "element", Name: "html", Attributes: []ASTNode{{Type: "attribute", Kind: "quoted", Name: "lang", Value: "en", Raw: "\"en\""}}, Children: []ASTNode{{Type: "element", Name: "head", Children: []ASTNode{{Type: "component", Name: "BaseHead"}}}, {Type: "element", Name: "body", Children: []ASTNode{{Type: "component", Name: "Header"}}}}}, {Type: "element", Name: "style", Children: []ASTNode{{Type: "text", Value: "@use \"../styles/global.scss\";"}}}},
},
{
name: "style after body with component in head and body",
source: `<html lang="en"><head><BaseHead /></head><body><Header /></body><style>@use "../styles/global.scss";</style></html>`,
want: []ASTNode{{Type: "element", Name: "html", Attributes: []ASTNode{{Type: "attribute", Kind: "quoted", Name: "lang", Value: "en", Raw: "\"en\""}}, Children: []ASTNode{{Type: "element", Name: "head", Children: []ASTNode{{Type: "component", Name: "BaseHead"}}}, {Type: "element", Name: "body", Children: []ASTNode{{Type: "component", Name: "Header"}}}, {Type: "element", Name: "style", Children: []ASTNode{{Type: "text", Value: "@use \"../styles/global.scss\";"}}}}}},
},
{
name: "style in html",
source: `<html><body><h1>Hello world!</h1></body><style></style></html>`,
Expand All @@ -3776,6 +3845,19 @@ const c = '\''
source: `<main id=` + BACKTICK + `gotcha />`,
want: []ASTNode{{Type: "element", Name: "main", Attributes: []ASTNode{{Type: "attribute", Kind: "template-literal", Name: "id", Value: "gotcha", Raw: "`gotcha"}}}},
},
{
name: "top-level component does not drop body attributes",
source: `<Base><body class="foobar"><slot /></body></Base>`,
want: []ASTNode{{Type: "component", Name: "Base", Attributes: []ASTNode{}, Children: []ASTNode{{Type: "element", Name: "body", Attributes: []ASTNode{{Type: "attribute", Kind: "quoted", Name: "class", Value: "foobar", Raw: "\"foobar\""}}, Children: []ASTNode{{Type: "element", Name: "slot"}}}}}},
},
}

for _, tt := range tests {
if tt.only {
tests = make([]jsonTestcase, 0)
tests = append(tests, tt)
break
}
}

for _, tt := range tests {
Expand Down
5 changes: 5 additions & 0 deletions internal/token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,11 @@ func TestBasic(t *testing.T) {
`<div></div><MyAstroComponent` + "\n",
[]TokenType{StartTagToken, EndTagToken, TextToken},
},
{
"literal body",
`<body><slot><p>Hello world!</p></slot></body>`,
[]TokenType{StartTagToken, StartTagToken, StartTagToken, TextToken, EndTagToken, EndTagToken, EndTagToken},
},
}

runTokenTypeTest(t, Basic)
Expand Down
Loading