From 2b9a65dcca399a8efda56ab45d4cbc7eebd6e82e Mon Sep 17 00:00:00 2001 From: Alex Dunmow Date: Sat, 4 Jul 2026 14:36:02 +0800 Subject: [PATCH] Revert "feat(pongo): non-panicking Engine compile variants + global 'lines' filter (WO-WZ-021)" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Core-dissolution direction (Captain's ruling, WO-WZ-026/027): host-side machinery must not grow in core — the engine additions now live in cms as backend/plugin/pongoengine (absorbed copy). Tag v0.19.1 still points at the reverted commit; nothing consumes it. The v0.19.0 codeless BUILDER keys stay: the ninja CLI lives here until WO-WZ-023 moves it into cms. This reverts commit 630dfc7dd1cd35b46482d81904f77dbbcb01c885. Co-Authored-By: Claude Fable 5 --- templates/pongo/engine.go | 50 ++++---------------------- templates/pongo/engine_test.go | 66 ---------------------------------- templates/pongo/filters.go | 35 ------------------ 3 files changed, 6 insertions(+), 145 deletions(-) delete mode 100644 templates/pongo/engine_test.go delete mode 100644 templates/pongo/filters.go diff --git a/templates/pongo/engine.go b/templates/pongo/engine.go index eaee220..bf71a23 100644 --- a/templates/pongo/engine.go +++ b/templates/pongo/engine.go @@ -62,25 +62,11 @@ func (c *pongoComponent) Render(ctx context.Context, w io.Writer) error { // {{ site_settings }} — bn.SiteSettingsData struct // {{ page_meta }} — bn.PageMeta struct func (e *Engine) MustPageTemplate(name string) templates.TemplateFunc { - fn, err := e.PageTemplate(name) - if err != nil { - panic(err) - } - return fn -} - -// PageTemplate is MustPageTemplate without the panic — for hosts compiling -// artifact-supplied templates at load time (a malformed artifact must fail -// the load, not the process). -func (e *Engine) PageTemplate(name string) (templates.TemplateFunc, error) { - tpl, err := e.set.FromFile(name) - if err != nil { - return nil, err - } + tpl := pongo2.Must(e.set.FromFile(name)) return func(ctx context.Context, doc map[string]any) templates.HTMLComponent { pongoCtx := e.buildPageContext(ctx, doc) return &pongoComponent{tpl: tpl, ctx: pongoCtx} - }, nil + } } // MustBlockTemplate parses a pongo2 block template and returns a BlockFunc. @@ -89,19 +75,7 @@ func (e *Engine) PageTemplate(name string) (templates.TemplateFunc, error) { // The content map fields are available directly as template variables. // Request context is available under {{ ctx.url }}, {{ ctx.isEditor }}, etc. func (e *Engine) MustBlockTemplate(name string) blocks.BlockFunc { - fn, err := e.BlockTemplate(name) - if err != nil { - panic(err) - } - return fn -} - -// BlockTemplate is MustBlockTemplate without the panic (see PageTemplate). -func (e *Engine) BlockTemplate(name string) (blocks.BlockFunc, error) { - tpl, err := e.set.FromFile(name) - if err != nil { - return nil, err - } + tpl := pongo2.Must(e.set.FromFile(name)) return func(ctx context.Context, content map[string]any) string { pongoCtx := buildBlockContext(ctx, content) out, err := tpl.Execute(pongoCtx) @@ -109,7 +83,7 @@ func (e *Engine) BlockTemplate(name string) (blocks.BlockFunc, error) { return "" } return blocks.ProcessIcons(out) - }, nil + } } // MustBlockTemplateWithDefaults is like MustBlockTemplate but merges default @@ -155,19 +129,7 @@ func (e *Engine) MustTemplateOverride(name string) blocks.BlockFunc { // {{ colors.muted }} — muted hex color // (and all other EmailColors fields as lowercase keys) func (e *Engine) MustEmailWrapper(name string) templates.EmailWrapperFunc { - fn, err := e.EmailWrapper(name) - if err != nil { - panic(err) - } - return fn -} - -// EmailWrapper is MustEmailWrapper without the panic (see PageTemplate). -func (e *Engine) EmailWrapper(name string) (templates.EmailWrapperFunc, error) { - tpl, err := e.set.FromFile(name) - if err != nil { - return nil, err - } + tpl := pongo2.Must(e.set.FromFile(name)) return func(body string, ctx templates.EmailContext) string { pongoCtx := pongo2.Context{ "body": body, @@ -196,7 +158,7 @@ func (e *Engine) EmailWrapper(name string) (templates.EmailWrapperFunc, error) { return body } return out - }, nil + } } // renderComponent renders any HTMLComponent to a string. diff --git a/templates/pongo/engine_test.go b/templates/pongo/engine_test.go deleted file mode 100644 index 67d4ee5..0000000 --- a/templates/pongo/engine_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package pongo - -import ( - "strings" - "testing" - "testing/fstest" - - "git.dev.alexdunmow.com/block/core/templates" -) - -func TestNonPanickingCompileVariants(t *testing.T) { - fsys := fstest.MapFS{ - "templates/theme/default.ninjatpl": {Data: []byte(`
{{ slots.main|safe }}
`)}, - "templates/overrides/theme/heading.ninjatpl": {Data: []byte(`

{{ text }}

`)}, - "templates/email/theme.ninjatpl": {Data: []byte(`{{ body|safe }} {{ colors.mutedForeground }}
`)}, - "templates/broken.ninjatpl": {Data: []byte(`{% if %}`)}, - } - e := NewEngine(fsys) - - if _, err := e.PageTemplate("templates/theme/default.ninjatpl"); err != nil { - t.Fatalf("PageTemplate: %v", err) - } - bf, err := e.BlockTemplate("templates/overrides/theme/heading.ninjatpl") - if err != nil { - t.Fatalf("BlockTemplate: %v", err) - } - if got := bf(t.Context(), map[string]any{"text": "hi"}); got != "

hi

" { - t.Errorf("override render = %q", got) - } - ef, err := e.EmailWrapper("templates/email/theme.ninjatpl") - if err != nil { - t.Fatalf("EmailWrapper: %v", err) - } - ectx := templates.EmailContext{} - ectx.Colors.MutedForeground = "#6c5b35" - if got := ef("

x

", ectx); got != "

x

#6c5b35
" { - t.Errorf("email render = %q", got) - } - - // Malformed templates return errors — no panic (hot-install safety). - if _, err := e.PageTemplate("templates/broken.ninjatpl"); err == nil { - t.Error("PageTemplate on broken template: want error") - } - if _, err := e.BlockTemplate("templates/missing.ninjatpl"); err == nil { - t.Error("BlockTemplate on missing file: want error") - } -} - -func TestLinesFilter(t *testing.T) { - fsys := fstest.MapFS{ - "t.ninjatpl": {Data: []byte(`{% for l in address|lines %}
{{ l }}
{% endfor %}`)}, - } - e := NewEngine(fsys) - bf, err := e.BlockTemplate("t.ninjatpl") - if err != nil { - t.Fatal(err) - } - got := bf(t.Context(), map[string]any{"address": "1 Meridian Plaza\r\n Floor 2 \n\nNew Gotham"}) - want := "
1 Meridian Plaza
Floor 2
New Gotham
" - if got != want { - t.Errorf("lines render = %q, want %q", got, want) - } - if strings.Contains(got, "\n") { - t.Error("unexpected raw newline in output") - } -} diff --git a/templates/pongo/filters.go b/templates/pongo/filters.go deleted file mode 100644 index 0a975d7..0000000 --- a/templates/pongo/filters.go +++ /dev/null @@ -1,35 +0,0 @@ -package pongo - -import ( - "strings" - - "github.com/flosch/pongo2/v6" -) - -// Custom pongo2 filters registered process-globally (pongo2's filter registry -// is package-level, so these are available to every TemplateSet in the -// process — the plugin Engine, the CMS definition engine, and the powered -// renderer alike). -// -// lines — split a string into its non-empty lines (newline-separated). -// pongo2 string literals cannot contain \n, so {{ v|split:"\n" }} -// is inexpressible; multi-line textarea fields (e.g. postal -// addresses rendered one
per line) need this filter: -// -// {% for line in address|lines %}
{{ line }}
{% endfor %} -func init() { - // Ignore an already-registered error: multiple inits (tests, plugins - // linking this package twice) must not panic. - _ = pongo2.RegisterFilter("lines", filterLines) -} - -func filterLines(in *pongo2.Value, _ *pongo2.Value) (*pongo2.Value, *pongo2.Error) { - raw := strings.ReplaceAll(in.String(), "\r\n", "\n") - var out []string - for line := range strings.SplitSeq(raw, "\n") { - if trimmed := strings.TrimSpace(line); trimmed != "" { - out = append(out, trimmed) - } - } - return pongo2.AsValue(out), nil -}