Mirror: The spec-compliant minimum of client-side GraphQL.
1import { ASTNode } from './ast'; 2 3export function printString(string: string) { 4 return JSON.stringify(string); 5} 6 7export function printBlockString(string: string) { 8 return '"""\n' + string.replace(/"""/g, '\\"""') + '\n"""'; 9} 10 11const hasItems = <T>(array: ReadonlyArray<T> | undefined | null): array is ReadonlyArray<T> => 12 !!(array && array.length); 13 14const MAX_LINE_LENGTH = 80; 15 16export function print(node: ASTNode): string { 17 let out: string; 18 switch (node.kind) { 19 case 'OperationDefinition': 20 if ( 21 node.operation === 'query' && 22 !node.name && 23 !hasItems(node.variableDefinitions) && 24 !hasItems(node.directives) 25 ) { 26 return print(node.selectionSet); 27 } 28 out = node.operation; 29 if (node.name) out += ' ' + node.name.value; 30 if (hasItems(node.variableDefinitions)) { 31 if (!node.name) out += ' '; 32 out += '(' + node.variableDefinitions.map(print).join(', ') + ')'; 33 } 34 if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 35 return out + ' ' + print(node.selectionSet); 36 37 case 'VariableDefinition': 38 out = print(node.variable) + ': ' + print(node.type); 39 if (node.defaultValue) out += ' = ' + print(node.defaultValue); 40 if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 41 return out; 42 43 case 'Field': 44 out = (node.alias ? print(node.alias) + ': ' : '') + node.name.value; 45 if (hasItems(node.arguments)) { 46 const args = node.arguments.map(print); 47 const argsLine = out + '(' + args.join(', ') + ')'; 48 out = 49 argsLine.length > MAX_LINE_LENGTH 50 ? out + '(\n ' + args.join('\n').replace(/\n/g, '\n ') + '\n)' 51 : argsLine; 52 } 53 if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 54 return node.selectionSet ? out + ' ' + print(node.selectionSet) : out; 55 56 case 'StringValue': 57 return node.block ? printBlockString(node.value) : printString(node.value); 58 59 case 'BooleanValue': 60 return '' + node.value; 61 62 case 'NullValue': 63 return 'null'; 64 65 case 'IntValue': 66 case 'FloatValue': 67 case 'EnumValue': 68 case 'Name': 69 return node.value; 70 71 case 'ListValue': 72 return '[' + node.values.map(print).join(', ') + ']'; 73 74 case 'ObjectValue': 75 return '{' + node.fields.map(print).join(', ') + '}'; 76 77 case 'ObjectField': 78 return node.name.value + ': ' + print(node.value); 79 80 case 'Variable': 81 return '$' + node.name.value; 82 83 case 'Document': 84 return hasItems(node.definitions) ? node.definitions.map(print).join('\n\n') : ''; 85 86 case 'SelectionSet': 87 return '{\n ' + node.selections.map(print).join('\n').replace(/\n/g, '\n ') + '\n}'; 88 89 case 'Argument': 90 return node.name.value + ': ' + print(node.value); 91 92 case 'FragmentSpread': 93 out = '...' + node.name.value; 94 if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 95 return out; 96 97 case 'InlineFragment': 98 out = '...'; 99 if (node.typeCondition) out += ' on ' + node.typeCondition.name.value; 100 if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 101 return out + ' ' + print(node.selectionSet); 102 103 case 'FragmentDefinition': 104 out = 'fragment ' + node.name.value; 105 out += ' on ' + node.typeCondition.name.value; 106 if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 107 return out + ' ' + print(node.selectionSet); 108 109 case 'Directive': 110 out = '@' + node.name.value; 111 if (hasItems(node.arguments)) out += '(' + node.arguments.map(print).join(', ') + ')'; 112 return out; 113 114 case 'NamedType': 115 return node.name.value; 116 117 case 'ListType': 118 return '[' + print(node.type) + ']'; 119 120 case 'NonNullType': 121 return print(node.type) + '!'; 122 123 default: 124 return ''; 125 } 126}