Improve Katex error handling and fix handling of large expressions

* Make throwOnError=true the new default
* Handle JS errors as part of the RPC request/response flow
* Return a new Result type with .Err on it

This enables constructs on the form:

```handlebars
{{ with transform.ToMath "c = \\foo{a^2 + b^2}" }}
	{{ with .Err }}
	 	{{ warnf "error: %s" . }}
	{{ else }}
		{{ . }}
	{{ end }}
{{ end }}
```

Note that the new `Result` type behaves like `template.HTML` (or a string if needed) when printed, but it will panic if in a error state.

Closes #12748
This commit is contained in:
Bjørn Erik Pedersen
2024-08-11 20:31:17 +02:00
parent e42263529c
commit e1e1baa1bd
14 changed files with 569 additions and 24 deletions

View File

@@ -14,6 +14,8 @@
package transform_test
import (
"fmt"
"strings"
"testing"
qt "github.com/frankban/quicktest"
@@ -150,6 +152,109 @@ disableKinds = ['page','rss','section','sitemap','taxonomy','term']
`)
}
func TestToMathError(t *testing.T) {
t.Run("Default", func(t *testing.T) {
t.Parallel()
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) {
t.Parallel()
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) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
-- layouts/index.html --
{{ with transform.ToMath "c = \\foo{a^2 + b^2}" }}
{{ with .Err }}
{{ warnf "error: %s" . }}
{{ else }}
{{ . }}
{{ end }}
{{ end }}
`
b, err := hugolib.TestE(t, files, hugolib.TestOptWarn())
b.Assert(err, qt.IsNil)
b.AssertLogContains("WARN error: KaTeX parse error: Undefined control sequence: \\foo")
})
}
func TestToMathBigAndManyExpressions(t *testing.T) {
t.Parallel()
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
`)
})
//
}
func TestToMathMacros(t *testing.T) {
t.Parallel()