@@ -4,11 +4,11 @@ use serde::Deserialize;
4
4
use std:: path:: { Path , PathBuf } ;
5
5
use swc_core:: {
6
6
atoms:: Atom ,
7
- common:: { util :: take :: Take , Span } ,
7
+ common:: Span ,
8
8
ecma:: {
9
9
ast:: * ,
10
10
utils:: { prepend_stmts, quote_ident} ,
11
- visit:: { visit_mut_pass , VisitMut , VisitMutWith } ,
11
+ visit:: { fold_pass , Fold , FoldWith } ,
12
12
} ,
13
13
plugin:: {
14
14
errors:: HANDLER , metadata:: TransformPluginMetadataContextKind , plugin_transform,
@@ -30,16 +30,16 @@ pub struct GraphQLCodegenOptions {
30
30
pub gql_tag_name : String ,
31
31
}
32
32
33
- pub struct GraphQLVisitor {
33
+ pub struct GraphQLCodegen {
34
34
options : GraphQLCodegenOptions ,
35
- graphql_operations_or_fragments_to_import : Vec < GraphQLModuleItem > ,
35
+ imports : Vec < GraphQLModuleItem > ,
36
36
}
37
37
38
- impl GraphQLVisitor {
38
+ impl GraphQLCodegen {
39
39
pub fn new ( options : GraphQLCodegenOptions ) -> Self {
40
- GraphQLVisitor {
40
+ GraphQLCodegen {
41
41
options,
42
- graphql_operations_or_fragments_to_import : Vec :: new ( ) ,
42
+ imports : Vec :: new ( ) ,
43
43
}
44
44
}
45
45
@@ -77,120 +77,103 @@ impl GraphQLVisitor {
77
77
let platform_specific_path = start_of_path. to_string ( ) + relative. to_str ( ) . unwrap ( ) ;
78
78
platform_specific_path. replace ( '\\' , "/" )
79
79
}
80
- }
81
80
82
- pub fn create_graphql_codegen_visitor ( options : GraphQLCodegenOptions ) -> impl VisitMut {
83
- GraphQLVisitor :: new ( options)
84
- }
81
+ fn build_call_expr_from_call ( & mut self , call : & CallExpr ) -> Option < Expr > {
82
+ let ident = call. callee . as_expr ( ) ?. as_ident ( ) ?;
83
+ if & * ident. sym != self . options . gql_tag_name . as_str ( ) {
84
+ return None ;
85
+ }
85
86
86
- impl VisitMut for GraphQLVisitor {
87
- fn visit_mut_var_decl ( & mut self , e : & mut VarDecl ) {
88
- e. visit_mut_children_with ( self ) ;
87
+ if call. args . is_empty ( ) {
88
+ self . handle_error ( "missing GraphQL query" , call. span ) ;
89
+ return None ;
90
+ }
89
91
90
- for decl in e. decls . iter_mut ( ) {
91
- if let Some ( init) = & mut decl. init {
92
- if let Expr :: Call ( CallExpr { callee, args, .. } ) = & mut * * init {
93
- if args. is_empty ( ) {
94
- return ;
95
- }
92
+ let tpl = & dbg ! ( & call. args[ 0 ] . expr) . as_tpl ( ) ?;
93
+ let graphql_ast = tpl. quasis . iter ( ) . find_map ( |quasis| {
94
+ match parse_query :: < & str > ( dbg ! ( quasis. cooked. as_ref( ) ?) ) {
95
+ Ok ( ast) => Some ( ast) ,
96
+ Err ( e) => {
97
+ // Currently the parser outputs a string like: "query parse error", so we add "GraphQL" to the beginning
98
+ let error = format ! ( "GraphQL {}" , e) ;
99
+ self . handle_error ( error. as_str ( ) , quasis. span ) ;
100
+ return None ;
101
+ }
102
+ }
103
+ } ) ?;
104
+
105
+ let first_definition = match graphql_ast. definitions . get ( 0 ) {
106
+ Some ( definition) => definition,
107
+ None => return None ,
108
+ } ;
96
109
97
- match callee. as_expr ( ) {
98
- Some ( expr_box) => match & * * expr_box {
99
- Expr :: Ident ( ident) => {
100
- if & ident. sym != self . options . gql_tag_name . as_str ( ) {
101
- return ;
102
- }
103
- }
104
- _ => return ,
105
- } ,
106
- _ => return ,
110
+ let operation_name = match first_definition {
111
+ graphql_parser:: query:: Definition :: Fragment ( fragment) => {
112
+ fragment. name . to_string ( ) + "FragmentDoc"
113
+ }
114
+ graphql_parser:: query:: Definition :: Operation ( op) => match op {
115
+ graphql_parser:: query:: OperationDefinition :: Query ( query) => match query. name {
116
+ Some ( name) => name. to_string ( ) + "Document" ,
117
+ None => return None ,
118
+ } ,
119
+ graphql_parser:: query:: OperationDefinition :: Mutation ( mutation) => {
120
+ match mutation. name {
121
+ Some ( name) => name. to_string ( ) + "Document" ,
122
+ None => return None ,
123
+ }
124
+ }
125
+ graphql_parser:: query:: OperationDefinition :: Subscription ( subscription) => {
126
+ match subscription. name {
127
+ Some ( name) => name. to_string ( ) + "Document" ,
128
+ None => return None ,
107
129
}
130
+ }
131
+ _ => return None ,
132
+ } ,
133
+ } ;
134
+
135
+ let capitalized_operation_name: Atom = capitalize ( & operation_name) . into ( ) ;
136
+ self . imports . push ( GraphQLModuleItem {
137
+ operation_or_fragment_name : capitalized_operation_name. clone ( ) ,
138
+ } ) ;
139
+
140
+ // now change the call expression to a Identifier
141
+ Some ( Expr :: Ident ( quote_ident ! ( capitalized_operation_name) . into ( ) ) )
142
+ }
143
+ }
108
144
109
- let quasis = match & * args[ 0 ] . expr {
110
- Expr :: Tpl ( tpl) => & tpl. quasis ,
111
- _ => return ,
112
- } ;
113
-
114
- let raw = match & quasis[ 0 ] . cooked {
115
- Some ( cooked) => cooked,
116
- None => return ,
117
- } ;
118
-
119
- let graphql_ast = match parse_query :: < & str > ( raw) {
120
- Ok ( ast) => ast,
121
- Err ( e) => {
122
- // Currently the parser outputs a string like: "query parse error", so we add "GraphQL" to the beginning
123
- let error = format ! ( "GraphQL {}" , e) ;
124
- self . handle_error ( error. as_str ( ) , quasis[ 0 ] . span ) ;
125
- return ;
126
- }
127
- } ;
128
-
129
- let first_definition = match graphql_ast. definitions . get ( 0 ) {
130
- Some ( definition) => definition,
131
- None => return ,
132
- } ;
133
-
134
- let operation_name = match first_definition {
135
- graphql_parser:: query:: Definition :: Fragment ( fragment) => {
136
- fragment. name . to_string ( ) + "FragmentDoc"
137
- }
138
- graphql_parser:: query:: Definition :: Operation ( op) => match op {
139
- graphql_parser:: query:: OperationDefinition :: Query ( query) => {
140
- match query. name {
141
- Some ( name) => name. to_string ( ) + "Document" ,
142
- None => return ,
143
- }
144
- }
145
- graphql_parser:: query:: OperationDefinition :: Mutation ( mutation) => {
146
- match mutation. name {
147
- Some ( name) => name. to_string ( ) + "Document" ,
148
- None => return ,
149
- }
150
- }
151
- graphql_parser:: query:: OperationDefinition :: Subscription (
152
- subscription,
153
- ) => match subscription. name {
154
- Some ( name) => name. to_string ( ) + "Document" ,
155
- None => return ,
156
- } ,
157
- _ => return ,
158
- } ,
159
- } ;
160
-
161
- let capitalized_operation_name: Atom = capitalize ( & operation_name) . into ( ) ;
162
- self . graphql_operations_or_fragments_to_import
163
- . push ( GraphQLModuleItem {
164
- operation_or_fragment_name : capitalized_operation_name. clone ( ) ,
165
- } ) ;
166
-
167
- // now change the call expression to a Identifier
168
- let new_expr = Expr :: Ident ( quote_ident ! ( capitalized_operation_name) . into ( ) ) ;
169
-
170
- * init = Box :: new ( new_expr) ;
145
+ impl Fold for GraphQLCodegen {
146
+ fn fold_expr ( & mut self , expr : Expr ) -> Expr {
147
+ let expr = expr. fold_children_with ( self ) ;
148
+ match & expr {
149
+ Expr :: Call ( call) => {
150
+ if let Some ( built_expr) = dbg ! ( self . build_call_expr_from_call( call) ) {
151
+ built_expr
152
+ } else {
153
+ expr
171
154
}
172
155
}
156
+ _ => expr,
173
157
}
174
158
}
175
159
176
- fn visit_mut_module ( & mut self , module : & mut Module ) {
177
- // First visit all its children, collect the GraphQL document names, and then add the necessary imports
178
- module. visit_mut_children_with ( self ) ;
179
-
180
- if self . graphql_operations_or_fragments_to_import . is_empty ( ) {
181
- return ;
182
- }
160
+ fn fold_module_items ( & mut self , items : Vec < ModuleItem > ) -> Vec < ModuleItem > {
161
+ // First fold all its children, collect the GraphQL document names, and then add the necessary imports
162
+ let mut items = items
163
+ . into_iter ( )
164
+ . map ( |item| item. fold_children_with ( self ) )
165
+ . collect :: < Vec < _ > > ( ) ;
183
166
184
167
let platform_specific_path: Atom = self . get_relative_import_path ( "graphql" ) . into ( ) ;
185
168
186
- let mut items = module. body . take ( ) ;
187
169
prepend_stmts (
188
170
& mut items,
189
- self . graphql_operations_or_fragments_to_import
171
+ self . imports
190
172
. iter ( )
191
173
. map ( |module_item| module_item. as_module_item ( platform_specific_path. clone ( ) ) ) ,
192
174
) ;
193
- module. body = items;
175
+
176
+ items
194
177
}
195
178
}
196
179
@@ -249,12 +232,11 @@ pub fn process_transform(program: Program, metadata: TransformPluginProgramMetad
249
232
panic ! ( "artifactDirectory is not present in the config for @graphql-codegen/client-preset-swc-plugin" ) ;
250
233
}
251
234
252
- let visitor = create_graphql_codegen_visitor ( GraphQLCodegenOptions {
235
+ let pass = fold_pass ( GraphQLCodegen :: new ( GraphQLCodegenOptions {
253
236
filename,
254
237
cwd,
255
238
artifact_directory,
256
239
gql_tag_name : plugin_config. gqlTagName ,
257
- } ) ;
258
-
259
- program. apply ( & mut visit_mut_pass ( visitor) )
240
+ } ) ) ;
241
+ program. apply ( pass)
260
242
}
0 commit comments