UNPKG

@gapi/cli

Version:
392 lines (391 loc) 13.3 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const graphql_1 = require('graphql'); const util_1 = require('../../util/dist'); const language_typescript_1 = require('../../language-typescript/dist'); const subtype_1 = require('./subtype'); const doIt = (schema, query, typeMap = {}, providedOptions = {}) => { const enumDeclarations = new Map(); const TypeMap = Object.assign( {}, language_typescript_1.DEFAULT_TYPE_MAP, typeMap ); const { wrapList, wrapPartial, generateSubTypeInterfaceName, printType, formatInput, generateFragmentName, generateQueryName, interfaceBuilder, typeBuilder, typeJoiner, generateInterfaceDeclaration, exportFunction, postProcessor, generateInputName, addExtensionsToInterfaceName, enumTypeBuilder, formatEnum, generateEnumName, generateDocumentation, } = Object.assign({}, language_typescript_1.DEFAULT_OPTIONS, providedOptions); const getSubtype = subtype_1.GenerateSubtypeCache(); const parsedSchema = util_1.schemaFromInputs(schema); const parsedSelection = graphql_1.parse(query); const handleInputObject = (type, isNonNull) => { const variables = Object.keys(type.getFields()).map( (k) => type.getFields()[k] ); const variableDeclarations = variables.map((v) => formatInput(v.name, true, convertToType(v.type)) ); const builder = generateInterfaceDeclaration( variableDeclarations.map((v) => v) ); return printType(builder, isNonNull); }; const handleEnum = (type, isNonNull) => { const enumName = generateEnumName(type.name); if (!enumDeclarations.has(type.name)) { const enumDeclaration = enumTypeBuilder( enumName, formatEnum(type.getValues(), generateDocumentation) ); enumDeclarations.set(type.name, enumDeclaration); } return printType(enumName, isNonNull); }; const handleNamedTypeInput = (type, isNonNull) => { if ( type.kind === 'NamedType' && type.name.kind === 'Name' && type.name.value ) { const newType = parsedSchema.getType(type.name.value); if (newType instanceof graphql_1.GraphQLEnumType) { return handleEnum(newType, isNonNull); } else if (newType instanceof graphql_1.GraphQLInputObjectType) { return handleInputObject(newType, isNonNull); } } }; const handleRegularType = (type, isNonNull, replacement) => { const typeValue = typeof type.name === 'string' ? type.toString() : type.name.value; const showValue = replacement || typeValue; const show = TypeMap[showValue] || (replacement ? showValue : TypeMap.__DEFAULT); return printType(show, isNonNull); }; const convertVariable = (type, isNonNull = false, replacement = null) => { if (type.kind === 'ListType') { return printType( wrapList(convertVariable(type.type, false, replacement)), isNonNull ); } else if (type.kind === 'NonNullType') { return convertVariable(type.type, true, replacement); } else { return ( handleNamedTypeInput(type, isNonNull) || handleRegularType(type, isNonNull, replacement) ); } }; const convertToType = (type, isNonNull = false, replacement = null) => { if (util_1.isList(type)) { return printType( wrapList(convertToType(type.ofType, false, replacement)), isNonNull ); } else if (util_1.isNonNullable(type)) { return convertToType(type.ofType, true, replacement); } else if (util_1.isEnum(type)) { return handleEnum(type, isNonNull); } else { return handleRegularType(type, isNonNull, replacement); } }; const UndefinedDirectives = new Set(['include', 'skip']); const isUndefinedFromDirective = (directives) => { if (!directives || !directives.length) { return false; } const badDirectives = directives.filter( (d) => !UndefinedDirectives.has(d.name.value) ); const hasDirectives = directives.some((d) => UndefinedDirectives.has(d.name.value) ); if (badDirectives.length) { console.error('Found some unknown directives:'); badDirectives.forEach((d) => console.error(d.name.value)); } return hasDirectives; }; const getOperationFields = (operation) => { switch (operation) { case 'query': return parsedSchema.getQueryType(); case 'mutation': return parsedSchema.getMutationType(); case 'subscription': return parsedSchema.getSubscriptionType(); default: throw new Error('Unsupported Operation'); } }; const wrapPossiblePartial = (possiblePartial) => { if (possiblePartial.isPartial) { return wrapPartial(possiblePartial.iface); } else { return possiblePartial.iface; } }; const flattenComplexTypes = (children) => children.reduce((acc, child) => { acc.push(...child.complexTypes); return acc; }, []); const getField = (operation, selection, parent) => { if (parent && graphql_1.isCompositeType(parent)) { if (parent instanceof graphql_1.GraphQLUnionType) { return parent .getTypes() .map((t) => t.getFields()[selection.name.value]) .find((z) => !!z); } else { return parent.getFields()[selection.name.value]; } } else { const operationFields = getOperationFields(operation); // operation is taken from the schema, so it should never be falsy return operationFields.getFields()[selection.name.value]; } }; const getChildSelections = ( operation, selection, parent, isUndefined = false ) => { let str = ''; let isFragment = false; let isPartial = false; const complexTypes = []; if (selection.kind === 'Field') { const field = getField(operation, selection, parent); const selectionName = selection.alias ? selection.alias.value : selection.name.value; let childType; isUndefined = isUndefined || isUndefinedFromDirective(selection.directives); let resolvedType; if (selectionName.startsWith('__')) { resolvedType = TypeMap.String; } else if (!!selection.selectionSet) { let newParent; const fieldType = graphql_1.getNamedType(field.type); if (graphql_1.isCompositeType(fieldType)) { newParent = fieldType; } const selections = selection.selectionSet.selections.map((sel) => getChildSelections(operation, sel, newParent) ); const nonFragments = selections.filter((s) => !s.isFragment); const fragments = selections.filter((s) => s.isFragment); const andOps = []; complexTypes.push(...flattenComplexTypes(selections)); if (nonFragments.length) { const nonPartialNonFragments = nonFragments.filter( (nf) => !nf.isPartial ); const partialNonFragments = nonFragments.filter((nf) => nf.isPartial); if (nonPartialNonFragments.length) { const interfaceDeclaration = generateInterfaceDeclaration( nonPartialNonFragments.map((f) => f.iface) ); const subtypeInfo = getSubtype( selection, interfaceDeclaration, generateSubTypeInterfaceName ); const newInterfaceName = subtypeInfo ? subtypeInfo.name : null; andOps.push(newInterfaceName || interfaceDeclaration); if (newInterfaceName && subtypeInfo && !subtypeInfo.dupe) { complexTypes.push({ iface: interfaceDeclaration, isPartial: false, name: newInterfaceName, }); } } if (partialNonFragments.length) { const interfaceDeclaration = wrapPartial( generateInterfaceDeclaration( partialNonFragments.map((f) => f.iface) ) ); const subtypeInfo = getSubtype( selection, interfaceDeclaration, generateSubTypeInterfaceName ); const newInterfaceName = subtypeInfo ? subtypeInfo.name : null; andOps.push(newInterfaceName || interfaceDeclaration); if (newInterfaceName && subtypeInfo && !subtypeInfo.dupe) { complexTypes.push({ iface: interfaceDeclaration, isPartial: true, name: newInterfaceName, }); } } } andOps.push(...fragments.map(wrapPossiblePartial)); childType = typeJoiner(andOps); resolvedType = convertToType(field.type, false, childType); } else { resolvedType = convertToType(field.type, false, childType); } str = formatInput(selectionName, isUndefined, resolvedType); } else if (selection.kind === 'FragmentSpread') { str = generateFragmentName(selection.name.value); isFragment = true; isPartial = isUndefinedFromDirective(selection.directives); } else if (selection.kind === 'InlineFragment') { const anon = !selection.typeCondition; if (!anon) { const typeName = selection.typeCondition.name.value; parent = parsedSchema.getType(typeName); } const selections = selection.selectionSet.selections.map((sel) => getChildSelections(operation, sel, parent, !anon) ); const joinSelections = util_1.filterAndJoinArray( selections.map((s) => s.iface), '\n' ); isPartial = isUndefinedFromDirective(selection.directives); complexTypes.push(...flattenComplexTypes(selections)); return { iface: joinSelections, isFragment, isPartial, complexTypes, }; } return { iface: str, isFragment, isPartial, complexTypes, }; }; const getVariables = (variables) => variables.map((v) => { const optional = v.type.kind !== 'NonNullType'; return formatInput( v.variable.name.value, optional, convertVariable(v.type) ); }); const variablesToInterface = (opName, variables) => { if (!variables || !variables.length) { return ''; } const variableTypeDefs = getVariables(variables); return postProcessor( exportFunction( interfaceBuilder( generateInputName(opName), generateInterfaceDeclaration(variableTypeDefs) ) ) ); }; const buildAdditionalTypes = (children) => { const subTypes = flattenComplexTypes(children); return subTypes .map((subtype) => { if (subtype.isPartial) { return postProcessor( exportFunction(typeBuilder(subtype.name, subtype.iface)) ); } else { return postProcessor( exportFunction(interfaceBuilder(subtype.name, subtype.iface)) ); } }) .concat( [...enumDeclarations.values()].map((enumDecl) => postProcessor(exportFunction(enumDecl)) ) ); }; const joinOutputs = (output) => { const { variables, additionalTypes, interface: iface } = output; const result = postProcessor( util_1.filterAndJoinArray([variables, ...additionalTypes, iface], '\n\n') ); return Object.assign({}, output, { result }); }; return parsedSelection.definitions.map((def) => { if (def.kind === 'OperationDefinition') { const ifaceName = generateQueryName(def); const variableInterface = variablesToInterface( ifaceName, def.variableDefinitions ); const ret = def.selectionSet.selections.map((sel) => getChildSelections(def.operation, sel) ); const fields = ret.map((x) => x.iface); const iface = postProcessor( exportFunction( interfaceBuilder(ifaceName, generateInterfaceDeclaration(fields)) ) ); const additionalTypes = buildAdditionalTypes(ret); return joinOutputs({ variables: variableInterface, interface: iface, additionalTypes, }); } else if (def.kind === 'FragmentDefinition') { const ifaceName = generateFragmentName(def.name.value); // get the correct type const onType = def.typeCondition.name.value; const foundType = parsedSchema.getType(onType); const ret = def.selectionSet.selections.map((sel) => getChildSelections('query', sel, foundType) ); const extensions = ret.filter((x) => x.isFragment).map((x) => x.iface); const fields = ret.filter((x) => !x.isFragment).map((x) => x.iface); const iface = postProcessor( exportFunction( interfaceBuilder( addExtensionsToInterfaceName(ifaceName, extensions), generateInterfaceDeclaration(fields) ) ) ); const additionalTypes = buildAdditionalTypes(ret); return joinOutputs({ interface: iface, variables: '', additionalTypes, }); } else { throw new Error(`Unsupported Definition ${def.kind}`); } }); }; exports.default = doIt; //# sourceMappingURL=index.js.map