From e8da57b05e2c90b7ac288ae852eda2ab8a3a8920 Mon Sep 17 00:00:00 2001 From: joergsch Date: Tue, 3 Oct 2023 19:11:16 +0200 Subject: [PATCH] Correct line folding in `from ics`/`from vcf` (#10577) # Description Potential fix for #10398 datatracker.ietf.org/doc/html/rfc5545#section-3.1 datatracker.ietf.org/doc/html/rfc6350#section-3.2 --------- Co-authored-by: Joerg --- crates/nu_plugin_formats/src/from/ics.rs | 14 ++++++-- crates/nu_plugin_formats/src/from/vcf.rs | 14 ++++++-- tests/plugins/formats/ics.rs | 46 +++++++++++++++++++++++- tests/plugins/formats/vcf.rs | 41 ++++++++++++++++++++- 4 files changed, 107 insertions(+), 8 deletions(-) diff --git a/crates/nu_plugin_formats/src/from/ics.rs b/crates/nu_plugin_formats/src/from/ics.rs index d8260947b..ede4a0d89 100644 --- a/crates/nu_plugin_formats/src/from/ics.rs +++ b/crates/nu_plugin_formats/src/from/ics.rs @@ -14,9 +14,17 @@ pub fn from_ics_call(call: &EvaluatedCall, input: &Value) -> Result>() - .join("\n"); + .enumerate() + .map(|(i, x)| { + if i == 0 { + x.trim().to_string() + } else if x.len() > 1 && (x.starts_with(' ') || x.starts_with('\t')) { + x[1..].trim_end().to_string() + } else { + format!("\n{}", x.trim()) + } + }) + .collect::(); let input_bytes = input_string.as_bytes(); let buf_reader = BufReader::new(input_bytes); diff --git a/crates/nu_plugin_formats/src/from/vcf.rs b/crates/nu_plugin_formats/src/from/vcf.rs index c3302ce1b..1cb91d588 100644 --- a/crates/nu_plugin_formats/src/from/vcf.rs +++ b/crates/nu_plugin_formats/src/from/vcf.rs @@ -13,9 +13,17 @@ pub fn from_vcf_call(call: &EvaluatedCall, input: &Value) -> Result>() - .join("\n"); + .enumerate() + .map(|(i, x)| { + if i == 0 { + x.trim().to_string() + } else if x.len() > 1 && (x.starts_with(' ') || x.starts_with('\t')) { + x[1..].trim_end().to_string() + } else { + format!("\n{}", x.trim()) + } + }) + .collect::(); let input_bytes = input_string.as_bytes(); let cursor = std::io::Cursor::new(input_bytes); diff --git a/tests/plugins/formats/ics.rs b/tests/plugins/formats/ics.rs index cdc1876aa..c503f6569 100644 --- a/tests/plugins/formats/ics.rs +++ b/tests/plugins/formats/ics.rs @@ -1,4 +1,4 @@ -use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::fs::Stub::{FileWithContent, FileWithContentToBeTrimmed}; use nu_test_support::nu_with_plugins; use nu_test_support::playground::Playground; use pretty_assertions::assert_eq; @@ -98,3 +98,47 @@ fn from_ics_text_to_table() { assert_eq!(actual.out, "Maryland Game"); }) } + +#[test] +fn from_ics_text_with_linebreak_to_table() { + Playground::setup("filter_from_ics_test_3", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContent( + "calendar.txt", + r#"BEGIN:VCALENDAR +BEGIN:VEVENT +DTSTART:20171007T200000Z +DTEND:20171007T233000Z +DTSTAMP:20200319T182138Z +UID:4l80f6dcovnriq38g57g07btid@google.com +CREATED:20170719T202915Z +DESCRIPTION: +LAST-MODIFIED:20170930T190808Z +LOCATION:The Restaurant n + ear the + Belltower +SEQUENCE:1 +STATUS:CONFIRMED +SUMMARY:Dinner +TRANSP:TRANSPARENT +END:VEVENT +END:VCALENDAR"#, + )]); + + let cwd = dirs.test(); + let actual = nu_with_plugins!( + cwd: cwd, + plugin: ("nu_plugin_formats"), + r#" + open calendar.txt + | from ics + | get events.0 + | get properties.0 + | where name == "LOCATION" + | first + | get value + "# + ); + + assert_eq!(actual.out, "The Restaurant near the Belltower"); + }) +} diff --git a/tests/plugins/formats/vcf.rs b/tests/plugins/formats/vcf.rs index c70990e99..d57269bbd 100644 --- a/tests/plugins/formats/vcf.rs +++ b/tests/plugins/formats/vcf.rs @@ -1,4 +1,4 @@ -use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::fs::Stub::{FileWithContent, FileWithContentToBeTrimmed}; use nu_test_support::nu_with_plugins; use nu_test_support::playground::Playground; use pretty_assertions::assert_eq; @@ -82,3 +82,42 @@ fn from_vcf_text_to_table() { assert_eq!(actual.out, "john.doe99@gmail.com"); }) } + +#[test] +fn from_vcf_text_with_linebreak_to_table() { + Playground::setup("filter_from_vcf_test_3", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContent( + "contacts.txt", + r"BEGIN:VCARD +VERSION:3.0 +FN:John Doe +N:Doe;John;;; +EMAIL;TYPE=INTERNET:john.doe99 + @gmail.com +item1.ORG:'Alpine Ski Resort' +item1.X-ABLabel:Other +item2.TITLE:'Ski Instructor' +item2.X-ABLabel:Other +BDAY:19001106 +NOTE:Facebook: john.doe.3\nWebsite: \nHometown: Cleveland\, Ohio +CATEGORIES:myContacts +END:VCARD", + )]); + + let cwd = dirs.test(); + let actual = nu_with_plugins!( + cwd: cwd, + plugin: ("nu_plugin_formats"), + r#" + open contacts.txt + | from vcf + | get properties.0 + | where name == "EMAIL" + | first + | get value + "# + ); + + assert_eq!(actual.out, "john.doe99@gmail.com"); + }) +}