vue-di-container
Version:
Dependency injection container for Vue
60 lines (59 loc) • 2.02 kB
JavaScript
import { Inject, Service } from './decorators';
/* A hack to retain metadata from original class when using @Component decorator. */
function setupVueClassComponentCompat() {
Inject.hooks.push((cls) => {
let decorators = cls.__decorators__;
if (decorators === undefined) {
decorators = cls.__decorators__ = [];
}
decorators.push(options => options[ORIGINAL_CLASS] = cls);
});
Service.hooks.push((cls) => {
delete cls.__decorators__;
});
}
const ORIGINAL_CLASS = '_diContainer_originalClass';
setupVueClassComponentCompat();
export class VueDiContainerConstructor {
constructor(containerFactory, metadata) {
this.containerFactory = containerFactory;
this.metadata = metadata;
}
setupComponent(component) {
const { $parent, $options } = component;
let container = $options.diContainer;
if (container === undefined) {
container = this.containerFactory($parent && $parent.$diContainer);
}
for (const provider of $options.diProvide || []) {
container.register(provider);
}
component.$diContainer = container;
}
getInjections(options, container) {
if (!container) {
return {};
}
const data = {};
const originalClass = options[ORIGINAL_CLASS];
let propertyKeys = options.diInject || {};
if (typeof originalClass === 'function') {
propertyKeys = this.metadata.getPropertyKeys(originalClass, propertyKeys);
}
for (const name of Object.keys(propertyKeys)) {
data[name] = container.get(propertyKeys[name]);
}
return data;
}
install(Vue, options) {
const plugin = this;
Vue.mixin({
beforeCreate() {
plugin.setupComponent(this);
},
data() {
return plugin.getInjections(this.$options, this.$diContainer);
},
});
}
}