yerba 0.4.0-x86_64-linux-gnu → 0.4.1-x86_64-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 +3 -0
- data/exe/x86_64-linux-gnu/yerba +0 -0
- data/ext/yerba/include/yerba.h +13 -0
- data/ext/yerba/yerba.c +50 -1
- 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 +1 -1
- data/lib/yerba/document.rb +29 -3
- data/lib/yerba/query_result.rb +50 -0
- data/lib/yerba/sequence.rb +19 -1
- data/lib/yerba/version.rb +1 -1
- data/lib/yerba/yerbafile.rb +45 -0
- data/lib/yerba.rb +2 -0
- data/rust/Cargo.lock +3 -1
- data/rust/Cargo.toml +3 -2
- data/rust/src/commands/apply.rs +11 -2
- data/rust/src/commands/check.rs +11 -2
- data/rust/src/commands/mod.rs +11 -8
- data/rust/src/document/insert.rs +70 -0
- data/rust/src/document/set.rs +11 -1
- data/rust/src/document/sort.rs +95 -63
- data/rust/src/ffi.rs +66 -0
- data/rust/src/main.rs +2 -0
- data/rust/src/yerbafile.rs +47 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c63edced27fb5d271865615abddb05ee8c028d4205fe01ddf1debfef105b962
|
|
4
|
+
data.tar.gz: 56f52e28f3360c7dcec764e1878b68f90b3d80c4b24ab59e15e664da3c9e848c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4b5257dcd6171cb8982c2a2839cc79faf0020bd39f740e6d4646e3c293f2b067f7effe497e7385632c35f9a55ac00edfd8eb21f3121a47b413bb350270091f55
|
|
7
|
+
data.tar.gz: 56377b990d5379a88233a2d50f39952662d295f919011f1480ae4137e85f9e1d03c5830784e9a4f088295c5f04a8e003e332c8e946bc0158f198db3594f06991
|
data/README.md
CHANGED
|
@@ -413,7 +413,10 @@ Use `yerba init` to create one, then `yerba apply` to apply all rules, or `yerba
|
|
|
413
413
|
```bash
|
|
414
414
|
yerba init
|
|
415
415
|
yerba apply
|
|
416
|
+
yerba apply path/to/file.yml
|
|
417
|
+
|
|
416
418
|
yerba check
|
|
419
|
+
yerba check path/to/file.yml
|
|
417
420
|
```
|
|
418
421
|
|
|
419
422
|
Each rule specifies a file glob and a list of steps to run in order:
|
data/exe/x86_64-linux-gnu/yerba
CHANGED
|
Binary file
|
data/ext/yerba/include/yerba.h
CHANGED
|
@@ -121,6 +121,10 @@ struct YerbaResult yerba_document_insert_object(struct Document *document,
|
|
|
121
121
|
|
|
122
122
|
struct YerbaResult yerba_document_delete(struct Document *document, const char *path);
|
|
123
123
|
|
|
124
|
+
struct YerbaResult yerba_document_insert_objects(struct Document *document,
|
|
125
|
+
const char *path,
|
|
126
|
+
const char *json);
|
|
127
|
+
|
|
124
128
|
struct YerbaResult yerba_document_remove(struct Document *document,
|
|
125
129
|
const char *path,
|
|
126
130
|
const char *value);
|
|
@@ -161,6 +165,15 @@ struct YerbaResult yerba_document_blank_lines(struct Document *document,
|
|
|
161
165
|
const char *path,
|
|
162
166
|
uintptr_t count);
|
|
163
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Caller must free with yerba_string_free.
|
|
170
|
+
*/
|
|
171
|
+
char *yerba_yerbafile_find(const char *directory);
|
|
172
|
+
|
|
173
|
+
struct YerbaResult yerba_document_apply_yerbafile(struct Document *document,
|
|
174
|
+
const char *file_path,
|
|
175
|
+
const char *yerbafile_path);
|
|
176
|
+
|
|
164
177
|
char *yerba_document_to_string(const struct Document *document);
|
|
165
178
|
|
|
166
179
|
void yerba_string_free(char *s);
|
data/ext/yerba/yerba.c
CHANGED
|
@@ -488,6 +488,17 @@ static VALUE document_insert_object(int argc, VALUE *argv, VALUE self) {
|
|
|
488
488
|
return self;
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
+
/* document.insert_objects(path, array) */
|
|
492
|
+
static VALUE document_insert_objects(VALUE self, VALUE path, VALUE array) {
|
|
493
|
+
struct Document *document = get_document(self);
|
|
494
|
+
VALUE json_string = rb_funcall(rb_path2class("JSON"), rb_intern("generate"), 1, array);
|
|
495
|
+
|
|
496
|
+
YerbaResult result = yerba_document_insert_objects(document, StringValueCStr(path), StringValueCStr(json_string));
|
|
497
|
+
check_result(result);
|
|
498
|
+
|
|
499
|
+
return self;
|
|
500
|
+
}
|
|
501
|
+
|
|
491
502
|
/* document.delete(path, condition: nil) */
|
|
492
503
|
static VALUE document_delete(int argc, VALUE *argv, VALUE self) {
|
|
493
504
|
VALUE path, opts;
|
|
@@ -671,6 +682,23 @@ static VALUE document_blank_lines(VALUE self, VALUE path, VALUE count) {
|
|
|
671
682
|
return self;
|
|
672
683
|
}
|
|
673
684
|
|
|
685
|
+
/* document.apply_yerbafile(yerbafile_path = nil) */
|
|
686
|
+
static VALUE document_apply_yerbafile(int argc, VALUE *argv, VALUE self) {
|
|
687
|
+
VALUE yerbafile_path;
|
|
688
|
+
rb_scan_args(argc, argv, "01", &yerbafile_path);
|
|
689
|
+
|
|
690
|
+
struct Document *document = get_document(self);
|
|
691
|
+
VALUE file_path = rb_iv_get(self, "@path");
|
|
692
|
+
|
|
693
|
+
const char *file_path_str = NIL_P(file_path) ? "" : StringValueCStr(file_path);
|
|
694
|
+
const char *yerbafile_path_str = NIL_P(yerbafile_path) ? NULL : StringValueCStr(yerbafile_path);
|
|
695
|
+
|
|
696
|
+
YerbaResult result = yerba_document_apply_yerbafile(document, file_path_str, yerbafile_path_str);
|
|
697
|
+
check_result(result);
|
|
698
|
+
|
|
699
|
+
return self;
|
|
700
|
+
}
|
|
701
|
+
|
|
674
702
|
/* document.to_s */
|
|
675
703
|
static VALUE document_to_s(VALUE self) {
|
|
676
704
|
struct Document *document = get_document(self);
|
|
@@ -773,6 +801,22 @@ static VALUE collection_s_find(int argc, VALUE *argv, VALUE self) {
|
|
|
773
801
|
return rb_funcall(rb_path2class("JSON"), rb_intern("parse"), 1, json_string);
|
|
774
802
|
}
|
|
775
803
|
|
|
804
|
+
/* Yerbafile.locate(directory = nil) → path string or nil */
|
|
805
|
+
static VALUE yerbafile_s_locate(int argc, VALUE *argv, VALUE klass) {
|
|
806
|
+
VALUE directory;
|
|
807
|
+
rb_scan_args(argc, argv, "01", &directory);
|
|
808
|
+
|
|
809
|
+
const char *dir = NIL_P(directory) ? NULL : StringValueCStr(directory);
|
|
810
|
+
char *result = yerba_yerbafile_find(dir);
|
|
811
|
+
|
|
812
|
+
if (!result) return Qnil;
|
|
813
|
+
|
|
814
|
+
VALUE path = make_utf8_string(result);
|
|
815
|
+
yerba_string_free(result);
|
|
816
|
+
|
|
817
|
+
return path;
|
|
818
|
+
}
|
|
819
|
+
|
|
776
820
|
void Init_yerba(void) {
|
|
777
821
|
rb_require("json");
|
|
778
822
|
|
|
@@ -803,6 +847,7 @@ void Init_yerba(void) {
|
|
|
803
847
|
rb_define_method(rb_cDocument, "set", document_set, -1);
|
|
804
848
|
rb_define_method(rb_cDocument, "insert", document_insert, -1);
|
|
805
849
|
rb_define_method(rb_cDocument, "insert_object", document_insert_object, -1);
|
|
850
|
+
rb_define_method(rb_cDocument, "insert_objects", document_insert_objects, 2);
|
|
806
851
|
rb_define_method(rb_cDocument, "delete", document_delete, -1);
|
|
807
852
|
rb_define_method(rb_cDocument, "remove", document_remove, 2);
|
|
808
853
|
rb_define_method(rb_cDocument, "remove_at", document_remove_at, 2);
|
|
@@ -811,8 +856,12 @@ void Init_yerba(void) {
|
|
|
811
856
|
rb_define_method(rb_cDocument, "sort_keys", document_sort_keys, 2);
|
|
812
857
|
rb_define_method(rb_cDocument, "quote_style", document_quote_style, -1);
|
|
813
858
|
rb_define_method(rb_cDocument, "blank_lines", document_blank_lines, 2);
|
|
859
|
+
rb_define_method(rb_cDocument, "apply_yerbafile", document_apply_yerbafile, -1);
|
|
814
860
|
rb_define_method(rb_cDocument, "to_s", document_to_s, 0);
|
|
815
|
-
rb_define_method(rb_cDocument, "
|
|
861
|
+
rb_define_method(rb_cDocument, "write!", document_save, 0);
|
|
816
862
|
rb_define_method(rb_cDocument, "changed?", document_changed_p, 0);
|
|
817
863
|
rb_define_method(rb_cDocument, "path", document_path, 0);
|
|
864
|
+
|
|
865
|
+
VALUE rb_cYerbafile = rb_define_class_under(rb_mYerba, "Yerbafile", rb_cObject);
|
|
866
|
+
rb_define_singleton_method(rb_cYerbafile, "locate", yerbafile_s_locate, -1);
|
|
818
867
|
}
|
data/lib/yerba/3.2/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/3.3/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/3.4/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/4.0/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/collection.rb
CHANGED
data/lib/yerba/document.rb
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module Yerba
|
|
4
4
|
class Document
|
|
5
|
+
ROOT_SELECTOR = ""
|
|
6
|
+
|
|
5
7
|
def root
|
|
6
|
-
self[
|
|
8
|
+
self[ROOT_SELECTOR]
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
def map?
|
|
@@ -15,11 +17,11 @@ module Yerba
|
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
def to_h
|
|
18
|
-
get_value(
|
|
20
|
+
get_value(ROOT_SELECTOR)
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def to_a
|
|
22
|
-
get_value(
|
|
24
|
+
get_value(ROOT_SELECTOR)
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def to_yaml
|
|
@@ -64,6 +66,30 @@ module Yerba
|
|
|
64
66
|
root << item
|
|
65
67
|
end
|
|
66
68
|
|
|
69
|
+
def concat(items)
|
|
70
|
+
root.concat(items)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def save!(apply: false)
|
|
74
|
+
Yerbafile.apply!(self, apply) if apply
|
|
75
|
+
write!
|
|
76
|
+
|
|
77
|
+
self
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def apply!(yerbafile = nil)
|
|
81
|
+
apply(yerbafile)
|
|
82
|
+
write! if changed?
|
|
83
|
+
|
|
84
|
+
self
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def apply(yerbafile = nil)
|
|
88
|
+
Yerbafile.apply!(self, yerbafile)
|
|
89
|
+
|
|
90
|
+
self
|
|
91
|
+
end
|
|
92
|
+
|
|
67
93
|
def inspect
|
|
68
94
|
if path
|
|
69
95
|
"#<Yerba::Document path=#{path.inspect}>"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yerba
|
|
4
|
+
class QueryResult
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
7
|
+
def initialize(sequence, indices)
|
|
8
|
+
@sequence = sequence
|
|
9
|
+
@indices = indices
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def each
|
|
13
|
+
return enum_for(:each) unless block_given?
|
|
14
|
+
|
|
15
|
+
@indices.each { |index| yield @sequence[index] }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def [](position)
|
|
19
|
+
index = @indices[position]
|
|
20
|
+
|
|
21
|
+
@sequence[index] if index
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def first
|
|
25
|
+
self[0]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def last
|
|
29
|
+
self[-1]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def length
|
|
33
|
+
@indices.length
|
|
34
|
+
end
|
|
35
|
+
alias size length
|
|
36
|
+
alias count length
|
|
37
|
+
|
|
38
|
+
def empty?
|
|
39
|
+
@indices.empty?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def indices
|
|
43
|
+
@indices.dup
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def inspect
|
|
47
|
+
"#<Yerba::QueryResult length=#{length}>"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/yerba/sequence.rb
CHANGED
|
@@ -55,6 +55,24 @@ module Yerba
|
|
|
55
55
|
self
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
+
def concat(items)
|
|
59
|
+
if @document
|
|
60
|
+
hashes = items.map do |item|
|
|
61
|
+
case item
|
|
62
|
+
when Map then item.to_hash
|
|
63
|
+
when Hash then item
|
|
64
|
+
else { value: item.to_s }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
@document.insert_objects(@selector, hashes)
|
|
69
|
+
else
|
|
70
|
+
@data.concat(items)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
self
|
|
74
|
+
end
|
|
75
|
+
|
|
58
76
|
def each
|
|
59
77
|
return enum_for(:each) unless block_given?
|
|
60
78
|
|
|
@@ -68,7 +86,7 @@ module Yerba
|
|
|
68
86
|
end
|
|
69
87
|
|
|
70
88
|
def where(selector = nil, value = nil, **criteria)
|
|
71
|
-
indices_of(selector, value, **criteria)
|
|
89
|
+
QueryResult.new(self, indices_of(selector, value, **criteria))
|
|
72
90
|
end
|
|
73
91
|
|
|
74
92
|
def pluck(*fields)
|
data/lib/yerba/version.rb
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yerba
|
|
4
|
+
class Yerbafile
|
|
5
|
+
attr_reader :path
|
|
6
|
+
|
|
7
|
+
def initialize(path)
|
|
8
|
+
@path = File.expand_path(path)
|
|
9
|
+
|
|
10
|
+
raise Yerba::Error, "Yerbafile not found: #{path}" unless File.exist?(@path)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.find(directory = Dir.pwd)
|
|
14
|
+
path = locate(directory)
|
|
15
|
+
|
|
16
|
+
path ? new(path) : nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.find!(directory = Dir.pwd)
|
|
20
|
+
find(directory) || raise(Yerba::Error, "No Yerbafile found")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.resolve(yerbafile = nil)
|
|
24
|
+
case yerbafile
|
|
25
|
+
when Yerbafile then yerbafile
|
|
26
|
+
when String then new(yerbafile)
|
|
27
|
+
when true, nil then find!
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.apply!(document, yerbafile = nil)
|
|
32
|
+
resolve(yerbafile).apply(document)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def apply(document)
|
|
36
|
+
document.apply_yerbafile(@path)
|
|
37
|
+
|
|
38
|
+
document
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def inspect
|
|
42
|
+
"#<Yerba::Yerbafile path=#{@path.inspect}>"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/yerba.rb
CHANGED
|
@@ -8,8 +8,10 @@ require_relative "yerba/formatting"
|
|
|
8
8
|
require_relative "yerba/scalar"
|
|
9
9
|
require_relative "yerba/map"
|
|
10
10
|
require_relative "yerba/sequence"
|
|
11
|
+
require_relative "yerba/query_result"
|
|
11
12
|
require_relative "yerba/document"
|
|
12
13
|
require_relative "yerba/collection"
|
|
14
|
+
require_relative "yerba/yerbafile"
|
|
13
15
|
|
|
14
16
|
begin
|
|
15
17
|
major, minor, = RUBY_VERSION.split(".")
|
data/rust/Cargo.lock
CHANGED
|
@@ -472,6 +472,7 @@ version = "1.0.149"
|
|
|
472
472
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
473
473
|
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
|
474
474
|
dependencies = [
|
|
475
|
+
"indexmap",
|
|
475
476
|
"itoa",
|
|
476
477
|
"memchr",
|
|
477
478
|
"serde",
|
|
@@ -784,7 +785,7 @@ dependencies = [
|
|
|
784
785
|
|
|
785
786
|
[[package]]
|
|
786
787
|
name = "yerba"
|
|
787
|
-
version = "0.4.
|
|
788
|
+
version = "0.4.1"
|
|
788
789
|
dependencies = [
|
|
789
790
|
"cbindgen",
|
|
790
791
|
"clap",
|
|
@@ -795,6 +796,7 @@ dependencies = [
|
|
|
795
796
|
"serde",
|
|
796
797
|
"serde_json",
|
|
797
798
|
"serde_yaml",
|
|
799
|
+
"tempfile",
|
|
798
800
|
"yaml_parser",
|
|
799
801
|
]
|
|
800
802
|
|
data/rust/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "yerba"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.1"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Marco Roth <marco.roth@intergga.ch>"]
|
|
6
6
|
description = "YAML Editing and Refactoring with Better Accuracy"
|
|
@@ -25,7 +25,7 @@ rowan = "0.16"
|
|
|
25
25
|
glob = "0.3"
|
|
26
26
|
serde = { version = "1", features = ["derive"] }
|
|
27
27
|
serde_yaml = "0.9"
|
|
28
|
-
serde_json = "1"
|
|
28
|
+
serde_json = { version = "1", features = ["preserve_order"] }
|
|
29
29
|
clap = { version = "4", features = ["derive"] }
|
|
30
30
|
indoc = "2"
|
|
31
31
|
rayon = "1"
|
|
@@ -34,3 +34,4 @@ rayon = "1"
|
|
|
34
34
|
cbindgen = "0.28"
|
|
35
35
|
|
|
36
36
|
[dev-dependencies]
|
|
37
|
+
tempfile = "3"
|
data/rust/src/commands/apply.rs
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
use super::run_yerbafile;
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
#[derive(clap::Args)]
|
|
4
|
+
#[command(about = "Apply Yerbafile rules to all matching files (or specific files)")]
|
|
5
|
+
pub struct Args {
|
|
6
|
+
/// Specific files to apply rules to (applies to all if omitted)
|
|
7
|
+
files: Vec<String>,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
impl Args {
|
|
11
|
+
pub fn run(self) {
|
|
12
|
+
run_yerbafile(true, self.files);
|
|
13
|
+
}
|
|
5
14
|
}
|
data/rust/src/commands/check.rs
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
use super::run_yerbafile;
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
#[derive(clap::Args)]
|
|
4
|
+
#[command(about = "Check if files match Yerbafile rules (exits 1 if changes needed)")]
|
|
5
|
+
pub struct Args {
|
|
6
|
+
/// Specific files to check (checks all if omitted)
|
|
7
|
+
files: Vec<String>,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
impl Args {
|
|
11
|
+
pub fn run(self) {
|
|
12
|
+
run_yerbafile(false, self.files);
|
|
13
|
+
}
|
|
5
14
|
}
|
data/rust/src/commands/mod.rs
CHANGED
|
@@ -156,10 +156,8 @@ pub enum Command {
|
|
|
156
156
|
Selectors(selectors::Args),
|
|
157
157
|
#[command(about = "Create a new Yerbafile in the current directory")]
|
|
158
158
|
Init,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
#[command(about = "Check if all files match Yerbafile rules (exits 1 if not)")]
|
|
162
|
-
Check,
|
|
159
|
+
Apply(apply::Args),
|
|
160
|
+
Check(check::Args),
|
|
163
161
|
#[command(about = "Print the yerba version")]
|
|
164
162
|
Version,
|
|
165
163
|
#[command(about = "\u{1f9c9}")]
|
|
@@ -184,15 +182,15 @@ impl Command {
|
|
|
184
182
|
Command::Directives(args) => args.run(),
|
|
185
183
|
Command::Selectors(args) => args.run(),
|
|
186
184
|
Command::Init => init::run(),
|
|
187
|
-
Command::Apply =>
|
|
188
|
-
Command::Check =>
|
|
185
|
+
Command::Apply(args) => args.run(),
|
|
186
|
+
Command::Check(args) => args.run(),
|
|
189
187
|
Command::Version => version::run(),
|
|
190
188
|
Command::Mate => mate::run(),
|
|
191
189
|
}
|
|
192
190
|
}
|
|
193
191
|
}
|
|
194
192
|
|
|
195
|
-
pub(crate) fn run_yerbafile(write: bool) {
|
|
193
|
+
pub(crate) fn run_yerbafile(write: bool, files: Vec<String>) {
|
|
196
194
|
use color::*;
|
|
197
195
|
|
|
198
196
|
let yerbafile_path = yerba::Yerbafile::find().unwrap_or_else(|| {
|
|
@@ -207,7 +205,12 @@ pub(crate) fn run_yerbafile(write: bool) {
|
|
|
207
205
|
|
|
208
206
|
eprintln!("🧉 {BOLD}Using{RESET} {}", yerbafile_path.display());
|
|
209
207
|
|
|
210
|
-
let results =
|
|
208
|
+
let results = if files.is_empty() {
|
|
209
|
+
yerbafile.apply(write)
|
|
210
|
+
} else {
|
|
211
|
+
files.iter().flat_map(|file| yerbafile.apply_file(file, write)).collect()
|
|
212
|
+
};
|
|
213
|
+
|
|
211
214
|
let mut has_changes = false;
|
|
212
215
|
let mut has_errors = false;
|
|
213
216
|
|
data/rust/src/document/insert.rs
CHANGED
|
@@ -52,6 +52,76 @@ impl Document {
|
|
|
52
52
|
self.insert_into(dot_path, &yaml_text, position)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
pub fn insert_objects(&mut self, dot_path: &str, json_values: &[serde_json::Value]) -> Result<(), YerbaError> {
|
|
56
|
+
if json_values.is_empty() {
|
|
57
|
+
return Ok(());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let quote_style = self.detect_sequence_quote_style(dot_path);
|
|
61
|
+
let current_node = self.navigate(dot_path)?;
|
|
62
|
+
|
|
63
|
+
let sequence = current_node
|
|
64
|
+
.descendants()
|
|
65
|
+
.find_map(BlockSeq::cast)
|
|
66
|
+
.ok_or_else(|| YerbaError::NotASequence(dot_path.to_string()))?;
|
|
67
|
+
|
|
68
|
+
let entries: Vec<_> = sequence.entries().collect();
|
|
69
|
+
|
|
70
|
+
if entries.is_empty() {
|
|
71
|
+
return Err(YerbaError::SelectorNotFound(dot_path.to_string()));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let indent = entries
|
|
75
|
+
.get(1)
|
|
76
|
+
.or(entries.first())
|
|
77
|
+
.map(|entry| preceding_whitespace_indent(entry.syntax()))
|
|
78
|
+
.unwrap_or_default();
|
|
79
|
+
|
|
80
|
+
let mut new_text = String::new();
|
|
81
|
+
|
|
82
|
+
for json_value in json_values {
|
|
83
|
+
let yaml_text = crate::yaml_writer::json_to_yaml_text(json_value, "e_style, 0);
|
|
84
|
+
|
|
85
|
+
let new_item = if yaml_text.contains('\n') {
|
|
86
|
+
let item_indent = format!("{} ", indent);
|
|
87
|
+
let lines: Vec<&str> = yaml_text.split('\n').collect();
|
|
88
|
+
|
|
89
|
+
let min_indent = lines
|
|
90
|
+
.iter()
|
|
91
|
+
.skip(1)
|
|
92
|
+
.filter(|line| !line.trim().is_empty())
|
|
93
|
+
.map(|line| line.len() - line.trim_start().len())
|
|
94
|
+
.min()
|
|
95
|
+
.unwrap_or(0);
|
|
96
|
+
|
|
97
|
+
let indented: Vec<String> = lines
|
|
98
|
+
.iter()
|
|
99
|
+
.enumerate()
|
|
100
|
+
.map(|(index, line)| {
|
|
101
|
+
if index == 0 {
|
|
102
|
+
line.to_string()
|
|
103
|
+
} else if line.trim().is_empty() {
|
|
104
|
+
String::new()
|
|
105
|
+
} else {
|
|
106
|
+
let relative = &line[min_indent..];
|
|
107
|
+
format!("{}{}", item_indent, relative)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
.collect();
|
|
111
|
+
|
|
112
|
+
format!("- {}", indented.join("\n"))
|
|
113
|
+
} else {
|
|
114
|
+
format!("- {}", yaml_text)
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
new_text.push_str(&format!("\n{}{}", indent, new_item));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let last_entry = entries.last().unwrap();
|
|
121
|
+
|
|
122
|
+
self.insert_after_node(last_entry.syntax(), &new_text)
|
|
123
|
+
}
|
|
124
|
+
|
|
55
125
|
pub fn insert_into(&mut self, dot_path: &str, value: &str, position: InsertPosition) -> Result<(), YerbaError> {
|
|
56
126
|
Self::validate_path(dot_path)?;
|
|
57
127
|
|
data/rust/src/document/set.rs
CHANGED
|
@@ -33,7 +33,17 @@ impl Document {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
for node in nodes.into_iter().rev() {
|
|
36
|
-
if let Some(
|
|
36
|
+
if let Some(block_scalar) = node.descendants().find(|child| child.kind() == SyntaxKind::BLOCK_SCALAR) {
|
|
37
|
+
let new_text = if value.is_empty() {
|
|
38
|
+
"\"\"".to_string()
|
|
39
|
+
} else if value.contains('\n') {
|
|
40
|
+
format!("|-\n {}", value.replace('\n', "\n "))
|
|
41
|
+
} else {
|
|
42
|
+
format!("\"{}\"", value.replace('"', "\\\""))
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
self.apply_edit(block_scalar.text_range(), &new_text)?;
|
|
46
|
+
} else if let Some(scalar_token) = find_scalar_token(&node) {
|
|
37
47
|
let new_text = format_scalar_value(value, scalar_token.kind());
|
|
38
48
|
|
|
39
49
|
self.replace_token(&scalar_token, &new_text)?;
|
data/rust/src/document/sort.rs
CHANGED
|
@@ -109,9 +109,7 @@ impl Document {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
pub fn validate_sort_keys(&self, dot_path: &str, key_order: &[&str]) -> Result<(), YerbaError> {
|
|
112
|
-
if
|
|
113
|
-
let sequence_path = if dot_path == "[]" { "" } else { &dot_path[..dot_path.len() - 3] };
|
|
114
|
-
|
|
112
|
+
if let Some(sequence_path) = strip_bracket_suffix(dot_path) {
|
|
115
113
|
return self.validate_each_sort_keys(sequence_path, key_order);
|
|
116
114
|
}
|
|
117
115
|
|
|
@@ -136,9 +134,7 @@ impl Document {
|
|
|
136
134
|
}
|
|
137
135
|
|
|
138
136
|
pub fn sort_keys(&mut self, dot_path: &str, key_order: &[&str]) -> Result<(), YerbaError> {
|
|
139
|
-
if
|
|
140
|
-
let sequence_path = if dot_path == "[]" { "" } else { &dot_path[..dot_path.len() - 3] };
|
|
141
|
-
|
|
137
|
+
if let Some(sequence_path) = strip_bracket_suffix(dot_path) {
|
|
142
138
|
return self.sort_each_keys(sequence_path, key_order);
|
|
143
139
|
}
|
|
144
140
|
|
|
@@ -200,72 +196,85 @@ impl Document {
|
|
|
200
196
|
}
|
|
201
197
|
|
|
202
198
|
pub fn sort_each_keys(&mut self, dot_path: &str, key_order: &[&str]) -> Result<(), YerbaError> {
|
|
203
|
-
let
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
199
|
+
let nodes = if dot_path.is_empty() {
|
|
200
|
+
match self.navigate(dot_path) {
|
|
201
|
+
Ok(node) => vec![node],
|
|
202
|
+
Err(_) => return Ok(()),
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
let found = self.navigate_all(dot_path);
|
|
206
|
+
if found.is_empty() {
|
|
207
|
+
return Ok(());
|
|
208
|
+
}
|
|
209
|
+
found
|
|
208
210
|
};
|
|
209
211
|
|
|
210
212
|
let mut edits: Vec<(TextRange, String)> = Vec::new();
|
|
211
213
|
|
|
212
|
-
for
|
|
213
|
-
let
|
|
214
|
-
|
|
215
|
-
let map = match entry_node.descendants().find_map(BlockMap::cast) {
|
|
216
|
-
Some(map) => map,
|
|
214
|
+
for current_node in &nodes {
|
|
215
|
+
let sequence = match current_node.descendants().find_map(BlockSeq::cast) {
|
|
216
|
+
Some(sequence) => sequence,
|
|
217
217
|
None => continue,
|
|
218
218
|
};
|
|
219
219
|
|
|
220
|
-
|
|
220
|
+
for entry in sequence.entries() {
|
|
221
|
+
let entry_node = entry.syntax();
|
|
221
222
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
223
|
+
let map = match entry_node.descendants().find_map(BlockMap::cast) {
|
|
224
|
+
Some(map) => map,
|
|
225
|
+
None => continue,
|
|
226
|
+
};
|
|
225
227
|
|
|
226
|
-
|
|
228
|
+
let entries: Vec<_> = map.entries().collect();
|
|
227
229
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
.map(|(entry, group)| {
|
|
232
|
-
let key_name = entry.key().and_then(|key_node| extract_scalar_text(key_node.syntax())).unwrap_or_default();
|
|
233
|
-
(key_name, group)
|
|
234
|
-
})
|
|
235
|
-
.collect();
|
|
230
|
+
if entries.len() <= 1 {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
236
233
|
|
|
237
|
-
|
|
234
|
+
let (groups, group_range) = collect_groups_with_range(map.syntax());
|
|
235
|
+
|
|
236
|
+
let mut keyed: Vec<(String, EntryGroup)> = entries
|
|
237
|
+
.iter()
|
|
238
|
+
.zip(groups)
|
|
239
|
+
.map(|(entry, group)| {
|
|
240
|
+
let key_name = entry.key().and_then(|key_node| extract_scalar_text(key_node.syntax())).unwrap_or_default();
|
|
241
|
+
(key_name, group)
|
|
242
|
+
})
|
|
243
|
+
.collect();
|
|
238
244
|
|
|
239
|
-
|
|
240
|
-
let position_a = key_order.iter().position(|&key| key == key_a);
|
|
241
|
-
let position_b = key_order.iter().position(|&key| key == key_b);
|
|
245
|
+
let original_keys: Vec<String> = keyed.iter().map(|(key, _)| key.clone()).collect();
|
|
242
246
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
(
|
|
246
|
-
(None, Some(_)) => std::cmp::Ordering::Greater,
|
|
247
|
+
keyed.sort_by(|(key_a, _), (key_b, _)| {
|
|
248
|
+
let position_a = key_order.iter().position(|&key| key == key_a);
|
|
249
|
+
let position_b = key_order.iter().position(|&key| key == key_b);
|
|
247
250
|
|
|
248
|
-
(
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
match (position_a, position_b) {
|
|
252
|
+
(Some(a), Some(b)) => a.cmp(&b),
|
|
253
|
+
(Some(_), None) => std::cmp::Ordering::Less,
|
|
254
|
+
(None, Some(_)) => std::cmp::Ordering::Greater,
|
|
251
255
|
|
|
252
|
-
|
|
256
|
+
(None, None) => {
|
|
257
|
+
let original_a = original_keys.iter().position(|key| key == key_a).unwrap();
|
|
258
|
+
let original_b = original_keys.iter().position(|key| key == key_b).unwrap();
|
|
259
|
+
|
|
260
|
+
original_a.cmp(&original_b)
|
|
261
|
+
}
|
|
253
262
|
}
|
|
254
|
-
}
|
|
255
|
-
});
|
|
263
|
+
});
|
|
256
264
|
|
|
257
|
-
|
|
258
|
-
|
|
265
|
+
let sorted_keys: Vec<&str> = keyed.iter().map(|(key, _)| key.as_str()).collect();
|
|
266
|
+
let orig_refs: Vec<&str> = original_keys.iter().map(|key| key.as_str()).collect();
|
|
259
267
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
268
|
+
if sorted_keys == orig_refs {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
263
271
|
|
|
264
|
-
|
|
272
|
+
let indent = entries.get(1).map(|entry| preceding_whitespace_indent(entry.syntax())).unwrap_or_default();
|
|
265
273
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
274
|
+
let sorted_groups: Vec<EntryGroup> = keyed.into_iter().map(|(_, group)| group).collect();
|
|
275
|
+
let map_text = rebuild_from_groups(&sorted_groups, &indent, false);
|
|
276
|
+
edits.push((group_range, map_text));
|
|
277
|
+
}
|
|
269
278
|
}
|
|
270
279
|
|
|
271
280
|
if edits.is_empty() {
|
|
@@ -292,21 +301,34 @@ impl Document {
|
|
|
292
301
|
}
|
|
293
302
|
|
|
294
303
|
pub fn validate_each_sort_keys(&self, dot_path: &str, key_order: &[&str]) -> Result<(), YerbaError> {
|
|
295
|
-
let
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
304
|
+
let nodes = if dot_path.is_empty() {
|
|
305
|
+
match self.navigate(dot_path) {
|
|
306
|
+
Ok(node) => vec![node],
|
|
307
|
+
Err(_) => return Ok(()),
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
let found = self.navigate_all(dot_path);
|
|
311
|
+
if found.is_empty() {
|
|
312
|
+
return Ok(());
|
|
313
|
+
}
|
|
314
|
+
found
|
|
300
315
|
};
|
|
301
316
|
|
|
302
317
|
let mut all_unknown: Vec<String> = Vec::new();
|
|
303
318
|
|
|
304
|
-
for
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
319
|
+
for current_node in &nodes {
|
|
320
|
+
let sequence = match current_node.descendants().find_map(BlockSeq::cast) {
|
|
321
|
+
Some(sequence) => sequence,
|
|
322
|
+
None => continue,
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
for entry in sequence.entries() {
|
|
326
|
+
if let Some(map) = entry.syntax().descendants().find_map(BlockMap::cast) {
|
|
327
|
+
for map_entry in map.entries() {
|
|
328
|
+
if let Some(key_name) = map_entry.key().and_then(|key_node| extract_scalar_text(key_node.syntax())) {
|
|
329
|
+
if !key_order.contains(&key_name.as_str()) && !all_unknown.contains(&key_name) {
|
|
330
|
+
all_unknown.push(key_name);
|
|
331
|
+
}
|
|
310
332
|
}
|
|
311
333
|
}
|
|
312
334
|
}
|
|
@@ -605,3 +627,13 @@ impl Document {
|
|
|
605
627
|
Ok(())
|
|
606
628
|
}
|
|
607
629
|
}
|
|
630
|
+
|
|
631
|
+
fn strip_bracket_suffix(path: &str) -> Option<&str> {
|
|
632
|
+
if path == "[]" {
|
|
633
|
+
Some("")
|
|
634
|
+
} else if let Some(stripped) = path.strip_suffix(".[]") {
|
|
635
|
+
Some(stripped)
|
|
636
|
+
} else {
|
|
637
|
+
path.strip_suffix("[]")
|
|
638
|
+
}
|
|
639
|
+
}
|
data/rust/src/ffi.rs
CHANGED
|
@@ -477,6 +477,23 @@ pub unsafe extern "C" fn yerba_document_delete(document: *mut Document, path: *c
|
|
|
477
477
|
}
|
|
478
478
|
}
|
|
479
479
|
|
|
480
|
+
#[no_mangle]
|
|
481
|
+
pub unsafe extern "C" fn yerba_document_insert_objects(document: *mut Document, path: *const c_char, json: *const c_char) -> YerbaResult {
|
|
482
|
+
let document = &mut *document;
|
|
483
|
+
let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
484
|
+
let json_string = CStr::from_ptr(json).to_str().unwrap_or("");
|
|
485
|
+
|
|
486
|
+
let json_values: Vec<serde_json::Value> = match serde_json::from_str(json_string) {
|
|
487
|
+
Ok(values) => values,
|
|
488
|
+
Err(e) => return YerbaResult::err(&format!("Invalid JSON: {}", e)),
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
match document.insert_objects(selector_string, &json_values) {
|
|
492
|
+
Ok(()) => YerbaResult::ok(),
|
|
493
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
480
497
|
#[no_mangle]
|
|
481
498
|
pub unsafe extern "C" fn yerba_document_remove(document: *mut Document, path: *const c_char, value: *const c_char) -> YerbaResult {
|
|
482
499
|
let document = &mut *document;
|
|
@@ -609,6 +626,55 @@ pub unsafe extern "C" fn yerba_document_blank_lines(document: *mut Document, pat
|
|
|
609
626
|
}
|
|
610
627
|
}
|
|
611
628
|
|
|
629
|
+
/// Caller must free with yerba_string_free.
|
|
630
|
+
#[no_mangle]
|
|
631
|
+
pub unsafe extern "C" fn yerba_yerbafile_find(directory: *const c_char) -> *mut c_char {
|
|
632
|
+
let start = if directory.is_null() {
|
|
633
|
+
std::env::current_dir().ok()
|
|
634
|
+
} else {
|
|
635
|
+
CStr::from_ptr(directory).to_str().ok().map(std::path::PathBuf::from)
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
let path = match start {
|
|
639
|
+
Some(dir) => crate::Yerbafile::find_from(dir),
|
|
640
|
+
None => None,
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
match path {
|
|
644
|
+
Some(path) => CString::new(path.to_string_lossy().to_string()).unwrap_or_default().into_raw(),
|
|
645
|
+
None => ptr::null_mut(),
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
#[no_mangle]
|
|
650
|
+
pub unsafe extern "C" fn yerba_document_apply_yerbafile(document: *mut Document, file_path: *const c_char, yerbafile_path: *const c_char) -> YerbaResult {
|
|
651
|
+
let document = &mut *document;
|
|
652
|
+
let file_path_string = CStr::from_ptr(file_path).to_str().unwrap_or("");
|
|
653
|
+
|
|
654
|
+
let yerbafile = if yerbafile_path.is_null() {
|
|
655
|
+
match crate::Yerbafile::find() {
|
|
656
|
+
Some(path) => match crate::Yerbafile::load(&path) {
|
|
657
|
+
Ok(yerbafile) => yerbafile,
|
|
658
|
+
Err(e) => return YerbaResult::err(&e.to_string()),
|
|
659
|
+
},
|
|
660
|
+
|
|
661
|
+
None => return YerbaResult::err("No Yerbafile found"),
|
|
662
|
+
}
|
|
663
|
+
} else {
|
|
664
|
+
let path = CStr::from_ptr(yerbafile_path).to_str().unwrap_or("");
|
|
665
|
+
|
|
666
|
+
match crate::Yerbafile::load(path) {
|
|
667
|
+
Ok(yerbafile) => yerbafile,
|
|
668
|
+
Err(e) => return YerbaResult::err(&e.to_string()),
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
match yerbafile.apply_to_document(document, file_path_string) {
|
|
673
|
+
Ok(_) => YerbaResult::ok(),
|
|
674
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
612
678
|
#[no_mangle]
|
|
613
679
|
pub unsafe extern "C" fn yerba_document_to_string(document: *const Document) -> *mut c_char {
|
|
614
680
|
let document = &*document;
|
data/rust/src/main.rs
CHANGED
|
@@ -31,7 +31,9 @@ static HELP: LazyLock<String> = LazyLock::new(|| {
|
|
|
31
31
|
Yerbafile:
|
|
32
32
|
yerba init Create a new Yerbafile in the current directory
|
|
33
33
|
yerba check Check if all files match the rules (exits 1 if not)
|
|
34
|
+
yerba check <file> Check a specific file against matching rules
|
|
34
35
|
yerba apply Apply all rules and write changes
|
|
36
|
+
yerba apply <file> Apply rules to a specific file
|
|
35
37
|
|
|
36
38
|
Examples:
|
|
37
39
|
yerba get config.yml "database.host"
|
data/rust/src/yerbafile.rs
CHANGED
|
@@ -195,9 +195,13 @@ impl Yerbafile {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
pub fn find() -> Option<PathBuf> {
|
|
198
|
+
Self::find_from(std::env::current_dir().ok()?)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
pub fn find_from(start: impl AsRef<Path>) -> Option<PathBuf> {
|
|
198
202
|
let candidates = ["Yerbafile", "Yerbafile.yml", "Yerbafile.yaml", ".yerbafile"];
|
|
199
203
|
|
|
200
|
-
let mut directory =
|
|
204
|
+
let mut directory = start.as_ref().to_path_buf();
|
|
201
205
|
|
|
202
206
|
loop {
|
|
203
207
|
for candidate in &candidates {
|
|
@@ -356,6 +360,48 @@ impl Yerbafile {
|
|
|
356
360
|
error: None,
|
|
357
361
|
}
|
|
358
362
|
}
|
|
363
|
+
|
|
364
|
+
pub fn apply_file(&self, file: &str, write: bool) -> Vec<RuleResult> {
|
|
365
|
+
let mut results = Vec::new();
|
|
366
|
+
|
|
367
|
+
for rule in &self.rules {
|
|
368
|
+
if let Ok(pattern) = glob::Pattern::new(&rule.files) {
|
|
369
|
+
if !pattern.matches(file) && !pattern.matches_path(Path::new(file)) {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
} else {
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
results.push(self.apply_pipeline_to_file(rule, file, write));
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
results
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
pub fn apply_to_document(&self, document: &mut Document, file_path: &str) -> Result<bool, YerbaError> {
|
|
383
|
+
let original = document.to_string();
|
|
384
|
+
|
|
385
|
+
for rule in &self.rules {
|
|
386
|
+
if !file_path.is_empty() {
|
|
387
|
+
if let Ok(pattern) = glob::Pattern::new(&rule.files) {
|
|
388
|
+
if !pattern.matches(file_path) && !pattern.matches_path(Path::new(file_path)) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
} else {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
let base_path = rule.path.as_deref();
|
|
397
|
+
|
|
398
|
+
for step in &rule.pipeline {
|
|
399
|
+
execute_step(document, step, base_path)?;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
Ok(document.to_string() != original)
|
|
404
|
+
}
|
|
359
405
|
}
|
|
360
406
|
|
|
361
407
|
fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<&str>) -> Result<(), YerbaError> {
|
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.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: x86_64-linux-gnu
|
|
6
6
|
authors:
|
|
7
7
|
- Marco Roth
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-05 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.
|
|
@@ -36,9 +36,11 @@ files:
|
|
|
36
36
|
- lib/yerba/formatting.rb
|
|
37
37
|
- lib/yerba/location.rb
|
|
38
38
|
- lib/yerba/map.rb
|
|
39
|
+
- lib/yerba/query_result.rb
|
|
39
40
|
- lib/yerba/scalar.rb
|
|
40
41
|
- lib/yerba/sequence.rb
|
|
41
42
|
- lib/yerba/version.rb
|
|
43
|
+
- lib/yerba/yerbafile.rb
|
|
42
44
|
- rust/Cargo.lock
|
|
43
45
|
- rust/Cargo.toml
|
|
44
46
|
- rust/build.rs
|