##// END OF EJS Templates
working on IoC configuration
cin -
r114:475b8ce3e850 ioc ts support
parent child
Show More
@@ -2,37 +2,38 import { TraceSource } from "../log/Trac
2 import { argumentNotNull, argumentNotEmptyString, isPrimitive, each, isNull } from "../safe";
2 import { argumentNotNull, argumentNotEmptyString, isPrimitive, each, isNull } from "../safe";
3 import { Descriptor, ServiceMap } from "./interfaces";
3 import { Descriptor, ServiceMap } from "./interfaces";
4 import { Container } from "./Container";
4 import { Container } from "./Container";
5 import { MapOf } from "../interfaces";
5
6
6 const trace = TraceSource.get("@implab/core/di/ActivationContext");
7 const trace = TraceSource.get("@implab/core/di/ActivationContext");
7
8
8 export interface ActivationContextInfo {
9 export interface ActivationContextInfo<S> {
9 name: string;
10 name: string;
10
11
11 service: string;
12 service: string;
12
13
13 scope: ServiceMap;
14 scope: ServiceMap<S>;
14 }
15 }
15
16
16 export class ActivationContext {
17 export class ActivationContext<S> {
17 _cache: object;
18 _cache: MapOf<any>;
18
19
19 _services: ServiceMap;
20 _services: ServiceMap<S>;
20
21
21 _stack: ActivationContextInfo[];
22 _stack: ActivationContextInfo<S>[];
22
23
23 _visited: object;
24 _visited: MapOf<any>;
24
25
25 _name: string;
26 _name: string;
26
27
27 _localized: boolean;
28 _localized: boolean = false;
28
29
29 container: Container;
30 container: Container<S>;
30
31
31 constructor(container: Container, services: ServiceMap, name?: string, cache?: object, visited?) {
32 constructor(container: Container<S>, services: ServiceMap<S>, name?: string, cache?: object, visited?: MapOf<any>) {
32 argumentNotNull(container, "container");
33 argumentNotNull(container, "container");
33 argumentNotNull(services, "services");
34 argumentNotNull(services, "services");
34
35
35 this._name = name;
36 this._name = name || "<unnamed>";
36 this._visited = visited || {};
37 this._visited = visited || {};
37 this._stack = [];
38 this._stack = [];
38 this._cache = cache || {};
39 this._cache = cache || {};
@@ -44,16 +45,17 export class ActivationContext {
44 return this._name;
45 return this._name;
45 }
46 }
46
47
47 resolve(name, def?): any {
48 resolve<K extends keyof S, T extends S[K]>(name: K, def?: T) {
48 const d = this._services[name];
49 const d = this._services[name];
49
50
50 if (!d)
51 if (d !== undefined) {
51 if (arguments.length > 1)
52 return this.activate(d as Descriptor<T>, name.toString());
53 } else {
54 if (def !== undefined && def !== null)
52 return def;
55 return def;
53 else
56 else
54 throw new Error(`Service ${name} not found`);
57 throw new Error(`Service ${name} not found`);
55
58 }
56 return this.activate(d, name);
57 }
59 }
58
60
59 /**
61 /**
@@ -62,7 +64,7 export class ActivationContext {
62 * @name{string} the name of the service
64 * @name{string} the name of the service
63 * @service{string} the service descriptor to register
65 * @service{string} the service descriptor to register
64 */
66 */
65 register(name: string, service: Descriptor) {
67 register<K extends keyof S>(name: K, service: Descriptor<S[K]>) {
66 argumentNotEmptyString(name, "name");
68 argumentNotEmptyString(name, "name");
67
69
68 this._services[name] = service;
70 this._services[name] = service;
@@ -82,20 +84,20 export class ActivationContext {
82 return id in this._cache;
84 return id in this._cache;
83 }
85 }
84
86
85 get(id: string) {
87 get<T>(id: string) {
86 return this._cache[id];
88 return this._cache[id];
87 }
89 }
88
90
89 store(id: string, value) {
91 store(id: string, value: any) {
90 return (this._cache[id] = value);
92 return (this._cache[id] = value);
91 }
93 }
92
94
93 activate(d: Descriptor, name: string) {
95 activate<T>(d: Descriptor<T>, name: string) {
94 if (trace.isLogEnabled())
96 if (trace.isLogEnabled())
95 trace.log(`enter ${name} ${d}`);
97 trace.log(`enter ${name} ${d}`);
96
98
97 this.enter(name, d.toString());
99 this.enter(name, d.toString());
98 const v = d.activate(this);
100 const v = d.activate<S>(this);
99 this.leave();
101 this.leave();
100
102
101 if (trace.isLogEnabled())
103 if (trace.isLogEnabled())
@@ -126,7 +128,11 export class ActivationContext {
126
128
127 private leave() {
129 private leave() {
128 const ctx = this._stack.pop();
130 const ctx = this._stack.pop();
129 this._services = ctx.scope;
131 if (ctx) {
130 this._name = ctx.name;
132 this._services = ctx.scope;
133 this._name = ctx.name;
134 } else {
135 trace.error("Trying to leave the last activation scope");
136 }
131 }
137 }
132 }
138 }
@@ -1,7 +1,10
1 import { ActivationContextInfo } from "./ActivationContext";
1 export interface ActivationItem {
2 name: string;
3 service: string;
4 }
2
5
3 export class ActivationError {
6 export class ActivationError {
4 activationStack: ActivationContextInfo[];
7 activationStack: ActivationItem[];
5
8
6 service: string;
9 service: string;
7
10
@@ -9,7 +12,7 export class ActivationError {
9
12
10 message: string;
13 message: string;
11
14
12 constructor(service: string, activationStack: ActivationContextInfo[], innerException: any) {
15 constructor(service: string, activationStack: ActivationItem[], innerException: any) {
13 this.message = "Failed to activate the service";
16 this.message = "Failed to activate the service";
14 this.activationStack = activationStack;
17 this.activationStack = activationStack;
15 this.service = service;
18 this.service = service;
@@ -2,33 +2,35 import { Descriptor, isDescriptor } from
2 import { ActivationContext } from "./ActivationContext";
2 import { ActivationContext } from "./ActivationContext";
3 import { isPrimitive } from "../safe";
3 import { isPrimitive } from "../safe";
4
4
5 export class AggregateDescriptor<T> implements Descriptor<T> {
5 type Parse<T> = T extends Descriptor<infer V> ? V :
6 T extends {} ? { [K in keyof T]: Parse<T[K]> } :
7 T;
8
9 export class AggregateDescriptor<T> implements Descriptor<Parse<T>> {
6 _value: T;
10 _value: T;
7
11
8 constructor(value: T) {
12 constructor(value: T) {
9 this._value = value;
13 this._value = value;
10 }
14 }
11
15
12 activate(context: ActivationContext) {
16 activate<S>(context: ActivationContext<S>) {
13 return this._parse(this._value, context, "$value");
17 return this._parse(this._value, context, "$value");
14 }
18 }
15
19
16 // TODO: make async
20 _parse<S, V>(value: V, context: ActivationContext<S>, path: string): Parse<V> {
17 _parse(value: T, context: ActivationContext, path: string) {
18 if (isPrimitive(value))
21 if (isPrimitive(value))
19 return value;
22 return value as any;
20
23
21 if (isDescriptor(value))
24 if (isDescriptor(value))
22 return context.activate(value, path);
25 return context.activate(value, path);
23
26
24 if (value instanceof Array)
27 if (value instanceof Array)
25 return value.map((x, i) => this._parse(x, context, `${path}[${i}]`));
28 return value.map((x, i) => this._parse(x, context, `${path}[${i}]`)) as any;
26
29
27 const t = {};
30 const t: any = {};
28 for (const p of Object.keys(value))
31 for (const p in value)
29 t[p] = this._parse(value[p], context, `${path}.${p}`);
32 t[p] = this._parse(value[p], context, `${path}.${p}`);
30 return t;
33 return t;
31
32 }
34 }
33
35
34 toString() {
36 toString() {
@@ -4,22 +4,40 export interface InjectOptions {
4 lazy?: boolean;
4 lazy?: boolean;
5 }
5 }
6
6
7 interface Dependency<K extends keyof any> {
8 $dependency: K;
9
10 lazy?: boolean;
11 }
12
13 interface Lazy<K extends keyof any> extends Dependency<K> {
14 lazy: true;
15 }
16
7 type Setter<T = any> = (v: T) => void;
17 type Setter<T = any> = (v: T) => void;
8
18
9 type Compatible<T1, T2> = T1 extends T2 ? any : never;
19 type Compatible<T1, T2> = T1 extends T2 ? any : never;
10
20
11 type SetterType<T> = T extends (v: infer V) => void ? V : never;
12
13 type ExtractService<K, S> = K extends keyof S ? S[K] : K;
21 type ExtractService<K, S> = K extends keyof S ? S[K] : K;
14
22
15 type ExtractDependency<D, S> = D extends { $dependency: infer K } ? D extends { lazy: true } ? () => ExtractService<K, S> : ExtractService<K, S> : VisitDependency<D, S>;
23 type ExtractDependency<D, S> = D extends { $dependency: infer K } ? D extends { lazy: true } ? () => ExtractService<K, S> : ExtractService<K, S> : VisitDependency<D, S>;
16
24
17 type VisitDependency<D, S> = D extends {} ? { [K in keyof D]: ExtractDependency<D[K], S> } : D;
25 type VisitDependency<D, S> = D extends {} ? { [K in keyof D]: ExtractDependency<D[K], S> } : D;
18
26
27 interface Config<S> {
28 dependency<K extends keyof S>(name: K): Dependency<K>;
29
30 lazy<K extends keyof S>(name: K): Lazy<K>;
31
32 build<T>(): Builder<T, S>;
33 }
34
35 export declare function services<S extends object>(): Config<S>;
36
19 export class Builder<T, S> {
37 export class Builder<T, S> {
20 consume<P extends any[]>(...args: P) {
38 consume<P extends any[]>(...args: P) {
21 return <C extends new (...args: ExtractDependency<P, S>) => T>(constructor: C) => {
39 return <C extends new (...args: ExtractDependency<P, S>) => T>(constructor: C) => {
22 return constructor as typeof constructor & { service: () => T };
40 return constructor;
23 };
41 };
24 }
42 }
25
43
@@ -39,3 +57,5 export class Builder<T, S> {
39 }
57 }
40
58
41 }
59 }
60
61
@@ -1,11 +1,11
1 export class ConfigError extends Error {
1 export class ConfigError extends Error {
2 inner: any;
2 inner?: {};
3
3
4 path: string;
4 path?: string;
5
5
6 configName: string;
6 configName?: string;
7
7
8 constructor(message: string, inner?: any) {
8 constructor(message: string, inner?: {}) {
9 super(message);
9 super(message);
10 this.inner = inner;
10 this.inner = inner;
11 }
11 }
@@ -28,7 +28,7 import { ICancellation } from "../interf
28
28
29 const trace = TraceSource.get("@implab/core/di/Configuration");
29 const trace = TraceSource.get("@implab/core/di/Configuration");
30
30
31 async function mapAll(data: any | any[], map?: (v: any, k: keyof any) => any): Promise<any> {
31 async function mapAll(data: any | any[], map?: (v: any, k: number | string) => any): Promise<any> {
32 if (data instanceof Array) {
32 if (data instanceof Array) {
33 return Promise.all(map ? data.map(map) : data);
33 return Promise.all(map ? data.map(map) : data);
34 } else {
34 } else {
@@ -47,21 +47,19 async function mapAll(data: any | any[],
47
47
48 export type ModuleResolver = (moduleName: string, ct?: ICancellation) => any;
48 export type ModuleResolver = (moduleName: string, ct?: ICancellation) => any;
49
49
50 type _key = string | number;
50 export class Configuration<S> {
51
52 export class Configuration {
53
51
54 _hasInnerDescriptors = false;
52 _hasInnerDescriptors = false;
55
53
56 _container: Container;
54 _container: Container<S>;
57
55
58 _path: Array<_key>;
56 _path: Array<string>;
59
57
60 _configName: string | undefined;
58 _configName: string | undefined;
61
59
62 _require: ModuleResolver | undefined;
60 _require: ModuleResolver | undefined;
63
61
64 constructor(container: Container) {
62 constructor(container: Container<S>) {
65 argumentNotNull(container, "container");
63 argumentNotNull(container, "container");
66 this._container = container;
64 this._container = container;
67 this._path = [];
65 this._path = [];
@@ -150,7 +148,7 export class Configuration {
150 return this._require(moduleName);
148 return this._require(moduleName);
151 }
149 }
152
150
153 async _visitRegistrations(data: any, name: _key) {
151 async _visitRegistrations(data: any, name: string) {
154 this._enter(name);
152 this._enter(name);
155
153
156 if (data.constructor &&
154 if (data.constructor &&
@@ -161,7 +159,7 export class Configuration {
161 const keys = Object.keys(data);
159 const keys = Object.keys(data);
162
160
163 const services = await mapAll(data, async (v, k) => {
161 const services = await mapAll(data, async (v, k) => {
164 const d = await this._visit(v, k);
162 const d = await this._visit(v, k.toString());
165 return isDescriptor(d) ? d : new AggregateDescriptor(d);
163 return isDescriptor(d) ? d : new AggregateDescriptor(d);
166 }) as ServiceMap;
164 }) as ServiceMap;
167
165
@@ -180,11 +178,11 export class Configuration {
180 trace.debug("<{0}", name);
178 trace.debug("<{0}", name);
181 }
179 }
182
180
183 async _visit<T extends object>(data: T, name: keyof T) {
181 async _visit<T>(data: T, name: string) {
184 if (isPrimitive(data) || isDescriptor(data))
182 if (isPrimitive(data) || isDescriptor(data))
185 return data;
183 return data;
186
184
187 if (isDependencyRegistration(data)) {
185 if (isDependencyRegistration<S>(data)) {
188 return this._visitDependencyRegistration(data, name);
186 return this._visitDependencyRegistration(data, name);
189 } else if (isValueRegistration(data)) {
187 } else if (isValueRegistration(data)) {
190 return this._visitValueRegistration(data, name);
188 return this._visitValueRegistration(data, name);
@@ -196,10 +194,10 export class Configuration {
196 return this._visitArray(data, name);
194 return this._visitArray(data, name);
197 }
195 }
198
196
199 return this._visitObject(data, name);
197 return this._visitObject(data as T & object, name);
200 }
198 }
201
199
202 async _visitObject(data: object, name: _key) {
200 async _visitObject<T extends object>(data: T, name: string) {
203 if (data.constructor &&
201 if (data.constructor &&
204 data.constructor.prototype !== Object.prototype)
202 data.constructor.prototype !== Object.prototype)
205 return new ValueDescriptor(data);
203 return new ValueDescriptor(data);
@@ -222,7 +220,7 export class Configuration {
222 return v;
220 return v;
223 }
221 }
224
222
225 async _visitArray(data: any[], name: _key) {
223 async _visitArray(data: any[], name: string) {
226 if (data.constructor &&
224 if (data.constructor &&
227 data.constructor.prototype !== Array.prototype)
225 data.constructor.prototype !== Array.prototype)
228 return new ValueDescriptor(data);
226 return new ValueDescriptor(data);
@@ -235,7 +233,7 export class Configuration {
235 return v;
233 return v;
236 }
234 }
237
235
238 _makeServiceParams<T, P, S>(data: ServiceRegistration<T, P, S>) {
236 _makeServiceParams<T, P>(data: ServiceRegistration<T, P, S>) {
239 const opts: any = {
237 const opts: any = {
240 owner: this._container
238 owner: this._container
241 };
239 };
@@ -291,14 +289,14 export class Configuration {
291 return opts;
289 return opts;
292 }
290 }
293
291
294 async _visitValueRegistration<T>(data: ValueRegistration<T>, name: _key) {
292 async _visitValueRegistration<T>(data: ValueRegistration<T>, name: string) {
295 this._enter(name);
293 this._enter(name);
296 const d = data.parse ? new AggregateDescriptor(data.$value) : new ValueDescriptor(data.$value);
294 const d = data.parse ? new AggregateDescriptor(data.$value) : new ValueDescriptor(data.$value);
297 this._leave();
295 this._leave();
298 return d;
296 return d;
299 }
297 }
300
298
301 async _visitDependencyRegistration<S, K extends keyof S>(data: DependencyRegistration<S, K>, name: keyof S) {
299 async _visitDependencyRegistration<K extends keyof S>(data: DependencyRegistration<S, K>, name: string) {
302 argumentNotEmptyString(data && data.$dependency, "data.$dependency");
300 argumentNotEmptyString(data && data.$dependency, "data.$dependency");
303 this._enter(name);
301 this._enter(name);
304 const d = new ReferenceDescriptor<S, K>({
302 const d = new ReferenceDescriptor<S, K>({
@@ -312,7 +310,7 export class Configuration {
312 return d;
310 return d;
313 }
311 }
314
312
315 async _visitTypeRegistration<T, P, S>(data: TypeRegistration<T, P, S>, name: _key) {
313 async _visitTypeRegistration<T, P>(data: TypeRegistration<T, P, S>, name: string) {
316 argumentNotNull(data.$type, "data.$type");
314 argumentNotNull(data.$type, "data.$type");
317 this._enter(name);
315 this._enter(name);
318
316
@@ -333,7 +331,7 export class Configuration {
333 return d;
331 return d;
334 }
332 }
335
333
336 async _visitFactoryRegistration<T, P, S>(data: FactoryRegistration<T, P, S>, name: _key) {
334 async _visitFactoryRegistration<T, P>(data: FactoryRegistration<T, P, S>, name: string) {
337 argumentOfType(data.$factory, Function, "data.$factory");
335 argumentOfType(data.$factory, Function, "data.$factory");
338 this._enter(name);
336 this._enter(name);
339
337
@@ -1,31 +1,35
1 import { ActivationContext } from "./ActivationContext";
1 import { ActivationContext } from "./ActivationContext";
2 import { ValueDescriptor } from "./ValueDescriptor";
2 import { ValueDescriptor } from "./ValueDescriptor";
3 import { ActivationError } from "./ActivationError";
3 import { ActivationError } from "./ActivationError";
4 import { isDescriptor, ServiceMap } from "./interfaces";
4 import { isDescriptor, ServiceMap, Descriptor } from "./interfaces";
5 import { TraceSource } from "../log/TraceSource";
5 import { TraceSource } from "../log/TraceSource";
6 import { Configuration } from "./Configuration";
6 import { Configuration } from "./Configuration";
7 import { Cancellation } from "../Cancellation";
7 import { Cancellation } from "../Cancellation";
8 import { MapOf } from "../interfaces";
8
9
9 const trace = TraceSource.get("@implab/core/di/ActivationContext");
10 const trace = TraceSource.get("@implab/core/di/ActivationContext");
10
11
11 export class Container {
12 export class Container<S extends { container?: Container<S> }> {
12 _services: ServiceMap;
13 readonly _services: ServiceMap<S>;
13
14
14 _cache: object;
15 readonly _cache: MapOf<any>;
16
17 readonly _cleanup: (() => void)[];
15
18
16 _cleanup: (() => void)[];
19 readonly _root: Container<S>;
17
20
18 _root: Container;
21 readonly _parent?: Container<S>;
19
22
20 _parent: Container;
23 _disposed: boolean;
21
24
22 constructor(parent?: Container) {
25 constructor(parent?: Container<S>) {
23 this._parent = parent;
26 this._parent = parent;
24 this._services = parent ? Object.create(parent._services) : {};
27 this._services = parent ? Object.create(parent._services) : {};
25 this._cache = {};
28 this._cache = {};
26 this._cleanup = [];
29 this._cleanup = [];
27 this._root = parent ? parent.getRootContainer() : this;
30 this._root = parent ? parent.getRootContainer() : this;
28 this._services.container = new ValueDescriptor(this);
31 this._services.container = new ValueDescriptor(this);
32 this._disposed = false;
29 }
33 }
30
34
31 getRootContainer() {
35 getRootContainer() {
@@ -36,57 +40,63 export class Container {
36 return this._parent;
40 return this._parent;
37 }
41 }
38
42
39 resolve(name: string, def?) {
43 resolve<K extends keyof S, T extends S[K] = S[K]>(name: K, def?: T) {
40 trace.debug("resolve {0}", name);
44 trace.debug("resolve {0}", name);
41 const d = this._services[name];
45 const d = this._services[name];
42 if (d === undefined) {
46 if (d === undefined) {
43 if (arguments.length > 1)
47 if (def !== undefined)
44 return def;
48 return def;
45 else
49 else
46 throw new Error("Service '" + name + "' isn't found");
50 throw new Error("Service '" + name + "' isn't found");
47 }
51 } else {
48
52
49 const context = new ActivationContext(this, this._services);
53 const context = new ActivationContext<S>(this, this._services);
50 try {
54 try {
51 return context.activate(d, name);
55 return context.activate(d as Descriptor<T>, name.toString());
52 } catch (error) {
56 } catch (error) {
53 throw new ActivationError(name, context.getStack(), error);
57 throw new ActivationError(name.toString(), context.getStack(), error);
58 }
54 }
59 }
55 }
60 }
56
61
57 /**
62 /**
58 * @deprecated use resolve() method
63 * @deprecated use resolve() method
59 */
64 */
60 getService() {
65 getService<K extends keyof S>(name: K, def?: S[K]) {
61 return this.resolve.apply(this, arguments);
66 return this.resolve(name, def);
62 }
67 }
63
68
64 register(nameOrCollection, service?) {
69 register<K extends keyof S>(name: K, service: Descriptor<S[K]>): this;
70 register(services: ServiceMap<S>): this;
71 register<K extends keyof S>(nameOrCollection: K | ServiceMap<S>, service?: Descriptor<S[K]>) {
65 if (arguments.length === 1) {
72 if (arguments.length === 1) {
66 const data = nameOrCollection;
73 const data = nameOrCollection as ServiceMap<S>;
67 for (const name in data)
74 for (const name in data) {
68 this.register(name, data[name]);
75 if (Object.prototype.hasOwnProperty.call(data, name)) {
76 this.register(name, data[name] as Descriptor<S[keyof S]>);
77 }
78 }
69 } else {
79 } else {
70 if (!isDescriptor(service))
80 if (!isDescriptor(service))
71 throw new Error("The service parameter must be a descriptor");
81 throw new Error("The service parameter must be a descriptor");
72
82
73 this._services[nameOrCollection] = service;
83 this._services[nameOrCollection as K] = service;
74 }
84 }
75 return this;
85 return this;
76 }
86 }
77
87
78 onDispose(callback) {
88 onDispose(callback: () => void) {
79 if (!(callback instanceof Function))
89 if (!(callback instanceof Function))
80 throw new Error("The callback must be a function");
90 throw new Error("The callback must be a function");
81 this._cleanup.push(callback);
91 this._cleanup.push(callback);
82 }
92 }
83
93
84 dispose() {
94 dispose() {
85 if (this._cleanup) {
95 if (this._disposed)
86 for (const f of this._cleanup)
96 return;
87 f();
97 this._disposed = true;
88 this._cleanup = null;
98 for (const f of this._cleanup)
89 }
99 f();
90 }
100 }
91
101
92 /**
102 /**
@@ -109,8 +119,8 export class Container {
109 }
119 }
110 }
120 }
111
121
112 createChildContainer() {
122 createChildContainer<S2 extends { container?: Container<S & S2> } = S>(): Container<S & S2> {
113 return new Container(this);
123 return new Container<S & S2>(this as any);
114 }
124 }
115
125
116 has(id: string | number) {
126 has(id: string | number) {
@@ -1,4 +1,4
1 import { isNull, argumentNotEmptyString, each } from "../safe";
1 import { isNull, argumentNotEmptyString, each, keys } from "../safe";
2 import { ActivationContext } from "./ActivationContext";
2 import { ActivationContext } from "./ActivationContext";
3 import { ServiceMap, Descriptor } from "./interfaces";
3 import { ServiceMap, Descriptor } from "./interfaces";
4 import { ActivationError } from "./ActivationError";
4 import { ActivationError } from "./ActivationError";
@@ -11,6 +11,12 export interface ReferenceDescriptorPara
11 services?: ServiceMap;
11 services?: ServiceMap;
12 }
12 }
13
13
14 function def<T>(v: T) {
15 if (v === undefined)
16 throw Error();
17 return v;
18 }
19
14 export class ReferenceDescriptor<S, K extends keyof S> implements Descriptor<S[K]> {
20 export class ReferenceDescriptor<S, K extends keyof S> implements Descriptor<S[K]> {
15 _name: K;
21 _name: K;
16
22
@@ -20,7 +26,7 export class ReferenceDescriptor<S, K ex
20
26
21 _default: any;
27 _default: any;
22
28
23 _services: ServiceMap;
29 _services: ServiceMap<S>;
24
30
25 constructor(opts: ReferenceDescriptorParams<S, K>) {
31 constructor(opts: ReferenceDescriptorParams<S, K>) {
26 argumentNotEmptyString(opts && opts.name, "opts.name");
32 argumentNotEmptyString(opts && opts.name, "opts.name");
@@ -32,24 +38,22 export class ReferenceDescriptor<S, K ex
32 this._services = opts.services || {};
38 this._services = opts.services || {};
33 }
39 }
34
40
35 activate(context: ActivationContext, name: string) {
41 activate(context: ActivationContext<S>) {
36 // добавляем сервисы
42 // добавляем сервисы
37 if (this._services) {
43 if (this._services) {
38 for (const p of Object.keys(this._services))
44 each(this._services, (v, k) => context.register(k, def(v)));
39 context.register(p, this._services[p]);
40 }
45 }
41
46
42 if (this._lazy) {
47 if (this._lazy) {
43 const saved = context.clone();
48 const saved = context.clone();
44
49
45 return (cfg: ServiceMap) => {
50 return (cfg: Partial<ServiceMap<S>>) => {
46 // защищаем контекст на случай исключения в процессе
51 // защищаем контекст на случай исключения в процессе
47 // активации
52 // активации
48 const ct = saved.clone();
53 const ct = saved.clone();
49 try {
54 try {
50 if (cfg) {
55 if (cfg) {
51 for (const k in cfg)
56 each(cfg, (v, k) => ct.register(k, v || {}));
52 ct.register(k, cfg[k]);
53 }
57 }
54
58
55 return this._optional ? ct.resolve(this._name, this._default) : ct
59 return this._optional ? ct.resolve(this._name, this._default) : ct
@@ -59,12 +63,6 export class ReferenceDescriptor<S, K ex
59 }
63 }
60 };
64 };
61 } else {
65 } else {
62 // добавляем сервисы
63 if (this._services) {
64 for (const p of Object.keys(this._services))
65 context.register(p, this._services[p]);
66 }
67
68 const v = this._optional ?
66 const v = this._optional ?
69 context.resolve(this._name, this._default) :
67 context.resolve(this._name, this._default) :
70 context.resolve(this._name);
68 context.resolve(this._name);
@@ -3,7 +3,7 import { ActivationContext } from "./Act
3 import { Constructor, Factory } from "../interfaces";
3 import { Constructor, Factory } from "../interfaces";
4
4
5 export interface Descriptor<T = any> {
5 export interface Descriptor<T = any> {
6 activate(context: ActivationContext, name?: string): T;
6 activate<S>(context: ActivationContext<S>): T;
7 }
7 }
8
8
9 export function isDescriptor(x: any): x is Descriptor {
9 export function isDescriptor(x: any): x is Descriptor {
@@ -70,6 +70,6 export function isValueRegistration(x: a
70 return (!isPrimitive(x)) && ("$value" in x);
70 return (!isPrimitive(x)) && ("$value" in x);
71 }
71 }
72
72
73 export function isDependencyRegistration(x: any): x is DependencyRegistration<any, string | number | symbol> {
73 export function isDependencyRegistration<S>(x: any): x is DependencyRegistration<S, keyof S> {
74 return (!isPrimitive(x)) && ("$dependency" in x);
74 return (!isPrimitive(x)) && ("$dependency" in x);
75 }
75 }
@@ -6,9 +6,9 const _oid = typeof Symbol === "function
6 Symbol("__implab__oid__") :
6 Symbol("__implab__oid__") :
7 "__implab__oid__";
7 "__implab__oid__";
8
8
9 export function oid(instance: object): string {
9 export function oid(instance: any): string | undefined {
10 if (isNull(instance))
10 if (isNull(instance))
11 return null;
11 return undefined;
12
12
13 if (_oid in instance)
13 if (_oid in instance)
14 return instance[_oid];
14 return instance[_oid];
@@ -16,6 +16,10 export function oid(instance: object): s
16 return (instance[_oid] = "oid_" + (++_nextOid));
16 return (instance[_oid] = "oid_" + (++_nextOid));
17 }
17 }
18
18
19 export function keys<T>(arg: T): (Extract<keyof T, string>)[] {
20 return isObject(arg) && arg ? Object.keys(arg) as (Extract<keyof T, string>)[] : [];
21 }
22
19 export function argumentNotNull(arg: any, name: string) {
23 export function argumentNotNull(arg: any, name: string) {
20 if (arg === null || arg === undefined)
24 if (arg === null || arg === undefined)
21 throw new Error("The argument " + name + " can't be null or undefined");
25 throw new Error("The argument " + name + " can't be null or undefined");
@@ -36,6 +40,10 export function argumentOfType(arg: any,
36 throw new Error("The argument '" + name + "' type doesn't match");
40 throw new Error("The argument '" + name + "' type doesn't match");
37 }
41 }
38
42
43 export function isObject(val: any): val is object {
44 return typeof val === "object";
45 }
46
39 export function isNull(val: any) {
47 export function isNull(val: any) {
40 return (val === null || val === undefined);
48 return (val === null || val === undefined);
41 }
49 }
@@ -65,21 +73,20 export function isCancellable(val: any):
65 return val && typeof val.cancel === "function";
73 return val && typeof val.cancel === "function";
66 }
74 }
67
75
68 export function isNullOrEmptyString(val: any): val is string | null | undefined {
76 export function isNullOrEmptyString(val: any): val is (string | null | undefined) {
69 if (val === null || val === undefined ||
77 return (val === null || val === undefined ||
70 ((typeof (val) === "string" || val instanceof String) && val.length === 0))
78 ((typeof (val) === "string" || val instanceof String) && val.length === 0))
71 return true;
72 }
79 }
73
80
74 export function isNotEmptyArray(arg: any): arg is Array<any> {
81 export function isNotEmptyArray(arg: any): arg is Array<any> {
75 return (arg instanceof Array && arg.length > 0);
82 return (arg instanceof Array && arg.length > 0);
76 }
83 }
77
84
78 function _isStrictMode() {
85 function _isStrictMode(this: any) {
79 return !this;
86 return !this;
80 }
87 }
81
88
82 function _getNonStrictGlobal() {
89 function _getNonStrictGlobal(this: any) {
83 return this;
90 return this;
84 }
91 }
85
92
@@ -119,7 +126,9 export function get(member: string, cont
119 * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
126 * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
120 * если достигнут конец массива.
127 * если достигнут конец массива.
121 */
128 */
122 export function each(obj, cb, thisArg?) {
129 export function each<T>(obj: T, cb: (v: T[keyof T], k: keyof T) => void): void;
130 export function each(obj: any, cb: any, thisArg?: any): any;
131 export function each(obj: any, cb: any, thisArg?: any) {
123 argumentNotNull(cb, "cb");
132 argumentNotNull(cb, "cb");
124 if (obj instanceof Array) {
133 if (obj instanceof Array) {
125 for (let i = 0; i < obj.length; i++) {
134 for (let i = 0; i < obj.length; i++) {
@@ -128,8 +137,8 export function each(obj, cb, thisArg?)
128 return x;
137 return x;
129 }
138 }
130 } else {
139 } else {
131 const keys = Object.keys(obj);
140 const _keys = Object.keys(obj);
132 for (const k of keys) {
141 for (const k of _keys) {
133 const x = cb.call(thisArg, obj[k], k);
142 const x = cb.call(thisArg, obj[k], k);
134 if (x !== undefined)
143 if (x !== undefined)
135 return x;
144 return x;
@@ -166,8 +175,8 export function mixin<T extends object,
166 _res[p] = source[p];
175 _res[p] = source[p];
167 }
176 }
168 } else if (template) {
177 } else if (template) {
169 const keys = Object.keys(source);
178 const _keys = Object.keys(source);
170 for (const p of keys) {
179 for (const p of _keys) {
171 if (p in template)
180 if (p in template)
172 _res[template[p]] = source[p];
181 _res[template[p]] = source[p];
173 }
182 }
@@ -184,7 +193,7 export function mixin<T extends object,
184 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
193 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
185 * @param{Function|String} fn [Required] Function wich will be wrapped.
194 * @param{Function|String} fn [Required] Function wich will be wrapped.
186 */
195 */
187 export function async(_fn: (...args: any[]) => any, thisArg): (...args: any[]) => PromiseLike<any> {
196 export function async(_fn: (...args: any[]) => any, thisArg: any): (...args: any[]) => PromiseLike<any> {
188 let fn = _fn;
197 let fn = _fn;
189
198
190 if (arguments.length === 2 && !(fn instanceof Function))
199 if (arguments.length === 2 && !(fn instanceof Function))
@@ -284,7 +293,7 export function pmap<T, T2>(
284 let i = 0;
293 let i = 0;
285 const result = new Array<T2>();
294 const result = new Array<T2>();
286
295
287 const next = () => {
296 const next = (): any => {
288 while (i < items.length) {
297 while (i < items.length) {
289 const r = cb(items[i], i);
298 const r = cb(items[i], i);
290 const ri = i;
299 const ri = i;
@@ -319,7 +328,7 export function pfor<T>(
319
328
320 let i = 0;
329 let i = 0;
321
330
322 const next = () => {
331 const next = (): any => {
323 while (i < items.length) {
332 while (i < items.length) {
324 const r = cb(items[i], i);
333 const r = cb(items[i], i);
325 i++;
334 i++;
@@ -1,6 +1,13
1 import { config } from "./config";
1 import { services } from "../di/Annotations";
2 import { Bar } from "./Bar";
2
3
3 const service = config.build("barBox");
4 // declare required dependencies
5 const config = services<{
6 bar: Bar;
7 }>();
8
9 // export service descriptor
10 export const service = config.build<Box<Bar>>();
4
11
5 @service.consume(config.dependency("bar"))
12 @service.consume(config.dependency("bar"))
6 export class Box<T> {
13 export class Box<T> {
@@ -25,4 +32,4 export class Box<T> {
25
32
26 return this._value;
33 return this._value;
27 }
34 }
28 } No newline at end of file
35 }
General Comments 0
You need to be logged in to leave comments. Login now