Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions foundations/src/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,8 @@ pub fn to_yaml_string(settings: &impl Settings) -> BootstrapResult<String> {
let mut doc_comments = Default::default();
let mut yaml_with_docs = String::new();
let mut key_stack = vec![];
let mut list_index = 0;
// Indentation and next item index of each list enclosing the current line.
let mut list_indices: Vec<(usize, usize)> = vec![];

settings.add_docs(&[], &mut doc_comments);

Expand All @@ -463,13 +464,27 @@ pub fn to_yaml_string(settings: &impl Settings) -> BootstrapResult<String> {

// NOTE: if we have a list item, then append the index of the item to the key stack.
if is_list_item {
// Lists nested in the previous item end here.
list_indices.retain(|&(indent, _)| indent <= spaces);

let list_index = match list_indices.last_mut() {
Some((indent, next_index)) if *indent == spaces => {
*next_index += 1;
*next_index - 1
}
_ => {
list_indices.push((spaces, 1));
0
}
};

key_stack.push(list_index.to_string());

field_name = field_name[LIST_ITEM_PREFIX.len()..].trim().to_string();
spaces += LIST_ITEM_PREFIX.len();
list_index += 1;
} else {
list_index = 0;
// A key at or left of a list's dash ends that list.
list_indices.retain(|&(indent, _)| indent < spaces);
}

key_stack.push(field_name);
Expand Down
16 changes: 16 additions & 0 deletions foundations/tests/data/serde-saphyr/with_vec_of_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Items
items:
# Name of the item
- name: foo
# Optional field
optional: null
# Name of the item
- name: bar
# Optional field
optional:
# A field, which is named the same as another field.
a: 1
# multi-line
# doc comment
b: 2
c: 3
17 changes: 17 additions & 0 deletions foundations/tests/data/serde-yaml/with_vec_of_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
# Items
items:
# Name of the item
- name: foo
# Optional field
optional: ~
# Name of the item
- name: bar
# Optional field
optional:
# A field, which is named the same as another field.
a: 1
# multi-line
# doc comment
b: 2
c: 3
32 changes: 32 additions & 0 deletions foundations/tests/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,20 @@ struct WithVec {
items: Vec<NestedStruct>,
}

#[settings]
struct NamedOption {
/// Name of the item
name: String,
/// Optional field
optional: Option<NestedStruct>,
}

#[settings]
struct WithVecOfOptions {
/// Items
items: Vec<NamedOption>,
}

mod foundations_reexport {
pub(crate) mod nested {
pub(crate) use foundations::*;
Expand Down Expand Up @@ -293,6 +307,24 @@ fn vec() {
assert_ser_eq!(s, "with_vec.yaml");
}

#[test]
fn vec_items_with_different_fields() {
let s = WithVecOfOptions {
items: vec![
NamedOption {
name: "foo".into(),
optional: None,
},
NamedOption {
name: "bar".into(),
optional: Some(NestedStruct { a: 1, b: 2, c: 3 }),
},
],
};

assert_ser_eq!(s, "with_vec_of_options.yaml");
}

#[test]
fn parse() {
const INVALID_YAML_WITH_SECRET: &str = r#"
Expand Down