Skip to content

Commit 6334948

Browse files
authored
Handle KaTeX warnings (#13760)
Co-authored-by: Joe Mooring <[email protected]> Fixes #13735
1 parent 7525963 commit 6334948

File tree

10 files changed

+76
-15
lines changed

10 files changed

+76
-15
lines changed

hugolib/site.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
204204
// Katex is relatively slow.
205205
PoolSize: 8,
206206
Infof: logger.InfoCommand("wasm").Logf,
207+
Warnf: logger.WarnCommand("wasm").Logf,
207208
},
208209
),
209210
}

internal/warpc/js/common.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ export function readInput(handle) {
44
let currentLine = [];
55
const buffer = new Uint8Array(buffSize);
66

7+
// These are not implemented by QuickJS.
8+
console.warn = (value) => {
9+
console.log(value);
10+
};
11+
12+
console.error = (value) => {
13+
throw new Error(value);
14+
};
15+
716
// Read all the available bytes
817
while (true) {
918
// Stdin file descriptor

internal/warpc/js/greet.bundle.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/warpc/js/renderkatex.bundle.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/warpc/js/renderkatex.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ const render = function (input) {
77
const expression = data.expression;
88
const options = data.options;
99
const header = input.header;
10+
header.warnings = [];
11+
12+
if (options.strict == 'warn') {
13+
// By default, KaTeX will write to console.warn, that's a little hard to handle.
14+
options.strict = (errorCode, errorMsg) => {
15+
header.warnings.push(
16+
`katex: LaTeX-incompatible input and strict mode is set to 'warn': ${errorMsg} [${errorCode}]`,
17+
);
18+
};
19+
}
1020
// Any error thrown here will be caught by the common.js readInput function.
1121
const output = katex.renderToString(expression, options);
1222
writeOutput({ header: header, data: { output: output } });

internal/warpc/warpc.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ type Header struct {
5151

5252
// Set in the response if there was an error.
5353
Err string `json:"err"`
54+
55+
// Warnings is a list of warnings that may be returned in the response.
56+
Warnings []string `json:"warnings,omitempty"`
5457
}
5558

5659
type Message[T any] struct {
@@ -155,6 +158,7 @@ func (p *dispatcherPool[Q, R]) Execute(ctx context.Context, q Message[Q]) (Messa
155158
}
156159

157160
resp, err := call.response, p.Err()
161+
158162
if err == nil && resp.Header.Err != "" {
159163
err = errors.New(resp.Header.Err)
160164
}
@@ -270,6 +274,8 @@ type Options struct {
270274

271275
Infof func(format string, v ...any)
272276

277+
Warnf func(format string, v ...any)
278+
273279
// E.g. quickjs wasm. May be omitted if not needed.
274280
Runtime Binary
275281

@@ -325,6 +331,7 @@ type dispatcherPool[Q, R any] struct {
325331
counter atomic.Uint32
326332
dispatchers []*dispatcher[Q, R]
327333
close func() error
334+
opts Options
328335

329336
errc chan error
330337
donec chan struct{}
@@ -355,6 +362,11 @@ func newDispatcher[Q, R any](opts Options) (*dispatcherPool[Q, R], error) {
355362
// noop
356363
}
357364
}
365+
if opts.Warnf == nil {
366+
opts.Warnf = func(format string, v ...any) {
367+
// noop
368+
}
369+
}
358370

359371
if opts.Memory <= 0 {
360372
// 32 MiB
@@ -466,6 +478,7 @@ func newDispatcher[Q, R any](opts Options) (*dispatcherPool[Q, R], error) {
466478

467479
dp := &dispatcherPool[Q, R]{
468480
dispatchers: make([]*dispatcher[Q, R], len(inOuts)),
481+
opts: opts,
469482

470483
errc: make(chan error, 10),
471484
donec: make(chan struct{}),

internal/warpc/wasm/greet.wasm

137 Bytes
Binary file not shown.

internal/warpc/wasm/renderkatex.wasm

492 Bytes
Binary file not shown.

tpl/transform/transform.go

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package transform
1717
import (
1818
"bytes"
1919
"context"
20+
"encoding/json"
2021
"encoding/xml"
2122
"errors"
2223
"fmt"
@@ -252,8 +253,16 @@ func (ns *Namespace) ToMath(ctx context.Context, args ...any) (template.HTML, er
252253
return "", fmt.Errorf("invalid strict mode; expected one of error, ignore, or warn; received %s", katexInput.Options.Strict)
253254
}
254255

256+
type fileCacheEntry struct {
257+
Version string `json:"version"`
258+
Output string `json:"output"`
259+
Warnings []string `json:"warnings,omitempty"`
260+
}
261+
262+
const fileCacheEntryVersion = "v1" // Increment on incompatible changes.
263+
255264
s := hashing.HashString(args...)
256-
key := "tomath/" + s[:2] + "/" + s[2:]
265+
key := "tomath/" + fileCacheEntryVersion + "/" + s[:2] + "/" + s[2:]
257266
fileCache := ns.deps.ResourceSpec.FileCaches.MiscCache()
258267

259268
v, err := ns.cacheMath.GetOrCreate(key, func(string) (template.HTML, error) {
@@ -274,15 +283,35 @@ func (ns *Namespace) ToMath(ctx context.Context, args ...any) (template.HTML, er
274283
if err != nil {
275284
return nil, err
276285
}
277-
return hugio.NewReadSeekerNoOpCloserFromString(result.Data.Output), nil
286+
287+
e := fileCacheEntry{
288+
Version: fileCacheEntryVersion,
289+
Output: result.Data.Output,
290+
Warnings: result.Header.Warnings,
291+
}
292+
293+
buf := &bytes.Buffer{}
294+
enc := json.NewEncoder(buf)
295+
enc.SetEscapeHTML(false)
296+
if err := enc.Encode(e); err != nil {
297+
return nil, fmt.Errorf("failed to encode file cache entry: %w", err)
298+
}
299+
return hugio.NewReadSeekerNoOpCloserFromBytes(buf.Bytes()), nil
278300
})
279301
if err != nil {
280302
return "", err
281303
}
282304

283-
s, err := hugio.ReadString(r)
305+
var e fileCacheEntry
306+
if err := json.NewDecoder(r).Decode(&e); err != nil {
307+
return "", fmt.Errorf("failed to decode file cache entry: %w", err)
308+
}
309+
310+
for _, warning := range e.Warnings {
311+
ns.deps.Log.Warnf("transform.ToMath: %s", warning)
312+
}
284313

285-
return template.HTML(s), err
314+
return template.HTML(e.Output), err
286315
})
287316
if err != nil {
288317
return "", err

tpl/transform/transform_integration_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -525,11 +525,10 @@ disableKinds = ['page','rss','section','sitemap','taxonomy','term']
525525
b.AssertFileContent("public/index.html", `<annotation encoding="application/x-tex">a %</annotation>`)
526526

527527
// strict: warn
528-
// TODO: see https://github.com/gohugoio/hugo/issues/13735
529-
// f = strings.ReplaceAll(files, "dict", `(dict "strict" "warn")`)
530-
// b = hugolib.Test(t, f, hugolib.TestOptWarn())
531-
// b.AssertLogMatches("[commentAtEnd]")
532-
// b.AssertFileContent("public/index.html", `<annotation encoding="application/x-tex">a %</annotation>`)
528+
f = strings.ReplaceAll(files, "dict", `(dict "strict" "warn")`)
529+
b = hugolib.Test(t, f, hugolib.TestOptWarn())
530+
b.AssertLogMatches("[commentAtEnd]")
531+
b.AssertFileContent("public/index.html", `<annotation encoding="application/x-tex">a %</annotation>`)
533532

534533
// strict mode: invalid value
535534
f = strings.ReplaceAll(files, "dict", `(dict "strict" "foo")`)

0 commit comments

Comments
 (0)