1
1
import {
2
2
buildSchema ,
3
+ GraphQLFieldConfig ,
3
4
GraphQLFieldConfigMap ,
4
- GraphQLFieldMap ,
5
5
GraphQLInterfaceType ,
6
6
GraphQLList ,
7
7
GraphQLNamedType ,
@@ -17,7 +17,6 @@ import {
17
17
validateSchema ,
18
18
} from "graphql" ;
19
19
import type { Maybe } from "graphql/jsutils/Maybe" ;
20
- import { ObjMap } from "graphql/jsutils/ObjMap" ;
21
20
import { readFile , writeFile } from "node:fs/promises" ;
22
21
import { parseArgs } from "node:util" ;
23
22
@@ -75,84 +74,20 @@ function makeConvertType(toStrict: boolean) {
75
74
function convertFields ( fields : GraphQLFieldConfigMap < any , any > ) {
76
75
return ( ) => {
77
76
return Object . fromEntries (
78
- Object . entries ( fields ) . map ( ( [ fieldName , spec ] ) => {
79
- const directive = spec . astNode ?. directives ?. find (
80
- ( d ) => d . name . value === "semanticNonNull" ,
81
- ) ;
82
- const levelsArg = directive ?. arguments ?. find (
83
- ( a ) => a . name . value === "levels" ,
84
- ) ;
85
- const levels =
86
- levelsArg ?. value ?. kind === Kind . LIST
87
- ? levelsArg . value . values
88
- . filter ( ( v ) => v . kind === Kind . INT )
89
- . map ( ( v ) => Number ( v . value ) )
90
- : [ 0 ] ;
91
- const type = directive
92
- ? applySemanticNonNull ( spec . type , levels )
93
- : spec . type ;
77
+ Object . entries ( fields ) . map ( ( [ fieldName , inSpec ] ) => {
78
+ const spec = applySemanticNonNullDirective ( inSpec ) ;
94
79
return [
95
80
fieldName ,
96
81
{
97
82
...spec ,
98
- type : convertType ( type ) ,
99
- astNode : spec . astNode
100
- ? {
101
- ...spec . astNode ,
102
- directives : spec . astNode . directives ?. filter (
103
- ( d ) => d . name . value !== "semanticNonNull" ,
104
- ) ,
105
- }
106
- : undefined ,
83
+ type : convertType ( spec . type ) ,
107
84
} ,
108
85
] ;
109
86
} ) ,
110
87
) as any ;
111
88
} ;
112
89
}
113
90
114
- /**
115
- * Takes a GraphQL type along with levels at which to apply
116
- * semantic-non-null, and returns a converted type with these levels applied.
117
- */
118
- function applySemanticNonNull ( type : GraphQLOutputType , levels : number [ ] ) {
119
- function recurse (
120
- type : GraphQLOutputType ,
121
- level : number ,
122
- ) : GraphQLOutputType {
123
- if ( type instanceof GraphQLSemanticNonNull ) {
124
- // Strip semantic-non-null types; this should never happen but if someone
125
- // uses both semantic-non-null and the `@semanticNonNull` directive, we
126
- // want the directive to win (I guess?)
127
- return recurse ( type . ofType , level ) ;
128
- } else if ( type instanceof GraphQLNonNull ) {
129
- const inner = recurse ( type . ofType , level ) ;
130
- if ( levels . includes ( level ) ) {
131
- // Semantic non-null from `inner` replaces our GrpahQLNonNull wrapper
132
- return inner ;
133
- } else {
134
- // Keep non-null wrapper; no semantic-non-null was added to `inner`
135
- return new GraphQLNonNull ( inner ) ;
136
- }
137
- } else if ( type instanceof GraphQLList ) {
138
- const inner = new GraphQLList ( recurse ( type . ofType , level + 1 ) ) ;
139
- if ( levels . includes ( level ) ) {
140
- return new GraphQLSemanticNonNull ( inner ) ;
141
- } else {
142
- return inner ;
143
- }
144
- } else {
145
- if ( levels . includes ( level ) ) {
146
- return new GraphQLSemanticNonNull ( type ) ;
147
- } else {
148
- return type ;
149
- }
150
- }
151
- }
152
-
153
- return recurse ( type , 0 ) ;
154
- }
155
-
156
91
function convertTypes (
157
92
types : readonly GraphQLInterfaceType [ ] | null | undefined ,
158
93
) : undefined | ( ( ) => readonly GraphQLInterfaceType [ ] ) ;
@@ -231,3 +166,68 @@ function makeConvertType(toStrict: boolean) {
231
166
232
167
return convertType ;
233
168
}
169
+
170
+ /**
171
+ * Takes a GraphQL type along with levels at which to apply
172
+ * semantic-non-null, and returns a converted type with these levels applied.
173
+ */
174
+ function applySemanticNonNullDirective (
175
+ spec : GraphQLFieldConfig < any , any , any > ,
176
+ ) : GraphQLFieldConfig < any , any , any > {
177
+ const directive = spec . astNode ?. directives ?. find (
178
+ ( d ) => d . name . value === "semanticNonNull" ,
179
+ ) ;
180
+ if ( ! directive ) {
181
+ return spec ;
182
+ }
183
+ const levelsArg = directive . arguments ?. find ( ( a ) => a . name . value === "levels" ) ;
184
+ const levels =
185
+ levelsArg ?. value ?. kind === Kind . LIST
186
+ ? levelsArg . value . values
187
+ . filter ( ( v ) => v . kind === Kind . INT )
188
+ . map ( ( v ) => Number ( v . value ) )
189
+ : [ 0 ] ;
190
+ function recurse ( type : GraphQLOutputType , level : number ) : GraphQLOutputType {
191
+ if ( type instanceof GraphQLSemanticNonNull ) {
192
+ // Strip semantic-non-null types; this should never happen but if someone
193
+ // uses both semantic-non-null and the `@semanticNonNull` directive, we
194
+ // want the directive to win (I guess?)
195
+ return recurse ( type . ofType , level ) ;
196
+ } else if ( type instanceof GraphQLNonNull ) {
197
+ const inner = recurse ( type . ofType , level ) ;
198
+ if ( levels . includes ( level ) ) {
199
+ // Semantic non-null from `inner` replaces our GrpahQLNonNull wrapper
200
+ return inner ;
201
+ } else {
202
+ // Keep non-null wrapper; no semantic-non-null was added to `inner`
203
+ return new GraphQLNonNull ( inner ) ;
204
+ }
205
+ } else if ( type instanceof GraphQLList ) {
206
+ const inner = new GraphQLList ( recurse ( type . ofType , level + 1 ) ) ;
207
+ if ( levels . includes ( level ) ) {
208
+ return new GraphQLSemanticNonNull ( inner ) ;
209
+ } else {
210
+ return inner ;
211
+ }
212
+ } else {
213
+ if ( levels . includes ( level ) ) {
214
+ return new GraphQLSemanticNonNull ( type ) ;
215
+ } else {
216
+ return type ;
217
+ }
218
+ }
219
+ }
220
+
221
+ return {
222
+ ...spec ,
223
+ type : recurse ( spec . type , 0 ) ,
224
+ astNode : spec . astNode
225
+ ? {
226
+ ...spec . astNode ,
227
+ directives : spec . astNode . directives ?. filter (
228
+ ( d ) => d . name . value !== "semanticNonNull" ,
229
+ ) ,
230
+ }
231
+ : undefined ,
232
+ } ;
233
+ }
0 commit comments