@ardatan/relay-compiler
Version:
Fork of `relay-compiler`
155 lines (134 loc) • 4.36 kB
JavaScript
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
* @emails oncall+relay
*/
// flowlint ambiguous-object-type:error
;
var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault');
var _objectSpread2 = _interopRequireDefault(require('@babel/runtime/helpers/objectSpread2'));
var IRTransformer = require('../core/IRTransformer');
// The purpose of this directive is to add GraphQL type inform for fields in
// the operation selection in order to use in in RelayMockPayloadGenerator
// to generate better mock values, and expand the API of MockResolvers
var SCHEMA_EXTENSION = 'directive @relay_test_operation on QUERY | MUTATION | SUBSCRIPTION';
function testOperationDirective(context) {
return IRTransformer.transform(context, {
Fragment: function Fragment(node) {
return node;
},
Root: visitRoot,
SplitOperation: function SplitOperation(node) {
return node;
},
});
}
function getTypeDetails(schema, fieldType) {
var nullableType = schema.getNullableType(fieldType);
var isNullable = !schema.isNonNull(fieldType);
var isPlural = schema.isList(nullableType);
var type = schema.getRawType(nullableType);
return {
enumValues: schema.isEnum(type) ? schema.getEnumValues(schema.assertEnumType(type)) : null,
nullable: isNullable,
plural: isPlural,
type: schema.getTypeString(type),
};
}
function visitRoot(node) {
// $FlowFixMe[incompatible-use]
var schema = this.getContext().getSchema();
var testDirective = node.directives.find(function (directive) {
return directive.name === 'relay_test_operation';
});
if (testDirective == null) {
return node;
}
var queue = [
{
selections: node.selections,
path: null,
},
];
var selectionsTypeInfo = {};
var _loop = function _loop() {
var _queue$pop = queue.pop(),
currentSelections = _queue$pop.selections,
path = _queue$pop.path;
currentSelections.forEach(function (selection) {
switch (selection.kind) {
case 'FragmentSpread':
// We don't expect to have fragment spreads at this point (it's operations only transform step)
break;
case 'ScalarField': {
var nextPath =
path === null ? selection.alias : ''.concat(path, '.').concat(selection.alias);
selectionsTypeInfo[nextPath] = getTypeDetails(schema, selection.type);
break;
}
case 'LinkedField': {
var _nextPath =
path === null ? selection.alias : ''.concat(path, '.').concat(selection.alias);
selectionsTypeInfo[_nextPath] = getTypeDetails(schema, selection.type);
queue.push({
selections: selection.selections,
path: _nextPath,
});
break;
}
case 'Condition':
case 'Defer':
case 'InlineDataFragmentSpread':
case 'InlineFragment':
case 'ModuleImport':
case 'Stream':
queue.push({
selections: selection.selections,
path: path,
});
break;
case 'ClientExtension':
// Clinet extensions are not part of the schema. We should not generate type info.
break;
default:
selection;
break;
}
});
};
while (queue.length > 0) {
_loop();
} // Sort selectionsTypeInfo
var keys = Object.keys(selectionsTypeInfo).sort(function (a, b) {
return a < b ? -1 : a > b ? 1 : 0;
});
var sortedSelectionsTypeInfo = {};
keys.forEach(function (key) {
sortedSelectionsTypeInfo[key] = selectionsTypeInfo[key];
});
return (0, _objectSpread2['default'])(
(0, _objectSpread2['default'])({}, node),
{},
{
directives: node.directives.filter(function (directive) {
return directive !== testDirective;
}),
metadata: (0, _objectSpread2['default'])(
(0, _objectSpread2['default'])({}, node.metadata || {}),
{},
{
relayTestingSelectionTypeInfo: sortedSelectionsTypeInfo,
},
),
},
);
}
module.exports = {
SCHEMA_EXTENSION: SCHEMA_EXTENSION,
transform: testOperationDirective,
};