yerba 0.2.2-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.
- checksums.yaml +4 -4
- data/README.md +167 -12
- data/exe/arm-linux-gnu/yerba +0 -0
- data/ext/yerba/extconf.rb +39 -12
- data/ext/yerba/include/yerba.h +21 -10
- data/ext/yerba/yerba.c +91 -25
- 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 +35 -0
- data/lib/yerba/document.rb +16 -0
- data/lib/yerba/sequence.rb +169 -1
- data/lib/yerba/version.rb +1 -1
- data/lib/yerba.rb +7 -2
- data/rust/Cargo.lock +1 -1
- data/rust/Cargo.toml +2 -2
- data/rust/cbindgen.toml +1 -0
- data/rust/rustfmt.toml +1 -1
- data/rust/src/commands/blank_lines.rs +1 -4
- data/rust/src/commands/delete.rs +9 -4
- data/rust/src/commands/directives.rs +61 -0
- data/rust/src/commands/get.rs +52 -26
- data/rust/src/commands/insert.rs +8 -4
- data/rust/src/commands/mod.rs +71 -9
- data/rust/src/commands/move_item.rs +2 -1
- data/rust/src/commands/move_key.rs +2 -1
- data/rust/src/commands/quote_style.rs +12 -6
- data/rust/src/commands/remove.rs +8 -4
- data/rust/src/commands/rename.rs +8 -4
- data/rust/src/commands/selectors.rs +158 -0
- data/rust/src/commands/set.rs +33 -16
- data/rust/src/commands/sort.rs +342 -10
- data/rust/src/didyoumean.rs +53 -0
- data/rust/src/document/condition.rs +139 -0
- data/rust/src/document/delete.rs +91 -0
- data/rust/src/document/get.rs +262 -0
- data/rust/src/document/insert.rs +314 -0
- data/rust/src/document/mod.rs +784 -0
- data/rust/src/document/set.rs +90 -0
- data/rust/src/document/sort.rs +607 -0
- data/rust/src/document/style.rs +473 -0
- data/rust/src/error.rs +35 -7
- data/rust/src/ffi.rs +213 -520
- data/rust/src/json.rs +1 -7
- data/rust/src/lib.rs +89 -2
- data/rust/src/main.rs +2 -0
- data/rust/src/quote_style.rs +83 -7
- data/rust/src/selector.rs +2 -7
- data/rust/src/syntax.rs +41 -21
- data/rust/src/yerbafile.rs +39 -18
- metadata +13 -3
- data/rust/src/document.rs +0 -2237
|
@@ -11,7 +11,7 @@ static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
|
11
11
|
yerba quote-style config.yml --keys plain
|
|
12
12
|
yerba quote-style config.yml --keys plain --values double
|
|
13
13
|
yerba quote-style config.yml "[].speakers" --values plain
|
|
14
|
-
yerba quote-style "data/**/*.yml" --keys plain --values double
|
|
14
|
+
yerba quote-style "data/**/*.yml" --keys plain --values double
|
|
15
15
|
"#})
|
|
16
16
|
});
|
|
17
17
|
|
|
@@ -25,12 +25,12 @@ pub struct Args {
|
|
|
25
25
|
file: String,
|
|
26
26
|
/// Selector to scope the operation (optional — omit for whole file)
|
|
27
27
|
selector: Option<String>,
|
|
28
|
-
/// Quote style for
|
|
28
|
+
/// Quote style for keys
|
|
29
29
|
#[arg(long)]
|
|
30
|
-
|
|
31
|
-
/// Quote style for
|
|
30
|
+
keys: Option<yerba::KeyStyle>,
|
|
31
|
+
/// Quote style for values
|
|
32
32
|
#[arg(long)]
|
|
33
|
-
|
|
33
|
+
values: Option<yerba::QuoteStyle>,
|
|
34
34
|
#[arg(long)]
|
|
35
35
|
dry_run: bool,
|
|
36
36
|
}
|
|
@@ -53,7 +53,13 @@ impl Args {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
if let Some(style) = &self.values {
|
|
56
|
-
let
|
|
56
|
+
if let Ok(warnings) = document.enforce_quotes_at(style, selector) {
|
|
57
|
+
for warning in warnings {
|
|
58
|
+
use super::color::*;
|
|
59
|
+
|
|
60
|
+
eprintln!("{YELLOW}Warning:{RESET} {} — {}", resolved_file, warning);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
output(&resolved_file, &document, self.dry_run);
|
data/rust/src/commands/remove.rs
CHANGED
|
@@ -3,7 +3,7 @@ use std::sync::LazyLock;
|
|
|
3
3
|
use indoc::indoc;
|
|
4
4
|
|
|
5
5
|
use super::colorize_examples;
|
|
6
|
-
use super::{output, parse_file, run_op};
|
|
6
|
+
use super::{output, parse_file, resolve_files, run_op};
|
|
7
7
|
|
|
8
8
|
static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
9
9
|
colorize_examples(indoc! {r#"
|
|
@@ -28,8 +28,12 @@ pub struct Args {
|
|
|
28
28
|
|
|
29
29
|
impl Args {
|
|
30
30
|
pub fn run(self) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
for resolved_file in resolve_files(&self.file) {
|
|
32
|
+
let mut document = parse_file(&resolved_file);
|
|
33
|
+
let result = document.remove(&self.selector, &self.value);
|
|
34
|
+
|
|
35
|
+
run_op(&resolved_file, &document, result);
|
|
36
|
+
output(&resolved_file, &document, self.dry_run);
|
|
37
|
+
}
|
|
34
38
|
}
|
|
35
39
|
}
|
data/rust/src/commands/rename.rs
CHANGED
|
@@ -3,7 +3,7 @@ use std::sync::LazyLock;
|
|
|
3
3
|
use indoc::indoc;
|
|
4
4
|
|
|
5
5
|
use super::colorize_examples;
|
|
6
|
-
use super::{output, parse_file, run_op};
|
|
6
|
+
use super::{output, parse_file, resolve_files, run_op};
|
|
7
7
|
|
|
8
8
|
static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
9
9
|
colorize_examples(indoc! {r#"
|
|
@@ -30,8 +30,12 @@ pub struct Args {
|
|
|
30
30
|
|
|
31
31
|
impl Args {
|
|
32
32
|
pub fn run(self) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
for resolved_file in resolve_files(&self.file) {
|
|
34
|
+
let mut document = parse_file(&resolved_file);
|
|
35
|
+
let result = document.rename(&self.source, &self.destination);
|
|
36
|
+
|
|
37
|
+
run_op(&resolved_file, &document, result);
|
|
38
|
+
output(&resolved_file, &document, self.dry_run);
|
|
39
|
+
}
|
|
36
40
|
}
|
|
37
41
|
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
use std::collections::BTreeMap;
|
|
2
|
+
use std::sync::LazyLock;
|
|
3
|
+
|
|
4
|
+
use indoc::indoc;
|
|
5
|
+
|
|
6
|
+
use super::colorize_examples;
|
|
7
|
+
use super::{color, parse_file, resolve_files};
|
|
8
|
+
|
|
9
|
+
static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
10
|
+
colorize_examples(indoc! {r#"
|
|
11
|
+
yerba selectors config.yml
|
|
12
|
+
yerba selectors config.yml "database"
|
|
13
|
+
yerba selectors videos.yml "[]"
|
|
14
|
+
yerba selectors videos.yml "[].speakers"
|
|
15
|
+
yerba selectors "data/**/videos.yml"
|
|
16
|
+
yerba selectors "data/**/videos.yml" "[].talks"
|
|
17
|
+
"#})
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
#[derive(clap::Args)]
|
|
21
|
+
#[command(
|
|
22
|
+
about = "Show all valid selectors in a YAML file",
|
|
23
|
+
arg_required_else_help = true,
|
|
24
|
+
after_help = EXAMPLES.as_str()
|
|
25
|
+
)]
|
|
26
|
+
pub struct Args {
|
|
27
|
+
file: String,
|
|
28
|
+
/// Show selectors starting from this path
|
|
29
|
+
selector: Option<String>,
|
|
30
|
+
/// Sort selectors alphabetically (default: document order)
|
|
31
|
+
#[arg(long)]
|
|
32
|
+
sorted: bool,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[derive(Debug, Default)]
|
|
36
|
+
struct SelectorInfo {
|
|
37
|
+
min_count: Option<usize>,
|
|
38
|
+
max_count: Option<usize>,
|
|
39
|
+
order: usize,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
impl SelectorInfo {
|
|
43
|
+
fn record_count(&mut self, count: usize) {
|
|
44
|
+
self.min_count = Some(self.min_count.map_or(count, |min| min.min(count)));
|
|
45
|
+
self.max_count = Some(self.max_count.map_or(count, |max| max.max(count)));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fn count_label(&self) -> Option<String> {
|
|
49
|
+
match (self.min_count, self.max_count) {
|
|
50
|
+
(Some(0), Some(0)) => Some("empty".to_string()),
|
|
51
|
+
|
|
52
|
+
(Some(min), Some(max)) if min == max => {
|
|
53
|
+
if max <= 5 {
|
|
54
|
+
let indices: Vec<String> = (0..max).map(|i| format!("[{}]", i)).collect();
|
|
55
|
+
|
|
56
|
+
Some(indices.join(", "))
|
|
57
|
+
} else {
|
|
58
|
+
Some(format!("[0]..[{}]", max - 1))
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
(Some(min), Some(max)) => {
|
|
63
|
+
if max <= 5 {
|
|
64
|
+
let indices: Vec<String> = (0..max).map(|i| format!("[{}]", i)).collect();
|
|
65
|
+
|
|
66
|
+
Some(format!("{} ({}-{} items)", indices.join(", "), min, max))
|
|
67
|
+
} else {
|
|
68
|
+
Some(format!("[0]..[{}] ({}-{} items)", max - 1, min, max))
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
_ => None,
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
impl Args {
|
|
77
|
+
pub fn run(self) {
|
|
78
|
+
let mut all_selectors: BTreeMap<String, SelectorInfo> = BTreeMap::new();
|
|
79
|
+
let mut counter: usize = 1;
|
|
80
|
+
let selector = self.selector.as_deref().unwrap_or("");
|
|
81
|
+
|
|
82
|
+
for resolved_file in resolve_files(&self.file) {
|
|
83
|
+
let document = parse_file(&resolved_file);
|
|
84
|
+
let prefix = if selector.is_empty() { String::new() } else { selector.to_string() };
|
|
85
|
+
|
|
86
|
+
let values = if selector.is_empty() {
|
|
87
|
+
document.get_value("").into_iter().collect::<Vec<_>>()
|
|
88
|
+
} else {
|
|
89
|
+
document.get_values(selector)
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
for value in values {
|
|
93
|
+
collect_selectors(&value, &prefix, &mut all_selectors, &mut counter);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let mut entries: Vec<(&String, &SelectorInfo)> = all_selectors.iter().collect();
|
|
98
|
+
|
|
99
|
+
if self.sorted {
|
|
100
|
+
entries.sort_by_key(|(name, _)| name.to_string());
|
|
101
|
+
} else {
|
|
102
|
+
entries.sort_by_key(|(_, info)| info.order);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let max_selector_len = entries.iter().map(|(selector, _)| selector.len()).max().unwrap_or(0);
|
|
106
|
+
|
|
107
|
+
for (selector, info) in &entries {
|
|
108
|
+
if let Some(label) = info.count_label() {
|
|
109
|
+
let padding = max_selector_len - selector.len() + 2;
|
|
110
|
+
|
|
111
|
+
println!("{}{}{}{}{}", selector, " ".repeat(padding), color::DIM, label, color::RESET);
|
|
112
|
+
} else {
|
|
113
|
+
println!("{}", selector);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fn collect_selectors(value: &serde_yaml::Value, prefix: &str, selectors: &mut BTreeMap<String, SelectorInfo>, counter: &mut usize) {
|
|
120
|
+
match value {
|
|
121
|
+
serde_yaml::Value::Mapping(map) => {
|
|
122
|
+
for (key, child) in map {
|
|
123
|
+
if let serde_yaml::Value::String(key_string) = key {
|
|
124
|
+
let selector = if prefix.is_empty() {
|
|
125
|
+
key_string.clone()
|
|
126
|
+
} else {
|
|
127
|
+
format!("{}.{}", prefix, key_string)
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
let entry = selectors.entry(selector.clone()).or_default();
|
|
131
|
+
if entry.order == 0 {
|
|
132
|
+
entry.order = *counter;
|
|
133
|
+
*counter += 1;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
collect_selectors(child, &selector, selectors, counter);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
serde_yaml::Value::Sequence(sequence) => {
|
|
142
|
+
let bracket_prefix = format!("{}[]", prefix);
|
|
143
|
+
|
|
144
|
+
let entry = selectors.entry(bracket_prefix.clone()).or_default();
|
|
145
|
+
entry.record_count(sequence.len());
|
|
146
|
+
if entry.order == 0 {
|
|
147
|
+
entry.order = *counter;
|
|
148
|
+
*counter += 1;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
for item in sequence {
|
|
152
|
+
collect_selectors(item, &bracket_prefix, selectors, counter);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
_ => {}
|
|
157
|
+
}
|
|
158
|
+
}
|
data/rust/src/commands/set.rs
CHANGED
|
@@ -3,7 +3,7 @@ use std::sync::LazyLock;
|
|
|
3
3
|
use indoc::indoc;
|
|
4
4
|
|
|
5
5
|
use super::colorize_examples;
|
|
6
|
-
use super::{output, parse_file,
|
|
6
|
+
use super::{output, parse_file, resolve_files, run_op_with_hint};
|
|
7
7
|
|
|
8
8
|
static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
9
9
|
colorize_examples(indoc! {r#"
|
|
@@ -12,6 +12,7 @@ static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
|
12
12
|
yerba set config.yml "database.host" "0.0.0.0" --condition ".port == 5432"
|
|
13
13
|
yerba set videos.yml "[0].title" "New Title"
|
|
14
14
|
yerba set "data/**/event.yml" "website" "" --if-exists
|
|
15
|
+
yerba set videos.yml "[].description" "" --all
|
|
15
16
|
"#})
|
|
16
17
|
});
|
|
17
18
|
|
|
@@ -32,28 +33,44 @@ pub struct Args {
|
|
|
32
33
|
#[arg(long)]
|
|
33
34
|
condition: Option<String>,
|
|
34
35
|
#[arg(long)]
|
|
36
|
+
all: bool,
|
|
37
|
+
#[arg(long)]
|
|
35
38
|
dry_run: bool,
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
impl Args {
|
|
39
42
|
pub fn run(self) {
|
|
40
|
-
let mut document = parse_file(&self.file);
|
|
41
43
|
let parent_path = self.selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
document
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
45
|
+
for resolved_file in resolve_files(&self.file) {
|
|
46
|
+
let mut document = parse_file(&resolved_file);
|
|
47
|
+
|
|
48
|
+
let should_set = if self.if_exists {
|
|
49
|
+
document.exists(&self.selector)
|
|
50
|
+
} else if self.if_missing {
|
|
51
|
+
!document.exists(&self.selector)
|
|
52
|
+
} else if let Some(condition) = &self.condition {
|
|
53
|
+
document.evaluate_condition(parent_path, condition)
|
|
54
|
+
} else {
|
|
55
|
+
true
|
|
56
|
+
};
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
if should_set {
|
|
59
|
+
let result = if self.all {
|
|
60
|
+
document.set_all(&self.selector, &self.value)
|
|
61
|
+
} else {
|
|
62
|
+
document.set(&self.selector, &self.value)
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
run_op_with_hint(
|
|
66
|
+
&resolved_file,
|
|
67
|
+
&document,
|
|
68
|
+
result,
|
|
69
|
+
Some("Use --if-exists to skip files where the selector is missing"),
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
output(&resolved_file, &document, self.dry_run);
|
|
74
|
+
}
|
|
58
75
|
}
|
|
59
76
|
}
|