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/lib/yerba/sequence.rb
CHANGED
|
@@ -45,6 +45,9 @@ module Yerba
|
|
|
45
45
|
|
|
46
46
|
def value_at(index)
|
|
47
47
|
if connected?
|
|
48
|
+
child = current_children&.[](index) if index.is_a?(Integer) && !index.negative?
|
|
49
|
+
return child.value if child.is_a?(Scalar)
|
|
50
|
+
|
|
48
51
|
new_path = "#{@selector}[#{index}]"
|
|
49
52
|
document.value_at(new_path)
|
|
50
53
|
else
|
|
@@ -73,15 +76,15 @@ module Yerba
|
|
|
73
76
|
|
|
74
77
|
def concat(items)
|
|
75
78
|
if connected?
|
|
76
|
-
|
|
79
|
+
values = items.map do |item|
|
|
77
80
|
case item
|
|
78
81
|
when Map then item.to_hash
|
|
79
|
-
when
|
|
80
|
-
else
|
|
82
|
+
when Scalar then item.value
|
|
83
|
+
else item
|
|
81
84
|
end
|
|
82
85
|
end
|
|
83
86
|
|
|
84
|
-
document.insert_objects(@selector,
|
|
87
|
+
document.insert_objects(@selector, values)
|
|
85
88
|
else
|
|
86
89
|
@data.concat(items)
|
|
87
90
|
end
|
|
@@ -92,6 +95,12 @@ module Yerba
|
|
|
92
95
|
def each(&)
|
|
93
96
|
return enum_for(:each) unless block_given?
|
|
94
97
|
|
|
98
|
+
if connected? && (tree = current_children)
|
|
99
|
+
tree.each { |child| yield child&.dup }
|
|
100
|
+
|
|
101
|
+
return self
|
|
102
|
+
end
|
|
103
|
+
|
|
95
104
|
if connected?
|
|
96
105
|
items = document.get_all("#{@selector}[]")
|
|
97
106
|
|
|
@@ -114,7 +123,7 @@ module Yerba
|
|
|
114
123
|
end
|
|
115
124
|
|
|
116
125
|
def where(selector = nil, value = nil, **criteria)
|
|
117
|
-
QueryResult.new(self, indices_of(selector, value, **criteria))
|
|
126
|
+
QueryResult.new(self, indices_of(selector, value, **criteria)) { indices_of(selector, value, **criteria) }
|
|
118
127
|
end
|
|
119
128
|
|
|
120
129
|
def pluck(*fields)
|
|
@@ -211,28 +220,24 @@ module Yerba
|
|
|
211
220
|
end
|
|
212
221
|
|
|
213
222
|
def length
|
|
214
|
-
|
|
215
|
-
scalar_items = document.value_at("#{@selector}[]")
|
|
223
|
+
return @data.length unless connected?
|
|
216
224
|
|
|
217
|
-
|
|
218
|
-
scalar_items.length
|
|
219
|
-
else
|
|
220
|
-
data = document.value_at(@selector)
|
|
221
|
-
|
|
222
|
-
data.is_a?(Array) ? data.length : 0
|
|
223
|
-
end
|
|
224
|
-
else
|
|
225
|
-
@data.length
|
|
226
|
-
end
|
|
225
|
+
current_children&.size || document.length_at(@selector)
|
|
227
226
|
end
|
|
228
227
|
alias size length
|
|
229
228
|
|
|
230
|
-
def first
|
|
231
|
-
self[0]
|
|
229
|
+
def first(count = nil)
|
|
230
|
+
return self[0] if count.nil?
|
|
231
|
+
|
|
232
|
+
super
|
|
232
233
|
end
|
|
233
234
|
|
|
234
|
-
def last
|
|
235
|
-
|
|
235
|
+
def last(count = nil)
|
|
236
|
+
size = length
|
|
237
|
+
return self[size - 1] if count.nil?
|
|
238
|
+
raise ArgumentError, "negative array size" if count.negative?
|
|
239
|
+
|
|
240
|
+
([size - count, 0].max...size).map { |index| self[index] }
|
|
236
241
|
end
|
|
237
242
|
|
|
238
243
|
def remove(value)
|
|
@@ -263,15 +268,15 @@ module Yerba
|
|
|
263
268
|
self
|
|
264
269
|
end
|
|
265
270
|
|
|
266
|
-
def sort(by: nil, case_sensitive: false)
|
|
267
|
-
document&.sort(@selector, by: by, case_sensitive: case_sensitive)
|
|
271
|
+
def sort(by: nil, order: nil, case_sensitive: false)
|
|
272
|
+
document&.sort(@selector, by: by, order: order, case_sensitive: case_sensitive)
|
|
268
273
|
|
|
269
274
|
self
|
|
270
275
|
end
|
|
271
276
|
|
|
272
277
|
# Deletes the entire sequence node from the YAML document.
|
|
273
278
|
#
|
|
274
|
-
# Removes the sequence at its selector
|
|
279
|
+
# Removes the sequence at its selector from the parent document.
|
|
275
280
|
# Has no effect if the sequence is not connected to a document.
|
|
276
281
|
#
|
|
277
282
|
# Returns the document, or +nil+ if the sequence is not connected to a document.
|
|
@@ -345,8 +350,8 @@ module Yerba
|
|
|
345
350
|
|
|
346
351
|
private
|
|
347
352
|
|
|
348
|
-
def dig_into(hash,
|
|
349
|
-
keys =
|
|
353
|
+
def dig_into(hash, selector)
|
|
354
|
+
keys = selector.split(".")
|
|
350
355
|
|
|
351
356
|
keys.reduce(hash) { |current, key| current.is_a?(Hash) ? current[key] : nil }
|
|
352
357
|
end
|
|
@@ -356,8 +361,8 @@ module Yerba
|
|
|
356
361
|
|
|
357
362
|
criteria.each do |field, value|
|
|
358
363
|
if value.is_a?(Hash)
|
|
359
|
-
flatten_hash("#{field}[]", value).each do |
|
|
360
|
-
expanded << [
|
|
364
|
+
flatten_hash("#{field}[]", value).each do |selector, leaf_value|
|
|
365
|
+
expanded << [selector, leaf_value]
|
|
361
366
|
end
|
|
362
367
|
elsif value.is_a?(Array)
|
|
363
368
|
value.each do |item|
|
|
@@ -375,12 +380,12 @@ module Yerba
|
|
|
375
380
|
result = {}
|
|
376
381
|
|
|
377
382
|
hash.each do |key, value|
|
|
378
|
-
|
|
383
|
+
selector = "#{prefix}.#{key}"
|
|
379
384
|
|
|
380
385
|
if value.is_a?(Hash)
|
|
381
|
-
flatten_hash("#{
|
|
386
|
+
flatten_hash("#{selector}[]", value).each { |nested_selector, leaf| result[nested_selector] = leaf }
|
|
382
387
|
else
|
|
383
|
-
result[
|
|
388
|
+
result[selector] = value
|
|
384
389
|
end
|
|
385
390
|
end
|
|
386
391
|
|
|
@@ -399,8 +404,8 @@ module Yerba
|
|
|
399
404
|
end
|
|
400
405
|
end
|
|
401
406
|
|
|
402
|
-
def dig_values(hash,
|
|
403
|
-
parts =
|
|
407
|
+
def dig_values(hash, selector)
|
|
408
|
+
parts = selector.split(".")
|
|
404
409
|
current = [hash]
|
|
405
410
|
|
|
406
411
|
parts.each do |part|
|
data/lib/yerba/version.rb
CHANGED
data/lib/yerba.rb
CHANGED
data/rust/Cargo.lock
CHANGED
data/rust/Cargo.toml
CHANGED
data/rust/src/commands/get.rs
CHANGED
|
@@ -45,9 +45,9 @@ pub struct Args {
|
|
|
45
45
|
impl Args {
|
|
46
46
|
pub fn run(self) {
|
|
47
47
|
let selector = yerba::Selector::parse(&self.selector);
|
|
48
|
-
let
|
|
48
|
+
let condition_selector = self.condition.as_deref().map(yerba::Selector::parse);
|
|
49
49
|
let select_fields: Option<Vec<&str>> = self.select.as_deref().map(|fields| fields.split(',').collect());
|
|
50
|
-
let (
|
|
50
|
+
let (search_selector, extract_field) = self.resolve_search_scope(&selector, condition_selector.as_ref());
|
|
51
51
|
|
|
52
52
|
let normalized_condition = self.condition.as_ref().map(|condition| {
|
|
53
53
|
if !condition.starts_with('.') {
|
|
@@ -73,7 +73,7 @@ impl Args {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
let
|
|
76
|
+
let search_selector_string = search_selector.to_selector_string();
|
|
77
77
|
let mut all_results: Vec<serde_json::Value> = Vec::new();
|
|
78
78
|
let files = resolve_files(&self.file);
|
|
79
79
|
let is_glob = files.len() > 1;
|
|
@@ -97,10 +97,10 @@ impl Args {
|
|
|
97
97
|
|
|
98
98
|
for field in fields {
|
|
99
99
|
let field_trimmed = field.trim().trim_start_matches('.');
|
|
100
|
-
let full_selector = if
|
|
100
|
+
let full_selector = if search_selector_string.is_empty() {
|
|
101
101
|
field_trimmed.to_string()
|
|
102
102
|
} else {
|
|
103
|
-
format!("{}.{}",
|
|
103
|
+
format!("{}.{}", search_selector_string, field_trimmed)
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
if !document.exists(&full_selector) {
|
|
@@ -122,24 +122,24 @@ impl Args {
|
|
|
122
122
|
|
|
123
123
|
let (values, selectors, lines): (Vec<yaml_serde::Value>, Vec<String>, Vec<usize>) = if select_fields.is_some() {
|
|
124
124
|
if let Some(condition) = &normalized_condition {
|
|
125
|
-
let triples = document.filter_with_selectors(&
|
|
125
|
+
let triples = document.filter_with_selectors(&search_selector_string, condition).unwrap_or_default();
|
|
126
126
|
let (values, rest): (Vec<_>, Vec<_>) = triples.into_iter().map(|(v, s, l)| (v, (s, l))).unzip();
|
|
127
127
|
let (selectors, lines): (Vec<_>, Vec<_>) = rest.into_iter().unzip();
|
|
128
128
|
|
|
129
129
|
(values, selectors, lines)
|
|
130
130
|
} else {
|
|
131
|
-
let located = document.get_all_located(&
|
|
131
|
+
let located = document.get_all_located(&search_selector_string);
|
|
132
132
|
let selectors = located.iter().map(|n| n.selector.clone()).collect();
|
|
133
133
|
let lines = located.iter().map(|n| n.line).collect();
|
|
134
|
-
let values = document.get_values(&
|
|
134
|
+
let values = document.get_values(&search_selector_string);
|
|
135
135
|
let values: Vec<_> = values.into_iter().filter(|v| !v.is_null()).collect();
|
|
136
136
|
|
|
137
137
|
(values, selectors, lines)
|
|
138
138
|
}
|
|
139
139
|
} else if let Some(condition) = &normalized_condition {
|
|
140
|
-
(document.filter(&
|
|
140
|
+
(document.filter(&search_selector_string, condition).unwrap_or_default(), Vec::new(), Vec::new())
|
|
141
141
|
} else {
|
|
142
|
-
(document.get_values(&
|
|
142
|
+
(document.get_values(&search_selector_string), Vec::new(), Vec::new())
|
|
143
143
|
};
|
|
144
144
|
|
|
145
145
|
for (index, value) in values.iter().enumerate() {
|
|
@@ -216,8 +216,8 @@ impl Args {
|
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
fn resolve_search_scope(&self, selector: &yerba::Selector,
|
|
220
|
-
if let Some(condition) =
|
|
219
|
+
fn resolve_search_scope(&self, selector: &yerba::Selector, condition_selector: Option<&yerba::Selector>) -> (yerba::Selector, Option<yerba::Selector>) {
|
|
220
|
+
if let Some(condition) = condition_selector {
|
|
221
221
|
if condition.is_relative() {
|
|
222
222
|
let (container, field) = selector.split_at_last_bracket();
|
|
223
223
|
|
data/rust/src/commands/init.rs
CHANGED
|
@@ -25,12 +25,12 @@ pub fn run() {
|
|
|
25
25
|
#
|
|
26
26
|
# # Override quote style for a specific selector
|
|
27
27
|
# - quote_style:
|
|
28
|
-
#
|
|
28
|
+
# selector: "[].speakers"
|
|
29
29
|
# value_style: plain
|
|
30
30
|
#
|
|
31
31
|
# # Sort keys in a predefined order (aborts on unknown keys)
|
|
32
32
|
# - sort_keys:
|
|
33
|
-
#
|
|
33
|
+
# selector: "[]"
|
|
34
34
|
# order:
|
|
35
35
|
# - id
|
|
36
36
|
# - title
|
|
@@ -38,7 +38,7 @@ pub fn run() {
|
|
|
38
38
|
#
|
|
39
39
|
# # Sort items in a sequence by field(s)
|
|
40
40
|
# - sort:
|
|
41
|
-
#
|
|
41
|
+
# selector: ""
|
|
42
42
|
# by: name
|
|
43
43
|
# # case_sensitive: false
|
|
44
44
|
#
|
|
@@ -54,19 +54,19 @@ pub fn run() {
|
|
|
54
54
|
#
|
|
55
55
|
# # Set a value (with optional condition)
|
|
56
56
|
# - set:
|
|
57
|
-
#
|
|
57
|
+
# selector: "status"
|
|
58
58
|
# value: "published"
|
|
59
59
|
# # condition: ".draft == true"
|
|
60
60
|
#
|
|
61
61
|
# # Insert a new key or sequence item
|
|
62
62
|
# - insert:
|
|
63
|
-
#
|
|
63
|
+
# selector: "tags"
|
|
64
64
|
# value: "yaml"
|
|
65
65
|
# # condition: ".tags not_contains yaml"
|
|
66
66
|
#
|
|
67
67
|
# # Delete a key (with optional condition)
|
|
68
68
|
# - delete:
|
|
69
|
-
#
|
|
69
|
+
# selector: "deprecated_field"
|
|
70
70
|
# # condition: ".deprecated_field == true"
|
|
71
71
|
#
|
|
72
72
|
# # Rename a key
|
|
@@ -76,12 +76,12 @@ pub fn run() {
|
|
|
76
76
|
#
|
|
77
77
|
# # Remove an item from a sequence
|
|
78
78
|
# - remove:
|
|
79
|
-
#
|
|
79
|
+
# selector: "tags"
|
|
80
80
|
# value: "obsolete"
|
|
81
81
|
#
|
|
82
82
|
# # Get a value and store it as a variable
|
|
83
83
|
# - get:
|
|
84
|
-
#
|
|
84
|
+
# selector: "[].name"
|
|
85
85
|
# as: "names"
|
|
86
86
|
# # file: "other_file.yml"
|
|
87
87
|
"#};
|
data/rust/src/commands/insert.rs
CHANGED
|
@@ -4,7 +4,7 @@ use std::sync::LazyLock;
|
|
|
4
4
|
use indoc::indoc;
|
|
5
5
|
|
|
6
6
|
use super::colorize_examples;
|
|
7
|
-
use super::{output, parse_file, resolve_files, run_op};
|
|
7
|
+
use super::{default_insert_position, output, parse_file, resolve_files, run_op};
|
|
8
8
|
|
|
9
9
|
static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
10
10
|
colorize_examples(indoc! {r#"
|
|
@@ -81,28 +81,14 @@ impl Args {
|
|
|
81
81
|
std::process::exit(1);
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
let parent_path = self.selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
85
|
-
|
|
86
84
|
let position = if let Some(index) = self.at {
|
|
87
85
|
yerba::InsertPosition::At(index)
|
|
88
86
|
} else if let Some(target) = self.before {
|
|
89
|
-
|
|
90
|
-
yerba::InsertPosition::BeforeCondition(target)
|
|
91
|
-
} else {
|
|
92
|
-
yerba::InsertPosition::Before(target)
|
|
93
|
-
}
|
|
87
|
+
yerba::InsertPosition::before(target)
|
|
94
88
|
} else if let Some(target) = self.after {
|
|
95
|
-
|
|
96
|
-
yerba::InsertPosition::AfterCondition(target)
|
|
97
|
-
} else {
|
|
98
|
-
yerba::InsertPosition::After(target)
|
|
99
|
-
}
|
|
89
|
+
yerba::InsertPosition::after(target)
|
|
100
90
|
} else {
|
|
101
|
-
|
|
102
|
-
.and_then(|yerbafile_path| yerba::Yerbafile::load(&yerbafile_path).ok())
|
|
103
|
-
.and_then(|yerbafile| yerbafile.sort_order_for(&self.file, parent_path))
|
|
104
|
-
.map(yerba::InsertPosition::FromSortOrder)
|
|
105
|
-
.unwrap_or(yerba::InsertPosition::Last)
|
|
91
|
+
default_insert_position(&self.file, &self.selector)
|
|
106
92
|
};
|
|
107
93
|
|
|
108
94
|
for resolved_file in resolve_files(&self.file) {
|
|
@@ -49,6 +49,8 @@ impl Args {
|
|
|
49
49
|
"end_column": info.location.end_column,
|
|
50
50
|
"start_offset": info.location.start_offset,
|
|
51
51
|
"end_offset": info.location.end_offset,
|
|
52
|
+
"start_character_column": info.location.start_character_column,
|
|
53
|
+
"end_character_column": info.location.end_character_column,
|
|
52
54
|
});
|
|
53
55
|
|
|
54
56
|
println!("{}", serde_json::to_string_pretty(&json).unwrap_or_default());
|
data/rust/src/commands/mod.rs
CHANGED
|
@@ -196,6 +196,24 @@ pub(crate) fn run_yerbafile(write: bool, files: Vec<String>) {
|
|
|
196
196
|
ui::subtle(format!("(from {})", yerbafile_path.display()))
|
|
197
197
|
);
|
|
198
198
|
|
|
199
|
+
if !yerbafile.deprecated_path_keys.is_empty() {
|
|
200
|
+
let keys = &yerbafile.deprecated_path_keys;
|
|
201
|
+
let mut places = keys.iter().take(3).cloned().collect::<Vec<_>>().join(", ");
|
|
202
|
+
|
|
203
|
+
if keys.len() > 3 {
|
|
204
|
+
places.push_str(&format!(" and {} more", keys.len() - 3));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
eprintln!(
|
|
208
|
+
"{} {} is deprecated, use {} instead ({}: {})\n",
|
|
209
|
+
ui::pending("Warning:"),
|
|
210
|
+
ui::strong("path:"),
|
|
211
|
+
ui::strong("selector:"),
|
|
212
|
+
pluralize(keys.len(), "place", "places"),
|
|
213
|
+
places
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
199
217
|
let started = std::time::Instant::now();
|
|
200
218
|
|
|
201
219
|
let results = if files.is_empty() {
|
|
@@ -309,14 +327,14 @@ fn format_duration(elapsed: std::time::Duration) -> String {
|
|
|
309
327
|
|
|
310
328
|
pub(crate) fn resolve_move_indexes(
|
|
311
329
|
document: &yerba::Document,
|
|
312
|
-
|
|
330
|
+
selector: &str,
|
|
313
331
|
item: &str,
|
|
314
332
|
before: Option<String>,
|
|
315
333
|
after: Option<String>,
|
|
316
334
|
to: Option<usize>,
|
|
317
335
|
resolve: impl Fn(&yerba::Document, &str, &str) -> Result<usize, yerba::YerbaError>,
|
|
318
336
|
) -> (usize, usize) {
|
|
319
|
-
let from_index = resolve(document,
|
|
337
|
+
let from_index = resolve(document, selector, item).unwrap_or_else(|error| {
|
|
320
338
|
eprintln!("{} {}", ui::failure("Error:"), error);
|
|
321
339
|
process::exit(1);
|
|
322
340
|
});
|
|
@@ -324,7 +342,7 @@ pub(crate) fn resolve_move_indexes(
|
|
|
324
342
|
let to_index = if let Some(index) = to {
|
|
325
343
|
index
|
|
326
344
|
} else if let Some(target) = &before {
|
|
327
|
-
let target_index = resolve(document,
|
|
345
|
+
let target_index = resolve(document, selector, target).unwrap_or_else(|error| {
|
|
328
346
|
eprintln!("{} {}", ui::failure("Error:"), error);
|
|
329
347
|
process::exit(1);
|
|
330
348
|
});
|
|
@@ -335,7 +353,7 @@ pub(crate) fn resolve_move_indexes(
|
|
|
335
353
|
target_index
|
|
336
354
|
}
|
|
337
355
|
} else if let Some(target) = &after {
|
|
338
|
-
let target_index = resolve(document,
|
|
356
|
+
let target_index = resolve(document, selector, target).unwrap_or_else(|error| {
|
|
339
357
|
eprintln!("{} {}", ui::failure("Error:"), error);
|
|
340
358
|
process::exit(1);
|
|
341
359
|
});
|
|
@@ -417,7 +435,7 @@ pub(crate) fn run_op_with_hint(display_file: &str, document: &yerba::Document, r
|
|
|
417
435
|
}
|
|
418
436
|
}
|
|
419
437
|
|
|
420
|
-
pub(crate) fn show_similar_selectors(file: &str, document: &yerba::Document,
|
|
438
|
+
pub(crate) fn show_similar_selectors(file: &str, document: &yerba::Document, invalid_selector: &str) {
|
|
421
439
|
use yerba::didyoumean::didyoumean_ranked;
|
|
422
440
|
|
|
423
441
|
let selectors = document.selectors();
|
|
@@ -426,7 +444,7 @@ pub(crate) fn show_similar_selectors(file: &str, document: &yerba::Document, inv
|
|
|
426
444
|
return;
|
|
427
445
|
}
|
|
428
446
|
|
|
429
|
-
let query =
|
|
447
|
+
let query = invalid_selector.split_whitespace().next().unwrap_or(invalid_selector);
|
|
430
448
|
let threshold = query.len() / 2 + 3;
|
|
431
449
|
let close = didyoumean_ranked(query, &selectors, threshold);
|
|
432
450
|
|
|
@@ -468,3 +486,13 @@ pub(crate) fn output(file: &str, document: &yerba::Document, dry_run: bool) {
|
|
|
468
486
|
});
|
|
469
487
|
}
|
|
470
488
|
}
|
|
489
|
+
|
|
490
|
+
pub(crate) fn default_insert_position(file: &str, selector: &str) -> yerba::InsertPosition {
|
|
491
|
+
let parent_selector = selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
492
|
+
|
|
493
|
+
yerba::Yerbafile::find()
|
|
494
|
+
.and_then(|yerbafile_path| yerba::Yerbafile::load(&yerbafile_path).ok())
|
|
495
|
+
.and_then(|yerbafile| yerbafile.sort_order_for(file, parent_selector))
|
|
496
|
+
.map(yerba::InsertPosition::FromSortOrder)
|
|
497
|
+
.unwrap_or(yerba::InsertPosition::Last)
|
|
498
|
+
}
|
|
@@ -45,7 +45,7 @@ impl Args {
|
|
|
45
45
|
self.before,
|
|
46
46
|
self.after,
|
|
47
47
|
self.to,
|
|
48
|
-
|document,
|
|
48
|
+
|document, selector, reference| document.resolve_sequence_index(selector, reference),
|
|
49
49
|
);
|
|
50
50
|
|
|
51
51
|
let result = document.move_item(&self.selector, from_index, to_index);
|
|
@@ -36,16 +36,16 @@ pub struct Args {
|
|
|
36
36
|
|
|
37
37
|
impl Args {
|
|
38
38
|
pub fn run(self) {
|
|
39
|
-
let (
|
|
39
|
+
let (parent_selector, key) = self.selector.rsplit_once('.').unwrap_or(("", &self.selector));
|
|
40
40
|
|
|
41
41
|
let mut document = parse_file(&self.file);
|
|
42
42
|
|
|
43
43
|
let before_key = self.before.map(|target| {
|
|
44
44
|
let (target_parent, target_key) = target.rsplit_once('.').unwrap_or(("", &target));
|
|
45
45
|
|
|
46
|
-
if target_parent !=
|
|
46
|
+
if target_parent != parent_selector {
|
|
47
47
|
eprintln!(
|
|
48
|
-
"{} cannot move key across different maps ({} \u{2192} {})\n\n Use 'yerba rename' to relocate keys to a different
|
|
48
|
+
"{} cannot move key across different maps ({} \u{2192} {})\n\n Use 'yerba rename' to relocate keys to a different map.",
|
|
49
49
|
ui::failure("Error:"),
|
|
50
50
|
self.selector,
|
|
51
51
|
target
|
|
@@ -60,9 +60,9 @@ impl Args {
|
|
|
60
60
|
let after_key = self.after.map(|target| {
|
|
61
61
|
let (target_parent, target_key) = target.rsplit_once('.').unwrap_or(("", &target));
|
|
62
62
|
|
|
63
|
-
if target_parent !=
|
|
63
|
+
if target_parent != parent_selector {
|
|
64
64
|
eprintln!(
|
|
65
|
-
"{} cannot move key across different maps ({} \u{2192} {})\n\n Use 'yerba rename' to relocate keys to a different
|
|
65
|
+
"{} cannot move key across different maps ({} \u{2192} {})\n\n Use 'yerba rename' to relocate keys to a different map.",
|
|
66
66
|
ui::failure("Error:"),
|
|
67
67
|
self.selector,
|
|
68
68
|
target
|
|
@@ -76,15 +76,15 @@ impl Args {
|
|
|
76
76
|
|
|
77
77
|
let (from_index, to_index) = resolve_move_indexes(
|
|
78
78
|
&document,
|
|
79
|
-
|
|
79
|
+
parent_selector,
|
|
80
80
|
key,
|
|
81
81
|
before_key,
|
|
82
82
|
after_key,
|
|
83
83
|
self.to,
|
|
84
|
-
|document,
|
|
84
|
+
|document, parent_selector, reference| document.resolve_key_index(parent_selector, reference),
|
|
85
85
|
);
|
|
86
86
|
|
|
87
|
-
let result = document.move_key(
|
|
87
|
+
let result = document.move_key(parent_selector, from_index, to_index);
|
|
88
88
|
run_op(&self.file, &document, result);
|
|
89
89
|
output(&self.file, &document, self.dry_run);
|
|
90
90
|
}
|
data/rust/src/commands/rename.rs
CHANGED
|
@@ -16,7 +16,7 @@ static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
|
16
16
|
|
|
17
17
|
#[derive(clap::Args)]
|
|
18
18
|
#[command(
|
|
19
|
-
about = "Rename a key, or move it to another map (the destination is a full selector
|
|
19
|
+
about = "Rename a key, or move it to another map (the destination is a full selector)",
|
|
20
20
|
arg_required_else_help = true,
|
|
21
21
|
after_help = EXAMPLES.as_str()
|
|
22
22
|
)]
|
|
@@ -25,7 +25,7 @@ static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
|
25
25
|
)]
|
|
26
26
|
pub struct Args {
|
|
27
27
|
file: String,
|
|
28
|
-
/// Show selectors starting from this
|
|
28
|
+
/// Show selectors starting from this selector
|
|
29
29
|
selector: Option<String>,
|
|
30
30
|
/// Sort selectors alphabetically (default: document order)
|
|
31
31
|
#[arg(long)]
|
data/rust/src/commands/set.rs
CHANGED
|
@@ -3,12 +3,13 @@ use std::sync::LazyLock;
|
|
|
3
3
|
use indoc::indoc;
|
|
4
4
|
|
|
5
5
|
use super::colorize_examples;
|
|
6
|
-
use super::{output, parse_file, resolve_files, run_op_with_hint};
|
|
6
|
+
use super::{default_insert_position, 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#"
|
|
10
10
|
yerba set config.yml "database.host" "0.0.0.0"
|
|
11
11
|
yerba set config.yml "database.host" "0.0.0.0" --if-exists
|
|
12
|
+
yerba set config.yml "database.pool" 5 --plain --if-missing
|
|
12
13
|
yerba set config.yml "database.host" "0.0.0.0" --condition ".port == 5432"
|
|
13
14
|
yerba set videos.yml "[0].title" "New Title"
|
|
14
15
|
yerba set videos.yml "[].title" "New Title" --condition ".id == talk-1"
|
|
@@ -21,7 +22,7 @@ static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
|
21
22
|
|
|
22
23
|
#[derive(clap::Args)]
|
|
23
24
|
#[command(
|
|
24
|
-
about = "Update an existing value at a
|
|
25
|
+
about = "Update an existing value at a selector (preserves quote style)",
|
|
25
26
|
arg_required_else_help = true,
|
|
26
27
|
after_help = EXAMPLES.as_str()
|
|
27
28
|
)]
|
|
@@ -46,7 +47,7 @@ pub struct Args {
|
|
|
46
47
|
|
|
47
48
|
impl Args {
|
|
48
49
|
pub fn run(self) {
|
|
49
|
-
let
|
|
50
|
+
let parent_selector = self.selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
50
51
|
|
|
51
52
|
if let Some(condition) = &self.condition {
|
|
52
53
|
if let Err(error) = yerba::validate_condition(condition) {
|
|
@@ -59,7 +60,7 @@ impl Args {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
let leaf = self.selector.rsplit_once('.').map(|(_, leaf)| leaf).unwrap_or(&self.selector);
|
|
62
|
-
let per_item = yerba::Selector::parse(
|
|
63
|
+
let per_item = yerba::Selector::parse(parent_selector).has_brackets();
|
|
63
64
|
|
|
64
65
|
for resolved_file in resolve_files(&self.file) {
|
|
65
66
|
let mut document = parse_file(&resolved_file);
|
|
@@ -69,14 +70,21 @@ impl Args {
|
|
|
69
70
|
} else if self.if_missing {
|
|
70
71
|
!document.exists(&self.selector)
|
|
71
72
|
} else if let Some(condition) = &self.condition {
|
|
72
|
-
per_item || document.evaluate_condition(
|
|
73
|
+
per_item || document.evaluate_condition(parent_selector, condition).unwrap_or(false)
|
|
73
74
|
} else {
|
|
74
75
|
true
|
|
75
76
|
};
|
|
76
77
|
|
|
77
78
|
if should_set {
|
|
78
79
|
let result = match &self.condition {
|
|
79
|
-
|
|
80
|
+
_ if self.if_missing => {
|
|
81
|
+
let value = if self.plain { self.value.clone() } else { yerba::quote_scalar(&self.value) };
|
|
82
|
+
|
|
83
|
+
document.insert_into(&self.selector, &value, default_insert_position(&self.file, &self.selector))
|
|
84
|
+
}
|
|
85
|
+
Some(condition) if per_item => document
|
|
86
|
+
.set_where(parent_selector, leaf, &self.value, condition, self.all, self.plain)
|
|
87
|
+
.map(|_| ()),
|
|
80
88
|
_ if self.all && self.plain => document.set_all_plain(&self.selector, &self.value),
|
|
81
89
|
_ if self.all => document.set_all(&self.selector, &self.value),
|
|
82
90
|
_ if self.plain => document.set_plain(&self.selector, &self.value),
|