From 4f6ee85a4422ddcd7418526dfb4d06803c652ca7 Mon Sep 17 00:00:00 2001 From: Adam Lehechka <42357034+alehechka@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:18:26 -0600 Subject: [PATCH 1/5] feat: ComponentScript spread attribute support --- .version | 2 +- .../visualize/sourcemapvisualisation_templ.go | 2 +- .../external-libraries/components_templ.go | 2 +- generator/generator.go | 26 +++++++++++----- generator/test-script-usage/template_templ.go | 6 ++-- .../test-spread-attributes/template_templ.go | 30 +++++++++++++++++-- runtime.go | 16 ++++++++-- runtime_test.go | 4 +-- 8 files changed, 67 insertions(+), 21 deletions(-) diff --git a/.version b/.version index 0229a488e..f94611877 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -0.2.608 \ No newline at end of file +0.2.610 \ No newline at end of file diff --git a/cmd/templ/visualize/sourcemapvisualisation_templ.go b/cmd/templ/visualize/sourcemapvisualisation_templ.go index 7af88e176..2024f9079 100644 --- a/cmd/templ/visualize/sourcemapvisualisation_templ.go +++ b/cmd/templ/visualize/sourcemapvisualisation_templ.go @@ -226,7 +226,7 @@ func mappedCharacter(s string, sourceID, targetID string) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, highlight(sourceID, targetID), removeHighlight(sourceID, targetID)) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{}, highlight(sourceID, targetID), removeHighlight(sourceID, targetID)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/examples/external-libraries/components_templ.go b/examples/external-libraries/components_templ.go index 3fb06a012..33c8c693a 100644 --- a/examples/external-libraries/components_templ.go +++ b/examples/external-libraries/components_templ.go @@ -38,7 +38,7 @@ func page(data []TimeValue) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, graph(data)) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{}, graph(data)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/generator/generator.go b/generator/generator.go index df9c0a66f..ae3aff255 100644 --- a/generator/generator.go +++ b/generator/generator.go @@ -1021,15 +1021,18 @@ func isScriptAttribute(name string) bool { func (g *generator) writeElementScript(indentLevel int, n parser.Element) (err error) { var scriptExpressions []string + var spreadAttributes []string for _, attr := range n.Attributes { - scriptExpressions = append(scriptExpressions, getAttributeScripts(attr)...) + scripts, spreads := getAttributeScripts(attr) + scriptExpressions = append(scriptExpressions, scripts...) + spreadAttributes = append(spreadAttributes, spreads...) } - if len(scriptExpressions) == 0 { + if len(scriptExpressions) == 0 && len(spreadAttributes) == 0 { return } // Render the scripts before the element if required. - // templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, a, b, c) - if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, "+strings.Join(scriptExpressions, ", ")+")\n"); err != nil { + // templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []Attributes, a, b, c) + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{"+strings.Join(spreadAttributes, ", ")+"}, "+strings.Join(scriptExpressions, ", ")+")\n"); err != nil { return err } if err = g.writeErrorHandler(indentLevel); err != nil { @@ -1038,13 +1041,17 @@ func (g *generator) writeElementScript(indentLevel int, n parser.Element) (err e return err } -func getAttributeScripts(attr parser.Attribute) (scripts []string) { +func getAttributeScripts(attr parser.Attribute) (scripts []string, spreads []string) { if attr, ok := attr.(parser.ConditionalAttribute); ok { for _, attr := range attr.Then { - scripts = append(scripts, getAttributeScripts(attr)...) + thenScripts, thenSpreads := getAttributeScripts(attr) + scripts = append(scripts, thenScripts...) + spreads = append(spreads, thenSpreads...) } for _, attr := range attr.Else { - scripts = append(scripts, getAttributeScripts(attr)...) + elseScripts, elseSpreads := getAttributeScripts(attr) + scripts = append(scripts, elseScripts...) + spreads = append(spreads, elseSpreads...) } } if attr, ok := attr.(parser.ExpressionAttribute); ok { @@ -1053,7 +1060,10 @@ func getAttributeScripts(attr parser.Attribute) (scripts []string) { scripts = append(scripts, attr.Expression.Value) } } - return scripts + if attr, ok := attr.(parser.SpreadAttributes); ok { + spreads = append(spreads, attr.Expression.Value) + } + return } func (g *generator) writeBoolConstantAttribute(indentLevel int, attr parser.BoolConstantAttribute) (err error) { diff --git a/generator/test-script-usage/template_templ.go b/generator/test-script-usage/template_templ.go index 716f96d20..d84c5a85a 100644 --- a/generator/test-script-usage/template_templ.go +++ b/generator/test-script-usage/template_templ.go @@ -52,7 +52,7 @@ func Button(text string) templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, withParameters("test", text, 123), withoutParameters()) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{}, withParameters("test", text, 123), withoutParameters()) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -133,7 +133,7 @@ func ThreeButtons() templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, onClick()) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{}, onClick()) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -184,7 +184,7 @@ func Conditional(show bool) templ.Component { templ_7745c5c3_Var7 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, conditionalScript()) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{}, conditionalScript()) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/generator/test-spread-attributes/template_templ.go b/generator/test-spread-attributes/template_templ.go index f6eb5af08..096a900de 100644 --- a/generator/test-spread-attributes/template_templ.go +++ b/generator/test-spread-attributes/template_templ.go @@ -22,7 +22,15 @@ func BasicTemplate(spread templ.Attributes) templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{spread}) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("texttext") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{spread}) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("text2
text2") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{spread}) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" element, if the script has not already been rendered. -func RenderScriptItems(ctx context.Context, w io.Writer, scripts ...ComponentScript) (err error) { +func RenderScriptItems(ctx context.Context, w io.Writer, attrSlice []Attributes, scripts ...ComponentScript) (err error) { + for _, attrs := range attrSlice { + for _, attr := range attrs { + if script, ok := attr.(ComponentScript); ok { + scripts = append(scripts, script) + } + } + } + if len(scripts) == 0 { return nil } diff --git a/runtime_test.go b/runtime_test.go index be7ba3ff9..6a5d75c46 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -532,14 +532,14 @@ func TestRenderScriptItems(t *testing.T) { // Render twice, reusing the same context so that there's a memory of which classes have been rendered. ctx = templ.InitializeContext(ctx) - err := templ.RenderScriptItems(ctx, b, tt.toIgnore...) + err := templ.RenderScriptItems(ctx, b, []templ.Attributes{}, tt.toIgnore...) if err != nil { t.Fatalf("failed to render initial scripts: %v", err) } // Now render again to check that only the expected classes were rendered. b.Reset() - err = templ.RenderScriptItems(ctx, b, tt.toRender...) + err = templ.RenderScriptItems(ctx, b, []templ.Attributes{}, tt.toRender...) if err != nil { t.Fatalf("failed to render scripts: %v", err) } From 702d72944d2f6c3459efdf107f5f7e68a2bfb6ea Mon Sep 17 00:00:00 2001 From: Adam Lehechka <42357034+alehechka@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:35:51 -0600 Subject: [PATCH 2/5] fix: add RenderScriptItemsWithSpread to avoid breaking change --- cmd/templ/visualize/sourcemapvisualisation_templ.go | 2 +- examples/external-libraries/components_templ.go | 2 +- generator/generator.go | 9 ++++++++- generator/test-script-usage/template_templ.go | 6 +++--- generator/test-spread-attributes/template_templ.go | 6 +++--- runtime.go | 10 ++++++++-- runtime_test.go | 4 ++-- 7 files changed, 26 insertions(+), 13 deletions(-) diff --git a/cmd/templ/visualize/sourcemapvisualisation_templ.go b/cmd/templ/visualize/sourcemapvisualisation_templ.go index 2024f9079..7af88e176 100644 --- a/cmd/templ/visualize/sourcemapvisualisation_templ.go +++ b/cmd/templ/visualize/sourcemapvisualisation_templ.go @@ -226,7 +226,7 @@ func mappedCharacter(s string, sourceID, targetID string) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{}, highlight(sourceID, targetID), removeHighlight(sourceID, targetID)) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, highlight(sourceID, targetID), removeHighlight(sourceID, targetID)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/examples/external-libraries/components_templ.go b/examples/external-libraries/components_templ.go index 33c8c693a..3fb06a012 100644 --- a/examples/external-libraries/components_templ.go +++ b/examples/external-libraries/components_templ.go @@ -38,7 +38,7 @@ func page(data []TimeValue) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{}, graph(data)) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, graph(data)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/generator/generator.go b/generator/generator.go index ae3aff255..fee79c91e 100644 --- a/generator/generator.go +++ b/generator/generator.go @@ -1030,9 +1030,16 @@ func (g *generator) writeElementScript(indentLevel int, n parser.Element) (err e if len(scriptExpressions) == 0 && len(spreadAttributes) == 0 { return } + + renderFuncString := "RenderScriptItems" + spreadParamString := "" + if len(spreadAttributes) > 0 { + renderFuncString = "RenderScriptItemsWithSpread" + spreadParamString = "[]templ.Attributes{" + strings.Join(spreadAttributes, ", ") + "}, " + } // Render the scripts before the element if required. // templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []Attributes, a, b, c) - if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{"+strings.Join(spreadAttributes, ", ")+"}, "+strings.Join(scriptExpressions, ", ")+")\n"); err != nil { + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_Err = templ."+renderFuncString+"(ctx, templ_7745c5c3_Buffer, "+spreadParamString+strings.Join(scriptExpressions, ", ")+")\n"); err != nil { return err } if err = g.writeErrorHandler(indentLevel); err != nil { diff --git a/generator/test-script-usage/template_templ.go b/generator/test-script-usage/template_templ.go index d84c5a85a..716f96d20 100644 --- a/generator/test-script-usage/template_templ.go +++ b/generator/test-script-usage/template_templ.go @@ -52,7 +52,7 @@ func Button(text string) templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{}, withParameters("test", text, 123), withoutParameters()) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, withParameters("test", text, 123), withoutParameters()) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -133,7 +133,7 @@ func ThreeButtons() templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{}, onClick()) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, onClick()) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -184,7 +184,7 @@ func Conditional(show bool) templ.Component { templ_7745c5c3_Var7 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{}, conditionalScript()) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, conditionalScript()) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/generator/test-spread-attributes/template_templ.go b/generator/test-spread-attributes/template_templ.go index 096a900de..9dbc1c493 100644 --- a/generator/test-spread-attributes/template_templ.go +++ b/generator/test-spread-attributes/template_templ.go @@ -26,7 +26,7 @@ func BasicTemplate(spread templ.Attributes) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{spread}) + templ_7745c5c3_Err = templ.RenderScriptItemsWithSpread(ctx, templ_7745c5c3_Buffer, []templ.Attributes{spread}) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -42,7 +42,7 @@ func BasicTemplate(spread templ.Attributes) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{spread}) + templ_7745c5c3_Err = templ.RenderScriptItemsWithSpread(ctx, templ_7745c5c3_Buffer, []templ.Attributes{spread}) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -60,7 +60,7 @@ func BasicTemplate(spread templ.Attributes) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, []templ.Attributes{spread}) + templ_7745c5c3_Err = templ.RenderScriptItemsWithSpread(ctx, templ_7745c5c3_Buffer, []templ.Attributes{spread}) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/runtime.go b/runtime.go index fd113495f..1289cb0e4 100644 --- a/runtime.go +++ b/runtime.go @@ -675,7 +675,7 @@ type ComponentScript struct { var _ Component = ComponentScript{} func (c ComponentScript) Render(ctx context.Context, w io.Writer) error { - err := RenderScriptItems(ctx, w, nil, c) + err := RenderScriptItems(ctx, w, c) if err != nil { return err } @@ -694,7 +694,13 @@ func (c ComponentScript) Render(ctx context.Context, w io.Writer) error { } // RenderScriptItems renders a + text -
+
text2
-
+
text3
diff --git a/generator/test-spread-attributes/render_test.go b/generator/test-spread-attributes/render_test.go index 398feeaf5..f98df5d54 100644 --- a/generator/test-spread-attributes/render_test.go +++ b/generator/test-spread-attributes/render_test.go @@ -37,6 +37,8 @@ func Test(t *testing.T) { "optional-from-func-false": func() bool { return false }, // Optional attribute based on result of func() bool. "optional-from-func-true": func() bool { return true }, + // Should render a - + text -
+
-
+ +
text3
diff --git a/generator/test-spread-attributes/render_test.go b/generator/test-spread-attributes/render_test.go index f98df5d54..275817ebe 100644 --- a/generator/test-spread-attributes/render_test.go +++ b/generator/test-spread-attributes/render_test.go @@ -12,34 +12,39 @@ import ( var expected string func Test(t *testing.T) { - component := BasicTemplate(templ.Attributes{ - // Should render as `bool` as the value is true, and the conditional render is also true. - "bool": templ.KV(true, true), - // Should not render, as the conditional render value is false. - "bool-disabled": templ.KV(true, false), - // Should render as `dateId="my-custom-id"`. - "dateId": "my-custom-id", - // Should render as `hx-get="/page"`. - "hx-get": "/page", - // Should render as `id="test"`. - "id": "test", - // Should not render, as the attribute value, and the conditional render value is false. - "no-bool": templ.KV(false, false), - // Should not render, as the conditional render value is false. - "no-text": templ.KV("empty", false), - // Should render as `nonshare`, as the value is true. - "nonshade": true, - // Should not render, as the value is false. - "shade": false, - // Should render text="lorem" as the value is true. - "text": templ.KV("lorem", true), - // Optional attribute based on result of func() bool. - "optional-from-func-false": func() bool { return false }, - // Optional attribute based on result of func() bool. - "optional-from-func-true": func() bool { return true }, - // Should render a