Skip to content

Commit fd9d779

Browse files
Merge pull request #7 from code0-tech/#6-support-html
added html support
2 parents 2106a73 + 1a267ea commit fd9d779

5 files changed

Lines changed: 83 additions & 4 deletions

File tree

crates/lupus/src/engine.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use crate::codec::Codec;
55
use crate::data::Data;
66
use crate::error::ConvertError;
77
use crate::format::Format;
8-
use crate::formats::{CsvCodec, HttpFormCodec, JsonCodec, ProtobufCodec, TextCodec, XmlCodec};
8+
use crate::formats::{
9+
CsvCodec, HtmlCodec, HttpFormCodec, JsonCodec, ProtobufCodec, TextCodec, XmlCodec,
10+
};
911
use crate::schema::{DecodeContext, EncodeContext, JsonSchema};
1012
use crate::transform::{data_into_markup, data_to_text, markup_into_data, markup_to_text};
1113
use crate::validation::validate_json_schema;
@@ -24,6 +26,7 @@ impl Engine {
2426
let mut engine = Self::new();
2527
engine.register(JsonCodec);
2628
engine.register(XmlCodec);
29+
engine.register(HtmlCodec);
2730
engine.register(TextCodec);
2831
engine.register(CsvCodec);
2932
engine.register(HttpFormCodec);
@@ -180,6 +183,21 @@ mod tests {
180183
Ok(())
181184
}
182185

186+
#[test]
187+
fn json_converts_to_html_markup() -> Result<(), Box<dyn std::error::Error>> {
188+
let engine = Engine::with_default_codecs();
189+
let html = engine.convert(
190+
br#"{"article":{"h1":"Hello","p":"World"}}"#,
191+
Format::Json,
192+
Format::Html,
193+
&DecodeContext,
194+
&EncodeContext::default(),
195+
)?;
196+
197+
assert_eq!(html, b"<article><h1>Hello</h1><p>World</p></article>");
198+
Ok(())
199+
}
200+
183201
#[test]
184202
fn codecs_pretty_print_structured_output_when_requested()
185203
-> Result<(), Box<dyn std::error::Error>> {

crates/lupus/src/format.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub const TEXT: &str = "text";
44
pub const PROTOBUF: &str = "protobuf";
55
pub const CSV: &str = "csv";
66
pub const HTTP_FORM: &str = "http-form";
7+
pub const HTML: &str = "html";
78
pub const XML: &str = "xml";
89
pub const JSON: &str = "json";
910

@@ -13,14 +14,16 @@ pub enum Format {
1314
Protobuf,
1415
Csv,
1516
HttpForm,
17+
Html,
1618
Xml,
1719
Json,
1820
}
1921

2022
impl Format {
21-
pub const ALL: [Self; 6] = [
23+
pub const ALL: [Self; 7] = [
2224
Self::Json,
2325
Self::Xml,
26+
Self::Html,
2427
Self::Text,
2528
Self::Csv,
2629
Self::HttpForm,
@@ -33,6 +36,7 @@ impl Format {
3336
Format::Protobuf => PROTOBUF,
3437
Format::Csv => CSV,
3538
Format::HttpForm => HTTP_FORM,
39+
Format::Html => HTML,
3640
Format::Xml => XML,
3741
Format::Json => JSON,
3842
}
@@ -42,6 +46,7 @@ impl Format {
4246
match self {
4347
Format::Json => "JSON",
4448
Format::Xml => "XML",
49+
Format::Html => "HTML",
4550
Format::Text => "Text",
4651
Format::Csv => "CSV",
4752
Format::HttpForm => "HTTP Form",

crates/lupus/src/formats/html.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use crate::artifact::{Artifact, ArtifactKind};
2+
use crate::codec::Codec;
3+
use crate::error::ConvertError;
4+
use crate::format::Format;
5+
use crate::formats::xml::{parse_xml, write_xml};
6+
use crate::schema::{DecodeContext, EncodeContext};
7+
8+
pub struct HtmlCodec;
9+
10+
impl Codec for HtmlCodec {
11+
fn format(&self) -> Format {
12+
Format::Html
13+
}
14+
15+
fn artifact_kind(&self) -> ArtifactKind {
16+
ArtifactKind::Markup
17+
}
18+
19+
fn decode(&self, input: &[u8], _ctx: &DecodeContext) -> Result<Artifact, ConvertError> {
20+
let input = std::str::from_utf8(input)
21+
.map_err(|err| ConvertError::Decoding(format!("html is not valid UTF-8: {err}")))?;
22+
Ok(Artifact::Markup(parse_xml(input)?))
23+
}
24+
25+
fn encode(&self, artifact: &Artifact, ctx: &EncodeContext) -> Result<Vec<u8>, ConvertError> {
26+
let Artifact::Markup(markup) = artifact else {
27+
return Err(ConvertError::WrongArtifact {
28+
expected: ArtifactKind::Markup,
29+
found: artifact.kind(),
30+
});
31+
};
32+
33+
Ok(write_xml(markup, ctx.pretty).into_bytes())
34+
}
35+
}
36+
37+
#[cfg(test)]
38+
mod tests {
39+
use crate::codec::Codec;
40+
use crate::formats::HtmlCodec;
41+
use crate::schema::{DecodeContext, EncodeContext};
42+
43+
#[test]
44+
fn html_codec_decodes_and_encodes_markup() -> Result<(), Box<dyn std::error::Error>> {
45+
let codec = HtmlCodec;
46+
let artifact = codec.decode(b"<article><h1>Hello</h1></article>", &DecodeContext)?;
47+
48+
assert_eq!(
49+
codec.encode(&artifact, &EncodeContext::default())?,
50+
b"<article><h1>Hello</h1></article>"
51+
);
52+
Ok(())
53+
}
54+
}

crates/lupus/src/formats/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
pub mod csv;
2+
pub mod html;
23
pub mod http_form;
34
pub mod json;
45
pub mod protobuf;
56
pub mod text;
67
pub mod xml;
78

89
pub use csv::CsvCodec;
10+
pub use html::HtmlCodec;
911
pub use http_form::HttpFormCodec;
1012
pub use json::JsonCodec;
1113
pub use protobuf::{ProtobufCodec, data_to_value, value_to_data};

crates/lupus/src/formats/xml.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl Codec for XmlCodec {
3434
}
3535
}
3636

37-
fn parse_xml(input: &str) -> Result<Markup, ConvertError> {
37+
pub(crate) fn parse_xml(input: &str) -> Result<Markup, ConvertError> {
3838
let mut parser = XmlParser::new(input);
3939
parser.skip_misc()?;
4040
let root = parser.parse_node()?;
@@ -286,7 +286,7 @@ impl<'a> XmlParser<'a> {
286286
}
287287
}
288288

289-
fn write_xml(markup: &Markup, pretty: bool) -> String {
289+
pub(crate) fn write_xml(markup: &Markup, pretty: bool) -> String {
290290
let mut output = String::new();
291291
write_node(&markup.root, 0, pretty, &mut output);
292292
output

0 commit comments

Comments
 (0)