use std::fmt::Write as _;
#[must_use]
pub fn concat(parts: &[(String, String)]) -> String {
let mut out = String::new();
for (name, body) in parts {
let _ = writeln!(out);
let _ = writeln!(out, "<!-- # from bundle: {name} -->");
out.push_str(body);
if !body.ends_with('\n') {
out.push('\n');
}
}
out
}
#[must_use]
pub fn concat_with_rules(parts: &[(String, String)], rules: &[super::rules::RuleFile]) -> String {
let mut out = concat(parts);
for r in rules {
let _ = writeln!(out);
let _ = writeln!(
out,
"<!-- # from bundle: {} {} -->",
r.bundle,
r.rel.display()
);
out.push_str(&r.body);
if !r.body.ends_with('\n') {
out.push('\n');
}
}
out
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn empty_input_yields_empty_string() {
assert_eq!(concat(&[]), "");
}
#[test]
fn concat_with_rules_appends_bodies() {
use super::super::rules::RuleFile;
use std::path::PathBuf;
let parts = vec![("base".into(), "# base\n".into())];
let rules = vec![RuleFile {
bundle: "base".into(),
rel: PathBuf::from("rules/rust.md"),
frontmatter: Some("scope: rust".into()),
body: "# rust rules\n".into(),
raw: "---\nscope: rust\n---\n# rust rules\n".into(),
}];
let s = concat_with_rules(&parts, &rules);
assert!(s.contains("<!-- # from bundle: base -->"));
assert!(s.contains("<!-- # from bundle: base rules/rust.md -->"));
assert!(s.contains("# rust rules"));
assert!(!s.contains("scope: rust"));
}
#[test]
fn each_part_gets_provenance_header() {
let s = concat(&[
("base".into(), "# base\n".into()),
("rust".into(), "# rust".into()),
]);
assert!(s.contains("<!-- # from bundle: base -->"));
assert!(s.contains("<!-- # from bundle: rust -->"));
assert!(s.ends_with('\n'));
}
}