feat: publish cli

This commit is contained in:
Jonathan Kelley committed 2022-01-09 00:23:58 -05:00
1 parent 12be67bf4c
commit 44d7b32992
12 files changed
+240 -191

No files matched your search

+2
View File
@@ -10,3 +10,5 @@ pub struct Build {
#[structopt(flatten)]
pub build: ConfigOptsBuild,
}
pub async fn perform_build() {}
+20 -21
View File
@@ -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
View File
@@ -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(())
}
-127
View File
@@ -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(())
}