graphql 16.11.0 → 16.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +49 -6
  2. package/execution/execute.d.ts +14 -1
  3. package/execution/execute.js +72 -13
  4. package/execution/execute.mjs +72 -13
  5. package/execution/subscribe.js +1 -0
  6. package/execution/subscribe.mjs +2 -0
  7. package/index.d.ts +11 -0
  8. package/index.js +24 -0
  9. package/index.mjs +6 -2
  10. package/language/ast.d.ts +45 -1
  11. package/language/ast.js +14 -1
  12. package/language/ast.mjs +14 -1
  13. package/language/index.d.ts +14 -1
  14. package/language/index.js +12 -0
  15. package/language/index.mjs +8 -1
  16. package/language/kinds.d.ts +6 -0
  17. package/language/kinds.js +5 -0
  18. package/language/kinds.mjs +5 -0
  19. package/language/lexer.d.ts +52 -1
  20. package/language/lexer.js +10 -0
  21. package/language/lexer.mjs +17 -4
  22. package/language/parser.d.ts +30 -3
  23. package/language/parser.js +129 -13
  24. package/language/parser.mjs +123 -11
  25. package/language/predicates.d.ts +4 -0
  26. package/language/predicates.js +11 -0
  27. package/language/predicates.mjs +9 -0
  28. package/language/printer.js +42 -13
  29. package/language/printer.mjs +42 -13
  30. package/language/schemaCoordinateLexer.d.ts +43 -0
  31. package/language/schemaCoordinateLexer.js +171 -0
  32. package/language/schemaCoordinateLexer.mjs +122 -0
  33. package/language/tokenKind.d.ts +1 -0
  34. package/language/tokenKind.js +1 -0
  35. package/language/tokenKind.mjs +1 -0
  36. package/package.json +1 -1
  37. package/utilities/index.d.ts +5 -0
  38. package/utilities/index.js +14 -0
  39. package/utilities/index.mjs +5 -0
  40. package/utilities/resolveSchemaCoordinate.d.ts +80 -0
  41. package/utilities/resolveSchemaCoordinate.js +260 -0
  42. package/utilities/resolveSchemaCoordinate.mjs +243 -0
  43. package/validation/rules/ValuesOfCorrectTypeRule.js +7 -36
  44. package/validation/rules/ValuesOfCorrectTypeRule.mjs +7 -35
  45. package/validation/validate.js +12 -0
  46. package/validation/validate.mjs +13 -2
  47. package/version.js +2 -2
  48. package/version.mjs +2 -2
@@ -6,6 +6,7 @@ Object.defineProperty(exports, '__esModule', {
6
6
  exports.Parser = void 0;
7
7
  exports.parse = parse;
8
8
  exports.parseConstValue = parseConstValue;
9
+ exports.parseSchemaCoordinate = parseSchemaCoordinate;
9
10
  exports.parseType = parseType;
10
11
  exports.parseValue = parseValue;
11
12
 
@@ -19,6 +20,8 @@ var _kinds = require('./kinds.js');
19
20
 
20
21
  var _lexer = require('./lexer.js');
21
22
 
23
+ var _schemaCoordinateLexer = require('./schemaCoordinateLexer.js');
24
+
22
25
  var _source = require('./source.js');
23
26
 
24
27
  var _tokenKind = require('./tokenKind.js');
@@ -84,6 +87,29 @@ function parseType(source, options) {
84
87
  parser.expectToken(_tokenKind.TokenKind.EOF);
85
88
  return type;
86
89
  }
90
+ /**
91
+ * Given a string containing a GraphQL Schema Coordinate (ex. `Type.field`),
92
+ * parse the AST for that schema coordinate.
93
+ * Throws GraphQLError if a syntax error is encountered.
94
+ *
95
+ * Consider providing the results to the utility function:
96
+ * resolveASTSchemaCoordinate(). Or calling resolveSchemaCoordinate() directly
97
+ * with an unparsed source.
98
+ */
99
+
100
+ function parseSchemaCoordinate(source) {
101
+ const sourceObj = (0, _source.isSource)(source)
102
+ ? source
103
+ : new _source.Source(source);
104
+ const lexer = new _schemaCoordinateLexer.SchemaCoordinateLexer(sourceObj);
105
+ const parser = new Parser(source, {
106
+ lexer,
107
+ });
108
+ parser.expectToken(_tokenKind.TokenKind.SOF);
109
+ const coordinate = parser.parseSchemaCoordinate();
110
+ parser.expectToken(_tokenKind.TokenKind.EOF);
111
+ return coordinate;
112
+ }
87
113
  /**
88
114
  * This class is exported only to assist people in implementing their own parsers
89
115
  * without duplicating too much code and should be used only as last resort for cases
@@ -98,11 +124,18 @@ function parseType(source, options) {
98
124
 
99
125
  class Parser {
100
126
  constructor(source, options = {}) {
101
- const sourceObj = (0, _source.isSource)(source)
102
- ? source
103
- : new _source.Source(source);
104
- this._lexer = new _lexer.Lexer(sourceObj);
105
- this._options = options;
127
+ const { lexer, ..._options } = options;
128
+
129
+ if (lexer) {
130
+ this._lexer = lexer;
131
+ } else {
132
+ const sourceObj = (0, _source.isSource)(source)
133
+ ? source
134
+ : new _source.Source(source);
135
+ this._lexer = new _lexer.Lexer(sourceObj);
136
+ }
137
+
138
+ this._options = _options;
106
139
  this._tokenCounter = 0;
107
140
  }
108
141
 
@@ -169,6 +202,14 @@ class Parser {
169
202
  ? this._lexer.lookahead()
170
203
  : this._lexer.token;
171
204
 
205
+ if (hasDescription && keywordToken.kind === _tokenKind.TokenKind.BRACE_L) {
206
+ throw (0, _syntaxError.syntaxError)(
207
+ this._lexer.source,
208
+ this._lexer.token.start,
209
+ 'Unexpected description, descriptions are not supported on shorthand queries.',
210
+ );
211
+ }
212
+
172
213
  if (keywordToken.kind === _tokenKind.TokenKind.NAME) {
173
214
  switch (keywordToken.value) {
174
215
  case 'schema':
@@ -196,14 +237,6 @@ class Parser {
196
237
  return this.parseDirectiveDefinition();
197
238
  }
198
239
 
199
- if (hasDescription) {
200
- throw (0, _syntaxError.syntaxError)(
201
- this._lexer.source,
202
- this._lexer.token.start,
203
- 'Unexpected description, descriptions are supported only on type definitions.',
204
- );
205
- }
206
-
207
240
  switch (keywordToken.value) {
208
241
  case 'query':
209
242
  case 'mutation':
@@ -212,7 +245,17 @@ class Parser {
212
245
 
213
246
  case 'fragment':
214
247
  return this.parseFragmentDefinition();
248
+ }
249
+
250
+ if (hasDescription) {
251
+ throw (0, _syntaxError.syntaxError)(
252
+ this._lexer.source,
253
+ this._lexer.token.start,
254
+ 'Unexpected description, only GraphQL definitions support descriptions.',
255
+ );
256
+ }
215
257
 
258
+ switch (keywordToken.value) {
216
259
  case 'extend':
217
260
  return this.parseTypeSystemExtension();
218
261
  }
@@ -234,6 +277,7 @@ class Parser {
234
277
  return this.node(start, {
235
278
  kind: _kinds.Kind.OPERATION_DEFINITION,
236
279
  operation: _ast.OperationTypeNode.QUERY,
280
+ description: undefined,
237
281
  name: undefined,
238
282
  variableDefinitions: [],
239
283
  directives: [],
@@ -241,6 +285,7 @@ class Parser {
241
285
  });
242
286
  }
243
287
 
288
+ const description = this.parseDescription();
244
289
  const operation = this.parseOperationType();
245
290
  let name;
246
291
 
@@ -251,6 +296,7 @@ class Parser {
251
296
  return this.node(start, {
252
297
  kind: _kinds.Kind.OPERATION_DEFINITION,
253
298
  operation,
299
+ description,
254
300
  name,
255
301
  variableDefinitions: this.parseVariableDefinitions(),
256
302
  directives: this.parseDirectives(false),
@@ -295,6 +341,7 @@ class Parser {
295
341
  parseVariableDefinition() {
296
342
  return this.node(this._lexer.token, {
297
343
  kind: _kinds.Kind.VARIABLE_DEFINITION,
344
+ description: this.parseDescription(),
298
345
  variable: this.parseVariable(),
299
346
  type:
300
347
  (this.expectToken(_tokenKind.TokenKind.COLON),
@@ -443,6 +490,7 @@ class Parser {
443
490
 
444
491
  parseFragmentDefinition() {
445
492
  const start = this._lexer.token;
493
+ const description = this.parseDescription();
446
494
  this.expectKeyword('fragment'); // Legacy support for defining variables within fragments changes
447
495
  // the grammar of FragmentDefinition:
448
496
  // - fragment FragmentName VariableDefinitions? on TypeCondition Directives? SelectionSet
@@ -450,6 +498,7 @@ class Parser {
450
498
  if (this._options.allowLegacyFragmentVariables === true) {
451
499
  return this.node(start, {
452
500
  kind: _kinds.Kind.FRAGMENT_DEFINITION,
501
+ description,
453
502
  name: this.parseFragmentName(),
454
503
  variableDefinitions: this.parseVariableDefinitions(),
455
504
  typeCondition: (this.expectKeyword('on'), this.parseNamedType()),
@@ -460,6 +509,7 @@ class Parser {
460
509
 
461
510
  return this.node(start, {
462
511
  kind: _kinds.Kind.FRAGMENT_DEFINITION,
512
+ description,
463
513
  name: this.parseFragmentName(),
464
514
  typeCondition: (this.expectKeyword('on'), this.parseNamedType()),
465
515
  directives: this.parseDirectives(false),
@@ -1364,6 +1414,72 @@ class Parser {
1364
1414
  }
1365
1415
 
1366
1416
  throw this.unexpected(start);
1417
+ } // Schema Coordinates
1418
+
1419
+ /**
1420
+ * SchemaCoordinate :
1421
+ * - Name
1422
+ * - Name . Name
1423
+ * - Name . Name ( Name : )
1424
+ * - \@ Name
1425
+ * - \@ Name ( Name : )
1426
+ */
1427
+
1428
+ parseSchemaCoordinate() {
1429
+ const start = this._lexer.token;
1430
+ const ofDirective = this.expectOptionalToken(_tokenKind.TokenKind.AT);
1431
+ const name = this.parseName();
1432
+ let memberName;
1433
+
1434
+ if (!ofDirective && this.expectOptionalToken(_tokenKind.TokenKind.DOT)) {
1435
+ memberName = this.parseName();
1436
+ }
1437
+
1438
+ let argumentName;
1439
+
1440
+ if (
1441
+ (ofDirective || memberName) &&
1442
+ this.expectOptionalToken(_tokenKind.TokenKind.PAREN_L)
1443
+ ) {
1444
+ argumentName = this.parseName();
1445
+ this.expectToken(_tokenKind.TokenKind.COLON);
1446
+ this.expectToken(_tokenKind.TokenKind.PAREN_R);
1447
+ }
1448
+
1449
+ if (ofDirective) {
1450
+ if (argumentName) {
1451
+ return this.node(start, {
1452
+ kind: _kinds.Kind.DIRECTIVE_ARGUMENT_COORDINATE,
1453
+ name,
1454
+ argumentName,
1455
+ });
1456
+ }
1457
+
1458
+ return this.node(start, {
1459
+ kind: _kinds.Kind.DIRECTIVE_COORDINATE,
1460
+ name,
1461
+ });
1462
+ } else if (memberName) {
1463
+ if (argumentName) {
1464
+ return this.node(start, {
1465
+ kind: _kinds.Kind.ARGUMENT_COORDINATE,
1466
+ name,
1467
+ fieldName: memberName,
1468
+ argumentName,
1469
+ });
1470
+ }
1471
+
1472
+ return this.node(start, {
1473
+ kind: _kinds.Kind.MEMBER_COORDINATE,
1474
+ name,
1475
+ memberName,
1476
+ });
1477
+ }
1478
+
1479
+ return this.node(start, {
1480
+ kind: _kinds.Kind.TYPE_COORDINATE,
1481
+ name,
1482
+ });
1367
1483
  } // Core parsing utility functions
1368
1484
 
1369
1485
  /**
@@ -3,6 +3,7 @@ import { Location, OperationTypeNode } from './ast.mjs';
3
3
  import { DirectiveLocation } from './directiveLocation.mjs';
4
4
  import { Kind } from './kinds.mjs';
5
5
  import { isPunctuatorTokenKind, Lexer } from './lexer.mjs';
6
+ import { SchemaCoordinateLexer } from './schemaCoordinateLexer.mjs';
6
7
  import { isSource, Source } from './source.mjs';
7
8
  import { TokenKind } from './tokenKind.mjs';
8
9
  /**
@@ -70,6 +71,27 @@ export function parseType(source, options) {
70
71
  parser.expectToken(TokenKind.EOF);
71
72
  return type;
72
73
  }
74
+ /**
75
+ * Given a string containing a GraphQL Schema Coordinate (ex. `Type.field`),
76
+ * parse the AST for that schema coordinate.
77
+ * Throws GraphQLError if a syntax error is encountered.
78
+ *
79
+ * Consider providing the results to the utility function:
80
+ * resolveASTSchemaCoordinate(). Or calling resolveSchemaCoordinate() directly
81
+ * with an unparsed source.
82
+ */
83
+
84
+ export function parseSchemaCoordinate(source) {
85
+ const sourceObj = isSource(source) ? source : new Source(source);
86
+ const lexer = new SchemaCoordinateLexer(sourceObj);
87
+ const parser = new Parser(source, {
88
+ lexer,
89
+ });
90
+ parser.expectToken(TokenKind.SOF);
91
+ const coordinate = parser.parseSchemaCoordinate();
92
+ parser.expectToken(TokenKind.EOF);
93
+ return coordinate;
94
+ }
73
95
  /**
74
96
  * This class is exported only to assist people in implementing their own parsers
75
97
  * without duplicating too much code and should be used only as last resort for cases
@@ -84,9 +106,16 @@ export function parseType(source, options) {
84
106
 
85
107
  export class Parser {
86
108
  constructor(source, options = {}) {
87
- const sourceObj = isSource(source) ? source : new Source(source);
88
- this._lexer = new Lexer(sourceObj);
89
- this._options = options;
109
+ const { lexer, ..._options } = options;
110
+
111
+ if (lexer) {
112
+ this._lexer = lexer;
113
+ } else {
114
+ const sourceObj = isSource(source) ? source : new Source(source);
115
+ this._lexer = new Lexer(sourceObj);
116
+ }
117
+
118
+ this._options = _options;
90
119
  this._tokenCounter = 0;
91
120
  }
92
121
 
@@ -153,6 +182,14 @@ export class Parser {
153
182
  ? this._lexer.lookahead()
154
183
  : this._lexer.token;
155
184
 
185
+ if (hasDescription && keywordToken.kind === TokenKind.BRACE_L) {
186
+ throw syntaxError(
187
+ this._lexer.source,
188
+ this._lexer.token.start,
189
+ 'Unexpected description, descriptions are not supported on shorthand queries.',
190
+ );
191
+ }
192
+
156
193
  if (keywordToken.kind === TokenKind.NAME) {
157
194
  switch (keywordToken.value) {
158
195
  case 'schema':
@@ -180,14 +217,6 @@ export class Parser {
180
217
  return this.parseDirectiveDefinition();
181
218
  }
182
219
 
183
- if (hasDescription) {
184
- throw syntaxError(
185
- this._lexer.source,
186
- this._lexer.token.start,
187
- 'Unexpected description, descriptions are supported only on type definitions.',
188
- );
189
- }
190
-
191
220
  switch (keywordToken.value) {
192
221
  case 'query':
193
222
  case 'mutation':
@@ -196,7 +225,17 @@ export class Parser {
196
225
 
197
226
  case 'fragment':
198
227
  return this.parseFragmentDefinition();
228
+ }
229
+
230
+ if (hasDescription) {
231
+ throw syntaxError(
232
+ this._lexer.source,
233
+ this._lexer.token.start,
234
+ 'Unexpected description, only GraphQL definitions support descriptions.',
235
+ );
236
+ }
199
237
 
238
+ switch (keywordToken.value) {
200
239
  case 'extend':
201
240
  return this.parseTypeSystemExtension();
202
241
  }
@@ -218,6 +257,7 @@ export class Parser {
218
257
  return this.node(start, {
219
258
  kind: Kind.OPERATION_DEFINITION,
220
259
  operation: OperationTypeNode.QUERY,
260
+ description: undefined,
221
261
  name: undefined,
222
262
  variableDefinitions: [],
223
263
  directives: [],
@@ -225,6 +265,7 @@ export class Parser {
225
265
  });
226
266
  }
227
267
 
268
+ const description = this.parseDescription();
228
269
  const operation = this.parseOperationType();
229
270
  let name;
230
271
 
@@ -235,6 +276,7 @@ export class Parser {
235
276
  return this.node(start, {
236
277
  kind: Kind.OPERATION_DEFINITION,
237
278
  operation,
279
+ description,
238
280
  name,
239
281
  variableDefinitions: this.parseVariableDefinitions(),
240
282
  directives: this.parseDirectives(false),
@@ -279,6 +321,7 @@ export class Parser {
279
321
  parseVariableDefinition() {
280
322
  return this.node(this._lexer.token, {
281
323
  kind: Kind.VARIABLE_DEFINITION,
324
+ description: this.parseDescription(),
282
325
  variable: this.parseVariable(),
283
326
  type: (this.expectToken(TokenKind.COLON), this.parseTypeReference()),
284
327
  defaultValue: this.expectOptionalToken(TokenKind.EQUALS)
@@ -421,6 +464,7 @@ export class Parser {
421
464
 
422
465
  parseFragmentDefinition() {
423
466
  const start = this._lexer.token;
467
+ const description = this.parseDescription();
424
468
  this.expectKeyword('fragment'); // Legacy support for defining variables within fragments changes
425
469
  // the grammar of FragmentDefinition:
426
470
  // - fragment FragmentName VariableDefinitions? on TypeCondition Directives? SelectionSet
@@ -428,6 +472,7 @@ export class Parser {
428
472
  if (this._options.allowLegacyFragmentVariables === true) {
429
473
  return this.node(start, {
430
474
  kind: Kind.FRAGMENT_DEFINITION,
475
+ description,
431
476
  name: this.parseFragmentName(),
432
477
  variableDefinitions: this.parseVariableDefinitions(),
433
478
  typeCondition: (this.expectKeyword('on'), this.parseNamedType()),
@@ -438,6 +483,7 @@ export class Parser {
438
483
 
439
484
  return this.node(start, {
440
485
  kind: Kind.FRAGMENT_DEFINITION,
486
+ description,
441
487
  name: this.parseFragmentName(),
442
488
  typeCondition: (this.expectKeyword('on'), this.parseNamedType()),
443
489
  directives: this.parseDirectives(false),
@@ -1323,6 +1369,72 @@ export class Parser {
1323
1369
  }
1324
1370
 
1325
1371
  throw this.unexpected(start);
1372
+ } // Schema Coordinates
1373
+
1374
+ /**
1375
+ * SchemaCoordinate :
1376
+ * - Name
1377
+ * - Name . Name
1378
+ * - Name . Name ( Name : )
1379
+ * - \@ Name
1380
+ * - \@ Name ( Name : )
1381
+ */
1382
+
1383
+ parseSchemaCoordinate() {
1384
+ const start = this._lexer.token;
1385
+ const ofDirective = this.expectOptionalToken(TokenKind.AT);
1386
+ const name = this.parseName();
1387
+ let memberName;
1388
+
1389
+ if (!ofDirective && this.expectOptionalToken(TokenKind.DOT)) {
1390
+ memberName = this.parseName();
1391
+ }
1392
+
1393
+ let argumentName;
1394
+
1395
+ if (
1396
+ (ofDirective || memberName) &&
1397
+ this.expectOptionalToken(TokenKind.PAREN_L)
1398
+ ) {
1399
+ argumentName = this.parseName();
1400
+ this.expectToken(TokenKind.COLON);
1401
+ this.expectToken(TokenKind.PAREN_R);
1402
+ }
1403
+
1404
+ if (ofDirective) {
1405
+ if (argumentName) {
1406
+ return this.node(start, {
1407
+ kind: Kind.DIRECTIVE_ARGUMENT_COORDINATE,
1408
+ name,
1409
+ argumentName,
1410
+ });
1411
+ }
1412
+
1413
+ return this.node(start, {
1414
+ kind: Kind.DIRECTIVE_COORDINATE,
1415
+ name,
1416
+ });
1417
+ } else if (memberName) {
1418
+ if (argumentName) {
1419
+ return this.node(start, {
1420
+ kind: Kind.ARGUMENT_COORDINATE,
1421
+ name,
1422
+ fieldName: memberName,
1423
+ argumentName,
1424
+ });
1425
+ }
1426
+
1427
+ return this.node(start, {
1428
+ kind: Kind.MEMBER_COORDINATE,
1429
+ name,
1430
+ memberName,
1431
+ });
1432
+ }
1433
+
1434
+ return this.node(start, {
1435
+ kind: Kind.TYPE_COORDINATE,
1436
+ name,
1437
+ });
1326
1438
  } // Core parsing utility functions
1327
1439
 
1328
1440
  /**
@@ -3,6 +3,7 @@ import type {
3
3
  ConstValueNode,
4
4
  DefinitionNode,
5
5
  ExecutableDefinitionNode,
6
+ SchemaCoordinateNode,
6
7
  SelectionNode,
7
8
  TypeDefinitionNode,
8
9
  TypeExtensionNode,
@@ -31,3 +32,6 @@ export declare function isTypeSystemExtensionNode(
31
32
  export declare function isTypeExtensionNode(
32
33
  node: ASTNode,
33
34
  ): node is TypeExtensionNode;
35
+ export declare function isSchemaCoordinateNode(
36
+ node: ASTNode,
37
+ ): node is SchemaCoordinateNode;
@@ -6,6 +6,7 @@ Object.defineProperty(exports, '__esModule', {
6
6
  exports.isConstValueNode = isConstValueNode;
7
7
  exports.isDefinitionNode = isDefinitionNode;
8
8
  exports.isExecutableDefinitionNode = isExecutableDefinitionNode;
9
+ exports.isSchemaCoordinateNode = isSchemaCoordinateNode;
9
10
  exports.isSelectionNode = isSelectionNode;
10
11
  exports.isTypeDefinitionNode = isTypeDefinitionNode;
11
12
  exports.isTypeExtensionNode = isTypeExtensionNode;
@@ -107,3 +108,13 @@ function isTypeExtensionNode(node) {
107
108
  node.kind === _kinds.Kind.INPUT_OBJECT_TYPE_EXTENSION
108
109
  );
109
110
  }
111
+
112
+ function isSchemaCoordinateNode(node) {
113
+ return (
114
+ node.kind === _kinds.Kind.TYPE_COORDINATE ||
115
+ node.kind === _kinds.Kind.MEMBER_COORDINATE ||
116
+ node.kind === _kinds.Kind.ARGUMENT_COORDINATE ||
117
+ node.kind === _kinds.Kind.DIRECTIVE_COORDINATE ||
118
+ node.kind === _kinds.Kind.DIRECTIVE_ARGUMENT_COORDINATE
119
+ );
120
+ }
@@ -79,3 +79,12 @@ export function isTypeExtensionNode(node) {
79
79
  node.kind === Kind.INPUT_OBJECT_TYPE_EXTENSION
80
80
  );
81
81
  }
82
+ export function isSchemaCoordinateNode(node) {
83
+ return (
84
+ node.kind === Kind.TYPE_COORDINATE ||
85
+ node.kind === Kind.MEMBER_COORDINATE ||
86
+ node.kind === Kind.ARGUMENT_COORDINATE ||
87
+ node.kind === Kind.DIRECTIVE_COORDINATE ||
88
+ node.kind === Kind.DIRECTIVE_ARGUMENT_COORDINATE
89
+ );
90
+ }
@@ -33,22 +33,27 @@ const printDocASTReducer = {
33
33
  },
34
34
  OperationDefinition: {
35
35
  leave(node) {
36
- const varDefs = wrap('(', join(node.variableDefinitions, ', '), ')');
37
- const prefix = join(
38
- [
39
- node.operation,
40
- join([node.name, varDefs]),
41
- join(node.directives, ' '),
42
- ],
43
- ' ',
44
- ); // Anonymous queries with no directives or variable definitions can use
36
+ const varDefs = hasMultilineItems(node.variableDefinitions)
37
+ ? wrap('(\n', join(node.variableDefinitions, '\n'), '\n)')
38
+ : wrap('(', join(node.variableDefinitions, ', '), ')');
39
+ const prefix =
40
+ wrap('', node.description, '\n') +
41
+ join(
42
+ [
43
+ node.operation,
44
+ join([node.name, varDefs]),
45
+ join(node.directives, ' '),
46
+ ],
47
+ ' ',
48
+ ); // Anonymous queries with no directives or variable definitions can use
45
49
  // the query short form.
46
50
 
47
51
  return (prefix === 'query' ? '' : prefix + ' ') + node.selectionSet;
48
52
  },
49
53
  },
50
54
  VariableDefinition: {
51
- leave: ({ variable, type, defaultValue, directives }) =>
55
+ leave: ({ variable, type, defaultValue, directives, description }) =>
56
+ wrap('', description, '\n') +
52
57
  variable +
53
58
  ': ' +
54
59
  type +
@@ -91,9 +96,15 @@ const printDocASTReducer = {
91
96
  ),
92
97
  },
93
98
  FragmentDefinition: {
94
- leave: (
95
- { name, typeCondition, variableDefinitions, directives, selectionSet }, // Note: fragment variable definitions are experimental and may be changed
96
- ) =>
99
+ leave: ({
100
+ name,
101
+ typeCondition,
102
+ variableDefinitions,
103
+ directives,
104
+ selectionSet,
105
+ description,
106
+ }) =>
107
+ wrap('', description, '\n') + // Note: fragment variable definitions are experimental and may be changed
97
108
  // or removed in the future.
98
109
  `fragment ${name}${wrap('(', join(variableDefinitions, ', '), ')')} ` +
99
110
  `on ${typeCondition} ${wrap('', join(directives, ' '), ' ')}` +
@@ -297,6 +308,24 @@ const printDocASTReducer = {
297
308
  leave: ({ name, directives, fields }) =>
298
309
  join(['extend input', name, join(directives, ' '), block(fields)], ' '),
299
310
  },
311
+ // Schema Coordinates
312
+ TypeCoordinate: {
313
+ leave: ({ name }) => name,
314
+ },
315
+ MemberCoordinate: {
316
+ leave: ({ name, memberName }) => join([name, wrap('.', memberName)]),
317
+ },
318
+ ArgumentCoordinate: {
319
+ leave: ({ name, fieldName, argumentName }) =>
320
+ join([name, wrap('.', fieldName), wrap('(', argumentName, ':)')]),
321
+ },
322
+ DirectiveCoordinate: {
323
+ leave: ({ name }) => join(['@', name]),
324
+ },
325
+ DirectiveArgumentCoordinate: {
326
+ leave: ({ name, argumentName }) =>
327
+ join(['@', name, wrap('(', argumentName, ':)')]),
328
+ },
300
329
  };
301
330
  /**
302
331
  * Given maybeArray, print an empty string if it is null or empty, otherwise
@@ -23,22 +23,27 @@ const printDocASTReducer = {
23
23
  },
24
24
  OperationDefinition: {
25
25
  leave(node) {
26
- const varDefs = wrap('(', join(node.variableDefinitions, ', '), ')');
27
- const prefix = join(
28
- [
29
- node.operation,
30
- join([node.name, varDefs]),
31
- join(node.directives, ' '),
32
- ],
33
- ' ',
34
- ); // Anonymous queries with no directives or variable definitions can use
26
+ const varDefs = hasMultilineItems(node.variableDefinitions)
27
+ ? wrap('(\n', join(node.variableDefinitions, '\n'), '\n)')
28
+ : wrap('(', join(node.variableDefinitions, ', '), ')');
29
+ const prefix =
30
+ wrap('', node.description, '\n') +
31
+ join(
32
+ [
33
+ node.operation,
34
+ join([node.name, varDefs]),
35
+ join(node.directives, ' '),
36
+ ],
37
+ ' ',
38
+ ); // Anonymous queries with no directives or variable definitions can use
35
39
  // the query short form.
36
40
 
37
41
  return (prefix === 'query' ? '' : prefix + ' ') + node.selectionSet;
38
42
  },
39
43
  },
40
44
  VariableDefinition: {
41
- leave: ({ variable, type, defaultValue, directives }) =>
45
+ leave: ({ variable, type, defaultValue, directives, description }) =>
46
+ wrap('', description, '\n') +
42
47
  variable +
43
48
  ': ' +
44
49
  type +
@@ -81,9 +86,15 @@ const printDocASTReducer = {
81
86
  ),
82
87
  },
83
88
  FragmentDefinition: {
84
- leave: (
85
- { name, typeCondition, variableDefinitions, directives, selectionSet }, // Note: fragment variable definitions are experimental and may be changed
86
- ) =>
89
+ leave: ({
90
+ name,
91
+ typeCondition,
92
+ variableDefinitions,
93
+ directives,
94
+ selectionSet,
95
+ description,
96
+ }) =>
97
+ wrap('', description, '\n') + // Note: fragment variable definitions are experimental and may be changed
87
98
  // or removed in the future.
88
99
  `fragment ${name}${wrap('(', join(variableDefinitions, ', '), ')')} ` +
89
100
  `on ${typeCondition} ${wrap('', join(directives, ' '), ' ')}` +
@@ -285,6 +296,24 @@ const printDocASTReducer = {
285
296
  leave: ({ name, directives, fields }) =>
286
297
  join(['extend input', name, join(directives, ' '), block(fields)], ' '),
287
298
  },
299
+ // Schema Coordinates
300
+ TypeCoordinate: {
301
+ leave: ({ name }) => name,
302
+ },
303
+ MemberCoordinate: {
304
+ leave: ({ name, memberName }) => join([name, wrap('.', memberName)]),
305
+ },
306
+ ArgumentCoordinate: {
307
+ leave: ({ name, fieldName, argumentName }) =>
308
+ join([name, wrap('.', fieldName), wrap('(', argumentName, ':)')]),
309
+ },
310
+ DirectiveCoordinate: {
311
+ leave: ({ name }) => join(['@', name]),
312
+ },
313
+ DirectiveArgumentCoordinate: {
314
+ leave: ({ name, argumentName }) =>
315
+ join(['@', name, wrap('(', argumentName, ':)')]),
316
+ },
288
317
  };
289
318
  /**
290
319
  * Given maybeArray, print an empty string if it is null or empty, otherwise