UNPKG

context-tree

Version:

Simple hierarchical dependency injection library, as the part of Fractal Architecture

126 lines 4.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Context = exports.ContextResolvers = exports.ContextResolver = void 0; class ContextResolver { constructor(context, resolver) { this.context = context; this.resolver = resolver; } } exports.ContextResolver = ContextResolver; class ContextResolvers { constructor() { this.resolvers = new Map(); } addResolver(resolver) { const { context, resolver: _resolver } = resolver; this.resolvers.set(context, _resolver); } removeResolver(context) { this.resolvers.delete(context); } findResolver(_context) { let context = _context; while (context) { const resolver = this.resolvers.get(context); if (resolver) { return resolver; } context = context.parent; } return null; } } exports.ContextResolvers = ContextResolvers; const contextTypeResolversCache = new WeakMap(); class Context { constructor(name, parent = null) { this.parent = parent; this.name = name; } static resolvers(resolvers) { const contextResolvers = new ContextResolvers(); for (const resolver of resolvers) { contextResolvers.addResolver(resolver); } return contextResolvers; } static checkRequired(instance) { const constructor = instance.constructor; const requiredContexts = instance.requiredContexts ?? constructor?.requiredContexts; if (requiredContexts && Array.isArray(requiredContexts)) { const missingContexts = requiredContexts.filter((context) => !context.findResolver(instance)); if (missingContexts.length > 0) { const contextNames = missingContexts .map((context) => context.name) .join(", "); throw new Error(`Missing required contexts for instance of class '${constructor.name}': ${contextNames}`); } } } partial(name) { return new Context(name, this); } resolvesTo(resolver) { return new ContextResolver(this, resolver); } resolve(instance) { const resolver = this.findResolver(instance); if (resolver) { return resolver(); } else { throw new Error(`Cannot find resolver for context ${this.name}`); } } resolveMaybe(instance) { const resolver = this.findResolver(instance); if (resolver) { return resolver(); } else { return undefined; } } findResolver(startInstance) { const bfsQueue = new Set(); bfsQueue.add(startInstance); let resolver = null; for (const instance of bfsQueue) { const resolver = this.contextTypeResolver(instance) ?? instance.contextResolvers?.findResolver(this); if (resolver) { return resolver; } const { context } = instance; if (context) { if (Array.isArray(context)) { for (const parent of context) { bfsQueue.add(parent); } } else { bfsQueue.add(context); } } } return null; } contextTypeResolver(instance) { let context = this; while (context) { if (instance.contextType === context) { let instanceResolver = contextTypeResolversCache.get(instance); if (!instanceResolver) { instanceResolver = () => instance; contextTypeResolversCache.set(instance, instanceResolver); } return instanceResolver; } context = context.parent; } return null; } } exports.Context = Context; //# sourceMappingURL=index.js.map