Skip to content

Add JSON and HTML render formats - #23

Merged
lancekrogers merged 2 commits into
mainfrom
feature/html-json-formats
Apr 14, 2026
Merged

Add JSON and HTML render formats#23
lancekrogers merged 2 commits into
mainfrom
feature/html-json-formats

Conversation

@lancekrogers

Copy link
Copy Markdown
Member

Summary

Adds two new output formats to camp-graph render alongside the existing DOT, SVG, and PNG:

  • --format json — Versioned envelope ({version, nodes, edges}) with deterministic sort order, suitable for piping into jq or feeding custom visualizations (vis.js, d3, Cytoscape, etc.). Reuses the existing json struct tags on graph.Node and graph.Edge.
  • --format html — Self-contained browser-viewable document with inlined SVG. No JavaScript, no CDN, no external fonts. Includes a node-type legend, node/edge count summary, and prefers-color-scheme light/dark support.

Zero new dependencies — both formats build on the stdlib (encoding/json, html/template, embed) and the existing go-graphviz pipeline (HTML reuses RenderGraphviz to produce the embedded SVG).

Design highlights

  • Deterministic JSON. Nodes sorted by ID, edges sorted by (from, to, type). Re-rendering the same graph produces byte-identical output — enables diffable artifacts and reliable round-trip tests.
  • Schema versioning. JSON envelope includes a "version": "1" field so consumers can detect breaking shape changes.
  • Shared palette. Renamed unexported styleForNodeStyleForNode so the HTML legend reuses the same color mapping as DOT/SVG/PNG — single source of truth.
  • Template via embed.FS. templates/graph.html.tmpl is embedded at build time; no runtime filesystem dependencies.
  • Stdout behavior. JSON streams to stdout like DOT (for | jq pipelines). HTML requires --output or the default .campaign/graphs/ auto-save, matching SVG/PNG semantics.

Changes

File Change
internal/render/format.go Add FormatJSON, FormatHTML + parse cases
internal/render/json.go NewRenderJSON with deterministic sort
internal/render/html.go NewRenderHTML with legend + inlined SVG
internal/render/templates/graph.html.tmpl New — embedded HTML template
internal/render/renderer.go Dispatch for JSON and HTML
internal/render/dot.go Export StyleForNode for cross-renderer use
cmd/camp-graph/root.go Flag help, stdout branch widening
README.md Usage examples for new formats
internal/render/*_test.go Full test coverage for both new formats

Test plan

  • just lint — fmt + vet clean
  • just test unit — 68/68 tests pass (5 new across render package)
  • just build — clean binary
  • Smoke: camp-graph render -f json --no-save | jq '{version, node_count: (.nodes|length)}'{"version": "1", "node_count": 934} on real campaign
  • Smoke: camp-graph render -f html -o /tmp/g.html → 1.1MB self-contained file, renders correctly in browser
  • Regression: -f dot, -f svg, -f png all unchanged
  • Error path: -f html --no-save without --output returns clear error
  • No new entries in go.mod / go.sum

Example output

$ camp-graph render -f json --no-save | jq '.version, (.nodes|length), (.edges|length)'
"1"
934
722

$ camp-graph render -f html -o campaign.html && open campaign.html

Extends internal/render with two new output formats alongside DOT, SVG, and PNG.

JSON: versioned envelope ({version, nodes, edges}) with deterministic sort
order by node ID and edge key, so output is diffable and git-friendly. Reuses
the existing json struct tags on graph.Node and graph.Edge.

HTML: self-contained browser-viewable document with inlined SVG (no JS, no
CDN, no external fonts). Uses embed.FS for the template, a legend derived
from the exported StyleForNode palette, and a light/dark color scheme via
prefers-color-scheme. Reuses the existing RenderGraphviz pipeline to
generate the embedded SVG.

Renames unexported styleForNode to StyleForNode so html.go can share the
node-type palette with DOT output.

Tests cover: parse cases for both new formats, deterministic JSON output
(byte-for-byte across renders), round-trip node/edge counts, and HTML
smoke test ensuring no external script/stylesheet references.
- render --format flag help updated to list json and html
- renderCmd Short/Long updated to mention all five formats
- stdout branch widened so json streams like dot (for jq pipelines)
- no-save+no-output error path updated to permit both text formats
- README quickstart shows -f json and -f html examples

@obey-agent obey-agent left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: Approve

Overview:
This PR adds json and html render formats in the right place: the new behavior stays isolated to the render layer, keeps the CLI surface coherent, and does not introduce new dependencies or release-process churn. I re-ran the repo gates locally and smoke-tested both formats against the live campaign graph; the implementation is production-ready.

Key Findings:

  • No blocking findings.

What's Done Well:

  • JSON output is deterministic and wrapped in a versioned envelope, which is the right contract for downstream tooling.
  • HTML rendering reuses the existing Graphviz/SVG path and the existing node-style palette instead of creating a parallel rendering stack.
  • Tests cover parser changes plus JSON/HTML renderer behavior, and the branch also passed just lint, just test unit, and just build locally.
  • Smoke validation succeeded with camp-graph render -f json --no-save | jq ... and camp-graph render -f html -o ... against the real campaign graph.

Residual Risk:

  • HTML correctness is covered structurally rather than visually; if the team wants stronger regression protection later, the next step would be a snapshot or browser-level golden check for the generated HTML/SVG.

Staff Standard:
Yes. I would be comfortable submitting this as my own work.

@lancekrogers
lancekrogers merged commit 2430a81 into main Apr 14, 2026
1 check passed
@lancekrogers
lancekrogers deleted the feature/html-json-formats branch April 14, 2026 05:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants