diff --git a/Cargo.lock b/Cargo.lock index 9b4c1e4..6743a5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -201,8 +201,11 @@ dependencies = [ "graphql-parser", "handlebars", "handlebars_misc_helpers", + "minidom", "once_cell", "path-dedot", + "quick-xml 0.31.0", + "quickxml_to_serde", "regex", "reqwest", "rhai", @@ -811,6 +814,15 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minidom" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe549115a674f5ec64c754d85e37d6f42664bd0ef4ffb62b619489ad99c6cb1a" +dependencies = [ + "quick-xml 0.17.2", +] + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1060,6 +1072,37 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-xml" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe1e430bdcf30c9fdc25053b9c459bb1a4672af4617b6c783d7d91dc17c6bbb0" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quickxml_to_serde" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f35112b35480fd72f63444289083eeedbd61d13907c82c4309f0ccda35e244" +dependencies = [ + "minidom", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "quote" version = "1.0.33" diff --git a/codegenr/Cargo.toml b/codegenr/Cargo.toml index 36c0c6f..3223100 100644 --- a/codegenr/Cargo.toml +++ b/codegenr/Cargo.toml @@ -53,6 +53,9 @@ serde_json = { version = "1.0", features = ["preserve_order"] } serde_yaml = "0.8" # 0.9 failing with deserializing from YAML containing more than one document is not supported on most files serde = "1.0" graphql-parser = "0.4" +quick-xml = { version = "0.31", features = ["serialize"] } +quickxml_to_serde = "0.5" +minidom = "0.12" # Templating handlebars = { version = "4.4", features = ["script_helper"] } diff --git a/codegenr/_samples/resolver/plant_catalog.xml b/codegenr/_samples/resolver/plant_catalog.xml new file mode 100644 index 0000000..4275db9 --- /dev/null +++ b/codegenr/_samples/resolver/plant_catalog.xml @@ -0,0 +1,291 @@ + + + + Bloodroot + Sanguinaria canadensis + 4 + Mostly Shady + $2.44 + 031599 + + + Columbine + Aquilegia canadensis + 3 + Mostly Shady + $9.37 + 030699 + + + Marsh Marigold + Caltha palustris + 4 + Mostly Sunny + $6.81 + 051799 + + + Cowslip + Caltha palustris + 4 + Mostly Shady + $9.90 + 030699 + + + Dutchman's-Breeches + Dicentra cucullaria + 3 + Mostly Shady + $6.44 + 012099 + + + Ginger, Wild + Asarum canadense + 3 + Mostly Shady + $9.03 + 041899 + + + Hepatica + Hepatica americana + 4 + Mostly Shady + $4.45 + 012699 + + + Liverleaf + Hepatica americana + 4 + Mostly Shady + $3.99 + 010299 + + + Jack-In-The-Pulpit + Arisaema triphyllum + 4 + Mostly Shady + $3.23 + 020199 + + + Mayapple + Podophyllum peltatum + 3 + Mostly Shady + $2.98 + 060599 + + + Phlox, Woodland + Phlox divaricata + 3 + Sun or Shade + $2.80 + 012299 + + + Phlox, Blue + Phlox divaricata + 3 + Sun or Shade + $5.59 + 021699 + + + Spring-Beauty + Claytonia Virginica + 7 + Mostly Shady + $6.59 + 020199 + + + Trillium + Trillium grandiflorum + 5 + Sun or Shade + $3.90 + 042999 + + + Wake Robin + Trillium grandiflorum + 5 + Sun or Shade + $3.20 + 022199 + + + Violet, Dog-Tooth + Erythronium americanum + 4 + Shade + $9.04 + 020199 + + + Trout Lily + Erythronium americanum + 4 + Shade + $6.94 + 032499 + + + Adder's-Tongue + Erythronium americanum + 4 + Shade + $9.58 + 041399 + + + Anemone + Anemone blanda + 6 + Mostly Shady + $8.86 + 122698 + + + Grecian Windflower + Anemone blanda + 6 + Mostly Shady + $9.16 + 071099 + + + Bee Balm + Monarda didyma + 4 + Shade + $4.59 + 050399 + + + Bergamot + Monarda didyma + 4 + Shade + $7.16 + 042799 + + + Black-Eyed Susan + Rudbeckia hirta + Annual + Sunny + $9.80 + 061899 + + + Buttercup + Ranunculus + 4 + Shade + $2.57 + 061099 + + + Crowfoot + Ranunculus + 4 + Shade + $9.34 + 040399 + + + Butterfly Weed + Asclepias tuberosa + Annual + Sunny + $2.78 + 063099 + + + Cinquefoil + Potentilla + Annual + Shade + $7.06 + 052599 + + + Primrose + Oenothera + 3 - 5 + Sunny + $6.56 + 013099 + + + Gentian + Gentiana + 4 + Sun or Shade + $7.81 + 051899 + + + Blue Gentian + Gentiana + 4 + Sun or Shade + $8.56 + 050299 + + + Jacob's Ladder + Polemonium caeruleum + Annual + Shade + $9.26 + 022199 + + + Greek Valerian + Polemonium caeruleum + Annual + Shade + $4.36 + 071499 + + + California Poppy + Eschscholzia californica + Annual + Sun + $7.89 + 032799 + + + Shooting Star + Dodecatheon + Annual + Mostly Shady + $8.60 + 051399 + + + Snakeroot + Cimicifuga + Annual + Shade + $5.63 + 071199 + + + Cardinal Flower + Lobelia cardinalis + 2 + Shade + $3.02 + 022299 + + diff --git a/codegenr/src/loaders/document_path.rs b/codegenr/src/loaders/document_path.rs index b100f77..8bfbc1e 100644 --- a/codegenr/src/loaders/document_path.rs +++ b/codegenr/src/loaders/document_path.rs @@ -82,6 +82,8 @@ impl DocumentPath { FormatHint::Toml } else if s.ends_with(".graphql") || s.ends_with(".gql") { FormatHint::Graphql + } else if s.ends_with(".xml") || s.ends_with(".xaml") || s.ends_with(".wsdl") || s.ends_with(".xsd") || s.ends_with(".xul") { + FormatHint::Xml } else { FormatHint::NoIdea } diff --git a/codegenr/src/loaders/mod.rs b/codegenr/src/loaders/mod.rs index 5874c6e..271fe37 100644 --- a/codegenr/src/loaders/mod.rs +++ b/codegenr/src/loaders/mod.rs @@ -7,6 +7,7 @@ pub use document_path::*; pub mod graphql; pub mod json; pub mod toml; +pub mod xml; pub mod yaml; pub trait DocumentLoader { @@ -48,12 +49,15 @@ pub enum LoaderError { json_error: serde_json::Error, yaml_error: serde_yaml::Error, toml_error: ::toml::de::Error, + xml_error: minidom::Error, graphql_error: graphql_parser::schema::ParseError, }, #[error("Yaml error: `{0}`.")] YamlError(#[from] serde_yaml::Error), #[error("Json error: `{0}`.")] JsonError(#[from] serde_json::Error), + #[error("Xml error: `{0}`.")] + XmlError(#[from] minidom::Error), #[error("Graphql error: `{0}`.")] GraphqlError(#[from] graphql_parser::schema::ParseError), #[error("Did not try all the file loaders.")] @@ -68,6 +72,8 @@ pub(crate) enum FormatHint { Yaml, /// The content should be toml Toml, + /// The content should be xml + Xml, /// The content should be a graphql schema Graphql, /// We have no f.....g idea @@ -79,9 +85,10 @@ fn json_from_string(content: &str, hint: FormatHint) -> Result try_loaders(content, &[Json, Yaml, Toml, Graphql]), - FormatHint::Yaml => try_loaders(content, &[Yaml, Json, Toml, Graphql]), - FormatHint::Toml => try_loaders(content, &[Toml, Json, Yaml, Graphql]), - FormatHint::Graphql => try_loaders(content, &[Graphql, Json, Yaml, Toml]), + FormatHint::Yaml => try_loaders(content, &[Yaml, Json, Toml, Xml, Graphql]), + FormatHint::Toml => try_loaders(content, &[Toml, Json, Yaml, Xml, Graphql]), + FormatHint::Xml => try_loaders(content, &[Xml, Json, Yaml, Toml, Graphql]), + FormatHint::Graphql => try_loaders(content, &[Graphql, Json, Yaml, Toml, Xml]), } } @@ -90,6 +97,7 @@ fn try_loaders(content: &str, formats: &[FormatHint]) -> Result = None; let mut yaml_error: Option = None; let mut toml_error: Option<::toml::de::Error> = None; + let mut xml_error: Option<::minidom::Error> = None; let mut graphql_error: Option = None; for hint in formats { @@ -112,6 +120,12 @@ fn try_loaders(content: &str, formats: &[FormatHint]) -> Result e, }); } + FormatHint::Xml => { + xml_error = Some(match xml::XmlLoader::json_from_str(content) { + Ok(json) => return Ok(json), + Err(e) => e, + }); + } FormatHint::Graphql => { graphql_error = Some(match graphql::GraphqlLoader::json_from_str(content) { Ok(json) => return Ok(json), @@ -129,6 +143,7 @@ fn try_loaders(content: &str, formats: &[FormatHint]) -> Result Result<(), LoaderError> { + let _result = DocumentPath::parse("./_samples/resolver/plant_catalog.xml")?.load_raw()?; + dbg!(_result); + Ok(()) + } + #[allow(clippy::result_large_err)] #[test] #[ignore] diff --git a/codegenr/src/loaders/xml.rs b/codegenr/src/loaders/xml.rs new file mode 100644 index 0000000..cab971f --- /dev/null +++ b/codegenr/src/loaders/xml.rs @@ -0,0 +1,11 @@ +use super::DocumentLoader; +use quickxml_to_serde::xml_str_to_json; + +pub struct XmlLoader {} +impl DocumentLoader for XmlLoader { + type Error = minidom::Error; + fn json_from_str(content: &str) -> Result { + let config = quickxml_to_serde::Config::default(); + xml_str_to_json(content, &config) + } +} diff --git a/codegenr/src/processor/file.rs b/codegenr/src/processor/file.rs index 6b1e14d..1c51f6d 100644 --- a/codegenr/src/processor/file.rs +++ b/codegenr/src/processor/file.rs @@ -73,7 +73,7 @@ impl Drop for FileLineHandler { #[cfg(test)] mod tests { use super::*; - use crate::filesystem::make_path_from_root; + use crate::filesystem::create_file; use tempdir::TempDir; #[test] @@ -81,7 +81,7 @@ mod tests { let tmp = TempDir::new("FILE_tests")?; let instruction = FileInstruction::new(tmp.path().to_string_lossy().into()); let handler = instruction.start(vec!["sub/plop.txt".into()])?; - let should_exists_path = make_path_from_root(tmp.path(), "sub/plop.txt"); + let (_file, should_exists_path) = create_file(tmp.path(), "sub/plop.txt")?; assert!(should_exists_path.exists()); handler.handle_line("hello ...")?; assert!(should_exists_path.exists());