rototo 0.1.0-alpha.8

Control plane for runtime configuration of your application.
Documentation
use std::collections::{BTreeMap, BTreeSet};

use crate::diagnostics::{DiagnosticCatalogEntry, LintDiagnostic, RototoRuleId, SemanticEntity};
use crate::error::{Result, RototoError};
use crate::expression::{ContextScalarType, Expression};
use crate::model::{
    AllocationArmInspectReport, AllocationInspectReport, AssignInspectReport,
    CatalogEntryInspectReport, CatalogInspectReport, ContextAttributeDeclarationReport,
    ContextAttributeInspectReport, DependencyInspectReport, EvaluationContextInspectReport,
    EvaluationContextSampleInspectReport, InspectRuntimeStatus, InspectSelection,
    LintAuthorityInspectReport, LintRuleInspectReport, LinterInspectReport,
    LinterRegistrationInspectReport, PackageInspectReport, PackageInspectRequest,
    QueryInspectReport, ReferenceInspectReport, ResolveInspectReport, RulePathwayInspectReport,
    RuleSampleCoverageReport, ValueInspectReport, VariableInspectReport,
    VariableSampleCoverageReport,
};
use crate::resolve::trace_variable_unchecked;

use super::evaluation_context::{
    ContextPathTypeFit, context_path_declaration, context_path_type_fit, variable_resolve_rules,
};
use super::index::*;
use super::references::{ReferenceSource, ReferenceTarget};
use super::{PackageLintSnapshot, RuntimePackage};

mod catalog;
mod context;
mod request;
mod variable;

use catalog::*;
use context::*;
use request::*;
use variable::*;

pub(crate) async fn inspect_snapshot(
    snapshot: &PackageLintSnapshot,
    runtime: Option<&RuntimePackage>,
    runtime_error: Option<String>,
    request: &PackageInspectRequest,
) -> Result<PackageInspectReport> {
    validate_context_request(request)?;

    let catalog = catalog_from_snapshot(snapshot);
    validate_request(snapshot, request, &catalog)?;

    let inventory = request.variables.is_none()
        && request.catalogs.is_none()
        && request.lint_rules.is_none()
        && request.lint_authorities.is_none()
        && request.linters.is_none();
    let variable_ids = selected_ids(
        &request.variables,
        snapshot.index.variables.keys().map(String::as_str),
        inventory,
    );
    let catalog_ids = selected_ids(
        &request.catalogs,
        snapshot.index.catalogs.keys().map(String::as_str),
        inventory,
    );

    let mut variables = Vec::new();
    for id in variable_ids {
        variables.push(inspect_variable(snapshot, runtime, request, &id).await?);
    }

    let mut catalogs = Vec::new();
    for id in catalog_ids {
        catalogs.push(inspect_catalog(snapshot, &id)?);
    }

    let evaluation_contexts = selected_evaluation_contexts(snapshot, inventory);
    let lint_rules = selected_lint_rules(snapshot, request, &catalog);
    let lint_authorities = selected_lint_authorities(snapshot, request, &catalog, inventory);
    let linters = selected_linters(snapshot, request, inventory);
    let diagnostics = selected_diagnostics(snapshot, request, inventory);

    Ok(PackageInspectReport {
        package: snapshot.lint.root.display().to_string(),
        documents: snapshot.lint.documents.clone(),
        runtime: match runtime_error {
            Some(reason) => InspectRuntimeStatus::Unavailable { reason },
            None => InspectRuntimeStatus::Available,
        },
        diagnostics,
        evaluation_contexts,
        catalogs,
        variables,
        lint_rules,
        lint_authorities,
        linters,
    })
}

pub(super) fn document_uri_path(
    snapshot: &PackageLintSnapshot,
    doc: crate::diagnostics::DocId,
) -> (String, String) {
    snapshot
        .lint
        .documents
        .iter()
        .find(|document| document.id == doc)
        .map(|document| (document.uri.clone(), document.path.clone()))
        .unwrap_or_else(|| (String::new(), String::new()))
}

pub(super) fn present_string_value(field: &ProjectField<String>) -> Option<String> {
    match field {
        ProjectField::Present(value) => Some(value.value.clone()),
        ProjectField::Invalid { .. } | ProjectField::Missing { .. } => None,
    }
}

pub(super) fn present_json_value(
    field: &ProjectField<serde_json::Value>,
) -> Option<serde_json::Value> {
    match field {
        ProjectField::Present(value) => Some(value.value.clone()),
        ProjectField::Invalid { .. } | ProjectField::Missing { .. } => None,
    }
}

pub(super) fn present_expression_source(
    field: &Option<ProjectField<Expression>>,
) -> Option<String> {
    match field {
        Some(ProjectField::Present(value)) => Some(value.value.source().to_owned()),
        Some(ProjectField::Invalid { .. } | ProjectField::Missing { .. }) | None => None,
    }
}