From 4380898e23e3bfac9e740ac60c75fd20ee7c203c Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Mon, 29 Jan 2024 13:17:45 +0000 Subject: [PATCH 01/13] localize relevant state in expression --- internal/printer/print-to-js.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index 2d6b7bba9..6a5c03344 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -686,7 +686,8 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { } } if c.Expression { - nestedSlotsCount := 0 + nestedSlotsInExprCount := 0 + hasAnyDynamicSlotsInExpr := false var firstNestedSlotProp string for c1 := c.FirstChild; c1 != nil; c1 = c1.NextSibling { var slotProp = "" @@ -697,9 +698,11 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { } else if a.Type == ExpressionAttribute { slotProp = fmt.Sprintf(`[%s]`, a.Val) hasAnyDynamicSlots = true + hasAnyDynamicSlotsInExpr = true } else if a.Type == TemplateLiteralAttribute { slotProp = fmt.Sprintf(`[%s%s%s]`, BACKTICK, a.Val, BACKTICK) hasAnyDynamicSlots = true + hasAnyDynamicSlotsInExpr = true } else { panic(`unknown slot attribute type`) } @@ -709,17 +712,18 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { } } if firstNestedSlotProp != "" { - nestedSlotsCount++ + nestedSlotsInExprCount++ } } - if nestedSlotsCount == 1 && !hasAnyDynamicSlots { + if nestedSlotsInExprCount == 1 && !hasAnyDynamicSlotsInExpr { slottedChildren[firstNestedSlotProp] = append(slottedChildren[firstNestedSlotProp], c) continue - } else if nestedSlotsCount > 1 || hasAnyDynamicSlots { + } else if nestedSlotsInExprCount > 1 || hasAnyDynamicSlotsInExpr { child_loop: for c1 := c.FirstChild; c1 != nil; c1 = c1.NextSibling { foundNamedSlot := false + isFirstInGroup := c1 == c.FirstChild for _, a := range c1.Attr { if a.Key == "slot" { var nestedSlotProp string @@ -737,13 +741,11 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { 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) From baab72ad2a29cbf7125f24f56b634d7e94b60454 Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Mon, 29 Jan 2024 14:26:40 +0000 Subject: [PATCH 02/13] reuse default slot constant --- internal/printer/print-to-js.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index 6a5c03344..23bb8d8f1 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -432,7 +432,7 @@ func render1(p *printer, n *Node, opts RenderOptions) { p.printAttributesToObject(n) } else if isSlot { if len(n.Attr) == 0 { - p.print(`"default"`) + p.print(DEFAULT_SLOT_PROP) } else { slotted := false for _, a := range n.Attr { @@ -454,7 +454,7 @@ func render1(p *printer, n *Node, opts RenderOptions) { } } if !slotted { - p.print(`"default"`) + p.print(DEFAULT_SLOT_PROP) } } p.print(`]`) @@ -559,7 +559,7 @@ func render1(p *printer, n *Node, opts RenderOptions) { switch true { case n.CustomElement: p.print(`,({`) - p.print(fmt.Sprintf(`"%s": () => `, "default")) + p.print(fmt.Sprintf(`%s: () => `, DEFAULT_SLOT_PROP)) p.printTemplateLiteralOpen() for c := n.FirstChild; c != nil; c = c.NextSibling { render1(p, c, RenderOptions{ @@ -638,6 +638,8 @@ func render1(p *printer, n *Node, opts RenderOptions) { } } +const DEFAULT_SLOT_PROP = `"default"` + // Section 12.1.2, "Elements", gives this list of void elements. Void elements // are those that can't have any contents. // nolint @@ -667,7 +669,7 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { numberOfNestedSlots := 0 for c := n.FirstChild; c != nil; c = c.NextSibling { - slotProp := `"default"` + slotProp := DEFAULT_SLOT_PROP for _, a := range c.Attr { if a.Key == "slot" { if a.Type == QuotedAttribute { @@ -747,7 +749,7 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { } } if !foundNamedSlot && c1.Type == ElementNode { - pseudoSlotEntry := &NestedSlotChild{`"default"`, []*Node{c1}, isFirstInGroup} + pseudoSlotEntry := &NestedSlotChild{DEFAULT_SLOT_PROP, []*Node{c1}, isFirstInGroup} nestedSlotChildren = append(nestedSlotChildren, pseudoSlotEntry) } else { nestedSlotEntry := &NestedSlotChild{`"@@NON_ELEMENT_ENTRY"`, []*Node{c1}, isFirstInGroup} @@ -785,7 +787,7 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { children := slottedChildren[slotProp] // If there are named slots, the default slot cannot be only whitespace - if numberOfSlots > 1 && slotProp == "\"default\"" { + if numberOfSlots > 1 && slotProp == DEFAULT_SLOT_PROP { // Loop over the children and verify that at least one non-whitespace node exists. foundNonWhitespace := false for _, child := range children { @@ -910,7 +912,7 @@ func generateEndSlotIndexes(nestedSlotChildren []*NestedSlotChild) map[int]bool } func mergeDefaultSlotsAndUpdateIndexes(nestedSlotChildren *[]*NestedSlotChild, endSlotIndexes map[int]bool) { - defaultSlot := &NestedSlotChild{SlotProp: `"default"`, Children: []*Node{}} + defaultSlot := &NestedSlotChild{SlotProp: DEFAULT_SLOT_PROP, Children: []*Node{}} mergedSlotChildren := make([]*NestedSlotChild, 0) numberOfMergedSlotsInSlotChain := 0 @@ -924,7 +926,7 @@ func mergeDefaultSlotsAndUpdateIndexes(nestedSlotChildren *[]*NestedSlotChild, e if shouldMergeDefaultSlot(endSlotIndexes, i, defaultSlot) { resetEndSlotIndexes(endSlotIndexes, i, &numberOfMergedSlotsInSlotChain) mergedSlotChildren = append(mergedSlotChildren, defaultSlot) - defaultSlot = &NestedSlotChild{SlotProp: `"default"`, Children: []*Node{}} + defaultSlot = &NestedSlotChild{SlotProp: DEFAULT_SLOT_PROP, Children: []*Node{}} } } *nestedSlotChildren = mergedSlotChildren @@ -945,7 +947,7 @@ func isNonWhitespaceTextNode(n *Node) bool { } func isDefaultSlot(slot *NestedSlotChild) bool { - return slot.SlotProp == `"default"` + return slot.SlotProp == DEFAULT_SLOT_PROP } func shouldMergeDefaultSlot(endSlotIndexes map[int]bool, i int, defaultSlot *NestedSlotChild) bool { From a91022b2754e0b02153901157ef71152c07882af Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Mon, 29 Jan 2024 14:27:28 +0000 Subject: [PATCH 03/13] more granular use of `mergeSlots` --- internal/printer/print-to-js.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index 23bb8d8f1..b1e4ae953 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -690,9 +690,8 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { if c.Expression { nestedSlotsInExprCount := 0 hasAnyDynamicSlotsInExpr := false - var firstNestedSlotProp string + var slotProp = DEFAULT_SLOT_PROP for c1 := c.FirstChild; c1 != nil; c1 = c1.NextSibling { - var slotProp = "" for _, a := range c1.Attr { if a.Key == "slot" { if a.Type == QuotedAttribute { @@ -709,17 +708,14 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { panic(`unknown slot attribute type`) } } - if firstNestedSlotProp == "" && slotProp != "" { - firstNestedSlotProp = slotProp - } } - if firstNestedSlotProp != "" { + if c1.Type == ElementNode { nestedSlotsInExprCount++ } } if nestedSlotsInExprCount == 1 && !hasAnyDynamicSlotsInExpr { - slottedChildren[firstNestedSlotProp] = append(slottedChildren[firstNestedSlotProp], c) + slottedChildren[slotProp] = append(slottedChildren[slotProp], c) continue } else if nestedSlotsInExprCount > 1 || hasAnyDynamicSlotsInExpr { child_loop: From a6f985d410c2964f65e91bc5c612f5ca069e2932 Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Mon, 29 Jan 2024 14:52:59 +0000 Subject: [PATCH 04/13] skip expressions with comments-only earlier --- internal/printer/print-to-js.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index b1e4ae953..10ba42a27 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -688,6 +688,11 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { } } if c.Expression { + // 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 + } nestedSlotsInExprCount := 0 hasAnyDynamicSlotsInExpr := false var slotProp = DEFAULT_SLOT_PROP @@ -757,11 +762,6 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { } } - // 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) } From df18a090d41bb3e3cf3c486455021e61b68ff69b Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Mon, 29 Jan 2024 15:01:34 +0000 Subject: [PATCH 05/13] test: edit test to reflect changes --- internal/printer/printer_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/printer/printer_test.go b/internal/printer/printer_test.go index 24f76f471..8bc99ea75 100644 --- a/internal/printer/printer_test.go +++ b/internal/printer/printer_test.go @@ -278,7 +278,7 @@ func TestPrinter(t *testing.T) { {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`})))}", + code: "${$$renderComponent($$result,'Slotted',Slotted,{},({\"a\": () => $$render`${true && $$render`${$$maybeRenderHead($$result)}A`}`,\"b\": () => $$render`${true ? $$render`B` : null}`,\"c\": () => $$render`${() => $$render`C`}`,\"default\": () => $$render`${true && $$render`Default`}`,}))}", }, }, { @@ -300,7 +300,7 @@ func TestPrinter(t *testing.T) { }} `, 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 + `}),() => { + code: `${$$renderComponent($$result,'Slotted',Slotted,{},$$mergeSlots(({"b": () => $$render` + BACKTICK + `${true ? $$render` + BACKTICK + `${$$maybeRenderHead($$result)}B` + BACKTICK + ` : null}` + BACKTICK + `,"c": () => $$render` + BACKTICK + `${() => $$render` + BACKTICK + `C` + BACKTICK + `}` + BACKTICK + `,}),true && ({["a"]: () => $$render` + BACKTICK + `A` + BACKTICK + `}),() => { const value = 0.33; if (value > 0.25) { return ({"hey": () => $$render` + BACKTICK + `Another` + BACKTICK + `, "default": () => $$render` + BACKTICK + `Default` + BACKTICK + `}) From 7c97372d044c06d7d4ac4b1bc781e28da3435122 Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Mon, 29 Jan 2024 17:20:06 +0000 Subject: [PATCH 06/13] refactor mergeSlots printing --- internal/printer/print-to-js.go | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index 10ba42a27..8345e0adb 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -664,9 +664,11 @@ var voidElements = map[string]bool{ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { p.print(`,`) slottedChildren := make(map[string][]*Node) - hasAnyDynamicSlots := false + hasAnyNestedDynamicSlot := false nestedSlotChildren := make([]*NestedSlotChild, 0) - numberOfNestedSlots := 0 + + // the highest number of nested slots in an expression + maxNestedSlotsCount := 0 for c := n.FirstChild; c != nil; c = c.NextSibling { slotProp := DEFAULT_SLOT_PROP @@ -703,11 +705,11 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { slotProp = fmt.Sprintf(`"%s"`, escapeDoubleQuote(a.Val)) } else if a.Type == ExpressionAttribute { slotProp = fmt.Sprintf(`[%s]`, a.Val) - hasAnyDynamicSlots = true + hasAnyNestedDynamicSlot = true hasAnyDynamicSlotsInExpr = true } else if a.Type == TemplateLiteralAttribute { slotProp = fmt.Sprintf(`[%s%s%s]`, BACKTICK, a.Val, BACKTICK) - hasAnyDynamicSlots = true + hasAnyNestedDynamicSlot = true hasAnyDynamicSlotsInExpr = true } else { panic(`unknown slot attribute type`) @@ -723,6 +725,9 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { slottedChildren[slotProp] = append(slottedChildren[slotProp], c) continue } else if nestedSlotsInExprCount > 1 || hasAnyDynamicSlotsInExpr { + if nestedSlotsInExprCount > maxNestedSlotsCount { + maxNestedSlotsCount = nestedSlotsInExprCount + } child_loop: for c1 := c.FirstChild; c1 != nil; c1 = c1.NextSibling { foundNamedSlot := false @@ -733,12 +738,12 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { var nestedSlotEntry *NestedSlotChild if a.Type == QuotedAttribute { nestedSlotProp = fmt.Sprintf(`"%s"`, escapeDoubleQuote(a.Val)) - hasAnyDynamicSlots = true + hasAnyNestedDynamicSlot = true } else if a.Type == ExpressionAttribute { nestedSlotProp = fmt.Sprintf(`[%s]`, a.Val) - hasAnyDynamicSlots = true + hasAnyNestedDynamicSlot = true } else if a.Type == TemplateLiteralAttribute { - hasAnyDynamicSlots = true + hasAnyNestedDynamicSlot = true nestedSlotProp = fmt.Sprintf(`[%s%s%s]`, BACKTICK, a.Val, BACKTICK) } else { panic(`unknown slot attribute type`) @@ -756,7 +761,6 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { nestedSlotEntry := &NestedSlotChild{`"@@NON_ELEMENT_ENTRY"`, []*Node{c1}, isFirstInGroup} nestedSlotChildren = append(nestedSlotChildren, nestedSlotEntry) } - numberOfNestedSlots++ } continue } @@ -772,7 +776,12 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { slottedKeys = append(slottedKeys, k) } sort.Strings(slottedKeys) - if numberOfNestedSlots > 0 || hasAnyDynamicSlots { + + // if any slotted expression contains more than one nested slot (e.g. {true ?
Bar
:
Foo
}
) + // OR if any expression contains a dynamic slot (e.g. {items.map((item)=> (
{item.name}
)}
) + // we need to use $$mergeSlots + shouldPrintMergeSlots := maxNestedSlotsCount > 1 || hasAnyNestedDynamicSlot + if shouldPrintMergeSlots { p.print(`$$mergeSlots(`) } p.print(`({`) @@ -820,7 +829,7 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { } p.print(`})`) // print nested slots - if numberOfNestedSlots > 0 || hasAnyDynamicSlots { + if len(nestedSlotChildren) > 0 || hasAnyNestedDynamicSlot { endSlotIndexes := generateEndSlotIndexes(nestedSlotChildren) mergeDefaultSlotsAndUpdateIndexes(&nestedSlotChildren, endSlotIndexes) @@ -843,6 +852,9 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { hasFoundFirstElementNode = false } } + } + if shouldPrintMergeSlots { + // close $$mergeSlots call p.print(`)`) } } From 3fa9b303ae14d58192598a3cc2781cdb1fb65b4b Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Mon, 29 Jan 2024 17:22:01 +0000 Subject: [PATCH 07/13] simplify condition --- internal/printer/print-to-js.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index 8345e0adb..811518228 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -829,7 +829,7 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { } p.print(`})`) // print nested slots - if len(nestedSlotChildren) > 0 || hasAnyNestedDynamicSlot { + if len(nestedSlotChildren) > 0 { endSlotIndexes := generateEndSlotIndexes(nestedSlotChildren) mergeDefaultSlotsAndUpdateIndexes(&nestedSlotChildren, endSlotIndexes) From d06c2d9c5bce62c06c92ee2274547144820570f1 Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Mon, 29 Jan 2024 17:26:59 +0000 Subject: [PATCH 08/13] remove wrong assumption --- internal/printer/print-to-js.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index 811518228..198e6b63a 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -738,7 +738,6 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { var nestedSlotEntry *NestedSlotChild if a.Type == QuotedAttribute { nestedSlotProp = fmt.Sprintf(`"%s"`, escapeDoubleQuote(a.Val)) - hasAnyNestedDynamicSlot = true } else if a.Type == ExpressionAttribute { nestedSlotProp = fmt.Sprintf(`[%s]`, a.Val) hasAnyNestedDynamicSlot = true From e054183a4c124ea0d37a27ec48d46a543f0234be Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Mon, 29 Jan 2024 18:03:25 +0000 Subject: [PATCH 09/13] chore: one-liner --- internal/printer/print-to-js.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index 198e6b63a..1548c44c4 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -705,12 +705,10 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { slotProp = fmt.Sprintf(`"%s"`, escapeDoubleQuote(a.Val)) } else if a.Type == ExpressionAttribute { slotProp = fmt.Sprintf(`[%s]`, a.Val) - hasAnyNestedDynamicSlot = true - hasAnyDynamicSlotsInExpr = true + hasAnyNestedDynamicSlot, hasAnyDynamicSlotsInExpr = true, true } else if a.Type == TemplateLiteralAttribute { slotProp = fmt.Sprintf(`[%s%s%s]`, BACKTICK, a.Val, BACKTICK) - hasAnyNestedDynamicSlot = true - hasAnyDynamicSlotsInExpr = true + hasAnyNestedDynamicSlot, hasAnyDynamicSlotsInExpr = true, true } else { panic(`unknown slot attribute type`) } From 923184801a1621ab533f30f6426044be221d24fe Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Mon, 29 Jan 2024 18:23:33 +0000 Subject: [PATCH 10/13] chore: changeset --- .changeset/dull-socks-provide.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/dull-socks-provide.md diff --git a/.changeset/dull-socks-provide.md b/.changeset/dull-socks-provide.md new file mode 100644 index 000000000..32b2cb6fa --- /dev/null +++ b/.changeset/dull-socks-provide.md @@ -0,0 +1,5 @@ +--- +'@astrojs/compiler': patch +--- + +Fixes an issue where a slotted element in an expression would cause subsequent ones to be incorrectly printed From 45ee05bee42f5a44ba022860085a7f4efd51e892 Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Tue, 30 Jan 2024 08:27:30 +0000 Subject: [PATCH 11/13] add test case that failed in core smoke tests --- internal/printer/printer_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/internal/printer/printer_test.go b/internal/printer/printer_test.go index 8bc99ea75..030f7997d 100644 --- a/internal/printer/printer_test.go +++ b/internal/printer/printer_test.go @@ -240,6 +240,35 @@ func TestPrinter(t *testing.T) { code: "${$$renderComponent($$result,'Component',Component,{},$$mergeSlots(({}),Math.random() > 0.5 ? ({\"a\": () => $$render`${$$maybeRenderHead($$result)}
A
`}) : ({\"b\": () => $$render`
B
`})))}", }, }, + { + name: "ternary slot II", + source: ` + { + Astro.request.method === 'GET' ? ( +

Contact Form

+
+ + +
+ ) : ( +
Got: {formData?.get('name')}
+ ) + } +
`, + want: want{ + code: `${$$renderComponent($$result,'Layout',Layout,{},$$mergeSlots(({}), + Astro.request.method === 'GET' ? ( + + ({"default": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}

Contact Form

+ + +
` + BACKTICK + `}) + ) : ( + ({"default": () => $$render` + BACKTICK + `
Got: ${formData?.get('name')}
` + BACKTICK + `}) + ) + ))}`, + }, + }, { name: "ternary slot with one implicit default", source: `
From 3ffac4157963c42aaeabed614cce962970cbd7b9 Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Tue, 30 Jan 2024 08:28:32 +0000 Subject: [PATCH 12/13] correctly determine the end of slot chains --- internal/printer/print-to-js.go | 53 +++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index 1548c44c4..e75a46664 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -828,8 +828,7 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) { // print nested slots if len(nestedSlotChildren) > 0 { endSlotIndexes := generateEndSlotIndexes(nestedSlotChildren) - mergeDefaultSlotsAndUpdateIndexes(&nestedSlotChildren, endSlotIndexes) - + mergeDefaultSlotsAndUpdateIndexes(&nestedSlotChildren, &endSlotIndexes) hasFoundFirstElementNode := false for j, nestedSlot := range nestedSlotChildren { if nestedSlot.FirstInGroup { @@ -916,25 +915,45 @@ func generateEndSlotIndexes(nestedSlotChildren []*NestedSlotChild) map[int]bool return endSlotIndexes } -func mergeDefaultSlotsAndUpdateIndexes(nestedSlotChildren *[]*NestedSlotChild, endSlotIndexes map[int]bool) { +func mergeDefaultSlotsAndUpdateIndexes(nestedSlotChildren *[]*NestedSlotChild, endSlotIndexes *map[int]bool) { defaultSlot := &NestedSlotChild{SlotProp: DEFAULT_SLOT_PROP, Children: []*Node{}} - mergedSlotChildren := make([]*NestedSlotChild, 0) - numberOfMergedSlotsInSlotChain := 0 + updatedNestedSlotChildren := make([]*NestedSlotChild, 0) + updatedEndSlotIndexes := make(map[int]bool) for i, nestedSlot := range *nestedSlotChildren { + var isDefault bool if isDefaultSlot(nestedSlot) { + isDefault = true defaultSlot.Children = append(defaultSlot.Children, nestedSlot.Children...) - numberOfMergedSlotsInSlotChain++ } else { - mergedSlotChildren = append(mergedSlotChildren, nestedSlot) + updatedNestedSlotChildren = append(updatedNestedSlotChildren, nestedSlot) } - if shouldMergeDefaultSlot(endSlotIndexes, i, defaultSlot) { - resetEndSlotIndexes(endSlotIndexes, i, &numberOfMergedSlotsInSlotChain) - mergedSlotChildren = append(mergedSlotChildren, defaultSlot) - defaultSlot = &NestedSlotChild{SlotProp: DEFAULT_SLOT_PROP, Children: []*Node{}} + + // we reached the end of a slot chain + if (*endSlotIndexes)[i] { + // free up memory, this information is now outdated + // the updated information is stored in updatedEndSlotIndexes + delete(*endSlotIndexes, i) + + if len(defaultSlot.Children) > 0 { + // if the last element in a slot chain is a default slot + // let's add it to the updated nested slot children + updatedEndSlotIndexes[len(updatedNestedSlotChildren)] = true + updatedNestedSlotChildren = append(updatedNestedSlotChildren, defaultSlot) + defaultSlot = &NestedSlotChild{SlotProp: DEFAULT_SLOT_PROP, Children: []*Node{}} + } else if !isDefault { + // if it's not a default slot, we just need to set the updated end slot indexes + // we already added it in the previous iteration + updatedEndSlotIndexes[len(updatedNestedSlotChildren)-1] = true + } } + + // free up memory, the actual information of nested slot + // is now stored in updatedNestedSlotChildren + (*nestedSlotChildren)[i] = nil } - *nestedSlotChildren = mergedSlotChildren + *nestedSlotChildren = updatedNestedSlotChildren + *endSlotIndexes = updatedEndSlotIndexes } func getSlotRenderFunction(isNewSlotObject bool) string { @@ -954,13 +973,3 @@ func isNonWhitespaceTextNode(n *Node) bool { func isDefaultSlot(slot *NestedSlotChild) bool { return slot.SlotProp == DEFAULT_SLOT_PROP } - -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 -} From 336021bb80ddc4efc67c3304fa775fe31aec3435 Mon Sep 17 00:00:00 2001 From: Moustapha HappyDev Date: Tue, 30 Jan 2024 14:33:02 +0000 Subject: [PATCH 13/13] simplify code --- internal/printer/print-to-js.go | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/internal/printer/print-to-js.go b/internal/printer/print-to-js.go index e75a46664..c37cf2061 100644 --- a/internal/printer/print-to-js.go +++ b/internal/printer/print-to-js.go @@ -916,15 +916,13 @@ func generateEndSlotIndexes(nestedSlotChildren []*NestedSlotChild) map[int]bool } func mergeDefaultSlotsAndUpdateIndexes(nestedSlotChildren *[]*NestedSlotChild, endSlotIndexes *map[int]bool) { - defaultSlot := &NestedSlotChild{SlotProp: DEFAULT_SLOT_PROP, Children: []*Node{}} + bufferedDefaultSlot := &NestedSlotChild{SlotProp: DEFAULT_SLOT_PROP, Children: []*Node{}} updatedNestedSlotChildren := make([]*NestedSlotChild, 0) updatedEndSlotIndexes := make(map[int]bool) for i, nestedSlot := range *nestedSlotChildren { - var isDefault bool if isDefaultSlot(nestedSlot) { - isDefault = true - defaultSlot.Children = append(defaultSlot.Children, nestedSlot.Children...) + bufferedDefaultSlot.Children = append(bufferedDefaultSlot.Children, nestedSlot.Children...) } else { updatedNestedSlotChildren = append(updatedNestedSlotChildren, nestedSlot) } @@ -935,17 +933,16 @@ func mergeDefaultSlotsAndUpdateIndexes(nestedSlotChildren *[]*NestedSlotChild, e // the updated information is stored in updatedEndSlotIndexes delete(*endSlotIndexes, i) - if len(defaultSlot.Children) > 0 { - // if the last element in a slot chain is a default slot - // let's add it to the updated nested slot children - updatedEndSlotIndexes[len(updatedNestedSlotChildren)] = true - updatedNestedSlotChildren = append(updatedNestedSlotChildren, defaultSlot) - defaultSlot = &NestedSlotChild{SlotProp: DEFAULT_SLOT_PROP, Children: []*Node{}} - } else if !isDefault { - // if it's not a default slot, we just need to set the updated end slot indexes - // we already added it in the previous iteration - updatedEndSlotIndexes[len(updatedNestedSlotChildren)-1] = true + if len(bufferedDefaultSlot.Children) > 0 { + // if the buffered default slot contains any children + // add it to the updated nested slot children + updatedNestedSlotChildren = append(updatedNestedSlotChildren, bufferedDefaultSlot) + + // reset the buffered default slot + bufferedDefaultSlot = &NestedSlotChild{SlotProp: DEFAULT_SLOT_PROP, Children: []*Node{}} } + // record the index of the last slot in the chain + updatedEndSlotIndexes[len(updatedNestedSlotChildren)-1] = true } // free up memory, the actual information of nested slot