feat: publish cli
This commit is contained in:
1 parent
12be67bf4c
commit
44d7b32992
12 files changed
+240
-191
No files matched your search
+1
-2
@@ -14,10 +14,8 @@ log = "0.4.13"
|
|||||||
fern = { version = "0.6.0", features = ["colored"] }
|
fern = { version = "0.6.0", features = ["colored"] }
|
||||||
wasm-bindgen-cli-support = "0.2.78"
|
wasm-bindgen-cli-support = "0.2.78"
|
||||||
anyhow = "1.0.38"
|
anyhow = "1.0.38"
|
||||||
|
|
||||||
serde = { version = "1.0.133", features = ["derive"] }
|
serde = { version = "1.0.133", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
|
||||||
fs_extra = "1.2.0"
|
fs_extra = "1.2.0"
|
||||||
cargo_toml = "0.10.0"
|
cargo_toml = "0.10.0"
|
||||||
futures = "0.3.12"
|
futures = "0.3.12"
|
||||||
@@ -30,6 +28,7 @@ convert_case = "0.5.0"
|
|||||||
structopt = "0.3.25"
|
structopt = "0.3.25"
|
||||||
cargo_metadata = "0.14.1"
|
cargo_metadata = "0.14.1"
|
||||||
tokio = { version = "1.15.0", features = ["full"] }
|
tokio = { version = "1.15.0", features = ["full"] }
|
||||||
|
atty = "0.2.14"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<h1>📦✨ dioxus-Studio </h1>
|
<h1>📦✨ dioxus-cli </h1>
|
||||||
<p>
|
<p>
|
||||||
<strong>Tooling to supercharge dioxus projects</strong>
|
<strong>Tooling to supercharge dioxus projects</strong>
|
||||||
</p>
|
</p>
|
||||||
@@ -10,6 +10,14 @@
|
|||||||
|
|
||||||
# About
|
# 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.
|
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.
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
const selection = editor.selection;
|
const selection = editor.selection;
|
||||||
const word = document.getText(selection);
|
const word = document.getText(selection);
|
||||||
|
|
||||||
const child_proc = spawn("dioxus", ["translate", "-t", word]);
|
const child_proc = spawn("dioxus", ["translate", "--source", word]);
|
||||||
|
|
||||||
let result = '';
|
let result = '';
|
||||||
child_proc.stdout?.on('data', data => result += data);
|
child_proc.stdout?.on('data', data => result += data);
|
||||||
@@ -37,7 +37,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
const selection = editor.selection;
|
const selection = editor.selection;
|
||||||
const word = document.getText(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 = '';
|
let result = '';
|
||||||
child_proc.stdout?.on('data', data => result += data);
|
child_proc.stdout?.on('data', data => result += data);
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let result = 2 + 2;
|
||||||
|
assert_eq!(result, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,3 +10,5 @@ pub struct Build {
|
|||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
pub build: ConfigOptsBuild,
|
pub build: ConfigOptsBuild,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn perform_build() {}
|
||||||
+20
-21
@@ -10,38 +10,37 @@ pub mod serve;
|
|||||||
pub mod translate;
|
pub mod translate;
|
||||||
pub mod watch;
|
pub mod watch;
|
||||||
|
|
||||||
/// Build, bundle & ship your Rust WASM application to the web.
|
/// Build, bundle, & ship your Dioxus app.
|
||||||
|
///
|
||||||
|
///
|
||||||
#[derive(StructOpt)]
|
#[derive(StructOpt)]
|
||||||
#[structopt(name = "trunk")]
|
#[structopt(name = "dioxus")]
|
||||||
pub struct Trunk {
|
pub struct Cli {
|
||||||
#[structopt(subcommand)]
|
#[structopt(subcommand)]
|
||||||
pub action: TrunkSubcommands,
|
pub action: Commands,
|
||||||
|
|
||||||
/// Path to the Trunk config file [default: Trunk.toml]
|
|
||||||
#[structopt(long, parse(from_os_str), env = "TRUNK_CONFIG")]
|
|
||||||
pub config: Option<PathBuf>,
|
|
||||||
|
|
||||||
/// Enable verbose logging.
|
/// Enable verbose logging.
|
||||||
#[structopt(short)]
|
#[structopt(short)]
|
||||||
pub v: bool,
|
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)]
|
#[derive(StructOpt)]
|
||||||
pub enum TrunkSubcommands {
|
pub enum Commands {
|
||||||
/// Build the Rust WASM app and all of its assets.
|
// /// Build the Rust WASM app and all of its assets.
|
||||||
Build(build::Build),
|
// Build(build::Build),
|
||||||
|
|
||||||
/// Translate some source file into Dioxus code.
|
/// Translate some source file into Dioxus code.
|
||||||
Translate(translate::Translate),
|
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.
|
// /// Clean output artifacts.
|
||||||
///
|
// Clean(clean::Clean),
|
||||||
///
|
|
||||||
Serve(serve::Serve),
|
|
||||||
|
|
||||||
/// Clean output artifacts.
|
// /// Trunk config controls.
|
||||||
Clean(clean::Clean),
|
// Config(config::Config),
|
||||||
|
|
||||||
/// Trunk config controls.
|
|
||||||
Config(config::Config),
|
|
||||||
}
|
}
|
||||||
+144
-3
@@ -1,5 +1,7 @@
|
|||||||
use crate::cfg::ConfigOptsBuild;
|
use html_parser::Dom;
|
||||||
use anyhow::Result;
|
use html_parser::Node;
|
||||||
|
use std::fmt::Write;
|
||||||
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
@@ -10,4 +12,143 @@ pub mod translate;
|
|||||||
/// Build the Rust WASM app and all of its assets.
|
/// Build the Rust WASM app and all of its assets.
|
||||||
#[derive(Clone, Debug, StructOpt)]
|
#[derive(Clone, Debug, StructOpt)]
|
||||||
#[structopt(name = "translate")]
|
#[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(())
|
||||||
|
}
|
||||||
@@ -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(())
|
|
||||||
}
|
|
||||||
+17
-34
@@ -1,49 +1,32 @@
|
|||||||
use dioxus_studio::*;
|
use dioxus_cli::*;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let args = Trunk::from_args();
|
let args = Cli::from_args();
|
||||||
set_up_logging();
|
set_up_logging();
|
||||||
|
|
||||||
match args.action {
|
match args.action {
|
||||||
TrunkSubcommands::Build(_) => {
|
Commands::Translate(opts) => {
|
||||||
//
|
opts.translate();
|
||||||
}
|
}
|
||||||
|
|
||||||
TrunkSubcommands::Translate(opts) => {
|
// Commands::Build(_) => {
|
||||||
// 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::Clean(_) => {
|
||||||
// }
|
// //
|
||||||
// }
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
TrunkSubcommands::Clean(_) => {
|
// Commands::Config(_) => {
|
||||||
//
|
// //
|
||||||
}
|
// }
|
||||||
TrunkSubcommands::Config(_) => {
|
|
||||||
//
|
// Commands::Serve(_) => {
|
||||||
}
|
// //
|
||||||
TrunkSubcommands::Serve(_) => {
|
// }
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in new issue
Block a user