Skip to content

Commit 9a7ddd6

Browse files
committed
Fix gen file creation for structured templates
1 parent 7a86d69 commit 9a7ddd6

2 files changed

Lines changed: 106 additions & 2 deletions

File tree

internal/app/dev/appdev.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"fmt"
1111
"io"
1212
"net/http"
13+
"path"
1314
"slices"
1415
"strings"
1516

@@ -212,9 +213,39 @@ func (a *AppDev) GenerateHTML() error {
212213
}
213214
}
214215

215-
openrunGenData, err := a.sourceFS.ReadFile(apptype.CLACE_GEN_FILE)
216+
// When the app has base templates (structured mode), the base template set
217+
// is parsed only from the base_templates folder, so the generated file must
218+
// live there for its definitions to be usable from the base and page
219+
// templates. Otherwise it lives at the app root, where the unstructured
220+
// template glob picks it up. The mode check ignores the generated file
221+
// itself, so a leftover copy in base_templates does not keep the app in
222+
// structured mode; the copy at the location for the other mode is removed.
223+
baseDir := "base_templates"
224+
if a.Config.Routing.BaseTemplates != "" {
225+
baseDir = a.Config.Routing.BaseTemplates
226+
}
227+
baseGenFile := path.Join(baseDir, apptype.CLACE_GEN_FILE)
228+
baseFiles, err := a.sourceFS.Glob(path.Join(baseDir, "*.go.html"))
229+
if err != nil {
230+
return err
231+
}
232+
structured := slices.ContainsFunc(baseFiles, func(file string) bool {
233+
return file != baseGenFile
234+
})
235+
236+
genFile, staleGenFile := apptype.CLACE_GEN_FILE, baseGenFile
237+
if structured {
238+
genFile, staleGenFile = baseGenFile, apptype.CLACE_GEN_FILE
239+
}
240+
241+
openrunGenData, err := a.sourceFS.ReadFile(genFile)
216242
if err != nil || !bytes.Equal(openrunGenData, openrunGenEmbed) {
217-
if err := a.sourceFS.Write(apptype.CLACE_GEN_FILE, openrunGenEmbed); err != nil {
243+
if err := a.sourceFS.Write(genFile, openrunGenEmbed); err != nil {
244+
return err
245+
}
246+
}
247+
if _, err := a.sourceFS.Stat(staleGenFile); err == nil {
248+
if err := a.sourceFS.Remove(staleGenFile); err != nil {
218249
return err
219250
}
220251
}

internal/app/tests/tmpl_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,76 @@ def handler(req):
132132
testutil.AssertEqualsInt(t, "code", 200, response.Code)
133133
testutil.AssertEqualsString(t, "body", "frag respvalue", response.Body.String())
134134
}
135+
136+
func TestBaseTemplateDevGenFile(t *testing.T) {
137+
// In dev mode with base templates (structured mode), the generated
138+
// openrun_gen.go.html must be written into the base_templates folder (the
139+
// base template set is parsed only from there), so base templates can use
140+
// the openrun_gen_import block. No copy should be left at the app root.
141+
logger := testutil.TestLogger()
142+
fileData := map[string]string{
143+
"app.star": `
144+
app = ace.app("testApp", custom_layout=True, routes = [ace.html("/")])
145+
146+
def handler(req):
147+
return {"key": "myvalue"}`,
148+
"index.go.html": `ABC {{.Data.key}} {{- template "base" . -}}`,
149+
"base_templates/aaa.go.html": `{{define "base"}} aaa{{template "openrun_gen_import" .}}{{end}}`,
150+
}
151+
a, _, err := CreateDevModeTestApp(logger, fileData)
152+
if err != nil {
153+
t.Fatalf("Error %s", err)
154+
}
155+
156+
if _, ok := fileData["base_templates/openrun_gen.go.html"]; !ok {
157+
t.Fatal("openrun_gen.go.html was not generated in the base_templates folder")
158+
}
159+
if _, ok := fileData["openrun_gen.go.html"]; ok {
160+
t.Fatal("openrun_gen.go.html was left at the app root in base templates mode")
161+
}
162+
163+
request := httptest.NewRequest("GET", "/test", nil)
164+
response := httptest.NewRecorder()
165+
a.ServeHTTP(response, request)
166+
167+
testutil.AssertEqualsInt(t, "code", 200, response.Code)
168+
testutil.AssertStringContains(t, response.Body.String(), "ABC myvalue aaa")
169+
// The import block emits the htmx script and the dev live-reload listener
170+
testutil.AssertStringContains(t, response.Body.String(), "htmx")
171+
testutil.AssertStringContains(t, response.Body.String(), "cl_reload_listener")
172+
}
173+
174+
func TestUnstructuredDevGenFileCleanup(t *testing.T) {
175+
// Without base templates (unstructured mode), the generated file stays at
176+
// the app root; a stale generated copy inside base_templates (e.g. left
177+
// over after the app's base templates were removed) is cleaned up and does
178+
// not force the app into structured mode.
179+
logger := testutil.TestLogger()
180+
fileData := map[string]string{
181+
"app.star": `
182+
app = ace.app("testApp", custom_layout=True, routes = [ace.html("/")])
183+
184+
def handler(req):
185+
return {"key": "myvalue"}`,
186+
"index.go.html": `ABC {{.Data.key}} {{- template "openrun_gen_import" . -}}`,
187+
"base_templates/openrun_gen.go.html": `stale generated copy`,
188+
}
189+
a, _, err := CreateDevModeTestApp(logger, fileData)
190+
if err != nil {
191+
t.Fatalf("Error %s", err)
192+
}
193+
194+
if _, ok := fileData["openrun_gen.go.html"]; !ok {
195+
t.Fatal("openrun_gen.go.html was not generated at the app root")
196+
}
197+
if _, ok := fileData["base_templates/openrun_gen.go.html"]; ok {
198+
t.Fatal("stale openrun_gen.go.html was not removed from base_templates")
199+
}
200+
201+
request := httptest.NewRequest("GET", "/test", nil)
202+
response := httptest.NewRecorder()
203+
a.ServeHTTP(response, request)
204+
205+
testutil.AssertEqualsInt(t, "code", 200, response.Code)
206+
testutil.AssertStringContains(t, response.Body.String(), "ABC myvalue")
207+
}

0 commit comments

Comments
 (0)