use super::parse::segment_display;
use super::{AliasPolicy, PathError, PathSegment};
pub(super) fn registry_for(
node: &crate::yaml::SyntaxNode,
) -> crate::anchor_resolution::AnchorRegistry {
use crate::anchor_resolution::{document_scope, AnchorRegistry};
AnchorRegistry::from_tree(&document_scope(node))
}
pub(super) fn undefined_alias(
error: crate::anchor_resolution::AliasError,
segment: &PathSegment,
) -> PathError {
use crate::anchor_resolution::AliasError;
let (AliasError::Undefined { alias } | AliasError::Recursive { alias }) = error;
PathError::UndefinedAlias {
at: segment_display(segment),
alias,
}
}
pub(super) fn resolve_alias(
alias: &crate::yaml::Alias,
segment: &PathSegment,
policy: AliasPolicy,
) -> Result<crate::as_yaml::YamlNode, PathError> {
use rowan::ast::AstNode;
if policy == AliasPolicy::Refuse {
return Err(PathError::AliasRefused {
at: segment_display(segment),
alias: alias.name(),
});
}
let registry = registry_for(alias.syntax());
crate::anchor_resolution::resolve_alias_with(alias, ®istry, |target| {
if policy == AliasPolicy::Expand {
expanded_copy(target)
} else {
target.clone()
}
})
.map_err(|e| undefined_alias(e, segment))
}
fn expanded_copy(target: &crate::yaml::SyntaxNode) -> crate::yaml::SyntaxNode {
use crate::lex::SyntaxKind;
let mut builder = rowan::GreenNodeBuilder::new();
builder.start_node(target.kind().into());
let base = crate::column::node_column(target) as isize;
crate::as_yaml::copy_node_content_reindent(&mut builder, target, -base);
builder.finish_node();
let copy = crate::yaml::SyntaxNode::new_root_mut(builder.finish());
let anchors: Vec<_> = copy
.descendants_with_tokens()
.filter_map(|e| e.into_token())
.filter(|t| t.kind() == SyntaxKind::ANCHOR)
.collect();
for anchor in anchors {
crate::nodes::detach_anchor(&anchor);
}
copy
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_expand_copy_keeps_tag_after_anchor() {
use crate::yaml::Document;
use std::str::FromStr;
for src in [
"a: !!map &x\n k: 1\nb: *x\n",
"a: &x !!map\n k: 1\nb: *x\n",
] {
let doc = Document::from_str(src).unwrap();
let Some(crate::as_yaml::YamlNode::Alias(alias)) = doc.as_mapping().unwrap().get("b")
else {
panic!("b is not an alias in {src:?}");
};
let segment = PathSegment::Key("b".to_string());
let copy = resolve_alias(&alias, &segment, AliasPolicy::Expand).unwrap();
assert_eq!(copy.to_string(), "!!map\nk: 1\n", "{src:?}");
}
}
}