1+ use proc_macro2:: TokenTree ;
12use std:: str:: FromStr ;
3+ use syn:: Meta ;
24
35use graphql_client_codegen:: deprecation:: DeprecationStrategy ;
46use graphql_client_codegen:: normalization:: Normalization ;
57
68const DEPRECATION_ERROR : & str = "deprecated must be one of 'allow', 'deny', or 'warn'" ;
79const NORMALIZATION_ERROR : & str = "normalization must be one of 'none' or 'rust'" ;
810
9- /// The `graphql` attribute as a `syn::Path`.
10- fn path_to_match ( ) -> syn:: Path {
11- syn:: parse_str ( "graphql" ) . expect ( "`graphql` is a valid path" )
12- }
13-
1411pub fn ident_exists ( ast : & syn:: DeriveInput , ident : & str ) -> Result < ( ) , syn:: Error > {
15- let graphql_path = path_to_match ( ) ;
1612 let attribute = ast
1713 . attrs
1814 . iter ( )
19- . find ( |attr| attr. path == graphql_path )
15+ . find ( |attr| attr. path ( ) . is_ident ( "graphql" ) )
2016 . ok_or_else ( || syn:: Error :: new_spanned ( ast, "The graphql attribute is missing" ) ) ?;
2117
22- if let syn:: Meta :: List ( items) = & attribute. parse_meta ( ) . expect ( "Attribute is well formatted" ) {
23- for item in items. nested . iter ( ) {
24- if let syn:: NestedMeta :: Meta ( syn:: Meta :: Path ( path) ) = item {
25- if let Some ( ident_) = path. get_ident ( ) {
26- if ident_ == ident {
27- return Ok ( ( ) ) ;
28- }
18+ if let Meta :: List ( list) = & attribute. meta {
19+ for item in list. tokens . clone ( ) . into_iter ( ) {
20+ if let TokenTree :: Ident ( ident_) = item {
21+ if ident_ == ident {
22+ return Ok ( ( ) ) ;
2923 }
3024 }
3125 }
@@ -39,21 +33,21 @@ pub fn ident_exists(ast: &syn::DeriveInput, ident: &str) -> Result<(), syn::Erro
3933
4034/// Extract an configuration parameter specified in the `graphql` attribute.
4135pub fn extract_attr ( ast : & syn:: DeriveInput , attr : & str ) -> Result < String , syn:: Error > {
42- let attributes = & ast. attrs ;
43- let graphql_path = path_to_match ( ) ;
44- let attribute = attributes
36+ let attribute = ast
37+ . attrs
4538 . iter ( )
46- . find ( |attr| attr . path == graphql_path )
39+ . find ( |a| a . path ( ) . is_ident ( "graphql" ) )
4740 . ok_or_else ( || syn:: Error :: new_spanned ( ast, "The graphql attribute is missing" ) ) ?;
48- if let syn:: Meta :: List ( items) = & attribute. parse_meta ( ) . expect ( "Attribute is well formatted" ) {
49- for item in items. nested . iter ( ) {
50- if let syn:: NestedMeta :: Meta ( syn:: Meta :: NameValue ( name_value) ) = item {
51- let syn:: MetaNameValue { path, lit, .. } = name_value;
52- if let Some ( ident) = path. get_ident ( ) {
53- if ident == attr {
54- if let syn:: Lit :: Str ( lit) = lit {
55- return Ok ( lit. value ( ) ) ;
56- }
41+
42+ if let Meta :: List ( list) = & attribute. meta {
43+ let mut iter = list. tokens . clone ( ) . into_iter ( ) ;
44+ while let Some ( item) = iter. next ( ) {
45+ if let TokenTree :: Ident ( ident) = item {
46+ if ident == attr {
47+ iter. next ( ) ;
48+ if let Some ( TokenTree :: Literal ( lit) ) = iter. next ( ) {
49+ let lit_str: syn:: LitStr = syn:: parse_str ( & lit. to_string ( ) ) ?;
50+ return Ok ( lit_str. value ( ) ) ;
5751 }
5852 }
5953 }
@@ -68,38 +62,41 @@ pub fn extract_attr(ast: &syn::DeriveInput, attr: &str) -> Result<String, syn::E
6862
6963/// Extract a list of configuration parameter values specified in the `graphql` attribute.
7064pub fn extract_attr_list ( ast : & syn:: DeriveInput , attr : & str ) -> Result < Vec < String > , syn:: Error > {
71- let attributes = & ast. attrs ;
72- let graphql_path = path_to_match ( ) ;
73- let attribute = attributes
65+ let attribute = ast
66+ . attrs
7467 . iter ( )
75- . find ( |attr| attr . path == graphql_path )
68+ . find ( |a| a . path ( ) . is_ident ( "graphql" ) )
7669 . ok_or_else ( || syn:: Error :: new_spanned ( ast, "The graphql attribute is missing" ) ) ?;
77- if let syn:: Meta :: List ( items) = & attribute. parse_meta ( ) . expect ( "Attribute is well formatted" ) {
78- for item in items. nested . iter ( ) {
79- if let syn:: NestedMeta :: Meta ( syn:: Meta :: List ( value_list) ) = item {
80- if let Some ( ident) = value_list. path . get_ident ( ) {
81- if ident == attr {
82- return value_list
83- . nested
84- . iter ( )
85- . map ( |lit| {
86- if let syn:: NestedMeta :: Lit ( syn:: Lit :: Str ( lit) ) = lit {
87- Ok ( lit. value ( ) )
88- } else {
89- Err ( syn:: Error :: new_spanned (
90- lit,
91- "Attribute inside value list must be a literal" ,
92- ) )
93- }
94- } )
95- . collect ( ) ;
70+
71+ let mut result = Vec :: new ( ) ;
72+
73+ if let Meta :: List ( list) = & attribute. meta {
74+ let mut iter = list. tokens . clone ( ) . into_iter ( ) ;
75+ while let Some ( item) = iter. next ( ) {
76+ if let TokenTree :: Ident ( ident) = item {
77+ if ident == attr {
78+ if let Some ( TokenTree :: Group ( group) ) = iter. next ( ) {
79+ for token in group. stream ( ) {
80+ if let TokenTree :: Literal ( lit) = token {
81+ let lit_str: syn:: LitStr = syn:: parse_str ( & lit. to_string ( ) ) ?;
82+ result. push ( lit_str. value ( ) ) ;
83+ }
84+ }
85+ return Ok ( result) ;
9686 }
9787 }
9888 }
9989 }
10090 }
10191
102- Err ( syn:: Error :: new_spanned ( ast, "Attribute not found" ) )
92+ if result. is_empty ( ) {
93+ Err ( syn:: Error :: new_spanned (
94+ ast,
95+ format ! ( "Attribute list `{}` not found or empty" , attr) ,
96+ ) )
97+ } else {
98+ Ok ( result)
99+ }
103100}
104101
105102/// Get the deprecation from a struct attribute in the derive case.
@@ -278,4 +275,24 @@ mod test {
278275 let parsed = syn:: parse_str ( input) . unwrap ( ) ;
279276 assert ! ( !extract_skip_serializing_none( & parsed) ) ;
280277 }
278+
279+ #[ test]
280+ fn test_external_enums ( ) {
281+ let input = r#"
282+ #[derive(Serialize, Deserialize, Debug)]
283+ #[derive(GraphQLQuery)]
284+ #[graphql(
285+ schema_path = "x",
286+ query_path = "x",
287+ extern_enums("Direction", "DistanceUnit"),
288+ )]
289+ struct MyQuery;
290+ "# ;
291+ let parsed: syn:: DeriveInput = syn:: parse_str ( input) . unwrap ( ) ;
292+
293+ assert_eq ! (
294+ extract_attr_list( & parsed, "extern_enums" ) . ok( ) . unwrap( ) ,
295+ vec![ "Direction" , "DistanceUnit" ] ,
296+ ) ;
297+ }
281298}
0 commit comments