1use crate::root_envelopes::{RootEnvelopeMode, serialize_named_json_output};
4use serde::Serialize;
5
6#[derive(Debug, Clone, Serialize)]
9#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
10pub struct ListOutput<Boundaries, Diagnostic> {
11 #[serde(default, skip_serializing_if = "Option::is_none")]
13 pub plugins: Option<Vec<ListPluginOutput>>,
14 #[serde(default, skip_serializing_if = "Option::is_none")]
16 pub file_count: Option<usize>,
17 #[serde(default, skip_serializing_if = "Option::is_none")]
19 pub files: Option<Vec<String>>,
20 #[serde(default, skip_serializing_if = "Option::is_none")]
22 pub entry_point_count: Option<usize>,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub entry_points: Option<Vec<ListEntryPointOutput>>,
26 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub boundaries: Option<Boundaries>,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub workspace_count: Option<usize>,
32 #[serde(default, skip_serializing_if = "Option::is_none")]
34 pub workspaces: Option<Vec<WorkspaceInfo>>,
35 #[serde(default, skip_serializing_if = "Option::is_none")]
37 pub workspace_diagnostics: Option<Vec<Diagnostic>>,
38}
39
40#[derive(Debug, Clone, Serialize)]
42#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
43pub struct ListPluginOutput {
44 pub name: String,
46}
47
48#[derive(Debug, Clone, Serialize)]
50#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
51pub struct ListEntryPointOutput {
52 pub path: String,
54 pub source: String,
56}
57
58#[derive(Debug, Clone, Serialize)]
63#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
64#[cfg_attr(
65 feature = "schema",
66 schemars(title = "fallow list --boundaries --format json")
67)]
68pub struct ListBoundariesOutput<Status, Rule> {
69 pub boundaries: BoundariesListing<Status, Rule>,
71}
72
73#[derive(Debug, Clone, Serialize)]
75#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
76#[cfg_attr(
77 feature = "schema",
78 schemars(title = "fallow workspaces --format json")
79)]
80pub struct WorkspacesOutput<Diagnostic> {
81 pub workspace_count: usize,
83 pub workspaces: Vec<WorkspaceInfo>,
86 pub workspace_diagnostics: Vec<Diagnostic>,
92}
93
94#[derive(Debug, Clone, Serialize)]
96#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
97pub struct WorkspaceInfo {
98 pub name: String,
101 pub path: String,
104 pub is_internal_dependency: bool,
107}
108
109#[derive(Debug, Clone, Serialize)]
111#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
112pub struct BoundariesListing<Status, Rule> {
113 pub configured: bool,
115 pub zone_count: usize,
117 pub zones: Vec<BoundariesListZone>,
119 pub rule_count: usize,
121 pub rules: Vec<BoundariesListRule>,
123 pub logical_group_count: usize,
125 pub logical_groups: Vec<BoundariesListLogicalGroup<Status, Rule>>,
127}
128
129#[derive(Debug, Clone, Serialize)]
132#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
133pub struct BoundariesListZone {
134 pub name: String,
136 pub patterns: Vec<String>,
138 pub file_count: usize,
140}
141
142#[derive(Debug, Clone, Serialize)]
147#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
148pub struct BoundariesListRule {
149 pub from: String,
151 pub allow: Vec<String>,
153}
154
155#[derive(Debug, Clone, Serialize)]
160#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
161pub struct BoundariesListLogicalGroup<Status, Rule> {
162 pub name: String,
164 pub children: Vec<String>,
166 pub auto_discover: Vec<String>,
168 pub status: Status,
170 pub source_zone_index: usize,
172 pub file_count: usize,
174 #[serde(default, skip_serializing_if = "Option::is_none")]
176 pub authored_rule: Option<Rule>,
177 #[serde(default, skip_serializing_if = "Option::is_none")]
179 pub fallback_zone: Option<String>,
180 #[serde(default, skip_serializing_if = "Option::is_none")]
182 pub merged_from: Option<Vec<usize>>,
183 #[serde(default, skip_serializing_if = "Option::is_none")]
185 pub original_zone_root: Option<String>,
186 #[serde(default, skip_serializing_if = "Vec::is_empty")]
188 pub child_source_indices: Vec<usize>,
189}
190
191pub fn serialize_list_boundaries_json_output<T: Serialize>(
197 output: T,
198 mode: RootEnvelopeMode,
199) -> Result<serde_json::Value, serde_json::Error> {
200 serialize_named_json_output(output, "list-boundaries", mode)
201}
202
203pub fn serialize_list_workspaces_json_output<T: Serialize>(
209 output: T,
210 mode: RootEnvelopeMode,
211) -> Result<serde_json::Value, serde_json::Error> {
212 serialize_named_json_output(output, "list-workspaces", mode)
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218 use serde_json::json;
219
220 #[test]
221 fn list_boundaries_json_output_uses_output_owned_root_contract() {
222 let value = serialize_list_boundaries_json_output(
223 json!({"boundaries": {}}),
224 RootEnvelopeMode::Tagged,
225 )
226 .expect("list boundaries output should serialize");
227
228 assert_eq!(value["kind"], "list-boundaries");
229 }
230
231 #[test]
232 fn list_workspaces_json_output_uses_output_owned_root_contract() {
233 let value = serialize_list_workspaces_json_output(
234 json!({"workspace_count": 0, "workspaces": []}),
235 RootEnvelopeMode::Tagged,
236 )
237 .expect("list workspaces output should serialize");
238
239 assert_eq!(value["kind"], "list-workspaces");
240 }
241}