From 2273ce77b819895022d62dec8a8446f9e0345260 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Tue, 31 Oct 2023 22:30:23 +0000 Subject: [PATCH] feat: trim whitespace from multi-line strings Resolves #24 --- assets/inputs/string_multiline.corn | 6 ++++ assets/outputs/json/string.json | 2 +- assets/outputs/json/string_multiline.json | 3 ++ assets/outputs/toml/string.toml | 6 ++-- assets/outputs/toml/string_multiline.toml | 5 +++ assets/outputs/yaml/string.yml | 3 +- assets/outputs/yaml/string_multiline.yml | 4 +++ libcorn/src/parser.rs | 40 +++++++++++++++++++++++ libcorn/src/wasm.rs | 1 - 9 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 assets/inputs/string_multiline.corn create mode 100644 assets/outputs/json/string_multiline.json create mode 100644 assets/outputs/toml/string_multiline.toml create mode 100644 assets/outputs/yaml/string_multiline.yml diff --git a/assets/inputs/string_multiline.corn b/assets/inputs/string_multiline.corn new file mode 100644 index 0000000..c1d25a0 --- /dev/null +++ b/assets/inputs/string_multiline.corn @@ -0,0 +1,6 @@ +{ + foo = " + hello + world + " +} \ No newline at end of file diff --git a/assets/outputs/json/string.json b/assets/outputs/json/string.json index 61c3a14..53e6ede 100644 --- a/assets/outputs/json/string.json +++ b/assets/outputs/json/string.json @@ -1,6 +1,6 @@ { "foo": "bar", - "bar": "\"\\\n\r\t", + "bar": "\"\\\n", "baz": "a", "qux": "" } diff --git a/assets/outputs/json/string_multiline.json b/assets/outputs/json/string_multiline.json new file mode 100644 index 0000000..888d65d --- /dev/null +++ b/assets/outputs/json/string_multiline.json @@ -0,0 +1,3 @@ +{ + "foo": "hello\nworld\n" +} diff --git a/assets/outputs/toml/string.toml b/assets/outputs/toml/string.toml index 5d05e07..f4cc605 100644 --- a/assets/outputs/toml/string.toml +++ b/assets/outputs/toml/string.toml @@ -1,7 +1,7 @@ foo = "bar" -bar = """ -\"\\ -\r\t""" +bar = ''' +"\ +''' baz = "a" qux = "" diff --git a/assets/outputs/toml/string_multiline.toml b/assets/outputs/toml/string_multiline.toml new file mode 100644 index 0000000..d2a49da --- /dev/null +++ b/assets/outputs/toml/string_multiline.toml @@ -0,0 +1,5 @@ +foo = """ +hello +world +""" + diff --git a/assets/outputs/yaml/string.yml b/assets/outputs/yaml/string.yml index 6a78af1..f1649d4 100644 --- a/assets/outputs/yaml/string.yml +++ b/assets/outputs/yaml/string.yml @@ -1,5 +1,6 @@ foo: bar -bar: "\"\\\n\r\t" +bar: | + "\ baz: a qux: '' diff --git a/assets/outputs/yaml/string_multiline.yml b/assets/outputs/yaml/string_multiline.yml new file mode 100644 index 0000000..58f9fac --- /dev/null +++ b/assets/outputs/yaml/string_multiline.yml @@ -0,0 +1,4 @@ +foo: | + hello + world + diff --git a/libcorn/src/parser.rs b/libcorn/src/parser.rs index af80470..1964ab8 100644 --- a/libcorn/src/parser.rs +++ b/libcorn/src/parser.rs @@ -124,6 +124,12 @@ impl<'a> CornParser<'a> { }; } + let full_string = if full_string.contains('\n') { + trim_multiline_string(&full_string) + } else { + full_string + }; + Ok(Cow::Owned(full_string)) } @@ -315,6 +321,40 @@ impl<'a> CornParser<'a> { } } +/// Takes a multiline string and trims the maximum amount of +/// whitespace at the start of each line +/// while preserving formatting. +/// +/// Based on code from `indoc` crate: +/// + +fn trim_multiline_string(string: &str) -> String { + let ignore_first_line = string.starts_with('\n') || string.starts_with("\r\n"); + + let spaces = string + .lines() + .skip(1) + .map(|line| line.chars().take_while(char::is_ascii_whitespace).count()) + .min() + .unwrap_or_default(); + + let mut result = String::with_capacity(string.len()); + for (i, line) in string.lines().enumerate() { + if i > 1 || (i == 1 && !ignore_first_line) { + result.push('\n'); + } + if i == 0 { + // Do not un-indent anything on same line as opening quote + result.push_str(line); + } else if line.len() > spaces { + // Whitespace-only lines may have fewer than the number of spaces + // being removed + result.push_str(&line[spaces..]); + } + } + result +} + /// Parses the input string into a `Config` /// containing the resolved inputs /// and a map of values representing the top-level object. diff --git a/libcorn/src/wasm.rs b/libcorn/src/wasm.rs index e0943e4..b688bbf 100644 --- a/libcorn/src/wasm.rs +++ b/libcorn/src/wasm.rs @@ -10,7 +10,6 @@ use wasm_bindgen_test::*; #[wasm_bindgen] pub fn parse(corn: &str) -> Result { console_error_panic_hook::set_once(); - let res = crate::parse(corn); match res {