Repository: toml-rs/toml
Pull request #529 (2023-03-15 02:41:48)

fix(edit): Avoid newlines from dotted keys in std tables


Patch:
diff --git a/crates/toml_edit/src/encode.rs b/crates/toml_edit/src/encode.rs
index ea24c2db..9940f282 100644
--- a/crates/toml_edit/src/encode.rs
+++ b/crates/toml_edit/src/encode.rs
@@ -48,6 +48,37 @@ impl Encode for Key {
     }
 }
 
+impl<'k> Encode for &'k [Key] {
+    fn encode(
+        &self,
+        buf: &mut dyn Write,
+        input: Option<&str>,
+        default_decor: (&str, &str),
+    ) -> Result {
+        for (i, key) in self.iter().enumerate() {
+            let first = i == 0;
+            let last = i + 1 == self.len();
+
+            let prefix = if first {
+                default_decor.0
+            } else {
+                DEFAULT_KEY_PATH_DECOR.0
+            };
+            let suffix = if last {
+                default_decor.1
+            } else {
+                DEFAULT_KEY_PATH_DECOR.1
+            };
+
+            if !first {
+                write!(buf, ".")?;
+            }
+            key.encode(buf, input, (prefix, suffix))?;
+        }
+        Ok(())
+    }
+}
+
 impl<'k> Encode for &'k [&'k Key] {
     fn encode(
         &self,
@@ -230,12 +261,12 @@ impl Display for Document {
 
 fn visit_nested_tables<'t, F>(
     table: &'t Table,
-    path: &mut Vec<&'t Key>,
+    path: &mut Vec<Key>,
     is_array_of_tables: bool,
     callback: &mut F,
 ) -> Result
 where
-    F: FnMut(&'t Table, &Vec<&'t Key>, bool) -> Result,
+    F: FnMut(&'t Table, &Vec<Key>, bool) -> Result,
 {
     if !table.is_dotted() {
         callback(table, path, is_array_of_tables)?;
@@ -244,13 +275,19 @@ where
     for kv in table.items.values() {
         match kv.value {
             Item::Table(ref t) => {
-                path.push(&kv.key);
+                let mut key = kv.key.clone();
+                if t.is_dotted() {
+                    // May have newlines and generally isn't written for standard tables
+                    key.decor_mut().clear();
+                }
+                path.push(key);
                 visit_nested_tables(t, path, false, callback)?;
                 path.pop();
             }
             Item::ArrayOfTables(ref a) => {
                 for t in a.iter() {
-                    path.push(&kv.key);
+                    let key = kv.key.clone();
+                    path.push(key);
                     visit_nested_tables(t, path, true, callback)?;
                     path.pop();
                 }
@@ -265,7 +302,7 @@ fn visit_table(
     buf: &mut dyn Write,
     input: Option<&str>,
     table: &Table,
-    path: &[&Key],
+    path: &[Key],
     is_array_of_tables: bool,
     first_table: &mut bool,
 ) -> Result {


Test patch:
diff --git a/crates/toml_edit/tests/testsuite/parse.rs b/crates/toml_edit/tests/testsuite/parse.rs
index 4155e97e..9f59f69d 100644
--- a/crates/toml_edit/tests/testsuite/parse.rs
+++ b/crates/toml_edit/tests/testsuite/parse.rs
@@ -1459,3 +1459,19 @@ expected newline, `#`
 "#
     );
 }
+
+#[test]
+fn dont_use_dotted_key_prefix_on_table_fuzz_57049() {
+    // This could generate
+    // ```toml
+    // [
+    // p.o]
+    // ```
+    let input = r#"
+p.a=4
+[p.o]
+"#;
+    let document = input.parse::<Document>().unwrap();
+    let actual = document.to_string();
+    assert_eq(input, actual);
+}