From 14bc007c15cc6406010a940fa2aab2cfbc9d3964 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 28 Dec 2022 11:51:41 -0500 Subject: [PATCH 1/9] wip: refactor out translation into its own crate --- Cargo.toml | 1 + packages/autofmt/src/lib.rs | 28 ++++++++++++++++++++++-- packages/html-to-rsx/Cargo.toml | 20 +++++++++++++++++ packages/html-to-rsx/README.md | 19 ++++++++++++++++ packages/html-to-rsx/examples/html.rs | 13 +++++++++++ packages/html-to-rsx/src/lib.rs | 31 +++++++++++++++++++++++++++ packages/rsx/src/comments.rs | 24 +++++++++++++++++++++ packages/rsx/src/lib.rs | 3 +++ packages/rsx/src/node.rs | 16 ++++++++++++++ 9 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 packages/html-to-rsx/Cargo.toml create mode 100644 packages/html-to-rsx/README.md create mode 100644 packages/html-to-rsx/examples/html.rs create mode 100644 packages/html-to-rsx/src/lib.rs create mode 100644 packages/rsx/src/comments.rs diff --git a/Cargo.toml b/Cargo.toml index 5955451f8..044421f24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "packages/native-core", "packages/native-core-macro", "docs/guide", + "packages/html-to-rsx" ] # This is a "virtual package" diff --git a/packages/autofmt/src/lib.rs b/packages/autofmt/src/lib.rs index aca9f64b0..a19fe54fe 100644 --- a/packages/autofmt/src/lib.rs +++ b/packages/autofmt/src/lib.rs @@ -1,3 +1,5 @@ +use dioxus_rsx::CallBody; + use crate::buffer::*; use crate::util::*; @@ -31,6 +33,11 @@ pub struct FormattedBlock { /// Format a file into a list of `FormattedBlock`s to be applied by an IDE for autoformatting. /// /// This function expects a complete file, not just a block of code. To format individual rsx! blocks, use fmt_block instead. +/// +/// The point here is to provide precise modifications of a source file so an accompanying IDE tool can map these changes +/// back to the file precisely. +/// +/// Nested blocks of RSX will be handled automatically pub fn fmt_file(contents: &str) -> Vec { let mut formatted_blocks = Vec::new(); let mut last_bracket_end = 0; @@ -93,15 +100,32 @@ pub fn fmt_file(contents: &str) -> Vec { formatted_blocks } +pub fn write_block_out(body: CallBody) -> Option { + let mut buf = Buffer { + src: vec![], + indent: 0, + ..Buffer::default() + }; + + // Oneliner optimization + if buf.is_short_children(&body.roots).is_some() { + buf.write_ident(&body.roots[0]).unwrap(); + } else { + buf.write_body_indented(&body.roots).unwrap(); + } + + buf.consume() +} + pub fn fmt_block(block: &str, indent_level: usize) -> Option { + let body = syn::parse_str::(block).unwrap(); + let mut buf = Buffer { src: block.lines().map(|f| f.to_string()).collect(), indent: indent_level, ..Buffer::default() }; - let body = syn::parse_str::(block).unwrap(); - // Oneliner optimization if buf.is_short_children(&body.roots).is_some() { buf.write_ident(&body.roots[0]).unwrap(); diff --git a/packages/html-to-rsx/Cargo.toml b/packages/html-to-rsx/Cargo.toml new file mode 100644 index 000000000..3ff43c3b3 --- /dev/null +++ b/packages/html-to-rsx/Cargo.toml @@ -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"] } +thiserror = "1.0.38" + +# [features] +# default = ["html"] + +# eventually more output options diff --git a/packages/html-to-rsx/README.md b/packages/html-to-rsx/README.md new file mode 100644 index 000000000..35f86d00a --- /dev/null +++ b/packages/html-to-rsx/README.md @@ -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. diff --git a/packages/html-to-rsx/examples/html.rs b/packages/html-to-rsx/examples/html.rs new file mode 100644 index 000000000..7f5031857 --- /dev/null +++ b/packages/html-to-rsx/examples/html.rs @@ -0,0 +1,13 @@ +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); +} diff --git a/packages/html-to-rsx/src/lib.rs b/packages/html-to-rsx/src/lib.rs new file mode 100644 index 000000000..46d4017fb --- /dev/null +++ b/packages/html-to-rsx/src/lib.rs @@ -0,0 +1,31 @@ +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 { + 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) +} diff --git a/packages/rsx/src/comments.rs b/packages/rsx/src/comments.rs new file mode 100644 index 000000000..3c999eed9 --- /dev/null +++ b/packages/rsx/src/comments.rs @@ -0,0 +1,24 @@ +use std::hash::Hash; + +use proc_macro2::Span; + +// A form of whitespace +#[derive(Debug, Clone)] +pub struct UserComment { + pub span: Span, + pub comment: String, +} + +impl PartialEq for UserComment { + fn eq(&self, other: &Self) -> bool { + self.comment == other.comment + } +} + +impl Eq for UserComment {} + +impl Hash for UserComment { + fn hash(&self, state: &mut H) { + self.comment.hash(state); + } +} diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index d22b122e9..4b33a71c8 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -13,6 +13,7 @@ #[macro_use] mod errors; +mod comments; mod component; mod element; pub mod hot_reload; @@ -296,6 +297,8 @@ impl DynamicMapping { BodyNode::Text(text) if text.is_static() => {} + BodyNode::Comment(_) => {} + BodyNode::RawExpr(_) | BodyNode::Text(_) | BodyNode::ForLoop(_) diff --git a/packages/rsx/src/node.rs b/packages/rsx/src/node.rs index ef76d14ff..eb2f95a42 100644 --- a/packages/rsx/src/node.rs +++ b/packages/rsx/src/node.rs @@ -1,3 +1,5 @@ +use crate::comments::UserComment; + use super::*; use proc_macro2::{Span, TokenStream as TokenStream2}; @@ -16,6 +18,17 @@ Parse -> component() -> "text {with_args}" -> (0..10).map(|f| rsx!("asd")), // <--- notice the comma - must be a complete expr +-> // some comment here (no support for slash asterisk comments - those get deleted completely) + + + +div { + // Comment + div { // a comment here because it shares the line + + } +} + */ #[derive(PartialEq, Eq, Clone, Debug, Hash)] pub enum BodyNode { @@ -25,6 +38,7 @@ pub enum BodyNode { IfChain(ExprIf), Text(IfmtInput), RawExpr(Expr), + Comment(UserComment), } impl BodyNode { @@ -40,6 +54,7 @@ impl BodyNode { BodyNode::RawExpr(exp) => exp.span(), BodyNode::ForLoop(fl) => fl.for_token.span(), BodyNode::IfChain(f) => f.if_token.span(), + BodyNode::Comment(c) => c.span, } } } @@ -128,6 +143,7 @@ impl Parse for BodyNode { impl ToTokens for BodyNode { fn to_tokens(&self, tokens: &mut TokenStream2) { match &self { + BodyNode::Comment(_) => {} BodyNode::Element(el) => el.to_tokens(tokens), BodyNode::Component(comp) => comp.to_tokens(tokens), BodyNode::Text(txt) => tokens.append_all(quote! { From d22577082ceff5f579a3d8ca30e7562db7ad3a73 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 28 Dec 2022 12:05:13 -0500 Subject: [PATCH 2/9] chore: remove comment from syn tree --- packages/rsx/src/lib.rs | 2 -- packages/rsx/src/node.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 4b33a71c8..7946a7132 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -297,8 +297,6 @@ impl DynamicMapping { BodyNode::Text(text) if text.is_static() => {} - BodyNode::Comment(_) => {} - BodyNode::RawExpr(_) | BodyNode::Text(_) | BodyNode::ForLoop(_) diff --git a/packages/rsx/src/node.rs b/packages/rsx/src/node.rs index eb2f95a42..c83655cb0 100644 --- a/packages/rsx/src/node.rs +++ b/packages/rsx/src/node.rs @@ -38,7 +38,6 @@ pub enum BodyNode { IfChain(ExprIf), Text(IfmtInput), RawExpr(Expr), - Comment(UserComment), } impl BodyNode { @@ -54,7 +53,6 @@ impl BodyNode { BodyNode::RawExpr(exp) => exp.span(), BodyNode::ForLoop(fl) => fl.for_token.span(), BodyNode::IfChain(f) => f.if_token.span(), - BodyNode::Comment(c) => c.span, } } } @@ -143,7 +141,6 @@ impl Parse for BodyNode { impl ToTokens for BodyNode { fn to_tokens(&self, tokens: &mut TokenStream2) { match &self { - BodyNode::Comment(_) => {} BodyNode::Element(el) => el.to_tokens(tokens), BodyNode::Component(comp) => comp.to_tokens(tokens), BodyNode::Text(txt) => tokens.append_all(quote! { From bc3cf6501c5c916d053549727a6df7389015adbe Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 28 Dec 2022 16:22:20 -0500 Subject: [PATCH 3/9] feat: complete html to rsx rosetta --- Cargo.toml | 82 ++++++++--------- packages/autofmt/src/lib.rs | 2 +- packages/html-to-rsx/examples/html.rs | 13 --- packages/html-to-rsx/src/lib.rs | 31 ------- .../{html-to-rsx => rsx-rosetta}/Cargo.toml | 2 +- .../{html-to-rsx => rsx-rosetta}/README.md | 0 packages/rsx-rosetta/examples/html.rs | 24 +++++ packages/rsx-rosetta/src/lib.rs | 92 +++++++++++++++++++ 8 files changed, 159 insertions(+), 87 deletions(-) delete mode 100644 packages/html-to-rsx/examples/html.rs delete mode 100644 packages/html-to-rsx/src/lib.rs rename packages/{html-to-rsx => rsx-rosetta}/Cargo.toml (94%) rename packages/{html-to-rsx => rsx-rosetta}/README.md (100%) create mode 100644 packages/rsx-rosetta/examples/html.rs create mode 100644 packages/rsx-rosetta/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 044421f24..51b4ac829 100644 --- a/Cargo.toml +++ b/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 diff --git a/packages/autofmt/src/lib.rs b/packages/autofmt/src/lib.rs index a19fe54fe..37e5e1b33 100644 --- a/packages/autofmt/src/lib.rs +++ b/packages/autofmt/src/lib.rs @@ -102,7 +102,7 @@ pub fn fmt_file(contents: &str) -> Vec { pub fn write_block_out(body: CallBody) -> Option { let mut buf = Buffer { - src: vec![], + src: vec!["".to_string()], indent: 0, ..Buffer::default() }; diff --git a/packages/html-to-rsx/examples/html.rs b/packages/html-to-rsx/examples/html.rs deleted file mode 100644 index 7f5031857..000000000 --- a/packages/html-to-rsx/examples/html.rs +++ /dev/null @@ -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); -} diff --git a/packages/html-to-rsx/src/lib.rs b/packages/html-to-rsx/src/lib.rs deleted file mode 100644 index 46d4017fb..000000000 --- a/packages/html-to-rsx/src/lib.rs +++ /dev/null @@ -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 { - 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) -} diff --git a/packages/html-to-rsx/Cargo.toml b/packages/rsx-rosetta/Cargo.toml similarity index 94% rename from packages/html-to-rsx/Cargo.toml rename to packages/rsx-rosetta/Cargo.toml index 3ff43c3b3..2def4e7c8 100644 --- a/packages/html-to-rsx/Cargo.toml +++ b/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"] diff --git a/packages/html-to-rsx/README.md b/packages/rsx-rosetta/README.md similarity index 100% rename from packages/html-to-rsx/README.md rename to packages/rsx-rosetta/README.md diff --git a/packages/rsx-rosetta/examples/html.rs b/packages/rsx-rosetta/examples/html.rs new file mode 100644 index 000000000..4a64b6c57 --- /dev/null +++ b/packages/rsx-rosetta/examples/html.rs @@ -0,0 +1,24 @@ +use html_parser::Dom; + +fn main() { + let html = r#" +
+
hello world!
+
hello world!
+
hello world!
+
hello world!
+
hello world!
+
hello world!
+ hello world! +
+ "# + .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); +} diff --git a/packages/rsx-rosetta/src/lib.rs b/packages/rsx-rosetta/src/lib.rs new file mode 100644 index 000000000..1d1248852 --- /dev/null +++ b/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 { + 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![], + } +} From c890051f875f84b40c377846738d636a3ab31eee Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 28 Dec 2022 16:23:05 -0500 Subject: [PATCH 4/9] chore: add back examples --- Cargo.toml | 80 +++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 51b4ac829..606aef6be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,45 +22,45 @@ members = [ "docs/guide", ] -# # 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 From d3c3c41d9efcf698be055afa18169d0272cf5629 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 28 Dec 2022 16:39:24 -0500 Subject: [PATCH 5/9] chore: remove comments module --- packages/rsx/src/comments.rs | 24 ------------------------ packages/rsx/src/lib.rs | 1 - packages/rsx/src/node.rs | 2 -- 3 files changed, 27 deletions(-) delete mode 100644 packages/rsx/src/comments.rs diff --git a/packages/rsx/src/comments.rs b/packages/rsx/src/comments.rs deleted file mode 100644 index 3c999eed9..000000000 --- a/packages/rsx/src/comments.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::hash::Hash; - -use proc_macro2::Span; - -// A form of whitespace -#[derive(Debug, Clone)] -pub struct UserComment { - pub span: Span, - pub comment: String, -} - -impl PartialEq for UserComment { - fn eq(&self, other: &Self) -> bool { - self.comment == other.comment - } -} - -impl Eq for UserComment {} - -impl Hash for UserComment { - fn hash(&self, state: &mut H) { - self.comment.hash(state); - } -} diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 7946a7132..d22b122e9 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -13,7 +13,6 @@ #[macro_use] mod errors; -mod comments; mod component; mod element; pub mod hot_reload; diff --git a/packages/rsx/src/node.rs b/packages/rsx/src/node.rs index c83655cb0..d7dfbf0d6 100644 --- a/packages/rsx/src/node.rs +++ b/packages/rsx/src/node.rs @@ -1,5 +1,3 @@ -use crate::comments::UserComment; - use super::*; use proc_macro2::{Span, TokenStream as TokenStream2}; From bc707db8325f9d95e3f94e962b1f378a6a04d0de Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 29 Dec 2022 00:46:02 -0500 Subject: [PATCH 6/9] chore: make clippy happy and limit workspace checks --- .vscode/settings.json | 3 ++- packages/rsx-rosetta/src/lib.rs | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 819ffec5d..ebd52887e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,6 @@ "editor.formatOnSave": true, "[toml]": { "editor.formatOnSave": false - } + }, + "rust-analyzer.checkOnSave.allTargets": false, } diff --git a/packages/rsx-rosetta/src/lib.rs b/packages/rsx-rosetta/src/lib.rs index 1d1248852..83f79883c 100644 --- a/packages/rsx-rosetta/src/lib.rs +++ b/packages/rsx-rosetta/src/lib.rs @@ -8,8 +8,7 @@ pub fn convert_from_html(dom: Dom) -> CallBody { roots: dom .children .into_iter() - .map(|f| create_body_node_from_node(f)) - .filter_map(|f| f) + .filter_map(create_body_node_from_node) .collect(), } } @@ -37,7 +36,7 @@ fn create_body_node_from_node(node: Node) -> Option { ElementAttrNamed { attr: ElementAttr::AttrText { name: ident, - value: ifmt_from_text(value.unwrap_or("false".to_string())), + value: ifmt_from_text(value.unwrap_or_else(|| "false".to_string())), }, el_name: el_name.clone(), } @@ -68,8 +67,7 @@ fn create_body_node_from_node(node: Node) -> Option { let children = el .children .into_iter() - .map(|f| create_body_node_from_node(f)) - .filter_map(|f| f) + .filter_map(create_body_node_from_node) .collect(); Some(BodyNode::Element(Element { From 138976659645a53942790255fce72085014b5ef2 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 29 Dec 2022 00:55:04 -0500 Subject: [PATCH 7/9] chore: take domtree by reference --- packages/rsx-rosetta/examples/html.rs | 2 +- packages/rsx-rosetta/src/lib.rs | 36 ++++++++++++++------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/rsx-rosetta/examples/html.rs b/packages/rsx-rosetta/examples/html.rs index 4a64b6c57..ef3006f31 100644 --- a/packages/rsx-rosetta/examples/html.rs +++ b/packages/rsx-rosetta/examples/html.rs @@ -16,7 +16,7 @@ fn main() { let dom = Dom::parse(html).unwrap(); - let body = rsx_rosetta::convert_from_html(dom); + let body = rsx_rosetta::rsx_from_html(dom); let out = dioxus_autofmt::write_block_out(body).unwrap(); diff --git a/packages/rsx-rosetta/src/lib.rs b/packages/rsx-rosetta/src/lib.rs index 83f79883c..440a41ebc 100644 --- a/packages/rsx-rosetta/src/lib.rs +++ b/packages/rsx-rosetta/src/lib.rs @@ -1,30 +1,30 @@ +use convert_case::{Case, Casing}; 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 { +/// Convert an HTML DOM tree into an RSX CallBody +pub fn rsx_from_html(dom: &Dom) -> CallBody { CallBody { roots: dom .children - .into_iter() + .iter() .filter_map(create_body_node_from_node) .collect(), } } -fn create_body_node_from_node(node: Node) -> Option { +fn create_body_node_from_node(node: &Node) -> Option { 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() + .iter() .map(|(name, value)| { let ident = if matches!(name.as_str(), "for" | "async" | "type" | "as") { Ident::new_raw(name.as_str(), Span::call_site()) @@ -34,11 +34,11 @@ fn create_body_node_from_node(node: Node) -> Option { }; ElementAttrNamed { - attr: ElementAttr::AttrText { - name: ident, - value: ifmt_from_text(value.unwrap_or_else(|| "false".to_string())), - }, el_name: el_name.clone(), + attr: ElementAttr::AttrText { + value: ifmt_from_text(value.as_deref().unwrap_or("false")), + name: ident, + }, } }) .collect(); @@ -46,27 +46,27 @@ fn create_body_node_from_node(node: Node) -> Option { let class = el.classes.join(" "); if !class.is_empty() { attributes.push(ElementAttrNamed { + el_name: el_name.clone(), attr: ElementAttr::AttrText { name: Ident::new("class", Span::call_site()), - value: ifmt_from_text(class), + value: ifmt_from_text(&class), }, - el_name: el_name.clone(), }); } - if let Some(id) = el.id { + if let Some(id) = &el.id { attributes.push(ElementAttrNamed { + el_name: el_name.clone(), 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() + .iter() .filter_map(create_body_node_from_node) .collect(); @@ -78,13 +78,15 @@ fn create_body_node_from_node(node: Node) -> Option { key: None, })) } + + // We ignore comments Node::Comment(_) => None, } } -fn ifmt_from_text(text: String) -> IfmtInput { +fn ifmt_from_text(text: &str) -> IfmtInput { IfmtInput { - source: Some(LitStr::new(text.as_str(), Span::call_site())), + source: Some(LitStr::new(text, Span::call_site())), segments: vec![], } } From ecb154db6f8e23fed16b7565b4ade906f1b7c23a Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 29 Dec 2022 00:56:23 -0500 Subject: [PATCH 8/9] chore: rename method --- packages/rsx-rosetta/src/lib.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/rsx-rosetta/src/lib.rs b/packages/rsx-rosetta/src/lib.rs index 440a41ebc..430ab54dc 100644 --- a/packages/rsx-rosetta/src/lib.rs +++ b/packages/rsx-rosetta/src/lib.rs @@ -7,15 +7,14 @@ use syn::LitStr; /// Convert an HTML DOM tree into an RSX CallBody pub fn rsx_from_html(dom: &Dom) -> CallBody { CallBody { - roots: dom - .children - .iter() - .filter_map(create_body_node_from_node) - .collect(), + roots: dom.children.iter().filter_map(rsx_node_from_html).collect(), } } -fn create_body_node_from_node(node: &Node) -> Option { +/// Convert an HTML Node into an RSX BodyNode +/// +/// If the node is a comment, it will be ignored since RSX doesn't support comments +pub fn rsx_node_from_html(node: &Node) -> Option { match node { Node::Text(text) => Some(BodyNode::Text(ifmt_from_text(text))), Node::Element(el) => { @@ -64,11 +63,7 @@ fn create_body_node_from_node(node: &Node) -> Option { }); } - let children = el - .children - .iter() - .filter_map(create_body_node_from_node) - .collect(); + let children = el.children.iter().filter_map(rsx_node_from_html).collect(); Some(BodyNode::Element(Element { name: el_name, From 5c63ae4b5db9c822febdb0322436077749260aa1 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 29 Dec 2022 01:02:07 -0500 Subject: [PATCH 9/9] chore: dont panic --- packages/autofmt/src/lib.rs | 2 +- packages/rsx/src/node.rs | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/autofmt/src/lib.rs b/packages/autofmt/src/lib.rs index 37e5e1b33..a5da71c9b 100644 --- a/packages/autofmt/src/lib.rs +++ b/packages/autofmt/src/lib.rs @@ -118,7 +118,7 @@ pub fn write_block_out(body: CallBody) -> Option { } pub fn fmt_block(block: &str, indent_level: usize) -> Option { - let body = syn::parse_str::(block).unwrap(); + let body = syn::parse_str::(block).ok()?; let mut buf = Buffer { src: block.lines().map(|f| f.to_string()).collect(), diff --git a/packages/rsx/src/node.rs b/packages/rsx/src/node.rs index d7dfbf0d6..ef76d14ff 100644 --- a/packages/rsx/src/node.rs +++ b/packages/rsx/src/node.rs @@ -16,17 +16,6 @@ Parse -> component() -> "text {with_args}" -> (0..10).map(|f| rsx!("asd")), // <--- notice the comma - must be a complete expr --> // some comment here (no support for slash asterisk comments - those get deleted completely) - - - -div { - // Comment - div { // a comment here because it shares the line - - } -} - */ #[derive(PartialEq, Eq, Clone, Debug, Hash)] pub enum BodyNode {