weavatrix-rust 2.16.4

Protocol-independent Rust repository intelligence: typed evidence graphs for impact, architecture, APIs, Git, n8n, Dify, Agent catalogs, Mermaid, and Web3 ABI
Documentation
use std::path::{Component, Path, PathBuf};

#[must_use]
pub(crate) fn member_key(path: &str, kind: &str, signature: &str) -> String {
    format!("{path}#{kind}:{signature}")
}

#[must_use]
pub(crate) fn resolve_import(from_file: &str, spec: &str) -> Option<String> {
    if spec.starts_with("http:") || spec.starts_with("https:") || spec.starts_with("ipfs:") {
        return None;
    }
    if !(spec.starts_with("./") || spec.starts_with("../")) {
        return None;
    }
    let parent = Path::new(from_file)
        .parent()
        .unwrap_or_else(|| Path::new("."));
    Some(normalize(&parent.join(spec)))
}

#[must_use]
fn normalize(path: &Path) -> String {
    let mut parts = PathBuf::new();
    for component in path.components() {
        match component {
            Component::CurDir => {}
            Component::ParentDir => {
                parts.pop();
            }
            other => parts.push(other.as_os_str()),
        }
    }
    parts.to_string_lossy().replace('\\', "/")
}

#[cfg(test)]
mod tests {
    use super::{member_key, resolve_import};

    #[test]
    fn import_specs_stay_relative_and_normalized() {
        assert_eq!(
            member_key("a.json", "event", "Deposit()"),
            "a.json#event:Deposit()"
        );
        assert_eq!(
            resolve_import("src/app.ts", "./abis/Vault.json"),
            Some("src/abis/Vault.json".into())
        );
        assert_eq!(
            resolve_import("src/app.ts", "../abis/Vault.json"),
            Some("abis/Vault.json".into())
        );
        assert_eq!(resolve_import("src/app.ts", "https://x/abi.json"), None);
        assert_eq!(resolve_import("src/app.ts", "ipfs://x"), None);
        assert_eq!(resolve_import("src/app.ts", "vault"), None);
    }
}