bluejay_typegen_macro/
lib.rs1use bluejay_core::definition::{EnumTypeDefinition, EnumValueDefinition};
2use bluejay_typegen_codegen::{
3 generate_schema, names::field_ident, CodeGenerator, ExecutableEnum, ExecutableField,
4 ExecutableStruct, Input,
5};
6use proc_macro2::Span;
7use quote::ToTokens;
8use syn::{parse_macro_input, parse_quote};
9
10#[proc_macro_attribute]
81pub fn typegen(
82 attr: proc_macro::TokenStream,
83 item: proc_macro::TokenStream,
84) -> proc_macro::TokenStream {
85 let input = parse_macro_input!(attr as Input);
86 let mut module = parse_macro_input!(item as syn::ItemMod);
87
88 if let Err(error) = generate_schema(input, &mut module, Default::default(), SerdeCodeGenerator)
89 {
90 return error.to_compile_error().into();
91 }
92
93 module.to_token_stream().into()
94}
95
96struct SerdeCodeGenerator;
97
98impl CodeGenerator for SerdeCodeGenerator {
99 fn attributes_for_executable_struct(
100 &self,
101 _executable_struct: &ExecutableStruct,
102 ) -> Vec<syn::Attribute> {
103 vec![
104 parse_quote! { #[derive(::std::clone::Clone, ::std::cmp::PartialEq, ::std::fmt::Debug, ::bluejay_typegen::serde::Deserialize)] },
105 parse_quote! { #[serde(crate = "bluejay_typegen::serde")] },
106 ]
107 }
108
109 fn fields_for_executable_struct(&self, executable_struct: &ExecutableStruct) -> syn::Fields {
110 let fields: Vec<syn::Field> = executable_struct
111 .fields()
112 .iter()
113 .map(|executable_field| {
114 let name_ident = field_ident(executable_field.graphql_name());
115
116 let attributes = self.attributes_for_field(executable_field);
117 let ty = executable_struct.compute_type(executable_field.r#type());
118
119 parse_quote! {
120 #(#attributes)*
121 pub #name_ident: #ty
122 }
123 })
124 .collect();
125
126 let fields_named: syn::FieldsNamed = parse_quote! { { #(#fields,)* } };
127
128 fields_named.into()
129 }
130
131 fn attributes_for_executable_enum(
132 &self,
133 _executable_enum: &ExecutableEnum,
134 ) -> Vec<syn::Attribute> {
135 vec![
136 parse_quote! { #[derive(::std::clone::Clone, ::std::cmp::PartialEq, ::std::fmt::Debug, ::bluejay_typegen::serde::Deserialize)] },
137 parse_quote! { #[serde(crate = "bluejay_typegen::serde")] },
138 parse_quote! { #[serde(tag = "__typename")] },
139 ]
140 }
141
142 fn attributes_for_executable_enum_variant(
143 &self,
144 executable_struct: &ExecutableStruct,
145 ) -> Vec<syn::Attribute> {
146 let mut attributes = Vec::new();
147
148 let serialized_as = syn::LitStr::new(executable_struct.parent_name(), Span::call_site());
149 attributes.push(parse_quote! { #[serde(rename = #serialized_as)] });
150
151 if executable_struct.borrows() {
152 attributes.push(parse_quote! { #[serde(borrow)] });
153 }
154
155 attributes
156 }
157
158 fn attributes_for_executable_enum_variant_other(&self) -> Vec<syn::Attribute> {
159 vec![parse_quote! { #[serde(other)] }]
160 }
161
162 fn attributes_for_enum(
163 &self,
164 _enum_type_definition: &impl EnumTypeDefinition,
165 ) -> Vec<syn::Attribute> {
166 vec![
167 parse_quote! { #[derive(::std::clone::Clone, ::std::cmp::PartialEq, ::std::fmt::Debug, ::bluejay_typegen::serde::Serialize, ::bluejay_typegen::serde::Deserialize)] },
168 parse_quote! { #[serde(crate = "bluejay_typegen::serde")] },
169 ]
170 }
171
172 fn attributes_for_enum_variant(
173 &self,
174 enum_value_definition: &impl EnumValueDefinition,
175 ) -> Vec<syn::Attribute> {
176 let serialized_as = syn::LitStr::new(enum_value_definition.name(), Span::call_site());
177 vec![parse_quote! { #[serde(rename = #serialized_as)] }]
178 }
179
180 fn attributes_for_enum_variant_other(&self) -> Vec<syn::Attribute> {
181 vec![parse_quote! { #[serde(other)] }]
182 }
183
184 fn attributes_for_input_object(
185 &self,
186 #[allow(unused_variables)]
187 input_object_type_definition: &impl bluejay_core::definition::InputObjectTypeDefinition,
188 ) -> Vec<syn::Attribute> {
189 vec![
190 parse_quote! { #[derive(::std::clone::Clone, ::std::cmp::PartialEq, ::std::fmt::Debug, ::bluejay_typegen::serde::Serialize)] },
191 parse_quote! { #[serde(crate = "bluejay_typegen::serde")] },
192 ]
193 }
194
195 fn attributes_for_input_object_field(
196 &self,
197 input_value_definition: &impl bluejay_core::definition::InputValueDefinition,
198 borrows: bool,
199 ) -> Vec<syn::Attribute> {
200 let serialized_as = syn::LitStr::new(input_value_definition.name(), Span::call_site());
201 let mut attributes = vec![parse_quote! { #[serde(rename = #serialized_as)] }];
202
203 if borrows {
204 attributes.push(parse_quote! { #[serde(borrow)] });
205 }
206
207 attributes
208 }
209
210 fn attributes_for_one_of_input_object(
211 &self,
212 #[allow(unused_variables)]
213 input_object_type_definition: &impl bluejay_core::definition::InputObjectTypeDefinition,
214 ) -> Vec<syn::Attribute> {
215 self.attributes_for_input_object(input_object_type_definition)
217 }
218
219 fn attributes_for_one_of_input_object_field(
220 &self,
221 input_value_definition: &impl bluejay_core::definition::InputValueDefinition,
222 borrows: bool,
223 ) -> Vec<syn::Attribute> {
224 self.attributes_for_input_object_field(input_value_definition, borrows)
226 }
227}
228
229impl SerdeCodeGenerator {
230 fn attributes_for_field(&self, executable_field: &ExecutableField) -> Vec<syn::Attribute> {
231 let mut attributes = Vec::new();
232
233 let serialized_as = syn::LitStr::new(executable_field.graphql_name(), Span::call_site());
234 attributes.push(parse_quote! { #[serde(rename = #serialized_as)] });
235
236 if executable_field.r#type().base().borrows() {
237 attributes.push(parse_quote! { #[serde(borrow)] });
238 }
239
240 attributes
241 }
242}