diff --git a/.changeset/green-camels-hide.md b/.changeset/green-camels-hide.md new file mode 100644 index 000000000..c33eea8fa --- /dev/null +++ b/.changeset/green-camels-hide.md @@ -0,0 +1,7 @@ +--- +'@astrojs/compiler': minor +--- + +- Adds support for dynamic slots inside loops +- Fixes an issue where successive named slotted elements would cause a runtime error +- Fixes an issue in which if there was an implicit default slotted element next to named one, the former would get swallowed by the later. diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index c43b0d8b2..2d6b7bba9 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -69,6 +69,12 @@ type ExtractedStatement struct { Loc loc.Loc } +type NestedSlotChild struct { + SlotProp string + Children []*Node + FirstInGroup bool +} + func printToJs(p *printer, n *Node, cssLen int, opts transform.TransformOptions) PrintResult { printedMaybeHead := false render1(p, n, RenderOptions{ @@ -439,6 +445,7 @@ func render1(p *printer, n *Node, opts RenderOptions) { p.print(`"` + escapeDoubleQuote(a.Val) + `"`) slotted = true default: + // add ability to use expressions for slot names later p.handler.AppendError(&loc.ErrorWithRange{ Code: loc.ERROR_UNSUPPORTED_SLOT_ATTRIBUTE, Text: "slot[name] must be a static string", @@ -551,7 +558,7 @@ func render1(p *printer, n *Node, opts RenderOptions) { if !isAllWhiteSpace { switch true { case n.CustomElement: - p.print(`,{`) + p.print(`,({`) p.print(fmt.Sprintf(`"%s": () => `, "default")) p.printTemplateLiteralOpen() for c := n.FirstChild; c != nil; c = c.NextSibling { @@ -565,166 +572,9 @@ func render1(p *printer, n *Node, opts RenderOptions) { }) } p.printTemplateLiteralClose() - p.print(`,}`) + p.print(`,})`) case isComponent: - p.print(`,`) - slottedChildren := make(map[string][]*Node) - conditionalSlottedChildren := make([][]*Node, 0) - for c := n.FirstChild; c != nil; c = c.NextSibling { - slotProp := `"default"` - for _, a := range c.Attr { - if a.Key == "slot" { - if a.Type == QuotedAttribute { - slotProp = fmt.Sprintf(`"%s"`, escapeDoubleQuote(a.Val)) - } else if a.Type == ExpressionAttribute { - slotProp = fmt.Sprintf(`[%s]`, a.Val) - } else { - p.handler.AppendError(&loc.ErrorWithRange{ - Code: loc.ERROR_UNSUPPORTED_SLOT_ATTRIBUTE, - Text: "slot[name] must be a static string", - Range: loc.Range{Loc: a.ValLoc, Len: len(a.Val)}, - }) - } - } - } - if c.Expression { - nestedSlots := make([]string, 0) - for c1 := c.FirstChild; c1 != nil; c1 = c1.NextSibling { - for _, a := range c1.Attr { - if a.Key == "slot" { - if a.Type == QuotedAttribute { - nestedSlotProp := fmt.Sprintf(`"%s"`, escapeDoubleQuote(a.Val)) - nestedSlots = append(nestedSlots, nestedSlotProp) - } else if a.Type == ExpressionAttribute { - nestedSlotProp := fmt.Sprintf(`[%s]`, a.Val) - nestedSlots = append(nestedSlots, nestedSlotProp) - } else { - panic(`unknown slot attribute type`) - } - } - } - } - - if len(nestedSlots) == 1 { - slotProp = nestedSlots[0] - slottedChildren[slotProp] = append(slottedChildren[slotProp], c) - continue - } else if len(nestedSlots) > 1 { - conditionalChildren := make([]*Node, 0) - child_loop: - for c1 := c.FirstChild; c1 != nil; c1 = c1.NextSibling { - for _, a := range c1.Attr { - if a.Key == "slot" { - if a.Type == QuotedAttribute { - nestedSlotProp := fmt.Sprintf(`"%s"`, escapeDoubleQuote(a.Val)) - nestedSlots = append(nestedSlots, nestedSlotProp) - conditionalChildren = append(conditionalChildren, &Node{Type: TextNode, Data: fmt.Sprintf("{%s: () => ", nestedSlotProp), Loc: make([]loc.Loc, 1)}) - conditionalChildren = append(conditionalChildren, c1) - conditionalChildren = append(conditionalChildren, &Node{Type: TextNode, Data: "}", Loc: make([]loc.Loc, 1)}) - continue child_loop - } else if a.Type == ExpressionAttribute { - nestedSlotProp := fmt.Sprintf(`[%s]`, a.Val) - nestedSlots = append(nestedSlots, nestedSlotProp) - conditionalChildren = append(conditionalChildren, &Node{Type: TextNode, Data: fmt.Sprintf("{%s: () => ", nestedSlotProp), Loc: make([]loc.Loc, 1)}) - conditionalChildren = append(conditionalChildren, c1) - conditionalChildren = append(conditionalChildren, &Node{Type: TextNode, Data: "}", Loc: make([]loc.Loc, 1)}) - continue child_loop - } else { - panic(`unknown slot attribute type`) - } - } - } - conditionalChildren = append(conditionalChildren, c1) - } - conditionalSlottedChildren = append(conditionalSlottedChildren, conditionalChildren) - continue - } - } - - // Only slot ElementNodes (except expressions containing only comments) or non-empty TextNodes! - // CommentNode, JSX comments and others should not be slotted - if expressionOnlyHasComment(c) { - continue - } - if c.Type == ElementNode || c.Type == TextNode && !emptyTextNodeWithoutSiblings(c) { - slottedChildren[slotProp] = append(slottedChildren[slotProp], c) - } - } - // fix: sort keys for stable output - slottedKeys := make([]string, 0, len(slottedChildren)) - for k := range slottedChildren { - slottedKeys = append(slottedKeys, k) - } - sort.Strings(slottedKeys) - if len(conditionalSlottedChildren) > 0 { - p.print(`$$mergeSlots(`) - } - p.print(`{`) - numberOfSlots := len(slottedKeys) - if numberOfSlots > 0 { - childrenLoop: - for _, slotProp := range slottedKeys { - children := slottedChildren[slotProp] - - // If there are named slots, the default slot cannot be only whitespace - if numberOfSlots > 1 && slotProp == "\"default\"" { - // Loop over the children and verify that at least one non-whitespace node exists. - foundNonWhitespace := false - for _, child := range children { - if child.Type != TextNode || strings.TrimSpace(child.Data) != "" { - foundNonWhitespace = true - } - } - if !foundNonWhitespace { - continue childrenLoop - } - } - - // If selected, pass through result object on the Astro side - if opts.opts.ResultScopedSlot { - p.print(fmt.Sprintf(`%s: ($$result) => `, slotProp)) - } else { - p.print(fmt.Sprintf(`%s: () => `, slotProp)) - } - - p.printTemplateLiteralOpen() - for _, child := range children { - render1(p, child, RenderOptions{ - isRoot: false, - isExpression: opts.isExpression, - depth: depth + 1, - opts: opts.opts, - cssLen: opts.cssLen, - printedMaybeHead: opts.printedMaybeHead, - }) - } - p.printTemplateLiteralClose() - p.print(`,`) - } - } - p.print(`}`) - if len(conditionalSlottedChildren) > 0 { - for _, children := range conditionalSlottedChildren { - p.print(",") - for _, child := range children { - if child.Type == ElementNode { - p.printTemplateLiteralOpen() - } - render1(p, child, RenderOptions{ - isRoot: false, - isExpression: opts.isExpression, - depth: depth + 1, - opts: opts.opts, - cssLen: opts.cssLen, - printedMaybeHead: opts.printedMaybeHead, - }) - if child.Type == ElementNode { - p.printTemplateLiteralClose() - } - } - } - p.print(`)`) - } + handleSlots(p, n, opts, depth) case isSlot: p.print(`,`) p.printTemplateLiteralOpen() @@ -808,3 +658,300 @@ var voidElements = map[string]bool{ "track": true, "wbr": true, } + +func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { + p.print(`,`) + slottedChildren := make(map[string][]*Node) + hasAnyDynamicSlots := false + nestedSlotChildren := make([]*NestedSlotChild, 0) + numberOfNestedSlots := 0 + + for c := n.FirstChild; c != nil; c = c.NextSibling { + slotProp := `"default"` + for _, a := range c.Attr { + if a.Key == "slot" { + if a.Type == QuotedAttribute { + slotProp = fmt.Sprintf(`"%s"`, escapeDoubleQuote(a.Val)) + } else if a.Type == ExpressionAttribute { + slotProp = fmt.Sprintf(`[%s]`, a.Val) + } else if a.Type == TemplateLiteralAttribute { + slotProp = fmt.Sprintf(`[%s%s%s]`, BACKTICK, a.Val, BACKTICK) + } else { + p.handler.AppendError(&loc.ErrorWithRange{ + Code: loc.ERROR_UNSUPPORTED_SLOT_ATTRIBUTE, + Text: "Unsupported slot attribute type", + Range: loc.Range{Loc: a.ValLoc, Len: len(a.Val)}, + }) + } + } + } + if c.Expression { + nestedSlotsCount := 0 + var firstNestedSlotProp string + for c1 := c.FirstChild; c1 != nil; c1 = c1.NextSibling { + var slotProp = "" + for _, a := range c1.Attr { + if a.Key == "slot" { + if a.Type == QuotedAttribute { + slotProp = fmt.Sprintf(`"%s"`, escapeDoubleQuote(a.Val)) + } else if a.Type == ExpressionAttribute { + slotProp = fmt.Sprintf(`[%s]`, a.Val) + hasAnyDynamicSlots = true + } else if a.Type == TemplateLiteralAttribute { + slotProp = fmt.Sprintf(`[%s%s%s]`, BACKTICK, a.Val, BACKTICK) + hasAnyDynamicSlots = true + } else { + panic(`unknown slot attribute type`) + } + } + if firstNestedSlotProp == "" && slotProp != "" { + firstNestedSlotProp = slotProp + } + } + if firstNestedSlotProp != "" { + nestedSlotsCount++ + } + } + + if nestedSlotsCount == 1 && !hasAnyDynamicSlots { + slottedChildren[firstNestedSlotProp] = append(slottedChildren[firstNestedSlotProp], c) + continue + } else if nestedSlotsCount > 1 || hasAnyDynamicSlots { + child_loop: + for c1 := c.FirstChild; c1 != nil; c1 = c1.NextSibling { + foundNamedSlot := false + for _, a := range c1.Attr { + if a.Key == "slot" { + var nestedSlotProp string + var nestedSlotEntry *NestedSlotChild + if a.Type == QuotedAttribute { + nestedSlotProp = fmt.Sprintf(`"%s"`, escapeDoubleQuote(a.Val)) + hasAnyDynamicSlots = true + } else if a.Type == ExpressionAttribute { + nestedSlotProp = fmt.Sprintf(`[%s]`, a.Val) + hasAnyDynamicSlots = true + } else if a.Type == TemplateLiteralAttribute { + hasAnyDynamicSlots = true + nestedSlotProp = fmt.Sprintf(`[%s%s%s]`, BACKTICK, a.Val, BACKTICK) + } else { + panic(`unknown slot attribute type`) + } + foundNamedSlot = true + isFirstInGroup := c1 == c.FirstChild + nestedSlotEntry = &NestedSlotChild{nestedSlotProp, []*Node{c1}, isFirstInGroup} + nestedSlotChildren = append(nestedSlotChildren, nestedSlotEntry) + continue child_loop + } + } + isFirstInGroup := c1 == c.FirstChild + if !foundNamedSlot && c1.Type == ElementNode { + pseudoSlotEntry := &NestedSlotChild{`"default"`, []*Node{c1}, isFirstInGroup} + nestedSlotChildren = append(nestedSlotChildren, pseudoSlotEntry) + } else { + nestedSlotEntry := &NestedSlotChild{`"@@NON_ELEMENT_ENTRY"`, []*Node{c1}, isFirstInGroup} + nestedSlotChildren = append(nestedSlotChildren, nestedSlotEntry) + } + numberOfNestedSlots++ + } + continue + } + } + + // Only slot ElementNodes (except expressions containing only comments) or non-empty TextNodes! + // CommentNode, JSX comments and others should not be slotted + if expressionOnlyHasComment(c) { + continue + } + if c.Type == ElementNode || c.Type == TextNode && !emptyTextNodeWithoutSiblings(c) { + slottedChildren[slotProp] = append(slottedChildren[slotProp], c) + } + } + // fix: sort keys for stable output + slottedKeys := make([]string, 0, len(slottedChildren)) + for k := range slottedChildren { + slottedKeys = append(slottedKeys, k) + } + sort.Strings(slottedKeys) + if numberOfNestedSlots > 0 || hasAnyDynamicSlots { + p.print(`$$mergeSlots(`) + } + p.print(`({`) + numberOfSlots := len(slottedKeys) + if numberOfSlots > 0 { + childrenLoop: + for _, slotProp := range slottedKeys { + children := slottedChildren[slotProp] + + // If there are named slots, the default slot cannot be only whitespace + if numberOfSlots > 1 && slotProp == "\"default\"" { + // Loop over the children and verify that at least one non-whitespace node exists. + foundNonWhitespace := false + for _, child := range children { + if child.Type != TextNode || strings.TrimSpace(child.Data) != "" { + foundNonWhitespace = true + } + } + if !foundNonWhitespace { + continue childrenLoop + } + } + + // If selected, pass through result object on the Astro side + if opts.opts.ResultScopedSlot { + p.print(fmt.Sprintf(`%s: ($$result) => `, slotProp)) + } else { + p.print(fmt.Sprintf(`%s: () => `, slotProp)) + } + + p.printTemplateLiteralOpen() + for _, child := range children { + render1(p, child, RenderOptions{ + isRoot: false, + isExpression: opts.isExpression, + depth: depth + 1, + opts: opts.opts, + cssLen: opts.cssLen, + printedMaybeHead: opts.printedMaybeHead, + }) + } + p.printTemplateLiteralClose() + p.print(`,`) + } + } + p.print(`})`) + // print nested slots + if numberOfNestedSlots > 0 || hasAnyDynamicSlots { + endSlotIndexes := generateEndSlotIndexes(nestedSlotChildren) + mergeDefaultSlotsAndUpdateIndexes(&nestedSlotChildren, endSlotIndexes) + + hasFoundFirstElementNode := false + for j, nestedSlot := range nestedSlotChildren { + if nestedSlot.FirstInGroup { + p.print(`,`) + } + // whether this is the first element node in the chain + // (used to determine which slot render function to use) + var isFirstElementInChain bool + isLastInChain := endSlotIndexes[j] + if nestedSlot.Children[0].Type == ElementNode && !hasFoundFirstElementNode { + isFirstElementInChain = true + hasFoundFirstElementNode = true + } + renderNestedSlotChild(p, nestedSlot, isFirstElementInChain, isLastInChain, depth, opts) + if isLastInChain { + // reset hasFoundFirstElementNode for the next chain + hasFoundFirstElementNode = false + } + } + p.print(`)`) + } +} + +// Helper function to encapsulate nested slot entry rendering +func renderNestedSlotChild(p *printer, nestedSlotChild *NestedSlotChild, isFirstElementInChain bool, isLastInChain bool, depth int, opts RenderOptions) { + if nestedSlotChild.SlotProp == `"@@NON_ELEMENT_ENTRY"` { + for _, child := range nestedSlotChild.Children { + p.print(child.Data) + } + return + } + slotRenderFunction := getSlotRenderFunction(isFirstElementInChain) + slotRenderFunctionNode := &Node{Type: TextNode, Data: fmt.Sprintf(slotRenderFunction, nestedSlotChild.SlotProp), Loc: make([]loc.Loc, 1)} + // print the slot render function + render1(p, slotRenderFunctionNode, RenderOptions{ + isRoot: false, + isExpression: opts.isExpression, + depth: depth + 1, + opts: opts.opts, + cssLen: opts.cssLen, + printedMaybeHead: opts.printedMaybeHead, + }) + + // print the nested slotted children + p.printTemplateLiteralOpen() + for _, child := range nestedSlotChild.Children { + render1(p, child, RenderOptions{ + isRoot: false, + isExpression: false, + depth: depth, + opts: opts.opts, + cssLen: opts.cssLen, + printedMaybeHead: opts.printedMaybeHead, + }) + } + p.printTemplateLiteralClose() + + // when we are at the end of the chain, close the slot render function + if isLastInChain { + p.print(`})`) + } +} + +func generateEndSlotIndexes(nestedSlotChildren []*NestedSlotChild) map[int]bool { + endSlotIndexes := make(map[int]bool) + var latestElementNodeIndex int + + for i, nestedSlot := range nestedSlotChildren { + if nestedSlot.Children[0].Type == ElementNode { + latestElementNodeIndex = i + } else if isNonWhitespaceTextNode(nestedSlot.Children[0]) { + endSlotIndexes[latestElementNodeIndex] = true + } + } + + // Ensure the last element node index is also added to endSlotIndexes + if latestElementNodeIndex < len(nestedSlotChildren) { + endSlotIndexes[latestElementNodeIndex] = true + } + + return endSlotIndexes +} + +func mergeDefaultSlotsAndUpdateIndexes(nestedSlotChildren *[]*NestedSlotChild, endSlotIndexes map[int]bool) { + defaultSlot := &NestedSlotChild{SlotProp: `"default"`, Children: []*Node{}} + mergedSlotChildren := make([]*NestedSlotChild, 0) + numberOfMergedSlotsInSlotChain := 0 + + for i, nestedSlot := range *nestedSlotChildren { + if isDefaultSlot(nestedSlot) { + defaultSlot.Children = append(defaultSlot.Children, nestedSlot.Children...) + numberOfMergedSlotsInSlotChain++ + } else { + mergedSlotChildren = append(mergedSlotChildren, nestedSlot) + } + if shouldMergeDefaultSlot(endSlotIndexes, i, defaultSlot) { + resetEndSlotIndexes(endSlotIndexes, i, &numberOfMergedSlotsInSlotChain) + mergedSlotChildren = append(mergedSlotChildren, defaultSlot) + defaultSlot = &NestedSlotChild{SlotProp: `"default"`, Children: []*Node{}} + } + } + *nestedSlotChildren = mergedSlotChildren +} + +func getSlotRenderFunction(isNewSlotObject bool) string { + const FIRST_SLOT_CHILD_FUNCTION = "({%s: () => " + const NEXT_SLOT_CHILD_FUNCTION = ", %s: () => " + + if isNewSlotObject { + return FIRST_SLOT_CHILD_FUNCTION + } + return NEXT_SLOT_CHILD_FUNCTION +} + +func isNonWhitespaceTextNode(n *Node) bool { + return n.Type == TextNode && strings.TrimSpace(n.Data) != "" +} + +func isDefaultSlot(slot *NestedSlotChild) bool { + return slot.SlotProp == `"default"` +} + +func shouldMergeDefaultSlot(endSlotIndexes map[int]bool, i int, defaultSlot *NestedSlotChild) bool { + return endSlotIndexes[i] && len(defaultSlot.Children) > 0 +} + +func resetEndSlotIndexes(endSlotIndexes map[int]bool, i int, numberOfMergedSlotsInSlotChain *int) { + endSlotIndexes[i] = false + endSlotIndexes[i-(*numberOfMergedSlotsInSlotChain)+1] = true + (*numberOfMergedSlotsInSlotChain) = 0 +} diff --git a/internal/printer/printer_test.go b/internal/printer/printer_test.go index 36c1629a3..22dcf7ebd 100644 --- a/internal/printer/printer_test.go +++ b/internal/printer/printer_test.go @@ -165,14 +165,14 @@ func TestPrinter(t *testing.T) { name: "ternary component", source: `{special ?

Special

:

Not special

}`, want: want{ - code: `${special ? $$render` + BACKTICK + `${$$renderComponent($$result,'ChildDiv',ChildDiv,{},{"default": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}

Special

` + BACKTICK + `,})}` + BACKTICK + ` : $$render` + BACKTICK + `

Not special

` + BACKTICK + `}`, + code: `${special ? $$render` + BACKTICK + `${$$renderComponent($$result,'ChildDiv',ChildDiv,{},({"default": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}

Special

` + BACKTICK + `,}))}` + BACKTICK + ` : $$render` + BACKTICK + `

Not special

` + BACKTICK + `}`, }, }, { name: "ternary layout", source: `{toggleError ?

SITE: {Astro.site}

: <>

SITE: {Astro.site}

}`, want: want{ - code: `${toggleError ? $$render` + BACKTICK + `${$$renderComponent($$result,'BaseLayout',BaseLayout,{},{"default": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}

SITE: ${Astro.site}

` + BACKTICK + `,})}` + BACKTICK + ` : $$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `

SITE: ${Astro.site}

` + BACKTICK + `,})}` + BACKTICK + `}`, + code: `${toggleError ? $$render` + BACKTICK + `${$$renderComponent($$result,'BaseLayout',BaseLayout,{},({"default": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}

SITE: ${Astro.site}

` + BACKTICK + `,}))}` + BACKTICK + ` : $$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `

SITE: ${Astro.site}

` + BACKTICK + `,}))}` + BACKTICK + `}`, }, }, { @@ -182,32 +182,135 @@ func TestPrinter(t *testing.T) { code: `${$$renderSlot($$result,$$slots["default"])}`, }, }, + { + name: "nested dynamic slots I", + source: `{items.map((item)=>

)}`, + want: want{ + code: "${$$renderComponent($$result,'Component',Component,{},$$mergeSlots(({}),items.map((item)=>({[item.id]: () => $$render`${$$maybeRenderHead($$result)}

`}))))}", + }, + }, + { + name: "nested dynamic slots II", + source: `{items.map((item)=>

)}`, + want: want{ + code: "${$$renderComponent($$result,'Component',Component,{},$$mergeSlots(({}),items.map((item)=>({[item.id]: () => $$render`${$$maybeRenderHead($$result)}

`, [item.id+1]: () => $$render`

`}))))}", + }, + }, + { + name: "nested dynamic slots III", + source: `{items.map((item)=>
hey

There

!
)}
`, + want: want{ + code: "${$$renderComponent($$result,'Component',Component,{},$$mergeSlots(({}),items.map((item)=> ({[item.id]: () => $$render`${$$maybeRenderHead($$result)}

`, [item.id+1]: () => $$render`

`, \"default\": () => $$render`
hey
There
!
`}))))}", + }, + }, + { + name: "nested dynamic slots IV", + source: `{items.map((item)=>
hey

There

!
)}
`, + want: want{ + code: "${$$renderComponent($$result,'Component',Component,{},$$mergeSlots(({}),items.map((item)=> ({[item.id]: () => $$render`${$$maybeRenderHead($$result)}

` , [item.id+1]: () => $$render`

` , \"default\": () => $$render`
hey
There
!
`}))))}", + }, + }, + { + name: "nested dynamic slots V", + source: ` + + {items.map((item) => ( +
hey
+

+ There +

+

!
+ ))} +
`, + want: want{ + code: "${$$renderComponent($$result,'Component',Component,{},$$mergeSlots(({}),items.map((item) => (\n\t\t({[item.id]: () => $$render`${$$maybeRenderHead($$result)}

`\n\t\t, [item.id + 1]: () => $$render`

`\n\t\t, \"default\": () => $$render`
hey
There
!
`})\n\t))))}", + }, + }, { name: "conditional slot", source: `{value &&
foo
}
`, want: want{ - code: "${$$renderComponent($$result,'Component',Component,{},{\"test\": () => $$render`${value && $$render`${$$maybeRenderHead($$result)}
foo
`}`,})}", + code: "${$$renderComponent($$result,'Component',Component,{},({\"test\": () => $$render`${value && $$render`${$$maybeRenderHead($$result)}
foo
`}`,}))}", }, }, { name: "ternary slot", source: `{Math.random() > 0.5 ?
A
:
B
}
`, want: want{ - code: "${$$renderComponent($$result,'Component',Component,{},$$mergeSlots({},Math.random() > 0.5 ? {\"a\": () => $$render`${$$maybeRenderHead($$result)}
A
`} : {\"b\": () => $$render`
B
`}))}", + code: "${$$renderComponent($$result,'Component',Component,{},$$mergeSlots(({}),Math.random() > 0.5 ? ({\"a\": () => $$render`${$$maybeRenderHead($$result)}
A
`}) : ({\"b\": () => $$render`
B
`})))}", + }, + }, + { + name: "ternary slot with one implicit default", + source: `
+ {useSlot + ?
Inside slot with red background
+ :
Outside slot without background
+ } +
`, + want: want{ + code: `${$$renderComponent($$result,'Main',Main,{},$$mergeSlots(({}),useSlot + ? ({"outside": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}
Inside slot with red background
` + BACKTICK + `}) + : ({"default": () => $$render` + BACKTICK + `
Outside slot without background
` + BACKTICK + `}) + ))}`, }, }, { name: "function expression slots", source: "\n{() => { switch (value) {\ncase 'a': return
A
\ncase 'b': return
B
\ncase 'c': return
C
\n}\n}}\n
", want: want{ - code: "${$$renderComponent($$result,'Component',Component,{},$$mergeSlots({},() => { switch (value) {\ncase 'a': return {\"a\": () => $$render`${$$maybeRenderHead($$result)}
A
`}\ncase 'b': return {\"b\": () => $$render`
B
`}\ncase 'c': return {\"c\": () => $$render`
C
`}}\n}))}", + code: "${$$renderComponent($$result,'Component',Component,{},$$mergeSlots(({}),() => { switch (value) {\ncase 'a': return ({\"a\": () => $$render`${$$maybeRenderHead($$result)}
A
`})\ncase 'b': return ({\"b\": () => $$render`
B
`})\ncase 'c': return ({\"c\": () => $$render`
C
`})}\n}))}", }, }, { - name: "expression slot", + name: "expression slot I", source: `{true &&
A
}{false &&
B
}
`, want: want{ - code: "${$$renderComponent($$result,'Component',Component,{},{\"a\": () => $$render`${true && $$render`${$$maybeRenderHead($$result)}
A
`}`,\"b\": () => $$render`${false && $$render`
B
`}`,})}", + code: "${$$renderComponent($$result,'Component',Component,{},({\"a\": () => $$render`${true && $$render`${$$maybeRenderHead($$result)}
A
`}`,\"b\": () => $$render`${false && $$render`
B
`}`,}))}", + }, + }, + { + name: "expression slot II", + source: ` + {true && A} + {true ? B : null} + {() => C} + {true && Default} +`, + want: want{ + code: "${$$renderComponent($$result,'Slotted',Slotted,{},$$mergeSlots(({\"a\": () => $$render`${true && $$render`${$$maybeRenderHead($$result)}A`}`,}),true ? ({\"b\": () => $$render`B`}) : null,() => ({\"c\": () => $$render`C`}),true && ({\"default\": () => $$render`Default`})))}", + }, + }, + { + name: "expression slot III", + source: ` + {true && A} + {true ? B : null} + {() => C} + {() => { + const value = 0.33; + if (value > 0.25) { + return DefaultAnother + } else if (value > 0.5) { + return Another + } else if (value > 0.75) { + return Other + } + return Yet Another + }} +`, + want: want{ + code: `${$$renderComponent($$result,'Slotted',Slotted,{},$$mergeSlots(({}),true && ({["a"]: () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}A` + BACKTICK + `}),true ? ({"b": () => $$render` + BACKTICK + `B` + BACKTICK + `}) : null,() => ({"c": () => $$render` + BACKTICK + `C` + BACKTICK + `}),() => { + const value = 0.33; + if (value > 0.25) { + return ({"hey": () => $$render` + BACKTICK + `Another` + BACKTICK + `, "default": () => $$render` + BACKTICK + `Default` + BACKTICK + `}) + } else if (value > 0.5) { + return ({"hey": () => $$render` + BACKTICK + `Another` + BACKTICK + `}) + } else if (value > 0.75) { + return ({"default": () => $$render` + BACKTICK + `Other` + BACKTICK + `}) + } + return ({"default": () => $$render` + BACKTICK + `Yet Another` + BACKTICK + `}) + }))}`, }, }, { @@ -252,9 +355,9 @@ func TestPrinter(t *testing.T) {

Paragraph 2

`, want: want{ - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + BACKTICK + ` + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + BACKTICK + ` ${$$maybeRenderHead($$result)}

Paragraph 1

-

Paragraph 2

` + BACKTICK + `,})}`, +

Paragraph 2

` + BACKTICK + `,}))}`, }, }, { @@ -480,7 +583,7 @@ import type data from "test" }, }, { - name: "nested template literal expression", + name: "nested template literal expression I", source: "
", want: want{ code: "${$$maybeRenderHead($$result)}
", @@ -490,7 +593,7 @@ import type data from "test" name: "component in expression with its child expression before its child element", source: "{list.map(() => ({name}))}", want: want{ - code: "${list.map(() => ($$render`${$$renderComponent($$result,'Component',Component,{},{\"default\": () => $$render`${name}`,})}`))}", + code: "${list.map(() => ($$render`${$$renderComponent($$result,'Component',Component,{},({\"default\": () => $$render`${name}`,}))}`))}", }, }, { @@ -519,7 +622,7 @@ import type data from "test" `, want: want{ - code: `${$$renderComponent($$result,'Layout',Layout,{"title":"Welcome to Astro."},{"default": () => $$render` + BACKTICK + ` + code: `${$$renderComponent($$result,'Layout',Layout,{"title":"Welcome to Astro."},({"default": () => $$render` + BACKTICK + ` ${$$maybeRenderHead($$result)}

Welcome to Astro

${ @@ -541,7 +644,7 @@ import type data from "test" }) }
-` + BACKTICK + `,})}`, +` + BACKTICK + `,}))}`, }, }, { @@ -633,7 +736,7 @@ import * as ns from '../components'; name: "slot with quoted attributes", source: `
`, want: want{ - code: `${` + RENDER_COMPONENT + `($$result,'Component',Component,{},{"\"name\"": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}
` + BACKTICK + `,})}`, + code: `${` + RENDER_COMPONENT + `($$result,'Component',Component,{},({"\"name\"": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}
` + BACKTICK + `,}))}`, }, }, { @@ -905,14 +1008,14 @@ const groups = [[0, 1, 2], [3, 4, 5]]; name: "HTML comment in component inside expression I", source: "{(() => )}", want: want{ - code: "${(() => $$render`${$$renderComponent($$result,'Component',Component,{},{})}`)}", + code: "${(() => $$render`${$$renderComponent($$result,'Component',Component,{},({}))}`)}", }, }, { name: "HTML comment in component inside expression II", source: "{list.map(() => )}", want: want{ - code: "${list.map(() => $$render`${$$renderComponent($$result,'Component',Component,{},{})}`)}", + code: "${list.map(() => $$render`${$$renderComponent($$result,'Component',Component,{},({}))}`)}", }, }, { @@ -947,7 +1050,7 @@ const groups = [[0, 1, 2], [3, 4, 5]]; name: "nested expressions V", source: `

title

{list.map(group =>

{group.label}

{group.items.map(item => {item})}
)}
`, want: want{ - code: "${$$maybeRenderHead($$result)}

title

${list.map(group => $$render`${$$renderComponent($$result,'Fragment',Fragment,{},{\"default\": () => $$render`

${group.label}

${group.items.map(item => $$render`${item}`)}`,})}`)}
", + code: "${$$maybeRenderHead($$result)}

title

${list.map(group => $$render`${$$renderComponent($$result,'Fragment',Fragment,{},({\"default\": () => $$render`

${group.label}

${group.items.map(item => $$render`${item}`)}`,}))}`)}
", }, }, { @@ -1038,7 +1141,7 @@ import Component from "test"; want: want{ frontmatter: []string{`import Component from "test";`}, metadata: metadata{modules: []string{`{ module: $$module1, specifier: 'test', assert: {} }`}}, - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + "`" + ` ${$$maybeRenderHead($$result)}
Default
` + "`" + `,"named": () => $$render` + "`" + `
Named
` + "`" + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + "`" + ` ${$$maybeRenderHead($$result)}
Default
` + "`" + `,"named": () => $$render` + "`" + `
Named
` + "`" + `,}))}`, }, }, { @@ -1054,7 +1157,7 @@ import Component from 'test'; want: want{ frontmatter: []string{`import Component from 'test';`}, metadata: metadata{modules: []string{`{ module: $$module1, specifier: 'test', assert: {} }`}}, - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + "`" + ` ${$$maybeRenderHead($$result)}
Default
` + "`" + `,"named": () => $$render` + "`" + `
Named
` + "`" + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + "`" + ` ${$$maybeRenderHead($$result)}
Default
` + "`" + `,"named": () => $$render` + "`" + `
Named
` + "`" + `,}))}`, }, }, { @@ -1064,7 +1167,7 @@ import Component from 'test'; {items.map(item =>
{item}
)} `, want: want{ - code: `${$$renderComponent($$result,'Component',Component,{"data":(data)},{"default": () => $$render` + BACKTICK + `${items.map(item => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}
${item}
` + BACKTICK + `)}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{"data":(data)},({"default": () => $$render` + BACKTICK + `${items.map(item => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}
${item}
` + BACKTICK + `)}` + BACKTICK + `,}))}`, }, }, { @@ -1113,7 +1216,7 @@ const testBool = true; ${testBool ? "Hey" : "Bye"} - ${testBool && ($$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `` + BACKTICK + `,})}` + BACKTICK + `)} + ${testBool && ($$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `` + BACKTICK + `,}))}` + BACKTICK + `)} ` + RENDER_HEAD_RESULT + `
@@ -1134,11 +1237,11 @@ const testBool = true; want: want{ code: `${ props.title && ( - $$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + ` + $$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + ` ${props.title} - ` + BACKTICK + `,})}` + BACKTICK + ` + ` + BACKTICK + `,}))}` + BACKTICK + ` ) }`, }, @@ -1296,9 +1399,9 @@ const someProps = { ` + 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` + "`" + ` + ${$$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!

- ` + "`" + `,})} + ` + "`" + `,}))}
`, @@ -1406,7 +1509,7 @@ const name = 'named'; want: want{ frontmatter: []string{`import Component from 'test';`, `const name = 'named';`}, metadata: metadata{modules: []string{`{ module: $$module1, specifier: 'test', assert: {} }`}}, - code: `${$$renderComponent($$result,'Component',Component,{},{[name]: () => $$render` + "`" + `${$$maybeRenderHead($$result)}
Named
` + "`" + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({[name]: () => $$render` + "`" + `${$$maybeRenderHead($$result)}
Named
` + "`" + `,}))}`, }, }, { @@ -1417,7 +1520,7 @@ const name = 'named'; C `, want: want{ - code: `${$$renderComponent($$result,'Slotted',Slotted,{},{"a": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}A` + BACKTICK + `,"b": () => $$render` + BACKTICK + `B` + BACKTICK + `,"c": () => $$render` + BACKTICK + `C` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Slotted',Slotted,{},({"a": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}A` + BACKTICK + `,"b": () => $$render` + BACKTICK + `B` + BACKTICK + `,"c": () => $$render` + BACKTICK + `C` + BACKTICK + `,}))}`, }, }, { @@ -1776,7 +1879,7 @@ import { Container, Col, Row } from 'react-bootstrap'; want: want{ frontmatter: []string{`import { Container, Col, Row } from 'react-bootstrap';`}, metadata: metadata{modules: []string{`{ module: $$module1, specifier: 'react-bootstrap', assert: {} }`}}, - code: "${$$renderComponent($$result,'Container',Container,{},{\"default\": () => $$render`\n ${$$renderComponent($$result,'Row',Row,{},{\"default\": () => $$render`\n ${$$renderComponent($$result,'Col',Col,{},{\"default\": () => $$render`\n ${$$maybeRenderHead($$result)}

Hi!

\n `,})}\n `,})}`,})}", + code: "${$$renderComponent($$result,'Container',Container,{},({\"default\": () => $$render`\n ${$$renderComponent($$result,'Row',Row,{},({\"default\": () => $$render`\n ${$$renderComponent($$result,'Col',Col,{},({\"default\": () => $$render`\n ${$$maybeRenderHead($$result)}

Hi!

\n `,}))}\n `,}))}`,}))}", }, }, { @@ -1858,49 +1961,49 @@ import { Container, Col, Row } from 'react-bootstrap'; name: "Fragment", source: `
Default
Named
`, want: want{ - code: `${$$maybeRenderHead($$result)}${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `
Default
Named
` + BACKTICK + `,})}`, + code: `${$$maybeRenderHead($$result)}${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `
Default
Named
` + BACKTICK + `,}))}`, }, }, { name: "Fragment shorthand", source: `<>
Default
Named
`, want: want{ - code: `${$$maybeRenderHead($$result)}${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `
Default
Named
` + BACKTICK + `,})}`, + code: `${$$maybeRenderHead($$result)}${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `
Default
Named
` + BACKTICK + `,}))}`, }, }, { name: "Fragment shorthand only", source: `<>Hello`, want: want{ - code: `${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `Hello` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `Hello` + BACKTICK + `,}))}`, }, }, { name: "Fragment literal only", source: `world`, want: want{ - code: `${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `world` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `world` + BACKTICK + `,}))}`, }, }, { name: "Fragment slotted", source: `<>
Default
Named
`, want: want{ - code: `${$$maybeRenderHead($$result)}${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `
Default
Named
` + BACKTICK + `,})}` + BACKTICK + `,})}`, + code: `${$$maybeRenderHead($$result)}${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `
Default
Named
` + BACKTICK + `,}))}` + BACKTICK + `,}))}`, }, }, { name: "Fragment slotted with name", source: `
Default
Named
`, want: want{ - code: `${$$maybeRenderHead($$result)}${$$renderComponent($$result,'Component',Component,{},{"named": () => $$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{"slot":"named"},{"default": () => $$render` + BACKTICK + `
Default
Named
` + BACKTICK + `,})}` + BACKTICK + `,})}`, + code: `${$$maybeRenderHead($$result)}${$$renderComponent($$result,'Component',Component,{},({"named": () => $$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{"slot":"named"},({"default": () => $$render` + BACKTICK + `
Default
Named
` + BACKTICK + `,}))}` + BACKTICK + `,}))}`, }, }, { name: "Preserve slots inside custom-element", source: `
Name
Default
`, want: want{ - code: `${$$maybeRenderHead($$result)}${$$renderComponent($$result,'my-element','my-element',{},{"default": () => $$render` + BACKTICK + `
Name
Default
` + BACKTICK + `,})}`, + code: `${$$maybeRenderHead($$result)}${$$renderComponent($$result,'my-element','my-element',{},({"default": () => $$render` + BACKTICK + `
Name
Default
` + BACKTICK + `,}))}`, }, }, { @@ -2191,7 +2294,7 @@ const content = "lol"; - ${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `${Array(7).fill(false).map((entry, index) => $$render` + BACKTICK + `` + BACKTICK + `)}` + BACKTICK + `,})} + ${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `${Array(7).fill(false).map((entry, index) => $$render` + BACKTICK + `` + BACKTICK + `)}` + BACKTICK + `,}))} @@ -2364,7 +2467,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "textarea in form", source: `
`, want: want{ - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}` + BACKTICK + `,}))}`, }, }, { @@ -2385,7 +2488,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "slot inside of Base", source: `
Hello
`, want: want{ - code: `${$$renderComponent($$result,'Base',Base,{"title":"Home"},{"default": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}
Hello
` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Base',Base,{"title":"Home"},({"default": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}
Hello
` + BACKTICK + `,}))}`, }, }, { @@ -2541,7 +2644,7 @@ const items = ["Dog", "Cat", "Platipus"]; name: "Component is:raw", source: "{<% awesome %>}", want: want{ - code: "${$$renderComponent($$result,'Component',Component,{},{\"default\": () => $$render`{<% awesome %>}`,})}", + code: "${$$renderComponent($$result,'Component',Component,{},({\"default\": () => $$render`{<% awesome %>}`,}))}", }, }, { @@ -2603,112 +2706,112 @@ const items = ["Dog", "Cat", "Platipus"]; name: "set:html on Component", source: ``, want: want{ - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + "`${$$unescapeHTML(content)}`," + `})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + "`${$$unescapeHTML(content)}`," + `}))}`, }, }, { name: "set:html on Component with quoted attribute", source: ``, want: want{ - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + BACKTICK + `${"content"}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + BACKTICK + `${"content"}` + BACKTICK + `,}))}`, }, }, { name: "set:html on Component with template literal attribute without variable", source: ``, want: want{ - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + BACKTICK + `${` + BACKTICK + `content` + BACKTICK + `}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + BACKTICK + `${` + BACKTICK + `content` + BACKTICK + `}` + BACKTICK + `,}))}`, }, }, { name: "set:html on Component with template literal attribute with variable", source: ``, want: want{ - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + BACKTICK + `${` + BACKTICK + `${content}` + BACKTICK + `}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + BACKTICK + `${` + BACKTICK + `${content}` + BACKTICK + `}` + BACKTICK + `,}))}`, }, }, { name: "set:text on Component", source: "", want: want{ - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + "`${content}`," + `})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + "`${content}`," + `}))}`, }, }, { name: "set:text on Component with quoted attribute", source: ``, want: want{ - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + BACKTICK + `content` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + BACKTICK + `content` + BACKTICK + `,}))}`, }, }, { name: "set:text on Component with template literal attribute without variable", source: ``, want: want{ - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + BACKTICK + `${` + BACKTICK + `content` + BACKTICK + `}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + BACKTICK + `${` + BACKTICK + `content` + BACKTICK + `}` + BACKTICK + `,}))}`, }, }, { name: "set:text on Component with template literal attribute with variable", source: ``, want: want{ - code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + BACKTICK + `${` + BACKTICK + `${content}` + BACKTICK + `}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Component',Component,{},({"default": () => $$render` + BACKTICK + `${` + BACKTICK + `${content}` + BACKTICK + `}` + BACKTICK + `,}))}`, }, }, { name: "set:html on custom-element", source: "", want: want{ - code: `${$$renderComponent($$result,'custom-element','custom-element',{},{"default": () => $$render` + "`${$$unescapeHTML(content)}`," + `})}`, + code: `${$$renderComponent($$result,'custom-element','custom-element',{},({"default": () => $$render` + "`${$$unescapeHTML(content)}`," + `}))}`, }, }, { name: "set:html on custom-element with quoted attribute", source: ``, want: want{ - code: `${$$renderComponent($$result,'custom-element','custom-element',{},{"default": () => $$render` + BACKTICK + `${"content"}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'custom-element','custom-element',{},({"default": () => $$render` + BACKTICK + `${"content"}` + BACKTICK + `,}))}`, }, }, { name: "set:html on custom-element with template literal attribute without variable", source: ``, want: want{ - code: `${$$renderComponent($$result,'custom-element','custom-element',{},{"default": () => $$render` + BACKTICK + `${` + BACKTICK + `content` + BACKTICK + `}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'custom-element','custom-element',{},({"default": () => $$render` + BACKTICK + `${` + BACKTICK + `content` + BACKTICK + `}` + BACKTICK + `,}))}`, }, }, { name: "set:html on custom-element with template literal attribute with variable", source: ``, want: want{ - code: `${$$renderComponent($$result,'custom-element','custom-element',{},{"default": () => $$render` + BACKTICK + `${` + BACKTICK + `${content}` + BACKTICK + `}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'custom-element','custom-element',{},({"default": () => $$render` + BACKTICK + `${` + BACKTICK + `${content}` + BACKTICK + `}` + BACKTICK + `,}))}`, }, }, { name: "set:text on custom-element", source: "", want: want{ - code: `${$$renderComponent($$result,'custom-element','custom-element',{},{"default": () => $$render` + "`${content}`," + `})}`, + code: `${$$renderComponent($$result,'custom-element','custom-element',{},({"default": () => $$render` + "`${content}`," + `}))}`, }, }, { name: "set:text on custom-element with quoted attribute", source: ``, want: want{ - code: `${$$renderComponent($$result,'custom-element','custom-element',{},{"default": () => $$render` + BACKTICK + `content` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'custom-element','custom-element',{},({"default": () => $$render` + BACKTICK + `content` + BACKTICK + `,}))}`, }, }, { name: "set:text on custom-element with template literal attribute without variable", source: ``, want: want{ - code: `${$$renderComponent($$result,'custom-element','custom-element',{},{"default": () => $$render` + BACKTICK + `${` + BACKTICK + `content` + BACKTICK + `}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'custom-element','custom-element',{},({"default": () => $$render` + BACKTICK + `${` + BACKTICK + `content` + BACKTICK + `}` + BACKTICK + `,}))}`, }, }, { name: "set:text on custom-element with template literal attribute with variable", source: ``, want: want{ - code: `${$$renderComponent($$result,'custom-element','custom-element',{},{"default": () => $$render` + BACKTICK + `${` + BACKTICK + `${content}` + BACKTICK + `}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'custom-element','custom-element',{},({"default": () => $$render` + BACKTICK + `${` + BACKTICK + `${content}` + BACKTICK + `}` + BACKTICK + `,}))}`, }, }, { @@ -2920,28 +3023,28 @@ const items = ["Dog", "Cat", "Platipus"]; name: "set:html on Fragment", source: "<i>This should NOT be italic</i>

\"} />", want: want{ - code: "${$$renderComponent($$result,'Fragment',Fragment,{},{\"default\": () => $$render`${$$unescapeHTML(\"

<i>This should NOT be italic</i>

\")}`,})}", + code: "${$$renderComponent($$result,'Fragment',Fragment,{},({\"default\": () => $$render`${$$unescapeHTML(\"

<i>This should NOT be italic</i>

\")}`,}))}", }, }, { name: "set:html on Fragment with quoted attribute", source: "<i>This should NOT be italic</i>

\" />", want: want{ - code: "${$$renderComponent($$result,'Fragment',Fragment,{},{\"default\": () => $$render`${\"

This should NOT be italic

\"}`,})}", + code: "${$$renderComponent($$result,'Fragment',Fragment,{},({\"default\": () => $$render`${\"

This should NOT be italic

\"}`,}))}", }, }, { name: "set:html on Fragment with template literal attribute without variable", source: "<i>This should NOT be italic</i>

` />", want: want{ - code: "${$$renderComponent($$result,'Fragment',Fragment,{},{\"default\": () => $$render`${`

This should NOT be italic

`}`,})}", + code: "${$$renderComponent($$result,'Fragment',Fragment,{},({\"default\": () => $$render`${`

This should NOT be italic

`}`,}))}", }, }, { name: "set:html on Fragment with template literal attribute with variable", source: ``, want: want{ - code: `${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `${` + BACKTICK + `${content}` + BACKTICK + `}` + BACKTICK + `,})}`, + code: `${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `${` + BACKTICK + `${content}` + BACKTICK + `}` + BACKTICK + `,}))}`, }, }, { @@ -3086,7 +3189,7 @@ const items = ["Dog", "Cat", "Platipus"]; want: want{ code: `${ list.map((i) => ( - $$render` + BACKTICK + `${$$renderComponent($$result,'Component',Component,{},{})}` + BACKTICK + ` + $$render` + BACKTICK + `${$$renderComponent($$result,'Component',Component,{},({}))}` + BACKTICK + ` )) }`, }, @@ -3105,7 +3208,7 @@ const items = ["Dog", "Cat", "Platipus"]; want: want{ code: `${ list.map((i) => ( - $$render` + BACKTICK + `${$$renderComponent($$result,'Component',Component,{},{})}` + BACKTICK + ` + $$render` + BACKTICK + `${$$renderComponent($$result,'Component',Component,{},({}))}` + BACKTICK + ` )) }`, }, @@ -3147,7 +3250,7 @@ const items = ["Dog", "Cat", "Platipus"]; source: `{(` + BACKTICK + `} />{Node.children.map((child) => ())}` + BACKTICK + `} />)}`, filename: "/projects/app/src/components/RenderNode.astro", want: want{ - code: `${($$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `${$$unescapeHTML(` + BACKTICK + `<${Node.tag} ${stringifyAttributes(Node.attributes)}>` + BACKTICK + `)}` + BACKTICK + `,})}${Node.children.map((child) => ($$render` + BACKTICK + `${$$renderComponent($$result,'Astro.self',Astro.self,{"node":(child)})}` + BACKTICK + `))}${$$renderComponent($$result,'Fragment',Fragment,{},{"default": () => $$render` + BACKTICK + `${$$unescapeHTML(` + BACKTICK + `` + BACKTICK + `)}` + BACKTICK + `,})}` + BACKTICK + `,})}` + BACKTICK + `)}`, + code: `${($$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `${$$unescapeHTML(` + BACKTICK + `<${Node.tag} ${stringifyAttributes(Node.attributes)}>` + BACKTICK + `)}` + BACKTICK + `,}))}${Node.children.map((child) => ($$render` + BACKTICK + `${$$renderComponent($$result,'Astro.self',Astro.self,{"node":(child)})}` + BACKTICK + `))}${$$renderComponent($$result,'Fragment',Fragment,{},({"default": () => $$render` + BACKTICK + `${$$unescapeHTML(` + BACKTICK + `` + BACKTICK + `)}` + BACKTICK + `,}))}` + BACKTICK + `,}))}` + BACKTICK + `)}`, }, }, {
AA