1use anyhow::{Context, Result};
6use code_ranker_graph::snapshot::Snapshot;
7
8pub fn extract_embedded_snapshot(html: &str, id: &str) -> Option<Result<Snapshot>> {
12 let needle = format!("id=\"{id}\">");
13 let start = html.find(&needle)? + needle.len();
14 let end = start + html[start..].find("</script>")?;
15 let body = html[start..end].trim();
16 if body.is_empty() || body == "null" {
17 return None;
18 }
19 let json = body.replace("<\\/", "</");
21 Some(serde_json::from_str(&json).with_context(|| format!("parsing embedded snapshot `{id}`")))
22}
23
24const ASSET_CSS_BASE: &str = include_str!("assets/base.css");
29const ASSET_CSS_MAP: &str = include_str!("assets/map.css");
30const ASSET_CSS_MODAL: &str = include_str!("assets/modal.css");
31const ASSET_CSS_TABLES: &str = include_str!("assets/tables.css");
32const ASSET_CSS_EXPORT: &str = include_str!("assets/export.css");
33const ASSET_CSS_SNAP: &str = include_str!("assets/snap.css");
34const ASSET_CSS_MAP_SVG: &str = include_str!("assets/map-svg.css");
35const ASSET_GV: &str = include_str!("assets/graphviz.umd.js");
36const ASSET_SNARKDOWN: &str = include_str!("assets/snarkdown.umd.js");
37const ASSET_SCHEMA: &str = include_str!("assets/schema.js");
38const ASSET_GROUPING: &str = include_str!("assets/grouping.js");
39const ASSET_DIFF: &str = include_str!("assets/diff.js");
40const ASSET_LAYOUT: &str = include_str!("assets/layout.js");
41const ASSET_UTILS: &str = include_str!("assets/utils.js");
42const ASSET_TOOLTIP: &str = include_str!("assets/tooltip.js");
43const ASSET_MODAL: &str = include_str!("assets/modal.js");
44const ASSET_PANZOOM: &str = include_str!("assets/panzoom.js");
45const ASSET_SOURCE_LINKS: &str = include_str!("assets/source-links.js");
46const ASSET_NODE_POPUP: &str = include_str!("assets/node-popup.js");
47const ASSET_MODAL_CONTENT: &str = include_str!("assets/modal-content.js");
48const ASSET_MAP_INTERACTIONS: &str = include_str!("assets/map-interactions.js");
49const ASSET_MAP_RENDER: &str = include_str!("assets/map-render.js");
50const ASSET_UI: &str = include_str!("assets/ui.js");
51const ASSET_SUMMARY: &str = include_str!("assets/summary.js");
52const ASSET_EXPORT_POPUP: &str = include_str!("assets/export-popup.js");
53const ASSET_NODE_TABLE: &str = include_str!("assets/node-table.js");
54const ASSET_NAV: &str = include_str!("assets/nav.js");
55const ASSET_VIEW_STATE: &str = include_str!("assets/view-state.js");
56const ASSET_SNAP_CONTROLS: &str = include_str!("assets/snap-controls.js");
57const ASSET_APP: &str = include_str!("assets/app.js");
58const ASSET_HTML: &str = include_str!("assets/index.html");
59
60pub fn render_html_viewer(baseline: Option<&Snapshot>, current: Option<&Snapshot>) -> String {
66 let embed = |id: &str, snap: Option<&Snapshot>| {
69 let json = match snap {
70 Some(s) => {
71 code_ranker_graph::serialize::to_canonical_string(s).expect("serialize snapshot")
72 }
73 None => "null".to_string(),
74 };
75 format!(
76 "<script type=\"application/json\" id=\"{id}\">{}</script>",
77 json.replace("</", "<\\/")
78 )
79 };
80 let data_script = format!(
81 "{}\n{}",
82 embed("cs-baseline", baseline),
83 embed("cs-current", current),
84 );
85
86 ASSET_HTML
87 .replace(
88 r#"<link rel="stylesheet" href="./index.css">"#,
89 &format!(
90 "<style>{}{}{}{}{}{}{}</style>",
91 ASSET_CSS_BASE,
92 ASSET_CSS_MAP,
93 ASSET_CSS_MODAL,
94 ASSET_CSS_TABLES,
95 ASSET_CSS_EXPORT,
96 ASSET_CSS_SNAP,
97 ASSET_CSS_MAP_SVG,
98 ),
99 )
100 .replace(
101 r#"<script src="./graphviz.umd.js"></script>"#,
102 &format!("<script>{}</script>", ASSET_GV),
103 )
104 .replace(
105 r#"<script src="./snarkdown.umd.js"></script>"#,
106 &format!("<script>{}</script>", ASSET_SNARKDOWN),
107 )
108 .replace(r#"<script src="./data.js"></script>"#, &data_script)
109 .replace(
110 r#"<script src="./schema.js"></script>"#,
111 &format!("<script>{}</script>", ASSET_SCHEMA),
112 )
113 .replace(
114 r#"<script src="./grouping.js"></script>"#,
115 &format!("<script>{}</script>", ASSET_GROUPING),
116 )
117 .replace(
118 r#"<script src="./diff.js"></script>"#,
119 &format!("<script>{}</script>", ASSET_DIFF),
120 )
121 .replace(
122 r#"<script src="./layout.js"></script>"#,
123 &format!("<script>{}</script>", ASSET_LAYOUT),
124 )
125 .replace(
126 r#"<script src="./utils.js"></script>"#,
127 &format!("<script>{}</script>", ASSET_UTILS),
128 )
129 .replace(
130 r#"<script src="./tooltip.js"></script>"#,
131 &format!("<script>{}</script>", ASSET_TOOLTIP),
132 )
133 .replace(
134 r#"<script src="./modal.js"></script>"#,
135 &format!("<script>{}</script>", ASSET_MODAL),
136 )
137 .replace(
138 r#"<script src="./panzoom.js"></script>"#,
139 &format!("<script>{}</script>", ASSET_PANZOOM),
140 )
141 .replace(
142 r#"<script src="./source-links.js"></script>"#,
143 &format!("<script>{}</script>", ASSET_SOURCE_LINKS),
144 )
145 .replace(
146 r#"<script src="./node-popup.js"></script>"#,
147 &format!("<script>{}</script>", ASSET_NODE_POPUP),
148 )
149 .replace(
150 r#"<script src="./modal-content.js"></script>"#,
151 &format!("<script>{}</script>", ASSET_MODAL_CONTENT),
152 )
153 .replace(
154 r#"<script src="./map-interactions.js"></script>"#,
155 &format!("<script>{}</script>", ASSET_MAP_INTERACTIONS),
156 )
157 .replace(
158 r#"<script src="./map-render.js"></script>"#,
159 &format!("<script>{}</script>", ASSET_MAP_RENDER),
160 )
161 .replace(
162 r#"<script src="./ui.js"></script>"#,
163 &format!("<script>{}</script>", ASSET_UI),
164 )
165 .replace(
166 r#"<script src="./summary.js"></script>"#,
167 &format!("<script>{}</script>", ASSET_SUMMARY),
168 )
169 .replace(
170 r#"<script src="./export-popup.js"></script>"#,
171 &format!("<script>{}</script>", ASSET_EXPORT_POPUP),
172 )
173 .replace(
174 r#"<script src="./node-table.js"></script>"#,
175 &format!("<script>{}</script>", ASSET_NODE_TABLE),
176 )
177 .replace(
178 r#"<script src="./nav.js"></script>"#,
179 &format!("<script>{}</script>", ASSET_NAV),
180 )
181 .replace(
182 r#"<script src="./view-state.js"></script>"#,
183 &format!("<script>{}</script>", ASSET_VIEW_STATE),
184 )
185 .replace(
186 r#"<script src="./snap-controls.js"></script>"#,
187 &format!("<script>{}</script>", ASSET_SNAP_CONTROLS),
188 )
189 .replace(
190 r#"<script src="./app.js"></script>"#,
191 &format!("<script>{}</script>", ASSET_APP),
192 )
193}