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 }