Monorepo for Tangled
tangled.org
1package pages
2
3import (
4 "io/fs"
5 "regexp"
6 "strings"
7 "testing"
8)
9
10var repoRkeyAllowlist = map[string]bool{
11 "templates/repo/settings/sites.html": true,
12}
13
14var repoRkeyPattern = regexp.MustCompile(`\.(Repo|RepoInfo)\.Rkey\b`)
15
16func TestNoRepoRkeyInTemplates(t *testing.T) {
17 err := fs.WalkDir(Files, "templates", func(path string, d fs.DirEntry, err error) error {
18 if err != nil {
19 return err
20 }
21 if d.IsDir() || !strings.HasSuffix(path, ".html") {
22 return nil
23 }
24 if repoRkeyAllowlist[path] {
25 return nil
26 }
27 data, err := fs.ReadFile(Files, path)
28 if err != nil {
29 return err
30 }
31 for i, line := range strings.Split(string(data), "\n") {
32 if repoRkeyPattern.MatchString(line) {
33 t.Errorf("%s:%d uses .Repo.Rkey or .RepoInfo.Rkey in URL position. Use .Slug to prefer Name over TID-Rkey.\n %s",
34 path, i+1, strings.TrimSpace(line))
35 }
36 }
37 return nil
38 })
39 if err != nil {
40 t.Fatal(err)
41 }
42}
43
44var bareDidAllowlist = map[string]bool{
45 "templates/strings/string.html": true,
46 "templates/strings/fragments/form.html": true,
47 "templates/spindles/dashboard.html": true,
48}
49
50var didCloseAsUrlSegment = regexp.MustCompile(`\.(?:Did|OwnerDid)\s*\}\}\s*/`)
51var printfWithUrlFormat = regexp.MustCompile(`printf\s+"[^"]*/[^"]*%s`)
52var didArgRef = regexp.MustCompile(`\b[\$\.]\w+(?:\.\w+)*\.(?:Did|OwnerDid)\b`)
53
54func TestNoBareDidInTemplateRepoUrls(t *testing.T) {
55 err := fs.WalkDir(Files, "templates", func(path string, d fs.DirEntry, err error) error {
56 if err != nil {
57 return err
58 }
59 if d.IsDir() || !strings.HasSuffix(path, ".html") {
60 return nil
61 }
62 if bareDidAllowlist[path] {
63 return nil
64 }
65 data, err := fs.ReadFile(Files, path)
66 if err != nil {
67 return err
68 }
69 for i, line := range strings.Split(string(data), "\n") {
70 for _, idx := range didCloseAsUrlSegment.FindAllStringIndex(line, -1) {
71 openIdx := strings.LastIndex(line[:idx[0]], "{{")
72 if openIdx == -1 {
73 continue
74 }
75 action := line[openIdx:idx[1]]
76 if !strings.Contains(action, "resolve") {
77 t.Errorf("%s:%d renders raw DID as URL path segment. Wrap in `resolve` so the handle appears.\n %s",
78 path, i+1, strings.TrimSpace(line))
79 break
80 }
81 }
82 if printfWithUrlFormat.MatchString(line) && didArgRef.MatchString(line) && !strings.Contains(line, "resolve ") {
83 t.Errorf("%s:%d builds a URL path via printf with a raw DID arg. Wrap the DID in `resolve` so handle appears.\n %s",
84 path, i+1, strings.TrimSpace(line))
85 }
86 }
87 return nil
88 })
89 if err != nil {
90 t.Fatal(err)
91 }
92}