use super::{CHUNK_BASE, CODE_BASE, DOC_BASE};
pub fn iri_segment_decode(encoded: &str) -> String {
let bytes = encoded.as_bytes();
let mut out = Vec::with_capacity(bytes.len());
let mut i = 0;
while i < bytes.len() {
if bytes[i] == b'%' && i + 2 < bytes.len() {
let hi = (bytes[i + 1] as char).to_digit(16);
let lo = (bytes[i + 2] as char).to_digit(16);
if let (Some(hi), Some(lo)) = (hi, lo) {
out.push((hi * 16 + lo) as u8);
i += 3;
continue;
}
}
out.push(bytes[i]);
i += 1;
}
String::from_utf8_lossy(&out).into_owned()
}
pub fn entity_iri_file_path(iri: &str) -> Option<String> {
let rest = [CODE_BASE, DOC_BASE, CHUNK_BASE]
.iter()
.find_map(|base| iri.strip_prefix(*base))?;
let (_repo, path_and_suffix) = rest.split_once('/')?;
let encoded_path = path_and_suffix
.split("::")
.next()
.and_then(|s| s.split('#').next())
.filter(|s| !s.is_empty())?;
Some(iri_segment_decode(encoded_path))
}
pub fn code_module_prefix_of(chunk_iri: &str) -> Option<String> {
if let Some(rest) = chunk_iri.strip_prefix(CHUNK_BASE) {
let span = rest.split('#').next()?;
return Some(format!("{CODE_BASE}{span}::"));
}
if let Some(rest) = chunk_iri.strip_prefix(CODE_BASE) {
let module = rest.split("::").next()?;
return Some(format!("{CODE_BASE}{module}::"));
}
None
}
#[cfg(test)]
mod tests {
use super::super::{
chunk_iri, code_module_iri, document_iri, iri_segment, section_iri, symbol_iri,
INFERRED_BASE,
};
use super::*;
#[test]
fn parses_what_the_minters_mint() {
for path in [
"src/main.rs",
"build.rs",
"src/store/ops.rs",
"docs/my file.md",
"tests/no_internal_identifiers.rs",
"vendor/50% done/[Symbol.iterator].js",
] {
for iri in [
code_module_iri("quipu", path),
symbol_iri("quipu", path, "negotiate"),
symbol_iri("quipu", path, "[Symbol.iterator]"),
document_iri("quipu", path),
section_iri("quipu", path, "REST API / Web UI"),
chunk_iri("quipu", path, 42),
] {
assert_eq!(
entity_iri_file_path(&iri).as_deref(),
Some(path),
"round trip lost the path for {iri}"
);
}
}
}
#[test]
fn does_not_parse_the_superseded_or_quarantined_lanes() {
assert_eq!(
entity_iri_file_path("http://aegis.gastown.local/code/quipu/src%2Fw3c.rs"),
None
);
assert_eq!(entity_iri_file_path("bobbin:code/repo/src/lib.rs"), None);
assert_eq!(
entity_iri_file_path("http://aegis.gastown.local/ontology/CodeModule"),
None
);
assert_eq!(
entity_iri_file_path(&format!("{INFERRED_BASE}quipu/src%2Fa.rs")),
None
);
}
#[test]
fn decode_is_the_inverse_of_encode() {
for raw in [
"plain",
"50% done",
"%2F",
"a|b\\c^d`e",
"[Symbol.iterator]",
] {
assert_eq!(iri_segment_decode(&iri_segment(raw)), raw);
}
assert_eq!(iri_segment_decode("a%zz"), "a%zz");
assert_eq!(iri_segment_decode("trailing%2"), "trailing%2");
}
#[test]
fn module_prefix_narrows_from_either_lane() {
let want = "http://aegis.gastown.local/ontology/code/q/src%2Fa.rs::".to_string();
assert_eq!(
code_module_prefix_of(&chunk_iri("q", "src/a.rs", 12)),
Some(want.clone())
);
assert_eq!(
code_module_prefix_of(&symbol_iri("q", "src/a.rs", "run")),
Some(want)
);
assert_eq!(
code_module_prefix_of(§ion_iri("q", "README.md", "Features")),
None
);
let prefix = code_module_prefix_of(&chunk_iri("q", "src/a.rs", 12)).unwrap();
assert!(symbol_iri("q", "src/a.rs", "sibling").starts_with(&prefix));
assert!(!symbol_iri("q", "src/b.rs", "sibling").starts_with(&prefix));
}
}