#![warn(missing_docs)]
mod agx;
mod canonical;
mod parse;
mod plan;
mod validate;
pub use agx::{AgxCall, AgxError, ParsedExpression, parse_expression};
pub use canonical::{CanonicalError, canonical_json, graph_digest};
pub use parse::{ParseError, load, parse};
pub use plan::{PlanError, graph_effective_edges, plan_graph, topological_order};
pub use validate::{validate, validate_path};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
pub const AGS_VERSION: &str = "1.0";
pub const SUPPORT_VERSION: &str = "1.0.4";
pub type Document = Map<String, Value>;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Finding {
pub code: String,
pub severity: String,
pub message: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub pointer: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationReport {
#[serde(skip_serializing_if = "Option::is_none")]
pub document: Option<Document>,
pub findings: Vec<Finding>,
pub errors: Vec<Finding>,
pub warnings: Vec<Finding>,
pub ok: bool,
}
impl ValidationReport {
fn new(document: Document) -> Self {
Self {
document: Some(document),
findings: vec![],
errors: vec![],
warnings: vec![],
ok: true,
}
}
fn add(
&mut self,
code: &str,
severity: &str,
message: impl Into<String>,
pointer: impl Into<String>,
) {
let finding = Finding {
code: code.into(),
severity: severity.into(),
message: message.into(),
pointer: pointer.into(),
};
self.findings.push(finding.clone());
if severity == "error" {
self.errors.push(finding);
self.ok = false;
} else {
self.warnings.push(finding);
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct EffectiveEdge {
pub from: String,
pub to: String,
pub kind: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub when: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct GraphPlan {
pub graph_id: String,
pub graph_digest: String,
pub order: Vec<String>,
pub entrypoints: Vec<String>,
pub effective_edges: Vec<EffectiveEdge>,
pub reachable: Vec<String>,
pub unreachable: Vec<String>,
pub tier_histogram: std::collections::BTreeMap<String, usize>,
pub worst_case_node_executions: u64,
pub executable: bool,
pub unsupported_features: Vec<String>,
}
pub(crate) fn object(value: Option<&Value>) -> &Map<String, Value> {
value.and_then(Value::as_object).unwrap_or_else(|| {
static EMPTY: std::sync::LazyLock<Map<String, Value>> = std::sync::LazyLock::new(Map::new);
&EMPTY
})
}
pub(crate) fn strings(value: Option<&Value>) -> Vec<String> {
value
.and_then(Value::as_array)
.into_iter()
.flatten()
.filter_map(Value::as_str)
.map(str::to_owned)
.collect()
}