yerba 0.3.0-aarch64-linux-gnu → 0.4.1-aarch64-linux-gnu

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +93 -8
  3. data/exe/aarch64-linux-gnu/yerba +0 -0
  4. data/ext/yerba/extconf.rb +22 -3
  5. data/ext/yerba/include/yerba.h +32 -9
  6. data/ext/yerba/yerba.c +133 -25
  7. data/lib/yerba/3.2/yerba.so +0 -0
  8. data/lib/yerba/3.3/yerba.so +0 -0
  9. data/lib/yerba/3.4/yerba.so +0 -0
  10. data/lib/yerba/4.0/yerba.so +0 -0
  11. data/lib/yerba/collection.rb +35 -0
  12. data/lib/yerba/document.rb +45 -3
  13. data/lib/yerba/query_result.rb +50 -0
  14. data/lib/yerba/sequence.rb +187 -1
  15. data/lib/yerba/version.rb +1 -1
  16. data/lib/yerba/yerbafile.rb +45 -0
  17. data/lib/yerba.rb +2 -0
  18. data/rust/Cargo.lock +3 -1
  19. data/rust/Cargo.toml +3 -2
  20. data/rust/cbindgen.toml +1 -0
  21. data/rust/rustfmt.toml +1 -1
  22. data/rust/src/commands/apply.rs +11 -2
  23. data/rust/src/commands/blank_lines.rs +1 -4
  24. data/rust/src/commands/check.rs +11 -2
  25. data/rust/src/commands/directives.rs +61 -0
  26. data/rust/src/commands/get.rs +5 -22
  27. data/rust/src/commands/mod.rs +16 -18
  28. data/rust/src/commands/quote_style.rs +12 -6
  29. data/rust/src/commands/selectors.rs +3 -19
  30. data/rust/src/commands/sort.rs +22 -157
  31. data/rust/src/didyoumean.rs +2 -4
  32. data/rust/src/document/condition.rs +139 -0
  33. data/rust/src/document/delete.rs +91 -0
  34. data/rust/src/document/get.rs +262 -0
  35. data/rust/src/document/insert.rs +384 -0
  36. data/rust/src/document/mod.rs +784 -0
  37. data/rust/src/document/set.rs +100 -0
  38. data/rust/src/document/sort.rs +639 -0
  39. data/rust/src/document/style.rs +473 -0
  40. data/rust/src/error.rs +24 -6
  41. data/rust/src/ffi.rs +272 -518
  42. data/rust/src/json.rs +1 -7
  43. data/rust/src/lib.rs +88 -2
  44. data/rust/src/main.rs +2 -0
  45. data/rust/src/quote_style.rs +83 -7
  46. data/rust/src/selector.rs +2 -7
  47. data/rust/src/syntax.rs +41 -21
  48. data/rust/src/yerbafile.rs +86 -19
  49. metadata +13 -3
  50. data/rust/src/document.rs +0 -2304
@@ -0,0 +1,384 @@
1
+ use super::*;
2
+
3
+ impl Document {
4
+ pub fn append(&mut self, dot_path: &str, value: &str) -> Result<(), YerbaError> {
5
+ self.insert_into(dot_path, value, InsertPosition::Last)
6
+ }
7
+
8
+ pub fn detect_sequence_quote_style(&self, dot_path: &str) -> QuoteStyle {
9
+ let try_paths = if dot_path.is_empty() {
10
+ vec!["[]".to_string(), "[0]".to_string()]
11
+ } else {
12
+ vec![format!("{}[]", dot_path), format!("{}[0]", dot_path)]
13
+ };
14
+
15
+ for try_path in &try_paths {
16
+ for scalar in self.get_all_typed(try_path) {
17
+ if scalar.kind == SyntaxKind::DOUBLE_QUOTED_SCALAR {
18
+ return QuoteStyle::Double;
19
+ } else if scalar.kind == SyntaxKind::SINGLE_QUOTED_SCALAR {
20
+ return QuoteStyle::Single;
21
+ }
22
+ }
23
+ }
24
+
25
+ if let Some(serde_yaml::Value::Sequence(sequence)) = self.get_value(dot_path).as_ref() {
26
+ if let Some(serde_yaml::Value::Mapping(map)) = sequence.first() {
27
+ if let Some((serde_yaml::Value::String(key_name), _)) = map.iter().next() {
28
+ let deep_path = if dot_path.is_empty() {
29
+ format!("[].{}", key_name)
30
+ } else {
31
+ format!("{}[].{}", dot_path, key_name)
32
+ };
33
+
34
+ for scalar in self.get_all_typed(&deep_path) {
35
+ if scalar.kind == SyntaxKind::DOUBLE_QUOTED_SCALAR {
36
+ return QuoteStyle::Double;
37
+ } else if scalar.kind == SyntaxKind::SINGLE_QUOTED_SCALAR {
38
+ return QuoteStyle::Single;
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+ QuoteStyle::Plain
46
+ }
47
+
48
+ pub fn insert_object(&mut self, dot_path: &str, json_value: &serde_json::Value, position: InsertPosition) -> Result<(), YerbaError> {
49
+ let quote_style = self.detect_sequence_quote_style(dot_path);
50
+ let yaml_text = crate::yaml_writer::json_to_yaml_text(json_value, &quote_style, 0);
51
+
52
+ self.insert_into(dot_path, &yaml_text, position)
53
+ }
54
+
55
+ pub fn insert_objects(&mut self, dot_path: &str, json_values: &[serde_json::Value]) -> Result<(), YerbaError> {
56
+ if json_values.is_empty() {
57
+ return Ok(());
58
+ }
59
+
60
+ let quote_style = self.detect_sequence_quote_style(dot_path);
61
+ let current_node = self.navigate(dot_path)?;
62
+
63
+ let sequence = current_node
64
+ .descendants()
65
+ .find_map(BlockSeq::cast)
66
+ .ok_or_else(|| YerbaError::NotASequence(dot_path.to_string()))?;
67
+
68
+ let entries: Vec<_> = sequence.entries().collect();
69
+
70
+ if entries.is_empty() {
71
+ return Err(YerbaError::SelectorNotFound(dot_path.to_string()));
72
+ }
73
+
74
+ let indent = entries
75
+ .get(1)
76
+ .or(entries.first())
77
+ .map(|entry| preceding_whitespace_indent(entry.syntax()))
78
+ .unwrap_or_default();
79
+
80
+ let mut new_text = String::new();
81
+
82
+ for json_value in json_values {
83
+ let yaml_text = crate::yaml_writer::json_to_yaml_text(json_value, &quote_style, 0);
84
+
85
+ let new_item = if yaml_text.contains('\n') {
86
+ let item_indent = format!("{} ", indent);
87
+ let lines: Vec<&str> = yaml_text.split('\n').collect();
88
+
89
+ let min_indent = lines
90
+ .iter()
91
+ .skip(1)
92
+ .filter(|line| !line.trim().is_empty())
93
+ .map(|line| line.len() - line.trim_start().len())
94
+ .min()
95
+ .unwrap_or(0);
96
+
97
+ let indented: Vec<String> = lines
98
+ .iter()
99
+ .enumerate()
100
+ .map(|(index, line)| {
101
+ if index == 0 {
102
+ line.to_string()
103
+ } else if line.trim().is_empty() {
104
+ String::new()
105
+ } else {
106
+ let relative = &line[min_indent..];
107
+ format!("{}{}", item_indent, relative)
108
+ }
109
+ })
110
+ .collect();
111
+
112
+ format!("- {}", indented.join("\n"))
113
+ } else {
114
+ format!("- {}", yaml_text)
115
+ };
116
+
117
+ new_text.push_str(&format!("\n{}{}", indent, new_item));
118
+ }
119
+
120
+ let last_entry = entries.last().unwrap();
121
+
122
+ self.insert_after_node(last_entry.syntax(), &new_text)
123
+ }
124
+
125
+ pub fn insert_into(&mut self, dot_path: &str, value: &str, position: InsertPosition) -> Result<(), YerbaError> {
126
+ Self::validate_path(dot_path)?;
127
+
128
+ if let Ok(current_node) = self.navigate(dot_path) {
129
+ if current_node.descendants().find_map(BlockSeq::cast).is_some() {
130
+ return self.insert_sequence_item(dot_path, value, position);
131
+ }
132
+ }
133
+
134
+ let (parent_path, key) = dot_path.rsplit_once('.').unwrap_or(("", dot_path));
135
+
136
+ self.insert_map_key(parent_path, key, value, position)
137
+ }
138
+
139
+ fn insert_sequence_item(&mut self, dot_path: &str, value: &str, position: InsertPosition) -> Result<(), YerbaError> {
140
+ let current_node = self.navigate(dot_path)?;
141
+
142
+ let sequence = current_node
143
+ .descendants()
144
+ .find_map(BlockSeq::cast)
145
+ .ok_or_else(|| YerbaError::NotASequence(dot_path.to_string()))?;
146
+
147
+ let entries: Vec<_> = sequence.entries().collect();
148
+
149
+ if entries.is_empty() {
150
+ return Err(YerbaError::SelectorNotFound(dot_path.to_string()));
151
+ }
152
+
153
+ let indent = entries
154
+ .get(1)
155
+ .or(entries.first())
156
+ .map(|entry| preceding_whitespace_indent(entry.syntax()))
157
+ .unwrap_or_default();
158
+
159
+ let new_item = if value.contains('\n') {
160
+ let item_indent = format!("{} ", indent);
161
+ let lines: Vec<&str> = value.split('\n').collect();
162
+
163
+ let min_indent = lines
164
+ .iter()
165
+ .skip(1)
166
+ .filter(|line| !line.trim().is_empty())
167
+ .map(|line| line.len() - line.trim_start().len())
168
+ .min()
169
+ .unwrap_or(0);
170
+
171
+ let indented: Vec<String> = lines
172
+ .iter()
173
+ .enumerate()
174
+ .map(|(index, line)| {
175
+ if index == 0 {
176
+ line.to_string()
177
+ } else if line.trim().is_empty() {
178
+ String::new()
179
+ } else {
180
+ let relative = &line[min_indent..];
181
+ format!("{}{}", item_indent, relative)
182
+ }
183
+ })
184
+ .collect();
185
+
186
+ format!("- {}", indented.join("\n"))
187
+ } else {
188
+ format!("- {}", value)
189
+ };
190
+
191
+ match position {
192
+ InsertPosition::Last => {
193
+ let last_entry = entries.last().unwrap();
194
+ let new_text = format!("\n{}{}", indent, new_item);
195
+
196
+ self.insert_after_node(last_entry.syntax(), &new_text)
197
+ }
198
+
199
+ InsertPosition::At(index) => {
200
+ if index >= entries.len() {
201
+ let last_entry = entries.last().unwrap();
202
+ let new_text = format!("\n{}{}", indent, new_item);
203
+
204
+ self.insert_after_node(last_entry.syntax(), &new_text)
205
+ } else {
206
+ let target_entry = &entries[index];
207
+ let target_range = target_entry.syntax().text_range();
208
+ let replacement = format!("{}\n{}", new_item, indent);
209
+ let insert_range = TextRange::new(target_range.start(), target_range.start());
210
+
211
+ self.apply_edit(insert_range, &replacement)
212
+ }
213
+ }
214
+
215
+ InsertPosition::Before(target_value) => {
216
+ let target_entry = entries
217
+ .iter()
218
+ .find(|entry| {
219
+ entry
220
+ .flow()
221
+ .and_then(|flow| extract_scalar_text(flow.syntax()))
222
+ .map(|text| text == target_value)
223
+ .unwrap_or(false)
224
+ })
225
+ .ok_or_else(|| YerbaError::SelectorNotFound(format!("{} item '{}'", dot_path, target_value)))?;
226
+
227
+ let target_range = target_entry.syntax().text_range();
228
+ let replacement = format!("{}\n{}", new_item, indent);
229
+ let insert_range = TextRange::new(target_range.start(), target_range.start());
230
+
231
+ self.apply_edit(insert_range, &replacement)
232
+ }
233
+
234
+ InsertPosition::After(target_value) => {
235
+ let target_entry = entries
236
+ .iter()
237
+ .find(|entry| {
238
+ entry
239
+ .flow()
240
+ .and_then(|flow| extract_scalar_text(flow.syntax()))
241
+ .map(|text| text == target_value)
242
+ .unwrap_or(false)
243
+ })
244
+ .ok_or_else(|| YerbaError::SelectorNotFound(format!("{} item '{}'", dot_path, target_value)))?;
245
+
246
+ let new_text = format!("\n{}{}", indent, new_item);
247
+
248
+ self.insert_after_node(target_entry.syntax(), &new_text)
249
+ }
250
+
251
+ InsertPosition::BeforeCondition(condition) => {
252
+ let target_entry = entries
253
+ .iter()
254
+ .find(|entry| self.evaluate_condition_on_node(entry.syntax(), &condition))
255
+ .ok_or_else(|| YerbaError::SelectorNotFound(format!("{} condition '{}'", dot_path, condition)))?;
256
+
257
+ let target_range = target_entry.syntax().text_range();
258
+ let replacement = format!("{}\n{}", new_item, indent);
259
+ let insert_range = TextRange::new(target_range.start(), target_range.start());
260
+
261
+ self.apply_edit(insert_range, &replacement)
262
+ }
263
+
264
+ InsertPosition::AfterCondition(condition) => {
265
+ let target_entry = entries
266
+ .iter()
267
+ .find(|entry| self.evaluate_condition_on_node(entry.syntax(), &condition))
268
+ .ok_or_else(|| YerbaError::SelectorNotFound(format!("{} condition '{}'", dot_path, condition)))?;
269
+
270
+ let new_text = format!("\n{}{}", indent, new_item);
271
+
272
+ self.insert_after_node(target_entry.syntax(), &new_text)
273
+ }
274
+
275
+ InsertPosition::FromSortOrder(_) => {
276
+ let last_entry = entries.last().unwrap();
277
+ let new_text = format!("\n{}{}", indent, new_item);
278
+
279
+ self.insert_after_node(last_entry.syntax(), &new_text)
280
+ }
281
+ }
282
+ }
283
+
284
+ fn insert_map_key(&mut self, dot_path: &str, key: &str, value: &str, position: InsertPosition) -> Result<(), YerbaError> {
285
+ let current_node = self.navigate(dot_path)?;
286
+
287
+ let map = current_node
288
+ .descendants()
289
+ .find_map(BlockMap::cast)
290
+ .ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
291
+
292
+ let entries: Vec<_> = map.entries().collect();
293
+
294
+ if entries.is_empty() {
295
+ let indent = preceding_whitespace_indent(map.syntax());
296
+ let new_entry = format!("\n{}{}: {}", indent, key, value);
297
+
298
+ return self.insert_after_node(map.syntax(), &new_entry);
299
+ }
300
+
301
+ if find_entry_by_key(&map, key).is_some() {
302
+ return Err(YerbaError::ParseError(format!("key '{}' already exists at '{}'", key, dot_path)));
303
+ }
304
+
305
+ let indent = entries
306
+ .get(1)
307
+ .or(entries.first())
308
+ .map(|entry| preceding_whitespace_indent(entry.syntax()))
309
+ .unwrap_or_default();
310
+
311
+ let new_entry_text = format!("{}: {}", key, value);
312
+
313
+ match position {
314
+ InsertPosition::Last => {
315
+ let last_entry = entries.last().unwrap();
316
+ let new_text = format!("\n{}{}", indent, new_entry_text);
317
+
318
+ self.insert_after_node(last_entry.syntax(), &new_text)
319
+ }
320
+
321
+ InsertPosition::At(index) => {
322
+ if index >= entries.len() {
323
+ let last_entry = entries.last().unwrap();
324
+ let new_text = format!("\n{}{}", indent, new_entry_text);
325
+
326
+ self.insert_after_node(last_entry.syntax(), &new_text)
327
+ } else {
328
+ let target_entry = &entries[index];
329
+ let target_range = target_entry.syntax().text_range();
330
+ let replacement = format!("{}\n{}", new_entry_text, indent);
331
+ let insert_range = TextRange::new(target_range.start(), target_range.start());
332
+
333
+ self.apply_edit(insert_range, &replacement)
334
+ }
335
+ }
336
+
337
+ InsertPosition::Before(target_key) => {
338
+ let target_entry = find_entry_by_key(&map, &target_key).ok_or_else(|| YerbaError::SelectorNotFound(format!("{}.{}", dot_path, target_key)))?;
339
+
340
+ let target_range = target_entry.syntax().text_range();
341
+ let replacement = format!("{}\n{}", new_entry_text, indent);
342
+ let insert_range = TextRange::new(target_range.start(), target_range.start());
343
+
344
+ self.apply_edit(insert_range, &replacement)
345
+ }
346
+
347
+ InsertPosition::After(target_key) => {
348
+ let target_entry = find_entry_by_key(&map, &target_key).ok_or_else(|| YerbaError::SelectorNotFound(format!("{}.{}", dot_path, target_key)))?;
349
+
350
+ let new_text = format!("\n{}{}", indent, new_entry_text);
351
+
352
+ self.insert_after_node(target_entry.syntax(), &new_text)
353
+ }
354
+
355
+ InsertPosition::BeforeCondition(_) | InsertPosition::AfterCondition(_) => self.insert_map_key(dot_path, key, value, InsertPosition::Last),
356
+
357
+ InsertPosition::FromSortOrder(order) => {
358
+ let new_key_position = order.iter().position(|ordered_key| ordered_key == key);
359
+
360
+ let resolved = match new_key_position {
361
+ Some(new_position) => {
362
+ let mut insert_after: Option<String> = None;
363
+
364
+ for ordered_key in order.iter().take(new_position).rev() {
365
+ if find_entry_by_key(&map, ordered_key).is_some() {
366
+ insert_after = Some(ordered_key.clone());
367
+ break;
368
+ }
369
+ }
370
+
371
+ match insert_after {
372
+ Some(after_key) => InsertPosition::After(after_key),
373
+ None => InsertPosition::At(0),
374
+ }
375
+ }
376
+
377
+ None => InsertPosition::Last,
378
+ };
379
+
380
+ self.insert_map_key(dot_path, key, value, resolved)
381
+ }
382
+ }
383
+ }
384
+ }