Pārlūkot izejas kodu

wip: refactor out translation into its own crate

Jonathan Kelley 2 gadi atpakaļ
vecāks
revīzija
14bc007c15

+ 1 - 0
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"

+ 26 - 2
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<FormattedBlock> {
     let mut formatted_blocks = Vec::new();
     let mut last_bracket_end = 0;
@@ -93,15 +100,32 @@ pub fn fmt_file(contents: &str) -> Vec<FormattedBlock> {
     formatted_blocks
 }
 
+pub fn write_block_out(body: CallBody) -> Option<String> {
+    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<String> {
+    let body = syn::parse_str::<dioxus_rsx::CallBody>(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::<dioxus_rsx::CallBody>(block).unwrap();
-
     // Oneliner optimization
     if buf.is_short_children(&body.roots).is_some() {
         buf.write_ident(&body.roots[0]).unwrap();

+ 20 - 0
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

+ 19 - 0
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.

+ 13 - 0
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);
+}

+ 31 - 0
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<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)
+}

+ 24 - 0
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<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.comment.hash(state);
+    }
+}

+ 3 - 0
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(_)

+ 16 - 0
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! {