Add JSON and HTML render formats - #23
Merged
Merged
Conversation
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
approved these changes
Apr 14, 2026
obey-agent
left a comment
Member
There was a problem hiding this comment.
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, andjust buildlocally. - Smoke validation succeeded with
camp-graph render -f json --no-save | jq ...andcamp-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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two new output formats to
camp-graph renderalongside the existing DOT, SVG, and PNG:--format json— Versioned envelope ({version, nodes, edges}) with deterministic sort order, suitable for piping intojqor feeding custom visualizations (vis.js, d3, Cytoscape, etc.). Reuses the existingjsonstruct tags ongraph.Nodeandgraph.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, andprefers-color-schemelight/dark support.Zero new dependencies — both formats build on the stdlib (
encoding/json,html/template,embed) and the existinggo-graphvizpipeline (HTML reusesRenderGraphvizto produce the embedded SVG).Design highlights
"version": "1"field so consumers can detect breaking shape changes.styleForNode→StyleForNodeso the HTML legend reuses the same color mapping as DOT/SVG/PNG — single source of truth.embed.FS.templates/graph.html.tmplis embedded at build time; no runtime filesystem dependencies.| jqpipelines). HTML requires--outputor the default.campaign/graphs/auto-save, matching SVG/PNG semantics.Changes
internal/render/format.goFormatJSON,FormatHTML+ parse casesinternal/render/json.goRenderJSONwith deterministic sortinternal/render/html.goRenderHTMLwith legend + inlined SVGinternal/render/templates/graph.html.tmplinternal/render/renderer.gointernal/render/dot.goStyleForNodefor cross-renderer usecmd/camp-graph/root.goREADME.mdinternal/render/*_test.goTest plan
just lint— fmt + vet cleanjust test unit— 68/68 tests pass (5 new across render package)just build— clean binarycamp-graph render -f json --no-save | jq '{version, node_count: (.nodes|length)}'→{"version": "1", "node_count": 934}on real campaigncamp-graph render -f html -o /tmp/g.html→ 1.1MB self-contained file, renders correctly in browser-f dot,-f svg,-f pngall unchanged-f html --no-savewithout--outputreturns clear errorgo.mod/go.sumExample output