UNPKG

contexify

Version:

A TypeScript library providing a powerful dependency injection container with context-based IoC capabilities, inspired by LoopBack's Context system.

158 lines 5.4 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); import { MetadataAccessor, MetadataInspector } from "metarize"; import createDebugger from "../utils/debug.js"; import { ContextTags } from "../utils/keys.js"; import { Binding, isDynamicValueProviderClass } from "./binding.js"; const debug = createDebugger("contexify:binding-inspector"); const BINDING_METADATA_KEY = MetadataAccessor.create("binding.metadata"); function isProviderClass(cls) { return typeof cls === "function" && typeof cls.prototype?.value === "function"; } __name(isProviderClass, "isProviderClass"); function asProvider(target) { return /* @__PURE__ */ __name(function bindAsProvider(binding) { binding.toProvider(target).tag(ContextTags.PROVIDER, { [ContextTags.TYPE]: ContextTags.PROVIDER }); }, "bindAsProvider"); } __name(asProvider, "asProvider"); function asClassOrProvider(target) { return /* @__PURE__ */ __name(function bindAsClassOrProvider(binding) { if (isProviderClass(target)) { asProvider(target)(binding); } else if (isDynamicValueProviderClass(target)) { binding.toDynamicValue(target).tag(ContextTags.DYNAMIC_VALUE_PROVIDER, { [ContextTags.TYPE]: ContextTags.DYNAMIC_VALUE_PROVIDER }); } else { binding.toClass(target); } }, "bindAsClassOrProvider"); } __name(asClassOrProvider, "asClassOrProvider"); function asBindingTemplate(scopeAndTags) { return /* @__PURE__ */ __name(function applyBindingScopeAndTag(binding) { if (scopeAndTags.scope) { binding.inScope(scopeAndTags.scope); } if (scopeAndTags.tags) { if (Array.isArray(scopeAndTags.tags)) { binding.tag(...scopeAndTags.tags); } else { binding.tag(scopeAndTags.tags); } } }, "applyBindingScopeAndTag"); } __name(asBindingTemplate, "asBindingTemplate"); function getBindingMetadata(target) { return MetadataInspector.getClassMetadata(BINDING_METADATA_KEY, target); } __name(getBindingMetadata, "getBindingMetadata"); function removeNameAndKeyTags(binding) { if (binding.tagMap) { delete binding.tagMap.name; delete binding.tagMap.key; } } __name(removeNameAndKeyTags, "removeNameAndKeyTags"); function bindingTemplateFor(cls, options) { const spec = getBindingMetadata(cls); debug("class %s has binding metadata", cls.name, spec); const templateFunctions = [ ...spec?.templates ?? [] ]; if (spec?.target !== cls) { templateFunctions.push(asClassOrProvider(cls)); } return /* @__PURE__ */ __name(function applyBindingTemplatesFromMetadata(binding) { for (const t of templateFunctions) { binding.apply(t); } if (spec?.target !== cls) { binding.apply(removeNameAndKeyTags); } if (options != null) { applyClassBindingOptions(binding, options); } }, "applyBindingTemplatesFromMetadata"); } __name(bindingTemplateFor, "bindingTemplateFor"); const DEFAULT_TYPE_NAMESPACES = { class: "classes", provider: "providers", dynamicValueProvider: "dynamicValueProviders" }; function createBindingFromClass(cls, options = {}) { debug("create binding from class %s with options", cls.name, options); try { const templateFn = bindingTemplateFor(cls, options); const key = buildBindingKey(cls, options); const binding = Binding.bind(key).apply(templateFn); return binding; } catch (err) { if (err instanceof Error) { err.message += ` (while building binding for class ${cls.name})`; } throw err; } } __name(createBindingFromClass, "createBindingFromClass"); function applyClassBindingOptions(binding, options) { if (options.name) { binding.tag({ name: options.name }); } if (options.type) { binding.tag({ type: options.type }, options.type); } if (options.defaultScope) { binding.applyDefaultScope(options.defaultScope); } } __name(applyClassBindingOptions, "applyClassBindingOptions"); function getNamespace(type, typeNamespaces = DEFAULT_TYPE_NAMESPACES) { if (type in typeNamespaces) { return typeNamespaces[type]; } return `${type}s`; } __name(getNamespace, "getNamespace"); function buildBindingKey(cls, options = {}) { if (options.key) return options.key; const templateFn = bindingTemplateFor(cls); const bindingTemplate = new Binding("template").apply(templateFn); let key = bindingTemplate.tagMap[ContextTags.KEY]; if (key) return key; let namespace = options.namespace ?? bindingTemplate.tagMap[ContextTags.NAMESPACE] ?? options.defaultNamespace; if (!namespace) { const namespaces = Object.assign({}, DEFAULT_TYPE_NAMESPACES, options.typeNamespaceMapping); let type = options.type ?? bindingTemplate.tagMap[ContextTags.TYPE]; if (!type) { type = bindingTemplate.tagNames.find((t) => namespaces[t] != null) ?? ContextTags.CLASS; } namespace = getNamespace(type, namespaces); } const name = options.name ?? (bindingTemplate.tagMap[ContextTags.NAME] || cls.name); key = `${namespace}.${name}`; return key; } __name(buildBindingKey, "buildBindingKey"); export { BINDING_METADATA_KEY, DEFAULT_TYPE_NAMESPACES, asBindingTemplate, asClassOrProvider, asProvider, bindingTemplateFor, createBindingFromClass, getBindingMetadata, isProviderClass, removeNameAndKeyTags }; //# sourceMappingURL=binding-inspector.js.map