gapi-cli
Version:
Gapi command line interface
269 lines • 13.6 kB
JavaScript
;
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;
let 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));
let 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