Skip to content

Instantly share code, notes, and snippets.

@matjaz
Last active June 24, 2016 21:38
Show Gist options
  • Save matjaz/62e5e6b7073ee09b56016eaadaefa3de to your computer and use it in GitHub Desktop.
Save matjaz/62e5e6b7073ee09b56016eaadaefa3de to your computer and use it in GitHub Desktop.
import {autoinject, inject} from './decorators'
class Greeter {
welcome(name): string {
return `Welcome ${name}!`;
}
}
@autoinject // used for constructor DI
export class App {
@autoinject greeter: Greeter; // magic
@inject(Greeter) // used for non-typed languages
greeter2: Greeter;
constructor (private g: Greeter) {
console.log(this.g)
console.log(this.g === this.greeter) // true
console.log(this.g === this.greeter2) // true
// return this
// constructor returns new object:
// return {
// greeatAll() {
// console.log(this.greeter.welcome('my master'))
// }
// }
}
greetAll() {
this.message = this.greeter.welcome('everybody');
}
message: string = 'Welcome!';
}
import {metadata} from 'aurelia-metadata';
import {PropertyInjectorInvoker} from './invoker';
import {inject} from 'aurelia-property-injection-heruan'; // heruan implementation
export function autoinject (potentialTarget?: any, potentialKey?: any): any {
const deco = function (target, key, descriptor?) {
if (!key) {
target.inject = metadata.getOwn(metadata.paramTypes, target, key) || Object.freeze([]);
} else if (!descriptor) {
let targetConstructor = target.constructor;
if (!targetConstructor.injectProperties) {
targetConstructor.injectProperties = Object.create(null);
// set invoker for constructor function
metadata.define(metadata.invoker, PropertyInjectorInvoker.instance, targetConstructor);
}
targetConstructor.injectProperties[key] = metadata.getOwn('design:type', target, key);
}
};
return potentialTarget ? deco(potentialTarget, potentialKey) : deco;
}
export {inject} from 'aurelia-property-injection-heruan';
import {Invoker} from 'aurelia-dependency-injection';
let singleton;
export class PropertyInjectorInvoker implements Invoker {
static get instance () {
return singleton || (singleton = new PropertyInjectorInvoker);
}
}
PropertyInjectorInvoker.prototype.invoke = invoke;
PropertyInjectorInvoker.prototype.invokeWithDynamicDependencies = invoke;
function invoke (container, fn, staticDependencies, dynamicDependencies) {
var injectProps;
const injectProperties = fn.injectProperties;
if (injectProperties) {
injectProps = Object.create(null);
for (let property in injectProperties) {
injectProps[property] = {
value: container.get(injectProperties[property])
};
}
}
// inject properties as soon as object is created, before calling constructor
let instance = Object.create(fn.prototype || null, injectProps);
let i = staticDependencies.length;
let args = new Array(i);
while (i--) {
args[i] = container.get(staticDependencies[i]);
}
if (dynamicDependencies) {
args = args.concat(dynamicDependencies);
}
var ctReturn = fn.apply(instance, args);
if (ctReturn && ctReturn !== instance && typeof ctReturn === 'object') {
// if constructor returns object inject properties to new object
instance = ctReturn;
if (injectProperties) {
for (let property in injectProperties) {
Object.defineProperty(instance, property, {
value: container.get(injectProperties[property])
});
}
}
}
return instance;
}
@matjaz
Copy link
Author

matjaz commented Jun 24, 2016

Not really. Object.create creates new object with prototype of fn and then we apply fn as constructor function. (same as new)
In JavaScript constructor can return different object, hence the second injectProps() (not used/commented out in this gist). But it looks this doesn't work well with Aurelia.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment