printer.mjs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. import { visit } from './visitor';
  2. import { printBlockString } from './blockString';
  3. /**
  4. * Converts an AST into a string, using one set of reasonable
  5. * formatting rules.
  6. */
  7. export function print(ast) {
  8. return visit(ast, {
  9. leave: printDocASTReducer
  10. });
  11. } // TODO: provide better type coverage in future
  12. var printDocASTReducer = {
  13. Name: function Name(node) {
  14. return node.value;
  15. },
  16. Variable: function Variable(node) {
  17. return '$' + node.name;
  18. },
  19. // Document
  20. Document: function Document(node) {
  21. return join(node.definitions, '\n\n') + '\n';
  22. },
  23. OperationDefinition: function OperationDefinition(node) {
  24. var op = node.operation;
  25. var name = node.name;
  26. var varDefs = wrap('(', join(node.variableDefinitions, ', '), ')');
  27. var directives = join(node.directives, ' ');
  28. var selectionSet = node.selectionSet; // Anonymous queries with no directives or variable definitions can use
  29. // the query short form.
  30. return !name && !directives && !varDefs && op === 'query' ? selectionSet : join([op, join([name, varDefs]), directives, selectionSet], ' ');
  31. },
  32. VariableDefinition: function VariableDefinition(_ref) {
  33. var variable = _ref.variable,
  34. type = _ref.type,
  35. defaultValue = _ref.defaultValue,
  36. directives = _ref.directives;
  37. return variable + ': ' + type + wrap(' = ', defaultValue) + wrap(' ', join(directives, ' '));
  38. },
  39. SelectionSet: function SelectionSet(_ref2) {
  40. var selections = _ref2.selections;
  41. return block(selections);
  42. },
  43. Field: function Field(_ref3) {
  44. var alias = _ref3.alias,
  45. name = _ref3.name,
  46. args = _ref3.arguments,
  47. directives = _ref3.directives,
  48. selectionSet = _ref3.selectionSet;
  49. return join([wrap('', alias, ': ') + name + wrap('(', join(args, ', '), ')'), join(directives, ' '), selectionSet], ' ');
  50. },
  51. Argument: function Argument(_ref4) {
  52. var name = _ref4.name,
  53. value = _ref4.value;
  54. return name + ': ' + value;
  55. },
  56. // Fragments
  57. FragmentSpread: function FragmentSpread(_ref5) {
  58. var name = _ref5.name,
  59. directives = _ref5.directives;
  60. return '...' + name + wrap(' ', join(directives, ' '));
  61. },
  62. InlineFragment: function InlineFragment(_ref6) {
  63. var typeCondition = _ref6.typeCondition,
  64. directives = _ref6.directives,
  65. selectionSet = _ref6.selectionSet;
  66. return join(['...', wrap('on ', typeCondition), join(directives, ' '), selectionSet], ' ');
  67. },
  68. FragmentDefinition: function FragmentDefinition(_ref7) {
  69. var name = _ref7.name,
  70. typeCondition = _ref7.typeCondition,
  71. variableDefinitions = _ref7.variableDefinitions,
  72. directives = _ref7.directives,
  73. selectionSet = _ref7.selectionSet;
  74. return (// Note: fragment variable definitions are experimental and may be changed
  75. // or removed in the future.
  76. "fragment ".concat(name).concat(wrap('(', join(variableDefinitions, ', '), ')'), " ") + "on ".concat(typeCondition, " ").concat(wrap('', join(directives, ' '), ' ')) + selectionSet
  77. );
  78. },
  79. // Value
  80. IntValue: function IntValue(_ref8) {
  81. var value = _ref8.value;
  82. return value;
  83. },
  84. FloatValue: function FloatValue(_ref9) {
  85. var value = _ref9.value;
  86. return value;
  87. },
  88. StringValue: function StringValue(_ref10, key) {
  89. var value = _ref10.value,
  90. isBlockString = _ref10.block;
  91. return isBlockString ? printBlockString(value, key === 'description' ? '' : ' ') : JSON.stringify(value);
  92. },
  93. BooleanValue: function BooleanValue(_ref11) {
  94. var value = _ref11.value;
  95. return value ? 'true' : 'false';
  96. },
  97. NullValue: function NullValue() {
  98. return 'null';
  99. },
  100. EnumValue: function EnumValue(_ref12) {
  101. var value = _ref12.value;
  102. return value;
  103. },
  104. ListValue: function ListValue(_ref13) {
  105. var values = _ref13.values;
  106. return '[' + join(values, ', ') + ']';
  107. },
  108. ObjectValue: function ObjectValue(_ref14) {
  109. var fields = _ref14.fields;
  110. return '{' + join(fields, ', ') + '}';
  111. },
  112. ObjectField: function ObjectField(_ref15) {
  113. var name = _ref15.name,
  114. value = _ref15.value;
  115. return name + ': ' + value;
  116. },
  117. // Directive
  118. Directive: function Directive(_ref16) {
  119. var name = _ref16.name,
  120. args = _ref16.arguments;
  121. return '@' + name + wrap('(', join(args, ', '), ')');
  122. },
  123. // Type
  124. NamedType: function NamedType(_ref17) {
  125. var name = _ref17.name;
  126. return name;
  127. },
  128. ListType: function ListType(_ref18) {
  129. var type = _ref18.type;
  130. return '[' + type + ']';
  131. },
  132. NonNullType: function NonNullType(_ref19) {
  133. var type = _ref19.type;
  134. return type + '!';
  135. },
  136. // Type System Definitions
  137. SchemaDefinition: function SchemaDefinition(_ref20) {
  138. var directives = _ref20.directives,
  139. operationTypes = _ref20.operationTypes;
  140. return join(['schema', join(directives, ' '), block(operationTypes)], ' ');
  141. },
  142. OperationTypeDefinition: function OperationTypeDefinition(_ref21) {
  143. var operation = _ref21.operation,
  144. type = _ref21.type;
  145. return operation + ': ' + type;
  146. },
  147. ScalarTypeDefinition: addDescription(function (_ref22) {
  148. var name = _ref22.name,
  149. directives = _ref22.directives;
  150. return join(['scalar', name, join(directives, ' ')], ' ');
  151. }),
  152. ObjectTypeDefinition: addDescription(function (_ref23) {
  153. var name = _ref23.name,
  154. interfaces = _ref23.interfaces,
  155. directives = _ref23.directives,
  156. fields = _ref23.fields;
  157. return join(['type', name, wrap('implements ', join(interfaces, ' & ')), join(directives, ' '), block(fields)], ' ');
  158. }),
  159. FieldDefinition: addDescription(function (_ref24) {
  160. var name = _ref24.name,
  161. args = _ref24.arguments,
  162. type = _ref24.type,
  163. directives = _ref24.directives;
  164. return name + (hasMultilineItems(args) ? wrap('(\n', indent(join(args, '\n')), '\n)') : wrap('(', join(args, ', '), ')')) + ': ' + type + wrap(' ', join(directives, ' '));
  165. }),
  166. InputValueDefinition: addDescription(function (_ref25) {
  167. var name = _ref25.name,
  168. type = _ref25.type,
  169. defaultValue = _ref25.defaultValue,
  170. directives = _ref25.directives;
  171. return join([name + ': ' + type, wrap('= ', defaultValue), join(directives, ' ')], ' ');
  172. }),
  173. InterfaceTypeDefinition: addDescription(function (_ref26) {
  174. var name = _ref26.name,
  175. directives = _ref26.directives,
  176. fields = _ref26.fields;
  177. return join(['interface', name, join(directives, ' '), block(fields)], ' ');
  178. }),
  179. UnionTypeDefinition: addDescription(function (_ref27) {
  180. var name = _ref27.name,
  181. directives = _ref27.directives,
  182. types = _ref27.types;
  183. return join(['union', name, join(directives, ' '), types && types.length !== 0 ? '= ' + join(types, ' | ') : ''], ' ');
  184. }),
  185. EnumTypeDefinition: addDescription(function (_ref28) {
  186. var name = _ref28.name,
  187. directives = _ref28.directives,
  188. values = _ref28.values;
  189. return join(['enum', name, join(directives, ' '), block(values)], ' ');
  190. }),
  191. EnumValueDefinition: addDescription(function (_ref29) {
  192. var name = _ref29.name,
  193. directives = _ref29.directives;
  194. return join([name, join(directives, ' ')], ' ');
  195. }),
  196. InputObjectTypeDefinition: addDescription(function (_ref30) {
  197. var name = _ref30.name,
  198. directives = _ref30.directives,
  199. fields = _ref30.fields;
  200. return join(['input', name, join(directives, ' '), block(fields)], ' ');
  201. }),
  202. DirectiveDefinition: addDescription(function (_ref31) {
  203. var name = _ref31.name,
  204. args = _ref31.arguments,
  205. repeatable = _ref31.repeatable,
  206. locations = _ref31.locations;
  207. return 'directive @' + name + (hasMultilineItems(args) ? wrap('(\n', indent(join(args, '\n')), '\n)') : wrap('(', join(args, ', '), ')')) + (repeatable ? ' repeatable' : '') + ' on ' + join(locations, ' | ');
  208. }),
  209. SchemaExtension: function SchemaExtension(_ref32) {
  210. var directives = _ref32.directives,
  211. operationTypes = _ref32.operationTypes;
  212. return join(['extend schema', join(directives, ' '), block(operationTypes)], ' ');
  213. },
  214. ScalarTypeExtension: function ScalarTypeExtension(_ref33) {
  215. var name = _ref33.name,
  216. directives = _ref33.directives;
  217. return join(['extend scalar', name, join(directives, ' ')], ' ');
  218. },
  219. ObjectTypeExtension: function ObjectTypeExtension(_ref34) {
  220. var name = _ref34.name,
  221. interfaces = _ref34.interfaces,
  222. directives = _ref34.directives,
  223. fields = _ref34.fields;
  224. return join(['extend type', name, wrap('implements ', join(interfaces, ' & ')), join(directives, ' '), block(fields)], ' ');
  225. },
  226. InterfaceTypeExtension: function InterfaceTypeExtension(_ref35) {
  227. var name = _ref35.name,
  228. directives = _ref35.directives,
  229. fields = _ref35.fields;
  230. return join(['extend interface', name, join(directives, ' '), block(fields)], ' ');
  231. },
  232. UnionTypeExtension: function UnionTypeExtension(_ref36) {
  233. var name = _ref36.name,
  234. directives = _ref36.directives,
  235. types = _ref36.types;
  236. return join(['extend union', name, join(directives, ' '), types && types.length !== 0 ? '= ' + join(types, ' | ') : ''], ' ');
  237. },
  238. EnumTypeExtension: function EnumTypeExtension(_ref37) {
  239. var name = _ref37.name,
  240. directives = _ref37.directives,
  241. values = _ref37.values;
  242. return join(['extend enum', name, join(directives, ' '), block(values)], ' ');
  243. },
  244. InputObjectTypeExtension: function InputObjectTypeExtension(_ref38) {
  245. var name = _ref38.name,
  246. directives = _ref38.directives,
  247. fields = _ref38.fields;
  248. return join(['extend input', name, join(directives, ' '), block(fields)], ' ');
  249. }
  250. };
  251. function addDescription(cb) {
  252. return function (node) {
  253. return join([node.description, cb(node)], '\n');
  254. };
  255. }
  256. /**
  257. * Given maybeArray, print an empty string if it is null or empty, otherwise
  258. * print all items together separated by separator if provided
  259. */
  260. function join(maybeArray, separator) {
  261. return maybeArray ? maybeArray.filter(function (x) {
  262. return x;
  263. }).join(separator || '') : '';
  264. }
  265. /**
  266. * Given array, print each item on its own line, wrapped in an
  267. * indented "{ }" block.
  268. */
  269. function block(array) {
  270. return array && array.length !== 0 ? '{\n' + indent(join(array, '\n')) + '\n}' : '';
  271. }
  272. /**
  273. * If maybeString is not null or empty, then wrap with start and end, otherwise
  274. * print an empty string.
  275. */
  276. function wrap(start, maybeString, end) {
  277. return maybeString ? start + maybeString + (end || '') : '';
  278. }
  279. function indent(maybeString) {
  280. return maybeString && ' ' + maybeString.replace(/\n/g, '\n ');
  281. }
  282. function isMultiline(string) {
  283. return string.indexOf('\n') !== -1;
  284. }
  285. function hasMultilineItems(maybeArray) {
  286. return maybeArray && maybeArray.some(isMultiline);
  287. }