weavatrix-rust 2.0.2

Protocol-independent Rust repository intelligence: typed evidence graphs for impact, architecture, APIs, Git, search, and memory
Documentation
use weavatrix_rust::{Analyzer, EdgeKind, Snapshot, SourceInput};

#[test]
fn member_calls_do_not_bind_to_repository_wide_name_matches() {
    let snapshot = analyze(&[
        (
            "src/app.js",
            "import { includes } from './imported.js';\nfunction parse() {}\nfunction filter() {}\nexport function run(path, values) {\n  JSON.parse('{}');\n  statSync(path).isFile();\n  const note = `non-ASCII — receiver`;\n  return [note, ...values.map(String)].filter(Boolean).includes('x');\n}\n",
        ),
        ("src/unrelated.js", "export function isFile() {}\n"),
        ("src/imported.js", "export function includes() {}\n"),
    ]);

    for (name, declaring_file) in [
        ("parse", "app.js"),
        ("filter", "app.js"),
        ("isFile", "unrelated.js"),
        ("includes", "imported.js"),
    ] {
        assert!(
            snapshot
                .nodes
                .iter()
                .any(|node| node.label == name && node.id.as_str().contains(declaring_file)),
            "the unrelated declaration must exist for the regression to exercise each scope"
        );
        assert!(
            !snapshot.edges.iter().any(|edge| {
                edge.kind == EdgeKind::Calls
                    && snapshot.nodes.iter().any(|node| {
                        node.id == edge.target
                            && node.label == name
                            && node.id.as_str().contains(declaring_file)
                    })
            }),
            "{name} member call must not bind by its final segment"
        );
    }
}

#[test]
fn local_and_import_scoped_calls_still_resolve() {
    let snapshot = analyze(&[
        ("src/lib.js", "export function imported() { return 1; }\n"),
        (
            "src/app.js",
            "import { imported } from './lib.js';\nfunction local() { return 2; }\nexport function run() { return [...imported(), local()]; }\n",
        ),
    ]);

    for (target, detail) in [
        (
            "imported",
            "resolved through an exact imported-name binding",
        ),
        ("local", "resolved in the referencing file's own scope"),
    ] {
        assert!(
            snapshot.edges.iter().any(|edge| {
                edge.kind == EdgeKind::Calls
                    && edge.provenance.detail.as_deref() == Some(detail)
                    && snapshot
                        .nodes
                        .iter()
                        .any(|node| node.id == edge.target && node.label == target)
            }),
            "{target} must retain its scoped call edge"
        );
    }
}

#[test]
fn free_calls_remain_resolvable_in_go_java_and_python() {
    let go = analyze(&[
        ("main.go", "package main\nfunc main() { LoadUser() }\n"),
        ("service.go", "package main\nfunc LoadUser() {}\n"),
    ]);
    assert_call(&go, "LoadUser");

    let java = analyze(&[(
        "App.java",
        "class App { static void helper() {} static void run() { helper(); } }\n",
    )]);
    assert_call(&java, "helper");

    let python = analyze(&[
        (
            "main.py",
            "from service import load_user\n\ndef bootstrap():\n    return load_user()\n",
        ),
        ("service.py", "def load_user():\n    return {}\n"),
    ]);
    assert_call(&python, "load_user");
}

#[test]
fn locally_imported_reexport_binding_remains_resolvable() {
    let snapshot = analyze(&[
        (
            "src/app.js",
            "import { safeRead } from './barrel.js';\nexport function run() { return safeRead('x'); }\n",
        ),
        (
            "src/barrel.js",
            "import { safeRead } from './util.js';\nexport { safeRead };\n",
        ),
        (
            "src/util.js",
            "export function safeRead(path) { return path; }\n",
        ),
    ]);

    assert_call(&snapshot, "safeRead");
}

#[test]
fn exact_binding_follows_its_own_barrel_despite_an_unrelated_name_collision() {
    let snapshot = analyze(&[
        (
            "src/app.js",
            "import { loadGraph } from './graph-barrel.js';\nimport { computeDuplicates } from './duplicates-barrel.js';\nexport function run() { computeDuplicates(); return loadGraph(); }\n",
        ),
        ("src/graph-barrel.js", "export * from './graph-core.js';\n"),
        (
            "src/graph-core.js",
            "export function loadGraph() { return {}; }\n",
        ),
        (
            "src/duplicates-barrel.js",
            "export * from './duplicates-core.js';\n",
        ),
        (
            "src/duplicates-core.js",
            "function loadGraph() { return {}; }\nexport function computeDuplicates() { return loadGraph(); }\n",
        ),
    ]);

    let app_call = snapshot.edges.iter().find(|edge| {
        edge.kind == EdgeKind::Calls
            && edge
                .provenance
                .span
                .as_ref()
                .is_some_and(|span| span.file == "src/app.js" && span.start.line == 3)
            && snapshot
                .nodes
                .iter()
                .any(|node| node.id == edge.target && node.label == "loadGraph")
    });
    let target = app_call
        .and_then(|edge| snapshot.nodes.iter().find(|node| node.id == edge.target))
        .expect("loadGraph imported through graph-barrel must resolve");
    assert!(
        target.id.as_str().contains("graph-core.js"),
        "the exact import binding must not select the unrelated collision: {}",
        target.id
    );
}

#[test]
fn recursive_and_callable_local_names_beat_unrelated_imported_matches() {
    let snapshot = analyze(&[
        (
            "src/app.js",
            "import { other } from './unrelated.js';\nfunction holder() { const count = 1; return count; }\nfunction count(values) { return values.length; }\nfunction visit(node) { if (node) visit(null); }\nexport function run() { visit({}); return count([]); }\n",
        ),
        (
            "src/unrelated.js",
            "export function other() {}\nexport function count() {}\nexport function visit() {}\n",
        ),
    ]);

    for name in ["count", "visit"] {
        assert!(snapshot.edges.iter().any(|edge| {
            edge.kind == EdgeKind::Calls
                && snapshot.nodes.iter().any(|node| {
                    node.id == edge.target
                        && node.label == name
                        && node.id.as_str().contains("app.js")
                })
        }));
        assert!(!snapshot.edges.iter().any(|edge| {
            edge.kind == EdgeKind::Calls
                && snapshot.nodes.iter().any(|node| {
                    node.id == edge.target
                        && node.label == name
                        && node.id.as_str().contains("unrelated.js")
                })
        }));
    }

    let visit = snapshot
        .nodes
        .iter()
        .find(|node| node.label == "visit" && node.id.as_str().contains("app.js"))
        .unwrap();
    assert!(snapshot.edges.iter().any(|edge| {
        edge.kind == EdgeKind::Calls && edge.source == visit.id && edge.target == visit.id
    }));
}

#[test]
fn aliased_imports_bind_to_the_original_export_not_an_unrelated_local_name() {
    let snapshot = analyze(&[
        (
            "src/app.js",
            "import { realPathAllowed as pathAllowed, realRound as round } from './policy.js';\nexport function run(info) { return round(pathAllowed(info)); }\n",
        ),
        (
            "src/policy.js",
            "export function realPathAllowed(info) { return info; }\nexport function realRound(value) { return value; }\n",
        ),
        (
            "src/unrelated.js",
            "export function pathAllowed() {}\nexport function round() {}\n",
        ),
    ]);

    for (imported, unrelated) in [("realPathAllowed", "pathAllowed"), ("realRound", "round")] {
        assert!(snapshot.edges.iter().any(|edge| {
            edge.kind == EdgeKind::Calls
                && snapshot.nodes.iter().any(|node| {
                    node.id == edge.target
                        && node.label == imported
                        && node.id.as_str().contains("policy.js")
                })
        }));
        assert!(!snapshot.edges.iter().any(|edge| {
            edge.kind == EdgeKind::Calls
                && snapshot.nodes.iter().any(|node| {
                    node.id == edge.target
                        && node.label == unrelated
                        && node.id.as_str().contains("unrelated.js")
                })
        }));
    }
}

fn assert_call(snapshot: &Snapshot, target: &str) {
    assert!(
        snapshot.edges.iter().any(|edge| {
            edge.kind == EdgeKind::Calls
                && snapshot
                    .nodes
                    .iter()
                    .any(|node| node.id == edge.target && node.label == target)
        }),
        "{target} free call must resolve"
    );
}

fn analyze(sources: &[(&str, &str)]) -> Snapshot {
    Analyzer::default()
        .analyze_sources(
            std::env::current_dir().unwrap(),
            "call-resolution-test",
            sources.iter().map(|(path, source)| SourceInput {
                path: (*path).to_owned(),
                bytes: source.as_bytes().to_vec(),
                content_hash: None,
            }),
        )
        .unwrap()
}