Skip to content

Commit

Permalink
feat: fmt: Go format expression attributes
Browse files Browse the repository at this point in the history
Co-authored-by: Adrian Hesketh <[email protected]>
  • Loading branch information
gungun974 and a-h authored Nov 6, 2023
1 parent 519f570 commit ceb6f14
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 27 deletions.
104 changes: 77 additions & 27 deletions parser/v2/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package parser

import (
"bytes"
"errors"
"fmt"
"go/format"
Expand Down Expand Up @@ -155,16 +156,21 @@ func (exp GoExpression) Write(w io.Writer, indent int) error {
if err != nil {
return writeIndent(w, indent, exp.Expression.Value)
}

_, err = w.Write(data)
return err
}

func writeIndent(w io.Writer, level int, s string) (err error) {
if _, err = w.Write([]byte(strings.Repeat("\t", level))); err != nil {
return
func writeIndent(w io.Writer, level int, s ...string) (err error) {
indent := strings.Repeat("\t", level)
if _, err = io.WriteString(w, indent); err != nil {
return err
}
for _, ss := range s {
_, err = io.WriteString(w, ss)
if err != nil {
return
}
}
_, err = w.Write([]byte(s))
return
}

Expand Down Expand Up @@ -216,7 +222,7 @@ type CSSTemplate struct {

func (css CSSTemplate) IsTemplateFileNode() bool { return true }
func (css CSSTemplate) Write(w io.Writer, indent int) error {
if err := writeIndent(w, indent, "css "+css.Name.Value+"() {\n"); err != nil {
if err := writeIndent(w, indent, "css ", css.Name.Value, "() {\n"); err != nil {
return err
}
for _, p := range css.Properties {
Expand Down Expand Up @@ -273,7 +279,7 @@ type ExpressionCSSProperty struct {

func (c ExpressionCSSProperty) IsCSSProperty() bool { return true }
func (c ExpressionCSSProperty) Write(w io.Writer, indent int) error {
if err := writeIndent(w, indent, c.Name+": "); err != nil {
if err := writeIndent(w, indent, c.Name, ": "); err != nil {
return err
}
if err := c.Value.Write(w, 0); err != nil {
Expand All @@ -292,7 +298,7 @@ type DocType struct {

func (dt DocType) IsNode() bool { return true }
func (dt DocType) Write(w io.Writer, indent int) error {
return writeIndent(w, indent, "<!DOCTYPE "+dt.Value+">")
return writeIndent(w, indent, "<!DOCTYPE ", dt.Value, ">")
}

// HTMLTemplate definition.
Expand All @@ -310,7 +316,7 @@ type HTMLTemplate struct {
func (t HTMLTemplate) IsTemplateFileNode() bool { return true }

func (t HTMLTemplate) Write(w io.Writer, indent int) error {
if err := writeIndent(w, indent, "templ "+t.Expression.Value+" {\n"); err != nil {
if err := writeIndent(w, indent, "templ ", t.Expression.Value, " {\n"); err != nil {
return err
}
if err := writeNodesIndented(w, indent+1, t.Children); err != nil {
Expand Down Expand Up @@ -462,7 +468,7 @@ func containsNonTextNodes(nodes []Node) bool {

func (e Element) IsNode() bool { return true }
func (e Element) Write(w io.Writer, indent int) error {
if err := writeIndent(w, indent, "<"+e.Name); err != nil {
if err := writeIndent(w, indent, "<", e.Name); err != nil {
return err
}
for i := 0; i < len(e.Attributes); i++ {
Expand Down Expand Up @@ -497,7 +503,7 @@ func (e Element) Write(w io.Writer, indent int) error {
if err := writeNodesIndented(w, indent+1, e.Children); err != nil {
return err
}
if err := writeIndent(w, indent, "</"+e.Name+">"); err != nil {
if err := writeIndent(w, indent, "</", e.Name, ">"); err != nil {
return err
}
return nil
Expand All @@ -519,7 +525,7 @@ func (e Element) Write(w io.Writer, indent int) error {
}
return nil
}
if err := writeIndent(w, closeAngleBracketIndent, "></"+e.Name+">"); err != nil {
if err := writeIndent(w, closeAngleBracketIndent, "></", e.Name, ">"); err != nil {
return err
}
return nil
Expand Down Expand Up @@ -607,7 +613,7 @@ type RawElement struct {
func (e RawElement) IsNode() bool { return true }
func (e RawElement) Write(w io.Writer, indent int) error {
// Start.
if err := writeIndent(w, indent, "<"+e.Name); err != nil {
if err := writeIndent(w, indent, "<", e.Name); err != nil {
return err
}
for i := 0; i < len(e.Attributes); i++ {
Expand Down Expand Up @@ -687,11 +693,55 @@ type ExpressionAttribute struct {
}

func (ea ExpressionAttribute) String() string {
return ea.Name + `={ ` + ea.Expression.Value + ` }`
sb := new(strings.Builder)
ea.Write(sb, 0)
return sb.String()
}

func (ea ExpressionAttribute) Write(w io.Writer, indent int) error {
return writeIndent(w, indent, ea.String())
func (ea ExpressionAttribute) formatExpression() (exp []string) {
trimmed := strings.TrimSpace(ea.Expression.Value)
if !strings.Contains(trimmed, "\n") {
formatted, err := format.Source([]byte(trimmed))
if err != nil {
return []string{trimmed}
}
return []string{string(formatted)}
}

buf := bytes.NewBufferString("[]any{\n")
buf.WriteString(trimmed)
buf.WriteString("\n}")

formatted, err := format.Source(buf.Bytes())
if err != nil {
return []string{trimmed}
}

// Trim prefix and suffix.
lines := strings.Split(string(formatted), "\n")
if len(lines) < 3 {
return []string{trimmed}
}

// Return.
return lines[1 : len(lines)-1]
}

func (ea ExpressionAttribute) Write(w io.Writer, indent int) (err error) {
lines := ea.formatExpression()
if len(lines) == 1 {
return writeIndent(w, indent, ea.Name, `={ `, lines[0], ` }`)
}

if err = writeIndent(w, indent, ea.Name, "={\n"); err != nil {
return err
}
for _, line := range lines {
if err = writeIndent(w, indent, line, "\n"); err != nil {
return err
}
}
return writeIndent(w, indent, "}")
}

// <a href="test" \
Expand Down Expand Up @@ -769,9 +819,9 @@ type GoComment struct {
func (c GoComment) IsNode() bool { return true }
func (c GoComment) Write(w io.Writer, indent int) error {
if c.Multiline {
return writeIndent(w, indent, "/*"+c.Contents+"*/")
return writeIndent(w, indent, "/*", c.Contents, "*/")
}
return writeIndent(w, indent, "//"+c.Contents)
return writeIndent(w, indent, "//", c.Contents)
}

// HTMLComment.
Expand All @@ -781,7 +831,7 @@ type HTMLComment struct {

func (c HTMLComment) IsNode() bool { return true }
func (c HTMLComment) Write(w io.Writer, indent int) error {
return writeIndent(w, indent, "<!--"+c.Contents+"-->")
return writeIndent(w, indent, "<!--", c.Contents, "-->")
}

// Nodes.
Expand All @@ -797,7 +847,7 @@ type CallTemplateExpression struct {

func (cte CallTemplateExpression) IsNode() bool { return true }
func (cte CallTemplateExpression) Write(w io.Writer, indent int) error {
return writeIndent(w, indent, `{! `+cte.Expression.Value+` }`)
return writeIndent(w, indent, `{! `, cte.Expression.Value, ` }`)
}

// TemplElementExpression can be used to create and render a template using data.
Expand Down Expand Up @@ -856,7 +906,7 @@ type ElseIfExpression struct {

func (n IfExpression) IsNode() bool { return true }
func (n IfExpression) Write(w io.Writer, indent int) error {
if err := writeIndent(w, indent, "if "+n.Expression.Value+" {\n"); err != nil {
if err := writeIndent(w, indent, "if ", n.Expression.Value, " {\n"); err != nil {
return err
}
indent++
Expand All @@ -865,7 +915,7 @@ func (n IfExpression) Write(w io.Writer, indent int) error {
}
indent--
for _, elseIf := range n.ElseIfs {
if err := writeIndent(w, indent, "} else if "+elseIf.Expression.Value+" {\n"); err != nil {
if err := writeIndent(w, indent, "} else if ", elseIf.Expression.Value, " {\n"); err != nil {
return err
}
indent++
Expand Down Expand Up @@ -898,13 +948,13 @@ type SwitchExpression struct {

func (se SwitchExpression) IsNode() bool { return true }
func (se SwitchExpression) Write(w io.Writer, indent int) error {
if err := writeIndent(w, indent, "switch "+se.Expression.Value+" {\n"); err != nil {
if err := writeIndent(w, indent, "switch ", se.Expression.Value, " {\n"); err != nil {
return err
}
indent++
for i := 0; i < len(se.Cases); i++ {
c := se.Cases[i]
if err := writeIndent(w, indent, c.Expression.Value+"\n"); err != nil {
if err := writeIndent(w, indent, c.Expression.Value, "\n"); err != nil {
return err
}
if err := writeNodesIndented(w, indent+1, c.Children); err != nil {
Expand Down Expand Up @@ -934,7 +984,7 @@ type ForExpression struct {

func (fe ForExpression) IsNode() bool { return true }
func (fe ForExpression) Write(w io.Writer, indent int) error {
if err := writeIndent(w, indent, "for "+fe.Expression.Value+" {\n"); err != nil {
if err := writeIndent(w, indent, "for ", fe.Expression.Value, " {\n"); err != nil {
return err
}
if err := writeNodesIndented(w, indent+1, fe.Children); err != nil {
Expand All @@ -961,7 +1011,7 @@ func (se StringExpression) Trailing() TrailingSpace {
func (se StringExpression) IsNode() bool { return true }
func (se StringExpression) IsStyleDeclarationValue() bool { return true }
func (se StringExpression) Write(w io.Writer, indent int) error {
return writeIndent(w, indent, `{ `+se.Expression.Value+` }`)
return writeIndent(w, indent, `{ `, se.Expression.Value, ` }`)
}

// ScriptTemplate is a script block.
Expand All @@ -973,7 +1023,7 @@ type ScriptTemplate struct {

func (s ScriptTemplate) IsTemplateFileNode() bool { return true }
func (s ScriptTemplate) Write(w io.Writer, indent int) error {
if err := writeIndent(w, indent, "script "+s.Name.Value+"("+s.Parameters.Value+") {\n"); err != nil {
if err := writeIndent(w, indent, "script ", s.Name.Value, "(", s.Parameters.Value, ") {\n"); err != nil {
return err
}
if _, err := io.WriteString(w, s.Value); err != nil {
Expand Down
39 changes: 39 additions & 0 deletions parser/v2/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,45 @@ templ x() {
</a>
</li>
}
`,
},
{
name: "templ expression attribute are formatted correctly when multiline",
input: ` // first line removed to make indentation clear
package main
templ x(id string, class string) {
<button
id={id}
name={
"name"
}
class={
"blue",
class,
map[string]bool{
"a": true,
},
}
></button>
}
`,
expected: ` // first line removed to make indentation clear
package main
templ x(id string, class string) {
<button
id={ id }
name={ "name" }
class={
"blue",
class,
map[string]bool{
"a": true,
},
}
></button>
}
`,
},
{
Expand Down

0 comments on commit ceb6f14

Please sign in to comment.