use std::fs;
use std::path::{Path, PathBuf};
pub(super) fn collapse_repeated_underscores(value: &str) -> String {
let mut out = String::with_capacity(value.len());
let mut last_underscore = false;
for ch in value.chars() {
if ch == '_' {
if !last_underscore {
out.push(ch);
}
last_underscore = true;
} else {
out.push(ch);
last_underscore = false;
}
}
out
}
pub(super) fn generated_header(command: &str, language: &str) -> String {
match language {
"typescript" => format!(
"// GENERATED by `{command}` - do not edit by hand.\n\
// Source: Harn adapter schemas and Rust wire vocabulary.\n\n"
),
"swift" => format!(
"// GENERATED by `{command}` - do not edit by hand.\n\
// Source: Harn adapter schemas and Rust wire vocabulary.\n\n"
),
_ => String::new(),
}
}
pub(super) fn schema_provenance(relative_path: &str) -> Result<serde_json::Value, String> {
let source: serde_json::Value = serde_json::from_str(&read_repo_text(relative_path)?)
.map_err(|error| format!("failed to parse {relative_path}: {error}"))?;
Ok(source
.get("x-harn-provenance")
.cloned()
.unwrap_or(serde_json::Value::Null))
}
pub(super) fn read_repo_text(relative_path: &str) -> Result<String, String> {
let path = repo_root().join(relative_path);
fs::read_to_string(&path).map_err(|error| format!("failed to read {}: {error}", path.display()))
}
pub(super) fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("..").join("..")
}
pub(super) fn json_string_literal(value: &str) -> String {
serde_json::to_string(value).expect("string serializes")
}
pub(super) fn ensure_trailing_newline(mut text: String) -> String {
if !text.ends_with('\n') {
text.push('\n');
}
text
}
pub(super) fn normalize_line_endings(text: &str) -> String {
text.replace("\r\n", "\n").replace('\r', "\n")
}