diff --git a/loco-new/base_template/Cargo.toml.t b/loco-new/base_template/Cargo.toml.t index 5f14ece4f..cbf0286fb 100644 --- a/loco-new/base_template/Cargo.toml.t +++ b/loco-new/base_template/Cargo.toml.t @@ -48,10 +48,12 @@ include_dir = { version = "0.7" } {%- endif %} {%- if settings.asset %} +{%- if settings.asset.kind == "server" %} # view engine i18n fluent-templates = { version = "0.8.0", features = ["tera"] } unic-langid = { version = "0.9.4" } # /view engine +{%- endif %} axum-extra = { version = "0.10", features = ["form"] } {%- endif %} diff --git a/loco-new/setup.rhai b/loco-new/setup.rhai index 7622b222d..070b284c8 100644 --- a/loco-new/setup.rhai +++ b/loco-new/setup.rhai @@ -84,7 +84,7 @@ if db { // ===================== // Initializers Support // ===================== -if initializers { +if settings.initializers.view_engine { gen.copy_file("src/initializers/view_engine.rs"); // Template for view engine initializer } @@ -121,20 +121,16 @@ if background { } // ===================== -// Asset Management +// Server side // ===================== -// Adds asset directory if assets are configured in the app. - -if asset { - gen.copy_dir("assets"); // Static assets directory +if settings.asset.is_server_side { + gen.copy_dir("assets"); // Static assets directory } - // ===================== // Client side // ===================== - -if settings.clientside { +if settings.asset.is_client_side { gen.copy_dir("frontend"); gen.create_file("frontend/dist/index.html", "this is a placeholder. please run your frontend build (npm build)"); } diff --git a/loco-new/src/generator/mod.rs b/loco-new/src/generator/mod.rs index a477ab1b6..ca7b1d16b 100644 --- a/loco-new/src/generator/mod.rs +++ b/loco-new/src/generator/mod.rs @@ -7,8 +7,16 @@ pub mod template; use std::sync::Arc; use include_dir::{include_dir, Dir}; -use rhai::{Engine, Scope}; - +use rhai::{ + export_module, exported_module, + plugin::{ + Dynamic, FnNamespace, FuncRegistration, Module, NativeCallContext, PluginFunc, RhaiResult, + TypeId, + }, + Engine, Scope, +}; + +use crate::wizard::AssetsOption; use crate::{settings, OS}; static APP_TEMPLATE: Dir<'_> = include_dir!("base_template"); @@ -68,7 +76,12 @@ impl Generator { ); engine .build_type::() - .build_type::() + .register_type_with_name::>("Option") + .register_type_with_name::>("Option") + .register_static_module( + "rhai_settings_extensions", + exported_module!(rhai_settings_extensions).into(), + ) .register_fn("copy_file", Self::copy_file) .register_fn("create_file", Self::create_file) .register_fn("copy_files", Self::copy_files) @@ -232,6 +245,36 @@ impl Generator { } } +/// This module provides extensions to the [`rhai`] scripting language, +/// enabling ergonomic access to specific. +/// These extensions allow scripts to interact with internal settings +/// in a controlled and expressive way. +#[export_module] +mod rhai_settings_extensions { + + /// Retrieves the value of the `view_engine` field from the [`settings::Initializers`] struct. + #[rhai_fn(global, get = "view_engine", pure)] + pub fn view_engine(initializers: &mut Option) -> bool { + initializers.as_ref().is_some_and(|i| i.view_engine) + } + + /// Checks if the rendering method is set to client-side rendering. + #[rhai_fn(global, get = "is_client_side", pure)] + pub fn is_client_side(rendering_method: &mut Option) -> bool { + rendering_method + .as_ref() + .is_some_and(|r| matches!(r.kind, AssetsOption::Clientside)) + } + + /// Checks if the rendering method is set to server-side rendering. + #[rhai_fn(global, get = "is_server_side", pure)] + pub fn is_server_side(rendering_method: &mut Option) -> bool { + rendering_method + .as_ref() + .is_some_and(|r| matches!(r.kind, AssetsOption::Serverside)) + } +} + #[cfg(test)] mod tests { use executer::MockExecuter; diff --git a/loco-new/src/settings.rs b/loco-new/src/settings.rs index b142b09be..18530fe86 100644 --- a/loco-new/src/settings.rs +++ b/loco-new/src/settings.rs @@ -21,7 +21,6 @@ pub struct Settings { pub asset: Option, pub auth: bool, pub mailer: bool, - pub clientside: bool, pub initializers: Option, pub features: Features, pub loco_version_text: String, @@ -80,8 +79,7 @@ impl Settings { db: prompt_selection.db.clone().into(), background: prompt_selection.background.clone().into(), asset: prompt_selection.asset.clone().into(), - clientside: prompt_selection.asset.enable(), - initializers: if prompt_selection.asset.enable() { + initializers: if prompt_selection.asset == AssetsOption::Serverside { Some(Initializers { view_engine: true }) } else { None @@ -103,7 +101,6 @@ impl Default for Settings { asset: Default::default(), auth: Default::default(), mailer: Default::default(), - clientside: Default::default(), initializers: Default::default(), features: Default::default(), loco_version_text: get_loco_version_text(), diff --git a/loco-new/tests/templates/snapshots/r#mod__templates__asset__cargo_dependencies_Clientside.snap b/loco-new/tests/templates/snapshots/r#mod__templates__asset__cargo_dependencies_Clientside.snap index a75738380..bb43f8703 100644 --- a/loco-new/tests/templates/snapshots/r#mod__templates__asset__cargo_dependencies_Clientside.snap +++ b/loco-new/tests/templates/snapshots/r#mod__templates__asset__cargo_dependencies_Clientside.snap @@ -2,4 +2,4 @@ source: tests/templates/asset.rs expression: "content.get(\"dependencies\").unwrap()" --- -{ async-trait = { version = "0.1.74" }, axum = { version = "0.8.1" }, axum-extra = { features = ["form"], version = "0.10" }, fluent-templates = { features = ["tera"], version = "0.8.0" }, loco-rs = { workspace = true }, regex = { version = "1.11.1" }, serde = { features = ["derive"], version = "1" }, serde_json = { version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing = { version = "0.1.40" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" }, unic-langid = { version = "0.9.4" } } +{ async-trait = { version = "0.1.74" }, axum = { version = "0.8.1" }, axum-extra = { features = ["form"], version = "0.10" }, loco-rs = { workspace = true }, regex = { version = "1.11.1" }, serde = { features = ["derive"], version = "1" }, serde_json = { version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing = { version = "0.1.40" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } } diff --git a/loco-new/tests/wizard/new.rs b/loco-new/tests/wizard/new.rs index e8669ee2c..e90818df9 100644 --- a/loco-new/tests/wizard/new.rs +++ b/loco-new/tests/wizard/new.rs @@ -7,61 +7,41 @@ use loco::{ }; use std::{collections::HashMap, path::PathBuf, process::Output, sync::Arc}; -#[cfg(feature = "test-wizard")] -#[rstest::rstest] -fn test_all_combinations( - #[values(DBOption::None, DBOption::Sqlite)] db: DBOption, - #[values( - BackgroundOption::Async, - BackgroundOption::Queue, - BackgroundOption::Blocking, - BackgroundOption::None - )] - background: BackgroundOption, - #[values(AssetsOption::Serverside, AssetsOption::Clientside, AssetsOption::None)] - asset: AssetsOption, -) { - test_combination(db, background, asset, false); -} +// #[cfg(feature = "test-wizard")] +// #[rstest::rstest] +// fn test_all_combinations( +// #[values(DBOption::None, DBOption::Sqlite)] db: DBOption, +// #[values( +// BackgroundOption::Async, +// BackgroundOption::Queue, +// BackgroundOption::Blocking, +// BackgroundOption::None +// )] +// background: BackgroundOption, +// #[values(AssetsOption::Serverside, AssetsOption::Clientside, AssetsOption::None)] +// asset: AssetsOption, +// ) { +// test_combination(db, background, asset, true); +// } // when running locally set LOCO_DEV_MODE_PATH= -#[test] -fn test_starter_combinations() { - // lightweight service - test_combination( - DBOption::None, - BackgroundOption::None, - AssetsOption::None, - true, - ); - // REST API - test_combination( - DBOption::Sqlite, - BackgroundOption::Async, - AssetsOption::None, - true, - ); - // SaaS, serverside - test_combination( - DBOption::Sqlite, - BackgroundOption::Async, - AssetsOption::Serverside, - true, - ); - // SaaS, clientside - test_combination( - DBOption::Sqlite, - BackgroundOption::Async, - AssetsOption::Clientside, - true, - ); - // test only DB - test_combination( - DBOption::Sqlite, - BackgroundOption::None, - AssetsOption::None, - true, - ); +#[rstest::rstest] +// lightweight service +#[case(DBOption::None, BackgroundOption::None, AssetsOption::None)] +// REST API +#[case(DBOption::Sqlite, BackgroundOption::Async, AssetsOption::None)] +// SaaS, serverside +#[case(DBOption::None, BackgroundOption::None, AssetsOption::Serverside)] +// SaaS, clientside +#[case(DBOption::None, BackgroundOption::None, AssetsOption::Clientside)] +// test only DB +#[case(DBOption::Sqlite, BackgroundOption::None, AssetsOption::None)] +fn test_starter_combinations( + #[case] db: DBOption, + #[case] background: BackgroundOption, + #[case] asset: AssetsOption, +) { + test_combination(db, background, asset, true); } fn test_combination(