瀏覽代碼

feat: complete html to rsx rosetta

Jonathan Kelley 2 年之前
父節點
當前提交
bc3cf6501c

+ 41 - 41
Cargo.toml

@@ -18,49 +18,49 @@ members = [
     "packages/tui",
     "packages/native-core",
     "packages/native-core-macro",
+    "packages/rsx-rosetta",
     "docs/guide",
-    "packages/html-to-rsx"
 ]
 
-# This is a "virtual package"
-# It is not meant to be published, but is used so "cargo run --example XYZ" works properly
-[package]
-name = "dioxus-examples"
-version = "0.0.0"
-authors = ["Jonathan Kelley"]
-edition = "2021"
-description = "Top level crate for the Dioxus repository"
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/DioxusLabs/dioxus/"
-homepage = "https://dioxuslabs.com"
-documentation = "https://dioxuslabs.com"
-keywords = ["dom", "ui", "gui", "react", "wasm"]
-rust-version = "1.60.0"
-publish = false
+# # This is a "virtual package"
+# # It is not meant to be published, but is used so "cargo run --example XYZ" works properly
+# [package]
+# name = "dioxus-examples"
+# version = "0.0.0"
+# authors = ["Jonathan Kelley"]
+# edition = "2021"
+# description = "Top level crate for the Dioxus repository"
+# license = "MIT OR Apache-2.0"
+# repository = "https://github.com/DioxusLabs/dioxus/"
+# homepage = "https://dioxuslabs.com"
+# documentation = "https://dioxuslabs.com"
+# keywords = ["dom", "ui", "gui", "react", "wasm"]
+# rust-version = "1.60.0"
+# publish = false
 
-[dev-dependencies]
-dioxus = { path = "./packages/dioxus" }
-dioxus-desktop = { path = "./packages/desktop" }
-dioxus-ssr = { path = "./packages/ssr" }
-dioxus-router = { path = "./packages/router" }
-fermi = { path = "./packages/fermi" }
-futures-util = "0.3.21"
-log = "0.4.14"
-num-format = "0.4.0"
-separator = "0.4.1"
-serde = { version = "1.0.136", features = ["derive"] }
-im-rc = "15.0.0"
-anyhow = "1.0.53"
-serde_json = "1.0.79"
-rand = { version = "0.8.4", features = ["small_rng"] }
-tokio = { version = "1.16.1", features = ["full"] }
-reqwest = { version = "0.11.9", features = ["json"] }
-fern = { version = "0.6.0", features = ["colored"] }
-thiserror = "1.0.30"
-env_logger = "0.9.0"
-simple_logger = "4.0.0"
+# [dev-dependencies]
+# dioxus = { path = "./packages/dioxus" }
+# dioxus-desktop = { path = "./packages/desktop" }
+# dioxus-ssr = { path = "./packages/ssr" }
+# dioxus-router = { path = "./packages/router" }
+# fermi = { path = "./packages/fermi" }
+# futures-util = "0.3.21"
+# log = "0.4.14"
+# num-format = "0.4.0"
+# separator = "0.4.1"
+# serde = { version = "1.0.136", features = ["derive"] }
+# im-rc = "15.0.0"
+# anyhow = "1.0.53"
+# serde_json = "1.0.79"
+# rand = { version = "0.8.4", features = ["small_rng"] }
+# tokio = { version = "1.16.1", features = ["full"] }
+# reqwest = { version = "0.11.9", features = ["json"] }
+# fern = { version = "0.6.0", features = ["colored"] }
+# thiserror = "1.0.30"
+# env_logger = "0.9.0"
+# simple_logger = "4.0.0"
 
-[profile.release]
-opt-level = 3
-lto = true
-debug = true
+# [profile.release]
+# opt-level = 3
+# lto = true
+# debug = true

+ 1 - 1
packages/autofmt/src/lib.rs

@@ -102,7 +102,7 @@ pub fn fmt_file(contents: &str) -> Vec<FormattedBlock> {
 
 pub fn write_block_out(body: CallBody) -> Option<String> {
     let mut buf = Buffer {
-        src: vec![],
+        src: vec!["".to_string()],
         indent: 0,
         ..Buffer::default()
     };

+ 0 - 13
packages/html-to-rsx/examples/html.rs

@@ -1,13 +0,0 @@
-use html_parser::Dom;
-
-fn main() {
-    let html = "hello world!";
-
-    let dom = Dom::parse(html).unwrap();
-
-    let body = rsx_rosetta::convert_from_html(dom);
-
-    let out = dioxus_autofmt::write_block_out(body).unwrap();
-
-    dbg!(out);
-}

+ 0 - 31
packages/html-to-rsx/src/lib.rs

@@ -1,31 +0,0 @@
-use dioxus_rsx::{BodyNode, CallBody, IfmtInput};
-use html_parser::{Dom, Node};
-use proc_macro2::Span;
-use syn::LitStr;
-
-#[derive(thiserror::Error, Debug)]
-pub enum ConvertError {}
-
-pub fn convert_from_html(html: Dom) -> CallBody {
-    let roots = html
-        .children
-        .into_iter()
-        .map(|f| create_body_node_from_node(f))
-        .filter_map(|f| f)
-        .collect();
-
-    CallBody { roots }
-}
-
-fn create_body_node_from_node(node: Node) -> Option<BodyNode> {
-    let res = match node {
-        Node::Text(text) => BodyNode::Text(IfmtInput {
-            source: Some(LitStr::new(text.as_str(), Span::call_site())),
-            segments: vec![],
-        }),
-        Node::Element(_) => todo!(),
-        Node::Comment(_) => return None,
-    };
-
-    Some(res)
-}

+ 1 - 1
packages/html-to-rsx/Cargo.toml → packages/rsx-rosetta/Cargo.toml

@@ -12,7 +12,7 @@ html_parser = "0.6.3"
 proc-macro2 = "1.0.49"
 quote = "1.0.23"
 syn = { version = "1.0.107", features = ["full"] }
-thiserror = "1.0.38"
+convert_case = "0.5.0"
 
 # [features]
 # default = ["html"]

+ 0 - 0
packages/html-to-rsx/README.md → packages/rsx-rosetta/README.md


+ 24 - 0
packages/rsx-rosetta/examples/html.rs

@@ -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 - 0
packages/rsx-rosetta/src/lib.rs

@@ -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![],
+    }
+}