use tree_sitter::Node;
use super::intelligence::{node_text, span_trimmed};
use super::types::*;
use super::walk::{Descend, walk_bounded, warn_if_truncated};
pub(super) fn structure(root: &Node<'_>, source: &str) -> Vec<StructureItem> {
let mut items = Vec::new();
let truncated = walk_bounded(root, |node, _depth| {
if node.kind() != "policy" {
return Descend::Children;
}
if let Some(id) = policy_id(node, source) {
items.push(StructureItem {
kind: StructureKind::Other("Policy".to_string()),
name: Some(id),
span: span_trimmed(node, source),
..StructureItem::default()
});
}
Descend::Skip
});
warn_if_truncated(truncated, "intel::cedar", "cedar");
items
}
fn policy_id(policy: &Node<'_>, source: &str) -> Option<String> {
let mut cursor = policy.walk();
policy
.named_children(&mut cursor)
.filter(|child| child.kind() == "annotation")
.find_map(|annotation| {
let mut inner = annotation.walk();
let mut parts = annotation.named_children(&mut inner);
parts.next().filter(|key| node_text(key, source) == "id")?;
let string = parts.next().filter(|value| value.kind() == "string")?;
let mut chars = string.walk();
string
.named_children(&mut chars)
.find(|part| part.kind() == "string_content")
.map(|content| node_text(&content, source).to_string())
})
}