Files
Agent-System/internal/doccontent/canonicalize.go
T
weichenandCursor 9ddc673eb8 feat(doccontent): extract shared markdown canonicalization and SHA
docgov saves content hashes through the new leaf module so it no longer
imports docrevision. Existing docrevision exports stay as thin wrappers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 10:24:24 +00:00

46 lines
1.2 KiB
Go

package doccontent
import (
"crypto/sha256"
"encoding/hex"
"strings"
"golang.org/x/text/unicode/norm"
)
// CanonicalizeMarkdown applies LF, UTF-8 NFC, and a single trailing newline.
// It must not trim trailing spaces or tabs: two trailing spaces are Markdown hard breaks.
func CanonicalizeMarkdown(raw string) string {
s := strings.ReplaceAll(raw, "\r\n", "\n")
s = strings.ReplaceAll(s, "\r", "\n")
s = norm.NFC.String(s)
if s != "" && !strings.HasSuffix(s, "\n") {
s += "\n"
}
return s
}
// LegacyDestructiveCanonicalizeMarkdown reproduces the pre-fix canonicalizer that
// stripped per-line trailing spaces/tabs. Used only to classify historical drift.
func LegacyDestructiveCanonicalizeMarkdown(raw string) string {
s := strings.ReplaceAll(raw, "\r\n", "\n")
s = strings.ReplaceAll(s, "\r", "\n")
s = norm.NFC.String(s)
lines := strings.Split(s, "\n")
for i, line := range lines {
lines[i] = strings.TrimRightFunc(line, func(r rune) bool {
return r == ' ' || r == '\t'
})
}
s = strings.Join(lines, "\n")
if s != "" && !strings.HasSuffix(s, "\n") {
s += "\n"
}
return s
}
func SHA256Hex(content string) string {
sum := sha256.Sum256([]byte(content))
return hex.EncodeToString(sum[:])
}