use std::sync::OnceLock;
const README: &str = include_str!("../README.md");
const SECTION: &str = "### Setting it up in your client";
#[derive(Debug, Clone, serde::Serialize)]
pub struct Stanza {
pub format: String,
pub text: String,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct Client {
pub name: String,
pub note: String,
pub stanzas: Vec<Stanza>,
}
pub fn clients() -> &'static [Client] {
static PARSED: OnceLock<Vec<Client>> = OnceLock::new();
PARSED.get_or_init(|| parse(README))
}
fn parse(readme: &str) -> Vec<Client> {
let Some(start) = readme.find(SECTION) else {
return Vec::new();
};
let rest = &readme[start + SECTION.len()..];
let section = match rest.find("\n## ") {
Some(end) => &rest[..end],
None => rest,
};
let mut out: Vec<Client> = Vec::new();
let mut lines = section.lines().peekable();
while let Some(line) = lines.next() {
let Some(after) = line.strip_prefix("**") else {
continue;
};
let Some((name, tail)) = after.split_once("**") else {
continue;
};
let mut note = tail.trim_start_matches([' ', '—', '-']).trim().to_string();
for next in lines.by_ref() {
if next.trim().is_empty() {
break;
}
if next.starts_with("```") || next.starts_with("**") {
break;
}
note.push(' ');
note.push_str(next.trim());
}
let mut stanzas = Vec::new();
while let Some(peeked) = lines.peek() {
if peeked.starts_with("**") {
break;
}
let line = lines.next().expect("just peeked");
let Some(format) = line.strip_prefix("```") else {
continue;
};
let mut text = String::new();
for body in lines.by_ref() {
if body.starts_with("```") {
break;
}
text.push_str(body);
text.push('\n');
}
stanzas.push(Stanza {
format: format.trim().to_string(),
text,
});
}
if !stanzas.is_empty() {
out.push(Client {
name: name.trim().to_string(),
note: squeeze(¬e),
stanzas,
});
}
}
out
}
fn squeeze(note: &str) -> String {
note.replace("**", "")
.replace('`', "")
.split_whitespace()
.collect::<Vec<_>>()
.join(" ")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_documented_client_is_parsed_with_at_least_one_stanza() {
let parsed = clients();
assert!(
parsed.len() >= 12,
"only {} clients parsed out of the README",
parsed.len()
);
for client in parsed {
assert!(!client.name.is_empty());
assert!(!client.stanzas.is_empty(), "{} has no stanza", client.name);
for stanza in &client.stanzas {
assert!(
!stanza.text.trim().is_empty(),
"{} has an empty stanza",
client.name
);
}
}
}
#[test]
fn no_parsed_stanza_carries_a_store_path() {
for client in clients() {
for stanza in &client.stanzas {
assert!(
!stanza.text.contains("--store"),
"{} still passes --store:\n{}",
client.name,
stanza.text
);
}
}
}
#[test]
fn claude_code_is_the_first_client_and_has_both_of_its_forms() {
let first = &clients()[0];
assert_eq!(first.name, "Claude Code");
let formats: Vec<&str> = first.stanzas.iter().map(|s| s.format.as_str()).collect();
assert_eq!(formats, vec!["sh", "json"]);
assert_eq!(
first.stanzas[0].text.trim(),
"claude mcp add semlith -- semlith mcp"
);
}
}