1
1
use crate :: {
2
2
result:: { GraphQLScope , UnsupportedAttribute } ,
3
- util:: { self , span_container:: SpanContainer } ,
3
+ util:: { self , duplicate :: Duplicate , span_container:: SpanContainer } ,
4
4
} ;
5
5
use proc_macro2:: TokenStream ;
6
6
use quote:: quote;
7
7
use syn:: { self , ext:: IdentExt , spanned:: Spanned , Data , Fields } ;
8
8
9
+ pub fn create_field_definition (
10
+ field : syn:: Field ,
11
+ error : & GraphQLScope ,
12
+ ) -> Option < util:: GraphQLTypeDefinitionField > {
13
+ let span = field. span ( ) ;
14
+ let field_attrs = match util:: FieldAttributes :: from_attrs (
15
+ & field. attrs ,
16
+ util:: FieldAttributeParseMode :: Object ,
17
+ ) {
18
+ Ok ( attrs) => attrs,
19
+ Err ( e) => {
20
+ proc_macro_error:: emit_error!( e) ;
21
+ return None ;
22
+ }
23
+ } ;
24
+
25
+ if field_attrs. skip . is_some ( ) {
26
+ return None ;
27
+ }
28
+
29
+ let field_name = & field. ident . unwrap ( ) ;
30
+ let name = field_attrs
31
+ . name
32
+ . clone ( )
33
+ . map ( SpanContainer :: into_inner)
34
+ . unwrap_or_else ( || util:: to_camel_case ( & field_name. unraw ( ) . to_string ( ) ) ) ;
35
+
36
+ if name. starts_with ( "__" ) {
37
+ error. no_double_underscore ( if let Some ( name) = field_attrs. name {
38
+ name. span_ident ( )
39
+ } else {
40
+ field_name. span ( )
41
+ } ) ;
42
+ }
43
+
44
+ if let Some ( default) = field_attrs. default {
45
+ error. unsupported_attribute_within ( default. span_ident ( ) , UnsupportedAttribute :: Default ) ;
46
+ }
47
+
48
+ let resolver_code = quote ! (
49
+ & self . #field_name
50
+ ) ;
51
+
52
+ Some ( util:: GraphQLTypeDefinitionField {
53
+ name,
54
+ _type : field. ty ,
55
+ args : Vec :: new ( ) ,
56
+ description : field_attrs. description . map ( SpanContainer :: into_inner) ,
57
+ deprecation : field_attrs. deprecation . map ( SpanContainer :: into_inner) ,
58
+ resolver_code,
59
+ default : None ,
60
+ is_type_inferred : true ,
61
+ is_async : false ,
62
+ span,
63
+ } )
64
+ }
65
+
9
66
pub fn build_derive_object (
10
67
ast : syn:: DeriveInput ,
11
68
is_internal : bool ,
@@ -32,64 +89,17 @@ pub fn build_derive_object(
32
89
33
90
let fields = struct_fields
34
91
. into_iter ( )
35
- . filter_map ( |field| {
36
- let span = field. span ( ) ;
37
- let field_attrs = match util:: FieldAttributes :: from_attrs (
38
- & field. attrs ,
39
- util:: FieldAttributeParseMode :: Object ,
40
- ) {
41
- Ok ( attrs) => attrs,
42
- Err ( e) => {
43
- proc_macro_error:: emit_error!( e) ;
44
- return None ;
45
- }
46
- } ;
47
-
48
- if field_attrs. skip . is_some ( ) {
49
- return None ;
50
- }
51
-
52
- let field_name = & field. ident . unwrap ( ) ;
53
- let name = field_attrs
54
- . name
55
- . clone ( )
56
- . map ( SpanContainer :: into_inner)
57
- . unwrap_or_else ( || util:: to_camel_case ( & field_name. unraw ( ) . to_string ( ) ) ) ;
58
-
59
- if name. starts_with ( "__" ) {
60
- error. no_double_underscore ( if let Some ( name) = field_attrs. name {
61
- name. span_ident ( )
62
- } else {
63
- field_name. span ( )
64
- } ) ;
65
- }
66
-
67
- if let Some ( default) = field_attrs. default {
68
- error. unsupported_attribute_within (
69
- default. span_ident ( ) ,
70
- UnsupportedAttribute :: Default ,
71
- ) ;
72
- }
73
-
74
- let resolver_code = quote ! (
75
- & self . #field_name
76
- ) ;
77
-
78
- Some ( util:: GraphQLTypeDefinitionField {
79
- name,
80
- _type : field. ty ,
81
- args : Vec :: new ( ) ,
82
- description : field_attrs. description . map ( SpanContainer :: into_inner) ,
83
- deprecation : field_attrs. deprecation . map ( SpanContainer :: into_inner) ,
84
- resolver_code,
85
- default : None ,
86
- is_type_inferred : true ,
87
- is_async : false ,
88
- span,
89
- } )
90
- } )
92
+ . filter_map ( |field| create_field_definition ( field, & error) )
91
93
. collect :: < Vec < _ > > ( ) ;
92
94
95
+ if let Some ( duplicates) = Duplicate :: find_by_key ( & fields, |field| field. name . as_str ( ) ) {
96
+ error. duplicate ( duplicates. iter ( ) ) ;
97
+ }
98
+
99
+ if fields. is_empty ( ) {
100
+ error. not_empty ( ast_span) ;
101
+ }
102
+
93
103
// Early abort after checking all fields
94
104
proc_macro_error:: abort_if_dirty ( ) ;
95
105
@@ -99,12 +109,6 @@ pub fn build_derive_object(
99
109
} ) ;
100
110
}
101
111
102
- if let Some ( duplicates) =
103
- crate :: util:: duplicate:: Duplicate :: find_by_key ( & fields, |field| field. name . as_str ( ) )
104
- {
105
- error. duplicate ( duplicates. iter ( ) ) ;
106
- }
107
-
108
112
if name. starts_with ( "__" ) && !is_internal {
109
113
error. no_double_underscore ( if let Some ( name) = attrs. name {
110
114
name. span_ident ( )
@@ -113,10 +117,6 @@ pub fn build_derive_object(
113
117
} ) ;
114
118
}
115
119
116
- if fields. is_empty ( ) {
117
- error. not_empty ( ast_span) ;
118
- }
119
-
120
120
// Early abort after GraphQL properties
121
121
proc_macro_error:: abort_if_dirty ( ) ;
122
122
@@ -130,10 +130,64 @@ pub fn build_derive_object(
130
130
generics : ast. generics ,
131
131
interfaces : None ,
132
132
include_type_generics : true ,
133
+ include_struct_fields : false ,
133
134
generic_scalar : true ,
134
135
no_async : attrs. no_async . is_some ( ) ,
135
136
} ;
136
137
137
138
let juniper_crate_name = if is_internal { "crate" } else { "juniper" } ;
138
139
Ok ( definition. into_tokens ( juniper_crate_name) )
139
140
}
141
+
142
+ pub fn build_derive_object_info (
143
+ ast : syn:: DeriveInput ,
144
+ is_internal : bool ,
145
+ error : GraphQLScope ,
146
+ ) -> syn:: Result < TokenStream > {
147
+ let ast_span = ast. span ( ) ;
148
+ let struct_fields = match ast. data {
149
+ Data :: Struct ( data) => match data. fields {
150
+ Fields :: Named ( fields) => fields. named ,
151
+ _ => return Err ( error. custom_error ( ast_span, "only named fields are allowed" ) ) ,
152
+ } ,
153
+ _ => return Err ( error. custom_error ( ast_span, "can only be applied to structs" ) ) ,
154
+ } ;
155
+
156
+ // Parse attributes.
157
+ let attrs = util:: ObjectInfoAttributes :: from_attrs ( & ast. attrs ) ?;
158
+
159
+ let ident = & ast. ident ;
160
+ let fields = struct_fields
161
+ . into_iter ( )
162
+ . filter_map ( |field| create_field_definition ( field, & error) )
163
+ . collect :: < Vec < _ > > ( ) ;
164
+
165
+ if let Some ( duplicates) = Duplicate :: find_by_key ( & fields, |field| field. name . as_str ( ) ) {
166
+ error. duplicate ( duplicates. iter ( ) ) ;
167
+ }
168
+
169
+ if fields. is_empty ( ) {
170
+ error. not_empty ( ast_span) ;
171
+ }
172
+
173
+ // Early abort after checking all fields
174
+ proc_macro_error:: abort_if_dirty ( ) ;
175
+
176
+ let definition = util:: GraphQLTypeDefiniton {
177
+ name : ident. unraw ( ) . to_string ( ) ,
178
+ _type : syn:: parse_str ( & ast. ident . to_string ( ) ) . unwrap ( ) ,
179
+ context : attrs. context . map ( SpanContainer :: into_inner) ,
180
+ scalar : attrs. scalar . map ( SpanContainer :: into_inner) ,
181
+ description : None ,
182
+ fields,
183
+ generics : ast. generics ,
184
+ interfaces : None ,
185
+ include_type_generics : true ,
186
+ include_struct_fields : false ,
187
+ generic_scalar : true ,
188
+ no_async : false ,
189
+ } ;
190
+
191
+ let juniper_crate_name = if is_internal { "crate" } else { "juniper" } ;
192
+ Ok ( definition. into_info_tokens ( juniper_crate_name) )
193
+ }
0 commit comments