Skip to main content

bnto_core/metadata/
parameters.rs

1// Parameter schema types — definitions for node parameters.
2//
3// These types describe what parameters a node accepts: their names,
4// types, constraints, UI hints, and conditional visibility rules.
5// Used by both the engine (validation) and the UI (control rendering).
6
7use serde::Serialize;
8
9// --- ParamCondition — Conditional Visibility / Requirement Rules ---
10
11/// A single condition entry: "when `param` has the value `equals`".
12///
13/// Used both standalone (in `ParamCondition::Single`) and as entries
14/// in the `ParamCondition::Any` array.
15#[derive(Debug, Clone, Serialize, PartialEq)]
16#[serde(rename_all = "camelCase")]
17pub struct ParamConditionEntry {
18    /// The name of the parameter to check against.
19    pub param: String,
20    /// The value that triggers visibility/requirement.
21    pub equals: String,
22}
23
24/// Conditional visibility/requirement rule for a parameter.
25///
26/// Uses `#[serde(untagged)]` so Single serializes as a plain object and
27/// Any serializes as an array — no type discriminator field needed.
28#[derive(Debug, Clone, Serialize, PartialEq)]
29#[serde(untagged)]
30pub enum ParamCondition {
31    /// Show/require when a single parameter matches a value.
32    Single(ParamConditionEntry),
33    /// Show/require when ANY of multiple conditions match (OR logic).
34    Any(Vec<ParamConditionEntry>),
35}
36
37// --- OptionEntry — labeled enum choice ---
38
39/// A single choice inside an `Enum` parameter. Carries a machine value
40/// and a human-readable label.
41#[derive(Debug, Clone, Serialize, PartialEq)]
42#[serde(rename_all = "camelCase")]
43pub struct OptionEntry {
44    /// The value stored in config JSON (e.g., `"jpeg"`).
45    pub value: String,
46    /// The label shown in the UI (e.g., `"JPEG"`).
47    pub label: String,
48}
49
50// --- ParameterType ---
51
52/// The type of a node parameter. Determines what UI control to render.
53#[derive(Debug, Clone, Serialize, PartialEq, Default)]
54#[serde(tag = "type", rename_all = "camelCase")]
55pub enum ParameterType {
56    Number,
57    #[default]
58    String,
59    Boolean,
60    /// A choice from a fixed set of options (like a dropdown/select).
61    Enum {
62        options: Vec<OptionEntry>,
63    },
64    Object,
65    /// A file upload parameter (base64-encoded).
66    File {
67        accept: Vec<std::string::String>,
68    },
69}
70
71// --- Constraints ---
72
73/// Optional constraints on a parameter's value (min/max range, required flag).
74#[derive(Debug, Clone, Serialize, PartialEq)]
75#[serde(rename_all = "camelCase")]
76pub struct Constraints {
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub min: Option<f64>,
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub max: Option<f64>,
81    pub required: bool,
82}
83
84// --- PresetEntry — quick-pick preset for sliders/numerics ---
85
86/// A labeled preset value offered next to a parameter's control.
87#[derive(Debug, Clone, Serialize, PartialEq)]
88#[serde(rename_all = "camelCase")]
89pub struct PresetEntry {
90    pub value: serde_json::Value,
91    pub label: String,
92}
93
94// --- ParameterDef ---
95
96/// A complete definition of one parameter a node accepts. Provides
97/// everything the engine (validation) and UI (control rendering) need.
98#[derive(Debug, Clone, Serialize, PartialEq)]
99#[serde(rename_all = "camelCase")]
100pub struct ParameterDef {
101    pub name: std::string::String,
102    pub label: std::string::String,
103    pub description: std::string::String,
104    /// Value type — determines what UI control to render.
105    pub param_type: ParameterType,
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub default: Option<serde_json::Value>,
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub constraints: Option<Constraints>,
110
111    // --- UI Metadata Fields ---
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub placeholder: Option<String>,
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub visible_when: Option<ParamCondition>,
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub required_when: Option<ParamCondition>,
118    /// Whether this param can be surfaced in container config panels.
119    #[serde(default = "default_true")]
120    pub surfaceable: bool,
121    /// Whether someone running a recipe sets this param: the run screen
122    /// shows it when the recipe declares no `fields`. False for params that
123    /// are the program itself (a shell command and its args), which only the
124    /// author sets; authoring surfaces go by `surfaceable`. Native-only: no
125    /// browser node needs it, so it stays out of the catalog.
126    #[serde(skip)]
127    pub run_option: bool,
128
129    // --- Presentation Fields (engine-owned schema) ---
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub group: Option<String>,
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub suffix: Option<String>,
134    /// Override control identifier (e.g., `"slider"`, `"select"`, `"file"`).
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub control: Option<String>,
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub accept: Option<Vec<String>>,
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub presets: Option<Vec<PresetEntry>>,
141    /// Flip the semantic of a boolean control.
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub inverted: Option<bool>,
144}
145
146/// Serde default for `surfaceable` field during deserialization.
147#[allow(dead_code)]
148fn default_true() -> bool {
149    true
150}
151
152impl Default for ParameterDef {
153    fn default() -> Self {
154        Self {
155            name: String::default(),
156            label: String::default(),
157            description: String::default(),
158            param_type: ParameterType::default(),
159            default: None,
160            constraints: None,
161            placeholder: None,
162            visible_when: None,
163            required_when: None,
164            surfaceable: true,
165            run_option: true,
166            group: None,
167            suffix: None,
168            control: None,
169            accept: None,
170            presets: None,
171            inverted: None,
172        }
173    }
174}