Mirror: The spec-compliant minimum of client-side GraphQL.
1import { Kind } from './kind'; 2import { ASTNode } from './ast'; 3 4export function printString(string: string) { 5 return JSON.stringify(string); 6} 7 8export function printBlockString(string: string) { 9 return '"""\n' + string.replace(/"""/g, '\\"""') + '\n"""'; 10} 11 12const hasItems = <T>( 13 array: ReadonlyArray<T> | undefined | null 14): array is ReadonlyArray<T> => !!(array && array.length); 15 16const MAX_LINE_LENGTH = 80; 17 18export function print(node: ASTNode): string { 19 let out: string; 20 switch (node.kind) { 21 case Kind.OPERATION_DEFINITION: 22 if (node.operation === 'query' && !node.name && !hasItems(node.variableDefinitions) && !hasItems(node.directives)) { 23 return print(node.selectionSet); 24 } 25 out = node.operation; 26 if (node.name) 27 out += ' ' + node.name.value; 28 if (hasItems(node.variableDefinitions)) { 29 if (!node.name) out += ' '; 30 out += '(' + node.variableDefinitions.map(print).join(', ') + ')'; 31 } 32 if (hasItems(node.directives)) 33 out += ' ' + node.directives.map(print).join(' '); 34 return out + ' ' + print(node.selectionSet); 35 36 case Kind.VARIABLE_DEFINITION: 37 out = print(node.variable) + 38 ': ' + 39 print(node.type); 40 if (node.defaultValue) 41 out += ' = ' + print(node.defaultValue); 42 if (hasItems(node.directives)) 43 out += ' ' + node.directives.map(print).join(' '); 44 return out; 45 46 case Kind.FIELD: 47 out = (node.alias ? print(node.alias) + ': ' : '') + node.name.value 48 if (hasItems(node.arguments)) { 49 const args = node.arguments.map(print); 50 const argsLine = out + '(' + args.join(', ') + ')'; 51 out = argsLine.length > MAX_LINE_LENGTH 52 ? out + '(\n ' + args.join('\n').replace(/\n/g, '\n ') + '\n)' 53 : argsLine; 54 } 55 if (hasItems(node.directives)) 56 out += ' ' + node.directives.map(print).join(' '); 57 return node.selectionSet 58 ? out + ' ' + print(node.selectionSet) 59 : out; 60 61 case Kind.STRING: 62 return node.block 63 ? printBlockString(node.value) 64 : printString(node.value); 65 66 case Kind.BOOLEAN: 67 return '' + node.value; 68 69 case Kind.NULL: 70 return 'null'; 71 72 case Kind.INT: 73 case Kind.FLOAT: 74 case Kind.ENUM: 75 case Kind.NAME: 76 return node.value; 77 78 case Kind.LIST: 79 return '[' + node.values.map(print).join(', ') + ']'; 80 81 case Kind.OBJECT: 82 return '{' + node.fields.map(print).join(', ') + '}'; 83 84 case Kind.OBJECT_FIELD: 85 return node.name.value + ': ' + print(node.value); 86 87 case Kind.VARIABLE: 88 return '$' + node.name.value; 89 90 case Kind.DOCUMENT: 91 return hasItems(node.definitions) 92 ? node.definitions.map(print).join('\n\n') 93 : ''; 94 95 case Kind.SELECTION_SET: 96 return '{\n ' + 97 node.selections.map(print).join('\n').replace(/\n/g, '\n ') + 98 '\n}'; 99 100 case Kind.ARGUMENT: 101 return node.name.value + ': ' + print(node.value); 102 103 case Kind.FRAGMENT_SPREAD: 104 out = '...' + node.name.value; 105 if (hasItems(node.directives)) 106 out += ' ' + node.directives.map(print).join(' '); 107 return out; 108 109 case Kind.INLINE_FRAGMENT: 110 out = '...'; 111 if (node.typeCondition) 112 out += ' on ' + node.typeCondition.name.value; 113 if (hasItems(node.directives)) 114 out += ' ' + node.directives.map(print).join(' '); 115 return out + ' ' + print(node.selectionSet); 116 117 case Kind.FRAGMENT_DEFINITION: 118 out = 'fragment ' + node.name.value; 119 out += ' on ' + node.typeCondition.name.value; 120 if (hasItems(node.directives)) 121 out += ' ' + node.directives.map(print).join(' '); 122 return out + ' ' + print(node.selectionSet); 123 124 case Kind.DIRECTIVE: 125 out = '@' + node.name.value; 126 if (hasItems(node.arguments)) 127 out += '(' + node.arguments.map(print).join(', ') + ')'; 128 return out; 129 130 case Kind.NAMED_TYPE: 131 return node.name.value; 132 133 case Kind.LIST_TYPE: 134 return '[' + print(node.type) + ']'; 135 136 case Kind.NON_NULL_TYPE: 137 return print(node.type) + '!'; 138 } 139}