Skip to main content

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}