##// END OF EJS Templates
ported IoC container to typescript...
cin -
r34:bf1098a8d031 di-typescript
parent child
Show More
@@ -0,0 +1,37
1 import { ActivationContextInfo } from "./ActivationContext";
2
3 export class ActivationError {
4 activationStack: ActivationContextInfo[]
5
6 service: string
7
8 innerException: any
9
10 message: string
11
12 constructor(service: string, activationStack: ActivationContextInfo[], innerException) {
13 this.message = "Failed to activate the service";
14 this.activationStack = activationStack;
15 this.service = service;
16 this.innerException = innerException;
17 }
18
19 toString() {
20 var parts = [this.message];
21 if (this.service)
22 parts.push("when activating: " + this.service.toString());
23
24 if (this.innerException)
25 parts.push("caused by: " + this.innerException.toString());
26
27 if (this.activationStack) {
28 parts.push("at");
29 this.activationStack.forEach(function (x) {
30 parts.push(" " + x.name + " " +
31 (x.service ? x.service.toString() : ""));
32 });
33 }
34
35 return parts.join("\n");
36 }
37 } No newline at end of file
@@ -0,0 +1,24
1 import { Descriptor } from "./interfaces";
2 import { ActivationContext } from "./ActivationContext";
3
4 export class AggregateDescriptor<T> implements Descriptor {
5 _value: T
6
7 constructor(value: T) {
8
9 }
10
11 activate(context: ActivationContext, name: string) {
12 context.enter(name);
13 let v = context.parse(this._value, ".params");
14 context.leave();
15 return v;
16 }
17
18 isInstanceCreated(): boolean {
19 return false;
20 }
21 getInstance(): T {
22 throw new Error("Not supported exception");
23 }
24 }
@@ -0,0 +1,17
1 import { argumentNotEmptyString, get } from "../safe";
2
3 export abstract class ModuleResolverBase {
4
5
6 async resolve(typeName: string) {
7 argumentNotEmptyString(typeName, "typeName");
8 let [moduleName, localName] = typeName.split("#", 2);
9
10 let moduleObject = await this.loadModule(moduleName);
11 return localName ? get(localName, moduleObject) : moduleObject;
12 }
13
14 abstract loadModule(moduleName: string): PromiseLike<Object>
15
16 abstract createResolver(moduleName: string): PromiseLike<ModuleResolverBase>
17 } No newline at end of file
@@ -0,0 +1,75
1 import { ModuleResolverBase } from "./ModuleResolverBase";
2 import { Uuid } from "../Uuid";
3 import { argumentNotEmptyString } from "../safe";
4 import { TraceSource } from "../log/TraceSource";
5
6 declare function require(modules: string[], cb?: (...args: any[]) => any): void;
7
8 declare function define(name: string, modules: string[], cb?: (...args: any[]) => any): void;
9
10 class RequireJsResolverParams {
11 contextRequire: (modules: string[], cb?: (...args: any[]) => any) => void
12
13 base: string
14 }
15
16 TraceSource.get("RequireJsResolver");
17
18 export class RequireJsResolver extends ModuleResolverBase {
19 _contextRequire = require
20
21 _base: string
22
23 constructor(opts) {
24 super();
25
26 if (opts) {
27
28 if (opts.contextRequire)
29 this._contextRequire = opts.contextRequire;
30
31 if (opts.base) {
32 if (opts.base.indexOf("./") == 0)
33 throw new Error(`A module id should be an absolute: '${opts.base}'`);
34 this._base = opts.base;
35 }
36 }
37
38 }
39
40 async createResolver(moduleName: string): Promise<ModuleResolverBase> {
41 argumentNotEmptyString(moduleName, "moduleName");
42
43 let parts = moduleName.split("/");
44 if (parts[0] == ".") {
45 if (this._base)
46 parts[0] = this._base;
47 else
48 throw new Error(`Can't resolve a relative module '${moduleName}'`);
49 }
50
51 if(parts.length > 1)
52 parts.splice(-1,1,Uuid());
53 else
54 parts.push(Uuid());
55
56 var shim = parts.join('/');
57
58 let contextRequire = await new Promise((resolve, reject) => {
59 define(shim, ["require"], function (ctx) {
60 resolve(ctx);
61 })
62 });
63
64 return new RequireJsResolver({
65 base: parts.slice(0,-1).join('/'),
66 contextRequire: contextRequire
67 });
68 }
69
70 async loadModule(moduleName: string): Promise<Object> {
71 return new Promise<Object>((resolve) => this._contextRequire.call(null, [moduleName], resolve)
72 );
73 }
74
75 } No newline at end of file
@@ -0,0 +1,275
1 import { ActivationContext } from "./ActivationContext";
2 import { Descriptor, ActivationType, ServiceMap, Constructor, Factory } from "./interfaces";
3 import { Container } from "./Container";
4 import { argumentNotNull, isPrimitive, oid } from "../safe";
5
6 let cacheId = 0;
7
8 function injectMethod(target, method, context, args) {
9 var m = target[method];
10 if (!m)
11 throw new Error("Method '" + method + "' not found");
12
13 if (args instanceof Array)
14 m.apply(target, context.parse(args, "." + method));
15 else
16 m.call(target, context.parse(args, "." + method));
17 };
18
19 function makeClenupCallback(target, method) {
20 if (typeof (method) === "string") {
21 return function () {
22 target[method]();
23 };
24 } else {
25 return function () {
26 method(target);
27 };
28 }
29 };
30
31 export interface ServiceDescriptorParams<T> {
32 activation: ActivationType
33
34 owner: Container
35
36 type: Constructor<T>
37
38 factory: Factory<T>
39
40 params
41
42 inject
43
44 services: ServiceMap
45
46 cleanup: (instance: T) => void
47 }
48
49 export class ServiceDescriptor<T> implements Descriptor {
50 _instance: T = null
51
52 _hasInstance = false
53
54 _activationType = ActivationType.CALL
55
56 _services: ServiceMap
57
58 _type: Constructor<T> = null
59
60 _factory: Factory<T> = null
61
62 _params
63
64 _inject: Array<Object>
65
66 _cleanup: (instance: T) => void
67
68 _cacheId: any
69
70 _owner: Container
71
72 constructor(opts: ServiceDescriptorParams<T>) {
73 argumentNotNull(opts, "opts");
74 argumentNotNull(opts.owner, "owner");
75
76 this._owner = opts.owner;
77
78 if (!(opts.type || opts.factory))
79 throw new Error(
80 "Either a type or a factory must be specified");
81
82 if (opts.activation)
83 this._activationType = opts.activation;
84
85 if (opts.type)
86 this._type = opts.type;
87
88 if (opts.params)
89 this._params = opts.params;
90
91 if (opts.inject)
92 this._inject = opts.inject instanceof Array ? opts.inject : [opts.inject];
93
94 if (opts.services)
95 this._services = opts.services;
96
97 if (opts.factory)
98 this._factory = opts.factory;
99
100 if (opts.cleanup) {
101 if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function))
102 throw new Error(
103 "The cleanup parameter must be either a function or a function name");
104
105 this._cleanup = opts.cleanup;
106 }
107
108 if (this._activationType == ActivationType.SINGLETON) {
109 let tof = this._type || this._factory;
110
111 // create the persistent cache identifier for the type
112 if (isPrimitive(tof))
113 this._cacheId = tof;
114 else
115 this._cacheId = oid(tof);
116 } else {
117 this._cacheId = ++cacheId;
118 }
119 }
120
121 activate(context: ActivationContext, name: string) {
122 // if we have a local service records, register them first
123 let instance;
124
125 switch (this._activationType) {
126 case ActivationType.SINGLETON: // SINGLETON
127 // if the value is cached return it
128 if (this._hasInstance)
129 return this._instance;
130
131 // singletons are bound to the root container
132 let container = context.container.getRootContainer();
133
134 if (container.has(this._cacheId)) {
135 instance = container.get(this._cacheId);
136 } else {
137 instance = this._create(context, name);
138 container.store(this._cacheId, instance);
139 if (this._cleanup)
140 container.onDispose(
141 makeClenupCallback(instance, this._cleanup));
142 }
143
144 this._hasInstance = true;
145 return (this._instance = instance);
146
147 case ActivationType.CONTAINER: // CONTAINER
148 //return a cached value
149 if (this._hasInstance)
150 return this._instance;
151
152 // create an instance
153 instance = this._create(context, name);
154
155 // the instance is bound to the container
156 if (this._cleanup)
157 this._owner.onDispose(
158 makeClenupCallback(instance, this._cleanup));
159
160 // cache and return the instance
161 this._hasInstance = true;
162 return (this._instance = instance);
163 case ActivationType.CONTEXT: // CONTEXT
164 //return a cached value if one exists
165 if (context.has(this._cacheId))
166 return context.get(this._cacheId);
167 // context context activated instances are controlled by callers
168 return context.store(this._cacheId, this._create(
169 context,
170 name));
171 case ActivationType.CALL: // CALL
172 // per-call created instances are controlled by callers
173 return this._create(context, name);
174 case ActivationType.HIERARCHY: // HIERARCHY
175 // hierarchy activated instances are behave much like container activated
176 // except they are created and bound to the child container
177
178 // return a cached value
179 if (context.container.has(this._cacheId))
180 return context.container.get(this._cacheId);
181
182 instance = this._create(context, name);
183
184 if (this._cleanup)
185 context.container.onDispose(makeClenupCallback(
186 instance,
187 this._cleanup));
188
189 return context.container.store(this._cacheId, instance);
190 default:
191 throw "Invalid activation type: " + this._activationType;
192 }
193 }
194
195 isInstanceCreated() {
196 return this._hasInstance;
197 }
198
199 getInstance() {
200 return this._instance;
201 }
202
203 _create(context, name) {
204 context.enter(name, this, Boolean(this._services));
205
206 if (this._activationType != ActivationType.CALL &&
207 context.visit(this._cacheId) > 0)
208 throw new Error("Recursion detected");
209
210 if (this._services) {
211 for (var p in this._services)
212 context.register(p, this._services[p]);
213 }
214
215 var instance;
216
217 if (!this._factory) {
218 var ctor = this._type;
219
220 if (this._params === undefined) {
221 this._factory = function () {
222 return new ctor();
223 };
224 } else if (this._params instanceof Array) {
225 this._factory = function () {
226 var inst = Object.create(ctor.prototype);
227 var ret = ctor.apply(inst, arguments);
228 return typeof (ret) === "object" ? ret : inst;
229 };
230 } else {
231 this._factory = function (param) {
232 return new ctor(param);
233 };
234 }
235 }
236
237 if (this._params === undefined) {
238 instance = this._factory();
239 } else if (this._params instanceof Array) {
240 instance = this._factory.apply(this, context.parse(
241 this._params,
242 ".params"));
243 } else {
244 instance = this._factory(context.parse(
245 this._params,
246 ".params"));
247 }
248
249 if (this._inject) {
250 this._inject.forEach(function (spec) {
251 for (var m in spec)
252 injectMethod(instance, m, context, spec[m]);
253 });
254 }
255
256 context.leave();
257
258 return instance;
259 }
260
261 // @constructor {singleton} foo/bar/Baz
262 // @factory {singleton}
263 toString() {
264 var parts = [];
265
266 parts.push(this._type ? "@constructor" : "@factory");
267
268 parts.push(ActivationType[this._activationType]);
269
270 if (typeof (this._type) === "string")
271 parts.push(this._type);
272
273 return parts.join(" ");
274 }
275 } No newline at end of file
@@ -0,0 +1,23
1 import { Descriptor } from "./interfaces";
2 import { ActivationContext } from "./ActivationContext";
3
4 export class ValueDescriptor<T> implements Descriptor {
5 _value: T
6
7 constructor(value: T) {
8 this._value = value;
9 }
10
11 activate(context: ActivationContext, name: string) {
12 context.enter(name);
13 let v = this._value;
14 context.leave();
15 return v;
16 }
17 isInstanceCreated(): boolean {
18 return true;
19 }
20 getInstance(): T {
21 return this._value;
22 }
23 } No newline at end of file
@@ -0,0 +1,28
1 import { isNull } from "../safe";
2 import { ActivationContext } from "./ActivationContext";
3
4 export interface Descriptor {
5 activate(context: ActivationContext, name?: string);
6 }
7
8 export type Constructor<T = {}> = new (...args: any[]) => T;
9
10
11 export type Factory<T = {}> = (...args: any[]) => T;
12
13 export function isDescriptor(instance): instance is Descriptor {
14 return (!isNull(instance)) &&
15 ('activate' in instance);
16 }
17
18 export interface ServiceMap {
19 [s: string] : Descriptor
20 }
21
22 export enum ActivationType {
23 SINGLETON,
24 CONTAINER,
25 HIERARCHY,
26 CONTEXT,
27 CALL
28 } No newline at end of file
@@ -0,0 +1,40
1 {
2 "extends": "tslint:recommended",
3 "rules": {
4 "align": [
5 true,
6 "parameters",
7 "statements"
8 ],
9 "interface-name": [false],
10 "max-line-length": [ true, 185 ],
11 "member-access": false,
12 "member-ordering": [
13 false,
14 "variables-before-functions"
15 ],
16 "no-bitwise": false,
17 "no-empty": false,
18 "no-namespace": false,
19 "no-string-literal": false,
20 "ordered-imports": false,
21 "one-line": [
22 true,
23 "check-open-brace",
24 "check-catch",
25 "check-whitespace"
26 ],
27 "object-literal-sort-keys": false,
28 "trailing-comma": [
29 true,
30 {
31 "singleline": "never",
32 "multiline": "never"
33 }
34 ],
35 "variable-name": false,
36 "curly": false,
37 "array-type": false,
38 "arrow-parens": [true, "ban-single-arg-parens"]
39 }
40 } No newline at end of file
@@ -57,7 +57,7 task _packageMeta(type: Copy) {
57 57 }
58 58 }
59 59
60 task build(dependsOn: [_npmInstall, _buildTs, _legacyJs, _packageMeta]) {
60 task build(dependsOn: [_legacyJs, _npmInstall, _buildTs, _packageMeta]) {
61 61
62 62 }
63 63
@@ -258,7 +258,7 function _v4(options?, buf?, offset?): s
258 258 }
259 259
260 260 export function Uuid() {
261
261 return _v4();
262 262 }
263 263
264 264 export namespace Uuid {
@@ -1,126 +0,0
1 import { TraceSource } from "./log/TraceSource";
2 import { argumentNotNull, argumentNotEmptyString, isPrimitive, each, isNull } from "./safe";
3 import { Uuid } from './Uuid';
4 import {ActivationContext} from "./di/ActivationContext";
5
6 let trace = TraceSource.get("di");
7
8 export interface Descriptor {
9 activate(context: ActivationContext, name: string): any
10 }
11
12 export function isDescriptor(value: any): value is Descriptor {
13 return ("activate" in value);
14 }
15
16 export interface ServiceMap {
17 [s: string] : Descriptor
18 }
19
20 export class ActivationContextInfo {
21 name: string
22
23 service: string
24
25 scope: ServiceMap
26 }
27
28 export class ActivationError {
29 activationStack: ActivationContextInfo[]
30
31 service: string
32
33 innerException: any
34
35 message: string
36
37 constructor(service: string, activationStack: ActivationContextInfo[], innerException) {
38 this.message = "Failed to activate the service";
39 this.activationStack = activationStack;
40 this.service = service;
41 this.innerException = innerException;
42 }
43
44 toString() {
45 var parts = [this.message];
46 if (this.service)
47 parts.push("when activating: " + this.service.toString());
48
49 if (this.innerException)
50 parts.push("caused by: " + this.innerException.toString());
51
52 if (this.activationStack) {
53 parts.push("at");
54 this.activationStack.forEach(function (x) {
55 parts.push(" " + x.name + " " +
56 (x.service ? x.service.toString() : ""));
57 });
58 }
59
60 return parts.join("\n");
61 }
62 }
63
64
65 export enum ActivationType {
66 SINGLETON,
67 CONTAINER,
68 HIERARCHY,
69 CONTEXT,
70 CALL
71 }
72
73
74
75 interface ServiceDescriptorParams {
76
77 }
78
79 class ServiceDescriptor extends Descriptor {
80 constructor(opts: ServiceDescriptorParams) {
81 super();
82 }
83
84 activate(context: ActivationContext, name: string) {
85 throw new Error("Method not implemented.");
86 }
87 isInstanceCreated(): boolean {
88 throw new Error("Method not implemented.");
89 }
90 getInstance() {
91 throw new Error("Method not implemented.");
92 }
93 }
94
95
96
97 class AggregateDescriptor<T> extends Descriptor {
98 constructor(value: T) {
99 super();
100 }
101
102 activate(context: ActivationContext, name: string) {
103 throw new Error("Method not implemented.");
104 }
105 isInstanceCreated(): boolean {
106 throw new Error("Method not implemented.");
107 }
108 getInstance(): T {
109 throw new Error("Method not implemented.");
110 }
111 }
112
113 class ValueDescriptor<T> implements Descriptor {
114 activate(context: ActivationContext, name: string) {
115 throw new Error("Method not implemented.");
116 }
117 isInstanceCreated(): boolean {
118 throw new Error("Method not implemented.");
119 }
120 getInstance(): T {
121 throw new Error("Method not implemented.");
122 }
123 constructor(value: T) {
124
125 }
126 } No newline at end of file
@@ -1,10 +1,18
1 1 import { TraceSource } from "../log/TraceSource";
2 2 import { argumentNotNull, argumentNotEmptyString, isPrimitive, each, isNull } from "../safe";
3 import { Uuid } from '../Uuid';
4 import { Container, ActivationContextInfo, ServiceMap, Descriptor, isDescriptor } from "../di";
3 import { Descriptor, ServiceMap, isDescriptor } from "./interfaces";
4 import { Container } from "./Container";
5 5
6 6 let trace = TraceSource.get("di");
7 7
8 export class ActivationContextInfo {
9 name: string
10
11 service: string
12
13 scope: ServiceMap
14 }
15
8 16
9 17 export class ActivationContext {
10 18 _cache: object
@@ -1,6 +1,16
1 declare function require(modules: string[], cb?: (...args: any[]) => any) : void;
2
3 declare function define(name:string, modules: string[], cb?: (...args: any[]) => any) : void;
4
1 5 import { Uuid } from "../Uuid";
2 6 import { ActivationContext } from "./ActivationContext";
3 import { ActivationError } from "../di";
7 import { ValueDescriptor } from "./ValueDescriptor";
8 import { ActivationError } from "./ActivationError";
9 import { isDescriptor, ActivationType } from "./interfaces";
10 import { AggregateDescriptor } from "./AggregateDescriptor";
11 import { isPrimitive } from "../safe";
12 import { ReferenceDescriptor } from "./ReferenceDescriptor";
13 import { ServiceDescriptor } from "./ServiceDescriptor";
4 14
5 15
6 16 export class Container {
@@ -57,7 +67,7 export class Container {
57 67 for (let name in data)
58 68 this.register(name, data[name]);
59 69 } else {
60 if (!(service instanceof Descriptor))
70 if (!(isDescriptor(service)))
61 71 service = new ValueDescriptor(service);
62 72 this._services[nameOrCollection] = service;
63 73 }
@@ -147,7 +157,7 export class Container {
147 157
148 158 for (p in data) {
149 159 var service = me._parse(data[p], typemap);
150 if (!(service instanceof Descriptor))
160 if (!(isDescriptor(service)))
151 161 service = new AggregateDescriptor(service);
152 162 services[p] = service;
153 163 }
@@ -174,7 +184,7 export class Container {
174 184 }
175 185
176 186 _parse(data, typemap) {
177 if (isPrimitive(data) || data instanceof Descriptor)
187 if (isPrimitive(data) || isDescriptor(data))
178 188 return data;
179 189 if (data.$dependency) {
180 190 return new ReferenceDescriptor(
@@ -1,6 +1,9
1 1 import { isNull, argumentNotEmptyString, each } from "../safe";
2 import { ActivationContext } from "./ActivationContext";
3 import { ServiceMap, Descriptor } from "./interfaces";
4 import { ActivationError } from "./ActivationError";
2 5
3 class ReferenceDescriptor extends Descriptor {
6 export class ReferenceDescriptor implements Descriptor {
4 7 _name: string
5 8
6 9 _lazy = false
@@ -9,10 +12,9 class ReferenceDescriptor extends Descri
9 12
10 13 _default: any
11 14
12 _services: object
15 _services: ServiceMap
13 16
14 constructor(name: string, lazy: boolean, optional: boolean, def, services: object) {
15 super();
17 constructor(name: string, lazy: boolean, optional: boolean, def, services: ServiceMap) {
16 18 argumentNotEmptyString(name, "name");
17 19 this._name = name;
18 20 this._lazy = Boolean(lazy);
@@ -30,22 +32,22 class ReferenceDescriptor extends Descri
30 32 if (me._services) {
31 33 for (var p in me._services) {
32 34 var sv = me._services[p];
33 context.register(p, sv instanceof Descriptor ? sv : new AggregateDescriptor(sv));
35 context.register(p, sv);
34 36 }
35 37 }
36 38
37 39 if (me._lazy) {
38 40 // сохраняем контекст активации
39 41 context = context.clone();
40 return function (cfg) {
42 return function (cfg: ServiceMap) {
41 43 // защищаем контекст на случай исключения в процессе
42 44 // активации
43 45 var ct = context.clone();
44 46 try {
45 47 if (cfg)
46 each(cfg, function (v, k) {
47 ct.register(k, v instanceof Descriptor ? v : new AggregateDescriptor(v));
48 });
48 for(let k in cfg)
49 ct.register(k, cfg[v]);
50
49 51 return me._optional ? ct.getService(me._name, me._default) : ct
50 52 .getService(me._name);
51 53 } catch (error) {
@@ -1,3 +1,16
1 let _nextOid = 0;
2 const _oid = Symbol("__oid");
3
4 export function oid(instance: object) {
5 if (isNull(instance))
6 return null;
7
8 if (_oid in instance)
9 return instance[_oid];
10 else
11 return (instance[_oid] = "oid_" + (++_nextOid));
12 }
13
1 14 export function argumentNotNull(arg, name) {
2 15 if (arg === null || arg === undefined)
3 16 throw new Error("The argument " + name + " can't be null or undefined");
@@ -28,20 +41,20 export function isPrimitive(arg) {
28 41 }
29 42
30 43 export function isInteger(arg) {
31 return parseInt(arg) == arg;
44 return parseInt(arg, 10) === arg;
32 45 }
33 46
34 47 export function isNumber(arg) {
35 return parseFloat(arg) == arg;
48 return parseFloat(arg) === arg;
36 49 }
37 50
38 51 export function isString(val) {
39 return typeof (val) == "string" || val instanceof String;
52 return typeof (val) === "string" || val instanceof String;
40 53 }
41 54
42 55 export function isNullOrEmptyString(str) {
43 56 if (str === null || str === undefined ||
44 ((typeof (str) == "string" || str instanceof String) && str.length === 0))
57 ((typeof (str) === "string" || str instanceof String) && str.length === 0))
45 58 return true;
46 59 }
47 60
@@ -49,11 +62,28 export function isNotEmptyArray(arg): ar
49 62 return (arg instanceof Array && arg.length > 0);
50 63 }
51 64
65 export function getGlobal() {
66 return this;
67 }
68
69 export function get(member: string, context?: object) {
70 argumentNotEmptyString(member, "member");
71 let that = context || getGlobal();
72 const parts = member.split(".");
73 for (const m of parts) {
74 if (!m)
75 continue;
76 if (isNull(that = that[m]))
77 break;
78 }
79 return that;
80 }
81
52 82 /**
53 83 * Выполняет метод для каждого элемента массива, останавливается, когда
54 84 * либо достигнут конец массива, либо функция <c>cb</c> вернула
55 85 * значение.
56 *
86 *
57 87 * @param {Array | Object} obj массив элементов для просмотра
58 88 * @param {Function} cb функция, вызываемая для каждого элемента
59 89 * @param {Object} thisArg значение, которое будет передано в качестве
@@ -63,18 +93,16 export function isNotEmptyArray(arg): ar
63 93 */
64 94 export function each(obj, cb, thisArg?) {
65 95 argumentNotNull(cb, "cb");
66 var i, x;
67 96 if (obj instanceof Array) {
68 for (i = 0; i < obj.length; i++) {
69 x = cb.call(thisArg, obj[i], i);
97 for (let i = 0; i < obj.length; i++) {
98 const x = cb.call(thisArg, obj[i], i);
70 99 if (x !== undefined)
71 100 return x;
72 101 }
73 102 } else {
74 var keys = Object.keys(obj);
75 for (i = 0; i < keys.length; i++) {
76 var k = keys[i];
77 x = cb.call(thisArg, obj[k], k);
103 const keys = Object.keys(obj);
104 for (const k of keys) {
105 const x = cb.call(thisArg, obj[k], k);
78 106 if (x !== undefined)
79 107 return x;
80 108 }
@@ -83,7 +111,7 export function each(obj, cb, thisArg?)
83 111
84 112 /** Copies property values from a source object to the destination and returns
85 113 * the destination onject.
86 *
114 *
87 115 * @param dest The destination object into which properties from the source
88 116 * object will be copied.
89 117 * @param source The source of values which will be copied to the destination
@@ -95,31 +123,27 export function each(obj, cb, thisArg?)
95 123 * where keys are property names in the source and the values are property
96 124 * names in the destination object. If the template isn't specified then the
97 125 * own properties of the source are entirely copied to the destination.
98 *
126 *
99 127 */
100 export function mixin<T,S>(dest: T, source: S, template?: string[] | object) : T & S {
128 export function mixin<T, S>(dest: T, source: S, template?: string[] | object): T & S {
101 129 argumentNotNull(dest, "to");
102 let _res = <T & S>dest;
130 const _res = dest as T & S;
103 131
104 132 if (template instanceof Array) {
105 for(let i = 0; i < template.length; i++) {
106 let p = template[i];
133 for (const p of template) {
107 134 if (p in source)
108 135 _res[p] = source[p];
109 136 }
110 137 } else if (template) {
111 let keys = Object.keys(source);
112 for(let i = 0; i < keys.length; i++) {
113 let p = keys[i];
138 const keys = Object.keys(source);
139 for (const p of keys) {
114 140 if (p in template)
115 141 _res[template[p]] = source[p];
116 142 }
117 143 } else {
118 let keys = Object.keys(source);
119 for(let i = 0; i < keys.length; i++) {
120 let p = keys[i];
144 const keys = Object.keys(source);
145 for (const p of keys)
121 146 _res[p] = source[p];
122 }
123 147 }
124 148
125 149 return _res;
@@ -132,7 +156,7 export function mixin<T,S>(dest: T, sour
132 156 export function async(_fn: (...args: any[]) => any, thisArg): (...args: any[]) => PromiseLike<any> {
133 157 let fn = _fn;
134 158
135 if (arguments.length == 2 && !(fn instanceof Function))
159 if (arguments.length === 2 && !(fn instanceof Function))
136 160 fn = thisArg[fn];
137 161
138 162 if (fn == null)
@@ -141,7 +165,7 export function async(_fn: (...args: any
141 165 function wrapresult(x, e?): PromiseLike<any> {
142 166 if (e) {
143 167 return {
144 then: function (cb, eb) {
168 then(cb, eb) {
145 169 try {
146 170 return eb ? wrapresult(eb(e)) : this;
147 171 } catch (e2) {
@@ -153,7 +177,7 export function async(_fn: (...args: any
153 177 if (x && x.then)
154 178 return x;
155 179 return {
156 then: function (cb) {
180 then(cb) {
157 181 try {
158 182 return cb ? wrapresult(cb(x)) : this;
159 183 } catch (e2) {
@@ -164,16 +188,18 export function async(_fn: (...args: any
164 188 }
165 189 }
166 190
167 return function () {
191 return (...args) => {
168 192 try {
169 return wrapresult(fn.apply(thisArg, arguments));
193 return wrapresult(fn.apply(thisArg, args));
170 194 } catch (e) {
171 195 return wrapresult(null, e);
172 196 }
173 197 };
174 198 }
175 199
176 export function delegate<T, K extends keyof T>(target: T, _method: (K | Function)) {
200 type _AnyFn = (...args) => any;
201
202 export function delegate<T, K extends keyof T>(target: T, _method: (K | _AnyFn)) {
177 203 let method;
178 204
179 205 if (!(_method instanceof Function)) {
@@ -185,18 +211,18 export function delegate<T, K extends ke
185 211 method = _method;
186 212 }
187 213
188 return function () {
189 return method.apply(target, arguments);
214 return (...args) => {
215 return method.apply(target, args);
190 216 };
191 217 }
192 218
193 219 /**
194 220 * Для каждого элемента массива вызывает указанную функцию и сохраняет
195 221 * возвращенное значение в массиве результатов.
196 *
222 *
197 223 * @remarks cb может выполняться асинхронно, при этом одновременно будет
198 224 * только одна операция.
199 *
225 *
200 226 * @async
201 227 */
202 228 export function pmap(items, cb) {
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now