pharos_runtime_docs/reference.rs
1use serde_json::{Map, Value};
2
3const MAX_REFERENCE_TEXT_BYTES: usize = 2 * 1024 * 1024;
4
5/// Performs text.
6fn text(value: Option<&Value>) -> String {
7 match value {
8 Some(Value::String(value)) => value.clone(),
9 Some(Value::Null) | None => String::new(),
10 Some(value) => serde_json::to_string(value).unwrap_or_default(),
11 }
12}
13
14/// Performs escape.
15fn escape(value: &str) -> String {
16 value
17 .replace('&', "&")
18 .replace('<', "<")
19 .replace('>', ">")
20 .replace('"', """)
21}
22
23/// Returns whether an action declaration has a user-visible effect hook.
24///
25/// # Parameters
26///
27/// - `actions`: Input consumed by [`crate::reference::reference_actions_have_effect_hook`].
28///
29/// # Returns
30///
31/// Returns `true` when the condition checked by [`crate::reference::reference_actions_have_effect_hook`] holds and `false` otherwise.
32///
33/// # Performance
34///
35/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::reference::reference_actions_have_effect_hook`].
36///
37/// # Examples
38///
39/// ```rust,ignore
40/// let _result = pharos_runtime_docs::reference::reference_actions_have_effect_hook(todo!());
41/// ```
42///
43/// # Related
44///
45/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
46pub fn reference_actions_have_effect_hook(actions: &Value) -> bool {
47 actions.as_array().is_some_and(|items| {
48 items.iter().any(|item| {
49 item.get("effect_hook")
50 .and_then(Value::as_str)
51 .is_some_and(|hook| !hook.is_empty())
52 })
53 })
54}
55
56/// Appends formatted text to a bounded reference buffer.
57///
58/// # Parameters
59///
60/// - `output`: Input consumed by [`crate::reference::reference_buffer_append_format`].
61/// - `fragment`: Input consumed by [`crate::reference::reference_buffer_append_format`].
62///
63/// # Returns
64///
65/// Returns `true` when the condition checked by [`crate::reference::reference_buffer_append_format`] holds and `false` otherwise.
66///
67/// # Examples
68///
69/// ```rust,ignore
70/// let _result = pharos_runtime_docs::reference::reference_buffer_append_format(todo!(), todo!());
71/// ```
72///
73/// # Related
74///
75/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
76pub fn reference_buffer_append_format(output: &mut String, fragment: &str) -> bool {
77 if output.len().saturating_add(fragment.len()) > MAX_REFERENCE_TEXT_BYTES {
78 return false;
79 }
80 output.push_str(fragment);
81 true
82}
83
84/// Appends HTML-escaped text to a bounded reference buffer.
85///
86/// # Parameters
87///
88/// - `output`: Input consumed by [`crate::reference::reference_buffer_append_html_escaped`].
89/// - `value`: Input consumed by [`crate::reference::reference_buffer_append_html_escaped`].
90///
91/// # Returns
92///
93/// Returns `true` when the condition checked by [`crate::reference::reference_buffer_append_html_escaped`] holds and `false` otherwise.
94///
95/// # Examples
96///
97/// ```rust,ignore
98/// let _result = pharos_runtime_docs::reference::reference_buffer_append_html_escaped(todo!(), "value");
99/// ```
100///
101/// # Related
102///
103/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
104pub fn reference_buffer_append_html_escaped(output: &mut String, value: &str) -> bool {
105 reference_buffer_append_format(output, &escape(value))
106}
107
108#[allow(non_snake_case)]
109/// Loads one reference fragment template through the current bounded rendering contract.
110///
111/// # Parameters
112///
113/// - `template`: Input consumed by [`crate::reference::LOAD_REF_FRAGMENT`].
114/// - `parameters`: Input consumed by [`crate::reference::LOAD_REF_FRAGMENT`].
115///
116/// # Returns
117///
118/// Returns [`Some`] when [`crate::reference::LOAD_REF_FRAGMENT`] can produce a value and [`None`] otherwise.
119///
120/// # Examples
121///
122/// ```rust,ignore
123/// let _result = pharos_runtime_docs::reference::LOAD_REF_FRAGMENT(todo!(), todo!());
124/// ```
125///
126/// # Related
127///
128/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
129pub fn LOAD_REF_FRAGMENT(template: &str, parameters: &Value) -> Option<String> {
130 reference_render_fragment(template, parameters)
131}
132
133/// Appends one generated reference entry using escaped declarative fields.
134///
135/// # Parameters
136///
137/// - `output`: Input consumed by [`crate::reference::reference_append_generated_entry`].
138/// - `entry`: Input consumed by [`crate::reference::reference_append_generated_entry`].
139///
140/// # Returns
141///
142/// Returns `true` when the condition checked by [`crate::reference::reference_append_generated_entry`] holds and `false` otherwise.
143///
144/// # Examples
145///
146/// ```rust,ignore
147/// let _result = pharos_runtime_docs::reference::reference_append_generated_entry(todo!(), todo!());
148/// ```
149///
150/// # Related
151///
152/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
153pub fn reference_append_generated_entry(output: &mut String, entry: &Value) -> bool {
154 let name = escape(&text(entry.get("name")));
155 let description = escape(&text(entry.get("description")));
156 let fragment = format!("<article><h3>{name}</h3><p>{description}</p></article>");
157 if output.len().saturating_add(fragment.len()) > MAX_REFERENCE_TEXT_BYTES {
158 return false;
159 }
160 reference_buffer_append_format(output, &fragment)
161}
162
163/// Returns a compact sidebar group representation.
164///
165/// # Parameters
166///
167/// - `group`: Input consumed by [`crate::reference::reference_sidebar_group`].
168///
169/// # Returns
170///
171/// Returns [`Some`] when [`crate::reference::reference_sidebar_group`] can produce a value and [`None`] otherwise.
172///
173/// # Examples
174///
175/// ```rust,ignore
176/// let _result = pharos_runtime_docs::reference::reference_sidebar_group(todo!());
177/// ```
178///
179/// # Related
180///
181/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
182pub fn reference_sidebar_group(group: &Value) -> Option<String> {
183 let title = text(group.get("title"));
184 let entries = group.get("entries")?.as_array()?;
185 (!title.is_empty()).then(|| {
186 serde_json::json!({
187 "title": title,
188 "entries": entries,
189 })
190 .to_string()
191 })
192}
193
194/// Returns the escaped sidebar shell text from declarative groups.
195///
196/// # Parameters
197///
198/// - `groups`: Input consumed by [`crate::reference::reference_sidebar_shell`].
199///
200/// # Returns
201///
202/// Returns [`Some`] when [`crate::reference::reference_sidebar_shell`] can produce a value and [`None`] otherwise.
203///
204/// # Performance
205///
206/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::reference::reference_sidebar_shell`].
207///
208/// # Examples
209///
210/// ```rust,ignore
211/// let _result = pharos_runtime_docs::reference::reference_sidebar_shell(todo!());
212/// ```
213///
214/// # Related
215///
216/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
217pub fn reference_sidebar_shell(groups: &Value) -> Option<String> {
218 let groups = groups.as_array()?;
219 let mut output = String::from("<aside><nav>");
220 for group in groups {
221 let title = escape(&text(group.get("title")));
222 output.push_str("<section><h2>");
223 output.push_str(&title);
224 output.push_str("</h2><ul>");
225 for entry in group
226 .get("entries")
227 .and_then(Value::as_array)
228 .into_iter()
229 .flatten()
230 {
231 output.push_str("<li>");
232 output.push_str(&escape(&text(
233 entry.get("label").or_else(|| entry.get("name")),
234 )));
235 output.push_str("</li>");
236 }
237 output.push_str("</ul></section>");
238 }
239 output.push_str("</nav></aside>");
240 (output.len() <= MAX_REFERENCE_TEXT_BYTES).then_some(output)
241}
242
243/// Renders an escaped reference preview fragment.
244///
245/// # Parameters
246///
247/// - `value`: Input consumed by [`crate::reference::reference_ui_preview_fragment`].
248///
249/// # Returns
250///
251/// Returns [`Some`] when [`crate::reference::reference_ui_preview_fragment`] can produce a value and [`None`] otherwise.
252///
253/// # Examples
254///
255/// ```rust,ignore
256/// let _result = pharos_runtime_docs::reference::reference_ui_preview_fragment("value");
257/// ```
258///
259/// # Related
260///
261/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
262pub fn reference_ui_preview_fragment(value: &Value) -> Option<String> {
263 let title = escape(&text(value.get("title").or_else(|| value.get("name"))));
264 let body = escape(&text(
265 value.get("body").or_else(|| value.get("description")),
266 ));
267 Some(format!(
268 "<div class=\"reference-preview\"><h3>{title}</h3><p>{body}</p></div>"
269 ))
270}
271
272/// Appends one reference entry to a bounded output buffer.
273///
274/// # Parameters
275///
276/// - `output`: Input consumed by [`crate::reference::reference_append_reference_entry`].
277/// - `entry`: Input consumed by [`crate::reference::reference_append_reference_entry`].
278///
279/// # Returns
280///
281/// Returns `true` when the condition checked by [`crate::reference::reference_append_reference_entry`] holds and `false` otherwise.
282///
283/// # Examples
284///
285/// ```rust,ignore
286/// let _result = pharos_runtime_docs::reference::reference_append_reference_entry(todo!(), todo!());
287/// ```
288///
289/// # Related
290///
291/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
292pub fn reference_append_reference_entry(output: &mut String, entry: &Value) -> bool {
293 reference_append_generated_entry(output, entry)
294}
295
296/// Converts one reference value into a compact example document.
297///
298/// # Parameters
299///
300/// - `value`: Input consumed by [`crate::reference::reference_example_from_value`].
301///
302/// # Returns
303///
304/// Returns [`Some`] when [`crate::reference::reference_example_from_value`] can produce a value and [`None`] otherwise.
305///
306/// # Examples
307///
308/// ```rust,ignore
309/// let _result = pharos_runtime_docs::reference::reference_example_from_value("value");
310/// ```
311///
312/// # Related
313///
314/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
315pub fn reference_example_from_value(value: &Value) -> Option<String> {
316 let example = value
317 .get("example")
318 .cloned()
319 .unwrap_or_else(|| value.clone());
320 serde_json::to_string(&example).ok()
321}
322
323/// Finds an object by an exact string field.
324///
325/// # Parameters
326///
327/// - `root`: Input consumed by [`crate::reference::reference_find_object_by_string_field`].
328/// - `field`: Input consumed by [`crate::reference::reference_find_object_by_string_field`].
329/// - `expected`: Input consumed by [`crate::reference::reference_find_object_by_string_field`].
330///
331/// # Returns
332///
333/// Returns [`Some`] when [`crate::reference::reference_find_object_by_string_field`] can produce a value and [`None`] otherwise.
334///
335/// # Performance
336///
337/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::reference::reference_find_object_by_string_field`].
338///
339/// # Examples
340///
341/// ```rust,ignore
342/// let _result = pharos_runtime_docs::reference::reference_find_object_by_string_field(std::path::Path::new("."), "field", "value");
343/// ```
344///
345/// # Related
346///
347/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
348pub fn reference_find_object_by_string_field<'a>(
349 root: &'a Value,
350 field: &str,
351 expected: &str,
352) -> Option<&'a Value> {
353 root.as_array()?.iter().find(|item| {
354 item.as_object()
355 .and_then(|object| object.get(field))
356 .and_then(Value::as_str)
357 == Some(expected)
358 })
359}
360
361/// Extracts reference parameters from one object into compact JSON.
362///
363/// # Parameters
364///
365/// - `value`: Input consumed by [`crate::reference::reference_parameters_from_object`].
366///
367/// # Returns
368///
369/// Returns [`Some`] when [`crate::reference::reference_parameters_from_object`] can produce a value and [`None`] otherwise.
370///
371/// # Performance
372///
373/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::reference::reference_parameters_from_object`].
374///
375/// # Examples
376///
377/// ```rust,ignore
378/// let _result = pharos_runtime_docs::reference::reference_parameters_from_object("value");
379/// ```
380///
381/// # Related
382///
383/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
384pub fn reference_parameters_from_object(value: &Value) -> Option<String> {
385 let object = value.as_object()?;
386 let mut parameters = Map::new();
387 for (key, value) in object {
388 if key == "parameters" {
389 continue;
390 }
391 parameters.insert(key.clone(), value.clone());
392 }
393 serde_json::to_string(&Value::Object(parameters)).ok()
394}
395
396/// Appends one object-key parameter to a bounded reference parameter list.
397///
398/// # Parameters
399///
400/// - `output`: Input consumed by [`crate::reference::reference_append_object_key_parameter`].
401/// - `key`: Input consumed by [`crate::reference::reference_append_object_key_parameter`].
402/// - `value`: Input consumed by [`crate::reference::reference_append_object_key_parameter`].
403///
404/// # Returns
405///
406/// Returns `true` when the condition checked by [`crate::reference::reference_append_object_key_parameter`] holds and `false` otherwise.
407///
408/// # Examples
409///
410/// ```rust,ignore
411/// let _result = pharos_runtime_docs::reference::reference_append_object_key_parameter(todo!(), "key", "value");
412/// ```
413///
414/// # Related
415///
416/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
417pub fn reference_append_object_key_parameter(
418 output: &mut Vec<Value>,
419 key: &str,
420 value: &Value,
421) -> bool {
422 if key.is_empty() || output.len() >= 4096 {
423 return false;
424 }
425 output.push(serde_json::json!({"key": key, "value": value}));
426 true
427}
428
429/// Appends one table-of-contents item with an escaped anchor target.
430///
431/// # Parameters
432///
433/// - `output`: Input consumed by [`crate::reference::reference_append_toc_item`].
434/// - `label`: Input consumed by [`crate::reference::reference_append_toc_item`].
435/// - `anchor`: Input consumed by [`crate::reference::reference_append_toc_item`].
436///
437/// # Returns
438///
439/// Returns `true` when the condition checked by [`crate::reference::reference_append_toc_item`] holds and `false` otherwise.
440///
441/// # Examples
442///
443/// ```rust,ignore
444/// let _result = pharos_runtime_docs::reference::reference_append_toc_item(todo!(), todo!(), todo!());
445/// ```
446///
447/// # Related
448///
449/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
450pub fn reference_append_toc_item(output: &mut String, label: &str, anchor: &str) -> bool {
451 if label.is_empty() || anchor.is_empty() || output.len() >= MAX_REFERENCE_TEXT_BYTES {
452 return false;
453 }
454 output.push_str(&format!(
455 "<li><a href=\"#{}\">{}</a></li>",
456 escape(anchor),
457 escape(label)
458 ));
459 true
460}
461
462/// Returns reference attributes as a compact JSON array.
463///
464/// # Parameters
465///
466/// - `value`: Input consumed by [`crate::reference::reference_attributes_list`].
467///
468/// # Returns
469///
470/// Returns [`Some`] when [`crate::reference::reference_attributes_list`] can produce a value and [`None`] otherwise.
471///
472/// # Examples
473///
474/// ```rust,ignore
475/// let _result = pharos_runtime_docs::reference::reference_attributes_list("value");
476/// ```
477///
478/// # Related
479///
480/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
481pub fn reference_attributes_list(value: &Value) -> Option<String> {
482 let attributes = value.get("attributes").and_then(Value::as_array)?;
483 serde_json::to_string(attributes).ok()
484}
485
486/// Returns stable pretty JSON for a reference value with a bounded depth/size.
487///
488/// # Parameters
489///
490/// - `value`: Input consumed by [`crate::reference::reference_json_pretty`].
491///
492/// # Returns
493///
494/// Returns [`Some`] when [`crate::reference::reference_json_pretty`] can produce a value and [`None`] otherwise.
495///
496/// # Examples
497///
498/// ```rust,ignore
499/// let _result = pharos_runtime_docs::reference::reference_json_pretty("value");
500/// ```
501///
502/// # Related
503///
504/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
505pub fn reference_json_pretty(value: &Value) -> Option<String> {
506 let text = serde_json::to_string_pretty(value).ok()?;
507 (text.len() <= MAX_REFERENCE_TEXT_BYTES).then_some(text)
508}
509
510/// Renders a reference fragment from a template value and parameter object.
511///
512/// # Parameters
513///
514/// - `template`: Input consumed by [`crate::reference::reference_render_fragment`].
515/// - `parameters`: Input consumed by [`crate::reference::reference_render_fragment`].
516///
517/// # Returns
518///
519/// Returns [`Some`] when [`crate::reference::reference_render_fragment`] can produce a value and [`None`] otherwise.
520///
521/// # Performance
522///
523/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::reference::reference_render_fragment`].
524///
525/// # Examples
526///
527/// ```rust,ignore
528/// let _result = pharos_runtime_docs::reference::reference_render_fragment(todo!(), todo!());
529/// ```
530///
531/// # Related
532///
533/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
534pub fn reference_render_fragment(template: &str, parameters: &Value) -> Option<String> {
535 let mut output = template.to_owned();
536 for (key, value) in parameters.as_object()? {
537 let marker = format!("{{{key}}}");
538 output = output.replace(&marker, &escape(&text(Some(value))));
539 }
540 (output.len() <= MAX_REFERENCE_TEXT_BYTES).then_some(output)
541}
542
543/// Summarizes one reference value without exposing uncontrolled nested data.
544///
545/// # Parameters
546///
547/// - `value`: Input consumed by [`crate::reference::reference_value_summary`].
548///
549/// # Returns
550///
551/// Returns the computed value produced by [`crate::reference::reference_value_summary`].
552///
553/// # Performance
554///
555/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::reference::reference_value_summary`].
556///
557/// # Examples
558///
559/// ```rust,ignore
560/// let _result = pharos_runtime_docs::reference::reference_value_summary("value");
561/// ```
562///
563/// # Related
564///
565/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
566pub fn reference_value_summary(value: &Value) -> String {
567 match value {
568 Value::Null => "null".to_owned(),
569 Value::Bool(value) => value.to_string(),
570 Value::Number(value) => value.to_string(),
571 Value::String(value) => value.chars().take(256).collect(),
572 Value::Array(values) => format!("array:{}", values.len()),
573 Value::Object(values) => format!("object:{}", values.len()),
574 }
575}
576
577/// Returns the stable JSON type name used by reference rendering.
578///
579/// # Parameters
580///
581/// - `value`: Input consumed by [`crate::reference::reference_value_type_name`].
582///
583/// # Returns
584///
585/// Returns the computed value produced by [`crate::reference::reference_value_type_name`].
586///
587/// # Examples
588///
589/// ```rust,ignore
590/// let _result = pharos_runtime_docs::reference::reference_value_type_name("value");
591/// ```
592///
593/// # Related
594///
595/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
596pub fn reference_value_type_name(value: &Value) -> &'static str {
597 match value {
598 Value::Null => "null",
599 Value::Bool(_) => "boolean",
600 Value::Number(_) => "number",
601 Value::String(_) => "string",
602 Value::Array(_) => "array",
603 Value::Object(_) => "object",
604 }
605}
606
607/// Removes the query and fragment from a request target.
608///
609/// # Parameters
610///
611/// - `target`: Input consumed by [`crate::reference::request_path_without_query`].
612///
613/// # Returns
614///
615/// Returns [`Some`] when [`crate::reference::request_path_without_query`] can produce a value and [`None`] otherwise.
616///
617/// # Performance
618///
619/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::reference::request_path_without_query`].
620///
621/// # Examples
622///
623/// ```rust,ignore
624/// let _result = pharos_runtime_docs::reference::request_path_without_query("/");
625/// ```
626///
627/// # Related
628///
629/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
630pub fn request_path_without_query(target: &str) -> Option<String> {
631 if target.is_empty() || !target.starts_with('/') {
632 return None;
633 }
634 Some(
635 target
636 .split(['?', '#'])
637 .next()
638 .unwrap_or_default()
639 .to_owned(),
640 )
641}
642
643/// Resolves a request target relative to an app mount path.
644///
645/// # Parameters
646///
647/// - `mount_path`: Input consumed by [`crate::reference::request_target_for_mount`].
648/// - `target`: Input consumed by [`crate::reference::request_target_for_mount`].
649///
650/// # Returns
651///
652/// Returns [`Some`] when [`crate::reference::request_target_for_mount`] can produce a value and [`None`] otherwise.
653///
654/// # Examples
655///
656/// ```rust,ignore
657/// let _result = pharos_runtime_docs::reference::request_target_for_mount(todo!(), "/");
658/// ```
659///
660/// # Related
661///
662/// - [`crate::reference`] for adjacent helpers that share the same runtime surface.
663pub fn request_target_for_mount(mount_path: &str, target: &str) -> Option<String> {
664 let target = request_path_without_query(target)?;
665 let mount = if mount_path.is_empty() {
666 "/"
667 } else {
668 mount_path
669 };
670 if mount == "/" {
671 return Some(target);
672 }
673 let remainder = target.strip_prefix(mount)?;
674 Some(if remainder.is_empty() {
675 "/".to_owned()
676 } else if remainder.starts_with('/') {
677 remainder.to_owned()
678 } else {
679 format!("/{remainder}")
680 })
681}