Skip to content

Commit

Permalink
✨ add command to generate leptos component
Browse files Browse the repository at this point in the history
  • Loading branch information
Odonno committed Jun 25, 2023
1 parent 0206669 commit d013cfa
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,10 @@ pub enum GenerateAction {
#[clap(short, long)]
watch: bool,
},
/// Generate a new leptos component inside the `/components` folder
#[clap(aliases = vec!["c"])]
Component {
/// Name of the component to generate
name: String,
},
}
1 change: 1 addition & 0 deletions src/generate.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod component;
pub mod db;
43 changes: 43 additions & 0 deletions src/generate/component.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use anyhow::{Context, Result};
use convert_case::{Case, Casing};
use include_dir::{include_dir, Dir};
use minijinja::{context, Environment};
use std::path::{Path, PathBuf};

pub fn main(name: String) -> Result<()> {
let src_dir = Path::new("src");

let components_dir = src_dir.join("components");
ensures_folder_exists(&components_dir)?;

const TEMPLATES_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/templates/generate");

let template_content = TEMPLATES_DIR
.get_file("component.rs.jinja2")
.context("Cannot get template 'component.rs.jinja2'")?
.contents_utf8()
.context("Cannot get template 'component.rs.jinja2'")?
.to_string();

let component_name = name.to_case(Case::Pascal);
let content = Environment::new().render_str(&template_content, context! { component_name })?;

let file_name = name.to_case(Case::Snake);
let file_name = format!("{}.rs", file_name);

let component_file = components_dir.join(file_name);

std::fs::write(component_file, content)?;

println!("Component {} successfully created", name);

Ok(())
}

fn ensures_folder_exists(dir_path: &PathBuf) -> Result<()> {
if !dir_path.exists() {
fs_extra::dir::create_all(dir_path, false)?;
}

Ok(())
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ async fn main() -> Result<()> {
Action::New { name, template } => new::main(name, template),
Action::Generate { command } => match command {
GenerateAction::Db { watch } => generate::db::main(watch),
GenerateAction::Component { name } => generate::component::main(name),
},
},
}
Expand Down
13 changes: 13 additions & 0 deletions templates/generate/component.rs.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use leptos::*;

#[component]
pub fn {{ component_name }}(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
let on_click = move |_| set_count.update(|count| *count += 1);

view! { cx,
<button type="button" on:click=on_click>
{count}
</button>
}
}
1 change: 1 addition & 0 deletions tests/cli/generate.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mod component;
mod db;
56 changes: 56 additions & 0 deletions tests/cli/generate/component.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use anyhow::Result;
use assert_fs::{fixture::PathChild, prelude::PathAssert};

use crate::helpers::*;

#[test]
fn generate_new_leptos_component() -> Result<()> {
let temp_dir = assert_fs::TempDir::new()?;

{
let mut cmd = create_cmd()?;
cmd.current_dir(&temp_dir).arg("new").arg("ultime-project");

cmd.assert().success();
}

let project_dir = temp_dir.child("ultime-project");

let mut cmd = create_cmd()?;
cmd.current_dir(&project_dir)
.arg("generate")
.arg("component")
.arg("my-component");

cmd.assert()
.success()
.stdout("Component my-component successfully created\n");

let src_dir = project_dir.child("src");
let components_dir = src_dir.child("components");

assert!(components_dir.exists());

let my_component_file = components_dir.child("my_component.rs");

assert!(my_component_file.is_file());
my_component_file.assert(
r#"use leptos::*;
#[component]
pub fn MyComponent(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
let on_click = move |_| set_count.update(|count| *count += 1);
view! { cx,
<button type="button" on:click=on_click>
{count}
</button>
}
}"#,
);

temp_dir.close()?;

Ok(())
}

0 comments on commit d013cfa

Please sign in to comment.