ralph_workflow/rendering/xml/
mod.rs1mod commit_message;
15mod development_plan;
16mod development_result;
17mod fix_result;
18mod helpers;
19mod review_issues;
20
21use crate::files::llm_output_extraction::SkillsMcp;
22use crate::reducer::ui_event::{XmlOutputContext, XmlOutputType};
23
24#[must_use]
28pub fn render_skills_mcp_markdown(skills_mcp: Option<&SkillsMcp>) -> String {
29 let Some(sm) = skills_mcp else {
30 return String::new();
31 };
32
33 let has_structured = !sm.skills.is_empty() || !sm.mcps.is_empty();
34 if !(has_structured || sm.raw_content.is_some()) {
35 return String::new();
36 }
37
38 let skills_lines: Vec<String> = sm
40 .skills
41 .iter()
42 .map(|skill| {
43 if let Some(ref reason) = skill.reason {
44 format!(" - skill: {} \u{2014} {}", skill.name, reason)
45 } else {
46 format!(" - skill: {}", skill.name)
47 }
48 })
49 .collect();
50
51 let mcp_lines: Vec<String> = sm
53 .mcps
54 .iter()
55 .map(|mcp| {
56 if let Some(ref reason) = mcp.reason {
57 format!(" - mcp: {} \u{2014} {}", mcp.name, reason)
58 } else {
59 format!(" - mcp: {}", mcp.name)
60 }
61 })
62 .collect();
63
64 let raw_line: Option<String> = sm.raw_content.as_ref().and_then(|raw| {
66 let trimmed: &str = raw.trim();
67 if trimmed.is_empty() || has_structured {
68 None
69 } else {
70 Some(format!(" - {}", trimmed))
71 }
72 });
73
74 std::iter::once(" - Skills & MCP:".to_string())
76 .chain(skills_lines)
77 .chain(mcp_lines)
78 .chain(raw_line)
79 .collect::<Vec<_>>()
80 .join("\n")
81}
82
83#[must_use]
88pub fn render_xml(
89 xml_type: &XmlOutputType,
90 content: &str,
91 output_context: &Option<XmlOutputContext>,
92) -> String {
93 match xml_type {
94 XmlOutputType::DevelopmentResult => {
95 development_result::render(content, output_context.as_ref())
96 }
97 XmlOutputType::DevelopmentPlan => development_plan::render(content),
98 XmlOutputType::ReviewIssues => review_issues::render(content, output_context.as_ref()),
99 XmlOutputType::FixResult => fix_result::render(content, output_context.as_ref()),
100 XmlOutputType::CommitMessage => commit_message::render(content),
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn test_render_xml_routes_to_development_result() {
110 let content = r"<ralph-development-result>
111<ralph-status>completed</ralph-status>
112<ralph-summary>Done</ralph-summary>
113</ralph-development-result>";
114
115 let output = render_xml(&XmlOutputType::DevelopmentResult, content, &None);
116 assert!(
117 output.contains("✅"),
118 "Should route to development result renderer"
119 );
120 }
121
122 #[test]
123 fn test_render_xml_routes_to_review_issues() {
124 let content = r"<ralph-issues>
125<ralph-issue>Test issue</ralph-issue>
126</ralph-issues>";
127
128 let output = render_xml(&XmlOutputType::ReviewIssues, content, &None);
129 assert!(
130 output.contains("1 issue"),
131 "Should route to issues renderer"
132 );
133 }
134
135 #[test]
136 fn test_render_xml_routes_to_commit_message() {
137 let content = r"<ralph-commit>
138<ralph-subject>feat: add feature</ralph-subject>
139</ralph-commit>";
140
141 let output = render_xml(&XmlOutputType::CommitMessage, content, &None);
142 assert!(
143 output.contains("feat: add feature"),
144 "Should route to commit renderer"
145 );
146 }
147}