Explorar o código

feat: publish cli

Jonathan Kelley %!s(int64=3) %!d(string=hai) anos
pai
achega
44d7b32992

+ 1 - 2
Cargo.toml

@@ -14,10 +14,8 @@ log = "0.4.13"
 fern = { version = "0.6.0", features = ["colored"] }
 wasm-bindgen-cli-support = "0.2.78"
 anyhow = "1.0.38"
-
 serde = { version = "1.0.133", features = ["derive"] }
 serde_json = "1"
-
 fs_extra = "1.2.0"
 cargo_toml = "0.10.0"
 futures = "0.3.12"
@@ -30,6 +28,7 @@ convert_case = "0.5.0"
 structopt = "0.3.25"
 cargo_metadata = "0.14.1"
 tokio = { version = "1.15.0", features = ["full"] }
+atty = "0.2.14"
 
 [[bin]]
 path = "src/main.rs"

+ 10 - 2
README.md

@@ -1,5 +1,5 @@
 <div align="center">
-  <h1>📦✨  dioxus-Studio </h1>
+  <h1>📦✨  dioxus-cli </h1>
   <p>
     <strong>Tooling to supercharge dioxus projects</strong>
   </p>
@@ -10,6 +10,14 @@
 
 # About
 
-
 dioxus-studio (inspired by wasm-pack and webpack) is a tool to help get dioxus projects off the ground. It handles all the build, development, bundling, and publishing to make web development simple.
 
+
+## Installation
+
+```
+$ cargo install dioxus-cli
+```
+
+Now, `dioxus` is in your path.
+

+ 2 - 2
extension/src/extension.ts

@@ -13,7 +13,7 @@ export function activate(context: vscode.ExtensionContext) {
 			const selection = editor.selection;
 			const word = document.getText(selection);
 
-			const child_proc = spawn("dioxus", ["translate", "-t", word]);
+			const child_proc = spawn("dioxus", ["translate", "--source", word]);
 
 			let result = '';
 			child_proc.stdout?.on('data', data => result += data);
@@ -37,7 +37,7 @@ export function activate(context: vscode.ExtensionContext) {
 			const selection = editor.selection;
 			const word = document.getText(selection);
 
-			const child_proc = spawn("dioxus", ["translate", "-c", "-t", word]);
+			const child_proc = spawn("dioxus", ["translate", "--component", "--source", word]);
 
 			let result = '';
 			child_proc.stdout?.on('data', data => result += data);

+ 23 - 0
out.rsx

@@ -0,0 +1,23 @@
+
+use dioxus::prelude::*;
+fn component(cx: Scope) -> Element {
+    cx.render(rsx!(
+        div { 
+            h1 { 
+                "hello"
+            }
+        }
+    ))
+}
+
+use dioxus::prelude::*;
+fn component(cx: Scope) -> Element {
+    cx.render(rsx!(
+        div { 
+            h1 { 
+                "hello"
+            }
+        }
+    ))
+}
+

+ 8 - 0
packages/rsx-translate/Cargo.toml

@@ -0,0 +1,8 @@
+[package]
+name = "rsx-translate"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]

+ 8 - 0
packages/rsx-translate/src/lib.rs

@@ -0,0 +1,8 @@
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn it_works() {
+        let result = 2 + 2;
+        assert_eq!(result, 4);
+    }
+}

+ 2 - 0
src/cli/build/mod.rs

@@ -10,3 +10,5 @@ pub struct Build {
     #[structopt(flatten)]
     pub build: ConfigOptsBuild,
 }
+
+pub async fn perform_build() {}

+ 20 - 21
src/cli/mod.rs

@@ -10,38 +10,37 @@ pub mod serve;
 pub mod translate;
 pub mod watch;
 
-/// Build, bundle & ship your Rust WASM application to the web.
+/// Build, bundle, & ship your Dioxus app.
+///
+///
 #[derive(StructOpt)]
-#[structopt(name = "trunk")]
-pub struct Trunk {
+#[structopt(name = "dioxus")]
+pub struct Cli {
     #[structopt(subcommand)]
-    pub action: TrunkSubcommands,
-
-    /// Path to the Trunk config file [default: Trunk.toml]
-    #[structopt(long, parse(from_os_str), env = "TRUNK_CONFIG")]
-    pub config: Option<PathBuf>,
+    pub action: Commands,
 
     /// Enable verbose logging.
     #[structopt(short)]
     pub v: bool,
+    //
+    // // note: dioxus is still roughly compatible with trunk
+    // /// Path to the Trunk config file [default: Trunk.toml]
+    // #[structopt(long, parse(from_os_str), env = "TRUNK_CONFIG")]
+    // pub config: Option<PathBuf>,
 }
 
 #[derive(StructOpt)]
-pub enum TrunkSubcommands {
-    /// Build the Rust WASM app and all of its assets.
-    Build(build::Build),
-
+pub enum Commands {
+    // /// Build the Rust WASM app and all of its assets.
+    // Build(build::Build),
     /// Translate some source file into Dioxus code.
     Translate(translate::Translate),
+    // /// Build, watch & serve the Rust WASM app and all of its assets.
+    // Serve(serve::Serve),
 
-    /// Build, watch & serve the Rust WASM app and all of its assets.
-    ///
-    ///
-    Serve(serve::Serve),
-
-    /// Clean output artifacts.
-    Clean(clean::Clean),
+    // /// Clean output artifacts.
+    // Clean(clean::Clean),
 
-    /// Trunk config controls.
-    Config(config::Config),
+    // /// Trunk config controls.
+    // Config(config::Config),
 }

+ 144 - 3
src/cli/translate/mod.rs

@@ -1,5 +1,7 @@
-use crate::cfg::ConfigOptsBuild;
-use anyhow::Result;
+use html_parser::Dom;
+use html_parser::Node;
+use std::fmt::Write;
+use std::io::Read;
 use std::path::PathBuf;
 use structopt::StructOpt;
 
@@ -10,4 +12,143 @@ pub mod translate;
 /// Build the Rust WASM app and all of its assets.
 #[derive(Clone, Debug, StructOpt)]
 #[structopt(name = "translate")]
-pub struct Translate {}
+pub struct Translate {
+    /// Activate debug mode
+    // short and long flags (-d, --debug) will be deduced from the field's name
+    #[structopt(short, long)]
+    pub component: bool,
+
+    /// Input file
+    #[structopt(short, long)]
+    pub source: Option<String>,
+
+    /// Input file
+    #[structopt(short, long, parse(from_os_str))]
+    pub input: Option<PathBuf>,
+
+    /// Output file, stdout if not present
+    #[structopt(parse(from_os_str))]
+    pub output: Option<PathBuf>,
+}
+
+impl Translate {
+    pub fn translate(self) -> anyhow::Result<()> {
+        let Translate {
+            component: as_component,
+            input,
+            output,
+            source,
+        } = self;
+
+        let contents = input
+            .map(|f| {
+                std::fs::read_to_string(&f)
+                    .unwrap_or_else(|e| panic!("Could not read input file: {}", e))
+            })
+            .unwrap_or(source.unwrap_or_else(|| {
+                if atty::is(atty::Stream::Stdin) {
+                    panic!("No input file, source, or stdin to translate from");
+                }
+
+                let mut buffer = String::new();
+                std::io::stdin().read_to_string(&mut buffer).unwrap();
+
+                buffer.trim().to_string()
+            }));
+
+        // parse the input as html and prepare the output
+        let dom = Dom::parse(&contents)?;
+        let mut out_buf = String::new();
+
+        if as_component {
+            writeln!(out_buf, "use dioxus::prelude::*;")?;
+            writeln!(out_buf, "fn component(cx: Scope) -> Element {{")?;
+            writeln!(out_buf, "    cx.render(rsx!(")?;
+        }
+        for child in &dom.children {
+            render_child(&mut out_buf, child, if as_component { 2 } else { 0 })?;
+        }
+        if as_component {
+            writeln!(out_buf, "    ))")?;
+            writeln!(out_buf, "}}")?;
+        }
+
+        if let Some(output) = output {
+            std::fs::write(&output, out_buf)?;
+        } else {
+            print!("{}", out_buf);
+        }
+
+        Ok(())
+    }
+}
+
+fn render_child(f: &mut impl Write, child: &Node, il: u32) -> std::fmt::Result {
+    write_tabs(f, il)?;
+    match child {
+        Node::Text(t) => writeln!(f, "\"{}\"", t)?,
+        Node::Comment(e) => writeln!(f, "/* {} */", e)?,
+        Node::Element(el) => {
+            // open the tag
+            write!(f, "{} {{ ", &el.name)?;
+
+            // todo: dioxus will eventually support classnames
+            // for now, just write them with a space between each
+            let class_iter = &mut el.classes.iter();
+            if let Some(first_class) = class_iter.next() {
+                write!(f, "class: \"{}", first_class)?;
+                for next_class in class_iter {
+                    write!(f, " {}", next_class)?;
+                }
+                write!(f, "\",")?;
+            }
+            write!(f, "\n")?;
+
+            // write the attributes
+            if let Some(id) = &el.id {
+                write_tabs(f, il + 1)?;
+                writeln!(f, "id: \"{}\",", id)?;
+            }
+
+            for (name, value) in &el.attributes {
+                write_tabs(f, il + 1)?;
+
+                use convert_case::{Case, Casing};
+                if name.chars().any(|ch| ch.is_ascii_uppercase() || ch == '-') {
+                    let new_name = name.to_case(Case::Snake);
+                    match value {
+                        Some(val) => writeln!(f, "{}: \"{}\",", new_name, val)?,
+                        None => writeln!(f, "{}: \"\",", new_name)?,
+                    }
+                } else {
+                    match name.as_str() {
+                        "for" | "async" | "type" | "as" => write!(f, "r#")?,
+                        _ => {}
+                    }
+
+                    match value {
+                        Some(val) => writeln!(f, "{}: \"{}\",", name, val)?,
+                        None => writeln!(f, "{}: \"\",", name)?,
+                    }
+                }
+            }
+
+            // now the children
+            for child in &el.children {
+                render_child(f, child, il + 1)?;
+            }
+
+            // close the tag
+            write_tabs(f, il)?;
+            writeln!(f, "}}")?;
+        }
+    };
+    Ok(())
+}
+
+fn write_tabs(f: &mut impl Write, num: u32) -> std::fmt::Result {
+    for _ in 0..num {
+        write!(f, "    ")?
+    }
+    Ok(())
+}

+ 0 - 127
src/cli/translate/translate.rs

@@ -1,128 +1 @@
-use std::fmt::{Display, Formatter};
 
-use anyhow::Result;
-
-use html_parser::{Dom, Node};
-
-pub fn translate_from_html_file(target: &str) -> Result<RsxRenderer> {
-    use std::fs::File;
-    use std::io::Read;
-    let mut file = File::open(target).unwrap();
-
-    let mut contents = String::new();
-    file.read_to_string(&mut contents)
-        .expect("Failed to read your file.");
-    translate_from_html_to_rsx(&contents, true)
-}
-
-pub fn translate_from_html_to_rsx(html: &str, as_call: bool) -> Result<RsxRenderer> {
-    let contents = Dom::parse(html)?;
-    let renderer = RsxRenderer {
-        as_call,
-        dom: contents,
-    };
-    Ok(renderer)
-}
-
-pub struct RsxRenderer {
-    dom: Dom,
-    as_call: bool,
-}
-
-impl Display for RsxRenderer {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        if self.as_call {
-            writeln!(f, r##"use dioxus::prelude::*;"##)?;
-            writeln!(
-                f,
-                r##"
-fn component(cx: Scope) -> Element {{
-    cx.render(rsx!(
-"##
-            )?;
-        }
-        for child in &self.dom.children {
-            render_child(f, child, 1)?;
-        }
-        if self.as_call {
-            write!(
-                f,
-                r##"
-    )
-)            
-            "##
-            )?;
-        }
-        Ok(())
-    }
-}
-
-fn render_child(f: &mut Formatter<'_>, child: &Node, il: u32) -> std::fmt::Result {
-    write_tabs(f, il);
-    match child {
-        Node::Text(t) => writeln!(f, "\"{}\"", t)?,
-        Node::Comment(e) => writeln!(f, "/* {} */", e)?,
-        Node::Element(el) => {
-            // open the tag
-            write!(f, "{} {{ ", &el.name)?;
-
-            // todo: dioxus will eventually support classnames
-            // for now, just write them with a space between each
-            let class_iter = &mut el.classes.iter();
-            if let Some(first_class) = class_iter.next() {
-                write!(f, "class: \"{}", first_class)?;
-                for next_class in class_iter {
-                    write!(f, " {}", next_class)?;
-                }
-                write!(f, "\",")?;
-            }
-            write!(f, "\n")?;
-
-            // write the attributes
-            if let Some(id) = &el.id {
-                write_tabs(f, il + 1)?;
-                writeln!(f, "id: \"{}\",", id)?;
-            }
-
-            for (name, value) in &el.attributes {
-                write_tabs(f, il + 1)?;
-
-                use convert_case::{Case, Casing};
-                if name.chars().any(|ch| ch.is_ascii_uppercase() || ch == '-') {
-                    let new_name = name.to_case(Case::Snake);
-                    match value {
-                        Some(val) => writeln!(f, "{}: \"{}\",", new_name, val)?,
-                        None => writeln!(f, "{}: \"\",", new_name)?,
-                    }
-                } else {
-                    match name.as_str() {
-                        "for" | "async" | "type" | "as" => write!(f, "r#")?,
-                        _ => {}
-                    }
-
-                    match value {
-                        Some(val) => writeln!(f, "{}: \"{}\",", name, val)?,
-                        None => writeln!(f, "{}: \"\",", name)?,
-                    }
-                }
-            }
-
-            // now the children
-            for child in &el.children {
-                render_child(f, child, il + 1)?;
-            }
-
-            // close the tag
-            write_tabs(f, il)?;
-            writeln!(f, "}}")?;
-        }
-    };
-    Ok(())
-}
-
-fn write_tabs(f: &mut Formatter, num: u32) -> std::fmt::Result {
-    for _ in 0..num {
-        write!(f, "    ")?
-    }
-    Ok(())
-}

+ 19 - 36
src/main.rs

@@ -1,49 +1,32 @@
-use dioxus_studio::*;
+use dioxus_cli::*;
 use structopt::StructOpt;
 
 #[tokio::main]
 async fn main() -> Result<()> {
-    let args = Trunk::from_args();
+    let args = Cli::from_args();
     set_up_logging();
 
     match args.action {
-        TrunkSubcommands::Build(_) => {
-            //
+        Commands::Translate(opts) => {
+            opts.translate();
         }
 
-        TrunkSubcommands::Translate(opts) => {
-            // let TranslateOptions {
-            //     file,
-            //     text,
-            //     component,
-            // } = cfg;
-
-            // match component {
-            //     true => {
-            //         let f = helpers::to_component::convert_html_to_component(&text.unwrap())?;
-            //         println!("{}", f);
-            //     }
-            //     false => {
-            //         let renderer = match (file, text) {
-            //             (None, Some(text)) => translate::translate_from_html_to_rsx(&text, false)?,
-            //             (Some(file), None) => translate::translate_from_html_file(&file)?,
-            //             _ => panic!("Must select either file or text - not both or none!"),
-            //         };
-
-            //         println!("{}", renderer);
-            //     }
-            // }
-        }
+        // Commands::Build(_) => {
+        //     //
+        // }
 
-        TrunkSubcommands::Clean(_) => {
-            //
-        }
-        TrunkSubcommands::Config(_) => {
-            //
-        }
-        TrunkSubcommands::Serve(_) => {
-            //
-        }
+
+        // Commands::Clean(_) => {
+        //     //
+        // }
+
+        // Commands::Config(_) => {
+        //     //
+        // }
+
+        // Commands::Serve(_) => {
+        //     //
+        // }
     }
 
     Ok(())

+ 5 - 0
test.html

@@ -0,0 +1,5 @@
+<div>
+    <h1>
+        hello
+    </h1>
+</div>