use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::expr::Expr;
use crate::primitives::{AssertId, OnMissingInput};
use crate::selector::{ElementSelectorIR, RectIR, TextMatchIR};
use crate::vocab::{ElementState, VerifyChannel};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[schemars(extend("allOf" = [
{
"if": {
"properties": {
"predicate": {
"type": "object",
"properties": { "type": { "const": "expr" } },
"required": ["type"]
}
},
"required": ["predicate"]
},
"then": { "properties": { "verifyVia": { "maxItems": 0 } } },
"else": { "properties": { "verifyVia": { "minItems": 1 } } }
},
{
"if": {
"properties": {
"predicate": {
"type": "object",
"properties": { "type": { "const": "visual" } },
"required": ["type"]
}
},
"required": ["predicate"]
},
"then": { "properties": { "verifyVia": { "const": ["vision"] } } }
},
{
"if": {
"properties": {
"predicate": {
"type": "object",
"properties": { "type": { "enum": ["elementState", "elementText"] } },
"required": ["type"]
},
"verifyVia": { "type": "array", "contains": { "const": "vision" } }
},
"required": ["predicate", "verifyVia"]
},
"then": { "required": ["visionPrompt"] },
"else": { "not": { "required": ["visionPrompt"] } }
}
]))]
pub struct AssertionIR {
pub assert_id: AssertId,
pub predicate: PredicateIR,
#[schemars(schema_with = "unique_verify_via_schema")]
pub verify_via: Vec<VerifyChannel>,
#[serde(skip_serializing_if = "Option::is_none")]
#[schemars(length(min = 1, max = 16384))]
pub vision_prompt: Option<String>,
pub on_missing_input: OnMissingInput,
}
fn unique_verify_via_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
let mut schema = <Vec<VerifyChannel>>::json_schema(generator);
schema
.ensure_object()
.insert("uniqueItems".to_owned(), serde_json::Value::Bool(true));
schema
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "type", rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub enum PredicateIR {
ElementState {
selector: ElementSelectorIR,
state: ElementState,
},
ElementText {
selector: ElementSelectorIR,
r#match: TextMatchIR,
},
Expr {
expr: Expr,
},
Visual {
#[schemars(length(min = 1, max = 16384))]
prompt: String,
#[serde(skip_serializing_if = "Option::is_none")]
region: Option<RectIR>,
},
}