File remove-wasm-tomath.patch of Package hugo

commit 9265a26eaddc6402751973cbdefbd779173b5a14
Author: Jeff Kowalczyk <jkowalczyk@suse.com>
Date:   Sun Apr 13 14:19:13 2025 -0700

    Remove warpc and javy dep supporting ToMath() LaTex to MathML
    
    Upstream Hugo added a feature render LaTex to MathML server-side. Remove the
    functionality in Hugo related to this feature. Original patchset by darix.
    
    While useful, ToMath() brings along a dependency on the javy JS to WebAssembly
    toolchain implemented in Rust. Upstream ships precompiled .wasm binaries, but we
    cannot ship these in OBS built packages. These .wasm binaries are already being
    removed as a packaging step, see package changelog.
    
    There is currently no RPM package available for javy. If and when a javy package
    built in OBS is available, drop this patch.
    
    Upstream has declined suggestions to not ship precompiled .wasm in the source
    distribution. See deleted comments from darix on:
    
    hugo#12736 transform.ToMath, WASI/Wasm modules feedback thread
    https://github.com/gohugoio/hugo/issues/12736

diff --git a/deps/deps.go b/deps/deps.go
index d0d6d95f..b6009a39 100644
--- a/deps/deps.go
+++ b/deps/deps.go
@@ -25,7 +25,6 @@ import (
 	"github.com/gohugoio/hugo/hugofs"
 	"github.com/gohugoio/hugo/identity"
 	"github.com/gohugoio/hugo/internal/js"
-	"github.com/gohugoio/hugo/internal/warpc"
 	"github.com/gohugoio/hugo/media"
 	"github.com/gohugoio/hugo/resources/page"
 	"github.com/gohugoio/hugo/resources/postpub"
@@ -101,10 +100,6 @@ type Deps struct {
 	// Misc counters.
 	Counters *Counters
 
-	// Holds RPC dispatchers for Katex etc.
-	// TODO(bep) rethink this re. a plugin setup, but this will have to do for now.
-	WasmDispatchers *warpc.Dispatchers
-
 	// The JS batcher client.
 	JSBatcherClient js.BatcherClient
 
@@ -380,9 +375,6 @@ func (d *Deps) Close() error {
 	if d.MemCache != nil {
 		d.MemCache.Stop()
 	}
-	if d.WasmDispatchers != nil {
-		d.WasmDispatchers.Close()
-	}
 	return d.BuildClosers.Close()
 }
 
diff --git a/hugolib/site.go b/hugolib/site.go
index 728b036d..6bce24db 100644
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -43,7 +43,6 @@ import (
 	"github.com/gohugoio/hugo/hugolib/doctree"
 	"github.com/gohugoio/hugo/hugolib/pagesfromdata"
 	"github.com/gohugoio/hugo/internal/js/esbuild"
-	"github.com/gohugoio/hugo/internal/warpc"
 	"github.com/gohugoio/hugo/langs/i18n"
 	"github.com/gohugoio/hugo/modules"
 	"github.com/gohugoio/hugo/resources"
@@ -197,15 +196,6 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
 		Counters:            &deps.Counters{},
 		MemCache:            memCache,
 		TranslationProvider: i18n.NewTranslationProvider(),
-		WasmDispatchers: warpc.AllDispatchers(
-			warpc.Options{
-				CompilationCacheDir: filepath.Join(conf.Dirs().CacheDir, "_warpc"),
-
-				// Katex is relatively slow.
-				PoolSize: 8,
-				Infof:    logger.InfoCommand("wasm").Logf,
-			},
-		),
 	}
 
 	if err := firstSiteDeps.Init(); err != nil {
diff --git a/tpl/transform/transform.go b/tpl/transform/transform.go
index bc6d97cf..654bf0e1 100644
--- a/tpl/transform/transform.go
+++ b/tpl/transform/transform.go
@@ -18,10 +18,8 @@ import (
 	"bytes"
 	"context"
 	"encoding/xml"
-	"errors"
 	"html"
 	"html/template"
-	"io"
 	"strings"
 	"sync/atomic"
 
@@ -30,15 +28,11 @@ import (
 	"github.com/bep/goportabletext"
 
 	"github.com/gohugoio/hugo/cache/dynacache"
-	"github.com/gohugoio/hugo/common/hashing"
-	"github.com/gohugoio/hugo/common/hugio"
-	"github.com/gohugoio/hugo/internal/warpc"
 	"github.com/gohugoio/hugo/markup/converter/hooks"
 	"github.com/gohugoio/hugo/markup/highlight"
 	"github.com/gohugoio/hugo/markup/highlight/chromalexers"
 	"github.com/gohugoio/hugo/resources"
 	"github.com/gohugoio/hugo/tpl"
-	"github.com/mitchellh/mapstructure"
 
 	"github.com/gohugoio/hugo/deps"
 	"github.com/gohugoio/hugo/helpers"
@@ -216,72 +210,6 @@ func (ns *Namespace) PortableText(v any) (string, error) {
 	return buf.String(), nil
 }
 
-// ToMath converts a LaTeX string to math in the given format, default MathML.
-// This uses KaTeX to render the math, see https://katex.org/.
-func (ns *Namespace) ToMath(ctx context.Context, args ...any) (template.HTML, error) {
-	if len(args) < 1 {
-		return "", errors.New("must provide at least one argument")
-	}
-	expression, err := cast.ToStringE(args[0])
-	if err != nil {
-		return "", err
-	}
-
-	katexInput := warpc.KatexInput{
-		Expression: expression,
-		Options: warpc.KatexOptions{
-			Output:           "mathml",
-			MinRuleThickness: 0.04,
-			ErrorColor:       "#cc0000",
-			ThrowOnError:     true,
-		},
-	}
-
-	if len(args) > 1 {
-		if err := mapstructure.WeakDecode(args[1], &katexInput.Options); err != nil {
-			return "", err
-		}
-	}
-
-	s := hashing.HashString(args...)
-	key := "tomath/" + s[:2] + "/" + s[2:]
-	fileCache := ns.deps.ResourceSpec.FileCaches.MiscCache()
-
-	v, err := ns.cacheMath.GetOrCreate(key, func(string) (template.HTML, error) {
-		_, r, err := fileCache.GetOrCreate(key, func() (io.ReadCloser, error) {
-			message := warpc.Message[warpc.KatexInput]{
-				Header: warpc.Header{
-					Version: 1,
-					ID:      ns.id.Add(1),
-				},
-				Data: katexInput,
-			}
-
-			k, err := ns.deps.WasmDispatchers.Katex()
-			if err != nil {
-				return nil, err
-			}
-			result, err := k.Execute(ctx, message)
-			if err != nil {
-				return nil, err
-			}
-			return hugio.NewReadSeekerNoOpCloserFromString(result.Data.Output), nil
-		})
-		if err != nil {
-			return "", err
-		}
-
-		s, err := hugio.ReadString(r)
-
-		return template.HTML(s), err
-	})
-	if err != nil {
-		return "", err
-	}
-
-	return v, nil
-}
-
 // For internal use.
 func (ns *Namespace) Reset() {
 	ns.cacheUnmarshal.Clear()
diff --git a/tpl/transform/transform_integration_test.go b/tpl/transform/transform_integration_test.go
index ceb80309..6fe4aa0a 100644
--- a/tpl/transform/transform_integration_test.go
+++ b/tpl/transform/transform_integration_test.go
@@ -136,202 +136,6 @@ Scar,"a "dead cat",11
 	`)
 }
 
-func TestToMath(t *testing.T) {
-	files := `
--- hugo.toml --
-disableKinds = ['page','rss','section','sitemap','taxonomy','term']
--- layouts/index.html --
-{{ transform.ToMath "c = \\pm\\sqrt{a^2 + b^2}" }}
-  `
-	b := hugolib.Test(t, files)
-
-	b.AssertFileContent("public/index.html", `
-<span class="katex"><math
-	`)
-}
-
-func TestToMathError(t *testing.T) {
-	t.Run("Default", func(t *testing.T) {
-		files := `
--- hugo.toml --
-disableKinds = ['page','rss','section','sitemap','taxonomy','term']
--- layouts/index.html --
-{{  transform.ToMath "c = \\foo{a^2 + b^2}" }}
-  `
-		b, err := hugolib.TestE(t, files, hugolib.TestOptWarn())
-
-		b.Assert(err, qt.IsNotNil)
-		b.Assert(err.Error(), qt.Contains, "KaTeX parse error: Undefined control sequence: \\foo")
-	})
-
-	t.Run("Disable ThrowOnError", func(t *testing.T) {
-		files := `
--- hugo.toml --
-disableKinds = ['page','rss','section','sitemap','taxonomy','term']
--- layouts/index.html --
-{{ $opts := dict "throwOnError" false }}
-{{  transform.ToMath "c = \\foo{a^2 + b^2}" $opts }}
-  `
-		b, err := hugolib.TestE(t, files, hugolib.TestOptWarn())
-
-		b.Assert(err, qt.IsNil)
-		b.AssertFileContent("public/index.html", `#cc0000`) // Error color
-	})
-
-	t.Run("Handle in template", func(t *testing.T) {
-		files := `
--- hugo.toml --
-disableKinds = ['page','rss','section','sitemap','taxonomy','term']
--- layouts/index.html --
-{{ with try (transform.ToMath "c = \\foo{a^2 + b^2}") }}
-	{{ with .Err }}
-	 	{{ warnf "error: %s" . }}
-	{{ else }}
-		{{ .Value }}
-	{{ end }}
-{{ end }}
-  `
-		b, err := hugolib.TestE(t, files, hugolib.TestOptWarn())
-
-		b.Assert(err, qt.IsNil)
-		b.AssertLogContains("WARN  error: template: index.html:1:22: executing \"index.html\" at <transform.ToMath>: error calling ToMath: KaTeX parse error: Undefined control sequence: \\foo at position 5: c = \\̲f̲o̲o̲{a^2 + b^2}")
-	})
-
-	// See issue 13239.
-	t.Run("Handle in template, old Err construct", func(t *testing.T) {
-		files := `
--- hugo.toml --
-disableKinds = ['page','rss','section','sitemap','taxonomy','term']
--- layouts/index.html --
-{{ with transform.ToMath "c = \\pm\\sqrt{a^2 + b^2}" }}
-	{{ with .Err }}
-	 	{{ warnf "error: %s" . }}
-	{{ else }}
-		{{ . }}
-	{{ end }}
-{{ end }}
-  `
-		b, err := hugolib.TestE(t, files, hugolib.TestOptWarn())
-
-		b.Assert(err, qt.IsNotNil)
-		b.Assert(err.Error(), qt.Contains, "the return type of transform.ToMath was changed in Hugo v0.141.0 and the error handling replaced with a new try keyword, see https://gohugo.io/functions/go-template/try/")
-	})
-}
-
-func TestToMathBigAndManyExpressions(t *testing.T) {
-	filesTemplate := `
--- hugo.toml --
-disableKinds = ['rss','section','sitemap','taxonomy','term']
-[markup.goldmark.extensions.passthrough]
-enable = true
-[markup.goldmark.extensions.passthrough.delimiters]
-block  = [['\[', '\]'], ['$$', '$$']]
-inline = [['\(', '\)'], ['$', '$']]
--- content/p1.md --
-P1_CONTENT
--- layouts/index.html --
-Home.
--- layouts/_default/single.html --
-Content: {{ .Content }}|
--- layouts/_default/_markup/render-passthrough.html --
-{{ $opts := dict "throwOnError" false "displayMode" true }}
-{{ transform.ToMath .Inner $opts }}
-  `
-
-	t.Run("Very large file with many complex KaTeX expressions", func(t *testing.T) {
-		files := strings.ReplaceAll(filesTemplate, "P1_CONTENT", "sourcefilename: testdata/large-katex.md")
-		b := hugolib.Test(t, files)
-		b.AssertFileContent("public/p1/index.html", `
-		<span class="katex"><math
-			`)
-	})
-
-	t.Run("Large and complex expression", func(t *testing.T) {
-		// This is pulled from the file above, which times out for some reason.
-		largeAndComplexeExpressions := `\begin{align*} \frac{\pi^2}{6}&=\frac{4}{3}\frac{(\arcsin 1)^2}{2}\\ &=\frac{4}{3}\int_0^1\frac{\arcsin x}{\sqrt{1-x^2}}\,dx\\ &=\frac{4}{3}\int_0^1\frac{x+\sum_{n=1}^{\infty}\frac{(2n-1)!!}{(2n)!!}\frac{x^{2n+1}}{2n+1}}{\sqrt{1-x^2}}\,dx\\ &=\frac{4}{3}\int_0^1\frac{x}{\sqrt{1-x^2}}\,dx +\frac{4}{3}\sum_{n=1}^{\infty}\frac{(2n-1)!!}{(2n)!!(2n+1)}\int_0^1x^{2n}\frac{x}{\sqrt{1-x^2}}\,dx\\ &=\frac{4}{3}+\frac{4}{3}\sum_{n=1}^{\infty}\frac{(2n-1)!!}{(2n)!!(2n+1)}\left[\frac{(2n)!!}{(2n+1)!!}\right]\\ &=\frac{4}{3}\sum_{n=0}^{\infty}\frac{1}{(2n+1)^2}\\ &=\frac{4}{3}\left(\sum_{n=1}^{\infty}\frac{1}{n^2}-\frac{1}{4}\sum_{n=1}^{\infty}\frac{1}{n^2}\right)\\ &=\sum_{n=1}^{\infty}\frac{1}{n^2} \end{align*}`
-		files := strings.ReplaceAll(filesTemplate, "P1_CONTENT", fmt.Sprintf(`---
-title: p1
----
-
-$$%s$$
-	`, largeAndComplexeExpressions))
-
-		b := hugolib.Test(t, files)
-		b.AssertFileContent("public/p1/index.html", `
-		<span class="katex"><math
-			`)
-	})
-}
-
-// Issue #13406.
-func TestToMathRenderHookPosition(t *testing.T) {
-	filesTemplate := `
--- hugo.toml --
-disableKinds = ['rss','section','sitemap','taxonomy','term']
-[markup.goldmark.extensions.passthrough]
-enable = true
-[markup.goldmark.extensions.passthrough.delimiters]
-block  = [['\[', '\]'], ['$$', '$$']]
-inline = [['\(', '\)'], ['$', '$']]
--- content/p1.md --
----
-title: p1
----
-
-Block:
-
-$$1+2$$
-
-Some inline $1+3$ math.
-
--- layouts/index.html --
-Home.
--- layouts/_default/single.html --
-Content: {{ .Content }}|
--- layouts/_default/_markup/render-passthrough.html --
-{{ $opts := dict "throwOnError" true "displayMode" true }}
-{{- with try (transform.ToMath .Inner $opts ) }}
-  {{- with .Err }}
-    {{ errorf "KaTeX: %s: see %s." . $.Position }}
-  {{- else }}
-    {{- .Value }}
-  {{- end }}
-{{- end -}}
-
-`
-
-	// Block math.
-	files := strings.Replace(filesTemplate, "$$1+2$$", "$$\\foo1+2$$", 1)
-	b, err := hugolib.TestE(t, files)
-	b.Assert(err, qt.IsNotNil)
-	b.AssertLogContains("p1.md:6:1")
-
-	// Inline math.
-	files = strings.Replace(filesTemplate, "$1+3$", "$\\foo1+3$", 1)
-	b, err = hugolib.TestE(t, files)
-	b.Assert(err, qt.IsNotNil)
-	b.AssertLogContains("p1.md:8:13")
-}
-
-func TestToMathMacros(t *testing.T) {
-	files := `
--- hugo.toml --
-disableKinds = ['page','rss','section','sitemap','taxonomy','term']
--- layouts/index.html --
-{{ $macros := dict
-    "\\addBar" "\\bar{#1}"
-	"\\bold" "\\mathbf{#1}"
-}}
-{{ $opts := dict "macros" $macros }}
-{{ transform.ToMath "\\addBar{y} + \\bold{H}" $opts }}
-  `
-	b := hugolib.Test(t, files)
-
-	b.AssertFileContent("public/index.html", `
-<mi>y</mi>
-	`)
-}
-
 // Issue #12977
 func TestUnmarshalWithIndentedYAML(t *testing.T) {
 	t.Parallel()
openSUSE Build Service is sponsored by