ai_xiaopei
6 days ago 1196f409d86bc61e7596eb274840244a62ce84ba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package vault
 
import (
    "bufio"
    "os"
    "regexp"
    "strings"
 
    "gopkg.in/yaml.v3"
)
 
// FileMeta 文件元数据
type FileMeta struct {
    Path      string   // 相对路径
    Title     string   // frontmatter title
    Section   string   // 所属板块
    Tags      []string // frontmatter tags
    Entities  []string // frontmatter entities
    Wikilinks []string // 正文中的 [[xxx]] 链接
    Content   string   // 纯文本内容(去 frontmatter)
}
 
// Frontmatter YAML 结构
type Frontmatter struct {
    Title    string   `yaml:"title"`
    Tags     []string `yaml:"tags"`
    Entities []string `yaml:"entities"`
    Aliases  []string `yaml:"aliases"`
}
 
var wikilinkRe = regexp.MustCompile(`\[\[([^\]]+)\]\]`)
 
// ParseFile 解析单个 markdown 文件
func ParseFile(absPath, relPath string) (*FileMeta, error) {
    f, err := os.Open(absPath)
    if err != nil {
        return nil, err
    }
    defer f.Close()
 
    meta := &FileMeta{
        Path:    relPath,
        Section: GetSection(relPath),
    }
 
    scanner := bufio.NewScanner(f)
    inFrontmatter := false
    fmLines := []string{}
    contentLines := []string{}
    lineNum := 0
 
    for scanner.Scan() {
        line := scanner.Text()
        lineNum++
 
        if lineNum == 1 && line == "---" {
            inFrontmatter = true
            continue
        }
        if inFrontmatter && line == "---" {
            inFrontmatter = false
            continue
        }
        if inFrontmatter {
            fmLines = append(fmLines, line)
        } else {
            contentLines = append(contentLines, line)
        }
    }
 
    // 解析 frontmatter
    if len(fmLines) > 0 {
        var fm Frontmatter
        if err := yaml.Unmarshal([]byte(strings.Join(fmLines, "\n")), &fm); err == nil {
            meta.Title = fm.Title
            meta.Tags = fm.Tags
            meta.Entities = fm.Entities
        }
    }
 
    // 提取 wikilinks 和内容
    content := strings.Join(contentLines, "\n")
    meta.Content = content
 
    matches := wikilinkRe.FindAllStringSubmatch(content, -1)
    seen := make(map[string]bool)
    for _, m := range matches {
        link := m[1]
        if !seen[link] {
            meta.Wikilinks = append(meta.Wikilinks, link)
            seen[link] = true
        }
    }
 
    return meta, nil
}