Skip to content

Commit

Permalink
chore: use original "class" scoping technique
Browse files Browse the repository at this point in the history
  • Loading branch information
Nate Moore committed May 16, 2022
1 parent 92002c0 commit 4603704
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 79 deletions.
2 changes: 1 addition & 1 deletion internal/printer/printer_css_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestPrinterCSS(t *testing.T) {
<h1 class="title">Page Title</h1>
<p class="body">I’m a page</p>`,
want: want{
styles: []string{".title:where([data-astro-scope=\"DPOHFLYM\"]){font-family:fantasy;font-size:28px}.body:where([data-astro-scope=\"DPOHFLYM\"]){font-size:1em}"},
styles: []string{".title:where(.astro-DPOHFLYM){font-family:fantasy;font-size:28px}.body:where(.astro-DPOHFLYM){font-size:1em}"},
},
},
}
Expand Down
26 changes: 13 additions & 13 deletions internal/printer/printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,9 @@ const name = "world";
<h1 class="title">Page Title</h1>
<p class="body">I’m a page</p>`,
want: want{
styles: []string{"{props:{\"data-astro-id\":\"DPOHFLYM\"},children:`.title:where([data-astro-scope=\"DPOHFLYM\"]){font-family:fantasy;font-size:28px}.body:where([data-astro-scope=\"DPOHFLYM\"]){font-size:1em}`}"},
code: "\n\n\t\t" + `<h1 class="title" data-astro-scope="DPOHFLYM">Page Title</h1>
<p class="body" data-astro-scope="DPOHFLYM">I’m a page</p>`,
styles: []string{"{props:{\"data-astro-id\":\"DPOHFLYM\"},children:`.title:where(.astro-DPOHFLYM){font-family:fantasy;font-size:28px}.body:where(.astro-DPOHFLYM){font-size:1em}`}"},
code: "\n\n\t\t" + `<h1 class="title astro-DPOHFLYM">Page Title</h1>
<p class="body astro-DPOHFLYM">I’m a page</p>`,
},
},
{
Expand Down Expand Up @@ -761,16 +761,16 @@ import Counter from '../components/Counter.jsx'`,
hydratedComponents: []string{`Counter`},
hydrationDirectives: []string{"visible"},
},
code: `<html lang="en" data-astro-scope="HMNNHVCQ">
code: `<html lang="en" class="astro-HMNNHVCQ">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
` + RENDER_HEAD_RESULT + `</head>
<body>
<main data-astro-scope="HMNNHVCQ">
${$$renderComponent($$result,'Counter',Counter,{...(someProps),"client:visible":true,"client:component-hydration":"visible","client:component-path":($$metadata.getPath(Counter)),"client:component-export":($$metadata.getExport(Counter)),"data-astro-scope":"HMNNHVCQ"},{"default": () => $$render` + "`" + `<h1 data-astro-scope="HMNNHVCQ">Hello React!</h1>` + "`" + `,})}
<main class="astro-HMNNHVCQ">
${$$renderComponent($$result,'Counter',Counter,{...(someProps),"client:visible":true,"client:component-hydration":"visible","client:component-path":($$metadata.getPath(Counter)),"client:component-export":($$metadata.getExport(Counter)),"class":"astro-HMNNHVCQ"},{"default": () => $$render` + "`" + `<h1 class="astro-HMNNHVCQ">Hello React!</h1>` + "`" + `,})}
</main>
</body></html>
`,
Expand Down Expand Up @@ -1246,11 +1246,11 @@ import { Container, Col, Row } from 'react-bootstrap';
<div />`,
want: want{
styles: []string{
"{props:{\"data-astro-id\":\"EX5CHM4O\"},children:`div:where([data-astro-scope=\"EX5CHM4O\"]){color:blue}`}",
"{props:{\"data-astro-id\":\"EX5CHM4O\"},children:`div:where([data-astro-scope=\"EX5CHM4O\"]){color:green}`}",
"{props:{\"data-astro-id\":\"EX5CHM4O\"},children:`div:where(.astro-EX5CHM4O){color:blue}`}",
"{props:{\"data-astro-id\":\"EX5CHM4O\"},children:`div:where(.astro-EX5CHM4O){color:green}`}",
"{props:{\"global\":true},children:`div { color: red }`}",
},
code: "<head>\n\n\n\n\n\n\n" + RENDER_HEAD_RESULT + "</head>\n<div data-astro-scope=\"EX5CHM4O\"></div>",
code: "<head>\n\n\n\n\n\n\n" + RENDER_HEAD_RESULT + "</head>\n<div class=\"astro-EX5CHM4O\"></div>",
},
},
{
Expand Down Expand Up @@ -1570,8 +1570,8 @@ const items = ["Dog", "Cat", "Platipus"];
</style><div class="container">My Text</div>`,

want: want{
styles: []string{fmt.Sprintf(`{props:{"data-astro-id":"SJ3WYE6H"},children:%s.container:where([data-astro-scope="SJ3WYE6H"]){padding:2rem}%s}`, BACKTICK, BACKTICK)},
code: `<div class="container" data-astro-scope="SJ3WYE6H">My Text</div>`,
styles: []string{fmt.Sprintf(`{props:{"data-astro-id":"SJ3WYE6H"},children:%s.container:where(.astro-SJ3WYE6H){padding:2rem}%s}`, BACKTICK, BACKTICK)},
code: `<div class="container astro-SJ3WYE6H">My Text</div>`,
},
},
{
Expand Down Expand Up @@ -1732,9 +1732,9 @@ const items = ["Dog", "Cat", "Platipus"];
source: "<style>h1{color:green;}</style><style define:vars={{color:'green'}}>h1{color:var(--color)}</style><h1>testing</h1>",
staticExtraction: true,
want: want{
code: `<h1 data-astro-scope="VFS5OEMV">testing</h1>`,
code: `<h1 class="astro-VFS5OEMV">testing</h1>`,
styles: []string{
"{props:{\"define:vars\":({color:'green'}),\"data-astro-id\":\"VFS5OEMV\"},children:`h1:where([data-astro-scope=\"VFS5OEMV\"]){color:var(--color)}`}",
"{props:{\"define:vars\":({color:'green'}),\"data-astro-id\":\"VFS5OEMV\"},children:`h1:where(.astro-VFS5OEMV){color:var(--color)}`}",
},
},
},
Expand Down
70 changes: 35 additions & 35 deletions internal/transform/scope-css_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,97 +20,97 @@ func TestScopeStyle(t *testing.T) {
{
name: "class",
source: ".class{}",
want: ".class:where([data-astro-scope=\"XXXXXX\"]){}",
want: ".class:where(.astro-XXXXXX){}",
},
{
name: "id",
source: "#class{}",
want: "#class:where([data-astro-scope=\"XXXXXX\"]){}",
want: "#class:where(.astro-XXXXXX){}",
},
{
name: "element",
source: "h1{}",
want: "h1:where([data-astro-scope=\"XXXXXX\"]){}",
want: "h1:where(.astro-XXXXXX){}",
},
{
name: "adjacent sibling",
source: ".class+.class{}",
want: ".class:where([data-astro-scope=\"XXXXXX\"])+.class:where([data-astro-scope=\"XXXXXX\"]){}",
want: ".class:where(.astro-XXXXXX)+.class:where(.astro-XXXXXX){}",
},
{
name: "and selector",
source: ".class,.class{}",
want: ".class:where([data-astro-scope=\"XXXXXX\"]),.class:where([data-astro-scope=\"XXXXXX\"]){}",
want: ".class:where(.astro-XXXXXX),.class:where(.astro-XXXXXX){}",
},
{
name: "children universal",
source: ".class *{}",
want: ".class:where([data-astro-scope=\"XXXXXX\"]) :where([data-astro-scope=\"XXXXXX\"]){}",
want: ".class:where(.astro-XXXXXX) :where(.astro-XXXXXX){}",
},
{
name: "attr",
source: "a[aria-current=\"page\"]{}",
want: "a:where([data-astro-scope=\"XXXXXX\"])[aria-current=page]{}",
source: "a[aria-current=page]{}",
want: "a:where(.astro-XXXXXX)[aria-current=page]{}",
},
{
name: "attr universal implied",
source: "[aria-visible],[aria-hidden]{}",
want: ":where([data-astro-scope=\"XXXXXX\"])[aria-visible],:where([data-astro-scope=\"XXXXXX\"])[aria-hidden]{}",
want: ":where(.astro-XXXXXX)[aria-visible],:where(.astro-XXXXXX)[aria-hidden]{}",
},
{
name: "universal pseudo state",
source: "*:hover{}",
want: ":where([data-astro-scope=\"XXXXXX\"]):hover{}",
want: ":where(.astro-XXXXXX):hover{}",
},
{
name: "immediate child universal",
source: ".class>*{}",
want: ".class:where([data-astro-scope=\"XXXXXX\"])>:where([data-astro-scope=\"XXXXXX\"]){}",
want: ".class:where(.astro-XXXXXX)>:where(.astro-XXXXXX){}",
},
{
name: "element + pseudo state",
source: ".class button:focus{}",
want: ".class:where([data-astro-scope=\"XXXXXX\"]) button:where([data-astro-scope=\"XXXXXX\"]):focus{}",
want: ".class:where(.astro-XXXXXX) button:where(.astro-XXXXXX):focus{}",
},
{
name: "element + pseudo element",
source: ".class h3::before{}",
want: ".class:where([data-astro-scope=\"XXXXXX\"]) h3:where([data-astro-scope=\"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([data-astro-scope=\"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([data-astro-scope=\"XXXXXX\"]):focus::before{}",
want: "button:where(.astro-XXXXXX):focus::before{}",
},
{
name: "global children",
source: ".class :global(ul li){}",
want: ".class:where([data-astro-scope=\"XXXXXX\"]) ul li{}",
want: ".class:where(.astro-XXXXXX) ul li{}",
},
{
name: "global universal",
source: ".class :global(*){}",
want: ".class:where([data-astro-scope=\"XXXXXX\"]) *{}",
want: ".class:where(.astro-XXXXXX) *{}",
},
{
name: "global with scoped children",
source: ":global(section) .class{}",
want: "section .class:where([data-astro-scope=\"XXXXXX\"]){}",
want: "section .class:where(.astro-XXXXXX){}",
},
{
name: "subsequent siblings + global",
source: ".class~:global(a){}",
want: ".class:where([data-astro-scope=\"XXXXXX\"])~a{}",
want: ".class:where(.astro-XXXXXX)~a{}",
},
{
name: "global nested parens",
source: ".class :global(.nav:not(.is-active)){}",
want: ".class:where([data-astro-scope=\"XXXXXX\"]) .nav:not(.is-active){}",
want: ".class:where(.astro-XXXXXX) .nav:not(.is-active){}",
},
{
name: "global nested parens + chained class",
Expand All @@ -125,27 +125,27 @@ func TestScopeStyle(t *testing.T) {
{
name: "class chained global",
source: ".class:global(.bar){}",
want: ".class:where([data-astro-scope=\"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([data-astro-scope=\"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([data-astro-scope=\"XXXXXX\"]):focus{}",
want: ":hover.a:where(.astro-XXXXXX):focus{}",
},
{
name: "more weird chaining",
source: ":not(.is-disabled).a{}",
want: ":not(.is-disabled).a:where([data-astro-scope=\"XXXXXX\"]){}",
want: ":not(.is-disabled).a:where(.astro-XXXXXX){}",
},
{
name: "body",
source: "body h1{}",
want: "body h1:where([data-astro-scope=\"XXXXXX\"]){}",
want: "body h1:where(.astro-XXXXXX){}",
},
{
name: "body class",
Expand All @@ -165,7 +165,7 @@ func TestScopeStyle(t *testing.T) {
{
name: "escaped characters",
source: ".class\\:class:focus{}",
want: ".class\\:class:where([data-astro-scope=\"XXXXXX\"]):focus{}",
want: ".class\\:class:where(.astro-XXXXXX):focus{}",
},
// the following tests assert we leave valid CSS alone
{
Expand All @@ -191,17 +191,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([data-astro-scope=\"XXXXXX\"]){}h2:where([data-astro-scope=\"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([data-astro-scope=\"XXXXXX\"]){}@keyframes shuffle{0%{transform:rotate(0deg);color:blue}100%{transform:rotate(360deg)}}h2:where([data-astro-scope=\"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([data-astro-scope=\"XXXXXX\"]){}h2:where([data-astro-scope=\"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",
Expand All @@ -211,7 +211,7 @@ func TestScopeStyle(t *testing.T) {
{
name: "grid-template-columns",
source: "div{grid-template-columns: [content-start] 1fr [content-end];}",
want: "div:where([data-astro-scope=\"XXXXXX\"]){grid-template-columns:[content-start] 1fr [content-end]}",
want: "div:where(.astro-XXXXXX){grid-template-columns:[content-start] 1fr [content-end]}",
},
{
name: "charset",
Expand Down Expand Up @@ -239,7 +239,7 @@ func TestScopeStyle(t *testing.T) {
color: blue
font-size: 18px;
}`,
want: `.foo:where([data-astro-scope="XXXXXX"]){color:blue font-size: 18px}`,
want: `.foo:where(.astro-XXXXXX){color:blue font-size: 18px}`,
},
{
name: "nesting media",
Expand All @@ -249,12 +249,12 @@ func TestScopeStyle(t *testing.T) {
{
name: "nesting combinator",
source: "div { & span { color: blue } }",
want: "div:where([data-astro-scope=\"XXXXXX\"]){& span:where([data-astro-scope=\"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([data-astro-scope=\"XXXXXX\"]){background-color:white;&.dark{background-color:blue}}",
want: ".header:where(.astro-XXXXXX){background-color:white;&.dark{background-color:blue}}",
},
{
name: "@container",
Expand All @@ -263,12 +263,12 @@ func TestScopeStyle(t *testing.T) {
font-size: 30px;
}
}`,
want: "@container (min-width: 200px) and (min-height: 200px){h1:where([data-astro-scope=\"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([data-astro-scope=\"XXXXXX\"]){color:rebeccapurple}}",
want: "@layer theme,layout,utilities;@layer special{.item:where(.astro-XXXXXX){color:rebeccapurple}}",
},
}
for _, tt := range tests {
Expand Down
15 changes: 8 additions & 7 deletions internal/transform/scope-html.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,40 +39,41 @@ var NeverScopedSelectors map[string]bool = map[string]bool{
}

func injectScopedClass(n *astro.Node, opts TransformOptions) {
scopedClass := fmt.Sprintf(`astro-%s`, opts.Scope)
for i, attr := range n.Attr {
// If we find an existing class attribute, append the scoped class
if attr.Key == "data-astro-scope" {
if attr.Key == "class" {
switch attr.Type {
case astro.ShorthandAttribute:
if n.Component {
attr.Val = fmt.Sprintf(`%s + "%s"`, attr.Key, opts.Scope)
attr.Val = fmt.Sprintf(`%s + "%s"`, attr.Key, scopedClass)
attr.Type = astro.ExpressionAttribute
n.Attr[i] = attr
return
}
case astro.EmptyAttribute:
// instead of an empty string
attr.Type = astro.QuotedAttribute
attr.Val = opts.Scope
attr.Val = scopedClass
n.Attr[i] = attr
return
case astro.QuotedAttribute, astro.TemplateLiteralAttribute:
// as a plain string
attr.Val = fmt.Sprintf(`%s %s`, attr.Val, opts.Scope)
attr.Val = fmt.Sprintf(`%s %s`, attr.Val, scopedClass)
n.Attr[i] = attr
return
case astro.ExpressionAttribute:
// as an expression
attr.Val = fmt.Sprintf(`(%s) + " %s"`, attr.Val, opts.Scope)
attr.Val = fmt.Sprintf(`(%s) + " %s"`, attr.Val, scopedClass)
n.Attr[i] = attr
return
}
}
}
// If we didn't find an existing class attribute, let's add one
n.Attr = append(n.Attr, astro.Attribute{
Key: "data-astro-scope",
Key: "class",
Type: astro.QuotedAttribute,
Val: opts.Scope,
Val: scopedClass,
})
}
Loading

0 comments on commit 4603704

Please sign in to comment.