yerba 0.9.2-arm-linux-gnu → 0.10.1-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 +53 -17
- data/exe/arm-linux-gnu/yerba +0 -0
- data/ext/yerba/include/yerba.h +58 -35
- data/ext/yerba/yerba.c +281 -187
- 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 +3 -1
- data/lib/yerba/sequence.rb +38 -33
- data/lib/yerba/version.rb +1 -1
- 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/commands/sort.rs +5 -1
- 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 +202 -76
- 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 +105 -60
- 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 +234 -107
- data/rust/src/json.rs +62 -2
- data/rust/src/lib.rs +4 -2
- 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 +168 -94
- metadata +3 -2
data/rust/src/yerbafile.rs
CHANGED
|
@@ -15,16 +15,51 @@ pub struct Yerbafile {
|
|
|
15
15
|
pub rules: Vec<Rule>,
|
|
16
16
|
#[serde(skip)]
|
|
17
17
|
pub directory: Option<PathBuf>,
|
|
18
|
+
#[serde(skip)]
|
|
19
|
+
pub deprecated_path_keys: Vec<String>,
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
#[derive(Debug, Clone, Deserialize)]
|
|
21
23
|
pub struct Rule {
|
|
22
24
|
pub files: String,
|
|
25
|
+
#[serde(default, deserialize_with = "string_or_list")]
|
|
26
|
+
pub exclude: Vec<String>,
|
|
23
27
|
#[serde(default)]
|
|
24
|
-
|
|
28
|
+
#[serde(alias = "path")]
|
|
29
|
+
pub selector: Option<String>,
|
|
25
30
|
pub pipeline: Vec<PipelineStep>,
|
|
26
31
|
}
|
|
27
32
|
|
|
33
|
+
impl Rule {
|
|
34
|
+
pub fn matches(&self, file: &str) -> bool {
|
|
35
|
+
matches_glob(&self.files, file) && !self.excludes(file)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pub fn excludes(&self, file: &str) -> bool {
|
|
39
|
+
self.exclude.iter().any(|pattern| matches_glob(pattern, file))
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fn matches_glob(pattern: &str, file: &str) -> bool {
|
|
44
|
+
glob::Pattern::new(pattern)
|
|
45
|
+
.map(|pattern| pattern.matches(file) || pattern.matches_path(Path::new(file)))
|
|
46
|
+
.unwrap_or(false)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fn string_or_list<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Vec<String>, D::Error> {
|
|
50
|
+
#[derive(Deserialize)]
|
|
51
|
+
#[serde(untagged)]
|
|
52
|
+
enum StringOrList {
|
|
53
|
+
String(String),
|
|
54
|
+
List(Vec<String>),
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Ok(match StringOrList::deserialize(deserializer)? {
|
|
58
|
+
StringOrList::String(string) => vec![string],
|
|
59
|
+
StringOrList::List(list) => list,
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
28
63
|
#[derive(Debug, Clone)]
|
|
29
64
|
pub enum PipelineStep {
|
|
30
65
|
SortKeys(SortKeysConfig),
|
|
@@ -48,17 +83,21 @@ pub enum PipelineStep {
|
|
|
48
83
|
#[derive(Debug, Clone, Deserialize)]
|
|
49
84
|
pub struct SortConfig {
|
|
50
85
|
#[serde(default)]
|
|
51
|
-
|
|
86
|
+
#[serde(alias = "path")]
|
|
87
|
+
pub selector: Option<String>,
|
|
52
88
|
#[serde(default)]
|
|
53
89
|
pub by: Option<String>,
|
|
54
90
|
#[serde(default)]
|
|
55
91
|
pub case_sensitive: bool,
|
|
92
|
+
#[serde(default)]
|
|
93
|
+
pub missing: Option<crate::SortMissing>,
|
|
56
94
|
}
|
|
57
95
|
|
|
58
96
|
#[derive(Debug, Clone, Deserialize)]
|
|
59
97
|
pub struct BlankLinesConfig {
|
|
60
98
|
#[serde(default)]
|
|
61
|
-
|
|
99
|
+
#[serde(alias = "path")]
|
|
100
|
+
pub selector: Option<String>,
|
|
62
101
|
pub count: usize,
|
|
63
102
|
#[serde(default)]
|
|
64
103
|
pub before: Vec<String>,
|
|
@@ -81,7 +120,8 @@ pub struct DirectivesConfig {
|
|
|
81
120
|
#[derive(Debug, Clone, Deserialize)]
|
|
82
121
|
pub struct UniqueConfig {
|
|
83
122
|
#[serde(default)]
|
|
84
|
-
|
|
123
|
+
#[serde(alias = "path")]
|
|
124
|
+
pub selector: Option<String>,
|
|
85
125
|
#[serde(default = "default_dot")]
|
|
86
126
|
pub by: String,
|
|
87
127
|
#[serde(default)]
|
|
@@ -98,7 +138,8 @@ fn default_dot() -> String {
|
|
|
98
138
|
pub struct SchemaConfig {
|
|
99
139
|
pub file: String,
|
|
100
140
|
#[serde(default)]
|
|
101
|
-
|
|
141
|
+
#[serde(alias = "path")]
|
|
142
|
+
pub selector: Option<String>,
|
|
102
143
|
#[serde(default)]
|
|
103
144
|
pub items: bool,
|
|
104
145
|
}
|
|
@@ -112,7 +153,8 @@ pub struct FinalNewlineConfig {
|
|
|
112
153
|
#[derive(Debug, Clone, Deserialize)]
|
|
113
154
|
pub struct EscapesConfig {
|
|
114
155
|
#[serde(default)]
|
|
115
|
-
|
|
156
|
+
#[serde(alias = "path")]
|
|
157
|
+
pub selector: Option<String>,
|
|
116
158
|
}
|
|
117
159
|
|
|
118
160
|
fn default_one() -> usize {
|
|
@@ -129,7 +171,8 @@ pub struct RenameConfig {
|
|
|
129
171
|
|
|
130
172
|
#[derive(Debug, Clone, Deserialize)]
|
|
131
173
|
pub struct RemoveConfig {
|
|
132
|
-
|
|
174
|
+
#[serde(alias = "path")]
|
|
175
|
+
pub selector: String,
|
|
133
176
|
pub value: String,
|
|
134
177
|
#[serde(default)]
|
|
135
178
|
pub condition: Option<String>,
|
|
@@ -231,7 +274,8 @@ impl<'de> Deserialize<'de> for PipelineStep {
|
|
|
231
274
|
#[derive(Debug, Clone, Deserialize)]
|
|
232
275
|
pub struct SortKeysConfig {
|
|
233
276
|
#[serde(default)]
|
|
234
|
-
|
|
277
|
+
#[serde(alias = "path")]
|
|
278
|
+
pub selector: Option<String>,
|
|
235
279
|
pub order: Vec<String>,
|
|
236
280
|
}
|
|
237
281
|
|
|
@@ -241,26 +285,30 @@ pub struct QuoteStyleConfig {
|
|
|
241
285
|
pub key_style: String,
|
|
242
286
|
pub value_style: String,
|
|
243
287
|
#[serde(default)]
|
|
244
|
-
|
|
288
|
+
#[serde(alias = "path")]
|
|
289
|
+
pub selector: Option<String>,
|
|
245
290
|
}
|
|
246
291
|
|
|
247
292
|
#[derive(Debug, Clone, Deserialize)]
|
|
248
293
|
pub struct CollectionStyleConfig {
|
|
249
294
|
pub style: String,
|
|
250
295
|
#[serde(default)]
|
|
251
|
-
|
|
296
|
+
#[serde(alias = "path")]
|
|
297
|
+
pub selector: Option<String>,
|
|
252
298
|
}
|
|
253
299
|
|
|
254
300
|
#[derive(Debug, Clone, Deserialize)]
|
|
255
301
|
pub struct SequenceIndentConfig {
|
|
256
302
|
pub style: String,
|
|
257
303
|
#[serde(default)]
|
|
258
|
-
|
|
304
|
+
#[serde(alias = "path")]
|
|
305
|
+
pub selector: Option<String>,
|
|
259
306
|
}
|
|
260
307
|
|
|
261
308
|
#[derive(Debug, Clone, Deserialize)]
|
|
262
309
|
pub struct SetConfig {
|
|
263
|
-
|
|
310
|
+
#[serde(alias = "path")]
|
|
311
|
+
pub selector: String,
|
|
264
312
|
pub value: String,
|
|
265
313
|
#[serde(default)]
|
|
266
314
|
pub condition: Option<String>,
|
|
@@ -270,7 +318,8 @@ pub struct SetConfig {
|
|
|
270
318
|
|
|
271
319
|
#[derive(Debug, Clone, Deserialize)]
|
|
272
320
|
pub struct InsertConfig {
|
|
273
|
-
|
|
321
|
+
#[serde(alias = "path")]
|
|
322
|
+
pub selector: String,
|
|
274
323
|
pub value: String,
|
|
275
324
|
#[serde(default)]
|
|
276
325
|
pub condition: Option<String>,
|
|
@@ -280,7 +329,8 @@ pub struct InsertConfig {
|
|
|
280
329
|
|
|
281
330
|
#[derive(Debug, Clone, Deserialize)]
|
|
282
331
|
pub struct DeleteConfig {
|
|
283
|
-
|
|
332
|
+
#[serde(alias = "path")]
|
|
333
|
+
pub selector: String,
|
|
284
334
|
#[serde(default)]
|
|
285
335
|
pub condition: Option<String>,
|
|
286
336
|
}
|
|
@@ -301,6 +351,7 @@ impl Yerbafile {
|
|
|
301
351
|
let content = fs::read_to_string(path.as_ref())?;
|
|
302
352
|
let mut yerbafile: Yerbafile = yaml_serde::from_str(&content).map_err(|error| YerbaError::ParseError(format!("{}", error)))?;
|
|
303
353
|
yerbafile.directory = path.as_ref().parent().map(|p| p.to_path_buf());
|
|
354
|
+
yerbafile.deprecated_path_keys = deprecated_path_keys(&content);
|
|
304
355
|
yerbafile.validate_conditions()?;
|
|
305
356
|
Ok(yerbafile)
|
|
306
357
|
}
|
|
@@ -359,7 +410,7 @@ impl Yerbafile {
|
|
|
359
410
|
}
|
|
360
411
|
}
|
|
361
412
|
|
|
362
|
-
pub fn sort_order_for(&self, file_path: &str,
|
|
413
|
+
pub fn sort_order_for(&self, file_path: &str, selector: &str) -> Option<Vec<String>> {
|
|
363
414
|
for rule in &self.rules {
|
|
364
415
|
let sort_keys_config = rule.pipeline.iter().find_map(|step| match step {
|
|
365
416
|
PipelineStep::SortKeys(config) => Some(config),
|
|
@@ -367,17 +418,15 @@ impl Yerbafile {
|
|
|
367
418
|
});
|
|
368
419
|
|
|
369
420
|
if let Some(config) = sort_keys_config {
|
|
370
|
-
let
|
|
371
|
-
let normalized =
|
|
421
|
+
let full_selector = resolve_step_selector(rule.selector.as_deref(), config.selector.as_deref());
|
|
422
|
+
let normalized = full_selector.trim_end_matches("[]").trim_end_matches('.');
|
|
372
423
|
|
|
373
|
-
if normalized !=
|
|
424
|
+
if normalized != selector && !normalized.is_empty() && !selector.is_empty() {
|
|
374
425
|
continue;
|
|
375
426
|
}
|
|
376
427
|
|
|
377
|
-
if
|
|
378
|
-
|
|
379
|
-
return Some(config.order.clone());
|
|
380
|
-
}
|
|
428
|
+
if rule.matches(file_path) {
|
|
429
|
+
return Some(config.order.clone());
|
|
381
430
|
}
|
|
382
431
|
}
|
|
383
432
|
}
|
|
@@ -404,7 +453,11 @@ impl Yerbafile {
|
|
|
404
453
|
}
|
|
405
454
|
};
|
|
406
455
|
|
|
407
|
-
let file_strings: Vec<String> = files
|
|
456
|
+
let file_strings: Vec<String> = files
|
|
457
|
+
.iter()
|
|
458
|
+
.map(|path| path.to_string_lossy().to_string())
|
|
459
|
+
.filter(|file| !rule.excludes(file))
|
|
460
|
+
.collect();
|
|
408
461
|
|
|
409
462
|
let file_results: Vec<RuleResult> = file_strings
|
|
410
463
|
.par_iter()
|
|
@@ -472,10 +525,10 @@ impl Yerbafile {
|
|
|
472
525
|
}
|
|
473
526
|
}
|
|
474
527
|
|
|
475
|
-
let
|
|
528
|
+
let base_selector = rule.selector.as_deref();
|
|
476
529
|
|
|
477
530
|
for step in &rule.pipeline {
|
|
478
|
-
if let Err(error) = execute_step(&mut document, step,
|
|
531
|
+
if let Err(error) = execute_step(&mut document, step, base_selector, file, self) {
|
|
479
532
|
return RuleResult {
|
|
480
533
|
file: file.to_string(),
|
|
481
534
|
changed: false,
|
|
@@ -509,11 +562,7 @@ impl Yerbafile {
|
|
|
509
562
|
let mut ran_global = false;
|
|
510
563
|
|
|
511
564
|
for rule in &self.rules {
|
|
512
|
-
if
|
|
513
|
-
if !pattern.matches(file) && !pattern.matches_path(Path::new(file)) {
|
|
514
|
-
continue;
|
|
515
|
-
}
|
|
516
|
-
} else {
|
|
565
|
+
if !rule.matches(file) {
|
|
517
566
|
continue;
|
|
518
567
|
}
|
|
519
568
|
|
|
@@ -625,20 +674,14 @@ impl Yerbafile {
|
|
|
625
674
|
}
|
|
626
675
|
|
|
627
676
|
for rule in &self.rules {
|
|
628
|
-
if !match_path.is_empty() {
|
|
629
|
-
|
|
630
|
-
if !pattern.matches(match_path) && !pattern.matches_path(Path::new(match_path)) {
|
|
631
|
-
continue;
|
|
632
|
-
}
|
|
633
|
-
} else {
|
|
634
|
-
continue;
|
|
635
|
-
}
|
|
677
|
+
if !match_path.is_empty() && !rule.matches(match_path) {
|
|
678
|
+
continue;
|
|
636
679
|
}
|
|
637
680
|
|
|
638
|
-
let
|
|
681
|
+
let base_selector = rule.selector.as_deref();
|
|
639
682
|
|
|
640
683
|
for step in &rule.pipeline {
|
|
641
|
-
execute_step(document, step,
|
|
684
|
+
execute_step(document, step, base_selector, file_path, self)?;
|
|
642
685
|
}
|
|
643
686
|
}
|
|
644
687
|
|
|
@@ -652,7 +695,7 @@ fn control_character_error(source: &str) -> Option<YerbaError> {
|
|
|
652
695
|
(!found.is_empty()).then_some(YerbaError::ControlCharacters(found))
|
|
653
696
|
}
|
|
654
697
|
|
|
655
|
-
fn execute_pipeline(document: &mut Document, steps: &[PipelineStep],
|
|
698
|
+
fn execute_pipeline(document: &mut Document, steps: &[PipelineStep], base_selector: Option<&str>, file: &str, yerbafile: &Yerbafile) -> Result<(), YerbaError> {
|
|
656
699
|
use crate::document::style::StyleEnforcement;
|
|
657
700
|
|
|
658
701
|
let mut enforcement = StyleEnforcement {
|
|
@@ -667,17 +710,17 @@ fn execute_pipeline(document: &mut Document, steps: &[PipelineStep], base_path:
|
|
|
667
710
|
|
|
668
711
|
for step in steps {
|
|
669
712
|
match step {
|
|
670
|
-
PipelineStep::CollectionStyle(config) if config.
|
|
713
|
+
PipelineStep::CollectionStyle(config) if config.selector.is_none() && base_selector.is_none() => {
|
|
671
714
|
enforcement.collection_style = Some(config.style.clone());
|
|
672
715
|
has_enforcement = true;
|
|
673
716
|
}
|
|
674
717
|
|
|
675
|
-
PipelineStep::SequenceIndent(config) if config.
|
|
718
|
+
PipelineStep::SequenceIndent(config) if config.selector.is_none() && base_selector.is_none() => {
|
|
676
719
|
enforcement.sequence_indent = Some(config.style.clone());
|
|
677
720
|
has_enforcement = true;
|
|
678
721
|
}
|
|
679
722
|
|
|
680
|
-
PipelineStep::QuoteStyle(config) if config.
|
|
723
|
+
PipelineStep::QuoteStyle(config) if config.selector.is_none() && base_selector.is_none() => {
|
|
681
724
|
let key_style = config.key_style.parse::<crate::KeyStyle>().ok();
|
|
682
725
|
let value_style = config.value_style.parse::<QuoteStyle>().ok();
|
|
683
726
|
|
|
@@ -695,23 +738,23 @@ fn execute_pipeline(document: &mut Document, steps: &[PipelineStep], base_path:
|
|
|
695
738
|
}
|
|
696
739
|
|
|
697
740
|
for step in remaining_steps {
|
|
698
|
-
execute_step(document, step,
|
|
741
|
+
execute_step(document, step, base_selector, file, yerbafile)?;
|
|
699
742
|
}
|
|
700
743
|
|
|
701
744
|
Ok(())
|
|
702
745
|
}
|
|
703
746
|
|
|
704
|
-
fn execute_step(document: &mut Document, step: &PipelineStep,
|
|
747
|
+
fn execute_step(document: &mut Document, step: &PipelineStep, base_selector: Option<&str>, _file: &str, yerbafile: &Yerbafile) -> Result<(), YerbaError> {
|
|
705
748
|
match step {
|
|
706
749
|
PipelineStep::QuoteStyle(config) => {
|
|
707
|
-
let
|
|
750
|
+
let selector = config.selector.as_deref();
|
|
708
751
|
|
|
709
752
|
let key_style = config.key_style.parse::<crate::KeyStyle>().map_err(YerbaError::ParseError)?;
|
|
710
753
|
|
|
711
754
|
let value_style = config.value_style.parse::<QuoteStyle>().map_err(YerbaError::ParseError)?;
|
|
712
755
|
|
|
713
|
-
document.enforce_key_style(&key_style,
|
|
714
|
-
let warnings = document.enforce_quotes_at(&value_style,
|
|
756
|
+
document.enforce_key_style(&key_style, selector)?;
|
|
757
|
+
let warnings = document.enforce_quotes_at(&value_style, selector)?;
|
|
715
758
|
|
|
716
759
|
for warning in &warnings {
|
|
717
760
|
eprintln!(" warning: {}", warning);
|
|
@@ -721,52 +764,52 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
721
764
|
}
|
|
722
765
|
|
|
723
766
|
PipelineStep::CollectionStyle(config) => {
|
|
724
|
-
let
|
|
725
|
-
let path = if
|
|
767
|
+
let selector = resolve_step_selector(base_selector, config.selector.as_deref());
|
|
768
|
+
let path = if selector.is_empty() { None } else { Some(selector.as_str()) };
|
|
726
769
|
|
|
727
770
|
document.enforce_collection_style(&config.style, path)
|
|
728
771
|
}
|
|
729
772
|
|
|
730
773
|
PipelineStep::SequenceIndent(config) => {
|
|
731
|
-
let
|
|
732
|
-
let path = if
|
|
774
|
+
let selector = resolve_step_selector(base_selector, config.selector.as_deref());
|
|
775
|
+
let path = if selector.is_empty() { None } else { Some(selector.as_str()) };
|
|
733
776
|
|
|
734
777
|
document.enforce_sequence_indent(&config.style, path)
|
|
735
778
|
}
|
|
736
779
|
|
|
737
780
|
PipelineStep::SortKeys(config) => {
|
|
738
|
-
let
|
|
781
|
+
let full_selector = resolve_step_selector(base_selector, config.selector.as_deref());
|
|
739
782
|
let key_order: Vec<&str> = config.order.iter().map(|key| key.as_str()).collect();
|
|
740
783
|
|
|
741
|
-
document.validate_sort_keys(&
|
|
742
|
-
document.sort_keys(&
|
|
784
|
+
document.validate_sort_keys(&full_selector, &key_order)?;
|
|
785
|
+
document.sort_keys(&full_selector, &key_order)
|
|
743
786
|
}
|
|
744
787
|
|
|
745
788
|
PipelineStep::Set(config) => {
|
|
746
|
-
let
|
|
789
|
+
let full_selector = resolve_step_selector(base_selector, Some(&config.selector));
|
|
747
790
|
|
|
748
791
|
if let Some(condition) = &config.condition {
|
|
749
|
-
let
|
|
792
|
+
let parent_selector = full_selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
750
793
|
|
|
751
|
-
if !document.evaluate_condition(
|
|
794
|
+
if !document.evaluate_condition(parent_selector, condition)? {
|
|
752
795
|
return Ok(());
|
|
753
796
|
}
|
|
754
797
|
}
|
|
755
798
|
|
|
756
799
|
if config.plain {
|
|
757
|
-
document.set_plain(&
|
|
800
|
+
document.set_plain(&full_selector, &config.value)
|
|
758
801
|
} else {
|
|
759
|
-
document.set(&
|
|
802
|
+
document.set(&full_selector, &config.value)
|
|
760
803
|
}
|
|
761
804
|
}
|
|
762
805
|
|
|
763
806
|
PipelineStep::Insert(config) => {
|
|
764
|
-
let
|
|
807
|
+
let full_selector = resolve_step_selector(base_selector, Some(&config.selector));
|
|
765
808
|
|
|
766
809
|
if let Some(condition) = &config.condition {
|
|
767
|
-
let
|
|
810
|
+
let parent_selector = full_selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
768
811
|
|
|
769
|
-
if !document.evaluate_condition(
|
|
812
|
+
if !document.evaluate_condition(parent_selector, condition)? {
|
|
770
813
|
return Ok(());
|
|
771
814
|
}
|
|
772
815
|
}
|
|
@@ -777,20 +820,20 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
777
820
|
crate::syntax::quote_scalar(&config.value)
|
|
778
821
|
};
|
|
779
822
|
|
|
780
|
-
document.insert_into(&
|
|
823
|
+
document.insert_into(&full_selector, &value, crate::InsertPosition::Last)
|
|
781
824
|
}
|
|
782
825
|
|
|
783
826
|
PipelineStep::Delete(config) => {
|
|
784
|
-
let
|
|
827
|
+
let full_selector = resolve_step_selector(base_selector, Some(&config.selector));
|
|
785
828
|
|
|
786
|
-
if
|
|
787
|
-
let concrete_selectors = document.resolve_selectors(&
|
|
829
|
+
if full_selector.contains("[]") {
|
|
830
|
+
let concrete_selectors = document.resolve_selectors(&full_selector);
|
|
788
831
|
|
|
789
832
|
for selector in concrete_selectors.into_iter().rev() {
|
|
790
833
|
if let Some(condition) = &config.condition {
|
|
791
|
-
let
|
|
834
|
+
let parent_selector = selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
792
835
|
|
|
793
|
-
if !document.evaluate_condition(
|
|
836
|
+
if !document.evaluate_condition(parent_selector, condition)? {
|
|
794
837
|
continue;
|
|
795
838
|
}
|
|
796
839
|
}
|
|
@@ -801,47 +844,47 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
801
844
|
Ok(())
|
|
802
845
|
} else {
|
|
803
846
|
if let Some(condition) = &config.condition {
|
|
804
|
-
let
|
|
847
|
+
let parent_selector = full_selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
805
848
|
|
|
806
|
-
if !document.evaluate_condition(
|
|
849
|
+
if !document.evaluate_condition(parent_selector, condition)? {
|
|
807
850
|
return Ok(());
|
|
808
851
|
}
|
|
809
852
|
}
|
|
810
853
|
|
|
811
|
-
document.delete(&
|
|
854
|
+
document.delete(&full_selector)
|
|
812
855
|
}
|
|
813
856
|
}
|
|
814
857
|
|
|
815
858
|
PipelineStep::Rename(config) => {
|
|
816
|
-
let
|
|
859
|
+
let full_selector = resolve_step_selector(base_selector, Some(&config.from));
|
|
817
860
|
|
|
818
861
|
if let Some(condition) = &config.condition {
|
|
819
|
-
let
|
|
862
|
+
let parent_selector = full_selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
820
863
|
|
|
821
|
-
if !document.evaluate_condition(
|
|
864
|
+
if !document.evaluate_condition(parent_selector, condition)? {
|
|
822
865
|
return Ok(());
|
|
823
866
|
}
|
|
824
867
|
}
|
|
825
868
|
|
|
826
|
-
document.rename(&
|
|
869
|
+
document.rename(&full_selector, &config.to)
|
|
827
870
|
}
|
|
828
871
|
|
|
829
872
|
PipelineStep::Remove(config) => {
|
|
830
|
-
let
|
|
873
|
+
let full_selector = resolve_step_selector(base_selector, Some(&config.selector));
|
|
831
874
|
|
|
832
875
|
if let Some(condition) = &config.condition {
|
|
833
|
-
let
|
|
876
|
+
let parent_selector = full_selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
834
877
|
|
|
835
|
-
if !document.evaluate_condition(
|
|
878
|
+
if !document.evaluate_condition(parent_selector, condition)? {
|
|
836
879
|
return Ok(());
|
|
837
880
|
}
|
|
838
881
|
}
|
|
839
882
|
|
|
840
|
-
document.remove(&
|
|
883
|
+
document.remove(&full_selector, &config.value)
|
|
841
884
|
}
|
|
842
885
|
|
|
843
886
|
PipelineStep::BlankLines(config) => {
|
|
844
|
-
let
|
|
887
|
+
let full_selector = resolve_step_selector(base_selector, config.selector.as_deref());
|
|
845
888
|
|
|
846
889
|
let options = crate::BlankLineOptions {
|
|
847
890
|
before: config.before.clone(),
|
|
@@ -849,14 +892,14 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
849
892
|
skip_empty: config.skip_empty,
|
|
850
893
|
};
|
|
851
894
|
|
|
852
|
-
document.enforce_blank_lines_with(&
|
|
895
|
+
document.enforce_blank_lines_with(&full_selector, config.count, &options)
|
|
853
896
|
}
|
|
854
897
|
|
|
855
898
|
PipelineStep::Sort(config) => {
|
|
856
|
-
let
|
|
899
|
+
let full_selector = resolve_step_selector(base_selector, config.selector.as_deref());
|
|
857
900
|
let sort_fields = config.by.as_deref().map(crate::SortField::parse_list).unwrap_or_default();
|
|
858
901
|
|
|
859
|
-
document.
|
|
902
|
+
document.sort_items_with(&full_selector, &sort_fields, config.case_sensitive, config.missing)
|
|
860
903
|
}
|
|
861
904
|
|
|
862
905
|
PipelineStep::Directives(config) => {
|
|
@@ -868,7 +911,7 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
868
911
|
let locations = document.directive_locations();
|
|
869
912
|
|
|
870
913
|
if locations.len() > max {
|
|
871
|
-
let positions: Vec<String> = locations.iter().map(|(line,
|
|
914
|
+
let positions: Vec<String> = locations.iter().map(|(line, column)| format!("{}:{}", line, column + 1)).collect();
|
|
872
915
|
|
|
873
916
|
return Err(YerbaError::ParseError(format!(
|
|
874
917
|
"found {} directive markers (---) at {}, expected at most {}",
|
|
@@ -891,7 +934,7 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
891
934
|
PipelineStep::Schema(config) => {
|
|
892
935
|
let schema_path = yerbafile.resolve_path(&config.file);
|
|
893
936
|
let schema = crate::schema::load_schema(&schema_path)?;
|
|
894
|
-
let selector =
|
|
937
|
+
let selector = resolve_step_selector(base_selector, config.selector.as_deref());
|
|
895
938
|
let errors = document.validate_schema(&schema, config.items, if selector.is_empty() { None } else { Some(&selector) });
|
|
896
939
|
|
|
897
940
|
if errors.is_empty() {
|
|
@@ -902,8 +945,8 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
902
945
|
}
|
|
903
946
|
|
|
904
947
|
PipelineStep::Unique(config) => {
|
|
905
|
-
let
|
|
906
|
-
let duplicates = document.unique_with_options(&
|
|
948
|
+
let full_selector = resolve_step_selector(base_selector, config.selector.as_deref());
|
|
949
|
+
let duplicates = document.unique_with_options(&full_selector, &config.by, config.remove, config.allow_blank_duplicates)?;
|
|
907
950
|
|
|
908
951
|
if !duplicates.is_empty() && !config.remove {
|
|
909
952
|
return Err(YerbaError::DuplicateValues(duplicates));
|
|
@@ -915,17 +958,17 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
915
958
|
PipelineStep::FinalNewline(config) => document.enforce_final_newline(config.count),
|
|
916
959
|
|
|
917
960
|
PipelineStep::Escapes(config) => {
|
|
918
|
-
let
|
|
919
|
-
let scope = if
|
|
961
|
+
let full_selector = resolve_step_selector(base_selector, config.selector.as_deref());
|
|
962
|
+
let scope = if full_selector.is_empty() { None } else { Some(full_selector.as_str()) };
|
|
920
963
|
|
|
921
964
|
document.decode_escapes(scope).map(|_| ())
|
|
922
965
|
}
|
|
923
966
|
}
|
|
924
967
|
}
|
|
925
968
|
|
|
926
|
-
fn
|
|
927
|
-
let base =
|
|
928
|
-
let step =
|
|
969
|
+
fn resolve_step_selector(base_selector: Option<&str>, step_selector: Option<&str>) -> String {
|
|
970
|
+
let base = base_selector.unwrap_or("");
|
|
971
|
+
let step = step_selector.unwrap_or("");
|
|
929
972
|
|
|
930
973
|
match (base.is_empty(), step.is_empty()) {
|
|
931
974
|
(true, true) => String::new(),
|
|
@@ -934,3 +977,34 @@ fn resolve_step_path(base_path: Option<&str>, step_path: Option<&str>) -> String
|
|
|
934
977
|
(false, false) => format!("{}.{}", base, step),
|
|
935
978
|
}
|
|
936
979
|
}
|
|
980
|
+
|
|
981
|
+
// TODO(v1.0): remove together with the `path` aliases on the rule and step configs.
|
|
982
|
+
fn deprecated_path_keys(content: &str) -> Vec<String> {
|
|
983
|
+
let Ok(yerbafile) = yaml_serde::from_str::<yaml_serde::Value>(content) else {
|
|
984
|
+
return Vec::new();
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
let mut found = Vec::new();
|
|
988
|
+
|
|
989
|
+
let check_pipeline = |pipeline: Option<&yaml_serde::Value>, prefix: &str, found: &mut Vec<String>| {
|
|
990
|
+
for (index, step) in pipeline.and_then(|pipeline| pipeline.as_sequence()).into_iter().flatten().enumerate() {
|
|
991
|
+
for (name, config) in step.as_mapping().into_iter().flatten() {
|
|
992
|
+
if config.get("path").is_some() {
|
|
993
|
+
found.push(format!("{}pipeline[{}].{}", prefix, index, name.as_str().unwrap_or_default()));
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
|
|
999
|
+
check_pipeline(yerbafile.get("pipeline"), "", &mut found);
|
|
1000
|
+
|
|
1001
|
+
for (index, rule) in yerbafile.get("rules").and_then(|rules| rules.as_sequence()).into_iter().flatten().enumerate() {
|
|
1002
|
+
if rule.get("path").is_some() {
|
|
1003
|
+
found.push(format!("rules[{}]", index));
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
check_pipeline(rule.get("pipeline"), &format!("rules[{}].", index), &mut found);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
found
|
|
1010
|
+
}
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yerba
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.1
|
|
5
5
|
platform: arm-linux-gnu
|
|
6
6
|
authors:
|
|
7
7
|
- Marco Roth
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A CLI tool for editing YAML while preserving structure, comments, and
|
|
14
14
|
format.
|
|
@@ -78,6 +78,7 @@ files:
|
|
|
78
78
|
- rust/src/document/get.rs
|
|
79
79
|
- rust/src/document/insert.rs
|
|
80
80
|
- rust/src/document/mod.rs
|
|
81
|
+
- rust/src/document/nodes.rs
|
|
81
82
|
- rust/src/document/schema.rs
|
|
82
83
|
- rust/src/document/set.rs
|
|
83
84
|
- rust/src/document/sort.rs
|