feat(14.2.1-03): add markdown and multilingual cabana fields

Lift locale maps before ProjectWritableFields so a Journal-shaped save can persist the default host scalar and non-default locales through TranslationWriter without dropping nested JSON.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jakub Zych
2026-10-06 12:32:54 +02:00
parent 234111d245
commit a04116d41f
13 changed files with 895 additions and 3 deletions

View File

@@ -0,0 +1,46 @@
package cabana
import (
"bytes"
"fmt"
"regexp"
"github.com/yuin/goldmark"
)
var (
markdownEngine = goldmark.New()
markdownUnsafeTag = regexp.MustCompile(`(?i)<(?:script|iframe|object|embed)\b`)
markdownEventHandler = regexp.MustCompile(`(?i)\son[a-z]+\s*=`)
markdownDangerousURL = regexp.MustCompile(`(?i)(?:javascript|vbscript|data):`)
)
// RenderMarkdown converts source to HTML using the pinned goldmark engine
// without html.WithUnsafe. Output that still contains script/iframe tags,
// event handlers, or javascript/vbscript/data URLs is rejected, matching
// postcard's mail HTML gate.
func RenderMarkdown(src string) (string, error) {
var buf bytes.Buffer
if err := markdownEngine.Convert([]byte(src), &buf); err != nil {
return "", fmt.Errorf("cabana: markdown: %w", err)
}
html := buf.String()
if err := rejectUnsafeMarkdownHTML(html); err != nil {
return "", err
}
return html, nil
}
func rejectUnsafeMarkdownHTML(html string) error {
if markdownUnsafeTag.MatchString(html) {
return fmt.Errorf("cabana: rendered HTML contains raw unsafe tags")
}
if markdownEventHandler.MatchString(html) {
return fmt.Errorf("cabana: rendered HTML contains event handlers")
}
if markdownDangerousURL.MatchString(html) {
return fmt.Errorf("cabana: rendered HTML contains a dangerous URL scheme")
}
return nil
}