weavatrix-rust 2.16.1

Protocol-independent Rust repository intelligence: typed evidence graphs for impact, architecture, APIs, Git, search, and memory
Documentation
use super::model::{
    McpConfig, PluginRecord, ServerRecord, SkillRecord, declares, extension_kind, mcp_config_kind,
    mcp_server_kind, plugin_kind, skill_kind,
};
use super::redaction::redact_label;
use crate::language::{DomainFact, FileFacts, ReferenceFact, SymbolFact, SymbolLocator};
use weavatrix_graph::{EdgeKind, NodeKind, SourceSpan};

pub(super) fn plugin_facts(path: &str, _raw: &str, record: &PluginRecord) -> FileFacts {
    let mut facts = FileFacts {
        diagnostics: record.diagnostics.clone(),
        ..FileFacts::default()
    };
    let plugin = symbol(&record.name, plugin_kind(), record.span.clone());
    let owner = locator(&plugin);
    facts.symbols.push(plugin);
    push_meta(
        &mut facts,
        &owner,
        &record.span,
        &[
            format!("profile:{}", record.profile.as_str()),
            format!("package:{}", record.package_root),
            format!("completeness:{}", record.completeness.as_str()),
            format!(
                "schema:{}",
                record.schema.as_deref().unwrap_or("undeclared")
            ),
        ],
    );
    if let Some(version) = &record.version {
        push_meta(
            &mut facts,
            &owner,
            &record.span,
            &[format!("version:{version}")],
        );
    }
    for field in &record.unknown_fields {
        push_named(
            &mut facts,
            &owner,
            &record.span,
            &format!("unrecognized_field:{field}"),
            NodeKind::Unknown,
            declares(),
        );
    }
    for namespace in &record.extensions {
        let extension = symbol(namespace, extension_kind(), record.span.clone());
        facts
            .references
            .push(contains(&owner, namespace, record.span.clone()));
        facts.symbols.push(extension);
        push_named(
            &mut facts,
            &owner,
            &record.span,
            &format!("extension:{namespace}"),
            NodeKind::Unknown,
            declares(),
        );
    }
    for declared in &record.declared_paths {
        push_named(
            &mut facts,
            &owner,
            &record.span,
            &format!("declared_path:{declared}"),
            NodeKind::Binding,
            EdgeKind::References,
        );
    }
    let _ = path;
    facts
}

pub(super) fn mcp_facts(_path: &str, _raw: &str, config: &McpConfig) -> FileFacts {
    let mut facts = FileFacts {
        diagnostics: config.diagnostics.clone(),
        ..FileFacts::default()
    };
    let label = if config.package_root.is_empty() {
        "mcp.json".to_owned()
    } else {
        format!("{}::mcp", config.package_root)
    };
    let parent = symbol(&label, mcp_config_kind(), config.span.clone());
    let owner = locator(&parent);
    facts.symbols.push(parent);
    push_meta(
        &mut facts,
        &owner,
        &config.span,
        &[
            format!("profile:{}", config.profile.as_str()),
            format!("package:{}", config.package_root),
            format!("completeness:{}", config.completeness.as_str()),
            format!(
                "schema:{}",
                config.schema.as_deref().unwrap_or("undeclared")
            ),
            "executed:false".to_owned(),
        ],
    );
    for field in &config.unknown_fields {
        push_named(
            &mut facts,
            &owner,
            &config.span,
            &format!("unrecognized_field:{field}"),
            NodeKind::Unknown,
            declares(),
        );
    }
    for server in &config.servers {
        emit_server(&mut facts, &owner, server);
    }
    facts
}

pub(super) fn skill_facts(_path: &str, _raw: &str, record: &SkillRecord) -> FileFacts {
    let mut facts = FileFacts {
        diagnostics: record.diagnostics.clone(),
        ..FileFacts::default()
    };
    let skill = symbol(&record.name, skill_kind(), record.span.clone());
    let owner = locator(&skill);
    facts.symbols.push(skill);
    push_meta(
        &mut facts,
        &owner,
        &record.span,
        &[
            format!("package:{}", record.package_root),
            format!("directory:{}", record.directory),
            format!("completeness:{}", record.completeness.as_str()),
            "authorization:none".to_owned(),
        ],
    );
    for tool in &record.allowed_tools {
        push_named(
            &mut facts,
            &owner,
            &record.span,
            &format!("declared_allowed_tools:{tool}"),
            NodeKind::ConfigKey,
            declares(),
        );
    }
    for reference in &record.references {
        push_named(
            &mut facts,
            &owner,
            &record.span,
            &format!("ref:{reference}"),
            NodeKind::Binding,
            EdgeKind::References,
        );
    }
    facts
}

fn emit_server(facts: &mut FileFacts, owner: &SymbolLocator, server: &ServerRecord) {
    let node = symbol(&server.key, mcp_server_kind(), server.span.clone());
    facts
        .references
        .push(contains(owner, &server.key, server.span.clone()));
    facts.symbols.push(node);
    let server_owner = SymbolLocator {
        name: server.key.clone(),
        kind: mcp_server_kind(),
        span: server.span.clone(),
    };
    push_meta(
        facts,
        &server_owner,
        &server.span,
        &[
            format!("transport:{}", server.transport),
            format!("completeness:{}", server.completeness.as_str()),
            "executed:false".to_owned(),
        ],
    );
    if let Some(command) = &server.command {
        push_named(
            facts,
            &server_owner,
            &server.span,
            &redact_label("command", command),
            NodeKind::Binding,
            declares(),
        );
    }
    if let Some(url) = &server.url {
        push_named(
            facts,
            &server_owner,
            &server.span,
            &redact_label("url", url),
            NodeKind::Binding,
            declares(),
        );
    }
}

pub(super) fn push_meta(
    facts: &mut FileFacts,
    owner: &SymbolLocator,
    span: &SourceSpan,
    names: &[String],
) {
    for name in names {
        push_named(
            facts,
            owner,
            span,
            name,
            NodeKind::Unknown,
            EdgeKind::Configures,
        );
    }
}

pub(super) fn push_named(
    facts: &mut FileFacts,
    owner: &SymbolLocator,
    span: &SourceSpan,
    name: &str,
    kind: NodeKind,
    relation: EdgeKind,
) {
    facts.domains.push(DomainFact {
        name: name.to_owned(),
        kind,
        relation,
        span: span.clone(),
        owner: Some(owner.clone()),
    });
}

pub(super) fn symbol(name: &str, kind: NodeKind, span: SourceSpan) -> SymbolFact {
    SymbolFact {
        name: name.to_owned(),
        kind,
        span,
        test_only: false,
        exported: true,
        source_fingerprint: None,
        source_extent: None,
        owner: None,
    }
}

pub(super) fn locator(symbol: &SymbolFact) -> SymbolLocator {
    SymbolLocator {
        name: symbol.name.clone(),
        kind: symbol.kind.clone(),
        span: symbol.span.clone(),
    }
}

pub(super) fn contains(owner: &SymbolLocator, name: &str, span: SourceSpan) -> ReferenceFact {
    ReferenceFact {
        name: name.to_owned(),
        kind: EdgeKind::Contains,
        receiver: None,
        qualified: false,
        span,
        owner: Some(owner.clone()),
    }
}