~repos /gromer

#golang#htmx#ssr

git clone https://pyrossh.dev/repos/gromer.git

gromer is a framework and cli to build multipage web apps in golang using htmx and alpinejs.


f2cc55aa Peter John

3 years ago
fix for in component
Files changed (3) hide show
  1. gsx/gsx.go +25 -26
  2. gsx/gsx_test.go +162 -147
  3. gsx/parser.go +1 -1
gsx/gsx.go CHANGED
@@ -228,7 +228,7 @@ func populate(c *Context, tags []*Tag) []*Tag {
228
228
 
229
229
  func populateTag(c *Context, tag *Tag) {
230
230
  if tag.Name == "" {
231
- if tag.Text.Ref != nil {
231
+ if tag.Text.Str == nil && tag.Text.Ref != nil {
232
232
  value := getRefValue(c, *tag.Text.Ref)
233
233
  children, ok := value.([]*Tag)
234
234
  if ok {
@@ -250,48 +250,47 @@ func populateTag(c *Context, tag *Tag) {
250
250
  compContext.data[loop.Index] = i
251
251
  compContext.data[loop.Key] = v.Index(i).Interface()
252
252
  newTags := populate(compContext, cloneTags(statement.Tags))
253
- for _, t := range newTags {
254
- tag.Children = append(tag.Children, t)
253
+ tag.Children = append(tag.Children, newTags...)
255
- }
256
254
  }
257
255
  }
258
256
  }
259
257
  } else {
260
258
  if comp, ok := compMap[tag.Name]; ok {
259
+ tag.Name = "fragment"
261
260
  if tag.SelfClosing {
262
261
  tag.SelfClosing = false
263
262
  }
264
- compContext := c.Clone(tag.Name)
263
+ compContext := c.Clone(comp.Name)
265
264
  nodes := comp.Render(compContext, tag)
266
265
  populate(compContext, tag.Children)
267
266
  compContext.Set("children", tag.Children)
267
+ populate(compContext, nodes)
268
268
  tag.Children = nodes
269
- populate(compContext, tag.Children)
270
269
  } else {
271
- populate(c, tag.Children)
270
+ for _, a := range tag.Attributes {
271
+ if a.Value.Str != nil {
272
+ if strings.Contains(*a.Value.Str, "{") {
273
+ subs := substituteString(c, removeQuotes(*a.Value.Str))
274
+ a.Value = &Literal{Str: &subs}
275
+ } else {
276
+ *a.Value.Str = removeQuotes(*a.Value.Str)
272
- }
277
+ }
273
- for _, a := range tag.Attributes {
274
- if a.Value.Str != nil {
278
+ } else if a.Value.Ref != nil {
275
- if strings.Contains(*a.Value.Str, "{") {
276
- subs := substituteString(c, removeQuotes(*a.Value.Str))
279
+ subs := substituteString(c, *a.Value.Ref)
277
280
  a.Value = &Literal{Str: &subs}
281
+ } else if a.Key == "class" && a.Value.KV != nil {
278
- } else {
282
+ classes := []string{}
283
+ for _, a := range a.Value.KV {
279
- *a.Value.Str = removeQuotes(*a.Value.Str)
284
+ varValue := getRefValue(c, a.Value)
285
+ if varValue.(bool) {
286
+ classes = append(classes, removeQuotes(a.Key))
280
- }
287
+ }
281
- } else if a.Value.Ref != nil {
282
- subs := substituteString(c, *a.Value.Ref)
283
- a.Value = &Literal{Str: &subs}
284
- } else if a.Key == "class" && a.Value.KV != nil {
285
- classes := []string{}
286
- for _, a := range a.Value.KV {
287
- varValue := getRefValue(c, a.Value)
288
- if varValue.(bool) {
289
- classes = append(classes, removeQuotes(a.Key))
290
288
  }
289
+ result := strings.Join(classes, " ")
290
+ a.Value.Str = &result
291
291
  }
292
- result := strings.Join(classes, " ")
293
- a.Value.Str = &result
294
292
  }
293
+ populate(c, tag.Children)
295
294
  }
296
295
  }
297
296
  }
gsx/gsx_test.go CHANGED
@@ -31,8 +31,12 @@ func Todo(c *Context, todo *TodoData) []*Tag {
31
31
 
32
32
  func TodoList(c *Context, todos []*TodoData) []*Tag {
33
33
  return c.Render(`
34
- <ul id="todo-list" class="relative" x-for="todo in todos">
34
+ <ul id="todo-list" class="relative">
35
+ for i, v := range todos {
36
+ return (
35
- <Todo />
37
+ <Todo todo={v}>
38
+ )
39
+ }
36
40
  </ul>
37
41
  `)
38
42
  }
@@ -71,54 +75,46 @@ func TestComponent(t *testing.T) {
71
75
  `)
72
76
  actual := RenderString(nodes)
73
77
  expected := trimLeft(`
74
- <Todo>
75
- <li id="todo-4" class="completed">
78
+ <li id="todo-4" class="completed">
76
- <div class="upper">
79
+ <div class="upper">
77
- <span>
78
- My fourth todo
79
- </span>
80
- <span>
81
- My fourth todo
82
- </span>
83
- </div>
84
80
  <span>
85
81
  My fourth todo
86
82
  </span>
83
+ <span>
84
+ My fourth todo
85
+ </span>
86
+ </div>
87
+ <nil>
88
+ <div class="bottom">
89
+ <span>
90
+ true
91
+ </span>
87
92
  <span>
88
93
  true
89
94
  </span>
95
+ </div>
96
+ </li>
90
97
 
98
+ <li id="todo-4" class="completed">
99
+ <div class="upper">
100
+ <span>
101
+ My fourth todo
102
+ </span>
103
+ <span>
104
+ My fourth todo
105
+ </span>
106
+ </div>
107
+ <nil>
91
- <div class="bottom">
108
+ <div class="bottom">
92
- <span>
109
+ <span>
93
- true
110
+ true
94
- </span>
111
+ </span>
95
- <span>
112
+ <span>
96
- true
113
+ true
97
- </span>
114
+ </span>
98
- </div>
115
+ </div>
99
- </li>
116
+ </li>
100
- </Todo>
101
- <Todo>
102
- <li id="todo-4" class="completed">
103
- <div class="upper">
104
- <span>
105
- My fourth todo
106
- </span>
107
- <span>
108
- My fourth todo
109
- </span>
110
- </div>
111
117
 
112
- <div class="bottom">
113
- <span>
114
- true
115
- </span>
116
- <span>
117
- true
118
- </span>
119
- </div>
120
- </li>
121
- </Todo>
122
118
  `)
123
119
  r.Equal(expected, actual)
124
120
  }
@@ -139,35 +135,33 @@ func TestMultipleComponent(t *testing.T) {
139
135
  `)
140
136
  actual := RenderString(nodes)
141
137
  expected := trimLeft(`
142
- <Todo>
143
- <li id="todo-4" class="completed">
138
+ <li id="todo-4" class="completed">
144
- <div class="upper">
139
+ <div class="upper">
145
- <span>
140
+ <span>
146
- My fourth todo
141
+ My fourth todo
147
- </span>
142
+ </span>
148
- <span>
143
+ <span>
149
- My fourth todo
144
+ My fourth todo
150
- </span>
145
+ </span>
151
- </div>
146
+ </div>
147
+ <nil>
148
+ <div class="bottom">
149
+ <span>
150
+ true
151
+ </span>
152
+ <span>
153
+ true
154
+ </span>
155
+ </div>
156
+ </li>
157
+
158
+ <span id="todo-count" class="todo-count" hx-swap-oob="true">
159
+ <strong>
160
+ 10
161
+ </strong>
162
+ item left
163
+ </span>
152
164
 
153
- <div class="bottom">
154
- <span>
155
- true
156
- </span>
157
- <span>
158
- true
159
- </span>
160
- </div>
161
- </li>
162
- </Todo>
163
- <TodoCount>
164
- <span id="todo-count" class="todo-count" hx-swap-oob="true">
165
- <strong>
166
- 10
167
- </strong>
168
- item left
169
- </span>
170
- </TodoCount>
171
165
  `)
172
166
  r.Equal(expected, actual)
173
167
  }
@@ -252,7 +246,95 @@ func TestFor(t *testing.T) {
252
246
 
253
247
  </ul>
254
248
  <ol>
249
+ <li id="todo-1" class="completed">
250
+ <div class="upper">
251
+ <span>
252
+ My first todo
253
+ </span>
254
+ <span>
255
+ My first todo
256
+ </span>
257
+ </div>
258
+ <nil>
259
+ <div class="bottom">
260
+ <span>
261
+ true
262
+ </span>
263
+ <span>
264
+ true
265
+ </span>
266
+ </div>
267
+ </li>
268
+
255
- <Todo todo="v">
269
+ <li id="todo-2">
270
+ <div class="upper">
271
+ <span>
272
+ My second todo
273
+ </span>
274
+ <span>
275
+ My second todo
276
+ </span>
277
+ </div>
278
+ <nil>
279
+ <div class="bottom">
280
+ <span>
281
+ false
282
+ </span>
283
+ <span>
284
+ false
285
+ </span>
286
+ </div>
287
+ </li>
288
+
289
+ <li id="todo-3">
290
+ <div class="upper">
291
+ <span>
292
+ My third todo
293
+ </span>
294
+ <span>
295
+ My third todo
296
+ </span>
297
+ </div>
298
+ <nil>
299
+ <div class="bottom">
300
+ <span>
301
+ false
302
+ </span>
303
+ <span>
304
+ false
305
+ </span>
306
+ </div>
307
+ </li>
308
+
309
+
310
+ </ol>
311
+ `)
312
+ r.Equal(expected, actual)
313
+ }
314
+
315
+ func TestForComponent(t *testing.T) {
316
+ r := require.New(t)
317
+ RegisterComponent(Todo, nil, "todo")
318
+ RegisterComponent(TodoList, nil, "todos")
319
+ RegisterFunc(WebsiteName)
320
+ h := Context{
321
+ data: map[string]interface{}{
322
+ "todos": []*TodoData{
323
+ {ID: "1", Text: "My first todo", Completed: true},
324
+ {ID: "2", Text: "My second todo", Completed: false},
325
+ {ID: "3", Text: "My third todo", Completed: false},
326
+ },
327
+ },
328
+ }
329
+ nodes := h.Render(`
330
+ <div>
331
+ <TodoList />
332
+ </div>
333
+ `)
334
+ actual := RenderString(nodes)
335
+ expected := trimLeft(`
336
+ <div>
337
+ <ul id="todo-list" class="relative">
256
338
  <li id="todo-1" class="completed">
257
339
  <div class="upper">
258
340
  <span>
@@ -262,15 +344,7 @@ func TestFor(t *testing.T) {
262
344
  My first todo
263
345
  </span>
264
346
  </div>
265
- <div class="todo-panel">
266
- <span>
347
+ <nil>
267
- My first todo
268
- </span>
269
- <span>
270
- true
271
- </span>
272
- </div>
273
-
274
348
  <div class="bottom">
275
349
  <span>
276
350
  true
@@ -280,8 +354,7 @@ func TestFor(t *testing.T) {
280
354
  </span>
281
355
  </div>
282
356
  </li>
283
- </Todo>
357
+
284
- <Todo todo="v">
285
358
  <li id="todo-2">
286
359
  <div class="upper">
287
360
  <span>
@@ -291,15 +364,7 @@ func TestFor(t *testing.T) {
291
364
  My second todo
292
365
  </span>
293
366
  </div>
294
- <div class="todo-panel">
295
- <span>
367
+ <nil>
296
- My second todo
297
- </span>
298
- <span>
299
- false
300
- </span>
301
- </div>
302
-
303
368
  <div class="bottom">
304
369
  <span>
305
370
  false
@@ -309,8 +374,7 @@ func TestFor(t *testing.T) {
309
374
  </span>
310
375
  </div>
311
376
  </li>
312
- </Todo>
377
+
313
- <Todo todo="v">
314
378
  <li id="todo-3">
315
379
  <div class="upper">
316
380
  <span>
@@ -320,15 +384,7 @@ func TestFor(t *testing.T) {
320
384
  My third todo
321
385
  </span>
322
386
  </div>
323
- <div class="todo-panel">
324
- <span>
387
+ <nil>
325
- My third todo
326
- </span>
327
- <span>
328
- false
329
- </span>
330
- </div>
331
-
332
388
  <div class="bottom">
333
389
  <span>
334
390
  false
@@ -338,52 +394,11 @@ func TestFor(t *testing.T) {
338
394
  </span>
339
395
  </div>
340
396
  </li>
341
- </Todo>
342
397
 
398
+
343
- </ol>
399
+ </ul>
400
+
401
+ </div>
344
402
  `)
345
403
  r.Equal(expected, actual)
346
404
  }
347
-
348
- // func TestForComponent(t *testing.T) {
349
- // r := require.New(t)
350
- // RegisterComponent(Todo, nil, "todo")
351
- // RegisterComponent(TodoList, nil, "todos")
352
- // RegisterFunc(WebsiteName)
353
- // h := Context{
354
- // data: map[string]interface{}{
355
- // "todos": []*TodoData{
356
- // {ID: "1", Text: "My first todo", Completed: true},
357
- // {ID: "2", Text: "My second todo", Completed: false},
358
- // {ID: "3", Text: "My third todo", Completed: false},
359
- // },
360
- // },
361
- // }
362
- // actual := h.Render(`
363
- // <div>
364
- // <TodoList />
365
- // </div>
366
- // `).String()
367
- // expected := stripWhitespace(`
368
- // <div>
369
- // <ul id="todo-list" class="relative" x-for="todo in todos">
370
- // <li id="todo-1" class="completed">
371
- // <div class="view"><span>My first todo</span><span>My first todo</span></div>
372
- // <div class="todo-panel"><span>My first todo</span><span>true</span></div>
373
- // <div class="count"><span>true</span><span>true</span></div>
374
- // </li>
375
- // <li id="todo-2" class="">
376
- // <div class="view"><span>My second todo</span><span>My second todo</span></div>
377
- // <div class="todo-panel"><span>My second todo</span><span>false</span></div>
378
- // <div class="count"><span>false</span><span>false</span></div>
379
- // </li>
380
- // <li id="todo-3" class="">
381
- // <div class="view"><span>My third todo</span><span>My third todo</span></div>
382
- // <div class="todo-panel"><span>My third todo</span><span>false</span></div>
383
- // <div class="count"><span>false</span><span>false</span></div>
384
- // </li>
385
- // </ul>
386
- // </div>
387
- // `)
388
- // r.Equal(expected, actual)
389
- // }
gsx/parser.go CHANGED
@@ -205,7 +205,7 @@ func processTree(nodes []*AstNode) []*Tag {
205
205
  if n.Close.Name == prevTag.Name {
206
206
  prevTag, _ = stack.Pop()
207
207
  } else {
208
- panic(fmt.Errorf("Brackets not matching in line %d:%d", n.Close.Pos.Line, n.Close.Pos.Column))
208
+ panic(fmt.Errorf("Brackets not matching for tag %s in line %d:%d, prevTag: %s", n.Close.Name, n.Close.Pos.Line, n.Close.Pos.Column, prevTag.Name))
209
209
  }
210
210
  } else if n.Content != nil {
211
211
  newTag := &Tag{