yerba 0.4.2 → 0.5.1
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.
- checksums.yaml +4 -4
- data/README.md +242 -54
- data/ext/yerba/include/yerba.h +13 -1
- data/ext/yerba/yerba.c +239 -113
- data/lib/yerba/document.rb +54 -18
- data/lib/yerba/map.rb +55 -43
- data/lib/yerba/node.rb +58 -0
- data/lib/yerba/scalar.rb +20 -23
- data/lib/yerba/sequence.rb +88 -55
- data/lib/yerba/version.rb +1 -1
- data/lib/yerba.rb +2 -0
- data/rust/Cargo.toml +3 -2
- data/rust/src/commands/delete.rs +1 -1
- data/rust/src/commands/get.rs +47 -12
- data/rust/src/commands/insert.rs +1 -1
- data/rust/src/commands/location.rs +56 -0
- data/rust/src/commands/mod.rs +33 -5
- data/rust/src/commands/remove.rs +1 -1
- data/rust/src/commands/rename.rs +1 -1
- data/rust/src/commands/schema.rs +84 -0
- data/rust/src/commands/selectors.rs +4 -4
- data/rust/src/commands/set.rs +1 -1
- data/rust/src/commands/sort.rs +1 -1
- data/rust/src/commands/unique.rs +80 -0
- data/rust/src/document/condition.rs +18 -2
- data/rust/src/document/delete.rs +52 -8
- data/rust/src/document/get.rs +256 -25
- data/rust/src/document/insert.rs +3 -3
- data/rust/src/document/mod.rs +112 -34
- data/rust/src/document/schema.rs +73 -0
- data/rust/src/document/set.rs +1 -1
- data/rust/src/document/sort.rs +21 -15
- data/rust/src/document/style.rs +3 -3
- data/rust/src/document/unique.rs +86 -0
- data/rust/src/error.rs +78 -0
- data/rust/src/ffi.rs +89 -9
- data/rust/src/json.rs +16 -16
- data/rust/src/lib.rs +7 -12
- data/rust/src/main.rs +2 -0
- data/rust/src/schema.rs +93 -0
- data/rust/src/selector.rs +16 -0
- data/rust/src/syntax.rs +91 -31
- data/rust/src/yerbafile.rs +127 -81
- metadata +8 -1
data/rust/src/document/get.rs
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
use super::*;
|
|
2
2
|
|
|
3
3
|
impl Document {
|
|
4
|
+
pub fn is_valid_selector(&self, dot_path: &str) -> bool {
|
|
5
|
+
if dot_path.is_empty() {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let selectors = self.selectors();
|
|
10
|
+
|
|
11
|
+
if selectors.contains(&dot_path.to_string()) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let wildcard_version = dot_path.replace(|c: char| c.is_ascii_digit(), "").replace("[.", "[");
|
|
16
|
+
|
|
17
|
+
let mut normalized = String::new();
|
|
18
|
+
let mut chars = dot_path.chars().peekable();
|
|
19
|
+
|
|
20
|
+
while let Some(char) = chars.next() {
|
|
21
|
+
if char == '[' {
|
|
22
|
+
normalized.push('[');
|
|
23
|
+
|
|
24
|
+
while chars.peek().map(|char| char.is_ascii_digit()).unwrap_or(false) {
|
|
25
|
+
chars.next();
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
normalized.push(char);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
selectors.contains(&normalized) || selectors.contains(&wildcard_version)
|
|
33
|
+
}
|
|
34
|
+
|
|
4
35
|
pub fn get(&self, dot_path: &str) -> Option<String> {
|
|
5
36
|
if dot_path.contains('[') {
|
|
6
37
|
return self.get_all(dot_path).into_iter().next();
|
|
@@ -12,7 +43,7 @@ impl Document {
|
|
|
12
43
|
}
|
|
13
44
|
|
|
14
45
|
pub fn get_all(&self, dot_path: &str) -> Vec<String> {
|
|
15
|
-
self.
|
|
46
|
+
self.navigate_all_compact(dot_path).iter().filter_map(extract_scalar_text).collect()
|
|
16
47
|
}
|
|
17
48
|
|
|
18
49
|
pub fn get_typed(&self, dot_path: &str) -> Option<ScalarValue> {
|
|
@@ -34,7 +65,7 @@ impl Document {
|
|
|
34
65
|
|
|
35
66
|
pub fn get_all_typed(&self, dot_path: &str) -> Vec<ScalarValue> {
|
|
36
67
|
self
|
|
37
|
-
.
|
|
68
|
+
.navigate_all_compact(dot_path)
|
|
38
69
|
.iter()
|
|
39
70
|
.filter(|node| {
|
|
40
71
|
!node
|
|
@@ -45,6 +76,59 @@ impl Document {
|
|
|
45
76
|
.collect()
|
|
46
77
|
}
|
|
47
78
|
|
|
79
|
+
pub fn resolve_selectors(&self, dot_path: &str) -> Vec<String> {
|
|
80
|
+
self.navigate_all_compact(dot_path).iter().map(node_selector).collect()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
pub fn get_all_located(&self, dot_path: &str) -> Vec<LocatedNode> {
|
|
84
|
+
let source = self.root.text().to_string();
|
|
85
|
+
let file_path = self.path.as_ref().map(|p| p.to_string_lossy().to_string());
|
|
86
|
+
|
|
87
|
+
self
|
|
88
|
+
.navigate_all_compact(dot_path)
|
|
89
|
+
.iter()
|
|
90
|
+
.map(|node| {
|
|
91
|
+
let offset: usize = node.text_range().start().into();
|
|
92
|
+
let line = source[..offset].matches('\n').count() + 1;
|
|
93
|
+
let selector = node_selector(node);
|
|
94
|
+
let is_scalar = !node
|
|
95
|
+
.descendants()
|
|
96
|
+
.any(|child| child.kind() == SyntaxKind::BLOCK_MAP || child.kind() == SyntaxKind::BLOCK_SEQ);
|
|
97
|
+
|
|
98
|
+
let (text, value_type) = if is_scalar {
|
|
99
|
+
extract_scalar(node)
|
|
100
|
+
.map(|s| (Some(s.text.clone()), Some(crate::syntax::detect_yaml_type(&s))))
|
|
101
|
+
.unwrap_or((None, None))
|
|
102
|
+
} else {
|
|
103
|
+
(None, None)
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
let node_type = if is_scalar {
|
|
107
|
+
"scalar"
|
|
108
|
+
} else {
|
|
109
|
+
let map_pos = node.descendants().find_map(BlockMap::cast).map(|m| m.syntax().text_range().start());
|
|
110
|
+
let seq_pos = node.descendants().find_map(BlockSeq::cast).map(|s| s.syntax().text_range().start());
|
|
111
|
+
|
|
112
|
+
match (map_pos, seq_pos) {
|
|
113
|
+
(Some(m), Some(s)) if s < m => "sequence",
|
|
114
|
+
(Some(_), _) => "map",
|
|
115
|
+
(None, Some(_)) => "sequence",
|
|
116
|
+
_ => "map",
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
LocatedNode {
|
|
121
|
+
node_type: node_type.to_string(),
|
|
122
|
+
text,
|
|
123
|
+
value_type,
|
|
124
|
+
file_path: file_path.clone(),
|
|
125
|
+
selector,
|
|
126
|
+
line,
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
.collect()
|
|
130
|
+
}
|
|
131
|
+
|
|
48
132
|
pub fn node_type(&self, dot_path: &str) -> NodeType {
|
|
49
133
|
match self.navigate(dot_path) {
|
|
50
134
|
Ok(node) => {
|
|
@@ -97,15 +181,43 @@ impl Document {
|
|
|
97
181
|
key_name,
|
|
98
182
|
key_location,
|
|
99
183
|
},
|
|
100
|
-
None =>
|
|
101
|
-
node_type
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
184
|
+
None => {
|
|
185
|
+
let (node_type, entry_location, entry_key_name, entry_key_location) = if self.navigate(dot_path).is_err() {
|
|
186
|
+
if let Some(entry_node) = self.find_entry(dot_path) {
|
|
187
|
+
let range = entry_node.text_range();
|
|
188
|
+
let entry_location = compute_location(&source, range.start().into(), range.end().into());
|
|
189
|
+
|
|
190
|
+
let (node, location) = yaml_parser::ast::BlockMapEntry::cast(entry_node.clone())
|
|
191
|
+
.and_then(|entry| {
|
|
192
|
+
entry.key().and_then(|key_node| {
|
|
193
|
+
let key_text = extract_scalar_text(key_node.syntax())?;
|
|
194
|
+
let key_range = key_node.syntax().text_range();
|
|
195
|
+
let key_location = compute_location(&source, key_range.start().into(), key_range.end().into());
|
|
196
|
+
|
|
197
|
+
Some((key_text, key_location))
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
.map(|(name, location)| (Some(name), location))
|
|
201
|
+
.unwrap_or((None, Location::default()));
|
|
202
|
+
|
|
203
|
+
(NodeType::Scalar, entry_location, node, location)
|
|
204
|
+
} else {
|
|
205
|
+
(self.node_type(dot_path), location, key_name, key_location)
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
(self.node_type(dot_path), location, key_name, key_location)
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
NodeInfo {
|
|
212
|
+
node_type,
|
|
213
|
+
is_list: false,
|
|
214
|
+
value: None,
|
|
215
|
+
list_values: vec![],
|
|
216
|
+
location: entry_location,
|
|
217
|
+
key_name: entry_key_name,
|
|
218
|
+
key_location: entry_key_location,
|
|
219
|
+
}
|
|
220
|
+
}
|
|
109
221
|
}
|
|
110
222
|
}
|
|
111
223
|
|
|
@@ -166,28 +278,61 @@ impl Document {
|
|
|
166
278
|
.collect()
|
|
167
279
|
}
|
|
168
280
|
|
|
169
|
-
pub fn get_value(&self, dot_path: &str) -> Option<
|
|
281
|
+
pub fn get_value(&self, dot_path: &str) -> Option<yaml_serde::Value> {
|
|
170
282
|
if dot_path.is_empty() {
|
|
171
283
|
return Some(node_to_yaml_value(&self.root));
|
|
172
284
|
}
|
|
173
285
|
|
|
174
|
-
let
|
|
286
|
+
let parsed = crate::selector::Selector::parse(dot_path);
|
|
175
287
|
|
|
176
|
-
if
|
|
177
|
-
|
|
178
|
-
}
|
|
288
|
+
if parsed.has_wildcard() {
|
|
289
|
+
let padded = self.navigate_all(dot_path);
|
|
179
290
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
291
|
+
if padded.is_empty() {
|
|
292
|
+
return None;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let values: Vec<yaml_serde::Value> = padded
|
|
296
|
+
.iter()
|
|
297
|
+
.map(|maybe_node| match maybe_node {
|
|
298
|
+
Some(node) => node_to_yaml_value(node),
|
|
299
|
+
None => yaml_serde::Value::Null,
|
|
300
|
+
})
|
|
301
|
+
.collect();
|
|
302
|
+
|
|
303
|
+
Some(yaml_serde::Value::Sequence(values))
|
|
304
|
+
} else {
|
|
305
|
+
let nodes = self.navigate_all_compact(dot_path);
|
|
183
306
|
|
|
184
|
-
|
|
307
|
+
if nodes.is_empty() {
|
|
308
|
+
return None;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if nodes.len() == 1 {
|
|
312
|
+
return Some(node_to_yaml_value(&nodes[0]));
|
|
313
|
+
}
|
|
185
314
|
|
|
186
|
-
|
|
315
|
+
let values: Vec<yaml_serde::Value> = nodes.iter().map(node_to_yaml_value).collect();
|
|
316
|
+
|
|
317
|
+
Some(yaml_serde::Value::Sequence(values))
|
|
318
|
+
}
|
|
187
319
|
}
|
|
188
320
|
|
|
189
|
-
pub fn get_values(&self, dot_path: &str) -> Vec<
|
|
190
|
-
|
|
321
|
+
pub fn get_values(&self, dot_path: &str) -> Vec<yaml_serde::Value> {
|
|
322
|
+
let parsed = crate::selector::Selector::parse(dot_path);
|
|
323
|
+
|
|
324
|
+
if parsed.has_wildcard() {
|
|
325
|
+
self
|
|
326
|
+
.navigate_all(dot_path)
|
|
327
|
+
.iter()
|
|
328
|
+
.map(|maybe_node| match maybe_node {
|
|
329
|
+
Some(node) => node_to_yaml_value(node),
|
|
330
|
+
None => yaml_serde::Value::Null,
|
|
331
|
+
})
|
|
332
|
+
.collect()
|
|
333
|
+
} else {
|
|
334
|
+
self.navigate_all_compact(dot_path).iter().map(node_to_yaml_value).collect()
|
|
335
|
+
}
|
|
191
336
|
}
|
|
192
337
|
|
|
193
338
|
pub fn selectors(&self) -> Vec<String> {
|
|
@@ -206,10 +351,33 @@ impl Document {
|
|
|
206
351
|
|
|
207
352
|
pub fn exists(&self, dot_path: &str) -> bool {
|
|
208
353
|
if dot_path.contains('[') {
|
|
209
|
-
|
|
354
|
+
if !self.navigate_all_compact(dot_path).is_empty() {
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
} else if self.navigate(dot_path).is_ok() {
|
|
358
|
+
return true;
|
|
210
359
|
}
|
|
211
360
|
|
|
212
|
-
self.
|
|
361
|
+
self.find_entry(dot_path).is_some()
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
fn find_entry(&self, dot_path: &str) -> Option<SyntaxNode> {
|
|
365
|
+
let (parent_path, last_key) = match dot_path.rsplit_once('.') {
|
|
366
|
+
Some((parent, key)) => (parent, key),
|
|
367
|
+
None => ("", dot_path),
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
let parent_node = if parent_path.is_empty() {
|
|
371
|
+
let root = Root::cast(self.root.clone())?;
|
|
372
|
+
let document = root.documents().next()?;
|
|
373
|
+
document.syntax().clone()
|
|
374
|
+
} else {
|
|
375
|
+
self.navigate(parent_path).ok()?
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
let map = parent_node.descendants().find_map(BlockMap::cast)?;
|
|
379
|
+
|
|
380
|
+
find_entry_by_key(&map, last_key).map(|entry| entry.syntax().clone())
|
|
213
381
|
}
|
|
214
382
|
|
|
215
383
|
pub fn get_sequence_values(&self, dot_path: &str) -> Vec<String> {
|
|
@@ -260,3 +428,66 @@ impl Document {
|
|
|
260
428
|
None
|
|
261
429
|
}
|
|
262
430
|
}
|
|
431
|
+
|
|
432
|
+
pub(crate) fn node_selector(node: &SyntaxNode) -> String {
|
|
433
|
+
let mut parts: Vec<String> = Vec::new();
|
|
434
|
+
let mut current = node.clone();
|
|
435
|
+
|
|
436
|
+
if current.kind() == SyntaxKind::BLOCK_SEQ_ENTRY {
|
|
437
|
+
if let Some(parent) = current.parent() {
|
|
438
|
+
let index = parent
|
|
439
|
+
.children()
|
|
440
|
+
.filter(|child| child.kind() == SyntaxKind::BLOCK_SEQ_ENTRY)
|
|
441
|
+
.position(|child| child == current)
|
|
442
|
+
.unwrap_or(0);
|
|
443
|
+
|
|
444
|
+
parts.push(format!("[{}]", index));
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
loop {
|
|
449
|
+
let parent = match current.parent() {
|
|
450
|
+
Some(parent) => parent,
|
|
451
|
+
None => break,
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
match parent.kind() {
|
|
455
|
+
SyntaxKind::BLOCK_SEQ_ENTRY => {
|
|
456
|
+
if let Some(grandparent) = parent.parent() {
|
|
457
|
+
let index = grandparent
|
|
458
|
+
.children()
|
|
459
|
+
.filter(|child| child.kind() == SyntaxKind::BLOCK_SEQ_ENTRY)
|
|
460
|
+
.position(|child| child == parent)
|
|
461
|
+
.unwrap_or(0);
|
|
462
|
+
|
|
463
|
+
parts.push(format!("[{}]", index));
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
SyntaxKind::BLOCK_MAP_ENTRY => {
|
|
468
|
+
if let Some(key_node) = parent.children().find(|child| child.kind() == SyntaxKind::BLOCK_MAP_KEY) {
|
|
469
|
+
if let Some(key_text) = extract_scalar_text(&key_node) {
|
|
470
|
+
parts.push(key_text);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
_ => {}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
current = parent;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
parts.reverse();
|
|
482
|
+
let mut result = String::new();
|
|
483
|
+
|
|
484
|
+
for part in &parts {
|
|
485
|
+
if !part.starts_with('[') && !result.is_empty() {
|
|
486
|
+
result.push('.');
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
result.push_str(part);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
result
|
|
493
|
+
}
|
data/rust/src/document/insert.rs
CHANGED
|
@@ -22,9 +22,9 @@ impl Document {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
if let Some(
|
|
26
|
-
if let Some(
|
|
27
|
-
if let Some((
|
|
25
|
+
if let Some(yaml_serde::Value::Sequence(sequence)) = self.get_value(dot_path).as_ref() {
|
|
26
|
+
if let Some(yaml_serde::Value::Mapping(map)) = sequence.first() {
|
|
27
|
+
if let Some((yaml_serde::Value::String(key_name), _)) = map.iter().next() {
|
|
28
28
|
let deep_path = if dot_path.is_empty() {
|
|
29
29
|
format!("[].{}", key_name)
|
|
30
30
|
} else {
|
data/rust/src/document/mod.rs
CHANGED
|
@@ -2,9 +2,24 @@ mod condition;
|
|
|
2
2
|
mod delete;
|
|
3
3
|
mod get;
|
|
4
4
|
mod insert;
|
|
5
|
+
mod schema;
|
|
5
6
|
mod set;
|
|
6
7
|
mod sort;
|
|
7
8
|
mod style;
|
|
9
|
+
mod unique;
|
|
10
|
+
pub use unique::DuplicateInfo;
|
|
11
|
+
|
|
12
|
+
use crate::syntax::YerbaValueType;
|
|
13
|
+
|
|
14
|
+
#[derive(Debug, Clone)]
|
|
15
|
+
pub struct LocatedNode {
|
|
16
|
+
pub node_type: String,
|
|
17
|
+
pub text: Option<String>,
|
|
18
|
+
pub value_type: Option<YerbaValueType>,
|
|
19
|
+
pub file_path: Option<String>,
|
|
20
|
+
pub selector: String,
|
|
21
|
+
pub line: usize,
|
|
22
|
+
}
|
|
8
23
|
|
|
9
24
|
use std::fs;
|
|
10
25
|
use std::path::{Path, PathBuf};
|
|
@@ -19,8 +34,8 @@ use crate::error::YerbaError;
|
|
|
19
34
|
use crate::QuoteStyle;
|
|
20
35
|
|
|
21
36
|
use crate::syntax::{
|
|
22
|
-
extract_scalar, extract_scalar_text, find_entry_by_key, find_scalar_token, format_scalar_value, is_map_key, is_yaml_non_string,
|
|
23
|
-
removal_range, unescape_double_quoted, unescape_single_quoted, ScalarValue,
|
|
37
|
+
dedent_block_scalar, extract_scalar, extract_scalar_text, find_entry_by_key, find_scalar_token, format_scalar_value, is_map_key, is_yaml_non_string,
|
|
38
|
+
preceding_whitespace_indent, removal_range, unescape_double_quoted, unescape_single_quoted, ScalarValue,
|
|
24
39
|
};
|
|
25
40
|
|
|
26
41
|
#[derive(Debug, Clone)]
|
|
@@ -155,7 +170,7 @@ impl Document {
|
|
|
155
170
|
return Ok(document.syntax().clone());
|
|
156
171
|
}
|
|
157
172
|
|
|
158
|
-
let nodes = self.
|
|
173
|
+
let nodes = self.navigate_all_compact(dot_path);
|
|
159
174
|
|
|
160
175
|
match nodes.len() {
|
|
161
176
|
0 => Err(YerbaError::SelectorNotFound(dot_path.to_string())),
|
|
@@ -164,7 +179,11 @@ impl Document {
|
|
|
164
179
|
}
|
|
165
180
|
}
|
|
166
181
|
|
|
167
|
-
pub fn
|
|
182
|
+
pub fn navigate_all_compact(&self, dot_path: &str) -> Vec<SyntaxNode> {
|
|
183
|
+
self.navigate_all(dot_path).into_iter().flatten().collect()
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
pub fn navigate_all(&self, dot_path: &str) -> Vec<Option<SyntaxNode>> {
|
|
168
187
|
if Document::validate_path(dot_path).is_err() {
|
|
169
188
|
return Vec::new();
|
|
170
189
|
}
|
|
@@ -181,26 +200,63 @@ impl Document {
|
|
|
181
200
|
None => return Vec::new(),
|
|
182
201
|
};
|
|
183
202
|
|
|
184
|
-
let mut current_nodes = vec![document.syntax().clone()];
|
|
203
|
+
let mut current_nodes: Vec<Option<SyntaxNode>> = vec![Some(document.syntax().clone())];
|
|
185
204
|
|
|
186
205
|
if parsed.is_empty() {
|
|
187
206
|
if let Some(sequence) = document.syntax().descendants().find_map(BlockSeq::cast) {
|
|
188
|
-
current_nodes = sequence.entries().map(|entry| entry.syntax().clone()).collect();
|
|
207
|
+
current_nodes = sequence.entries().map(|entry| Some(entry.syntax().clone())).collect();
|
|
189
208
|
}
|
|
190
209
|
|
|
191
210
|
return current_nodes;
|
|
192
211
|
}
|
|
193
212
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
213
|
+
let segments = parsed.segments();
|
|
214
|
+
|
|
215
|
+
for (i, segment) in segments.iter().enumerate() {
|
|
216
|
+
let is_wildcard = matches!(segment, crate::selector::SelectorSegment::AllItems);
|
|
217
|
+
let has_remaining = i + 1 < segments.len();
|
|
218
|
+
let mut next_nodes: Vec<Option<SyntaxNode>> = Vec::new();
|
|
219
|
+
|
|
220
|
+
for maybe_node in ¤t_nodes {
|
|
221
|
+
match maybe_node {
|
|
222
|
+
None => next_nodes.push(None),
|
|
223
|
+
Some(node) => {
|
|
224
|
+
let resolved = resolve_segment(node, segment);
|
|
225
|
+
|
|
226
|
+
if is_wildcard && has_remaining {
|
|
227
|
+
let remaining = &segments[i + 1..];
|
|
228
|
+
|
|
229
|
+
for item in &resolved {
|
|
230
|
+
let results = navigate_remaining(item, remaining);
|
|
231
|
+
|
|
232
|
+
if results.is_empty() {
|
|
233
|
+
next_nodes.push(None);
|
|
234
|
+
} else {
|
|
235
|
+
for result in results {
|
|
236
|
+
next_nodes.push(Some(result));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return next_nodes;
|
|
242
|
+
} else if is_wildcard {
|
|
243
|
+
for item in resolved {
|
|
244
|
+
next_nodes.push(Some(item));
|
|
245
|
+
}
|
|
246
|
+
} else if resolved.is_empty() {
|
|
247
|
+
return Vec::new();
|
|
248
|
+
} else {
|
|
249
|
+
for item in resolved {
|
|
250
|
+
next_nodes.push(Some(item));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
199
255
|
}
|
|
200
256
|
|
|
201
257
|
current_nodes = next_nodes;
|
|
202
258
|
|
|
203
|
-
if current_nodes.
|
|
259
|
+
if current_nodes.iter().all(|n| n.is_none()) {
|
|
204
260
|
break;
|
|
205
261
|
}
|
|
206
262
|
}
|
|
@@ -389,11 +445,11 @@ pub(crate) fn compute_location(source: &str, start_offset: usize, end_offset: us
|
|
|
389
445
|
}
|
|
390
446
|
}
|
|
391
447
|
|
|
392
|
-
pub fn collect_selectors(value: &
|
|
448
|
+
pub fn collect_selectors(value: &yaml_serde::Value, prefix: &str, selectors: &mut Vec<String>) {
|
|
393
449
|
match value {
|
|
394
|
-
|
|
450
|
+
yaml_serde::Value::Mapping(map) => {
|
|
395
451
|
for (key, child) in map {
|
|
396
|
-
if let
|
|
452
|
+
if let yaml_serde::Value::String(key_string) = key {
|
|
397
453
|
let selector = if prefix.is_empty() {
|
|
398
454
|
key_string.clone()
|
|
399
455
|
} else {
|
|
@@ -406,7 +462,7 @@ pub fn collect_selectors(value: &serde_yaml::Value, prefix: &str, selectors: &mu
|
|
|
406
462
|
}
|
|
407
463
|
}
|
|
408
464
|
|
|
409
|
-
|
|
465
|
+
yaml_serde::Value::Sequence(sequence) => {
|
|
410
466
|
let bracket_prefix = format!("{}[]", prefix);
|
|
411
467
|
selectors.push(bracket_prefix.clone());
|
|
412
468
|
|
|
@@ -419,21 +475,21 @@ pub fn collect_selectors(value: &serde_yaml::Value, prefix: &str, selectors: &mu
|
|
|
419
475
|
}
|
|
420
476
|
}
|
|
421
477
|
|
|
422
|
-
pub(crate) fn node_to_yaml_value(node: &SyntaxNode) ->
|
|
478
|
+
pub(crate) fn node_to_yaml_value(node: &SyntaxNode) -> yaml_serde::Value {
|
|
423
479
|
if let Some(sequence) = node.descendants().find_map(BlockSeq::cast) {
|
|
424
480
|
let map_position = node.descendants().find_map(BlockMap::cast).map(|map| map.syntax().text_range().start());
|
|
425
481
|
|
|
426
482
|
let sequence_position = sequence.syntax().text_range().start();
|
|
427
483
|
|
|
428
484
|
if map_position.is_none() || sequence_position <= map_position.unwrap() {
|
|
429
|
-
let values: Vec<
|
|
485
|
+
let values: Vec<yaml_serde::Value> = sequence.entries().map(|entry| node_to_yaml_value(entry.syntax())).collect();
|
|
430
486
|
|
|
431
|
-
return
|
|
487
|
+
return yaml_serde::Value::Sequence(values);
|
|
432
488
|
}
|
|
433
489
|
}
|
|
434
490
|
|
|
435
491
|
if let Some(map) = node.descendants().find_map(BlockMap::cast) {
|
|
436
|
-
let mut mapping =
|
|
492
|
+
let mut mapping = yaml_serde::Mapping::new();
|
|
437
493
|
|
|
438
494
|
for entry in map.entries() {
|
|
439
495
|
let key = entry.key().and_then(|key_node| extract_scalar_text(key_node.syntax())).unwrap_or_default();
|
|
@@ -441,18 +497,18 @@ pub(crate) fn node_to_yaml_value(node: &SyntaxNode) -> serde_yaml::Value {
|
|
|
441
497
|
let value = entry
|
|
442
498
|
.value()
|
|
443
499
|
.map(|value_node| node_to_yaml_value(value_node.syntax()))
|
|
444
|
-
.unwrap_or(
|
|
500
|
+
.unwrap_or(yaml_serde::Value::Null);
|
|
445
501
|
|
|
446
|
-
mapping.insert(
|
|
502
|
+
mapping.insert(yaml_serde::Value::String(key), value);
|
|
447
503
|
}
|
|
448
504
|
|
|
449
|
-
return
|
|
505
|
+
return yaml_serde::Value::Mapping(mapping);
|
|
450
506
|
}
|
|
451
507
|
|
|
452
508
|
if let Some(sequence) = node.descendants().find_map(BlockSeq::cast) {
|
|
453
|
-
let values: Vec<
|
|
509
|
+
let values: Vec<yaml_serde::Value> = sequence.entries().map(|entry| node_to_yaml_value(entry.syntax())).collect();
|
|
454
510
|
|
|
455
|
-
return
|
|
511
|
+
return yaml_serde::Value::Sequence(values);
|
|
456
512
|
}
|
|
457
513
|
|
|
458
514
|
if let Some(block_scalar) = node.descendants().find(|child| child.kind() == SyntaxKind::BLOCK_SCALAR) {
|
|
@@ -463,35 +519,37 @@ pub(crate) fn node_to_yaml_value(node: &SyntaxNode) -> serde_yaml::Value {
|
|
|
463
519
|
.map(|token| token.text().to_string())
|
|
464
520
|
.unwrap_or_default();
|
|
465
521
|
|
|
466
|
-
|
|
522
|
+
let text = dedent_block_scalar(&text);
|
|
523
|
+
|
|
524
|
+
return yaml_serde::Value::String(text);
|
|
467
525
|
}
|
|
468
526
|
|
|
469
527
|
if let Some(scalar) = extract_scalar(node) {
|
|
470
528
|
use crate::syntax::{detect_yaml_type, is_yaml_truthy, YerbaValueType};
|
|
471
529
|
|
|
472
530
|
return match detect_yaml_type(&scalar) {
|
|
473
|
-
YerbaValueType::Null =>
|
|
474
|
-
YerbaValueType::Boolean =>
|
|
531
|
+
YerbaValueType::Null => yaml_serde::Value::Null,
|
|
532
|
+
YerbaValueType::Boolean => yaml_serde::Value::Bool(is_yaml_truthy(&scalar.text)),
|
|
475
533
|
|
|
476
534
|
YerbaValueType::Integer => scalar
|
|
477
535
|
.text
|
|
478
536
|
.parse::<i64>()
|
|
479
|
-
.map(|n|
|
|
480
|
-
.unwrap_or(
|
|
537
|
+
.map(|n| yaml_serde::Value::Number(yaml_serde::Number::from(n)))
|
|
538
|
+
.unwrap_or(yaml_serde::Value::String(scalar.text)),
|
|
481
539
|
|
|
482
540
|
YerbaValueType::Float => scalar
|
|
483
541
|
.text
|
|
484
542
|
.parse::<f64>()
|
|
485
|
-
.map(|n|
|
|
486
|
-
.unwrap_or(
|
|
543
|
+
.map(|n| yaml_serde::Value::Number(yaml_serde::Number::from(n)))
|
|
544
|
+
.unwrap_or(yaml_serde::Value::String(scalar.text)),
|
|
487
545
|
|
|
488
|
-
YerbaValueType::String =>
|
|
546
|
+
YerbaValueType::String => yaml_serde::Value::String(scalar.text),
|
|
489
547
|
};
|
|
490
548
|
}
|
|
491
549
|
|
|
492
550
|
let text = node.text().to_string();
|
|
493
551
|
|
|
494
|
-
|
|
552
|
+
yaml_serde::from_str(&text).unwrap_or(yaml_serde::Value::String(text))
|
|
495
553
|
}
|
|
496
554
|
|
|
497
555
|
pub(crate) fn parse_condition(condition: &str) -> Option<(String, &str, String)> {
|
|
@@ -516,6 +574,26 @@ pub(crate) fn parse_condition(condition: &str) -> Option<(String, &str, String)>
|
|
|
516
574
|
Some((left.to_string(), operator, right.to_string()))
|
|
517
575
|
}
|
|
518
576
|
|
|
577
|
+
fn navigate_remaining(node: &SyntaxNode, segments: &[crate::selector::SelectorSegment]) -> Vec<SyntaxNode> {
|
|
578
|
+
let mut current_nodes = vec![node.clone()];
|
|
579
|
+
|
|
580
|
+
for segment in segments {
|
|
581
|
+
let mut next_nodes = Vec::new();
|
|
582
|
+
|
|
583
|
+
for current in ¤t_nodes {
|
|
584
|
+
next_nodes.extend(resolve_segment(current, segment));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if next_nodes.is_empty() {
|
|
588
|
+
return Vec::new();
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
current_nodes = next_nodes;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
current_nodes
|
|
595
|
+
}
|
|
596
|
+
|
|
519
597
|
fn resolve_segment(node: &SyntaxNode, segment: &crate::selector::SelectorSegment) -> Vec<SyntaxNode> {
|
|
520
598
|
use crate::selector::SelectorSegment;
|
|
521
599
|
|