rototo 0.1.0-alpha.6

Control plane for runtime configuration of your application.
Documentation
use crate::diagnostics::{RototoRuleId, SemanticField};

use super::super::engine::LintContext;
use super::super::index::*;
use super::super::references::{ReferenceSource, ReferenceTarget};
use super::super::stages::{push_project_diagnostic, push_reference_diagnostic};
use super::field_is_integer;

pub(super) fn lint_qualifier_shapes(ctx: &mut LintContext) {
    let diagnostics = &mut ctx.diagnostics;
    for qualifier in ctx.index.qualifiers.values() {
        if !field_is_integer(&qualifier.schema_version, 1) {
            push_project_diagnostic(
                diagnostics,
                RototoRuleId::QualifierSchemaVersion,
                qualifier.field_target(SemanticField::SchemaVersion),
                qualifier.schema_version.location(),
                "qualifier must declare schema_version = 1",
            );
        }

        match &qualifier.when {
            ProjectField::Present(_) => {}
            ProjectField::Invalid { location } => push_project_diagnostic(
                diagnostics,
                RototoRuleId::QualifierWhenShape,
                qualifier.field_target(SemanticField::QualifierWhen),
                location.clone(),
                "qualifier when expression is invalid",
            ),
            ProjectField::Missing { location } => push_project_diagnostic(
                diagnostics,
                RototoRuleId::QualifierWhenMissing,
                qualifier.field_target(SemanticField::QualifierWhen),
                location.clone(),
                "qualifier must declare when",
            ),
        }

        if let PredicateCollection::Invalid { location } = &qualifier.predicates {
            push_project_diagnostic(
                diagnostics,
                RototoRuleId::QualifierWhenShape,
                qualifier.field_target(SemanticField::QualifierWhen),
                location.clone(),
                "[[predicate]] is no longer supported; use when = \"...\"",
            );
        }
    }
}

/// Flag root identifiers a qualifier `when` expression uses that rototo does not
/// provide: the legacy bare `qualifier[...]` root, unknown `env` members, and
/// any other unknown identifier. Without this the expression would fail at
/// resolution with cel's raw "undefined variable" error.
pub(super) fn lint_qualifier_expression_roots(ctx: &mut LintContext) {
    let diagnostics = &mut ctx.diagnostics;
    for qualifier in ctx.index.qualifiers.values() {
        let ProjectField::Present(when) = &qualifier.when else {
            continue;
        };
        for issue in &when.value.references().invalid_roots {
            push_project_diagnostic(
                diagnostics,
                RototoRuleId::QualifierWhenInvalidReference,
                qualifier.field_target(SemanticField::QualifierWhen),
                when.location.clone(),
                issue.describe(),
            );
        }
        if when.value.references().uses_resolving {
            push_project_diagnostic(
                diagnostics,
                RototoRuleId::QualifierWhenInvalidReference,
                qualifier.field_target(SemanticField::QualifierWhen),
                when.location.clone(),
                "env.resolving is only available in [[trace]] policies",
            );
        }
    }
}

pub(super) fn lint_qualifier_references(ctx: &mut LintContext) {
    let diagnostics = &mut ctx.diagnostics;

    for edge in ctx.references.edges() {
        let ReferenceSource::QualifierWhenQualifier { .. } = &edge.source else {
            continue;
        };
        if edge.is_resolved() {
            continue;
        }
        let ReferenceTarget::Qualifier(reference) = &edge.target else {
            continue;
        };

        push_reference_diagnostic(
            diagnostics,
            RototoRuleId::QualifierWhenUnknownQualifier,
            edge.semantic_target.clone(),
            edge.location.clone(),
            format!(
                "when expression references unknown qualifier: {}",
                reference
            ),
        );
    }
}