From e05e5590026d746dcde2e4f344c757f132ed9300 Mon Sep 17 00:00:00 2001 From: MnlPhlp Date: Fri, 29 May 2026 12:40:52 +0200 Subject: [PATCH 1/3] allow type names to prevent warning --- taurpc/taurpc-macros/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/taurpc/taurpc-macros/src/lib.rs b/taurpc/taurpc-macros/src/lib.rs index dbf65fb..6a18dec 100644 --- a/taurpc/taurpc-macros/src/lib.rs +++ b/taurpc/taurpc-macros/src/lib.rs @@ -112,7 +112,11 @@ pub fn resolvers(_attr: TokenStream, item: TokenStream) -> TokenStream { item.items.push(syn::ImplItem::Type(t)); } - quote!(#item).into() + quote! { + #[allow(non_camel_case_types)] + #item + } + .into() } /// Transform an async method into a sync one that returns a `Pin>`. From 043a0293243e37632e89512beb0315987cad45c4 Mon Sep 17 00:00:00 2001 From: MnlPhlp Date: Fri, 29 May 2026 13:05:28 +0200 Subject: [PATCH 2/3] carry over comments from trait to ts code --- taurpc/src/export.rs | 16 +++++++++++++++- taurpc/taurpc-macros/src/attrs.rs | 11 +++++++++++ taurpc/taurpc-macros/src/generator.rs | 16 +++++++++++++++- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/taurpc/src/export.rs b/taurpc/src/export.rs index 9d1348c..af5909f 100644 --- a/taurpc/src/export.rs +++ b/taurpc/src/export.rs @@ -174,7 +174,21 @@ fn generate_function( }; let name = function.name().split_once("_taurpc_fn__").unwrap().1; - Ok(format!(r#"{name}: ({args}) => Promise<{return_ty}>"#)) + + let docs = function.docs(); + let jsdoc = if docs.is_empty() { + String::new() + } else { + let lines: Vec<&str> = docs.lines().collect(); + if lines.len() == 1 { + format!("/** {} */ ", lines[0]) + } else { + let body = lines.iter().map(|l| format!(" * {l}")).join("\n"); + format!("/**\n{body}\n */ ") + } + }; + + Ok(format!(r#"{jsdoc}{name}: ({args}) => Promise<{return_ty}>"#)) } fn try_write(file: &mut File, data: &str) { diff --git a/taurpc/taurpc-macros/src/attrs.rs b/taurpc/taurpc-macros/src/attrs.rs index 7bd45f6..ffc2680 100644 --- a/taurpc/taurpc-macros/src/attrs.rs +++ b/taurpc/taurpc-macros/src/attrs.rs @@ -106,6 +106,7 @@ pub struct MethodAttrs { pub(crate) skip: bool, pub(crate) alias: Option, pub(crate) is_event: bool, + pub(crate) comments: Vec, } impl Parse for MethodAttrs { @@ -116,6 +117,16 @@ impl Parse for MethodAttrs { let mut errors = Ok(()); for attr in attrs { + if attr.path().is_ident("doc") { + if let syn::Meta::NameValue(meta) = &attr.meta { + if let Expr::Lit(expr_lit) = &meta.value { + if let Lit::Str(lit_str) = &expr_lit.lit { + res.comments.push(lit_str.value().trim().to_string()); + } + } + } + continue; + } if !attr.path().is_ident("taurpc") { extend_errors!( errors, diff --git a/taurpc/taurpc-macros/src/generator.rs b/taurpc/taurpc-macros/src/generator.rs index befa36b..906cc97 100644 --- a/taurpc/taurpc-macros/src/generator.rs +++ b/taurpc/taurpc-macros/src/generator.rs @@ -38,11 +38,18 @@ impl ProceduresGenerator<'_> { } = self; let fn_types = alias_method_idents.iter().zip(methods).map( - |(ident, IpcMethod { output, args, .. })| { + |(ident, IpcMethod { output, args, attrs, .. })| { let args = args.iter().filter(|&arg| !arg.skip_type); let fn_ident = fn_ident(trait_ident, ident); + let doc_attrs = if attrs.comments.is_empty() { + quote! {} + } else { + let lines = attrs.comments.iter().map(|line| quote! { #[doc = #line] }); + quote! { #( #lines )* } + }; quote! { + #doc_attrs #[specta::specta] #[allow(non_snake_case, unused_variables)] fn #fn_ident( #( #args ),*) #output { @@ -69,12 +76,19 @@ impl ProceduresGenerator<'_> { } let ty_doc = format!("The response future returned by [`{trait_ident}::{ident}`]."); let future_type_ident = method_fut_ident(ident); + let doc_attrs = if attrs.comments.is_empty() { + quote! {} + } else { + let lines = attrs.comments.iter().map(|line| quote! { #[doc = #line] }); + quote! { #( #lines )* } + }; Some(quote! { #[allow(non_camel_case_types)] #[doc = #ty_doc] type #future_type_ident: std::future::Future + Send; + #doc_attrs fn #ident #generics(self, #( #args ),*) -> Self::#future_type_ident; }) }, From a5d485bb490963da3f200b630263eb33ddbd63e5 Mon Sep 17 00:00:00 2001 From: MnlPhlp Date: Fri, 29 May 2026 13:24:49 +0200 Subject: [PATCH 3/3] spans and attr passthrough for propper errors/warnings in trait etc. --- taurpc/taurpc-macros/src/args.rs | 9 +++++++-- taurpc/taurpc-macros/src/attrs.rs | 15 ++++++--------- taurpc/taurpc-macros/src/generator.rs | 27 ++++++++++++++++++--------- taurpc/taurpc-macros/src/proc.rs | 9 ++++++++- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/taurpc/taurpc-macros/src/args.rs b/taurpc/taurpc-macros/src/args.rs index a4ffed3..c5e0afc 100644 --- a/taurpc/taurpc-macros/src/args.rs +++ b/taurpc/taurpc-macros/src/args.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream as TokenStream2; -use quote::{quote, ToTokens}; +use quote::{quote_spanned, ToTokens}; use syn::{ext::IdentExt, spanned::Spanned, Ident, Pat, PatType, Type}; // TODO: Add raw request?? @@ -20,6 +20,10 @@ impl Arg { pub fn pat(&self) -> &Pat { &self.pat.pat } + + pub fn span(&self) -> proc_macro2::Span { + self.pat.span() + } } impl From for Arg { @@ -77,8 +81,9 @@ fn parse_arg(arg: &Arg, message: &Ident, proc_ident: &Ident) -> syn::Result ::tauri::ipc::CommandArg::from_command( ::tauri::ipc::CommandItem { name: stringify!(#proc_ident), key: #key, diff --git a/taurpc/taurpc-macros/src/attrs.rs b/taurpc/taurpc-macros/src/attrs.rs index ffc2680..6c0da99 100644 --- a/taurpc/taurpc-macros/src/attrs.rs +++ b/taurpc/taurpc-macros/src/attrs.rs @@ -101,12 +101,14 @@ impl Parse for ProceduresAttrs { /// Attributes defined on methods inside a procedures trait. /// Parse the attributes to make sure they are defined in the correct way, like `#[taurpc( ... )]`, accumulate /// all errors and then display them together with `extend_errors!()`. -#[derive(Default, Debug)] +#[derive(Default)] pub struct MethodAttrs { pub(crate) skip: bool, pub(crate) alias: Option, pub(crate) is_event: bool, pub(crate) comments: Vec, + /// Attributes to forward to the generated code (e.g., #[allow(...)]) + pub(crate) passthrough_attrs: Vec, } impl Parse for MethodAttrs { @@ -128,14 +130,9 @@ impl Parse for MethodAttrs { continue; } if !attr.path().is_ident("taurpc") { - extend_errors!( - errors, - syn::Error::new( - attr.meta.span(), - "these attributes are not supported, use `#[taurpc(...)]` instead" - ) - ); - // continue; + // Forward non-taurpc attributes (like #[allow(...)], #[cfg(...)], etc.) to generated code + res.passthrough_attrs.push(attr); + continue; } if let Err(e) = attr.parse_nested_meta(|meta| { diff --git a/taurpc/taurpc-macros/src/generator.rs b/taurpc/taurpc-macros/src/generator.rs index 906cc97..6eac8ed 100644 --- a/taurpc/taurpc-macros/src/generator.rs +++ b/taurpc/taurpc-macros/src/generator.rs @@ -2,7 +2,7 @@ use crate::args::{parse_arg_key, parse_args}; use crate::{method_fut_ident, proc::IpcMethod}; use proc_macro2::TokenStream as TokenStream2; -use quote::{format_ident, quote, ToTokens}; +use quote::{format_ident, quote, quote_spanned, ToTokens}; use std::collections::BTreeMap; use syn::{parse_quote, Attribute, Generics, Ident, Type, Visibility}; @@ -38,7 +38,7 @@ impl ProceduresGenerator<'_> { } = self; let fn_types = alias_method_idents.iter().zip(methods).map( - |(ident, IpcMethod { output, args, attrs, .. })| { + |(ident, IpcMethod { output, args, attrs, span, .. })| { let args = args.iter().filter(|&arg| !arg.skip_type); let fn_ident = fn_ident(trait_ident, ident); let doc_attrs = if attrs.comments.is_empty() { @@ -47,9 +47,11 @@ impl ProceduresGenerator<'_> { let lines = attrs.comments.iter().map(|line| quote! { #[doc = #line] }); quote! { #( #lines )* } }; + let passthrough_attrs = &attrs.passthrough_attrs; - quote! { + quote_spanned! {*span=> #doc_attrs + #( #passthrough_attrs )* #[specta::specta] #[allow(non_snake_case, unused_variables)] fn #fn_ident( #( #args ),*) #output { @@ -66,6 +68,7 @@ impl ProceduresGenerator<'_> { args, generics, attrs, + span, .. }, output_ty, @@ -82,13 +85,15 @@ impl ProceduresGenerator<'_> { let lines = attrs.comments.iter().map(|line| quote! { #[doc = #line] }); quote! { #( #lines )* } }; + let passthrough_attrs = &attrs.passthrough_attrs; - Some(quote! { + Some(quote_spanned! {*span=> #[allow(non_camel_case_types)] #[doc = #ty_doc] type #future_type_ident: std::future::Future + Send; #doc_attrs + #( #passthrough_attrs )* fn #ident #generics(self, #( #args ),*) -> Self::#future_type_ident; }) }, @@ -264,19 +269,20 @@ impl ProceduresGenerator<'_> { |( proc_name, IpcMethod { - ident, args, attrs, .. + ident, args, attrs, span, .. }, )| { if attrs.is_event { return None; } let args = parse_args(args, &message, ident).unwrap(); + let method_call = quote_spanned!(*span=> #trait_ident::#ident( + self.methods, #( #args.unwrap() ),* + )); Some(quote! { stringify!(#proc_name) => { #resolver.respond_async_serialized(async move { - let res = #trait_ident::#ident( - self.methods, #( #args.unwrap() ),* - ); + let res = #method_call; let kind = (&res).async_kind(); kind.future(res).await }); @@ -400,6 +406,7 @@ impl ProceduresGenerator<'_> { args, generics, attrs, + span, .. }, )| { @@ -410,8 +417,10 @@ impl ProceduresGenerator<'_> { let args = args.iter().filter(|arg| !arg.skip_type).collect::>(); let arg_pats = args.iter().map(|arg| arg.pat()).collect::>(); + let passthrough_attrs = &attrs.passthrough_attrs; - Some(quote! { + Some(quote_spanned! {*span=> + #( #passthrough_attrs )* #[allow(unused)] #vis fn #ident #generics(&self, #( #args ),*) -> tauri::Result<()> { let proc_name = stringify!(#alias_ident); diff --git a/taurpc/taurpc-macros/src/proc.rs b/taurpc/taurpc-macros/src/proc.rs index 29d4727..9f6b873 100644 --- a/taurpc/taurpc-macros/src/proc.rs +++ b/taurpc/taurpc-macros/src/proc.rs @@ -1,4 +1,5 @@ use super::extend_errors; +use proc_macro2::Span; use syn::{ braced, ext::IdentExt, @@ -27,6 +28,8 @@ pub struct IpcMethod { pub args: Vec, pub generics: Generics, pub attrs: MethodAttrs, + /// Span of the method signature, used for better error reporting + pub span: Span, } impl Parse for Procedures { @@ -107,7 +110,7 @@ impl Parse for IpcMethod { fn parse(input: ParseStream) -> parse::Result { let attrs = MethodAttrs::parse(input)?; - ::parse(input)?; + let async_token = ::parse(input)?; ::parse(input)?; let ident: Ident = input.parse()?; @@ -134,12 +137,16 @@ impl Parse for IpcMethod { let output = input.parse()?; ::parse(input)?; + // Capture the span from async token (start of signature), fallback to ident span + let span = async_token.span; + Ok(IpcMethod { ident, output, args, generics, attrs, + span, }) } }