From 88b261d478ba5e5b093f2280799a1bc6b567b6bf Mon Sep 17 00:00:00 2001
From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com>
Date: Sat, 28 Feb 2026 02:17:35 +0000
Subject: [PATCH] =?UTF-8?q?fix:=20combine=20graph=20visualization=20fixes?=
=?UTF-8?q?=20=E2=80=94=20populate=20ArchData,=20fix=20double-encoding,=20?=
=?UTF-8?q?fix=20len()?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Combines changes from both fix branches to fully resolve graph rendering:
1. Populate ArchData (domain/subdomain force graph) in renderHomepage
2. Populate entity ChartData (profile chart) in renderEntityPage
3. Fix homepage chart JSON field names (label/topEntries → name/count/slug)
4. Change template.HTML → template.JS for all JSON in `,
+ data: struct {
+ Data template.JS
+ }{
+ Data: template.JS(`{"nodes":[{"id":"root","name":"Root"}],"links":[]}`),
+ },
+ scriptID: "test-data",
+ },
+ {
+ name: "template.JS with nested JSON",
+ tmplText: ``,
+ data: struct {
+ ChartData template.JS
+ }{
+ ChartData: template.JS(`{"taxonomies":[{"label":"Category","topEntries":[{"name":"Web","count":5}]}],"totalEntities":42}`),
+ },
+ scriptID: "chart-data",
+ },
+ {
+ name: "empty template.JS produces empty output",
+ tmplText: ``,
+ data: struct {
+ ChartData template.JS
+ }{
+ ChartData: template.JS(""),
+ },
+ scriptID: "empty-data",
+ },
+ }
+
+ scriptContentRe := regexp.MustCompile(``)
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ tmpl, err := template.New("test").Parse(tt.tmplText)
+ if err != nil {
+ t.Fatalf("failed to parse template: %v", err)
+ }
+
+ var buf bytes.Buffer
+ if err := tmpl.Execute(&buf, tt.data); err != nil {
+ t.Fatalf("failed to execute template: %v", err)
+ }
+
+ rendered := buf.String()
+
+ matches := scriptContentRe.FindStringSubmatch(rendered)
+ if matches == nil {
+ t.Fatalf("no `
+ tmpl, err := template.New("test").Parse(tmplText)
+ if err != nil {
+ t.Fatalf("failed to parse template: %v", err)
+ }
+
+ data := struct {
+ Data template.HTML
+ }{
+ Data: template.HTML(`{"nodes":[{"id":"root"}]}`),
+ }
+
+ var buf bytes.Buffer
+ if err := tmpl.Execute(&buf, data); err != nil {
+ t.Fatalf("failed to execute template: %v", err)
+ }
+
+ rendered := buf.String()
+
+ // Extract content between script tags
+ re := regexp.MustCompile(``)
+ matches := re.FindStringSubmatch(rendered)
+ if matches == nil {
+ t.Fatal("no script tag found")
+ }
+ content := matches[1]
+
+ // With template.HTML in a script context, html/template double-encodes it.
+ // The content should NOT parse as a valid JSON object directly.
+ var result interface{}
+ if err := json.Unmarshal([]byte(content), &result); err != nil {
+ // If it doesn't parse at all, that's also a form of brokenness
+ t.Logf("template.HTML in script tag produced unparseable content (expected): %s", content)
+ return
+ }
+
+ // If it parses as a string, it's the double-encoding we saw
+ if s, isString := result.(string); isString {
+ maxLen := len(s)
+ if maxLen > 60 {
+ maxLen = 60
+ }
+ t.Logf("Confirmed: template.HTML causes double-encoding in script tags. JSON.parse returns string: %s", s[:maxLen])
+ return
+ }
+
+ // If it somehow parses as an object, that's unexpected for template.HTML in script context
+ t.Log("Warning: template.HTML in script tag parsed as object — behavior may have changed in this Go version")
+}
+
+// TestLengthWithVariousTypes verifies the reflect-based length function
+// works with all slice types including taxonomy.Entry slices.
+func TestLengthWithVariousTypes(t *testing.T) {
+ type CustomStruct struct {
+ Name string
+ }
+
+ tests := []struct {
+ name string
+ input interface{}
+ expected int
+ }{
+ {"nil", nil, 0},
+ {"empty string", "", 0},
+ {"string", "hello", 5},
+ {"string slice", []string{"a", "b", "c"}, 3},
+ {"empty slice", []string{}, 0},
+ {"interface slice", []interface{}{1, "two", 3.0}, 3},
+ {"map", map[string]interface{}{"a": 1, "b": 2}, 2},
+ {"custom struct slice", []CustomStruct{{Name: "a"}, {Name: "b"}}, 2},
+ {"int slice", []int{1, 2, 3, 4, 5}, 5},
+ {"map string string", map[string]string{"a": "1"}, 1},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := length(tt.input)
+ if got != tt.expected {
+ t.Errorf("length(%v) = %d, want %d", tt.input, got, tt.expected)
+ }
+ })
+ }
+}