@@ -23,17 +23,18 @@ const printDocASTReducer: ASTReducer<string> = {
2323 // Document
2424
2525 Document : {
26- leave : ( node ) => join ( node . definitions , '\n\n' ) ,
26+ leave : ( node ) => truthyJoin ( node . definitions , '\n\n' ) ,
2727 } ,
2828
2929 OperationDefinition : {
3030 leave ( node ) {
31- const varDefs = wrap ( '(' , join ( node . variableDefinitions , ', ' ) , ')' ) ;
31+ const varDefs = wrap ( '(' , truthyJoin ( node . variableDefinitions , ', ' ) , ')' ) ;
3232 const prefix = join (
3333 [
3434 node . operation ,
35+ // TODO: optimize
3536 join ( [ node . name , varDefs ] ) ,
36- join ( node . directives , ' ' ) ,
37+ truthyJoin ( node . directives , ' ' ) ,
3738 ] ,
3839 ' ' ,
3940 ) ;
@@ -50,20 +51,20 @@ const printDocASTReducer: ASTReducer<string> = {
5051 ': ' +
5152 type +
5253 wrap ( ' = ' , defaultValue ) +
53- wrap ( ' ' , join ( directives , ' ' ) ) ,
54+ wrap ( ' ' , truthyJoin ( directives , ' ' ) ) ,
5455 } ,
5556 SelectionSet : { leave : ( { selections } ) => block ( selections ) } ,
5657
5758 Field : {
5859 leave ( { alias, name, arguments : args , directives, selectionSet } ) {
5960 const prefix = wrap ( '' , alias , ': ' ) + name ;
60- let argsLine = prefix + wrap ( '(' , join ( args , ', ' ) , ')' ) ;
61+ let argsLine = prefix + wrap ( '(' , truthyJoin ( args , ', ' ) , ')' ) ;
6162
6263 if ( argsLine . length > MAX_LINE_LENGTH ) {
63- argsLine = prefix + wrap ( '(\n' , indent ( join ( args , '\n' ) ) , '\n)' ) ;
64+ argsLine = prefix + wrap ( '(\n' , indent ( truthyJoin ( args , '\n' ) ) , '\n)' ) ;
6465 }
6566
66- return join ( [ argsLine , join ( directives , ' ' ) , selectionSet ] , ' ' ) ;
67+ return join ( [ argsLine , truthyJoin ( directives , ' ' ) , selectionSet ] , ' ' ) ;
6768 } ,
6869 } ,
6970
@@ -73,7 +74,7 @@ const printDocASTReducer: ASTReducer<string> = {
7374
7475 FragmentSpread : {
7576 leave : ( { name, directives } ) =>
76- '...' + name + wrap ( ' ' , join ( directives , ' ' ) ) ,
77+ '...' + name + wrap ( ' ' , truthyJoin ( directives , ' ' ) ) ,
7778 } ,
7879
7980 InlineFragment : {
@@ -82,7 +83,7 @@ const printDocASTReducer: ASTReducer<string> = {
8283 [
8384 '...' ,
8485 wrap ( 'on ' , typeCondition ) ,
85- join ( directives , ' ' ) ,
86+ truthyJoin ( directives , ' ' ) ,
8687 selectionSet ,
8788 ] ,
8889 ' ' ,
@@ -99,8 +100,8 @@ const printDocASTReducer: ASTReducer<string> = {
99100 } ) =>
100101 // Note: fragment variable definitions are experimental and may be changed
101102 // or removed in the future.
102- `fragment ${ name } ${ wrap ( '(' , join ( variableDefinitions , ', ' ) , ')' ) } ` +
103- `on ${ typeCondition } ${ wrap ( '' , join ( directives , ' ' ) , ' ' ) } ` +
103+ `fragment ${ name } ${ wrap ( '(' , truthyJoin ( variableDefinitions , ', ' ) , ')' ) } ` +
104+ `on ${ typeCondition } ${ wrap ( '' , truthyJoin ( directives , ' ' ) , ' ' ) } ` +
104105 selectionSet ,
105106 } ,
106107
@@ -115,15 +116,15 @@ const printDocASTReducer: ASTReducer<string> = {
115116 BooleanValue : { leave : ( { value } ) => ( value ? 'true' : 'false' ) } ,
116117 NullValue : { leave : ( ) => 'null' } ,
117118 EnumValue : { leave : ( { value } ) => value } ,
118- ListValue : { leave : ( { values } ) => '[' + join ( values , ', ' ) + ']' } ,
119- ObjectValue : { leave : ( { fields } ) => '{' + join ( fields , ', ' ) + '}' } ,
119+ ListValue : { leave : ( { values } ) => '[' + truthyJoin ( values , ', ' ) + ']' } ,
120+ ObjectValue : { leave : ( { fields } ) => '{' + truthyJoin ( fields , ', ' ) + '}' } ,
120121 ObjectField : { leave : ( { name, value } ) => name + ': ' + value } ,
121122
122123 // Directive
123124
124125 Directive : {
125126 leave : ( { name, arguments : args } ) =>
126- '@' + name + wrap ( '(' , join ( args , ', ' ) , ')' ) ,
127+ '@' + name + wrap ( '(' , truthyJoin ( args , ', ' ) , ')' ) ,
127128 } ,
128129
129130 // Type
@@ -147,7 +148,7 @@ const printDocASTReducer: ASTReducer<string> = {
147148 ScalarTypeDefinition : {
148149 leave : ( { description, name, directives } ) =>
149150 wrap ( '' , description , '\n' ) +
150- join ( [ 'scalar' , name , join ( directives , ' ' ) ] , ' ' ) ,
151+ join ( [ 'scalar' , name , truthyJoin ( directives , ' ' ) ] , ' ' ) ,
151152 } ,
152153
153154 ObjectTypeDefinition : {
@@ -157,8 +158,8 @@ const printDocASTReducer: ASTReducer<string> = {
157158 [
158159 'type' ,
159160 name ,
160- wrap ( 'implements ' , join ( interfaces , ' & ' ) ) ,
161- join ( directives , ' ' ) ,
161+ wrap ( 'implements ' , truthyJoin ( interfaces , ' & ' ) ) ,
162+ truthyJoin ( directives , ' ' ) ,
162163 block ( fields ) ,
163164 ] ,
164165 ' ' ,
@@ -170,18 +171,18 @@ const printDocASTReducer: ASTReducer<string> = {
170171 wrap ( '' , description , '\n' ) +
171172 name +
172173 ( hasMultilineItems ( args )
173- ? wrap ( '(\n' , indent ( join ( args , '\n' ) ) , '\n)' )
174- : wrap ( '(' , join ( args , ', ' ) , ')' ) ) +
174+ ? wrap ( '(\n' , indent ( truthyJoin ( args , '\n' ) ) , '\n)' )
175+ : wrap ( '(' , truthyJoin ( args , ', ' ) , ')' ) ) +
175176 ': ' +
176177 type +
177- wrap ( ' ' , join ( directives , ' ' ) ) ,
178+ wrap ( ' ' , truthyJoin ( directives , ' ' ) ) ,
178179 } ,
179180
180181 InputValueDefinition : {
181182 leave : ( { description, name, type, defaultValue, directives } ) =>
182183 wrap ( '' , description , '\n' ) +
183184 join (
184- [ name + ': ' + type , wrap ( '= ' , defaultValue ) , join ( directives , ' ' ) ] ,
185+ [ name + ': ' + type , wrap ( '= ' , defaultValue ) , truthyJoin ( directives , ' ' ) ] ,
185186 ' ' ,
186187 ) ,
187188 } ,
@@ -193,8 +194,8 @@ const printDocASTReducer: ASTReducer<string> = {
193194 [
194195 'interface' ,
195196 name ,
196- wrap ( 'implements ' , join ( interfaces , ' & ' ) ) ,
197- join ( directives , ' ' ) ,
197+ wrap ( 'implements ' , truthyJoin ( interfaces , ' & ' ) ) ,
198+ truthyJoin ( directives , ' ' ) ,
198199 block ( fields ) ,
199200 ] ,
200201 ' ' ,
@@ -205,26 +206,26 @@ const printDocASTReducer: ASTReducer<string> = {
205206 leave : ( { description, name, directives, types } ) =>
206207 wrap ( '' , description , '\n' ) +
207208 join (
208- [ 'union' , name , join ( directives , ' ' ) , wrap ( '= ' , join ( types , ' | ' ) ) ] ,
209+ [ 'union' , name , truthyJoin ( directives , ' ' ) , wrap ( '= ' , truthyJoin ( types , ' | ' ) ) ] ,
209210 ' ' ,
210211 ) ,
211212 } ,
212213
213214 EnumTypeDefinition : {
214215 leave : ( { description, name, directives, values } ) =>
215216 wrap ( '' , description , '\n' ) +
216- join ( [ 'enum' , name , join ( directives , ' ' ) , block ( values ) ] , ' ' ) ,
217+ join ( [ 'enum' , name , truthyJoin ( directives , ' ' ) , block ( values ) ] , ' ' ) ,
217218 } ,
218219
219220 EnumValueDefinition : {
220221 leave : ( { description, name, directives } ) =>
221- wrap ( '' , description , '\n' ) + join ( [ name , join ( directives , ' ' ) ] , ' ' ) ,
222+ wrap ( '' , description , '\n' ) + join ( [ name , truthyJoin ( directives , ' ' ) ] , ' ' ) ,
222223 } ,
223224
224225 InputObjectTypeDefinition : {
225226 leave : ( { description, name, directives, fields } ) =>
226227 wrap ( '' , description , '\n' ) +
227- join ( [ 'input' , name , join ( directives , ' ' ) , block ( fields ) ] , ' ' ) ,
228+ join ( [ 'input' , name , truthyJoin ( directives , ' ' ) , block ( fields ) ] , ' ' ) ,
228229 } ,
229230
230231 DirectiveDefinition : {
@@ -233,24 +234,24 @@ const printDocASTReducer: ASTReducer<string> = {
233234 'directive @' +
234235 name +
235236 ( hasMultilineItems ( args )
236- ? wrap ( '(\n' , indent ( join ( args , '\n' ) ) , '\n)' )
237- : wrap ( '(' , join ( args , ', ' ) , ')' ) ) +
237+ ? wrap ( '(\n' , indent ( truthyJoin ( args , '\n' ) ) , '\n)' )
238+ : wrap ( '(' , truthyJoin ( args , ', ' ) , ')' ) ) +
238239 ( repeatable ? ' repeatable' : '' ) +
239240 ' on ' +
240- join ( locations , ' | ' ) ,
241+ truthyJoin ( locations , ' | ' ) ,
241242 } ,
242243
243244 SchemaExtension : {
244245 leave : ( { directives, operationTypes } ) =>
245246 join (
246- [ 'extend schema' , join ( directives , ' ' ) , block ( operationTypes ) ] ,
247+ [ 'extend schema' , truthyJoin ( directives , ' ' ) , block ( operationTypes ) ] ,
247248 ' ' ,
248249 ) ,
249250 } ,
250251
251252 ScalarTypeExtension : {
252253 leave : ( { name, directives } ) =>
253- join ( [ 'extend scalar' , name , join ( directives , ' ' ) ] , ' ' ) ,
254+ join ( [ 'extend scalar' , name , truthyJoin ( directives , ' ' ) ] , ' ' ) ,
254255 } ,
255256
256257 ObjectTypeExtension : {
@@ -259,8 +260,8 @@ const printDocASTReducer: ASTReducer<string> = {
259260 [
260261 'extend type' ,
261262 name ,
262- wrap ( 'implements ' , join ( interfaces , ' & ' ) ) ,
263- join ( directives , ' ' ) ,
263+ wrap ( 'implements ' , truthyJoin ( interfaces , ' & ' ) ) ,
264+ truthyJoin ( directives , ' ' ) ,
264265 block ( fields ) ,
265266 ] ,
266267 ' ' ,
@@ -273,8 +274,8 @@ const printDocASTReducer: ASTReducer<string> = {
273274 [
274275 'extend interface' ,
275276 name ,
276- wrap ( 'implements ' , join ( interfaces , ' & ' ) ) ,
277- join ( directives , ' ' ) ,
277+ wrap ( 'implements ' , truthyJoin ( interfaces , ' & ' ) ) ,
278+ truthyJoin ( directives , ' ' ) ,
278279 block ( fields ) ,
279280 ] ,
280281 ' ' ,
@@ -287,21 +288,21 @@ const printDocASTReducer: ASTReducer<string> = {
287288 [
288289 'extend union' ,
289290 name ,
290- join ( directives , ' ' ) ,
291- wrap ( '= ' , join ( types , ' | ' ) ) ,
291+ truthyJoin ( directives , ' ' ) ,
292+ wrap ( '= ' , truthyJoin ( types , ' | ' ) ) ,
292293 ] ,
293294 ' ' ,
294295 ) ,
295296 } ,
296297
297298 EnumTypeExtension : {
298299 leave : ( { name, directives, values } ) =>
299- join ( [ 'extend enum' , name , join ( directives , ' ' ) , block ( values ) ] , ' ' ) ,
300+ join ( [ 'extend enum' , name , truthyJoin ( directives , ' ' ) , block ( values ) ] , ' ' ) ,
300301 } ,
301302
302303 InputObjectTypeExtension : {
303304 leave : ( { name, directives, fields } ) =>
304- join ( [ 'extend input' , name , join ( directives , ' ' ) , block ( fields ) ] , ' ' ) ,
305+ join ( [ 'extend input' , name , truthyJoin ( directives , ' ' ) , block ( fields ) ] , ' ' ) ,
305306 } ,
306307} ;
307308
@@ -313,7 +314,30 @@ function join(
313314 maybeArray : Maybe < ReadonlyArray < string | undefined > > ,
314315 separator = '' ,
315316) : string {
316- return maybeArray ?. filter ( ( x ) => x ) . join ( separator ) ?? '' ;
317+ if ( ! maybeArray ) return ''
318+
319+ const list = maybeArray . filter ( ( x ) => x ) ;
320+ const listLength = list . length ;
321+ let result = '' ;
322+ for ( let i = 0 ; i < listLength ; i ++ ) {
323+ if ( i === listLength - 1 ) return result + list [ i ] ;
324+ else result += list [ i ] + separator ;
325+ }
326+ return result
327+ }
328+
329+ function truthyJoin (
330+ list : ReadonlyArray < string > | undefined ,
331+ separator : string ,
332+ ) : string {
333+ if ( ! list ) return ''
334+ const listLength = list . length ;
335+ let result = '' ;
336+ for ( let i = 0 ; i < listLength ; i ++ ) {
337+ if ( i === listLength - 1 ) return result + list [ i ] ;
338+ else result += list [ i ] + separator ;
339+ }
340+ return result
317341}
318342
319343/**
0 commit comments