yerba 0.9.1-arm-linux-gnu → 0.10.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.
- checksums.yaml +4 -4
- data/README.md +60 -16
- data/exe/arm-linux-gnu/yerba +0 -0
- data/ext/yerba/include/yerba.h +67 -32
- data/ext/yerba/yerba.c +296 -186
- data/lib/yerba/3.2/yerba.so +0 -0
- data/lib/yerba/3.3/yerba.so +0 -0
- data/lib/yerba/3.4/yerba.so +0 -0
- data/lib/yerba/4.0/yerba.so +0 -0
- data/lib/yerba/collection.rb +4 -4
- data/lib/yerba/document.rb +134 -0
- data/lib/yerba/formatting.rb +1 -0
- data/lib/yerba/location.rb +8 -1
- data/lib/yerba/map.rb +16 -6
- data/lib/yerba/node.rb +41 -0
- data/lib/yerba/query_result.rb +33 -10
- data/lib/yerba/scalar.rb +29 -0
- data/lib/yerba/selector.rb +142 -0
- data/lib/yerba/sequence.rb +38 -33
- data/lib/yerba/version.rb +1 -1
- data/lib/yerba.rb +1 -0
- data/rust/Cargo.lock +1 -1
- data/rust/Cargo.toml +1 -1
- data/rust/src/commands/get.rs +12 -12
- data/rust/src/commands/init.rs +8 -8
- data/rust/src/commands/insert.rs +4 -18
- data/rust/src/commands/location.rs +2 -0
- data/rust/src/commands/mod.rs +34 -6
- data/rust/src/commands/move_item.rs +1 -1
- data/rust/src/commands/move_key.rs +8 -8
- data/rust/src/commands/rename.rs +1 -1
- data/rust/src/commands/selectors.rs +1 -1
- data/rust/src/commands/set.rs +14 -6
- data/rust/src/document/condition.rs +25 -25
- data/rust/src/document/delete.rs +57 -43
- data/rust/src/document/get.rs +91 -82
- data/rust/src/document/insert.rs +77 -77
- data/rust/src/document/mod.rs +138 -64
- data/rust/src/document/nodes.rs +162 -0
- data/rust/src/document/schema.rs +8 -8
- data/rust/src/document/set.rs +49 -26
- data/rust/src/document/sort.rs +54 -54
- data/rust/src/document/style.rs +50 -49
- data/rust/src/document/unique.rs +5 -5
- data/rust/src/error.rs +8 -4
- data/rust/src/ffi.rs +272 -102
- data/rust/src/json.rs +62 -2
- data/rust/src/lib.rs +2 -1
- data/rust/src/main.rs +2 -1
- data/rust/src/selector.rs +48 -7
- data/rust/src/syntax.rs +449 -56
- data/rust/src/validation.rs +5 -3
- data/rust/src/yerbafile.rs +124 -76
- metadata +4 -2
data/rust/src/document/mod.rs
CHANGED
|
@@ -2,6 +2,7 @@ mod condition;
|
|
|
2
2
|
mod delete;
|
|
3
3
|
mod get;
|
|
4
4
|
mod insert;
|
|
5
|
+
mod nodes;
|
|
5
6
|
mod set;
|
|
6
7
|
mod sort;
|
|
7
8
|
mod unique;
|
|
@@ -32,6 +33,7 @@ pub struct LocatedNode {
|
|
|
32
33
|
use std::fs;
|
|
33
34
|
use std::path::{Path, PathBuf};
|
|
34
35
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
36
|
+
use std::sync::OnceLock;
|
|
35
37
|
|
|
36
38
|
use rowan::ast::AstNode;
|
|
37
39
|
use rowan::{TextRange, TextSize};
|
|
@@ -46,34 +48,34 @@ use crate::syntax::{
|
|
|
46
48
|
column_at, dedent_block_scalar, extract_scalar, extract_scalar_text, find_block_map, find_block_sequence, find_entry_by_key, find_flow_entry_by_key,
|
|
47
49
|
find_flow_map, find_flow_sequence, find_scalar_token, first_collection, flow_map_entries, flow_sequence_entries, format_scalar_value, in_flow_collection,
|
|
48
50
|
is_map_key, is_yaml_non_string, line_at, line_start_at, preceding_whitespace_indent, preceding_whitespace_token, raw_scalar_value, removal_range,
|
|
49
|
-
FirstCollection, ScalarValue,
|
|
51
|
+
FirstCollection, LineIndex, ScalarValue,
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
#[derive(Debug, Clone)]
|
|
53
55
|
pub struct SortField {
|
|
54
|
-
pub
|
|
56
|
+
pub selector: String,
|
|
55
57
|
pub ascending: bool,
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
impl SortField {
|
|
59
|
-
pub fn asc(
|
|
61
|
+
pub fn asc(selector: &str) -> Self {
|
|
60
62
|
SortField {
|
|
61
|
-
|
|
63
|
+
selector: selector.to_string(),
|
|
62
64
|
ascending: true,
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
pub fn desc(
|
|
68
|
+
pub fn desc(selector: &str) -> Self {
|
|
67
69
|
SortField {
|
|
68
|
-
|
|
70
|
+
selector: selector.to_string(),
|
|
69
71
|
ascending: false,
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
pub fn parse(input: &str) -> Self {
|
|
74
|
-
if let Some((
|
|
76
|
+
if let Some((selector, direction)) = input.rsplit_once(':') {
|
|
75
77
|
match direction {
|
|
76
|
-
"desc" | "descending" => SortField::desc(
|
|
78
|
+
"desc" | "descending" => SortField::desc(selector),
|
|
77
79
|
_ => SortField::asc(input),
|
|
78
80
|
}
|
|
79
81
|
} else {
|
|
@@ -82,7 +84,35 @@ impl SortField {
|
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
pub fn parse_list(input: &str) -> Vec<Self> {
|
|
85
|
-
|
|
87
|
+
let mut fields = Vec::new();
|
|
88
|
+
let mut current = String::new();
|
|
89
|
+
let mut depth = 0usize;
|
|
90
|
+
let mut quote: Option<char> = None;
|
|
91
|
+
|
|
92
|
+
for character in input.chars() {
|
|
93
|
+
match (quote, character) {
|
|
94
|
+
(Some(open), _) if character == open => quote = None,
|
|
95
|
+
(Some(_), _) => {}
|
|
96
|
+
(None, '"' | '\'') => quote = Some(character),
|
|
97
|
+
(None, '[') => depth += 1,
|
|
98
|
+
(None, ']') => depth = depth.saturating_sub(1),
|
|
99
|
+
(None, ',') if depth == 0 => {
|
|
100
|
+
fields.push(std::mem::take(&mut current));
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
(None, _) if character.is_whitespace() && depth == 0 => {
|
|
104
|
+
fields.push(std::mem::take(&mut current));
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
_ => {}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
current.push(character);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
fields.push(current);
|
|
114
|
+
|
|
115
|
+
fields.iter().filter(|field| !field.is_empty()).map(|field| SortField::parse(field)).collect()
|
|
86
116
|
}
|
|
87
117
|
}
|
|
88
118
|
|
|
@@ -103,6 +133,8 @@ pub struct Location {
|
|
|
103
133
|
pub end_column: usize,
|
|
104
134
|
pub start_offset: usize,
|
|
105
135
|
pub end_offset: usize,
|
|
136
|
+
pub start_character_column: usize,
|
|
137
|
+
pub end_character_column: usize,
|
|
106
138
|
}
|
|
107
139
|
|
|
108
140
|
#[derive(Debug)]
|
|
@@ -127,6 +159,28 @@ pub enum InsertPosition {
|
|
|
127
159
|
FromSortOrder(Vec<String>),
|
|
128
160
|
}
|
|
129
161
|
|
|
162
|
+
impl InsertPosition {
|
|
163
|
+
pub fn before(target: impl Into<String>) -> Self {
|
|
164
|
+
let target = target.into();
|
|
165
|
+
|
|
166
|
+
if target.starts_with('.') {
|
|
167
|
+
InsertPosition::BeforeCondition(target)
|
|
168
|
+
} else {
|
|
169
|
+
InsertPosition::Before(target)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
pub fn after(target: impl Into<String>) -> Self {
|
|
174
|
+
let target = target.into();
|
|
175
|
+
|
|
176
|
+
if target.starts_with('.') {
|
|
177
|
+
InsertPosition::AfterCondition(target)
|
|
178
|
+
} else {
|
|
179
|
+
InsertPosition::After(target)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
130
184
|
static NEXT_GENERATION: AtomicU64 = AtomicU64::new(1);
|
|
131
185
|
|
|
132
186
|
#[derive(Debug)]
|
|
@@ -134,6 +188,7 @@ pub struct Document {
|
|
|
134
188
|
root: SyntaxNode,
|
|
135
189
|
path: Option<PathBuf>,
|
|
136
190
|
generation: u64,
|
|
191
|
+
line_index: OnceLock<LineIndex>,
|
|
137
192
|
}
|
|
138
193
|
|
|
139
194
|
impl Document {
|
|
@@ -146,6 +201,7 @@ impl Document {
|
|
|
146
201
|
root: tree,
|
|
147
202
|
path: None,
|
|
148
203
|
generation: NEXT_GENERATION.fetch_add(1, Ordering::Relaxed),
|
|
204
|
+
line_index: OnceLock::new(),
|
|
149
205
|
})
|
|
150
206
|
}
|
|
151
207
|
|
|
@@ -181,49 +237,49 @@ impl Document {
|
|
|
181
237
|
Ok(())
|
|
182
238
|
}
|
|
183
239
|
|
|
184
|
-
pub fn source(&self,
|
|
185
|
-
let node = self.navigate(
|
|
240
|
+
pub fn source(&self, selector: &str) -> Result<String, YerbaError> {
|
|
241
|
+
let node = self.navigate(selector)?;
|
|
186
242
|
Ok(node.text().to_string())
|
|
187
243
|
}
|
|
188
244
|
|
|
189
|
-
pub fn navigate(&self,
|
|
190
|
-
Self::
|
|
245
|
+
pub fn navigate(&self, selector: &str) -> Result<SyntaxNode, YerbaError> {
|
|
246
|
+
Self::validate_selector(selector)?;
|
|
191
247
|
|
|
192
|
-
if
|
|
193
|
-
let root = Root::cast(self.root.clone()).ok_or_else(|| YerbaError::SelectorNotFound(
|
|
248
|
+
if selector.is_empty() {
|
|
249
|
+
let root = Root::cast(self.root.clone()).ok_or_else(|| YerbaError::SelectorNotFound(selector.to_string()))?;
|
|
194
250
|
|
|
195
|
-
let document = root.documents().next().ok_or_else(|| YerbaError::SelectorNotFound(
|
|
251
|
+
let document = root.documents().next().ok_or_else(|| YerbaError::SelectorNotFound(selector.to_string()))?;
|
|
196
252
|
|
|
197
253
|
return Ok(document.syntax().clone());
|
|
198
254
|
}
|
|
199
255
|
|
|
200
|
-
let nodes = self.navigate_all_compact(
|
|
256
|
+
let nodes = self.navigate_all_compact(selector);
|
|
201
257
|
|
|
202
258
|
match nodes.len() {
|
|
203
|
-
0 => Err(YerbaError::SelectorNotFound(
|
|
259
|
+
0 => Err(YerbaError::SelectorNotFound(selector.to_string())),
|
|
204
260
|
1 => Ok(nodes.into_iter().next().unwrap()),
|
|
205
|
-
_ => Err(YerbaError::AmbiguousSelector(
|
|
261
|
+
_ => Err(YerbaError::AmbiguousSelector(selector.to_string(), nodes.len())),
|
|
206
262
|
}
|
|
207
263
|
}
|
|
208
264
|
|
|
209
|
-
pub fn navigate_all_compact(&self,
|
|
210
|
-
self.navigate_all(
|
|
265
|
+
pub fn navigate_all_compact(&self, selector: &str) -> Vec<SyntaxNode> {
|
|
266
|
+
self.navigate_all(selector).into_iter().flatten().collect()
|
|
211
267
|
}
|
|
212
268
|
|
|
213
|
-
pub(crate) fn refuse_flow_target(&self,
|
|
214
|
-
if self.navigate_all_compact(
|
|
215
|
-
return Err(YerbaError::FlowCollectionNotWritable(
|
|
269
|
+
pub(crate) fn refuse_flow_target(&self, selector: &str) -> Result<(), YerbaError> {
|
|
270
|
+
if self.navigate_all_compact(selector).iter().any(in_flow_collection) {
|
|
271
|
+
return Err(YerbaError::FlowCollectionNotWritable(selector.to_string()));
|
|
216
272
|
}
|
|
217
273
|
|
|
218
274
|
Ok(())
|
|
219
275
|
}
|
|
220
276
|
|
|
221
|
-
pub fn navigate_all(&self,
|
|
222
|
-
if Document::
|
|
277
|
+
pub fn navigate_all(&self, selector: &str) -> Vec<Option<SyntaxNode>> {
|
|
278
|
+
if Document::validate_selector(selector).is_err() {
|
|
223
279
|
return Vec::new();
|
|
224
280
|
}
|
|
225
281
|
|
|
226
|
-
let parsed = crate::selector::Selector::parse(
|
|
282
|
+
let parsed = crate::selector::Selector::parse(selector);
|
|
227
283
|
|
|
228
284
|
let root = match Root::cast(self.root.clone()) {
|
|
229
285
|
Some(root) => root,
|
|
@@ -299,21 +355,21 @@ impl Document {
|
|
|
299
355
|
current_nodes
|
|
300
356
|
}
|
|
301
357
|
|
|
302
|
-
pub fn
|
|
303
|
-
if
|
|
304
|
-
return Err(YerbaError::ParseError(format!("invalid
|
|
358
|
+
pub fn validate_selector(selector: &str) -> Result<(), YerbaError> {
|
|
359
|
+
if selector.ends_with('.') {
|
|
360
|
+
return Err(YerbaError::ParseError(format!("invalid selector: trailing dot in '{}'", selector)));
|
|
305
361
|
}
|
|
306
362
|
|
|
307
|
-
if
|
|
308
|
-
return Err(YerbaError::ParseError(format!("invalid
|
|
363
|
+
if selector.contains("..") {
|
|
364
|
+
return Err(YerbaError::ParseError(format!("invalid selector: double dot in '{}'", selector)));
|
|
309
365
|
}
|
|
310
366
|
|
|
311
|
-
if
|
|
312
|
-
return Err(YerbaError::ParseError(format!("invalid
|
|
367
|
+
if selector.starts_with('.') {
|
|
368
|
+
return Err(YerbaError::ParseError(format!("invalid selector: leading dot in '{}'", selector)));
|
|
313
369
|
}
|
|
314
370
|
|
|
315
|
-
if
|
|
316
|
-
return Err(YerbaError::ParseError(format!("invalid
|
|
371
|
+
if selector.contains('[') && !selector.contains(']') {
|
|
372
|
+
return Err(YerbaError::ParseError(format!("invalid selector: unclosed bracket in '{}'", selector)));
|
|
317
373
|
}
|
|
318
374
|
|
|
319
375
|
Ok(())
|
|
@@ -487,6 +543,10 @@ impl Document {
|
|
|
487
543
|
self.root.text().to_string()
|
|
488
544
|
}
|
|
489
545
|
|
|
546
|
+
fn line_index(&self) -> &LineIndex {
|
|
547
|
+
self.line_index.get_or_init(|| LineIndex::new(&self.source_text()))
|
|
548
|
+
}
|
|
549
|
+
|
|
490
550
|
fn reparse(&mut self, new_source: &str) -> Result<(), YerbaError> {
|
|
491
551
|
let document = Self::parse(new_source)?;
|
|
492
552
|
let path = self.path.take();
|
|
@@ -538,17 +598,19 @@ fn check_duplicate_keys(root: &SyntaxNode) -> Result<(), YerbaError> {
|
|
|
538
598
|
Ok(())
|
|
539
599
|
}
|
|
540
600
|
|
|
541
|
-
pub(crate) fn compute_location(
|
|
542
|
-
let start = start_offset.min(
|
|
543
|
-
let end = end_offset.min(
|
|
601
|
+
pub(crate) fn compute_location(index: &LineIndex, start_offset: usize, end_offset: usize) -> Location {
|
|
602
|
+
let start = start_offset.min(index.source_length());
|
|
603
|
+
let end = end_offset.min(index.source_length());
|
|
544
604
|
|
|
545
605
|
Location {
|
|
546
606
|
start_offset: start,
|
|
547
607
|
end_offset: end,
|
|
548
|
-
start_line: line_at(
|
|
549
|
-
start_column: column_at(
|
|
550
|
-
end_line: line_at(
|
|
551
|
-
end_column: column_at(
|
|
608
|
+
start_line: index.line_at(start),
|
|
609
|
+
start_column: index.column_at(start),
|
|
610
|
+
end_line: index.line_at(end),
|
|
611
|
+
end_column: index.column_at(end),
|
|
612
|
+
start_character_column: index.character_column_at(start),
|
|
613
|
+
end_character_column: index.character_column_at(end),
|
|
552
614
|
}
|
|
553
615
|
}
|
|
554
616
|
|
|
@@ -635,25 +697,17 @@ pub(crate) fn node_to_yaml_value(node: &SyntaxNode) -> yaml_serde::Value {
|
|
|
635
697
|
}
|
|
636
698
|
|
|
637
699
|
if let Some(scalar) = extract_scalar(node) {
|
|
638
|
-
use crate::syntax::{
|
|
639
|
-
|
|
640
|
-
return match
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
YerbaValueType::Float => scalar
|
|
651
|
-
.text
|
|
652
|
-
.parse::<f64>()
|
|
653
|
-
.map(|n| yaml_serde::Value::Number(yaml_serde::Number::from(n)))
|
|
654
|
-
.unwrap_or(yaml_serde::Value::String(scalar.text)),
|
|
655
|
-
|
|
656
|
-
YerbaValueType::String => yaml_serde::Value::String(scalar.text),
|
|
700
|
+
use crate::syntax::{resolve_scalar, PlainScalar};
|
|
701
|
+
|
|
702
|
+
return match resolve_scalar(&scalar) {
|
|
703
|
+
PlainScalar::Null => yaml_serde::Value::Null,
|
|
704
|
+
PlainScalar::Boolean(boolean) => yaml_serde::Value::Bool(boolean),
|
|
705
|
+
PlainScalar::Integer(integer) => yaml_serde::Value::Number(match i64::try_from(integer) {
|
|
706
|
+
Ok(integer) => yaml_serde::Number::from(integer),
|
|
707
|
+
Err(_) => yaml_serde::Number::from(integer as u64),
|
|
708
|
+
}),
|
|
709
|
+
PlainScalar::Float(float) => yaml_serde::Value::Number(yaml_serde::Number::from(float)),
|
|
710
|
+
PlainScalar::String => yaml_serde::Value::String(scalar.text),
|
|
657
711
|
};
|
|
658
712
|
}
|
|
659
713
|
|
|
@@ -728,6 +782,26 @@ fn resolve_segment(node: &SyntaxNode, segment: &crate::selector::SelectorSegment
|
|
|
728
782
|
}
|
|
729
783
|
}
|
|
730
784
|
|
|
785
|
+
SelectorSegment::IndexFromEnd(_) => {
|
|
786
|
+
if let Some(sequence) = find_block_sequence(node) {
|
|
787
|
+
segment
|
|
788
|
+
.sequence_index(sequence.entries().count())
|
|
789
|
+
.and_then(|index| sequence.entries().nth(index))
|
|
790
|
+
.map(|entry| vec![entry.syntax().clone()])
|
|
791
|
+
.unwrap_or_default()
|
|
792
|
+
} else if let Some(sequence) = find_flow_sequence(node) {
|
|
793
|
+
let entries = flow_sequence_entries(&sequence);
|
|
794
|
+
|
|
795
|
+
segment
|
|
796
|
+
.sequence_index(entries.len())
|
|
797
|
+
.and_then(|index| entries.into_iter().nth(index))
|
|
798
|
+
.map(|entry| vec![entry])
|
|
799
|
+
.unwrap_or_default()
|
|
800
|
+
} else {
|
|
801
|
+
Vec::new()
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
731
805
|
SelectorSegment::AllKeys => {
|
|
732
806
|
if let Some(map) = find_block_map(node) {
|
|
733
807
|
map.entries().filter_map(|entry| entry.value().map(|value| value.syntax().clone())).collect()
|
|
@@ -765,8 +839,8 @@ fn resolve_segment(node: &SyntaxNode, segment: &crate::selector::SelectorSegment
|
|
|
765
839
|
}
|
|
766
840
|
}
|
|
767
841
|
|
|
768
|
-
pub(crate) fn navigate_from_node(node: &SyntaxNode,
|
|
769
|
-
let parsed = crate::selector::Selector::parse(
|
|
842
|
+
pub(crate) fn navigate_from_node(node: &SyntaxNode, selector: &str) -> Vec<SyntaxNode> {
|
|
843
|
+
let parsed = crate::selector::Selector::parse(selector);
|
|
770
844
|
|
|
771
845
|
navigate_remaining(node, parsed.segments())
|
|
772
846
|
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
|
|
3
|
+
#[derive(Debug)]
|
|
4
|
+
pub struct NodeRecord {
|
|
5
|
+
pub parent: Option<usize>,
|
|
6
|
+
pub node_type: NodeType,
|
|
7
|
+
pub selector: String,
|
|
8
|
+
pub key_name: Option<String>,
|
|
9
|
+
pub scalar: Option<ScalarValue>,
|
|
10
|
+
pub has_value: bool,
|
|
11
|
+
pub location: Location,
|
|
12
|
+
pub key_location: Location,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fn location_of(lines: &LineIndex, range: TextRange) -> Location {
|
|
16
|
+
compute_location(lines, range.start().into(), range.end().into())
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fn collection_type(node: &SyntaxNode) -> Option<NodeType> {
|
|
20
|
+
let mut flow = None;
|
|
21
|
+
|
|
22
|
+
for descendant in node.descendants() {
|
|
23
|
+
match descendant.kind() {
|
|
24
|
+
SyntaxKind::BLOCK_SEQ => return Some(NodeType::Sequence),
|
|
25
|
+
SyntaxKind::BLOCK_MAP => return Some(NodeType::Map),
|
|
26
|
+
SyntaxKind::FLOW_SEQ if flow.is_none() => flow = Some(NodeType::Sequence),
|
|
27
|
+
SyntaxKind::FLOW_MAP if flow.is_none() => flow = Some(NodeType::Map),
|
|
28
|
+
_ => {}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
flow
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
struct Walker<'a> {
|
|
36
|
+
lines: &'a LineIndex,
|
|
37
|
+
records: Vec<NodeRecord>,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
impl Walker<'_> {
|
|
41
|
+
fn push(&mut self, parent: Option<usize>, node: Option<&SyntaxNode>, selector: String, key: Option<(String, Location)>) {
|
|
42
|
+
let collection = node.and_then(collection_type);
|
|
43
|
+
let scalar = match (node, collection) {
|
|
44
|
+
(Some(node), None) => extract_scalar(node),
|
|
45
|
+
_ => None,
|
|
46
|
+
};
|
|
47
|
+
let node_type = match (collection, &scalar) {
|
|
48
|
+
(Some(node_type), _) => node_type,
|
|
49
|
+
(None, Some(_)) => NodeType::Scalar,
|
|
50
|
+
(None, None) => NodeType::NotFound,
|
|
51
|
+
};
|
|
52
|
+
let location = match node {
|
|
53
|
+
Some(node) if parent.is_some() || !matches!(node_type, NodeType::Sequence) => location_of(self.lines, node.text_range()),
|
|
54
|
+
_ => Location::default(),
|
|
55
|
+
};
|
|
56
|
+
let (key_name, key_location) = key.map(|(name, location)| (Some(name), location)).unwrap_or((None, Location::default()));
|
|
57
|
+
|
|
58
|
+
let index = self.records.len();
|
|
59
|
+
|
|
60
|
+
self.records.push(NodeRecord {
|
|
61
|
+
parent,
|
|
62
|
+
node_type,
|
|
63
|
+
selector: selector.clone(),
|
|
64
|
+
key_name,
|
|
65
|
+
scalar,
|
|
66
|
+
has_value: true,
|
|
67
|
+
location,
|
|
68
|
+
key_location,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if let Some(node) = node {
|
|
72
|
+
match node_type {
|
|
73
|
+
NodeType::Sequence => self.sequence_children(index, node, &selector),
|
|
74
|
+
NodeType::Map => self.map_children(index, node, &selector),
|
|
75
|
+
_ => {}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
fn sequence_children(&mut self, index: usize, node: &SyntaxNode, selector: &str) {
|
|
81
|
+
let entries: Vec<SyntaxNode> = if let Some(sequence) = find_block_sequence(node) {
|
|
82
|
+
sequence.entries().map(|entry| entry.syntax().clone()).collect()
|
|
83
|
+
} else if let Some(sequence) = find_flow_sequence(node) {
|
|
84
|
+
flow_sequence_entries(&sequence)
|
|
85
|
+
} else {
|
|
86
|
+
Vec::new()
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
for (position, entry) in entries.iter().enumerate() {
|
|
90
|
+
self.push(Some(index), Some(entry), format!("{}[{}]", selector, position), None);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
fn map_children(&mut self, index: usize, node: &SyntaxNode, selector: &str) {
|
|
95
|
+
let entries: Vec<(SyntaxNode, Option<SyntaxNode>, Option<SyntaxNode>)> = if let Some(map) = find_block_map(node) {
|
|
96
|
+
map
|
|
97
|
+
.entries()
|
|
98
|
+
.map(|entry| {
|
|
99
|
+
(
|
|
100
|
+
entry.syntax().clone(),
|
|
101
|
+
entry.key().map(|key| key.syntax().clone()),
|
|
102
|
+
entry.value().map(|value| value.syntax().clone()),
|
|
103
|
+
)
|
|
104
|
+
})
|
|
105
|
+
.collect()
|
|
106
|
+
} else if let Some(map) = find_flow_map(node) {
|
|
107
|
+
flow_map_entries(&map)
|
|
108
|
+
.into_iter()
|
|
109
|
+
.map(|entry| {
|
|
110
|
+
(
|
|
111
|
+
entry.syntax().clone(),
|
|
112
|
+
entry.key().map(|key| key.syntax().clone()),
|
|
113
|
+
entry.value().map(|value| value.syntax().clone()),
|
|
114
|
+
)
|
|
115
|
+
})
|
|
116
|
+
.collect()
|
|
117
|
+
} else {
|
|
118
|
+
Vec::new()
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
for (entry_node, key_node, value_node) in entries {
|
|
122
|
+
let Some(key_node) = key_node else { continue };
|
|
123
|
+
let Some(key_name) = extract_scalar_text(&key_node) else { continue };
|
|
124
|
+
|
|
125
|
+
let key_location = location_of(self.lines, key_node.text_range());
|
|
126
|
+
let child_selector = if selector.is_empty() {
|
|
127
|
+
key_name.clone()
|
|
128
|
+
} else {
|
|
129
|
+
format!("{}.{}", selector, key_name)
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
match value_node {
|
|
133
|
+
Some(value_node) => self.push(Some(index), Some(&value_node), child_selector, Some((key_name, key_location))),
|
|
134
|
+
None => self.records.push(NodeRecord {
|
|
135
|
+
parent: Some(index),
|
|
136
|
+
node_type: NodeType::Scalar,
|
|
137
|
+
selector: child_selector,
|
|
138
|
+
key_name: Some(key_name),
|
|
139
|
+
scalar: None,
|
|
140
|
+
has_value: false,
|
|
141
|
+
location: location_of(self.lines, entry_node.text_range()),
|
|
142
|
+
key_location,
|
|
143
|
+
}),
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
impl Document {
|
|
150
|
+
pub fn node_records(&self) -> Vec<NodeRecord> {
|
|
151
|
+
let mut walker = Walker {
|
|
152
|
+
lines: self.line_index(),
|
|
153
|
+
records: Vec::new(),
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
if let Some(document) = Root::cast(self.root.clone()).and_then(|root| root.documents().next()) {
|
|
157
|
+
walker.push(None, Some(document.syntax()), String::new(), None);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
walker.records
|
|
161
|
+
}
|
|
162
|
+
}
|
data/rust/src/document/schema.rs
CHANGED
|
@@ -2,10 +2,10 @@ use super::*;
|
|
|
2
2
|
|
|
3
3
|
impl Document {
|
|
4
4
|
pub fn validate_schema(&self, schema: &serde_json::Value, items: bool, selector: Option<&str>) -> Vec<crate::schema::ValidationError> {
|
|
5
|
-
let
|
|
6
|
-
let has_wildcard = crate::selector::Selector::parse(
|
|
5
|
+
let selector = selector.unwrap_or("");
|
|
6
|
+
let has_wildcard = crate::selector::Selector::parse(selector).has_wildcard();
|
|
7
7
|
|
|
8
|
-
let value = match self.get_value(
|
|
8
|
+
let value = match self.get_value(selector) {
|
|
9
9
|
Some(value) => crate::json::yaml_to_json(&value),
|
|
10
10
|
None => return vec![],
|
|
11
11
|
};
|
|
@@ -62,12 +62,12 @@ fn json_pointer_to_selector(pointer: &str) -> String {
|
|
|
62
62
|
segment.to_string()
|
|
63
63
|
}
|
|
64
64
|
})
|
|
65
|
-
.fold(String::new(), |mut
|
|
66
|
-
if !
|
|
67
|
-
|
|
65
|
+
.fold(String::new(), |mut selector, segment| {
|
|
66
|
+
if !selector.is_empty() && !segment.starts_with('[') {
|
|
67
|
+
selector.push('.');
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
selector.push_str(&segment);
|
|
71
|
+
selector
|
|
72
72
|
})
|
|
73
73
|
}
|