package store import ( "regexp" "sort" "strings" ) // linkPattern findet Verweise der Form [[slug]] im Inhalt eines Eintrags. // // Die Schreibweise stammt aus Wiki-Systemen und ist Menschen wie KI-Werkzeugen // vertraut. Sie hat einen praktischen Vorzug gegenüber Markdown-Links: Sie // enthält nur den Bezeichner, keine URL — die Verweise bleiben also gültig, // wenn sich Adressen ändern, und sie sind ohne Kontextwissen erkennbar. // // Erlaubt ist derselbe Zeichenvorrat wie bei Slugs (siehe ValidSlug). Damit wird // aus "[[siehe hier]]" kein Verweis — das ist gewollt, sonst würde jede eckige // Klammer im Text zu einem Falschtreffer. var linkPattern = regexp.MustCompile(`\[\[([a-z0-9][a-z0-9_-]{0,63})\]\]`) // ExtractLinks liest alle [[slug]]-Verweise aus einem Text. // Das Ergebnis ist sortiert und ohne Dubletten — ein zweiter Verweis auf dasselbe // Ziel ist keine zusätzliche Information. func ExtractLinks(content string) []string { treffer := linkPattern.FindAllStringSubmatch(content, -1) if len(treffer) == 0 { return nil } gesehen := make(map[string]bool, len(treffer)) var ziele []string for _, t := range treffer { ziel := t[1] if gesehen[ziel] { continue } gesehen[ziel] = true ziele = append(ziele, ziel) } sort.Strings(ziele) return ziele } // ReplaceLinks ersetzt jeden [[slug]]-Verweis durch das Ergebnis von fn. // // Wird beim Rendern verwendet, um aus den Verweisen echte Links zu machen. Die // Ersetzungsfunktion bekommt den Slug und liefert den Ersatztext. func ReplaceLinks(content string, fn func(slug string) string) string { return linkPattern.ReplaceAllStringFunc(content, func(treffer string) string { slug := strings.TrimSuffix(strings.TrimPrefix(treffer, "[["), "]]") return fn(slug) }) }