UNPKG

@pothos/core

Version:

Pothos (formerly GiraphQL) is a plugin based schema builder for creating code-first GraphQL schemas in typescript

519 lines (518 loc) 21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "BuildCache", { enumerable: true, get: function() { return BuildCache; } }); const _graphql = require("graphql"); const _errors = require("./errors"); const _plugins = require("./plugins"); const _builtinscalar = require("./refs/builtin-scalar"); const _types = require("./types"); const _utils = require("./utils"); function _define_property(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } class BuildCache { getTypeConfig(ref, kind) { const baseConfig = this.configStore.getTypeConfig(ref, kind); if (!this.typeConfigs.has(baseConfig.name)) { this.typeConfigs.set(baseConfig.name, this.plugin.onTypeConfig(baseConfig)); } const typeConfig = this.typeConfigs.get(baseConfig.name); return typeConfig; } getInputTypeFieldConfigs(ref) { const typeConfig = this.getTypeConfig(ref, 'InputObject'); const builtType = this.types.get(typeConfig.name); if (!builtType) { throw new _errors.PothosSchemaError(`Input type ${typeConfig.name} has not been built yet`); } const fields = builtType.getFields(); const fieldConfigs = {}; for (const fieldName of Object.keys(fields)){ var _fields_fieldName_extensions; fieldConfigs[fieldName] = (_fields_fieldName_extensions = fields[fieldName].extensions) === null || _fields_fieldName_extensions === void 0 ? void 0 : _fields_fieldName_extensions.pothosConfig; } return fieldConfigs; } getImplementers(iface) { if (this.implementers.has(iface.name)) { return this.implementers.get(iface.name); } const implementers = [ ...this.configStore.typeConfigs.values() ].filter((config)=>config.kind === 'Object' && config.interfaces.find((i)=>this.configStore.getTypeConfig(i).name === iface.name)); this.implementers.set(iface.name, implementers); return implementers; } buildAll() { this.configStore.prepareForBuild(); for (const config of this.configStore.typeConfigs.values()){ if (config.kind === 'Enum' || config.kind === 'Scalar') { this.buildTypeFromConfig(config); } } for (const config of this.configStore.typeConfigs.values()){ if (config.kind === 'InputObject') { this.buildTypeFromConfig(config); } } for (const type of this.types.values()){ if (type instanceof _graphql.GraphQLInputObjectType) { type.getFields(); } } for (const config of this.configStore.typeConfigs.values()){ if (config.kind === 'Interface') { this.buildTypeFromConfig(config); } } for (const config of this.configStore.typeConfigs.values()){ if (config.kind === 'Object') { this.buildTypeFromConfig(config); } } for (const config of this.configStore.typeConfigs.values()){ if (config.kind === 'Union') { this.buildTypeFromConfig(config); } } for (const config of this.configStore.typeConfigs.values()){ if (config.kind === 'Query' || config.kind === 'Mutation' || config.kind === 'Subscription') { this.buildTypeFromConfig(config); } } for (const type of this.types.values()){ if (type instanceof _graphql.GraphQLObjectType || type instanceof _graphql.GraphQLInterfaceType) { type.getFields(); } else if (type instanceof _graphql.GraphQLUnionType) { type.getTypes(); } } } buildTypeFromConfig(baseConfig) { const config = this.getTypeConfig(baseConfig.name); const { name } = config; this.typeConfigs.set(name, config); switch(config.kind){ case 'Enum': this.addType(name, this.buildEnum(config)); break; case 'InputObject': this.addType(name, this.buildInputObject(config)); break; case 'Interface': this.addType(name, this.buildInterface(config)); break; case 'Scalar': this.addType(name, this.buildScalar(config)); break; case 'Union': this.addType(name, this.buildUnion(config)); break; case 'Object': case 'Query': case 'Mutation': case 'Subscription': this.addType(name, this.buildObject(config)); break; default: (0, _utils.assertNever)(config); } } addType(ref, type) { if (this.types.has(ref)) { throw new _errors.PothosSchemaError(`reference or name has already been used to create another type (${type.name})`); } this.types.set(ref, type); } buildOutputTypeParam(type) { if (type.kind === 'List') { if (type.nullable) { return new _graphql.GraphQLList(this.buildOutputTypeParam(type.type)); } return new _graphql.GraphQLNonNull(new _graphql.GraphQLList(this.buildOutputTypeParam(type.type))); } if (type.nullable) { return this.getOutputType(type.ref); } return new _graphql.GraphQLNonNull(this.getOutputType(type.ref)); } buildInputTypeParam(type) { if (type.kind === 'List') { if (type.required) { return new _graphql.GraphQLNonNull(new _graphql.GraphQLList(this.buildInputTypeParam(type.type))); } return new _graphql.GraphQLList(this.buildInputTypeParam(type.type)); } if (type.required) { return new _graphql.GraphQLNonNull(this.getInputType(type.ref)); } return this.getInputType(type.ref); } buildFields(fields) { const built = {}; for (const [fieldName, originalConfig] of fields){ if (!this.outputFieldConfigs.has(originalConfig)) { this.outputFieldConfigs.set(originalConfig, this.plugin.onOutputFieldConfig(originalConfig)); } const updatedConfig = this.outputFieldConfigs.get(originalConfig); if (!updatedConfig) { continue; } const config = { ...updatedConfig }; const argMap = new Map(); for (const argName of Object.keys(config.args)){ argMap.set(argName, config.args[argName]); } const args = this.buildInputFields(argMap); const argConfigs = {}; for (const argName of Object.keys(config.args)){ argConfigs[argName] = this.inputFieldConfigs.get(config.args[argName]); } config.args = argConfigs; var _config_resolve; const resolve = this.plugin.wrapResolve((_config_resolve = config.resolve) !== null && _config_resolve !== void 0 ? _config_resolve : _graphql.defaultFieldResolver, config); const subscribe = this.plugin.wrapSubscribe(config.subscribe, config); var _config_resolve1; built[fieldName] = { ...config, type: this.buildOutputTypeParam(config.type), args, extensions: { ...config.extensions, pothosResolveWrapped: resolve !== ((_config_resolve1 = config.resolve) !== null && _config_resolve1 !== void 0 ? _config_resolve1 : _graphql.defaultFieldResolver), pothosSubscribeWrapped: subscribe !== config.subscribe, pothosOptions: config.pothosOptions, pothosConfig: config, pothosArgMappers: config.argMappers }, resolve: resolve === _graphql.defaultFieldResolver ? undefined : resolve, subscribe }; } return built; } buildInputFields(fields) { const built = {}; for (const [fieldName, originalConfig] of fields){ if (!this.inputFieldConfigs.has(originalConfig)) { this.inputFieldConfigs.set(originalConfig, this.plugin.onInputFieldConfig(originalConfig)); } const config = this.inputFieldConfigs.get(originalConfig); if (config) { built[fieldName] = { ...config, type: this.buildInputTypeParam(config.type), extensions: { ...config.extensions, pothosOptions: config.pothosOptions, pothosConfig: config } }; } } return built; } getInterfaceFields(type) { const interfaceFields = type.getInterfaces()// biome-ignore lint/performance/noAccumulatingSpread: this is fine .reduce((all, iface)=>Object.assign(all, this.getFields(iface)), {}); const configs = this.configStore.getFields(type.name, 'Interface'); const fields = this.buildFields(configs); return { ...interfaceFields, ...fields }; } getObjectFields(type) { const interfaceFields = type.getInterfaces()// biome-ignore lint/performance/noAccumulatingSpread: this is fine .reduce((all, iface)=>Object.assign(all, this.getFields(iface)), {}); const objectFields = this.buildFields(this.configStore.getFields(type.name, 'Object')); return { ...interfaceFields, ...objectFields }; } getRootFields(type) { return this.buildFields(this.configStore.getFields(type.name, 'Object')); } getFields(type) { if (type instanceof _graphql.GraphQLObjectType) { const config = this.configStore.getTypeConfig(type.name); if (config.kind === 'Query' || config.kind === 'Mutation' || config.kind === 'Subscription') { return this.getRootFields(type); } return this.getObjectFields(type); } if (type instanceof _graphql.GraphQLInterfaceType) { return this.getInterfaceFields(type); } throw new _errors.PothosSchemaError(`Type ${type.name} does not have fields to resolve`); } getInputFields(type) { return this.buildInputFields(this.configStore.getFields(type.name, 'InputObject')); } getType(ref) { if (ref instanceof _builtinscalar.BuiltinScalarRef) { return ref.type; } const typeConfig = this.configStore.getTypeConfig(ref); const type = this.types.get(typeConfig.name); if (!type) { this.buildTypeFromConfig(typeConfig); return this.types.get(typeConfig.name); } return type; } getOutputType(ref) { const type = this.getType(ref); if (type instanceof _graphql.GraphQLInputObjectType) { throw new _errors.PothosSchemaError(`Expected ${String(ref)} to be an output type but it was defined as an InputObject`); } return type; } getInputType(ref) { const type = this.getType(ref); if (!type) { throw new _errors.PothosSchemaError(`Missing implementation of for type ${String(ref)}`); } if (type instanceof _graphql.GraphQLObjectType) { throw new _errors.PothosSchemaError(`Expected ${type.name} to be an input type but it was defined as a GraphQLObjectType`); } if (type instanceof _graphql.GraphQLInterfaceType) { throw new _errors.PothosSchemaError(`Expected ${type.name} to be an input type but it was defined as a GraphQLInterfaceType`); } if (type instanceof _graphql.GraphQLUnionType) { throw new _errors.PothosSchemaError(`Expected ${String(ref)} to be an input type but it was defined as an GraphQLUnionType`); } return type; } getTypeOfKind(ref, kind) { const type = this.getType(ref); switch(kind){ case 'Object': case 'Query': case 'Mutation': case 'Subscription': if (type instanceof _graphql.GraphQLObjectType) { return type; } break; case 'Interface': if (type instanceof _graphql.GraphQLInterfaceType) { return type; } break; case 'Union': if (type instanceof _graphql.GraphQLUnionType) { return type; } break; case 'Enum': if (type instanceof _graphql.GraphQLEnumType) { return type; } break; case 'Scalar': if (type instanceof _graphql.GraphQLScalarType) { return type; } break; case 'InputObject': if (type instanceof _graphql.GraphQLScalarType) { return type; } break; default: break; } throw new _errors.PothosSchemaError(`Expected ${String(ref)} to be of type ${kind}`); } buildObject(config) { var _config_isTypeOf; const type = new _graphql.GraphQLObjectType({ ...config, extensions: { ...config.extensions, pothosOptions: config.pothosOptions, pothosConfig: config }, fields: ()=>this.getFields(type), isTypeOf: config.kind === 'Object' ? this.plugin.wrapIsTypeOf((_config_isTypeOf = config.isTypeOf) !== null && _config_isTypeOf !== void 0 ? _config_isTypeOf : undefined, config) : undefined, interfaces: config.kind === 'Object' ? ()=>config.interfaces.map((iface)=>this.getTypeOfKind(iface, 'Interface')) : undefined }); return type; } buildInterface(config) { const resolveType = (parent, context, info)=>{ const typeBrand = (0, _utils.getTypeBrand)(parent); if (typeBrand) { if (typeof typeBrand === 'string') { return typeBrand; } return this.getTypeConfig(typeBrand).name; } var _config_resolveType; const resolver = (_config_resolveType = config.resolveType) !== null && _config_resolveType !== void 0 ? _config_resolveType : _graphql.defaultTypeResolver; return resolver(parent, context, info, type); }; const type = new _graphql.GraphQLInterfaceType({ ...config, extensions: { ...config.extensions, pothosOptions: config.pothosOptions, pothosConfig: config }, interfaces: ()=>config.interfaces.map((iface)=>this.getTypeOfKind(iface, 'Interface')), fields: ()=>this.getFields(type), resolveType: this.plugin.wrapResolveType(resolveType, config) }); return type; } buildUnion(config) { const resolveType = (parent, context, info, type)=>{ if (typeof parent === 'object' && parent !== null && _types.typeBrandKey in parent) { const typeBrand = parent[_types.typeBrandKey]; if (typeof typeBrand === 'string') { return typeBrand; } return this.getTypeConfig(typeBrand).name; } if (!config.resolveType) { return (0, _graphql.defaultTypeResolver)(parent, context, info, type); } const resultOrPromise = config.resolveType(parent, context, info, type); const getResult = (result)=>{ if (typeof result === 'string' || !result) { return result; } if (result instanceof _graphql.GraphQLObjectType) { return result.name; } try { const typeConfig = this.configStore.getTypeConfig(result); return typeConfig.name; } catch { // ignore } return result; }; return (0, _utils.isThenable)(resultOrPromise) ? resultOrPromise.then(getResult) : getResult(resultOrPromise); }; return new _graphql.GraphQLUnionType({ ...config, extensions: { ...config.extensions, pothosOptions: config.pothosOptions, pothosConfig: config }, types: ()=>config.types.map((member)=>this.getTypeOfKind(member, 'Object')), resolveType: this.plugin.wrapResolveType(resolveType, config) }); } buildInputObject(config) { const type = new _graphql.GraphQLInputObjectType({ ...config, extensions: { ...config.extensions, pothosOptions: config.pothosOptions, pothosConfig: config }, fields: ()=>this.getInputFields(type) }); return type; } buildScalar(config) { if (config.name === 'ID') { return _graphql.GraphQLID; } if (config.name === 'Int') { return _graphql.GraphQLInt; } if (config.name === 'Float') { return _graphql.GraphQLFloat; } if (config.name === 'Boolean') { return _graphql.GraphQLBoolean; } if (config.name === 'String') { return _graphql.GraphQLString; } return new _graphql.GraphQLScalarType({ ...config, extensions: { ...config.extensions, pothosOptions: config.pothosOptions, pothosConfig: config } }); } buildEnum(config) { const values = {}; const configValues = typeof config.values === 'function' ? config.values() : config.values; for (const key of Object.keys(config.values)){ const original = configValues[key]; if (!this.enumValueConfigs.has(original)) { this.enumValueConfigs.set(original, this.plugin.onEnumValueConfig(original)); } const valueConfig = this.enumValueConfigs.get(original); if (valueConfig) { values[key] = this.enumValueConfigs.get(original); } } return new _graphql.GraphQLEnumType({ ...config, values, extensions: { ...config.extensions, pothosOptions: config.pothosOptions, pothosConfig: config } }); } constructor(builder, options){ _define_property(this, "types", new Map()); _define_property(this, "builder", void 0); _define_property(this, "plugin", void 0); _define_property(this, "options", void 0); _define_property(this, "configStore", void 0); _define_property(this, "pluginList", void 0); _define_property(this, "implementers", new Map()); _define_property(this, "typeConfigs", new Map()); _define_property(this, "enumValueConfigs", new Map()); _define_property(this, "outputFieldConfigs", new Map()); _define_property(this, "inputFieldConfigs", new Map()); this.builder = builder; this.configStore = builder.configStore; this.options = options; const plugins = {}; var _builder_options_plugins; this.pluginList = ((_builder_options_plugins = builder.options.plugins) !== null && _builder_options_plugins !== void 0 ? _builder_options_plugins : []).map((pluginName)=>{ const Plugin = this.builder.constructor.plugins[pluginName]; if (!Plugin) { throw new _errors.PothosError(`No plugin named ${pluginName} was registered`); } plugins[pluginName] = new Plugin(this, pluginName); return plugins[pluginName]; }); this.plugin = new _plugins.MergedPlugins(this, this.pluginList); } } //# sourceMappingURL=build-cache.js.map