yerba 0.4.2 → 0.5.0
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 +241 -53
- 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 +2 -1
- 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/set.rs +1 -1
- data/rust/src/commands/unique.rs +80 -0
- data/rust/src/document/condition.rs +17 -1
- data/rust/src/document/get.rs +254 -23
- data/rust/src/document/mod.rs +90 -12
- data/rust/src/document/schema.rs +73 -0
- data/rust/src/document/set.rs +1 -1
- data/rust/src/document/sort.rs +19 -13
- 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/lib.rs +5 -10
- data/rust/src/main.rs +2 -0
- data/rust/src/schema.rs +93 -0
- data/rust/src/syntax.rs +91 -31
- data/rust/src/yerbafile.rs +107 -18
- metadata +8 -1
data/rust/src/yerbafile.rs
CHANGED
|
@@ -9,6 +9,8 @@ use crate::{Document, QuoteStyle, YerbaError};
|
|
|
9
9
|
pub struct Yerbafile {
|
|
10
10
|
#[serde(default)]
|
|
11
11
|
pub rules: Vec<Rule>,
|
|
12
|
+
#[serde(skip)]
|
|
13
|
+
pub directory: Option<PathBuf>,
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
#[derive(Debug, Clone, Deserialize)]
|
|
@@ -31,6 +33,8 @@ pub enum PipelineStep {
|
|
|
31
33
|
BlankLines(BlankLinesConfig),
|
|
32
34
|
Sort(SortConfig),
|
|
33
35
|
Directives(DirectivesConfig),
|
|
36
|
+
Unique(UniqueConfig),
|
|
37
|
+
Schema(SchemaConfig),
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
#[derive(Debug, Clone, Deserialize)]
|
|
@@ -58,6 +62,31 @@ pub struct DirectivesConfig {
|
|
|
58
62
|
pub remove: bool,
|
|
59
63
|
}
|
|
60
64
|
|
|
65
|
+
#[derive(Debug, Clone, Deserialize)]
|
|
66
|
+
pub struct UniqueConfig {
|
|
67
|
+
#[serde(default)]
|
|
68
|
+
pub path: Option<String>,
|
|
69
|
+
#[serde(default = "default_dot")]
|
|
70
|
+
pub by: String,
|
|
71
|
+
#[serde(default)]
|
|
72
|
+
pub remove: bool,
|
|
73
|
+
#[serde(default)]
|
|
74
|
+
pub allow_blank_duplicates: bool,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fn default_dot() -> String {
|
|
78
|
+
".".to_string()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#[derive(Debug, Clone, Deserialize)]
|
|
82
|
+
pub struct SchemaConfig {
|
|
83
|
+
pub file: String,
|
|
84
|
+
#[serde(default)]
|
|
85
|
+
pub path: Option<String>,
|
|
86
|
+
#[serde(default)]
|
|
87
|
+
pub items: bool,
|
|
88
|
+
}
|
|
89
|
+
|
|
61
90
|
#[derive(Debug, Clone, Deserialize)]
|
|
62
91
|
pub struct RenameConfig {
|
|
63
92
|
pub from: String,
|
|
@@ -131,8 +160,18 @@ impl<'de> Deserialize<'de> for PipelineStep {
|
|
|
131
160
|
return Ok(PipelineStep::Sort(config));
|
|
132
161
|
}
|
|
133
162
|
|
|
163
|
+
if let Some(value) = mapping.get(serde_yaml::Value::String("unique".to_string())) {
|
|
164
|
+
let config: UniqueConfig = serde_yaml::from_value(value.clone()).map_err(serde::de::Error::custom)?;
|
|
165
|
+
return Ok(PipelineStep::Unique(config));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if let Some(value) = mapping.get(serde_yaml::Value::String("schema".to_string())) {
|
|
169
|
+
let config: SchemaConfig = serde_yaml::from_value(value.clone()).map_err(serde::de::Error::custom)?;
|
|
170
|
+
return Ok(PipelineStep::Schema(config));
|
|
171
|
+
}
|
|
172
|
+
|
|
134
173
|
Err(serde::de::Error::custom(
|
|
135
|
-
"unknown pipeline step: expected sort_keys, quote_style, set, insert, delete, rename, remove, blank_lines, sort, or
|
|
174
|
+
"unknown pipeline step: expected sort_keys, quote_style, set, insert, delete, rename, remove, blank_lines, sort, directives, unique, or schema",
|
|
136
175
|
))
|
|
137
176
|
}
|
|
138
177
|
}
|
|
@@ -184,16 +223,24 @@ fn default_key_style() -> String {
|
|
|
184
223
|
pub struct RuleResult {
|
|
185
224
|
pub file: String,
|
|
186
225
|
pub changed: bool,
|
|
187
|
-
pub error: Option<
|
|
226
|
+
pub error: Option<YerbaError>,
|
|
188
227
|
}
|
|
189
228
|
|
|
190
229
|
impl Yerbafile {
|
|
191
230
|
pub fn load(path: impl AsRef<Path>) -> Result<Self, YerbaError> {
|
|
192
231
|
let content = fs::read_to_string(path.as_ref())?;
|
|
193
|
-
let yerbafile: Yerbafile = serde_yaml::from_str(&content).map_err(|error| YerbaError::ParseError(format!("{}", error)))?;
|
|
232
|
+
let mut yerbafile: Yerbafile = serde_yaml::from_str(&content).map_err(|error| YerbaError::ParseError(format!("{}", error)))?;
|
|
233
|
+
yerbafile.directory = path.as_ref().parent().map(|p| p.to_path_buf());
|
|
194
234
|
Ok(yerbafile)
|
|
195
235
|
}
|
|
196
236
|
|
|
237
|
+
pub fn resolve_path(&self, relative: &str) -> PathBuf {
|
|
238
|
+
match &self.directory {
|
|
239
|
+
Some(directory) => directory.join(relative),
|
|
240
|
+
None => PathBuf::from(relative),
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
197
244
|
pub fn find() -> Option<PathBuf> {
|
|
198
245
|
Self::find_from(std::env::current_dir().ok()?)
|
|
199
246
|
}
|
|
@@ -255,7 +302,7 @@ impl Yerbafile {
|
|
|
255
302
|
results.push(RuleResult {
|
|
256
303
|
file: rule.files.clone(),
|
|
257
304
|
changed: false,
|
|
258
|
-
error: Some(format!("invalid glob: {}", error)),
|
|
305
|
+
error: Some(YerbaError::ParseError(format!("invalid glob: {}", error))),
|
|
259
306
|
});
|
|
260
307
|
|
|
261
308
|
continue;
|
|
@@ -280,7 +327,7 @@ impl Yerbafile {
|
|
|
280
327
|
return Some(RuleResult {
|
|
281
328
|
file: file.clone(),
|
|
282
329
|
changed: false,
|
|
283
|
-
error: Some(
|
|
330
|
+
error: Some(error),
|
|
284
331
|
});
|
|
285
332
|
}
|
|
286
333
|
};
|
|
@@ -289,7 +336,7 @@ impl Yerbafile {
|
|
|
289
336
|
Some(RuleResult {
|
|
290
337
|
file: file.clone(),
|
|
291
338
|
changed: false,
|
|
292
|
-
error: Some(
|
|
339
|
+
error: Some(error),
|
|
293
340
|
})
|
|
294
341
|
} else {
|
|
295
342
|
None
|
|
@@ -323,7 +370,7 @@ impl Yerbafile {
|
|
|
323
370
|
return RuleResult {
|
|
324
371
|
file: file.to_string(),
|
|
325
372
|
changed: false,
|
|
326
|
-
error: Some(
|
|
373
|
+
error: Some(error),
|
|
327
374
|
}
|
|
328
375
|
}
|
|
329
376
|
};
|
|
@@ -332,11 +379,11 @@ impl Yerbafile {
|
|
|
332
379
|
let base_path = rule.path.as_deref();
|
|
333
380
|
|
|
334
381
|
for step in &rule.pipeline {
|
|
335
|
-
if let Err(error) = execute_step(&mut document, step, base_path) {
|
|
382
|
+
if let Err(error) = execute_step(&mut document, step, base_path, file, self) {
|
|
336
383
|
return RuleResult {
|
|
337
384
|
file: file.to_string(),
|
|
338
385
|
changed: false,
|
|
339
|
-
error: Some(
|
|
386
|
+
error: Some(error),
|
|
340
387
|
};
|
|
341
388
|
}
|
|
342
389
|
}
|
|
@@ -349,7 +396,7 @@ impl Yerbafile {
|
|
|
349
396
|
return RuleResult {
|
|
350
397
|
file: file.to_string(),
|
|
351
398
|
changed,
|
|
352
|
-
error: Some(
|
|
399
|
+
error: Some(YerbaError::IoError(error)),
|
|
353
400
|
};
|
|
354
401
|
}
|
|
355
402
|
}
|
|
@@ -396,7 +443,7 @@ impl Yerbafile {
|
|
|
396
443
|
let base_path = rule.path.as_deref();
|
|
397
444
|
|
|
398
445
|
for step in &rule.pipeline {
|
|
399
|
-
execute_step(document, step, base_path)?;
|
|
446
|
+
execute_step(document, step, base_path, file_path, self)?;
|
|
400
447
|
}
|
|
401
448
|
}
|
|
402
449
|
|
|
@@ -404,7 +451,7 @@ impl Yerbafile {
|
|
|
404
451
|
}
|
|
405
452
|
}
|
|
406
453
|
|
|
407
|
-
fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<&str
|
|
454
|
+
fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<&str>, _file: &str, yerbafile: &Yerbafile) -> Result<(), YerbaError> {
|
|
408
455
|
match step {
|
|
409
456
|
PipelineStep::QuoteStyle(config) => {
|
|
410
457
|
let dot_path = config.path.as_deref();
|
|
@@ -461,15 +508,33 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
461
508
|
PipelineStep::Delete(config) => {
|
|
462
509
|
let full_path = resolve_step_path(base_path, Some(&config.path));
|
|
463
510
|
|
|
464
|
-
if
|
|
465
|
-
let
|
|
511
|
+
if full_path.contains("[]") {
|
|
512
|
+
let concrete_selectors = document.resolve_selectors(&full_path);
|
|
466
513
|
|
|
467
|
-
|
|
468
|
-
|
|
514
|
+
for selector in concrete_selectors.into_iter().rev() {
|
|
515
|
+
if let Some(condition) = &config.condition {
|
|
516
|
+
let parent_path = selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
517
|
+
|
|
518
|
+
if !document.evaluate_condition(parent_path, condition) {
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
document.delete(&selector)?;
|
|
469
524
|
}
|
|
470
|
-
}
|
|
471
525
|
|
|
472
|
-
|
|
526
|
+
Ok(())
|
|
527
|
+
} else {
|
|
528
|
+
if let Some(condition) = &config.condition {
|
|
529
|
+
let parent_path = full_path.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
530
|
+
|
|
531
|
+
if !document.evaluate_condition(parent_path, condition) {
|
|
532
|
+
return Ok(());
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
document.delete(&full_path)
|
|
537
|
+
}
|
|
473
538
|
}
|
|
474
539
|
|
|
475
540
|
PipelineStep::Rename(config) => {
|
|
@@ -526,6 +591,30 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
526
591
|
Ok(())
|
|
527
592
|
}
|
|
528
593
|
}
|
|
594
|
+
|
|
595
|
+
PipelineStep::Schema(config) => {
|
|
596
|
+
let schema_path = yerbafile.resolve_path(&config.file);
|
|
597
|
+
let schema = crate::schema::load_schema(&schema_path)?;
|
|
598
|
+
let selector = resolve_step_path(base_path, config.path.as_deref());
|
|
599
|
+
let errors = document.validate_schema(&schema, config.items, if selector.is_empty() { None } else { Some(&selector) });
|
|
600
|
+
|
|
601
|
+
if errors.is_empty() {
|
|
602
|
+
Ok(())
|
|
603
|
+
} else {
|
|
604
|
+
Err(YerbaError::SchemaValidation(errors))
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
PipelineStep::Unique(config) => {
|
|
609
|
+
let full_path = resolve_step_path(base_path, config.path.as_deref());
|
|
610
|
+
let duplicates = document.unique_with_options(&full_path, &config.by, config.remove, config.allow_blank_duplicates)?;
|
|
611
|
+
|
|
612
|
+
if !duplicates.is_empty() && !config.remove {
|
|
613
|
+
return Err(YerbaError::DuplicateValues(duplicates));
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
Ok(())
|
|
617
|
+
}
|
|
529
618
|
}
|
|
530
619
|
}
|
|
531
620
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yerba
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marco Roth
|
|
@@ -31,6 +31,7 @@ files:
|
|
|
31
31
|
- lib/yerba/formatting.rb
|
|
32
32
|
- lib/yerba/location.rb
|
|
33
33
|
- lib/yerba/map.rb
|
|
34
|
+
- lib/yerba/node.rb
|
|
34
35
|
- lib/yerba/query_result.rb
|
|
35
36
|
- lib/yerba/scalar.rb
|
|
36
37
|
- lib/yerba/sequence.rb
|
|
@@ -49,6 +50,7 @@ files:
|
|
|
49
50
|
- rust/src/commands/get.rs
|
|
50
51
|
- rust/src/commands/init.rs
|
|
51
52
|
- rust/src/commands/insert.rs
|
|
53
|
+
- rust/src/commands/location.rs
|
|
52
54
|
- rust/src/commands/mate.rs
|
|
53
55
|
- rust/src/commands/mod.rs
|
|
54
56
|
- rust/src/commands/move_item.rs
|
|
@@ -56,10 +58,12 @@ files:
|
|
|
56
58
|
- rust/src/commands/quote_style.rs
|
|
57
59
|
- rust/src/commands/remove.rs
|
|
58
60
|
- rust/src/commands/rename.rs
|
|
61
|
+
- rust/src/commands/schema.rs
|
|
59
62
|
- rust/src/commands/selectors.rs
|
|
60
63
|
- rust/src/commands/set.rs
|
|
61
64
|
- rust/src/commands/sort.rs
|
|
62
65
|
- rust/src/commands/sort_keys.rs
|
|
66
|
+
- rust/src/commands/unique.rs
|
|
63
67
|
- rust/src/commands/version.rs
|
|
64
68
|
- rust/src/didyoumean.rs
|
|
65
69
|
- rust/src/document/condition.rs
|
|
@@ -67,15 +71,18 @@ files:
|
|
|
67
71
|
- rust/src/document/get.rs
|
|
68
72
|
- rust/src/document/insert.rs
|
|
69
73
|
- rust/src/document/mod.rs
|
|
74
|
+
- rust/src/document/schema.rs
|
|
70
75
|
- rust/src/document/set.rs
|
|
71
76
|
- rust/src/document/sort.rs
|
|
72
77
|
- rust/src/document/style.rs
|
|
78
|
+
- rust/src/document/unique.rs
|
|
73
79
|
- rust/src/error.rs
|
|
74
80
|
- rust/src/ffi.rs
|
|
75
81
|
- rust/src/json.rs
|
|
76
82
|
- rust/src/lib.rs
|
|
77
83
|
- rust/src/main.rs
|
|
78
84
|
- rust/src/quote_style.rs
|
|
85
|
+
- rust/src/schema.rs
|
|
79
86
|
- rust/src/selector.rs
|
|
80
87
|
- rust/src/syntax.rs
|
|
81
88
|
- rust/src/yaml_writer.rs
|