feat: complete html to rsx rosetta

This commit is contained in:
Jonathan Kelley committed 2022-12-28 16:22:20 -05:00
1 parent d22577082c
commit bc3cf6501c
8 files changed
+159 -87

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
[package]
name = "rsx-rosetta"
version = "0.0.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dioxus-autofmt = { path = "../autofmt" }
dioxus-rsx = { path = "../rsx" }
html_parser = "0.6.3"
proc-macro2 = "1.0.49"
quote = "1.0.23"
syn = { version = "1.0.107", features = ["full"] }
convert_case = "0.5.0"
# [features]
# default = ["html"]
# eventually more output options
+19
View File
@@ -0,0 +1,19 @@
# Rosetta for RSX
---
Dioxus sports its own templating language inspired by C#/Kotlin/RTMP, etc. It's pretty straightforward.
However, it's NOT HTML. This is done since HTML is verbose and you'd need a dedicated LSP or IDE integration to get a good DX in .rs files.
RSX is simple... It's similar enough to regular Rust code to trick most IDEs into automatically providing support for things like block selections, folding, highlighting, etc.
To accomodate the transition from HTML to RSX, you might need to translate some existing code.
This library provids a central AST that can accept a number of inputs:
- HTML
- Syn (todo)
- Akama (todo)
- Jinja (todo)
From there, you can convert directly to a string or into some other AST.
+24
View File
@@ -0,0 +1,24 @@
use html_parser::Dom;
fn main() {
let html = r#"
<div>
<div class="asd">hello world!</div>
<div id="asd">hello world!</div>
<div id="asd">hello world!</div>
<div for="asd">hello world!</div>
<div async="asd">hello world!</div>
<div LargeThing="asd">hello world!</div>
<ai-is-awesome>hello world!</ai-is-awesome>
</div>
"#
.trim();
let dom = Dom::parse(html).unwrap();
let body = rsx_rosetta::convert_from_html(dom);
let out = dioxus_autofmt::write_block_out(body).unwrap();
println!("{}", out);
}
+92
View File
@@ -0,0 +1,92 @@
use dioxus_rsx::{BodyNode, CallBody, Element, ElementAttr, ElementAttrNamed, IfmtInput};
pub use html_parser::{Dom, Node};
use proc_macro2::{Ident, Span};
use syn::LitStr;
pub fn convert_from_html(dom: Dom) -> CallBody {
CallBody {
roots: dom
.children
.into_iter()
.map(|f| create_body_node_from_node(f))
.filter_map(|f| f)
.collect(),
}
}
fn create_body_node_from_node(node: Node) -> Option<BodyNode> {
match node {
Node::Text(text) => Some(BodyNode::Text(ifmt_from_text(text))),
Node::Element(el) => {
use convert_case::{Case, Casing};
let el_name = el.name.to_case(Case::Snake);
let el_name = Ident::new(el_name.as_str(), Span::call_site());
let mut attributes: Vec<_> = el
.attributes
.into_iter()
.map(|(name, value)| {
let ident = if matches!(name.as_str(), "for" | "async" | "type" | "as") {
Ident::new_raw(name.as_str(), Span::call_site())
} else {
let new_name = name.to_case(Case::Snake);
Ident::new(new_name.as_str(), Span::call_site())
};
ElementAttrNamed {
attr: ElementAttr::AttrText {
name: ident,
value: ifmt_from_text(value.unwrap_or("false".to_string())),
},
el_name: el_name.clone(),
}
})
.collect();
let class = el.classes.join(" ");
if !class.is_empty() {
attributes.push(ElementAttrNamed {
attr: ElementAttr::AttrText {
name: Ident::new("class", Span::call_site()),
value: ifmt_from_text(class),
},
el_name: el_name.clone(),
});
}
if let Some(id) = el.id {
attributes.push(ElementAttrNamed {
attr: ElementAttr::AttrText {
name: Ident::new("id", Span::call_site()),
value: ifmt_from_text(id),
},
el_name: el_name.clone(),
});
}
let children = el
.children
.into_iter()
.map(|f| create_body_node_from_node(f))
.filter_map(|f| f)
.collect();
Some(BodyNode::Element(Element {
name: el_name,
children,
attributes,
_is_static: false,
key: None,
}))
}
Node::Comment(_) => None,
}
}
fn ifmt_from_text(text: String) -> IfmtInput {
IfmtInput {
source: Some(LitStr::new(text.as_str(), Span::call_site())),
segments: vec![],
}
}