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
|
}
|