Skip to main content

pharos_native/runtime/
ui.rs

1#![allow(clippy::too_many_arguments)]
2
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use serde_json::{Map, Value};
7
8#[allow(non_snake_case)]
9/// Performs ADD UI PARAM.
10///
11/// # Parameters
12///
13/// - `params`: Input consumed by [`crate::runtime::ui::ADD_UI_PARAM`].
14/// - `key`: Input consumed by [`crate::runtime::ui::ADD_UI_PARAM`].
15/// - `text`: Input consumed by [`crate::runtime::ui::ADD_UI_PARAM`].
16///
17/// # Returns
18///
19/// Returns `true` when the condition checked by [`crate::runtime::ui::ADD_UI_PARAM`] holds and `false` otherwise.
20///
21/// # Examples
22///
23/// ```rust,ignore
24/// let _result = pharos_native::runtime::ui::ADD_UI_PARAM(todo!(), "key", "{}");
25/// ```
26///
27/// # Related
28///
29/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
30pub fn ADD_UI_PARAM(params: &mut Map<String, Value>, key: &str, text: &str) -> bool {
31    if key.is_empty() {
32        return false;
33    }
34    params.insert(key.to_owned(), Value::String(text.to_owned()));
35    true
36}
37
38/// Performs UI render param map.
39///
40/// # Parameters
41///
42/// - `id`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
43/// - `input_type`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
44/// - `button_type`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
45/// - `name`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
46/// - `label`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
47/// - `label_html`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
48/// - `value`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
49/// - `class_name`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
50/// - `label_class`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
51/// - `attributes_html`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
52/// - `options_html`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
53/// - `help_html`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
54/// - `content_html`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
55/// - `element_type`: Input consumed by [`crate::runtime::ui::ui_render_param_map`].
56///
57/// # Returns
58///
59/// Returns [`Some`] when [`crate::runtime::ui::ui_render_param_map`] can produce a value and [`None`] otherwise.
60///
61/// # Examples
62///
63/// ```rust,ignore
64/// let _result = pharos_native::runtime::ui::ui_render_param_map(todo!(), todo!(), todo!(), "name", todo!(), todo!(), "value", todo!(), todo!(), todo!(), todo!(), todo!(), todo!(), todo!());
65/// ```
66///
67/// # Related
68///
69/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
70pub fn ui_render_param_map(
71    id: &str,
72    input_type: Option<&str>,
73    button_type: Option<&str>,
74    name: &str,
75    label: &str,
76    label_html: &str,
77    value: &str,
78    class_name: Option<&str>,
79    label_class: Option<&str>,
80    attributes_html: &str,
81    options_html: &str,
82    help_html: &str,
83    content_html: &str,
84    element_type: &str,
85) -> Option<Map<String, Value>> {
86    if id.is_empty() || name.is_empty() || label.is_empty() || element_type.is_empty() {
87        return None;
88    }
89    let mut params = Map::new();
90    let resolved_class_name = class_name.unwrap_or(if element_type == "button" {
91        ""
92    } else {
93        "form-control"
94    });
95    let resolved_label_class = label_class.unwrap_or("");
96    ADD_UI_PARAM(&mut params, "id", id).then_some(())?;
97    ADD_UI_PARAM(&mut params, "input_type", input_type.unwrap_or("text")).then_some(())?;
98    ADD_UI_PARAM(&mut params, "button_type", button_type.unwrap_or("button")).then_some(())?;
99    ADD_UI_PARAM(&mut params, "name", name).then_some(())?;
100    ADD_UI_PARAM(&mut params, "label", label).then_some(())?;
101    ADD_UI_PARAM(&mut params, "label_html", label_html).then_some(())?;
102    ADD_UI_PARAM(&mut params, "value", value).then_some(())?;
103    ADD_UI_PARAM(&mut params, "class_name", resolved_class_name).then_some(())?;
104    ADD_UI_PARAM(&mut params, "label_class", resolved_label_class).then_some(())?;
105    ADD_UI_PARAM(&mut params, "attributes_html", attributes_html).then_some(())?;
106    ADD_UI_PARAM(&mut params, "options_html", options_html).then_some(())?;
107    ADD_UI_PARAM(&mut params, "help_html", help_html).then_some(())?;
108    ADD_UI_PARAM(&mut params, "content_html", content_html).then_some(())?;
109    Some(params)
110}
111
112const UI_BUFFER_LIMIT: usize = 2 * 1024 * 1024;
113const UI_IDENTIFIER_LIMIT: usize = 128;
114
115/// Performs HTML escape.
116fn html_escape(value: &str) -> String {
117    value
118        .replace('&', "&amp;")
119        .replace('<', "&lt;")
120        .replace('>', "&gt;")
121        .replace('"', "&quot;")
122        .replace('\'', "&#39;")
123}
124
125/// Appends a bounded slice to a canonical UI buffer.
126///
127/// # Parameters
128///
129/// - `buffer`: Input consumed by [`crate::runtime::ui::ui_buffer_append_n`].
130/// - `text`: Input consumed by [`crate::runtime::ui::ui_buffer_append_n`].
131/// - `length`: Input consumed by [`crate::runtime::ui::ui_buffer_append_n`].
132///
133/// # Returns
134///
135/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_buffer_append_n`] holds and `false` otherwise.
136///
137/// # Examples
138///
139/// ```rust,ignore
140/// let _result = pharos_native::runtime::ui::ui_buffer_append_n(&mut [], "{}", todo!());
141/// ```
142///
143/// # Related
144///
145/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
146pub fn ui_buffer_append_n(buffer: &mut String, text: &str, length: usize) -> bool {
147    let Some(end) = length.checked_add(0) else {
148        return false;
149    };
150    let Some(fragment) = text.get(..end.min(text.len())) else {
151        return false;
152    };
153    if buffer.len().saturating_add(fragment.len()) > UI_BUFFER_LIMIT {
154        return false;
155    }
156    buffer.push_str(fragment);
157    true
158}
159
160/// Appends one complete canonical UI fragment to a bounded buffer.
161///
162/// # Parameters
163///
164/// - `buffer`: Input consumed by [`crate::runtime::ui::ui_buffer_append`].
165/// - `text`: Input consumed by [`crate::runtime::ui::ui_buffer_append`].
166///
167/// # Returns
168///
169/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_buffer_append`] holds and `false` otherwise.
170///
171/// # Examples
172///
173/// ```rust,ignore
174/// let _result = pharos_native::runtime::ui::ui_buffer_append(&mut [], "{}");
175/// ```
176///
177/// # Related
178///
179/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
180pub fn ui_buffer_append(buffer: &mut String, text: &str) -> bool {
181    ui_buffer_append_n(buffer, text, text.len())
182}
183
184/// Takes ownership of a canonical UI buffer and leaves it empty.
185///
186/// # Parameters
187///
188/// - `buffer`: Input consumed by [`crate::runtime::ui::ui_buffer_take`].
189///
190/// # Returns
191///
192/// Returns [`Some`] when [`crate::runtime::ui::ui_buffer_take`] can produce a value and [`None`] otherwise.
193///
194/// # Examples
195///
196/// ```rust,ignore
197/// let _result = pharos_native::runtime::ui::ui_buffer_take(&mut []);
198/// ```
199///
200/// # Related
201///
202/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
203pub fn ui_buffer_take(buffer: &mut String) -> Option<String> {
204    (!buffer.is_empty()).then(|| std::mem::take(buffer))
205}
206
207/// Validates an identifier used by the canonical UI ledger.
208///
209/// # Parameters
210///
211/// - `value`: Input consumed by [`crate::runtime::ui::ui_identifier_valid`].
212///
213/// # Returns
214///
215/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_identifier_valid`] holds and `false` otherwise.
216///
217/// # Performance
218///
219/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_identifier_valid`].
220///
221/// # Examples
222///
223/// ```rust,ignore
224/// let _result = pharos_native::runtime::ui::ui_identifier_valid("value");
225/// ```
226///
227/// # Related
228///
229/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
230pub fn ui_identifier_valid(value: &str) -> bool {
231    !value.is_empty()
232        && value.len() <= UI_IDENTIFIER_LIMIT
233        && value
234            .bytes()
235            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'-'))
236        && value.as_bytes()[0].is_ascii_alphabetic()
237}
238
239/// Restricts input widgets to the HTML types supported by the declarative contract.
240///
241/// # Parameters
242///
243/// - `value`: Input consumed by [`crate::runtime::ui::ui_input_type_allowed`].
244///
245/// # Returns
246///
247/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_input_type_allowed`] holds and `false` otherwise.
248///
249/// # Examples
250///
251/// ```rust,ignore
252/// let _result = pharos_native::runtime::ui::ui_input_type_allowed("value");
253/// ```
254///
255/// # Related
256///
257/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
258pub fn ui_input_type_allowed(value: &str) -> bool {
259    matches!(
260        value,
261        "text"
262            | "email"
263            | "password"
264            | "number"
265            | "date"
266            | "time"
267            | "url"
268            | "tel"
269            | "search"
270            | "hidden"
271    )
272}
273
274/// Validates an app-relative fragment path and rejects traversal or control bytes.
275///
276/// # Parameters
277///
278/// - `relative`: Input consumed by [`crate::runtime::ui::ui_fragment_path_valid`].
279///
280/// # Returns
281///
282/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_fragment_path_valid`] holds and `false` otherwise.
283///
284/// # Performance
285///
286/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_fragment_path_valid`].
287///
288/// # Examples
289///
290/// ```rust,ignore
291/// let _result = pharos_native::runtime::ui::ui_fragment_path_valid(todo!());
292/// ```
293///
294/// # Related
295///
296/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
297pub fn ui_fragment_path_valid(relative: &str) -> bool {
298    !relative.is_empty()
299        && relative.len() <= 512
300        && !relative.starts_with('/')
301        && !relative.contains("..")
302        && !relative.bytes().any(|byte| byte < 0x20 || byte == 0x7f)
303}
304
305/// Resolves a validated app-relative UI path while preserving containment.
306///
307/// # Parameters
308///
309/// - `app_root`: Input consumed by [`crate::runtime::ui::ui_path`].
310/// - `relative`: Input consumed by [`crate::runtime::ui::ui_path`].
311///
312/// # Returns
313///
314/// Returns [`Some`] when [`crate::runtime::ui::ui_path`] can produce a value and [`None`] otherwise.
315///
316/// # Examples
317///
318/// ```rust,ignore
319/// let _result = pharos_native::runtime::ui::ui_path(std::path::Path::new("apps/dev_docs"), todo!());
320/// ```
321///
322/// # Related
323///
324/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
325pub fn ui_path(app_root: &str, relative: &str) -> Option<String> {
326    if app_root.is_empty() || !ui_fragment_path_valid(relative) {
327        return None;
328    }
329    let root = Path::new(app_root).canonicalize().ok()?;
330    let candidate = root.join(relative);
331    let resolved = candidate.canonicalize().ok()?;
332    resolved
333        .starts_with(&root)
334        .then(|| resolved.to_string_lossy().into_owned())
335}
336
337/// Identifies shared framework fragments.
338///
339/// # Parameters
340///
341/// - `relative`: Input consumed by [`crate::runtime::ui::ui_shared_asset_fragment`].
342///
343/// # Returns
344///
345/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_shared_asset_fragment`] holds and `false` otherwise.
346///
347/// # Examples
348///
349/// ```rust,ignore
350/// let _result = pharos_native::runtime::ui::ui_shared_asset_fragment(todo!());
351/// ```
352///
353/// # Related
354///
355/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
356pub fn ui_shared_asset_fragment(relative: &str) -> bool {
357    relative.starts_with("templates/shared/") && ui_fragment_path_valid(relative)
358}
359
360/// Resolves a shared framework fragment under the app root.
361///
362/// # Parameters
363///
364/// - `app_root`: Input consumed by [`crate::runtime::ui::ui_shared_asset_path`].
365/// - `relative`: Input consumed by [`crate::runtime::ui::ui_shared_asset_path`].
366///
367/// # Returns
368///
369/// Returns [`Some`] when [`crate::runtime::ui::ui_shared_asset_path`] can produce a value and [`None`] otherwise.
370///
371/// # Examples
372///
373/// ```rust,ignore
374/// let _result = pharos_native::runtime::ui::ui_shared_asset_path(std::path::Path::new("apps/dev_docs"), todo!());
375/// ```
376///
377/// # Related
378///
379/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
380pub fn ui_shared_asset_path(app_root: &str, relative: &str) -> Option<String> {
381    ui_shared_asset_fragment(relative)
382        .then(|| ui_path(app_root, relative))
383        .flatten()
384}
385
386/// Appends HTML-escaped attribute text to a canonical buffer.
387///
388/// # Parameters
389///
390/// - `buffer`: Input consumed by [`crate::runtime::ui::ui_append_attr_escaped`].
391/// - `value`: Input consumed by [`crate::runtime::ui::ui_append_attr_escaped`].
392///
393/// # Returns
394///
395/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_append_attr_escaped`] holds and `false` otherwise.
396///
397/// # Examples
398///
399/// ```rust,ignore
400/// let _result = pharos_native::runtime::ui::ui_append_attr_escaped(&mut [], "value");
401/// ```
402///
403/// # Related
404///
405/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
406pub fn ui_append_attr_escaped(buffer: &mut String, value: &str) -> bool {
407    ui_buffer_append(buffer, &html_escape(value))
408}
409
410/// Builds one optional escaped HTML attribute.
411///
412/// # Parameters
413///
414/// - `attribute`: Input consumed by [`crate::runtime::ui::ui_optional_attribute`].
415/// - `value`: Input consumed by [`crate::runtime::ui::ui_optional_attribute`].
416///
417/// # Returns
418///
419/// Returns [`Some`] when [`crate::runtime::ui::ui_optional_attribute`] can produce a value and [`None`] otherwise.
420///
421/// # Examples
422///
423/// ```rust,ignore
424/// let _result = pharos_native::runtime::ui::ui_optional_attribute(todo!(), "value");
425/// ```
426///
427/// # Related
428///
429/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
430pub fn ui_optional_attribute(attribute: &str, value: Option<&str>) -> Option<String> {
431    if attribute.is_empty() || !ui_identifier_valid(attribute) {
432        return None;
433    }
434    value
435        .filter(|text| !text.is_empty())
436        .map(|text| format!(" {attribute}=\"{}\"", html_escape(text)))
437}
438
439/// Appends a boolean HTML attribute when enabled.
440///
441/// # Parameters
442///
443/// - `buffer`: Input consumed by [`crate::runtime::ui::ui_append_boolean_attribute`].
444/// - `attribute`: Input consumed by [`crate::runtime::ui::ui_append_boolean_attribute`].
445/// - `enabled`: Input consumed by [`crate::runtime::ui::ui_append_boolean_attribute`].
446///
447/// # Returns
448///
449/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_append_boolean_attribute`] holds and `false` otherwise.
450///
451/// # Examples
452///
453/// ```rust,ignore
454/// let _result = pharos_native::runtime::ui::ui_append_boolean_attribute(&mut [], todo!(), todo!());
455/// ```
456///
457/// # Related
458///
459/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
460pub fn ui_append_boolean_attribute(buffer: &mut String, attribute: &str, enabled: bool) -> bool {
461    if !enabled {
462        return true;
463    }
464    if attribute.is_empty() || !ui_identifier_valid(attribute) {
465        return false;
466    }
467    ui_buffer_append(buffer, &format!(" {attribute}"))
468}
469
470/// Rejects event literals that could inject markup or script.
471///
472/// # Parameters
473///
474/// - `value`: Input consumed by [`crate::runtime::ui::ui_event_literal_allowed`].
475///
476/// # Returns
477///
478/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_event_literal_allowed`] holds and `false` otherwise.
479///
480/// # Performance
481///
482/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_event_literal_allowed`].
483///
484/// # Examples
485///
486/// ```rust,ignore
487/// let _result = pharos_native::runtime::ui::ui_event_literal_allowed("value");
488/// ```
489///
490/// # Related
491///
492/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
493pub fn ui_event_literal_allowed(value: &str) -> bool {
494    !value.is_empty()
495        && value.len() <= 256
496        && !value
497            .chars()
498            .any(|ch| ch.is_control() || matches!(ch, '<' | '>' | '"' | '\''))
499}
500
501/// Performs value text.
502fn value_text(value: Option<&Value>) -> String {
503    match value {
504        Some(Value::String(text)) => text.clone(),
505        Some(Value::Bool(value)) => value.to_string(),
506        Some(Value::Number(value)) => value.to_string(),
507        Some(Value::Null) | None => String::new(),
508        Some(value) => serde_json::to_string(value).unwrap_or_default(),
509    }
510}
511
512/// Performs resolved value.
513fn resolved_value<'a>(value: Option<&'a Value>, params: &'a Value) -> Option<&'a Value> {
514    match value {
515        Some(Value::String(text)) if text.starts_with("{") && text.ends_with('}') => {
516            params.get(&text[1..text.len() - 1])
517        }
518        other => other,
519    }
520}
521
522/// Resolves a trusted HTML value from a declaration or page parameters.
523///
524/// # Parameters
525///
526/// - `value`: Input consumed by [`crate::runtime::ui::ui_resolved_trusted_html`].
527/// - `params`: Input consumed by [`crate::runtime::ui::ui_resolved_trusted_html`].
528///
529/// # Returns
530///
531/// Returns [`Some`] when [`crate::runtime::ui::ui_resolved_trusted_html`] can produce a value and [`None`] otherwise.
532///
533/// # Examples
534///
535/// ```rust,ignore
536/// let _result = pharos_native::runtime::ui::ui_resolved_trusted_html("value", todo!());
537/// ```
538///
539/// # Related
540///
541/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
542pub fn ui_resolved_trusted_html<'a>(value: Option<&'a Value>, params: &'a Value) -> Option<String> {
543    resolved_value(value, params)
544        .and_then(Value::as_str)
545        .map(ToOwned::to_owned)
546}
547
548/// Expands bounded parameter placeholders without executing authored code.
549///
550/// # Parameters
551///
552/// - `template_text`: Input consumed by [`crate::runtime::ui::ui_render_mutable_params`].
553/// - `params`: Input consumed by [`crate::runtime::ui::ui_render_mutable_params`].
554///
555/// # Returns
556///
557/// Returns [`Some`] when [`crate::runtime::ui::ui_render_mutable_params`] can produce a value and [`None`] otherwise.
558///
559/// # Performance
560///
561/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_render_mutable_params`].
562///
563/// # Examples
564///
565/// ```rust,ignore
566/// let _result = pharos_native::runtime::ui::ui_render_mutable_params(todo!(), todo!());
567/// ```
568///
569/// # Related
570///
571/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
572pub fn ui_render_mutable_params(template_text: &str, params: &Value) -> Option<String> {
573    let object = params.as_object()?;
574    let mut output = String::with_capacity(template_text.len());
575    let mut cursor = 0usize;
576    while let Some(offset) = template_text[cursor..].find('{') {
577        let open = cursor + offset;
578        output.push_str(&template_text[cursor..open]);
579        let close = template_text[open + 1..].find('}')? + open + 1;
580        let key = &template_text[open + 1..close];
581        let value = object
582            .get(key)
583            .map(|value| value_text(Some(value)))
584            .unwrap_or_default();
585        output.push_str(&html_escape(&value));
586        cursor = close + 1;
587    }
588    output.push_str(&template_text[cursor..]);
589    (output.len() <= UI_BUFFER_LIMIT).then_some(output)
590}
591
592/// Loads and renders one validated app fragment.
593///
594/// # Parameters
595///
596/// - `app_root`: Input consumed by [`crate::runtime::ui::ui_render_fragment`].
597/// - `relative`: Input consumed by [`crate::runtime::ui::ui_render_fragment`].
598/// - `params`: Input consumed by [`crate::runtime::ui::ui_render_fragment`].
599///
600/// # Returns
601///
602/// Returns [`Some`] when [`crate::runtime::ui::ui_render_fragment`] can produce a value and [`None`] otherwise.
603///
604/// # Performance
605///
606/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_render_fragment`].
607///
608/// # Examples
609///
610/// ```rust,ignore
611/// let _result = pharos_native::runtime::ui::ui_render_fragment(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
612/// ```
613///
614/// # Related
615///
616/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
617pub fn ui_render_fragment(app_root: &str, relative: &str, params: &Value) -> Option<String> {
618    let path = if ui_shared_asset_fragment(relative) {
619        ui_shared_asset_path(app_root, relative)
620    } else {
621        ui_path(app_root, relative)
622    }?;
623    ui_render_mutable_params(&fs::read_to_string(path).ok()?, params)
624}
625
626/// Converts one scalar value to its canonical display text.
627///
628/// # Parameters
629///
630/// - `value`: Input consumed by [`crate::runtime::ui::ui_scalar_text`].
631///
632/// # Returns
633///
634/// Returns the computed value produced by [`crate::runtime::ui::ui_scalar_text`].
635///
636/// # Examples
637///
638/// ```rust,ignore
639/// let _result = pharos_native::runtime::ui::ui_scalar_text("value");
640/// ```
641///
642/// # Related
643///
644/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
645pub fn ui_scalar_text(value: Option<&Value>) -> String {
646    value_text(value)
647}
648
649/// Resolves a string value through page parameters.
650///
651/// # Parameters
652///
653/// - `value`: Input consumed by [`crate::runtime::ui::ui_resolved_string`].
654/// - `params`: Input consumed by [`crate::runtime::ui::ui_resolved_string`].
655///
656/// # Returns
657///
658/// Returns the computed value produced by [`crate::runtime::ui::ui_resolved_string`].
659///
660/// # Examples
661///
662/// ```rust,ignore
663/// let _result = pharos_native::runtime::ui::ui_resolved_string("value", todo!());
664/// ```
665///
666/// # Related
667///
668/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
669pub fn ui_resolved_string(value: Option<&Value>, params: &Value) -> String {
670    value_text(resolved_value(value, params))
671}
672
673/// Interpolates `{key}` placeholders in a scalar string.
674///
675/// # Parameters
676///
677/// - `value`: Input consumed by [`crate::runtime::ui::ui_interpolated_string`].
678/// - `params`: Input consumed by [`crate::runtime::ui::ui_interpolated_string`].
679///
680/// # Returns
681///
682/// Returns [`Some`] when [`crate::runtime::ui::ui_interpolated_string`] can produce a value and [`None`] otherwise.
683///
684/// # Examples
685///
686/// ```rust,ignore
687/// let _result = pharos_native::runtime::ui::ui_interpolated_string("value", todo!());
688/// ```
689///
690/// # Related
691///
692/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
693pub fn ui_interpolated_string(value: Option<&Value>, params: &Value) -> Option<String> {
694    ui_render_mutable_params(value?.as_str()?, params)
695}
696
697/// Resolves a boolean value through page parameters.
698///
699/// # Parameters
700///
701/// - `value`: Input consumed by [`crate::runtime::ui::ui_resolved_bool`].
702/// - `params`: Input consumed by [`crate::runtime::ui::ui_resolved_bool`].
703///
704/// # Returns
705///
706/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_resolved_bool`] holds and `false` otherwise.
707///
708/// # Examples
709///
710/// ```rust,ignore
711/// let _result = pharos_native::runtime::ui::ui_resolved_bool("value", todo!());
712/// ```
713///
714/// # Related
715///
716/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
717pub fn ui_resolved_bool(value: Option<&Value>, params: &Value) -> bool {
718    match resolved_value(value, params) {
719        Some(Value::Bool(value)) => *value,
720        Some(Value::String(value)) => matches!(value.as_str(), "true" | "1" | "yes" | "on"),
721        Some(Value::Number(value)) => value.as_i64().is_some_and(|number| number != 0),
722        _ => false,
723    }
724}
725
726/// Finds fragment value.
727fn find_fragment_value<'a>(root: &'a Value, id: &str) -> Option<&'a Value> {
728    root.get("elements")
729        .and_then(Value::as_array)?
730        .iter()
731        .find(|item| item.get("id").and_then(Value::as_str) == Some(id))
732}
733
734/// Renders choice options from a declarative array.
735///
736/// # Parameters
737///
738/// - `options`: Input consumed by [`crate::runtime::ui::ui_render_options`].
739/// - `params`: Input consumed by [`crate::runtime::ui::ui_render_options`].
740/// - `selected`: Input consumed by [`crate::runtime::ui::ui_render_options`].
741///
742/// # Returns
743///
744/// Returns [`Some`] when [`crate::runtime::ui::ui_render_options`] can produce a value and [`None`] otherwise.
745///
746/// # Performance
747///
748/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_render_options`].
749///
750/// # Examples
751///
752/// ```rust,ignore
753/// let _result = pharos_native::runtime::ui::ui_render_options(todo!(), todo!(), todo!());
754/// ```
755///
756/// # Related
757///
758/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
759pub fn ui_render_options(
760    options: Option<&Value>,
761    params: &Value,
762    selected: &str,
763) -> Option<String> {
764    let mut output = String::new();
765    for option in options?.as_array()? {
766        let value = ui_resolved_string(option.get("value"), params);
767        let label = ui_resolved_string(option.get("label"), params);
768        let selected_attr = if value == selected { " selected" } else { "" };
769        if !ui_buffer_append(
770            &mut output,
771            &format!(
772                "<option value=\"{}\"{}>{}</option>",
773                html_escape(&value),
774                selected_attr,
775                html_escape(&label)
776            ),
777        ) {
778            return None;
779        }
780    }
781    Some(output)
782}
783
784/// Renders escaped help copy as a fragment.
785///
786/// # Parameters
787///
788/// - `app_root`: Input consumed by [`crate::runtime::ui::ui_render_help`].
789/// - `help`: Input consumed by [`crate::runtime::ui::ui_render_help`].
790///
791/// # Returns
792///
793/// Returns [`Some`] when [`crate::runtime::ui::ui_render_help`] can produce a value and [`None`] otherwise.
794///
795/// # Examples
796///
797/// ```rust,ignore
798/// let _result = pharos_native::runtime::ui::ui_render_help(std::path::Path::new("apps/dev_docs"), todo!());
799/// ```
800///
801/// # Related
802///
803/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
804pub fn ui_render_help(app_root: &str, help: &str) -> Option<String> {
805    if help.is_empty() {
806        return Some(String::new());
807    }
808    let relative = help.strip_prefix("fragment:").unwrap_or(help);
809    if relative != help {
810        ui_render_fragment(app_root, relative, &Value::Object(Map::new()))
811    } else {
812        Some(format!(
813            "<small class=\"form-text\">{}</small>",
814            html_escape(help)
815        ))
816    }
817}
818
819/// Finds a canonical UI declaration by identifier.
820///
821/// # Parameters
822///
823/// - `ledger_root`: Input consumed by [`crate::runtime::ui::ui_find_element`].
824/// - `canonical_id`: Input consumed by [`crate::runtime::ui::ui_find_element`].
825///
826/// # Returns
827///
828/// Returns [`Some`] when [`crate::runtime::ui::ui_find_element`] can produce a value and [`None`] otherwise.
829///
830/// # Examples
831///
832/// ```rust,ignore
833/// let _result = pharos_native::runtime::ui::ui_find_element(todo!(), todo!());
834/// ```
835///
836/// # Related
837///
838/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
839pub fn ui_find_element<'a>(ledger_root: &'a Value, canonical_id: &str) -> Option<&'a Value> {
840    find_fragment_value(ledger_root, canonical_id)
841}
842
843/// Duplicates one scalar display value after parameter resolution.
844///
845/// # Parameters
846///
847/// - `value`: Input consumed by [`crate::runtime::ui::ui_scalar_dup`].
848/// - `params`: Input consumed by [`crate::runtime::ui::ui_scalar_dup`].
849///
850/// # Returns
851///
852/// Returns [`Some`] when [`crate::runtime::ui::ui_scalar_dup`] can produce a value and [`None`] otherwise.
853///
854/// # Examples
855///
856/// ```rust,ignore
857/// let _result = pharos_native::runtime::ui::ui_scalar_dup("value", todo!());
858/// ```
859///
860/// # Related
861///
862/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
863pub fn ui_scalar_dup(value: Option<&Value>, params: &Value) -> Option<String> {
864    Some(ui_resolved_string(value, params))
865}
866
867/// Renders a declared fragment with page parameters.
868///
869/// # Parameters
870///
871/// - `app_root`: Input consumed by [`crate::runtime::ui::ui_render_page_params_fragment`].
872/// - `field`: Input consumed by [`crate::runtime::ui::ui_render_page_params_fragment`].
873/// - `params`: Input consumed by [`crate::runtime::ui::ui_render_page_params_fragment`].
874///
875/// # Returns
876///
877/// Returns [`Some`] when [`crate::runtime::ui::ui_render_page_params_fragment`] can produce a value and [`None`] otherwise.
878///
879/// # Examples
880///
881/// ```rust,ignore
882/// let _result = pharos_native::runtime::ui::ui_render_page_params_fragment(std::path::Path::new("apps/dev_docs"), "field", todo!());
883/// ```
884///
885/// # Related
886///
887/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
888pub fn ui_render_page_params_fragment(
889    app_root: &str,
890    field: &Value,
891    params: &Value,
892) -> Option<String> {
893    let relative = field
894        .get("path")
895        .or_else(|| field.get("fragment"))
896        .and_then(Value::as_str)?;
897    ui_render_fragment(app_root, relative, params)
898}
899
900/// Adds a ledger-backed attribute after resolving its value.
901///
902/// # Parameters
903///
904/// - `buffer`: Input consumed by [`crate::runtime::ui::ui_append_ledger_attribute`].
905/// - `element`: Input consumed by [`crate::runtime::ui::ui_append_ledger_attribute`].
906/// - `key`: Input consumed by [`crate::runtime::ui::ui_append_ledger_attribute`].
907/// - `attribute`: Input consumed by [`crate::runtime::ui::ui_append_ledger_attribute`].
908/// - `params`: Input consumed by [`crate::runtime::ui::ui_append_ledger_attribute`].
909/// - `event_policy`: Input consumed by [`crate::runtime::ui::ui_append_ledger_attribute`].
910///
911/// # Returns
912///
913/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_append_ledger_attribute`] holds and `false` otherwise.
914///
915/// # Examples
916///
917/// ```rust,ignore
918/// let _result = pharos_native::runtime::ui::ui_append_ledger_attribute(&mut [], todo!(), "key", todo!(), todo!(), todo!());
919/// ```
920///
921/// # Related
922///
923/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
924pub fn ui_append_ledger_attribute(
925    buffer: &mut String,
926    element: &Value,
927    key: &str,
928    attribute: &str,
929    params: &Value,
930    event_policy: bool,
931) -> bool {
932    let value = ui_resolved_string(element.get(key), params);
933    if value.is_empty() {
934        return true;
935    }
936    if event_policy && !ui_event_literal_allowed(&value) {
937        return false;
938    }
939    ui_buffer_append(buffer, &format!(" {attribute}=\"{}\"", html_escape(&value)))
940}
941
942/// Validates structured data and HTMX attribute keys.
943///
944/// # Parameters
945///
946/// - `group`: Input consumed by [`crate::runtime::ui::ui_structured_key_allowed`].
947/// - `key`: Input consumed by [`crate::runtime::ui::ui_structured_key_allowed`].
948///
949/// # Returns
950///
951/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_structured_key_allowed`] holds and `false` otherwise.
952///
953/// # Examples
954///
955/// ```rust,ignore
956/// let _result = pharos_native::runtime::ui::ui_structured_key_allowed(todo!(), "key");
957/// ```
958///
959/// # Related
960///
961/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
962pub fn ui_structured_key_allowed(group: &str, key: &str) -> bool {
963    matches!(group, "data" | "hx") && ui_identifier_valid(key)
964}
965
966/// Appends a structured attribute group from a declaration.
967///
968/// # Parameters
969///
970/// - `buffer`: Input consumed by [`crate::runtime::ui::ui_append_structured_attributes`].
971/// - `element`: Input consumed by [`crate::runtime::ui::ui_append_structured_attributes`].
972/// - `group`: Input consumed by [`crate::runtime::ui::ui_append_structured_attributes`].
973/// - `params`: Input consumed by [`crate::runtime::ui::ui_append_structured_attributes`].
974///
975/// # Returns
976///
977/// Returns `true` when the condition checked by [`crate::runtime::ui::ui_append_structured_attributes`] holds and `false` otherwise.
978///
979/// # Performance
980///
981/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_append_structured_attributes`].
982///
983/// # Examples
984///
985/// ```rust,ignore
986/// let _result = pharos_native::runtime::ui::ui_append_structured_attributes(&mut [], todo!(), todo!(), todo!());
987/// ```
988///
989/// # Related
990///
991/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
992pub fn ui_append_structured_attributes(
993    buffer: &mut String,
994    element: &Value,
995    group: &str,
996    params: &Value,
997) -> bool {
998    let Some(values) = element.get(group).and_then(Value::as_object) else {
999        return true;
1000    };
1001    for (key, value) in values {
1002        if !ui_structured_key_allowed(group, key)
1003            || !ui_append_ledger_attribute(
1004                buffer,
1005                &Value::Object(Map::from_iter([(key.clone(), value.clone())])),
1006                key,
1007                &format!("{group}-{key}"),
1008                params,
1009                group == "hx",
1010            )
1011        {
1012            return false;
1013        }
1014    }
1015    true
1016}
1017
1018/// Renders a choice group as safe option or radio markup.
1019///
1020/// # Parameters
1021///
1022/// - `_app_root`: Input consumed by [`crate::runtime::ui::ui_render_choice_options`].
1023/// - `element`: Input consumed by [`crate::runtime::ui::ui_render_choice_options`].
1024/// - `params`: Input consumed by [`crate::runtime::ui::ui_render_choice_options`].
1025/// - `group_name`: Input consumed by [`crate::runtime::ui::ui_render_choice_options`].
1026/// - `group_id`: Input consumed by [`crate::runtime::ui::ui_render_choice_options`].
1027/// - `radio_mode`: Input consumed by [`crate::runtime::ui::ui_render_choice_options`].
1028///
1029/// # Returns
1030///
1031/// Returns [`Some`] when [`crate::runtime::ui::ui_render_choice_options`] can produce a value and [`None`] otherwise.
1032///
1033/// # Performance
1034///
1035/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_render_choice_options`].
1036///
1037/// # Examples
1038///
1039/// ```rust,ignore
1040/// let _result = pharos_native::runtime::ui::ui_render_choice_options(todo!(), todo!(), todo!(), todo!(), todo!(), todo!());
1041/// ```
1042///
1043/// # Related
1044///
1045/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
1046pub fn ui_render_choice_options(
1047    _app_root: &str,
1048    element: &Value,
1049    params: &Value,
1050    group_name: &str,
1051    group_id: &str,
1052    radio_mode: bool,
1053) -> Option<String> {
1054    let options = element.get("options")?.as_array()?;
1055    let selected = ui_resolved_string(element.get("value"), params);
1056    let mut output = String::new();
1057    for option in options {
1058        let value = ui_resolved_string(option.get("value"), params);
1059        let label = ui_resolved_string(option.get("label"), params);
1060        if radio_mode {
1061            output.push_str(&format!(
1062                "<label><input type=\"radio\" name=\"{}\" value=\"{}\"{}> {}</label>",
1063                html_escape(group_name),
1064                html_escape(&value),
1065                if value == selected { " checked" } else { "" },
1066                html_escape(&label)
1067            ));
1068        } else {
1069            output.push_str(&format!(
1070                "<option value=\"{}\"{}>{}</option>",
1071                html_escape(&value),
1072                if value == selected { " selected" } else { "" },
1073                html_escape(&label)
1074            ));
1075        }
1076    }
1077    (!group_id.is_empty()).then_some(output)
1078}
1079
1080/// Renders a button row from a declaration.
1081///
1082/// # Parameters
1083///
1084/// - `app_root`: Input consumed by [`crate::runtime::ui::ui_render_button_row`].
1085/// - `element`: Input consumed by [`crate::runtime::ui::ui_render_button_row`].
1086/// - `params`: Input consumed by [`crate::runtime::ui::ui_render_button_row`].
1087/// - `group_id`: Input consumed by [`crate::runtime::ui::ui_render_button_row`].
1088/// - `class_name`: Input consumed by [`crate::runtime::ui::ui_render_button_row`].
1089///
1090/// # Returns
1091///
1092/// Returns [`Some`] when [`crate::runtime::ui::ui_render_button_row`] can produce a value and [`None`] otherwise.
1093///
1094/// # Performance
1095///
1096/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_render_button_row`].
1097///
1098/// # Examples
1099///
1100/// ```rust,ignore
1101/// let _result = pharos_native::runtime::ui::ui_render_button_row(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!());
1102/// ```
1103///
1104/// # Related
1105///
1106/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
1107pub fn ui_render_button_row(
1108    app_root: &str,
1109    element: &Value,
1110    params: &Value,
1111    group_id: &str,
1112    class_name: &str,
1113) -> Option<String> {
1114    let buttons = element.get("buttons")?.as_array()?;
1115    let mut output = format!(
1116        "<div id=\"{}\" class=\"{}\">",
1117        html_escape(group_id),
1118        html_escape(class_name)
1119    );
1120    for button in buttons {
1121        let label = ui_resolved_string(button.get("label"), params);
1122        let path = ui_resolved_string(button.get("path"), params);
1123        if !ui_event_literal_allowed(&path) {
1124            return None;
1125        }
1126        output.push_str(&format!(
1127            "<a href=\"{}\">{}</a>",
1128            html_escape(&path),
1129            html_escape(&label)
1130        ));
1131    }
1132    output.push_str("</div>");
1133    let _ = app_root;
1134    Some(output)
1135}
1136
1137/// Renders one complete declaration using the canonical UI contract.
1138///
1139/// # Parameters
1140///
1141/// - `app_root`: Input consumed by [`crate::runtime::ui::ui_render_declaration_html`].
1142/// - `element`: Input consumed by [`crate::runtime::ui::ui_render_declaration_html`].
1143/// - `params`: Input consumed by [`crate::runtime::ui::ui_render_declaration_html`].
1144///
1145/// # Returns
1146///
1147/// Returns [`Some`] when [`crate::runtime::ui::ui_render_declaration_html`] can produce a value and [`None`] otherwise.
1148///
1149/// # Examples
1150///
1151/// ```rust,ignore
1152/// let _result = pharos_native::runtime::ui::ui_render_declaration_html(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
1153/// ```
1154///
1155/// # Related
1156///
1157/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
1158pub fn ui_render_declaration_html(
1159    app_root: &str,
1160    element: &Value,
1161    params: &Value,
1162) -> Option<String> {
1163    let element_type = element
1164        .get("element_type")
1165        .or_else(|| element.get("type"))
1166        .and_then(Value::as_str)?;
1167    let id = element.get("id").and_then(Value::as_str)?;
1168    if !ui_identifier_valid(id) {
1169        return None;
1170    }
1171    if element_type == "button_row" {
1172        return ui_render_button_row(
1173            app_root,
1174            element,
1175            params,
1176            id,
1177            element
1178                .get("class")
1179                .and_then(Value::as_str)
1180                .unwrap_or("ui-button-row"),
1181        );
1182    }
1183    let name = element.get("name").and_then(Value::as_str).unwrap_or(id);
1184    let label = ui_resolved_string(element.get("label"), params);
1185    let value = ui_resolved_string(element.get("value"), params);
1186    let input_type = element
1187        .get("input_type")
1188        .and_then(Value::as_str)
1189        .unwrap_or("text");
1190    if element_type == "input" && !ui_input_type_allowed(input_type) {
1191        return None;
1192    }
1193    let mut attrs = format!(
1194        " id=\"{}\" name=\"{}\" type=\"{}\" value=\"{}\"",
1195        html_escape(id),
1196        html_escape(name),
1197        html_escape(input_type),
1198        html_escape(&value)
1199    );
1200    let mut attr_buffer = String::new();
1201    if !ui_append_structured_attributes(&mut attr_buffer, element, "data", params)
1202        || !ui_append_structured_attributes(&mut attr_buffer, element, "hx", params)
1203    {
1204        return None;
1205    }
1206    attrs.push_str(&attr_buffer);
1207    Some(format!(
1208        "<label for=\"{}\">{}</label><input{}>",
1209        html_escape(id),
1210        html_escape(&label),
1211        attrs
1212    ))
1213}
1214
1215/// Loads a UI ledger JSON document from an app root.
1216///
1217/// # Parameters
1218///
1219/// - `app_root`: Input consumed by [`crate::runtime::ui::ui_load_ledger`].
1220///
1221/// # Returns
1222///
1223/// Returns [`Some`] when [`crate::runtime::ui::ui_load_ledger`] can produce a value and [`None`] otherwise.
1224///
1225/// # Performance
1226///
1227/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_load_ledger`].
1228///
1229/// # Examples
1230///
1231/// ```rust,ignore
1232/// let _result = pharos_native::runtime::ui::ui_load_ledger(std::path::Path::new("apps/dev_docs"));
1233/// ```
1234///
1235/// # Related
1236///
1237/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
1238pub fn ui_load_ledger(app_root: &str) -> Option<Value> {
1239    let path = PathBuf::from(app_root).join("data/contracts/canonical-ui.json");
1240    serde_json::from_str(&fs::read_to_string(path).ok()?).ok()
1241}
1242
1243/// Computes a validated placeholder identifier.
1244///
1245/// # Parameters
1246///
1247/// - `name`: Input consumed by [`crate::runtime::ui::ui_placeholder_id`].
1248///
1249/// # Returns
1250///
1251/// Returns [`Some`] when [`crate::runtime::ui::ui_placeholder_id`] can produce a value and [`None`] otherwise.
1252///
1253/// # Examples
1254///
1255/// ```rust,ignore
1256/// let _result = pharos_native::runtime::ui::ui_placeholder_id("name");
1257/// ```
1258///
1259/// # Related
1260///
1261/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
1262pub fn ui_placeholder_id(name: &str) -> Option<String> {
1263    let name = name.trim();
1264    ui_identifier_valid(name).then(|| name.to_owned())
1265}
1266
1267/// Renders a page template after ledger declarations are resolved.
1268///
1269/// # Parameters
1270///
1271/// - `app_root`: Input consumed by [`crate::runtime::ui::ui_render_page_file`].
1272/// - `template_file`: Input consumed by [`crate::runtime::ui::ui_render_page_file`].
1273/// - `page_params`: Input consumed by [`crate::runtime::ui::ui_render_page_file`].
1274///
1275/// # Returns
1276///
1277/// Returns [`Some`] when [`crate::runtime::ui::ui_render_page_file`] can produce a value and [`None`] otherwise.
1278///
1279/// # Performance
1280///
1281/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_render_page_file`].
1282///
1283/// # Examples
1284///
1285/// ```rust,ignore
1286/// let _result = pharos_native::runtime::ui::ui_render_page_file(std::path::Path::new("apps/dev_docs"), std::path::Path::new("template.html"), todo!());
1287/// ```
1288///
1289/// # Related
1290///
1291/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
1292pub fn ui_render_page_file(
1293    app_root: &str,
1294    template_file: &str,
1295    page_params: &Value,
1296) -> Option<String> {
1297    let template_path = ui_path(app_root, template_file)?;
1298    let template = fs::read_to_string(template_path).ok()?;
1299    ui_render_mutable_params(&template, page_params)
1300}
1301
1302/// Builds the validated attribute string for one UI declaration.
1303///
1304/// # Parameters
1305///
1306/// - `element`: Input consumed by [`crate::runtime::ui::ui_declaration_attributes`].
1307/// - `params`: Input consumed by [`crate::runtime::ui::ui_declaration_attributes`].
1308///
1309/// # Returns
1310///
1311/// Returns [`Some`] when [`crate::runtime::ui::ui_declaration_attributes`] can produce a value and [`None`] otherwise.
1312///
1313/// # Performance
1314///
1315/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::ui::ui_declaration_attributes`].
1316///
1317/// # Examples
1318///
1319/// ```rust,ignore
1320/// let _result = pharos_native::runtime::ui::ui_declaration_attributes(todo!(), todo!());
1321/// ```
1322///
1323/// # Related
1324///
1325/// - [`crate::runtime::ui`] for adjacent helpers that share the same runtime surface.
1326pub fn ui_declaration_attributes(element: &Value, params: &Value) -> Option<String> {
1327    let mut output = String::new();
1328    for (key, attribute, event_policy) in [
1329        ("placeholder", "placeholder", false),
1330        ("aria_label", "aria-label", false),
1331        ("hx_get", "hx-get", true),
1332        ("hx_post", "hx-post", true),
1333    ] {
1334        if !ui_append_ledger_attribute(&mut output, element, key, attribute, params, event_policy) {
1335            return None;
1336        }
1337    }
1338    if !ui_append_boolean_attribute(
1339        &mut output,
1340        "required",
1341        ui_resolved_bool(element.get("required"), params),
1342    ) || !ui_append_boolean_attribute(
1343        &mut output,
1344        "checked",
1345        ui_resolved_bool(element.get("checked"), params),
1346    ) {
1347        return None;
1348    }
1349    Some(output)
1350}