graphql-codegen
Version:
Generate client code based on a GraphQL schema and query documents
430 lines (335 loc) • 14.8 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.CodeGenerationContext = undefined;
var _from = require('babel-runtime/core-js/array/from');
var _from2 = _interopRequireDefault(_from);
var _assign = require('babel-runtime/core-js/object/assign');
var _assign2 = _interopRequireDefault(_assign);
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _getIterator2 = require('babel-runtime/core-js/get-iterator');
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');
var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
var _values = require('babel-runtime/core-js/object/values');
var _values2 = _interopRequireDefault(_values);
var _create = require('babel-runtime/core-js/object/create');
var _create2 = _interopRequireDefault(_create);
var _set = require('babel-runtime/core-js/set');
var _set2 = _interopRequireDefault(_set);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
exports.printFields = printFields;
var _graphql = require('graphql');
var _printing = require('./utilities/printing.js');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Parts of this code are adapted from graphql-js
var CodeGenerationContext = exports.CodeGenerationContext = function () {
function CodeGenerationContext(schema, document) {
var _this = this;
(0, _classCallCheck3.default)(this, CodeGenerationContext);
this.schema = schema;
this.typesUsedSet = new _set2.default();
this.fragmentMap = (0, _create2.default)(null);
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = (0, _getIterator3.default)(document.definitions), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var definition = _step.value;
if (definition.kind === _graphql.Kind.FRAGMENT_DEFINITION) {
this.fragmentMap[definition.name.value] = this.augmentWithTypes(definition);
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
this.queries = [];
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = (0, _getIterator3.default)(document.definitions), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _definition = _step2.value;
if (_definition.kind === _graphql.Kind.OPERATION_DEFINITION) {
var _augmentWithTypes = this.augmentWithTypes(_definition);
var loc = _augmentWithTypes.loc;
var name = _augmentWithTypes.name;
var operation = _augmentWithTypes.operation;
var variableDefinitions = _augmentWithTypes.variableDefinitions;
var selectionSet = _augmentWithTypes.selectionSet;
var variables = variableDefinitions.map(function (node) {
return { name: node.variable.name.value, type: node.type };
});
var rootType = operationRootType(this.schema, operation);
var _collectFieldsAndFrag3 = this.collectFieldsAndFragmentNames(rootType, selectionSet);
var _collectFieldsAndFrag4 = (0, _slicedToArray3.default)(_collectFieldsAndFrag3, 1);
var groupedFieldSet = _collectFieldsAndFrag4[0];
var _resolveFields3 = this.resolveFields(groupedFieldSet);
var _resolveFields4 = (0, _slicedToArray3.default)(_resolveFields3, 2);
var fields = _resolveFields4[0];
var fragmentNames = _resolveFields4[1];
this.queries.push({ name: name.value, variables: variables, fields: fields, source: sourceAt(loc), fragmentNames: fragmentNames });
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
this.fragments = (0, _values2.default)(this.fragmentMap).map(function (_ref) {
var loc = _ref.loc;
var name = _ref.name;
var typeCondition = _ref.typeCondition;
var selectionSet = _ref.selectionSet;
var fragmentType = (0, _graphql.typeFromAST)(_this.schema, typeCondition);
var _collectFieldsAndFrag = _this.collectFieldsAndFragmentNames(fragmentType, selectionSet);
var _collectFieldsAndFrag2 = (0, _slicedToArray3.default)(_collectFieldsAndFrag, 1);
var groupedFieldSet = _collectFieldsAndFrag2[0];
var _resolveFields = _this.resolveFields(groupedFieldSet);
var _resolveFields2 = (0, _slicedToArray3.default)(_resolveFields, 1);
var fields = _resolveFields2[0];
return { name: name.value, fields: fields, source: sourceAt(loc) };
});
}
(0, _createClass3.default)(CodeGenerationContext, [{
key: 'augmentWithTypes',
value: function augmentWithTypes(ast) {
var _this2 = this;
var typeInfo = new _graphql.TypeInfo(this.schema);
return (0, _graphql.visit)(ast, (0, _graphql.visitWithTypeInfo)(typeInfo, {
leave: {
VariableDefinition: function VariableDefinition(node) {
var type = typeInfo.getInputType();
_this2.addUsedType(type);
return (0, _extends3.default)({}, node, { type: type });
},
Field: function Field(node) {
var type = typeInfo.getType();
_this2.addUsedType(type);
return (0, _extends3.default)({}, node, { type: type });
}
}
}));
}
}, {
key: 'addUsedType',
value: function addUsedType(type) {
var namedType = (0, _graphql.getNamedType)(type);
this.typesUsedSet.add(namedType);
}
}, {
key: 'collectFieldsAndFragmentNames',
value: function collectFieldsAndFragmentNames(parentType, selectionSet) {
var groupedFieldSet = arguments.length <= 2 || arguments[2] === undefined ? (0, _create2.default)(null) : arguments[2];
var visitedFragmentSet = arguments.length <= 3 || arguments[3] === undefined ? (0, _create2.default)(null) : arguments[3];
if (!(0, _graphql.isCompositeType)(parentType)) {
throw new Error('parentType should be a composite type');
}
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = (0, _getIterator3.default)(selectionSet.selections), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var selection = _step3.value;
switch (selection.kind) {
case _graphql.Kind.FIELD:
{
var fieldName = selection.name.value;
var responseName = selection.alias ? selection.alias.value : fieldName;
var field = parentType.getFields()[fieldName];
if (!field) {
throw new _graphql.GraphQLError('Cannot query field "' + fieldName + '" on type "' + parentType.name + '"', [selection]);
}
var fieldType = field.type;
if (!groupedFieldSet[responseName]) {
groupedFieldSet[responseName] = [];
}
groupedFieldSet[responseName].push((0, _extends3.default)({}, selection, { type: fieldType }));
break;
}
case _graphql.Kind.INLINE_FRAGMENT:
{
var typeCondition = selection.typeCondition;
var inlineFragmentType = typeCondition ? (0, _graphql.typeFromAST)(this.schema, typeCondition) : parentType;
if (inlineFragmentType !== parentType) {
throw new _graphql.GraphQLError('Apollo iOS does not yet support polymorphic results through type conditions', [typeCondition]);
}
this.collectFieldsAndFragmentNames(inlineFragmentType, selection.selectionSet, groupedFieldSet, visitedFragmentSet);
break;
}
case _graphql.Kind.FRAGMENT_SPREAD:
{
var fragmentName = selection.name.value;
if (visitedFragmentSet[fragmentName]) continue;
visitedFragmentSet[fragmentName] = true;
var fragment = this.fragmentMap[fragmentName];
if (!fragment) continue;
var _typeCondition = fragment.typeCondition;
var fragmentType = (0, _graphql.typeFromAST)(this.schema, _typeCondition);
if (fragmentType !== parentType) {
throw new _graphql.GraphQLError('Apollo iOS does not yet support polymorphic results through type conditions', [_typeCondition]);
}
this.collectFieldsAndFragmentNames(fragmentType, fragment.selectionSet, groupedFieldSet, visitedFragmentSet);
break;
}
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
return [groupedFieldSet, visitedFragmentSet];
}
}, {
key: 'resolveFields',
value: function resolveFields(groupedFieldSet) {
var fields = [];
var fragmentNameSet = (0, _create2.default)(null);
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = (0, _getIterator3.default)((0, _keys2.default)(groupedFieldSet)), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var name = _step4.value;
var fieldSet = groupedFieldSet[name];
var type = fieldSet[0].type;
var field = { name: name, type: type };
var namedType = (0, _graphql.getNamedType)(type);
if ((0, _graphql.isCompositeType)(namedType)) {
var _mergeSelectionSets = this.mergeSelectionSets(namedType, fieldSet);
var _mergeSelectionSets2 = (0, _slicedToArray3.default)(_mergeSelectionSets, 2);
var nestedGroupedFieldSet = _mergeSelectionSets2[0];
var nestedFragmentNameSet = _mergeSelectionSets2[1];
fragmentNameSet = (0, _assign2.default)(fragmentNameSet, nestedFragmentNameSet);
field.fragmentNames = (0, _keys2.default)(nestedFragmentNameSet);
var _resolveFields5 = this.resolveFields(nestedGroupedFieldSet);
var _resolveFields6 = (0, _slicedToArray3.default)(_resolveFields5, 1);
var subfields = _resolveFields6[0];
field.subfields = subfields;
}
fields.push(field);
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
return [fields, (0, _keys2.default)(fragmentNameSet)];
}
}, {
key: 'mergeSelectionSets',
value: function mergeSelectionSets(parentType, fieldSet) {
var groupedFieldSet = (0, _create2.default)(null);
var visitedFragmentSet = (0, _create2.default)(null);
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = (0, _getIterator3.default)(fieldSet), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var field = _step5.value;
var selectionSet = field.selectionSet;
if (selectionSet) {
this.collectFieldsAndFragmentNames(parentType, selectionSet, groupedFieldSet, visitedFragmentSet);
};
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
return [groupedFieldSet, visitedFragmentSet];
}
}, {
key: 'typesUsed',
get: function get() {
return (0, _from2.default)(this.typesUsedSet);
}
}]);
return CodeGenerationContext;
}();
function sourceAt(location) {
return location.source.body.slice(location.start, location.end);
}
function printFields(fields) {
return fields && (0, _printing.block)(fields.map(function (field) {
return field.name + ': ' + String(field.type) + (0, _printing.wrap)(' ', printFields(field.subfields));
}));
}
/**
* Extracts the root type of the operation from the schema.
*/
function operationRootType(schema, operation) {
switch (operation) {
case 'query':
return schema.getQueryType();
case 'mutation':
var mutationType = schema.getMutationType();
if (!mutationType) {
throw new _graphql.GraphQLError('Schema is not configured for mutations', [operation]);
}
return mutationType;
case 'subscription':
var subscriptionType = schema.getSubscriptionType();
if (!subscriptionType) {
throw new _graphql.GraphQLError('Schema is not configured for subscriptions', [operation]);
}
return subscriptionType;
default:
throw new _graphql.GraphQLError('Can only execute queries, mutations and subscriptions', [operation]);
}
}