diff --git a/.changeset/popular-wombats-promise.md b/.changeset/popular-wombats-promise.md new file mode 100644 index 000000000..d7a09876a --- /dev/null +++ b/.changeset/popular-wombats-promise.md @@ -0,0 +1,9 @@ +--- +'@astrojs/compiler': major +--- + +The scope hash created by the compiler is now **lowercase**. + +This aligns with the HTML spec of the attribute names, where they are lowercase by spec. + +This change is needed because the compiler now creates data attributes that contain the hash in their name. diff --git a/cmd/astro-wasm/astro-wasm.go b/cmd/astro-wasm/astro-wasm.go index 1b08f2364..d9914c54b 100644 --- a/cmd/astro-wasm/astro-wasm.go +++ b/cmd/astro-wasm/astro-wasm.go @@ -223,7 +223,7 @@ func Parse() any { source := jsString(args[0]) parseOptions := makeParseOptions(js.Value(args[1])) transformOptions := makeTransformOptions(js.Value(args[1])) - transformOptions.Scope = "XXXXXX" + transformOptions.Scope = "xxxxxx" h := handler.NewHandler(source, parseOptions.Filename) var doc *astro.Node @@ -247,7 +247,7 @@ func ConvertToTSX() any { return js.FuncOf(func(this js.Value, args []js.Value) any { source := jsString(args[0]) transformOptions := makeTransformOptions(js.Value(args[1])) - transformOptions.Scope = "XXXXXX" + transformOptions.Scope = "xxxxxx" h := handler.NewHandler(source, transformOptions.Filename) var doc *astro.Node diff --git a/internal/hash.go b/internal/hash.go index 8ef1ca4a5..079b49f2a 100644 --- a/internal/hash.go +++ b/internal/hash.go @@ -2,6 +2,7 @@ package astro import ( "encoding/base32" + "strings" "github.com/withastro/compiler/internal/xxhash" ) @@ -11,5 +12,5 @@ func HashString(str string) string { //nolint h.Write([]byte(str)) hashBytes := h.Sum(nil) - return base32.StdEncoding.EncodeToString(hashBytes)[:8] + return strings.ToLower(base32.StdEncoding.EncodeToString(hashBytes)[:8]) } diff --git a/internal/printer/printer_css_test.go b/internal/printer/printer_css_test.go index dbb2c0d05..78e554b4a 100644 --- a/internal/printer/printer_css_test.go +++ b/internal/printer/printer_css_test.go @@ -34,7 +34,7 @@ func TestPrinterCSS(t *testing.T) {

Page Title

I’m a page

`, - want: ".title:where(.astro-DPOHFLYM){font-family:fantasy;font-size:28px}.body:where(.astro-DPOHFLYM){font-size:1em}", + want: ".title:where(.astro-dpohflym){font-family:fantasy;font-size:28px}.body:where(.astro-dpohflym){font-size:1em}", }, { name: "scopedStyleStrategy: 'class'", @@ -52,7 +52,7 @@ func TestPrinterCSS(t *testing.T) {

Page Title

I’m a page

`, scopedStyleStrategy: "class", - want: ".title.astro-DPOHFLYM{font-family:fantasy;font-size:28px}.body.astro-DPOHFLYM{font-size:1em}", + want: ".title.astro-dpohflym{font-family:fantasy;font-size:28px}.body.astro-dpohflym{font-size:1em}", }, { name: "scopedStyleStrategy: 'attribute'", @@ -70,7 +70,7 @@ func TestPrinterCSS(t *testing.T) {

Page Title

I’m a page

`, scopedStyleStrategy: "attribute", - want: ".title[data-astro-cid-DPOHFLYM]{font-family:fantasy;font-size:28px}.body[data-astro-cid-DPOHFLYM]{font-size:1em}", + want: ".title[data-astro-cid-dpohflym]{font-family:fantasy;font-size:28px}.body[data-astro-cid-dpohflym]{font-size:1em}", }, } diff --git a/internal/printer/printer_test.go b/internal/printer/printer_test.go index 4ebe7638f..f9feb45c4 100644 --- a/internal/printer/printer_test.go +++ b/internal/printer/printer_test.go @@ -1030,8 +1030,8 @@ const testBool = true;

Page Title

I’m a page

`, want: want{ - code: "\n\n\t\t" + `${$$maybeRenderHead($$result)}

Page Title

-

I’m a page

`, + code: "\n\n\t\t" + `${$$maybeRenderHead($$result)}

Page Title

+

I’m a page

`, }, }, { @@ -1158,17 +1158,17 @@ const someProps = { hydratedComponents: []string{`Counter`}, hydrationDirectives: []string{"visible"}, }, - code: ` + code: ` ` + RENDER_HEAD_RESULT + ` - -
- ${$$renderComponent($$result,'Counter',Counter,{...(someProps),"client:visible":true,"client:component-hydration":"visible","client:component-path":("../components/Counter.jsx"),"client:component-export":("default"),"class":"astro-HMNNHVCQ"},{"default": () => $$render` + "`" + ` -

Hello React!

+ +
+ ${$$renderComponent($$result,'Counter',Counter,{...(someProps),"client:visible":true,"client:component-hydration":"visible","client:component-path":("../components/Counter.jsx"),"client:component-export":("default"),"class":"astro-hmnnhvcq"},{"default": () => $$render` + "`" + ` +

Hello React!

` + "`" + `,})}
@@ -1659,7 +1659,7 @@ import { Container, Col, Row } from 'react-bootstrap';
`, want: want{ - code: "\n\n\n\n\n\n\n" + RENDER_HEAD_RESULT + "\n
", + code: "\n\n\n\n\n\n\n" + RENDER_HEAD_RESULT + "\n
", }, }, { @@ -2124,7 +2124,7 @@ const items = ["Dog", "Cat", "Platipus"];
My Text
`, want: want{ - code: `${$$maybeRenderHead($$result)}
My Text
`, + code: `${$$maybeRenderHead($$result)}
My Text
`, }, }, { @@ -2648,7 +2648,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "define:vars on style", source: "

testing

", want: want{ - code: `${$$maybeRenderHead($$result)}

testing

`, + code: `${$$maybeRenderHead($$result)}

testing

`, definedVars: []string{"{color:'green'}"}, }, }, @@ -2656,7 +2656,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "define:vars on style tag with style shorthand attribute on element", source: "

testing

", want: want{ - code: `${$$maybeRenderHead($$result)}testing`, + code: `${$$maybeRenderHead($$result)}testing`, definedVars: []string{"{color:'green'}"}, }, }, @@ -2664,7 +2664,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "define:vars on style tag with style expression attribute on element", source: "

testing

", want: want{ - code: `${$$maybeRenderHead($$result)}testing`, + code: `${$$maybeRenderHead($$result)}testing`, definedVars: []string{"{color:'green'}"}, }, }, @@ -2672,7 +2672,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "define:vars on style tag with style empty attribute on element", source: "

testing

", want: want{ - code: `${$$maybeRenderHead($$result)}testing`, + code: `${$$maybeRenderHead($$result)}testing`, definedVars: []string{"{color:'green'}"}, }, }, @@ -2680,7 +2680,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "define:vars on style tag with style quoted attribute on element", source: "

testing

", want: want{ - code: `${$$maybeRenderHead($$result)}testing`, + code: `${$$maybeRenderHead($$result)}testing`, definedVars: []string{"{color:'green'}"}, }, }, @@ -2688,7 +2688,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "define:vars on style tag with style template literal attribute on element", source: "

testing

", want: want{ - code: `${$$maybeRenderHead($$result)}testing`, + code: `${$$maybeRenderHead($$result)}testing`, definedVars: []string{"{color:'green'}"}, }, }, @@ -2696,7 +2696,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "multiple define:vars on style", source: "

foo

bar

", want: want{ - code: `${$$maybeRenderHead($$result)}

foo

bar

`, + code: `${$$maybeRenderHead($$result)}

foo

bar

`, definedVars: []string{"{color:'red'}", "{color:'green'}"}, }, }, @@ -2704,7 +2704,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "define:vars on non-root elements", source: "{true ?

foo

:

bar

}", want: want{ - code: `${true ? $$render` + BACKTICK + `${$$maybeRenderHead($$result)}

foo

` + BACKTICK + ` : $$render` + BACKTICK + `

bar

` + BACKTICK + `}`, + code: `${true ? $$render` + BACKTICK + `${$$maybeRenderHead($$result)}

foo

` + BACKTICK + ` : $$render` + BACKTICK + `

bar

` + BACKTICK + `}`, definedVars: []string{"{color:'green'}"}, }, }, @@ -2804,7 +2804,7 @@ const items = ["Dog", "Cat", "Platipus"]; filename: "/projects/app/src/pages/page.astro", transitions: true, want: want{ - code: `${$$maybeRenderHead($$result)}
`, + code: `${$$maybeRenderHead($$result)}`, }, }, { @@ -2813,7 +2813,7 @@ const items = ["Dog", "Cat", "Platipus"]; filename: "/projects/app/src/pages/page.astro", transitions: true, want: want{ - code: `${$$maybeRenderHead($$result)}`, + code: `${$$maybeRenderHead($$result)}`, }, }, { @@ -2822,7 +2822,7 @@ const items = ["Dog", "Cat", "Platipus"]; filename: "/projects/app/src/pages/page.astro", transitions: true, want: want{ - code: `${$$maybeRenderHead($$result)}`, + code: `${$$maybeRenderHead($$result)}`, }, }, { @@ -2831,7 +2831,7 @@ 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, "X2GW3NPO", "morph", ""))})}`, + code: `${$$renderComponent($$result,'Component',Component,{"class":"bar","data-astro-transition-scope":($$renderTransition($$result, "wkm5vset", "morph", ""))})}`, }, }, { @@ -2839,7 +2839,7 @@ const items = ["Dog", "Cat", "Platipus"]; source: `
`, transitions: true, want: want{ - code: `${$$maybeRenderHead($$result)}`, + code: `${$$maybeRenderHead($$result)}`, }, }, { @@ -2847,7 +2847,7 @@ const items = ["Dog", "Cat", "Platipus"]; source: `
`, transitions: true, want: want{ - code: `${$$maybeRenderHead($$result)}
`, + code: `${$$maybeRenderHead($$result)}
`, }, }, } diff --git a/internal/transform/scope-css_test.go b/internal/transform/scope-css_test.go index 7a33d7eaf..7ad6c93ae 100644 --- a/internal/transform/scope-css_test.go +++ b/internal/transform/scope-css_test.go @@ -19,97 +19,97 @@ func TestScopeStyle(t *testing.T) { { name: "class", source: ".class{}", - want: ".class:where(.astro-XXXXXX){}", + want: ".class:where(.astro-xxxxxx){}", }, { name: "id", source: "#class{}", - want: "#class:where(.astro-XXXXXX){}", + want: "#class:where(.astro-xxxxxx){}", }, { name: "element", source: "h1{}", - want: "h1:where(.astro-XXXXXX){}", + want: "h1:where(.astro-xxxxxx){}", }, { name: "adjacent sibling", source: ".class+.class{}", - want: ".class:where(.astro-XXXXXX)+.class:where(.astro-XXXXXX){}", + want: ".class:where(.astro-xxxxxx)+.class:where(.astro-xxxxxx){}", }, { name: "and selector", source: ".class,.class{}", - want: ".class:where(.astro-XXXXXX),.class:where(.astro-XXXXXX){}", + want: ".class:where(.astro-xxxxxx),.class:where(.astro-xxxxxx){}", }, { name: "children universal", source: ".class *{}", - want: ".class:where(.astro-XXXXXX) :where(.astro-XXXXXX){}", + want: ".class:where(.astro-xxxxxx) :where(.astro-xxxxxx){}", }, { name: "attr", source: "a[aria-current=page]{}", - want: "a:where(.astro-XXXXXX)[aria-current=page]{}", + want: "a:where(.astro-xxxxxx)[aria-current=page]{}", }, { name: "attr universal implied", source: "[aria-visible],[aria-hidden]{}", - want: ":where(.astro-XXXXXX)[aria-visible],:where(.astro-XXXXXX)[aria-hidden]{}", + want: ":where(.astro-xxxxxx)[aria-visible],:where(.astro-xxxxxx)[aria-hidden]{}", }, { name: "universal pseudo state", source: "*:hover{}", - want: ":where(.astro-XXXXXX):hover{}", + want: ":where(.astro-xxxxxx):hover{}", }, { name: "immediate child universal", source: ".class>*{}", - want: ".class:where(.astro-XXXXXX)>:where(.astro-XXXXXX){}", + want: ".class:where(.astro-xxxxxx)>:where(.astro-xxxxxx){}", }, { name: "element + pseudo state", source: ".class button:focus{}", - want: ".class:where(.astro-XXXXXX) button:where(.astro-XXXXXX):focus{}", + want: ".class:where(.astro-xxxxxx) button:where(.astro-xxxxxx):focus{}", }, { name: "element + pseudo element", source: ".class h3::before{}", - want: ".class:where(.astro-XXXXXX) h3:where(.astro-XXXXXX)::before{}", + want: ".class:where(.astro-xxxxxx) h3:where(.astro-xxxxxx)::before{}", }, { name: "media query", source: "@media screen and (min-width:640px){.class{}}", - want: "@media screen and (min-width:640px){.class:where(.astro-XXXXXX){}}", + want: "@media screen and (min-width:640px){.class:where(.astro-xxxxxx){}}", }, { name: "element + pseudo state + pseudo element", source: "button:focus::before{}", - want: "button:where(.astro-XXXXXX):focus::before{}", + want: "button:where(.astro-xxxxxx):focus::before{}", }, { name: "global children", source: ".class :global(ul li){}", - want: ".class:where(.astro-XXXXXX) ul li{}", + want: ".class:where(.astro-xxxxxx) ul li{}", }, { name: "global universal", source: ".class :global(*){}", - want: ".class:where(.astro-XXXXXX) *{}", + want: ".class:where(.astro-xxxxxx) *{}", }, { name: "global with scoped children", source: ":global(section) .class{}", - want: "section .class:where(.astro-XXXXXX){}", + want: "section .class:where(.astro-xxxxxx){}", }, { name: "subsequent siblings + global", source: ".class~:global(a){}", - want: ".class:where(.astro-XXXXXX)~a{}", + want: ".class:where(.astro-xxxxxx)~a{}", }, { name: "global nested parens", source: ".class :global(.nav:not(.is-active)){}", - want: ".class:where(.astro-XXXXXX) .nav:not(.is-active){}", + want: ".class:where(.astro-xxxxxx) .nav:not(.is-active){}", }, { name: "global nested parens + chained class", @@ -124,27 +124,27 @@ func TestScopeStyle(t *testing.T) { { name: "class chained global", source: ".class:global(.bar){}", - want: ".class:where(.astro-XXXXXX).bar{}", // technically this may be incorrect, but would require a lookahead to fix + want: ".class:where(.astro-xxxxxx).bar{}", // technically this may be incorrect, but would require a lookahead to fix }, { name: "chained :not()", source: ".class:not(.is-active):not(.is-disabled){}", - want: ".class:where(.astro-XXXXXX):not(.is-active):not(.is-disabled){}", + want: ".class:where(.astro-xxxxxx):not(.is-active):not(.is-disabled){}", }, { name: "weird chaining", source: ":hover.a:focus{}", // yes this is valid. yes I’m just upset as you are :( - want: ":hover.a:where(.astro-XXXXXX):focus{}", + want: ":hover.a:where(.astro-xxxxxx):focus{}", }, { name: "more weird chaining", source: ":not(.is-disabled).a{}", - want: ":not(.is-disabled).a:where(.astro-XXXXXX){}", + want: ":not(.is-disabled).a:where(.astro-xxxxxx){}", }, { name: "body", source: "body h1{}", - want: "body h1:where(.astro-XXXXXX){}", + want: "body h1:where(.astro-xxxxxx){}", }, { name: "body class", @@ -164,7 +164,7 @@ func TestScopeStyle(t *testing.T) { { name: "escaped characters", source: ".class\\:class:focus{}", - want: ".class\\:class:where(.astro-XXXXXX):focus{}", + want: ".class\\:class:where(.astro-xxxxxx):focus{}", }, // the following tests assert we leave valid CSS alone { @@ -190,17 +190,17 @@ func TestScopeStyle(t *testing.T) { { name: "keyframes start", source: "@keyframes shuffle{0%{transform:rotate(0deg);color:blue}100%{transform:rotate(360deg)}} h1{} h2{}", - want: "@keyframes shuffle{0%{transform:rotate(0deg);color:blue}100%{transform:rotate(360deg)}}h1:where(.astro-XXXXXX){}h2:where(.astro-XXXXXX){}", + want: "@keyframes shuffle{0%{transform:rotate(0deg);color:blue}100%{transform:rotate(360deg)}}h1:where(.astro-xxxxxx){}h2:where(.astro-xxxxxx){}", }, { name: "keyframes middle", source: "h1{} @keyframes shuffle{0%{transform:rotate(0deg);color:blue}100%{transform:rotate(360deg)}} h2{}", - want: "h1:where(.astro-XXXXXX){}@keyframes shuffle{0%{transform:rotate(0deg);color:blue}100%{transform:rotate(360deg)}}h2:where(.astro-XXXXXX){}", + want: "h1:where(.astro-xxxxxx){}@keyframes shuffle{0%{transform:rotate(0deg);color:blue}100%{transform:rotate(360deg)}}h2:where(.astro-xxxxxx){}", }, { name: "keyframes end", source: "h1{} h2{} @keyframes shuffle{0%{transform:rotate(0deg);color:blue}100%{transform:rotate(360deg)}}", - want: "h1:where(.astro-XXXXXX){}h2:where(.astro-XXXXXX){}@keyframes shuffle{0%{transform:rotate(0deg);color:blue}100%{transform:rotate(360deg)}}", + want: "h1:where(.astro-xxxxxx){}h2:where(.astro-xxxxxx){}@keyframes shuffle{0%{transform:rotate(0deg);color:blue}100%{transform:rotate(360deg)}}", }, { name: "calc", @@ -210,7 +210,7 @@ func TestScopeStyle(t *testing.T) { { name: "grid-template-columns", source: "div{grid-template-columns: [content-start] 1fr [content-end];}", - want: "div:where(.astro-XXXXXX){grid-template-columns:[content-start] 1fr [content-end]}", + want: "div:where(.astro-xxxxxx){grid-template-columns:[content-start] 1fr [content-end]}", }, { name: "charset", @@ -238,7 +238,7 @@ func TestScopeStyle(t *testing.T) { color: blue font-size: 18px; }`, - want: `.foo:where(.astro-XXXXXX){color:blue font-size: 18px}`, + want: `.foo:where(.astro-xxxxxx){color:blue font-size: 18px}`, }, { name: "nesting media", @@ -248,12 +248,12 @@ func TestScopeStyle(t *testing.T) { { name: "nesting combinator", source: "div { & span { color: blue } }", - want: "div:where(.astro-XXXXXX){& span:where(.astro-XXXXXX){color:blue}}", + want: "div:where(.astro-xxxxxx){& span:where(.astro-xxxxxx){color:blue}}", }, { name: "nesting modifier", source: ".header { background-color: white; &.dark { background-color: blue; }}", - want: ".header:where(.astro-XXXXXX){background-color:white;&.dark{background-color:blue}}", + want: ".header:where(.astro-xxxxxx){background-color:white;&.dark{background-color:blue}}", }, { name: "@container", @@ -262,12 +262,12 @@ func TestScopeStyle(t *testing.T) { font-size: 30px; } }`, - want: "@container (min-width: 200px) and (min-height: 200px){h1:where(.astro-XXXXXX){font-size:30px}}", + want: "@container (min-width: 200px) and (min-height: 200px){h1:where(.astro-xxxxxx){font-size:30px}}", }, { name: "@layer", source: "@layer theme, layout, utilities; @layer special { .item { color: rebeccapurple; }}", - want: "@layer theme,layout,utilities;@layer special{.item:where(.astro-XXXXXX){color:rebeccapurple}}", + want: "@layer theme,layout,utilities;@layer special{.item:where(.astro-xxxxxx){color:rebeccapurple}}", }, } for _, tt := range tests { @@ -280,7 +280,7 @@ func TestScopeStyle(t *testing.T) { } styleEl := doc.LastChild.FirstChild.FirstChild // note: root is , and we need to get
`, - want: `
`, + want: `
`, }, { @@ -87,7 +87,7 @@ func transformScopingFixtures() []struct {
`, - want: `
`, + want: `
`, }, { name: "scoped multiple", @@ -96,7 +96,7 @@ func transformScopingFixtures() []struct {
`, - want: `
`, + want: `
`, }, { name: "global multiple", @@ -114,7 +114,7 @@ func transformScopingFixtures() []struct {
`, - want: `
`, + want: `
`, }, { name: "multiple scoped :global", @@ -123,7 +123,7 @@ func transformScopingFixtures() []struct {
`, - want: `
`, + want: `
`, }, { name: "inline does not scope", @@ -139,7 +139,7 @@ func transformScopingFixtures() []struct {
`, - want: `
`, + want: `
`, scopeStyle: "attribute", }, { @@ -148,7 +148,7 @@ func transformScopingFixtures() []struct {
`, - want: `
`, + want: `
`, scopeStyle: "attribute", }, { @@ -157,7 +157,7 @@ func transformScopingFixtures() []struct {
`, - want: `
`, + want: `
`, scopeStyle: "attribute", }, { @@ -166,7 +166,7 @@ func transformScopingFixtures() []struct {
`, - want: `
`, + want: `
`, scopeStyle: "attribute", }, } @@ -191,7 +191,7 @@ func TestTransformScoping(t *testing.T) { } else { scopeStyle = "where" } - Transform(doc, TransformOptions{Scope: "XXXXXX", ScopedStyleStrategy: scopeStyle}, handler.NewHandler(tt.source, "/test.astro")) + Transform(doc, TransformOptions{Scope: "xxxxxx", ScopedStyleStrategy: scopeStyle}, handler.NewHandler(tt.source, "/test.astro")) astro.PrintToSource(&b, doc.LastChild.FirstChild.NextSibling.FirstChild) got := b.String() if tt.want != got { @@ -212,13 +212,13 @@ func FuzzTransformScoping(f *testing.F) { t.Skip("Invalid parse, skipping rest of fuzz test") } ExtractStyles(doc) - Transform(doc, TransformOptions{Scope: "XXXXXX"}, handler.NewHandler(source, "/test.astro")) + Transform(doc, TransformOptions{Scope: "xxxxxx"}, handler.NewHandler(source, "/test.astro")) var b strings.Builder astro.PrintToSource(&b, doc.LastChild.FirstChild.NextSibling.FirstChild) got := b.String() // hacky - we only expect scoping for non global styles / non inline styles testRegex := regexp.MustCompile(`is:global|:global\(|is:inline|`) - if !testRegex.MatchString(source) && !strings.Contains(got, "astro-XXXXXX") { + if !testRegex.MatchString(source) && !strings.Contains(got, "astro-xxxxxx") { t.Errorf("HTML scoping failed to include the astro scope\n source: %q\n got: %q", source, got) } if utf8.ValidString(source) && !utf8.ValidString(got) { diff --git a/packages/compiler/test/basic/trailing-spaces-ii.ts b/packages/compiler/test/basic/trailing-spaces-ii.ts index 16d0fc607..198626215 100644 --- a/packages/compiler/test/basic/trailing-spaces-ii.ts +++ b/packages/compiler/test/basic/trailing-spaces-ii.ts @@ -26,7 +26,7 @@ test('trailing space', () => { assert.ok(result.code, 'Expected to compiler'); assert.match( result.code, - ` + ` \${$$renderSlot($$result,$$slots["default"])} \`` );