UNPKG

apollo-codegen

Version:

Generate API code or type annotations based on a GraphQL schema and query documents

368 lines (309 loc) 12.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateSource = generateSource; exports.typeDeclarationForGraphQLType = typeDeclarationForGraphQLType; exports.interfaceVariablesDeclarationForOperation = interfaceVariablesDeclarationForOperation; exports.typeDeclarationForOperation = typeDeclarationForOperation; exports.typeDeclarationForFragment = typeDeclarationForFragment; exports.propertiesFromFields = propertiesFromFields; exports.propertyFromField = propertyFromField; exports.propertyDeclarations = propertyDeclarations; var _graphql = require('graphql'); var _graphql2 = require('../utilities/graphql'); var _changeCase = require('change-case'); var _inflected = require('inflected'); var _inflected2 = _interopRequireDefault(_inflected); var _printing = require('../utilities/printing'); var _CodeGenerator = require('../utilities/CodeGenerator'); var _CodeGenerator2 = _interopRequireDefault(_CodeGenerator); var _language = require('./language'); var _types = require('./types'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function generateSource(context, options) { var generator = new _CodeGenerator2.default(context); generator.printOnNewline('/* @flow */'); generator.printOnNewline('// This file was automatically generated and should not be edited.'); typeDeclarationForGraphQLType(context.typesUsed.forEach(function (type) { return typeDeclarationForGraphQLType(generator, type); })); // When an object has fragment spreads or inline fragments // and __typename is requested at the top level, __typename // needs to be added as a property of the fragments var fragmentsWithTypenameField = {}; Object.values(context.operations).forEach(function (operation) { interfaceVariablesDeclarationForOperation(generator, operation); typeDeclarationForOperation(generator, operation, fragmentsWithTypenameField); }); Object.values(context.fragments).forEach(function (operation) { return typeDeclarationForFragment(generator, operation, fragmentsWithTypenameField); }); return generator.output; } function typeDeclarationForGraphQLType(generator, type) { if (type instanceof _graphql.GraphQLEnumType) { enumerationDeclaration(generator, type); } else if (type instanceof _graphql.GraphQLInputObjectType) { structDeclarationForInputObjectType(generator, type); } } function enumerationDeclaration(generator, type) { var name = type.name, description = type.description; var values = type.getValues(); generator.printNewlineIfNeeded(); generator.printOnNewline(description && `// ${description}`); generator.printOnNewline(`export type ${name} =`); var nValues = values.length; values.forEach(function (value, i) { return generator.printOnNewline(` "${value.value}"${i === nValues - 1 ? ';' : ' |'}${(0, _printing.wrap)(' // ', value.description)}`); }); generator.printNewline(); } function structDeclarationForInputObjectType(generator, type) { var interfaceName = (0, _changeCase.pascalCase)(type.name); (0, _language.typeDeclaration)(generator, { interfaceName }, function () { var properties = propertiesFromFields(generator.context, Object.values(type.getFields())); propertyDeclarations(generator, properties, true); }); } function interfaceNameFromOperation(_ref) { var operationName = _ref.operationName, operationType = _ref.operationType; switch (operationType) { case 'query': return `${(0, _changeCase.pascalCase)(operationName)}Query`; break; case 'mutation': return `${(0, _changeCase.pascalCase)(operationName)}Mutation`; break; case 'subscription': return `${(0, _changeCase.pascalCase)(operationName)}Subscription`; break; default: throw new _graphql.GraphQLError(`Unsupported operation type "${operationType}"`); } } function interfaceVariablesDeclarationForOperation(generator, _ref2) { var operationName = _ref2.operationName, operationType = _ref2.operationType, variables = _ref2.variables, fields = _ref2.fields, fragmentsReferenced = _ref2.fragmentsReferenced, source = _ref2.source; if (!variables || variables.length < 1) { return null; } var interfaceName = `${interfaceNameFromOperation({ operationName, operationType })}Variables`; (0, _language.typeDeclaration)(generator, { interfaceName }, function () { var properties = propertiesFromFields(generator.context, variables); propertyDeclarations(generator, properties, true); }); } function typeDeclarationForOperation(generator, _ref3, fragmentsWithTypenameField) { var operationName = _ref3.operationName, operationType = _ref3.operationType, variables = _ref3.variables, fields = _ref3.fields, fragmentSpreads = _ref3.fragmentSpreads, inlineFragments = _ref3.inlineFragments, fragmentsReferenced = _ref3.fragmentsReferenced, source = _ref3.source; if (hasTypenameField(fields)) { console.error('__typename on operations are not yet supported'); } var interfaceName = interfaceNameFromOperation({ operationName, operationType }); var properties = propertiesFromFields(generator.context, fields, { typeNameSuffix: `From${operationName}` }); (0, _language.typeDeclaration)(generator, { interfaceName }, function () { propertyDeclarations(generator, properties, true); }); properties.forEach(function (_ref4) { var fragmentSpreads = _ref4.fragmentSpreads, inlineFragments = _ref4.inlineFragments, bareTypeName = _ref4.bareTypeName; if (fragmentSpreads.length > 0) { fragmentSpreads.forEach(function (fragmentSpread) { fragmentsWithTypenameField[fragmentSpread] = true; }); } if (inlineFragments.length > 0) { var fragmentName = `${(0, _changeCase.pascalCase)(bareTypeName)}From${operationName}`; handleInlineFragments(generator, fragmentName, inlineFragments); } }); } function typeDeclarationForFragment(generator, _ref5, fragmentsWithTypenameField) { var fragmentName = _ref5.fragmentName, typeCondition = _ref5.typeCondition, fields = _ref5.fields, inlineFragments = _ref5.inlineFragments, fragmentSpreads = _ref5.fragmentSpreads, source = _ref5.source, possibleTypes = _ref5.possibleTypes; var interfaceName = `${(0, _changeCase.pascalCase)(fragmentName)}Fragment`; if (inlineFragments.length > 0) { handleInlineFragments(generator, interfaceName, inlineFragments); } else { (0, _language.typeDeclaration)(generator, { interfaceName // extendTypes: fragmentSpreads ? fragmentSpreads.map(f => `${pascalCase(f)}Fragment`) : null, }, function () { if (fragmentsWithTypenameField[fragmentName]) { addTypenameFieldIfNeeded(generator, fields, typeCondition); } var properties = propertiesFromFields(generator.context, fields, { typeNameSuffix: 'Fragment' }); propertyDeclarations(generator, properties, true); }); } } function propertiesFromFields(context, fields) { var _ref6 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, forceNullable = _ref6.forceNullable, typeNameSuffix = _ref6.typeNameSuffix; return fields.map(function (field) { return propertyFromField(context, field, { forceNullable, typeNameSuffix }); }); } function propertyFromField(context, field) { var _ref7 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, forceNullable = _ref7.forceNullable, typeNameSuffix = _ref7.typeNameSuffix; var fieldName = field.name, fieldType = field.type, description = field.description, fragmentSpreads = field.fragmentSpreads, inlineFragments = field.inlineFragments; fieldName = fieldName || field.responseName; var propertyName = fieldName; var property = { fieldName, fieldType, propertyName, description, inlineFragments }; var namedType = (0, _graphql.getNamedType)(fieldType); if ((0, _graphql.isCompositeType)(namedType)) { var typeName = void 0, bareTypeName = void 0; if (propertyName === '__typename') { // Handle the __typename field specially. the fieldType is set // to the parentType but we want the target type to be a string literal // of the parentType. bareTypeName = `"${fieldType}"`; typeName = `"${fieldType}"`; } else { bareTypeName = (0, _changeCase.pascalCase)(_inflected2.default.singularize(propertyName)); if (inlineFragments && inlineFragments.length > 0 || fragmentSpreads && fragmentSpreads.length > 0) { typeName = (0, _types.typeNameFromGraphQLType)(context, fieldType, `${(0, _changeCase.pascalCase)(bareTypeName)}${typeNameSuffix}`); } else { typeName = (0, _types.typeNameFromGraphQLType)(context, fieldType, bareTypeName); } } var isArray = false; if (fieldType instanceof _graphql.GraphQLList) { isArray = true; } else if (fieldType instanceof _graphql.GraphQLNonNull && fieldType.ofType instanceof _graphql.GraphQLList) { isArray = true; } var isNullable = true; if (fieldType instanceof _graphql.GraphQLNonNull && !forceNullable) { isNullable = false; } return Object.assign({}, property, { typeName, bareTypeName, fields: field.fields, isComposite: true, fragmentSpreads, inlineFragments, fieldType, isArray, isNullable }); } else { var _typeName = (0, _types.typeNameFromGraphQLType)(context, fieldType); return Object.assign({}, property, { typeName: _typeName, isComposite: false, fieldType }); } } function propertyDeclarations(generator, properties, inInterface) { if (!properties) return; properties.forEach(function (property) { if (property.fields && property.fields.length > 0 || property.inlineFragments && property.inlineFragments.length > 0) { if (property.inlineFragments.length > 0) { (0, _language.propertyDeclaration)(generator, Object.assign({}, property, { inInterface })); } else { (0, _language.propertyDeclaration)(generator, Object.assign({}, property, { inInterface }), function () { var properties = propertiesFromFields(generator.context, property.fields); propertyDeclarations(generator, properties); }); } } else { (0, _language.propertyDeclaration)(generator, Object.assign({}, property, { inInterface })); } }); } function makeTypenameField(typeName) { return { responseName: '__typename', fieldName: '__typename', type: typeName }; } function hasTypenameField(fields) { if (!fields) { return false; } return fields.find(function (field) { return field.fieldName === '__typename' || field.responseName === '__typename'; }); } function removeTypenameFieldIfExists(generator, fields) { if (hasTypenameField(fields)) { fields = fields.filter(function (field) { return field.fieldName !== '__typename' || field.responseName !== '__typename'; }); return true; } else { return false; } } /** * NOTE: Mutates `fields` */ function addTypenameFieldIfNeeded(generator, fields, parentTypeName) { var removed = removeTypenameFieldIfExists(); if (generator.context.addTypename || removed) { fields.unshift(makeTypenameField(parentTypeName)); } } function handleInlineFragments(generator, fragmentName, inlineFragments) { // Keep track of these generated destination type names so we can build a union afterwards var unionTypes = []; inlineFragments.forEach(function (_ref8) { var fields = _ref8.fields, typeCondition = _ref8.typeCondition; var typeName = `${fragmentName}On${typeCondition}`; unionTypes.push(typeName); addTypenameFieldIfNeeded(generator, fields, typeCondition); var properties = propertiesFromFields(generator.context, fields, { typeNameSuffix: 'Fragment' }); (0, _language.typeDeclaration)(generator, { interfaceName: typeName }, function () { propertyDeclarations(generator, properties, true); }); properties.forEach(function (_ref9) { var inlineFragments = _ref9.inlineFragments, bareTypeName = _ref9.bareTypeName; if (inlineFragments && inlineFragments.length > 0) { var innerFragmentName = `${bareTypeName}Fragment`; handleInlineFragments(generator, innerFragmentName, inlineFragments); } }); }); // TODO: Refactor typeDeclaration to not automatically assume bracketed type (0, _language.typeDeclaration)(generator, { interfaceName: fragmentName, noBrackets: true }, function () { (0, _language.unionDeclaration)(generator, unionTypes); }); } //# sourceMappingURL=codeGeneration.js.map