use std::collections::{BTreeMap, BTreeSet};
use super::type_expr::TypeExpr;
#[derive(Clone, Debug, Default)]
pub(crate) struct ComponentRegistry {
types: BTreeMap<String, TypeExpr>,
order: Vec<String>,
in_progress: BTreeSet<String>,
}
impl ComponentRegistry {
pub(super) fn register(&mut self, name: String, ty: TypeExpr) {
if !self.types.contains_key(&name) {
self.order.push(name.clone());
}
self.types.insert(name, ty);
}
pub(super) fn contains(&self, name: &str) -> bool {
self.types.contains_key(name)
}
pub(super) fn is_in_progress(&self, name: &str) -> bool {
self.in_progress.contains(name)
}
pub(super) fn begin_resolution(&mut self, name: &str) {
self.in_progress.insert(name.to_string());
}
pub(super) fn finish_resolution(&mut self, name: &str) {
self.in_progress.remove(name);
}
pub(crate) fn render_aliases(&self) -> String {
if self.order.is_empty() {
return String::new();
}
let mut out = String::new();
for name in &self.order {
if let Some(ty) = self.types.get(name) {
out.push_str(&format!("type {} = {};\n", name, ty.render()));
}
}
out
}
}
pub(super) fn ref_name_from_pointer(pointer: &str) -> Option<String> {
let stripped = pointer.trim_start_matches('#').trim_start_matches('/');
let last = stripped.rsplit('/').next()?;
if last.is_empty() {
None
} else {
Some(last.to_string())
}
}
pub(super) fn resolve_json_ref<'a>(
root: &'a serde_json::Value,
pointer: &str,
) -> Option<&'a serde_json::Value> {
let stripped = pointer.trim_start_matches('#').trim_start_matches('/');
if stripped.is_empty() {
return Some(root);
}
let mut current = root;
for segment in stripped.split('/') {
let decoded = segment.replace("~1", "/").replace("~0", "~");
current = match current {
serde_json::Value::Object(obj) => obj.get(&decoded)?,
serde_json::Value::Array(arr) => {
let idx: usize = decoded.parse().ok()?;
arr.get(idx)?
}
_ => return None,
};
}
Some(current)
}