UNPKG

graphql-auto-generating-cms

Version:

This module will use your existed graphQL schema to generate simple for use CMS in a couple minutes!

347 lines (334 loc) 12.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.fileUploadingMiddleware = exports.graphqlCMS = exports.fixPath = exports.isListOfType = exports.hasNestedFields = exports.resolveInputControl = exports.resolveInputType = exports.getFields = exports.getTypeListData = exports.getListHeader = exports.checkMethodPermission = exports.findResolverArgs = exports.getResolverName = exports.applyRules = undefined; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; exports.default = function (config) { const schema = config.schema ? (0, _graphql.parse)(config.schema) : false; if (!schema) { throw new Error('you have to provide your PRINTED schema in config object "{schema: myPrintedSchema}"'); } const rules = config.rules ? config.rules : false; const exclude = config.exclude ? config.exclude : false; const uploadRoot = config.uploadRoot ? fixPath(config.uploadRoot) : false; return (req, res) => { if (req.method.toLowerCase() === 'get') { res.send(applyRules({ rules, shape: graphqlCMS({ schema, rules, exclude, uploadRoot }) })); } else if (req.method.toLowerCase() === 'post') { fileUploadingMiddleware.call(this, req, res, uploadRoot); } }; }; var _formidable = require('formidable'); var _formidable2 = _interopRequireDefault(_formidable); var _fsExtra = require('fs-extra'); var _fsExtra2 = _interopRequireDefault(_fsExtra); var _util = require('util'); var _util2 = _interopRequireDefault(_util); var _graphql = require('graphql'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const applyRules = function funcApplyRules(args) { const { shape, rules } = args; const response = rules ? _extends({}, rules) : _extends({}, shape); if (rules) { Object.keys(shape).forEach(key => { if (typeof shape[key] === 'object') { if (!response[key]) { response[key] = shape[key]; } else { response[key] = applyRules({ shape: shape[key], rules: response[key] }); } } else if (!response[key] && typeof response[key] !== 'boolean') { response[key] = shape[key]; } }); } Object.keys(response).forEach(key => { if (key === 'resolvers') { Object.keys(response[key]).forEach(resolver => { if (typeof response[key][resolver].allowed === 'boolean' && !response[key][resolver].allowed) { delete response[key][resolver]; } }); } }); return response; }; const getResolverName = function funcGetResolverName(args) { const { typeName, method, rules } = args; let resolverName = ''; if (rules && rules[typeName] && rules[typeName].resolvers && rules[typeName].resolvers[method] && rules[typeName].resolvers[method].resolver) { resolverName = rules[typeName].resolvers[method].resolver; } else { resolverName = `${typeName}_${method}`; } return resolverName; }; const findResolverArgs = function funcFindResolverArgs(args) { const { typeName, method, fields, rules } = args; const respond = {}; let tmpObj = {}; if (rules && rules[typeName] && rules[typeName].resolvers && rules[typeName].resolvers[method] && rules[typeName].resolvers[method].resolver) { tmpObj = fields.find(obj => obj.name.value === rules[typeName].resolvers[method].resolver); } else { tmpObj = fields.find(obj => obj.name.value === `${typeName}_${method}`); } if (tmpObj && tmpObj.arguments) { tmpObj.arguments.forEach(argObj => { respond[argObj.name.value] = argObj.type.kind === 'NonNullType' ? `${argObj.type.type.name.value}!` : argObj.type.name.value; }); } return respond; }; const checkMethodPermission = function funcCheckMethodPermission(args) { const { typeName, method, mutations, rules } = args; let hasMethod = !!mutations.fields.find(obj => obj.name.value === `${typeName}_${method}`); if (rules && hasMethod && rules[typeName] && rules[typeName].resolvers && rules[typeName].resolvers[method] && (rules[typeName].resolvers[method].allowed || typeof rules[typeName].resolvers[method].allowed === 'boolean')) { hasMethod = rules[typeName].resolvers[method].allowed; } return hasMethod; }; const getListHeader = function funcGetListHeader(args) { const { shape } = args; const response = _extends({}, shape); let id; let title; Object.keys(response).forEach(key => { id = Object.keys(response[key].fields).find(i => i === 'id' || i === '_id'); title = Object.keys(response[key].fields)[1]; response[key].listHeader = { id: [id], title: [title] }; }); return response; }; const getTypeListData = function funcGetTypeListData(args) { const { schema, typeName, rules } = args; const Queries = schema.definitions.find(obj => obj.name.value === 'Query'); const Mutations = schema.definitions.find(obj => obj.name.value === 'Mutation'); return { propTypeName: typeName, label: false, resolvers: { find: { resolver: getResolverName({ rules, typeName, method: 'find' }), args: findResolverArgs({ rules, typeName, method: 'find', fields: Queries.fields }) }, create: { resolver: getResolverName({ rules, typeName, method: 'create' }), args: findResolverArgs({ rules, typeName, method: 'create', fields: Mutations.fields }) } } }; }; const hasNestedFields = function funcHasNestedFields(propType) { switch (propType.toLowerCase()) { case 'boolean': return false; case 'string': return false; case 'int': return false; case 'float': return false; case 'number': return false; default: return true; } }; const isListOfType = function funcIsListOfType(typeValue) { switch (typeValue) { case 'Int': return false; case 'Float': return false; case 'Boolean': return false; case 'String': return false; default: return true; } }; const resolveInputType = function funcResolveInputType(scalarType) { switch (scalarType || scalarType.slice(0, -1)) { case 'Int': return 'number'; case 'Float': return 'number'; case 'Boolean': return 'checkbox'; case 'String': return 'text'; default: return 'text'; } }; const resolveInputControl = function funcResolveInputControl(scalarType) { switch (scalarType || scalarType.slice(0, -1)) { case 'Int': return 'input'; case 'Float': return 'input'; case 'Boolean': return 'input'; case 'String': return 'input'; default: return 'input'; } }; const getFields = function funcGetFields(args) { const { schema, typeName, rules } = args; const typeObject = schema.definitions.find(obj => obj.name.value === typeName); const result = {}; typeObject.fields.forEach(prop => { if (prop && prop.type && prop.type.kind !== 'ListType') { if (prop.name && prop.name.value && prop.type.name && prop.type.name.value && prop.name.value !== 'Mutation' && prop.name.value !== 'Query') { const has = hasNestedFields(prop.type.name.value); result[prop.name.value] = { label: prop.name.value, fieldType: prop.type.name.value, inputType: has ? 'String' : resolveInputType(prop.type.name.value), inputControl: resolveInputControl(prop.type.name.value), disabled: false, exclude: false, list: false, nestedFields: has ? getFields({ schema, rules, typeName: prop.type.name.value }) : false }; } } else if (prop && prop.type && prop.type.type && prop.type.type.name && prop.type.type.name.value && isListOfType(prop.type.type.name.value) && prop.name.value !== 'Mutation' && prop.name.value !== 'Query') { result[prop.name.value] = { label: prop.name.value, fieldType: prop.type.type.name.value, inputType: false, inputControl: 'selection', disabled: false, exclude: false, list: getTypeListData({ schema, rules, typeName: prop.type.type.name.value }), nestedFields: getFields({ schema, typeName: prop.type.type.name.value }) }; } }); return result; }; const fixPath = function funcFixPath(string) { let response = ''; if (string.slice(0, 1) === '/' || string.slice(0, 1) === '.') { response = string; } else { response = `/${string}`; } if (response.slice(-1) === '/') { response = response.slice(0, -1); } return response; }; const graphqlCMS = function funcGraphqlCMS(args) { const { schema, rules, exclude, uploadRoot } = args; const Mutations = schema.definitions.find(obj => obj.name.value === 'Mutation'); const Queries = schema.definitions.find(obj => obj.name.value === 'Query'); let shape = {}; Queries.fields.forEach(method => { const methodTypeName = method.type && method.type.type && method.type.type.name && method.type.type.name.value ? method.type.type.name.value : false; if (methodTypeName && Mutations.fields.find(obj => obj.name.value.split('_')[0] === methodTypeName) && (!exclude || !exclude.find(type => type === methodTypeName))) { shape[methodTypeName] = { uploadRoot, label: methodTypeName, listHeader: false, resolvers: { find: { resolver: getResolverName({ rules, typeName: methodTypeName, method: 'find' }), args: findResolverArgs({ rules, typeName: methodTypeName, method: 'find', fields: Queries.fields }), allowed: true }, create: { resolver: getResolverName({ rules, typeName: methodTypeName, method: 'create' }), args: findResolverArgs({ rules, typeName: methodTypeName, method: 'create', fields: Mutations.fields }), allowed: checkMethodPermission({ rules, typeName: methodTypeName, method: 'create', mutations: Mutations }) }, update: { resolver: getResolverName({ rules, typeName: methodTypeName, method: 'update' }), args: findResolverArgs({ rules, typeName: methodTypeName, method: 'update', fields: Mutations.fields }), allowed: checkMethodPermission({ rules, typeName: methodTypeName, method: 'update', mutations: Mutations }) }, remove: { resolver: getResolverName({ rules, typeName: methodTypeName, method: 'remove' }), args: findResolverArgs({ rules, typeName: methodTypeName, method: 'remove', fields: Mutations.fields }), allowed: checkMethodPermission({ rules, typeName: methodTypeName, method: 'remove', mutations: Mutations }) } }, fields: getFields({ schema, rules, typeName: methodTypeName }) }; } }); shape = getListHeader({ shape }); return shape; }; const fileUploadingMiddleware = function funcFileUploadingMiddleware(req, res, uploadRoot) { const form = new _formidable2.default.IncomingForm(); form.parse(req, (err, fields, files) => { res.end(_util2.default.inspect({ fields, files })); }); form.on('error', err => { if (err) throw new Error(err); }); form.on('end', function () { const tempPath = this.openedFiles[0].path; const fileName = this.openedFiles[0].name.split(',')[0]; const folderPath = fixPath(this.openedFiles[0].name.split(',')[1]); _fsExtra2.default.copy(tempPath, `${uploadRoot}${folderPath}/${fileName}`, err => { if (err) throw new Error(err); }); }); }; // export declared only for test cases exports.applyRules = applyRules; exports.getResolverName = getResolverName; exports.findResolverArgs = findResolverArgs; exports.checkMethodPermission = checkMethodPermission; exports.getListHeader = getListHeader; exports.getTypeListData = getTypeListData; exports.getFields = getFields; exports.resolveInputType = resolveInputType; exports.resolveInputControl = resolveInputControl; exports.hasNestedFields = hasNestedFields; exports.isListOfType = isListOfType; exports.fixPath = fixPath; exports.graphqlCMS = graphqlCMS; exports.fileUploadingMiddleware = fileUploadingMiddleware;