feat(knowledge): index note relationships and maintain moved links

This commit is contained in:
eezd committed 2026-10-22 14:52:37 +08:00
1 parent d34d1f2183
commit a923c2dfb9
19 files changed
+545 -79

No files matched your search

+75
View File
@@ -0,0 +1,75 @@
package vault
import (
"errors"
"reflect"
"strings"
"testing"
)
func TestAnalyzeRelationshipsAndTags(t *testing.T) {
content := "---\ntags: [知识, daily]\n---\n# 标题\n正文 #读书 和 #tag/nested\n[笔记](../目标.md#章节) ![图片](a.assets/p.png) [引用][ref]\n\n[ref]: other.md\n\n`#code [伪](bad.md)`\n```\n#not-tag\n[fake](fake.md)\n```\n"
m := Analyze("dir/a.md", []byte(content))
if !reflect.DeepEqual(m.Tags, []string{"daily", "tag/nested", "知识", "读书"}) {
t.Fatalf("标签不符:%v", m.Tags)
}
if len(m.Links) != 2 || m.Links[0].Target != "目标.md" || m.Links[1].Target != "dir/other.md" || m.Links[0].Line != 6 {
t.Fatalf("链接不符:%+v", m.Links)
}
if len(m.Assets) != 1 || m.Assets[0].Target != "dir/a.assets/p.png" {
t.Fatalf("图片引用不符:%+v", m.Assets)
}
if len(m.Warnings) != 0 {
t.Fatal(m.Warnings)
}
for _, content := range []string{"---\ntags: [broken\n---\n", "---\ntags: {key: value}\n---", "---\ntags: 12\n---", "---\ntags: x"} {
if len(Analyze("x.md", []byte(content)).Warnings) == 0 {
t.Fatalf("无效元数据未报告:%s", content)
}
}
}
func TestMoveMaintainsIncomingAndOutgoingLinks(t *testing.T) {
v := newVault(t)
for p, body := range map[string]string{
"dir/a.md": "[外部](../other.md) [同级](b.md#section) ![](a.assets/p.png)\n`[不改](b.md)`\n",
"dir/b.md": "[入链](a.md?q=1#section)", "other.md": "[入链](dir/a.md)",
} {
if _, err := v.Write(p, []byte(body), Precondition{}); err != nil {
t.Fatal(err)
}
}
if _, err := v.SaveAsset("dir/a.md", "p.png", strings.NewReader("image"), 100); err != nil {
t.Fatal(err)
}
if _, err := v.Move("dir/a.md", "new/renamed.md", nil); err != nil {
t.Fatal(err)
}
body, _, _ := v.Read("new/renamed.md")
if !strings.Contains(string(body), "../dir/b.md#section") || !strings.Contains(string(body), "renamed.assets/p.png") || !strings.Contains(string(body), "`[不改](b.md)`") {
t.Fatalf("出链错误:%s", body)
}
body, _, _ = v.Read("dir/b.md")
if string(body) != "[入链](../new/renamed.md?q=1#section)" {
t.Fatalf("入链错误:%s", body)
}
if _, err := v.Move("new", "deep/folder", nil); err != nil {
t.Fatal(err)
}
body, _, _ = v.Read("deep/folder/renamed.md")
if !strings.Contains(string(body), "../../other.md") {
t.Fatalf("目录出链错误:%s", body)
}
original, _, _ := v.Read("other.md")
failure := errors.New("提交失败")
if _, err := v.Move("deep/folder", "rollback", func() error { return failure }); !errors.Is(err, failure) {
t.Fatal(err)
}
body, _, _ = v.Read("other.md")
if string(body) != string(original) {
t.Fatalf("入链未回滚:%s", body)
}
if _, _, err := v.Read("deep/folder/renamed.md"); err != nil {
t.Fatal("移动主体未回滚", err)
}
}