##// END OF EJS Templates
tests
tests

File last commit:

r41:eae7e609c38a di-typescript
r41:eae7e609c38a di-typescript
Show More
ServiceDescriptor.ts
286 lines | 8.3 KiB | video/mp2t | TypeScriptLexer
/ src / ts / di / ServiceDescriptor.ts
cin
ported IoC container to typescript...
r34 import { ActivationContext } from "./ActivationContext";
cin
tests
r41 import { Descriptor, ActivationType, ServiceMap, isDescriptor } from "./interfaces";
cin
ported IoC container to typescript...
r34 import { Container } from "./Container";
cin
ts code cleanup, linting
r39 import { argumentNotNull, isPrimitive, oid, isPromise } from "../safe";
import { Constructor, Factory } from "../interfaces";
cin
tests
r41 import { TraceSource } from "../log/TraceSource";
cin
ported IoC container to typescript...
r34
let cacheId = 0;
cin
tests
r41 const trace = TraceSource.get("@implab/core/di/ActivationContext");
cin
ported IoC container to typescript...
r34 function injectMethod(target, method, context, args) {
cin
working on IoC container
r38 const m = target[method];
cin
ported IoC container to typescript...
r34 if (!m)
throw new Error("Method '" + method + "' not found");
if (args instanceof Array)
cin
ts code cleanup, linting
r39 return m.apply(target, context.parse(args, "." + method));
cin
ported IoC container to typescript...
r34 else
cin
ts code cleanup, linting
r39 return m.call(target, context.parse(args, "." + method));
cin
working on IoC container
r38 }
cin
ported IoC container to typescript...
r34
cin
ts code cleanup, linting
r39 function makeClenupCallback(target, method: ((instance) => void) | string) {
cin
ported IoC container to typescript...
r34 if (typeof (method) === "string") {
cin
working on IoC container
r38 return () => {
cin
ported IoC container to typescript...
r34 target[method]();
};
} else {
cin
working on IoC container
r38 return () => {
cin
ported IoC container to typescript...
r34 method(target);
};
}
cin
working on IoC container
r38 }
cin
ported IoC container to typescript...
r34
cin
tests
r41 // TODO: make async
function _parse(value, context: ActivationContext, path: string) {
if (isPrimitive(value))
return value;
if (isDescriptor(value))
return context.activate(value, path);
if (value instanceof Array)
return value.map((x, i) => this._parse(x, context, `${path}[${i}]`));
const t = {};
for (const p of Object.keys(value))
t[p] = this._parse(value[p], context, `${path}.${p}`);
return t;
}
cin
ts code cleanup, linting
r39 export interface ServiceDescriptorParams {
cin
working on IoC container
r38 activation?: ActivationType;
cin
ported IoC container to typescript...
r34
cin
working on IoC container
r38 owner: Container;
cin
ported IoC container to typescript...
r34
cin
ts code cleanup, linting
r39 type?: Constructor;
cin
ported IoC container to typescript...
r34
cin
ts code cleanup, linting
r39 factory?: Factory;
cin
ported IoC container to typescript...
r34
cin
working on IoC container
r38 params?;
cin
ported IoC container to typescript...
r34
cin
ts code cleanup, linting
r39 inject?: object[];
cin
ported IoC container to typescript...
r34
cin
working on IoC container
r38 services?: ServiceMap;
cin
ported IoC container to typescript...
r34
cin
ts code cleanup, linting
r39 cleanup?: ((x) => void) | string;
cin
ported IoC container to typescript...
r34 }
cin
ts code cleanup, linting
r39 export class ServiceDescriptor implements Descriptor {
_instance;
cin
ported IoC container to typescript...
r34
cin
working on IoC container
r38 _hasInstance = false;
cin
ported IoC container to typescript...
r34
cin
working on IoC container
r38 _activationType = ActivationType.Call;
cin
ported IoC container to typescript...
r34
cin
working on IoC container
r38 _services: ServiceMap;
cin
ported IoC container to typescript...
r34
cin
ts code cleanup, linting
r39 _type: Constructor = null;
cin
ported IoC container to typescript...
r34
cin
ts code cleanup, linting
r39 _factory: Factory = null;
cin
ported IoC container to typescript...
r34
cin
working on IoC container
r38 _params;
cin
ported IoC container to typescript...
r34
cin
ts code cleanup, linting
r39 _inject: object[];
cin
ported IoC container to typescript...
r34
cin
ts code cleanup, linting
r39 _cleanup: ((x) => void) | string;
cin
ported IoC container to typescript...
r34
cin
working on IoC container
r38 _cacheId: any;
cin
ported IoC container to typescript...
r34
cin
working on IoC container
r38 _owner: Container;
cin
ported IoC container to typescript...
r34
cin
ts code cleanup, linting
r39 constructor(opts: ServiceDescriptorParams) {
cin
ported IoC container to typescript...
r34 argumentNotNull(opts, "opts");
argumentNotNull(opts.owner, "owner");
this._owner = opts.owner;
if (!(opts.type || opts.factory))
throw new Error(
"Either a type or a factory must be specified");
if (opts.activation)
this._activationType = opts.activation;
if (opts.type)
this._type = opts.type;
if (opts.params)
this._params = opts.params;
if (opts.inject)
cin
ts code cleanup, linting
r39 this._inject = opts.inject;
cin
ported IoC container to typescript...
r34
if (opts.services)
this._services = opts.services;
if (opts.factory)
this._factory = opts.factory;
if (opts.cleanup) {
if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function))
throw new Error(
"The cleanup parameter must be either a function or a function name");
this._cleanup = opts.cleanup;
}
cin
working on IoC container
r38 if (this._activationType === ActivationType.Singleton) {
const tof = this._type || this._factory;
cin
ported IoC container to typescript...
r34
// create the persistent cache identifier for the type
if (isPrimitive(tof))
this._cacheId = tof;
else
this._cacheId = oid(tof);
} else {
this._cacheId = ++cacheId;
}
}
cin
tests
r41 activate(context: ActivationContext) {
cin
ported IoC container to typescript...
r34 // if we have a local service records, register them first
let instance;
switch (this._activationType) {
cin
working on IoC container
r38 case ActivationType.Singleton: // SINGLETON
cin
ported IoC container to typescript...
r34 // if the value is cached return it
if (this._hasInstance)
return this._instance;
// singletons are bound to the root container
cin
working on IoC container
r38 const container = context.container.getRootContainer();
cin
ported IoC container to typescript...
r34
if (container.has(this._cacheId)) {
instance = container.get(this._cacheId);
} else {
cin
tests
r41 instance = this._create(context);
cin
ported IoC container to typescript...
r34 container.store(this._cacheId, instance);
if (this._cleanup)
container.onDispose(
makeClenupCallback(instance, this._cleanup));
}
this._hasInstance = true;
return (this._instance = instance);
cin
working on IoC container
r38 case ActivationType.Container: // CONTAINER
// return a cached value
cin
ported IoC container to typescript...
r34 if (this._hasInstance)
return this._instance;
// create an instance
cin
tests
r41 instance = this._create(context);
cin
ported IoC container to typescript...
r34
// the instance is bound to the container
if (this._cleanup)
this._owner.onDispose(
makeClenupCallback(instance, this._cleanup));
// cache and return the instance
this._hasInstance = true;
return (this._instance = instance);
cin
working on IoC container
r38 case ActivationType.Context: // CONTEXT
// return a cached value if one exists
cin
ported IoC container to typescript...
r34 if (context.has(this._cacheId))
return context.get(this._cacheId);
cin
working on IoC container
r38 // context context activated instances are controlled by callers
cin
tests
r41 return context.store(this._cacheId, this._create(context));
cin
working on IoC container
r38 case ActivationType.Call: // CALL
cin
ported IoC container to typescript...
r34 // per-call created instances are controlled by callers
cin
tests
r41 return this._create(context);
cin
working on IoC container
r38 case ActivationType.Hierarchy: // HIERARCHY
cin
ported IoC container to typescript...
r34 // hierarchy activated instances are behave much like container activated
// except they are created and bound to the child container
// return a cached value
if (context.container.has(this._cacheId))
return context.container.get(this._cacheId);
cin
tests
r41 instance = this._create(context);
cin
ported IoC container to typescript...
r34
if (this._cleanup)
context.container.onDispose(makeClenupCallback(
instance,
this._cleanup));
return context.container.store(this._cacheId, instance);
default:
cin
working on IoC container
r38 throw new Error("Invalid activation type: " + this._activationType);
cin
ported IoC container to typescript...
r34 }
}
isInstanceCreated() {
return this._hasInstance;
}
getInstance() {
return this._instance;
}
cin
tests
r41 _create(context: ActivationContext) {
trace.debug(`constructing ${context._name}`);
cin
ported IoC container to typescript...
r34
cin
working on IoC container
r38 if (this._activationType !== ActivationType.Call &&
cin
ported IoC container to typescript...
r34 context.visit(this._cacheId) > 0)
throw new Error("Recursion detected");
if (this._services) {
cin
working on IoC container
r38 for (const p in this._services)
cin
ported IoC container to typescript...
r34 context.register(p, this._services[p]);
}
cin
working on IoC container
r38 let instance;
cin
ported IoC container to typescript...
r34
if (!this._factory) {
cin
working on IoC container
r38 const ctor = this._type;
cin
ts code cleanup, linting
r39 if (this._params && this._params.length) {
this._factory = (...args) => {
const t = Object.create(ctor.prototype);
const inst = ctor.apply(t, args);
return isPrimitive(inst) ? t : inst;
};
} else {
this._factory = () => {
return new ctor();
};
}
cin
ported IoC container to typescript...
r34 }
if (this._params === undefined) {
instance = this._factory();
} else if (this._params instanceof Array) {
cin
tests
r41 instance = this._factory.apply(this, _parse(this._params, context, "args"));
cin
ported IoC container to typescript...
r34 } else {
cin
tests
r41 instance = this._factory(_parse(this._params, context, "args"));
cin
ported IoC container to typescript...
r34 }
if (this._inject) {
cin
working on IoC container
r38 this._inject.forEach(spec => {
for (const m in spec)
cin
ported IoC container to typescript...
r34 injectMethod(instance, m, context, spec[m]);
});
}
return instance;
}
// @constructor {singleton} foo/bar/Baz
// @factory {singleton}
toString() {
cin
working on IoC container
r38 const parts = [];
cin
ported IoC container to typescript...
r34
parts.push(this._type ? "@constructor" : "@factory");
parts.push(ActivationType[this._activationType]);
if (typeof (this._type) === "string")
parts.push(this._type);
return parts.join(" ");
}
cin
working on IoC container
r38 }