fallow_api/
list_output.rs1use fallow_output::{
4 ListEntryPointOutput, ListOutput, ListPluginOutput, RootEnvelopeMode, WorkspacesOutput,
5};
6use serde::Serialize;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum ListJsonEnvelope {
11 Plain,
13 Boundaries,
15 Workspaces,
17}
18
19pub struct ListJsonOutputInput<Boundaries, Diagnostic> {
21 pub plugins: Option<Vec<String>>,
22 pub files: Option<Vec<String>>,
23 pub entry_points: Option<Vec<ListEntryPointOutput>>,
24 pub boundaries: Option<Boundaries>,
25 pub workspaces: Option<WorkspacesOutput<Diagnostic>>,
26}
27
28#[must_use]
30pub fn build_list_json_output<Boundaries, Diagnostic>(
31 input: ListJsonOutputInput<Boundaries, Diagnostic>,
32) -> ListOutput<Boundaries, Diagnostic> {
33 let plugins = input.plugins.map(|plugins| {
34 plugins
35 .into_iter()
36 .map(|name| ListPluginOutput { name })
37 .collect()
38 });
39 let file_count = input.files.as_ref().map(Vec::len);
40 let entry_point_count = input.entry_points.as_ref().map(Vec::len);
41 let (workspace_count, workspaces, workspace_diagnostics) =
42 input.workspaces.map_or((None, None, None), |workspaces| {
43 (
44 Some(workspaces.workspace_count),
45 Some(workspaces.workspaces),
46 Some(workspaces.workspace_diagnostics),
47 )
48 });
49
50 ListOutput {
51 plugins,
52 file_count,
53 files: input.files,
54 entry_point_count,
55 entry_points: input.entry_points,
56 boundaries: input.boundaries,
57 workspace_count,
58 workspaces,
59 workspace_diagnostics,
60 }
61}
62
63pub fn serialize_list_json_output<Boundaries, Diagnostic>(
70 input: ListJsonOutputInput<Boundaries, Diagnostic>,
71 mode: RootEnvelopeMode,
72 envelope: ListJsonEnvelope,
73) -> Result<serde_json::Value, serde_json::Error>
74where
75 Boundaries: Serialize,
76 Diagnostic: Serialize,
77{
78 let output = build_list_json_output(input);
79 match envelope {
80 ListJsonEnvelope::Plain => serde_json::to_value(output),
81 ListJsonEnvelope::Boundaries => {
82 fallow_output::serialize_list_boundaries_json_output(output, mode)
83 }
84 ListJsonEnvelope::Workspaces => {
85 fallow_output::serialize_list_workspaces_json_output(output, mode)
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use fallow_output::ListEntryPointOutput;
93 use serde_json::json;
94
95 use super::*;
96
97 #[test]
98 fn list_json_output_preserves_plain_legacy_body() {
99 let value = serialize_list_json_output::<serde_json::Value, serde_json::Value>(
100 ListJsonOutputInput {
101 plugins: Some(vec!["react".to_string()]),
102 files: Some(vec!["src/index.ts".to_string()]),
103 entry_points: Some(vec![ListEntryPointOutput {
104 path: "src/index.ts".to_string(),
105 source: "package.json main".to_string(),
106 }]),
107 boundaries: None,
108 workspaces: None,
109 },
110 RootEnvelopeMode::Tagged,
111 ListJsonEnvelope::Plain,
112 )
113 .expect("list output should serialize");
114
115 assert_eq!(value["plugins"][0]["name"], "react");
116 assert_eq!(value["file_count"], 1);
117 assert_eq!(value["files"], json!(["src/index.ts"]));
118 assert_eq!(value["entry_point_count"], 1);
119 assert!(value.get("kind").is_none());
120 }
121
122 #[test]
123 fn list_json_output_wraps_boundary_payloads() {
124 let value = serialize_list_json_output::<serde_json::Value, serde_json::Value>(
125 ListJsonOutputInput {
126 plugins: None,
127 files: None,
128 entry_points: None,
129 boundaries: Some(json!({"configured": false})),
130 workspaces: None,
131 },
132 RootEnvelopeMode::Tagged,
133 ListJsonEnvelope::Boundaries,
134 )
135 .expect("list output should serialize");
136
137 assert_eq!(value["kind"], "list-boundaries");
138 assert_eq!(value["boundaries"]["configured"], false);
139 }
140}