1
+ use proc_macro2:: TokenTree ;
1
2
use std:: str:: FromStr ;
3
+ use syn:: Meta ;
2
4
3
5
use graphql_client_codegen:: deprecation:: DeprecationStrategy ;
4
6
use graphql_client_codegen:: normalization:: Normalization ;
5
7
6
8
const DEPRECATION_ERROR : & str = "deprecated must be one of 'allow', 'deny', or 'warn'" ;
7
9
const NORMALIZATION_ERROR : & str = "normalization must be one of 'none' or 'rust'" ;
8
10
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
-
14
11
pub fn ident_exists ( ast : & syn:: DeriveInput , ident : & str ) -> Result < ( ) , syn:: Error > {
15
- let graphql_path = path_to_match ( ) ;
16
12
let attribute = ast
17
13
. attrs
18
14
. iter ( )
19
- . find ( |attr| attr. path == graphql_path )
15
+ . find ( |attr| attr. path ( ) . is_ident ( "graphql" ) )
20
16
. ok_or_else ( || syn:: Error :: new_spanned ( ast, "The graphql attribute is missing" ) ) ?;
21
17
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 ( ( ) ) ;
29
23
}
30
24
}
31
25
}
@@ -39,21 +33,21 @@ pub fn ident_exists(ast: &syn::DeriveInput, ident: &str) -> Result<(), syn::Erro
39
33
40
34
/// Extract an configuration parameter specified in the `graphql` attribute.
41
35
pub 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
45
38
. iter ( )
46
- . find ( |attr| attr . path == graphql_path )
39
+ . find ( |a| a . path ( ) . is_ident ( "graphql" ) )
47
40
. 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 ( ) ) ;
57
51
}
58
52
}
59
53
}
@@ -68,38 +62,41 @@ pub fn extract_attr(ast: &syn::DeriveInput, attr: &str) -> Result<String, syn::E
68
62
69
63
/// Extract a list of configuration parameter values specified in the `graphql` attribute.
70
64
pub 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
74
67
. iter ( )
75
- . find ( |attr| attr . path == graphql_path )
68
+ . find ( |a| a . path ( ) . is_ident ( "graphql" ) )
76
69
. 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) ;
96
86
}
97
87
}
98
88
}
99
89
}
100
90
}
101
91
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
+ }
103
100
}
104
101
105
102
/// Get the deprecation from a struct attribute in the derive case.
@@ -278,4 +275,24 @@ mod test {
278
275
let parsed = syn:: parse_str ( input) . unwrap ( ) ;
279
276
assert ! ( !extract_skip_serializing_none( & parsed) ) ;
280
277
}
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
+ }
281
298
}
0 commit comments