diff --git a/Cargo.toml b/Cargo.toml index 5975f24..80f285f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ license = "MIT OR Apache-2.0" default = ["remote"] toml-serde = ["toml", "serde"] json-serde = ["serde_json", "serde"] +toml-edit = ["toml_edit"] remote = ["reqwest"] compression = ["compression-tar", "compression-zip"] compression-tar = ["flate2", "tar", "xz2"] @@ -30,6 +31,7 @@ tar = { version = "0.4.38", optional = true } zip = { version = "0.6.4", optional = true } flate2 = { version = "1.0.25", optional = true } xz2 = { version = "0.1.7", optional = true } +toml_edit = { version = "0.19.9", optional = true } [dev-dependencies] assert_fs = "1" diff --git a/src/error.rs b/src/error.rs index d20ab3f..29c7c5a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -333,4 +333,20 @@ pub enum AxoassetError { #[source] details: toml::de::Error, }, + + /// This error indicates we tried to deserialize some TOML with toml_edit + /// but failed. + #[cfg(feature = "toml-edit")] + #[error("failed to edit TOML document")] + TomlEdit { + /// The SourceFile we were trying to parse + #[source_code] + source: crate::SourceFile, + /// The range the error was found on + #[label] + span: Option, + /// Details of the error + #[source] + details: toml_edit::TomlError, + }, } diff --git a/src/source.rs b/src/source.rs index 54b58e1..5d88867 100644 --- a/src/source.rs +++ b/src/source.rs @@ -110,6 +110,23 @@ impl SourceFile { Ok(toml) } + /// Try to deserialize the contents of the SourceFile as a toml_edit Document + #[cfg(feature = "toml-edit")] + pub fn deserialize_toml_edit(&self) -> Result { + let toml = self + .contents() + .parse::() + .map_err(|details| { + let span = details.span().map(SourceSpan::from); + AxoassetError::TomlEdit { + source: self.clone(), + span, + details, + } + })?; + Ok(toml) + } + /// Get the filename of a SourceFile pub fn filename(&self) -> &str { &self.inner.filename diff --git a/tests/source.rs b/tests/source.rs index 83aa510..9bb6d5d 100644 --- a/tests/source.rs +++ b/tests/source.rs @@ -29,3 +29,132 @@ fn substr_span_invalid() { let there_span = source.span_for_substr("there"); assert_eq!(there_span, None); } + +#[cfg(feature = "json-serde")] +#[test] +fn json_valid() { + #[derive(serde::Deserialize, PartialEq, Eq, Debug)] + struct MyType { + hello: String, + goodbye: bool, + } + + // Make the file + let contents = String::from(r##"{ "hello": "there", "goodbye": true }"##); + let source = axoasset::SourceFile::new("file.js", contents); + + // Get the span for a non-substring (string literal isn't pointing into the String) + let val = source.deserialize_json::().unwrap(); + assert_eq!( + val, + MyType { + hello: "there".to_string(), + goodbye: true + } + ); +} + +#[cfg(feature = "json-serde")] +#[test] +fn json_invalid() { + #[derive(serde::Deserialize, PartialEq, Eq, Debug)] + struct MyType { + hello: String, + goodbye: bool, + } + + // Make the file + let contents = String::from(r##"{ "hello": "there", "goodbye": true, }"##); + let source = axoasset::SourceFile::new("file.js", contents); + + // Get the span for a non-substring (string literal isn't pointing into the String) + let res = source.deserialize_json::(); + assert!(res.is_err()); +} + +#[cfg(feature = "toml-serde")] +#[test] +fn toml_valid() { + #[derive(serde::Deserialize, PartialEq, Eq, Debug)] + struct MyType { + hello: String, + goodbye: bool, + } + + // Make the file + let contents = String::from( + r##" +hello = "there" +goodbye = true +"##, + ); + let source = axoasset::SourceFile::new("file.toml", contents); + + // Get the span for a non-substring (string literal isn't pointing into the String) + let val = source.deserialize_toml::().unwrap(); + assert_eq!( + val, + MyType { + hello: "there".to_string(), + goodbye: true + } + ); +} + +#[cfg(feature = "toml-serde")] +#[test] +fn toml_invalid() { + #[derive(serde::Deserialize, PartialEq, Eq, Debug)] + struct MyType { + hello: String, + goodbye: bool, + } + + // Make the file + let contents = String::from( + r##" +hello = "there" +goodbye = +"##, + ); + let source = axoasset::SourceFile::new("file.toml", contents); + + // Get the span for a non-substring (string literal isn't pointing into the String) + let res = source.deserialize_toml::(); + assert!(res.is_err()); +} + +#[cfg(feature = "toml-edit")] +#[test] +fn toml_edit_valid() { + // Make the file + let contents = String::from( + r##" +hello = "there" +goodbye = true +"##, + ); + let source = axoasset::SourceFile::new("file.toml", contents); + + // Get the span for a non-substring (string literal isn't pointing into the String) + let val = source.deserialize_toml_edit().unwrap(); + assert_eq!(val["hello"].as_str().unwrap(), "there"); + assert_eq!(val["goodbye"].as_bool().unwrap(), true); +} + +#[cfg(feature = "toml-edit")] +#[test] +fn toml_edit_invalid() { + // Make the file + let contents = String::from( + r##" +hello = "there" +goodbye = +"##, + ); + let source = axoasset::SourceFile::new("file.toml", contents); + + // Get the span for a non-substring (string literal isn't pointing into the String) + let res = source.deserialize_toml_edit(); + assert!(res.is_err()); +}