Repository: toml-rs/toml
Pull request #892 (2025-05-06 21:31:05)

fix(parse): Correctly handle whitespace between 'key .'


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 8aeb1b57..824eb377 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1194,9 +1194,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 
 [[package]]
 name = "winnow"
-version = "0.7.6"
+version = "0.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
+checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
 dependencies = [
  "memchr",
 ]
diff --git a/crates/toml_edit/Cargo.toml b/crates/toml_edit/Cargo.toml
index 3afd4b6c..f53c5751 100644
--- a/crates/toml_edit/Cargo.toml
+++ b/crates/toml_edit/Cargo.toml
@@ -41,7 +41,7 @@ unbounded = []
 
 [dependencies]
 indexmap = { version = "2.3.0", features = ["std"] }
-winnow = { version = "0.7.6", optional = true }
+winnow = { version = "0.7.10", optional = true }
 serde = { version = "1.0.145", optional = true }
 kstring = { version = "2.0.0", features = ["max_inline"], optional = true }
 toml_datetime = { version = "0.6.9", path = "../toml_datetime" }
diff --git a/crates/toml_parse/Cargo.toml b/crates/toml_parse/Cargo.toml
index a605e66e..63ffa73f 100644
--- a/crates/toml_parse/Cargo.toml
+++ b/crates/toml_parse/Cargo.toml
@@ -36,7 +36,7 @@ unstable-debug = ["std", "dep:anstream", "dep:anstyle"]
 [dependencies]
 anstream = { version = "0.6.15", optional = true }
 anstyle = { version = "1.0.8", optional = true }
-winnow = { version = "0.7.6", default-features = false }
+winnow = { version = "0.7.10", default-features = false }
 
 [dev-dependencies]
 anstream = { version = "0.6.15", features = ["test"] }
diff --git a/crates/toml_parse/src/parser/document.rs b/crates/toml_parse/src/parser/document.rs
index 74dd796b..b489b02f 100644
--- a/crates/toml_parse/src/parser/document.rs
+++ b/crates/toml_parse/src/parser/document.rs
@@ -163,7 +163,7 @@ fn document(tokens: &mut Stream<'_>, receiver: &mut dyn EventReceiver, error: &m
             | TokenKind::LeftCurlyBracket => {
                 on_missing_expression_key(tokens, current_token, receiver, error);
             }
-            TokenKind::Whitespace => receiver.newline(current_token.span(), error),
+            TokenKind::Whitespace => receiver.whitespace(current_token.span(), error),
             TokenKind::Newline => receiver.newline(current_token.span(), error),
             TokenKind::Comment => on_comment(tokens, current_token, receiver, error),
             TokenKind::Eof => {
@@ -528,6 +528,7 @@ fn on_key(
                 TokenKind::Atom => None,
             };
             receiver.simple_key(current_token.span(), kind, error);
+            opt_whitespace(tokens, receiver, error);
         } else {
             error.report_error(ParseError {
                 context,
diff --git a/crates/toml_parse/src/parser/event.rs b/crates/toml_parse/src/parser/event.rs
index 8696aca2..aa563d32 100644
--- a/crates/toml_parse/src/parser/event.rs
+++ b/crates/toml_parse/src/parser/event.rs
@@ -283,30 +283,7 @@ impl EventReceiver for Vec<Event> {
     }
 }
 
-impl EventReceiver for () {
-    fn std_table_open(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn std_table_close(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn array_table_open(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn array_table_close(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn inline_table_open(&mut self, _span: Span, _error: &mut dyn ErrorSink) -> bool {
-        true
-    }
-    fn inline_table_close(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn array_open(&mut self, _span: Span, _error: &mut dyn ErrorSink) -> bool {
-        true
-    }
-    fn array_close(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn simple_key(&mut self, _span: Span, _encoding: Option<Encoding>, _error: &mut dyn ErrorSink) {
-    }
-    fn key_sep(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn key_val_sep(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn scalar(&mut self, _span: Span, _encoding: Option<Encoding>, _error: &mut dyn ErrorSink) {}
-    fn value_sep(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn whitespace(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn comment(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn newline(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-    fn error(&mut self, _span: Span, _error: &mut dyn ErrorSink) {}
-}
+impl EventReceiver for () {}
 
 pub struct RecursionGuard<'r> {
     receiver: &'r mut dyn EventReceiver,


Test patch:
diff --git a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_complex.txt b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_complex.txt
index db65c0bf..6a9c99b7 100644
--- a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_complex.txt
+++ b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_complex.txt
@@ -59,7 +59,7 @@ EventResults {
             span: 52..53,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 53..57,
         },
@@ -84,7 +84,7 @@ EventResults {
             span: 64..65,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 65..69,
         },
@@ -121,7 +121,7 @@ EventResults {
             span: 96..97,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 97..101,
         },
@@ -171,7 +171,7 @@ EventResults {
             span: 153..154,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 154..158,
         },
@@ -196,7 +196,7 @@ EventResults {
             span: 168..169,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 169..173,
         },
@@ -233,7 +233,7 @@ EventResults {
             span: 195..196,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 196..200,
         },
@@ -318,7 +318,7 @@ EventResults {
             span: 228..229,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 229..233,
         },
@@ -353,7 +353,7 @@ EventResults {
             span: 254..255,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 255..259,
         },
@@ -393,7 +393,7 @@ EventResults {
             span: 274..275,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 275..279,
         },
@@ -423,7 +423,7 @@ EventResults {
             span: 289..290,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 290..294,
         },
@@ -468,7 +468,7 @@ EventResults {
             span: 372..373,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 373..377,
         },
@@ -505,7 +505,7 @@ EventResults {
             span: 392..393,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 393..397,
         },
@@ -547,7 +547,7 @@ EventResults {
             span: 411..412,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 412..416,
         },
@@ -582,7 +582,7 @@ EventResults {
             span: 430..431,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 431..435,
         },
@@ -619,7 +619,7 @@ EventResults {
             span: 450..451,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 451..455,
         },
@@ -661,7 +661,7 @@ EventResults {
             span: 469..470,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 470..474,
         },
@@ -686,7 +686,7 @@ EventResults {
             span: 483..484,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 484..488,
         },
@@ -815,7 +815,7 @@ EventResults {
             span: 526..527,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 527..531,
         },
@@ -914,7 +914,7 @@ EventResults {
             span: 608..609,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 609..612,
         },
@@ -963,7 +963,7 @@ EventResults {
             span: 766..767,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 767..770,
         },
@@ -1002,7 +1002,7 @@ EventResults {
             span: 799..800,
         },
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 800..803,
         },
diff --git a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid.txt b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid.txt
index a8f6a0c4..9e8dbdf8 100644
--- a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid.txt
+++ b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid.txt
@@ -2,7 +2,7 @@ EventResults {
     input: " hello = 'darkness' # my old friend\n$",
     events: [
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 0..1,
         },
diff --git a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid_comment.txt b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid_comment.txt
index 1ceda21e..e2e8dadf 100644
--- a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid_comment.txt
+++ b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid_comment.txt
@@ -2,7 +2,7 @@ EventResults {
     input: " hello = 'darkness' # my old\0 friend\n",
     events: [
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 0..1,
         },
diff --git a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid_cr.txt b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid_cr.txt
index 2eded66a..73ef66a4 100644
--- a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid_cr.txt
+++ b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_invalid_cr.txt
@@ -2,7 +2,7 @@ EventResults {
     input: " hello = 'darkness' # my old friend\r",
     events: [
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 0..1,
         },
diff --git a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_key_string_comment.txt b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_key_string_comment.txt
index 1ba12083..77fb5714 100644
--- a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_key_string_comment.txt
+++ b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_key_string_comment.txt
@@ -2,7 +2,7 @@ EventResults {
     input: " hello = 'darkness' # my old friend\n",
     events: [
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 0..1,
         },
diff --git a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_key_ws.txt b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_key_ws.txt
new file mode 100644
index 00000000..0416dd9f
--- /dev/null
+++ b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_key_ws.txt
@@ -0,0 +1,83 @@
+EventResults {
+    input: " hello . darkness . my = 'old friend'\n",
+    events: [
+        Event {
+            kind: Whitespace,
+            encoding: None,
+            span: 0..1,
+        },
+        Event {
+            kind: SimpleKey,
+            encoding: None,
+            span: 1..6,
+        },
+        Event {
+            kind: Whitespace,
+            encoding: None,
+            span: 6..7,
+        },
+        Event {
+            kind: KeySep,
+            encoding: None,
+            span: 7..8,
+        },
+        Event {
+            kind: Whitespace,
+            encoding: None,
+            span: 8..9,
+        },
+        Event {
+            kind: SimpleKey,
+            encoding: None,
+            span: 9..17,
+        },
+        Event {
+            kind: Whitespace,
+            encoding: None,
+            span: 17..18,
+        },
+        Event {
+            kind: KeySep,
+            encoding: None,
+            span: 18..19,
+        },
+        Event {
+            kind: Whitespace,
+            encoding: None,
+            span: 19..20,
+        },
+        Event {
+            kind: SimpleKey,
+            encoding: None,
+            span: 20..22,
+        },
+        Event {
+            kind: Whitespace,
+            encoding: None,
+            span: 22..23,
+        },
+        Event {
+            kind: KeyValSep,
+            encoding: None,
+            span: 23..24,
+        },
+        Event {
+            kind: Whitespace,
+            encoding: None,
+            span: 24..25,
+        },
+        Event {
+            kind: Scalar,
+            encoding: Some(
+                LiteralString,
+            ),
+            span: 25..37,
+        },
+        Event {
+            kind: Newline,
+            encoding: None,
+            span: 37..38,
+        },
+    ],
+    errors: [],
+}
diff --git a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_ws.txt b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_ws.txt
index 5d64f818..c91935df 100644
--- a/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_ws.txt
+++ b/crates/toml_parse/tests/snapshots/testsuite__parse_document__document_ws.txt
@@ -2,7 +2,7 @@ EventResults {
     input: "  ",
     events: [
         Event {
-            kind: Newline,
+            kind: Whitespace,
             encoding: None,
             span: 0..2,
         },
diff --git a/crates/toml_parse/tests/testsuite/parse_document.rs b/crates/toml_parse/tests/testsuite/parse_document.rs
index 0a800a76..edc506d8 100644
--- a/crates/toml_parse/tests/testsuite/parse_document.rs
+++ b/crates/toml_parse/tests/testsuite/parse_document.rs
@@ -56,6 +56,15 @@ fn document_key_string_comment() {
     );
 }
 
+#[test]
+fn document_key_ws() {
+    t(
+        r#" hello . darkness . my = 'old friend'
+"#,
+        file![_].raw(),
+    );
+}
+
 #[test]
 fn document_table() {
     t(