renderGraphViewHTML injects the data into the template and writes the file.
(data GraphData, output string)
| 527 | |
| 528 | // renderGraphViewHTML injects the data into the template and writes the file. |
| 529 | func renderGraphViewHTML(data GraphData, output string) (string, error) { |
| 530 | payload, err := json.Marshal(data) // HTMLEscape on by default → safe inside <script> |
| 531 | if err != nil { |
| 532 | return "", fmt.Errorf("encoding graph data: %w", err) |
| 533 | } |
| 534 | html := strings.Replace(graphViewTemplate, graphViewDataPlaceholder, string(payload), 1) |
| 535 | |
| 536 | path := output |
| 537 | if path == "" { |
| 538 | f, terr := os.CreateTemp("", "chatcli-graph-*.html") |
| 539 | if terr != nil { |
| 540 | return "", fmt.Errorf("creating temp file: %w", terr) |
| 541 | } |
| 542 | path = f.Name() |
| 543 | _ = f.Close() |
| 544 | } else { |
| 545 | if dir := filepath.Dir(path); dir != "" { |
| 546 | if err := os.MkdirAll(dir, 0o750); err != nil { |
| 547 | return "", fmt.Errorf("creating output dir: %w", err) |
| 548 | } |
| 549 | } |
| 550 | } |
| 551 | if err := os.WriteFile(path, []byte(html), 0o600); err != nil { |
| 552 | return "", fmt.Errorf("writing %q: %w", path, err) |
| 553 | } |
| 554 | abs, err := filepath.Abs(path) |
| 555 | if err != nil { |
| 556 | abs = path |
| 557 | } |
| 558 | return abs, nil |
| 559 | } |
| 560 | |
| 561 | // openInBrowser opens a local file in the OS default browser. Mirrors |
| 562 | // auth.openBrowser but kept package-local to avoid a cli→auth coupling. |