yerba 0.1.0-aarch64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ use clap::ValueEnum;
2
+ use yaml_parser::SyntaxKind;
3
+
4
+ #[derive(Debug, Clone, PartialEq, ValueEnum)]
5
+ pub enum QuoteStyle {
6
+ Plain,
7
+ #[value(alias = "single-quoted")]
8
+ Single,
9
+ #[value(alias = "double-quoted")]
10
+ Double,
11
+ #[value(alias = "block-literal")]
12
+ Literal,
13
+ #[value(alias = "block-folded")]
14
+ Folded,
15
+ }
16
+
17
+ impl std::str::FromStr for QuoteStyle {
18
+ type Err = String;
19
+
20
+ fn from_str(string: &str) -> Result<Self, Self::Err> {
21
+ match string {
22
+ "plain" => Ok(QuoteStyle::Plain),
23
+ "single" | "single-quoted" => Ok(QuoteStyle::Single),
24
+ "double" | "double-quoted" => Ok(QuoteStyle::Double),
25
+ "literal" | "block-literal" => Ok(QuoteStyle::Literal),
26
+ "folded" | "block-folded" => Ok(QuoteStyle::Folded),
27
+ _ => Err(format!("unknown quote style: '{}'", string)),
28
+ }
29
+ }
30
+ }
31
+
32
+ impl QuoteStyle {
33
+ pub(crate) fn to_syntax_kind(&self) -> SyntaxKind {
34
+ match self {
35
+ QuoteStyle::Plain => SyntaxKind::PLAIN_SCALAR,
36
+ QuoteStyle::Single => SyntaxKind::SINGLE_QUOTED_SCALAR,
37
+ QuoteStyle::Double => SyntaxKind::DOUBLE_QUOTED_SCALAR,
38
+ QuoteStyle::Literal => SyntaxKind::BLOCK_SCALAR_TEXT,
39
+ QuoteStyle::Folded => SyntaxKind::BLOCK_SCALAR_TEXT,
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,186 @@
1
+ use rowan::ast::AstNode;
2
+ use rowan::{TextRange, TextSize};
3
+
4
+ use yaml_parser::ast::{BlockMap, BlockMapEntry};
5
+ use yaml_parser::{SyntaxKind, SyntaxNode, SyntaxToken};
6
+
7
+ pub fn is_map_key(token: &SyntaxToken) -> bool {
8
+ token
9
+ .parent_ancestors()
10
+ .any(|ancestor| ancestor.kind() == SyntaxKind::BLOCK_MAP_KEY)
11
+ }
12
+
13
+ pub fn find_entry_by_key(map: &BlockMap, key: &str) -> Option<BlockMapEntry> {
14
+ map.entries().find(|entry| {
15
+ entry
16
+ .key()
17
+ .and_then(|key_node| extract_scalar_text(key_node.syntax()))
18
+ .map(|key_text| key_text == key)
19
+ .unwrap_or(false)
20
+ })
21
+ }
22
+
23
+ pub fn find_scalar_token(node: &SyntaxNode) -> Option<SyntaxToken> {
24
+ node
25
+ .descendants_with_tokens()
26
+ .filter_map(|element| element.into_token())
27
+ .find(|token| {
28
+ matches!(
29
+ token.kind(),
30
+ SyntaxKind::PLAIN_SCALAR | SyntaxKind::DOUBLE_QUOTED_SCALAR | SyntaxKind::SINGLE_QUOTED_SCALAR
31
+ )
32
+ })
33
+ }
34
+
35
+ pub fn format_scalar_value(value: &str, kind: SyntaxKind) -> String {
36
+ match kind {
37
+ SyntaxKind::DOUBLE_QUOTED_SCALAR => {
38
+ let escaped = value.replace('\\', "\\\\").replace('"', "\\\"");
39
+ format!("\"{}\"", escaped)
40
+ }
41
+
42
+ SyntaxKind::SINGLE_QUOTED_SCALAR => {
43
+ let escaped = value.replace('\'', "''");
44
+ format!("'{}'", escaped)
45
+ }
46
+
47
+ _ => value.to_string(),
48
+ }
49
+ }
50
+
51
+ pub fn extract_scalar_text(node: &SyntaxNode) -> Option<String> {
52
+ let token = find_scalar_token(node)?;
53
+
54
+ match token.kind() {
55
+ SyntaxKind::PLAIN_SCALAR => Some(token.text().to_string()),
56
+
57
+ SyntaxKind::DOUBLE_QUOTED_SCALAR => {
58
+ let text = token.text();
59
+ let inner = &text[1..text.len() - 1];
60
+
61
+ Some(unescape_double_quoted(inner))
62
+ }
63
+
64
+ SyntaxKind::SINGLE_QUOTED_SCALAR => {
65
+ let text = token.text();
66
+ let inner = &text[1..text.len() - 1];
67
+
68
+ Some(unescape_single_quoted(inner))
69
+ }
70
+
71
+ _ => None,
72
+ }
73
+ }
74
+
75
+ pub fn unescape_double_quoted(text: &str) -> String {
76
+ text.replace("\\\"", "\"").replace("\\\\", "\\")
77
+ }
78
+
79
+ pub fn unescape_single_quoted(text: &str) -> String {
80
+ text.replace("''", "'")
81
+ }
82
+
83
+ pub fn preceding_whitespace_indent(node: &SyntaxNode) -> String {
84
+ if let Some(token) = preceding_whitespace_token(node) {
85
+ let text = token.text();
86
+
87
+ if let Some(newline) = text.rfind('\n') {
88
+ return text[newline + 1..].to_string();
89
+ }
90
+ }
91
+
92
+ let start_offset: usize = node.text_range().start().into();
93
+ let root = node.ancestors().last().unwrap_or_else(|| node.clone());
94
+ let source = root.text().to_string();
95
+
96
+ if start_offset > 0 {
97
+ let before = &source[..start_offset];
98
+
99
+ if let Some(newline_position) = before.rfind('\n') {
100
+ return before[newline_position + 1..].to_string();
101
+ }
102
+ }
103
+
104
+ String::new()
105
+ }
106
+
107
+ pub fn preceding_whitespace_token(node: &SyntaxNode) -> Option<SyntaxToken> {
108
+ node
109
+ .prev_sibling_or_token()
110
+ .and_then(|sibling| sibling.into_token())
111
+ .filter(|token| token.kind() == SyntaxKind::WHITESPACE)
112
+ }
113
+
114
+ pub fn following_whitespace_token(node: &SyntaxNode) -> Option<SyntaxToken> {
115
+ node
116
+ .next_sibling_or_token()
117
+ .and_then(|sibling| sibling.into_token())
118
+ .filter(|token| token.kind() == SyntaxKind::WHITESPACE)
119
+ }
120
+
121
+ pub fn removal_range(node: &SyntaxNode) -> TextRange {
122
+ let node_range = node.text_range();
123
+
124
+ if let Some(whitespace_token) = preceding_whitespace_token(node) {
125
+ let whitespace_text = whitespace_token.text();
126
+ let whitespace_start = whitespace_token.text_range().start();
127
+
128
+ let remove_from = whitespace_text
129
+ .rfind('\n')
130
+ .map(|offset| whitespace_start + TextSize::from(offset as u32))
131
+ .unwrap_or(whitespace_start);
132
+
133
+ return TextRange::new(remove_from, node_range.end());
134
+ }
135
+
136
+ if let Some(whitespace_token) = following_whitespace_token(node) {
137
+ return TextRange::new(node_range.start(), whitespace_token.text_range().end());
138
+ }
139
+
140
+ node_range
141
+ }
142
+
143
+ pub fn is_yaml_non_string(value: &str) -> bool {
144
+ // Null (YAML 1.1 + 1.2)
145
+ if matches!(value, "null" | "Null" | "NULL" | "~" | "") {
146
+ return true;
147
+ }
148
+
149
+ // Boolean (YAML 1.2)
150
+ if matches!(value, "true" | "True" | "TRUE" | "false" | "False" | "FALSE") {
151
+ return true;
152
+ }
153
+
154
+ // Boolean (YAML 1.1 extras)
155
+ if matches!(
156
+ value,
157
+ "yes" | "Yes" | "YES" | "no" | "No" | "NO" | "on" | "On" | "ON" | "off" | "Off" | "OFF" | "y" | "Y" | "n" | "N"
158
+ ) {
159
+ return true;
160
+ }
161
+
162
+ // Special floats (YAML 1.1 + 1.2)
163
+ if matches!(
164
+ value,
165
+ ".inf" | ".Inf" | ".INF" | "-.inf" | "-.Inf" | "-.INF" | "+.inf" | "+.Inf" | "+.INF" | ".nan" | ".NaN" | ".NAN"
166
+ ) {
167
+ return true;
168
+ }
169
+
170
+ // Integer
171
+ if value.parse::<i64>().is_ok() {
172
+ return true;
173
+ }
174
+
175
+ // Octal (0o...) and hex (0x...)
176
+ if value.starts_with("0x") || value.starts_with("0X") || value.starts_with("0o") || value.starts_with("0O") {
177
+ return true;
178
+ }
179
+
180
+ // Float
181
+ if value.parse::<f64>().is_ok() {
182
+ return true;
183
+ }
184
+
185
+ false
186
+ }