spec_driven_docs/services/
agents_render.rs1use crate::domain::instance_config::WritingStyle;
11use crate::domain::marker::{AGENTS_BEGIN, AGENTS_END};
12
13const ROUTE_PLACEHOLDER: &str = "- {writing_style}";
17
18#[must_use]
21pub fn snippet() -> &'static str {
22 crate::embedded::SNIPPETS
23 .get_file("AGENTS-docs.md")
24 .and_then(include_dir::File::contents_utf8)
25 .unwrap_or_default()
26}
27
28#[must_use]
31pub fn route_line(selection: &WritingStyle) -> Option<String> {
32 selection
33 .route()
34 .map(|route| format!("- Read the writing style before you author or edit prose: {route}."))
35}
36
37#[must_use]
40#[allow(
41 clippy::literal_string_with_formatting_args,
42 reason = "the braces are the block template's placeholder, not a formatting argument"
43)]
44pub fn render_block(docs_root: &str, selection: &WritingStyle) -> String {
45 let mut body = String::new();
46 for line in snippet().replace("{docs_root}", docs_root).lines() {
47 let line = if line == ROUTE_PLACEHOLDER {
48 match route_line(selection) {
49 Some(route) => route,
50 None => continue,
51 }
52 } else {
53 line.to_string()
54 };
55 body.push_str(&line);
56 body.push('\n');
57 }
58 let body = body.trim_end_matches('\n');
59 format!("{AGENTS_BEGIN}\n{body}\n{AGENTS_END}\n")
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use crate::domain::instance_config::WritingSource;
66
67 #[test]
68 fn the_block_carries_the_markers_and_the_root() {
69 let block = render_block("docs", &WritingStyle::default());
70 assert!(block.starts_with("<!-- BEGIN spec-driven-docs docs -->\n"));
71 assert!(block.ends_with("<!-- END spec-driven-docs docs -->\n"));
72 assert!(block.contains(
73 "Read the writing style before you author or edit prose: `sdd method writing-style`."
74 ));
75 assert!(!block.contains("{docs_root}"));
76 assert!(!block.contains("{writing_style}"));
77 assert!(!block.contains("simple-english"));
78 }
79
80 #[test]
81 fn the_underscore_root_reaches_the_block() {
82 let block = render_block("_docs", &WritingStyle::default());
83 assert!(block.contains(
84 "Read the writing style before you author or edit prose: `sdd method writing-style`."
85 ));
86 assert!(block.contains("`_docs/specs/SPEC-<domain>.md`"));
87 }
88
89 #[test]
90 fn the_route_matches_each_selection() {
91 let project = WritingStyle {
92 source: WritingSource::Project,
93 path: Some("docs/STYLE.md".to_string()),
94 };
95 assert!(
96 render_block("docs", &project).contains(
97 "Read the writing style before you author or edit prose: `docs/STYLE.md`."
98 )
99 );
100 let none = WritingStyle {
101 source: WritingSource::None,
102 path: None,
103 };
104 let block = render_block("docs", &none);
105 assert!(!block.contains("writing style"), "{block}");
106 assert!(!block.contains("{writing_style}"));
107 assert!(
108 !block.contains("\n\n<!-- END"),
109 "the removed route left a blank line:\n{block}"
110 );
111 }
112}