@backland/schema
Version:
TypeScript schema declaration and validation library with static type inference
323 lines (321 loc) • 12.8 kB
JavaScript
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