yerba 0.3.0-arm-linux-gnu → 0.4.0-arm-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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +90 -8
  3. data/exe/arm-linux-gnu/yerba +0 -0
  4. data/ext/yerba/extconf.rb +22 -3
  5. data/ext/yerba/include/yerba.h +19 -9
  6. data/ext/yerba/yerba.c +83 -24
  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 +16 -0
  13. data/lib/yerba/sequence.rb +169 -1
  14. data/lib/yerba/version.rb +1 -1
  15. data/rust/Cargo.lock +1 -1
  16. data/rust/Cargo.toml +1 -1
  17. data/rust/cbindgen.toml +1 -0
  18. data/rust/rustfmt.toml +1 -1
  19. data/rust/src/commands/blank_lines.rs +1 -4
  20. data/rust/src/commands/directives.rs +61 -0
  21. data/rust/src/commands/get.rs +5 -22
  22. data/rust/src/commands/mod.rs +5 -10
  23. data/rust/src/commands/quote_style.rs +12 -6
  24. data/rust/src/commands/selectors.rs +3 -19
  25. data/rust/src/commands/sort.rs +22 -157
  26. data/rust/src/didyoumean.rs +2 -4
  27. data/rust/src/document/condition.rs +139 -0
  28. data/rust/src/document/delete.rs +91 -0
  29. data/rust/src/document/get.rs +262 -0
  30. data/rust/src/document/insert.rs +314 -0
  31. data/rust/src/document/mod.rs +784 -0
  32. data/rust/src/document/set.rs +90 -0
  33. data/rust/src/document/sort.rs +607 -0
  34. data/rust/src/document/style.rs +473 -0
  35. data/rust/src/error.rs +24 -6
  36. data/rust/src/ffi.rs +208 -520
  37. data/rust/src/json.rs +1 -7
  38. data/rust/src/lib.rs +88 -2
  39. data/rust/src/quote_style.rs +83 -7
  40. data/rust/src/selector.rs +2 -7
  41. data/rust/src/syntax.rs +41 -21
  42. data/rust/src/yerbafile.rs +39 -18
  43. metadata +10 -2
  44. data/rust/src/document.rs +0 -2304
data/rust/src/ffi.rs CHANGED
@@ -12,10 +12,8 @@ use std::ffi::{CStr, CString};
12
12
  use std::os::raw::c_char;
13
13
  use std::ptr;
14
14
 
15
- use yaml_parser::SyntaxKind;
16
-
17
- use crate::selector::Selector;
18
15
  use crate::syntax::{detect_yaml_type, YerbaValueType};
16
+ use crate::NodeType;
19
17
  use crate::{Document, InsertPosition, QuoteStyle};
20
18
 
21
19
  #[repr(C)]
@@ -52,15 +50,6 @@ pub struct YerbaTypedList {
52
50
  pub length: usize,
53
51
  }
54
52
 
55
- #[repr(C)]
56
- #[derive(Debug, Clone, Copy, PartialEq)]
57
- pub enum YerbaNodeType {
58
- Scalar = 0,
59
- Map = 1,
60
- Sequence = 2,
61
- NotFound = 3,
62
- }
63
-
64
53
  #[repr(C)]
65
54
  pub struct YerbaParseResult {
66
55
  pub document: *mut Document,
@@ -80,7 +69,7 @@ pub struct YerbaLocation {
80
69
  #[repr(C)]
81
70
  pub struct YerbaGetResult {
82
71
  pub is_list: bool,
83
- pub node_type: YerbaNodeType,
72
+ pub node_type: NodeType,
84
73
  pub single: YerbaTypedValue,
85
74
  pub list: YerbaTypedList,
86
75
  pub location: YerbaLocation,
@@ -89,6 +78,72 @@ pub struct YerbaGetResult {
89
78
  pub error: *mut c_char,
90
79
  }
91
80
 
81
+ impl YerbaGetResult {
82
+ fn empty() -> Self {
83
+ YerbaGetResult {
84
+ is_list: false,
85
+ node_type: NodeType::NotFound,
86
+ single: YerbaTypedValue {
87
+ text: ptr::null_mut(),
88
+ value_type: YerbaValueType::Null,
89
+ },
90
+ list: YerbaTypedList {
91
+ json: ptr::null_mut(),
92
+ length: 0,
93
+ },
94
+ location: EMPTY_LOCATION,
95
+ key_name: ptr::null_mut(),
96
+ key_location: EMPTY_LOCATION,
97
+ error: ptr::null_mut(),
98
+ }
99
+ }
100
+
101
+ fn with_error(error: &str) -> Self {
102
+ let mut result = Self::empty();
103
+
104
+ result.error = CString::new(error).unwrap_or_default().into_raw();
105
+
106
+ result
107
+ }
108
+
109
+ fn with_location(mut self, location: YerbaLocation, key_name: *mut c_char, key_location: YerbaLocation) -> Self {
110
+ self.location = location;
111
+ self.key_name = key_name;
112
+ self.key_location = key_location;
113
+
114
+ self
115
+ }
116
+
117
+ fn scalar(mut self, text: &str, value_type: YerbaValueType) -> Self {
118
+ self.node_type = NodeType::Scalar;
119
+
120
+ self.single = YerbaTypedValue {
121
+ text: CString::new(text).unwrap_or_default().into_raw(),
122
+ value_type,
123
+ };
124
+
125
+ self
126
+ }
127
+
128
+ fn list(mut self, json: &str, length: usize) -> Self {
129
+ self.is_list = true;
130
+ self.node_type = NodeType::Sequence;
131
+
132
+ self.list = YerbaTypedList {
133
+ json: CString::new(json).unwrap_or_default().into_raw(),
134
+ length,
135
+ };
136
+
137
+ self
138
+ }
139
+
140
+ fn with_node_type(mut self, node_type: NodeType) -> Self {
141
+ self.node_type = node_type;
142
+
143
+ self
144
+ }
145
+ }
146
+
92
147
  #[no_mangle]
93
148
  pub unsafe extern "C" fn yerba_document_parse_file(path: *const c_char) -> YerbaParseResult {
94
149
  if path.is_null() {
@@ -98,19 +153,17 @@ pub unsafe extern "C" fn yerba_document_parse_file(path: *const c_char) -> Yerba
98
153
  };
99
154
  }
100
155
 
101
- let path_string = match CStr::from_ptr(path).to_str() {
156
+ let file_path = match CStr::from_ptr(path).to_str() {
102
157
  Ok(string) => string,
103
158
  Err(e) => {
104
159
  return YerbaParseResult {
105
160
  document: ptr::null_mut(),
106
- error: CString::new(format!("Invalid UTF-8 in path: {}", e))
107
- .unwrap_or_default()
108
- .into_raw(),
161
+ error: CString::new(format!("Invalid UTF-8 in path: {}", e)).unwrap_or_default().into_raw(),
109
162
  }
110
163
  }
111
164
  };
112
165
 
113
- match Document::parse_file(path_string) {
166
+ match Document::parse_file(file_path) {
114
167
  Ok(document) => YerbaParseResult {
115
168
  document: Box::into_raw(Box::new(document)),
116
169
  error: ptr::null_mut(),
@@ -137,9 +190,7 @@ pub unsafe extern "C" fn yerba_document_parse(content: *const c_char) -> YerbaPa
137
190
  Err(e) => {
138
191
  return YerbaParseResult {
139
192
  document: ptr::null_mut(),
140
- error: CString::new(format!("Invalid UTF-8: {}", e))
141
- .unwrap_or_default()
142
- .into_raw(),
193
+ error: CString::new(format!("Invalid UTF-8: {}", e)).unwrap_or_default().into_raw(),
143
194
  }
144
195
  }
145
196
  };
@@ -157,28 +208,6 @@ pub unsafe extern "C" fn yerba_document_parse(content: *const c_char) -> YerbaPa
157
208
  }
158
209
  }
159
210
 
160
- fn compute_location(source: &str, start_offset: usize, end_offset: usize) -> YerbaLocation {
161
- let start = start_offset.min(source.len());
162
- let end = end_offset.min(source.len());
163
-
164
- let before_start = &source[..start];
165
- let start_line = before_start.chars().filter(|c| *c == '\n').count() + 1;
166
- let start_column = start - before_start.rfind('\n').map(|p| p + 1).unwrap_or(0);
167
-
168
- let before_end = &source[..end];
169
- let end_line = before_end.chars().filter(|c| *c == '\n').count() + 1;
170
- let end_column = end - before_end.rfind('\n').map(|p| p + 1).unwrap_or(0);
171
-
172
- YerbaLocation {
173
- start_offset: start,
174
- end_offset: end,
175
- start_line,
176
- start_column,
177
- end_line,
178
- end_column,
179
- }
180
- }
181
-
182
211
  const EMPTY_LOCATION: YerbaLocation = YerbaLocation {
183
212
  start_offset: 0,
184
213
  end_offset: 0,
@@ -198,173 +227,71 @@ pub unsafe extern "C" fn yerba_document_free(document: *mut Document) {
198
227
  #[no_mangle]
199
228
  pub unsafe extern "C" fn yerba_document_get(document: *const Document, path: *const c_char) -> YerbaGetResult {
200
229
  let document = &*document;
201
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
230
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
202
231
 
203
- let selector = Selector::parse(path_string);
204
-
205
- if let Err(e) = Document::validate_path(path_string) {
206
- return YerbaGetResult {
207
- is_list: false,
208
- node_type: YerbaNodeType::NotFound,
209
- single: YerbaTypedValue {
210
- text: ptr::null_mut(),
211
- value_type: YerbaValueType::Null,
212
- },
213
- list: YerbaTypedList {
214
- json: ptr::null_mut(),
215
- length: 0,
216
- },
217
- key_name: ptr::null_mut(),
218
- key_location: EMPTY_LOCATION,
219
- location: EMPTY_LOCATION,
220
- error: CString::new(e.to_string()).unwrap_or_default().into_raw(),
221
- };
232
+ if let Err(e) = Document::validate_path(selector_string) {
233
+ return YerbaGetResult::with_error(&e.to_string());
222
234
  }
223
235
 
224
- let source = document.to_string();
225
-
226
- let (location, key_text, key_location) = match document.navigate(path_string) {
227
- Ok(node) => {
228
- let range = node.text_range();
229
- let location = compute_location(&source, range.start().into(), range.end().into());
236
+ let info = document.get_node_info(selector_string);
237
+ let location = location_to_ffi(info.location);
238
+ let key_location = location_to_ffi(info.key_location);
230
239
 
231
- let (key_text, key_location) = node
232
- .parent()
233
- .and_then(|parent| {
234
- use rowan::ast::AstNode;
235
- use yaml_parser::ast::BlockMapEntry;
236
-
237
- BlockMapEntry::cast(parent).and_then(|entry| {
238
- entry.key().and_then(|key_node| {
239
- let key_text = crate::syntax::extract_scalar_text(key_node.syntax())?;
240
- let key_range = key_node.syntax().text_range();
241
- let key_location = compute_location(&source, key_range.start().into(), key_range.end().into());
242
-
243
- Some((key_text, key_location))
244
- })
245
- })
246
- })
247
- .map(|(name, location)| (Some(name), location))
248
- .unwrap_or((None, EMPTY_LOCATION));
249
-
250
- (location, key_text, key_location)
251
- }
252
- Err(_) => (EMPTY_LOCATION, None, EMPTY_LOCATION),
253
- };
254
-
255
- let key_name_pointer = key_text
240
+ let key_name = info
241
+ .key_name
256
242
  .map(|name| CString::new(name).unwrap_or_default().into_raw())
257
243
  .unwrap_or(ptr::null_mut());
258
244
 
259
- if selector.has_wildcard() {
260
- let values = document.get_all_typed(path_string);
245
+ let base = YerbaGetResult::empty().with_location(location, key_name, key_location);
261
246
 
262
- let typed: Vec<serde_json::Value> = values
247
+ if info.is_list {
248
+ let typed: Vec<serde_json::Value> = info
249
+ .list_values
263
250
  .iter()
264
- .map(|serde_value| {
251
+ .map(|value| {
265
252
  serde_json::json!({
266
- "text": serde_value.text,
267
- "type": detect_yaml_type(serde_value) as u8
253
+ "text": value.text,
254
+ "type": detect_yaml_type(value) as u8
268
255
  })
269
256
  })
270
257
  .collect();
271
258
 
272
259
  let json = serde_json::to_string(&typed).unwrap_or_else(|_| "[]".to_string());
273
- let length = values.len();
274
260
 
275
- YerbaGetResult {
276
- is_list: true,
277
- node_type: YerbaNodeType::Sequence,
278
- single: YerbaTypedValue {
279
- text: ptr::null_mut(),
280
- value_type: YerbaValueType::Null,
281
- },
282
- list: YerbaTypedList {
283
- json: CString::new(json).unwrap_or_default().into_raw(),
284
- length,
285
- },
286
- location,
287
- key_name: key_name_pointer,
288
- key_location,
289
- error: ptr::null_mut(),
290
- }
261
+ base.list(&json, info.list_values.len())
291
262
  } else {
292
- match document.get_typed(path_string) {
293
- Some(scalar) => {
294
- let vtype = detect_yaml_type(&scalar);
295
-
296
- YerbaGetResult {
297
- is_list: false,
298
- node_type: YerbaNodeType::Scalar,
299
- single: YerbaTypedValue {
300
- text: CString::new(scalar.text).unwrap_or_default().into_raw(),
301
- value_type: vtype,
302
- },
303
- list: YerbaTypedList {
304
- json: ptr::null_mut(),
305
- length: 0,
306
- },
307
- location,
308
- key_name: key_name_pointer,
309
- key_location,
310
- error: ptr::null_mut(),
311
- }
312
- }
313
-
314
- None => {
315
- use rowan::ast::AstNode;
316
- use yaml_parser::ast::{BlockMap, BlockSeq};
317
-
318
- let node_type = match document.navigate(path_string) {
319
- Ok(node) => {
320
- if node.children().any(|child| BlockSeq::can_cast(child.kind())) {
321
- YerbaNodeType::Sequence
322
- } else if node.children().any(|child| BlockMap::can_cast(child.kind())) {
323
- YerbaNodeType::Map
324
- } else if node.descendants().any(|child| BlockSeq::can_cast(child.kind())) {
325
- YerbaNodeType::Sequence
326
- } else if node.descendants().any(|child| BlockMap::can_cast(child.kind())) {
327
- YerbaNodeType::Map
328
- } else {
329
- YerbaNodeType::NotFound
330
- }
331
- }
332
- Err(_) => YerbaNodeType::NotFound,
333
- };
334
-
335
- YerbaGetResult {
336
- is_list: false,
337
- node_type,
338
- single: YerbaTypedValue {
339
- text: ptr::null_mut(),
340
- value_type: YerbaValueType::Null,
341
- },
342
- list: YerbaTypedList {
343
- json: ptr::null_mut(),
344
- length: 0,
345
- },
346
- location,
347
- key_name: key_name_pointer,
348
- key_location,
349
- error: ptr::null_mut(),
350
- }
351
- }
263
+ match info.value {
264
+ Some(scalar) => base.scalar(&scalar.text, detect_yaml_type(&scalar)),
265
+ None => base.with_node_type(info.node_type),
352
266
  }
353
267
  }
354
268
  }
355
269
 
270
+ fn location_to_ffi(location: crate::Location) -> YerbaLocation {
271
+ YerbaLocation {
272
+ start_offset: location.start_offset,
273
+ end_offset: location.end_offset,
274
+ start_line: location.start_line,
275
+ start_column: location.start_column,
276
+ end_line: location.end_line,
277
+ end_column: location.end_column,
278
+ }
279
+ }
280
+
356
281
  /// Caller must free with yerba_string_free.
357
282
  #[no_mangle]
358
283
  pub unsafe extern "C" fn yerba_document_get_value(document: *const Document, path: *const c_char) -> *mut c_char {
359
284
  let document = &*document;
360
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
285
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
361
286
 
362
- match document.get_value(path_string) {
287
+ match document.get_value(selector_string) {
363
288
  Some(value) => {
364
289
  let json = crate::json::yaml_to_json(&value);
365
290
  let json_string = serde_json::to_string(&json).unwrap_or_else(|_| "null".to_string());
291
+
366
292
  CString::new(json_string).unwrap_or_default().into_raw()
367
293
  }
294
+
368
295
  None => ptr::null_mut(),
369
296
  }
370
297
  }
@@ -373,9 +300,9 @@ pub unsafe extern "C" fn yerba_document_get_value(document: *const Document, pat
373
300
  #[no_mangle]
374
301
  pub unsafe extern "C" fn yerba_document_get_values(document: *const Document, path: *const c_char) -> *mut c_char {
375
302
  let document = &*document;
376
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
303
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
377
304
 
378
- let values = document.get_values(path_string);
305
+ let values = document.get_values(selector_string);
379
306
  let json_values: Vec<serde_json::Value> = values.iter().map(crate::json::yaml_to_json).collect();
380
307
  let json_string = serde_json::to_string(&json_values).unwrap_or_else(|_| "[]".to_string());
381
308
 
@@ -383,50 +310,40 @@ pub unsafe extern "C" fn yerba_document_get_values(document: *const Document, pa
383
310
  }
384
311
 
385
312
  #[no_mangle]
386
- pub unsafe extern "C" fn yerba_document_get_quote_style(document: *const Document, path: *const c_char) -> i32 {
313
+ pub unsafe extern "C" fn yerba_document_get_quote_style(document: *const Document, path: *const c_char) -> *mut c_char {
387
314
  let document = &*document;
388
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
389
-
390
- match document.get_typed(path_string) {
391
- Some(scalar) => match scalar.kind {
392
- SyntaxKind::PLAIN_SCALAR => 0,
393
- SyntaxKind::SINGLE_QUOTED_SCALAR => 1,
394
- SyntaxKind::DOUBLE_QUOTED_SCALAR => 2,
395
- _ => -1,
396
- },
315
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
397
316
 
398
- None => -1,
317
+ match document.get_quote_style(selector_string) {
318
+ Some(style) => {
319
+ let ruby_style = style.replace('-', "_");
320
+
321
+ CString::new(ruby_style).map(|s| s.into_raw()).unwrap_or(std::ptr::null_mut())
322
+ }
323
+
324
+ None => std::ptr::null_mut(),
399
325
  }
400
326
  }
401
327
 
402
328
  #[no_mangle]
403
- pub unsafe extern "C" fn yerba_document_set_quote_style(
404
- document: *mut Document,
405
- path: *const c_char,
406
- style: i32,
407
- ) -> YerbaResult {
329
+ pub unsafe extern "C" fn yerba_document_set_quote_style(document: *mut Document, path: *const c_char, style: *const c_char) -> YerbaResult {
408
330
  let document = &mut *document;
409
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
331
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
332
+ let style_string = &CStr::from_ptr(style).to_str().unwrap_or("").replace('_', "-");
410
333
 
411
- let quote_style = match style {
412
- 0 => QuoteStyle::Plain,
413
- 1 => QuoteStyle::Single,
414
- 2 => QuoteStyle::Double,
415
- _ => return YerbaResult::err("Invalid quote style (use 0=plain, 1=single, 2=double)"),
334
+ let quote_style = match style_string.parse::<QuoteStyle>() {
335
+ Ok(style) => style,
336
+ Err(e) => return YerbaResult::err(&e),
416
337
  };
417
338
 
418
- match document.set_scalar_style(path_string, &quote_style) {
419
- Ok(()) => YerbaResult::ok(),
339
+ match document.enforce_quotes_at(&quote_style, Some(selector_string)) {
340
+ Ok(_warnings) => YerbaResult::ok(),
420
341
  Err(e) => YerbaResult::err(&e.to_string()),
421
342
  }
422
343
  }
423
344
 
424
345
  #[no_mangle]
425
- pub unsafe extern "C" fn yerba_document_evaluate_condition(
426
- document: *const Document,
427
- parent_path: *const c_char,
428
- condition: *const c_char,
429
- ) -> bool {
346
+ pub unsafe extern "C" fn yerba_document_evaluate_condition(document: *const Document, parent_path: *const c_char, condition: *const c_char) -> bool {
430
347
  let document = &*document;
431
348
  let parent = CStr::from_ptr(parent_path).to_str().unwrap_or("");
432
349
  let cond = CStr::from_ptr(condition).to_str().unwrap_or("");
@@ -436,62 +353,22 @@ pub unsafe extern "C" fn yerba_document_evaluate_condition(
436
353
  #[no_mangle]
437
354
  pub unsafe extern "C" fn yerba_document_exists(document: *const Document, path: *const c_char) -> bool {
438
355
  let document = &*document;
439
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
440
- document.exists(path_string)
356
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
357
+ document.exists(selector_string)
441
358
  }
442
359
 
443
360
  #[no_mangle]
444
- pub unsafe extern "C" fn yerba_document_find(
445
- document: *const Document,
446
- path: *const c_char,
447
- condition: *const c_char,
448
- select: *const c_char,
449
- ) -> *mut c_char {
361
+ pub unsafe extern "C" fn yerba_document_find(document: *const Document, path: *const c_char, condition: *const c_char, select: *const c_char) -> *mut c_char {
450
362
  let document = &*document;
451
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
452
-
453
- let condition_str = if condition.is_null() {
454
- None
455
- } else {
456
- CStr::from_ptr(condition).to_str().ok()
457
- };
458
-
459
- let _select_string = if select.is_null() {
460
- None
461
- } else {
462
- CStr::from_ptr(select).to_str().ok()
463
- };
464
-
465
- let values = match condition_str {
466
- Some(cond) => document.filter(path_string, cond),
467
- None => document.get_values(path_string),
468
- };
469
-
470
- let select_fields: Option<Vec<&str>> = _select_string.map(|s| s.split(',').collect());
471
-
472
- let mut results: Vec<serde_json::Value> = Vec::new();
363
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
473
364
 
474
- for value in &values {
475
- match &select_fields {
476
- Some(fields) => {
477
- let mut result = serde_json::Map::new();
365
+ let condition_string = if condition.is_null() { None } else { CStr::from_ptr(condition).to_str().ok() };
478
366
 
479
- for field in fields {
480
- let json_value = crate::json::resolve_select_field(value, field);
481
- let json_key = crate::json::select_field_key(field);
482
-
483
- result.insert(json_key, json_value);
484
- }
485
-
486
- results.push(serde_json::Value::Object(result));
487
- }
488
- None => {
489
- results.push(crate::json::yaml_to_json(value));
490
- }
491
- }
492
- }
367
+ let select_string = if select.is_null() { None } else { CStr::from_ptr(select).to_str().ok() };
493
368
 
369
+ let results = document.find_items(selector_string, condition_string, select_string);
494
370
  let json = serde_json::to_string_pretty(&results).unwrap_or_else(|_| "[]".to_string());
371
+
495
372
  CString::new(json).unwrap_or_default().into_raw()
496
373
  }
497
374
 
@@ -504,15 +381,15 @@ pub unsafe extern "C" fn yerba_document_set(
504
381
  all: bool,
505
382
  ) -> YerbaResult {
506
383
  let document = &mut *document;
507
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
384
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
508
385
  let value_string = CStr::from_ptr(value).to_str().unwrap_or("");
509
386
 
510
387
  let result = if all {
511
- document.set_all(path_string, value_string)
388
+ document.set_all(selector_string, value_string)
512
389
  } else {
513
390
  match value_type {
514
- YerbaValueType::String => document.set(path_string, value_string),
515
- _ => document.set_plain(path_string, value_string),
391
+ YerbaValueType::String => document.set(selector_string, value_string),
392
+ _ => document.set_plain(selector_string, value_string),
516
393
  }
517
394
  };
518
395
 
@@ -532,7 +409,7 @@ pub unsafe extern "C" fn yerba_document_insert(
532
409
  at: i64,
533
410
  ) -> YerbaResult {
534
411
  let document = &mut *document;
535
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
412
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
536
413
  let value_string = CStr::from_ptr(value).to_str().unwrap_or("");
537
414
 
538
415
  let position = if at >= 0 {
@@ -547,7 +424,7 @@ pub unsafe extern "C" fn yerba_document_insert(
547
424
  InsertPosition::Last
548
425
  };
549
426
 
550
- match document.insert_into(path_string, value_string, position) {
427
+ match document.insert_into(selector_string, value_string, position) {
551
428
  Ok(()) => YerbaResult::ok(),
552
429
  Err(e) => YerbaResult::err(&e.to_string()),
553
430
  }
@@ -563,60 +440,14 @@ pub unsafe extern "C" fn yerba_document_insert_object(
563
440
  at: i64,
564
441
  ) -> YerbaResult {
565
442
  let document = &mut *document;
566
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
443
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
567
444
  let json_string = CStr::from_ptr(json).to_str().unwrap_or("");
568
445
 
569
446
  let json_value: serde_json::Value = match serde_json::from_str(json_string) {
570
- Ok(v) => v,
447
+ Ok(value) => value,
571
448
  Err(e) => return YerbaResult::err(&format!("Invalid JSON: {}", e)),
572
449
  };
573
450
 
574
- let try_paths = if path_string.is_empty() {
575
- vec!["[]".to_string(), "[0]".to_string()]
576
- } else {
577
- vec![format!("{}[]", path_string), format!("{}[0]", path_string)]
578
- };
579
-
580
- let mut quote_style = QuoteStyle::Plain;
581
-
582
- 'outer: for try_path in &try_paths {
583
- for scalar in document.get_all_typed(try_path) {
584
- if scalar.kind == SyntaxKind::DOUBLE_QUOTED_SCALAR {
585
- quote_style = QuoteStyle::Double;
586
- break 'outer;
587
- } else if scalar.kind == SyntaxKind::SINGLE_QUOTED_SCALAR {
588
- quote_style = QuoteStyle::Single;
589
- break 'outer;
590
- }
591
- }
592
- }
593
-
594
- if quote_style == QuoteStyle::Plain {
595
- if let Some(serde_yaml::Value::Sequence(seq)) = document.get_value(path_string).as_ref() {
596
- if let Some(serde_yaml::Value::Mapping(map)) = seq.first() {
597
- if let Some((serde_yaml::Value::String(key_name), _)) = map.iter().next() {
598
- let deep_path = if path_string.is_empty() {
599
- format!("[].{}", key_name)
600
- } else {
601
- format!("{}[].{}", path_string, key_name)
602
- };
603
-
604
- for scalar in document.get_all_typed(&deep_path) {
605
- if scalar.kind == SyntaxKind::DOUBLE_QUOTED_SCALAR {
606
- quote_style = QuoteStyle::Double;
607
- break;
608
- } else if scalar.kind == SyntaxKind::SINGLE_QUOTED_SCALAR {
609
- quote_style = QuoteStyle::Single;
610
- break;
611
- }
612
- }
613
- }
614
- }
615
- }
616
- }
617
-
618
- let yaml_text = crate::yaml_writer::json_to_yaml_text(&json_value, &quote_style, 0);
619
-
620
451
  let position = if at >= 0 {
621
452
  InsertPosition::At(at as usize)
622
453
  } else if !before.is_null() {
@@ -629,7 +460,7 @@ pub unsafe extern "C" fn yerba_document_insert_object(
629
460
  InsertPosition::Last
630
461
  };
631
462
 
632
- match document.insert_into(path_string, &yaml_text, position) {
463
+ match document.insert_object(selector_string, &json_value, position) {
633
464
  Ok(()) => YerbaResult::ok(),
634
465
  Err(e) => YerbaResult::err(&e.to_string()),
635
466
  }
@@ -638,51 +469,50 @@ pub unsafe extern "C" fn yerba_document_insert_object(
638
469
  #[no_mangle]
639
470
  pub unsafe extern "C" fn yerba_document_delete(document: *mut Document, path: *const c_char) -> YerbaResult {
640
471
  let document = &mut *document;
641
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
472
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
642
473
 
643
- match document.delete(path_string) {
474
+ match document.delete(selector_string) {
644
475
  Ok(()) => YerbaResult::ok(),
645
476
  Err(e) => YerbaResult::err(&e.to_string()),
646
477
  }
647
478
  }
648
479
 
649
480
  #[no_mangle]
650
- pub unsafe extern "C" fn yerba_document_remove(
651
- document: *mut Document,
652
- path: *const c_char,
653
- value: *const c_char,
654
- ) -> YerbaResult {
481
+ pub unsafe extern "C" fn yerba_document_remove(document: *mut Document, path: *const c_char, value: *const c_char) -> YerbaResult {
655
482
  let document = &mut *document;
656
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
483
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
657
484
  let value_string = CStr::from_ptr(value).to_str().unwrap_or("");
658
485
 
659
- match document.remove(path_string, value_string) {
486
+ match document.remove(selector_string, value_string) {
660
487
  Ok(()) => YerbaResult::ok(),
661
488
  Err(e) => YerbaResult::err(&e.to_string()),
662
489
  }
663
490
  }
664
491
 
665
492
  #[no_mangle]
666
- pub unsafe extern "C" fn yerba_document_remove_at(
667
- document: *mut Document,
668
- path: *const c_char,
669
- index: usize,
670
- ) -> YerbaResult {
493
+ pub unsafe extern "C" fn yerba_document_remove_at(document: *mut Document, path: *const c_char, index: usize) -> YerbaResult {
671
494
  let document = &mut *document;
672
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
495
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
673
496
 
674
- match document.remove_at(path_string, index) {
497
+ match document.remove_at(selector_string, index) {
675
498
  Ok(()) => YerbaResult::ok(),
676
499
  Err(e) => YerbaResult::err(&e.to_string()),
677
500
  }
678
501
  }
679
502
 
680
503
  #[no_mangle]
681
- pub unsafe extern "C" fn yerba_document_rename(
682
- document: *mut Document,
683
- source: *const c_char,
684
- dest: *const c_char,
685
- ) -> YerbaResult {
504
+ pub unsafe extern "C" fn yerba_document_move_item(document: *mut Document, path: *const c_char, from: usize, to: usize) -> YerbaResult {
505
+ let document = &mut *document;
506
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
507
+
508
+ match document.move_item(selector_string, from, to) {
509
+ Ok(()) => YerbaResult::ok(),
510
+ Err(e) => YerbaResult::err(&e.to_string()),
511
+ }
512
+ }
513
+
514
+ #[no_mangle]
515
+ pub unsafe extern "C" fn yerba_document_rename(document: *mut Document, source: *const c_char, dest: *const c_char) -> YerbaResult {
686
516
  let document = &mut *document;
687
517
  let source_string = CStr::from_ptr(source).to_str().unwrap_or("");
688
518
  let dest_string = CStr::from_ptr(dest).to_str().unwrap_or("");
@@ -694,59 +524,46 @@ pub unsafe extern "C" fn yerba_document_rename(
694
524
  }
695
525
 
696
526
  #[no_mangle]
697
- pub unsafe extern "C" fn yerba_document_sort(
698
- document: *mut Document,
699
- path: *const c_char,
700
- by: *const c_char,
701
- case_sensitive: bool,
702
- ) -> YerbaResult {
527
+ pub unsafe extern "C" fn yerba_document_sort(document: *mut Document, path: *const c_char, by: *const c_char, case_sensitive: bool) -> YerbaResult {
703
528
  let document = &mut *document;
704
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
529
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
705
530
 
706
- let by_string = if by.is_null() {
707
- None
708
- } else {
709
- CStr::from_ptr(by).to_str().ok()
710
- };
531
+ let by_string = if by.is_null() { None } else { CStr::from_ptr(by).to_str().ok() };
711
532
 
712
533
  let sort_fields: Vec<crate::SortField> = match by_string {
713
- Some(fields) => fields
714
- .split(',')
715
- .map(|field| {
716
- if let Some(name) = field.strip_suffix(":desc") {
717
- crate::SortField {
718
- path: name.to_string(),
719
- ascending: false,
720
- }
721
- } else {
722
- crate::SortField {
723
- path: field.to_string(),
724
- ascending: true,
725
- }
726
- }
727
- })
728
- .collect(),
534
+ Some(fields) => crate::SortField::parse_list(fields),
729
535
  None => vec![],
730
536
  };
731
537
 
732
- match document.sort_items(path_string, &sort_fields, case_sensitive) {
538
+ match document.sort_items(selector_string, &sort_fields, case_sensitive) {
733
539
  Ok(()) => YerbaResult::ok(),
734
540
  Err(e) => YerbaResult::err(&e.to_string()),
735
541
  }
736
542
  }
737
543
 
738
544
  #[no_mangle]
739
- pub unsafe extern "C" fn yerba_document_sort_keys(
740
- document: *mut Document,
741
- path: *const c_char,
742
- order: *const c_char,
743
- ) -> YerbaResult {
545
+ pub unsafe extern "C" fn yerba_document_reorder(document: *mut Document, path: *const c_char, by: *const c_char, order_csv: *const c_char) -> YerbaResult {
744
546
  let document = &mut *document;
745
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
547
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
548
+ let by_string = CStr::from_ptr(by).to_str().unwrap_or("");
549
+ let order_string = CStr::from_ptr(order_csv).to_str().unwrap_or("");
550
+
551
+ let desired_order: Vec<&str> = order_string.split(',').map(|s| s.trim()).collect();
552
+
553
+ match document.reorder_items(selector_string, by_string, &desired_order) {
554
+ Ok(()) => YerbaResult::ok(),
555
+ Err(e) => YerbaResult::err(&e.to_string()),
556
+ }
557
+ }
558
+
559
+ #[no_mangle]
560
+ pub unsafe extern "C" fn yerba_document_sort_keys(document: *mut Document, path: *const c_char, order: *const c_char) -> YerbaResult {
561
+ let document = &mut *document;
562
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
746
563
  let order_string = CStr::from_ptr(order).to_str().unwrap_or("");
747
564
  let key_order: Vec<&str> = order_string.split(',').collect();
748
565
 
749
- match document.sort_keys(path_string, &key_order) {
566
+ match document.sort_keys(selector_string, &key_order) {
750
567
  Ok(()) => YerbaResult::ok(),
751
568
  Err(e) => YerbaResult::err(&e.to_string()),
752
569
  }
@@ -761,55 +578,32 @@ pub unsafe extern "C" fn yerba_document_quote_style(
761
578
  ) -> YerbaResult {
762
579
  let document = &mut *document;
763
580
 
764
- let path_string = if path.is_null() {
765
- None
766
- } else {
767
- CStr::from_ptr(path).to_str().ok()
768
- };
581
+ let selector = if path.is_null() { None } else { CStr::from_ptr(path).to_str().ok() };
769
582
 
770
- let key_quote_style = if key_style.is_null() {
583
+ let key = if key_style.is_null() {
771
584
  None
772
585
  } else {
773
- CStr::from_ptr(key_style)
774
- .to_str()
775
- .ok()
776
- .and_then(|s| s.parse::<QuoteStyle>().ok())
586
+ CStr::from_ptr(key_style).to_str().ok().and_then(|s| s.parse::<crate::KeyStyle>().ok())
777
587
  };
778
588
 
779
- let value_quote_style = if value_style.is_null() {
589
+ let value = if value_style.is_null() {
780
590
  None
781
591
  } else {
782
- CStr::from_ptr(value_style)
783
- .to_str()
784
- .ok()
785
- .and_then(|s| s.parse::<QuoteStyle>().ok())
592
+ CStr::from_ptr(value_style).to_str().ok().and_then(|s| s.parse::<QuoteStyle>().ok())
786
593
  };
787
594
 
788
- if let Some(ref key_style) = key_quote_style {
789
- if let Err(e) = document.enforce_key_style(key_style, path_string) {
790
- return YerbaResult::err(&e.to_string());
791
- }
792
- }
793
-
794
- if let Some(ref value_style) = value_quote_style {
795
- if let Err(e) = document.enforce_quotes_at(value_style, path_string) {
796
- return YerbaResult::err(&e.to_string());
797
- }
595
+ match document.enforce_quote_style(key.as_ref(), value.as_ref(), selector) {
596
+ Ok(()) => YerbaResult::ok(),
597
+ Err(e) => YerbaResult::err(&e.to_string()),
798
598
  }
799
-
800
- YerbaResult::ok()
801
599
  }
802
600
 
803
601
  #[no_mangle]
804
- pub unsafe extern "C" fn yerba_document_blank_lines(
805
- document: *mut Document,
806
- path: *const c_char,
807
- count: usize,
808
- ) -> YerbaResult {
602
+ pub unsafe extern "C" fn yerba_document_blank_lines(document: *mut Document, path: *const c_char, count: usize) -> YerbaResult {
809
603
  let document = &mut *document;
810
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
604
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
811
605
 
812
- match document.enforce_blank_lines(path_string, count) {
606
+ match document.enforce_blank_lines(selector_string, count) {
813
607
  Ok(()) => YerbaResult::ok(),
814
608
  Err(e) => YerbaResult::err(&e.to_string()),
815
609
  }
@@ -855,42 +649,12 @@ pub unsafe extern "C" fn yerba_get_result_free(result: YerbaGetResult) {
855
649
  #[no_mangle]
856
650
  pub unsafe extern "C" fn yerba_glob_get(glob_pattern: *const c_char, path: *const c_char) -> YerbaTypedList {
857
651
  let pattern = CStr::from_ptr(glob_pattern).to_str().unwrap_or("");
858
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
859
- let selector = Selector::parse(path_string);
860
-
861
- let files = match glob::glob(pattern) {
862
- Ok(paths) => paths.filter_map(|p| p.ok()).collect::<Vec<_>>(),
863
- Err(_) => {
864
- return YerbaTypedList {
865
- json: CString::new("[]").unwrap_or_default().into_raw(),
866
- length: 0,
867
- }
868
- }
869
- };
870
-
871
- use rayon::prelude::*;
872
-
873
- let results: Vec<serde_json::Value> = files
874
- .par_iter()
875
- .flat_map(|file| {
876
- let mut file_results = Vec::new();
652
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
653
+ let scalars = crate::glob_get(pattern, selector_string);
877
654
 
878
- if let Ok(document) = Document::parse_file(file) {
879
- if selector.has_wildcard() {
880
- for scalar in document.get_all_typed(path_string) {
881
- let value_type = detect_yaml_type(&scalar);
882
-
883
- file_results.push(serde_json::json!({"text": scalar.text, "type": value_type as u8}));
884
- }
885
- } else if let Some(scalar) = document.get_typed(path_string) {
886
- let value_type = detect_yaml_type(&scalar);
887
-
888
- file_results.push(serde_json::json!({"text": scalar.text, "type": value_type as u8}));
889
- }
890
- }
891
-
892
- file_results
893
- })
655
+ let results: Vec<serde_json::Value> = scalars
656
+ .iter()
657
+ .map(|scalar| serde_json::json!({"text": scalar.text, "type": detect_yaml_type(scalar) as u8}))
894
658
  .collect();
895
659
 
896
660
  let length = results.len();
@@ -903,89 +667,13 @@ pub unsafe extern "C" fn yerba_glob_get(glob_pattern: *const c_char, path: *cons
903
667
  }
904
668
 
905
669
  #[no_mangle]
906
- pub unsafe extern "C" fn yerba_glob_find(
907
- glob_pattern: *const c_char,
908
- path: *const c_char,
909
- condition: *const c_char,
910
- select: *const c_char,
911
- ) -> YerbaTypedList {
670
+ pub unsafe extern "C" fn yerba_glob_find(glob_pattern: *const c_char, path: *const c_char, condition: *const c_char, select: *const c_char) -> YerbaTypedList {
912
671
  let pattern = CStr::from_ptr(glob_pattern).to_str().unwrap_or("");
913
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
914
-
915
- let condition_string = if condition.is_null() {
916
- None
917
- } else {
918
- CStr::from_ptr(condition).to_str().ok()
919
- };
920
-
921
- let _select_string = if select.is_null() {
922
- None
923
- } else {
924
- CStr::from_ptr(select).to_str().ok()
925
- };
926
-
927
- let files = match glob::glob(pattern) {
928
- Ok(paths) => paths.filter_map(|p| p.ok()).collect::<Vec<_>>(),
929
- Err(_) => {
930
- return YerbaTypedList {
931
- json: CString::new("[]").unwrap_or_default().into_raw(),
932
- length: 0,
933
- }
934
- }
935
- };
936
-
937
- use rayon::prelude::*;
938
-
939
- let select_fields: Option<Vec<&str>> = _select_string.map(|s| s.split(',').collect());
940
-
941
- let all_results: Vec<serde_json::Value> = files
942
- .par_iter()
943
- .flat_map(|file| {
944
- let mut file_results = Vec::new();
945
-
946
- if let Ok(document) = Document::parse_file(file) {
947
- let values = match condition_string {
948
- Some(cond) => document.filter(path_string, cond),
949
- None => document.get_values(path_string),
950
- };
951
-
952
- let file_string = file.to_string_lossy().to_string();
953
-
954
- for value in &values {
955
- let mut result = serde_json::Map::new();
956
- result.insert("__file".to_string(), serde_json::Value::String(file_string.clone()));
957
-
958
- match &select_fields {
959
- Some(fields) => {
960
- for field in fields {
961
- let json_value = crate::json::resolve_select_field(value, field);
962
- let json_key = crate::json::select_field_key(field);
963
- result.insert(json_key, json_value);
964
- }
965
- }
966
-
967
- None => {
968
- if let serde_yaml::Value::Mapping(map) = value {
969
- for (key, yaml_value) in map {
970
- let json_key = match key {
971
- serde_yaml::Value::String(string) => string.clone(),
972
- _ => format!("{:?}", key),
973
- };
974
-
975
- result.insert(json_key, crate::json::yaml_to_json(yaml_value));
976
- }
977
- }
978
- }
979
- }
980
-
981
- file_results.push(serde_json::Value::Object(result));
982
- }
983
- }
984
-
985
- file_results
986
- })
987
- .collect();
672
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
673
+ let condition_string = if condition.is_null() { None } else { CStr::from_ptr(condition).to_str().ok() };
674
+ let select_string = if select.is_null() { None } else { CStr::from_ptr(select).to_str().ok() };
988
675
 
676
+ let all_results = crate::glob_find(pattern, selector_string, condition_string, select_string);
989
677
  let length = all_results.len();
990
678
  let json = serde_json::to_string_pretty(&all_results).unwrap_or_else(|_| "[]".to_string());
991
679