gitstack

grindlemire/go-tui code browser

2.6 KB Go 132 lines 2026-06-12 · 21be938 raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package formatter

import (
	"testing"
)

// TestFormatElementAttributesCoverage exercises attribute value printing
// (int, float, bool literals), key={...} extraction in single-line and
// multi-line attribute layouts, and inline-children fallbacks.
func TestFormatElementAttributesCoverage(t *testing.T) {
	type tc struct {
		input string
		want  string
	}

	tests := map[string]tc{
		"literal attribute values normalized to braced form": {
			input: `package main

templ A() {
<div width=10 flexGrow=1.5 disabled=false focusable>hi</div>
}
`,
			want: `package main

templ A() {
	<div width={10} flexGrow={1.5} disabled={false} focusable={true}>hi</div>
}
`,
		},
		"key attribute single line": {
			input: `package main

templ A(items []string) {
for i, it := range items {
<span key={i} class="p-1">{it}</span>
}
}
`,
			want: `package main

templ A(items []string) {
	for i, it := range items {
		<span key={i} class="p-1">{it}</span>
	}
}
`,
		},
		"key attribute multi line": {
			input: `package main

templ A(items []string) {
for i, it := range items {
<div
key={i}
class="p-1">{it}</div>
}
}
`,
			want: `package main

templ A(items []string) {
	for i, it := range items {
		<div
			key={i}
			class="p-1">{it}</div>
	}
}
`,
		},
		"element child forces multi-line": {
			input: `package main

templ A() {
<div><span>a</span></div>
}
`,
			want: `package main

templ A() {
	<div>
		<span>a</span>
	</div>
}
`,
		},
		"go expression with newline forces multi-line": {
			input: "package main\n\ntempl A() {\n<span>{fmt.Sprintf(\n\"x\")}</span>\n}\n",
			want:  "package main\n\ntempl A() {\n\t<span>\n\t\t{fmt.Sprintf(\n\"x\")}\n\t</span>\n}\n",
		},
		"raw string child preserved": {
			input: "package main\n\ntempl A() {\n<span>{fn(`raw /* x */ string`)}</span>\n}\n",
			want:  "package main\n\ntempl A() {\n\t<span>{fn(`raw /* x */ string`)}</span>\n}\n",
		},
		"escaped quote in expression preserved": {
			input: `package main

templ A() {
<span>{fmt.Sprintf("a\"b /* not comment */")}</span>
}
`,
			want: `package main

templ A() {
	<span>{fmt.Sprintf("a\"b /* not comment */")}</span>
}
`,
		},
	}

	for name, tt := range tests {
		t.Run(name, func(t *testing.T) {
			fmtr := newTestFormatter()
			got, err := fmtr.Format("test.gsx", tt.input)
			if err != nil {
				t.Fatalf("Format() error = %v", err)
			}
			if got != tt.want {
				t.Errorf("Format() mismatch:\ngot:\n%s\nwant:\n%s", got, tt.want)
			}

			// Formatting must be idempotent.
			again, err := fmtr.Format("test.gsx", got)
			if err != nil {
				t.Fatalf("second Format() error = %v", err)
			}
			if again != got {
				t.Errorf("Format() not idempotent:\nfirst:\n%s\nsecond:\n%s", got, again)
			}
		})
	}
}