From eb4613f02a14e4659d9bebd6ee9d3183d97c0cd6 Mon Sep 17 00:00:00 2001 From: Callum Cunha Date: Sat, 23 Dec 2023 07:03:23 +0000 Subject: [PATCH] feat: carry over field docs --- src/lib.rs | 11 +++++++++++ src/patch.rs | 19 ++++++++++++++----- src/view.rs | 10 +++++++--- tests/view.rs | 4 ++++ 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f2cf2ee..0f9e1bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -209,6 +209,17 @@ fn extract_oai_f_attributes(attrs: &[syn::Attribute]) -> Vec<&syn::Attribute> { .collect() } +fn is_doc(v: &&Attribute) -> bool { + v.meta.require_name_value().map_or(false, |v| { + v.path.segments.first().map_or(false, |v| v.ident == "doc") + }) +} + +fn extract_docs(attrs: &[Attribute]) -> proc_macro2::TokenStream { + let docs: Vec<_> = attrs.iter().filter(is_doc).collect(); + quote!(#(#docs)*) +} + /// Aborts on unexpected args to show that they arent valid fn abort_unexpected_args(names: Vec<&str>, args: &[TokenTree]) { for tk in args.iter() { diff --git a/src/patch.rs b/src/patch.rs index d3bd893..7b1d47b 100644 --- a/src/patch.rs +++ b/src/patch.rs @@ -1,9 +1,9 @@ use crate::*; use proc_macro2::{Group, Ident, TokenStream, TokenTree}; +use proc_macro_error::abort; use quote::quote; use syn::{Attribute, DeriveInput, Type}; -use proc_macro_error::abort; struct PatchModelArgs { name: Ident, @@ -40,7 +40,7 @@ pub fn impl_patch_model( } // Add - let field_ty = &field.ty; + let docs = extract_docs(&field.attrs); let oai_f_attributes: Vec<_> = field_attributes .iter() .filter(|attr| { @@ -51,6 +51,7 @@ pub fn impl_patch_model( .map_or(false, |seg| seg.ident == "oai") }) .collect(); + let field_ty = &field.ty; let option_ty = extract_type_from_option(field_ty); fields_and_is_option.push((field_name, option_ty.is_some())); @@ -58,6 +59,7 @@ pub fn impl_patch_model( field_name, field_ty, option_ty, + &docs, &oai_f_attributes, )); }), @@ -216,6 +218,7 @@ fn impl_struct_fields( field_name: &Ident, field_ty: &Type, #[allow(unused_variables)] option_ty: Option<&Type>, + docs: &TokenStream, oai_f_attr: &Vec<&Attribute>, ) -> TokenStream { #[cfg(feature = "openapi")] @@ -223,12 +226,14 @@ fn impl_struct_fields( match option_ty { Some(t) => { quote! { - #(#oai_f_attr)* - pub #field_name: ::poem_openapi::types::MaybeUndefined<#t> + #docs + #(#oai_f_attr)* + pub #field_name: ::poem_openapi::types::MaybeUndefined<#t> } } _ => { quote! { + #docs #(#oai_f_attr)* pub #field_name: core::option::Option<#field_ty> } @@ -238,6 +243,7 @@ fn impl_struct_fields( #[cfg(not(feature = "openapi"))] { quote! { + #docs #(#oai_f_attr)* pub #field_name: core::option::Option<#field_ty> } @@ -257,7 +263,10 @@ fn parse_patch_arg(attr: &Attribute) -> PatchModelArgs { let name = match &tks[0] { TokenTree::Ident(v) => v.clone(), x => { - abort!(x, "First argument must be an identifier (name) of the struct for the view") + abort!( + x, + "First argument must be an identifier (name) of the struct for the view" + ) } }; diff --git a/src/view.rs b/src/view.rs index 00b22de..40a61ba 100644 --- a/src/view.rs +++ b/src/view.rs @@ -36,14 +36,16 @@ pub fn impl_view_model( let field_attr: &Vec = &field.attrs; let vis = &field.vis; + let docs = extract_docs(&field.attrs); + let oai_f_attributes: Vec<_> = extract_oai_f_attributes(field_attr); let field_name = &field.ident.as_ref().unwrap(); let field_ty = &field.ty; - let oai_f_attributes: Vec<_> = extract_oai_f_attributes(field_attr); field_from_mapping.push(quote!(#field_name: value.#field_name)); quote! { - #(#oai_f_attributes)* - #vis #field_name: #field_ty + #docs + #(#oai_f_attributes)* + #vis #field_name: #field_ty } }) .collect(), @@ -58,6 +60,7 @@ pub fn impl_view_model( let mut field_without_attrs = field.clone(); field_without_attrs.attrs = vec![]; + let docs = extract_docs(&field.attrs); let field_name = &field.ident; match &field.fields { @@ -99,6 +102,7 @@ pub fn impl_view_model( }; quote! { + #docs #(#oai_f_attr)* #field_without_attrs } diff --git a/tests/view.rs b/tests/view.rs index 67c1c48..1c10d5f 100644 --- a/tests/view.rs +++ b/tests/view.rs @@ -8,7 +8,9 @@ use restructed::Models; #[derive(Models)] #[view(UserProfile, fields(display_name, bio))] struct User { + /// This should be omitted id: i32, + /// This shouldn't be omitted display_name: String, bio: String, password: String, @@ -53,6 +55,8 @@ fn only_fields() { #[derive(Debug, Clone, Models)] #[view(ApiErrorReads, fields(NotFound, Unauthorized, InternalServerError))] pub enum ApiError { + /// This "NotFound" rustdoc will carry over
+ /// Even for multiple lines NotFound(String), ConflictX(String), ConflictY(u64),