From 69778bbfa64f8b031e871cc3621687dbd3df5b3c Mon Sep 17 00:00:00 2001 From: Bauke Date: Fri, 6 Jan 2023 14:03:43 +0100 Subject: [PATCH] Add source and test files. --- source/lib.rs | 71 ++++++++++++++++++++++++++ tests/errors.rs | 20 ++++++++ tests/parsing.rs | 29 +++++++++++ tests/snapshots/parsing__markdown.snap | 7 +++ tests/snapshots/parsing__toml.snap | 5 ++ 5 files changed, 132 insertions(+) create mode 100644 source/lib.rs create mode 100644 tests/errors.rs create mode 100644 tests/parsing.rs create mode 100644 tests/snapshots/parsing__markdown.snap create mode 100644 tests/snapshots/parsing__toml.snap diff --git a/source/lib.rs b/source/lib.rs new file mode 100644 index 0000000..75c3caa --- /dev/null +++ b/source/lib.rs @@ -0,0 +1,71 @@ +/*! +# toml-frontmatter + +> **TOML frontmatter parser.** + +See the [`parse`] documentation for an example. + +## License + +Distributed under the [Apache License 2.0](https://spdx.org/licenses/Apache-2.0.html) and [MIT](https://spdx.org/licenses/MIT.html) licenses, see [LICENSE-Apache](https://git.bauke.xyz/Holllo/toml-frontmatter/src/branch/main/LICENSE-Apache) and [LICENSE-MIT](https://git.bauke.xyz/Holllo/toml-frontmatter/src/branch/main/LICENSE-MIT) for more information. +*/ + +#![forbid(unsafe_code)] +#![warn(missing_docs, clippy::missing_docs_in_private_items)] + +use { + anyhow::{anyhow, Result}, + serde::Deserialize, +}; + +/** +Parse a struct that implements [`serde::Deserialize`] from frontmatter and +return the remaining contents of the string. + +## Errors + +This function will return an [`Err`] when: + +- the data doesn't have a frontmatter section, +- the frontmatter isnt' at the beginning of the data. + +## Example + +```rust +#[derive(serde::Deserialize)] +struct Frontmatter { + date: String, +} + +let sample = r#" +---toml +date = "2023-01-01" +--- + +Some **Markdown**. Or something else! +"#.trim(); + +let (frontmatter, markdown) = toml_frontmatter::parse::(sample).unwrap(); +``` +*/ +pub fn parse<'a, D: Deserialize<'a>>(data: &'a str) -> Result<(D, &'a str)> { + let start_marker = "---toml\n"; + let end_marker = "\n---\n"; + + let (start, end) = match (data.find(start_marker), data.find(end_marker)) { + (Some(start), Some(end)) => (start, end), + _ => return Err(anyhow!("Missing frontmatter")), + }; + + if start != 0 { + return Err(anyhow!("Frontmatter not at beginning of data")); + } + + let start = start + start_marker.len(); + let frontmatter = &data[start..end]; + + let end = end + end_marker.len(); + let extra = &data[end..]; + + Ok((toml::from_str::(frontmatter)?, extra.trim_start())) +} diff --git a/tests/errors.rs b/tests/errors.rs new file mode 100644 index 0000000..16afd06 --- /dev/null +++ b/tests/errors.rs @@ -0,0 +1,20 @@ +#[test] +#[should_panic(expected = "Missing frontmatter")] +fn test_missing_frontmatter() { + toml_frontmatter::parse::<()>("# Heading").unwrap(); +} + +#[test] +#[should_panic(expected = "Frontmatter not at beginning of data")] +fn test_frontmatter_not_at_start() { + let sample = r#" +# Heading + +---toml +date = "2023-01-01" +--- + +Text."#; + + toml_frontmatter::parse::<()>(sample).unwrap(); +} diff --git a/tests/parsing.rs b/tests/parsing.rs new file mode 100644 index 0000000..0d2274c --- /dev/null +++ b/tests/parsing.rs @@ -0,0 +1,29 @@ +use { + anyhow::Result, + insta::{assert_snapshot, assert_toml_snapshot}, + serde::{Deserialize, Serialize}, +}; + +#[derive(Debug, Deserialize, Serialize)] +struct Frontmatter { + date: String, +} + +#[test] +fn test_parsing() -> Result<()> { + let sample = r#" +---toml +date = "2023-01-01" +--- + +# Some Markdown + +With text!"#; + + let (toml, markdown) = toml_frontmatter::parse::(sample.trim())?; + + assert_toml_snapshot!("toml", toml); + assert_snapshot!("markdown", markdown); + + Ok(()) +} diff --git a/tests/snapshots/parsing__markdown.snap b/tests/snapshots/parsing__markdown.snap new file mode 100644 index 0000000..58aefe8 --- /dev/null +++ b/tests/snapshots/parsing__markdown.snap @@ -0,0 +1,7 @@ +--- +source: tests/parsing.rs +expression: markdown +--- +# Some Markdown + +With text! diff --git a/tests/snapshots/parsing__toml.snap b/tests/snapshots/parsing__toml.snap new file mode 100644 index 0000000..1ccd144 --- /dev/null +++ b/tests/snapshots/parsing__toml.snap @@ -0,0 +1,5 @@ +--- +source: tests/parsing.rs +expression: toml +--- +date = '2023-01-01'