78 lines
2.0 KiB
Go
78 lines
2.0 KiB
Go
package topdata
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
type wikiPagePathDocument struct {
|
|
PagePaths wikiPagePaths `json:"page_paths" yaml:"page_paths"`
|
|
}
|
|
|
|
type wikiPagePaths struct {
|
|
SlugOverrides []wikiPageSlugOverride `json:"slug_overrides" yaml:"slug_overrides"`
|
|
}
|
|
|
|
type wikiPageSlugOverride struct {
|
|
PageID string `json:"page_id" yaml:"page_id"`
|
|
Slug string `json:"slug" yaml:"slug"`
|
|
}
|
|
|
|
func loadWikiPagePathDeclarations(path string) (map[string]string, error) {
|
|
raw, err := os.ReadFile(path)
|
|
if os.IsNotExist(err) {
|
|
return map[string]string{}, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return parseWikiPagePathDeclarations(raw, path)
|
|
}
|
|
|
|
func parseWikiPagePathDeclarations(raw []byte, path string) (map[string]string, error) {
|
|
var doc wikiPagePathDocument
|
|
if err := yaml.Unmarshal(raw, &doc); err != nil {
|
|
return nil, fmt.Errorf("parse wiki page paths %s: %w", path, err)
|
|
}
|
|
if len(doc.PagePaths.SlugOverrides) > 0 {
|
|
return nil, fmt.Errorf("parse wiki page paths %s: page_paths.slug_overrides is retired; generated public wiki paths are title-derived", path)
|
|
}
|
|
overrides := map[string]string{}
|
|
for _, override := range doc.PagePaths.SlugOverrides {
|
|
pageID := strings.TrimSpace(override.PageID)
|
|
slug := strings.TrimSpace(override.Slug)
|
|
if pageID == "" {
|
|
return nil, fmt.Errorf("parse wiki page paths %s: slug override has empty page_id", path)
|
|
}
|
|
if !isCanonicalWikiSlug(slug) {
|
|
return nil, fmt.Errorf("parse wiki page paths %s: page_id %q has invalid slug %q", path, pageID, override.Slug)
|
|
}
|
|
if _, ok := overrides[pageID]; ok {
|
|
return nil, fmt.Errorf("parse wiki page paths %s: duplicate page_id %q", path, pageID)
|
|
}
|
|
overrides[pageID] = slug
|
|
}
|
|
return overrides, nil
|
|
}
|
|
|
|
func isCanonicalWikiSlug(value string) bool {
|
|
if value == "" || value != strings.ToLower(value) {
|
|
return false
|
|
}
|
|
parts := strings.Split(value, "-")
|
|
for _, part := range parts {
|
|
if part == "" {
|
|
return false
|
|
}
|
|
for _, r := range part {
|
|
if !((r >= 'a' && r <= 'z') || (r >= '0' && r <= '9')) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|