清除业务契约双读:抽奖/草稿/时间戳/邮件只认新格式,并删除 legacy 短代码改写。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -248,7 +248,7 @@ func MatchPasswordBlocks(content, password string) ([]int, error) {
|
||||
return hit, nil
|
||||
}
|
||||
|
||||
// WrapContentAsHide 将整篇正文包进单一隐藏块(旧帖迁移用)
|
||||
// WrapContentAsHide 将整篇正文包进单一隐藏块
|
||||
func WrapContentAsHide(kind string, points int, content string) string {
|
||||
body := strings.TrimRight(content, "\n")
|
||||
open := openMarkerLine(kind, points, "", false)
|
||||
@@ -258,7 +258,7 @@ func WrapContentAsHide(kind string, points int, content string) string {
|
||||
return open + "\n" + body + "\n[/hide]\n"
|
||||
}
|
||||
|
||||
// HasHideBlocks 快速判断正文是否已含隐藏块(迁移幂等)
|
||||
// HasHideBlocks 判断正文是否已含隐藏块
|
||||
func HasHideBlocks(content string) bool {
|
||||
blocks, err := ParseHideBlocks(content)
|
||||
if err != nil {
|
||||
|
||||
@@ -177,20 +177,3 @@ func TestTimelineDoesNotBreakHideValidate(t *testing.T) {
|
||||
t.Fatalf("timeline-only should pass: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRewriteLegacyDirectives(t *testing.T) {
|
||||
src := "公开\n\n:::hide login\n秘\n:::\n\n:::timeline\n## 2026-01-01 A\n:::\n"
|
||||
got := RewriteLegacyDirectives(src)
|
||||
if strings.Contains(got, ":::") {
|
||||
t.Fatalf("legacy remains: %q", got)
|
||||
}
|
||||
if !strings.Contains(got, "[hide login]") || !strings.Contains(got, "[/hide]") {
|
||||
t.Fatalf("hide missing: %q", got)
|
||||
}
|
||||
if !strings.Contains(got, "[timeline]") || !strings.Contains(got, "[/timeline]") {
|
||||
t.Fatalf("timeline missing: %q", got)
|
||||
}
|
||||
if err := ValidateHideContent(got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
package markdown
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RewriteLegacyDirectives 将旧式 :::hide / :::timeline / 裸 ::: 改写为行级 BBCode。
|
||||
// 幂等:已是 BBCode 的内容原样返回(若无旧标记)。代码围栏内不改写。
|
||||
func RewriteLegacyDirectives(content string) string {
|
||||
if content == "" {
|
||||
return content
|
||||
}
|
||||
if !strings.Contains(content, ":::") {
|
||||
return content
|
||||
}
|
||||
lines := splitLines(content)
|
||||
var out []string
|
||||
inCode := false
|
||||
i := 0
|
||||
for i < len(lines) {
|
||||
trimmed := strings.TrimSpace(lines[i])
|
||||
if strings.HasPrefix(trimmed, "```") {
|
||||
inCode = !inCode
|
||||
out = append(out, lines[i])
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if inCode {
|
||||
out = append(out, lines[i])
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
if kind, pts, pwd, locked, ok := parseLegacyHideOpen(trimmed); ok {
|
||||
bodyLines := make([]string, 0)
|
||||
j := i + 1
|
||||
innerCode := false
|
||||
found := false
|
||||
for j < len(lines) {
|
||||
inner := strings.TrimSpace(lines[j])
|
||||
if strings.HasPrefix(inner, "```") {
|
||||
innerCode = !innerCode
|
||||
bodyLines = append(bodyLines, lines[j])
|
||||
j++
|
||||
continue
|
||||
}
|
||||
if innerCode {
|
||||
bodyLines = append(bodyLines, lines[j])
|
||||
j++
|
||||
continue
|
||||
}
|
||||
if inner == ":::" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
bodyLines = append(bodyLines, lines[j])
|
||||
j++
|
||||
}
|
||||
out = append(out, openMarkerLine(kind, pts, pwd, locked))
|
||||
out = append(out, bodyLines...)
|
||||
if found {
|
||||
out = append(out, "[/hide]")
|
||||
i = j + 1
|
||||
} else {
|
||||
// 未闭合:仍写出已转换开标记与正文,避免丢内容
|
||||
i = j
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if trimmed == ":::timeline" || strings.HasPrefix(trimmed, ":::timeline ") {
|
||||
bodyLines := make([]string, 0)
|
||||
j := i + 1
|
||||
innerCode := false
|
||||
found := false
|
||||
for j < len(lines) {
|
||||
inner := strings.TrimSpace(lines[j])
|
||||
if strings.HasPrefix(inner, "```") {
|
||||
innerCode = !innerCode
|
||||
bodyLines = append(bodyLines, lines[j])
|
||||
j++
|
||||
continue
|
||||
}
|
||||
if innerCode {
|
||||
bodyLines = append(bodyLines, lines[j])
|
||||
j++
|
||||
continue
|
||||
}
|
||||
if inner == ":::" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
bodyLines = append(bodyLines, lines[j])
|
||||
j++
|
||||
}
|
||||
out = append(out, "[timeline]")
|
||||
out = append(out, bodyLines...)
|
||||
if found {
|
||||
out = append(out, "[/timeline]")
|
||||
i = j + 1
|
||||
} else {
|
||||
i = j
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
out = append(out, lines[i])
|
||||
i++
|
||||
}
|
||||
return strings.Join(out, "\n")
|
||||
}
|
||||
|
||||
// parseLegacyHideOpen 解析旧式 :::hide <kind> [arg] [locked]
|
||||
func parseLegacyHideOpen(trimmed string) (kind string, points int, password string, locked bool, ok bool) {
|
||||
if !strings.HasPrefix(trimmed, ":::hide") {
|
||||
return "", 0, "", false, false
|
||||
}
|
||||
rest := strings.TrimSpace(trimmed[len(":::hide"):])
|
||||
if rest == "" {
|
||||
return "", 0, "", false, false
|
||||
}
|
||||
parts := strings.Fields(rest)
|
||||
if len(parts) == 0 {
|
||||
return "", 0, "", false, false
|
||||
}
|
||||
kind = parts[0]
|
||||
switch kind {
|
||||
case HideKindLogin, HideKindReply, HideKindPoints, HideKindPassword:
|
||||
default:
|
||||
return "", 0, "", false, false
|
||||
}
|
||||
idx := 1
|
||||
if kind == HideKindPoints {
|
||||
if idx >= len(parts) {
|
||||
return "", 0, "", false, false
|
||||
}
|
||||
n, err := strconv.Atoi(parts[idx])
|
||||
if err != nil {
|
||||
return "", 0, "", false, false
|
||||
}
|
||||
points = n
|
||||
idx++
|
||||
} else if kind == HideKindPassword {
|
||||
if idx < len(parts) && parts[idx] != "locked" {
|
||||
password = parts[idx]
|
||||
idx++
|
||||
}
|
||||
}
|
||||
for ; idx < len(parts); idx++ {
|
||||
if parts[idx] == "locked" {
|
||||
locked = true
|
||||
} else {
|
||||
return "", 0, "", false, false
|
||||
}
|
||||
}
|
||||
return kind, points, password, locked, true
|
||||
}
|
||||
Reference in New Issue
Block a user