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>
46 lines
1.2 KiB
Go
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[:])
|
|
}
|