Skip to main content

pharos_runtime_compiler/
declarative.rs

1#![allow(clippy::too_many_arguments)]
2
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use serde_json::{Map, Value};
7
8/// Parses YAML file.
9fn parse_yaml_file(path: &Path) -> Option<Value> {
10    pharos_runtime_core::yaml::parse_yaml_file(path)
11}
12
13/// Builds source path.
14///
15/// # Parameters
16///
17/// - `base_dir`: Input consumed by [`crate::declarative::build_source_path`].
18/// - `rel_path`: Input consumed by [`crate::declarative::build_source_path`].
19/// - `ext`: Input consumed by [`crate::declarative::build_source_path`].
20///
21/// # Returns
22///
23/// Returns [`Some`] when [`crate::declarative::build_source_path`] can produce a value and [`None`] otherwise.
24///
25/// # Examples
26///
27/// ```rust,ignore
28/// let _result = pharos_runtime_compiler::declarative::build_source_path(std::path::Path::new("apps"), todo!(), todo!());
29/// ```
30///
31/// # Related
32///
33/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
34pub fn build_source_path(base_dir: &Path, rel_path: &str, ext: &str) -> Option<PathBuf> {
35    (!rel_path.is_empty() && !ext.is_empty()).then(|| base_dir.join(format!("{rel_path}{ext}")))
36}
37
38/// Loads YAML source.
39///
40/// # Parameters
41///
42/// - `base_dir`: Input consumed by [`crate::declarative::load_yaml_source`].
43/// - `rel_path`: Input consumed by [`crate::declarative::load_yaml_source`].
44///
45/// # Returns
46///
47/// Returns [`Some`] when [`crate::declarative::load_yaml_source`] can produce a value and [`None`] otherwise.
48///
49/// # Performance
50///
51/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::load_yaml_source`].
52///
53/// # Examples
54///
55/// ```rust,ignore
56/// let _result = pharos_runtime_compiler::declarative::load_yaml_source(std::path::Path::new("apps"), todo!());
57/// ```
58///
59/// # Related
60///
61/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
62pub fn load_yaml_source(base_dir: &Path, rel_path: &str) -> Option<Value> {
63    if rel_path.is_empty() {
64        return None;
65    }
66    let stem = rel_path
67        .strip_suffix(".yml")
68        .or_else(|| rel_path.strip_suffix(".yaml"))
69        .unwrap_or(rel_path);
70    let json_path = base_dir.join(format!("{stem}.json"));
71    if json_path.is_file() {
72        return serde_json::from_str(&fs::read_to_string(json_path).ok()?).ok();
73    }
74    let yaml_path = base_dir.join(format!("{stem}.yml"));
75    yaml_path
76        .is_file()
77        .then(|| parse_yaml_file(&yaml_path))
78        .flatten()
79}
80
81/// Performs declarative source load page decl.
82///
83/// # Parameters
84///
85/// - `base_dir`: Input consumed by [`crate::declarative::declarative_source_load_page_decl`].
86/// - `page_name`: Input consumed by [`crate::declarative::declarative_source_load_page_decl`].
87///
88/// # Returns
89///
90/// Returns [`Some`] when [`crate::declarative::declarative_source_load_page_decl`] can produce a value and [`None`] otherwise.
91///
92/// # Examples
93///
94/// ```rust,ignore
95/// let _result = pharos_runtime_compiler::declarative::declarative_source_load_page_decl(std::path::Path::new("apps"), todo!());
96/// ```
97///
98/// # Related
99///
100/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
101pub fn declarative_source_load_page_decl(base_dir: &Path, page_name: &str) -> Option<Value> {
102    if page_name.is_empty() {
103        return None;
104    }
105    load_yaml_source(base_dir, &format!("{page_name}.page"))
106}
107
108/// Performs declarative source load fixture.
109///
110/// # Parameters
111///
112/// - `base_dir`: Input consumed by [`crate::declarative::declarative_source_load_fixture`].
113/// - `rel_path`: Input consumed by [`crate::declarative::declarative_source_load_fixture`].
114///
115/// # Returns
116///
117/// Returns [`Some`] when [`crate::declarative::declarative_source_load_fixture`] can produce a value and [`None`] otherwise.
118///
119/// # Examples
120///
121/// ```rust,ignore
122/// let _result = pharos_runtime_compiler::declarative::declarative_source_load_fixture(std::path::Path::new("apps"), todo!());
123/// ```
124///
125/// # Related
126///
127/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
128pub fn declarative_source_load_fixture(base_dir: &Path, rel_path: &str) -> Option<Value> {
129    if rel_path.is_empty() {
130        return None;
131    }
132    if rel_path.ends_with(".json") {
133        let path = build_source_path(
134            base_dir,
135            rel_path.strip_suffix(".json").unwrap_or(rel_path),
136            ".json",
137        )?;
138        let metadata = fs::metadata(&path).ok()?;
139        if metadata.len() > 1024 * 1024 {
140            return None;
141        }
142        let text = fs::read_to_string(path).ok()?;
143        return serde_json::from_str(&text).ok();
144    }
145    load_yaml_source(base_dir, rel_path.strip_suffix(".yml").unwrap_or(rel_path))
146}
147
148/// Validates the minimum fields required by a declarative app manifest.
149///
150/// # Parameters
151///
152/// - `manifest_text`: Input consumed by [`crate::declarative::declarative_manifest_has_required_fields`].
153///
154/// # Returns
155///
156/// Returns `true` when the condition checked by [`crate::declarative::declarative_manifest_has_required_fields`] holds and `false` otherwise.
157///
158/// # Performance
159///
160/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_manifest_has_required_fields`].
161///
162/// # Examples
163///
164/// ```rust,ignore
165/// let _result = pharos_runtime_compiler::declarative::declarative_manifest_has_required_fields(todo!());
166/// ```
167///
168/// # Related
169///
170/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
171pub fn declarative_manifest_has_required_fields(manifest_text: &str) -> bool {
172    let Ok(root) = serde_json::from_str::<Value>(manifest_text) else {
173        return false;
174    };
175    let Some(object) = root.as_object() else {
176        return false;
177    };
178    ["app_id", "name", "version"].iter().all(|key| {
179        object
180            .get(*key)
181            .and_then(Value::as_str)
182            .is_some_and(|value| !value.trim().is_empty())
183    })
184}
185
186/// Loads the declarative manifest text from an app root with a bounded read.
187///
188/// # Parameters
189///
190/// - `app_root`: Input consumed by [`crate::declarative::declarative_source_load_manifest`].
191///
192/// # Returns
193///
194/// Returns [`Some`] when [`crate::declarative::declarative_source_load_manifest`] can produce a value and [`None`] otherwise.
195///
196/// # Performance
197///
198/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_load_manifest`].
199///
200/// # Examples
201///
202/// ```rust,ignore
203/// let _result = pharos_runtime_compiler::declarative::declarative_source_load_manifest(std::path::Path::new("apps/dev_docs"));
204/// ```
205///
206/// # Related
207///
208/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
209pub fn declarative_source_load_manifest(app_root: &Path) -> Option<String> {
210    let path = app_root.join("pharos.app.json");
211    let metadata = fs::metadata(&path).ok()?;
212    (metadata.len() <= 1024 * 1024)
213        .then(|| fs::read_to_string(path).ok())
214        .flatten()
215        .filter(|text| declarative_manifest_has_required_fields(text))
216}
217
218/// Performs declarative source has YAML page.
219///
220/// # Parameters
221///
222/// - `base_dir`: Input consumed by [`crate::declarative::declarative_source_has_yaml_page`].
223/// - `page_name`: Input consumed by [`crate::declarative::declarative_source_has_yaml_page`].
224///
225/// # Returns
226///
227/// Returns `true` when the condition checked by [`crate::declarative::declarative_source_has_yaml_page`] holds and `false` otherwise.
228///
229/// # Examples
230///
231/// ```rust,ignore
232/// let _result = pharos_runtime_compiler::declarative::declarative_source_has_yaml_page(std::path::Path::new("apps"), todo!());
233/// ```
234///
235/// # Related
236///
237/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
238pub fn declarative_source_has_yaml_page(base_dir: &Path, page_name: &str) -> bool {
239    if page_name.is_empty() {
240        return false;
241    }
242    build_source_path(base_dir, &format!("{page_name}.page"), ".yml")
243        .is_some_and(|path| path.exists())
244}
245
246/// Performs declarative source has YAML fixture.
247///
248/// # Parameters
249///
250/// - `base_dir`: Input consumed by [`crate::declarative::declarative_source_has_yaml_fixture`].
251/// - `rel_path`: Input consumed by [`crate::declarative::declarative_source_has_yaml_fixture`].
252///
253/// # Returns
254///
255/// Returns `true` when the condition checked by [`crate::declarative::declarative_source_has_yaml_fixture`] holds and `false` otherwise.
256///
257/// # Examples
258///
259/// ```rust,ignore
260/// let _result = pharos_runtime_compiler::declarative::declarative_source_has_yaml_fixture(std::path::Path::new("apps"), todo!());
261/// ```
262///
263/// # Related
264///
265/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
266pub fn declarative_source_has_yaml_fixture(base_dir: &Path, rel_path: &str) -> bool {
267    if rel_path.is_empty() {
268        return false;
269    }
270    build_source_path(base_dir, rel_path, ".yml").is_some_and(|path| path.exists())
271}
272
273/// Finds the first object in an array whose named field equals the expected string.
274///
275/// # Parameters
276///
277/// - `array_value`: Input consumed by [`crate::declarative::declarative_source_find_object_by_string_field`].
278/// - `field_name`: Input consumed by [`crate::declarative::declarative_source_find_object_by_string_field`].
279/// - `expected_value`: Input consumed by [`crate::declarative::declarative_source_find_object_by_string_field`].
280///
281/// # Returns
282///
283/// Returns [`Some`] when [`crate::declarative::declarative_source_find_object_by_string_field`] can produce a value and [`None`] otherwise.
284///
285/// # Performance
286///
287/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_find_object_by_string_field`].
288///
289/// # Examples
290///
291/// ```rust,ignore
292/// let _result = pharos_runtime_compiler::declarative::declarative_source_find_object_by_string_field(todo!(), todo!(), todo!());
293/// ```
294///
295/// # Related
296///
297/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
298pub fn declarative_source_find_object_by_string_field<'a>(
299    array_value: &'a Value,
300    field_name: &str,
301    expected_value: &str,
302) -> Option<&'a Value> {
303    array_value
304        .as_array()?
305        .iter()
306        .find(|item| item.get(field_name).and_then(Value::as_str) == Some(expected_value))
307}
308
309/// Performs declarative source route path to surface path.
310///
311/// # Parameters
312///
313/// - `route_path`: Input consumed by [`crate::declarative::declarative_source_route_path_to_surface_path`].
314///
315/// # Returns
316///
317/// Returns [`Some`] when [`crate::declarative::declarative_source_route_path_to_surface_path`] can produce a value and [`None`] otherwise.
318///
319/// # Performance
320///
321/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_route_path_to_surface_path`].
322///
323/// # Examples
324///
325/// ```rust,ignore
326/// let _result = pharos_runtime_compiler::declarative::declarative_source_route_path_to_surface_path(todo!());
327/// ```
328///
329/// # Related
330///
331/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
332pub fn declarative_source_route_path_to_surface_path(route_path: &str) -> Option<String> {
333    if route_path.is_empty() {
334        return Some(String::new());
335    }
336    let mut result = String::with_capacity(route_path.len());
337    let chars: Vec<char> = route_path.chars().collect();
338    let mut index = 0usize;
339    while index < chars.len() {
340        if chars[index] == ':' {
341            index += 1;
342            result.push('{');
343            while index < chars.len() && chars[index] != '/' {
344                result.push(chars[index]);
345                index += 1;
346            }
347            result.push('}');
348            continue;
349        }
350        result.push(chars[index]);
351        index += 1;
352    }
353    Some(result)
354}
355
356/// Performs declarative source copy optional member.
357///
358/// # Parameters
359///
360/// - `target_obj`: Input consumed by [`crate::declarative::declarative_source_copy_optional_member`].
361/// - `source_obj`: Input consumed by [`crate::declarative::declarative_source_copy_optional_member`].
362/// - `key`: Input consumed by [`crate::declarative::declarative_source_copy_optional_member`].
363///
364/// # Returns
365///
366/// Returns `true` when the condition checked by [`crate::declarative::declarative_source_copy_optional_member`] holds and `false` otherwise.
367///
368/// # Examples
369///
370/// ```rust,ignore
371/// let _result = pharos_runtime_compiler::declarative::declarative_source_copy_optional_member(todo!(), todo!(), "key");
372/// ```
373///
374/// # Related
375///
376/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
377pub fn declarative_source_copy_optional_member(
378    target_obj: &mut Map<String, Value>,
379    source_obj: &Value,
380    key: &str,
381) -> bool {
382    if key.is_empty() {
383        return false;
384    }
385    if let Some(value) = source_obj.as_object().and_then(|map| map.get(key)) {
386        target_obj.insert(key.to_owned(), value.clone());
387    }
388    true
389}
390
391/// Performs declarative source array has string.
392///
393/// # Parameters
394///
395/// - `array_value`: Input consumed by [`crate::declarative::declarative_source_array_has_string`].
396/// - `expected_value`: Input consumed by [`crate::declarative::declarative_source_array_has_string`].
397///
398/// # Returns
399///
400/// Returns `true` when the condition checked by [`crate::declarative::declarative_source_array_has_string`] holds and `false` otherwise.
401///
402/// # Performance
403///
404/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_array_has_string`].
405///
406/// # Examples
407///
408/// ```rust,ignore
409/// let _result = pharos_runtime_compiler::declarative::declarative_source_array_has_string(todo!(), todo!());
410/// ```
411///
412/// # Related
413///
414/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
415pub fn declarative_source_array_has_string(array_value: &Value, expected_value: &str) -> bool {
416    !expected_value.is_empty()
417        && array_value.as_array().is_some_and(|items| {
418            items
419                .iter()
420                .any(|item| item.as_str() == Some(expected_value))
421        })
422}
423
424/// Performs API prefixed route path.
425///
426/// # Parameters
427///
428/// - `route_path`: Input consumed by [`crate::declarative::api_prefixed_route_path`].
429///
430/// # Returns
431///
432/// Returns [`Some`] when [`crate::declarative::api_prefixed_route_path`] can produce a value and [`None`] otherwise.
433///
434/// # Examples
435///
436/// ```rust,ignore
437/// let _result = pharos_runtime_compiler::declarative::api_prefixed_route_path(todo!());
438/// ```
439///
440/// # Related
441///
442/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
443pub fn api_prefixed_route_path(route_path: &str) -> Option<String> {
444    Some(format!("/api{route_path}"))
445}
446
447/// Performs declarative source build operation mut.
448///
449/// # Parameters
450///
451/// - `method`: Input consumed by [`crate::declarative::declarative_source_build_operation_mut`].
452/// - `path`: Input consumed by [`crate::declarative::declarative_source_build_operation_mut`].
453/// - `capability`: Input consumed by [`crate::declarative::declarative_source_build_operation_mut`].
454///
455/// # Returns
456///
457/// Returns [`Some`] when [`crate::declarative::declarative_source_build_operation_mut`] can produce a value and [`None`] otherwise.
458///
459/// # Examples
460///
461/// ```rust,ignore
462/// let _result = pharos_runtime_compiler::declarative::declarative_source_build_operation_mut(todo!(), std::path::Path::new("fixture.json"), todo!());
463/// ```
464///
465/// # Related
466///
467/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
468pub fn declarative_source_build_operation_mut(
469    method: &str,
470    path: &str,
471    capability: &str,
472) -> Option<Value> {
473    if method.is_empty() || path.is_empty() || capability.is_empty() {
474        return None;
475    }
476    let surface_path = declarative_source_route_path_to_surface_path(path)?;
477    Some(serde_json::json!({
478        "method": method,
479        "path": surface_path,
480        "capability": capability,
481    }))
482}
483
484/// Performs declarative source build route operation mut.
485///
486/// # Parameters
487///
488/// - `route_root`: Input consumed by [`crate::declarative::declarative_source_build_route_operation_mut`].
489///
490/// # Returns
491///
492/// Returns [`Some`] when [`crate::declarative::declarative_source_build_route_operation_mut`] can produce a value and [`None`] otherwise.
493///
494/// # Examples
495///
496/// ```rust,ignore
497/// let _result = pharos_runtime_compiler::declarative::declarative_source_build_route_operation_mut(todo!());
498/// ```
499///
500/// # Related
501///
502/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
503pub fn declarative_source_build_route_operation_mut(route_root: &Value) -> Option<Value> {
504    let kind = route_root.get("kind").and_then(Value::as_str)?;
505    let path = route_root.get("path").and_then(Value::as_str)?;
506    let capability = route_root.get("policy_gate").and_then(Value::as_str)?;
507    let method = if kind == "page" { "GET" } else { "POST" };
508    declarative_source_build_operation_mut(method, path, capability)
509}
510
511/// Performs declarative source identity param.
512///
513/// # Parameters
514///
515/// - `edit_path`: Input consumed by [`crate::declarative::declarative_source_identity_param`].
516/// - `context_param`: Input consumed by [`crate::declarative::declarative_source_identity_param`].
517///
518/// # Returns
519///
520/// Returns [`Some`] when [`crate::declarative::declarative_source_identity_param`] can produce a value and [`None`] otherwise.
521///
522/// # Examples
523///
524/// ```rust,ignore
525/// let _result = pharos_runtime_compiler::declarative::declarative_source_identity_param(todo!(), todo!());
526/// ```
527///
528/// # Related
529///
530/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
531pub fn declarative_source_identity_param(
532    edit_path: &str,
533    context_param: Option<&str>,
534) -> Option<String> {
535    if edit_path.is_empty() {
536        return None;
537    }
538    let mut result = None;
539    let bytes = edit_path.as_bytes();
540    let mut index = 0usize;
541    while index < bytes.len() {
542        if bytes[index] != b':' {
543            index += 1;
544            continue;
545        }
546        let start = index + 1;
547        let mut end = start;
548        while end < bytes.len() && bytes[end] != b'/' {
549            end += 1;
550        }
551        if end > start {
552            let candidate = &edit_path[start..end];
553            if context_param != Some(candidate) {
554                result = Some(candidate.to_owned());
555            }
556        }
557        index = end;
558    }
559    result
560}
561
562/// Converts an identifier into the human-readable label used by generated surfaces.
563///
564/// # Parameters
565///
566/// - `identifier`: Input consumed by [`crate::declarative::declarative_source_label`].
567/// - `title_case`: Input consumed by [`crate::declarative::declarative_source_label`].
568///
569/// # Returns
570///
571/// Returns the computed value produced by [`crate::declarative::declarative_source_label`].
572///
573/// # Performance
574///
575/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_label`].
576///
577/// # Examples
578///
579/// ```rust,ignore
580/// let _result = pharos_runtime_compiler::declarative::declarative_source_label(todo!(), todo!());
581/// ```
582///
583/// # Related
584///
585/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
586pub fn declarative_source_label(identifier: &str, title_case: bool) -> String {
587    let mut next_word = true;
588    identifier
589        .chars()
590        .map(|ch| {
591            let mut out = if ch == '_' { ' ' } else { ch };
592            if title_case && next_word && out.is_ascii_lowercase() {
593                out = out.to_ascii_uppercase();
594            }
595            next_word = out == ' ';
596            out
597        })
598        .collect()
599}
600
601/// Returns the default item title field.
602///
603/// # Parameters
604///
605/// - `entity_fields`: Input consumed by [`crate::declarative::default_item_title_field`].
606/// - `identity_field`: Input consumed by [`crate::declarative::default_item_title_field`].
607/// - `scope_field`: Input consumed by [`crate::declarative::default_item_title_field`].
608///
609/// # Returns
610///
611/// Returns [`Some`] when [`crate::declarative::default_item_title_field`] can produce a value and [`None`] otherwise.
612///
613/// # Performance
614///
615/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::default_item_title_field`].
616///
617/// # Examples
618///
619/// ```rust,ignore
620/// let _result = pharos_runtime_compiler::declarative::default_item_title_field(todo!(), todo!(), todo!());
621/// ```
622///
623/// # Related
624///
625/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
626pub fn default_item_title_field(
627    entity_fields: &Value,
628    identity_field: Option<&str>,
629    scope_field: Option<&str>,
630) -> Option<String> {
631    let preferred = ["name", "title", "label", "slug", "day_of_week"];
632    let fields = entity_fields.as_array()?;
633    for candidate in preferred {
634        if fields
635            .iter()
636            .any(|item| item.get("field_id").and_then(Value::as_str) == Some(candidate))
637        {
638            return Some(candidate.to_owned());
639        }
640    }
641    for item in fields {
642        let Some(field_id) = item.get("field_id").and_then(Value::as_str) else {
643            continue;
644        };
645        if Some(field_id) == identity_field || Some(field_id) == scope_field {
646            continue;
647        }
648        return Some(field_id.to_owned());
649    }
650    Some(identity_field.unwrap_or("id").to_owned())
651}
652
653/// Performs declarative source default list columns mut.
654///
655/// # Parameters
656///
657/// - `response_fields`: Input consumed by [`crate::declarative::declarative_source_default_list_columns_mut`].
658/// - `identity_field`: Input consumed by [`crate::declarative::declarative_source_default_list_columns_mut`].
659/// - `scope_field`: Input consumed by [`crate::declarative::declarative_source_default_list_columns_mut`].
660///
661/// # Returns
662///
663/// Returns [`Some`] when [`crate::declarative::declarative_source_default_list_columns_mut`] can produce a value and [`None`] otherwise.
664///
665/// # Performance
666///
667/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_default_list_columns_mut`].
668///
669/// # Examples
670///
671/// ```rust,ignore
672/// let _result = pharos_runtime_compiler::declarative::declarative_source_default_list_columns_mut(todo!(), todo!(), todo!());
673/// ```
674///
675/// # Related
676///
677/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
678pub fn declarative_source_default_list_columns_mut(
679    response_fields: &Value,
680    identity_field: Option<&str>,
681    scope_field: Option<&str>,
682) -> Option<Value> {
683    let fields = response_fields.as_array()?;
684    let mut columns = Vec::new();
685    for item in fields {
686        let Some(field_name) = item.as_str() else {
687            continue;
688        };
689        if Some(field_name) == identity_field || Some(field_name) == scope_field {
690            continue;
691        }
692        columns.push(serde_json::json!({
693            "field": field_name,
694            "label": declarative_source_label(field_name, true),
695        }));
696        if columns.len() >= 3 {
697            break;
698        }
699    }
700    Some(Value::Array(columns))
701}
702
703/// Performs declarative source default list columns from form mut.
704///
705/// # Parameters
706///
707/// - `form_fields`: Input consumed by [`crate::declarative::declarative_source_default_list_columns_from_form_mut`].
708/// - `relation_inputs`: Input consumed by [`crate::declarative::declarative_source_default_list_columns_from_form_mut`].
709/// - `identity_field`: Input consumed by [`crate::declarative::declarative_source_default_list_columns_from_form_mut`].
710/// - `scope_field`: Input consumed by [`crate::declarative::declarative_source_default_list_columns_from_form_mut`].
711/// - `soft_delete_field`: Input consumed by [`crate::declarative::declarative_source_default_list_columns_from_form_mut`].
712/// - `auto_sequence_field`: Input consumed by [`crate::declarative::declarative_source_default_list_columns_from_form_mut`].
713///
714/// # Returns
715///
716/// Returns [`Some`] when [`crate::declarative::declarative_source_default_list_columns_from_form_mut`] can produce a value and [`None`] otherwise.
717///
718/// # Performance
719///
720/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_default_list_columns_from_form_mut`].
721///
722/// # Examples
723///
724/// ```rust,ignore
725/// let _result = pharos_runtime_compiler::declarative::declarative_source_default_list_columns_from_form_mut(todo!(), todo!(), todo!(), todo!(), todo!(), todo!());
726/// ```
727///
728/// # Related
729///
730/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
731pub fn declarative_source_default_list_columns_from_form_mut(
732    form_fields: Option<&Value>,
733    relation_inputs: Option<&Value>,
734    identity_field: Option<&str>,
735    scope_field: Option<&str>,
736    soft_delete_field: Option<&str>,
737    auto_sequence_field: Option<&str>,
738) -> Option<Value> {
739    let mut columns = Vec::new();
740    if let Some(fields) = form_fields.and_then(Value::as_array) {
741        for item in fields {
742            let Some(field_name) = item.get("field_id").and_then(Value::as_str) else {
743                continue;
744            };
745            if Some(field_name) == identity_field || Some(field_name) == scope_field {
746                continue;
747            }
748            columns.push(serde_json::json!({
749                "field": field_name,
750                "label": declarative_source_label(field_name, true),
751            }));
752            if columns.len() >= 3 {
753                return Some(Value::Array(columns));
754            }
755        }
756    }
757    if let Some(field_name) = auto_sequence_field.filter(|value| !value.is_empty())
758        && columns.len() < 3
759    {
760        columns.push(serde_json::json!({
761            "field": field_name,
762            "label": declarative_source_label(field_name, true),
763        }));
764        if columns.len() >= 3 {
765            return Some(Value::Array(columns));
766        }
767    }
768    if let Some(field_name) = soft_delete_field.filter(|value| !value.is_empty())
769        && columns.len() < 3
770    {
771        columns.push(serde_json::json!({
772            "field": field_name,
773            "label": declarative_source_label(field_name, true),
774        }));
775        if columns.len() >= 3 {
776            return Some(Value::Array(columns));
777        }
778    }
779    if let Some(inputs) = relation_inputs.and_then(Value::as_array) {
780        for item in inputs {
781            let Some(field_name) = item.get("field").and_then(Value::as_str) else {
782                continue;
783            };
784            columns.push(serde_json::json!({
785                "field": field_name,
786                "label": declarative_source_label(field_name, true),
787            }));
788            if columns.len() >= 3 {
789                break;
790            }
791        }
792    }
793    Some(Value::Array(columns))
794}
795
796/// Performs declarative source default context binding mut.
797///
798/// # Parameters
799///
800/// - `scope_field`: Input consumed by [`crate::declarative::declarative_source_default_context_binding_mut`].
801///
802/// # Returns
803///
804/// Returns [`Some`] when [`crate::declarative::declarative_source_default_context_binding_mut`] can produce a value and [`None`] otherwise.
805///
806/// # Examples
807///
808/// ```rust,ignore
809/// let _result = pharos_runtime_compiler::declarative::declarative_source_default_context_binding_mut(todo!());
810/// ```
811///
812/// # Related
813///
814/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
815pub fn declarative_source_default_context_binding_mut(scope_field: Option<&str>) -> Option<Value> {
816    if scope_field != Some("business_id") {
817        return None;
818    }
819    Some(serde_json::json!({
820        "state_collection": "businesses",
821        "param": "business_slug",
822        "match_field": "slug",
823        "context_id_field": "id",
824        "context_label_field": "name",
825        "tenant_collection": "tenants",
826        "tenant_match_field": "source_business_id",
827        "tenant_match_from_context_field": "id",
828    }))
829}
830
831/// Performs declarative source derived defaults mut.
832///
833/// # Parameters
834///
835/// - `form_fields`: Input consumed by [`crate::declarative::declarative_source_derived_defaults_mut`].
836/// - `relation_inputs`: Input consumed by [`crate::declarative::declarative_source_derived_defaults_mut`].
837/// - `soft_delete_field`: Input consumed by [`crate::declarative::declarative_source_derived_defaults_mut`].
838///
839/// # Returns
840///
841/// Returns [`Some`] when [`crate::declarative::declarative_source_derived_defaults_mut`] can produce a value and [`None`] otherwise.
842///
843/// # Performance
844///
845/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_derived_defaults_mut`].
846///
847/// # Examples
848///
849/// ```rust,ignore
850/// let _result = pharos_runtime_compiler::declarative::declarative_source_derived_defaults_mut(todo!(), todo!(), todo!());
851/// ```
852///
853/// # Related
854///
855/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
856pub fn declarative_source_derived_defaults_mut(
857    form_fields: Option<&Value>,
858    relation_inputs: Option<&Value>,
859    soft_delete_field: Option<&str>,
860) -> Option<Value> {
861    let mut defaults = Map::new();
862    if let Some(fields) = form_fields.and_then(Value::as_array) {
863        for item in fields {
864            let Some(field_name) = item.get("field_id").and_then(Value::as_str) else {
865                continue;
866            };
867            let widget = item.get("widget").and_then(Value::as_str);
868            let required = item
869                .get("required")
870                .and_then(Value::as_bool)
871                .unwrap_or(false);
872            if matches!(widget, Some("textarea" | "text" | "email" | "password")) {
873                defaults.insert(field_name.to_owned(), Value::String(String::new()));
874                continue;
875            }
876            if required {
877                continue;
878            }
879        }
880    }
881    if let Some(soft_delete_field) = soft_delete_field.filter(|value| !value.is_empty()) {
882        defaults.insert(soft_delete_field.to_owned(), Value::Bool(true));
883    }
884    if let Some(inputs) = relation_inputs.and_then(Value::as_array) {
885        for item in inputs {
886            if let Some(field_name) = item.get("field").and_then(Value::as_str)
887                && !field_name.is_empty()
888            {
889                defaults.insert(field_name.to_owned(), Value::Array(Vec::new()));
890            }
891        }
892    }
893    Some(Value::Object(defaults))
894}
895
896/// Performs declarative source derived audit events mut.
897///
898/// # Parameters
899///
900/// - `entity_id`: Input consumed by [`crate::declarative::declarative_source_derived_audit_events_mut`].
901/// - `hard_delete`: Input consumed by [`crate::declarative::declarative_source_derived_audit_events_mut`].
902///
903/// # Returns
904///
905/// Returns [`Some`] when [`crate::declarative::declarative_source_derived_audit_events_mut`] can produce a value and [`None`] otherwise.
906///
907/// # Examples
908///
909/// ```rust,ignore
910/// let _result = pharos_runtime_compiler::declarative::declarative_source_derived_audit_events_mut("entity", todo!());
911/// ```
912///
913/// # Related
914///
915/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
916pub fn declarative_source_derived_audit_events_mut(
917    entity_id: &str,
918    hard_delete: bool,
919) -> Option<Value> {
920    if entity_id.is_empty() {
921        return None;
922    }
923    Some(serde_json::json!({
924        "create": format!("generated_{entity_id}_created"),
925        "update": format!("generated_{entity_id}_updated"),
926        "delete": if hard_delete {
927            format!("generated_{entity_id}_deleted")
928        } else {
929            format!("generated_{entity_id}_deactivated")
930        },
931    }))
932}
933
934const MAX_DECLARATIVE_FILE_BYTES: u64 = 16 * 1024 * 1024;
935const MAX_DECLARATIVE_FILES: usize = 4096;
936
937/// Builds a safe relative path.
938fn safe_relative_path(text: &str) -> Option<&Path> {
939    let path = Path::new(text);
940    if text.is_empty()
941        || path.is_absolute()
942        || path.components().any(|component| {
943            matches!(
944                component,
945                std::path::Component::ParentDir
946                    | std::path::Component::RootDir
947                    | std::path::Component::Prefix(_)
948            )
949        })
950    {
951        return None;
952    }
953    Some(path)
954}
955
956/// Reads JSON or YAML.
957fn read_json_or_yaml(path: &Path) -> Option<Value> {
958    let metadata = fs::metadata(path).ok()?;
959    if !metadata.is_file() || metadata.len() > MAX_DECLARATIVE_FILE_BYTES {
960        return None;
961    }
962    let text = fs::read_to_string(path).ok()?;
963    if path.extension().and_then(|value| value.to_str()) == Some("yml")
964        || path.extension().and_then(|value| value.to_str()) == Some("yaml")
965    {
966        pharos_runtime_core::yaml::parse_yaml_text(&text)
967    } else {
968        serde_json::from_str(&text).ok()
969    }
970}
971
972/// Retains exact scalar declaration locations for generated JSON diagnostics.
973fn attach_yaml_source_map(value: &mut Value, text: &str, source_path: &Path) -> Option<()> {
974    let object = value.as_object_mut()?;
975    let mut locations = Map::new();
976    for (index, line) in text.lines().enumerate() {
977        let trimmed = line.trim_start().trim_start_matches("- ");
978        let Some((key, raw_value)) = trimmed.split_once(':') else {
979            continue;
980        };
981        let scalar = raw_value.trim().trim_matches(['\'', '"']);
982        if scalar.is_empty()
983            || !matches!(
984                key.trim(),
985                "route_id"
986                    | "action_id"
987                    | "entity_id"
988                    | "form_id"
989                    | "workflow_id"
990                    | "adapter_id"
991                    | "page_id"
992            )
993        {
994            continue;
995        }
996        let column = line.find(key.trim()).unwrap_or(0) + 1;
997        locations.insert(
998            format!("{}:{scalar}", key.trim()),
999            serde_json::json!({"line": index + 1, "column": column}),
1000        );
1001    }
1002    object.insert(
1003        "__pharos_source".to_owned(),
1004        serde_json::json!({
1005            "path": source_path.to_string_lossy(),
1006            "locations": locations,
1007        }),
1008    );
1009    Some(())
1010}
1011
1012/// Builds a safe path to one framework-owned contract file.
1013///
1014/// # Parameters
1015///
1016/// - `artifact_dir`: Input consumed by [`crate::declarative::declarative_source_framework_path`].
1017/// - `file_name`: Input consumed by [`crate::declarative::declarative_source_framework_path`].
1018///
1019/// # Returns
1020///
1021/// Returns [`Some`] when [`crate::declarative::declarative_source_framework_path`] can produce a value and [`None`] otherwise.
1022///
1023/// # Examples
1024///
1025/// ```rust,ignore
1026/// let _result = pharos_runtime_compiler::declarative::declarative_source_framework_path(std::path::Path::new("build/dev_docs"), todo!());
1027/// ```
1028///
1029/// # Related
1030///
1031/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1032pub fn declarative_source_framework_path(artifact_dir: &Path, file_name: &str) -> Option<PathBuf> {
1033    let relative = safe_relative_path(file_name)?;
1034    Some(artifact_dir.join("data/contracts").join(relative))
1035}
1036
1037/// Reads framework contract.
1038fn read_framework_contract(artifact_dir: &Path, file_name: &str) -> Option<Value> {
1039    let path = declarative_source_framework_path(artifact_dir, file_name)?;
1040    read_json_or_yaml(&path)
1041}
1042
1043/// Resolves a dot-separated object or array path without creating intermediate values.
1044///
1045/// # Parameters
1046///
1047/// - `root`: Input consumed by [`crate::declarative::declarative_source_resolve_dotted_path`].
1048/// - `dotted_path`: Input consumed by [`crate::declarative::declarative_source_resolve_dotted_path`].
1049///
1050/// # Returns
1051///
1052/// Returns [`Some`] when [`crate::declarative::declarative_source_resolve_dotted_path`] can produce a value and [`None`] otherwise.
1053///
1054/// # Performance
1055///
1056/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_resolve_dotted_path`].
1057///
1058/// # Examples
1059///
1060/// ```rust,ignore
1061/// let _result = pharos_runtime_compiler::declarative::declarative_source_resolve_dotted_path(std::path::Path::new("."), todo!());
1062/// ```
1063///
1064/// # Related
1065///
1066/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1067pub fn declarative_source_resolve_dotted_path<'a>(
1068    root: &'a Value,
1069    dotted_path: &str,
1070) -> Option<&'a Value> {
1071    if dotted_path.is_empty() {
1072        return None;
1073    }
1074    dotted_path.split('.').try_fold(root, |current, segment| {
1075        if segment.is_empty() {
1076            None
1077        } else if let Ok(index) = segment.parse::<usize>() {
1078            current.as_array()?.get(index)
1079        } else {
1080            current.as_object()?.get(segment)
1081        }
1082    })
1083}
1084
1085/// Loads a bounded framework contract reference such as `fields.yml#entity.fields`.
1086///
1087/// # Parameters
1088///
1089/// - `artifact_dir`: Input consumed by [`crate::declarative::declarative_source_load_ref_target`].
1090/// - `ref_text`: Input consumed by [`crate::declarative::declarative_source_load_ref_target`].
1091///
1092/// # Returns
1093///
1094/// Returns [`Some`] when [`crate::declarative::declarative_source_load_ref_target`] can produce a value and [`None`] otherwise.
1095///
1096/// # Examples
1097///
1098/// ```rust,ignore
1099/// let _result = pharos_runtime_compiler::declarative::declarative_source_load_ref_target(std::path::Path::new("build/dev_docs"), todo!());
1100/// ```
1101///
1102/// # Related
1103///
1104/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1105pub fn declarative_source_load_ref_target(artifact_dir: &Path, ref_text: &str) -> Option<Value> {
1106    let (file_name, dotted_path) = ref_text.split_once('#')?;
1107    let file_name = if file_name.ends_with(".json") {
1108        file_name.to_owned()
1109    } else {
1110        let stem = file_name
1111            .strip_suffix(".yml")
1112            .or_else(|| file_name.strip_suffix(".yaml"))
1113            .unwrap_or(file_name);
1114        format!("{stem}.json")
1115    };
1116    let root = read_framework_contract(artifact_dir, &file_name)?;
1117    Some(declarative_source_resolve_dotted_path(&root, dotted_path)?.clone())
1118}
1119
1120/// Returns whether the YAML app manifest exists at an app root.
1121///
1122/// # Parameters
1123///
1124/// - `app_root`: Input consumed by [`crate::declarative::declarative_source_has_yaml_manifest`].
1125///
1126/// # Returns
1127///
1128/// Returns `true` when the condition checked by [`crate::declarative::declarative_source_has_yaml_manifest`] holds and `false` otherwise.
1129///
1130/// # Examples
1131///
1132/// ```rust,ignore
1133/// let _result = pharos_runtime_compiler::declarative::declarative_source_has_yaml_manifest(std::path::Path::new("apps/dev_docs"));
1134/// ```
1135///
1136/// # Related
1137///
1138/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1139pub fn declarative_source_has_yaml_manifest(app_root: &Path) -> bool {
1140    app_root.join("pharos.app.yml").is_file()
1141}
1142
1143/// Resolves the source manifest-selected database contract for scoped compiler policy.
1144fn database_authoring_path(root: &Path) -> Option<PathBuf> {
1145    let manifest = pharos_runtime_core::yaml::parse_yaml_file(&root.join("pharos.app.yml"))?;
1146    let selected = manifest.pointer("/database/migration_contract")?.as_str()?;
1147    let relative = Path::new(selected);
1148    if !relative
1149        .components()
1150        .all(|component| matches!(component, std::path::Component::Normal(_)))
1151    {
1152        return None;
1153    }
1154    Some(root.join(relative))
1155}
1156
1157/// Compiles YAML matches in directory inner.
1158fn compile_yaml_matches_in_directory_inner(
1159    root: &Path,
1160    dir_path: &Path,
1161    yaml_suffix: &str,
1162    depth: usize,
1163    count: &mut usize,
1164    database_path: Option<&Path>,
1165) -> i32 {
1166    if depth > 64 {
1167        return 69;
1168    }
1169    let Ok(entries) = fs::read_dir(dir_path) else {
1170        return 0;
1171    };
1172    for entry in entries {
1173        let Ok(entry) = entry else {
1174            return 69;
1175        };
1176        let path = entry.path();
1177        if path.is_dir() {
1178            let code = compile_yaml_matches_in_directory_inner(
1179                root,
1180                &path,
1181                yaml_suffix,
1182                depth + 1,
1183                count,
1184                database_path,
1185            );
1186            if code != 0 {
1187                return code;
1188            }
1189            continue;
1190        }
1191        let Some(name) = path.file_name().and_then(|value| value.to_str()) else {
1192            continue;
1193        };
1194        let database_source = database_path == Some(path.as_path());
1195        if !name.ends_with(yaml_suffix)
1196            && !(yaml_suffix == ".yml" && database_source && name.ends_with(".yaml"))
1197        {
1198            continue;
1199        }
1200        *count = count.saturating_add(1);
1201        if *count > MAX_DECLARATIVE_FILES {
1202            return 69;
1203        }
1204        let parsed = if database_source {
1205            crate::database::compile_file(&path).ok()
1206        } else {
1207            read_json_or_yaml(&path)
1208        };
1209        let Some(mut value) = parsed else {
1210            return 69;
1211        };
1212        let Ok(yaml_text) = fs::read_to_string(&path) else {
1213            return 69;
1214        };
1215        let relative_source = path.strip_prefix(root).unwrap_or(&path);
1216        if !database_source
1217            && attach_yaml_source_map(&mut value, &yaml_text, relative_source).is_none()
1218        {
1219            return 69;
1220        }
1221        let output = path.with_extension("json");
1222        let Ok(text) = serde_json::to_string_pretty(&value) else {
1223            return 69;
1224        };
1225        if database_source && text.len() > 8 * 1024 * 1024 {
1226            return 69;
1227        }
1228        if pharos_runtime_core::fs::write_binary_file(&output, text.as_bytes(), 0o644).is_err() {
1229            return 69;
1230        }
1231    }
1232    0
1233}
1234
1235/// Compiles matching YAML files to sibling JSON artifacts without invoking a toolchain.
1236///
1237/// # Parameters
1238///
1239/// - `dir_path`: Input consumed by [`crate::declarative::compile_yaml_matches_in_directory`].
1240/// - `yaml_suffix`: Input consumed by [`crate::declarative::compile_yaml_matches_in_directory`].
1241///
1242/// # Returns
1243///
1244/// Returns the computed value produced by [`crate::declarative::compile_yaml_matches_in_directory`].
1245///
1246/// # Examples
1247///
1248/// ```rust,ignore
1249/// let _result = pharos_runtime_compiler::declarative::compile_yaml_matches_in_directory(todo!(), todo!());
1250/// ```
1251///
1252/// # Related
1253///
1254/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1255pub fn compile_yaml_matches_in_directory(dir_path: &Path, yaml_suffix: &str) -> i32 {
1256    if dir_path.as_os_str().is_empty() || yaml_suffix.is_empty() {
1257        return 69;
1258    }
1259    let mut count = 0;
1260    let database_path = database_authoring_path(dir_path);
1261    let manifest = if dir_path.join("pharos.app.yml").is_file() {
1262        let Some(manifest) =
1263            pharos_runtime_core::yaml::parse_yaml_file(&dir_path.join("pharos.app.yml"))
1264        else {
1265            return 69;
1266        };
1267        Some(manifest)
1268    } else {
1269        None
1270    };
1271    if yaml_suffix == ".yml"
1272        && manifest
1273            .as_ref()
1274            .is_some_and(|value| value.pointer("/database/migration_contract").is_some())
1275        && database_path.as_ref().is_none_or(|path| {
1276            !matches!(
1277                path.extension().and_then(|value| value.to_str()),
1278                Some("json" | "yml" | "yaml")
1279            ) || !fs::symlink_metadata(path).is_ok_and(|meta| meta.is_file())
1280        })
1281    {
1282        return 69;
1283    }
1284    let status = compile_yaml_matches_in_directory_inner(
1285        dir_path,
1286        dir_path,
1287        yaml_suffix,
1288        0,
1289        &mut count,
1290        database_path.as_deref(),
1291    );
1292    if status != 0 || yaml_suffix != ".yml" {
1293        return status;
1294    }
1295    if let Some(path) = database_path {
1296        let Some(app_id) = manifest
1297            .as_ref()
1298            .and_then(|value| value.get("app_id"))
1299            .and_then(Value::as_str)
1300        else {
1301            return 69;
1302        };
1303        if pharos_runtime_database::contract::load_contract(&path.with_extension("json"), app_id)
1304            .is_err()
1305        {
1306            return 69;
1307        }
1308    }
1309    0
1310}
1311
1312/// Performs declarative source compile pages in directory.
1313///
1314/// # Parameters
1315///
1316/// - `dir_path`: Input consumed by [`crate::declarative::declarative_source_compile_pages_in_directory`].
1317///
1318/// # Returns
1319///
1320/// Returns the computed value produced by [`crate::declarative::declarative_source_compile_pages_in_directory`].
1321///
1322/// # Examples
1323///
1324/// ```rust,ignore
1325/// let _result = pharos_runtime_compiler::declarative::declarative_source_compile_pages_in_directory(todo!());
1326/// ```
1327///
1328/// # Related
1329///
1330/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1331pub fn declarative_source_compile_pages_in_directory(dir_path: &Path) -> i32 {
1332    compile_yaml_matches_in_directory(dir_path, ".page.yml")
1333}
1334
1335/// Performs declarative source compile fixtures in directory.
1336///
1337/// # Parameters
1338///
1339/// - `dir_path`: Input consumed by [`crate::declarative::declarative_source_compile_fixtures_in_directory`].
1340///
1341/// # Returns
1342///
1343/// Returns the computed value produced by [`crate::declarative::declarative_source_compile_fixtures_in_directory`].
1344///
1345/// # Examples
1346///
1347/// ```rust,ignore
1348/// let _result = pharos_runtime_compiler::declarative::declarative_source_compile_fixtures_in_directory(todo!());
1349/// ```
1350///
1351/// # Related
1352///
1353/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1354pub fn declarative_source_compile_fixtures_in_directory(dir_path: &Path) -> i32 {
1355    compile_yaml_matches_in_directory(dir_path, ".yml")
1356}
1357
1358/// Normalizes compiled reference text.
1359fn normalize_compiled_reference_text(root: &Path, text: &str) -> Option<String> {
1360    let (path_text, fragment) = text.split_once('#').unwrap_or((text, ""));
1361    let stem = path_text
1362        .strip_suffix(".yml")
1363        .or_else(|| path_text.strip_suffix(".yaml"))?;
1364    let json_path = root.join(format!("{stem}.json"));
1365    if !json_path.is_file() {
1366        return None;
1367    }
1368    Some(if fragment.is_empty() {
1369        format!("{stem}.json")
1370    } else {
1371        format!("{stem}.json#{fragment}")
1372    })
1373}
1374
1375/// Normalizes compiled JSON value.
1376fn normalize_compiled_json_value(root: &Path, value: &mut Value) {
1377    match value {
1378        Value::Array(items) => {
1379            for item in items {
1380                normalize_compiled_json_value(root, item);
1381            }
1382        }
1383        Value::Object(fields) => {
1384            for item in fields.values_mut() {
1385                normalize_compiled_json_value(root, item);
1386            }
1387        }
1388        Value::String(text) => {
1389            if let Some(normalized) = normalize_compiled_reference_text(root, text) {
1390                *text = normalized;
1391            }
1392        }
1393        Value::Null | Value::Bool(_) | Value::Number(_) => {}
1394    }
1395}
1396
1397/// Normalizes compiled JSON references inner.
1398fn normalize_compiled_json_references_inner(root: &Path, dir: &Path, depth: usize) -> i32 {
1399    if depth > 64 {
1400        return 69;
1401    }
1402    let Ok(entries) = fs::read_dir(dir) else {
1403        return 69;
1404    };
1405    for entry in entries {
1406        let Ok(entry) = entry else {
1407            return 69;
1408        };
1409        let path = entry.path();
1410        let Ok(metadata) = fs::symlink_metadata(&path) else {
1411            return 69;
1412        };
1413        if metadata.file_type().is_symlink() {
1414            return 78;
1415        }
1416        if metadata.is_dir() {
1417            let code = normalize_compiled_json_references_inner(root, &path, depth + 1);
1418            if code != 0 {
1419                return code;
1420            }
1421            continue;
1422        }
1423        if !metadata.is_file() || path.extension().and_then(|value| value.to_str()) != Some("json")
1424        {
1425            continue;
1426        }
1427        let is_schema_surface = path
1428            .file_name()
1429            .and_then(|value| value.to_str())
1430            .is_some_and(|value| value.ends_with(".schema.json"))
1431            || path
1432                .parent()
1433                .and_then(Path::file_name)
1434                .and_then(|value| value.to_str())
1435                .is_some_and(|value| value == "schema");
1436        if is_schema_surface
1437            || database_authoring_path(root)
1438                .is_some_and(|source| source.with_extension("json") == path)
1439        {
1440            continue;
1441        }
1442        let Ok(text) = fs::read_to_string(&path) else {
1443            return 69;
1444        };
1445        let Ok(mut value) = serde_json::from_str::<Value>(&text) else {
1446            return 69;
1447        };
1448        let reference_root = path.parent().unwrap_or(root);
1449        normalize_compiled_json_value(reference_root, &mut value);
1450        let Ok(normalized) = serde_json::to_string_pretty(&value) else {
1451            return 75;
1452        };
1453        if pharos_runtime_core::fs::write_file_within(root, &path, normalized.as_bytes(), 0o644)
1454            .is_err()
1455        {
1456            return 69;
1457        }
1458    }
1459    0
1460}
1461
1462/// Rewrites compiled YAML references to sibling JSON artifacts in a deployment tree.
1463///
1464/// # Parameters
1465///
1466/// - `root`: Input consumed by [`crate::declarative::normalize_compiled_json_references`].
1467///
1468/// # Returns
1469///
1470/// Returns the computed value produced by [`crate::declarative::normalize_compiled_json_references`].
1471///
1472/// # Examples
1473///
1474/// ```rust,ignore
1475/// let _result = pharos_runtime_compiler::declarative::normalize_compiled_json_references(std::path::Path::new("."));
1476/// ```
1477///
1478/// # Related
1479///
1480/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1481pub fn normalize_compiled_json_references(root: &Path) -> i32 {
1482    if root.as_os_str().is_empty() || !root.is_dir() {
1483        return 64;
1484    }
1485    normalize_compiled_json_references_inner(root, root, 0)
1486}
1487
1488/// Converts one generated-admin path into its final resource segment.
1489///
1490/// # Parameters
1491///
1492/// - `manage_path`: Input consumed by [`crate::declarative::declarative_source_path_segment_from_manage_path`].
1493///
1494/// # Returns
1495///
1496/// Returns [`Some`] when [`crate::declarative::declarative_source_path_segment_from_manage_path`] can produce a value and [`None`] otherwise.
1497///
1498/// # Panics
1499///
1500/// May panic if an internal invariant assumed by [`crate::declarative::declarative_source_path_segment_from_manage_path`] is violated.
1501///
1502/// # Performance
1503///
1504/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_path_segment_from_manage_path`].
1505///
1506/// # Examples
1507///
1508/// ```rust,ignore
1509/// let _result = pharos_runtime_compiler::declarative::declarative_source_path_segment_from_manage_path(todo!());
1510/// ```
1511///
1512/// # Related
1513///
1514/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1515pub fn declarative_source_path_segment_from_manage_path(manage_path: &str) -> Option<String> {
1516    let segment = manage_path
1517        .trim_matches('/')
1518        .rsplit('/')
1519        .find(|value| !value.is_empty() && !value.starts_with(':') && !value.starts_with('{'))?;
1520    Some(segment.to_owned())
1521}
1522
1523/// Derives a stable generated-admin collection segment from entity metadata.
1524///
1525/// # Parameters
1526///
1527/// - `entity_id`: Input consumed by [`crate::declarative::declarative_source_default_path_segment`].
1528/// - `runtime_collection`: Input consumed by [`crate::declarative::declarative_source_default_path_segment`].
1529///
1530/// # Returns
1531///
1532/// Returns [`Some`] when [`crate::declarative::declarative_source_default_path_segment`] can produce a value and [`None`] otherwise.
1533///
1534/// # Performance
1535///
1536/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_default_path_segment`].
1537///
1538/// # Examples
1539///
1540/// ```rust,ignore
1541/// let _result = pharos_runtime_compiler::declarative::declarative_source_default_path_segment("entity", todo!());
1542/// ```
1543///
1544/// # Related
1545///
1546/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1547pub fn declarative_source_default_path_segment(
1548    entity_id: &str,
1549    runtime_collection: Option<&str>,
1550) -> Option<String> {
1551    if let Some(collection) = runtime_collection.filter(|value| !value.is_empty()) {
1552        if !collection.contains('_') {
1553            return Some(collection.to_owned());
1554        }
1555        if let Some(suffix) = collection
1556            .rsplit('_')
1557            .next()
1558            .filter(|value| !value.is_empty())
1559        {
1560            return Some(suffix.to_owned());
1561        }
1562    }
1563    if entity_id.is_empty() {
1564        return None;
1565    }
1566    if let Some(suffix) = entity_id
1567        .rsplit('_')
1568        .next()
1569        .filter(|value| !value.is_empty())
1570        && suffix != entity_id
1571    {
1572        return Some(suffix.to_owned());
1573    }
1574    Some(if let Some(stem) = entity_id.strip_suffix('y') {
1575        format!("{stem}ies")
1576    } else if entity_id.ends_with('s') {
1577        format!("{entity_id}es")
1578    } else {
1579        format!("{entity_id}s")
1580    })
1581}
1582
1583/// Builds one operation path using the route contract's colon-parameter syntax.
1584///
1585/// # Parameters
1586///
1587/// - `manage_path`: Input consumed by [`crate::declarative::declarative_source_operation_path`].
1588/// - `api_prefix`: Input consumed by [`crate::declarative::declarative_source_operation_path`].
1589/// - `identity_param`: Input consumed by [`crate::declarative::declarative_source_operation_path`].
1590/// - `suffix`: Input consumed by [`crate::declarative::declarative_source_operation_path`].
1591///
1592/// # Returns
1593///
1594/// Returns [`Some`] when [`crate::declarative::declarative_source_operation_path`] can produce a value and [`None`] otherwise.
1595///
1596/// # Examples
1597///
1598/// ```rust,ignore
1599/// let _result = pharos_runtime_compiler::declarative::declarative_source_operation_path(todo!(), todo!(), todo!(), todo!());
1600/// ```
1601///
1602/// # Related
1603///
1604/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1605pub fn declarative_source_operation_path(
1606    manage_path: &str,
1607    api_prefix: bool,
1608    identity_param: Option<&str>,
1609    suffix: Option<&str>,
1610) -> Option<String> {
1611    if manage_path.is_empty() {
1612        return None;
1613    }
1614    let mut output = String::with_capacity(manage_path.len() + 32);
1615    if api_prefix {
1616        output.push_str("/api");
1617    }
1618    output.push_str(manage_path);
1619    if let Some(identity) = identity_param.filter(|value| !value.is_empty()) {
1620        output.push(':');
1621        output.push_str(identity);
1622        output.push('/');
1623    }
1624    if let Some(suffix) = suffix {
1625        output.push_str(suffix);
1626    }
1627    Some(output)
1628}
1629
1630/// Performs declarative source route path has segment.
1631///
1632/// # Parameters
1633///
1634/// - `route_path`: Input consumed by [`crate::declarative::declarative_source_route_path_has_segment`].
1635/// - `path_segment`: Input consumed by [`crate::declarative::declarative_source_route_path_has_segment`].
1636///
1637/// # Returns
1638///
1639/// Returns `true` when the condition checked by [`crate::declarative::declarative_source_route_path_has_segment`] holds and `false` otherwise.
1640///
1641/// # Performance
1642///
1643/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_route_path_has_segment`].
1644///
1645/// # Examples
1646///
1647/// ```rust,ignore
1648/// let _result = pharos_runtime_compiler::declarative::declarative_source_route_path_has_segment(todo!(), todo!());
1649/// ```
1650///
1651/// # Related
1652///
1653/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1654pub fn declarative_source_route_path_has_segment(route_path: &str, path_segment: &str) -> bool {
1655    !path_segment.is_empty() && route_path.split('/').any(|segment| segment == path_segment)
1656}
1657
1658/// Performs declarative source identity param from surface.
1659///
1660/// # Parameters
1661///
1662/// - `path_segment`: Input consumed by [`crate::declarative::declarative_source_identity_param_from_surface`].
1663/// - `entity_id`: Input consumed by [`crate::declarative::declarative_source_identity_param_from_surface`].
1664///
1665/// # Returns
1666///
1667/// Returns [`Some`] when [`crate::declarative::declarative_source_identity_param_from_surface`] can produce a value and [`None`] otherwise.
1668///
1669/// # Examples
1670///
1671/// ```rust,ignore
1672/// let _result = pharos_runtime_compiler::declarative::declarative_source_identity_param_from_surface(todo!(), "entity");
1673/// ```
1674///
1675/// # Related
1676///
1677/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1678pub fn declarative_source_identity_param_from_surface(
1679    path_segment: Option<&str>,
1680    entity_id: &str,
1681) -> Option<String> {
1682    let base = path_segment
1683        .filter(|value| !value.is_empty())
1684        .unwrap_or(entity_id);
1685    if base.is_empty() {
1686        return None;
1687    }
1688    let base = base.strip_suffix('s').unwrap_or(base);
1689    Some(format!("{base}_id"))
1690}
1691
1692/// Performs declarative source runtime collection.
1693///
1694/// # Parameters
1695///
1696/// - `entity_id`: Input consumed by [`crate::declarative::declarative_source_runtime_collection`].
1697/// - `table_name`: Input consumed by [`crate::declarative::declarative_source_runtime_collection`].
1698///
1699/// # Returns
1700///
1701/// Returns [`Some`] when [`crate::declarative::declarative_source_runtime_collection`] can produce a value and [`None`] otherwise.
1702///
1703/// # Examples
1704///
1705/// ```rust,ignore
1706/// let _result = pharos_runtime_compiler::declarative::declarative_source_runtime_collection("entity", todo!());
1707/// ```
1708///
1709/// # Related
1710///
1711/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1712pub fn declarative_source_runtime_collection(
1713    entity_id: &str,
1714    table_name: Option<&str>,
1715) -> Option<String> {
1716    if let Some(table) = table_name.filter(|value| !value.is_empty()) {
1717        if table.contains('_') {
1718            return Some(table.to_owned());
1719        }
1720        if entity_id.is_empty() {
1721            return Some(table.to_owned());
1722        }
1723    }
1724    declarative_source_default_path_segment(entity_id, None)
1725}
1726
1727/// Appends a string to an array unless the same string is already present.
1728///
1729/// # Parameters
1730///
1731/// - `values`: Input consumed by [`crate::declarative::declarative_source_append_unique_string_mut`].
1732/// - `value`: Input consumed by [`crate::declarative::declarative_source_append_unique_string_mut`].
1733///
1734/// # Returns
1735///
1736/// Returns `true` when the condition checked by [`crate::declarative::declarative_source_append_unique_string_mut`] holds and `false` otherwise.
1737///
1738/// # Performance
1739///
1740/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_append_unique_string_mut`].
1741///
1742/// # Examples
1743///
1744/// ```rust,ignore
1745/// let _result = pharos_runtime_compiler::declarative::declarative_source_append_unique_string_mut(todo!(), "value");
1746/// ```
1747///
1748/// # Related
1749///
1750/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1751pub fn declarative_source_append_unique_string_mut(values: &mut Vec<Value>, value: &str) -> bool {
1752    if value.is_empty() {
1753        return false;
1754    }
1755    if values.iter().any(|entry| entry.as_str() == Some(value)) {
1756        return true;
1757    }
1758    values.push(Value::String(value.to_owned()));
1759    true
1760}
1761
1762/// Performs declarative source derived response fields mut.
1763///
1764/// # Parameters
1765///
1766/// - `form_fields`: Input consumed by [`crate::declarative::declarative_source_derived_response_fields_mut`].
1767/// - `relation_inputs`: Input consumed by [`crate::declarative::declarative_source_derived_response_fields_mut`].
1768/// - `identity_field`: Input consumed by [`crate::declarative::declarative_source_derived_response_fields_mut`].
1769/// - `scope_field`: Input consumed by [`crate::declarative::declarative_source_derived_response_fields_mut`].
1770/// - `soft_delete_field`: Input consumed by [`crate::declarative::declarative_source_derived_response_fields_mut`].
1771/// - `auto_sequence_field`: Input consumed by [`crate::declarative::declarative_source_derived_response_fields_mut`].
1772///
1773/// # Returns
1774///
1775/// Returns [`Some`] when [`crate::declarative::declarative_source_derived_response_fields_mut`] can produce a value and [`None`] otherwise.
1776///
1777/// # Performance
1778///
1779/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_derived_response_fields_mut`].
1780///
1781/// # Examples
1782///
1783/// ```rust,ignore
1784/// let _result = pharos_runtime_compiler::declarative::declarative_source_derived_response_fields_mut(todo!(), todo!(), todo!(), todo!(), todo!(), todo!());
1785/// ```
1786///
1787/// # Related
1788///
1789/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1790pub fn declarative_source_derived_response_fields_mut(
1791    form_fields: Option<&Value>,
1792    relation_inputs: Option<&Value>,
1793    identity_field: Option<&str>,
1794    scope_field: Option<&str>,
1795    soft_delete_field: Option<&str>,
1796    auto_sequence_field: Option<&str>,
1797) -> Option<Value> {
1798    let mut fields = Vec::new();
1799    declarative_source_append_unique_string_mut(&mut fields, identity_field.unwrap_or_default());
1800    declarative_source_append_unique_string_mut(&mut fields, scope_field.unwrap_or_default());
1801    if let Some(items) = form_fields.and_then(Value::as_array) {
1802        for item in items {
1803            declarative_source_append_unique_string_mut(
1804                &mut fields,
1805                item.get("field_id")
1806                    .and_then(Value::as_str)
1807                    .unwrap_or_default(),
1808            );
1809        }
1810    }
1811    declarative_source_append_unique_string_mut(
1812        &mut fields,
1813        auto_sequence_field.unwrap_or_default(),
1814    );
1815    declarative_source_append_unique_string_mut(&mut fields, soft_delete_field.unwrap_or_default());
1816    if let Some(items) = relation_inputs.and_then(Value::as_array) {
1817        for item in items {
1818            declarative_source_append_unique_string_mut(
1819                &mut fields,
1820                item.get("field")
1821                    .and_then(Value::as_str)
1822                    .unwrap_or_default(),
1823            );
1824        }
1825    }
1826    Some(Value::Array(fields))
1827}
1828
1829/// Finds one form-field declaration by its field id.
1830///
1831/// # Parameters
1832///
1833/// - `fields`: Input consumed by [`crate::declarative::declarative_source_find_field_decl`].
1834/// - `field_id`: Input consumed by [`crate::declarative::declarative_source_find_field_decl`].
1835///
1836/// # Returns
1837///
1838/// Returns [`Some`] when [`crate::declarative::declarative_source_find_field_decl`] can produce a value and [`None`] otherwise.
1839///
1840/// # Examples
1841///
1842/// ```rust,ignore
1843/// let _result = pharos_runtime_compiler::declarative::declarative_source_find_field_decl(todo!(), "field");
1844/// ```
1845///
1846/// # Related
1847///
1848/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1849pub fn declarative_source_find_field_decl<'a>(
1850    fields: Option<&'a Value>,
1851    field_id: &str,
1852) -> Option<&'a Value> {
1853    declarative_source_find_object_by_string_field(fields?, "field_id", field_id)
1854}
1855
1856/// Performs declarative source option values mut.
1857///
1858/// # Parameters
1859///
1860/// - `options`: Input consumed by [`crate::declarative::declarative_source_option_values_mut`].
1861///
1862/// # Returns
1863///
1864/// Returns [`Some`] when [`crate::declarative::declarative_source_option_values_mut`] can produce a value and [`None`] otherwise.
1865///
1866/// # Performance
1867///
1868/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_option_values_mut`].
1869///
1870/// # Examples
1871///
1872/// ```rust,ignore
1873/// let _result = pharos_runtime_compiler::declarative::declarative_source_option_values_mut(todo!());
1874/// ```
1875///
1876/// # Related
1877///
1878/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1879pub fn declarative_source_option_values_mut(options: &Value) -> Option<Value> {
1880    let options = options.as_array()?;
1881    Some(Value::Array(
1882        options
1883            .iter()
1884            .filter_map(|item| item.get("value").and_then(Value::as_str))
1885            .filter(|value| !value.is_empty())
1886            .map(|value| Value::String(value.to_owned()))
1887            .collect(),
1888    ))
1889}
1890
1891/// Performs declarative source derived filters mut.
1892///
1893/// # Parameters
1894///
1895/// - `filter_set`: Input consumed by [`crate::declarative::declarative_source_derived_filters_mut`].
1896/// - `form_fields`: Input consumed by [`crate::declarative::declarative_source_derived_filters_mut`].
1897/// - `relation_inputs`: Input consumed by [`crate::declarative::declarative_source_derived_filters_mut`].
1898/// - `scope_field`: Input consumed by [`crate::declarative::declarative_source_derived_filters_mut`].
1899/// - `soft_delete_field`: Input consumed by [`crate::declarative::declarative_source_derived_filters_mut`].
1900///
1901/// # Returns
1902///
1903/// Returns [`Some`] when [`crate::declarative::declarative_source_derived_filters_mut`] can produce a value and [`None`] otherwise.
1904///
1905/// # Performance
1906///
1907/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_derived_filters_mut`].
1908///
1909/// # Examples
1910///
1911/// ```rust,ignore
1912/// let _result = pharos_runtime_compiler::declarative::declarative_source_derived_filters_mut(todo!(), todo!(), todo!(), todo!(), todo!());
1913/// ```
1914///
1915/// # Related
1916///
1917/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
1918pub fn declarative_source_derived_filters_mut(
1919    filter_set: &Value,
1920    form_fields: Option<&Value>,
1921    relation_inputs: Option<&Value>,
1922    scope_field: Option<&str>,
1923    soft_delete_field: Option<&str>,
1924) -> Option<Value> {
1925    let mut filters = Vec::new();
1926    for field_name in filter_set.as_array()? {
1927        let field_name = field_name.as_str()?;
1928        if field_name.is_empty() || scope_field == Some(field_name) {
1929            continue;
1930        }
1931        let relation = relation_inputs
1932            .and_then(|value| value.as_array())
1933            .and_then(|items| {
1934                items
1935                    .iter()
1936                    .find(|item| item.get("field").and_then(Value::as_str) == Some(field_name))
1937            });
1938        let widget = declarative_source_find_field_decl(form_fields, field_name)
1939            .and_then(|value| value.get("widget"))
1940            .and_then(Value::as_str);
1941        let query = if relation.is_some() && field_name.ends_with("_ids") {
1942            field_name[..field_name.len() - 1].to_owned()
1943        } else {
1944            field_name.to_owned()
1945        };
1946        let (match_kind, extra) = if relation.is_some() {
1947            ("array_contains_integer", Value::Null)
1948        } else if soft_delete_field == Some(field_name) {
1949            ("boolean", serde_json::json!(true))
1950        } else if widget == Some("select")
1951            && declarative_source_find_field_decl(form_fields, field_name)
1952                .and_then(|value| value.get("options"))
1953                .is_some()
1954        {
1955            (
1956                "exact",
1957                declarative_source_find_field_decl(form_fields, field_name)
1958                    .and_then(|value| value.get("options"))
1959                    .cloned()
1960                    .unwrap_or(Value::Array(Vec::new())),
1961            )
1962        } else if widget == Some("checkbox") {
1963            ("boolean", Value::Null)
1964        } else {
1965            ("contains", Value::Null)
1966        };
1967        let mut filter = serde_json::Map::new();
1968        filter.insert("query".to_owned(), Value::String(query));
1969        filter.insert("field".to_owned(), Value::String(field_name.to_owned()));
1970        filter.insert("match".to_owned(), Value::String(match_kind.to_owned()));
1971        if !extra.is_null() {
1972            if match_kind == "boolean" {
1973                filter.insert("default".to_owned(), extra);
1974            } else {
1975                filter.insert("options".to_owned(), extra);
1976            }
1977        }
1978        filter.insert(
1979            "label".to_owned(),
1980            Value::String(declarative_source_label(field_name, true)),
1981        );
1982        filters.push(Value::Object(filter));
1983    }
1984    Some(Value::Array(filters))
1985}
1986
1987/// Performs declarative source derived sorts mut.
1988///
1989/// # Parameters
1990///
1991/// - `sort_set`: Input consumed by [`crate::declarative::declarative_source_derived_sorts_mut`].
1992///
1993/// # Returns
1994///
1995/// Returns [`Some`] when [`crate::declarative::declarative_source_derived_sorts_mut`] can produce a value and [`None`] otherwise.
1996///
1997/// # Performance
1998///
1999/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_derived_sorts_mut`].
2000///
2001/// # Examples
2002///
2003/// ```rust,ignore
2004/// let _result = pharos_runtime_compiler::declarative::declarative_source_derived_sorts_mut(todo!());
2005/// ```
2006///
2007/// # Related
2008///
2009/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2010pub fn declarative_source_derived_sorts_mut(sort_set: &Value) -> Option<Value> {
2011    let mut sorts = Vec::new();
2012    for sort_key in sort_set.as_array()? {
2013        let sort_key = sort_key.as_str()?;
2014        if sort_key.is_empty() {
2015            continue;
2016        }
2017        if sort_key == "day_time_asc" {
2018            sorts.push(serde_json::json!({
2019                "key": sort_key, "field": "day_of_week", "direction": "asc",
2020                "type": "weekday", "secondary_field": "start_time", "secondary_type": "string",
2021                "label": "Day / start time"
2022            }));
2023            continue;
2024        }
2025        let (field, direction) = if let Some(field) = sort_key.strip_suffix("_desc") {
2026            (field, "desc")
2027        } else if let Some(field) = sort_key.strip_suffix("_asc") {
2028            (field, "asc")
2029        } else {
2030            (sort_key, "asc")
2031        };
2032        if field.is_empty() {
2033            continue;
2034        }
2035        let kind = if field.contains("time") {
2036            "string"
2037        } else if field.contains("order") || field.contains("duration") {
2038            "number"
2039        } else {
2040            "string"
2041        };
2042        sorts.push(serde_json::json!({
2043            "key": sort_key, "field": field, "direction": direction,
2044            "type": kind, "label": declarative_source_label(field, true)
2045        }));
2046    }
2047    Some(Value::Array(sorts))
2048}
2049
2050/// Performs declarative source derived surface uniqueness rules mut.
2051///
2052/// # Parameters
2053///
2054/// - `uniqueness_rules`: Input consumed by [`crate::declarative::declarative_source_derived_surface_uniqueness_rules_mut`].
2055/// - `entity_fields`: Input consumed by [`crate::declarative::declarative_source_derived_surface_uniqueness_rules_mut`].
2056/// - `entity_id`: Input consumed by [`crate::declarative::declarative_source_derived_surface_uniqueness_rules_mut`].
2057///
2058/// # Returns
2059///
2060/// Returns [`Some`] when [`crate::declarative::declarative_source_derived_surface_uniqueness_rules_mut`] can produce a value and [`None`] otherwise.
2061///
2062/// # Performance
2063///
2064/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_derived_surface_uniqueness_rules_mut`].
2065///
2066/// # Examples
2067///
2068/// ```rust,ignore
2069/// let _result = pharos_runtime_compiler::declarative::declarative_source_derived_surface_uniqueness_rules_mut(todo!(), todo!(), "entity");
2070/// ```
2071///
2072/// # Related
2073///
2074/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2075pub fn declarative_source_derived_surface_uniqueness_rules_mut(
2076    uniqueness_rules: &Value,
2077    entity_fields: &Value,
2078    entity_id: &str,
2079) -> Option<Value> {
2080    if entity_id.is_empty() {
2081        return None;
2082    }
2083    let mut rules = Vec::new();
2084    for rule_text in uniqueness_rules.as_array()? {
2085        let rule_text = rule_text.as_str()?.trim();
2086        if rule_text.is_empty() {
2087            continue;
2088        }
2089        let fields: Vec<Value> = rule_text
2090            .split('+')
2091            .map(str::trim)
2092            .filter(|field| !field.is_empty())
2093            .map(|field| Value::String(field.to_owned()))
2094            .collect();
2095        if fields.is_empty() {
2096            continue;
2097        }
2098        let casefold_fields: Vec<Value> = fields
2099            .iter()
2100            .filter_map(|field| {
2101                let name = field.as_str()?;
2102                (declarative_source_find_field_decl(Some(entity_fields), name)
2103                    .and_then(|value| value.get("type"))
2104                    .and_then(Value::as_str)
2105                    == Some("string"))
2106                .then(|| Value::String(name.to_owned()))
2107            })
2108            .collect();
2109        let mut rule = serde_json::Map::new();
2110        rule.insert("fields".to_owned(), Value::Array(fields));
2111        if !casefold_fields.is_empty() {
2112            rule.insert("casefold_fields".to_owned(), Value::Array(casefold_fields));
2113        }
2114        rule.insert(
2115            "rule_id".to_owned(),
2116            Value::String(format!("{entity_id}_unique")),
2117        );
2118        rule.insert(
2119            "message".to_owned(),
2120            Value::String(format!("{entity_id} must be unique within this scope.")),
2121        );
2122        rules.push(Value::Object(rule));
2123    }
2124    Some(Value::Array(rules))
2125}
2126
2127/// Performs declarative source append surface.
2128///
2129/// # Parameters
2130///
2131/// - `surfaces`: Input consumed by [`crate::declarative::declarative_source_append_surface`].
2132/// - `surface_root`: Input consumed by [`crate::declarative::declarative_source_append_surface`].
2133///
2134/// # Returns
2135///
2136/// Returns `true` when the condition checked by [`crate::declarative::declarative_source_append_surface`] holds and `false` otherwise.
2137///
2138/// # Examples
2139///
2140/// ```rust,ignore
2141/// let _result = pharos_runtime_compiler::declarative::declarative_source_append_surface(todo!(), todo!());
2142/// ```
2143///
2144/// # Related
2145///
2146/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2147pub fn declarative_source_append_surface(surfaces: &mut Vec<Value>, surface_root: Value) -> bool {
2148    if surfaces.len() >= MAX_DECLARATIVE_FILES {
2149        return false;
2150    }
2151    surfaces.push(surface_root);
2152    true
2153}
2154
2155/// Performs declarative source append generated route mut.
2156///
2157/// # Parameters
2158///
2159/// - `routes`: Input consumed by [`crate::declarative::declarative_source_append_generated_route_mut`].
2160/// - `route_id`: Input consumed by [`crate::declarative::declarative_source_append_generated_route_mut`].
2161/// - `path`: Input consumed by [`crate::declarative::declarative_source_append_generated_route_mut`].
2162/// - `kind`: Input consumed by [`crate::declarative::declarative_source_append_generated_route_mut`].
2163/// - `page_or_action_id`: Input consumed by [`crate::declarative::declarative_source_append_generated_route_mut`].
2164/// - `auth_gate`: Input consumed by [`crate::declarative::declarative_source_append_generated_route_mut`].
2165/// - `policy_gate`: Input consumed by [`crate::declarative::declarative_source_append_generated_route_mut`].
2166/// - `layout_id`: Input consumed by [`crate::declarative::declarative_source_append_generated_route_mut`].
2167///
2168/// # Returns
2169///
2170/// Returns `true` when the condition checked by [`crate::declarative::declarative_source_append_generated_route_mut`] holds and `false` otherwise.
2171///
2172/// # Examples
2173///
2174/// ```rust,ignore
2175/// let _result = pharos_runtime_compiler::declarative::declarative_source_append_generated_route_mut(todo!(), todo!(), std::path::Path::new("fixture.json"), todo!(), todo!(), todo!(), todo!(), todo!());
2176/// ```
2177///
2178/// # Related
2179///
2180/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2181pub fn declarative_source_append_generated_route_mut(
2182    routes: &mut Vec<Value>,
2183    route_id: &str,
2184    path: &str,
2185    kind: &str,
2186    page_or_action_id: &str,
2187    auth_gate: Option<&str>,
2188    policy_gate: Option<&str>,
2189    layout_id: Option<&str>,
2190) -> bool {
2191    if route_id.is_empty()
2192        || path.is_empty()
2193        || page_or_action_id.is_empty()
2194        || !matches!(kind, "page" | "action")
2195    {
2196        return false;
2197    }
2198    let mut route = serde_json::Map::new();
2199    route.insert("route_id".to_owned(), Value::String(route_id.to_owned()));
2200    route.insert("path".to_owned(), Value::String(path.to_owned()));
2201    route.insert("kind".to_owned(), Value::String(kind.to_owned()));
2202    route.insert(
2203        (if kind == "page" {
2204            "page_id"
2205        } else {
2206            "action_id"
2207        })
2208        .to_owned(),
2209        Value::String(page_or_action_id.to_owned()),
2210    );
2211    route.insert(
2212        "layout_id".to_owned(),
2213        Value::String(layout_id.unwrap_or("generated_admin_shell").to_owned()),
2214    );
2215    route.insert(
2216        "auth_gate".to_owned(),
2217        Value::String(auth_gate.unwrap_or("session_required").to_owned()),
2218    );
2219    route.insert(
2220        "policy_gate".to_owned(),
2221        Value::String(policy_gate.unwrap_or_default().to_owned()),
2222    );
2223    route.insert("islands".to_owned(), Value::Array(Vec::new()));
2224    routes.push(Value::Object(route));
2225    true
2226}
2227
2228/// Performs declarative source generated API request hooks.
2229fn declarative_source_generated_api_request_hooks() -> Value {
2230    Value::Array(vec![Value::String("json_body_required".to_owned())])
2231}
2232
2233/// Performs declarative source find generated query for entity.
2234///
2235/// # Parameters
2236///
2237/// - `queries`: Input consumed by [`crate::declarative::declarative_source_find_generated_query_for_entity`].
2238/// - `entity_id`: Input consumed by [`crate::declarative::declarative_source_find_generated_query_for_entity`].
2239///
2240/// # Returns
2241///
2242/// Returns [`Some`] when [`crate::declarative::declarative_source_find_generated_query_for_entity`] can produce a value and [`None`] otherwise.
2243///
2244/// # Performance
2245///
2246/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_find_generated_query_for_entity`].
2247///
2248/// # Examples
2249///
2250/// ```rust,ignore
2251/// let _result = pharos_runtime_compiler::declarative::declarative_source_find_generated_query_for_entity(todo!(), "entity");
2252/// ```
2253///
2254/// # Related
2255///
2256/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2257pub fn declarative_source_find_generated_query_for_entity<'a>(
2258    queries: &'a Value,
2259    entity_id: &str,
2260) -> Option<&'a Value> {
2261    if entity_id.is_empty() {
2262        return None;
2263    }
2264    let items = queries.as_array()?;
2265    let mut match_value = None;
2266    for item in items {
2267        if item.get("entity_id").and_then(Value::as_str) != Some(entity_id) {
2268            continue;
2269        }
2270        if match_value.is_some() {
2271            return None;
2272        }
2273        match_value = Some(item);
2274    }
2275    match_value
2276}
2277
2278/// Performs declarative source find generated form for entity.
2279///
2280/// # Parameters
2281///
2282/// - `forms`: Input consumed by [`crate::declarative::declarative_source_find_generated_form_for_entity`].
2283/// - `entity_id`: Input consumed by [`crate::declarative::declarative_source_find_generated_form_for_entity`].
2284///
2285/// # Returns
2286///
2287/// Returns [`Some`] when [`crate::declarative::declarative_source_find_generated_form_for_entity`] can produce a value and [`None`] otherwise.
2288///
2289/// # Performance
2290///
2291/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_find_generated_form_for_entity`].
2292///
2293/// # Examples
2294///
2295/// ```rust,ignore
2296/// let _result = pharos_runtime_compiler::declarative::declarative_source_find_generated_form_for_entity(todo!(), "entity");
2297/// ```
2298///
2299/// # Related
2300///
2301/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2302pub fn declarative_source_find_generated_form_for_entity<'a>(
2303    forms: &'a Value,
2304    entity_id: &str,
2305) -> Option<&'a Value> {
2306    if entity_id.is_empty() {
2307        return None;
2308    }
2309    let items = forms.as_array()?;
2310    let mut match_value = None;
2311    for item in items {
2312        if item.get("entity_id").and_then(Value::as_str) != Some(entity_id) {
2313            continue;
2314        }
2315        if match_value.is_some() {
2316            return None;
2317        }
2318        match_value = Some(item);
2319    }
2320    match_value
2321}
2322
2323/// Performs declarative source find manage route.
2324///
2325/// # Parameters
2326///
2327/// - `routes`: Input consumed by [`crate::declarative::declarative_source_find_manage_route`].
2328/// - `path_segment`: Input consumed by [`crate::declarative::declarative_source_find_manage_route`].
2329///
2330/// # Returns
2331///
2332/// Returns [`Some`] when [`crate::declarative::declarative_source_find_manage_route`] can produce a value and [`None`] otherwise.
2333///
2334/// # Performance
2335///
2336/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_find_manage_route`].
2337///
2338/// # Examples
2339///
2340/// ```rust,ignore
2341/// let _result = pharos_runtime_compiler::declarative::declarative_source_find_manage_route(todo!(), todo!());
2342/// ```
2343///
2344/// # Related
2345///
2346/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2347pub fn declarative_source_find_manage_route<'a>(
2348    routes: &'a Value,
2349    path_segment: &str,
2350) -> Option<&'a Value> {
2351    if path_segment.is_empty() {
2352        return None;
2353    }
2354    let items = routes.as_array()?;
2355    let mut match_value = None;
2356    for item in items {
2357        let is_match = item.get("kind").and_then(Value::as_str) == Some("page")
2358            && item.get("page_id").and_then(Value::as_str) == Some("generated_admin_manage")
2359            && item
2360                .get("path")
2361                .and_then(Value::as_str)
2362                .is_some_and(|path| declarative_source_route_path_has_segment(path, path_segment));
2363        if !is_match {
2364            continue;
2365        }
2366        if match_value.is_some() {
2367            return None;
2368        }
2369        match_value = Some(item);
2370    }
2371    match_value
2372}
2373
2374/// Resolves array.
2375fn resolve_array(value: Option<&Value>, artifact_dir: &Path) -> Option<Value> {
2376    match value? {
2377        Value::Array(_) => value.cloned(),
2378        Value::String(reference) => declarative_source_load_ref_target(artifact_dir, reference),
2379        _ => None,
2380    }
2381}
2382
2383/// Copies member.
2384fn copy_member(target: &mut serde_json::Map<String, Value>, source: &Value, key: &str) {
2385    if let Some(value) = source.get(key) {
2386        target.insert(key.to_owned(), value.clone());
2387    }
2388}
2389
2390/// Builds one generated surface from declarative entity, query, form, and route values.
2391///
2392/// # Parameters
2393///
2394/// - `artifact_dir`: Input consumed by [`crate::declarative::declarative_source_build_surface_mut`].
2395/// - `entity_root`: Input consumed by [`crate::declarative::declarative_source_build_surface_mut`].
2396/// - `query_root`: Input consumed by [`crate::declarative::declarative_source_build_surface_mut`].
2397/// - `form_root`: Input consumed by [`crate::declarative::declarative_source_build_surface_mut`].
2398/// - `manage_route`: Input consumed by [`crate::declarative::declarative_source_build_surface_mut`].
2399/// - `surface_kind`: Input consumed by [`crate::declarative::declarative_source_build_surface_mut`].
2400///
2401/// # Returns
2402///
2403/// Returns [`Some`] when [`crate::declarative::declarative_source_build_surface_mut`] can produce a value and [`None`] otherwise.
2404///
2405/// # Performance
2406///
2407/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_build_surface_mut`].
2408///
2409/// # Examples
2410///
2411/// ```rust,ignore
2412/// let _result = pharos_runtime_compiler::declarative::declarative_source_build_surface_mut(std::path::Path::new("build/dev_docs"), todo!(), todo!(), todo!(), todo!(), todo!());
2413/// ```
2414///
2415/// # Related
2416///
2417/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2418pub fn declarative_source_build_surface_mut(
2419    artifact_dir: &Path,
2420    entity_root: &Value,
2421    query_root: &Value,
2422    form_root: &Value,
2423    manage_route: &Value,
2424    surface_kind: &str,
2425) -> Option<Value> {
2426    if !matches!(surface_kind, "generated_admin" | "generated_api") {
2427        return None;
2428    }
2429    let generated = entity_root.get("generated_surfaces")?;
2430    let requested = if surface_kind == "generated_admin" {
2431        "admin"
2432    } else {
2433        "api"
2434    };
2435    if !declarative_source_array_has_string(generated, requested) {
2436        return None;
2437    }
2438    let entity_id = entity_root.get("entity_id")?.as_str()?;
2439    let query_id = query_root.get("query_id")?.as_str()?;
2440    let form_id = form_root.get("form_id")?.as_str()?;
2441    let identity_field = entity_root.get("identity_field")?.as_str()?;
2442    let scope_field = entity_root.get("scope_field")?.as_str()?;
2443    let runtime_collection = entity_root
2444        .get("runtime_collection")
2445        .and_then(Value::as_str)
2446        .map(ToOwned::to_owned)
2447        .or_else(|| {
2448            declarative_source_runtime_collection(
2449                entity_id,
2450                entity_root.get("table").and_then(Value::as_str),
2451            )
2452        })?;
2453    let manage_path = manage_route.get("path")?.as_str()?;
2454    let path_segment = entity_root
2455        .get("path_segment")
2456        .and_then(Value::as_str)
2457        .filter(|value| !value.is_empty())
2458        .map(ToOwned::to_owned)
2459        .or_else(|| declarative_source_path_segment_from_manage_path(manage_path))?;
2460    let identity_param =
2461        declarative_source_identity_param_from_surface(Some(&path_segment), entity_id)?;
2462    let entity_fields = resolve_array(entity_root.get("fields"), artifact_dir)?;
2463    let form_fields = resolve_array(form_root.get("fields"), artifact_dir)?;
2464    let relation_inputs = form_root.get("relation_inputs");
2465    let field_types = {
2466        let mut types = serde_json::Map::new();
2467        for field in entity_fields.as_array()? {
2468            if let (Some(id), Some(kind)) = (
2469                field.get("field_id").and_then(Value::as_str),
2470                field.get("type").and_then(Value::as_str),
2471            ) {
2472                types.insert(id.to_owned(), Value::String(kind.to_owned()));
2473            }
2474        }
2475        if let Some(inputs) = relation_inputs.and_then(Value::as_array) {
2476            for input in inputs {
2477                if let Some(field) = input.get("field").and_then(Value::as_str) {
2478                    types.insert(field.to_owned(), Value::String("array_integer".to_owned()));
2479                }
2480            }
2481        }
2482        Value::Object(types)
2483    };
2484    let capability = manage_route
2485        .get("policy_gate")
2486        .and_then(Value::as_str)
2487        .unwrap_or("");
2488    let soft_restore_supported = entity_root
2489        .get("soft_delete_field")
2490        .and_then(Value::as_str)
2491        .is_some_and(|value| !value.is_empty())
2492        && entity_root.get("delete_strategy").and_then(Value::as_str) != Some("hard");
2493    let mut operations = if surface_kind == "generated_admin" {
2494        serde_json::json!({
2495            "manage": declarative_source_build_operation_mut("GET", manage_path, capability)?,
2496            "create": declarative_source_build_operation_mut("POST", &declarative_source_operation_path(manage_path, false, None, Some("new/"))?, capability)?,
2497            "edit": declarative_source_build_operation_mut("GET", &declarative_source_operation_path(manage_path, false, Some(&identity_param), Some("edit/"))?, capability)?,
2498            "update": declarative_source_build_operation_mut("POST", &declarative_source_operation_path(manage_path, false, Some(&identity_param), Some("edit/"))?, capability)?,
2499            "delete": declarative_source_build_operation_mut("POST", &declarative_source_operation_path(manage_path, false, Some(&identity_param), Some("delete/"))?, capability)?
2500        })
2501    } else {
2502        serde_json::json!({
2503            "list": declarative_source_build_operation_mut("GET", &api_prefixed_route_path(manage_path)?, capability)?,
2504            "schema": declarative_source_build_operation_mut("GET", &declarative_source_operation_path(manage_path, true, None, Some("schema/"))?, capability)?,
2505            "create": declarative_source_build_operation_mut("POST", &api_prefixed_route_path(manage_path)?, capability)?,
2506            "update": declarative_source_build_operation_mut("POST", &declarative_source_operation_path(manage_path, true, Some(&identity_param), None)?, capability)?,
2507            "delete": declarative_source_build_operation_mut("POST", &declarative_source_operation_path(manage_path, true, Some(&identity_param), Some("delete/"))?, capability)?
2508        })
2509    };
2510    if soft_restore_supported && let Some(object) = operations.as_object_mut() {
2511        let restore_path = declarative_source_operation_path(
2512            manage_path,
2513            surface_kind == "generated_api",
2514            Some(&identity_param),
2515            Some("restore/"),
2516        )?;
2517        object.insert(
2518            "restore".to_owned(),
2519            declarative_source_build_operation_mut("POST", &restore_path, capability)?,
2520        );
2521    }
2522    let mut surface = serde_json::Map::new();
2523    surface.insert(
2524        "surface_id".to_owned(),
2525        Value::String(format!("{entity_id}_{surface_kind}")),
2526    );
2527    surface.insert(
2528        "surface_kind".to_owned(),
2529        Value::String(surface_kind.to_owned()),
2530    );
2531    surface.insert("entity_id".to_owned(), Value::String(entity_id.to_owned()));
2532    surface.insert(
2533        "entity_collection".to_owned(),
2534        Value::String(runtime_collection.clone()),
2535    );
2536    surface.insert("query_id".to_owned(), Value::String(query_id.to_owned()));
2537    surface.insert("form_id".to_owned(), Value::String(form_id.to_owned()));
2538    surface.insert(
2539        "identity_field".to_owned(),
2540        Value::String(identity_field.to_owned()),
2541    );
2542    surface.insert("identity_param".to_owned(), Value::String(identity_param));
2543    surface.insert(
2544        "scope_field".to_owned(),
2545        Value::String(scope_field.to_owned()),
2546    );
2547    surface.insert("field_types".to_owned(), field_types);
2548    surface.insert("operations".to_owned(), operations);
2549    if let Some(value) = entity_root.get("context_binding") {
2550        surface.insert("context_binding".to_owned(), value.clone());
2551    } else if let Some(value) = declarative_source_default_context_binding_mut(Some(scope_field)) {
2552        surface.insert("context_binding".to_owned(), value);
2553    }
2554    if let Some(value) = query_root.get("response_fields") {
2555        surface.insert("response_fields".to_owned(), value.clone());
2556    } else if let Some(value) = declarative_source_derived_response_fields_mut(
2557        Some(&form_fields),
2558        relation_inputs,
2559        Some(identity_field),
2560        Some(scope_field),
2561        entity_root.get("soft_delete_field").and_then(Value::as_str),
2562        entity_root
2563            .get("auto_sequence_field")
2564            .and_then(Value::as_str),
2565    ) {
2566        surface.insert("response_fields".to_owned(), value);
2567    }
2568    if let Some(value) = query_root.get("filters") {
2569        surface.insert("filters".to_owned(), value.clone());
2570    } else if let Some(value) = query_root.get("filter_set").and_then(|value| {
2571        declarative_source_derived_filters_mut(
2572            value,
2573            Some(&form_fields),
2574            relation_inputs,
2575            Some(scope_field),
2576            entity_root.get("soft_delete_field").and_then(Value::as_str),
2577        )
2578    }) {
2579        surface.insert("filters".to_owned(), value);
2580    }
2581    if let Some(value) = query_root.get("sorts") {
2582        surface.insert("sorts".to_owned(), value.clone());
2583    } else if let Some(value) = query_root
2584        .get("sort_set")
2585        .and_then(declarative_source_derived_sorts_mut)
2586    {
2587        surface.insert("sorts".to_owned(), value);
2588    }
2589    if let Some(value) = form_root.get("defaults") {
2590        surface.insert("defaults".to_owned(), value.clone());
2591    } else if let Some(value) = declarative_source_derived_defaults_mut(
2592        Some(&form_fields),
2593        relation_inputs,
2594        entity_root.get("soft_delete_field").and_then(Value::as_str),
2595    ) {
2596        surface.insert("defaults".to_owned(), value);
2597    }
2598    copy_member(&mut surface, form_root, "field_constraints");
2599    copy_member(&mut surface, form_root, "relation_inputs");
2600    copy_member(&mut surface, entity_root, "auto_sequence_field");
2601    copy_member(&mut surface, entity_root, "soft_delete_field");
2602    copy_member(&mut surface, entity_root, "delete_strategy");
2603    if let Some(value) = entity_root.get("surface_uniqueness_rules") {
2604        surface.insert("surface_uniqueness_rules".to_owned(), value.clone());
2605    } else if let Some(value) = entity_root.get("uniqueness_rules").and_then(|value| {
2606        declarative_source_derived_surface_uniqueness_rules_mut(value, &entity_fields, entity_id)
2607    }) {
2608        surface.insert("surface_uniqueness_rules".to_owned(), value);
2609    }
2610    if let Some(value) = entity_root.get("audit_events") {
2611        surface.insert("audit_events".to_owned(), value.clone());
2612    } else if let Some(value) = declarative_source_derived_audit_events_mut(
2613        entity_id,
2614        entity_root.get("delete_strategy").and_then(Value::as_str) == Some("hard"),
2615    ) {
2616        surface.insert("audit_events".to_owned(), value);
2617    }
2618    if let Some(value) = surface.get("surface_uniqueness_rules").cloned() {
2619        surface.insert("uniqueness_rules".to_owned(), value);
2620    }
2621    if surface_kind == "generated_admin" {
2622        let admin_source = manage_route
2623            .get("admin_surface")
2624            .and_then(|value| value.as_object());
2625        let response_fields = surface
2626            .get("response_fields")
2627            .unwrap_or(&Value::Array(Vec::new()))
2628            .clone();
2629        let mut admin = serde_json::Map::new();
2630        admin.insert(
2631            "manage_page_template".to_owned(),
2632            Value::String("templates/generated_admin/manage.page.json".to_owned()),
2633        );
2634        admin.insert(
2635            "edit_page_template".to_owned(),
2636            Value::String("templates/generated_admin/edit.page.json".to_owned()),
2637        );
2638        admin.insert(
2639            "list_title".to_owned(),
2640            Value::String(declarative_source_label(entity_id, true)),
2641        );
2642        admin.insert(
2643            "list_intro".to_owned(),
2644            Value::String(declarative_source_label(&runtime_collection, true)),
2645        );
2646        admin.insert(
2647            "filter_title".to_owned(),
2648            Value::String(declarative_source_label(&runtime_collection, true)),
2649        );
2650        admin.insert(
2651            "records_title".to_owned(),
2652            Value::String(declarative_source_label(&runtime_collection, true)),
2653        );
2654        admin.insert(
2655            "create_title".to_owned(),
2656            Value::String(declarative_source_label(entity_id, true)),
2657        );
2658        admin.insert(
2659            "create_button_label".to_owned(),
2660            Value::String("Create".to_owned()),
2661        );
2662        admin.insert(
2663            "save_button_label".to_owned(),
2664            Value::String("Save".to_owned()),
2665        );
2666        admin.insert(
2667            "empty_state_text".to_owned(),
2668            Value::String("No records found.".to_owned()),
2669        );
2670        admin.insert(
2671            "item_title_field".to_owned(),
2672            Value::String(default_item_title_field(
2673                &entity_fields,
2674                Some(identity_field),
2675                Some(scope_field),
2676            )?),
2677        );
2678        admin.insert(
2679            "list_columns".to_owned(),
2680            declarative_source_default_list_columns_mut(
2681                &response_fields,
2682                Some(identity_field),
2683                Some(scope_field),
2684            )?,
2685        );
2686        if let Some(source) = admin_source {
2687            for key in [
2688                "list_title",
2689                "list_intro",
2690                "back_path_template",
2691                "filter_title",
2692                "records_title",
2693                "create_title",
2694                "create_button_label",
2695                "save_button_label",
2696                "empty_state_text",
2697                "item_title_field",
2698                "delete_button_label",
2699                "list_columns",
2700                "composition",
2701            ] {
2702                if let Some(value) = source.get(key) {
2703                    admin.insert(key.to_owned(), value.clone());
2704                }
2705            }
2706        }
2707        surface.insert("admin".to_owned(), Value::Object(admin));
2708    }
2709    Some(Value::Object(surface))
2710}
2711
2712/// Derives and writes the generated surface fixture from framework contract files.
2713///
2714/// # Parameters
2715///
2716/// - `artifact_dir`: Input consumed by [`crate::declarative::declarative_source_derive_generated_surface_fixture`].
2717///
2718/// # Returns
2719///
2720/// Returns [`Some`] when [`crate::declarative::declarative_source_derive_generated_surface_fixture`] can produce a value and [`None`] otherwise.
2721///
2722/// # Performance
2723///
2724/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_derive_generated_surface_fixture`].
2725///
2726/// # Examples
2727///
2728/// ```rust,ignore
2729/// let _result = pharos_runtime_compiler::declarative::declarative_source_derive_generated_surface_fixture(std::path::Path::new("build/dev_docs"));
2730/// ```
2731///
2732/// # Related
2733///
2734/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2735pub fn declarative_source_derive_generated_surface_fixture(artifact_dir: &Path) -> Option<usize> {
2736    let entities = read_framework_contract(artifact_dir, "entities.json")?
2737        .get("entities")?
2738        .clone();
2739    let queries = read_framework_contract(artifact_dir, "queries.json")?
2740        .get("queries")?
2741        .clone();
2742    let forms = read_framework_contract(artifact_dir, "forms.json")?
2743        .get("forms")?
2744        .clone();
2745    let routes = read_framework_contract(artifact_dir, "routes.json")?
2746        .get("routes")?
2747        .clone();
2748    let mut surfaces = Vec::new();
2749    for entity in entities.as_array()? {
2750        let entity_id = entity.get("entity_id").and_then(Value::as_str)?;
2751        let generated = entity.get("generated_surfaces");
2752        let generated_admin_requested =
2753            declarative_source_array_has_string(generated.unwrap_or(&Value::Null), "admin");
2754        let generated_api_requested =
2755            declarative_source_array_has_string(generated.unwrap_or(&Value::Null), "api");
2756        if !generated_admin_requested && !generated_api_requested {
2757            continue;
2758        }
2759        let collection = entity
2760            .get("runtime_collection")
2761            .and_then(Value::as_str)
2762            .or_else(|| entity.get("table").and_then(Value::as_str));
2763        let segment = entity
2764            .get("path_segment")
2765            .and_then(Value::as_str)
2766            .filter(|value| !value.is_empty())
2767            .map(ToOwned::to_owned)
2768            .or_else(|| declarative_source_default_path_segment(entity_id, collection));
2769        let query = queries
2770            .as_array()?
2771            .iter()
2772            .find(|value| value.get("entity_id").and_then(Value::as_str) == Some(entity_id));
2773        let form = forms
2774            .as_array()?
2775            .iter()
2776            .find(|value| value.get("entity_id").and_then(Value::as_str) == Some(entity_id));
2777        let routes_array = routes.as_array()?;
2778        let route = declarative_source_surface_anchor_route(
2779            routes_array,
2780            segment.as_deref(),
2781            entity_id,
2782            generated_admin_requested,
2783        );
2784        let (Some(query), Some(form), Some(route)) = (query, form, route) else {
2785            continue;
2786        };
2787        for kind in ["generated_api", "generated_admin"] {
2788            let requested = if kind == "generated_admin" {
2789                "admin"
2790            } else {
2791                "api"
2792            };
2793            if declarative_source_array_has_string(generated.unwrap_or(&Value::Null), requested)
2794                && let Some(surface) = declarative_source_build_surface_mut(
2795                    artifact_dir,
2796                    entity,
2797                    query,
2798                    form,
2799                    &route,
2800                    kind,
2801                )
2802            {
2803                surfaces.push(surface);
2804            }
2805        }
2806    }
2807    let output =
2808        serde_json::json!({"fixture_id": "generated_surface_fixture_v1", "surfaces": surfaces});
2809    let path = artifact_dir.join("data/contracts/generated-surfaces.json");
2810    if fs::create_dir_all(path.parent()?).is_err()
2811        || pharos_runtime_core::fs::write_file_within(
2812            artifact_dir,
2813            &path,
2814            serde_json::to_string_pretty(&output).ok()?.as_bytes(),
2815            0o644,
2816        )
2817        .is_err()
2818    {
2819        return None;
2820    }
2821    Some(output.get("surfaces")?.as_array()?.len())
2822}
2823
2824/// Performs declarative source surface path to route path.
2825///
2826/// # Parameters
2827///
2828/// - `surface_path`: Input consumed by [`crate::declarative::declarative_source_surface_path_to_route_path`].
2829///
2830/// # Returns
2831///
2832/// Returns [`Some`] when [`crate::declarative::declarative_source_surface_path_to_route_path`] can produce a value and [`None`] otherwise.
2833///
2834/// # Performance
2835///
2836/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_surface_path_to_route_path`].
2837///
2838/// # Examples
2839///
2840/// ```rust,ignore
2841/// let _result = pharos_runtime_compiler::declarative::declarative_source_surface_path_to_route_path(todo!());
2842/// ```
2843///
2844/// # Related
2845///
2846/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2847pub fn declarative_source_surface_path_to_route_path(surface_path: &str) -> Option<String> {
2848    if surface_path.is_empty() {
2849        return Some(String::new());
2850    }
2851    let mut output = String::with_capacity(surface_path.len());
2852    let mut chars = surface_path.chars().peekable();
2853    while let Some(character) = chars.next() {
2854        if character == '{' {
2855            output.push(':');
2856            for next in chars.by_ref() {
2857                if next == '}' {
2858                    break;
2859                }
2860                output.push(next);
2861            }
2862        } else {
2863            output.push(character);
2864        }
2865    }
2866    Some(output)
2867}
2868
2869/// Performs declarative source manage path from create route.
2870fn declarative_source_manage_path_from_create_route(path: &str) -> Option<String> {
2871    path.strip_suffix("new/").map(ToOwned::to_owned)
2872}
2873
2874/// Performs declarative source surface anchor route.
2875fn declarative_source_surface_anchor_route(
2876    routes: &[Value],
2877    segment: Option<&str>,
2878    entity_id: &str,
2879    require_generated_admin: bool,
2880) -> Option<Value> {
2881    let generated_admin_manage = routes.iter().find(|value| {
2882        value.get("kind").and_then(Value::as_str) == Some("page")
2883            && value.get("page_id").and_then(Value::as_str) == Some("generated_admin_manage")
2884            && segment.is_some_and(|segment| {
2885                value
2886                    .get("path")
2887                    .and_then(Value::as_str)
2888                    .is_some_and(|path| declarative_source_route_path_has_segment(path, segment))
2889            })
2890    });
2891    if require_generated_admin || generated_admin_manage.is_some() {
2892        return generated_admin_manage.cloned();
2893    }
2894    let create_action_id = format!("create_{entity_id}");
2895    routes.iter().find_map(|value| {
2896        if value.get("kind").and_then(Value::as_str) != Some("action")
2897            || value.get("action_id").and_then(Value::as_str) != Some(create_action_id.as_str())
2898        {
2899            return None;
2900        }
2901        let mut route = value.clone();
2902        let manage_path = route
2903            .get("path")
2904            .and_then(Value::as_str)
2905            .and_then(declarative_source_manage_path_from_create_route)?;
2906        route["path"] = Value::String(manage_path);
2907        Some(route)
2908    })
2909}
2910
2911/// Derives missing generated-admin child routes and writes the route artifact.
2912///
2913/// # Parameters
2914///
2915/// - `artifact_dir`: Input consumed by [`crate::declarative::declarative_source_derive_generated_admin_routes`].
2916///
2917/// # Returns
2918///
2919/// Returns [`Some`] when [`crate::declarative::declarative_source_derive_generated_admin_routes`] can produce a value and [`None`] otherwise.
2920///
2921/// # Performance
2922///
2923/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_derive_generated_admin_routes`].
2924///
2925/// # Examples
2926///
2927/// ```rust,ignore
2928/// let _result = pharos_runtime_compiler::declarative::declarative_source_derive_generated_admin_routes(std::path::Path::new("build/dev_docs"));
2929/// ```
2930///
2931/// # Related
2932///
2933/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
2934pub fn declarative_source_derive_generated_admin_routes(artifact_dir: &Path) -> Option<usize> {
2935    let root = read_framework_contract(artifact_dir, "routes.json")?;
2936    let surfaces = read_framework_contract(artifact_dir, "generated-surfaces.json")?;
2937    let mut routes = root.get("routes")?.as_array()?.to_vec();
2938    let mut added = 0usize;
2939    for surface in surfaces.get("surfaces")?.as_array()? {
2940        if surface.get("surface_kind").and_then(Value::as_str) != Some("generated_admin") {
2941            continue;
2942        }
2943        let operations = surface.get("operations")?;
2944        let manage_path = operations.get("manage")?.get("path")?.as_str()?;
2945        let manage_route_path = declarative_source_surface_path_to_route_path(manage_path)?;
2946        let manage = routes.iter().find(|route| {
2947            route.get("kind").and_then(Value::as_str) == Some("page")
2948                && route.get("page_id").and_then(Value::as_str) == Some("generated_admin_manage")
2949                && route.get("path").and_then(Value::as_str) == Some(manage_route_path.as_str())
2950        });
2951        let Some(manage) = manage else {
2952            continue;
2953        };
2954        let prefix = manage
2955            .get("route_id")
2956            .and_then(Value::as_str)
2957            .unwrap_or("generated")
2958            .strip_suffix("_manage")
2959            .unwrap_or("generated")
2960            .to_owned();
2961        let auth_gate = manage
2962            .get("auth_gate")
2963            .and_then(Value::as_str)
2964            .map(ToOwned::to_owned);
2965        let policy_gate = manage
2966            .get("policy_gate")
2967            .and_then(Value::as_str)
2968            .map(ToOwned::to_owned);
2969        let entity_id = surface
2970            .get("entity_id")
2971            .and_then(Value::as_str)
2972            .unwrap_or("entity")
2973            .to_owned();
2974        let mut route_specs = vec![
2975            (
2976                "create".to_owned(),
2977                "create".to_owned(),
2978                "action".to_owned(),
2979                format!("create_{entity_id}"),
2980            ),
2981            (
2982                "edit".to_owned(),
2983                "edit".to_owned(),
2984                "page".to_owned(),
2985                format!("{entity_id}_edit"),
2986            ),
2987            (
2988                "update".to_owned(),
2989                "update".to_owned(),
2990                "action".to_owned(),
2991                format!("update_{entity_id}"),
2992            ),
2993            (
2994                "delete".to_owned(),
2995                "delete".to_owned(),
2996                "action".to_owned(),
2997                format!("delete_{entity_id}"),
2998            ),
2999        ];
3000        if operations.get("restore").is_some() {
3001            route_specs.push((
3002                "restore".to_owned(),
3003                "restore".to_owned(),
3004                "action".to_owned(),
3005                format!("restore_{entity_id}"),
3006            ));
3007        }
3008        for (suffix, operation, kind, id) in route_specs {
3009            let route_id = format!("{prefix}_{suffix}");
3010            if routes
3011                .iter()
3012                .any(|route| route.get("route_id").and_then(Value::as_str) == Some(&route_id))
3013            {
3014                continue;
3015            }
3016            let Some(path) = operations
3017                .get(operation)
3018                .and_then(|value| value.get("path"))
3019                .and_then(Value::as_str)
3020                .and_then(declarative_source_surface_path_to_route_path)
3021            else {
3022                continue;
3023            };
3024            if declarative_source_append_generated_route_mut(
3025                &mut routes,
3026                &route_id,
3027                &path,
3028                &kind,
3029                &id,
3030                auth_gate.as_deref(),
3031                policy_gate.as_deref(),
3032                Some("generated_admin_shell"),
3033            ) {
3034                added += 1;
3035            }
3036        }
3037    }
3038    let mut result = root;
3039    result["routes"] = Value::Array(routes);
3040    pharos_runtime_core::fs::write_file_within(
3041        artifact_dir,
3042        &artifact_dir.join("data/contracts/routes.json"),
3043        serde_json::to_string_pretty(&result).ok()?.as_bytes(),
3044        0o644,
3045    )
3046    .ok()?;
3047    Some(added)
3048}
3049
3050/// Derives missing generated-api mutation routes and writes the route artifact.
3051///
3052/// # Parameters
3053///
3054/// - `artifact_dir`: Input consumed by [`crate::declarative::declarative_source_derive_generated_api_routes`].
3055///
3056/// # Returns
3057///
3058/// Returns [`Some`] when [`crate::declarative::declarative_source_derive_generated_api_routes`] can produce a value and [`None`] otherwise.
3059///
3060/// # Performance
3061///
3062/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::declarative_source_derive_generated_api_routes`].
3063///
3064/// # Examples
3065///
3066/// ```rust,ignore
3067/// let _result = pharos_runtime_compiler::declarative::declarative_source_derive_generated_api_routes(std::path::Path::new("build/dev_docs"));
3068/// ```
3069///
3070/// # Related
3071///
3072/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3073pub fn declarative_source_derive_generated_api_routes(artifact_dir: &Path) -> Option<usize> {
3074    let root = read_framework_contract(artifact_dir, "routes.json")?;
3075    let surfaces = read_framework_contract(artifact_dir, "generated-surfaces.json")?;
3076    let mut routes = root.get("routes")?.as_array()?.to_vec();
3077    let mut added = 0usize;
3078    for surface in surfaces.get("surfaces")?.as_array()? {
3079        if surface.get("surface_kind").and_then(Value::as_str) != Some("generated_api") {
3080            continue;
3081        }
3082        let operations = surface.get("operations")?;
3083        let entity_id = surface
3084            .get("entity_id")
3085            .and_then(Value::as_str)
3086            .unwrap_or("entity")
3087            .to_owned();
3088        let policy_gate = operations
3089            .get("create")
3090            .and_then(|value| value.get("capability"))
3091            .and_then(Value::as_str)
3092            .map(ToOwned::to_owned)
3093            .or_else(|| {
3094                operations
3095                    .as_object()?
3096                    .values()
3097                    .find_map(|value| value.get("capability").and_then(Value::as_str))
3098                    .map(ToOwned::to_owned)
3099            });
3100        let auth_gate = Some("session_required");
3101        let mut route_specs = vec![
3102            (
3103                "api_create".to_owned(),
3104                "create".to_owned(),
3105                format!("create_{entity_id}"),
3106            ),
3107            (
3108                "api_update".to_owned(),
3109                "update".to_owned(),
3110                format!("update_{entity_id}"),
3111            ),
3112            (
3113                "api_delete".to_owned(),
3114                "delete".to_owned(),
3115                format!("delete_{entity_id}"),
3116            ),
3117        ];
3118        if operations.get("restore").is_some() {
3119            route_specs.push((
3120                "api_restore".to_owned(),
3121                "restore".to_owned(),
3122                format!("restore_{entity_id}"),
3123            ));
3124        }
3125        for (suffix, operation, action_id) in route_specs {
3126            let route_id = format!("{entity_id}_{suffix}");
3127            if routes
3128                .iter()
3129                .any(|route| route.get("route_id").and_then(Value::as_str) == Some(&route_id))
3130            {
3131                continue;
3132            }
3133            let Some(path) = operations
3134                .get(operation)
3135                .and_then(|value| value.get("path"))
3136                .and_then(Value::as_str)
3137                .and_then(declarative_source_surface_path_to_route_path)
3138            else {
3139                continue;
3140            };
3141            if declarative_source_append_generated_route_mut(
3142                &mut routes,
3143                &route_id,
3144                &path,
3145                "action",
3146                &action_id,
3147                auth_gate,
3148                policy_gate.as_deref(),
3149                Some("generated_admin_shell"),
3150            ) {
3151                if let Some(route) = routes.last_mut().and_then(Value::as_object_mut) {
3152                    route.insert(
3153                        "request_hooks".to_owned(),
3154                        declarative_source_generated_api_request_hooks(),
3155                    );
3156                }
3157                added += 1;
3158            }
3159        }
3160    }
3161    let mut result = root;
3162    result["routes"] = Value::Array(routes);
3163    pharos_runtime_core::fs::write_file_within(
3164        artifact_dir,
3165        &artifact_dir.join("data/contracts/routes.json"),
3166        serde_json::to_string_pretty(&result).ok()?.as_bytes(),
3167        0o644,
3168    )
3169    .ok()?;
3170    Some(added)
3171}
3172
3173/// Resolves an app-owned artifact template without falling back to shell commands.
3174///
3175/// # Parameters
3176///
3177/// - `app_root`: Input consumed by [`crate::declarative::artifact_shared_template_path`].
3178/// - `relative_path`: Input consumed by [`crate::declarative::artifact_shared_template_path`].
3179///
3180/// # Returns
3181///
3182/// Returns [`Some`] when [`crate::declarative::artifact_shared_template_path`] can produce a value and [`None`] otherwise.
3183///
3184/// # Examples
3185///
3186/// ```rust,ignore
3187/// let _result = pharos_runtime_compiler::declarative::artifact_shared_template_path(std::path::Path::new("apps/dev_docs"), "page");
3188/// ```
3189///
3190/// # Related
3191///
3192/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3193pub fn artifact_shared_template_path(app_root: &Path, relative_path: &str) -> Option<PathBuf> {
3194    let relative = safe_relative_path(relative_path)?;
3195    let candidate = app_root.join("assets").join(relative);
3196    candidate.is_file().then_some(candidate)
3197}
3198
3199const YAML_INCLUDE_MAX_DEPTH: usize = 32;
3200const YAML_BUFFER_LIMIT: usize = 16 * 1024 * 1024;
3201
3202/// Appends bounded YAML source text to an output buffer.
3203///
3204/// # Parameters
3205///
3206/// - `buffer`: Input consumed by [`crate::declarative::yaml_buffer_append`].
3207/// - `text`: Input consumed by [`crate::declarative::yaml_buffer_append`].
3208///
3209/// # Returns
3210///
3211/// Returns `true` when the condition checked by [`crate::declarative::yaml_buffer_append`] holds and `false` otherwise.
3212///
3213/// # Examples
3214///
3215/// ```rust,ignore
3216/// let _result = pharos_runtime_compiler::declarative::yaml_buffer_append(&mut [], "{}");
3217/// ```
3218///
3219/// # Related
3220///
3221/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3222pub fn yaml_buffer_append(buffer: &mut String, text: &str) -> bool {
3223    if buffer.len().saturating_add(text.len()) > YAML_BUFFER_LIMIT {
3224        return false;
3225    }
3226    buffer.push_str(text);
3227    true
3228}
3229
3230/// Returns the parent directory of a YAML source file.
3231///
3232/// # Parameters
3233///
3234/// - `file_path`: Input consumed by [`crate::declarative::yaml_dup_parent_dir`].
3235///
3236/// # Returns
3237///
3238/// Returns [`Some`] when [`crate::declarative::yaml_dup_parent_dir`] can produce a value and [`None`] otherwise.
3239///
3240/// # Examples
3241///
3242/// ```rust,ignore
3243/// let _result = pharos_runtime_compiler::declarative::yaml_dup_parent_dir(todo!());
3244/// ```
3245///
3246/// # Related
3247///
3248/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3249pub fn yaml_dup_parent_dir(file_path: &str) -> Option<String> {
3250    Path::new(file_path)
3251        .parent()
3252        .map(|path| path.to_string_lossy().into_owned())
3253}
3254
3255/// Resolves a safe include path relative to a YAML source file.
3256///
3257/// # Parameters
3258///
3259/// - `base_file_path`: Input consumed by [`crate::declarative::yaml_join_relative_path`].
3260/// - `relative_path`: Input consumed by [`crate::declarative::yaml_join_relative_path`].
3261///
3262/// # Returns
3263///
3264/// Returns [`Some`] when [`crate::declarative::yaml_join_relative_path`] can produce a value and [`None`] otherwise.
3265///
3266/// # Examples
3267///
3268/// ```rust,ignore
3269/// let _result = pharos_runtime_compiler::declarative::yaml_join_relative_path(todo!(), "page");
3270/// ```
3271///
3272/// # Related
3273///
3274/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3275pub fn yaml_join_relative_path(base_file_path: &str, relative_path: &str) -> Option<String> {
3276    if relative_path.is_empty()
3277        || Path::new(relative_path).is_absolute()
3278        || relative_path.contains("..")
3279    {
3280        return None;
3281    }
3282    Some(
3283        Path::new(base_file_path)
3284            .parent()?
3285            .join(relative_path)
3286            .to_string_lossy()
3287            .into_owned(),
3288    )
3289}
3290
3291/// Identifies the supported YAML include token form.
3292///
3293/// # Parameters
3294///
3295/// - `token`: Input consumed by [`crate::declarative::yaml_token_is_include_path`].
3296///
3297/// # Returns
3298///
3299/// Returns `true` when the condition checked by [`crate::declarative::yaml_token_is_include_path`] holds and `false` otherwise.
3300///
3301/// # Examples
3302///
3303/// ```rust,ignore
3304/// let _result = pharos_runtime_compiler::declarative::yaml_token_is_include_path(todo!());
3305/// ```
3306///
3307/// # Related
3308///
3309/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3310pub fn yaml_token_is_include_path(token: &str) -> bool {
3311    token.trim().starts_with("!include ") || token.trim().starts_with("include:")
3312}
3313
3314/// Parses `!include relative[#section]` into its two components.
3315///
3316/// # Parameters
3317///
3318/// - `token`: Input consumed by [`crate::declarative::yaml_parse_include_token`].
3319/// - `Option<String>`: Input consumed by [`crate::declarative::yaml_parse_include_token`].
3320///
3321/// # Returns
3322///
3323/// Returns [`Some`] when [`crate::declarative::yaml_parse_include_token`] can produce a value and [`None`] otherwise.
3324///
3325/// # Examples
3326///
3327/// ```rust,ignore
3328/// let _result = pharos_runtime_compiler::declarative::yaml_parse_include_token(todo!(), todo!());
3329/// ```
3330///
3331/// # Related
3332///
3333/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3334pub fn yaml_parse_include_token(token: &str) -> Option<(String, Option<String>)> {
3335    if !yaml_token_is_include_path(token) {
3336        return None;
3337    }
3338    let raw = token
3339        .trim()
3340        .strip_prefix("!include ")
3341        .or_else(|| token.trim().strip_prefix("include:"))?
3342        .trim();
3343    let (path, section) = raw.split_once('#').map_or((raw, None), |(path, section)| {
3344        (path, Some(section.to_owned()))
3345    });
3346    (!path.is_empty() && !path.contains("..")).then(|| (path.to_owned(), section))
3347}
3348
3349/// Detects an include directive on one YAML line.
3350///
3351/// # Parameters
3352///
3353/// - `line`: Input consumed by [`crate::declarative::yaml_line_is_fields_include`].
3354/// - `String`: Input consumed by [`crate::declarative::yaml_line_is_fields_include`].
3355///
3356/// # Returns
3357///
3358/// Returns [`Some`] when [`crate::declarative::yaml_line_is_fields_include`] can produce a value and [`None`] otherwise.
3359///
3360/// # Examples
3361///
3362/// ```rust,ignore
3363/// let _result = pharos_runtime_compiler::declarative::yaml_line_is_fields_include(todo!(), todo!());
3364/// ```
3365///
3366/// # Related
3367///
3368/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3369pub fn yaml_line_is_fields_include(line: &str) -> Option<(usize, String)> {
3370    let indent = line
3371        .len()
3372        .saturating_sub(line.trim_start_matches(' ').len());
3373    let token = line.trim();
3374    yaml_parse_include_token(token).map(|(path, section)| {
3375        (
3376            indent,
3377            format!(
3378                "{}{}",
3379                path,
3380                section.map(|value| format!("#{value}")).unwrap_or_default()
3381            ),
3382        )
3383    })
3384}
3385
3386/// Looks up a dotted section in a compiled YAML JSON value.
3387///
3388/// # Parameters
3389///
3390/// - `root`: Input consumed by [`crate::declarative::yaml_lookup_include_section_value`].
3391/// - `section_path`: Input consumed by [`crate::declarative::yaml_lookup_include_section_value`].
3392///
3393/// # Returns
3394///
3395/// Returns [`Some`] when [`crate::declarative::yaml_lookup_include_section_value`] can produce a value and [`None`] otherwise.
3396///
3397/// # Examples
3398///
3399/// ```rust,ignore
3400/// let _result = pharos_runtime_compiler::declarative::yaml_lookup_include_section_value(std::path::Path::new("."), todo!());
3401/// ```
3402///
3403/// # Related
3404///
3405/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3406pub fn yaml_lookup_include_section_value<'a>(
3407    root: &'a Value,
3408    section_path: &str,
3409) -> Option<&'a Value> {
3410    declarative_source_resolve_dotted_path(root, section_path)
3411}
3412
3413/// Adds indentation to every line of an included YAML block.
3414///
3415/// # Parameters
3416///
3417/// - `buffer`: Input consumed by [`crate::declarative::yaml_append_indented_block`].
3418/// - `indent_prefix`: Input consumed by [`crate::declarative::yaml_append_indented_block`].
3419/// - `include_text`: Input consumed by [`crate::declarative::yaml_append_indented_block`].
3420///
3421/// # Returns
3422///
3423/// Returns `true` when the condition checked by [`crate::declarative::yaml_append_indented_block`] holds and `false` otherwise.
3424///
3425/// # Performance
3426///
3427/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::yaml_append_indented_block`].
3428///
3429/// # Examples
3430///
3431/// ```rust,ignore
3432/// let _result = pharos_runtime_compiler::declarative::yaml_append_indented_block(&mut [], todo!(), todo!());
3433/// ```
3434///
3435/// # Related
3436///
3437/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3438pub fn yaml_append_indented_block(
3439    buffer: &mut String,
3440    indent_prefix: &str,
3441    include_text: &str,
3442) -> bool {
3443    for line in include_text.lines() {
3444        if !yaml_buffer_append(buffer, indent_prefix)
3445            || !yaml_buffer_append(buffer, line)
3446            || !yaml_buffer_append(buffer, "\n")
3447        {
3448            return false;
3449        }
3450    }
3451    true
3452}
3453
3454/// Performs YAML preprocess includes inner.
3455fn yaml_preprocess_includes_inner(path: &Path, depth: usize) -> Option<String> {
3456    if depth > YAML_INCLUDE_MAX_DEPTH {
3457        return None;
3458    }
3459    let text = fs::read_to_string(path).ok()?;
3460    if text.len() > YAML_BUFFER_LIMIT {
3461        return None;
3462    }
3463    let mut output = String::new();
3464    for line in text.lines() {
3465        if let Some((indent, token)) = yaml_line_is_fields_include(line) {
3466            let (relative, section) = yaml_parse_include_token(&format!("!include {token}"))?;
3467            let child_path = yaml_join_relative_path(&path.to_string_lossy(), &relative)?;
3468            let child_text = yaml_preprocess_includes_inner(Path::new(&child_path), depth + 1)?;
3469            let child_text = if let Some(section) = section {
3470                let value = yaml_read_as_json(&child_path)?;
3471                serde_json::to_string_pretty(yaml_lookup_include_section_value(&value, &section)?)
3472                    .ok()?
3473            } else {
3474                child_text
3475            };
3476            if !yaml_append_indented_block(&mut output, &" ".repeat(indent), &child_text) {
3477                return None;
3478            }
3479        } else if !yaml_buffer_append(&mut output, line) || !yaml_buffer_append(&mut output, "\n") {
3480            return None;
3481        }
3482    }
3483    Some(output)
3484}
3485
3486/// Preprocesses bounded recursive YAML includes using app-relative paths.
3487///
3488/// # Parameters
3489///
3490/// - `file_path`: Input consumed by [`crate::declarative::yaml_preprocess_includes_from_file`].
3491/// - `depth`: Input consumed by [`crate::declarative::yaml_preprocess_includes_from_file`].
3492///
3493/// # Returns
3494///
3495/// Returns [`Some`] when [`crate::declarative::yaml_preprocess_includes_from_file`] can produce a value and [`None`] otherwise.
3496///
3497/// # Examples
3498///
3499/// ```rust,ignore
3500/// let _result = pharos_runtime_compiler::declarative::yaml_preprocess_includes_from_file(todo!(), todo!());
3501/// ```
3502///
3503/// # Related
3504///
3505/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3506pub fn yaml_preprocess_includes_from_file(file_path: &str, depth: usize) -> Option<String> {
3507    yaml_preprocess_includes_inner(Path::new(file_path), depth)
3508}
3509
3510/// Identifies an integer YAML scalar.
3511///
3512/// # Parameters
3513///
3514/// - `value`: Input consumed by [`crate::declarative::yaml_scalar_is_integer`].
3515///
3516/// # Returns
3517///
3518/// Returns `true` when the condition checked by [`crate::declarative::yaml_scalar_is_integer`] holds and `false` otherwise.
3519///
3520/// # Examples
3521///
3522/// ```rust,ignore
3523/// let _result = pharos_runtime_compiler::declarative::yaml_scalar_is_integer("value");
3524/// ```
3525///
3526/// # Related
3527///
3528/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3529pub fn yaml_scalar_is_integer(value: &str) -> bool {
3530    value.trim().parse::<i64>().is_ok()
3531}
3532
3533/// Identifies a finite floating-point YAML scalar.
3534///
3535/// # Parameters
3536///
3537/// - `value`: Input consumed by [`crate::declarative::yaml_scalar_is_float`].
3538///
3539/// # Returns
3540///
3541/// Returns `true` when the condition checked by [`crate::declarative::yaml_scalar_is_float`] holds and `false` otherwise.
3542///
3543/// # Examples
3544///
3545/// ```rust,ignore
3546/// let _result = pharos_runtime_compiler::declarative::yaml_scalar_is_float("value");
3547/// ```
3548///
3549/// # Related
3550///
3551/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3552pub fn yaml_scalar_is_float(value: &str) -> bool {
3553    value.trim().parse::<f64>().is_ok() && value.trim().contains('.')
3554}
3555
3556/// Identifies a YAML boolean scalar.
3557///
3558/// # Parameters
3559///
3560/// - `value`: Input consumed by [`crate::declarative::yaml_scalar_is_bool`].
3561///
3562/// # Returns
3563///
3564/// Returns `true` when the condition checked by [`crate::declarative::yaml_scalar_is_bool`] holds and `false` otherwise.
3565///
3566/// # Examples
3567///
3568/// ```rust,ignore
3569/// let _result = pharos_runtime_compiler::declarative::yaml_scalar_is_bool("value");
3570/// ```
3571///
3572/// # Related
3573///
3574/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3575pub fn yaml_scalar_is_bool(value: &str) -> bool {
3576    matches!(
3577        value.trim().to_ascii_lowercase().as_str(),
3578        "true" | "false" | "yes" | "no" | "on" | "off"
3579    )
3580}
3581
3582/// Identifies a YAML null scalar.
3583///
3584/// # Parameters
3585///
3586/// - `value`: Input consumed by [`crate::declarative::yaml_scalar_is_null`].
3587///
3588/// # Returns
3589///
3590/// Returns `true` when the condition checked by [`crate::declarative::yaml_scalar_is_null`] holds and `false` otherwise.
3591///
3592/// # Examples
3593///
3594/// ```rust,ignore
3595/// let _result = pharos_runtime_compiler::declarative::yaml_scalar_is_null("value");
3596/// ```
3597///
3598/// # Related
3599///
3600/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3601pub fn yaml_scalar_is_null(value: &str) -> bool {
3602    matches!(value.trim().to_ascii_lowercase().as_str(), "null" | "~")
3603}
3604
3605/// Identifies the YAML boolean tag.
3606///
3607/// # Parameters
3608///
3609/// - `tag`: Input consumed by [`crate::declarative::yaml_tag_is_bool`].
3610///
3611/// # Returns
3612///
3613/// Returns `true` when the condition checked by [`crate::declarative::yaml_tag_is_bool`] holds and `false` otherwise.
3614///
3615/// # Examples
3616///
3617/// ```rust,ignore
3618/// let _result = pharos_runtime_compiler::declarative::yaml_tag_is_bool(todo!());
3619/// ```
3620///
3621/// # Related
3622///
3623/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3624pub fn yaml_tag_is_bool(tag: &str) -> bool {
3625    matches!(tag, "!!bool" | "tag:yaml.org,2002:bool")
3626}
3627
3628/// Identifies the YAML floating-point tag.
3629///
3630/// # Parameters
3631///
3632/// - `tag`: Input consumed by [`crate::declarative::yaml_tag_is_float`].
3633///
3634/// # Returns
3635///
3636/// Returns `true` when the condition checked by [`crate::declarative::yaml_tag_is_float`] holds and `false` otherwise.
3637///
3638/// # Examples
3639///
3640/// ```rust,ignore
3641/// let _result = pharos_runtime_compiler::declarative::yaml_tag_is_float(todo!());
3642/// ```
3643///
3644/// # Related
3645///
3646/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3647pub fn yaml_tag_is_float(tag: &str) -> bool {
3648    matches!(tag, "!!float" | "tag:yaml.org,2002:float")
3649}
3650
3651/// Identifies the YAML integer tag.
3652///
3653/// # Parameters
3654///
3655/// - `tag`: Input consumed by [`crate::declarative::yaml_tag_is_int`].
3656///
3657/// # Returns
3658///
3659/// Returns `true` when the condition checked by [`crate::declarative::yaml_tag_is_int`] holds and `false` otherwise.
3660///
3661/// # Examples
3662///
3663/// ```rust,ignore
3664/// let _result = pharos_runtime_compiler::declarative::yaml_tag_is_int(todo!());
3665/// ```
3666///
3667/// # Related
3668///
3669/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3670pub fn yaml_tag_is_int(tag: &str) -> bool {
3671    matches!(tag, "!!int" | "tag:yaml.org,2002:int")
3672}
3673
3674/// Identifies the YAML null tag.
3675///
3676/// # Parameters
3677///
3678/// - `tag`: Input consumed by [`crate::declarative::yaml_tag_is_null`].
3679///
3680/// # Returns
3681///
3682/// Returns `true` when the condition checked by [`crate::declarative::yaml_tag_is_null`] holds and `false` otherwise.
3683///
3684/// # Examples
3685///
3686/// ```rust,ignore
3687/// let _result = pharos_runtime_compiler::declarative::yaml_tag_is_null(todo!());
3688/// ```
3689///
3690/// # Related
3691///
3692/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3693pub fn yaml_tag_is_null(tag: &str) -> bool {
3694    matches!(tag, "!!null" | "tag:yaml.org,2002:null")
3695}
3696
3697/// Identifies the YAML string tag.
3698///
3699/// # Parameters
3700///
3701/// - `tag`: Input consumed by [`crate::declarative::yaml_tag_is_str`].
3702///
3703/// # Returns
3704///
3705/// Returns `true` when the condition checked by [`crate::declarative::yaml_tag_is_str`] holds and `false` otherwise.
3706///
3707/// # Examples
3708///
3709/// ```rust,ignore
3710/// let _result = pharos_runtime_compiler::declarative::yaml_tag_is_str(todo!());
3711/// ```
3712///
3713/// # Related
3714///
3715/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3716pub fn yaml_tag_is_str(tag: &str) -> bool {
3717    matches!(tag, "!!str" | "tag:yaml.org,2002:str")
3718}
3719
3720#[derive(Debug, Clone, Default, Eq, PartialEq)]
3721/// Public struct `YamlCompileContext` used by this module.
3722///
3723/// # Fields
3724///
3725/// - `stack`: Stored field on `YamlCompileContext`.
3726/// - `root`: Stored field on `YamlCompileContext`.
3727///
3728/// # Examples
3729///
3730/// ```rust,ignore
3731/// let _ = std::mem::size_of::<pharos_runtime_compiler::declarative::YamlCompileContext>();
3732/// ```
3733///
3734/// # Related
3735///
3736/// - [`crate::declarative`] for constructors, helpers, and neighboring runtime types.
3737pub struct YamlCompileContext {
3738    pub stack: Vec<Value>,
3739    pub root: Option<Value>,
3740}
3741
3742/// Initializes a YAML compile context.
3743///
3744/// # Parameters
3745///
3746/// - `context`: Input consumed by [`crate::declarative::yaml_compile_context_init`].
3747///
3748/// # Returns
3749///
3750/// Returns after [`crate::declarative::yaml_compile_context_init`] applies its in-place effect.
3751///
3752/// # Examples
3753///
3754/// ```rust,ignore
3755/// let _result = pharos_runtime_compiler::declarative::yaml_compile_context_init(todo!());
3756/// ```
3757///
3758/// # Related
3759///
3760/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3761pub fn yaml_compile_context_init(context: &mut YamlCompileContext) {
3762    context.stack.clear();
3763    context.root = None;
3764}
3765
3766/// Releases a YAML compile context.
3767///
3768/// # Parameters
3769///
3770/// - `context`: Input consumed by [`crate::declarative::yaml_compile_context_free`].
3771///
3772/// # Returns
3773///
3774/// Returns after [`crate::declarative::yaml_compile_context_free`] applies its in-place effect.
3775///
3776/// # Examples
3777///
3778/// ```rust,ignore
3779/// let _result = pharos_runtime_compiler::declarative::yaml_compile_context_free(todo!());
3780/// ```
3781///
3782/// # Related
3783///
3784/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3785pub fn yaml_compile_context_free(context: &mut YamlCompileContext) {
3786    context.stack.clear();
3787    context.root = None;
3788}
3789
3790/// Pushes a mapping or sequence container.
3791///
3792/// # Parameters
3793///
3794/// - `context`: Input consumed by [`crate::declarative::yaml_compile_push`].
3795/// - `value`: Input consumed by [`crate::declarative::yaml_compile_push`].
3796///
3797/// # Returns
3798///
3799/// Returns `true` when the condition checked by [`crate::declarative::yaml_compile_push`] holds and `false` otherwise.
3800///
3801/// # Examples
3802///
3803/// ```rust,ignore
3804/// let _result = pharos_runtime_compiler::declarative::yaml_compile_push(todo!(), "value");
3805/// ```
3806///
3807/// # Related
3808///
3809/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3810pub fn yaml_compile_push(context: &mut YamlCompileContext, value: Value) -> bool {
3811    context.stack.push(value);
3812    true
3813}
3814
3815/// Completes and returns the current container.
3816///
3817/// # Parameters
3818///
3819/// - `context`: Input consumed by [`crate::declarative::yaml_compile_pop`].
3820///
3821/// # Returns
3822///
3823/// Returns [`Some`] when [`crate::declarative::yaml_compile_pop`] can produce a value and [`None`] otherwise.
3824///
3825/// # Examples
3826///
3827/// ```rust,ignore
3828/// let _result = pharos_runtime_compiler::declarative::yaml_compile_pop(todo!());
3829/// ```
3830///
3831/// # Related
3832///
3833/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3834pub fn yaml_compile_pop(context: &mut YamlCompileContext) -> Option<Value> {
3835    context.stack.pop()
3836}
3837
3838/// Borrows the current compile container.
3839///
3840/// # Parameters
3841///
3842/// - `context`: Input consumed by [`crate::declarative::yaml_compile_peek`].
3843///
3844/// # Returns
3845///
3846/// Returns [`Some`] when [`crate::declarative::yaml_compile_peek`] can produce a value and [`None`] otherwise.
3847///
3848/// # Examples
3849///
3850/// ```rust,ignore
3851/// let _result = pharos_runtime_compiler::declarative::yaml_compile_peek(todo!());
3852/// ```
3853///
3854/// # Related
3855///
3856/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3857pub fn yaml_compile_peek(context: &YamlCompileContext) -> Option<&Value> {
3858    context.stack.last()
3859}
3860
3861/// Adds a completed value to the active compile container or root.
3862///
3863/// # Parameters
3864///
3865/// - `context`: Input consumed by [`crate::declarative::yaml_compile_add_value`].
3866/// - `value`: Input consumed by [`crate::declarative::yaml_compile_add_value`].
3867///
3868/// # Returns
3869///
3870/// Returns `true` when the condition checked by [`crate::declarative::yaml_compile_add_value`] holds and `false` otherwise.
3871///
3872/// # Examples
3873///
3874/// ```rust,ignore
3875/// let _result = pharos_runtime_compiler::declarative::yaml_compile_add_value(todo!(), "value");
3876/// ```
3877///
3878/// # Related
3879///
3880/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3881pub fn yaml_compile_add_value(context: &mut YamlCompileContext, value: Value) -> bool {
3882    if let Some(parent) = context.stack.last_mut() {
3883        match parent {
3884            Value::Array(items) => items.push(value),
3885            Value::Object(map) => {
3886                let key = map.len().to_string();
3887                map.insert(key, value);
3888            }
3889            _ => return false,
3890        }
3891    } else {
3892        context.root = Some(value);
3893    }
3894    true
3895}
3896
3897/// Starts a YAML mapping container.
3898///
3899/// # Parameters
3900///
3901/// - `context`: Input consumed by [`crate::declarative::yaml_handle_mapping_start`].
3902///
3903/// # Returns
3904///
3905/// Returns `true` when the condition checked by [`crate::declarative::yaml_handle_mapping_start`] holds and `false` otherwise.
3906///
3907/// # Examples
3908///
3909/// ```rust,ignore
3910/// let _result = pharos_runtime_compiler::declarative::yaml_handle_mapping_start(todo!());
3911/// ```
3912///
3913/// # Related
3914///
3915/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3916pub fn yaml_handle_mapping_start(context: &mut YamlCompileContext) -> bool {
3917    yaml_compile_push(context, Value::Object(Map::new()))
3918}
3919
3920/// Ends a YAML mapping container.
3921///
3922/// # Parameters
3923///
3924/// - `context`: Input consumed by [`crate::declarative::yaml_handle_mapping_end`].
3925///
3926/// # Returns
3927///
3928/// Returns `true` when the condition checked by [`crate::declarative::yaml_handle_mapping_end`] holds and `false` otherwise.
3929///
3930/// # Examples
3931///
3932/// ```rust,ignore
3933/// let _result = pharos_runtime_compiler::declarative::yaml_handle_mapping_end(todo!());
3934/// ```
3935///
3936/// # Related
3937///
3938/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3939pub fn yaml_handle_mapping_end(context: &mut YamlCompileContext) -> bool {
3940    let value = yaml_compile_pop(context);
3941    value.is_some_and(|value| yaml_compile_add_value(context, value))
3942}
3943
3944/// Starts a YAML sequence container.
3945///
3946/// # Parameters
3947///
3948/// - `context`: Input consumed by [`crate::declarative::yaml_handle_sequence_start`].
3949///
3950/// # Returns
3951///
3952/// Returns `true` when the condition checked by [`crate::declarative::yaml_handle_sequence_start`] holds and `false` otherwise.
3953///
3954/// # Examples
3955///
3956/// ```rust,ignore
3957/// let _result = pharos_runtime_compiler::declarative::yaml_handle_sequence_start(todo!());
3958/// ```
3959///
3960/// # Related
3961///
3962/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3963pub fn yaml_handle_sequence_start(context: &mut YamlCompileContext) -> bool {
3964    yaml_compile_push(context, Value::Array(Vec::new()))
3965}
3966
3967/// Ends a YAML sequence container.
3968///
3969/// # Parameters
3970///
3971/// - `context`: Input consumed by [`crate::declarative::yaml_handle_sequence_end`].
3972///
3973/// # Returns
3974///
3975/// Returns `true` when the condition checked by [`crate::declarative::yaml_handle_sequence_end`] holds and `false` otherwise.
3976///
3977/// # Examples
3978///
3979/// ```rust,ignore
3980/// let _result = pharos_runtime_compiler::declarative::yaml_handle_sequence_end(todo!());
3981/// ```
3982///
3983/// # Related
3984///
3985/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
3986pub fn yaml_handle_sequence_end(context: &mut YamlCompileContext) -> bool {
3987    let value = yaml_compile_pop(context);
3988    value.is_some_and(|value| yaml_compile_add_value(context, value))
3989}
3990
3991/// Adds a scalar YAML value using the same scalar rules as saphyr.
3992///
3993/// # Parameters
3994///
3995/// - `context`: Input consumed by [`crate::declarative::yaml_handle_scalar`].
3996/// - `scalar`: Input consumed by [`crate::declarative::yaml_handle_scalar`].
3997///
3998/// # Returns
3999///
4000/// Returns `true` when the condition checked by [`crate::declarative::yaml_handle_scalar`] holds and `false` otherwise.
4001///
4002/// # Examples
4003///
4004/// ```rust,ignore
4005/// let _result = pharos_runtime_compiler::declarative::yaml_handle_scalar(todo!(), todo!());
4006/// ```
4007///
4008/// # Related
4009///
4010/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
4011pub fn yaml_handle_scalar(context: &mut YamlCompileContext, scalar: &str) -> bool {
4012    let value = if yaml_scalar_is_null(scalar) {
4013        Value::Null
4014    } else if yaml_scalar_is_bool(scalar) {
4015        Value::Bool(matches!(
4016            scalar.trim().to_ascii_lowercase().as_str(),
4017            "true" | "yes" | "on"
4018        ))
4019    } else if yaml_scalar_is_integer(scalar) {
4020        Value::Number(scalar.trim().parse::<i64>().ok().unwrap_or_default().into())
4021    } else if yaml_scalar_is_float(scalar) {
4022        serde_json::Number::from_f64(scalar.trim().parse::<f64>().ok().unwrap_or_default())
4023            .map(Value::Number)
4024            .unwrap_or_else(|| Value::String(scalar.to_owned()))
4025    } else {
4026        Value::String(scalar.to_owned())
4027    };
4028    yaml_compile_add_value(context, value)
4029}
4030
4031/// Compiles YAML text to one JSON value.
4032///
4033/// # Parameters
4034///
4035/// - `text`: Input consumed by [`crate::declarative::yaml_compile_to_json`].
4036///
4037/// # Returns
4038///
4039/// Returns [`Some`] when [`crate::declarative::yaml_compile_to_json`] can produce a value and [`None`] otherwise.
4040///
4041/// # Examples
4042///
4043/// ```rust,ignore
4044/// let _result = pharos_runtime_compiler::declarative::yaml_compile_to_json("{}");
4045/// ```
4046///
4047/// # Related
4048///
4049/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
4050pub fn yaml_compile_to_json(text: &str) -> Option<Value> {
4051    pharos_runtime_core::yaml::parse_yaml_text(text)
4052}
4053
4054/// Reads and compiles one YAML file to JSON.
4055///
4056/// # Returns
4057///
4058/// Returns `true` when the condition checked by [`crate::declarative::yaml_compile_enabled`] holds and `false` otherwise.
4059///
4060/// # Examples
4061///
4062/// ```rust,ignore
4063/// let _result = pharos_runtime_compiler::declarative::yaml_compile_enabled();
4064/// ```
4065///
4066/// # Related
4067///
4068/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
4069pub fn yaml_compile_enabled() -> bool {
4070    true
4071}
4072
4073/// Performs YAML read as JSON.
4074///
4075/// # Parameters
4076///
4077/// - `file_path`: Input consumed by [`crate::declarative::yaml_read_as_json`].
4078///
4079/// # Returns
4080///
4081/// Returns [`Some`] when [`crate::declarative::yaml_read_as_json`] can produce a value and [`None`] otherwise.
4082///
4083/// # Performance
4084///
4085/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::declarative::yaml_read_as_json`].
4086///
4087/// # Examples
4088///
4089/// ```rust,ignore
4090/// let _result = pharos_runtime_compiler::declarative::yaml_read_as_json(todo!());
4091/// ```
4092///
4093/// # Related
4094///
4095/// - [`crate::declarative`] for adjacent helpers that share the same runtime surface.
4096pub fn yaml_read_as_json(file_path: &str) -> Option<Value> {
4097    let text = yaml_preprocess_includes_from_file(file_path, 0)
4098        .or_else(|| fs::read_to_string(file_path).ok())?;
4099    yaml_compile_to_json(&text)
4100}
4101
4102#[cfg(test)]
4103mod tests {
4104    use super::{
4105        declarative_source_derive_generated_admin_routes,
4106        declarative_source_derive_generated_api_routes,
4107        declarative_source_derive_generated_surface_fixture,
4108    };
4109    use std::time::{SystemTime, UNIX_EPOCH};
4110
4111    /// Performs test root.
4112    fn test_root(label: &str) -> std::path::PathBuf {
4113        let nonce = SystemTime::now()
4114            .duration_since(UNIX_EPOCH)
4115            .expect("clock")
4116            .as_nanos();
4117        std::env::temp_dir().join(format!(
4118            "pharos-declarative-{label}-{}-{nonce}",
4119            std::process::id()
4120        ))
4121    }
4122
4123    /// Writes write.
4124    fn write(root: &std::path::Path, relative: &str, content: &str) {
4125        let path = root.join(relative);
4126        std::fs::create_dir_all(path.parent().expect("parent")).expect("directories");
4127        std::fs::write(path, content).expect("fixture");
4128    }
4129
4130    #[test]
4131    /// Performs derives generated admin delete route when missing.
4132    fn derives_generated_admin_delete_route_when_missing() {
4133        let root = test_root("generated-admin-routes");
4134        write(
4135            &root,
4136            "data/contracts/routes.json",
4137            r#"{"contract_version":"1.0","routes":[{"route_id":"service_manage","path":"/businesses/:business_slug/services/","kind":"page","page_id":"generated_admin_manage","layout_id":"generated_admin_shell","auth_gate":"session_required","policy_gate":"manage_services","islands":[]}]} "#,
4138        );
4139        write(
4140            &root,
4141            "data/contracts/generated-surfaces.json",
4142            r#"{"fixture_id":"generated_surface_fixture_v1","surfaces":[{"surface_id":"service_generated_admin","surface_kind":"generated_admin","entity_id":"service","operations":{"manage":{"method":"GET","path":"/businesses/{business_slug}/services/","capability":"manage_services"},"create":{"method":"POST","path":"/businesses/{business_slug}/services/new/","capability":"manage_services"},"edit":{"method":"GET","path":"/businesses/{business_slug}/services/{service_id}/edit/","capability":"manage_services"},"update":{"method":"POST","path":"/businesses/{business_slug}/services/{service_id}/edit/","capability":"manage_services"},"delete":{"method":"POST","path":"/businesses/{business_slug}/services/{service_id}/delete/","capability":"manage_services"},"restore":{"method":"POST","path":"/businesses/{business_slug}/services/{service_id}/restore/","capability":"manage_services"}}}]}"#,
4143        );
4144        assert_eq!(
4145            declarative_source_derive_generated_admin_routes(&root),
4146            Some(5)
4147        );
4148        let routes =
4149            std::fs::read_to_string(root.join("data/contracts/routes.json")).expect("routes");
4150        assert!(routes.contains("\"route_id\": \"service_delete\""));
4151        assert!(routes.contains("\"action_id\": \"delete_service\""));
4152        assert!(routes.contains("\"route_id\": \"service_restore\""));
4153        assert!(routes.contains("\"action_id\": \"restore_service\""));
4154        std::fs::remove_dir_all(root).expect("cleanup");
4155    }
4156
4157    #[test]
4158    /// Performs derives generated API mutation routes when missing.
4159    fn derives_generated_api_mutation_routes_when_missing() {
4160        let root = test_root("generated-api-routes");
4161        write(
4162            &root,
4163            "data/contracts/routes.json",
4164            r#"{"contract_version":"1.0","routes":[]}"#,
4165        );
4166        write(
4167            &root,
4168            "data/contracts/generated-surfaces.json",
4169            r#"{"fixture_id":"generated_surface_fixture_v1","surfaces":[{"surface_id":"service_generated_api","surface_kind":"generated_api","entity_id":"service","operations":{"list":{"method":"GET","path":"/api/businesses/{business_slug}/services/","capability":"manage_services"},"schema":{"method":"GET","path":"/api/businesses/{business_slug}/services/schema/","capability":"manage_services"},"create":{"method":"POST","path":"/api/businesses/{business_slug}/services/","capability":"manage_services"},"update":{"method":"POST","path":"/api/businesses/{business_slug}/services/{service_id}/","capability":"manage_services"},"delete":{"method":"POST","path":"/api/businesses/{business_slug}/services/{service_id}/delete/","capability":"manage_services"},"restore":{"method":"POST","path":"/api/businesses/{business_slug}/services/{service_id}/restore/","capability":"manage_services"}}}]}"#,
4170        );
4171        assert_eq!(
4172            declarative_source_derive_generated_api_routes(&root),
4173            Some(4)
4174        );
4175        let routes =
4176            std::fs::read_to_string(root.join("data/contracts/routes.json")).expect("routes");
4177        assert!(routes.contains("\"route_id\": \"service_api_create\""));
4178        assert!(routes.contains("\"route_id\": \"service_api_update\""));
4179        assert!(routes.contains("\"route_id\": \"service_api_delete\""));
4180        assert!(routes.contains("\"route_id\": \"service_api_restore\""));
4181        assert!(
4182            routes.contains("\"path\": \"/api/businesses/:business_slug/services/:service_id/\"")
4183        );
4184        assert!(routes.contains("\"action_id\": \"update_service\""));
4185        assert!(routes.contains("\"action_id\": \"restore_service\""));
4186        assert!(routes.contains("\"request_hooks\": [\n        \"json_body_required\"\n      ]"));
4187        std::fs::remove_dir_all(root).expect("cleanup");
4188    }
4189
4190    #[test]
4191    /// Performs derives generated API surface without generated admin anchor.
4192    fn derives_generated_api_surface_without_generated_admin_anchor() {
4193        let root = test_root("generated-api-surface-anchor");
4194        write(
4195            &root,
4196            "data/contracts/entities.json",
4197            r#"{"contract_version":"1.0","entities":[{"entity_id":"technician","table":"technician","identity_field":"id","scope_field":"business_id","generated_surfaces":["form","api","manifest"],"fields":[{"field_id":"id","type":"integer"},{"field_id":"business_id","type":"integer"},{"field_id":"name","type":"string"},{"field_id":"email","type":"string"},{"field_id":"is_active","type":"boolean"}],"soft_delete_field":"is_active"}]}"#,
4198        );
4199        write(
4200            &root,
4201            "data/contracts/queries.json",
4202            r#"{"contract_version":"1.0","queries":[{"query_id":"technicians_by_business","entity_id":"technician","filter_set":["business_id","is_active"],"sort_set":["name_asc"]}]}"#,
4203        );
4204        write(
4205            &root,
4206            "data/contracts/forms.json",
4207            r#"{"contract_version":"1.0","forms":[{"form_id":"technician_form","entity_id":"technician","fields":[{"field_id":"name","type":"string"},{"field_id":"email","type":"string"}],"submits_action":"create_technician"}]}"#,
4208        );
4209        write(
4210            &root,
4211            "data/contracts/routes.json",
4212            r#"{"contract_version":"1.0","routes":[{"route_id":"technician_create","path":"/businesses/:business_slug/technicians/new/","kind":"action","action_id":"create_technician","auth_gate":"session_required","policy_gate":"manage_technicians","islands":[]}]}"#,
4213        );
4214        assert_eq!(
4215            declarative_source_derive_generated_surface_fixture(&root),
4216            Some(1)
4217        );
4218        let surfaces = std::fs::read_to_string(root.join("data/contracts/generated-surfaces.json"))
4219            .expect("surfaces");
4220        assert!(surfaces.contains("\"surface_id\": \"technician_generated_api\""));
4221        assert!(surfaces.contains("\"path\": \"/api/businesses/{business_slug}/technicians/\""));
4222        assert!(surfaces.contains("\"restore\""));
4223        assert!(
4224            surfaces
4225                .contains("/api/businesses/{business_slug}/technicians/{technician_id}/restore/")
4226        );
4227        std::fs::remove_dir_all(root).expect("cleanup");
4228    }
4229}