yaml_edit/nodes/alias_node.rs
1use super::{Lang, SyntaxNode};
2use crate::as_yaml::{AsYaml, YamlKind};
3use crate::lex::SyntaxKind;
4use rowan::ast::AstNode;
5use rowan::GreenNodeBuilder;
6
7ast_node!(Alias, ALIAS, "A YAML alias reference (e.g., *anchor_name)");
8
9impl Alias {
10 /// Construct an alias that serializes as `*name`.
11 ///
12 /// `name` is the anchor name without the `*` prefix. The node implements
13 /// [`AsYaml`], so it can be passed to [`Mapping::set`](crate::Mapping::set)
14 /// and other mutation APIs without parsing a snippet.
15 ///
16 /// # Panics
17 ///
18 /// Panics if `name` is not a valid anchor name: it must be non-empty and
19 /// hold no whitespace, line breaks, flow indicators (`,[]{}`) or
20 /// non-printable characters.
21 ///
22 /// # Examples
23 ///
24 /// ```
25 /// use std::str::FromStr;
26 /// use yaml_edit::{Alias, Document};
27 ///
28 /// let doc = Document::from_str("shared: &shared value\nservice_a: old\n").unwrap();
29 /// let mapping = doc.as_mapping().unwrap();
30 /// mapping.set("service_a", Alias::new("shared"));
31 /// assert_eq!(doc.to_string(), "shared: &shared value\nservice_a: *shared\n");
32 /// ```
33 pub fn new(name: impl AsRef<str>) -> Self {
34 let name = name.as_ref();
35 assert!(
36 crate::lex::is_valid_anchor_name(name),
37 "alias name must be a valid anchor name, got {name:?}"
38 );
39 let text = format!("*{name}");
40 let mut builder = GreenNodeBuilder::new();
41 builder.start_node(SyntaxKind::ALIAS.into());
42 builder.token(SyntaxKind::REFERENCE.into(), &text);
43 builder.finish_node();
44 Alias(SyntaxNode::new_root_mut(builder.finish()))
45 }
46
47 /// Get the full text of this alias including the `*` prefix
48 pub fn value(&self) -> String {
49 self.0.text().to_string()
50 }
51
52 /// Get the anchor name this alias refers to (without the `*` prefix)
53 ///
54 /// # Examples
55 ///
56 /// ```
57 /// use yaml_edit::Document;
58 /// use std::str::FromStr;
59 ///
60 /// let yaml = r#"
61 /// anchor: &my_anchor
62 /// key: value
63 /// reference: *my_anchor
64 /// "#;
65 ///
66 /// let doc = Document::from_str(yaml).unwrap();
67 /// let mapping = doc.as_mapping().unwrap();
68 /// let reference = mapping.get("reference").unwrap();
69 ///
70 /// if let yaml_edit::YamlNode::Alias(alias) = reference {
71 /// assert_eq!(alias.name(), "my_anchor");
72 /// }
73 /// ```
74 pub fn name(&self) -> String {
75 let text = self.value();
76 // Remove the leading '*' character
77 if let Some(stripped) = text.strip_prefix('*') {
78 stripped.to_string()
79 } else {
80 text
81 }
82 }
83}
84
85impl AsYaml for Alias {
86 fn as_node(&self) -> Option<&SyntaxNode> {
87 Some(&self.0)
88 }
89
90 fn kind(&self) -> YamlKind {
91 YamlKind::Alias
92 }
93
94 fn build_content(
95 &self,
96 builder: &mut rowan::GreenNodeBuilder,
97 _indent: usize,
98 _flow_context: bool,
99 ) -> bool {
100 builder.start_node(SyntaxKind::ALIAS.into());
101 crate::as_yaml::copy_node_content(builder, &self.0);
102 builder.finish_node();
103 false
104 }
105
106 fn is_inline(&self) -> bool {
107 true
108 }
109}