1#![forbid(unsafe_code)]
3
4mod export;
5mod server;
6
7use minco_project_view::{
8 DerivedSummary, EdgeKind, InputUsage, ProjectIdentity, ProjectView, ViewLimits,
9};
10use serde::Serialize;
11use std::{collections::BTreeMap, fmt::Write as _};
12
13pub use export::{ExportFormat, ExportReport, ExportRequest, WorkbenchError, export_project_view};
14pub use server::{bind_loopback, serve_loopback};
15
16pub const WORKBENCH_SCHEMA_VERSION: u32 = 1;
17
18pub(crate) fn render_mermaid(view: &ProjectView) -> String {
19 let mut rendered = String::from("flowchart TD\n");
20 let mut node_indexes = BTreeMap::new();
21 for (index, node) in view.nodes.iter().enumerate() {
22 node_indexes.insert(node.id.as_str(), index);
23 let label = escape_mermaid_label(&node.label);
24 writeln!(&mut rendered, " n{index}[{label}]").expect("writing to a String is infallible");
25 }
26 for edge in &view.edges {
27 let (Some(from), Some(to)) = (
28 node_indexes.get(edge.from.as_str()),
29 node_indexes.get(edge.to.as_str()),
30 ) else {
31 continue;
32 };
33 writeln!(
34 &mut rendered,
35 " n{from} -->|{}| n{to}",
36 edge_kind(edge.kind)
37 )
38 .expect("writing to a String is infallible");
39 }
40 rendered
41}
42
43fn escape_mermaid_label(value: &str) -> String {
44 let escaped = value
45 .replace('&', "&")
46 .replace('<', "<")
47 .replace('>', ">");
48 serde_json::to_string(&escaped).expect("serializing a String is infallible")
49}
50
51const fn edge_kind(kind: EdgeKind) -> &'static str {
52 match kind {
53 EdgeKind::Contains => "contains",
54 EdgeKind::DependsOn => "depends_on",
55 EdgeKind::BelongsTo => "belongs_to",
56 EdgeKind::Implements => "implements",
57 EdgeKind::Exposes => "exposes",
58 }
59}
60
61#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
62pub struct WorkbenchCheckReport {
63 pub schema_version: u32,
64 pub status: &'static str,
65 pub mode: &'static str,
66 pub read_only: bool,
67 pub listening_sockets: usize,
68 pub writes: usize,
69 pub project: ProjectIdentity,
70 pub summary: DerivedSummary,
71 pub limits: ViewLimits,
72 pub input_usage: InputUsage,
73}
74
75#[must_use]
76pub fn check_report(view: &ProjectView) -> WorkbenchCheckReport {
77 WorkbenchCheckReport {
78 schema_version: WORKBENCH_SCHEMA_VERSION,
79 status: "ok",
80 mode: "check",
81 read_only: true,
82 listening_sockets: 0,
83 writes: 0,
84 project: view.project.clone(),
85 summary: view.summary.clone(),
86 limits: view.limits,
87 input_usage: view.input_usage.clone(),
88 }
89}