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
JavaScript
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