2018-12-19 12:27:49 -06:00
use proc_macro2 ::TokenStream ;
2018-08-27 16:51:12 -05:00
2020-04-18 00:09:04 -05:00
use crate ::util ;
2019-04-22 19:19:06 -05:00
use quote ::quote ;
2020-04-18 00:09:04 -05:00
use syn ::{ self , Data , Fields } ;
2017-06-24 06:23:20 -05:00
2020-04-18 00:09:04 -05:00
pub fn impl_enum ( ast : syn ::DeriveInput , is_internal : bool ) -> TokenStream {
if ! ast . generics . params . is_empty ( ) {
panic! ( " #[derive(GraphQLEnum) does not support generics or lifetimes " ) ;
2017-06-24 06:23:20 -05:00
}
2018-12-18 18:56:37 -06:00
2018-05-02 18:21:08 -05:00
let variants = match ast . data {
2020-04-18 00:09:04 -05:00
Data ::Enum ( enum_data ) = > enum_data . variants ,
2018-05-02 18:21:08 -05:00
_ = > {
2017-06-24 06:23:20 -05:00
panic! ( " #[derive(GraphlQLEnum)] may only be applied to enums, not to structs " ) ;
2017-08-06 13:48:46 -05:00
}
2017-06-24 06:23:20 -05:00
} ;
// Parse attributes.
2020-04-18 00:09:04 -05:00
let attrs = match util ::ObjectAttributes ::from_attrs ( & ast . attrs ) {
Ok ( a ) = > a ,
Err ( e ) = > {
panic! ( " Invalid #[graphql(...)] attribute: {} " , e ) ;
}
2017-08-02 21:18:11 -05:00
} ;
2020-04-18 00:09:04 -05:00
if ! attrs . interfaces . is_empty ( ) {
panic! ( " Invalid #[graphql(...)] attribute 'interfaces': #[derive(GraphQLEnum) does not support 'interfaces' " ) ;
}
if attrs . scalar . is_some ( ) {
panic! ( " Invalid #[graphql(...)] attribute 'scalar': #[derive(GraphQLEnum) does not support explicit scalars " ) ;
2017-08-06 13:48:46 -05:00
}
2017-06-24 06:23:20 -05:00
2020-04-18 00:09:04 -05:00
// Parse attributes.
let ident = & ast . ident ;
let name = attrs . name . unwrap_or_else ( | | ident . to_string ( ) ) ;
let mut mapping = std ::collections ::HashMap ::new ( ) ;
let fields = variants
. into_iter ( )
. filter_map ( | field | {
let field_attrs = match util ::FieldAttributes ::from_attrs (
field . attrs ,
util ::FieldAttributeParseMode ::Object ,
) {
Ok ( attrs ) = > attrs ,
Err ( e ) = > panic! ( " Invalid #[graphql] attribute for field: \n {} " , e ) ,
} ;
if field_attrs . skip {
panic! ( " #[derive(GraphQLEnum)] does not support #[graphql(skip)] on fields " ) ;
} else {
let field_name = field . ident ;
let name = field_attrs
. name
. clone ( )
. unwrap_or_else ( | | util ::to_upper_snake_case ( & field_name . to_string ( ) ) ) ;
match mapping . get ( & name ) {
Some ( other_field_name ) = >
panic! ( format! ( " #[derive(GraphQLEnum)] all variants needs to be unique. Another field name ` {} ` has the same identifier ` {} `, thus ` {} ` can not be named ` {} `. One of the fields is manually renamed! " , other_field_name , name , field_name , name ) ) ,
None = > {
mapping . insert ( name . clone ( ) , field_name . clone ( ) ) ;
}
}
2017-06-24 06:23:20 -05:00
2020-04-18 00:09:04 -05:00
let resolver_code = quote! ( #ident ::#field_name ) ;
2017-06-24 06:23:20 -05:00
2020-04-18 00:09:04 -05:00
let _type = match field . fields {
Fields ::Unit = > syn ::parse_str ( & field_name . to_string ( ) ) . unwrap ( ) ,
_ = > panic! ( " #[derive(GraphQLEnum)] all fields of the enum must be unnamed " ) ,
2019-11-14 02:51:32 -06:00
} ;
2017-06-24 06:23:20 -05:00
2020-04-18 00:09:04 -05:00
Some ( util ::GraphQLTypeDefinitionField {
name ,
_type ,
args : Vec ::new ( ) ,
description : field_attrs . description ,
deprecation : field_attrs . deprecation ,
resolver_code ,
is_type_inferred : true ,
is_async : false ,
} )
2017-06-24 06:23:20 -05:00
}
2020-04-18 00:09:04 -05:00
} )
. collect ::< Vec < _ > > ( ) ;
2017-06-24 06:23:20 -05:00
2020-04-18 00:09:04 -05:00
if fields . len ( ) = = 0 {
panic! ( " #[derive(GraphQLEnum)] requires at least one variants " ) ;
}
2019-08-18 14:36:44 -05:00
2020-04-18 00:09:04 -05:00
let definition = util ::GraphQLTypeDefiniton {
name ,
_type : syn ::parse_str ( & ast . ident . to_string ( ) ) . unwrap ( ) ,
context : attrs . context ,
scalar : None ,
description : attrs . description ,
fields ,
// NOTICE: only unit variants allow -> no generics possible
generics : syn ::Generics ::default ( ) ,
interfaces : None ,
include_type_generics : true ,
generic_scalar : true ,
no_async : attrs . no_async ,
2017-12-02 05:42:07 -06:00
} ;
2019-11-15 14:23:59 -06:00
2020-04-18 00:09:04 -05:00
let juniper_crate_name = if is_internal { " crate " } else { " juniper " } ;
definition . into_enum_tokens ( juniper_crate_name )
2017-06-24 06:23:20 -05:00
}