yerba 0.3.0 → 0.4.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 +90 -8
- data/ext/yerba/extconf.rb +22 -3
- data/ext/yerba/include/yerba.h +19 -9
- data/ext/yerba/yerba.c +83 -24
- 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/rust/Cargo.lock +1 -0
- data/rust/Cargo.toml +1 -1
- 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/directives.rs +61 -0
- data/rust/src/commands/get.rs +5 -22
- data/rust/src/commands/mod.rs +5 -10
- data/rust/src/commands/quote_style.rs +12 -6
- data/rust/src/commands/selectors.rs +3 -19
- data/rust/src/commands/sort.rs +22 -157
- data/rust/src/didyoumean.rs +2 -4
- 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 +24 -6
- data/rust/src/ffi.rs +208 -520
- data/rust/src/json.rs +1 -7
- data/rust/src/lib.rs +88 -2
- 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 +10 -2
- data/rust/Cargo.lock +0 -805
- data/rust/src/document.rs +0 -2304
data/rust/src/json.rs
CHANGED
|
@@ -117,12 +117,6 @@ pub fn select_field_key(field: &str) -> String {
|
|
|
117
117
|
parsed
|
|
118
118
|
.segments()
|
|
119
119
|
.iter()
|
|
120
|
-
.find_map(|segment| {
|
|
121
|
-
if let SelectorSegment::Key(key) = segment {
|
|
122
|
-
Some(key.clone())
|
|
123
|
-
} else {
|
|
124
|
-
None
|
|
125
|
-
}
|
|
126
|
-
})
|
|
120
|
+
.find_map(|segment| if let SelectorSegment::Key(key) = segment { Some(key.clone()) } else { None })
|
|
127
121
|
.unwrap_or_else(|| field.to_string())
|
|
128
122
|
}
|
data/rust/src/lib.rs
CHANGED
|
@@ -9,9 +9,9 @@ mod syntax;
|
|
|
9
9
|
mod yaml_writer;
|
|
10
10
|
pub mod yerbafile;
|
|
11
11
|
|
|
12
|
-
pub use document::{collect_selectors, Document, InsertPosition, SortField};
|
|
12
|
+
pub use document::{collect_selectors, Document, InsertPosition, Location, NodeInfo, NodeType, SortField};
|
|
13
13
|
pub use error::YerbaError;
|
|
14
|
-
pub use quote_style::QuoteStyle;
|
|
14
|
+
pub use quote_style::{KeyStyle, QuoteStyle};
|
|
15
15
|
pub use selector::Selector;
|
|
16
16
|
pub use syntax::{detect_yaml_type, ScalarValue, YerbaValueType};
|
|
17
17
|
pub use yaml_writer::json_to_yaml_text;
|
|
@@ -28,3 +28,89 @@ pub fn parse(source: &str) -> Result<Document, YerbaError> {
|
|
|
28
28
|
pub fn parse_file(path: impl AsRef<std::path::Path>) -> Result<Document, YerbaError> {
|
|
29
29
|
Document::parse_file(path)
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
pub fn glob_get(pattern: &str, selector: &str) -> Vec<ScalarValue> {
|
|
33
|
+
use rayon::prelude::*;
|
|
34
|
+
|
|
35
|
+
let parsed_selector = Selector::parse(selector);
|
|
36
|
+
|
|
37
|
+
let files = match glob::glob(pattern) {
|
|
38
|
+
Ok(paths) => paths.filter_map(|p| p.ok()).collect::<Vec<_>>(),
|
|
39
|
+
Err(_) => return vec![],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
files
|
|
43
|
+
.par_iter()
|
|
44
|
+
.flat_map(|file| {
|
|
45
|
+
let mut results = Vec::new();
|
|
46
|
+
|
|
47
|
+
if let Ok(document) = Document::parse_file(file) {
|
|
48
|
+
if parsed_selector.has_wildcard() {
|
|
49
|
+
results.extend(document.get_all_typed(selector));
|
|
50
|
+
} else if let Some(scalar) = document.get_typed(selector) {
|
|
51
|
+
results.push(scalar);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
results
|
|
56
|
+
})
|
|
57
|
+
.collect()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
pub fn glob_find(pattern: &str, selector: &str, condition: Option<&str>, select: Option<&str>) -> Vec<serde_json::Value> {
|
|
61
|
+
use rayon::prelude::*;
|
|
62
|
+
|
|
63
|
+
let files = match glob::glob(pattern) {
|
|
64
|
+
Ok(paths) => paths.filter_map(|p| p.ok()).collect::<Vec<_>>(),
|
|
65
|
+
Err(_) => return vec![],
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
let select_fields: Option<Vec<&str>> = select.map(|s| s.split(',').collect());
|
|
69
|
+
|
|
70
|
+
files
|
|
71
|
+
.par_iter()
|
|
72
|
+
.flat_map(|file| {
|
|
73
|
+
let mut file_results = Vec::new();
|
|
74
|
+
|
|
75
|
+
if let Ok(document) = Document::parse_file(file) {
|
|
76
|
+
let values = match condition {
|
|
77
|
+
Some(cond) => document.filter(selector, cond),
|
|
78
|
+
None => document.get_values(selector),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
let file_string = file.to_string_lossy().to_string();
|
|
82
|
+
|
|
83
|
+
for value in &values {
|
|
84
|
+
let mut result = serde_json::Map::new();
|
|
85
|
+
result.insert("__file".to_string(), serde_json::Value::String(file_string.clone()));
|
|
86
|
+
|
|
87
|
+
match &select_fields {
|
|
88
|
+
Some(fields) => {
|
|
89
|
+
for field in fields {
|
|
90
|
+
let json_value = json::resolve_select_field(value, field);
|
|
91
|
+
let json_key = json::select_field_key(field);
|
|
92
|
+
result.insert(json_key, json_value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
None => {
|
|
96
|
+
if let serde_yaml::Value::Mapping(map) = value {
|
|
97
|
+
for (key, yaml_value) in map {
|
|
98
|
+
let json_key = match key {
|
|
99
|
+
serde_yaml::Value::String(string) => string.clone(),
|
|
100
|
+
_ => format!("{:?}", key),
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
result.insert(json_key, json::yaml_to_json(yaml_value));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
file_results.push(serde_json::Value::Object(result));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
file_results
|
|
114
|
+
})
|
|
115
|
+
.collect()
|
|
116
|
+
}
|
data/rust/src/quote_style.rs
CHANGED
|
@@ -1,29 +1,85 @@
|
|
|
1
1
|
use clap::ValueEnum;
|
|
2
2
|
use yaml_parser::SyntaxKind;
|
|
3
3
|
|
|
4
|
+
#[derive(Debug, Clone, PartialEq, ValueEnum)]
|
|
5
|
+
pub enum KeyStyle {
|
|
6
|
+
/// Unquoted key (host:)
|
|
7
|
+
Plain,
|
|
8
|
+
/// Single-quoted key ('host':)
|
|
9
|
+
Single,
|
|
10
|
+
/// Double-quoted key ("host":)
|
|
11
|
+
Double,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
impl std::str::FromStr for KeyStyle {
|
|
15
|
+
type Err = String;
|
|
16
|
+
|
|
17
|
+
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
|
18
|
+
match string {
|
|
19
|
+
"plain" => Ok(KeyStyle::Plain),
|
|
20
|
+
"single" | "single-quoted" => Ok(KeyStyle::Single),
|
|
21
|
+
"double" | "double-quoted" => Ok(KeyStyle::Double),
|
|
22
|
+
_ => Err(format!("unknown key style: '{}'. Valid options: plain, single, double", string)),
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
impl KeyStyle {
|
|
28
|
+
pub(crate) fn to_syntax_kind(&self) -> SyntaxKind {
|
|
29
|
+
match self {
|
|
30
|
+
KeyStyle::Plain => SyntaxKind::PLAIN_SCALAR,
|
|
31
|
+
KeyStyle::Single => SyntaxKind::SINGLE_QUOTED_SCALAR,
|
|
32
|
+
KeyStyle::Double => SyntaxKind::DOUBLE_QUOTED_SCALAR,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
4
37
|
#[derive(Debug, Clone, PartialEq, ValueEnum)]
|
|
5
38
|
pub enum QuoteStyle {
|
|
39
|
+
/// Unquoted value (host: localhost)
|
|
6
40
|
Plain,
|
|
41
|
+
/// Single-quoted value (host: 'localhost')
|
|
7
42
|
#[value(alias = "single-quoted")]
|
|
8
43
|
Single,
|
|
44
|
+
/// Double-quoted value (host: "localhost")
|
|
9
45
|
#[value(alias = "double-quoted")]
|
|
10
46
|
Double,
|
|
11
|
-
|
|
47
|
+
/// Literal block scalar, strip trailing newline (|-)
|
|
48
|
+
#[value(alias = "block-literal", alias = "|-")]
|
|
12
49
|
Literal,
|
|
13
|
-
|
|
50
|
+
/// Literal block scalar, keep one trailing newline (|)
|
|
51
|
+
#[value(alias = "|")]
|
|
52
|
+
LiteralClip,
|
|
53
|
+
/// Literal block scalar, keep all trailing newlines (|+)
|
|
54
|
+
#[value(alias = "|+")]
|
|
55
|
+
LiteralKeep,
|
|
56
|
+
/// Folded block scalar, strip trailing newline (>-)
|
|
57
|
+
#[value(alias = "block-folded", alias = ">-")]
|
|
14
58
|
Folded,
|
|
59
|
+
/// Folded block scalar, keep one trailing newline (>)
|
|
60
|
+
#[value(alias = ">")]
|
|
61
|
+
FoldedClip,
|
|
62
|
+
/// Folded block scalar, keep all trailing newlines (>+)
|
|
63
|
+
#[value(alias = ">+")]
|
|
64
|
+
FoldedKeep,
|
|
15
65
|
}
|
|
16
66
|
|
|
17
67
|
impl std::str::FromStr for QuoteStyle {
|
|
18
68
|
type Err = String;
|
|
19
69
|
|
|
20
70
|
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
|
21
|
-
|
|
71
|
+
let normalized = string.replace('_', "-");
|
|
72
|
+
|
|
73
|
+
match normalized.as_str() {
|
|
22
74
|
"plain" => Ok(QuoteStyle::Plain),
|
|
23
75
|
"single" | "single-quoted" => Ok(QuoteStyle::Single),
|
|
24
76
|
"double" | "double-quoted" => Ok(QuoteStyle::Double),
|
|
25
|
-
"literal" | "block-literal" => Ok(QuoteStyle::Literal),
|
|
26
|
-
"
|
|
77
|
+
"literal" | "block-literal" | "|-" => Ok(QuoteStyle::Literal),
|
|
78
|
+
"literal-clip" | "|" => Ok(QuoteStyle::LiteralClip),
|
|
79
|
+
"literal-keep" | "|+" => Ok(QuoteStyle::LiteralKeep),
|
|
80
|
+
"folded" | "block-folded" | ">-" => Ok(QuoteStyle::Folded),
|
|
81
|
+
"folded-clip" | ">" => Ok(QuoteStyle::FoldedClip),
|
|
82
|
+
"folded-keep" | ">+" => Ok(QuoteStyle::FoldedKeep),
|
|
27
83
|
_ => Err(format!("unknown quote style: '{}'", string)),
|
|
28
84
|
}
|
|
29
85
|
}
|
|
@@ -35,8 +91,28 @@ impl QuoteStyle {
|
|
|
35
91
|
QuoteStyle::Plain => SyntaxKind::PLAIN_SCALAR,
|
|
36
92
|
QuoteStyle::Single => SyntaxKind::SINGLE_QUOTED_SCALAR,
|
|
37
93
|
QuoteStyle::Double => SyntaxKind::DOUBLE_QUOTED_SCALAR,
|
|
38
|
-
QuoteStyle::Literal =>
|
|
39
|
-
|
|
94
|
+
QuoteStyle::Literal | QuoteStyle::LiteralClip | QuoteStyle::LiteralKeep | QuoteStyle::Folded | QuoteStyle::FoldedClip | QuoteStyle::FoldedKeep => {
|
|
95
|
+
SyntaxKind::BLOCK_SCALAR_TEXT
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
pub(crate) fn is_block_scalar(&self) -> bool {
|
|
101
|
+
matches!(
|
|
102
|
+
self,
|
|
103
|
+
QuoteStyle::Literal | QuoteStyle::LiteralClip | QuoteStyle::LiteralKeep | QuoteStyle::Folded | QuoteStyle::FoldedClip | QuoteStyle::FoldedKeep
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
pub(crate) fn block_header(&self) -> &'static str {
|
|
108
|
+
match self {
|
|
109
|
+
QuoteStyle::Literal => "|-",
|
|
110
|
+
QuoteStyle::LiteralClip => "|",
|
|
111
|
+
QuoteStyle::LiteralKeep => "|+",
|
|
112
|
+
QuoteStyle::Folded => ">-",
|
|
113
|
+
QuoteStyle::FoldedClip => ">",
|
|
114
|
+
QuoteStyle::FoldedKeep => ">+",
|
|
115
|
+
_ => "",
|
|
40
116
|
}
|
|
41
117
|
}
|
|
42
118
|
}
|
data/rust/src/selector.rs
CHANGED
|
@@ -58,10 +58,7 @@ impl Selector {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
pub fn ends_with_bracket(&self) -> bool {
|
|
61
|
-
matches!(
|
|
62
|
-
self.segments().last(),
|
|
63
|
-
Some(SelectorSegment::AllItems | SelectorSegment::Index(_))
|
|
64
|
-
)
|
|
61
|
+
matches!(self.segments().last(), Some(SelectorSegment::AllItems | SelectorSegment::Index(_)))
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
pub fn has_brackets(&self) -> bool {
|
|
@@ -109,9 +106,7 @@ impl Selector {
|
|
|
109
106
|
pub fn split_at_first_bracket(&self) -> (Selector, Selector) {
|
|
110
107
|
let segments = self.segments();
|
|
111
108
|
|
|
112
|
-
let first_bracket = segments
|
|
113
|
-
.iter()
|
|
114
|
-
.position(|s| matches!(s, SelectorSegment::AllItems | SelectorSegment::Index(_)));
|
|
109
|
+
let first_bracket = segments.iter().position(|s| matches!(s, SelectorSegment::AllItems | SelectorSegment::Index(_)));
|
|
115
110
|
|
|
116
111
|
match first_bracket {
|
|
117
112
|
Some(position) => {
|
data/rust/src/syntax.rs
CHANGED
|
@@ -47,16 +47,11 @@ pub fn extract_scalar(node: &SyntaxNode) -> Option<ScalarValue> {
|
|
|
47
47
|
_ => return None,
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
Some(ScalarValue {
|
|
51
|
-
text,
|
|
52
|
-
kind: token.kind(),
|
|
53
|
-
})
|
|
50
|
+
Some(ScalarValue { text, kind: token.kind() })
|
|
54
51
|
}
|
|
55
52
|
|
|
56
53
|
pub fn is_map_key(token: &SyntaxToken) -> bool {
|
|
57
|
-
token
|
|
58
|
-
.parent_ancestors()
|
|
59
|
-
.any(|ancestor| ancestor.kind() == SyntaxKind::BLOCK_MAP_KEY)
|
|
54
|
+
token.parent_ancestors().any(|ancestor| ancestor.kind() == SyntaxKind::BLOCK_MAP_KEY)
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
pub fn find_entry_by_key(map: &BlockMap, key: &str) -> Option<BlockMapEntry> {
|
|
@@ -70,15 +65,12 @@ pub fn find_entry_by_key(map: &BlockMap, key: &str) -> Option<BlockMapEntry> {
|
|
|
70
65
|
}
|
|
71
66
|
|
|
72
67
|
pub fn find_scalar_token(node: &SyntaxNode) -> Option<SyntaxToken> {
|
|
73
|
-
node
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
SyntaxKind::PLAIN_SCALAR | SyntaxKind::DOUBLE_QUOTED_SCALAR | SyntaxKind::SINGLE_QUOTED_SCALAR
|
|
80
|
-
)
|
|
81
|
-
})
|
|
68
|
+
node.descendants_with_tokens().filter_map(|element| element.into_token()).find(|token| {
|
|
69
|
+
matches!(
|
|
70
|
+
token.kind(),
|
|
71
|
+
SyntaxKind::PLAIN_SCALAR | SyntaxKind::DOUBLE_QUOTED_SCALAR | SyntaxKind::SINGLE_QUOTED_SCALAR
|
|
72
|
+
)
|
|
73
|
+
})
|
|
82
74
|
}
|
|
83
75
|
|
|
84
76
|
pub fn format_scalar_value(value: &str, kind: SyntaxKind) -> String {
|
|
@@ -122,7 +114,38 @@ pub fn extract_scalar_text(node: &SyntaxNode) -> Option<String> {
|
|
|
122
114
|
}
|
|
123
115
|
|
|
124
116
|
pub fn unescape_double_quoted(text: &str) -> String {
|
|
125
|
-
text.
|
|
117
|
+
let mut result = String::with_capacity(text.len());
|
|
118
|
+
let mut chars = text.chars();
|
|
119
|
+
|
|
120
|
+
while let Some(character) = chars.next() {
|
|
121
|
+
if character == '\\' {
|
|
122
|
+
match chars.next() {
|
|
123
|
+
Some('n') => result.push('\n'),
|
|
124
|
+
Some('t') => result.push('\t'),
|
|
125
|
+
Some('r') => result.push('\r'),
|
|
126
|
+
Some('\\') => result.push('\\'),
|
|
127
|
+
Some('"') => result.push('"'),
|
|
128
|
+
Some('/') => result.push('/'),
|
|
129
|
+
Some('0') => result.push('\0'),
|
|
130
|
+
Some('a') => result.push('\u{07}'),
|
|
131
|
+
Some('b') => result.push('\u{08}'),
|
|
132
|
+
Some('e') => result.push('\u{1b}'),
|
|
133
|
+
Some('v') => result.push('\u{0b}'),
|
|
134
|
+
Some(' ') => result.push(' '),
|
|
135
|
+
Some('_') => result.push('\u{a0}'),
|
|
136
|
+
Some('\n') => {} // line continuation: skip newline and leading whitespace
|
|
137
|
+
Some(other) => {
|
|
138
|
+
result.push('\\');
|
|
139
|
+
result.push(other);
|
|
140
|
+
}
|
|
141
|
+
None => result.push('\\'),
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
result.push(character);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
result
|
|
126
149
|
}
|
|
127
150
|
|
|
128
151
|
pub fn unescape_single_quoted(text: &str) -> String {
|
|
@@ -194,10 +217,7 @@ pub fn is_yaml_non_string(value: &str) -> bool {
|
|
|
194
217
|
}
|
|
195
218
|
|
|
196
219
|
pub fn is_yaml_truthy(value: &str) -> bool {
|
|
197
|
-
matches!(
|
|
198
|
-
value,
|
|
199
|
-
"true" | "True" | "TRUE" | "yes" | "Yes" | "YES" | "on" | "On" | "ON" | "y" | "Y"
|
|
200
|
-
)
|
|
220
|
+
matches!(value, "true" | "True" | "TRUE" | "yes" | "Yes" | "YES" | "on" | "On" | "ON" | "y" | "Y")
|
|
201
221
|
}
|
|
202
222
|
|
|
203
223
|
pub fn detect_yaml_type_from_plain(value: &str) -> YerbaValueType {
|
data/rust/src/yerbafile.rs
CHANGED
|
@@ -30,6 +30,7 @@ pub enum PipelineStep {
|
|
|
30
30
|
Remove(RemoveConfig),
|
|
31
31
|
BlankLines(BlankLinesConfig),
|
|
32
32
|
Sort(SortConfig),
|
|
33
|
+
Directives(DirectivesConfig),
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
#[derive(Debug, Clone, Deserialize)]
|
|
@@ -49,6 +50,14 @@ pub struct BlankLinesConfig {
|
|
|
49
50
|
pub count: usize,
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
#[derive(Debug, Clone, Deserialize)]
|
|
54
|
+
pub struct DirectivesConfig {
|
|
55
|
+
#[serde(default)]
|
|
56
|
+
pub ensure: bool,
|
|
57
|
+
#[serde(default)]
|
|
58
|
+
pub remove: bool,
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
#[derive(Debug, Clone, Deserialize)]
|
|
53
62
|
pub struct RenameConfig {
|
|
54
63
|
pub from: String,
|
|
@@ -112,13 +121,18 @@ impl<'de> Deserialize<'de> for PipelineStep {
|
|
|
112
121
|
return Ok(PipelineStep::BlankLines(config));
|
|
113
122
|
}
|
|
114
123
|
|
|
124
|
+
if let Some(value) = mapping.get(serde_yaml::Value::String("directives".to_string())) {
|
|
125
|
+
let config: DirectivesConfig = serde_yaml::from_value(value.clone()).map_err(serde::de::Error::custom)?;
|
|
126
|
+
return Ok(PipelineStep::Directives(config));
|
|
127
|
+
}
|
|
128
|
+
|
|
115
129
|
if let Some(value) = mapping.get(serde_yaml::Value::String("sort".to_string())) {
|
|
116
130
|
let config: SortConfig = serde_yaml::from_value(value.clone()).map_err(serde::de::Error::custom)?;
|
|
117
131
|
return Ok(PipelineStep::Sort(config));
|
|
118
132
|
}
|
|
119
133
|
|
|
120
134
|
Err(serde::de::Error::custom(
|
|
121
|
-
"unknown pipeline step: expected sort_keys, quote_style, set, insert, delete, rename, remove, blank_lines, or
|
|
135
|
+
"unknown pipeline step: expected sort_keys, quote_style, set, insert, delete, rename, remove, blank_lines, sort, or directives",
|
|
122
136
|
))
|
|
123
137
|
}
|
|
124
138
|
}
|
|
@@ -176,8 +190,7 @@ pub struct RuleResult {
|
|
|
176
190
|
impl Yerbafile {
|
|
177
191
|
pub fn load(path: impl AsRef<Path>) -> Result<Self, YerbaError> {
|
|
178
192
|
let content = fs::read_to_string(path.as_ref())?;
|
|
179
|
-
let yerbafile: Yerbafile =
|
|
180
|
-
serde_yaml::from_str(&content).map_err(|error| YerbaError::ParseError(format!("{}", error)))?;
|
|
193
|
+
let yerbafile: Yerbafile = serde_yaml::from_str(&content).map_err(|error| YerbaError::ParseError(format!("{}", error)))?;
|
|
181
194
|
Ok(yerbafile)
|
|
182
195
|
}
|
|
183
196
|
|
|
@@ -291,10 +304,7 @@ impl Yerbafile {
|
|
|
291
304
|
continue;
|
|
292
305
|
}
|
|
293
306
|
|
|
294
|
-
let file_results: Vec<RuleResult> = file_strings
|
|
295
|
-
.par_iter()
|
|
296
|
-
.map(|file| self.apply_pipeline_to_file(rule, file, write))
|
|
297
|
-
.collect();
|
|
307
|
+
let file_results: Vec<RuleResult> = file_strings.par_iter().map(|file| self.apply_pipeline_to_file(rule, file, write)).collect();
|
|
298
308
|
|
|
299
309
|
results.extend(file_results);
|
|
300
310
|
}
|
|
@@ -353,15 +363,16 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
353
363
|
PipelineStep::QuoteStyle(config) => {
|
|
354
364
|
let dot_path = config.path.as_deref();
|
|
355
365
|
|
|
356
|
-
let key_style = config.key_style.parse::<
|
|
366
|
+
let key_style = config.key_style.parse::<crate::KeyStyle>().map_err(YerbaError::ParseError)?;
|
|
357
367
|
|
|
358
|
-
let value_style = config
|
|
359
|
-
.value_style
|
|
360
|
-
.parse::<QuoteStyle>()
|
|
361
|
-
.map_err(YerbaError::ParseError)?;
|
|
368
|
+
let value_style = config.value_style.parse::<QuoteStyle>().map_err(YerbaError::ParseError)?;
|
|
362
369
|
|
|
363
370
|
document.enforce_key_style(&key_style, dot_path)?;
|
|
364
|
-
document.enforce_quotes_at(&value_style, dot_path)?;
|
|
371
|
+
let warnings = document.enforce_quotes_at(&value_style, dot_path)?;
|
|
372
|
+
|
|
373
|
+
for warning in &warnings {
|
|
374
|
+
eprintln!(" warning: {}", warning);
|
|
375
|
+
}
|
|
365
376
|
|
|
366
377
|
Ok(())
|
|
367
378
|
}
|
|
@@ -451,14 +462,24 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
|
|
|
451
462
|
|
|
452
463
|
PipelineStep::Sort(config) => {
|
|
453
464
|
let full_path = resolve_step_path(base_path, config.path.as_deref());
|
|
454
|
-
let sort_fields = config
|
|
455
|
-
.by
|
|
456
|
-
.as_deref()
|
|
457
|
-
.map(crate::SortField::parse_list)
|
|
458
|
-
.unwrap_or_default();
|
|
465
|
+
let sort_fields = config.by.as_deref().map(crate::SortField::parse_list).unwrap_or_default();
|
|
459
466
|
|
|
460
467
|
document.sort_items(&full_path, &sort_fields, config.case_sensitive)
|
|
461
468
|
}
|
|
469
|
+
|
|
470
|
+
PipelineStep::Directives(config) => {
|
|
471
|
+
if config.ensure && config.remove {
|
|
472
|
+
return Err(YerbaError::ParseError("directives: ensure and remove are mutually exclusive".to_string()));
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if config.ensure {
|
|
476
|
+
document.ensure_directives()
|
|
477
|
+
} else if config.remove {
|
|
478
|
+
document.remove_directives()
|
|
479
|
+
} else {
|
|
480
|
+
Ok(())
|
|
481
|
+
}
|
|
482
|
+
}
|
|
462
483
|
}
|
|
463
484
|
}
|
|
464
485
|
|
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.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marco Roth
|
|
@@ -43,6 +43,7 @@ files:
|
|
|
43
43
|
- rust/src/commands/blank_lines.rs
|
|
44
44
|
- rust/src/commands/check.rs
|
|
45
45
|
- rust/src/commands/delete.rs
|
|
46
|
+
- rust/src/commands/directives.rs
|
|
46
47
|
- rust/src/commands/get.rs
|
|
47
48
|
- rust/src/commands/init.rs
|
|
48
49
|
- rust/src/commands/insert.rs
|
|
@@ -59,7 +60,14 @@ files:
|
|
|
59
60
|
- rust/src/commands/sort_keys.rs
|
|
60
61
|
- rust/src/commands/version.rs
|
|
61
62
|
- rust/src/didyoumean.rs
|
|
62
|
-
- rust/src/document.rs
|
|
63
|
+
- rust/src/document/condition.rs
|
|
64
|
+
- rust/src/document/delete.rs
|
|
65
|
+
- rust/src/document/get.rs
|
|
66
|
+
- rust/src/document/insert.rs
|
|
67
|
+
- rust/src/document/mod.rs
|
|
68
|
+
- rust/src/document/set.rs
|
|
69
|
+
- rust/src/document/sort.rs
|
|
70
|
+
- rust/src/document/style.rs
|
|
63
71
|
- rust/src/error.rs
|
|
64
72
|
- rust/src/ffi.rs
|
|
65
73
|
- rust/src/json.rs
|