UNPKG

27.3 kBJavaScriptView Raw
1// @generated
2/**
3 * Copyright (c) 2013-present, Facebook, Inc.
4 * All rights reserved.
5 *
6 * This source code is licensed under the BSD-style license found in the
7 * LICENSE file in the root directory of this source tree. An additional grant
8 * of patent rights can be found in the PATENTS file in the same directory.
9 *
10 *
11 * @fullSyntaxTransform
12 */
13
14'use strict';
15
16Object.defineProperty(exports, '__esModule', {
17 value: true
18});
19
20var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
21
22var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
23
24function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }
25
26function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
27
28var _require = require('./RelayQLAST');
29
30var RelayQLArgument = _require.RelayQLArgument;
31var RelayQLArgumentType = _require.RelayQLArgumentType;
32var RelayQLDefinition = _require.RelayQLDefinition;
33var RelayQLDirective = _require.RelayQLDirective;
34var RelayQLField = _require.RelayQLField;
35var RelayQLFragment = _require.RelayQLFragment;
36var RelayQLFragmentSpread = _require.RelayQLFragmentSpread;
37var RelayQLInlineFragment = _require.RelayQLInlineFragment;
38var RelayQLMutation = _require.RelayQLMutation;
39var RelayQLQuery = _require.RelayQLQuery;
40var RelayQLSubscription = _require.RelayQLSubscription;
41var RelayQLType = _require.RelayQLType;
42
43var find = require('./find');
44var invariant = require('./invariant');
45
46module.exports = function (t, options) {
47 var formatFields = options.snakeCase ? function (fields) {
48 var formatted = {};
49 Object.keys(fields).forEach(function (name) {
50 formatted[name] = name.replace(/[A-Z]/g, function (letter) {
51 return '_' + letter.toLowerCase();
52 });
53 });
54 return formatted;
55 } : function (fields) {
56 return fields;
57 };
58
59 var EMPTY_ARRAY = t.arrayExpression([]);
60 var FIELDS = formatFields({
61 __typename: '__typename',
62 clientMutationId: 'clientMutationId',
63 clientSubscriptionId: 'clientSubscriptionId',
64 cursor: 'cursor',
65 edges: 'edges',
66 hasNextPage: 'hasNextPage',
67 hasPreviousPage: 'hasPreviousPage',
68 id: 'id',
69 node: 'node',
70 pageInfo: 'pageInfo'
71 });
72 var INPUT_ARGUMENT_NAME = options.inputArgumentName || 'input';
73 var NULL = t.nullLiteral();
74
75 var RelayQLPrinter = (function () {
76 function RelayQLPrinter(tagName, variableNames) {
77 _classCallCheck(this, RelayQLPrinter);
78
79 this.tagName = tagName;
80 this.variableNames = variableNames;
81 }
82
83 /**
84 * Determine if a `... on Node { id }` fragment should be generated for a
85 * field/fragment to allow identification of the response record. This
86 * fragment should be added when some/all implementors of the node's type
87 * also implement `Node` but a `Node` fragment is not already present. If it
88 * is present then `id` would be added as a requisite field.
89 */
90
91 _createClass(RelayQLPrinter, [{
92 key: 'print',
93 value: function print(definition, substitutions) {
94 var printedDocument = undefined;
95 if (definition instanceof RelayQLQuery) {
96 printedDocument = this.printQuery(definition);
97 } else if (definition instanceof RelayQLFragment) {
98 printedDocument = this.printFragment(definition);
99 } else if (definition instanceof RelayQLMutation) {
100 printedDocument = this.printMutation(definition);
101 } else if (definition instanceof RelayQLSubscription) {
102 printedDocument = this.printSubscription(definition);
103 } else {
104 invariant(false, 'Unsupported definition: %s', definition);
105 }
106 return t.callExpression(t.functionExpression(null, substitutions.map(function (substitution) {
107 return t.identifier(substitution.name);
108 }), t.blockStatement([t.returnStatement(printedDocument)])), substitutions.map(function (substitution) {
109 return substitution.value;
110 }));
111 }
112 }, {
113 key: 'printQuery',
114 value: function printQuery(query) {
115 var rootFields = query.getFields();
116 invariant(rootFields.length === 1, 'There are %d fields supplied to the query named `%s`, but queries ' + 'must have exactly one field.', rootFields.length, query.getName());
117 var rootField = rootFields[0];
118 var rootFieldType = rootField.getType();
119 var rootFieldArgs = rootField.getArguments();
120
121 var requisiteFields = {};
122 var identifyingFieldDef = rootFieldType.getIdentifyingFieldDefinition();
123 if (identifyingFieldDef) {
124 requisiteFields[identifyingFieldDef.getName()] = true;
125 }
126 if (rootFieldType.isAbstract()) {
127 requisiteFields[FIELDS.__typename] = true;
128 }
129 var selections = this.printSelections(rootField, requisiteFields);
130 var metadata = {};
131 if (rootFieldType.isList()) {
132 metadata.isPlural = true;
133 }
134 if (rootFieldType.isAbstract()) {
135 metadata.isAbstract = true;
136 }
137 invariant(rootFieldArgs.length <= 1, 'Invalid root field `%s`; Relay only supports root fields with zero ' + 'or one argument.', rootField.getName());
138 var calls = NULL;
139 if (rootFieldArgs.length === 1) {
140 // Until such time as a root field's 'identifying argument' (one that has
141 // a 1-1 correspondence with a Relay record, or null) has a formal type,
142 // assume that the lone arg in a root field's call is the identifying one.
143 var identifyingArg = rootFieldArgs[0];
144 metadata.identifyingArgName = identifyingArg.getName();
145 metadata.identifyingArgType = this.printArgumentTypeForMetadata(identifyingArg.getType());
146 calls = t.arrayExpression([codify({
147 kind: t.valueToNode('Call'),
148 metadata: objectify({
149 type: this.printArgumentTypeForMetadata(identifyingArg.getType())
150 }),
151 name: t.valueToNode(identifyingArg.getName()),
152 value: this.printArgumentValue(identifyingArg)
153 })]);
154 }
155
156 return codify({
157 calls: calls,
158 children: selections,
159 directives: this.printDirectives(rootField.getDirectives()),
160 fieldName: t.valueToNode(rootField.getName()),
161 kind: t.valueToNode('Query'),
162 metadata: objectify(metadata),
163 name: t.valueToNode(query.getName()),
164 type: t.valueToNode(rootFieldType.getName({ modifiers: false }))
165 });
166 }
167 }, {
168 key: 'printFragment',
169 value: function printFragment(fragment) {
170 var fragmentType = fragment.getType();
171
172 var requisiteFields = {};
173 var idFragment = undefined;
174 if (fragmentType.hasField(FIELDS.id)) {
175 requisiteFields.id = true;
176 } else if (shouldGenerateIdFragment(fragment, fragmentType)) {
177 idFragment = fragmentType.generateIdFragment();
178 }
179 if (fragmentType.isAbstract()) {
180 requisiteFields[FIELDS.__typename] = true;
181 }
182 var selections = this.printSelections(fragment, requisiteFields, idFragment ? [idFragment] : null, fragment.hasDirective('generated'));
183 var metadata = this.printRelayDirectiveMetadata(fragment, {
184 isAbstract: fragmentType.isAbstract()
185 });
186
187 return codify({
188 children: selections,
189 directives: this.printDirectives(fragment.getDirectives()),
190 id: t.valueToNode(fragment.getFragmentID()),
191 kind: t.valueToNode('Fragment'),
192 metadata: metadata,
193 name: t.valueToNode(fragment.getName()),
194 type: t.valueToNode(fragmentType.getName({ modifiers: false }))
195 });
196 }
197 }, {
198 key: 'printMutation',
199 value: function printMutation(mutation) {
200 var rootFields = mutation.getFields();
201 invariant(rootFields.length === 1, 'There are %d fields supplied to the mutation named `%s`, but ' + 'mutations must have exactly one field.', rootFields.length, mutation.getName());
202 var rootField = rootFields[0];
203 var rootFieldType = rootField.getType();
204 validateMutationField(rootField);
205 var requisiteFields = {};
206 if (rootFieldType.hasField(FIELDS.clientMutationId)) {
207 requisiteFields[FIELDS.clientMutationId] = true;
208 }
209 var selections = this.printSelections(rootField, requisiteFields);
210 var metadata = {
211 inputType: this.printArgumentTypeForMetadata(rootField.getDeclaredArgument(INPUT_ARGUMENT_NAME))
212 };
213
214 return codify({
215 calls: t.arrayExpression([codify({
216 kind: t.valueToNode('Call'),
217 metadata: objectify({}),
218 name: t.valueToNode(rootField.getName()),
219 value: this.printVariable('input')
220 })]),
221 children: selections,
222 directives: this.printDirectives(mutation.getDirectives()),
223 kind: t.valueToNode('Mutation'),
224 metadata: objectify(metadata),
225 name: t.valueToNode(mutation.getName()),
226 responseType: t.valueToNode(rootFieldType.getName({ modifiers: false }))
227 });
228 }
229 }, {
230 key: 'printSubscription',
231 value: function printSubscription(subscription) {
232 var rootFields = subscription.getFields();
233 invariant(rootFields.length === 1, 'There are %d fields supplied to the subscription named `%s`, but ' + 'subscriptions must have exactly one field.', rootFields.length, subscription.getName());
234 var rootField = rootFields[0];
235 var rootFieldType = rootField.getType();
236 validateMutationField(rootField);
237 var requisiteFields = {};
238 if (rootFieldType.hasField(FIELDS.clientSubscriptionId)) {
239 requisiteFields[FIELDS.clientSubscriptionId] = true;
240 }
241 var selections = this.printSelections(rootField, requisiteFields);
242 var metadata = {
243 inputType: this.printArgumentTypeForMetadata(rootField.getDeclaredArgument(INPUT_ARGUMENT_NAME))
244 };
245
246 return codify({
247 calls: t.arrayExpression([codify({
248 kind: t.valueToNode('Call'),
249 metadata: objectify({}),
250 name: t.valueToNode(rootField.getName()),
251 value: this.printVariable('input')
252 })]),
253 children: selections,
254 directives: this.printDirectives(subscription.getDirectives()),
255 kind: t.valueToNode('Subscription'),
256 metadata: objectify(metadata),
257 name: t.valueToNode(subscription.getName()),
258 responseType: t.valueToNode(rootFieldType.getName({ modifiers: false }))
259 });
260 }
261 }, {
262 key: 'printSelections',
263 value: function printSelections(parent, requisiteFields, extraFragments) {
264 var _this = this;
265
266 var isGeneratedQuery = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
267
268 var fields = [];
269 var printedFragments = [];
270 var didPrintFragmentReference = false;
271 parent.getSelections().forEach(function (selection) {
272 if (selection instanceof RelayQLFragmentSpread) {
273 // Assume that all spreads exist via template substitution.
274 invariant(selection.getDirectives().length === 0, 'Directives are not yet supported for `${fragment}`-style fragment ' + 'references.');
275 printedFragments.push(_this.printFragmentReference(selection));
276 didPrintFragmentReference = true;
277 } else if (selection instanceof RelayQLInlineFragment) {
278 printedFragments.push(_this.printFragment(selection.getFragment()));
279 } else if (selection instanceof RelayQLField) {
280 fields.push(selection);
281 } else {
282 invariant(false, 'Unsupported selection type `%s`.', selection);
283 }
284 });
285 if (extraFragments) {
286 extraFragments.forEach(function (fragment) {
287 printedFragments.push(_this.printFragment(fragment));
288 });
289 }
290 var printedFields = this.printFields(fields, parent, requisiteFields, isGeneratedQuery);
291 var selections = [].concat(_toConsumableArray(printedFields), printedFragments);
292
293 if (selections.length) {
294 var arrayExpressionOfSelections = t.arrayExpression(selections);
295 return didPrintFragmentReference ? shallowFlatten(arrayExpressionOfSelections) : arrayExpressionOfSelections;
296 }
297 return NULL;
298 }
299 }, {
300 key: 'printFields',
301 value: function printFields(fields, parent, requisiteFields) {
302 var _this2 = this;
303
304 var isGeneratedQuery = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
305
306 var parentType = parent.getType();
307 if (parentType.isConnection() && parentType.hasField(FIELDS.pageInfo) && fields.some(function (field) {
308 return field.getName() === FIELDS.edges;
309 })) {
310 requisiteFields[FIELDS.pageInfo] = true;
311 }
312
313 var generatedFields = _extends({}, requisiteFields);
314
315 var printedFields = [];
316 fields.forEach(function (field) {
317 delete generatedFields[field.getName()];
318 printedFields.push(_this2.printField(field, parent, requisiteFields, generatedFields, isGeneratedQuery));
319 });
320
321 Object.keys(generatedFields).forEach(function (fieldName) {
322 var generatedField = parentType.generateField(fieldName);
323 printedFields.push(_this2.printField(generatedField, parent, requisiteFields, generatedFields, isGeneratedQuery));
324 });
325 return printedFields;
326 }
327 }, {
328 key: 'printField',
329 value: function printField(field, parent, requisiteSiblings, generatedSiblings) {
330 var _this3 = this;
331
332 var isGeneratedQuery = arguments.length <= 4 || arguments[4] === undefined ? false : arguments[4];
333
334 var fieldType = field.getType();
335
336 var metadata = {};
337 var requisiteFields = {};
338 var idFragment = undefined;
339 if (fieldType.hasField(FIELDS.id)) {
340 requisiteFields.id = true;
341 } else if (shouldGenerateIdFragment(field, fieldType)) {
342 idFragment = fieldType.generateIdFragment();
343 }
344
345 if (!isGeneratedQuery) {
346 validateField(field, parent.getType());
347 }
348
349 if (fieldType.canHaveSubselections()) {
350 metadata.canHaveSubselections = true;
351 }
352 // TODO: Generalize to non-`Node` types.
353 if (fieldType.alwaysImplements('Node')) {
354 metadata.inferredRootCallName = 'node';
355 metadata.inferredPrimaryKey = 'id';
356 }
357 if (fieldType.isConnection()) {
358 if (field.hasDeclaredArgument('first') || field.hasDeclaredArgument('last')) {
359 if (!isGeneratedQuery) {
360 validateConnectionField(field);
361 }
362 metadata.isConnection = true;
363 if (field.hasDeclaredArgument('find')) {
364 metadata.isFindable = true;
365 }
366 }
367 } else if (fieldType.isConnectionPageInfo()) {
368 requisiteFields[FIELDS.hasNextPage] = true;
369 requisiteFields[FIELDS.hasPreviousPage] = true;
370 } else if (fieldType.isConnectionEdge()) {
371 requisiteFields[FIELDS.cursor] = true;
372 requisiteFields[FIELDS.node] = true;
373 }
374 if (fieldType.isAbstract()) {
375 metadata.isAbstract = true;
376 requisiteFields[FIELDS.__typename] = true;
377 }
378 if (fieldType.isList()) {
379 metadata.isPlural = true;
380 }
381 if (generatedSiblings.hasOwnProperty(field.getName())) {
382 metadata.isGenerated = true;
383 }
384 if (requisiteSiblings.hasOwnProperty(field.getName())) {
385 metadata.isRequisite = true;
386 }
387
388 var selections = this.printSelections(field, requisiteFields, idFragment ? [idFragment] : null, isGeneratedQuery);
389 var fieldAlias = field.getAlias();
390 var args = field.getArguments();
391 var calls = args.length ? t.arrayExpression(args.map(function (arg) {
392 return _this3.printArgument(arg);
393 })) : NULL;
394
395 return codify({
396 alias: fieldAlias ? t.valueToNode(fieldAlias) : NULL,
397 calls: calls,
398 children: selections,
399 directives: this.printDirectives(field.getDirectives()),
400 fieldName: t.valueToNode(field.getName()),
401 kind: t.valueToNode('Field'),
402 metadata: this.printRelayDirectiveMetadata(field, metadata),
403 type: t.valueToNode(fieldType.getName({ modifiers: false }))
404 });
405 }
406 }, {
407 key: 'printFragmentReference',
408 value: function printFragmentReference(fragmentReference) {
409 return t.callExpression(t.memberExpression(identify(this.tagName), t.identifier('__frag')), [t.identifier(fragmentReference.getName())]);
410 }
411 }, {
412 key: 'printArgument',
413 value: function printArgument(arg) {
414 var metadata = {};
415 var inputType = this.printArgumentTypeForMetadata(arg.getType());
416 if (inputType) {
417 metadata.type = inputType;
418 }
419 return codify({
420 kind: t.valueToNode('Call'),
421 metadata: objectify(metadata),
422 name: t.valueToNode(arg.getName()),
423 value: this.printArgumentValue(arg)
424 });
425 }
426 }, {
427 key: 'printArgumentValue',
428 value: function printArgumentValue(arg) {
429 if (arg.isVariable()) {
430 return this.printVariable(arg.getVariableName());
431 } else {
432 return this.printValue(arg.getValue());
433 }
434 }
435 }, {
436 key: 'printVariable',
437 value: function printVariable(name) {
438 // Assume that variables named like substitutions are substitutions.
439 if (this.variableNames.hasOwnProperty(name)) {
440 return t.callExpression(t.memberExpression(identify(this.tagName), t.identifier('__var')), [t.identifier(name)]);
441 }
442 return codify({
443 kind: t.valueToNode('CallVariable'),
444 callVariableName: t.valueToNode(name)
445 });
446 }
447 }, {
448 key: 'printValue',
449 value: function printValue(value) {
450 var _this4 = this;
451
452 if (Array.isArray(value)) {
453 return t.arrayExpression(value.map(function (element) {
454 return _this4.printArgumentValue(element);
455 }));
456 }
457 return codify({
458 kind: t.valueToNode('CallValue'),
459 callValue: t.valueToNode(value)
460 });
461 }
462 }, {
463 key: 'printDirectives',
464 value: function printDirectives(directives) {
465 var _this5 = this;
466
467 var printedDirectives = [];
468 directives.forEach(function (directive) {
469 if (directive.getName() === 'relay') {
470 return;
471 }
472 printedDirectives.push(t.objectExpression([property('kind', t.valueToNode('Directive')), property('name', t.valueToNode(directive.getName())), property('args', t.arrayExpression(directive.getArguments().map(function (arg) {
473 return t.objectExpression([property('name', t.valueToNode(arg.getName())), property('value', _this5.printArgumentValue(arg))]);
474 })))]));
475 });
476 if (printedDirectives.length) {
477 return t.arrayExpression(printedDirectives);
478 }
479 return NULL;
480 }
481 }, {
482 key: 'printRelayDirectiveMetadata',
483 value: function printRelayDirectiveMetadata(node, maybeMetadata) {
484 var properties = [];
485 var relayDirective = find(node.getDirectives(), function (directive) {
486 return directive.getName() === 'relay';
487 });
488 if (relayDirective) {
489 relayDirective.getArguments().forEach(function (arg) {
490 if (arg.isVariable()) {
491 invariant(!arg.isVariable(), 'You supplied `$%s` as the `%s` argument to the `@relay` ' + 'directive, but `@relay` require scalar argument values.', arg.getVariableName(), arg.getName());
492 }
493 properties.push(property(arg.getName(), t.valueToNode(arg.getValue())));
494 });
495 }
496 if (maybeMetadata) {
497 (function () {
498 var metadata = maybeMetadata;
499 Object.keys(metadata).forEach(function (key) {
500 if (metadata[key]) {
501 properties.push(property(key, t.valueToNode(metadata[key])));
502 }
503 });
504 })();
505 }
506 return t.objectExpression(properties);
507 }
508
509 /**
510 * Prints the type for arguments that are transmitted via variables.
511 */
512 }, {
513 key: 'printArgumentTypeForMetadata',
514 value: function printArgumentTypeForMetadata(argType) {
515 // Currently, we always send Enum and Object types as variables.
516 if (argType.isEnum() || argType.isObject()) {
517 return argType.getName({ modifiers: true });
518 }
519 // Currently, we always inline scalar types.
520 if (argType.isScalar()) {
521 return null;
522 }
523 invariant(false, 'Unsupported input type: %s', argType);
524 }
525 }]);
526
527 return RelayQLPrinter;
528 })();
529
530 function shouldGenerateIdFragment(node) {
531 return node.getType().mayImplement('Node') && !node.getSelections().some(function (selection) {
532 return selection instanceof RelayQLInlineFragment && selection.getFragment().getType().getName({ modifiers: false }) === 'Node';
533 });
534 }
535
536 function validateField(field, parentType) {
537 if (field.getName() === 'node') {
538 var argTypes = field.getDeclaredArguments();
539 var argNames = Object.keys(argTypes);
540 invariant(argNames.length !== 1 || argNames[0] !== 'id', 'You defined a `node(id: %s)` field on type `%s`, but Relay requires ' + 'the `node` field to be defined on the root type. See the Object ' + 'Identification Guide: \n' + 'http://facebook.github.io/relay/docs/graphql-object-identification.html', argNames[0] && argTypes[argNames[0]].getName({ modifiers: true }), parentType.getName({ modifiers: false }));
541 }
542 }
543
544 function validateConnectionField(field) {
545 invariant(!field.hasArgument('first') || !field.hasArgument('before'), 'Connection arguments `%s(before: <cursor>, first: <count>)` are ' + 'not supported. Use `(first: <count>)`, ' + '`(after: <cursor>, first: <count>)`, or ' + '`(before: <cursor>, last: <count>)`.', field.getName());
546 invariant(!field.hasArgument('last') || !field.hasArgument('after'), 'Connection arguments `%s(after: <cursor>, last: <count>)` are ' + 'not supported. Use `(last: <count>)`, ' + '`(before: <cursor>, last: <count>)`, or ' + '`(after: <cursor>, first: <count>)`.', field.getName());
547
548 // Use `any` because we already check `isConnection` before validating.
549 var connectionNodeType = field.getType().getFieldDefinition(FIELDS.edges).getType().getFieldDefinition(FIELDS.node).getType();
550
551 // NOTE: These checks are imperfect because we cannot trace fragment spreads.
552 forEachRecursiveField(field, function (subfield) {
553 if (subfield.getName() === FIELDS.edges || subfield.getName() === FIELDS.pageInfo) {
554 invariant(field.isPattern() || field.hasArgument('find') || field.hasArgument('first') || field.hasArgument('last'), 'You supplied the `%s` field on a connection named `%s`, but you did ' + 'not supply an argument necessary to do so. Use either the `find`, ' + '`first`, or `last` argument.', subfield.getName(), field.getName());
555 } else {
556 // Suggest `edges{node{...}}` instead of `nodes{...}`.
557 var subfieldType = subfield.getType();
558 var isNodesLikeField = subfieldType.isList() && subfieldType.getName({ modifiers: false }) === connectionNodeType.getName({ modifiers: false });
559 invariant(!isNodesLikeField, 'You supplied a field named `%s` on a connection named `%s`, but ' + 'pagination is not supported on connections without using `%s`. ' + 'Use `%s{%s{%s{...}}}` instead.', subfield.getName(), field.getName(), FIELDS.edges, field.getName(), FIELDS.edges, FIELDS.node);
560 }
561 });
562 }
563
564 function validateMutationField(rootField) {
565 var declaredArgs = rootField.getDeclaredArguments();
566 var declaredArgNames = Object.keys(declaredArgs);
567 invariant(declaredArgNames.length === 1, 'Your schema defines a mutation field `%s` that takes %d arguments, ' + 'but mutation fields must have exactly one argument named `%s`.', rootField.getName(), declaredArgNames.length, INPUT_ARGUMENT_NAME);
568 invariant(declaredArgNames[0] === INPUT_ARGUMENT_NAME, 'Your schema defines a mutation field `%s` that takes an argument ' + 'named `%s`, but mutation fields must have exactly one argument ' + 'named `%s`.', rootField.getName(), declaredArgNames[0], INPUT_ARGUMENT_NAME);
569
570 var rootFieldArgs = rootField.getArguments();
571 invariant(rootFieldArgs.length <= 1, 'There are %d arguments supplied to the mutation field named `%s`, ' + 'but mutation fields must have exactly one `%s` argument.', rootFieldArgs.length, rootField.getName(), INPUT_ARGUMENT_NAME);
572 }
573
574 var forEachRecursiveField = function forEachRecursiveField(selection, callback) {
575 selection.getSelections().forEach(function (selection) {
576 if (selection instanceof RelayQLField) {
577 callback(selection);
578 } else if (selection instanceof RelayQLInlineFragment) {
579 forEachRecursiveField(selection.getFragment(), callback);
580 }
581 // Ignore `RelayQLFragmentSpread` selections.
582 });
583 };
584
585 function codify(obj) {
586 var properties = [];
587 Object.keys(obj).forEach(function (key) {
588 var value = obj[key];
589 if (value !== NULL) {
590 properties.push(property(key, value));
591 }
592 });
593 return t.objectExpression(properties);
594 }
595
596 function identify(str) {
597 return str.split('.').reduce(function (acc, name) {
598 if (!acc) {
599 return t.identifier(name);
600 }
601 return t.memberExpression(acc, t.identifier(name));
602 }, null);
603 }
604
605 function objectify(obj) {
606 var properties = [];
607 Object.keys(obj).forEach(function (key) {
608 var value = obj[key];
609 if (value) {
610 properties.push(property(key, t.valueToNode(value)));
611 }
612 });
613 return t.objectExpression(properties);
614 }
615
616 function property(name, value) {
617 return t.objectProperty(t.identifier(name), value);
618 }
619
620 function shallowFlatten(arr) {
621 return t.callExpression(t.memberExpression(t.memberExpression(EMPTY_ARRAY, t.identifier('concat')), t.identifier('apply')), [EMPTY_ARRAY, arr]);
622 }
623
624 return RelayQLPrinter;
625};
\No newline at end of file