a2ui_base/validate/ref_fields.rs
1//! The set of property names that hold component references.
2//!
3//! Rust has no runtime catalog schema (unlike Python, which derives these from
4//! JSON Schema via `CatalogSchemaValidator.extract_ref_fields()`). We hardcode
5//! the a2ui-standard reference fields here:
6//! - `child` (single), `activeTab` (single)
7//! - `children` (list: either a `Static` array of ids, or a `Template`
8//! `{componentId, path}` whose `componentId` is a component reference).
9//!
10//! This matches what `ComponentModel::child()` / `children()` already look at,
11//! and what the v0.9-flat samples use.
12
13/// Specification of which property keys carry component references.
14#[derive(Debug, Clone)]
15pub struct RefFieldSpec {
16 /// Keys whose value is a single component id string (e.g. `child`,
17 /// `activeTab`).
18 pub single_refs: &'static [&'static str],
19 /// Keys whose value is a list of component ids — either a JSON array of
20 /// strings (`Static`), or a `Template` object `{componentId, path}`
21 /// (e.g. `children`).
22 pub list_refs: &'static [&'static str],
23}
24
25impl RefFieldSpec {
26 /// The a2ui-standard reference fields: `child`, `activeTab` (single);
27 /// `children` (list).
28 pub const DEFAULT: Self = Self {
29 single_refs: &["child", "activeTab"],
30 list_refs: &["children"],
31 };
32}
33
34impl Default for RefFieldSpec {
35 fn default() -> Self {
36 Self::DEFAULT
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn default_contains_expected_fields() {
46 let s = RefFieldSpec::DEFAULT;
47 assert!(s.single_refs.contains(&"child"));
48 assert!(s.single_refs.contains(&"activeTab"));
49 assert!(s.list_refs.contains(&"children"));
50 }
51
52 #[test]
53 fn default_impl_matches_const() {
54 assert_eq!(RefFieldSpec::default().single_refs, RefFieldSpec::DEFAULT.single_refs);
55 assert_eq!(RefFieldSpec::default().list_refs, RefFieldSpec::DEFAULT.list_refs);
56 }
57}