UNPKG

graphql-modules

Version:

Create reusable, maintainable, testable and extendable GraphQL modules

150 lines (149 loc) 5.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createApplication = createApplication; const schema_1 = require("@graphql-tools/schema"); const di_1 = require("../di"); const errors_1 = require("../shared/errors"); const utils_1 = require("../shared/utils"); const di_2 = require("./di"); const context_1 = require("./context"); const execution_1 = require("./execution"); const subscription_1 = require("./subscription"); const apollo_1 = require("./apollo"); const operation_controller_1 = require("./operation-controller"); /** * @api * Creates Application out of Modules. Accepts `ApplicationConfig`. * * @example * * ```typescript * import { createApplication } from 'graphql-modules'; * import { usersModule } from './users'; * import { postsModule } from './posts'; * import { commentsModule } from './comments'; * * const app = createApplication({ * modules: [ * usersModule, * postsModule, * commentsModule * ] * }) * ``` */ function createApplication(applicationConfig) { function applicationFactory(cfg) { const config = cfg || applicationConfig; const providers = config.providers && typeof config.providers === 'function' ? config.providers() : config.providers; // Creates an Injector with singleton classes at application level const appSingletonProviders = di_1.ReflectiveInjector.resolve((0, di_1.onlySingletonProviders)(providers)); const appInjector = di_1.ReflectiveInjector.createFromResolved({ name: 'App (Singleton Scope)', providers: appSingletonProviders, }); // Filter Operation-scoped providers, and keep it here // so we don't do it over and over again const appOperationProviders = di_1.ReflectiveInjector.resolve((0, di_1.onlyOperationProviders)(providers)); const middlewareMap = config.middlewares || {}; // Validations ensureModuleUniqueIds(config.modules); // Create all modules const modules = config.modules.map((mod) => mod.factory({ injector: appInjector, middlewares: middlewareMap, })); const modulesMap = createModulesMap(modules); const singletonGlobalProvidersMap = (0, di_2.createGlobalProvidersMap)({ modules, scope: di_1.Scope.Singleton, }); const operationGlobalProvidersMap = (0, di_2.createGlobalProvidersMap)({ modules, scope: di_1.Scope.Operation, }); (0, di_2.attachGlobalProvidersMap)({ injector: appInjector, globalProvidersMap: singletonGlobalProvidersMap, moduleInjectorGetter(moduleId) { return modulesMap.get(moduleId).injector; }, }); // Creating a schema, flattening the typedefs and resolvers // is not expensive since it happens only once const typeDefs = (0, utils_1.flatten)(modules.map((mod) => mod.typeDefs)); const resolvers = modules.map((mod) => mod.resolvers).filter(utils_1.isDefined); const schema = (applicationConfig.schemaBuilder || schema_1.makeExecutableSchema)({ typeDefs, resolvers, }); const contextBuilder = (0, context_1.createContextBuilder)({ appInjector, appLevelOperationProviders: appOperationProviders, modulesMap: modulesMap, singletonGlobalProvidersMap, operationGlobalProvidersMap, }); const createOperationController = (0, operation_controller_1.operationControllerCreator)({ contextBuilder, }); const createSubscription = (0, subscription_1.subscriptionCreator)({ contextBuilder }); const createExecution = (0, execution_1.executionCreator)({ contextBuilder }); const createSchemaForApollo = (0, apollo_1.apolloSchemaCreator)({ createSubscription, contextBuilder, schema, }); const createApolloExecutor = (0, apollo_1.apolloExecutorCreator)({ createExecution, }); (0, di_2.instantiateSingletonProviders)({ appInjector, modulesMap, }); return { typeDefs, resolvers, schema, injector: appInjector, createOperationController, createSubscription, createExecution, createSchemaForApollo, createApolloExecutor, ɵfactory: applicationFactory, ɵconfig: config, }; } return applicationFactory(); } function createModulesMap(modules) { var _a; const modulesMap = new Map(); for (const module of modules) { if (modulesMap.has(module.id)) { const location = module.metadata.dirname; const existingLocation = (_a = modulesMap.get(module.id)) === null || _a === void 0 ? void 0 : _a.metadata.dirname; const info = []; if (existingLocation) { info.push(`Already registered module located at: ${existingLocation}`); } if (location) { info.push(`Duplicated module located at: ${location}`); } throw new errors_1.ModuleDuplicatedError(`Module "${module.id}" already exists`, ...info); } modulesMap.set(module.id, module); } return modulesMap; } function ensureModuleUniqueIds(modules) { const collisions = modules .filter((mod, i, all) => i !== all.findIndex((m) => m.id === mod.id)) .map((m) => m.id); if (collisions.length) { throw new errors_1.ModuleNonUniqueIdError(`Modules with non-unique ids: ${collisions.join(', ')}`, `All modules should have unique ids, please locate and fix them.`); } }