UNPKG

@backland/schema

Version:

TypeScript schema declaration and validation library with static type inference

323 lines (321 loc) 12.8 kB
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } import { BJSON, capitalize, notNull } from '@backland/utils'; import { formatGraphQL } from '@backland/utils'; import { tupleEnum } from '@backland/utils'; import { GraphQLObjectType, GraphQLSchema, printSchema } from 'graphql'; import groupBy from 'lodash/groupBy'; import { CircularDeps } from './CircularDeps'; import { GraphType } from './GraphType/GraphType'; import { generateClientUtils } from './GraphType/generateClientUtils'; import { getInnerGraphTypeId } from './GraphType/getInnerGraphTypeId'; import { getSchemaQueryTemplates } from './GraphType/getQueryTemplates'; import { parseFieldDefinitionConfig } from './ObjectType'; import { cleanMetaField } from './fields/MetaFieldField'; import { objectMock } from './mockObject'; export var resolverKinds = tupleEnum('mutation', 'query', 'subscription'); export function createGraphQLSchema() { var { graphql: { GraphQLSchema }, GraphType } = CircularDeps; var registeredResolvers = GraphType.resolvers.entries.map(el => el[1]); var resolvers = Array.isArray(arguments.length <= 0 ? undefined : arguments[0]) ? arguments.length <= 0 ? undefined : arguments[0] : registeredResolvers; var schemaResolvers = resolvers.filter(el => el.__isResolver && !el.__isRelation); var config = Array.isArray(arguments.length <= 0 ? undefined : arguments[0]) ? arguments.length <= 1 ? undefined : arguments[1] : arguments.length <= 0 ? undefined : arguments[0]; var grouped = groupBy(schemaResolvers, item => item.kind); function createFields(kind) { var fields = {}; if (grouped[kind]) { grouped[kind].forEach(item => { fields[item.name] = item; }); } return fields; } var usedConfig = _objectSpread({ mutation: grouped.mutation ? new GraphQLObjectType({ fields: createFields('mutation'), name: 'Mutation' }) : undefined, query: grouped.query ? new GraphQLObjectType({ fields: createFields('query'), name: 'Query' }) : undefined, subscription: grouped.subscription ? new GraphQLObjectType({ fields: createFields('subscription'), name: 'Subscription' }) : undefined }, config); var schema = new GraphQLSchema(usedConfig); var ts; var utils = { generateClientUtils() { return Promise.reject('not implemented'); }, grouped, print() { return printSchema(schema); }, queryExamples(options) { return queryExamples(_objectSpread({ grouped, schema }, options)); }, queryTemplates() { return getSchemaQueryTemplates(schema); }, registeredResolvers, resolvers, typescript(options) { return _asyncToGenerator(function* () { return ts = ts || resolversToTypescript(_objectSpread(_objectSpread({ name: 'GraphQLTypes' }, options), {}, { resolvers })); })(); }, usedConfig }; var result = Object.assign(schema, { utils }); utils.generateClientUtils = function _generateClientUtils() { return generateClientUtils(result); }; return result; } export function resolversTypescriptParts(_x) { return _resolversTypescriptParts.apply(this, arguments); } function _resolversTypescriptParts() { _resolversTypescriptParts = _asyncToGenerator(function* (params) { var { name = 'Schema' } = params; var prefix = ''; var mainResolvers = params.resolvers.filter(el => !el.__isRelation); var mainResolversConversion = mainResolvers.map(item => { return convertResolver({ allResolvers: params.resolvers, resolver: item }); }); var lines = yield Promise.all(mainResolversConversion); var typesCode = ''; var interfaceCode = "export interface ".concat(name, " {"); var queryCode = "export type QueryResolvers = {"; var mutationCode = "export type MutationResolvers = {"; var subscriptionCode = "export type SubscriptionResolvers = {"; lines.forEach(el => { var { entryName, code, payloadName, inputName, resolver: { description = '', kind } } = el; typesCode += "".concat(code, "\n"); if (description) { description = "\n/** ".concat(description, " **/\n"); } var resolverCode = "".concat(description, " ").concat(entryName, "(args: ").concat(inputName, "): Promise<").concat(payloadName, ">,"); switch (kind) { case 'mutation': { mutationCode += resolverCode; break; } case 'query': { queryCode += resolverCode; break; } case 'subscription': { subscriptionCode += resolverCode; break; } } interfaceCode += "".concat(description, " ").concat(entryName, ": {input: ").concat(inputName, ", payload: ").concat(payloadName, "},"); }); var code = "".concat(prefix, "\n").concat(typesCode, "\n").concat(interfaceCode, "}\n").concat(queryCode, "}\n").concat(mutationCode, "}\n").concat(subscriptionCode, "}\n").replace(/\n\n/gm, '\n') // remove multi line breaks .replace(/^\n/gm, ''); // remove empty lines // @ts-ignore circular code = CircularDeps.prettier.format(code, { parser: 'typescript' }); return { code, lines }; }); return _resolversTypescriptParts.apply(this, arguments); } export function resolversToTypescript(_x2) { return _resolversToTypescript.apply(this, arguments); } function _resolversToTypescript() { _resolversToTypescript = _asyncToGenerator(function* (params) { var { options = {} } = params; var { format = true } = options; var { code } = yield resolversTypescriptParts(params); return format ? // @ts-ignore circular CircularDeps.prettier.format(code, { parser: 'typescript', printWidth: 100 }) : code; }); return _resolversToTypescript.apply(this, arguments); } function convertResolver(_x3) { return _convertResolver.apply(this, arguments); } function _convertResolver() { _convertResolver = _asyncToGenerator(function* (options) { var { resolver, allResolvers } = options; var inputName = resolver.argsType.id; var payloadName = resolver.payloadType.id; var payloadOriginName = getInnerGraphTypeId(resolver.payloadType); var payloadDef = _objectSpread({}, cleanMetaField(resolver.typeDef)); allResolvers.filter(el => el.__isRelation).forEach(rel => { if (rel.__relatedToGraphTypeId === payloadOriginName) { var typeRelatedToFinalPayload = GraphType.register.get(rel.__graphTypeId); payloadDef.def[rel.name] = typeRelatedToFinalPayload.definition; } }); var [payload, args] = yield Promise.all([convertType({ entryName: payloadName, kind: 'output', type: payloadDef // TODO generate type for User[] not for plain object }), convertType({ entryName: inputName, kind: 'input', type: resolver.argsType.definition })]); var code = ''; code += "".concat(args.comments, "\nexport type ").concat(inputName, " = ").concat(args.code, ";"); code += "".concat(payload.comments, "\nexport type ").concat(payloadName, " = ").concat(payload.code, ";"); return { args, code, entryName: resolver.name, inputName, payload, payloadName, resolver }; }); return _convertResolver.apply(this, arguments); } function convertType(_x4) { return _convertType.apply(this, arguments); } function _convertType() { _convertType = _asyncToGenerator(function* (options) { var { entryName, type, kind } = options; var parsed = parseFieldDefinitionConfig(type, { deep: { omitMeta: true } }); var { description } = parsed; // @ts-ignore circular var result = yield CircularDeps.objectToTypescript(entryName, { CONVERT__REPLACE: _objectSpread({}, type) }, _objectSpread(_objectSpread({}, options), {}, { format: false, ignoreDefaultValues: kind !== 'input' })); var code = result.split('\n').slice(1, -2).join('\n').replace('CONVERT__REPLACE', ''); if (code.startsWith('?')) { code = "".concat(code, " | undefined"); } code = code.replace(/^\??: /, ""); var comments = description ? "\n/** ".concat(description, " **/\n") : ''; return { code, comments, description: description || '' }; }); return _convertType.apply(this, arguments); } function queryExamples(_ref) { var { schema, grouped, randomText, randomNumber, resolver: resolverName } = _ref; var templates = getSchemaQueryTemplates(schema); var examples = ''; Object.entries(grouped).forEach(_ref2 => { var [_kind, resolvers] = _ref2; var kind = _kind; if (!(resolvers !== null && resolvers !== void 0 && resolvers.length)) return; var resolversRecord = templates.queryByResolver[kind]; Object.entries(resolversRecord).forEach(_ref3 => { var _resolver$argsType$__; var [name, parsed] = _ref3; if (resolverName && resolverName !== name) return; var resolver = notNull(resolvers.find(el => el.name === name)); var argsDef = (_resolver$argsType$__ = resolver.argsType.__lazyGetter.objectType) === null || _resolver$argsType$__ === void 0 ? void 0 : _resolver$argsType$__.definition; var argsExamples = argsDef ? objectMock(argsDef, { randomNumber, randomText }) : ''; examples += "".concat(kind, " ").concat(name).concat(capitalize(kind), " { ").concat(name); if (parsed.argsParsed.vars.length) { examples += '('; var args = parsed.argsParsed.vars.map(val => { var example = argsExamples[val.name]; var ser = typeof example === 'string' ? "\"".concat(example, "\"") : example && typeof example === 'object' ? BJSON.stringify(example, { quoteKeys(str) { if (str.match(/[-.]/)) return "\"".concat(str, "\""); return str; } }) : example; return "".concat(val.name, ": ").concat(ser); }); examples += args.join(', '); examples += ')'; } if (parsed.query) { examples += " {".concat(parsed.query, "} "); } examples += '}\n'; }); }); return [formatGraphQL(examples), templates.fullQuery].join('\n'); } //# sourceMappingURL=createGraphQLSchema.js.map