feat(hemx): clarify generated authoring path
Close the fallible handler and example coherence slice: v0 uses typed todo newtypes, Result handler failure mapping, generated form/partial helpers, and page composition; kanban is explicitly marked as an advanced north-star milestone; raw render is isolated behind hemx::advanced::render. req: canonical_authoring/003 req: failure/004 req: public_api/005 req: examples/004
This commit is contained in:
+50
-35
@@ -1,4 +1,5 @@
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{format_ident, quote};
|
||||
use std::path::PathBuf;
|
||||
use syn::parse::Parser;
|
||||
@@ -651,20 +652,9 @@ fn add_component_register_helper(mut module: ItemMod, component: &str) -> ItemMo
|
||||
if handlers.is_empty() {
|
||||
return module;
|
||||
}
|
||||
let calls = handlers.iter().map(|handler| {
|
||||
let ident = &handler.ident;
|
||||
if handler.typed_arg_count == 1 && handler.is_async {
|
||||
quote!(.on_state_async(super::#component_ident::#ident, #ident))
|
||||
} else if handler.typed_arg_count == 1 {
|
||||
quote!(.on_state(super::#component_ident::#ident, #ident))
|
||||
} else if handler.is_async && handler.returns_result {
|
||||
quote!(.on_async_result(super::#component_ident::#ident, #ident))
|
||||
} else if handler.is_async {
|
||||
quote!(.on_async(super::#component_ident::#ident, #ident))
|
||||
} else {
|
||||
quote!(.on(super::#component_ident::#ident, #ident))
|
||||
}
|
||||
});
|
||||
let calls = handlers
|
||||
.iter()
|
||||
.map(|handler| component_registration_call(handler, &component_ident));
|
||||
let register: Item = syn::parse2(quote! {
|
||||
pub fn register(
|
||||
registry: ::hemx_axum::StateHandlerRegistry<#state_ty>,
|
||||
@@ -676,20 +666,9 @@ fn add_component_register_helper(mut module: ItemMod, component: &str) -> ItemMo
|
||||
}
|
||||
})
|
||||
.expect("generated component register helper parses");
|
||||
let calls = handlers.iter().map(|handler| {
|
||||
let ident = &handler.ident;
|
||||
if handler.typed_arg_count == 1 && handler.is_async {
|
||||
quote!(.on_state_async(super::#component_ident::#ident, #ident))
|
||||
} else if handler.typed_arg_count == 1 {
|
||||
quote!(.on_state(super::#component_ident::#ident, #ident))
|
||||
} else if handler.is_async && handler.returns_result {
|
||||
quote!(.on_async_result(super::#component_ident::#ident, #ident))
|
||||
} else if handler.is_async {
|
||||
quote!(.on_async(super::#component_ident::#ident, #ident))
|
||||
} else {
|
||||
quote!(.on(super::#component_ident::#ident, #ident))
|
||||
}
|
||||
});
|
||||
let calls = handlers
|
||||
.iter()
|
||||
.map(|handler| component_registration_call(handler, &component_ident));
|
||||
let register_with_state: Item = syn::parse2(quote! {
|
||||
pub fn register_with_state(
|
||||
registry: ::hemx_axum::HandlerRegistry,
|
||||
@@ -710,6 +689,30 @@ fn add_component_register_helper(mut module: ItemMod, component: &str) -> ItemMo
|
||||
module
|
||||
}
|
||||
|
||||
fn component_registration_call(
|
||||
handler: &ComponentHandler,
|
||||
component_ident: &syn::Ident,
|
||||
) -> TokenStream2 {
|
||||
let ident = &handler.ident;
|
||||
if handler.typed_arg_count == 1 && handler.is_async && handler.returns_result {
|
||||
quote!(.on_state_async_result(super::#component_ident::#ident, #ident))
|
||||
} else if handler.typed_arg_count == 1 && handler.returns_result {
|
||||
quote!(.on_state_result(super::#component_ident::#ident, #ident))
|
||||
} else if handler.typed_arg_count == 1 && handler.is_async {
|
||||
quote!(.on_state_async(super::#component_ident::#ident, #ident))
|
||||
} else if handler.typed_arg_count == 1 {
|
||||
quote!(.on_state(super::#component_ident::#ident, #ident))
|
||||
} else if handler.is_async && handler.returns_result {
|
||||
quote!(.on_async_result(super::#component_ident::#ident, #ident))
|
||||
} else if handler.returns_result {
|
||||
quote!(.on_result(super::#component_ident::#ident, #ident))
|
||||
} else if handler.is_async {
|
||||
quote!(.on_async(super::#component_ident::#ident, #ident))
|
||||
} else {
|
||||
quote!(.on(super::#component_ident::#ident, #ident))
|
||||
}
|
||||
}
|
||||
|
||||
fn component_contract_errors(
|
||||
path: &PathBuf,
|
||||
component: Option<&str>,
|
||||
@@ -1048,18 +1051,28 @@ mod tests {
|
||||
let module = parse_quote! {
|
||||
mod handlers {
|
||||
#[hemx::handler]
|
||||
fn create(app: super::App, form: super::NewTodo) -> impl hemx::IntoEffect {
|
||||
hemx::EventName::new("created").emit("")
|
||||
fn sync_form(app: super::App, form: super::NewTodo) -> impl hemx::IntoEffect {
|
||||
hemx::EventName::new("sync-form").emit("")
|
||||
}
|
||||
|
||||
#[hemx::handler]
|
||||
async fn increment(app: super::App) -> impl hemx::IntoEffect {
|
||||
hemx::EventName::new("incremented").emit("")
|
||||
async fn async_state(app: super::App) -> impl hemx::IntoEffect {
|
||||
hemx::EventName::new("async-state").emit("")
|
||||
}
|
||||
|
||||
#[hemx::handler]
|
||||
async fn save(app: super::App, form: super::NewTodo) -> Result<impl hemx::IntoEffect, super::Error> {
|
||||
Ok(hemx::EventName::new("saved").emit(""))
|
||||
fn sync_result(app: super::App) -> Result<impl hemx::IntoEffect, super::Error> {
|
||||
Ok(hemx::EventName::new("sync-result").emit(""))
|
||||
}
|
||||
|
||||
#[hemx::handler]
|
||||
async fn async_result(app: super::App) -> Result<impl hemx::IntoEffect, super::Error> {
|
||||
Ok(hemx::EventName::new("async-result").emit(""))
|
||||
}
|
||||
|
||||
#[hemx::handler]
|
||||
async fn async_form_result(app: super::App, form: super::NewTodo) -> Result<impl hemx::IntoEffect, super::Error> {
|
||||
Ok(hemx::EventName::new("async-form-result").emit(""))
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1070,11 +1083,13 @@ mod tests {
|
||||
assert!(generated.contains("register_with_state"), "{generated}");
|
||||
assert!(generated.contains("StateHandlerRegistry"), "{generated}");
|
||||
assert!(
|
||||
generated.contains("super :: todos :: create"),
|
||||
generated.contains("super :: todos :: sync_form"),
|
||||
"{generated}"
|
||||
);
|
||||
assert!(generated.contains(". on"), "{generated}");
|
||||
assert!(generated.contains(". on_state_async"), "{generated}");
|
||||
assert!(generated.contains(". on_state_result"), "{generated}");
|
||||
assert!(generated.contains(". on_state_async_result"), "{generated}");
|
||||
assert!(generated.contains(". on_async_result"), "{generated}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user