Mirror: The spec-compliant minimum of client-side GraphQL.
1import type { 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 16const nodes: { 17 [NodeT in ASTNode as NodeT['kind']]?: (node: NodeT) => string; 18} = { 19 OperationDefinition(node) { 20 if ( 21 node.operation === 'query' && 22 !node.name && 23 !hasItems(node.variableDefinitions) && 24 !hasItems(node.directives) 25 ) { 26 return nodes.SelectionSet!(node.selectionSet); 27 } 28 let out: string = 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(nodes.VariableDefinition!).join(', ') + ')'; 33 } 34 if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 35 return out + ' ' + nodes.SelectionSet!(node.selectionSet); 36 }, 37 VariableDefinition(node) { 38 let out = nodes.Variable!(node.variable) + ': ' + print(node.type); 39 if (node.defaultValue) out += ' = ' + print(node.defaultValue); 40 if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 41 return out; 42 }, 43 Field(node) { 44 let out = (node.alias ? node.alias.value + ': ' : '') + node.name.value; 45 if (hasItems(node.arguments)) { 46 const args = node.arguments.map(nodes.Argument!); 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(nodes.Directive!).join(' '); 54 return node.selectionSet ? out + ' ' + nodes.SelectionSet!(node.selectionSet) : out; 55 }, 56 StringValue(node) { 57 return node.block ? printBlockString(node.value) : printString(node.value); 58 }, 59 BooleanValue(node) { 60 return '' + node.value; 61 }, 62 NullValue(_node) { 63 return 'null'; 64 }, 65 IntValue(node) { 66 return node.value; 67 }, 68 FloatValue(node) { 69 return node.value; 70 }, 71 EnumValue(node) { 72 return node.value; 73 }, 74 Name(node) { 75 return node.value; 76 }, 77 Variable(node) { 78 return '$' + node.name.value; 79 }, 80 ListValue(node) { 81 return '[' + node.values.map(print).join(', ') + ']'; 82 }, 83 ObjectValue(node) { 84 return '{' + node.fields.map(nodes.ObjectField!).join(', ') + '}'; 85 }, 86 ObjectField(node) { 87 return node.name.value + ': ' + print(node.value); 88 }, 89 Document(node) { 90 return hasItems(node.definitions) ? node.definitions.map(print).join('\n\n') : ''; 91 }, 92 SelectionSet(node) { 93 return '{\n ' + node.selections.map(print).join('\n').replace(/\n/g, '\n ') + '\n}'; 94 }, 95 Argument(node) { 96 return node.name.value + ': ' + print(node.value); 97 }, 98 FragmentSpread(node) { 99 let out = '...' + node.name.value; 100 if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 101 return out; 102 }, 103 InlineFragment(node) { 104 let out = '...'; 105 if (node.typeCondition) out += ' on ' + node.typeCondition.name.value; 106 if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 107 return out + ' ' + print(node.selectionSet); 108 }, 109 FragmentDefinition(node) { 110 let out = 'fragment ' + node.name.value; 111 out += ' on ' + node.typeCondition.name.value; 112 if (hasItems(node.directives)) out += ' ' + node.directives.map(nodes.Directive!).join(' '); 113 return out + ' ' + print(node.selectionSet); 114 }, 115 Directive(node) { 116 let out = '@' + node.name.value; 117 if (hasItems(node.arguments)) out += '(' + node.arguments.map(nodes.Argument!).join(', ') + ')'; 118 return out; 119 }, 120 NamedType(node) { 121 return node.name.value; 122 }, 123 ListType(node) { 124 return '[' + print(node.type) + ']'; 125 }, 126 NonNullType(node) { 127 return print(node.type) + '!'; 128 }, 129}; 130 131export function print(node: ASTNode): string { 132 return nodes[node.kind] ? (nodes as any)[node.kind]!(node) : ''; 133}