#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PublicRegistry {
pub base: String,
pub store: Option<String>,
}
impl PublicRegistry {
pub fn versions_url(&self, name: &str) -> String {
self.with_store(format!("{}/{}/versions", self.base, name))
}
pub fn archive_url(&self, name: &str, version: &str) -> String {
self.with_store(format!("{}/{}/{}/archive", self.base, name, version))
}
pub fn contract_url(&self, name: &str, version: &str) -> String {
self.with_store(format!("{}/{}/{}/contract", self.base, name, version))
}
fn with_store(&self, url: String) -> String {
match &self.store {
Some(s) => format!("{url}?store={s}"),
None => url,
}
}
}
pub fn public(registry: &str) -> Option<PublicRegistry> {
let trimmed = registry.trim().trim_end_matches('/');
let (scheme, rest) = match trimmed.split_once("://") {
Some((s, r)) => (s, r),
None => ("https", trimmed),
};
let mut segs = rest.split('/').filter(|s| !s.is_empty());
let host = segs.next()?;
let tenant = segs.next()?; if host.is_empty() || tenant.is_empty() {
return None;
}
let store = segs.next().map(str::to_string);
Some(PublicRegistry {
base: format!("{scheme}://{host}/v1/public/{tenant}"),
store,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn flat_store_registry() {
let r = public("vcs.lexlang.org/alpibrusl").unwrap();
assert_eq!(r.base, "https://vcs.lexlang.org/v1/public/alpibrusl");
assert_eq!(r.store, None);
assert_eq!(
r.versions_url("lex-agent"),
"https://vcs.lexlang.org/v1/public/alpibrusl/lex-agent/versions"
);
assert_eq!(
r.archive_url("lex-agent", "0.1.0"),
"https://vcs.lexlang.org/v1/public/alpibrusl/lex-agent/0.1.0/archive"
);
}
#[test]
fn named_store_registry_adds_store_query() {
let r = public("vcs.lexlang.org/lex-official/lex-nt").unwrap();
assert_eq!(r.base, "https://vcs.lexlang.org/v1/public/lex-official");
assert_eq!(r.store.as_deref(), Some("lex-nt"));
assert_eq!(
r.versions_url("lex-nt"),
"https://vcs.lexlang.org/v1/public/lex-official/lex-nt/versions?store=lex-nt"
);
assert_eq!(
r.contract_url("lex-nt", "1.2.0"),
"https://vcs.lexlang.org/v1/public/lex-official/lex-nt/1.2.0/contract?store=lex-nt"
);
}
#[test]
fn explicit_scheme_is_preserved() {
let r = public("http://localhost:4040/acme").unwrap();
assert_eq!(r.base, "http://localhost:4040/v1/public/acme");
}
#[test]
fn bare_host_has_no_public_surface() {
assert_eq!(public("vcs.lexlang.org"), None);
assert_eq!(public("https://vcs.lexlang.org"), None);
assert_eq!(public(""), None);
}
}